LとRでそれぞれのテンポシンクができるようになりました~
だんだん音楽的な利用ができるようになってきたね~
前回から大分経過してしまいました。
引き続き、ディレイプラグインの機能を追加していきたいと思います。
今回は、テンポシンクの機能をLとRそれぞれに設定できるようにしました。もともとがステレオディレイなのに、テンポシンク状態だとLとRが一緒になるのもあれですので^^;
機能追加をする毎に、GUIのごちゃごちゃが増えていく点は、ご了承くださいませ!
ディレイプラグインを作成する前回までの一連の記事は、こちらをご参照ください。
変更の概要
今回は、次の3段階の変更を行いました。
①APVTSのパラメータをもう一つ追加しました。
②コンボボックスをもう一つ追加しました。
③パラメータ更新処理を変更しました。
APVTSパラメータの追加
普通に、APVTSパラメータを追加します。プロセッサクラスのprovateなメンバに安直にも「delayNumerator2」という命名ルールも何もない変数を追加しております・・・(自分がわかればそれでよいか的な追加なのです><)
class TheDelayAudioProcessor : public juce::AudioProcessor, private juce::Timer
{
//...略...
private:
//...略...
std::atomic<float>* delayNumerator = nullptr;
std::atomic<float>* delayNumerator2 = nullptr;//[1]メンバを追加しました。
juce::AudioPlayHead* playHead;
juce::AudioPlayHead::CurrentPositionInfo currentPositionInfo;
double current_bpm = 0.0;
double previous_bpm = 0.0;
bool tempopSyncState = false;
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TheDelayAudioProcessor)
};
次に、パラメータの定義を行います。前回のコンボボックス用のパラメータ(すぐ上)のモノをコピペして、IDとnameだけを変更です。
std::make_unique<juce::AudioParameterInt>("delayNumerator",
"DelayNumerator",
1.0f,
4.0f,
3.0f)
,
//[2]APVTSパラメータを追加しました。
std::make_unique<juce::AudioParameterInt>( "delayNumerator2", // ID
"DelayNumerator2", // name
1.0f, // min
4.0f, // max
3.0f) // default
})
{
//...略...
delayNumerator = parameters.getRawParameterValue("delayNumerator");
//[3]パラメータを紐づけします。
delayNumerator2 = parameters.getRawParameterValue("delayNumerator2");
最後の[3]では、パラメータを先ほどのprivateなメンバ、delayNumerator2に紐づけています。
コンボボックスの追加
次に、GUI側です。エディタクラス側です。
[1]のように、コンボボックスのコンポーネントクラスと、アタッチメントを準備します。すでに一個コンボボックスを使用しているので、比較的楽に追加ができますね。
private:
//...略...
juce::ComboBox DelayNumerator;
std::unique_ptr<ComboBoxAttachment> DelayNumeratorAttachment;
//[1]コンボボックスとアタッチメントを追加します。
juce::ComboBox DelayNumerator2;
std::unique_ptr<ComboBoxAttachment> DelayNumeratorAttachment2;
//...略...
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TheDelayAudioProcessorEditor)
};
PluginEditor.cppのAudioProcessorEditorクラスのコンストラクタに、コンボボックスの初期化処理を追加しました。
これも、既に1個つくってあるコンボボックスの流用で簡単にできました。
//...略...
//[2]コンボボックスの初期化
addAndMakeVisible(DelayNumerator2);
DelayNumeratorAttachment2.reset(new ComboBoxAttachment(valueTreeState, "delayNumerator2", DelayNumerator2));
DelayNumerator2.addItem("Whole", 1);
DelayNumerator2.addItem("2", 2);
DelayNumerator2.addItem("4", 3);
DelayNumerator2.addItem("8", 4);
DelayNumerator2.setSelectedId(3);
DelayNumerator2.setSelectedId(*(vts.getRawParameterValue("delayNumerator2")));
//...略...
}
コンボボックスをGUIに配置するresized関数です。位置的に、前のコンボボックスの右に来るようにしました。また、コンボボックスの幅をそろえて、上にあるダイヤルと同じようにL、Rと並ぶようにしてみました。
void TheDelayAudioProcessorEditor::resized()
{
//...略...
DelayNumerator.setBounds(40, 220, 60, 30);
//[3]GUIに配置します。
DelayNumerator2.setBounds(110, 220, 60, 30);
//...略...
}
パラメータ更新処理の変更
タイマー処理内、または諸々の都合でprocessBlock関数内で行っているディレイパラメータの更新処理の内容を変更しました。今までは、val3という変数はval2のコピーでしたが、これを今回作成したコンボボックスの値から変更されるようにしました。
//...略...
float val2 = 0;
float val3 = 0;
if (tempopSyncState == true) {
playHead = this->getPlayHead();
playHead->getCurrentPosition(currentPositionInfo);
current_bpm = currentPositionInfo.bpm;
float selected_delayNum = *delayNumerator;
float delayNum = 0.0f;
if (selected_delayNum == 1.0f) {
delayNum = 1.0f;
}
else if (selected_delayNum == 2.0f) {
delayNum = 2.0f;
}
else if (selected_delayNum == 3.0f) {
delayNum = 4.0f;
}
else if (selected_delayNum == 4.0f) {
delayNum = 8.0f;
}
val2 = ((float)60.0 / current_bpm) * (4.0f / delayNum);
if (val2 >= 2.0f) {
val2 = 1.99f;
}
//[1]以下の処理を追加しました。
//val3 = val2;//以前の処理です。
selected_delayNum = *delayNumerator2;
delayNum = 0.0f;
if (selected_delayNum == 1.0f) {
delayNum = 1.0f;
}
else if (selected_delayNum == 2.0f) {
delayNum = 2.0f;
}
else if (selected_delayNum == 3.0f) {
delayNum = 4.0f;
}
else if (selected_delayNum == 4.0f) {
delayNum = 8.0f;
}
val3 = ((float)60.0 / current_bpm) * (4.0f / delayNum);
if (val3 >= 2.0f) {
val3 = 1.99f;
}
}
今後の課題点
ディレイの最大時間をもっと長くしたいと思います。また、ディレイの最大時間がいろいろなところで定義されているので、定数にしてまとめたいなという感じもしています。
次に、mac版では、timerによるパラメータ更新がうまくいかないので、仕方なくprocessBlock内で条件分岐を利用してしまっています。JUCEチュートリアルによると、ビット演算を利用した条件の判定を行う方法がありましたので、随時そちらも勉強して、この部分を改良していきたいなと思いました。