周波数を可変としてAudioPluginHostからサイン波を出力するようなツールを作成したいです。
実験用のツールとしてはいい感じにできてきたね~
前回実装した440Hzのサイン波出力プラグインアプリに、周波数を可変とするパラメータを追加して、スライダーで周波数を操作できるように変更しました。
前回の記事はこちらです。前回の実装からの差分を記載していきます。
こんな人の役に立つかも
・JUCEプラグインを作成したい人
・JUCEでサイン波形を出力するプラグインを作成したい人
・周波数をスライダーで操作したい人
実装
PluginProcessor.h
AudioProcessorValueTreeState(以下APVTS)クラスを利用したパラメータを追加しています。
privaclass TheBasicSineAudioProcessor : public juce::AudioProcessor
{
//...略...
private:
//...略...
//以下のprivateなメンバを追加しました。
//[1]APVTSに係るメンバです。
juce::AudioProcessorValueTreeState parameters;
std::atomic<float>* Freqency = nullptr;
double sampleRate_from_prepareToPlay;//[2]
int numberOfOscillators = 1;//[3]
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TheBasicSineAudioProcessor)
};
[1]はAPVTSでパラメータを追加するためのメンバです。APVTSクラスでのパラメータ追加はこちらの記事もご参照ください。
[2]はsampleRateを受け取るprepareToPlayの値をprocessBlockでも利用できるように変数を作成しました。
[3]は、オシレータの個数設定です。以前はprepareToPlay関数ないでローカル変数として作成していましたが、こちらに移動させました。processBlock関数でも利用するためです。
PluginProcessor.cpp
APVTSのパラメータを初期化します。
TheBasicSineAudioProcessor::TheBasicSineAudioProcessor()
//...略...
//[1]パラメータ追加、設定します。
, parameters(*this, nullptr, juce::Identifier("APVTSTutorial"),
{
std::make_unique<juce::AudioParameterFloat>("frequency", // ID
"Frequency", // name
0.0f, // min
22000.0f, // max
0.0f)// default
})
{
//[2]紐づけます。
Freqency = parameters.getRawParameterValue("frequency");
}
[1]でパラメータ設定、[2]で先ほど宣言したメンバ「Frequency」に紐づけています。
prepareToPlay関数
次に、prepareToPlay関数を変更していきます。
//==============================================================================
void TheBasicSineAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
{
//[1]以下の変数はprivateなメンバにしたので削除します。
//auto numberOfOscillators = 1;
//[2]サンプルレートを取得します。
sampleRate_from_prepareToPlay = sampleRate;
//[3]周波数設定をパラメータから取得します。
float freq_val = *Freqency;
for (auto i = 0; i < numberOfOscillators; ++i)
{
auto* oscillator = new SineOscillator();
oscillator->setFrequency(freq_val, (float)sampleRate);//[4]周波数をパラメータから取得した変数に変更しました。
oscillators.add(oscillator);
}
level = 0.1f / (float)numberOfOscillators;
}
上記コメント部分を変更していきました。
変更点としてのポイントは、以下の3つです。
・サンプルレートをクラスのprivateなメンバとして保持する点
・オシレータの数の「numberOfOscillators」変数をprivateなメンバにした点
・周波数の設定をAPVTSのパラメータから[3]のように取得して利用すること
です。
processBlock関数内でも動的に周波数の変更をおこない、「setFrequency」関数を呼び出したいので、先の2つの変数はprivateなメンバとしてクラスの中にもっていきました。
processBlock関数
また、processBlock関数も次のように変更しました。次のコメントの部分を追加しました。
void TheBasicSineAudioProcessor::processBlock (juce::AudioBuffer<float>& buffer, juce::MidiBuffer& midiMessages)
{
//...略...
//[1]周波数をパラメータから取得します。
float freq_val = *Freqency;
for (auto i = 0; i < numberOfOscillators; ++i)
{
//[2]周波数の指定を取得したものに変更しています。(freq_val)
oscillators.getUnchecked(i)->setFrequency(freq_val, (float)sampleRate_from_prepareToPlay);
}
//追加ここまで
auto* leftBuffer = buffer.getWritePointer(0);
auto* rightBuffer = buffer.getWritePointer(1);
//...略...
}
ここでは、オシレータを管理している「OwnedArray」クラスの配列から、特定の番号のオシレータオブジェクトを呼び出して「setFrequency」関数で周波数を設定する点です。「getUnchecked」にインデックス番号を引数で入れることで、OwnedArrayに登録されているオシレータを取得できます。
createEditor関数
APVTSによるパラメータ管理を行うため、エディタ側へ渡すパラメータを引数として追加しました。
juce::AudioProcessorEditor* TheBasicSineAudioProcessor::createEditor()
{
//引数parametersを追加します。
return new TheBasicSineAudioProcessorEditor (*this, parameters);
}
PluginEditor.h
GUI側のAPVTSクラスのパラメータ管理のための設定を行いました。[1]~[3]のように追記しています。
class TheBasicSineAudioProcessorEditor : public juce::AudioProcessorEditor
{
public:
//[1]コンストラクタに引数を追加しました。
TheBasicSineAudioProcessorEditor (TheBasicSineAudioProcessor&, juce::AudioProcessorValueTreeState& vts);
~TheBasicSineAudioProcessorEditor() override;
//==============================================================================
void paint (juce::Graphics&) override;
void resized() override;
//[2]スライダーアタッチメントクラスをtypedefします。
typedef juce::AudioProcessorValueTreeState::SliderAttachment SliderAttachment;
private:
//[3]APVTSクラスでパラメータを管理するために以下のメンバを追加しました。
juce::AudioProcessorValueTreeState& valueTreeState;
juce::Slider FrequencySlider;
std::unique_ptr<SliderAttachment> FrequencyAttachment;
TheBasicSineAudioProcessor& audioProcessor;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TheBasicSineAudioProcessorEditor)
};
PluginEditor.cpp
コンストラクタ
[1]と[2]のように、コンストラクタの引数にvtsを渡してメンバイニシャライザでValueTreeStateのオブジェクトを初期化します。
//==============================================================================
TheBasicSineAudioProcessorEditor::TheBasicSineAudioProcessorEditor (TheBasicSineAudioProcessor& p, juce::AudioProcessorValueTreeState& vts)//[1]引数にvtsを追加しています。
: AudioProcessorEditor (&p), audioProcessor (p)
, valueTreeState(vts)//[2]ValueTreeStateの初期化を追加しました。
{
//[3]スライダーの可視化と、パラメータの紐づけを行います。
addAndMakeVisible(FrequencySlider);
FrequencyAttachment.reset(new SliderAttachment(valueTreeState, "frequency", FrequencySlider));
//[4]スライダーの中央値は1000Hzとします。
FrequencySlider.setRange(0.0, 22000.0);
FrequencySlider.setSkewFactorFromMidPoint(1000.0);
setSize (400, 300);
}
[3]では、スライダーオブジェクトを可視化、その後、スライダーアタッチメントクラスでスライダー「FrequencySlider」をパラメータ「frequency」と紐づけました。
[4]では、スライダーの中央値を1000として、可聴領域での周波数の変化を操作しやすくしています。
この中央値設定は、[3]のあとの紐づけ後、setRangeしてsetSkew…という順番が重要です。
paint関数
paint関数では、背景の塗りつぶしのみとしました。
void TheBasicSineAudioProcessorEditor::paint (juce::Graphics& g)
{
g.fillAll (getLookAndFeel().findColour (juce::ResizableWindow::backgroundColourId));
//これ以下のデフォルトの描画を削除しました。
}
resized関数
resized関数で、「FrequencySlider」をGUIに配置しました。
void TheBasicSineAudioProcessorEditor::resized()
{
//スライダーコンポーネントを配置します。
FrequencySlider.setBounds(10, 10, 200, 30);
}
動作検証をしていて、WindowsのReaperではプラグインとして読み込むことができますが、未だLogicで動作させられていないので、プラグイン設定のあたりも色々と検討しなければいけません。とりあえず今回は、AudioPluginHostで検証をしています。