Web Audio

Web Audio processes sound as a graph of nodes in an AudioContext. Sources (oscillators, decoded buffers, media elements, microphone streams) flow through effects (GainNode, BiquadFilterNode, ConvolverNode reverb, PannerNode for 3D) into ctx.destination, and an AnalyserNode can tap the signal for visualizers. The graph runs on a real-time audio thread, and every AudioParam can be automated with sample accuracy.

The audio graph built by the next listing
The audio graph built by the next listing
Rendering a filtered, enveloped, panned note offline and measuring its peaksJavaScript
const ctx = new OfflineAudioContext({ numberOfChannels: 2, length: 48000, sampleRate: 48000 });
const osc = new OscillatorNode(ctx, { type: 'sawtooth', frequency: 440 });
const gain = new GainNode(ctx, { gain: 0 });
osc.connect(new BiquadFilterNode(ctx, { type: 'lowpass', frequency: 1000 })).connect(gain)
  .connect(new StereoPannerNode(ctx, { pan: -0.5 })).connect(ctx.destination);
gain.gain.linearRampToValueAtTime(0.8, 0.05).exponentialRampToValueAtTime(0.01, 1);  // envelope
osc.start();
const buffer = await ctx.startRendering();                  // 1 s, rendered faster than real time
const peak = (ch) => Math.max(...buffer.getChannelData(ch).map(Math.abs));
const [left, right] = [peak(0), peak(1)];                   // 0.669 and 0.277: panned left

For live sound use new AudioContext() and resume() it in a click, since autoplay policies start it suspended. Write custom DSP as an AudioWorkletProcessor, not the deprecated ScriptProcessorNode.