スライダーの桁数を設定するのに意外とてこずりました
ちょっとした不具合なのかな??
シンプルなハイパスフィルターを作成するうえで、インプットゲインとアウトプットゲインを調整するスライダーを設置しようとしていました。
今まで、スライダーが表示する数値の桁数を気にすることなく、まあ、できるでしょうという感じで後回しにしていました。
もちろん、juce::Sliderクラスには、「setNumDecimalPlacesToDisplay()」関数があるので、これをコンストラクタなどで設定してあげればいいか、と思っていたのですが・・・全然桁数が変わりません><
いろいろと調べていくと、JUCEフォーラムにこの関数が効かないという記事が約2年前に上がっておりました。二年前なので、改善されているのかな、とも思いましたが、いろいろ順番を変えたり、検討してもダメでしたので、デフォルトの機能でスライダーのカスタマイズをすること自体が主流ではないということなのでしょうか。
https://forum.juce.com/t/setnumdecimalplacestodisplay-not-behaving-solved/33686/2
スライダーコンポーネントのデフォルトの機能で、テキスト表示周りを調整するためにやったことを記載していきます。今回の記事で、テキスト入力可能な小数点1桁デシベル表示のリニアスライダーを作るまでの備忘録となります。
こんな人の役に立つかも
・JUCEのスライダーの表示桁数を調整したい人
・juce::SliderのsetNumDecimalPlacesToDisplayの代替案を探している人
・AudioProcessorValueTreeStateでパラメータ桁数、単位を追加したい人
APVTSパラメータの定義方法について調査
JUCEフォーラムのやり方によると、AudioProcessorValueTreeStateのパラメータをメンバイニシャライザで定義して初期化するとき、引数にラムダ式を与えてデシベルの文字列を返すというような関数を定義することで、テキストボックスの「数値の桁数」、「単位」、「デシベルへの変換」を行うというようなものです。
PluginProcessor.cppのパラメータ定義に、次のようにパラメータを定義しました。
std::make_unique<juce::AudioParameterFloat>("inputGain",
"InputGain",
juce::NormalisableRange<float> (0.0f, 4.0f, 0.0001f, std::log(0.5f) / std::log((1.0f - (1.0f / 4.0f)) / (4.0f - (1.0f / 4.0f)))),//[1]
1.0f,//[2]
"input",//[3]
juce::AudioProcessorParameter::genericParameter,//[4]
[](float value, int) {return juce::String(juce::Decibels::gainToDecibels(value), 1) + " dB";}//[5]
),
以前、ゲインスライダーでデシベル管理を行った際には、パラメータで管理をする数値範囲は、-100~12というデシベル値でしたが、今回は「ゲイン値」を管理して、スライダー表示の際にデシベルに変換するという方式になります。
AudioParameterFloatを定義する際に、[1]~[5]のパラメータにしています。
[1]はNormalisableRangeを利用して、ゲインの最小値~最大値を定義します。今回、スライダーの上限値を12dbとしたかったので、4.0fとしました。また、0.0001fがゲインの変化量のステップ値になります。スライダーの変化量がゲイン値0.0001単位で変化します。そして、最後のlogの計算でゲイン値をスケーリングしています。
[2]は初期値です。1.0のゲイン値が0dbなので、1.0fとしています。
[3]はパラメータラベルとのことです。ちょっとここは具体的な挙動を追求できていない点です。
[4]はパラメータの種類です。AudioProcessorParameterのgenericParameterという種類を指定しました。
[5]で、テキストに表示する際のテキスト変換の関数をラムダ式で定義しています。
PluginEditor.cppのスライダーで行っていた桁数、スケーリング、単位表示に関するスライダーの初期設定を削除しました。
とりあえずシンプルに以下のような設定のみとしました。
addAndMakeVisible(inputGainSlider);
inputGainAttachment.reset(new SliderAttachment(valueTreeState, "inputGain", inputGainSlider));
inputGainSlider.setSliderStyle(juce::Slider::LinearVertical);
inputGainSlider.setTextBoxStyle(juce::Slider::TextBoxBelow, true, 65, 20);
ここまでの課題点と解決策
この方式にしたところで、以下のような問題が浮上してきました。
スライダーのテキストボックス入力(isTextBoxEditable関数をtrueにする)を有効にすると、テキストボックスの内容をスライダーに反映することができますが、今回の方法をとると、表示されているデシベルでの入力ではなく、ゲイン値を入力しなければいけないです。
例として、4.0で12db、1.0で0db、-0.5で-6dbなどテキストに入力する際にゲイン値を入れないといけません。
以前作成したDecibelSliderというクラスを定義して、getTextFromValue関数とgetValueFromText関数をオーバーライドしてみましたが、うまく動作しませんでした。
ここで問題となるのは、テキストボックスの値の変換のタイミングなので、そもそも値自体がデシベルであれば変換の必要もありません。
そこで、次のような方法を考えました。
・AudioProcessorValueTreeStateクラスのパラメータは「デシベル」で管理します。
・パラメータのラムダ式で「桁数」と「単位」を加工します。
・スライダークラスの「setSkewFactorFromMidPoint」関数でパラメータのスケーリングを行います。
APVTSクラスのパラメータの初期化と定義部分(PluginProcessor.cpp)は次のようにしました。
//前のパラメータ
std::make_unique<juce::AudioParameterFloat>("inputGain",
"InputGain",
juce::NormalisableRange<float>(-100.0f, 12.0f),//デシベルの範囲
0.0f,//初期値は0デシベルとします。
"input",
juce::AudioProcessorParameter::genericParameter,
[](float value, int) {return juce::String(value, 1) + " dB";}
),
//次のパラメータ
NormalisableRangeで「デシベル」の範囲を設定し、初期値も0としました。また、ここでのスケーリング計算はやめました。
最後の引数のラムダ式はそのまま利用しましたが、ここはすでにデシベルになっているので、value引数をそのまま、桁数をそろえて「db」を付けてreturnするという内容に変更しました。
そして、値のスケーリング、テキストボックス入力有効化の設定をスライダークラスの関数で行うように追加しました。(PluginEditor.cppのプラグイン本体クラスコンストラクタ内)
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);
今回のスライダーの値表示に関する調査で、次のような妄想をしました。
Logicなどで、オグジュアリのsendのスライダーなど、スライダーをドラッグして-2.9から-3.1に飛ぶなど0.1単位で微調整ができないようなものが時々あります。これは、おそらく、パラメータはゲイン値で変化していて、その表示を小数点1桁のデシベルに変換しているので、ゲイン値の変化の最小ステップ値の都合でゲイン値に飛ぶ値がでてくるのかなあ、という部分を想像しました。