Creating dub delay effects with the Web Audio API
Introduction
Dub music is a sub-genre of reggae. Typical of the style is the remixing of reggae records, first stripping them down to the bass and drums and then applying swirling, psychedelic delay effects to what’s left. In this post we’ll take a look at the classic dub delay sound, and try to recreate some of its character using the web audio API.
The chop
Dub delay can be applied to any element of a song, but often it’s applied to the “chop” - an off beat, minor-chord stab played on a keyboard or guitar. Here’s a chop
We’ve implemented it using a straight-forward HTML5 audio element wrapping an OGG-encoded file with the controls and looping enabled
<audio src="/demos/dub_delay/chop.ogg" controls="true" loop="true" />
Delay
The basis of the dub delay sound is, of course, the delay. You can think of a delay effect as simply taking the incoming sound and holding on to it for a pre-determined length of time, before letting it go again. Here’s how we create a delay using the Web Audio API
(function () {
var ctx = new AudioContext();
var audioElement = $('#delay audio')[0];
audioElement.addEventListener('play', function() {
var source = ctx.createMediaElementSource(audioElement);
var delay = ctx.createDelay();
delay.delayTime.value = 0.5;
source.connect(delay);
source.connect(ctx.destination);
delay.connect(ctx.destination);
});
})();
First we create an
AudioContext
to hold the nodes in our processing graph. The first node in our graph
is the
MediaElementSource
node, which allows routes the audio from a HTML5 audio element into
the graph. We have to wait for the play
event to fire to
be sure that the audio has loaded and has been decoded ready to hand
off to the audio context.
We then create a Delay node, with a delay time of 0.5 seconds. Finally we connect the delay to the destination. Note here that we’ve also connected the source itself to the destination, if we don’t do that, we’ll just here the delayed version of the chop, and not the original - this way, we hear both:
Feedback
The delay on its own is a good start, but somehow it sounds a little too sterile. We need to add some feedback to start getting the swirling, psychedelic sounds of dub. To recreate this sound, we have to understand a little bit about how dub producers created it.
In an analogue studio, each mixing desk channel typically has an “auxiliary send” which allows some of the channel’s audio to be routed to an external effects unit, for example a analogue tape delay. If the return from that unit is sent back to another channel of the mixing desk - that channel too has an auxiliary send. By increasing the send on the return channel, the delayed sound can be routed through the delay unit again, and again, and again… creating what is known as feedback. Here’s how we do that in code
(function() {
var ctx = new AudioContext();
var audioElement = $('#feedback audio')[0];
audioElement.addEventListener('play', function(){
var source = ctx.createMediaElementSource(audioElement);
var delay = ctx.createDelay();
delay.delayTime.value = 0.5;
var feedback = ctx.createGain();
feedback.gain.value = 0.8;
delay.connect(feedback);
feedback.connect(delay);
source.connect(delay);
source.connect(ctx.destination);
delay.connect(ctx.destination);
});
})();
This is very similar to the code we saw above, but we’ve introduced a Gain node between the output of the delay node and the input of the delay node. Connecting the delay node to itself is enough to create the feedback loop, but without the gain node we’d be feeding 100% of the delayed sound back into the delay - creating a delay that grows forever. Introducing the gain node allows us to control this. Here’s how it sounds
Notice as the audio element itself loops, the tail of the feedback keeps playing - the original source and the feedback combine in interesting rhythmic ways depending on the amount of feedback and the length of the delay. This is a characteristic sound of dub.
Degradation in the audio chain
When working with the Web Audio API we are manipulating digital signals. Each echo in our feedback chain is a perfect copy of the original, just slightly quieter. It’s as close to “perfect” as we can get. Dub producers work with much less perfect equipment - analogue mixing desks and analogue-tape based delay units. Each time the signal passes through that processing chain it loses some fidelity - and this contributes to the sound of the dub delay. Creating a clone of this sound using digital signals is something of a holy grail, but to start you on that journey, lets introduce something to “dirty” up the feedback.
(function () {
var ctx = new AudioContext();
var audioElement = $('#filter audio')[0];
audioElement.addEventListener('play', function(){
var source = ctx.createMediaElementSource(audioElement);
var delay = ctx.createDelay();
delay.delayTime.value = 0.5;
var feedback = ctx.createGain();
feedback.gain.value = 0.8;
var filter = ctx.createBiquadFilter();
filter.frequency.value = 1000;
delay.connect(feedback);
feedback.connect(filter);
filter.connect(delay);
source.connect(delay);
source.connect(ctx.destination);
delay.connect(ctx.destination);
});
})();
Here, we’ve introduced a
BiquadFilter
node. By default, this is a low-pass filter, which filters out
frequencies above the frequency
parameter. This is a simple way of
adding some interest and it mimics the way an analogue signal chain
would have a bigger effect on higher frequencies than lower ones.
As each echo decays away it also loses some of its high frequency content.
Putting it all together with knobs on!
Of course, most of the creative uses of dub delay don’t involve just the static application of the effect to the incoming sound. Instead the producer plays the equipment like an instrument, allowing the feedback to rise and dominate, stopping the original source to just play the echos, and adjusting the delay time and other filters in creative ways. Let’s try hooking up some simple sliders to some of the parameters of our dub delay effect.
(function () {
var ctx = new AudioContext();
audioElement = $('#sliders audio')[0]
audioElement.addEventListener('play', function(){
source = ctx.createMediaElementSource(audioElement);
delay = ctx.createDelay();
delay.delayTime.value = 0.5;
feedback = ctx.createGain();
feedback.gain.value = 0.8;
filter = ctx.createBiquadFilter();
filter.frequency.value = 1000;
delay.connect(feedback);
feedback.connect(filter);
filter.connect(delay);
source.connect(delay);
source.connect(ctx.destination);
delay.connect(ctx.destination);
});
var controls = $("div#sliders");
controls.find("input[name='delayTime']").on('input', function() {
delay.delayTime.value = $(this).val();
});
controls.find("input[name='feedback']").on('input', function() {
feedback.gain.value = $(this).val();
});
controls.find("input[name='frequency']").on('input', function() {
filter.frequency.value = $(this).val();
});
})();
Now, try adjusting the values of the parameters and experiment with how they sound together. Starting and stopping the audio element is also possible, since the effects are happening “inside” the audio context.
Summary
We’ve used the Web Audio API to create a simple recreation of some classic dub delay sounds. Where next?
- You might have noticed a small artifact when adjusting the delay
time. The specification
states
“When the delay time is changed, the implementation must make the
transition smoothly, without introducing noticeable clicks or
glitches to the audio stream”. When a change is made to the delay
time parameter, the implementations make a smooth transition to the
new value (called “dezippering”). In this case the more rapid change
in time creates an artifact, which an analogue tape recorder
wouldn’t have due to the mechanical constraints of the device on the
speed of the change. You can experiment with using
.setValueAtTime(value, 0)
to remove the dezippering effect. - Ping-pong delay is an effect where each echo is sent alternately to the left and right channels. You sometimes here this effect in use, and it is possible to implement it using an extra delay node together with the channel splitter and channel merger nodes.
References
- Analogue Warmth: The Sound Of Tubes, Tape & Transformers. A comprehensive take on the subject of analogue “warmth” - a rabbit hole you might be tempted to lose yourself in.
- Dubbing out in Ableton Live. An overview of how to create dub delay effects using the desktop software Abelton Live. All of the techniques in this video would be possible with the Web Audio API with enough effort.
Thanks
It took me a long time to write this post, as I hit some pretty odd bugs along the way. A huge thanks to Tom, Chris and James for providing advice, space and for putting up with my noise.
Also thanks to Chris Wilson for pointing out the issue with artifacts/dezippering.