CascadePluginはDSPのパラメータが固定であまり面白くないですね。
DSPモジュールのパラメータを外部からコントロールできるといいよね
前回までで作成した音声処理を数珠繋ぎするプラグイン「CascadePlugin」では、音声処理として「オシレータ」「ゲイン」「フィルター」をDSPモジュールから作成しました。
一方でとても基本的な作りでしたので、「オシレータ」は440Hz固定、「ゲイン」は-6db固定、「フィルター」は1000Hz固定のハイパスフィルターといった具合に、それぞれの音声処理モジュールのパラメータを固定にしていました。
あまりにも実用性がなかったので、CascadePluginにパラメータを追加して、まずはフィルターのカットオフ周波数を変化できるようにしたいなと思い、今回の改造を行いました。
こんな人の役に立つかも
・JUCEフレームワークに入門したい人
・VST、AUプラグイン開発の最初の一歩を踏み出したい人
・JUCEのチュートリアルをやっている人
改造の方向性
CascadePluginの全体的な構成を検討して、次のように変更することにしました。
パラメータ自体は、CascadePluginクラス(本体)に保持して、GenericEditorでUIを描画し、スライダーの値を取得してきます。パラメータをFilterProcessorクラスに渡すことで、FilterProcessorクラスが生成されるタイミング(updateGraph)で固定値だった初期値を渡されたパラメータで設定します。
具体的には、次の点を修正します。
①privateなメンバ変数にfloatパラメータの追加
パラメータはjuce::AudioParameterFloatクラスで「PluginProcessor.cpp」のprivateなメンバ変数として実装します。
②コンストラクタでパラメータ設定と初期化
③FilterProessor側の改良
FilterProcessorの固定値「1000.0f」を変数に変更して、この変数を外部から受け取るパラメータにしたいです。受け取るための変数として、FilterProcessorクラスのprivateなメンバ変数をAudioParameterFloatクラスで定義します。
④updateGraph関数でパラメータを渡してFilterProcessorを生成
FilterProcessorコンストラクタにパラメータを渡してカットオフ周波数を設定します。
変更点をプログラミング
①privateなメンバ変数にfloatパラメータの追加
「PluginProcessor.h」に以下のメンバ変数を追加しました。
テストのつもりで作成しましたので、「testparam」という名称です^^;
//↓add
juce::AudioParameterFloat* testparam;
//以下はもとからあったメンバです。
Node::Ptr audioInputNode;
Node::Ptr audioOutputNode;
Node::Ptr midiInputNode;
Node::Ptr midiOutputNode;
//...略...
②コンストラクタでパラメータの設定と初期化
次に、パラメータをコンストラクタで初期化します。コンストラクタにメンバイニシャライザでtestparamを初期化して、コンストラクタ内でaddParameterすることでパラメータの設定を行います。
CascadePluginAudioProcessor::CascadePluginAudioProcessor()
: AudioProcessor(BusesProperties().withInput("Input", juce::AudioChannelSet::stereo(), true)
.withOutput("Output", juce::AudioChannelSet::stereo(), true)),
mainProcessor(new juce::AudioProcessorGraph()),
muteInput(new juce::AudioParameterBool("mute", "Mute Input", true)),
processorSlot1(new juce::AudioParameterChoice("slot1", "Slot 1", processorChoices, 0)),
processorSlot2(new juce::AudioParameterChoice("slot2", "Slot 2", processorChoices, 0)),
processorSlot3(new juce::AudioParameterChoice("slot3", "Slot 3", processorChoices, 0)),
bypassSlot1(new juce::AudioParameterBool("bypass1", "Bypass 1", false)),
bypassSlot2(new juce::AudioParameterBool("bypass2", "Bypass 2", false)),
bypassSlot3(new juce::AudioParameterBool("bypass3", "Bypass 3", false)),
testparam(new juce::AudioParameterFloat("test", "testParam", 0.0f, 22000.0f, 500.0f))//ここを追加しました。
{
addParameter(muteInput);
addParameter(processorSlot1);
addParameter(processorSlot2);
addParameter(processorSlot3);
addParameter(bypassSlot1);
addParameter(bypassSlot2);
addParameter(bypassSlot3);
//↓ここも追加しました。
addParameter(testparam);
}
③FilterProessor側の改良
「PluginProcessor.h」に定義しているFilterProcessorクラスを次のように変更しました。
class FilterProcessor : public ProcessorBase
{
public:
FilterProcessor(juce::AudioParameterFloat* f) { freq = f; }//[2]コンストラクタで変数を初期化します。
void prepareToPlay(double sampleRate, int samplesPerBlock) override
{
*filter.state = *juce::dsp::IIR::Coefficients<float>::makeHighPass(sampleRate, *freq);//[3]カットオフ周波数を設定します。
//...略...
private:
juce::dsp::ProcessorDuplicator<juce::dsp::IIR::Filter<float>, juce::dsp::IIR::Coefficients<float>> filter;
juce::AudioParameterFloat* freq;//[1]メンバ変数を準備します。
};
[1]privateなメンバ変数として、渡される値と同じクラス、「AudioParameterFloat*」で変数を定義しました。
[2]で、コンストラクタに引数を受け取る形に変更し、先ほど定義した変数に代入します。
[3]のフィルターのカットオフ周波数設定で渡された値を設定するようにしています。
④updateGraph関数でパラメータを渡してFilterProcessorを生成
「PluginProcessor.h」のupdateGraph関数内で、FilterProcessorを作成する際に、「std::make_unique」でフィルタークラスのオブジェクトを生成しています。このときに、初期値を与えて生成するので、以下のように()内にtestparamを入れます。
slots.set(i, mainProcessor->addNode(std::make_unique<FilterProcessor>(testparam)));//!!changed
「std::make_unique」については、以下のサイトを参考にさせていただきました。
動作検証の際に、Mute Inputの初期値がTrueなので、まずここのチェックを外さないと音が鳴りません^^;また、updateGraphでスロットに変更があったときのみカットオフ周波数が設定されるので、上の図のような順番で設定を行うと、フィルターの効果が確認できます。
改良点
パラメータでカットオフ周波数が設定できるようになりましたが、チャンネルストリップのフィルターを設定したタイミングで周波数が設定されるので、リアルタイムに周波数変更ができていない点が課題です。
なんだかEQ感あるものになりつつ・・・