ミニマムなハイパスフィルターをカスタマイズしていこうかと思います。
この先には、パラメトリックなEQ的なものが・・・
前回作成したミニマムなフィルタープラグインは1kHzをカットオフ周波数と固定値だったので、かなり男設定なプラグインでした。フィルターのカットオフ周波数を変更できるようにしましたので、その備忘録になります。
こんな人の役にたつかも
・JUCEプラグインを作成したい人
・JUCEのDSPモジュール、フィルターを利用したい人
・JUCEでハイパスフィルターを作成したい人
前回までの流れと改良の概要
ミニマムなフィルタープラグインを作成するにあたり、今までの流れです。
こちらの記事で、Projucerのテンプレートに「FilterProcessor」というクラスを追加して、ハイパスフィルターを実装しました。この時点で、フィルターのパラメータ固定です。(カットオフ1kHz)
次に、カットオフ周波数をパラメータ値として管理するために、AudioProcessorValueTreeStateクラスに追加、管理をしました。
改良の方向性
追加したパラメータ「cutoffParam」をハイパスフィルターのクラス「FilterProcessor」内のprocessBlock関数内で利用して、フィルターのカットオフ周波数を変更できるようにしていきます。
実装
PluginProcessor.h
まずは、PluginProcessor.hに定義している「FilterProcessor」クラスを改良していきます。
class FilterProcessor : public ProcessorBase
{
public:
FilterProcessor() {}
void prepareToPlay(double sampleRate, int samplesPerBlock) override
{
*filter.state = *juce::dsp::IIR::Coefficients<float>::makeHighPass(sampleRate, 1000.0f);
//[1]受け取ったサンプルレートを保持します。
samplerate = sampleRate;
juce::dsp::ProcessSpec spec{ sampleRate, static_cast<juce::uint32> (samplesPerBlock), 2 };
filter.prepare(spec);
DBG("prepared");
}
void processBlock(juce::AudioSampleBuffer& buffer, juce::MidiBuffer&) override
{
//[2]フィルターのカットオフ周波数を設定します。
float cutoff_val = *cutoffParam_filter;
//DBG("processing" << cutoff_val);
*filter.state = *juce::dsp::IIR::Coefficients<float>::makeHighPass(samplerate, cutoff_val);
juce::dsp::AudioBlock<float> block(buffer);
juce::dsp::ProcessContextReplacing<float> context(block);
filter.process(context);
}
//...略...
//[3]filterProcessorにパラメータを渡す関数です。
void setCutoffParam(std::atomic<float>* param) {
cutoffParam_filter = param;
}
//...略...
private:
//[4]privateなメンバを追加しました。
std::atomic<float>* cutoffParam_filter = nullptr;
float samplerate;
juce::dsp::ProcessorDuplicator<juce::dsp::IIR::Filter<float>, juce::dsp::IIR::Coefficients<float>> filter;
};
[1]では、後ほどprocessBlockでmakeHighPass関数を利用する際に、サンプルレートが必要になるので、自身のprivateなメンバ変数samplerateに保持しておきます。
[2]で、makeHighPass関数でフィルターのパラメータを作成して設定します。
[3]は、新規に追加した関数で、パラメータを受け取る関数です。これをプラグイン本体のコンストラクタから呼び出してパラメータを受け取ることで、パラメータの参照ができるようにしています。単純に、パラメータの型であるstd::atomic<float>*型の変数を受け取り、自分のprivateなメンバに格納するだけという単純な構造です。
[4]では、先ほど利用したprivateなメンバ変数を定義しています。
PluginProcessor.cpp
次に、PluginProcessor.cppのプラグインのコンストラクタの定義で、FilterProcessorクラスのオブジェクトMyFilterにパラメータであるvutoffParamを渡します。(cutoffParamはポインタなので、MyFilterにパラメータの場所を教えてあげるイメージになります。)
//...略...
,parameters(*this, nullptr, juce::Identifier("APVTSTutorial"),
{
std::make_unique<juce::AudioParameterFloat>("cutoff", // ID
"Cutoff", // name
//[1]パラメータ範囲を変更しました。
20.0f, // min
22000.0f, // max
20.0f)// default
})
{
cutoffParam = parameters.getRawParameterValue("cutoff");
//[2]cutoffParamパラメータをMyFilterオブジェクトに設定します。
MyFilter.setCutoffParam(cutoffParam);
}
[1]ですが、与える数値が0だとエラーになりますので、最小のカットオフ周波数は20Hz、初期値も20Hzとなるように変更しました。
[2]で、MyFilterオブジェクトに作成したsetCutoffParam関数にパラメータcutoffParamを渡して、パラメータを参照できるようにします。
動作の雰囲気と改良点
Logicのテストオシレータでホワイトノイズを出して、ローカット具合を確認してみました。ちゃんと動作している模様。
スライダーの動作が、リニアなので、skewしてあげて低い周波数を細かく変化させることができるように改良したいと感じました。この変換は、以前やったことがあるので、苦労はしない、はずです^^;