How to Handle Audio Ducking in Howler.js
Howler.js is a powerful JavaScript audio library, but it does not feature an automatic, built-in mechanism for audio ducking. This article explores how developers can implement audio ducking—the process of lowering the volume of background audio when foreground audio plays—using manual volume fading and the Web Audio API integration provided by Howler.js.
The Manual Fading Approach
The simplest way to achieve audio ducking in Howler.js is by manually
controlling the volume of your audio objects using the built-in
fade() method. This method smoothly transitions the volume
of a sound over a specified duration.
When a primary audio track (like a voiceover) starts, you fade down the background music. Once the voiceover ends, you fade the background music back to its original volume.
// Initialize background music and voiceover
const backgroundMusic = new Howl({
src: ['music.mp3'],
volume: 0.8,
loop: true
});
const voiceOver = new Howl({
src: ['voiceover.mp3'],
volume: 1.0,
onplay: function() {
// Duck the background music to 20% volume over 500ms
backgroundMusic.fade(0.8, 0.2, 500);
},
onend: function() {
// Restore the background music to 80% volume over 500ms
backgroundMusic.fade(0.2, 0.8, 500);
}
});
// Play the audio
backgroundMusic.play();
setTimeout(() => {
voiceOver.play();
}, 2000);The Web Audio API Approach (Sidechain Compression)
For a more advanced, automated solution, you can leverage the Web Audio API. Because Howler.js is built on top of the Web Audio API, it exposes the underlying audio context and nodes. You can hook into Howler’s master gain node or individual sound nodes to set up a sidechain compressor.
To do this, you connect the output of your voiceover track to the
sidechain input of a DynamicsCompressorNode that processes
the background music.
1. Accessing the Audio Context
Howler.js exposes the global AudioContext via
Howler.ctx. You can use this context to create custom audio
nodes.
2. Creating a Dynamics Compressor
By creating a DynamicsCompressorNode, you can
automatically reduce the volume of the music when the signal level of
the voiceover exceeds a certain threshold.
const ctx = Howler.ctx;
// Create a compressor node
const compressor = ctx.createDynamicsCompressor();
compressor.threshold.setValueAtTime(-50, ctx.currentTime);
compressor.knee.setValueAtTime(40, ctx.currentTime);
compressor.ratio.setValueAtTime(12, ctx.currentTime);
compressor.attack.setValueAtTime(0, ctx.currentTime);
compressor.release.setValueAtTime(0.25, ctx.currentTime);3. Routing the Audio
To make this work, you must route the background music through the
compressor before it reaches the destination (speakers), while routing
the voiceover to both the destination and the compressor’s sidechain
parameters. Note that custom routing in Howler.js requires using the
masterGain or accessing the raw Web Audio nodes of
individual Howl instances using
sound._node.
Because manual routing with Web Audio nodes bypasses some of Howler’s
internal state management, the manual fade() method remains
the most stable, reliable, and frequently used approach for most
Howler.js projects.