チュートリアルのエクササイズにLとR別々に音量変更というものがあったので、これをやってみました。
知識の再確認と練習ですね。
JUCEのチュートリアル、Synthの項目の、「Control audio levels」をやっています。
チュートリアルのエクササイズとして、LとR別々のスライダーでそれぞれの音量変更をせよ、というものがありましたので、シンプルにスライダーを増やしてみました。
こんな人の役に立つかも
・JUCEフレームワークに入門したい人
・JUCEで音声プログラミングを学びたい人
・JUCEのSynth、「Control audio levels」チュートリアルを進めている人
MainComponent.h
まずは、ヘッダーファイルからです。ヘッダファイルにスライダーとラベルを追加しました。単純に2としたものを追加しただけです^^;
private:
juce::Slider levelSlider;
juce::Label levelLabel;
//↓
juce::Slider levelSlider2;
juce::Label levelLabel2;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainComponent)
};
ここだけで大項目を使うのは少し罪悪感です・・・
MainComponent.cpp
コンストラクタ
コンストラクタでは、「levelSlider2」と「levelLabel2」の初期化を行います。また、GUIでの可視化設定をします。
MainComponent::MainComponent()
{
levelSlider.setRange(0.0, 0.25);
levelSlider.setTextBoxStyle(juce::Slider::TextBoxRight, false, 100, 20);
levelLabel.setText("L", juce::dontSendNotification);
//↓スライダー2とラベル2の追加です。
levelSlider2.setRange(0.0, 0.25);
levelSlider2.setTextBoxStyle(juce::Slider::TextBoxRight, false, 100, 20);
levelLabel2.setText("R", juce::dontSendNotification);
addAndMakeVisible(levelSlider);
addAndMakeVisible(levelLabel);
//↓ここでGUI可視化を行います。
addAndMakeVisible(levelSlider2);
addAndMakeVisible(levelLabel2);
setSize(600, 100);
setAudioChannels(0, 2);
}
getNextAudioBlock関数
次に、getNextAudioBlock関数を変更しました。
今までは、ループで「channel=0」と「channel=1」とLRのチャンネルをループで指定していましたが、今回は、LチャンネルとRチャンネルを別々に記載してみました。
void MainComponent::getNextAudioBlock (const juce::AudioSourceChannelInfo& bufferToFill)
{
auto level = (float)levelSlider.getValue();
auto level2 = (float)levelSlider2.getValue();//[1]levelSlider2の値を取得します。
//[2]channnel0(Lチャンネル)の処理です。
auto* buffer = bufferToFill.buffer->getWritePointer(0, bufferToFill.startSample);
for (auto sample = 0; sample < bufferToFill.numSamples; ++sample)
{
auto noise = random.nextFloat() * 2.0f - 1.0f;
buffer[sample] = noise * level;
}
//[3]channnel1(Rチャンネル)の処理です。
auto* buffer2 = bufferToFill.buffer->getWritePointer(1, bufferToFill.startSample);
for (auto sample = 0; sample < bufferToFill.numSamples; ++sample)
{
auto noise2 = random.nextFloat() * 2.0f - 1.0f;
buffer2[sample] = noise2 * level2;
}
}
[1]で、levelSlider2の値を取得しています。
[2]と[3]は処理内容として同様のものですが、バッファーのチャンネルが違います。bufferToFill.bufferの「getWriterPointer」関数で、0チャンネルを取得したものがbuffer変数、1チャンネルを取得してきたものがbuffer2として、それぞれ音声バッファを取得してきています。
[2]と[3]でそれぞれのバッファサンプルすべてに対して、ランダムな値を書き込んでいます。
[2]と[3]のforループは、おなじものなので、同じforループにいれてしまっても大丈夫です。今回は、順番に見やすさを重視しましたので、それぞれ別々に書きました。少しだけ変更すると、次のようになりました。こちらの方が、データの流れとしてはわかりやすく、いろいろと応用するときも処理しやすいかもしれません。
//バッファーの取得。
auto* buffer = bufferToFill.buffer->getWritePointer(0, bufferToFill.startSample);
auto* buffer2 = bufferToFill.buffer->getWritePointer(1, bufferToFill.startSample);
for (auto sample = 0; sample < bufferToFill.numSamples; ++sample)
{
//Lチャンネルの処理
auto noise = random.nextFloat() * 2.0f - 1.0f;
buffer[sample] = noise * level;
//Rチャンネルの処理
auto noise2 = random.nextFloat() * 2.0f - 1.0f;
buffer2[sample] = noise2 * level2;
}
※後から気づいたのですが、音声処理の内容は、かけ算が一つ多い、工夫されていないほうの計算方法でやっていました^^;
resized関数
最後に、「levelSlider2」と「levelLabel2」をウィンドウに配置していきます。
void MainComponent::resized()
{
levelLabel.setBounds(10, 10, 90, 20);
levelSlider.setBounds(100, 10, getWidth() - 110, 20);
//↓GUIにスライダー2を追加です。
levelLabel2.setBounds(10, 40, 90, 20);
levelSlider2.setBounds(100, 40, getWidth() - 110, 20);
}
動作
このように、LとRのチャンネルのホワイトノイズ音量を個別で変更できるようになりました。
プログラム的には、配列で処理したり、もっとやり方はあると思いますが、今回は一番シンプルなパターンですね。