LoFiBeats・84分の作業用BGMを作成しました!

JUCEプログラミング、The AudioDeviceManager class、デモアプリの実装3

1_プログラミング

引き続きcppの実装です。長いです…

ひとつづつ、しっかり理解していこう~

こんな人の役に立つかも

・JUCEプログラミングを勉強している人

・JUCEのThe AudioDeviceManagerチュートリアルをしている人

スポンサーリンク

コンストラクタ

まずは、コンストラクタからです。次の内容に書き換えます。

MainComponent::MainComponent()
    //[1]メンバイニシャライザで初期化です。
    : audioSetupComp(deviceManager,
                        0,     // minimum input channels
                        256,   // maximum input channels
                        0,     // minimum output channels
                        256,   // maximum output channels
                        false, // ability to select midi inputs
                        false, // ability to select midi output device
                        false, // treat channels as stereo pairs
                        false) // hide advanced options
{
    //[2]audioSetupCompの可視化とdiagnosticsBoxの初期設定です。
    addAndMakeVisible(audioSetupComp);
    addAndMakeVisible(diagnosticsBox);

    diagnosticsBox.setMultiLine(true);
    diagnosticsBox.setReturnKeyStartsNewLine(true);
    diagnosticsBox.setReadOnly(true);
    diagnosticsBox.setScrollbarsShown(true);
    diagnosticsBox.setCaretVisible(false);
    diagnosticsBox.setPopupMenuEnabled(true);
    diagnosticsBox.setColour(juce::TextEditor::backgroundColourId, juce::Colour(0x32ffffff));
    diagnosticsBox.setColour(juce::TextEditor::outlineColourId, juce::Colour(0x1c000000));
    diagnosticsBox.setColour(juce::TextEditor::shadowColourId, juce::Colour(0x16000000));

    //[3]ラベル類の初期化です。
    cpuUsageLabel.setText("CPU Usage", juce::dontSendNotification);
    cpuUsageText.setJustificationType(juce::Justification::right);
    addAndMakeVisible(&cpuUsageLabel);
    addAndMakeVisible(&cpuUsageText);

    setSize(760, 360);

    setAudioChannels(2, 2);
    deviceManager.addChangeListener(this);

    startTimer(50);
//[4]タイマーをスタートさせます。
}

[1]では、AudioDeviceSelectorComponentクラスのインスタンス「audioSetupComp」の初期化を行います。

引数で、MIDIデバイスの入出力選択を可能にしたり、チャンネルをペアでまとめてステレオチャンネルとして選択できるような設定などがあります。今回は、チャンネル入出力を0~256までとした設定のみで、他の引数はfalseとして利用するようです。

[2]では、AudioDeviceSelectorComponentクラスのaudioSetupCompを可視化し、テキストエディタであるdiagnosticsBoxの設定を初期化しています。

「setMultiLine」関数で、テキストエディタを複数行表示にします。また、「setReturnKeyStartsNewLine」にtureを与えて、エディタの改行を有効にします。

次に、setReadOnlyで読み取り専用に、続けてsetScrollbarsShownでスクロールを有効にします。setCaretVisibleは、キャレット(入力時の位置を示すやつです)の表示を有効にするかどうかを設定します。今回は表示しない設定です。

setPopupMenuEnabledでは、右クリックのときに、コピーやペーストなどのメニューを表示するかどうかの設定をしています。trueなので、右クリックでメニューが表示されます。

右クリックで次のようにメニューが表示されます。

setColor関数では、テキストエディタの各部に色を設定できます。第一引数で、どの部分かを設定して、色を指定します。

[3]では、今まで勉強したように、ラベルを初期化しています。

[4]で、50msec毎に実行するタイマーを動作開始します。

デストラクタ

デストラクタではリスナーを取り除く処理を追加しています。

MainComponent::~MainComponent()
{
    deviceManager.removeChangeListener(this);//追加しました。
    shutdownAudio();
}

getNextAudioBlock関数

void MainComponent::getNextAudioBlock (const juce::AudioSourceChannelInfo& bufferToFill)
{
    //[1]チャンネル数取得部分です。
    auto* device = deviceManager.getCurrentAudioDevice();

    auto activeInputChannels = device->getActiveInputChannels();
    auto activeOutputChannels = device->getActiveOutputChannels();

    auto maxInputChannels = activeInputChannels.countNumberOfSetBits();
    auto maxOutputChannels = activeOutputChannels.countNumberOfSetBits();

    //[2]チャンネル数分の音声処理です。
    for (auto channel = 0; channel < maxOutputChannels; ++channel)
    {
        if ((!activeOutputChannels[channel]) || maxInputChannels == 0)
        {
            bufferToFill.buffer->clear(channel, bufferToFill.startSample, bufferToFill.numSamples);
        }
        else
        {
            auto actualInputChannel = channel % maxInputChannels;

            if (!activeInputChannels[channel])
            {
                bufferToFill.buffer->clear(channel, bufferToFill.startSample, bufferToFill.numSamples);
            }
            else
            {
               //[3]ここからが音声処理の内容です。
                auto* inBuffer = bufferToFill.buffer->getReadPointer(actualInputChannel,
                    bufferToFill.startSample);
                auto* outBuffer = bufferToFill.buffer->getWritePointer(channel, bufferToFill.startSample);
                //[4]ここでノイズを付け加えます。
                for (auto sample = 0; sample < bufferToFill.numSamples; ++sample)
                    outBuffer[sample] = inBuffer[sample] * random.nextFloat() * 0.25f;
            }
        }
    }
}

[1]では、音声デバイスのチャンネル数を取得する処理となります。以前、入力音声にホワイトノイズで変調するアプリを作成したときと全く同じ流れとなっています。

こちらの記事の「getNextAudioBlock関数での音声処理」の項目に内容を記載していますので、ご参照ください。

[2]では、取得したアクティブな入出力チャンネル数を取得しています。こちらも、入力音声のホワイトノイズ変調アプリの時と同様のエラー処理(バッファをクリアする処理)を入れています。

詳細はこちらの記事をご参照ください。

[3]からが、音声処理の内容になりますが、inBufferとoutBufferの取得についても先ほどの記事と同様です。

[4]では、randomクラスで取得した値と入力音声を掛け合わせて0.25にスケーリングしています。これもホワイトノイズ変調と同じことを行っています。実際に音声処理、という処理はこの点のみです。

入力音声をホワイトノイズ変調して出力しているだけですね~、以前のアプリと同じでした。

paint関数

paint関数を次のように書き換えます。

void MainComponent::paint (juce::Graphics& g)
{
    //以下の内容を追記しました。
    g.setColour(juce::Colours::grey);//[1]
    g.fillRect(getLocalBounds().removeFromRight(proportionOfWidth(0.4f)));//[2]
}

まずは[1]でgraphicsクラスで色をgreyに設定します。そして、removeFromRightは、指定したGUIの右側0.4の割合の領域をしていしています。removeFromRightは、返す値がrectangleクラスのオブジェクトで、右側の領域の矩形を返します。(自身は左の0.6の矩形となりますが、この後に利用していません。)この領域をgetLocalBoundsで指定して、fillRect関数で塗りつぶしています。塗りつぶすときの色が[1]のgreyになります。

音声処理は結構複雑で、いい復習になりました。ある意味、エラー処理のテンプレートとして理解していくのが良いのかもしれません。

次回は、このアプリ特有の関数について見ていきたいと思います。

タイトルとURLをコピーしました