Three.js From Zero · Article s9-01

S9-01 Web Audio Basics

Season 9 · Article 01

Web Audio Basics

The browser ships a modular synthesizer. AudioContext as the motherboard. Nodes (oscillator, filter, gain, delay, analyzer) plug into each other. Output the graph to speakers.

1. The graph

const ctx = new AudioContext();

// Oscillator (source)
const osc = ctx.createOscillator();
osc.type = 'sawtooth';
osc.frequency.value = 220;

// Gain (volume)
const gain = ctx.createGain();
gain.gain.value = 0.3;

// Connect: osc → gain → speakers
osc.connect(gain).connect(ctx.destination);
osc.start();

2. Main node types

  • OscillatorNode: sine, square, sawtooth, triangle, custom.
  • GainNode: volume / amplitude envelope.
  • BiquadFilterNode: lowpass, highpass, bandpass, notch…
  • DelayNode: echo.
  • ConvolverNode: reverb (S9-04).
  • AudioBufferSourceNode: play a recorded sample.
  • AnalyserNode: FFT output for visuals (S9-03).
  • PannerNode: 3D spatial position (S9-02).
  • AudioWorkletNode: custom DSP in an audio thread.

3. AudioParam scheduling

Every parameter can be scheduled with sample accuracy:

// ADSR envelope
gain.gain.setValueAtTime(0, ctx.currentTime);
gain.gain.linearRampToValueAtTime(1.0, ctx.currentTime + 0.01);  // Attack
gain.gain.linearRampToValueAtTime(0.7, ctx.currentTime + 0.1);   // Decay
// Sustain...
gain.gain.linearRampToValueAtTime(0, ctx.currentTime + 0.5);      // Release

4. User gesture requirement

// Must start audio context in response to a click/tap/keydown
button.addEventListener('click', async () => {
  if (ctx.state === 'suspended') await ctx.resume();
});

Browser policy: no audio until user interacts. Prevents ad autoplay spam.

5. Live demo — play with a synth

6. The graph pattern

Any synth is: sources → effects → master → destination. Copy and extend.

osc -> filter -> envelope (gain) -> delay ↴
                                          \
                              master ← direct ↲
                                |
                          destination

7. WebAudio in Three.js

const listener = new THREE.AudioListener();
camera.add(listener);

const sound = new THREE.Audio(listener);
const loader = new THREE.AudioLoader();
loader.load('ambient.ogg', buf => {
  sound.setBuffer(buf);
  sound.setLoop(true);
  sound.setVolume(0.5);
  sound.play();
});

Three.js wraps Web Audio. AudioListener is attached to camera (your "ears"). Audio (non-positional) and PositionalAudio (spatial, S9-02).

8. Takeaways

  • AudioContext is the root. Nodes are modules. Connect to build.
  • OscillatorNode + GainNode + BiquadFilter = subtractive synth.
  • AudioParam scheduling gives sample-accurate envelopes.
  • Must start context on user gesture.
  • Three.js AudioListener + Audio wrap Web Audio for scene use.