【JUCEチュートリアル】Create a string model with delay lines、ディレイエフェクトの実装①、パラメータ編

パンダさん

空間系のあのエフェクトが実装できますね。

コパンダ

みんな大好きなディレイですね~

JUCEチュートリアルの「Create a string model with delay lines」を進めていきます。前回、リングバッファの仕組みを利用したディレイラインクラスを実装(?写経)して、その動作の仕組みを詳しく調査しました。今回は、ディレイラインを利用して、なじみのあるディレイエフェクトを実装していきます。

公式チュートリアルはこちらの「Incorporate a delay effect」の項目からになります。

※20211108追記

ディレイエフェクトに関するこちらにWebサイトを一読してから進めると、パラメータの理解度が上昇しました。

株式会社エー・アール・アイ様「ディレイ、エコー時間遅延処理系1/3」

目次

こんな人の役に立つかも

・JUCE「Create a string model with delay lines」チュートリアルを進めている人

・Projucerテンプレートで「Create a string model with delay lines」チュートリアルの実装を行なっていきたい人

・JUCEでディレイエフェクトを実装したい人

実装(パラメータ処理)

チュートリアルでは、すでにデモの段階で実装されている関数も含めて動作の説明が行われます。

パラメータについて

ディレイクラスのコンストラクタで、ディレイエフェクトに関連するパラメータの設定を行っています。これはすでにデモの段階で実装済みになっています。

    Delay()
    {
        setMaxDelayTime (2.0f);//[1]遅延の最大時間です。
        setDelayTime (0, 0.7f);//[2-1]0チャンネル目の遅延時間です。
        setDelayTime (1, 0.5f);//[2-2]1チャンネル目の遅延時間です。
        setWetLevel (0.8f);//[3]
        setFeedback (0.5f);//[4]
    }

//...略...

[1]のsetMaxDelayTime関数でディレイの最大の長さを設定します。これは、2秒を設定していて、後でサンプルレートと掛け合わせることで、サンプル数に変換されます。また、[2-1][2-2]では、ステレオのそれぞれのチャンネルで遅延時間を設定しています。setMaxDelay、setDelayTimeは後程実装する関数です。

[3]はディレイの音量を決めるウェットパラメータです。[4]は残業をどれだけ残すかの数値であるフィードバックパラメータです。setFeedbackとsetWetLevelは、既に定義されている次の関数で、privateなメンバ変数のfeedback変数とwetLevel変数に数値が格納されます。

パラメータは次の4つを利用します。

最大遅延時間:時間が長いほど、DelayLineクラスによるバッファを多く確保することになり、その分長い時間のディレイエフェクトを実現できます。

遅延時間:信号の遅延させる時間です。

ウェット:入力音量に重ね合わせる遅延信号の音量です。

フィードバック:バッファに音声データを保存する際に、入力音量と遅延音声を重ねて保存します。このときの遅延させる音声の音量になります。

入力音声に対して、Wetを掛け合わせた遅延音声が②のように足しこまれて出力されます。そして、その音声は、次の遅延音声となるので、①のようにFeedBackを掛け合わせた遅延音声と入力の音声が足しこまれてバッファに入ります。ポイントとしては、出力される遅延の音声音量と、バッファに保存される遅延の音声音量がそれぞれ違うという点で、それぞれWetとFeedbackというパラメータになっているというところです。

wetとfeedbackパラメータは、既に実装されている関数によってprivateなメンバ変数として保持されます。

//...略...
    void setFeedback (Type newValue) noexcept
    {
        jassert (newValue >= Type (0) && newValue <= Type (1));
        feedback = newValue;
    }

    void setWetLevel (Type newValue) noexcept
    {
        jassert (newValue >= Type (0) && newValue <= Type (1));
        wetLevel = newValue;
    }
//...略...

先ほど、関数内から、幾つかprivateメンバ変数が出てきましたので、わかりやすいように、ディレイクラスのprivateなメンバ変数を以下に貼り付けます。

private:
    //==============================================================================
    std::array<DelayLine<Type>, maxNumChannels> delayLines;
    std::array<size_t, maxNumChannels> delayTimesSample;//遅延時間をサンプル数で保持します。
    std::array<Type, maxNumChannels> delayTimes;//遅延時間を秒で保持します。
    Type feedback { Type (0) };
    Type wetLevel { Type (0) };

    std::array<juce::dsp::IIR::Filter<Type>, maxNumChannels> filters;
    typename juce::dsp::IIR::Coefficients<Type>::Ptr filterCoefs;

    Type sampleRate   { Type (44.1e3) };
    Type maxDelayTime { Type (2) };

遅延最大時間の設定関数

publicな関数、setMaxDelayTime関数です。引数として、秒数を受け取り、変数、maxDelayTimeに値を格納して、updateDelayLineSize関数を呼び出します。(この関数もすでにチュートリアルでは準備されています。)

    void setMaxDelayTime (Type newValue)
    {
        jassert (newValue > Type (0));
        maxDelayTime = newValue;
        updateDelayLineSize();
    }

次に、呼び出されている、Delayクラスのprivateなメンバ関数、updateDelayLineSize関数です。

この関数は、中身が空なので、実装する必要があります。

    void updateDelayLineSize()
    {
        //[1]最大遅延時間をサンプル数に変換します。
        auto delayLineSizeSamples = (size_t) std::ceil (maxDelayTime * sampleRate);

        //[2]各チャンネルのディレイラインのサイズを設定します。
        for (auto& dline : delayLines)
            dline.resize (delayLineSizeSamples);
    }

[1]では、秒数として与えられたmaxDelayTime変数をサンプルレートとかけることで、サンプル数に変換しています。std::ceilは切り上げの関数です。

先ほど貼り付けたprivateなメンバの中に、delayLinesがありますが、これが前回実装したディレイラインクラスをstd::array化しているものになります。チャンネル数分のディレイラインを確保しています。そして、[2]のようにして、範囲for文でそれぞれのディレイラインクラスのオブジェクトを取り出して最大のバッファサイズを設定しています。

遅延時間(ディレイタイム)の設定

次に、遅延時間のパラメータです。publicなsetDelayTime関数と、そこから呼び出されるprivateなupdateDelayTime関数の実装になります。

setDelayTime関数は、デモの段階で実装されています。ここでは、流れを追うために引用しています。第一引数にチャンネル番号、第二引数に遅延時間(秒)を取ります。そして、遅延時間のパラメータはprivateなメンバであるdelayTimes[channel]配列に格納されて、updateDelayTime関数が呼び出されます。

    void setDelayTime (size_t channel, Type newValue)
    {
        if (channel >= getNumChannels())
        {
            jassertfalse;
            return;
        }
 
        jassert (newValue >= Type (0));
        delayTimes[channel] = newValue;
 
        updateDelayTime();
    }

updateDelayTime関数はprivateな関数なので、Delayクラスの一番下部分にあります。遠いです。この関数も中身が空の状態なので、実装しました。

    void updateDelayTime() noexcept
    {
        for (size_t ch = 0; ch < maxNumChannels; ++ch)
            delayTimesSample[ch] = (size_t) juce::roundToInt (delayTimes[ch] * sampleRate);
    }

このfor文では、チャンネル数分繰り返し処理を行います。ここでは、遅延時間をサンプル数に変換して、privateなメンバであるdelayTimeSamplesに格納しています。

今回は、ディレイエフェクトのためのパラメータのところまでを進めました。ちょっと長くなってしまったので、次回は音声処理部分を見ていきたいと思います。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次