AudioManager

AudioManager is a singleton that manages all audio playback using the Web Audio API, with an automatic HTML5 Audio fallback for environments without Web Audio support.

It is mounted automatically by Game — you do not need to set it up manually.

tsx
import { getAudioManager } from "@carverjs/core/systems";

How It Works #

  1. On Game mount, the AudioContext is created and unlock listeners are attached to the document.

  2. On first user gesture (click, tap, keypress), the AudioContext is resumed and a silent buffer is played to satisfy iOS Safari requirements. Queued music begins playing.

  3. Each frame (at priority -48, after input flush), flush() runs:

    • Pauses/resumes the context based on game phase

    • Updates spatial sound positions from Object3D refs

    • Syncs the Web Audio listener to the active camera

  4. On Game unmount, all sounds stop, the AudioContext closes, and all resources are freed.


Audio Backend Detection #

The system auto-detects the best available backend:

BackendWhen UsedFeatures
Web Audio APIAudioContext is available (98%+ of browsers)Full features: spatial audio, gain automation, AudioParam scheduling
HTML5 AudioAudioContext unavailableBasic playback, volume via audio.volume, no spatial audio

The fallback is transparent — the public API is identical regardless of backend.


Volume Routing (Web Audio) #

text
[Source] → [Instance Gain] → [Channel Gain] → [Master Gain] → destination
                                    │
                              One per channel:
                              sfx, music, ui,
                              ambient, voice

Channel gains are created once and persist for the lifetime of the AudioContext. Mute is implemented by setting gain to 0 and restoring on unmute.


API #

getAudioManager() #

Returns the singleton AudioManager instance. Creates one if it doesn't exist.

destroyAudioManager() #

Stops all sounds, closes the AudioContext, and destroys the singleton. Called automatically when Game unmounts.

Sound Registration #

MethodDescription
registerSound(name, def)Register a sound definition. Preloads by default
unregisterSound(name)Unregister and stop all instances

Playback #

MethodDescription
play(name, options?)Play a registered sound. Returns SoundHandle
stopByName(name)Stop all instances of a sound
pauseByName(name)Pause all instances
resumeByName(name)Resume paused instances
isSoundPlaying(name)Check if any instance is playing

Music #

MethodDescription
playMusic(src, options?)Play a music track with crossfade
stopMusic(fadeOut?)Stop music with optional fade-out
pauseMusic()Pause the music
resumeMusic()Resume the music
isMusicPlaying()Check if music is playing

Volume #

MethodDescription
setChannelVolume(channel, volume)Set channel volume (0–1)
getChannelVolume(channel)Get channel volume
setChannelMute(channel, muted)Mute/unmute a channel
isChannelMuted(channel)Check mute state
setMasterMute(muted)Mute/unmute all audio

Preloading #

MethodDescription
preload(name)Preload a registered sound
preloadAll(names)Preload multiple sounds
unloadBuffer(name)Free a sound's buffer from memory

Listener #

MethodDescription
setListenerSource(obj)Set the default listener (camera). Called by AudioFlush
setCustomListener(obj)Override the listener. Called by AudioListener component

Usage #

Most game code should use the useAudio hook. Direct manager access is useful for systems-level code:

tsx
import { getAudioManager } from "@carverjs/core/systems";
import { useGameLoop } from "@carverjs/core/hooks";

function AmbientSystem() {
  useGameLoop(() => {
    const mgr = getAudioManager();
    if (mgr.isSoundPlaying("rain")) return;
    mgr.play("rain", { loop: true });
  });
  return null;
}

Type Definitions #

See Types for AudioChannel, SoundDefinition, PlaySoundOptions, SoundHandle, MusicOptions, and SoundState.