ディストーションとは?

ディストーションとは, クリッピング (音割れ) を意図的に発生させて歪ませた音色を生み出すエフェクトであり, ロックギターを象徴する音です.

広義のディストーションとは意図的な歪みの音色を生み出すエフェクトの総称です. ディストーションは, 歪みのレベルによって, 一般的に以下の4つに分類されます.

クランチ (Crunch)
クリーンサウンドを少し歪みませた音色. カッティングなどで利用される.
オーバードライブ (Overdrive)
バッキング・ギターソロなど様々なパートで利用される中程度の歪みの音色.
ディストーション (Distortion)
狭義のディストーションは, 深い歪みの音色でありギターソロで利用されることが多い.
ファズ (Fuzz)
最も深い歪みをもつ. ギターソロで利用されることが多い.

Web Audio APIを利用してディストーションを実装するには, 以下の3つの方法があります.

  • ScriptProcessorNodeで実装する
  • ConvolverNodeを利用して, アンプシミュレーターのオーディオファイルを畳み込む
  • WaveShaperNodeを利用する

ScriptProcessorNodeを利用する場合の実装は他の書籍やWebサイトに譲ることにします.

ConvolverNodeを利用する実装では, アンプシミュレーターのオーディオファイルが必要になりますが, リバーブの実装と同様のアルゴリズムでディストーションが実装可能です.

したがって, このセクションでは, WaveShaperNodeを利用したディストーションの実装について解説します.

ディストーション

Web Audio APIにおいて, ディストーション (歪み系エフェクト) を実装するには, WaveShaperNodeクラスを利用します. ディストーションは原音そのものを歪ませる必要があるので, インサート型のエフェクトです. また, LFOやフィードバックの接続が不要なので, ノード接続は非常にシンプルです.

ディストーションのノード接続

図2 - 7 - a. ディストーションのノード接続

ディストーションはエフェクト音のみの出力であるインサート型エフェクトです.

まずは, インスタンスを生成してノード接続を完成させます. WaveShaperNodeインスタンスの生成には, AudioContextインスタンスのcreateWaveShaperメソッドを利用します.

サンプルコード 01


window.AudioContext = window.AudioContext || window.webkitAudioContext;

// Create the instance of AudioContext
var context = new AudioContext();

// Create the instance of WaveShaperNode
var distortion = context.createWaveShaper();

// Create the instance of OscillatorNode
var oscillator = context.createOscillator();  // for Input

// for legacy browsers
oscillator.start = oscillator.start || oscillator.noteOn;
oscillator.stop  = oscillator.stop  || oscillator.noteOff;

// Connect nodes for effect (Distortion) sound
// OscillatorNode (Input) -> WaveShaperNode (Distortion) -> AudioDestinationNode (Output)
oscillator.connect(distortion);
distortion.connect(context.destination);

// Start sound
oscillator.start(0);

もっとも, コンプレッサーなどのようにノード接続をしただけでは, ディトーションサウンドは生成できません. WaveShaperNodeインスタンスには, curveプロパティが定義されており, curveプロパティに原音を歪ませるための配列 (Float32Array型) を設定することで, クランチ・オーバードライブ・ファズといったバリエーションのあるディストーションサウンドを生成することが可能です.

したがって, ディストーションの実装では, 原音を歪ませるための配列の生成が非常に重要となりますが, その詳細に関しては次のセクションで解説することにします. とりあえず, 原音を歪ませる配列の生成は, Stack Overflowで公開されているアルゴリズムを利用します.

サンプルコード 02


/**
 * This function creates the instance of Float32Array for curve property in WaveShaperNode.
 * @param {number} amount This argument is distortion level.
 * @param {number} numberOfSamples This argument is size of Float32Array.
 * @return {Float32Array|null} This is curve property in WaveShaperNode.
 */
var createCurve = function(amount, numberOfSamples) {
    if ((amount > 0) && (amount < 1)) {
        var curves = new Float32Array(numberOfSamples);

        var k = (2 * amount) / (1 - amount);

        for (var i = 0; i < numberOfSamples; i++) {
            // LINEAR INTERPOLATION: x := (c - a) * (z - y) / (b - a) + y
            // a = 0, b = 2048, z = 1, y = -1, c = i
            var x = (((i - 0) * (1 - (-1))) / (numberOfSamples - 0)) + (-1);
            curves[i] = ((1 + k) * x) / (1 + k * Math.abs(x));
        }

        return curves;
    } else {
        return null;  // Clean sound (default value)
    }
};

第1引数には, 歪みのレベルを0より大きく, 1より小さい数値型で指定します (それ以外の値の場合は, デフォルトの値であるnullを返すようにしています). 値が1に近づくほどより歪んだディストーションサウンドになります.

第2引数は, Float32Array型配列のサイズですが, これは知覚的には, ほとんど影響を与えないので, とりあえず, 使用例が多い4096に固定します (知覚的にほとんど影響を与えない要因は次のセクションで解説します).

サンプルコード 03


/*
 * Add code to sample code 01
 */

// ....

var NUM_SUMPLES = 4096;

/**
 * This function creates the instance of Float32Array for curve property in WaveShaperNode.
 * @param {number} amount This argument is distortion level.
 * @return {Float32Array|null} This is curve property in WaveShaperNode.
 */
var createCurve = function(amount) {
    if ((amount > 0) && (amount < 1)) {
        var curves = new Float32Array(NUM_SUMPLES);

        var k = (2 * amount) / (1 - amount);

        for (var i = 0; i < NUM_SUMPLES; i++) {
            // LINEAR INTERPOLATION: x := (c - a) * (z - y) / (b - a) + y
            // a = 0, b = 2048, z = 1, y = -1, c = i
            var x = (((i - 0) * (1 - (-1))) / (NUM_SUMPLES - 0)) + (-1);
            curves[i] = ((1 + k) * x) / (1 + k * Math.abs(x));
        }

        return curves;
    } else {
        return null;  // Clean sound (default value)
    }
};

var DISTORTIONS = {
    CRUNCH     : 0.5,
    OVERDRIVE  : 0.7,
    DISTORTION : 0.8,
    FUZZ       : 0.9
};

// Set curve
distortion.curve = createCurve(DISTORTIONS.OVERDRIVE);

以上でディストーションが完成しました. デモ 20・デモ 21では, ディストーションの原理を視覚的に理解できるように, 時間領域の波形描画も実装しています.

デモ 20 (サウンド)

デモ 21 (オーディオ)

ディストーションの原理

このセクションでは, ディストーションの原理, すなわち, WaveShaperNodeインスタンスのcurveプロパティについて解説します. とりあえず, ディストーションが実装できればOKという場合はスルーしてください.

curveプロパティとクリッピング

ディストーションの原理は, クリッピング (音割れ) を意図的に発生させて歪ませることと解説しました.

ディストーションの原理 - クリッピング -

図2 - 7 - b. ディストーションの原理 - クリッピング -

あるレベルの振幅で波形が切り取られる (クリップされる) ことに着目してください

WaveShaperNodeインスタンスのcurveプロパティとクリッピングの関係を図示すると図2 - 7 - cのようになります. グラフのX軸は入力の振幅を, Y軸は出力の振幅を表しています. また, 赤いラインがディストーションカーブを表しています. ここで, 入力の振幅が-0.5 〜 0.5までは, その出力も-0.5 〜 0.5に対応しています. この範囲ではクリッピングは発生しません (つまり, 原音のままの出力であるクリーンサウンドとなります).

入力の振幅が-1.0 〜 -0.5, 0.5 〜 1.0の振幅に対する出力は一律に-0.5, 0.5になります. これが, クリッピングを意味しており, これがディストーションカーブ (curveプロパティ) とディストーションの原理であるクリッピングの関係になります.

ディストーションカーブ (curveプロパティ) とクリッピングの関係

図2 - 7 - c. ディストーションカーブとクリッピングの関係

赤いラインがディストーションカーブ (curveプロパティ) です. このイラストのディストーションカーブの場合, 0.5以上の振幅は, 一律に0.5にクリッピングされて出力となります.

ディストーションカーブ

curveプロパティに設定する (Float32Array型の) 配列は, サンプルコード 02の関数で生成する配列である必要はありません. 単純に, ソフトクリッピング / ハードクリッピングさせるだけであれば手動で値を設定しても実装できます.

図2 - 7 - d. ディストーションカーブ
(ソフトクリッピング / ハードクリッピング)

サンプルコード 04


/*
 * Add code to sample code 01
 */

// ....

var softClipping = new Float32Array([-0.7875, -0.775, -0.75, -0.7, -0.6, -0.4, 0, 0.4, 0.6, 0.7, 0.75, 0.775, 0.7875]);
var hardClipping = new Float32Array([-0.8000, -0.800, -0.80, -0.8, -0.8, -0.8, 0, 0.8, 0.8, 0.8, 0.80, 0.800, 0.8000]);

しかしながら, よりよいディストーションサウンドを生成するためには, 数式から算出される規則的なカーブ形状になるようなFloat32Array型配列を設定する必要があります.

ちなみに, サンプルコード 02の関数で生成される配列はそのようなカーブとなります.

図2 - 7 - e. ディストーションカーブ

ディストーションカーブの補間

ところで, 生成するFloat32Array型配列のサイズが小さい場合, そのディストーションカーブは本来階段状の形状になるはずです. 例えば, 図2 - 7 - dのディストーションカーブは, 本来はカクカクした形状 (図2 - 7 - f) です.

図2 - 7 - f. ディストーションカーブ (補間なし)
(ソフトクリッピング / ハードクリッピング)

ところが, 実際に生成されるディストーションカーブは, 配列のサイズが小さくても, 図2 - 7 - dのように滑らかな形状となります. これは, WaveShaperNodeの仕様によるもので, (Float32Array型の) 配列サイズが小さい場合でも, 滑らかな曲線となるようにサンプル点を補間するように実装されているからです.

これが, (Float32Array型の) 配列サイズが異なっても, 知覚的にはほとんど影響を与えない要因です.

ディストーション まとめ

このページでは, ディストーションの実装と原理の概要を解説しました. そして, それらのエッセンスは, WaveShaperNodeインスタンスのcurveプロパティ, すなわち, ディストーションカーブの生成に集約されます.

インスタンス生成
createWaveShaperメソッド
ノード接続
インサート型
curveプロパティ (ディストーションカーブ)
  • Float32Array型配列を設定する
  • Float32Array型配列のサイズが小さい場合でも, 補間により滑らかなカーブとなる

ディストーションカーブ生成のアルゴリズムを試行錯誤することにより, オリジナルのディストーションサウンドを生成することが可能です. ディストーションにこだわりのある方は, ぜひこのアルゴリズムを発明して自分だけのディストーションサウンドを創造してみてください.