@aosengine/audio
Interfaces
AudioBuses
The bus gain nodes, keyed by name.
Properties
master
ts
readonly master: GainNode;Sums sfx, music and voice; connected to context.destination.
music
ts
readonly music: GainNode;Music beds.
sfx
ts
readonly sfx: GainNode;One-shot gameplay sounds.
voice
ts
readonly voice: GainNode;Dialogue and say lines.
AudioEngine
The audio service: everything the host needs to run a frame of sound.
Properties
buses
ts
readonly buses: AudioBuses;The bus gain nodes. Adjust bus.gain.value for mixer sliders.
context
ts
readonly context: AudioContext;The context the graph lives on.
ended
ts
readonly ended: number[];Handles of sounds that ran to their natural end since the host last cleared this array. AudioEngine.update appends to it; the host turns each entry into a sound-ended event and then clears it with ended.length = 0.
A voice the game stopped itself — AudioEngine.stop, or a AudioEngine.play reusing a live handle — is not listed: the game already knows, and reporting it would claim a completion that never happened. Capped at 256 entries so a host that never drains it cannot grow the array without bound.
Methods
decode()
ts
decode(id, data): Promise<AudioBuffer>;Decode encoded audio bytes, memoised by id.
Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | Manifest asset id, the cache key. |
data | ArrayBuffer | Encoded bytes. |
Returns
Promise<AudioBuffer>
The decoded buffer. Repeat calls with the same id share a promise.
dispose()
ts
dispose(): void;Stop everything, drop the graph, and close a context this engine created.
Returns
void
play()
ts
play(args): void;Start a voice.
Parameters
| Parameter | Type | Description |
|---|---|---|
args | PlayArgs | What to play, where and how loud. |
Returns
void
resume()
ts
resume(): Promise<void>;Resume a context the browser suspended. Safe to call repeatedly.
Returns
Promise<void>
Resolves once the context is running.
setListener()
ts
setListener(pos, rotQuat): void;Move the listener.
Parameters
| Parameter | Type | Description |
|---|---|---|
pos | Vec3 | World position. |
rotQuat | Quat | Orientation; forward is local -Z, up is local +Y. |
Returns
void
setVolume()
ts
setVolume(id, v): void;Change a playing voice's gain.
Parameters
| Parameter | Type | Description |
|---|---|---|
id | number | The sound handle. Unknown ids are ignored. |
v | number | Linear gain, 0..1. |
Returns
void
stop()
ts
stop(id): void;Stop a voice now. Nothing is added to AudioEngine.ended: the caller asked for this, so it is not a completion.
Parameters
| Parameter | Type | Description |
|---|---|---|
id | number | The handle passed to AudioEngine.play. Unknown ids are ignored. |
Returns
void
update()
ts
update(): void;Retire every voice whose buffer has run out and drain them into ended.
Timing comes from context.currentTime, the clock the voices themselves run on, not from the caller's frame delta: a long frame, a background tab or a timeScale change cannot drift the two apart. A suspended context does not advance, and neither does playback, so nothing ends early.
Returns
void
AudioEngineOptions
Options for createAudioEngine.
Extended by
Properties
context?
ts
optional context?: AudioContext;An existing context to drive. When omitted a new AudioContext is constructed, which requires a DOM environment. Pass one in tests.
masterVolume?
ts
optional masterVolume?: number;Linear gain on the master bus, 0..1. Defaults to 1.
AudioModule
The 'audio' module. Its service is the AudioEngine it owns.
Extends
Properties
id
ts
readonly id: string;Unique id. Also the service id when init returns a service.
Inherited from
order?
ts
readonly optional order?: number;Sort key. Lower runs first; equal keys keep registration order.
Rough convention: input -100, gameplay -50, physics 0, rendering helpers 200. Gameplay runs before physics so that the commands a guest tick emits are simulated by the step that follows rather than the next one.
Inherited from
service
ts
readonly service: AudioEngine | null;The audio engine this module owns, or null before init and after dispose.
The engine is built by init, not by audio: constructing an AudioContext is a side effect on the page — browsers count them, and an unlocked one logs a warning — so a module that is never registered must never make one. init returns the engine, so the registry publishes it under 'audio' and engine.get('audio') hands back this same object.
Methods
beginFrame()?
ts
optional beginFrame(): void;Run before the frame's fixed steps. Input capture lives here.
Returns
void
Inherited from
decodeAsset()
ts
decodeAsset(idOrHandle): Promise<AudioBuffer>;Decode the bytes behind an asset id or handle, memoised.
This is the bridge from a play-sound command — which carries an asset handle, never a URL — to the AudioBuffer AudioEngine.play wants. The asset must already be loaded; type: 'audio' entries load as an ArrayBuffer.
Parameters
| Parameter | Type | Description |
|---|---|---|
idOrHandle | string | number | Manifest asset id, or the handle the guest minted for it. |
Returns
Promise<AudioBuffer>
The decoded buffer; rejects when the asset is missing or not audio.
decodedAsset()
ts
decodedAsset(idOrHandle): AudioBuffer | undefined;The already-decoded buffer for an asset, without awaiting anything.
This is what lets the host play a repeated sound — a footstep, a shot — inside the frame that asked for it instead of a microtask later. A miss means "not decoded yet"; fall back to AudioModule.decodeAsset.
Handles and ids share one cache entry: a handle is normalised through the asset registry first, so decodedAsset(7) and decodedAsset('sfx.shot') hit the same buffer.
Parameters
| Parameter | Type | Description |
|---|---|---|
idOrHandle | string | number | Manifest asset id, or the handle the guest minted for it. |
Returns
AudioBuffer | undefined
The decoded buffer, or undefined when no decode has finished.
dispose()
ts
dispose(): void;Release everything this module took.
Returns
void
Inherited from
endFrame()?
ts
optional endFrame(): void;Run after rendering. Input's end-of-frame bookkeeping lives here.
Returns
void
Inherited from
fixedUpdate()?
ts
optional fixedUpdate(dt): void;Run once per fixed step.
Parameters
| Parameter | Type | Description |
|---|---|---|
dt | number | Always ctx.config.fixedDt, whatever time.timeScale is; time scale changes how many steps a frame runs, not their length. |
Returns
void
Inherited from
init()
ts
init(ctx): AudioEngine;Build the engine and publish it as the 'audio' service.
Parameters
| Parameter | Type | Description |
|---|---|---|
ctx | EngineContext | The host surface; only ctx.assets is read. |
Returns
The audio engine.
Overrides
update()
ts
update(dt, alpha): void;Pump the engine: retire finished voices and fill service.ended. A no-op before init.
Always present on this module, so callers need no optional call.
Parameters
| Parameter | Type | Description |
|---|---|---|
dt | number | Wall-clock seconds since the previous frame; unused, because the engine times voices on the audio context's own clock. |
alpha | number | Interpolation factor; unused by audio. |
Returns
void
Overrides
AudioModuleOptions
Options for audio.
Extends
Properties
context?
ts
optional context?: AudioContext;An existing context to drive. When omitted a new AudioContext is constructed, which requires a DOM environment. Pass one in tests.
Inherited from
masterVolume?
ts
optional masterVolume?: number;Linear gain on the master bus, 0..1. Defaults to 1.
Inherited from
AudioEngineOptions.masterVolume
order?
ts
optional order?: number;Position in the module order. Lower runs first. Defaults to 30.
unlockTarget?
ts
optional unlockTarget?: EventTarget;Where the one-time unlock listener is installed. Defaults to the global object; pass the canvas to scope it, or a stub in tests.
PlayArgs
One call to AudioEngine.play.
Properties
buffer
ts
buffer: AudioBuffer;The decoded buffer to play, normally from AudioEngine.decode.
bus?
ts
optional bus?: BusName;Bus to route through. Defaults to 'sfx'.
id
ts
id: number;Guest-minted sound handle. Replaces any sound already using this handle.
loop?
ts
optional loop?: boolean;Loop until stopped. Looping voices never end on their own. Defaults to false.
pos?
ts
optional pos?: Vec3;World position. When given the voice gets an HRTF PannerNode.
volume?
ts
optional volume?: number;Linear gain, 0..1. Defaults to 1.
Type Aliases
BusName
ts
type BusName = "master" | "sfx" | "music" | "voice";The buses a voice can be routed to. master is the sum of the other three.
Quat
ts
type Quat = readonly [number, number, number, number];A rotation, as a plain [x, y, z, w] quaternion (three.js / Jolt order).
Vec3
ts
type Vec3 = readonly [number, number, number];A world-space position, as a plain [x, y, z] array.
Variables
PACKAGE
ts
const PACKAGE: "@aosengine/audio";Package identity marker.
Example
ts
import { PACKAGE } from '@aosengine/audio';
console.log(PACKAGE); // '@aosengine/audio'Functions
audio()
ts
function audio(options?): AudioModule;Create the audio module.
Register it in the engine's module list. init builds the AudioEngine and returns it, so it becomes the 'audio' service: the host maps play-sound / stop-sound / set-listener straight onto its methods and drains ended into sound-ended events each frame. Until then AudioModule.service is null and no AudioContext exists.
Browsers keep an AudioContext suspended until the page sees a user gesture, so init installs a single pointerdown + keydown listener that calls resume() once and then removes itself.
Parameters
| Parameter | Type | Description |
|---|---|---|
options | AudioModuleOptions | Engine options, plus the unlock target and module order. |
Returns
The module, ready to register.
Example
ts
import { audio } from '@aosengine/audio';
const mod = audio({ masterVolume: 0.8 });
const engine = mod.init(ctx);
const buffer = await mod.decodeAsset('pistol');
engine.play({ id: 1, buffer, pos: [0, 1, -3] });
mod.update(1 / 60, 0);
// The next shot needs no await: the decode has already settled.
const again = mod.decodedAsset('pistol');
if (again) engine.play({ id: 2, buffer: again });createAudioEngine()
ts
function createAudioEngine(options?): AudioEngine;Create the audio engine.
The graph is voice -> [panner] -> bus -> master -> destination. Nothing is allocated per frame: voices are pooled, the listener basis is written into scratch arrays, and ended is reused.
Parameters
| Parameter | Type | Description |
|---|---|---|
options | AudioEngineOptions | Context to adopt and initial master gain. |
Returns
The engine, which is also the 'audio' module's service.
Example
ts
import { createAudioEngine } from '@aosengine/audio';
const engine = createAudioEngine({ masterVolume: 0.8 });
const buffer = await engine.decode('pistol', bytes);
engine.play({ id: 1, buffer, pos: [3, 0, -4], bus: 'sfx' });
engine.update();
for (const id of engine.ended) console.log('ended', id);
engine.ended.length = 0;