見た目を整えると、それっぽくなってきますね~
結構いい感じの雰囲気が出てきたね~

市販のプラグインのように、見やすくしたいなと思い、JUCEで作成しているシンプルなハイパスフィルター、の見た目を調整しています。特にスペクトルアナライザの背景表示はまだまだ不完全ですが、とりあえず簡易的ではあれ何もないよりは見やすくなったかなと思います。
次のような作業を行いました。
・ゲインスライダーにルックアンドフィールクラスを追加
・カットオフ、Qのスライダーを入力可能に
・ラベルを描画
・スペアナの背景を描画
こんな人の役に立つかも
・JUCEでハイパスフィルターを作成したい人
・JUCEプラグインの見た目を整えたい人
・本ブログのシンプルなハイパスフィルターを作成している人
ゲインスライダーのルックアンドフィール
インプットゲインとアウトプットゲインのスライダーの外観を、こちらの記事をそのまま流用して描画しました。次の2記事で作成したスライダーと同じものを作成しています。
ゲインスライダー用のルックアンドフィールクラスを「PluginEditor.h」に定義しました。
class gainSliderLookAndFeelStyle01 : public juce::LookAndFeel_V4
{
public:
gainSliderLookAndFeelStyle01()
{
//[1]テキストボックスの枠線を透明にします。
setColour(juce::Slider::ColourIds::textBoxOutlineColourId, juce::Colour::fromRGBA(0, 0, 0, 0));
}
//[2]スライダー外観の描画関数です。
void drawLinearSlider(juce::Graphics& g,
int x,
int y,
int width,
int height,
float sliderPos,
float minSliderPos,
float maxSliderPos,
const juce::Slider::SliderStyle,
juce::Slider&
) override
{
g.setColour(juce::Colour::fromRGBA(128,128,128,128));
g.fillRect(x + width / 2, y, 3, height);
g.setColour(juce::Colours::white);
g.fillRect(x + width / 2 - 25, (int)sliderPos - 1, 50, 3);
//DBG("SliderPos:" << sliderPos);
}
};
また、テキストボックスの周囲のアウトラインは、[1]のように、RGBA指定のアルファ値を0にして非表示にしています。JUCEで色をRGBAで指定するときは、「juce::Colour::fromRGBA」を利用します。(ときどきjuce::Colorsという複数形のほうと混同します^^;こちらは色名で指定するときに利用します。)
[2]では、先ほどの記事の方法でdrawLinerSlider関数をオーバーライドして実装しました。色だけ、今回のGUI用に変更しています。
この作成したルックアンドフィールクラスを使うために、プラグイン本体クラスの〇〇AudioProcessorEditorクラスのprivateなメンバとして以下のように追加しました。
class _01_panda_filterAudioProcessorEditor : public juce::AudioProcessorEditor, private juce::Timer
{
//...略...
gainSliderLookAndFeelStyle01 gainSliderLookAndFeel01;//追加しました。
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (_01_panda_filterAudioProcessorEditor)
};
次に、PluginEditor.cppのコンストラクタ内でスライダーをルックアンドフィールクラスに紐づけます。
//...略...
addAndMakeVisible(inputGainSlider);
//...略...
inputGainSlider.setTextBoxStyle(juce::Slider::TextBoxAbove, true, 65, 20);//aboveに変更しました。
inputGainSlider.setLookAndFeel(&gainSliderLookAndFeel01);//追加しました。
addAndMakeVisible(outputGainSlider);
//...略...
outputGainSlider.setTextBoxStyle(juce::Slider::TextBoxAbove, true, 65, 20);//aboveに変更しました。
outputGainSlider.setLookAndFeel(&gainSliderLookAndFeel01);//追加しました。
setOpaque(true);
startTimerHz(30);
setSize (500, 300);
}
セットしたルックアンドフィールクラスはデストラクタで次のようにnullptrを入れます。
_01_panda_filterAudioProcessorEditor::~_01_panda_filterAudioProcessorEditor()
{
//...略...
inputGainSlider.setLookAndFeel(nullptr);
outputGainSlider.setLookAndFeel(nullptr);
}
カットオフ、Qをテキスト入力可能に変更
PluginEditor.cppのコンストラクタ、スライダーの初期化のところで、スライダークラスの「setTextBoxIsEditable」関数でテキストを直接入力可能に変更しました。
[1]のカットオフスライダーは、スライダークラスの関数で「Hz」の文字を付けていましたが、こちらも、AudioProcessorValueTreeStateクラスのパラメータ定義内のラムダ式で追加することにしました。そのため、setTextSuffix関数での指定は削除します。
//コンストラクタ内です。
{
//cutoff slider settings
addAndMakeVisible(cutoffSlider);
//...略...
//[1]カットオフのスライダーは次のように変更しました。
//cutoffSlider.setTextValueSuffix("Hz");//パラメータラムダ式でHzを追加しますので、削除です。
cutoffSlider.setTextBoxIsEditable(true);//テキスト入力可能にします。
cutoffSlider.setLookAndFeel(&dialLookAndFeel01);
//Q slider setting
addAndMakeVisible(QParamSlider);
//...略...
//[2]Qパラメータのスライダー初期化でもテキスト入力可能に設定します。
QParamSlider.setTextBoxIsEditable(true);
//...略...
次に、PluginProcessor.cppでAPVTSのパラメータを定義している部分を変更します。パラメータの定義に、数値の桁数、単位をラムダ式で追加するように変更しました。
, parameters(*this, nullptr, juce::Identifier("APVTSTutorial"),
{
std::make_unique<juce::AudioParameterFloat>("cutoff",
"Cutoff",
//[1]以下の内容に変更しました。
juce::NormalisableRange<float>(20.0f, 22000.0f),
1000.0f,
"cutoff",
juce::AudioProcessorParameter::genericParameter,
[](float value, int) {return juce::String(value, 0) + "Hz";}
),
std::make_unique<juce::AudioParameterFloat>("qParam",
"QParam",
//[2]以下の内容に変更しました。
juce::NormalisableRange<float>(0.01f, 4.0f),
0.70710678f,
"Qparam",
juce::AudioProcessorParameter::genericParameter,
[](float value, int) {return juce::String(value, 3);}
),
[1]、[2]のように、カットオフ周波数とQのパラメータを、ラムダ式で桁数をそろえ、単位を付け加えるようにしました。
ラベルを描画
それぞれのスライダーがどのようなパラメータを変化させるのか、文字で表示するようにしました。
表示位置は、泥臭く、GUI上の座標X,Yと幅、高さを指定する方法で地道に配置しました。
JUCEライブラリでは、GUI上に配置したりするときに、X、Y、幅、高さという順番がよく使われるので、この指定方法に慣れるという意味でも訓練になりました^^;
ゲーム開発等を経験している方は、この辺りの描画周りは得意なのかもしれません。
PluginEditor.cppのpaint関数に以下のテキスト描画を追記しました。
g.drawText("Input", 0.0f, 5.0f, 75.0f, 10.0f, juce::Justification::centred);
g.drawText("Output", 425.0f, 5.0f, 75.0f, 10.0f, juce::Justification::centred);
g.drawText("Cutoff", 80.0f, 280.0f, 100.0f, 10.0f, juce::Justification::centred);
g.drawText("Q", 197.0f, 280.0f, 100.0f, 10.0f, juce::Justification::centred);
g.drawText("Slope", 315.0f, 235.0f, 100.0f, 10.0f, juce::Justification::centred);
テキスト描画は、graphicsクラスのdrawText関数を利用します。テキストは、Justification::centredを指定することで、配置にセンタリングされます。
スペアナの背景を描画
簡易的な背景表示になってしまいましたが、とりあえずスペアナの背景部分を次のように描画しています。

void _01_panda_filterAudioProcessorEditor::paint (juce::Graphics& g)
{
g.fillAll (getLookAndFeel().findColour (juce::ResizableWindow::backgroundColourId));
//[1]背景の描画です。
g.setColour(juce::Colour::fromRGBA(128, 128, 128, 64));
g.fillRect(75.0f,0.0f,350.0f,150.0f);
//[2]1kの中央ラインの描画です。
g.setColour(juce::Colour::fromRGBA(128,128,128,128));
g.drawLine(250.0f,0.0f,250.0f,150.0f,2.0f);
//[3]1kという周波数表示の描画です。
g.setColour(juce::Colours::white);
g.drawText("1k",225.0f,155.0f,50.0f,10.0f,juce::Justification::centred);
//...略...
[1]では、背景を矩形で描画しました。色はアルファ128の透明度にしてうっすらとさせています。
[2]で、周波数1kHzの線を描画しています。透明度64です。
[3]では、スペアナの下に周波数表示を書き込んでいます。
これらの表示の変更に伴って、スライダーの配置位置の微調整も行っています。resized関数のsetBoundsで微調整です。
void _01_panda_filterAudioProcessorEditor::resized()
{
//スライダーの配置位置も微調整しました。
cutoffSlider.setBounds(80, 175, 100, 100);
QParamSlider.setBounds(197, 175, 100, 100);
SlopeComboBox.setBounds(315, 210, 100, 20);
inputGainSlider.setBounds(5, 25, 65 ,265);
outputGainSlider.setBounds(430, 25, 65, 265);
}