React package exports.
These APIs are imported from @webaudio-kit/react. The hooks must run under AudioProvider.
AudioProvider
Wraps React UI that needs playback. It creates AudioContext lazily, routes playback through masterGain -> analyser -> destination, and starts with a safe master gain.
function AudioProvider(props: AudioProviderProps): JSX.Element;
type AudioProviderProps = {
children: ReactNode;
initialGain?: number;
};import { AudioProvider } from "@webaudio-kit/react";
export function App() {
return (
<AudioProvider initialGain={0.2}>
<AudioControls />
</AudioProvider>
);
}| Name | Type | Default | Notes |
|---|---|---|---|
AudioProviderProps.children | ReactNode | n/a | Required React subtree that can call webaudio-kit hooks. |
AudioProviderProps.initialGain | number | 0.2 | Initial master gain. Non-finite values fall back to the package default and negative values clamp to 0. |
Returns
| Name | Type | Default | Notes |
|---|---|---|---|
audioContext | AudioContext | null | n/a | Null until the first user-initiated playback creates audio. |
masterGain | GainNode | null | n/a | Shared gain node for all playback created by provider hooks. |
analyser | AnalyserNode | null | n/a | Shared analyser node for waveform and spectrum UI. |
state | AudioContextState | "idle" | n/a | Idle before creation, then mirrors the current AudioContext state. |
useAudioContext
Reads the provider runtime state and low-level controls. Use this when you need context state, analyser access, or custom UI around provider gain.
function useAudioContext(): AudioProviderValue;
type AudioProviderValue = {
audioContext: AudioContext | null;
masterGain: GainNode | null;
analyser: AnalyserNode | null;
state: AudioContextState | "idle";
gain: number;
ensureAudioContext(): Promise<AudioRuntime>;
setGain(gain: number): Promise<void>;
stopAll(): void;
};import { useAudioContext } from "@webaudio-kit/react";
function AudioStateControls() {
const audio = useAudioContext();
return (
<>
<span>{audio.state}</span>
<button onClick={() => audio.stopAll()}>Stop all</button>
</>
);
}| Name | Type | Default | Notes |
|---|---|---|---|
state | AudioContextState | "idle" | n/a | Display whether audio is idle, running, suspended, closed, or interrupted by the browser. |
ensureAudioContext() | Promise<AudioRuntime> | n/a | Creates and resumes AudioContext on demand. Call it only from user-initiated handlers or higher-level hooks. |
setGain(gain) | Promise<void> | n/a | Updates provider master gain and clamps invalid input to safe values. |
stopAll() | void | n/a | Stops active and scheduled hook playback handles. Use this for panic buttons or alert acknowledgement; it is stronger than muting gain. |
useAudioUnlock
Returns a small UX primitive for explicit browser audio enablement from a button, tap target, or keyboard action.
function useAudioUnlock(): AudioUnlockControls;
type AudioUnlockControls = {
unlock(): Promise<AudioRuntime>;
status: "idle" | "unlocking" | "suspended" | "running" | "closed" | "error";
state: AudioContextState | "idle";
isUnlocked: boolean;
isUnlocking: boolean;
error: Error | null;
};import { useAudioUnlock } from "@webaudio-kit/react";
function EnableAudioButton() {
const audio = useAudioUnlock();
return (
<>
<button disabled={audio.isUnlocked} onClick={() => void audio.unlock()}>
{audio.isUnlocked ? "Audio enabled" : "Enable Audio"}
</button>
<span>{audio.status}</span>
{audio.error ? <span>unlock failed</span> : null}
</>
);
}| Name | Type | Default | Notes |
|---|---|---|---|
unlock() | Promise<AudioRuntime> | n/a | Creates/resumes the provider runtime. Call it from a click, tap, or keyboard handler because browser autoplay policy still requires a user gesture. |
status | "idle" | "unlocking" | "suspended" | "running" | "closed" | "error" | n/a | Display label for the current unlock UI. Use suspended for blocked browser audio and error for a failed unlock attempt. |
isUnlocked | boolean | n/a | True when the provider state is running and audio can be used for subsequent cues. |
error | Error | null | n/a | Stores the last failed unlock error so apps can show retry UI without losing the provider state label. |
useAudioEngine
Returns provider-scoped wrappers around core playback helpers for custom or layered React sounds.
function useAudioEngine(): AudioEngineControls;
type AudioEngineControls = AudioProviderValue & {
playTone(options): Promise<PlaybackHandle>;
playFrequencySweep(options): Promise<PlaybackHandle>;
playNoise(options): Promise<PlaybackHandle>;
withAudioRuntime<T>(
callback: (runtime: AudioRuntime) => T | Promise<T>,
): Promise<T>;
};import { useAudioEngine } from "@webaudio-kit/react";
function LayeredAlertButton() {
const engine = useAudioEngine();
async function playLayeredAlert() {
await engine.playTone({
frequency: 880,
durationMs: 160,
gain: 0.1,
type: "square",
});
await engine.playNoise({
durationMs: 120,
gain: 0.025,
type: "pink",
});
}
return (
<>
<button onClick={() => void playLayeredAlert()}>Play alert</button>
<button onClick={() => engine.stopAll()}>Stop all</button>
</>
);
}| Name | Type | Default | Notes |
|---|---|---|---|
playTone(options) | Promise<PlaybackHandle> | n/a | Ensures/resumes the provider runtime and routes tone playback through runtime.masterGain. |
playFrequencySweep(options) | Promise<PlaybackHandle> | n/a | Runs provider-scoped frequency sweeps without manual audioContext or masterGain plumbing. |
playNoise(options) | Promise<PlaybackHandle> | n/a | Runs provider-scoped white, pink, or brown noise bursts through the analyser graph. |
withAudioRuntime(callback) | Promise<T> | n/a | Provides the non-null provider runtime for custom Web Audio code that needs runtime.masterGain. |
useTone
Creates stable controls for one oscillator tone. Every play call creates fresh oscillator, gain, and pan nodes and cleans them up when playback ends.
function useTone(): {
play(options: ToneOptions): Promise<void>;
stop(): void;
isPlaying: boolean;
};
function useTone(options: ToneOptions): {
play(overrides?: Partial<ToneOptions>): Promise<void>;
stop(): void;
isPlaying: boolean;
};import { useTone } from "@webaudio-kit/react";
function AlertCueButton() {
const tone = useTone();
return (
<>
<button onClick={() => void tone.play({
frequency: 880,
durationMs: 120,
gain: 0.12,
type: "square",
envelope: { attackMs: 8, releaseMs: 45 },
filter: { frequency: 1800, q: 0.7 },
pattern: { repeat: 3, gapMs: 90 },
voices: { count: 2, spreadCents: 10 },
})}>
Play alert cue
</button>
<button onClick={tone.stop}>Stop</button>
</>
);
}| Name | Type | Default | Notes |
|---|---|---|---|
ToneOptions.frequency | number | n/a | Tone frequency in Hz. Values are clamped by core playback to 20..20000 by default. |
ToneOptions.gain | number | 0.2 | Per-play gain before the provider master gain. |
ToneOptions.type | OscillatorType | "sine" | Any browser oscillator type: "sine", "square", "sawtooth", or "triangle". |
ToneOptions.pan | number | 0 | Stereo pan from -1 left to 1 right when StereoPannerNode is available. |
ToneOptions.durationMs | number | n/a | Optional duration. Omit it for manual stop control. |
ToneOptions.detuneCents | number | 0 | Oscillator detune in cents. |
ToneOptions.envelope | { attackMs?: number; decayMs?: number; sustain?: number; releaseMs?: number } | n/a | Optional gain envelope. Durations are milliseconds; sustain is a 0..1 gain multiplier. |
ToneOptions.filter | { frequency: number; q?: number; type?: BiquadFilterType } | n/a | Optional filter node. Defaults to lowpass when set; frequency is clamped to the playable range. |
ToneOptions.pattern | { repeat?: number; gapMs?: number } | n/a | Optional repeat pattern. Repeated tones require durationMs and share one stop handle. |
ToneOptions.voices | { count?: number; spreadCents?: number } | n/a | Optional 1..8 oscillator layering. Requested gain is divided across voices. |
Returns
| Name | Type | Default | Notes |
|---|---|---|---|
play(overrides) | Promise<void> | n/a | Resumes provider audio, stops any previous tone from this hook, then starts the next tone. |
stop() | void | n/a | Stops and disconnects the current tone for this hook. |
isPlaying | boolean | n/a | True after play starts and false after stop or scheduled duration completion. |
useFrequencySweep
Creates stable controls for a scheduled oscillator ramp between two clamped frequencies.
function useFrequencySweep(): {
play(options: FrequencySweepOptions): Promise<void>;
stop(): void;
isPlaying: boolean;
};
function useFrequencySweep(options: FrequencySweepOptions): {
play(overrides?: Partial<FrequencySweepOptions>): Promise<void>;
stop(): void;
isPlaying: boolean;
};import { useFrequencySweep } from "@webaudio-kit/react";
function SweepButton() {
const sweep = useFrequencySweep({
from: 250,
to: 8000,
durationMs: 2400,
gain: 0.12,
});
return <button onClick={() => void sweep.play()}>Run sweep</button>;
}| Name | Type | Default | Notes |
|---|---|---|---|
FrequencySweepOptions.from | number | n/a | Start frequency in Hz. Core playback clamps it to the playable range. |
FrequencySweepOptions.to | number | n/a | End frequency in Hz. Core playback clamps it to the playable range. |
FrequencySweepOptions.durationMs | number | n/a | Required positive sweep duration. Invalid values throw before scheduling. |
FrequencySweepOptions.gain | number | 0.2 | Per-sweep gain before the provider master gain. |
FrequencySweepOptions.type | OscillatorType | "sine" | Oscillator waveform used throughout the sweep. |
FrequencySweepOptions.pan | number | 0 | Stereo pan from -1 left to 1 right when supported by the browser. |
FrequencySweepOptions.detuneCents | number | 0 | Oscillator detune in cents for sweep voices. |
FrequencySweepOptions.envelope | { attackMs?: number; decayMs?: number; sustain?: number; releaseMs?: number } | n/a | Optional gain envelope for softer sweep starts and stops. |
FrequencySweepOptions.filter | { frequency: number; q?: number; type?: BiquadFilterType } | n/a | Optional filter node for taming bright sweep waveforms. |
FrequencySweepOptions.pattern | { repeat?: number; gapMs?: number } | n/a | Optional repeat pattern for chirps or repeated sweeps without app-owned timers. |
FrequencySweepOptions.voices | { count?: number; spreadCents?: number } | n/a | Optional 1..8 oscillator layering for fuller sweep cues. |
Returns
| Name | Type | Default | Notes |
|---|---|---|---|
play(overrides) | Promise<void> | n/a | Resumes provider audio and schedules a linear frequency ramp. |
stop() | void | n/a | Stops and disconnects the active sweep. |
isPlaying | boolean | n/a | True while the scheduled sweep is active. |
useNoise
Creates stable controls for short generated white, pink, or brown noise buffers.
function useNoise(): {
play(options: NoiseOptions): Promise<void>;
stop(): void;
isPlaying: boolean;
};
function useNoise(options: NoiseOptions): {
play(overrides?: Partial<NoiseOptions>): Promise<void>;
stop(): void;
isPlaying: boolean;
};import { useNoise } from "@webaudio-kit/react";
function NoiseButton() {
const noise = useNoise({
type: "pink",
durationMs: 800,
gain: 0.08,
});
return <button onClick={() => void noise.play()}>Play pink noise</button>;
}| Name | Type | Default | Notes |
|---|---|---|---|
NoiseOptions.durationMs | number | n/a | Required positive duration for the generated buffer. |
NoiseOptions.gain | number | 0.2 | Per-burst gain before the provider master gain. Keep this low. |
NoiseOptions.pan | number | 0 | Stereo pan from -1 left to 1 right when supported by the browser. |
NoiseOptions.type | "white" | "pink" | "brown" | "white" | Noise color used when generating the buffer. |
NoiseOptions.envelope | { attackMs?: number; decayMs?: number; sustain?: number; releaseMs?: number } | n/a | Optional gain envelope for noise bursts that should fade in or out. |
NoiseOptions.filter | { frequency: number; q?: number; type?: BiquadFilterType } | n/a | Optional filter node for shaping white, pink, or brown noise. |
NoiseOptions.pattern | { repeat?: number; gapMs?: number } | n/a | Optional repeat pattern for repeated bursts without setTimeout wrappers. |
Returns
| Name | Type | Default | Notes |
|---|---|---|---|
play(overrides) | Promise<void> | n/a | Resumes provider audio, generates a fresh buffer, and starts it. |
stop() | void | n/a | Stops and disconnects the active noise source. |
isPlaying | boolean | n/a | True while the burst is active. |
useVolume
Reads and updates the provider master gain. Use this for one shared volume control across tone, sweep, and noise playback.
function useVolume(): {
gain: number;
setGain(gain: number): Promise<void>;
};import { useVolume } from "@webaudio-kit/react";
function VolumeSlider() {
const volume = useVolume();
return (
<input
max={0.5}
min={0}
onChange={(event) => void volume.setGain(event.currentTarget.valueAsNumber)}
step={0.01}
type="range"
value={volume.gain}
/>
);
}| Name | Type | Default | Notes |
|---|---|---|---|
gain | number | n/a | Current provider master gain. |
setGain(gain) | Promise<void> | n/a | Normalizes invalid input and updates masterGain when audio already exists. |
useVolumeControl
Builds a controlled volume slider from provider gain, safe bounds, and optional persisted browser preference storage.
function useVolumeControl(options?: VolumeControlOptions): VolumeControlControls;
type VolumeControlOptions = {
defaultGain?: number;
label?: string;
maxGain?: number;
minGain?: number;
step?: number;
storageKey?: string;
};
type VolumeControlControls = {
gain: number;
db: number;
inputProps: VolumeControlInputProps;
resetGain(): Promise<void>;
setGain(gain: number): Promise<void>;
};import { useVolumeControl } from "@webaudio-kit/react";
function ControlledVolumeSlider() {
const volume = useVolumeControl({
label: "Master volume",
maxGain: 0.5,
storageKey: "app-master-gain",
});
return (
<>
<input {...volume.inputProps} />
<span>{volume.gain.toFixed(2)}</span>
<button onClick={() => void volume.resetGain()}>Reset volume</button>
</>
);
}| Name | Type | Default | Notes |
|---|---|---|---|
inputProps | range input props | n/a | Spread onto an input to keep provider gain as the controlled value without duplicate React state. |
storageKey | string | undefined | n/a | Optional localStorage key for persisting a browser preference. Omit it when volume should reset each session. |
minGain / maxGain / step | number | n/a | Safe bounds for the controlled slider. Defaults are 0, 1, and 0.01. |
resetGain() | Promise<void> | n/a | Removes the stored preference and restores defaultGain through provider gain. |
useAnalyser
Returns the provider analyser node so custom visualizers can read time-domain or frequency-domain data.
function useAnalyser(): AnalyserNode | null;import { useAnalyser } from "@webaudio-kit/react";
function Meter() {
const analyser = useAnalyser();
if (!analyser) {
return <span>Idle</span>;
}
return <span>{analyser.fftSize} point analyser</span>;
}| Name | Type | Default | Notes |
|---|---|---|---|
return value | AnalyserNode | null | n/a | Null before the provider creates AudioContext. Non-null after playback initializes the graph. |
WaveformCanvas
Draws analyser time-domain data into a canvas and renders an idle center line before audio exists. Keep width/height as the backing buffer and use style or className for responsive CSS sizing.
function WaveformCanvas(props: WaveformCanvasProps): JSX.Element;
type WaveformCanvasProps = Omit<
CanvasHTMLAttributes<HTMLCanvasElement>,
"children"
> & {
backgroundColor?: string;
idleStrokeColor?: string;
lineWidth?: number;
strokeColor?: string;
};import { WaveformCanvas } from "@webaudio-kit/react";
function Signal() {
return (
<WaveformCanvas
aria-label="Waveform analyser"
height={180}
idleStrokeColor="#394135"
lineWidth={2}
strokeColor="#c8ea3a"
style={{ width: "100%", height: 140 }}
width={720}
/>
);
}| Name | Type | Default | Notes |
|---|---|---|---|
WaveformCanvasProps.strokeColor | string | "#c8ea3a" | Stroke color used when analyser data is available. |
WaveformCanvasProps.idleStrokeColor | string | n/a | Optional separate stroke color for the idle center line. |
WaveformCanvasProps.backgroundColor | string | "#10110f" | Canvas fill color. |
WaveformCanvasProps.lineWidth | number | 2 | Canvas stroke width. |
SpectrumCanvas
Draws analyser frequency-domain data into compact bars and renders low idle bars before audio exists. Keep width/height as the backing buffer and use style or className for responsive CSS sizing.
function SpectrumCanvas(props: SpectrumCanvasProps): JSX.Element;
type SpectrumCanvasProps = Omit<
CanvasHTMLAttributes<HTMLCanvasElement>,
"children"
> & {
backgroundColor?: string;
barColor?: string;
barCount?: number;
barGap?: number;
idleBarColor?: string;
minBarHeight?: number;
};import { SpectrumCanvas } from "@webaudio-kit/react";
function Spectrum() {
return (
<SpectrumCanvas
aria-label="Spectrum analyser"
backgroundColor="#10110f"
barColor="#8ed8ff"
barCount={48}
barGap={2}
height={140}
idleBarColor="#394135"
minBarHeight={2}
style={{ width: "100%", height: 120 }}
width={720}
/>
);
}| Name | Type | Default | Notes |
|---|---|---|---|
SpectrumCanvasProps.barColor | string | "#c8ea3a" | Bar color used when analyser data is available. |
SpectrumCanvasProps.idleBarColor | string | n/a | Optional separate bar color for the idle state. |
SpectrumCanvasProps.backgroundColor | string | "#10110f" | Canvas fill color. |
SpectrumCanvasProps.barCount | number | 48 | Number of bars to draw from the analyser bins. |
SpectrumCanvasProps.barGap | number | 2 | Gap in canvas pixels between bars. |
SpectrumCanvasProps.minBarHeight | number | 2 | Minimum rendered bar height so idle state stays visible. |
useAudioTestMode
Runs a short low-gain sequence that checks tone output, stereo pan, sweep scheduling, noise generation, and analyser routing.
function useAudioTestMode(options?: AudioTestModeOptions): AudioTestModeControls;
type AudioTestModeOptions = {
gapMs?: number;
steps?: AudioTestModeStep[];
};
type AudioTestModeControls = {
currentStep: AudioTestModeStep | null;
currentStepIndex: number;
isRunning: boolean;
previewStep: AudioTestModeStep | null;
previewStepIndex: number;
run(): Promise<void>;
stop(): void;
steps: AudioTestModeStep[];
};import { useAudioTestMode } from "@webaudio-kit/react";
function AudioSelfCheck() {
const testMode = useAudioTestMode();
return (
<>
<button onClick={() => void testMode.run()}>Run test</button>
<button onClick={testMode.stop}>Stop</button>
<span>{testMode.previewStep?.label ?? "Idle"}</span>
</>
);
}| Name | Type | Default | Notes |
|---|---|---|---|
AudioTestModeOptions.gapMs | number | 120 | Delay between steps. |
AudioTestModeOptions.steps | AudioTestModeStep[] | n/a | Custom sequence. Falls back to the package default steps when omitted or empty. |
AudioTestModeControls.currentStep | AudioTestModeStep | null | n/a | The active step while the sequence is running. currentStep remains null before run. |
AudioTestModeControls.previewStep | AudioTestModeStep | null | n/a | previewStep points at the first planned step before run, follows the active step while running, and resets to the first planned step after stop. |
AudioTestModeControls.previewStepIndex | number | n/a | Index for previewStep. Use it to highlight the initial or active planned step without guessing. |
AudioTestModeControls.run() | Promise<void> | n/a | Starts the full sequence from a user action. |
AudioProvider state machine
useAudioContext().state can return idle, suspended, running, or closed. idle is a webaudio-kit value, not a native browser AudioContextState.
| Name | Type | Default | Notes |
|---|---|---|---|
initial render | "idle" | n/a | No AudioContext, master gain, or analyser has been created. |
first user gesture | "suspended" | "running" | n/a | play(), setGain(), or ensureAudioContext() creates the graph and asks the browser to resume audio. |
resume allowed | "running" | n/a | The provider mirrors the native AudioContext state after browser autoplay policy allows playback. |
stopAll() | "running" | "suspended" | n/a | Stops active and scheduled hook playback, but does not close the shared AudioContext. |
provider unmount | "closed" | n/a | The provider closes the context when the browser allows close(). |
audio unavailable | "idle" | n/a | If AudioContext creation fails, hooks reject with the browser error and state remains usable for UI. |
import { useAudioContext } from "@webaudio-kit/react";
function AudioStateBadge() {
const audio = useAudioContext();
const label =
audio.state === "idle"
? "Idle: audio has not been created yet"
: `AudioContext: ${audio.state}`;
return <span aria-label={label}>{audio.state}</span>;
}Keep first playback directly inside click, tap, or keyboard handlers. Browsers may leave the context suspended until a gesture satisfies autoplay policy.
Core helpers
These exports come from @webaudio-kit/core and are also re-exported by the React package for convenience.
| Name | Type | Default | Notes |
|---|---|---|---|
PlaybackFilter | { frequency: number; q?: number; type?: BiquadFilterType } | n/a | Optional filter routing shared by tone, sweep, and noise options. Defaults to lowpass when set. |
PlaybackVoices | { count?: number; spreadCents?: number } | n/a | Optional oscillator voice layering for tone and sweep options. count is bounded to 1..8. |
PlaybackEnvelope | { attackMs?: number; decayMs?: number; sustain?: number; releaseMs?: number } | n/a | Optional gain envelope shared by tone, sweep, and noise options. Durations use milliseconds. |
dbToGain(db) | (db: number) => number | n/a | Returns 10 ** (db / 20). Use it when UI stores volume in decibels but Web Audio needs gain. |
gainToDb(gain) | (gain: number) => number | n/a | Returns 20 * log10(gain). Zero, negative, and non-finite values return -Infinity. |
clampFrequency(value, min, max) | (value: number, min?: number, max?: number) => number | 20..20000 | Clamps a frequency into the configured range and normalizes swapped min and max values. |
midiToFrequency(midiNote, concertA) | (midiNote: number, concertA?: number) => number | A4 = 440 | Converts a MIDI note number to Hz. Invalid input returns NaN. |
frequencyToMidi(frequency, concertA) | (frequency: number, concertA?: number) => number | A4 = 440 | Converts Hz to a fractional MIDI note number. Invalid input returns NaN. |
frequencyToNoteName(frequency, options) | (frequency: number, options?: NoteNameOptions) => string | n/a | Returns labels such as "A4" or "A4 +3c". Invalid input returns "unknown". |
PlaybackPattern | { repeat?: number; gapMs?: number } | n/a | Optional repeat schedule shared by tone, sweep, and noise options. repeat is total plays; gapMs is silence between plays. |
playTone(context, options, destination) | (AudioContext, ToneOptions, AudioNode?) => PlaybackHandle | n/a | Creates oscillator, gain, optional stereo panner, starts playback, and returns stop cleanup for one shot or the full pattern. |
playFrequencySweep(context, options, destination) | (AudioContext, FrequencySweepOptions, AudioNode?) => PlaybackHandle | n/a | Creates an oscillator and schedules a linear frequency ramp between clamped endpoints. |
playNoise(context, options, destination) | (AudioContext, NoiseOptions, AudioNode?) => PlaybackHandle | n/a | Generates a white, pink, or brown noise buffer for the requested duration. |
import {
clampFrequency,
dbToGain,
frequencyToNoteName,
gainToDb,
} from "@webaudio-kit/core";
const frequency = clampFrequency(inputFrequency);
const gain = dbToGain(-14);
const db = gainToDb(0.2);
const note = frequencyToNoteName(440, { includeCents: true });