【JUCEプラグイン開発】ディレイエフェクト、GUI画像の埋め込み、背景とスライダー画像の描画

パンダさん

まずはダイヤルスライダーの実装です。

コパンダ

以前やったことあるから、復習になるね~

JUCEでのディレイプラグイン作成の続きです。

今回記事にまとめた部分は、背景と、スライダーを画像にしてダイヤル化した点です。赤枠のような実装を進めていきます。

目次

こんな人の役に立つかも

・JUCEプラグイン開発をしている人

・JUCEでディレイプラグインを作成したい人

・JUCEでグラフィカルなGUIを作成したい人

デバッグをすぐできるための設定

getPlayHead関数は、DAW上で動作させていないとエラーになりますので、current_bpmを固定値にして、VisualStudioから直接実行できるようにして、いちいちDAWを開かなくても良いようにしました。

PluginProcessor.cppファイルのprepareToPlay関数

void TheDelayAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
{
//...略...
    if (tempopSyncState == true) {
        //以下の3行をコメントアウトしました。
        //playHead = this->getPlayHead();
        //playHead->getCurrentPosition(currentPositionInfo);

        //current_bpm = currentPositionInfo.bpm;

        //固定値を入れます。
        current_bpm = 120.0f;
//...略...

PluginProcessor.hファイルのtimerCallback関数

    void timerCallback() override
    {
        float val2 = 0;
        float val3 = 0;

        if(tempopSyncState == true){
            //同様の変更をおこないました。
            //playHead = this->getPlayHead();
            //playHead->getCurrentPosition(currentPositionInfo);
                        
            //current_bpm = currentPositionInfo.bpm;

            current_bpm = 120.0f;

プロジェクトへ画像を追加

Projucerのプロジェクトに前回準備した画像ファイルを配置しました。Projucerへの画像登録については、こちらの記事の方法と同様です。

これで

これで、JUCEプログラムからバイナリファイルとして画像を呼び出すことができるようになりました。注意点として、画像ファイルを移動させると画像が見つからなくなってしまうので、所定の場所を決めて画像を管理していくと良いと思います。私は、プロジェクトのSourceフォルダ内に配置するようにしています。

背景

背景画像は、paint関数内で画像を描画します。

void TheDelayAudioProcessorEditor::paint (juce::Graphics& g)
{
    g.fillAll (getLookAndFeel().findColour (juce::ResizableWindow::backgroundColourId));

    //追加しました。
    juce::Image background = juce::ImageCache::getFromMemory(BinaryData::Background_png, BinaryData::Background_pngSize);
    g.drawImageAt(background, 0, 0);
}

juce::ImageCacheのgetFromMemoryでバイナリデータを取得します。そして、graphicsクラスのdrawImageAt関数で画像の描画を行います。

ダイヤル

LookAndFeelクラスの作成

PluginEditor.hにカスタマイズしたLookAndFeelクラスを追加しました。このクラスは、以前までの記事をもとに、作成しました。基本的に、次のクラスを入れることで、画像をはめ込んだダイヤルの外観を作成することができますので、今後はコピペして追加していこうと思います。

class dialLookAndFeelStyle : public juce::LookAndFeel_V4
{
public:
    dialLookAndFeelStyle(){}

    void drawRotarySlider(juce::Graphics& g, int x, int y, int width, int height, float sliderPos,
        const float rotaryStartAngle, const float rotaryEndAngle, juce::Slider&) override
    {
        //[1]オフセットを0としています。
        int offset = 0;
        auto radius = (float)juce::jmin(width / 2, height / 2) - 4.0f;
        auto centreX = (float)x + (float)width * 0.5f;
        auto centreY = (float)y + (float)height * 0.5f;
        auto rx = centreX - radius + offset / 2;
        auto ry = centreY - radius + offset / 2;
        auto rw = radius * 2.0f - offset;
        auto angle = rotaryStartAngle + sliderPos * (rotaryEndAngle - rotaryStartAngle);

        juce::Image dial_top = juce::ImageCache::getFromMemory(BinaryData::Dial_png, BinaryData::Dial_pngSize);
        g.drawImageAt(dial_top, x, y);
        //[2]-32と32は今回の画像の半分の数値です。
        g.drawImageTransformed(dial_top, juce::AffineTransform::translation(-32, -32).rotated(angle).translated(32, 32));
    }
};

[1]のoffset変数は、ダイヤル画像の周りに余白などがある場合に利用しますので、今回は0としています。[2]では画像を回転させる際、左上の原点を中心で回転されます。そのため、画像の中心で回転するために、画像を左上に移動させる処理を行いますので、最初のtranslationの-32は画像の半分の大きさとします。画像は偶数値である必要がありますね。最後のtranslatedも回転後の画像をもとの領域に移動させるので、先ほどの移動の逆を行います。

そして、作成したクラスをAudioProcessorEditorクラスのprivateメンバとして定義しました。

class TheDelayAudioProcessorEditor  : public juce::AudioProcessorEditor
{
//...略...
    //追加しました。
    dialLookAndFeelStyle dialLookAndFeel;

    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TheDelayAudioProcessorEditor)
};

ダイヤルのLookAndFeelの設定

コンストラクタでスライダーの初期化を行います。

スライダー初期化で以下のプログラムを追記します。ダイヤル形式(Rotary)に設定、テキスト表示を非表示にして、ヘッダで追加したdialLookAndFeelクラスを紐づけました。

    //次の設定をコンストラクタ内に追加します。
    delayTimeLSlider.setSliderStyle(juce::Slider::Rotary);
    delayTimeLSlider.setTextBoxStyle(juce::Slider::NoTextBox, false, 0, 0);
    delayTimeLSlider.setLookAndFeel(&dialLookAndFeel);
    delayTimeRSlider.setSliderStyle(juce::Slider::Rotary);
    delayTimeRSlider.setTextBoxStyle(juce::Slider::NoTextBox, false, 0, 0);
    delayTimeRSlider.setLookAndFeel(&dialLookAndFeel);
    wetLevelSlider.setSliderStyle(juce::Slider::Rotary);
    wetLevelSlider.setTextBoxStyle(juce::Slider::NoTextBox, false, 0, 0);
    wetLevelSlider.setLookAndFeel(&dialLookAndFeel);
    feedbackSlider.setSliderStyle(juce::Slider::Rotary);
    feedbackSlider.setTextBoxStyle(juce::Slider::NoTextBox, false, 0, 0);
    feedbackSlider.setLookAndFeel(&dialLookAndFeel);

4つ分のスライダーの見た目をRotaryに、テキストを非表示に、setLookAndFeelで先ほど作成したメンバを紐づけます。

LookAndFeelはデストラクタでnullptrとする必要がありますので、次のプログラムを追加しました。

TheDelayAudioProcessorEditor::~TheDelayAudioProcessorEditor()
{
    delayTimeLSlider.setLookAndFeel(nullptr);
    delayTimeRSlider.setLookAndFeel(nullptr);
    wetLevelSlider.setLookAndFeel(nullptr);
    feedbackSlider.setLookAndFeel(nullptr);
}

最後に、スライダーの配置を調整しました。

void TheDelayAudioProcessorEditor::resized()
{
    delayTimeLSlider.setBounds(40, 65, 64, 64);
    delayTimeRSlider.setBounds(122, 65, 64, 64);
    wetLevelSlider.setBounds(208, 70, 64, 64);
    feedbackSlider.setBounds(287, 70, 64, 64);

//...略...
よかったらシェアしてね!
目次
閉じる