DAWを再起動すると、プラグインパラメータが初期化されてしまいます。
プラグインとしての体裁を整えるには、もう少し追加の仕組みが必要そうだね~
前回作成したゲインプラグインは、パラメータを変更した後に、DAWを閉じてしまうと再度プロジェクトを開いたときに初期値である0.1が設定されてしまいます。ちゃんとしたプラグインとしての体裁を整えるため、プラグインのパラメータをプロジェクトファイルに保存して、次回開いたときに設定する、というような挙動に変更していきます。
今回のチュートリアルは、こちらのページ「Storing and retrieving parameters」を進めていきます。
前回の記事はこちらになります。
こんな人の役に立つかも
・JUCEフレームワークに入門したい人
・VST、AUプラグイン開発の最初の一歩を踏み出したい人
・JUCEのチュートリアルをやっている人
getStateInformation関数
「PluginProcessor.cpp」には、DAWがプロジェクトファイル保存する際や、プリセット保存をする際に実行される「getStateInformation」という関数が実装されています。これをオーバーライドしてゲインプラグインの保存パラメータを追加していきます。
void GainPluginAudioProcessor::getStateInformation (juce::MemoryBlock& destData)
{
juce::MemoryOutputStream(destData, true).writeFloat(*gain);
}
writFloatはfloat型の数値を書き込みますが、他に型に合わせて書き込む関数がある模様です。
setStateInformation関数
DAWにパラメータを保存してもらう関数があるように、DAW起動時にパラメータを読み込む関数が「setStateInformation」です。プラグインの枠にあらかじめ存在している「PluginProcessor.cpp」の「setStateInformation」関数に次のプログラムを追加します。
void GainPluginAudioProcessor::setStateInformation (const void* data, int sizeInBytes) override
{
*gain = juce::MemoryInputStream (data, static_cast<size_t> (sizeInBytes), false).readFloat();
}
gainのポインタにreadFloat関数でFloat型の数値を読み込みます。
これで、DAWを閉じて起動した際にもGainの値が保持されるようになりました。
あたりまえに思えていたことも、あたりまえじゃなかった、と感じます。
ゲインプラグインの改善点
チュートリアルによると、ゲインプラグインには、次の改善点があるとのことです。
①素早くゲインパラメータを変化した際のノイズの混入
たしかに、プラグインのスライダーを素早く移動させると、ぶつぶつとノイズになります。モジュレーションを狙ったオートメーションを描くと致命的ですね。
②XMLでのより便利なパラメータの保持
今回行った「バイナリ形式でのプラグイン情報の保持」は、プラグインパラメータの記憶領域を消費するとのことでした。どうやら、バイナリ形式での情報の保存には、容量の限度があるようですね。そこで、XMLやJSON形式でプラグインのパラメータを保持しておくやり方があるようです。
パラメータ変化時のノイズを防ぐ
素早いゲインの変化によるノイズ発生を防ぐためのプログラムを追加していきます。
「PluginProcessor.h」に一つ前のオーディオバッファを定義します。
private:
//==============================================================================
juce::AudioParameterFloat* gain;
float previousGain; //これを追加します。
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TutorialProcessor)
};
「PluginProcessor.cpp」のprepareToPlay関数に次のプログラムを追加します。
void GainPluginAudioProcessor::prepareToPlay (double, int) override
{
previousGain = *gain;
}
一つ前のオーディオバッファにゲインの値を代入しました。
最後に、「PluginProcessor.cpp」内のprocessBlockを次のように書き換えます。
void GainPluginAudioProcessor::processBlock (juce::AudioSampleBuffer& buffer, juce::MidiBuffer&) override
{
//autoはC++の型を推論してくれるような型の機能らしいです。
auto currentGain = gain->get();
if (currentGain == previousGain)
{
//一つ前のバッファと同じゲイン数値の場合はそのままcurrentGainの値を入れます。
buffer.applyGain (currentGain);
}
else
{
//オーディオバッファのゲインを滑らかに変化させます。
buffer.applyGainRamp (0, buffer.getNumSamples(), previousGain, currentGain);
previousGain = currentGain;
}
}
これで、急なゲインの変更でもぶちぶちならずにスムーズな音量変化が実現できました。
applyGainRampは次のページにドキュメントがあります。
今回の引数の与え方は2/2のパターンのapplyGainRampになりますね。
今回の挙動を見ていて、processBlockは、オーディオバッファ毎に実行されるようですね。
PreviousGainは、一つ前のオーディオバッファの時にcurrentGainを代入したものになります。一つ前のオーディオバッファ取得時のcurrentGainを見ていて(previousGain=currentGain)一つ前のオーディオバッファと同じゲイン量の場合、そのままゲインを反映させます。もし、ゲインの値が変化していたら、「applyGainRamp」関数で、一つ前のオーディオバッファの時のゲインの値から、今スライダーで変化させたゲインの値になめらかにオーディオバッファのゲインをフェード処理します。
このような処理を行うことで、いきなり断続的に音量が変化することなく、ぶちぶちノイズがなくなることになります。
オーディオバッファのイメージも大切です。