JUCEでアプリケーション開発、AudioProcessorValueTreeStateを使ったリファクタリング

1_プログラミング

AudioProcessorValueTreeStateクラスでもっと効率的にパラメータが管理できるようです。

どんどんと方法も改善されて行っているんだね~

JUCEチュートリアルを進めています。このチュートリアルから、AudioProcessorValueTreeStateというクラスなどを利用することで、プラグインのパラメータ追加管理が前回までのチュートリアルより楽に、洗練されたものになる、ということでした。

これから進めていくチュートリアルは、次のページになります。

また、このチュートリアルは、以前のゲインプラグインをもとにしていますので、以前のチュートリアル記事もご参考ください。

こんな人の役に立つかも

・JUCEフレームワークに入門したい人

・VST、AUプラグイン開発の最初の一歩を踏み出したい人

・JUCEのチュートリアルをやっている人

スポンサーリンク

チュートリアルの概要について

前回までのチュートリアルでは、「AudioParameterFloat」クラスでゲインの値をパラメータとして保持し、「AudioParameterBool」で位相の値を保持するという方法をとっていました。

今回のチュートリアルからは、これらのパラメータを「AudioProcessorValueTreeState」というクラスで保持することでパラメータ管理がより楽になるというものです。本家チュートリアルでは、zipファイルをダウンロードしながら、プログラムを見ていくのですが、ここでは、前回までに作り上げた「GainPlugin」を変更しながら作り替えていきたいと思います。

また、前回のゲインプラグインには、EditorクラスにGUIを実装できていませんでした。DAWがデフォルトで割り振ってくれるUIのみで操作ができていましたが、「AudioProcessorTreeState」クラスを利用した方法では、EditorクラスへのGUI実装までをワンストップで行うことができるようです。

最終的には、次のようなGUIのゲインプラグインが完成しました。

チュートリアルはzipの.hファイルを参考に読み解く、みたいな感じでしたので、文章だけからだとプラグインを動作させるところまではいきませんでした。

プロセッサクラスをプログラミング

「PluginProcessor.h」と「PluginProcessor.cpp」でゲイン処理のプログラミングを行います。

パラメータのためのメンバ変数

まずは、パラメータを保存するためのメンバ変数として次のように「AudioProcessorValueTreeState」のオブジェクトを準備します。「PluginProcessor.h」のprivateなメンバ変数を以下のように変更します。

//...略...
private:
    //==============================================================================
    //juce::AudioParameterFloat* gain;
    //juce::AudioParameterBool* invertPhase;

    //新しく追加した「parameter」
    juce::AudioProcessorValueTreeState parameters;

    //少し後で利用するパラメータへのポインタを保持するメンバです。これも追加しておきましょう。
    std::atomic<float>* phaseParameter = nullptr;
    std::atomic<float>* gainParameter  = nullptr;

    //previousGainはそのまま利用します。
    float previousGain;
//...以下略...

今までの「gain」や「invertPhase」といった個別にパラメータを準備するのに変わり、「parameters」というオブジェクトで管理します。

少しあとで利用するパラメータへのポインタ、は、「アトミック操作」のポインタということで宣言してあります。アトミック操作は、私も少し調べた程度なのです!どうやら複数のスレッドから参照されても大丈夫みたいな雰囲気でしょうか。mutexとかと似ているとのことですが、排他的な制御ができるようなものになっています。おそらく、EditorクラスはProcessorクラス一つに対して何個もぶら下がることができる、と以前のチュートリアルで勉強したので、いろいろな操作系(スレッド)から操作されても大丈夫なようにこのようになっているのでしょう。とひとまず考えておきます 笑

確かに、Cの組み込み系ではいろいろと工夫したりして同時に排他的に変数を見ることができるようにしたりしましたが、C++ではすでにいろいろな宣言方法として組み込まれているみたいですね、ルールが複雑ですね^^;

コンストラクタでのパラメータの設定と初期化

次に、「PluginProcessor.cpp」のコンストラクタ「GainPluginAudioProcessor」も

//==============================================================================
/*GainPluginAudioProcessor::GainPluginAudioProcessor()
#ifndef JucePlugin_PreferredChannelConfigurations
     : AudioProcessor (BusesProperties()
                     #if ! JucePlugin_IsMidiEffect
                      #if ! JucePlugin_IsSynth
                       .withInput  ("Input",  juce::AudioChannelSet::stereo(), true)
                      #endif
                       .withOutput ("Output", juce::AudioChannelSet::stereo(), true)
                     #endif
                       )
#endif
{
    addParameter(gain = new juce::AudioParameterFloat("gain","Gain",0.0f,1.0f,0.1f));
    addParameter(invertPhase = new juce::AudioParameterBool("invertPhase", "Invert Phase", false));
}*/
//↑今までのコンストラクタを↓のように変更しました。
GainPluginAudioProcessor::GainPluginAudioProcessor()
    : parameters(*this, nullptr, juce::Identifier("APVTSTutorial"),
        {
            std::make_unique<juce::AudioParameterFloat>("gain",            // parameterID
                                                         "Gain",            // parameter name
                                                         0.0f,              // minimum value
                                                         1.0f,              // maximum value
                                                         0.5f),             // default value
            std::make_unique<juce::AudioParameterBool>("invertPhase",      // parameterID
                                                        "Invert Phase",     // parameter name
                                                        false)              // default value
        })
{
    phaseParameter = parameters.getRawParameterValue("invertPhase");
    gainParameter = parameters.getRawParameterValue("gain");
}

コンストラクタの「:」の後には、メンバ変数の初期化処理を行っています。ここで「parameters」は「AudioProcessorsValueTreeStateクラス」ですので、引数を与えてコンストラクタで初期化を行っています。「AudioProcessorsValueTreeStateクラスのコンストラクタ」は次のような引数となっています。

//これはコンストラクタの説明用なので、今回のプログラムに記載するものではありません。
AudioProcessorValueTreeState (AudioProcessor& processorToConnectTo,
                              UndoManager* undoManagerToUse,
                              const juce::Identifier& valueTreeType,
                              ParameterLayout parameterLayout);

第一引数に、「AudioProcessor」へのポインタ、「*this」が指定されています。第二引数にはUnDoの機能が追加できる「UndoManager」というものが指定できるようですが、今回のチュートリアルでUndo機能まではやりませんので、「nullptr」とします。第三引数のIdentifierには、valueTreeTypeを指定しますが、どうやら定数でパラメータの名前のようなものを付けている感じがします。ここはちょっと調べ切れていません。最後の「parameterLayout」には、パラメータの詳細を入れます。パラメータの入れ方としては、プログラムの例を参考に増やして行けそうです。

コンストラクタの中({と}の間)では「phaseParameter」と「gainParameter」メンバへのパラメータの紐づけが行われています。

ゲインの処理

一つ前のバッファをみて、ゲインパラメータ変更時にぶちぶちならないようにゲインを滑らかにする処理は健在です。

まずはprepareToPlayを次のように変更しています。

void GainPluginAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
{
    //auto phase = *invertPhase ? -1.0f : 1.0f;
    //previousGain = *gain * phase;
    auto phase = *phaseParameter < 0.5f ? 1.0f : -1.0f;
    previousGain = *gainParameter * phase;
}

phase変数への代入方法の計算が変更されています。これは、パラメータ値を取得する「getRawParameterValue」の返ってくる値が「float」型なので、判定式を「0.5より大きいか、小さいか」として3項演算子に判定をさせています。以前は「True」か「False」が入ってきていたので、変更した感じですね。

previousGainの値は、変数名を「*gain」から「gainParameter」へと変更しています。

最後に、音声バッファに処理を行っている「processBlock」関数の処理を次のように変更します。

void GainPluginAudioProcessor::processBlock (juce::AudioBuffer<float>& buffer, juce::MidiBuffer& midiMessages)
{
    //auto phase = *invertPhase ? -1.0f : 1.0f;
    //auto currentGain = *gain * phase;

    auto phase = *phaseParameter < 0.5f ? 1.0f : -1.0f;
    auto currentGain = *gainParameter * phase;
//...以下略...

これも、prepareToPlay関数と同じ変更を行っています。

今回は、少し長くなってしまいましたので、ここまでとします。次回も引き続きvalueTreeStateで作り変えるゲインプラグインを進めていきます。

タイトルとURLをコピーしました