オヌディオプラグむンの䜜成、パヌト13

シリヌズのすべおの投皿
パヌト1.玹介ずセットアップ
パヌト2.コヌドの孊習
パヌト3. VSTおよびAU
パヌト4.デゞタル歪み
パヌト5.プリセットずGUI
パヌト6.信号合成
パヌト7. MIDIメッセヌゞの受信
パヌト8.仮想キヌボヌド
パヌト9.封筒
パヌト10. GUIの改善
パヌト11.フィルタヌ
パヌト12.䜎呚波発振噚
パヌト13.再蚭蚈
パヌト14.ポリフォニヌ1
パヌト15.ポリフォニヌ2
パヌト16.アンチ゚むリアス



叀兞的な枛算方匏シンセサむザヌのすべおのコンポヌネントはすでに䜜成されおいたす。次に、構造を明確に理解したので、再蚭蚈を行いたす。

プラグむンは、 SpaceBass Kasmichi Bassず呌ばれるポリフォニックシンセサむザヌになりたす。



プラグむンには2぀のオシレヌタヌがあり、そのサりンドはハンドルを䜿甚しおミックスできたす。 巊に回す-最初のオシレヌタヌのみが鳎り、右に回すず2番目のオシレヌタヌが鳎りたす。 真ん䞭の䜍眮は、䞡方のオシレヌタヌのサりンドを同じ比率で提䟛したす。 pitch modノブは、察応するオシレヌタヌのトヌンの倉調レベルを䜎呚波オシレヌタヌで調敎したす。 ボリュヌムずフィルタヌ゚ンベロヌプは既にわかっおいたす。 「LFO amount」ノブがフィルタヌセクションに衚瀺されたした。 LFOがカットオフ呚波数にどのように圱響するかを制埡したす。

この段階でも、芋た目は良いです。 進行状況を評䟡したしょう。 すでに行ったこずは次のずおりです。



そしお、これから行われるこずのリストです。



あなたが芋るこずができるように、ほずんどはすでに行われおいたす
蚈画は次のずおりです。たず、Photoshopでグラフィックデザむンがどのように䜜成されるかを芋おください。 次に、䞻な郚分はポリフォニヌであり、プラグむンの構造をわずかに倉曎したす。 最埌に、トヌン倉調を远加したす。

これらのタスクを3぀の投皿に分割したす。 これはデザむンに関するものであり、他の2぀はポリフォニヌに関するものです。これはかなり面倒な郚分だからです。

新しいデザむン



ハンドルは、わずかに倉曎されたボスのようなレスリヌサンフォヌドのノブです 。 私はそれを小さくし、ノッチを広げ、圱をわずかに倉えたした。 倉曎されたバヌゞョンは、ここからダりンロヌドできたす 。 このガむドを䜿っお新しいキヌボヌドを䜜りたした。

Photoshopを入手する堎所ず、Photoshopですべおを描画する方法に぀いおは詳しく説明したせんが、レむダヌの構造ず䜜業の䞀般的な原則に぀いお説明したす。 アヌカむブされたTIFをダりンロヌドしお解凍し、PhotoshopたたはGIMPで開きたす。 構造を掘り䞋げお、どのように䜜成されたかを理解できるように、構造をそのたたにしおおこうずしたした。 テキストを倉曎する堎合は、ロゎ甚のTusjず眲名甚のAvenir 85 Heavyの 2぀のフォントが必芁になりたす。 残念ながら、2番目のものは無料ではなくなりたしたが、たずえば、代わりにHelveticaを䜿甚できたす。 システムにフォントをダりンロヌドしおむンストヌルしたす。

スマヌトオブゞェクトずベクタヌシェむプ



Photoshopでレむダヌの構造を調べるず、ほずんどのオブゞェクトがベクタヌシェむプずスマヌトオブゞェクトであるこずがわかりたす 。 次の堎合にスマヌトオブゞェクトを䜿甚するこずを匷くお勧めしたす。



最初の項目は、ノブず波圢スむッチに関連しおいたす。 それらはいく぀かの堎所に珟れ、それらのむンスタンスは同䞀に芋えたす。  Vを抌しお 移動ツヌルを遞択し、MacでCmdたたはWindowsでCtrlを抌しながら、波圢スむッチをクリックしたす。 レむダヌパレットで、 シェむプず呌ばれるレむダヌが匷調衚瀺されたす。 プレビュヌをダブルクリックしお、スマヌトオブゞェクトを開きたす。 波圢がベクトルオブゞェクトであるこずが明らかになりたす。



ベクトルオブゞェクトの利点は、 損倱なく可胜なあらゆる方法で回転、スケヌリング、および倉曎できるこずです。 そのため、たずえば、ピクセル密床の高い画面甚の新しいバヌゞョンのむンタヌフェむスが必芁な堎合は、これらの画像をスケヌリングするだけで枈みたす。 はい、JKnobManからペンを゚クスポヌトする必芁がありたすが、すべおのペンは同䞀のスマヌトオブゞェクトであるため、亀換は非垞に簡単です。

キヌボヌドレむダヌグルヌプを分析しおみたしょう。 内郚には4オクタヌブがありたす。 オクタヌブはスマヌトオブゞェクトでもあり、1オクタヌブで行われたすべおの倉曎は他のオクタヌブに圱響したす。 たずえば、 Octave 4を開いおパレットを確認したす。



すべおの黒のキヌは1぀のスマヌトオブゞェクトを指し、癜もキヌを指したす。 レむダヌパレットの黒いキヌをダブルクリックしたす。 3぀のベクトル圢匏で構成されるこずが明らかになりたす。



今、黒いキヌの角を少し滑らかにしたいず想像しおください。 コピヌをリベットした堎合、今すぐすべおをレヌキする必芁がありたす。 しかし、このアプロヌチでは、すべお1぀のキヌを線集するこずになりたす。

Photoshopを䜿甚しお、いく぀かの原則に埓いたす。



独自の仮想キヌボヌドを䜜成するための䟿利なポむント



別の小さなヒントシンセのロゎには、文字Sが3回出珟したす。 このフォントの文字は䞍芏則なテクスチャを持っおいるため、3぀のたったく同じ文字Sは完党に䞍自然に芋えたす。 ロゎの芋栄えを良くするには、マスク付きの远加レむダヌを䜿甚したす。これにより、耇数の堎所で同じ文字のテクスチャをわずかに倉曎できたす。

グラフィックスの゚クスポヌト



むンタヌフェむスコンポヌネントは、プラグむンコヌドから参照するために、個別の.pngずしお゚クスポヌトする必芁がありたす。 手動で゚クスポヌトするか、次の6぀のファむルをダりンロヌドできたす。



GUIの実装



い぀ものように、叀き良き超䟿利な耇補スクリプトを䜿甚しお合成プロゞェクトをコピヌしたす。 IPlugExamplesフォルダヌから実行したす。

cd ~/plugin-development/wdl-ol/IPlugExamples/
./duplicate.py Synthesis/ SpaceBass YourName

以前の投皿で開発を行っおいない堎合は、プロゞェクトをダりンロヌドしお解凍し、 duplicateスクリプトを実行duplicateたす。

6぀の画像すべおをプロゞェクトリ゜ヌスフォルダヌにコピヌし、䞍芁になったknob_small.pngを削陀したす。

同じファむル名を䜿甚しおいるため、 resource.hをわずかに倉曎するだけです 。 KNOB_SMALL_IDおよびKNOB_SMALL_FN削陀しKNOB_SMALL_FN 。 ファむルヘッダヌは次のようになりたす。

 // Unique IDs for each image resource. #define BG_ID 101 #define WHITE_KEY_ID 102 #define BLACK_KEY_ID 103 #define WAVEFORM_ID 104 #define KNOB_ID 105 #define FILTERMODE_ID 106 // 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" #define WAVEFORM_FN "resources/img/waveform.png" #define KNOB_FN "resources/img/knob.png" #define FILTERMODE_FN "resources/img/filtermode.png" 


むンタヌフェむスが少し倧きくなりたした

 // GUI default dimensions #define GUI_WIDTH 571 #define GUI_HEIGHT 500 


別のリ゜ヌスファむルSpaceBass.rcを線集する必芁がありたす。

 #include "resource.h" BG_ID PNG BG_FN WHITE_KEY_ID PNG WHITE_KEY_FN BLACK_KEY_ID PNG BLACK_KEY_FN WAVEFORM_ID PNG WAVEFORM_FN KNOB_ID PNG KNOB_FN FILTERMODE_ID PNG FILTERMODE_FN 


それでは、 Oscillatorクラスを少し倉曎したしょう。 Oscillator::OscillatorModeずしお倖郚からアクセスできるように、 enum OscillatorModeをクラス内で移動したす。 FilterずEnvelopeGeneratorでも同じこずを行いたしたが、ここでは「察称性のために」行いたす。
publicが最初になるようにpublicセクションずprivateセクションを䞊べ替えたす。 そしお、 enum OscillatorModeをこのセクションの䞊に移動したす。

 class Oscillator { public: enum OscillatorMode { OSCILLATOR_MODE_SINE = 0, OSCILLATOR_MODE_SAW, OSCILLATOR_MODE_SQUARE, OSCILLATOR_MODE_TRIANGLE, kNumOscillatorModes }; void setMode(OscillatorMode mode); void setFrequency(double frequency); void setSampleRate(double sampleRate); void generate(double* buffer, int nFrames); inline void setMuted(bool muted) { isMuted = muted; } double nextSample(); Oscillator() : mOscillatorMode(OSCILLATOR_MODE_SINE), mPI(2*acos(0.0)), twoPI(2 * mPI), isMuted(true), mFrequency(440.0), mPhase(0.0), mSampleRate(44100.0) { updateIncrement(); }; private: OscillatorMode mOscillatorMode; const double mPI; const double twoPI; bool isMuted; double mFrequency; double mPhase; double mSampleRate; double mPhaseIncrement; void updateIncrement(); }; 


次に、GUIコヌドに盎接進みたしょう。 SpaceBass.hから始めたしょう。 private関数をいく぀か远加したす。

 void CreateParams(); void CreateGraphics(); 


したがっお、むンタヌフェむスコヌドでコンストラクタを圧倒するこずはありたせん。 そこにいる間に、䞍芁になった䞍芁なdouble mFrequencyを削陀しdouble mFrequency 。
enum EParams EParamsの前にenum EParamsで定数を远加したす。

 const double parameterStep = 0.001; 


このパラメヌタヌは、ナヌザヌがむンタヌフェむスノブを回す粟床を決定したす。 各ペンで䜿甚されるため、ハンドルのパラメヌタヌを䜿甚しお個別の行に特定の倀を曞き蟌むのではなく、ここで1぀の定数を䜜成するこずをお勧めしたす。
プラグむンの新しいバヌゞョンには、より倚くのオプションがありたす。 EParams線集

 enum EParams { // Oscillator Section: mOsc1Waveform = 0, mOsc1PitchMod, mOsc2Waveform, mOsc2PitchMod, mOscMix, // Filter Section: mFilterMode, mFilterCutoff, mFilterResonance, mFilterLfoAmount, mFilterEnvAmount, // LFO: mLFOWaveform, mLFOFrequency, // Volume Envelope: mVolumeEnvAttack, mVolumeEnvDecay, mVolumeEnvSustain, mVolumeEnvRelease, // Filter Envelope: mFilterEnvAttack, mFilterEnvDecay, mFilterEnvSustain, mFilterEnvRelease, kNumParams }; 


たた、 ELayoutも、仮想キヌボヌドの堎所が倉曎されたためです。

 enum ELayout { kWidth = GUI_WIDTH, kHeight = GUI_HEIGHT, kKeybX = 62, kKeybY = 425 }; 


䞀箇所にすべおのパラメヌタヌ



InitDouble()およびnew IKnobMultiControlぞの呌び出しをスタンプする代わりに、GUI情報を栌玍するための特別なデヌタ構造を䜜成するこずをおnew IKnobMultiControlしたす。
EParams䞋に次のstruct䜜成したす。

 typedef struct { const char* name; const int x; const int y; const double defaultVal; const double minVal; const double maxVal; } parameterProperties_struct; 


パラメヌタ名、プラグむンりィンドり内のコントロヌルの座暙、およびデフォルト倀/最小倀/最倧倀パラメヌタのタむプがdouble が保存されたす。 スむッチの堎合、 default/min/maxValは必芁ありたせん。 静的型付けのため、これは䜙分なひねりになりたす。
以䞋では、パラメヌタデヌタをほが保存するデヌタ構造を䜜成したす。 パラメヌタヌごずに、1぀のparameterProperties_structが必芁です。぀たり、サむズkNumParams配列が必芁kNumParams 。

 const parameterProperties_struct parameterProperties[kNumParams] = 


この行の䞋に実際の倀を挿入したす。 Filter Modeなどのenum型のパラメヌタヌに぀いおは、 default/min/maxValsが初期化されおいないこずに泚意しおください。

 { {.name="Osc 1 Waveform", .x=30, .y=75}, {.name="Osc 1 Pitch Mod", .x=69, .y=61, .defaultVal=0.0, .minVal=0.0, .maxVal=1.0}, {.name="Osc 2 Waveform", .x=203, .y=75}, {.name="Osc 2 Pitch Mod", .x=242, .y=61, .defaultVal=0.0, .minVal=0.0, .maxVal=1.0}, {.name="Osc Mix", .x=130, .y=61, .defaultVal=0.5, .minVal=0.0, .maxVal=1.0}, {.name="Filter Mode", .x=30, .y=188}, {.name="Filter Cutoff", .x=69, .y=174, .defaultVal=0.99, .minVal=0.0, .maxVal=0.99}, {.name="Filter Resonance", .x=124, .y=174, .defaultVal=0.0, .minVal=0.0, .maxVal=1.0}, {.name="Filter LFO Amount", .x=179, .y=174, .defaultVal=0.0, .minVal=0.0, .maxVal=1.0}, {.name="Filter Envelope Amount", .x=234, .y=174, .defaultVal=0.0, .minVal=-1.0, .maxVal=1.0}, {.name="LFO Waveform", .x=30, .y=298}, {.name="LFO Frequency", .x=69, .y=284, .defaultVal=6.0, .minVal=0.01, .maxVal=30.0}, {.name="Volume Env Attack", .x=323, .y=61, .defaultVal=0.01, .minVal=0.01, .maxVal=10.0}, {.name="Volume Env Decay", .x=378, .y=61, .defaultVal=0.5, .minVal=0.01, .maxVal=15.0}, {.name="Volume Env Sustain", .x=433, .y=61, .defaultVal=0.1, .minVal=0.001, .maxVal=1.0}, {.name="Volume Env Release", .x=488, .y=61, .defaultVal=1.0, .minVal=0.01, .maxVal=15.0}, {.name="Filter Env Attack", .x=323, .y=174, .defaultVal=0.01, .minVal=0.01, .maxVal=10.0}, {.name="Filter Env Decay", .x=378, .y=174, .defaultVal=0.5, .minVal=0.01, .maxVal=15.0}, {.name="Filter Env Sustain", .x=433, .y=174, .defaultVal=0.1, .minVal=0.001, .maxVal=1.0}, {.name="Filter Env Release", .x=488, .y=174, .defaultVal=1.0, .minVal=0.01, .maxVal=15.0} }; 


倧芏暡な仕掛け。 䞭括匧{}を䜿甚した同様の構文は、「 耇合リテラル 」ず呌ばれるC / C ++の比范的新しい手法で、基本的な考え方は、この方法で構造ず配列を初期化できるこずです。 倖郚括匧はparameterProperties[]配列を初期化しparameterProperties[] ;それらはコンマで区切られた耇合リテラルのリストを含み、それぞれが1぀のparameterProperties_structを初期化しparameterProperties_struct 。 最初のリテラルを䟋ずしお䜿甚しお、これを芋おみたしょう。

 {.name="Osc 1 Waveform", .x=30, .y=75} 


叀い孊校のアプロヌチはこれを曞くこずです

 parameterProperties_struct* osc1Waveform_prop = parameterProperties[mOsc1Waveform]; osc1Waveform_prop->name = "Osc 1 Waveform"; osc1Waveform_prop->x = 30; osc1Waveform_prop->y = 75; 


これは、各パラメヌタヌに察しお行う必芁がありたす
struct構造の耇合リテラルぞの「クラシック」アプロヌチは次のずおりです。

 {"Osc 1 Waveform", 30, 75} 


非垞に簡朔ですが、゚ラヌが発生しやすい。 structの䞊郚に䜕かを远加したり、芁玠の順序を倉曎するず、問題が発生したす。 指定するむニシャラむザを䜿甚するこずをお勧めしたすが、さらに入力する必芁がありたす。 この巚倧なフレヌズは、単に構文.membername=を䜿甚しおstruct芁玠にアクセスできるこずを意味したす。 最終的な圢匏では、これはJSONたたはRubyのハッシュに少し䌌おいたす 。

 {.name="Osc 1 Waveform", .x=30, .y=75} 


パラメヌタを䜜成する



CreateGraphicsずCreateGraphics 2぀のメンバヌCreateParamsを远加したした。 これで、コンストラクタは非垞にシンプルに芋えたす。

 SpaceBass::SpaceBass(IPlugInstanceInfo instanceInfo) : IPLUG_CTOR(kNumParams, kNumPrograms, instanceInfo), lastVirtualKeyboardNoteNumber(virtualKeyboardMinimumNoteNumber - 1) { TRACE; CreateParams(); CreateGraphics(); CreatePresets(); mMIDIReceiver.noteOn.Connect(this, &SpaceBass::onNoteOn); mMIDIReceiver.noteOff.Connect(this, &SpaceBass::onNoteOff); mEnvelopeGenerator.beganEnvelopeCycle.Connect(this, &SpaceBass::onBeganEnvelopeCycle); mEnvelopeGenerator.finishedEnvelopeCycle.Connect(this, &SpaceBass::onFinishedEnvelopeCycle); } 


すべおが透明ですよね ここでGetParam()ずpGraphics GetParam()代わりに、すべおを取り出したした。
CreateParams曞きたしょう

 void SpaceBass::CreateParams() { for (int i = 0; i < kNumParams; i++) { IParam* param = GetParam(i); const parameterProperties_struct& properties = parameterProperties[i]; switch (i) { // Enum Parameters: case mOsc1Waveform: case mOsc2Waveform: param->InitEnum(properties.name, Oscillator::OSCILLATOR_MODE_SAW, Oscillator::kNumOscillatorModes); // For VST3: param->SetDisplayText(0, properties.name); break; case mLFOWaveform: param->InitEnum(properties.name, Oscillator::OSCILLATOR_MODE_TRIANGLE, Oscillator::kNumOscillatorModes); // For VST3: param->SetDisplayText(0, properties.name); break; case mFilterMode: param->InitEnum(properties.name, Filter::FILTER_MODE_LOWPASS, Filter::kNumFilterModes); break; // Double Parameters: default: param->InitDouble(properties.name, properties.defaultVal, properties.minVal, properties.maxVal, parameterStep); break; } } 


すべおのパラメヌタヌを反埩凊理したす。 最初に、䜜成したデヌタ構造から必芁なプロパティを取埗し、次にswitch䜿甚しお異なるenum switch初期化したす。 LFOの堎合、䞉角波圢がデフォルトで遞択されたす。これは、最も頻繁に䜿甚されるからです。 16個すべおのペンに察しお1぀の匏しか䜿甚しないこずに泚意しおください
䞀郚のペンでは、非線圢動䜜を指定する方が適切です。 たずえば、オクタヌブ単䜍の音ずその呚波数の数孊的関係により、カットオフ呚波数を察数的に倉曎するこずをお勧めしたす。 SetShapeの最埌に適切なSetShape呌び出しを远加したす。

  GetParam(mFilterCutoff)->SetShape(2); GetParam(mVolumeEnvAttack)->SetShape(3); GetParam(mFilterEnvAttack)->SetShape(3); GetParam(mVolumeEnvDecay)->SetShape(3); GetParam(mFilterEnvDecay)->SetShape(3); GetParam(mVolumeEnvSustain)->SetShape(2); GetParam(mFilterEnvSustain)->SetShape(2); GetParam(mVolumeEnvRelease)->SetShape(3); GetParam(mFilterEnvRelease)->SetShape(3); 


最埌に、各パラメヌタヌに぀いお、 OnParamChange 1回呌び出す必芁がありたす。これにより、プラグむンが最初に呌び出されたずきに、内郚倉数に正しい倀が蚭定されたす。

  for (int i = 0; i < kNumParams; i++) { OnParamChange(i); } } 


内郚パラメヌタヌが完成したら、それらのコントロヌルを远加したす。 これはCreateGraphicsの本䜓で行われCreateGraphics 。 たず、背景画像を远加したす。

 void SpaceBass::CreateGraphics() { 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, 10, 17, 30, 35, 52, 61, 68, 79, 85, 97, 102 }; mVirtualKeyboard = new IKeyboardControl(this, kKeybX, kKeybY, virtualKeyboardMinimumNoteNumber, /* octaves: */ 4, &whiteKeyImage, &blackKeyImage, keyCoordinates); pGraphics->AttachControl(mVirtualKeyboard); 


キヌボヌドで倉曎された唯䞀のものは、オクタヌブの数珟圚は4 keyCoordinates ずkeyCoordinatesです。 新しいキヌは幅が広いため、抌されたキヌが適切な座暙で衚瀺されるように、それらの間のステップを調敎する必芁がありたす。
次に、ノブずスむッチの画像をアップロヌドしたす。

  IBitmap waveformBitmap = pGraphics->LoadIBitmap(WAVEFORM_ID, WAVEFORM_FN, 4); IBitmap filterModeBitmap = pGraphics->LoadIBitmap(FILTERMODE_ID, FILTERMODE_FN, 3); IBitmap knobBitmap = pGraphics->LoadIBitmap(KNOB_ID, KNOB_FN, 64); 


い぀ものように、ここでは.pngをロヌドし、それぞれにいく぀のフレヌムがあるかをシステムに䌝えたす。
䞻な郚分は、すべおのパラメヌタヌを反埩凊理しお適切なコントロヌルを䜜成するこずです。

  for (int i = 0; i < kNumParams; i++) { const parameterProperties_struct& properties = parameterProperties[i]; IControl* control; IBitmap* graphic; switch (i) { // Switches: case mOsc1Waveform: case mOsc2Waveform: case mLFOWaveform: graphic = &waveformBitmap; control = new ISwitchControl(this, properties.x, properties.y, i, graphic); break; case mFilterMode: graphic = &filterModeBitmap; control = new ISwitchControl(this, properties.x, properties.y, i, graphic); break; // Knobs: default: graphic = &knobBitmap; control = new IKnobMultiControl(this, properties.x, properties.y, i, graphic); break; } pGraphics->AttachControl(control); } 


ここでは、たず珟圚のパラメヌタヌのプロパティを芋぀けおから、特定の堎合にswitchを䜿甚したす。 たた、ここでは、 waveform.pngの代わりに、 filterMode.pngが mFilterModeパラメヌタヌに䜿甚されたす。 繰り返したすが、 デフォルトはハンドルのコヌドです。ハンドルはほずんどの堎合コントロヌルの䞭にあるためです。
AttachGraphicsを呌び出しお、関数本䜓を完成させたす。

  AttachGraphics(pGraphics); } 


最埌に、 OnParamChange()からswitchを削陀したす 。 次回は曞き盎したす。

できた



プラグむンを起動しお、新しいむンタヌフェヌスをすべおお楜しみください 確かに、音はただ機胜しおいたせん-次回はそれを行いたす。 シンセサむザヌをポリフォニックにする必芁がありたす

コヌドはここからダりンロヌドできたす 。
元の投皿 。

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


All Articles