RSS Twitter Facebook
g200kg > VSTiの作り方 > 3.プログラム

VSTiの作り方

2004/08/22

3.プログラム



3.1 波形の作り方

じゃこの辺で、波形の作り方について説明しよう

たとえば正弦波を出すのなら単純に考えるとsin()なわけだが、もちろん波形生成時に
まともに使っていてはたまらなく遅い。 というわけでvstxsynthでもやってたように
テーブル化してしまうのが割りと普通かと思う。複雑な波形にする事もできそうだしな。
綺麗な波形が欲しければ読み出しの時に補間するなりの処理をしないと妙なエイリアス
がでるぞ! ま、そのエイリアスが味になるという場合もないではないがな。

というのがよくあるパターンではないかなぁ。
まあそれはそれとして・・・

例えば弦が張ってあるとしてだ。それを横にぐいと引っ張ると元に戻ろうとする力が
はたらくな。その力は大雑把に言えば弦の元の位置からのずれに比例する。
つまりxずれていればk*xだ。その力によって弦は元の位置に向かって一定の
加速度で加速する。
つまりだ。
v=速度
x=変位とすると

x=x+v
v=v-k*x

だ。たったこれだけ。たったこれだけで実に見事な正弦波がつくれるのDA!
ウソダと思うならすぐにExcelで確かめるのだ!!
Excel !? 実はExecはシミュレーション的には使い出があるぞ。

ABC
1100.001
2=A1+B1=B1-$c$1*A2
3
4
というぐあいだ。このAとBをずっと下の方まで複写していくと振動しているのが わかるぞ! さらにAの列を選択して折れ線グラフをつくるとこの通りだ↓↓

C1の0.001を色々変えると楽しいぞ!! それからさらに!! これは永久に振動しているが普通に考えて 例えば弦が振動すると空気の抵抗とかでだんだん速度がうしなわれるな。 つまり・・・

x=x+v
v=v*k2 - k1*x
でk2=0.99とかすれば、なんだか素敵っぽくなったりもするぞ!!




何か使いたくなる感じだろ?


3.2 MIDIイベントの扱い

さて、今回はリクエストもあったのでMIDIイベントの扱いについてDA!

VSTiはシンセなのでMIDIのイベントにしたがって音を出す。
で、そのMIDIイベントはVSTiにどんな風にやってくるのか!? という事だが・・・
ここはねぇ、はっきり言って私もDaichi氏のページのパクリなわけですよ。

でもまあ、私なりに解説しよう!!

まず大元から、
VSTiは起動した後、OnしたりOffしたりすると、それぞれ
resume() / suspend() というメソドが呼ばれるのだ。
で、vstxsynthのサンプルを見るとわかるように、普通suspend()では何もしないのだが、
resume()では wantEvents () を呼び出すのDA!! (これは、このタイミングで呼び出すもの
らしいぞ。コンストラクタのタイミングでは駄目だとドキュメントに書いてあるからな)

wantEvents()!! イベントが欲しいゼ!!
というわけだ。するとホストはイベント(MIDIとは限らない)を送りつけてくるのだ。

つまり、processEvents(VstEvents *ev)が、ぽこぽこと呼び出される。
で、このVstEventsというものは何者かというと、Typeで分かれていて
MIDI Type/Audio Type/Video Typeなんかがあるらしい。が!!
とりあえず必要なのはMIDITypeだ!! 他のは知らん!!
というわけでタイプがMIDIなら強引に(VstMIDIEvent*)にキャストして他は捨て!!
なのだ。

ところで...、
音を処理するprocess()/processReplacing() とMIDIイベントがやってくる
processEvents()の関係なのだが、process() 側では、まとまったブロック毎に
処理する事になっている。process()が呼び出されたらブロック分の波形を
作って返す訳だから、そのブロック内に必要なMIDIイベントは事前にprocessEvents()
で渡されているのだ。
これが、いくつあるかはわからない。なので、processEvents()
でMIDIイベントが来るととりあえずそれをバッファに溜めておいて process()が呼ばれた
時にそれをチェックしながら波形を作るわけだな。

こんな感じDA!!
このあたりの関係がvstxsynthのサンプルから読み取るのが難しいのだ。
というわけで、
Daichi氏ページだよりなのだ。
結局そこかよ!
......




3.3 デノーマルの罠

さて、最近のパソコンは速いし、浮動少数でごりごり計算しても結構いけるもんだね、
て感心してみたりもするが、実は危険な罠が待っているぞ!!

このコードだ!!

#include <windows.h>
#include <stdio.h>
 
int main(int argc,char *argv[]) {
    int i,j;
  float fVal,fVal2;
  DWORD dwTime1,dwTime2;
  fVal=0.1f;
  for(j=1;j<60;++j) {
        dwTime1=GetTickCount();
        for(i=0;i<10000000;++i) {
            fVal2=fVal*0.1f;
        }
        fVal=fVal2;
        dwTime2=GetTickCount();
        printf("%8dmsec\t%g\n",dwTime2-dwTime1,fVal);
    }
    return 0;
}
要するに何かに0.1を掛けて小さくしていっていつかは0になるだろうという コードだが、それぞれ1000万回やって時間を計っている。 単精度の浮動少数の指数部は符号含めて8ビット、つまり最小の値は2の マイナス128乗、10のマイナス38乗のあたりだ。 これを走らせると・・・

このざまDA!!! 大体平均30ミリ秒~40ミリ秒で1000万回の掛け算をやっているのだが、 限界値の10のマイナス38乗あたりでとんでもない時間がかかっているぞ!! 計算結果も微妙におかしい・・・これがデノーマルの罠だ。

200倍くらい遅いかなぁ。詳しくは説明しないが、0になっちゃうのが嫌なので、
限界を超えて頑張ってみたということだ。あきらめて0になっちゃえば元通り
30~40ミリ秒になる。CPUとしては悪気があってやったわけではないので
困ったものだが、これは音をリアルタイムで処理する上では致命的だ!

フィルタ関係で良く起こったりするが、単純に音量を減衰させようとかして
0.なんとかの数を掛け続けたりするだけでもはまるぞ。

これを避けるためには、やばそうな計算をする前に、わざと微小ノイズを
加えておくとか、値が充分小さければ0にしておくとかしとかないといけないぞ!!

めんどうな・・・


3.4 パラメータ

VSTiでツマミをいじったりして設定したものは、すべてホスト側で曲のデータと
一緒に記憶される事になるのだが、ここで重要な掟がある!!

設定するパラメータはすべて0.0~1.0の範囲のfloat値で扱うのDA!!
ぐりぐり回すつまみは0.0~1.0、ただのOn/Offスイッチなら0.0 or 1.0だ!
3点切り替えなら 0.0 or 0.5 or 1.0、 4点の切り替えなら0.0 or 0.333 or 0.666 or 1.0だ。

このパラメータ関係、実は結構ややこしいのだ。
パラメータを変化させる要因は
1. ユーザーがGUIのツマミをいじった
2. ホストのシーケンサのオートメーション機能で変化させた
3. MIDIのControlChangeとかで動かした
4. VSTiの別の音色(Program)を読み込んだ

と色々あるのだ! どの要因でも動かないといけないぞ!
で、パラメータが変化した時は、

1. 音の生成部にパラメータを反映する
2. GUI(が表示されていれば)ツマミの表示を更新する
3. 現在選択されているプログラムのパラメータに反映する

という動作になる。 それぞれの要因で、何がどういう順序で
呼ばれるかちゃんと考えないと妙な事になるからな。気をつけてくれ

APIもなんとなく紛らわしいぞ。整理すると・・・

CControlListener::valueChanged   ←ツマミをいじったら呼ばれる
AudioEffect::setParameterAutomated ←GUIのツマミがいじられたら呼ぶ
                         ホストはオートメーション記録はここでやる
                         これを呼ぶと↓のが呼ばれる。
AudioEffect::setParameter ←ホストのオートメーションとか、↑の奴とかで呼ばれる
AEffGUIEditor::setParameter ←上のと同じ。普通ここでGUI更新

という事だ。だからMIDI CCの対応だとAudioEffect::setParameterAutomatedから呼ばないと
いけないぞ!! 実はProtoPSG003はここ、失敗してる。MIDICCを受けた時にsetParameterAutomatedじゃなくて
setParameterでツマミを動かしているので、MIDI CCからオートメーション記録ができないのDA!!!
って直さなきゃね・・・。うん、そのうち・・・。


3.5 ダメダメVST

プログラムを書いたら動かしてみるのDA!!
で、適当なホストから呼び出して見る事になるのだが...

WIn用で開発しているのならCubaseで試すというのは必要だろう。
VSTの本家だしな。

うちでも試す時はいつもCubaseだ。本当はチェック用に起動が速い
軽いホストを準備しておくともっと効率良いとは思うが、怠惰なので
やってない。

まあ、そう簡単に一発で動くわけはないので、ずぶずぶとデバッグの
深みにはまって行く事になるのだが...

ここで注意事項があるのDA!!
これはホストによるかも知れん(良くしらん)が、Cubaseでは、
起動時にVSTフォルダをスキャンして、「ああ、このVSTiはダメダメだ!」
と判断されると、ダメダメマークが付けられてしまい、次の起動時から
は完全に無視されるのDA!!

こうなったら手動で直さないといけないぞ!!
「デバイス」-「プラグイン情報」で多分リストの一番下の方に捨て去られている
から、更新してさらにチェックを入れるのを忘れずにな!
でないといつまでたってもダメダメ状態から抜け出せないのだ。

で、何をやったらダメダメ状態になるのかとゆうと、実は良くわかってないの
だが、少なくとも例外吐いて落ちるような事をすると駄目のようだ。
Cubaseは例外をトラップして黙ってダメダメマークしてしまうのだ。気が付かないと
いくら直してもリストに出てこないというダメダメ状態から抜け出せないぞ!

間違いない!

ついでにな。ホストはそれぞれ挙動が違うから、あるホストで動いても他ので
動かないという事はあるぞ。この間、Cubaseでは動いているがOrion / FLStudio
で動かないという報告があったのがあった。
これは初期化の失敗で、起動時に超巨大パルスを一発出してしまっていたの
だ。Cubaseはへっちゃらだったが他のは駄目だったぞ!!

気をつけろ!




g200kg