【JUCEプラグイン開発】ディレイエフェクト、パラメータの保持、アンドゥ・リドゥの追加

パンダさん

今回は、地味に機能的な部分を改良してみました

コパンダ

当たり前の機能を追加することは大事だよね

ディレイプラグインの開発で、機能的な部分を追加をしました。パラメータの保持、アンドゥ、リドゥの機能を実装していきます。

パラメータの保持については、以前の記事で詳細に記載しております。

XML形式でプラグイン状態を保持

コンボボックスのAPVTSでのパラメータ保持について

また、アンドゥ、リドゥの機能についても以下の記事もご参照ください。

AudioProcessorValueTreeStateでアンドゥ、リドゥ機能を追加する

目次

こんな人の役に立つかも

・JUCEプラグイン開発をしている人

・AudioProcessorValueTreeStateのパラメータを保持したい人

・JUCEでアンドゥ、リドゥの処理を追加したい人

パラメータ保持

まずは、パラメータを保存、読み出しする機能です。これは、DAWプロジェクトを再度開いたとき、以前の設定状態になっているような機能です。この実装をしない場合、DAWプロジェクトを開くたびに、デフォルト値になってしまいます。

既にデフォルトで何も入っていないgetStateInformation関数、setStateInformation関数に以下のようなプログラムを追加します。

void TheDelayAudioProcessor::getStateInformation (juce::MemoryBlock& destData)
{
    //以下の内容を追加します。
    auto state = parameters.copyState();
    std::unique_ptr<juce::XmlElement> xml(state.createXml());
    copyXmlToBinary(*xml, destData);
}

void TheDelayAudioProcessor::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));
}

コンボボックスのみ、初期値が反映されない現象が起きますので、コンストラクタで初期値を入れるようにします。

TheDelayAudioProcessorEditor::TheDelayAudioProcessorEditor (TheDelayAudioProcessor& p, juce::AudioProcessorValueTreeState& vts)//add second param
    : AudioProcessorEditor (&p), audioProcessor (p), valueTreeState(vts)//add param
{
//...略...
    //コンボボックスの初期化を追加します。
    DelayNumerator.setSelectedId(*(vts.getRawParameterValue("delayNumerator")));

    setSize (400, 300);
}

保存されたパラメータから値を取得するためには、APVTSクラスのgetRawParameterValue関数が利用できます。引数には、パラメータIDを指定すればOKです。

アンドゥ・リドゥ機能

Undo、Redoボタンを追加して、パラメータの変更の後戻りなどができるようになります。APVTSにUndoManagerクラスを連携させることで実現ができます。

プロセッサ側

AudioProcessorクラス内に、publicなメンバとして、利用するUndoManagerを定義します。

class TheDelayAudioProcessor  : public juce::AudioProcessor, private juce::Timer
{
public:
//...略...

    //アンドゥマネージャをpublicなメンバとして追加しました。
    juce::UndoManager undoManager;

コンストラクタにて、APVTSのパラメータ初期化の際に、第二引数にundoManagerの参照を渡します。

TheDelayAudioProcessor::TheDelayAudioProcessor()
//...略...
    //第二引数にundoManagerの参照を追加します。
    , parameters(*this, &undoManager/*nullptr*/, juce::Identifier("APVTSTutorial"),

エディタ側で利用できるようにするため、createEditor関数で、AudioProcessorEditorクラスへの第三引数としてundoManagerを渡します。

juce::AudioProcessorEditor* TheDelayAudioProcessor::createEditor()
{
    //第三引数にundoManagerを追加します。
    return new TheDelayAudioProcessorEditor (*this, parameters, undoManager);
}

この状態で、undoManagerのundo関数、redo関数を呼び出すことでパラメータのアンドゥ、リドゥができる状態になりました。

エディタ側

PlugPluginEditor.h内、TheDelayAudioProcessorEditorクラスの内容となります。undo、redo関数は、ボタンから呼び出すため、今回は、テキストボタンを追加することでアンドゥ、リドゥ機能を実行できるようにします。

class TheDelayAudioProcessorEditor  : public juce::AudioProcessorEditor
{
public:
    //[1]第三引数を追加します。
    TheDelayAudioProcessorEditor (TheDelayAudioProcessor&, juce::AudioProcessorValueTreeState& vts, juce::UndoManager& um);

//...略...

    //[2]privateなメンバとしてボタンとundoManagerを追加します。
    juce::TextButton undoButton, redoButton;
    juce::UndoManager& undoManager;

    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TheDelayAudioProcessorEditor)
};

次に、PluginEditor.cppのコンストラクタを次のように変更しました。

//[1]コンストラクタの第三引数を追加します。
TheDelayAudioProcessorEditor::TheDelayAudioProcessorEditor (TheDelayAudioProcessor& p, juce::AudioProcessorValueTreeState& vts, juce::UndoManager& um)
    : AudioProcessorEditor (&p), audioProcessor (p), valueTreeState(vts)
    //[2]ボタン、アンドゥマネジャを初期化します。
    , undoButton("Undo"), redoButton("Redo")
    , undoManager(um)
{
//...略...

    //[3]ボタンの初期化をします。
    addAndMakeVisible(undoButton);
    addAndMakeVisible(redoButton);
    undoButton.onClick = [this] {
        undoManager.undo();//[1]undo処理です。
        DBG("undo");
    };
    redoButton.onClick = [this] {
        undoManager.redo();//[2]redo処理です。
        DBG("redo");
    };

    setSize (400, 300);
}

最後に、ボタンをGUIに配置して完了です。

void TheDelayAudioProcessorEditor::resized()
{
//...略...
    //ボタンを配置します。
    undoButton.setBounds(10, 200, 50, 30);
    redoButton.setBounds(60, 200, 50, 30);
}
よかったらシェアしてね!
目次
閉じる