[ Jpn | Eng ]

Main Menu



Recent

最近の記事

Search

サイト内検索:

Archive

Powered by
MTOS 5.2.2


g200kg > Web Audio API 解説 > 13.ディレイの使い方

Web Audio API 解説

2016/11/14

13.ディレイの使い方



ディレイエフェクトとしての使い方

Web Audio API の DelayNode はいわゆるエフェクターの「ディレイ」として完成されたものではなく、単に信号を指定の時間遅らせるだけのものでパラメータも遅らせる時間「delayTime」が1つあるだけです。まとまったエフェクトとしての「ディレイ」にするためには少なくとも元の音とミックスしたりフィードバックをかけたりと外部で接続をする必要があります。

一般的なエフェクターのディレイとして使用する場合、下の図のような構成が考えられます。入力出力に複数の信号が通っているので、モジュールとしてまとめるのならさらに入口/出口にノードを追加した方が良いかも知れません。


<!DOCTYPE html>
<html>
<head></head>
<body>
<h1>Delay Test</h1>
<img src="../images/delay1.png"/><br/>
<button onclick="Play()">Play</button><br/>
<button onclick="Stop()">Stop</button><br/>
<table>
<tr><td>Bypass :</td><td><input id="bypass" type="checkbox" onchange="Setup()"/></td></tr>
<tr><td>Time : </td><td><input type="text" size="8" id="time" value="0.25" onchange="Setup()"/></td></tr>
<tr><td>Feedback : </td><td><input type="text" size="8" id="feedback" value="0.4" onchange="Setup()"/></td></tr>
<tr><td>Mix : </td><td><input type="text" size="8" id="mix" value="0.4" onchange="Setup()"/></td></tr>
</table>
<script type="text/javascript">

window.AudioContext = window.webkitAudioContext||window.AudioContext;
var audioctx = new AudioContext();

var buffer = null;
LoadSample(audioctx, "./loop.wav");
var src = null;
var input = audioctx.createGain();
var delay = audioctx.createDelay();
var wetlevel = audioctx.createGain();
var drylevel = audioctx.createGain();
var feedback = audioctx.createGain();
input.connect(delay);
input.connect(drylevel);
delay.connect(wetlevel);
delay.connect(feedback);
feedback.connect(delay);
wetlevel.connect(audioctx.destination);
drylevel.connect(audioctx.destination);

function Stop() {
	if(src) src.stop();
	src = null;
}

function Play() {
	if(src === null) {
		src = audioctx.createBufferSource();
		src.buffer = buffer;
		src.loop = true;
		src.connect(input);
		src.start();
	}
}

function LoadSample(ctx, url) {
	var req = new XMLHttpRequest();
	req.open("GET", url, true);
	req.responseType = "arraybuffer";
	req.onload = function () {
		if(req.response) {
			ctx.decodeAudioData(req.response).then(function(b){buffer=b;},function(){});
		}
	}
	req.send();
}

function Setup() {
	var bypass = document.getElementById("bypass").checked;
	delay.delayTime.value = parseFloat(document.getElementById("time").value);
	feedback.gain.value = parseFloat(document.getElementById("feedback").value);
	var mix = parseFloat(document.getElementById("mix").value);
	if(bypass)
		mix = 0;
	wetlevel.gain.value = mix;
	drylevel.gain.value = 1 - mix;
}
Setup();

</script>
</body>
</html>
テストページ:ディレイ

ピンポンディレイへの応用

DelayNode に最初からこれくらいの機能を付けておいても良いのに...と思うかも知れませんが、パラメータが delayTime 1つだけという潔さからは、これは単体でエフェクターとして使うんじゃなくてエフェクターを組み立てる部品として使うのだ、という意図が見える気がします。

例えば ChannelSplitter/ChannelMerger と組み合わせてステレオピンポンディレイなんかも組み立てられます。

この例では ChannelSplitter でLRを分けて片方をずらし、ChannelMerger でまとめたものを二段目の delay の入力としています。構成がややこしそうに見えますが、前述の普通のディレイの前に片チャンネルだけのディレイを追加してあるだけです。

ノードの数はこの方が少なくてすみそうですが、LR分離したまま別ルートで処理する方法もあります。L<=>R間でマトリックスさせたり構成の方法はまだまだありそうです。


<!DOCTYPE html>
<html>
<head></head>
<body>
<h1>Delay (PingPong) Test</h1>
<img src="../images/delay2.png"/><br/>
<button onclick="Play()">Play</button><br/>
<button onclick="Stop()">Stop</button><br/>
<table>
<tr><td>Bypass</td><td><input type="checkbox" id="bypass"/></td></tr>
<tr><td>Time</td><td><input type="text" size="8" id="time" value="0.25" onchange="Setup()"/></td></tr>
<tr><td>Feedback</td><td><input type="text" size="8" id="feedback" value="0.1" onchange="Setup()"/></td></tr>
<tr><td>Mix</td><td><input type="text" size="8" id="mix" value="0.5" onchange="Setup()"/></td></tr>
</table>
<script type="text/javascript">

window.AudioContext = window.webkitAudioContext||window.AudioContext;
var audioctx = new AudioContext();

var buffer = null;
LoadSample(audioctx, "./loop.wav");
var src = null;
var input = audioctx.createGain();
var splitter = audioctx.createChannelSplitter();
var predelay = audioctx.createDelay();
var merger = audioctx.createChannelMerger();
var delay = audioctx.createDelay();
var wetlevel = audioctx.createGain();
var drylevel = audioctx.createGain();
var feedback = audioctx.createGain();
input.connect(splitter);
input.connect(drylevel);
splitter.connect(predelay,0);
predelay.connect(merger,0,0);
splitter.connect(merger,1,1);
merger.connect(delay);
delay.connect(wetlevel);
delay.connect(feedback);
feedback.connect(delay);
wetlevel.connect(audioctx.destination);
drylevel.connect(audioctx.destination);

function Stop() {
	if(src) src.stop();
	src = null;
}

function Play() {
	if(src == null) {
		src = audioctx.createBufferSource();
		src.buffer = buffer;
		src.loop = true;
		src.connect(input);
		src.start();
	}
}

function LoadSample(ctx, url) {
	var req = new XMLHttpRequest();
	req.open("GET", url, true);
	req.responseType = "arraybuffer";
	req.onload = function () {
		if(req.response) {
			ctx.decodeAudioData(req.response).then(function(b){buffer=b;},function(){});
		}
	}
	req.send();
}

function Setup() {
	var bypass=document.getElementById("bypass").checked;
	var timeval = parseFloat(document.getElementById("time").value);
	var fbval = parseFloat(document.getElementById("feedback").value);
	var mixval = parseFloat(document.getElementById("mix").value);
	if(bypass)
		mixval = 0;
	delay.delayTime.value = timeval*2;
	predelay.delayTime.value = timeval;
	wetlevel.gain.value = mixval;
	drylevel.gain.value = 1 - mixval;
	feedback.gain.value = fbval;
}
Setup();

</script>
</body>
</html>
テストページ:ピンポンディレイ

更なる応用

ここまではあくまでも「ディレイ」としての応用ですが、少し違った使い方も可能です。次の例は delayTime にオシレータからの変調をかけて「コーラス」を作っています。delayTime.value は 0.01 (=10mSec)を中心としてオシレーター(LFO)から揺らせ、元音と混ぜることでいわゆる「コーラスエフェクト」が発生します。


<!DOCTYPE html>
<html>
<head>
<style type="text/css">
input {
  margin:0px;
  padding:5px;
}
button {
  width:80px;
}
</style>
</head>
<body>
<h1>Chorus Test</h1>
<img src="../images/chorus.png"/><br/>
Status : <span id="status">Loading...</span><br/>
<button onclick="Play()">Play</button><br/>
<button onclick="Stop()">Stop</button><br/>
<table>
<tr><td>Bypass</td><td><input type="checkbox" id="bypass" onchange="Setup()"/></td></tr>
<tr><td>Speed</td><td><input type="range" min="0.1" max="10" step="0.1" size="8" id="speed" value="4" onchange="Setup()"/></td><td><div id="speedlabel"></div></td></tr>
<tr><td>Depth</td><td><input type="range" min="0.000" max="0.005" step="0.0001" size="8" id="depth" value="0.001" onchange="Setup()"/></td><td><div id="depthlabel"></div></td></tr>
<tr><td>Mix</td><td><input type="range" min="0" max="1" step="0.01" size="8" id="mix" value="0.6" onchange="Setup()"/></td><td><div id="mixlabel"></div></td></tr>
<tr><td>Output</td><td><input type="range" min="0" max="1" step="0.01" size="8" id="output" value="0.8" onchange="Setup()"/></td><td><div id="outputlabel"></div></td></tr>
</table>
<script type="text/javascript">

window.AudioContext = window.webkitAudioContext||window.AudioContext;
var audioctx = new AudioContext();

var buffer = null;
LoadSample(audioctx, "./loop.wav");
var src = null;
var lfo = audioctx.createOscillator();
var depth = audioctx.createGain();
var input = audioctx.createGain();
var delay = audioctx.createDelay();
var mix = audioctx.createGain();
var output = audioctx.createGain();

input.connect(delay);
input.connect(output);
lfo.connect(depth);
depth.connect(delay.delayTime);
delay.connect(mix);
mix.connect(output);
output.connect(audioctx.destination);

function Stop() {
	if(src) src.stop();
	src = null;
}

function Play() {
	if(src === null) {
		lfo.start(0);
		src = audioctx.createBufferSource();
		src.buffer = buffer;
		src.loop = true;
		src.connect(input);
		src.start();
	}
}

function LoadSample(ctx, url) {
	var req = new XMLHttpRequest();
	req.open("GET", url, true);
	req.responseType = "arraybuffer";
	req.onload = function () {
		document.getElementById("status").innerHTML = "Ready";
		if(req.response) {
			ctx.decodeAudioData(req.response).then(function(b){buffer=b;},function(){});
		}
	}
	req.send();
}

function Setup() {
	var bypass = document.getElementById("bypass").checked;
	var speedval = parseFloat(document.getElementById("speed").value);
	var depthval = parseFloat(document.getElementById("depth").value);
	var mixval = parseFloat(document.getElementById("mix").value);
	var outputval = parseFloat(document.getElementById("output").value);
	if(bypass) {
		mixval = 0;
		outputval = 1;
	}
	delay.delayTime.value = 0.01;
	lfo.frequency.value = document.getElementById("speedlabel").innerHTML = speedval;
	depth.gain.value = document.getElementById("depthlabel").innerHTML = depthval;
	mix.gain.value = document.getElementById("mixlabel").innerHTML = mixval;
	output.gain.value = document.getElementById("outputlabel").innerHTML = outputval;
}
Setup();

</script>
</body>
</html>
テストページ:コーラス





g200kg