Web Audio

The Web Audio API is not for playing files -- it is a signal processing graph. Sources feed into effects, effects chain into each other, and the result goes to your speakers. AudioContext, AudioNode, and AudioWorklet are the three concepts that unlock the whole thing.

June 12, 20265 min read2 / 6

I always assumed audio in the browser meant loading a file and calling .play(). The Web Audio API turns out to be something else entirely.

It is a signal processing graph. You create nodes, you wire them together, and audio flows through the chain from source to output. You can generate sound from scratch. You can build reverb, filters, and 3D spatial positioning. You can analyze a waveform in real time. None of it requires loading a file.

AudioContext: The Runtime

Everything in the Web Audio API lives inside an AudioContext. It owns the audio hardware connection, the sample rate, and the timing clock.

JavaScript
const ctx = new AudioContext()

One important constraint: browsers require a user gesture before allowing audio to start. Creating an AudioContext on page load is allowed, but audio will not actually play until the user has clicked, tapped, or otherwise interacted with the page. If you try to call ctx.resume() or start a node before that, most browsers will refuse silently.

The fix is to create the context (or call ctx.resume()) inside a click handler.

AudioNode: The Graph

Every piece of audio processing is an AudioNode. Nodes have inputs and outputs. You connect them with .connect() and audio flows forward:

JavaScript
const osc = ctx.createOscillator() // a source node const gain = ctx.createGain() // an effect node osc.connect(gain) gain.connect(ctx.destination) // ctx.destination = your speakers

The shape of this graph determines the sound. A simple chain -- oscillator to gain to destination -- produces a pure tone at controlled volume. A more complex graph can add reverb, spatial positioning, frequency analysis, or filtering.

Source nodes produce audio:

  • OscillatorNode -- generates a continuous waveform (sine, square, sawtooth, triangle) at a given frequency
  • AudioBufferSourceNode -- plays a decoded audio buffer from memory (useful for pre-loaded samples)
  • MediaStreamSourceNode -- wraps a getUserMedia microphone stream as an audio source

Effect nodes process audio flowing through them:

  • GainNode -- scales amplitude (volume control)
  • PannerNode -- positions a sound source in 3D space; combine with AudioListener for full spatial audio
  • BiquadFilterNode -- applies EQ filters (low-pass, high-pass, band-pass, etc.)
  • AnalyserNode -- taps the signal to extract frequency or time-domain data for visualization without modifying it

Making Sound

Here is a complete example -- a one-second tone at A4 (440 Hz):

JavaScript
const ctx = new AudioContext() const osc = ctx.createOscillator() osc.type = 'sine' osc.frequency.value = 440 const gain = ctx.createGain() gain.gain.value = 0.2 // keep it quiet osc.connect(gain) gain.connect(ctx.destination) osc.start() osc.stop(ctx.currentTime + 1) // stop after 1 second

ctx.currentTime is a high-precision clock in seconds. Scheduling with it instead of setTimeout gives sample-accurate timing -- critical for anything musical.

AudioParams are automatable. The gain.gain and osc.frequency properties are not plain numbers. They are AudioParam objects that can be scheduled to change over time:

JavaScript
// Fade out over 2 seconds gain.gain.setValueAtTime(0.3, ctx.currentTime) gain.gain.linearRampToValueAtTime(0, ctx.currentTime + 2)

This is how you build envelopes, vibrato, and filter sweeps without polling in JavaScript.

Web Audio API: AudioNode pipeline from source nodes through effect nodes to AudioDestinationNode, plus AudioWorklet and output options ExpandWeb Audio API: AudioNode pipeline from source nodes through effect nodes to AudioDestinationNode, plus AudioWorklet and output options

AudioWorklet: Custom Processing in a Dedicated Thread

The original Web Audio API ran all processing on the main audio thread managed by the browser. The newer AudioWorkletNode lets you write custom DSP code that runs in a dedicated, real-time audio thread -- separate from the main JavaScript thread and separate from the browser's rendering thread.

JavaScript
// Register a custom processor await ctx.audioWorklet.addModule('my-processor.js') const node = new AudioWorkletNode(ctx, 'my-processor') node.connect(ctx.destination)

The processor itself runs in a separate file with AudioWorkletProcessor:

JavaScript
// my-processor.js (runs in audio worklet scope) class MyProcessor extends AudioWorkletProcessor { process(inputs, outputs) { const output = outputs[0] for (const channel of output) { for (let i = 0; i < channel.length; i++) { channel[i] = Math.random() * 0.1 // white noise } } return true // keep processor alive } } registerProcessor('my-processor', MyProcessor)

AudioWorklet is the right tool for synthesizers, effects engines, and anything that needs to run custom logic at sample rate without risking audio glitches from main-thread interruption.

Spatial Audio

Three-dimensional sound placement uses PannerNode and AudioListener:

JavaScript
const panner = ctx.createPanner() panner.positionX.value = 2 // 2 meters right panner.positionY.value = 0 panner.positionZ.value = -5 // 5 meters ahead osc.connect(panner) panner.connect(ctx.destination) // Move the listener ctx.listener.positionX.value = 0 ctx.listener.positionY.value = 0 ctx.listener.positionZ.value = 0

The browser applies distance-based attenuation and stereo panning automatically. Useful for games, immersive experiences, and any scenario where sound direction matters.

Green Tier

Web Audio is green tier. Chrome, Firefox, Safari, and Edge all support it. It works on desktop and mobile, including iOS Safari.

JavaScript
if (typeof AudioContext !== 'undefined') { // Web Audio is available }

The permission model does not apply here -- no dialog appears for audio output. The user gesture requirement is enforced silently instead.

Web MIDI pairs naturally with Web Audio: use MIDI input to drive oscillator frequency and velocity, and Web Audio to synthesize the actual sound.

Web Audio generates and processes sound. The protocol for communicating musical events to hardware is separate -- that is Web MIDI, and it pairs with Web Audio to turn the browser into a synthesizer.

The Essentials

  1. AudioContext is the runtime. All nodes belong to one context. Create it inside a user gesture handler or call ctx.resume() there.
  2. Audio is a graph of nodes. Source nodes produce audio. Effect nodes transform it. ctx.destination is the output. Connect with .connect().
  3. AudioParam values can be scheduled with setValueAtTime() and linearRampToValueAtTime() for sample-accurate automation.
  4. AudioWorkletNode runs custom DSP in a real-time audio thread -- separate from the main JS thread. Use it for synthesizers and custom effects that cannot afford main-thread jitter.
  5. PannerNode + AudioListener = 3D spatial audio. The browser calculates distance attenuation and stereo panning automatically.
  6. Green tier -- Chrome, Firefox, Safari, Edge. The user gesture requirement is enforced by the browser, not the permission dialog system.

Further Reading and Watching