2016年5月21日土曜日

1.5 Output-Interpolated Panner


Output-Interpolated Panner



改良型 Pan と同じ動きをする、
より負荷の少ないものを作ることは難しいですが、
近似値を出す処理コストの小さい Pan を作ることはできます。


負荷を減らすためには、
`sqrt` 関数をfor ループの外に出さなければなりません。


---

改良型 Pan では、 まず `smooth` 関数を用い、
スライダーを読み込んだ後で、
2つの `sqrt` 関数を用いました。



Fig1.5 の改良型 Pan のダイアグラムを見ると、
`hslider` オブジェクトと、 `smooth`関数につながる箇所が、
すべての c ブロックの中に存在することがわかります。

`hslider` からの流れを追うと、
`sqrt` 関数を通過し、
最終的には、 ` - ` モジュールにたどりついています。


これらを言い換えると、 `smooth` 関数は、
いくつかの関数や引数と合わせて成り立っており、
その引数がサンプリングレートに影響されることからも、
`sqrt` 関数もサンプリングレートが影響していることになります。

もし、`sqrt` 関数の処理コストを、
2つ目のPan よりも少なくするなら、
`sqrt`関数を`smooth`関数の引数にしてしまう方法があります。
-----

それでは、新しい Pan のコードをみてみます。

Output-Interpolated Panner

DSPファイル


  1 import("filter.lib") ;
  2 
  3 t = hslider("interpolation time", 0.001, 0, 0.01, 0.0001);
  4 c = hslider("pan", 0.5, 0, 1, 0.01);              
  5 process = _ <: *((sqrt(1-c)) : smooth(tau2pole(t))),
  6                *((sqrt(c)) : smooth(tau2pole(t)));

C++コード


//-----------------------------------------------------
//
// Code generated with Faust 0.9.73 (http://faust.grame.fr)
//-----------------------------------------------------
/* link with  */
#include <math.h>
#ifndef FAUSTFLOAT
#define FAUSTFLOAT float
#endif  


#ifndef FAUSTCLASS 
#define FAUSTCLASS mydsp
#endif

class mydsp : public dsp {
  private:
float fConst0;
FAUSTFLOAT fslider0;
FAUSTFLOAT fslider1;
float fRec0[2];
float fRec1[2];
  public:
static void metadata(Meta* m)
m->declare("filter.lib/name", "Faust Filter Library");
m->declare("filter.lib/author", "Julius O. Smith (jos at ccrma.stanford.edu)");
m->declare("filter.lib/copyright", "Julius O. Smith III");
m->declare("filter.lib/version", "1.29");
m->declare("filter.lib/license", "STK-4.3");
m->declare("filter.lib/reference", "https://ccrma.stanford.edu/~jos/filters/");
m->declare("music.lib/name", "Music Library");
m->declare("music.lib/author", "GRAME");
m->declare("music.lib/copyright", "GRAME");
m->declare("music.lib/version", "1.0");
m->declare("music.lib/license", "LGPL with exception");
m->declare("math.lib/name", "Math Library");
m->declare("math.lib/author", "GRAME");
m->declare("math.lib/copyright", "GRAME");
m->declare("math.lib/version", "1.0");
m->declare("math.lib/license", "LGPL with exception");
}

virtual int getNumInputs() { return 1; }
virtual int getNumOutputs() { return 2; }
static void classInit(int samplingFreq) {
}
virtual void instanceInit(int samplingFreq) {
fSamplingFreq = samplingFreq;
fConst0 = (1.0f / float(min(192000, max(1, fSamplingFreq))));
fslider0 = 0.001f;
fslider1 = 0.5f;
for (int i=0; i<2; i++) fRec0[i] = 0;
for (int i=0; i<2; i++) fRec1[i] = 0;
}
virtual void init(int samplingFreq) {
classInit(samplingFreq);
instanceInit(samplingFreq);
}
virtual void buildUserInterface(UI* interface) {
interface->openVerticalBox("0x00");
interface->addHorizontalSlider("interpolation time", &fslider0, 0.001f, 0.0f, 0.01f, 0.0001f);
interface->addHorizontalSlider("pan", &fslider1, 0.5f, 0.0f, 1.0f, 0.01f);
interface->closeBox();
}
virtual void compute (int count, FAUSTFLOAT** input, FAUSTFLOAT** output) {
float fSlow0 = expf((0 - (fConst0 / float(fslider0))));
float fSlow1 = float(fslider1);
float fSlow2 = (1.0f - fSlow0);
float fSlow3 = (sqrtf((1 - fSlow1)) * fSlow2);
float fSlow4 = (sqrtf(fSlow1) * fSlow2);
FAUSTFLOAT* input0 = input[0];
FAUSTFLOAT* output0 = output[0];
FAUSTFLOAT* output1 = output[1];
for (int i=0; i<count; i++) {
float fTemp0 = (float)input0[i];
fRec0[0] = ((fSlow0 * fRec0[1]) + fSlow3);
output0[i] = (FAUSTFLOAT)(fTemp0 * fRec0[0]);
fRec1[0] = ((fSlow0 * fRec1[1]) + fSlow4);
output1[i] = (FAUSTFLOAT)(fTemp0 * fRec1[0]);
// post processing
fRec1[1] = fRec1[0];
fRec0[1] = fRec0[0];
}
}
};



SVG ダイアグラム



---

この Pan は改良型 Pan とほとんど同じ働きをするものの、
処理コストは、改良型 Pan に比べ、大幅に少なくなっています。

改良型 Pan との違いは、すべての値を S(c) 関数内部に入れてしまった部分です。


そして、出力される結果は、Condition(2) になるPan です。


改良型 Pan と比べ、 今回の"Output-Interpolated Panner"は、
`hslider`箇所が、S(c) 関数内部にあり、
補完値を出力しています。

よって、condition(2) を作り出すための計算は、
`hslider`の値を変えて、control rateを調整した際に処理が行われ、
補完値を出力する計算とは別に行われていることがわかります。

`hslider` の値を調整した際にわかる違いですが、
`Angle-Interpolated Pannder`では、常に同じ強度で聞こえていたのが、
`Output-Interpolanted Panner` では、音強度は、
`hslider`の値を変えたのちすぐに計算されるという部分です。

よって`hslider`をずっと動かし続けてしまうと、
補完部分のみしか聴こえなくなり、
元の音強度は正しく出力されません。

これはよくあるケースではありませんが、
例えば、音響実験では、
"Angled-Interpolated Panner"を用いなければなりません。

他のほとんどの音楽シーンでは、
代わりに "Output-Interpolated Panner" を用いても、
何の問題もないでしょう。


Output-Interpolated Pannerにて Pan を調整した際の特徴を Fig1.10に表しています。




緑の線は、その時間での`hslider` の値を表しています。
`hslider` は、サンプリングレート44.1KHz と
256サンプルのコントロールブロックにて、
0から1の値へ、0.1 秒かけて動いています。


よって、`hslider` の値は、毎256サンプルごとに更新され、
control block分だけ値が保持されます。
Fig.1.10では `hslider` の値は右側に書かれている値(0.0〜1.0)です。



赤色の線は、2ch の出力値の合計の平方根です。
値は一定の強度に比例し、変わるべきではありません。




しかし、この Pan では、非常にわずかな変化が起こっています。
この値は、左側の数値(1.002062 から 1.000100 pa2、大体0.0085dB)になります。


知覚するにはあまりにも小さな変化です。


Interpolative Time は 0.1 msに設定しています。
普通の Panとしてならば、非常に良好に動きます。


しかしながら、Panの値が本当に短い時間で、
2つの距離を動くならば(例えば、-1から1)、
明らかな違いがわかるでしょう。

0 件のコメント:

コメントを投稿