トレモロ・リングモジュレーターとは?

トレモロは音の大きさに揺らぎを与えるエフェクトです. ちなみに, ギターでは素早く (オルタネイト) ピッキングを繰り返すことで, 音が震えているように奏でるトレモロ奏法があります. トレモロは, トレモロ奏法を音信号処理によって実現するエフェクトとも言えます.

ギターでは, もう1つトレモロという名称がついているものがあります. ストラトキャスター (タイプ) のギターに搭載されているトレモロアームです. しかしながら, トレモロアームはビブラートの効果を与えるものなので, 同じトレモロという名称ですが, 別ものなのでご注意ください.

リングモジュレーターは金属的な音色に変化させるエフェクトです. 例として, ピアノにリングモジュレーターをかけると, 鐘のような音色に変化します.

エフェクトとして, トレモロとリングモジュレーターはかなり感じが違いますが, 原理は共通しています. その原理とは, AM変調を利用したエフェクトであることです.

AM変調に関してはのちほど解説することにして, まずは実装の解説からします.

トレモロ

トレモロは振幅 (音の大きさ) を周期的に変化させることによって, 実装することができます. すなわち, LFOをAudioParamインスタンスであるGainNodeインスタンスのgainプロパティに接続することによって, 音の大きさ (振幅) を周期的に変化させることができます.

ちなみに, トレモロはインサート型のエフェクトであり, 出力される音はエフェクト音のみです. トレモロの実装は以下の2つ処理に分解可能となります.

振幅 (音の大きさ) を周期的に変化させる
LFOをAudioParamインスタンスであるGainNodeインスタンスのgainプロパティに接続する
エフェクト音のみを出力する
入力ノードと出力ノード (AudioDestinationNode) の間に, トレモロのためのGainNodeを接続する

サンプルコード 01


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

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

// for legacy browsers
context.createDelay = context.createDelay || context.createDelayNode;

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

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

// for legacy browsers
context.createGain = context.createGain || context.createGainNode;

// Create the instance of GainNode
var amplitude = context.createGain();  // for Tremolo
var depth     = context.createGain();  // for LFO

// Connect nodes for effect (Tremolo) sound
// OscillatorNode (Input) -> GainNode (Amplitude) -> AudioDestinationNode (Output)
oscillator.connect(amplitude);
amplitude.connect(context.destination);

// Connect nodes for LFO that changes Amplitude periodically
// OscillatorNode (LFO) -> GainNode (Depth) -> gain (GainNode)
lfo.connect(depth);
depth.connect(amplitude.gain);

トレモロのノード接続

図2 - 5 - a. トレモロのノード接続

トレモロはエフェクト音のみを出力するインサート型エフェクトです.

トレモロは, 1を基準に値が変化するように定義されています (図2 - 5 - b). そして, その基準値をもとにゲイン (GainNodeインスタンスのgainプロパティ) が負数にならないように, LFOのDepthの範囲は0 〜 1となります.

a(n) = 1 + depth \cdot \sin \left(\frac{2{\pi} \cdot rate \cdot n}{f_s}\right)

図2 - 5 - b. トレモロの定義

サンプルコード 02


/*
 * Add code to sample code 01
 */

// ....

// Set Base Value
amplitude.gain.value = 1;  // 1 +- Depth

// Set Depth
depth.gain.value = 0.5;  // 1 +- 0.5

// Set Rate
lfo.frequency.value = 5;  // 5 Hz

ところで, トレモロのようなインサート型エフェクトの場合, センド・リターン型エフェクトのように, エフェクトのON / OFFの切り替えにおいて, エフェクト音の調整のためのGainNodeをコントロールすることによって, 原音のみを出力するという方法が使えません (インサート型は, エフェクト音のみの出力であるからです).

したがって, エフェクトのON / OFFの切り替えに応じて, ノード接続を変更する必要があります.

サンプルコード 03


/*
 * sample code 01
 */

// ....

// Clear connection
oscillator.disconnect(0);
amplitude.disconnect(0);

var toggleButton = document.createElement('input');

toggleButton.setAttribute('type',    'checkbox');
toggleButton.setAttribute('checked', 'checked');

document.body.appendChild(toggleButton);

if (toggleButton.checked) {
    // Tremolo ON

    // Connect nodes for effect (Tremolo) sound
    // OscillatorNode (Input) -> GainNode (Amplitude) -> AudioDestinationNode (Output)
    oscillator.connect(amplitude);
    amplitude.connect(context.destination);
} else {
    // Tremolo OFF

    // Connect nodes for original sound
    // OscillatorNode (Input) -> AudioDestinationNode (Output)
    oscillator.connect(context.destination);
}

最後にまとめのコードを記載します.

サンプルコード 04


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

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

// for legacy browsers
context.createDelay = context.createDelay || context.createDelayNode;

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

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

// for legacy browsers
context.createGain = context.createGain || context.createGainNode;

// Create the instance of GainNode
var amplitude = context.createGain();  // for Tremolo
var depth     = context.createGain();  // for LFO

// Clear connection
oscillator.disconnect(0);
amplitude.disconnect(0);

var toggleButton = document.createElement('input');

toggleButton.setAttribute('type',    'checkbox');
toggleButton.setAttribute('checked', 'checked');

document.body.appendChild(toggleButton);

if (toggleButton.checked) {
    // Tremolo ON

    // Connect nodes for effect (Tremolo) sound
    // OscillatorNode (Input) -> GainNode (Amplitude) -> AudioDestinationNode (Output)
    oscillator.connect(amplitude);
    amplitude.connect(context.destination);
} else {
    // Tremolo OFF

    // Connect nodes for original sound
    // OscillatorNode (Input) -> AudioDestinationNode (Output)
    oscillator.connect(context.destination);
}

// Connect nodes for LFO that changes Amplitude periodically
// OscillatorNode (LFO) -> GainNode (Depth) -> gain (GainNode)
lfo.connect(depth);
depth.connect(amplitude.gain);

// Set Base Value
amplitude.gain.value = 1;  // 1 +- Depth

// Set Depth
depth.gain.value = 0.5;  // 1 +- 0.5

// Set Rate
lfo.frequency.value = 5;  // 5 Hz

// Start sound
oscillator.start(0);

// Effector (Tremolo) ON
lfo.start(0);

トレモロのノード接続 (切り替え)

図2 - 5 - c. トレモロのノード接続 (切り替え)

トレモロのようなインサート型のエフェクトでは, ノード接続を切り替えることで, エフェクトのON / OFFを切り替えます.

以上でトレモロが完成しました. さっそく, デモ 12・デモ 13で試してみてください. 基本となるLFOのDepth / Rateに追加して, LFOの波形タイプも設定可能にしました. これらのパラメータを組み合わせてお好みのトレモロを発見してください.

デモ 12 (サウンド)

デモ 13 (オーディオ)

リングモジュレーター

リングモジュレーターの実装 (ノード接続) は, トレモロと同じです. 設定するパラメータの違いが, トレモロとは異なるエフェクトを生み出しています. パラメータの相違点は以下の2つです.

ゲインの基準値
リングモジュレーターは, 0を基準に値が変化するように定義されている
LFOのRate
リングモジュレーターは, 1000 Hz前後の高い周波数に設定する
リングモジュレーターのノード接続

図2 - 5 - d. リングモジュレーターのノード接続

リングモジュレーターは, トレモロと同じく, エフェクト音のみの出力であるインサート型エフェクトです. トレモロとノード接続は同じですが, パラメータの違いに着目してください.

a(n) = depth \cdot \sin \left(\frac{2{\pi} \cdot rate \cdot n}{f_s}\right)

図2 - 5 - e. リングモジュレーターの定義

ところで, 基準値を0にした場合, LFOのDepthの範囲はどうすればいいのでしょうか?結論としては, トレモロと同じ, 0 〜 1の範囲で問題ありません. なぜなら, GainNodeインスタンスのgainプロパティは, 負数を設定すると, 位相が反転すると仕様では定義されています. つまり, GainNodeインスタンスのgainプロパティは設定された値の絶対値をとるように定義されているわけです. 例えば, -0.5を設定しても, 0.5を設定しても, その絶対値である0.5として扱われるということです.

それでは, トレモロの実装をもとに, リングモジュレーターを実装します.

サンプルコード 05


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

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

// for legacy browsers
context.createDelay = context.createDelay || context.createDelayNode;

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

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

// for legacy browsers
context.createGain = context.createGain || context.createGainNode;

// Create the instance of GainNode
var amplitude = context.createGain();  // for Ring Modulator
var depth     = context.createGain();  // for LFO

// Clear connection
oscillator.disconnect(0);
amplitude.disconnect(0);

var toggleButton = document.createElement('input');

toggleButton.setAttribute('type',    'checkbox');
toggleButton.setAttribute('checked', 'checked');

document.body.appendChild(toggleButton);

if (toggleButton.checked) {
    // Ring Modulator ON

    // Connect nodes for effect (Ring Modulator) sound
    // OscillatorNode (Input) -> GainNode (Amplitude) -> AudioDestinationNode (Output)
    oscillator.connect(amplitude);
    amplitude.connect(context.destination);
} else {
    // Ring Modulator OFF

    // Connect nodes for original sound
    // OscillatorNode (Input) -> AudioDestinationNode (Output)
    oscillator.connect(context.destination);
}

// Connect nodes for LFO that changes Amplitude periodically
// OscillatorNode (LFO) -> GainNode (Depth) -> gain (GainNode)
lfo.connect(depth);
depth.connect(amplitude.gain);

// Set Base Value
amplitude.gain.value = 0;  // 0 +- Depth

// Set Depth
depth.gain.value = 0.5;  // 0 +- 0.5

// Set Rate
lfo.frequency.value = 1000;  // 1000 Hz

// Start sound
oscillator.start(0);

// Effector (Ring Modulator) ON
lfo.start(0);

ほとんどトレモロのコードをコピペしたようなものですね.

ちなみに, リングモジュレーターもインサート型エフェクトなので, エフェクトのON / OFFの切り替えに応じて, ノード接続を変更しています.

リングモジュレーターのノード接続 (切り替え)

図2 - 5 - f. リングモジュレーターのノード接続 (切り替え)

リングモジュレーターのようなインサート型のエフェクトでは, ノード接続を切り替えることによって, エフェクトのON / OFFを切り替えます.

以上でリングモジュレーターが完成しました. さっそく, デモ 14・デモ 15で試してみてください. LFOのDepth / Rateを組み合わせてお好みのリングモジュレーターを発見してください.

デモ 14 (サウンド)

デモ 15 (オーディオ)

AM変調

このセクションでは, トレモロ・リングモジュレーターの原理について簡単に解説しておきます. といっても, 既に解説しているように, 振幅 (音の大きさ) を周期的に変化させることが原理です.

専門的な用語で表現すれば, トレモロ・リングモジュレーターはAM変調が原理となっています (AMとは, Amplitude Modulationの略です). 日本語に翻訳すると振幅変調ということになります.

例えば, 正弦波 (sin波) をAM変調すると図2 - 5 - gのようになります. 時間の経過とともに, 振幅が変化していることに着目してみてください.

AM変調

図2 - 5 - g. AM変調 (LFOの周波数が低い場合)

図2 - 5 - gのようなAM変調をかけた波形は, LFOの周波数 (Rate) が低い, つまり, トレモロをかけた場合の波形です. リングモジュレーターのように, LFOの周波数 (Rate) を高くすると, 図2 - 5 - hのような波形になります.

AM変調 (LFOの周波数が高い場合)

図2 - 5 - h. AM変調 (LFOの周波数が高い場合)

おもしろいことに, LFOの周波数を高くしてAM変調 (リングモジュレーター) をかけると, その振幅エンベロープがもう1つの波形を表すように見えてきます.

トレモロ・リングモジュレーター まとめ

このページでは, トレモロ・リングモジュレーターの実装と原理の概要を解説しました. そのエッセンスをまとめておきます.

表2 - 5 - a. ノード接続
EffectorConnection
トレモロ
エフェクト音 (インサート型エフェクト)
入力ノード + Amplitude (GainNode) + AudioDestinationNode
LFO
OscillatorNode + Depth (GainNode) + gain (GainNode)
ゲイン (GainNodeインスタンスのgainプロパティ) の基準値は1
リングモジュレーター
エフェクト音 (インサート型エフェクト)
入力ノード + Amplitude (GainNode) + AudioDestinationNode
LFO
OscillatorNode + Depth (GainNode) + gain (GainNode)
ゲイン (GainNodeインスタンスのgainプロパティ) の基準値は0
LFOの周波数 (Rate) は1000 Hz前後に設定する

そして, トレモロ・リングモジュレーターの原理は, 振幅を時間経過とともに周期的に変化させるAM変調です.