【JUCEチュートリアル】Add distortion through waveshaping and convolution、歪みを加える処理を実装する

パンダさん

歪みの効果で音作りが広がります。

コパンダ

歪みの作り方が具体的に実感できるよね〜

JUCEチュートリアル、DSPの「Add distortion through waveshaping and convolution」、「Integrate the Waveshaper」の項目を進めていきます。前回までに勉強したウェーブシェーピングを利用して、波形に歪みを加えていく実装になります。

公式のチュートリアルページはこちらになります。

今回の内容は、前回実装したプログラムを基本として実装していきます。前回のデモアプリの基本の実装記事はこちらをご参照ください。

デモアプリに歪みを加えることで、次のような音の変化となりました。そもそもデモアプリの音色がノイズ多くて気持ち悪いのですが^^;

ギターのディストーションみたいに歪んでいることがわかります。今回のチュートリアルは、歪ませて元の音色のアラを目立たなくする、ということでいいでしょうか・・・

目次

実装

PluginProcessor.hの空の状態のDistortionクラスに実装を行っていきます。

空のDistortionクラス

前回実装したでもアプリのPluginProcessor.hファイルに、次のような空の状態のDistortionクラスが準備されています。このクラスにウェーブシェーピングクラスによる歪みを追加していきます。

template <typename Type>
class Distortion
{
public:
    //==============================================================================
    Distortion() {}

    //==============================================================================
    void prepare(const juce::dsp::ProcessSpec& spec)
    {
        juce::ignoreUnused(spec);
    }

    //==============================================================================
    template <typename ProcessContext>
    void process(const ProcessContext& context) noexcept
    {
        juce::ignoreUnused(context);
    }

    //==============================================================================
    void reset() noexcept {}

private:
    //==============================================================================
};

Distortionクラスへの追加

まずは、Distortionクラスのprivateなメンバとして、ProcessorChainクラスのメンバ、processirChainと、そのインデックスに利用するenumを定義します。

private:
    //[1]enumの定義です。
    enum
    {
        waveshaperIndex
    };
    //[2]ProcessorChainクラスの定義です。
    juce::dsp::ProcessorChain<juce::dsp::WaveShaper<Type>> processorChain;
};

[2]のProcessorChainクラスは、今まで何度も利用している、DSPモジュールを数珠繋ぎできるような便利なクラスです。今回は、WaveShaperモジュールを1つだけ入れています。今回は数珠繋ぎにならず、単発でWaveShaperクラスを利用するのと同じですが、今後、ここにゲインなど、他のDSPモジュールの追加も簡単にできるようにprocessorChainクラスを利用しています。

次に、processorChainクラスをリセットします。reset関数に次のように追記しました。

    void reset() noexcept
    {
        processorChain.reset();
    }

prepare関数にも、次のようにprocessorCahinのprepareを呼び出します。

void prepare (const juce::dsp::ProcessSpec& spec)
{
    //juce::ignoreUnused(spec);//こちらは削除します。
    processorChain.prepare (spec);
}

そして、コンストラクタです。

public:
    //==============================================================================
    Distortion()
    {
        auto& waveshaper = processorChain.template get<waveshaperIndex>();//[1]
        //[2]waveshaperの関数を定義します。
        waveshaper.functionToUse = [] (Type x)
                                   {
                                       return juce::jlimit (Type (-0.1), Type (0.1), x);
                                   };
    }

[1]のように、get関数で、waveshaperモジュールのインデックス(enum)を指定して、waveshaperの参照を取得します。これで、processorChainクラス内のwaveshaperクラスのオブジェクトにアクセスできます。[2]では、waveshaperの関数を定義します。dsp::WaveShaperは構造体のテンプレートになります。このコンストラクタで定義しているように、functionToUseに入力信号に反映させる処理を定義します。ここでは、jlimt関数で、-0.1または0.1を越えた信号を強制的に切り落とします。

最後に、音声処理を行うprocess関数を変更します。processChainのprocess関数を入れ子で呼び出すのみです。

    template <typename ProcessContext>
    void process (const ProcessContext& context) noexcept
    {
        //juce::ignoreUnused(context);//こちらは削除します。
        processorChain.process (context);//追記します。
    }

例題

functionToUseで-0.1~0.1という範囲を超えた波形を削り取りました。チュートリアルのExerciseにある-0.5~0.5にした時の音の変化を見てみたいと思います。

波形が削り取られるゲインレベルに余裕ができたので、より元の波形に近くなりました。この部分の数値パラメータを小さくすることで、削り取られる波形の頭が大きくなり、歪んだ感じになり、大きくすることで、波形が原型に近くなり、歪みが少なくなります。パラメータ化すると、歪み量を調整できるようになりそうです。

Distortionクラス全体

今回のDistortionクラス全体のプログラムです。コピペなどしてご利用くださいませ。

template <typename Type>
class Distortion
{
public:
    Distortion()
    {
        auto& waveshaper = processorChain.template get<waveshaperIndex>();
        waveshaper.functionToUse = [](Type x)
        {
            return juce::jlimit(Type(-0.1), Type(0.1), x);
        };
    }

    void prepare(const juce::dsp::ProcessSpec& spec)
    {
        processorChain.prepare(spec);
    }

    template <typename ProcessContext>
    void process(const ProcessContext& context) noexcept
    {
        processorChain.process(context);
    }

    void reset() noexcept
    {
        processorChain.reset();
    }

private:
    enum
    {
        waveshaperIndex
    };

    juce::dsp::ProcessorChain<juce::dsp::WaveShaper<Type>> processorChain;
};
よかったらシェアしてね!
目次
閉じる