すんなり出来ると信じているところに罠があるものです。
意外と普通にできそうなところに穴があるね〜
今回も、シンプルなハイパスフィルターの実装を進めて見ました。
DAWを閉じて開いたときにパラメータ初期化されないように以前の状態を保つ、という基本的な実装がまだでした。ということで、以前もチュートリアルで行なった、XMLでパラメータを保持するという方法を実装しようと思いましたが、思いがけず壁に当たりましたので、その備忘録を残したいと思います。
こんな人の役にたつかも
・AudioProcessorValueTreeStateのパラメータを保持する機能を追加したい人
・コンボボックスアタッチメントでパラメータの保持を行いたい人
・本ブログでシンプルなハイパスフィルターの実装を行なっている人
APVTSでパラメータ管理をしたときのXMLパラメータ保持
AudioProcessorValueTreeStateクラスのパラメータについては、次のようにgetStateInformation関数とsetStateInformation関数を実装することで、自動的にパラメータが読み込まれるようになりました。
void _01_panda_filterAudioProcessor::getStateInformation (juce::MemoryBlock& destData)
{
auto state = parameters.copyState();
std::unique_ptr<juce::XmlElement> xml(state.createXml());
copyXmlToBinary(*xml, destData);
}
void _01_panda_filterAudioProcessor::setStateInformation (const void* data, int sizeInBytes)
{
std::unique_ptr<juce::XmlElement> xmlState(getXmlFromBinary(data, sizeInBytes));
if (xmlState.get() != nullptr)
if (xmlState->hasTagName(parameters.state.getType()))
parameters.replaceState(juce::ValueTree::fromXml(*xmlState));
}
この内容は、JUCEチュートリアルの「Saving and loading your plug-in state」の内容をそのままコピペすればできます。
これで、すんなりパラメータの保持はできたと思いました。が、コンボボックスに罠がありました^^;
コンボボックスのパラメータ保持について
slopeパラメータを表示するコンボボックスについては、うまく動作しておらず、いろいろと検証した結果、パラメータ自体は変化していて、保持されています。一度値を-36db/octに変更して、DAWのプロジェクトとして保存、DAWを閉じて再度開くという動作を行ったところ、音声処理的にはslopeが-36db/octで効いています。
パラメータがプラグイン起動時にコンボボックスの値を変化させていないような挙動だとわかりました。
JUCEForumに見られるように、スライダーアタッチメント以外のアタッチメントクラスは、初期化を自分で実装する必要があるとみられます。
コンボボックスアタッチメントクラスを独自に作成するという手もありますが、出来るだけそう言った深入りせずに出来る方がいいなと思い、コンストラクタで直接コンボボックスの初期化を行えないかなと考えました。
コンボボックスに読み出したパラメータを反映する
PluginEditor.cppのコンストラクタ、コンボボックスを初期化するところで何とかならないかといろいろと模索して、次のようになりました。実装だけ見れば、普通のことなんですが^^;
PluginEditor.cppのコンストラクタ内、コンボボックスの初期化の部分で、[1]の処理を追加しました。
//コンボボックスの初期化
addAndMakeVisible(SlopeComboBox);
SlopeComboAttachment.reset(new ComboBoxAttachment(valueTreeState, "slope", SlopeComboBox));
SlopeComboBox.addItem("-6db", 1);
SlopeComboBox.addItem("-12db", 2);
SlopeComboBox.addItem("-18db", 3);
//DBG("slope param" << *(vts.getRawParameterValue("slope")));
//[1]初期値をAPVTSのパラメータ値を見て初期化します。
SlopeComboBox.setSelectedId(*(vts.getRawParameterValue("slope")));
APVTSクラスのオブジェクトのvtsがあり、すでにメンバイニシャライザで初期化していますので、ここからパラメータをもらうことにしました。これで、なんとかコンボボックスの値がパラメータに追従して変化するようになりました。
ついでに、PluginProcessor.hで定義しているslopeパラメータをAudioParameterIntに変更しました。ここは、コンボボックスが利用する数値が整数なので、Intに変更しました。今まで謎にFloatで管理していましたので、ちゃんとしようと思い、変更しました。
//AudioParameterIntに変更しました。
std::make_unique<juce::AudioParameterInt>("slope", // parameterID
"Slope", // parameter name
1, // min
3, // max
1)
,
それに伴い、PluginProcessor.cppのprocessBlock関数の条件の内容も整数に変更します。
void _01_panda_filterAudioProcessor::processBlock (juce::AudioBuffer<float>& buffer, juce::MidiBuffer& midiMessages)
{
//...略...
MyFilter.processBlock(buffer, midiMessages);
if (*slope == 2) {//[1]2の時フィルターが二段かかります。
MyFilter2.processBlock(buffer, midiMessages);
}
else if (*slope == 3) {//[2]3の時、フィルターが三段かかります。
MyFilter2.processBlock(buffer, midiMessages);
MyFilter3.processBlock(buffer, midiMessages);
}
条件を[1]と[2]のように変更したことで、コンボボックスが1の時は、条件に入らない、1つだけのフィルターが入ることになります。