MCPcopy Index your code
hub / github.com/audiojs/web-audio-api

github.com/audiojs/web-audio-api @v1.4.0

Chat with this repo
repository ↗ · DeepWiki ↗ · release v1.4.0 ↗ · + Follow
721 symbols 1,926 edges 117 files 2 documented · 0%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

web-audio-api test npm

Portable Web Audio API / polyfill.

  • 100% WPT conformance, no native deps.
  • Audio in CIOfflineAudioContext renders without speakers.
  • CLI audio scripting – pipe, process, synthesize from terminal.
  • Server-side audio – generate from APIs, bots, pipelines.
  • Tone.js and web audio libs work in Node as-is.
npm install web-audio-api

Use

import { AudioContext } from 'web-audio-api'

const ctx = new AudioContext()
await ctx.resume()

const osc = ctx.createOscillator()
osc.frequency.value = 440
osc.connect(ctx.destination)
osc.start()
// → A440 through your speakers

Built-in speaker output via audio-speaker — no extra setup.

Offline rendering

import { OfflineAudioContext } from 'web-audio-api'

const ctx = new OfflineAudioContext(2, 44100, 44100) // 1 second, stereo
const osc = ctx.createOscillator()
osc.frequency.value = 440
osc.connect(ctx.destination)
osc.start()

const buffer = await ctx.startRendering()
// buffer.getChannelData(0) → Float32Array of 44100 samples

Examples

node examples/<name>.js — all parametric. Positional args or key=value with prefix matching (f=440, freq=440 both work). Note names (A4, C#3, Eb5), k for kHz (20k), s/m/h for duration (10m).

Example
Test Signals
tone.js Reference pitch — sine A4 2s
sweep.js Hear the audible range — 20..20k exp 3s
noise.js White, pink, brown, blue, violet — pink 2s
impulse.js Dirac click — 5 0.5s
dtmf.js Dial a phone number — 5551234
stereo-test.js Left, right, center — 1k 1s
metronome.js Programmable click — 120..240 10m X-x-
Illusions
shepard.js Pitch that rises forever — up 15s
risset-rhythm.js Beat that accelerates forever — up 120 20s
binaural-beats.js Third tone from two (headphones!) — 200 10 10s
missing-fundamental.js Your brain fills in the note — 100 3s
beating.js Two close frequencies dance — 440 3 5s
Synthesis
subtractive-synth.js Sawtooth → filter sweep → ADSR
additive.js Waveforms from harmonics — square 220 16 3s
fm-synthesis.js DX7 frequency modulation — 440 2 5 3s
karplus-strong.js A string plucked from noise — A4 4s
Generative
sequencer.js Step sequencer — precise timing
serial.js Twelve-tone rows (Webern) — 72 30s
gamelan.js Balinese kotekan — two parts, one melody — 120 20s
drone.js Tanpura shimmer — C3 30s
jazz.js Modal jazz — new every time
API
speaker.js Hello world
lfo.js Tremolo via LFO
spatial.js Sound moving through space
worklet.js Custom AudioWorkletProcessor
linked-params.js One source controlling many gains
fft.js Frequency spectrum
render-to-buffer.js Offline render → buffer
process-file.js Audio file → EQ + compress → render
pipe-stdout.js PCM to stdout — pipe to aplay, sox, etc.
mic.js Live microphone → speakers with RMS meter (requires audio-mic)

Node extensions

Beyond the spec, for Node.js. Not portable to browsers.

  • addModule(fn) — register a processor via callback instead of URL, no file needed
  • sinkId: stream — pipe PCM to any writable: new AudioContext({ sinkId: process.stdout }) then node synth.js | aplay -f cd
  • numberOfChannels, bitDepth — control output format in the constructor
  • navigator.mediaDevices.getUserMedia({ audio: true }) — browser-parity microphone capture in Node. Load web-audio-api/polyfill and install audio-mic; browser mic code then runs verbatim. See the mic FAQ.

FAQ

How do I close an AudioContext?
await ctx.close()
Or with [explicit resource management](https://github.com/tc39/proposal-explicit-resource-management): `using ctx = new AudioContext()`
Why does it start suspended?
Per [W3C spec](https://webaudio.github.io/web-audio-api/#dom-audiocontext-audiocontext) — browsers require user gesture before audio plays. Call `await ctx.resume()` to start. `OfflineAudioContext` doesn't need it.
Does it work with Tone.js?
Yes. Tone.js uses `standardized-audio-context` which needs `window.AudioParam` etc. for `instanceof` checks. The polyfill sets that up — just load Tone.js after it:
import 'web-audio-api/polyfill'
const Tone = await import('tone')

Tone.setContext(new AudioContext())
const synth = new Tone.Synth().toDestination()
synth.triggerAttackRelease('C4', '8n')
Tone.js must be a dynamic `import()` — static imports get hoisted before the polyfill runs. Alternatively, use `--import`:
node --import web-audio-api/polyfill app.js
Then static `import * as Tone from 'tone'` works in `app.js`.
How do I decode audio files?
const buffer = await ctx.decodeAudioData(readFileSync('track.mp3'))
WAV, MP3, FLAC, OGG, AAC via [audio-decode](https://github.com/audiojs/audio-decode).
How do I capture audio from the microphone?
In Node, pair [`audio-mic`](https://github.com/audiojs/audio-mic) with `MediaStreamAudioSourceNode.pushData()`:
npm install audio-mic
import { AudioContext, MediaStreamAudioSourceNode } from 'web-audio-api'
import mic from 'audio-mic'

const ctx = new AudioContext()
await ctx.resume()

const src = new MediaStreamAudioSourceNode(ctx, { numberOfChannels: 1, bitDepth: 16 })
src.connect(ctx.destination) // live monitor

const read = mic({ sampleRate: ctx.sampleRate, channels: 1, bitDepth: 16 })
read((err, buf) => {
  if (err || !buf) return
  src.pushData(buf, { channels: 1, bitDepth: 16 })
})
`pushData()` accepts `Float32Array`, `Float32Array[]`, or interleaved 8/16/32-bit integer PCM buffers. Integer PCM conversion uses `pcm-convert`. With `web-audio-api/polyfill`, `navigator.mediaDevices.getUserMedia()` is also available and maps constraints to `audio-mic` options: `{ audio: { sampleRate, channelCount, sampleSize } }`. See [examples/mic.js](examples/mic.js) for a runnable demo with gain and VU meter. To record the graph to a buffer, use `OfflineAudioContext.startRendering()`. To capture live graph output as a stream, use `ctx.createMediaStreamDestination()`.
How do I use it as a polyfill?
import 'web-audio-api/polyfill'
// AudioContext, GainNode, etc. are now global
Can I unit-test audio code?
`OfflineAudioContext` renders without speakers — pair with any test runner. See [render-to-buffer.js](examples/render-to-buffer.js).
How fast is it?
All scenarios render faster than real-time. Pure JS matches Rust napi on simple graphs; heavier DSP (convolution, compression) is 2–4× slower — WASM kernels planned. `npm run bench:all` to measure.

Architecture

Pull-based audio graph. AudioDestinationNode pulls upstream via _tick(), 128-sample render quanta per spec. AudioWorklet runs synchronously (no thread isolation). DSP kernels separated from graph plumbing for future WASM swap.

EventTarget ← Emitter ← DspObject ← AudioNode ← concrete nodes
                                    ← AudioParam
EventTarget ← Emitter ← AudioPort ← AudioInput / AudioOutput

Alternatives

License

MIT

Core symbols most depended-on inside this repo

connect
called by 259
src/AudioNode.js
_tick
called by 136
src/GainNode.js
start
called by 91
src/AudioBufferSourceNode.js
createOscillator
called by 66
src/BaseAudioContext.js
setValueAtTime
called by 66
src/AudioParam.js
close
called by 64
src/AudioContext.js
createGain
called by 63
src/BaseAudioContext.js
$
called by 61
examples/_util.js

Shape

Method 387
Class 212
Function 122

Languages

TypeScript100%

Modules by API surface

test/wpt-runner.js74 symbols
index.d.ts72 symbols
src/BaseAudioContext.js34 symbols
src/AudioWorklet.js30 symbols
src/AudioContext.js27 symbols
src/PannerNode/PannerNode.js24 symbols
src/MediaStreamAudioSourceNode.js24 symbols
src/audioports.js20 symbols
src/AudioParam.js20 symbols
polyfill.js20 symbols
test/AudioWorklet.test.js18 symbols
src/AudioListener.js18 symbols

For agents

$ claude mcp add web-audio-api \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact

Ask about this repo answers extend the page