パラメーター情報のフィードバック
MIDIノートオン・オフに合わせてパラメーターを変更したり、音圧に応じて値が変わるVUメーターなど、音声処理クラスからパラメータ操作クラスに値をフィードバックさせる方法を説明いたします。
なお、パラメーターの作成などについては下記をご参照ください。
パラメーター実装方法 | パラメータ自体を実装する方法 |
パラメーター実装方法2 | 0.5~30.0の範囲や文字列リスト等のパラメーターを実装する方法。 |
パラメーター実装方法3 | 「フィルタのカットオフ周波数」等の線形でないパラメーターを実装する方法を記載 |
まずはパラメーター操作クラスのinitialize関数にパラメーターを追加します。(「パラメーター自体を実装する方法」と同じです。)
【controller.h】
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
// クラスを初期化する関数(必須) tresult PLUGIN_API MyVSTController::initialize(FUnknown* context) { // まず継承元クラスの初期化を実施 tresult result = EditController::initialize(context); if (result == kResultTrue) { // パラメーターを追加 ParamID id = 100; parameters.addParameter(STR16("param1"), STR16("..."), 0, 1, ParameterInfo::kCanAutomate, id); // 今回は何もしない } // 初期化が成功すればkResultTrueを返す。 result = kResultTrue; return result; } |
次に音声処理クラスのprocess関数に値をフィードバックする処理を追加します。(ここのprocess関数は「パラメーター自体を実装する方法」をベースにしています。)
パラメーターのフィードバックにはprocess関数の引数 dataのoutputParameterChangesを使用し下記(75~97行目)のように実装します。
【processor.cpp 追加分】
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
// =================================================================================== // 音声信号を処理する関数 // =================================================================================== tresult PLUGIN_API MyVSTProcessor::process(ProcessData& data) { // パラメーター変更の処理 // 与えられたパラメーターがあるとき、dataのinputParameterChangesに // IParameterChangesクラスへのポインタのアドレスが入る if (data.inputParameterChanges != NULL) { ~~ 中略 ~~ } // 入力・出力バッファのポインタをわかりやすい変数に格納 // inputs[]、outputs[]はAudioBusの数だけある(addAudioInput()、addAudioOutput()で追加した分だけ) // 今回はAudioBusは1つだけなので 0 のみとなる // channelBuffers32は32bit浮動小数点型のバッファで音声信号のチャンネル数分ある // モノラル(kMono)なら 0 のみで、ステレオ(kStereo)なら 0(Left) と 1(Right) となる Sample32* inL = data.inputs[0].channelBuffers32[0]; Sample32* inR = data.inputs[0].channelBuffers32[1]; Sample32* outL = data.outputs[0].channelBuffers32[0]; Sample32* outR = data.outputs[0].channelBuffers32[1]; // numSamplesで示されるサンプル分、音声を処理する for (int32 i = 0; i < data.numSamples; i++) { ~~ 中略 ~~ } // パラメーターのフィードバックの処理 // 音声処理中に変更されたパラメーターがある時、dataのoutputParameterChangesに // 変更を設定することで、パラメーター操作クラスに値をフィードバックできる // フィードバック用のIParameterChangesクラスのポインタを取得 IParameterChanges* outParamChanges = data.outputParameterChanges; if (outParamChanges) // 正常にポインタが取得出来たか確認 { // フィードバックするパラメーターを追加するとともにパラメーター値変更用のキューを取得 // (処理するサンプル内に複数回パラメーター変更情報がある可能性があるため、 // キューという形になっている。) int32 index = 0; // 何番目のパラメーターかを設定(0から順に増やす) ParamID id = 100; // フィードバックするパラメータのID IParamValueQueue* paramQueue = outParamChanges->addParameterData(id, index); if (paramQueue) { // フィードバックする値を設定する int32 queueIndex = 0; paramQueue->addPoint(0 , feedbackValue, queueIndex); //feedbackValueはフィードバックする値とする } } // 問題なければkResultTrueを返す(おそらく必ずkResultTrueを返す) return kResultTrue; } |
以上で音声処理クラスからパラメーター操作クラスに値をフィードバックさせることができます。
フィードバックさせるパラメーターが複数ある場合は、下記のように複数回 設定します。
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
tresult PLUGIN_API MyVSTProcessor::process(ProcessData& data) { ~~ 中略 ~~ // パラメーターのフィードバックの処理 // 音声処理中に変更されたパラメーターがある時、dataのoutputParameterChangesに // 変更を設定することで、パラメーター操作クラスに値をフィードバックできる // フィードバック用のIParameterChangesクラスのポインタを取得 IParameterChanges* outParamChanges = data.outputParameterChanges; if (outParamChanges) // 正常にポインタが取得出来たか確認 { // フィードバックするパラメーターを追加するとともにパラメーター値変更用のキューを取得 // 1つ目のパラメーターのフィードバック int32 index = 0; // 何番目のパラメーターかを設定(0から順に増やす) ParamID id = 100; // フィードバックするパラメータのID IParamValueQueue* paramQueue = outParamChanges->addParameterData(id, index); if (paramQueue) { // フィードバックする値を設定する int32 queueIndex = 0; paramQueue->addPoint(0 , feedbackValue, queueIndex); //feedbackValueはフィードバックする値とする } // 2つ目のパラメーターのフィードバック index = 1; id = 101; IParamValueQueue* paramQueue = outParamChanges->addParameterData(id, index); if (paramQueue) { // フィードバックする値を設定する int32 queueIndex = 0; paramQueue->addPoint(0 , feedbackValue2, queueIndex); //feedbackValue2はフィードバックする値とする } // 3つ目のパラメーターのフィードバック // 以下同様 ~~ 中略 ~~ } // 問題なければkResultTrueを返す(おそらく必ずkResultTrueを返す) return kResultTrue; } |
パラメーター操作クラスに値をフィードバックさせた後、UIなどを更新するには別途対応が必要となります。
対応方法の一つとしてUIを定期的に更新する方法があります。
上記以外にもVST3.6についての情報があります。下記をご参照ください。
また、質問やご指摘はコメント欄や掲示板、Twitterでいただけばとおもいます。
■掲示板
■Twitterアカウント:@vstcpp URL:https://twitter.com/vstcpp
ご無沙汰しております。
ようやく私もVST3の開発を始めることができまして、VST2.4で作った自作プラグインの移植を遅々と進めております。
VST2.4ではできていた変数の渡し方が封じられてしまったのが痛いです。
1つ1つ0.0~1.0に変換しながら渡してまた戻しています。(2.4も本来こんな感じでやるべきだったのでしょうけれど)
猫十さんご無沙汰しております。
確かにVST2.4よりそのあたりは面倒になりましたね…
バイナリデータなど(波形データなど)の受け渡しであればsendMessage()関数とnotify()関数が使えるのですが…。
うつぼかずらさん
おかげさまでVST3開発にも慣れてきました。
カスタムViewとか処理系なんかは結構2.4のがそのまま動いたりして感動してます。
さてsendmessageが便利でデバッグのためprocessからGUIへ大量のバイナリデータを高速で送っていたら、使用メモリが増加していくということがありました。
(process側変数の中身や動きを見るために片っ端からGUIにリアルタイム表示させる的なアレです。)
動作上は遅延などなくちゃんと動作しているのですが、VisualStudioの診断ツールのプロセスメモリがぐんぐん増えていくという状態でした。
もしかしたらsendmessageでのバイナリ送信は注意が必要なのかもしれません。
process側の変数をリアルタイムでグリグリ描画しまくってそうな製品プラグイン(Avengerとかfabfilterとか)はそのへんどうしてるのかとても疑問です…。
おそらくですが、allocateMessage()でIMessageクラスの確保をして、
sendMessage()でデータ(メッセージ)を送信した後、
IMessageクラスのrelease()を呼んでいないためにメモリリークしているのではないかと思います。
うつぼかずらさん
ご指摘の通り、sendMessage()したあとにrelease()を呼んだところメモリリークしなくなりました(汗)
sendMessage()まわりはsteinbergのagainとnote expression synthのコードを見ながらマネして書いたのですが、何か勘違いor解釈違いをしてしまっていたようです…。
本当にありがとうございました。