updateGraph、奥が深いです。
もしかしたらupdateGraphが今回のチュートリアルの一番重要な部分かもしれないですね
引き続きupdateGraph関数を詳細に調査しています。
今回もカスケードプラグイン、チュートリアルページの「Connecting graph nodes together」のupdateGraph関数を読み解いています。
こんな人の役に立つかも
・JUCEフレームワークに入門したい人
・VST、AUプラグイン開発の最初の一歩を踏み出したい人
・JUCEのチュートリアルをやっている人
updateGraph関数の続き
それぞれのスロットの設定が変更されたかどうかを確認します。スロット数分の3回の繰り返し処理で3スロット分の判定を行います。chiceという変数には、choicesの配列に格納されているオブジェクトの直接参照が「getReference」関数で取得できるようです。AudioParameterChoiceクラスのオブジェクトのポインタである、processorSlot1~3のアドレスを示しています。
また、slotには、ReferenceCountedArray(Arrayではない!!)のgetUncheckedでObjectClassPtrが取得されます。
//2.スロット数分繰り返し処理で各スロットの変化を見ます。
for (int i = 0; i < 3; ++i)
{
//JUCEのArrayのgetRefference。
auto& choice = choices.getReference(i);
//JUCEのArrayのgetUnchecked。
auto slot = slots.getUnchecked(i);
//[1]スロットの選択がemptyのときです。
if (choice->getIndex() == 0)//AudioParameterChoiceクラスのgetIndexを利用しています。
{
if (slot != nullptr)
{
mainProcessor->removeNode(slot.get());
slots.set(i, nullptr);
hasChanged = true;
}
}
//[2]スロットの選択がOscillatorのときです。
else if (choice->getIndex() == 1) // [2]
{
if (slot != nullptr)
{
if (slot->getProcessor()->getName() == "Oscillator")
continue;
mainProcessor->removeNode(slot.get());
}
slots.set(i, mainProcessor->addNode(std::make_unique<OscillatorProcessor>()));
hasChanged = true;
}
//[3]スロットの選択がGainのときです。
else if (choice->getIndex() == 2) // [3]
{
if (slot != nullptr)
{
if (slot->getProcessor()->getName() == "Gain")
continue;
mainProcessor->removeNode(slot.get());
}
slots.set(i, mainProcessor->addNode(std::make_unique<GainProcessor>()));
hasChanged = true;
}
//[4]スロットの選択がFilterのときです。
else if (choice->getIndex() == 3) // [4]
{
if (slot != nullptr)
{
if (slot->getProcessor()->getName() == "Filter")
continue;
mainProcessor->removeNode(slot.get());
}
slots.set(i, mainProcessor->addNode(std::make_unique<FilterProcessor>()));
hasChanged = true;
}
}
//...以下略...
[1]の処理は、スロットのノードを初期化するパターンです。[2]~[4]は、音声処理ノードを追加する処理になります。実質は、1と2~4の2つのパターンのプログラムになりますね。
[1]の処理について
slotは「ObjectClassPtr」なのですが、getでポインタの値が取得できるようです。
いろいろ調べて、どうやらObjectClassPtrは、「ReferenceCountedObjectPtr」とtypedefされているようです。ObjectClassPtrをReferenceCountedObjectPtrのドキュメントで同じものものとして見ることにしました。
「ReferenceCountedObjectPtr」はget関数でオブジェクトのポインタを返しますので、mainProcessorのremoveNode関数は、ノードのポインタを受け取るタイプのremoveNode関数だということもわかります。
ObjectClassPtrについては次のドキュメントを参考に追跡しました。
ReferenceCountedObjectPtrのget関数
AudioProcessorGraphのremoveNode関数
ということで、slot変数は、ノードに対するポインタ、と解釈すれば良さそうです。(AudioProcessorGraph::Nodeクラスのオブジェクトへのポインタ)
[2]〜[4]の処理について
まず、choiceは、「Element type&」を示します。最初にJuceのArrayの「getRefference」関数にて取得されています。ここで取得されるのは、choicesに格納されている、AudioParameterChoiceクラスのオブジェクトへのアドレスということでしょうか。
そのため、choiceは、アロー演算子を利用して、AudioParameterChoiceクラスのgetIndex関数にアクセスすることができます。
ここで取得できるIndexとしては、クラスの最初に定義した
juce::StringArray processorChoices { "Empty", "Oscillator", "Gain", "Filter" };
をコンストラクタにてAudioParameterChoiceに設定していますので、「==0」とすることで、スロットに設定されている音声処理が「empty」である場合を示します。(その他[1]~[3]も同様です。)
slot!=nullptrの意味
「slot!=nullptr」では、slotに何かしらの音声処理ノード(オシレータ、ゲイン、フィルタ)が設定されている場合のみの処理になります。slotが「empty」のとき、[1]の処理でslotにはnullptrが設定されますので、[0]~[3]のこの条件は飛ばされます。[1]~[3]ではそのまま他の音声処理が設定されます。
一方で、以前の設定に何かしらの音声処理(オシレータ、ゲイン、フィルター)が設定されている場合は、一度「slot!=nullptr」の条件でremoveNode関数を呼び出すことで、ノードをリセットしています。
これらの条件をクリアして、最後に、次のように、音声処理ノードをセットします。
slots.set(i, mainProcessor->addNode(std::make_unique<FilterProcessor>()));
slotsは、「ReferenceCountedArray」クラスで、このクラスの関数の「set」で音声処理ノードを設定します。iは、スロット番号で、2つ目の引数に、追加したノードを指定します。
実際の音声処理オブジェクトを追加するのは、「mainProcessor」になりますので、mainProcessorのaddNodeを呼び出してその引数として、音声処理クラス(オシレータ、ゲイン、フィルター)を渡します。
mainProcessorは「AudioProcessorGraph」クラスで、ノードのポインタを返すような関数「addNode」を持っています。
今回は文章でだらだらと書きすぎて申し訳ないです。JUCEは、クラスをいかに把握しているかという点も結構重要ですね。