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

シリーズのすべての投稿:

パート1.紹介とセットアップ

パート2.コードの学習

パート3. VSTおよびAU

パート4.デジタル歪み

パート5.プリセットとGUI

パート6.信号合成

パート7. MIDIメッセージの受信

パート8.仮想キーボード

パート9.封筒

パート10. GUIの改善

パート11.フィルター

パート12.低周波発振器

パート13.再設計

パート14.ポリフォニー1

パート15.ポリフォニー2

パート16.アンチエイリアス






REAPERで仮想キーボードを設定することはそれほど明白ではありません。さらに、ユーザーホストにはそのような機能がまったくない場合があります。 GUIに小さなオンスクリーンキーボードを追加しましょう。





GUI要素





WDL-OLでは、GUI要素はcontrolsと呼ばれます 。 このライブラリには、このタスクに必要なすべての機能を備えたIkeyboardControl



クラスがあります。

1つの背景画像と2つの追加のスプライトを使用します。1つは黒のキーを押し、もう1つは白のキーを押します。 論理的です。すべての黒のキーは同じ形状で、白のキーは異なります。 キーを押すと、これらのスプライトがキーボードの背景画像の上に表示され、常に表示されます。

すばらしいカスタムキーを作成する場合は、 このガイドをご覧ください 。 さて、ライブラリに付属するものは次のようになります。















これらのファイルをダウンロードして、プロジェクトフォルダー/ resources / img /にドロップします。 Xcodeを使用する場合は、それらをウィンドウにドラッグしてプロジェクトに追加します。 いつものように、グラフィックの操作は、ファイル名をresource.hに追加することから始まります。 同時に、そこにいる間に、 knob.pngbackground.pngへのリンクを削除し、プロジェクトからファイル自体を削除します。



 // Unique IDs for each image resource. #define BG_ID 101 #define WHITE_KEY_ID 102 #define BLACK_KEY_ID 103 // Image resource locations for this plug. #define BG_FN "resources/img/bg.png" #define WHITE_KEY_FN "resources/img/whitekey.png" #define BLACK_KEY_FN "resources/img/blackkey.png"
      
      







より大きなウィンドウサイズが必要:



 // GUI default dimensions #define GUI_WIDTH 434 #define GUI_HEIGHT 66
      
      







Windowsでは、 .pngファイルをアセンブリに含めるには、 Synthesis.rcヘッダーも編集する必要があります。



 #include "resource.h" BG_ID PNG BG_FN WHITE_KEY_ID PNG WHITE_KEY_FN BLACK_KEY_ID PNG BLACK_KEY_FN
      
      







次に、 Synthesis.hファイルのpublic



セクションに、 Synthesisクラスのメンバーをいくつか追加します。



 public: // ... // Needed for the GUI keyboard: // Should return non-zero if one or more keys are playing. inline int GetNumKeys() const { return mMIDIReceiver.getNumKeys(); }; // Should return true if the specified key is playing. inline bool GetKeyStatus(int key) const { return mMIDIReceiver.getKeyStatus(key); }; static const int virtualKeyboardMinimumNoteNumber = 48; int lastVirtualKeyboardNoteNumber;
      
      







Synthesis.cppの初期化リストに、lastVirtualKeyboardNoteNumberを追加します。



 Synthesis::Synthesis(IPlugInstanceInfo instanceInfo) : IPLUG_CTOR(kNumParams, kNumPrograms, instanceInfo), lastVirtualKeyboardNoteNumber(virtualKeyboardMinimumNoteNumber - 1) { // ... }
      
      







演奏されたノートのソースがホストの場合、プラグインキーボードで押された状態で表示されるはずです。 キーボードはgetNumKeys



getKeyStatus



を呼び出して、どのキーが押されたかを調べます。 前回、これらの機能をMIDIReceiver



実装MIDIReceiver



であるため、 MIDIReceiver







プライベートセクションでは、次の行も追加する必要があります。



 IControl* mVirtualKeyboard; void processVirtualKeyboard();
      
      







IControl



クラスは、すべてのGUIコントロールの基本クラスです。 IkeyboardControl



IkeyboardControl



オブジェクトを宣言することはできません。これは、 .hファイルには「不明」 IkeyboardControl



です。 したがって、ポインターを使用する必要があります。 IKeyboardControl.hには 、「プラグインのクラスを宣言した後にこのヘッダーを追加(#include)する必要があるため、プラグインのメインの.cppファイルに追加するのが最善です」というコメントがあります。

状況を明確にするために、 Synthesis.cppを見てみましょう。 #include resource.h



前に#include "IKeyboardControl.h"



を追加します。

次に、コンストラクタを変更します。



 Synthesis::Synthesis(IPlugInstanceInfo instanceInfo) : IPLUG_CTOR(kNumParams, kNumPrograms, instanceInfo), lastVirtualKeyboardNoteNumber(virtualKeyboardMinimumNoteNumber - 1) { TRACE; IGraphics* pGraphics = MakeGraphics(this, kWidth, kHeight); pGraphics->AttachBackground(BG_ID, BG_FN); IBitmap whiteKeyImage = pGraphics->LoadIBitmap(WHITE_KEY_ID, WHITE_KEY_FN, 6); IBitmap blackKeyImage = pGraphics->LoadIBitmap(BLACK_KEY_ID, BLACK_KEY_FN); // C# D# F# G# A# int keyCoordinates[12] = { 0, 7, 12, 20, 24, 36, 43, 48, 56, 60, 69, 72 }; mVirtualKeyboard = new IKeyboardControl(this, kKeybX, kKeybY, virtualKeyboardMinimumNoteNumber, /* octaves: */ 5, &whiteKeyImage, &blackKeyImage, keyCoordinates); pGraphics->AttachControl(mVirtualKeyboard); AttachGraphics(pGraphics); CreatePresets(); }
      
      







背景画像を添付すると興味深いことが始まります。 最初に、押された黒と白のキーをIbitmap



オブジェクトの形式でIbitmap



ます。 LoadIBitmap



6



)関数の3番目の引数は、 whitekeys.pngに6つのフレームが含まれていることをグラフィックスシステムに伝えます。



デフォルトでは、pRegularKeysには6つの画像(C / F、D、E / B、G、A、上部C)が含まれている必要がありますが、pSharpKeyには1つの画像(すべてのフラット/シャープ)しか含まれていません。
-IKeyboardControl.h



keyCoordinates



配列は、システムに左境界線を基準とした各キーのオフセットを伝えます。 このアクションは1オクターブのみで実行する必要があり、 IKeyboardControl



他のすべてのオクターブのオフセットを計算します。

大まかに言えば、次の行では、新しいオブジェクトnew IKeyboardControl



を初期化し、名前mVirtualKeyboard



を割り当てます。 多くの情報を送信します。



興味深いことに、仮想キーボードオブジェクトはbg.pngファイルの存在さえも知りません。 彼はただ彼を必要としません、すべてがそのように機能します。 キーボード画像は背景画像の一部になることができ、 IkeyboardControl



コンストラクターに渡すためだけにこのピースをカットする必要があるため、これはプラスです。



C ++でプログラミングの経験がある場合は、条件反射が発生するはずです。コンストラクターにはnew



が含まれているため、 delete mVirtualKeyboard



必要があります。 ただし、これを行ってからトラックからプラグインを削除すると、 ランタイム例外がポップアップします。 理由は、呼び出しが行われるときです



 pGraphics->AttachControl(mVirtualKeyboard);
      
      





メモリ管理をグラフィックシステムに移行し、このメモリ領域の管理は私たちの責任ではなくなりました。 delete



を使用して、既に空きメモリ領域の固定を解除します。



次に、 CreatePresets



関数の本体を削除します。



 void Synthesis::CreatePresets() { }
      
      







そして、kKeybXとkKeybYをELayoutに追加します。



 enum ELayout { kWidth = GUI_WIDTH, kHeight = GUI_HEIGHT, kKeybX = 1, kKeybY = 0 };
      
      







パフォーマンス上の理由から、 IKeyboardControl



はそれ自体を再描画しません。 これはグラフィックプログラミングの一般的な方法です。GUI要素を「ダーティ」としてマークします。つまり、そのイメージは次の再描画サイクルでのみ更新されます。 IKeyboardControl.h 、特にOnMouseDownOnMouseUp



を見ると、 mKey



mKey



割り当てられており、( Draw



ではなく) SetDirty



関数がSetDirty



ていることがSetDirty



ます。 SetDirty



IControl



クラスのメンバー関数です(その実装はそれぞれIControl.cppにあります)。 このコントロールのmDirty



パラメーターmDirty



true



に設定しtrue



。 再描画サイクルごとに、グラフィックシステムはmDirty



true



であるすべてのGUI要素を再描画しtrue



。 グラフィックシステムのこの側面を理解することが重要なので、このような詳細を掘り下げました。



外部MIDIメッセージへの応答





これまでのところ、キーボードをクリックすると汚れています。 mMIDIReceiver



からmMIDIReceiver



データを受信しますが、外部MIDIデータも受信する必要があります。 mVirtualKeyboard



mMIDIReceiver



はお互いについて何も知らないので、 Synthesis.cppで ProcessMidiMsg



を編集しましょう。



 void Synthesis::ProcessMidiMsg(IMidiMsg* pMsg) { mMIDIReceiver.onMessageReceived(pMsg); mVirtualKeyboard->SetDirty(); }
      
      







最初に、 mMIDIReceiver



は受信したMIDIデータに従ってmLast...



メンバーを更新します。 その後、 mVirtualKeyboard



はダーティとしてマークされます。 次に、次の再描画サイクルで、 Draw



mVirtualKeyboard



に対してmVirtualKeyboard



れ、次にGetNumKeys



およびGetKeyStatus



を呼び出します。 最初は複雑に思えるかもしれませんが、実際には、冗長性と不要な動きを避ける透明で明確に構造化された設計です。

仮想キーボードは外部MIDIメッセージに応答し、押されたキーを正しく描画します。



キーボード応答





ホストに組み込まれた仮想キーボードの押下にキーボードを強制的に応答させ、MIDIメッセージを生成し、受信者mMIDIReceiver



送信します。

forループの直前にこの呼び出しをProcessDoubleReplacing



追加します。



 processVirtualKeyboard();
      
      







そして適切な関数を書きます:



 void Synthesis::processVirtualKeyboard() { IKeyboardControl* virtualKeyboard = (IKeyboardControl*) mVirtualKeyboard; int virtualKeyboardNoteNumber = virtualKeyboard->GetKey() + virtualKeyboardMinimumNoteNumber; if(lastVirtualKeyboardNoteNumber >= virtualKeyboardMinimumNoteNumber && virtualKeyboardNoteNumber != lastVirtualKeyboardNoteNumber) { // The note number has changed from a valid key to something else (valid key or nothing). Release the valid key: IMidiMsg midiMessage; midiMessage.MakeNoteOffMsg(lastVirtualKeyboardNoteNumber, 0); mMIDIReceiver.onMessageReceived(&midiMessage); } if (virtualKeyboardNoteNumber >= virtualKeyboardMinimumNoteNumber && virtualKeyboardNoteNumber != lastVirtualKeyboardNoteNumber) { // A valid key is pressed that wasn't pressed the previous call. Send a "note on" message to the MIDI receiver: IMidiMsg midiMessage; midiMessage.MakeNoteOnMsg(virtualKeyboardNoteNumber, virtualKeyboard->GetVelocity(), 0); mMIDIReceiver.onMessageReceived(&midiMessage); } lastVirtualKeyboardNoteNumber = virtualKeyboardNoteNumber; }
      
      







GetKey



は、押されたキーに対応するノート番号を提供します。 IKeyboardControl



はマルチタッチをサポートしていないため、一度に1つのキーしか押すことができません。 最初のif



は、もう押されていないキー(ある場合)をリリースします。 この関数はmBlockSize



サンプルごとにmBlockSize



れるため、2番目のifは、このクリックに対してメッセージのメモが 1つだけ生成されるようにします( mBlockSize



サンプルごとではありません)。 関数が呼び出されるたびにこれらの「繰り返しクリック」を避けるために、 lastVirtualKeyboardNoteNumber



の値を覚えています。



行こう!





シンセを再び起動する準備ができました! すべてが正しく行われていれば、彼のキーボードで演奏できます。 そして、仮想ホストキーボードまたは他の接続されたMIDIソースの使用がプラグインキーボードに表示されます(順番に、最後に押されたキーが表示されます)。 確かに、音はこの最後の1つのキーにのみ対応します。 ポリフォニーについては少し後で説明します。

クラシックシンセサイザーサウンドで、お友達に自慢したり、お気に入りのベートーベンを演奏したりできます。 今だけ音は一種の「木」であり、キーを押して放すとクリック音が聞こえます。 これは、洞が生成される場合に特に顕著です。 そのため、封筒を追加する必要があります。 これは次の投稿で行います。



この段階のプロジェクトファイルは、ここからダウンロードできます



元の記事:

martin-finke.de/blog/articles/audio-plugins-010-virtual-keyboard



All Articles