音量に関する調整ができるようになりました。
入力と出力で音量がいじれると便利だね〜
前回の検証で、スライダーの小数点の桁数を設定することができるようになりましたので、インプットゲインとアウトプットゲインの機能をシンプルなハイパスフィルターに追加しました。
今回は、ゲイン周りの実装の備忘録になります。
こんな人の役に立つかも
・本ブログのシンプルなハイパスフィルターを実装している人
・JUCEでデシベル表記のスライダーで音量調整したい人
・JUCEプラグインにゲインを実装したい人
実装
PluginProcessor.h
まずはプロセッサ側にインプットゲインとアウトプットゲインに関するパラメータのためのメンバと追加しました。
class _01_panda_filterAudioProcessor : public juce::AudioProcessor
{
//...略...
//[1]privateなメンバとして、ゲイン処理に関するメンバを追加します。
std::atomic<float>* inputGainDb = nullptr;
std::atomic<float>* outputGainDb = nullptr;
float previousInputGain;
float previousOutputGain;
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (_01_panda_filterAudioProcessor)
};
入力ゲインパラメータを「inputGain」、出力ゲインのパラメータを「outputGain」という名称としました。のちにコンストラクタでAudioProcessorValueTreeState(APVTS)のパラメータにひもづきます。
previous●●の2つの変数は、ゲインの変更時に滑らかにゲインを変化させる仕組みに利用するための変数です。
PluginProcessor.cpp
[1]のようにAPVTSのパラメータを追加しました。
, parameters(*this, nullptr, juce::Identifier("APVTSTutorial"),
//...略...
//[1]APVTSに以下のパラメータを追加します。
std::make_unique<juce::AudioParameterFloat>("inputGain",
"InputGain",
juce::NormalisableRange<float>(-100.0f, 12.0f),
0.0f,
"input",
juce::AudioProcessorParameter::genericParameter,
[](float value, int) {return juce::String(value, 1) + " dB";}
),
std::make_unique<juce::AudioParameterFloat>("outputGain",
"OutputGain",
juce::NormalisableRange<float>(-100.0f, 12.0f),
0.0f,
"output",
juce::AudioProcessorParameter::genericParameter,
[](float value, int) {return juce::String(value, 1) + " dB";}
),
})
{
//[2]パラメータを変数へ紐づけます。
inputGainDb = parameters.getRawParameterValue("inputGain");
outputGainDb = parameters.getRawParameterValue("outputGain");
//...略...
そして、[2]のようにヘッダに定義したinputGainとoutpputGainへと紐付けます。
次に、prepareToPlay関数でインプットゲインとアウトプットゲインの初期値をprevious●●変数に格納しておきます。音量を滑らかに変化させるための仕組みに利用する変数の初期値を格納する、という感じです。
void _01_panda_filterAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
{
//...略...
//インプットゲインとアウトプットゲインの初期値を設定します。
float val = *inputGainDb;
previousInputGain = juce::Decibels::decibelsToGain(val);
float val2 = *outputGainDb;
previousOutputGain = juce::Decibels::decibelsToGain(val2);
}
processBlock関数では、音声の音量変更処理を追加しました。インプット時の音量変更、アウトプット時の音量変更とそれぞれ実装します。「滑らかな音量変化」については、以前のチュートリアル記事をそのまま利用しました。
void _01_panda_filterAudioProcessor::processBlock (juce::AudioBuffer<float>& buffer, juce::MidiBuffer& midiMessages)
{
//[1]インプットゲインの音量変更の処理です。
float currentInputGain = *inputGainDb;
float inputGainVal = juce::Decibels::decibelsToGain(currentInputGain);
DBG("inputGain:" << inputGainVal);
if (inputGainVal == previousInputGain)
{
buffer.applyGain(inputGainVal);
}
else
{
buffer.applyGainRamp(0, buffer.getNumSamples(), previousInputGain, inputGainVal);
previousInputGain = inputGainVal;
}
//フィルター処理
//...略...
//[2]アウトプットゲインの音量変更の処理です。
float currentOutputGain = *outputGainDb;
float outputGainVal = juce::Decibels::decibelsToGain(currentOutputGain);
if (outputGainVal == previousOutputGain)
{
buffer.applyGain(outputGainVal);
}
else
{
buffer.applyGainRamp(0, buffer.getNumSamples(), previousOutputGain, outputGainVal);
previousOutputGain = outputGainVal;
}
}
ここでは、音声処理の順番が重要で、アウトプットゲインは、フィルター処理された後の「buffer」の音量を変化させることになります。
次はGUI側、エディタの実装です。
PluginEditor.h
まずは必要な変数をヘッダに定義しておきます。
スライダークラスのオブジェクトと、アタッチメントクラスが必要です。
class _01_panda_filterAudioProcessorEditor : public juce::AudioProcessorEditor, private juce::Timer
{
//...略...
//以下のスライダークラスのコンポーネントを準備します。
juce::Slider inputGainSlider;
std::unique_ptr<SliderAttachment> inputGainAttachment;
juce::Slider outputGainSlider;
std::unique_ptr<SliderAttachment> outputGainAttachment;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (_01_panda_filterAudioProcessorEditor)
};
PluginEditor.cpp
次に、cppに移動して、次のようにコンストラクタにスライダーの初期化を追加しました。
前回記事で模索したように、[1]と[2]のようにスライダーの初期化関数を利用して設定しました。
_01_panda_filterAudioProcessorEditor::_01_panda_filterAudioProcessorEditor (_01_panda_filterAudioProcessor& p, juce::AudioProcessorValueTreeState& vts)
: AudioProcessorEditor (&p), valueTreeState(vts)
, forwardFFT(p.fftOrder),
window(p.fftSize, juce::dsp::WindowingFunction<float>::hann)
,audioProcessor(p)
{
//...略...
//[1]インプットゲインスライダーの初期設定です。
addAndMakeVisible(inputGainSlider);
inputGainAttachment.reset(new SliderAttachment(valueTreeState, "inputGain", inputGainSlider));
inputGainSlider.setSliderStyle(juce::Slider::LinearVertical);
inputGainSlider.setTextBoxStyle(juce::Slider::TextBoxBelow, true, 65, 20);
inputGainSlider.setTextBoxIsEditable(true);
inputGainSlider.setRange(-100.0f, 12.0f);
inputGainSlider.setSkewFactorFromMidPoint(-6.0f);
//[2]アウトプットゲインスライダーの初期設定です。
addAndMakeVisible(outputGainSlider);
outputGainAttachment.reset(new SliderAttachment(valueTreeState, "outputGain", outputGainSlider));
outputGainSlider.setSliderStyle(juce::Slider::LinearVertical);
outputGainSlider.setTextBoxStyle(juce::Slider::TextBoxBelow, true, 65, 20);
outputGainSlider.setTextBoxIsEditable(true);
outputGainSlider.setRange(-100.0f, 12.0f);
outputGainSlider.setSkewFactorFromMidPoint(-6.0f);
setOpaque(true);
startTimerHz(30);
setSize (500, 300);
}
resized関数で、スライダーを以下の位置に配置しました。
void _01_panda_filterAudioProcessorEditor::resized()
{
//...略...
//以下の位置にスライダーを配置しました。
inputGainSlider.setBounds(5, 10, 65 ,280);
outputGainSlider.setBounds(430, 10, 65, 280);
}
このように、左側にインプットのゲイン、右側にアウトプットのゲインのスライダーが配置されました。
改善したい点
ここまで作成してみて気づいた、改善点をメモしておきます。
1)リニアスライダーのルックアンドフィールを変更する。
2)スペアナの周波数の線の目安を背景に入れる。
3)どのスライダーが何のパラメータ名かわかるラベルを追加する。
4)自分のロゴを入れたい。
3については、また少しGUIコンポーネントの配置が変わりそうなので、最初からやっておけばよかったです^^;