オーディオプラグインの作成、パート2

シリーズのすべての投稿:
パート1.紹介とセットアップ
パート2.コードの学習
パート3. VSTおよびAU
パート4.デジタル歪み
パート5.プリセットとGUI
パート6.信号合成
パート7. MIDIメッセージの受信
パート8.仮想キーボード
パート9.封筒
パート10. GUIの改善
パート11.フィルター
パート12.低周波発振器
パート13.再設計
パート14.ポリフォニー1
パート15.ポリフォニー2
パート16.アンチエイリアス



テストプロジェクトを詳しく見てみましょう。 最も重要なファイルはresource.hMyFirstPlugin.hおよびMyFirstPlugin.cppです。 現時点では、プラグインはシンプルなボリュームコントロールです。


学習コード



定数、フラグ、画像ソース



ナビゲーターでresource.hを開きます。 このファイルには、プラグインの名前、バージョン、一意のID、GUIの画像ソースへのリンクなどの定数が含まれています。 行23〜26では、一意のIDを指定できます。

// 4 chars, single quotes. At least one capital letter #define PLUG_UNIQUE_ID 'Ipef' // make sure this is not the same as BUNDLE_MFR #define PLUG_MFR_ID 'Acme' 


IDは、プラグインの一般的なカタログ化にとって重要です。 ここで登録できます 。 56行目以降は、プラグインの起動時に表示されるボリュームノブのIDとイメージへのパスをさらに決定します。

 // Unique IDs for each image resource. #define KNOB_ID 101 // Image resource locations for this plug. #define KNOB_FN "resources/img/knob.png" 


ナビゲータで検索し、 リソース→img→knob.pngを開きます。 これは、サイズが48 x 48ピクセルの60の異なるペン位置を持つスプライトです。 プラグインを起動してノブを回しても、ハンドルの画像は回転しません。 プログラムは、このスプライトの対応する部分のみを表示します。
なぜ回転しないのですか? ペンにいくつかのノッチがあり、影を落としていると想像してください。 次に、回転中に影も回転します。 あなたが知っているように、これは実際には起こりません。

以下のresource.hで、プラグインウィンドウのサイズを設定できます。

 #define GUI_WIDTH 300 #define GUI_HEIGHT 300 


値をいじってプラグインを実行します。

プラグインクラスインターフェイス



MyFirstPlugin.hを開きます 。 プラグインクラスのインターフェイスが含まれています。 public部分には、コンストラクタ、デストラクタ、およびクラスの3つのメンバー関数が含まれます。



private部分には、現在のボリューム値を格納するdouble変数のみがあります。

実装



興味深い部分に進みます! MyFirstPlugin.cppを開きます 。 すぐに、 enumタイプの興味深いレシーバーが表示されます。

 enum EParams { kGain = 0, kNumParams }; 


kGain = 0設定し、その後にkNumParamsを置くと、 kNumParamsはプラグインパラメーターの数になります(この場合は1)。
次のenumは、 resource.hで説明されている定数を使用し、プラグインウィンドウでハンドル座標を設定します。

 enum ELayout { kWidth = GUI_WIDTH, kHeight = GUI_HEIGHT, kGainX = 100, kGainY = 100, kKnobFrames = 60 }; 


また、 knob.pngのフレーム数を60に設定します。
次に、コンストラクターの実装が開始されます。 プラグインの属性が設定されます:

 //arguments are: name, defaultVal, minVal, maxVal, step, label GetParam(kGain)->InitDouble("Gain", 50., 0., 100.0, 0.01, "%"); 


これまでのGUIでは、値もパーセント記号も表示されませんが、値は0から100まで変化できます。 デフォルト値は50です。 値のグラデーションが円上で均一ではないことに気付くかもしれません。 これはSetShape(2.)です。 これをSetShape(1.)に置き換えると、値の分布は線形になります。 非線形動作を定義するのはSetShapeです。
次に、デザイナーは目的のサイズのグラフィックコンテキストを作成し、背景の赤色を設定します。

 IGraphics* pGraphics = MakeGraphics(this, kWidth, kHeight); pGraphics->AttachPanelBackground(&COLOR_RED); 


その後、 knob.pngがロードされ、画像を含む新しいIKnobMultiControlが作成され、GUIにアタッチされます。 IKnobMultiControlは、インターフェイスハンドルのクラスです。
スプライト内のフレーム数を示すためにkKnobFramesパラメーターがどのように渡されるかに注意してください。

 IBitmap knob = pGraphics->LoadIBitmap(KNOB_ID, KNOB_FN, kKnobFrames); pGraphics->AttachControl(new IKnobMultiControl(this, kGainX, kGainY, kGain, &knob)); 


最後に、デザイナーはグラフィックスコンテキストをバインドし、プラグインのデフォルトプリセットを作成します。

 MakeDefaultPreset((char *) "-", kNumPrograms); 


OnParamChange見てOnParamChange (ファイルの最後)。 IMutexLockは、後で説明する概念であるストリーミングセキュリティを提供します。 それ以外は、変更するパラメーターに応じたオプションのセットです。

 case kGain: mGain = GetParam(kGain)->Value() / 100.; break; 


覚えているように、 kGainは0から100に変化します。したがって、値を100で除算した後、0から1の値をmGainクラスのメンバーにmGainます。

そこで、GUIを作成し、 mGainなどのパラメーターmGainバインドするプロセスを少し見てみました。 プラグインが着信オーディオを処理する方法を見てみましょう。 この場合、オーディオストリームはdoubleデータ型で表されるサンプルのシーケンスであり、各サンプルには特定の時点での信号振幅が含まれています。
ProcessDoubleReplacing関数に渡される最初のパラメーターはdouble** inputsです。 double*を使用して、 double*シーケンスを渡すことができます。 ただし、プラグインは2つのチャネル(ステレオ)またはそれ以上を処理するため、サンプルのシーケンスをいくつか必要とし、これをdouble**と通信します。 関数の最初の2行はこれを示しています。

 double* in1 = inputs[0]; double* in2 = inputs[1]; 


in1はサンプルの最初のシーケンス(左チャネル)を示し、 in2は右チャネルのサンプルを示します。 出力バッファーに対して同様のアクションを実行した後、入力バッファーと出力バッファーの要素を反復処理できます。

 for (int s = 0; s < nFrames; ++s, ++in1, ++in2, ++out1, ++out2) { *out1 = *in1 * mGain; *out2 = *in2 * mGain; } 


サンプルごとに、入力値を取得し、 mGainを乗算して出力バッファーに書き込みます。 nFramesは、チャネルごとに使用可能なサンプル数を示しているため、バッファの長さがわかります。
プラグインをスタンドアロンアプリケーションとして実行すると、コンピューターにマイクが内蔵されている場合、スピーカーから自分の声が聞こえることに気づいたかもしれません。 これは、アプリケーションがデフォルトでこのマイクを入力ソースとして使用するためです。 これ(および他の何か)を変更するには、 設定に移動します





Reset機能でブレークポイントを設定します。 右側のサンプリングレートを変更し、変更を適用します。 デバッガーは、 Reset機能でコードの実行を中断します。 lldb機能する右下で、 print GetSampleRate()と入力しprint GetSampleRate()



デバッガから任意の関数を呼び出して、正しい値を確認することもできます。 表示されたら左上の[ 停止]をクリックして続行することにします。
次に、コードからプラグインを作成し、ホストにアップロードします。 これは次の投稿のトピックになります。
それまでの間、

追加の読書



いくつかのギャップを埋めるために、本発明のオリ・ラーキン氏によるこれらのスライドを読むことを強くお勧めします。 WDL-OLに関する重要な説明の一部が含まれています。

元の記事:
martin-finke.de/blog/articles/audio-plugins-003-examining-the-code

Source: https://habr.com/ru/post/J225019/


All Articles