How to add effects to audio

Tony Conway
Tony Conway

The Web Audio API uses the AudioContext() interface to manage sources, filters, and destinations. Once you’ve created a new AudioContext(), create an audio source node, like an AudioBufferSourceNode or OscillatorNode. As an example, consider a basic oscillator with a low pass filter applied.

Browser Support

  • Chrome: 35.
  • Edge: 12.
  • Firefox: 25.
  • Safari: 14.1.

Source

Using the createBiquadFilter() method

First, create a new AudioContext(). Then create an audio source node, like an AudioBufferSourceNode or OscillatorNode. You'll create a sine oscillator node, for this example, which has a frequency of 420 hertz from the moment it starts playing.

const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
const oscillator = audioCtx.createOscillator()
oscillator.type = 'sine';
 // Value is in hertz.
oscillator.frequency.setValueAtTime(420, audioCtx.currentTime);

Next, create an effect node using createBiquadFilter(). Set the type to lowpass and the frequency to start one second after the start of playback. Then connect the biquadFilter to the oscillator.

const biquadFilter = audioCtx.createBiquadFilter();
biquadFilter.type = 'lowpass';
biquadFilter.frequency.setValueAtTime(200, audioCtx.currentTime + 1);
oscillator.connect(biquadFilter);

Finally connect the biquadFilter to the destination of the audioCtx, before starting the oscillator and stopping it after two seconds of playback.

biquadFilter.connect(audioCtx.destination);
oscillator.start();
oscillator.stop(2);

The sound from the oscillator is passed through the unaffected filter, and on to the destination, which is your computer's speakers. After one second of playback, the lowpass filter comes into effect. After two seconds, the oscillator is stopped.

Other available filters and effects

Other filter nodes can be added to an AudioContext to create different effects:

The classic way

Before the availability of the Web Audio API, there was no way to add effects to audio in the browser. Workarounds using server-side rendering and switching between streams are possible, but this can incur a lot of network overhead.

Using the audio element

The only audio effects that can be directly controlled are playback and volume.

const audio = document.querySelector('audio');
 // Sets audio volume to 50%
audio.volume = 0.5;
// Doubles the playback rate.
audio.playbackRate = 2;

Browser Support

  • Chrome: 3.
  • Edge: 12.
  • Firefox: 3.5.
  • Safari: 3.1.

Source

Further reading

Demo

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link
      rel="icon"
      href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🔉</text></svg>"
    />
    <title>How to add effects to audio</title>
  </head>
  <body>
    <h1>How to add effects to audio</h1>
    <button type="button">Press to hear audio effect</button>
  </body>
</html>

        :root {
  color-scheme: dark light;
}

html {
  box-sizing: border-box;
}

*,
*:before,
*:after {
  box-sizing: inherit;
}

body {
  margin: 1rem;
  font-family: system-ui, sans-serif;
}
        

        const button = document.querySelector('button');

button.addEventListener('click', () => {
  const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
  const oscillator = audioCtx.createOscillator();
  oscillator.type = 'sine';
  // Value is in hertz.
  oscillator.frequency.setValueAtTime(420, audioCtx.currentTime);

  const biquadFilter = audioCtx.createBiquadFilter();
  biquadFilter.type = 'lowpass';
  biquadFilter.frequency.setValueAtTime(200, audioCtx.currentTime + 1);
  oscillator.connect(biquadFilter);

  biquadFilter.connect(audioCtx.destination);
  oscillator.start();
  oscillator.stop(2);
});