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.