今回は結構地味な改善を行いました。
見えないところほど重要だよね~
シンプルなハイパスフィルターのスペアナ表示部分の調整と、フィルターカーブの描画処理の見直しを行いました。見た目の調整は、一般的なEQの表示部分に倣うようにしてみました。また、フィルターカーブの描画については、前回記事での課題点で記載した通り、変数の計算を描画処理から出して、計算量を減らすような工夫を取り入れました。
こんな人の役に立つかも
・JUCEでフィルターカーブを描きたい人
・本ブログのシンプルなハイパスフィルターを作成している人
本ブログのシンプルなハイパスフィルターの記事についてはこちらをご参照ください。
スペアナ部分の見た目の調整
何回も検討してきたスペアナ部分ですが、一般的なEQのように、ゲイン値の下の方が見えないような形で、表示するようにするといつもの雰囲気がでてきました。赤枠の部分ように、少しスペアナの表示部分を隠すように上から矩形を描画しています。
reaper付属のEQも、音量レベルが-12dbくらい?(目視です)までしか表示されていないみたいなので、これに倣いました。
変更点の実装
Plugineditor.cppのpaint関数の最後に、矩形を描画する処理を追加し、Khzのラベルをその下にもってきました。
void _01_panda_filterAudioProcessorEditor::paint (juce::Graphics& g)
{
//...略...
g.fillRect(75.0f, 125.0f, 350.0f, 27.0f);
g.setColour(juce::Colours::white);
g.drawText("20Hz", 83, 135.0f, 50.0f, 10.0f, juce::Justification::centred);
g.drawText("100Hz", 181, 135.0f, 50.0f, 10.0f, juce::Justification::centred);
g.drawText("500Hz", 367, 135.0f, 50.0f, 10.0f, juce::Justification::centred);
}
また、本フィルターはQ値が4という数値まで設定でき、3つのフィルターのQが重なるので、よりとがったQになるのですが、ここでは視認性を重視するため、表示上のゲインの幅をmaxGain変数で小さくするように調整しました。
PluginEditor.hのMaxGainが2だと、ちょうどいい塩梅のX軸方向の範囲表示となったので、変更しました。
const double maxGain = 2.0;
フィルターカーブ描画処理の改善
Paint関数内で周波数スケーリングを行うためにskewedPropotionX変数を計算していました。skewedPropotionX変数は、displayWidth変数がすでに決まっていれば、displayWidth個の定数となるので、あらかじめ配列のように定数を並べておいて、それを参照したほうが1秒間に30回繰り返されるpaint関数で計算するよりいいと思います。
dispplayWidth変数はヘッダファイルでprivateなメンバとしてconstで定義されています。この値を配列の要素数とした動的な配列を作成したかったので、周波数の低数値を格納するために、std::vectorを使いました。
実装
PluginEditor.hのprivateなメンバとして、std::vectorのskewedVectorを定義しました。
std::vector<double> skewedVector;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (_01_panda_filterAudioProcessorEditor)
};
PluginEditor.cppのコンストラクタ内最後に、先ほどのskewedVectorを初期化する処理を追加しました。vectorは、push_back関数で要素を追加できます。skwewdPropotionXにサンプリングレートの半分を掛けた値がHzとなるので、ここでは、引数として「skewedPropotionX*sampleRateDiv2」を入れています。
//skewedVectorを初期化します。
for (int i = 0; i < diaplayWidth; i++) {
auto skewedProportionX = 1.0f - std::exp(std::log(1.0f - (float)i / diaplayWidth) * 0.009f);
skewedVector.push_back(skewedProportionX * sampleRateDiv2);
}
DBG("skewdVectorSize:" << skewedVector.size());
setOpaque(true);
startTimerHz(30);
setSize (500, 300);
}
Paint関数内では、毎回skewedPropotionXを計算しなくてよくなったので、[1]の行を削除、[2]のgetMagnitudeForFrequency関数に与える第一引数をskewedVectorとしました。
for (int i = 0; i < diaplayWidth; i++) {
//[1]以下の1行を削除しました。
//auto skewedProportionX = 1.0f - std::exp(std::log(1.0f - (float)i / diaplayWidth) * 0.009f);
//[2]第一引数をskewedVectorとしました。
currentMagnitude = audioProcessor.getMyFilter().getFilterCoef().getMagnitudeForFrequency(skewedVector[i], currentSampleRate);
g.drawLine( i + displayMargin //start X
, (preMagnitude * displayHeight)/ maxGain * -1 + displayHeight //start Y
, i + displayMargin + 1 //end X
, (currentMagnitude * displayHeight)/ maxGain * -1 + displayHeight //end Y
, 1.0f); // Line thickness
preMagnitude = currentMagnitude;
}
vectorは配列のように[i]でi番目の要素にアクセスできて、とても便利です。