arcade2d
Class

AudioInstance

audio/audio-instance.ts:42

One playing voice in the audio graph — a single connection of an AudioBuffer through per-instance gain and panner nodes into a category bus on the AudioEngine.

AudioInstance is the handle the audio-playing components (AudioSource, Music) work through. It exposes the standard playback surface — play, pause, resume, stop, restart, volume, pan, loop — and hides the Web Audio bookkeeping that makes them work (recreating AudioBufferSourceNodes, tracking elapsed time across pause/resume).

Pause semantics

A Web Audio AudioBufferSourceNode cannot be paused once it has started — it can only be stopped, and stopping is terminal. To implement pause/resume, this class:

  1. Records currentTime when AudioInstance.play starts the source, plus the buffer offset it was started at.
  2. On AudioInstance.pause, computes the elapsed playback position, clamps or wraps it against the buffer duration depending on AudioInstance.loop, stores it, and stops the source.
  3. On the next AudioInstance.play, allocates a fresh source and starts it from the stored offset.

AudioInstance.stop resets the stored offset to zero, so the next AudioInstance.play resumes from the beginning.

Headless mode

When the AudioEngine has no AudioContext (a headless test environment, an SSR build, a browser that has audio disabled), every playback method is a no-op that updates the internal state flags but does not allocate Web Audio nodes. This mirrors the engine's input-component behaviour: code keeps running, audio is silently inert.

Constructors

#
constructor(engine: AudioEngine, buffer: AudioBuffer, _categoryGain: null | GainNode, options: AudioInstanceOptions): AudioInstance

Parameters

Properties

readonly #
buffer: AudioBuffer

The decoded Web Audio buffer. Typically taken from AudioAsset.raw.

readonly #
engine: AudioEngine

The AudioEngine this instance plays through. Required for context access; the engine's master/category gain nodes own the bus this instance ultimately feeds.

Accessors

readonly #
duration: number

Duration of the underlying clip in seconds. Equivalent to AudioAsset.duration for the asset this instance was built from.

#
loop: boolean

Whether the clip should loop back to its start on reaching the end. Changing this mid-play takes effect on the currently-running source — a clip that has not yet hit its end will start (or stop) looping from its next boundary.

#
pan: number

Stereo pan from -1 (left) to 1 (right). Setting it during playback applies instantly to the underlying StereoPannerNode.

readonly #
paused: boolean

Whether the clip is paused — AudioInstance.play will resume from the saved position. Mutually exclusive with AudioInstance.playing.

readonly #
playing: boolean

Whether the clip is currently advancing through the buffer (a source node is active and unpaused). Flips back to false when the clip finishes its last loop or is paused/stopped.

readonly #
stopped: boolean

Whether the clip is not currently emitting audio — true when idle, stopped, or paused; false while AudioInstance.playing is true.

#
volume: number

Per-instance volume from 0 to 1. Setting it during playback ramps the underlying gain instantly; setting it before AudioInstance.play applies on the next start.

Methods

#
destroy(): void

Tears the instance down completely: stops playback, disconnects every node from the audio graph, and drops them. The instance is not reusable after this call — discard the handle.

Called automatically by AudioSource when a one-shot SFX finishes and by Music.onDestroy when the host world tears down.

Returns

void
#
onEnded(listener: () => void): () => void

Subscribes to the natural end of playback — the moment the source reports onended because it finished its last loop (or because it was stopped). Returns an unsubscribe function. Fires at most once per play(), so call after each play if you want repeated notifications.

AudioSource uses this to prune finished one-shot voices.

Parameters

  • listener () => void

Returns

() => void
#
pause(): void

Pauses playback in place. The next AudioInstance.play resumes from this point. A no-op when the instance is not currently playing.

Returns

void
#
play(): void

Starts playback from the saved position — zero on a fresh or stopped instance, the pause offset on a paused one. Calling AudioInstance.play on an already-playing instance is a no-op (use AudioInstance.restart to restart from the beginning).

In headless mode this transitions the state flags but allocates no Web Audio nodes.

Returns

void
#
restart(): void

Stops the clip if it is running, resets the resume offset, then plays from the start. Equivalent to AudioInstance.stop followed by AudioInstance.play and the standard way to "play this sound again from scratch."

Returns

void
#
stop(): void

Stops playback and resets the resume offset to zero, so the next AudioInstance.play starts from the beginning of the clip. Idempotent — stopping an already-stopped instance is a no-op.

Returns

void
ESC