UNPKG

websfx

Version:

Play synthesized UI sound effects using the Web Audio API

89 lines (82 loc) • 2.21 kB
import type { Config } from './types'; import { clamp } from './utils'; /** * The shared audio graph that all sounds play through. */ interface AudioIO { context: AudioContext; master: GainNode; } let audio: AudioIO | undefined; let config: Config = { volume: 1 }; /** * Returns the shared audio graph, creating the `AudioContext` lazily on * first use. * * @returns The audio graph, or `undefined` when Web Audio is unavailable * (for example during server-side rendering) or when the master volume * is `0`. */ export function getAudio(): AudioIO | undefined { if (config.volume <= 0) return undefined; const io = ensureAudio(); if (io?.context.state === 'suspended') { void io.context.resume().catch(() => undefined); } return io; } /** * Reads or updates the global sound configuration. * * Called with a partial configuration it applies the update first. Always * returns the current configuration. Set `volume` to `0` to mute. * * @example * ```ts * configure({ volume: 0.5 }); * configure({ volume: 0 }); // mute * const { volume } = configure(); * ``` * * @param options - Partial configuration to merge. * @returns The current configuration. */ export function configure(options?: Partial<Config>): Readonly<Config> { if (options?.volume !== undefined) { config = { volume: clamp(options.volume) }; if (audio) { audio.master.gain.value = config.volume; } } return { ...config }; } /** * Creates the `AudioContext` and master gain node on first use. * * @returns The audio graph, or `undefined` when Web Audio is unavailable. */ function ensureAudio(): AudioIO | undefined { if (audio) return audio; if (typeof AudioContext === 'undefined') return undefined; let context: AudioContext; try { context = new AudioContext(); } catch { return undefined; } const master = context.createGain(); master.gain.value = config.volume; master.connect(context.destination); audio = { context, master }; return audio; } /** * Clears the memoized `AudioContext` and restores the default * configuration. * * @internal */ export function reset(): void { audio = undefined; config = { volume: 1 }; }