pnpm dlx shadcn@latest add @audio-ui/web-audio
import { WebAudio, webAudio } from "@/lib/web-audio";| Files | lib/web-audio.ts |
|---|---|
| Depends on | Nothing |
| npm | Nothing |
| Used by | arrangement-engine, block-audio-editor, block-device-chain, block-drum-rack, block-drum-synth, block-mixer, block-piano-roll, block-sampler, block-synth-panel, block-timeline, block-waveform-player, pad-demo, sequencer, spectrum-analyzer-demo, use-device-loop, use-master-bus, use-microphone, use-noise-through-eq, use-piano-roll-playback, use-transport-clock, use-web-audio, web |
| Export | Kind | What it is |
|---|---|---|
WebAudio | class | The page's one AudioContext: the factory every hook and block that starts sound gets it from, so a page never makes two. |
webAudio | const |
Usage
A page has one AudioContext, shared by every hook and engine on it, made the first time something asks for it. Ask for it where you need it:
import { webAudio } from "@/lib/web-audio";
const ctx = webAudio.getContext(); // null on the serverTo make it with options of its own, such as how much latency it trades for steadiness, configure it before anything asks for it. They do not change a context already made, so a change takes the next page load:
webAudio.configure({ latencyHint: "playback" });Browsers start a context suspended until the user does something on the page. webAudio.resume() gives the context and resumes it unless it already runs: call it from the gesture that starts the sound, such as a play button, a pad struck or a MIDI note, without waiting for it, so the note starts on the press.
const play = () => {
webAudio.resume();
transport.play();
};Where a context comes from is one rule. An engine or a lib takes it as a parameter (createDelayEngine(ctx, state)), so it also renders on an OfflineAudioContext. A hook given a node (a destination, an analyser) works on that node's context, the graph it plays into. Everything else, a block or a hook that starts sound from nothing, asks webAudio, and never makes a context of its own.