@sadhaka/loom-engine 0.14.0 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/audio/audio-asset-cache.d.ts +12 -0
- package/dist/audio/audio-asset-cache.d.ts.map +1 -0
- package/dist/audio/audio-asset-cache.js +53 -0
- package/dist/audio/audio-asset-cache.js.map +1 -0
- package/dist/audio/audio-asset-loader.d.ts +16 -0
- package/dist/audio/audio-asset-loader.d.ts.map +1 -0
- package/dist/audio/audio-asset-loader.js +100 -0
- package/dist/audio/audio-asset-loader.js.map +1 -0
- package/dist/audio/audio-listener-resource.d.ts +19 -0
- package/dist/audio/audio-listener-resource.d.ts.map +1 -0
- package/dist/audio/audio-listener-resource.js +57 -0
- package/dist/audio/audio-listener-resource.js.map +1 -0
- package/dist/audio/cue-catalog.d.ts +39 -0
- package/dist/audio/cue-catalog.d.ts.map +1 -0
- package/dist/audio/cue-catalog.js +186 -0
- package/dist/audio/cue-catalog.js.map +1 -0
- package/dist/audio/music-director.d.ts +18 -0
- package/dist/audio/music-director.d.ts.map +1 -0
- package/dist/audio/music-director.js +177 -0
- package/dist/audio/music-director.js.map +1 -0
- package/dist/audio/spatial-audio-bus.d.ts +66 -0
- package/dist/audio/spatial-audio-bus.d.ts.map +1 -0
- package/dist/audio/spatial-audio-bus.js +341 -0
- package/dist/audio/spatial-audio-bus.js.map +1 -0
- package/dist/audio/spatial-audio-system.d.ts +17 -0
- package/dist/audio/spatial-audio-system.d.ts.map +1 -0
- package/dist/audio/spatial-audio-system.js +98 -0
- package/dist/audio/spatial-audio-system.js.map +1 -0
- package/dist/audio/zone-audio-system.d.ts +78 -0
- package/dist/audio/zone-audio-system.d.ts.map +1 -0
- package/dist/audio/zone-audio-system.js +206 -0
- package/dist/audio/zone-audio-system.js.map +1 -0
- package/dist/index.d.ts +14 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -1
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
// MusicDirector - high-level music playback with fade + crossfade.
|
|
2
|
+
//
|
|
3
|
+
// Per LOOM-AUDIO-SPEC §4.3. Wraps AudioBufferSourceNode + GainNode
|
|
4
|
+
// chains and routes them through audioBus.input('music'). The 'music'
|
|
5
|
+
// bus is an AudioBus default (priority 'ambient'), so VE-budget gating
|
|
6
|
+
// already mutes it under load - the director does not duplicate that.
|
|
7
|
+
//
|
|
8
|
+
// State machine (single track at a time, except mid-crossfade):
|
|
9
|
+
// idle: nothing playing
|
|
10
|
+
// playing(track): one source -> one gain -> music bus
|
|
11
|
+
// crossfading(from -> to): two sources, two gains, both ramping
|
|
12
|
+
//
|
|
13
|
+
// playMusic(name, fadeIn): stops prior immediately (no fade), creates a
|
|
14
|
+
// new source+gain at gain=0, ramps to 1 over fadeInMs (default 500).
|
|
15
|
+
// Loops by default. No-op if asset not in cache.
|
|
16
|
+
//
|
|
17
|
+
// stopMusic(fadeOut): ramps current gain to 0 over fadeOutMs (default
|
|
18
|
+
// 800), stops source after fade. Resolves when fade completes. Safe
|
|
19
|
+
// when nothing playing.
|
|
20
|
+
//
|
|
21
|
+
// crossfadeMusic(name, fade): starts new track gain=0, ramps prior to 0
|
|
22
|
+
// + new to 1 simultaneously over fadeMs (default 1000), stops prior
|
|
23
|
+
// after fade. If nothing was playing, equivalent to playMusic with the
|
|
24
|
+
// same fade in.
|
|
25
|
+
const DEFAULT_FADE_IN_MS = 500;
|
|
26
|
+
const DEFAULT_FADE_OUT_MS = 800;
|
|
27
|
+
const DEFAULT_CROSSFADE_MS = 1000;
|
|
28
|
+
export class MusicDirector {
|
|
29
|
+
audioBus;
|
|
30
|
+
cache;
|
|
31
|
+
current = null;
|
|
32
|
+
constructor(audioBus, cache) {
|
|
33
|
+
this.audioBus = audioBus;
|
|
34
|
+
this.cache = cache;
|
|
35
|
+
}
|
|
36
|
+
static create(audioBus, cache) {
|
|
37
|
+
return new MusicDirector(audioBus, cache);
|
|
38
|
+
}
|
|
39
|
+
// Start a music track. If music is already playing, stops it
|
|
40
|
+
// immediately (no fade). Use crossfadeMusic for smooth transitions.
|
|
41
|
+
// No-op if asset not in cache.
|
|
42
|
+
playMusic(name, fadeInMs) {
|
|
43
|
+
var buffer = this.cache.get(name);
|
|
44
|
+
if (!buffer)
|
|
45
|
+
return;
|
|
46
|
+
// Stop prior immediately - no fade.
|
|
47
|
+
if (this.current) {
|
|
48
|
+
this.hardStop(this.current);
|
|
49
|
+
this.current = null;
|
|
50
|
+
}
|
|
51
|
+
var fade = fadeInMs !== undefined ? fadeInMs : DEFAULT_FADE_IN_MS;
|
|
52
|
+
this.current = this.startTrack(name, buffer, fade);
|
|
53
|
+
}
|
|
54
|
+
// Stop the current track with a fade-out. Resolves when fade
|
|
55
|
+
// completes. Safe to call when no music is playing.
|
|
56
|
+
stopMusic(fadeOutMs) {
|
|
57
|
+
var track = this.current;
|
|
58
|
+
if (!track)
|
|
59
|
+
return Promise.resolve();
|
|
60
|
+
var fade = fadeOutMs !== undefined ? fadeOutMs : DEFAULT_FADE_OUT_MS;
|
|
61
|
+
this.current = null;
|
|
62
|
+
return this.fadeOutAndStop(track, fade);
|
|
63
|
+
}
|
|
64
|
+
// Smoothly transition to a different track. If no track is playing,
|
|
65
|
+
// equivalent to playMusic with fadeMs as the fade-in. Same name as
|
|
66
|
+
// current is treated as a fresh play (the new buffer plays, prior
|
|
67
|
+
// fades; useful when the buffer was reloaded with a new variant).
|
|
68
|
+
crossfadeMusic(name, fadeMs) {
|
|
69
|
+
var buffer = this.cache.get(name);
|
|
70
|
+
if (!buffer)
|
|
71
|
+
return;
|
|
72
|
+
var fade = fadeMs !== undefined ? fadeMs : DEFAULT_CROSSFADE_MS;
|
|
73
|
+
var prior = this.current;
|
|
74
|
+
var next = this.startTrack(name, buffer, fade);
|
|
75
|
+
this.current = next;
|
|
76
|
+
if (prior) {
|
|
77
|
+
// Fade prior out; clean up after fade. We do not await - crossfade
|
|
78
|
+
// is fire-and-forget. If a NEW playMusic / crossfadeMusic call
|
|
79
|
+
// arrives mid-fade, hardStop on the prior (which is no longer
|
|
80
|
+
// referenced as `current`) is safe; the in-flight setTimeout
|
|
81
|
+
// closure will then call stop() on an already-stopped source,
|
|
82
|
+
// which the standard tolerates.
|
|
83
|
+
this.fadeOutAndStop(prior, fade);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// Currently-playing track name; null if silent. Mid-crossfade returns
|
|
87
|
+
// the NEW (incoming) track name - the prior is fading out and is no
|
|
88
|
+
// longer the canonical "current".
|
|
89
|
+
currentMusic() {
|
|
90
|
+
return this.current ? this.current.name : null;
|
|
91
|
+
}
|
|
92
|
+
// ---------- private ----------
|
|
93
|
+
startTrack(name, buffer, fadeInMs) {
|
|
94
|
+
var ctx = this.audioBus.ctx;
|
|
95
|
+
var source = ctx.createBufferSource();
|
|
96
|
+
source.buffer = buffer;
|
|
97
|
+
source.loop = true;
|
|
98
|
+
var gain = ctx.createGain();
|
|
99
|
+
var now = ctx.currentTime;
|
|
100
|
+
var fadeSec = Math.max(0, fadeInMs) / 1000;
|
|
101
|
+
if (fadeSec <= 0) {
|
|
102
|
+
gain.gain.value = 1;
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
// setValueAtTime + linearRampToValueAtTime is the canonical
|
|
106
|
+
// Web Audio fade pattern. Browsers schedule the ramp on the
|
|
107
|
+
// audio thread; no JS timer needed for the audio side.
|
|
108
|
+
gain.gain.setValueAtTime(0, now);
|
|
109
|
+
gain.gain.linearRampToValueAtTime(1, now + fadeSec);
|
|
110
|
+
}
|
|
111
|
+
source.connect(gain).connect(this.audioBus.input('music'));
|
|
112
|
+
source.start();
|
|
113
|
+
return { name: name, source: source, gain: gain };
|
|
114
|
+
}
|
|
115
|
+
fadeOutAndStop(track, fadeOutMs) {
|
|
116
|
+
var ctx = this.audioBus.ctx;
|
|
117
|
+
var now = ctx.currentTime;
|
|
118
|
+
var fadeSec = Math.max(0, fadeOutMs) / 1000;
|
|
119
|
+
if (fadeSec <= 0) {
|
|
120
|
+
// Immediate stop.
|
|
121
|
+
this.hardStop(track);
|
|
122
|
+
return Promise.resolve();
|
|
123
|
+
}
|
|
124
|
+
// Cancel any prior ramps on this gain (e.g. an in-progress fade-in)
|
|
125
|
+
// so the fade-out starts from the actual current value rather than
|
|
126
|
+
// a stale ramp target. cancelScheduledValues + setValueAtTime at
|
|
127
|
+
// the live gain.value is the standard pattern.
|
|
128
|
+
try {
|
|
129
|
+
track.gain.gain.cancelScheduledValues(now);
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
// some implementations / mocks may lack cancelScheduledValues;
|
|
133
|
+
// best-effort
|
|
134
|
+
}
|
|
135
|
+
var startVal = track.gain.gain.value;
|
|
136
|
+
track.gain.gain.setValueAtTime(startVal, now);
|
|
137
|
+
track.gain.gain.linearRampToValueAtTime(0, now + fadeSec);
|
|
138
|
+
return new Promise((resolve) => {
|
|
139
|
+
// Timer in JS-land mirrors the audio-thread ramp duration. After
|
|
140
|
+
// the fade window, hardStop disconnects the nodes and stops the
|
|
141
|
+
// source. setTimeout in tests runs against fake timers if the
|
|
142
|
+
// test installs them, but in production the duration matches the
|
|
143
|
+
// ramp.
|
|
144
|
+
setTimeout(() => {
|
|
145
|
+
this.hardStop(track);
|
|
146
|
+
resolve();
|
|
147
|
+
}, fadeOutMs);
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
hardStop(track) {
|
|
151
|
+
try {
|
|
152
|
+
track.source.stop();
|
|
153
|
+
}
|
|
154
|
+
catch {
|
|
155
|
+
// source.stop() throws if already-stopped on some implementations
|
|
156
|
+
// or if start() was never called - we don't treat that as an
|
|
157
|
+
// error.
|
|
158
|
+
}
|
|
159
|
+
try {
|
|
160
|
+
track.source.disconnect();
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
// ignore
|
|
164
|
+
}
|
|
165
|
+
try {
|
|
166
|
+
track.gain.disconnect();
|
|
167
|
+
}
|
|
168
|
+
catch {
|
|
169
|
+
// ignore
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
// Resource key for the world's resource registry. Engine consumers
|
|
174
|
+
// register a MusicDirector instance under this key alongside the audio
|
|
175
|
+
// bus + asset cache.
|
|
176
|
+
export const RESOURCE_MUSIC_DIRECTOR = 'music_director';
|
|
177
|
+
//# sourceMappingURL=music-director.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"music-director.js","sourceRoot":"","sources":["../../src/audio/music-director.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { AudioBus } from './audio-bus.js';
|
|
2
|
+
export interface PositionalPlayOptions {
|
|
3
|
+
x: number;
|
|
4
|
+
y: number;
|
|
5
|
+
z?: number;
|
|
6
|
+
distanceModel?: 'linear' | 'inverse' | 'exponential';
|
|
7
|
+
refDistance?: number;
|
|
8
|
+
maxDistance?: number;
|
|
9
|
+
rolloffFactor?: number;
|
|
10
|
+
gain?: number;
|
|
11
|
+
rate?: number;
|
|
12
|
+
loop?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface AudioListenerPose {
|
|
15
|
+
x: number;
|
|
16
|
+
y: number;
|
|
17
|
+
z?: number;
|
|
18
|
+
forward?: {
|
|
19
|
+
x: number;
|
|
20
|
+
y: number;
|
|
21
|
+
z: number;
|
|
22
|
+
};
|
|
23
|
+
up?: {
|
|
24
|
+
x: number;
|
|
25
|
+
y: number;
|
|
26
|
+
z: number;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export interface SpatialSourceHandle {
|
|
30
|
+
stop(): void;
|
|
31
|
+
setPosition(x: number, y: number, z?: number): void;
|
|
32
|
+
fadeOut(durationMs: number): Promise<void>;
|
|
33
|
+
isPlaying(): boolean;
|
|
34
|
+
}
|
|
35
|
+
export declare const SPATIAL_BUS_NAME = "spatial";
|
|
36
|
+
export declare function spatialDistance(listener: {
|
|
37
|
+
x: number;
|
|
38
|
+
y: number;
|
|
39
|
+
z?: number;
|
|
40
|
+
}, source: {
|
|
41
|
+
x: number;
|
|
42
|
+
y: number;
|
|
43
|
+
z?: number;
|
|
44
|
+
}): number;
|
|
45
|
+
export declare class SpatialAudioBus {
|
|
46
|
+
private readonly audioBus;
|
|
47
|
+
private readonly ctx;
|
|
48
|
+
private active;
|
|
49
|
+
private lastPose;
|
|
50
|
+
private constructor();
|
|
51
|
+
static create(audioBus: AudioBus): SpatialAudioBus;
|
|
52
|
+
getAudioBus(): AudioBus;
|
|
53
|
+
getListenerPose(): AudioListenerPose;
|
|
54
|
+
setListener(pose: AudioListenerPose): void;
|
|
55
|
+
playPositional(buffer: AudioBuffer, options: PositionalPlayOptions): SpatialSourceHandle | null;
|
|
56
|
+
playPositionalTone(freq: number, durationMs: number, options: PositionalPlayOptions & {
|
|
57
|
+
type?: OscillatorType;
|
|
58
|
+
}): SpatialSourceHandle | null;
|
|
59
|
+
stopAll(): void;
|
|
60
|
+
dispose(): void;
|
|
61
|
+
private canPlay;
|
|
62
|
+
private startSource;
|
|
63
|
+
private applyPositionTo;
|
|
64
|
+
private releaseSource;
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=spatial-audio-bus.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spatial-audio-bus.d.ts","sourceRoot":"","sources":["../../src/audio/spatial-audio-bus.ts"],"names":[],"mappings":"AA0CA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAI/C,MAAM,WAAW,qBAAqB;IAGpC,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IAEV,CAAC,CAAC,EAAE,MAAM,CAAC;IAKX,aAAa,CAAC,EAAE,QAAQ,GAAG,SAAS,GAAG,aAAa,CAAC;IACrD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAID,MAAM,WAAW,iBAAiB;IAChC,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,CAAC,EAAE,MAAM,CAAC;IAEX,OAAO,CAAC,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAE9C,EAAE,CAAC,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC1C;AAKD,MAAM,WAAW,mBAAmB;IAGlC,IAAI,IAAI,IAAI,CAAC;IAGb,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAEpD,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE3C,SAAS,IAAI,OAAO,CAAC;CACtB;AAKD,eAAO,MAAM,gBAAgB,YAAY,CAAC;AAM1C,wBAAgB,eAAe,CAC7B,QAAQ,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,CAAC,EAAE,MAAM,CAAA;CAAE,EAC9C,MAAM,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,CAAC,EAAE,MAAM,CAAA;CAAE,GAC3C,MAAM,CAeR;AAYD,qBAAa,eAAe;IAG1B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAW;IAGpC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IAGnC,OAAO,CAAC,MAAM,CAAgC;IAI9C,OAAO,CAAC,QAAQ,CAMd;IAEF,OAAO;IAgBP,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,QAAQ,GAAG,eAAe;IAMlD,WAAW,IAAI,QAAQ;IAKvB,eAAe,IAAI,iBAAiB;IAOpC,WAAW,CAAC,IAAI,EAAE,iBAAiB,GAAG,IAAI;IA6C1C,cAAc,CACZ,MAAM,EAAE,WAAW,EACnB,OAAO,EAAE,qBAAqB,GAC7B,mBAAmB,GAAG,IAAI;IAa7B,kBAAkB,CAChB,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,qBAAqB,GAAG;QAAE,IAAI,CAAC,EAAE,cAAc,CAAA;KAAE,GACzD,mBAAmB,GAAG,IAAI;IAiB7B,OAAO,IAAI,IAAI;IAaf,OAAO,IAAI,IAAI;IAcf,OAAO,CAAC,OAAO;IAcf,OAAO,CAAC,WAAW;IA2FnB,OAAO,CAAC,eAAe;IAsBvB,OAAO,CAAC,aAAa;CAQtB"}
|
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
// SpatialAudioBus - positional 3D audio for the Loom Engine.
|
|
2
|
+
//
|
|
3
|
+
// Composes the existing AudioBus (Phase 5 lock) and adds a 'spatial'
|
|
4
|
+
// sub-bus whose sources route through Web Audio PannerNodes. The
|
|
5
|
+
// existing 'sfx' / 'music' / 'voice' / 'ui' buses are untouched.
|
|
6
|
+
//
|
|
7
|
+
// Architecture per LOOM-AUDIO-SPEC.md Section 3.1:
|
|
8
|
+
//
|
|
9
|
+
// AudioContext.destination
|
|
10
|
+
// <- AudioBus.master (existing, Phase 5)
|
|
11
|
+
// <- 'sfx', 'music', 'voice', 'ui' (existing AudioBus sub-buses)
|
|
12
|
+
// <- 'spatial' (NEW: ambient priority, VE-budget gated)
|
|
13
|
+
// <- per-source PannerNode
|
|
14
|
+
// <- per-source GainNode
|
|
15
|
+
// <- AudioBufferSourceNode | OscillatorNode
|
|
16
|
+
//
|
|
17
|
+
// Each call to playPositional / playPositionalTone allocates ONE
|
|
18
|
+
// PannerNode + ONE GainNode + ONE source node. The PannerNode is reused
|
|
19
|
+
// when handle.setPosition is called - no realloc per frame for moving
|
|
20
|
+
// sources. fadeOut animates the gain to 0 over the requested duration
|
|
21
|
+
// then disconnects.
|
|
22
|
+
//
|
|
23
|
+
// VE-budget integration: SpatialAudioBus.create adds a 'spatial' bus on
|
|
24
|
+
// the underlying AudioBus with priority 'ambient'. Under VE-budget
|
|
25
|
+
// pressure (audioBudget < AUDIO_BUDGET_AMBIENT_FLOOR per audio-bus.ts)
|
|
26
|
+
// the entire spatial bus mutes; we surface that as null returns from
|
|
27
|
+
// playPositional so callers don't waste cycles building handles for
|
|
28
|
+
// inaudible sounds.
|
|
29
|
+
//
|
|
30
|
+
// Listener pose: setListener writes to AudioContext.listener
|
|
31
|
+
// (positionX/Y/Z + forwardX/Y/Z + upX/Y/Z). Per spec §8.4 the listener
|
|
32
|
+
// orientation is fixed in v1 to forward=(0,0,-1), up=(0,1,0); only
|
|
33
|
+
// position is meaningful. Modern AudioParam-style API is preferred;
|
|
34
|
+
// we fall back to the deprecated setPosition/setOrientation if the
|
|
35
|
+
// runtime exposes those instead (some test mocks).
|
|
36
|
+
//
|
|
37
|
+
// Inspirations (per PRIOR-ART.md):
|
|
38
|
+
// Web Audio PannerNode HRTF spec - W3C public technique
|
|
39
|
+
// Distance falloff models (linear / inverse / exponential) - Web
|
|
40
|
+
// Audio canonical, also FMOD / Wwise standard
|
|
41
|
+
// No patented techniques used.
|
|
42
|
+
// Name of the new sub-bus this class adds to the underlying AudioBus.
|
|
43
|
+
// Exported so consumers can adjust gain/mute via audioBus.setBusGain
|
|
44
|
+
// without depending on the literal.
|
|
45
|
+
export const SPATIAL_BUS_NAME = 'spatial';
|
|
46
|
+
// Distance helper shared with tests. Returns the Euclidean distance
|
|
47
|
+
// from the listener pose to a source. Treats undefined z as 0 and
|
|
48
|
+
// guards against NaN inputs (returns Infinity for any NaN coordinate
|
|
49
|
+
// so a defensive caller can skip muted sources cleanly).
|
|
50
|
+
export function spatialDistance(listener, source) {
|
|
51
|
+
if (Number.isNaN(listener.x) || Number.isNaN(listener.y) ||
|
|
52
|
+
Number.isNaN(source.x) || Number.isNaN(source.y) ||
|
|
53
|
+
(listener.z !== undefined && Number.isNaN(listener.z)) ||
|
|
54
|
+
(source.z !== undefined && Number.isNaN(source.z))) {
|
|
55
|
+
return Number.POSITIVE_INFINITY;
|
|
56
|
+
}
|
|
57
|
+
const dx = source.x - listener.x;
|
|
58
|
+
const dy = source.y - listener.y;
|
|
59
|
+
const lz = listener.z ?? 0;
|
|
60
|
+
const sz = source.z ?? 0;
|
|
61
|
+
const dz = sz - lz;
|
|
62
|
+
return Math.sqrt(dx * dx + dy * dy + dz * dz);
|
|
63
|
+
}
|
|
64
|
+
export class SpatialAudioBus {
|
|
65
|
+
// The composed AudioBus. We don't alter its master/sub-buses; we
|
|
66
|
+
// just add a 'spatial' sub-bus on it via addBus.
|
|
67
|
+
audioBus;
|
|
68
|
+
// The AudioContext from the underlying bus. Cached for cheap access.
|
|
69
|
+
ctx;
|
|
70
|
+
// Tracks live sources so dispose() / debug introspection can sweep.
|
|
71
|
+
active = new Set();
|
|
72
|
+
// Latest listener pose; remembered so handlers can read it without
|
|
73
|
+
// re-traversing the AudioContext.
|
|
74
|
+
lastPose = {
|
|
75
|
+
x: 0,
|
|
76
|
+
y: 0,
|
|
77
|
+
z: 0,
|
|
78
|
+
forward: { x: 0, y: 0, z: -1 },
|
|
79
|
+
up: { x: 0, y: 1, z: 0 },
|
|
80
|
+
};
|
|
81
|
+
constructor(audioBus) {
|
|
82
|
+
this.audioBus = audioBus;
|
|
83
|
+
this.ctx = audioBus.ctx;
|
|
84
|
+
// Idempotent: if a 'spatial' bus already exists (engine consumer
|
|
85
|
+
// wired one early), AudioBus.addBus is a no-op and we reuse it.
|
|
86
|
+
if (!audioBus.hasBus(SPATIAL_BUS_NAME)) {
|
|
87
|
+
audioBus.addBus(SPATIAL_BUS_NAME, {
|
|
88
|
+
initialGain: 1.0,
|
|
89
|
+
priority: 'ambient',
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
// Construct on top of an existing AudioBus. The AudioBus owns the
|
|
94
|
+
// AudioContext lifecycle (unlock, dispose). v1 does not own a second
|
|
95
|
+
// master gain; the spatial bus IS the master path through AudioBus.
|
|
96
|
+
static create(audioBus) {
|
|
97
|
+
return new SpatialAudioBus(audioBus);
|
|
98
|
+
}
|
|
99
|
+
// Read-only accessor for the underlying AudioBus, useful for tests
|
|
100
|
+
// and consumers that want to tweak the spatial sub-bus gain.
|
|
101
|
+
getAudioBus() {
|
|
102
|
+
return this.audioBus;
|
|
103
|
+
}
|
|
104
|
+
// Read-only accessor for the cached listener pose.
|
|
105
|
+
getListenerPose() {
|
|
106
|
+
return this.lastPose;
|
|
107
|
+
}
|
|
108
|
+
// Update the listener pose. Renderer pushes this each frame from the
|
|
109
|
+
// local character's transform via SpatialAudioSystem. Pose is global
|
|
110
|
+
// to the AudioContext - one listener per context.
|
|
111
|
+
setListener(pose) {
|
|
112
|
+
this.lastPose = pose;
|
|
113
|
+
var listener = this.ctx.listener;
|
|
114
|
+
if (!listener)
|
|
115
|
+
return;
|
|
116
|
+
var z = pose.z ?? 0;
|
|
117
|
+
var fwd = pose.forward ?? { x: 0, y: 0, z: -1 };
|
|
118
|
+
var up = pose.up ?? { x: 0, y: 1, z: 0 };
|
|
119
|
+
// Modern AudioParam API (Chrome 64+, Firefox 58+, Safari 14+).
|
|
120
|
+
if (listener.positionX !== undefined &&
|
|
121
|
+
typeof listener.positionX.setValueAtTime === 'function') {
|
|
122
|
+
var asParam = listener;
|
|
123
|
+
var now = this.ctx.currentTime;
|
|
124
|
+
asParam.positionX.setValueAtTime(pose.x, now);
|
|
125
|
+
asParam.positionY.setValueAtTime(pose.y, now);
|
|
126
|
+
asParam.positionZ.setValueAtTime(z, now);
|
|
127
|
+
asParam.forwardX.setValueAtTime(fwd.x, now);
|
|
128
|
+
asParam.forwardY.setValueAtTime(fwd.y, now);
|
|
129
|
+
asParam.forwardZ.setValueAtTime(fwd.z, now);
|
|
130
|
+
asParam.upX.setValueAtTime(up.x, now);
|
|
131
|
+
asParam.upY.setValueAtTime(up.y, now);
|
|
132
|
+
asParam.upZ.setValueAtTime(up.z, now);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
// Deprecated fallback (older Safari, some test mocks).
|
|
136
|
+
var legacy = listener;
|
|
137
|
+
if (typeof legacy.setPosition === 'function') {
|
|
138
|
+
legacy.setPosition(pose.x, pose.y, z);
|
|
139
|
+
}
|
|
140
|
+
if (typeof legacy.setOrientation === 'function') {
|
|
141
|
+
legacy.setOrientation(fwd.x, fwd.y, fwd.z, up.x, up.y, up.z);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
// Play a one-shot positional sound. Returns null if the AudioContext
|
|
145
|
+
// is suspended (AudioBus.unlock not yet called) or if the 'spatial'
|
|
146
|
+
// bus is muted by VE-budget pressure.
|
|
147
|
+
playPositional(buffer, options) {
|
|
148
|
+
if (!this.canPlay())
|
|
149
|
+
return null;
|
|
150
|
+
var src = this.ctx.createBufferSource();
|
|
151
|
+
src.buffer = buffer;
|
|
152
|
+
src.playbackRate.value = options.rate ?? 1;
|
|
153
|
+
src.loop = options.loop ?? false;
|
|
154
|
+
return this.startSource(src, false, options);
|
|
155
|
+
}
|
|
156
|
+
// Convenience: play a positional tone (no asset needed). Useful for
|
|
157
|
+
// tests and code-only demos. Honours options.type for the oscillator
|
|
158
|
+
// waveform; envelope is left to the consumer (or the natural source
|
|
159
|
+
// duration).
|
|
160
|
+
playPositionalTone(freq, durationMs, options) {
|
|
161
|
+
if (!this.canPlay())
|
|
162
|
+
return null;
|
|
163
|
+
var osc = this.ctx.createOscillator();
|
|
164
|
+
osc.type = options.type ?? 'sine';
|
|
165
|
+
osc.frequency.value = freq;
|
|
166
|
+
var handle = this.startSource(osc, true, options);
|
|
167
|
+
if (handle) {
|
|
168
|
+
// Schedule a stop at the end of the requested duration so the
|
|
169
|
+
// tone doesn't run forever. Tiny tail keeps the click low.
|
|
170
|
+
var stopAt = this.ctx.currentTime + Math.max(0.01, durationMs / 1000) + 0.05;
|
|
171
|
+
try {
|
|
172
|
+
osc.stop(stopAt);
|
|
173
|
+
}
|
|
174
|
+
catch { /* runtime may not support timestamped stop */ }
|
|
175
|
+
}
|
|
176
|
+
return handle;
|
|
177
|
+
}
|
|
178
|
+
// Stop every live spatial source and disconnect their nodes. Called
|
|
179
|
+
// by dispose() and useful for "scene change, kill everything" flows.
|
|
180
|
+
stopAll() {
|
|
181
|
+
// Snapshot to a list because handle.stop mutates the set.
|
|
182
|
+
var sources = [];
|
|
183
|
+
this.active.forEach(function (s) { sources.push(s); });
|
|
184
|
+
for (var i = 0; i < sources.length; i++) {
|
|
185
|
+
this.releaseSource(sources[i]);
|
|
186
|
+
}
|
|
187
|
+
this.active.clear();
|
|
188
|
+
}
|
|
189
|
+
// Tear down. Useful in tests; production demo lives the lifetime of
|
|
190
|
+
// the page. Does NOT dispose the underlying AudioBus - the consumer
|
|
191
|
+
// may still want sfx/music/etc.
|
|
192
|
+
dispose() {
|
|
193
|
+
this.stopAll();
|
|
194
|
+
}
|
|
195
|
+
// -------- private --------
|
|
196
|
+
// Returns true iff a play call would have a chance of producing
|
|
197
|
+
// audible output: context unlocked AND spatial bus not muted by
|
|
198
|
+
// VE-budget. We do NOT introspect AudioBus's internal state directly;
|
|
199
|
+
// we mirror the public contract:
|
|
200
|
+
// - audioBus.isUnlocked() must be true
|
|
201
|
+
// - audioBus.isBusMuted('spatial') must be false (explicit mute)
|
|
202
|
+
// - audioBus.getBusGain('spatial') must be > 0 after budget gating
|
|
203
|
+
// (the bus's input GainNode reflects this; we check the live gain)
|
|
204
|
+
canPlay() {
|
|
205
|
+
if (!this.audioBus.isUnlocked())
|
|
206
|
+
return false;
|
|
207
|
+
if (this.audioBus.isBusMuted(SPATIAL_BUS_NAME))
|
|
208
|
+
return false;
|
|
209
|
+
// Live gain after budget gating - if VE budget knocked it to 0,
|
|
210
|
+
// there's no point creating a source we can't hear.
|
|
211
|
+
var input = this.audioBus.input(SPATIAL_BUS_NAME);
|
|
212
|
+
if (input && input.gain && input.gain.value === 0)
|
|
213
|
+
return false;
|
|
214
|
+
return true;
|
|
215
|
+
}
|
|
216
|
+
// Wires a fresh source -> gain -> panner -> spatial bus input,
|
|
217
|
+
// applies position + falloff fields, registers the active source,
|
|
218
|
+
// and returns a handle. Caller is responsible for src.start() in the
|
|
219
|
+
// BufferSource case (we do it here so paths converge).
|
|
220
|
+
startSource(source, isOscillator, options) {
|
|
221
|
+
var panner = this.ctx.createPanner();
|
|
222
|
+
var gain = this.ctx.createGain();
|
|
223
|
+
gain.gain.value = options.gain ?? 1.0;
|
|
224
|
+
// Falloff fields. PannerNode defaults are ref=1, max=10000,
|
|
225
|
+
// rolloff=1, model='inverse'. Our defaults are documented in
|
|
226
|
+
// PositionalPlayOptions.
|
|
227
|
+
panner.distanceModel = options.distanceModel ?? 'inverse';
|
|
228
|
+
panner.refDistance = options.refDistance ?? 1;
|
|
229
|
+
panner.maxDistance = options.maxDistance ?? 32;
|
|
230
|
+
panner.rolloffFactor = options.rolloffFactor ?? 1;
|
|
231
|
+
panner.panningModel = 'HRTF';
|
|
232
|
+
var z = options.z ?? 0;
|
|
233
|
+
this.applyPositionTo(panner, options.x, options.y, z);
|
|
234
|
+
// Wire: source -> gain -> panner -> spatial-bus input.
|
|
235
|
+
source.connect(gain);
|
|
236
|
+
gain.connect(panner);
|
|
237
|
+
var spatialInput = this.audioBus.input(SPATIAL_BUS_NAME);
|
|
238
|
+
panner.connect(spatialInput);
|
|
239
|
+
// Track for cleanup BEFORE start() so an immediate end-of-buffer
|
|
240
|
+
// event still finds us in the active set.
|
|
241
|
+
var record = {
|
|
242
|
+
panner: panner,
|
|
243
|
+
gain: gain,
|
|
244
|
+
source: source,
|
|
245
|
+
isOscillator: isOscillator,
|
|
246
|
+
stopped: false,
|
|
247
|
+
};
|
|
248
|
+
this.active.add(record);
|
|
249
|
+
// BufferSourceNode.onended fires when the buffer plays out OR
|
|
250
|
+
// stop() is called. Use it to auto-cleanup so we don't leak nodes.
|
|
251
|
+
var self = this;
|
|
252
|
+
source.onended = function () {
|
|
253
|
+
self.releaseSource(record);
|
|
254
|
+
};
|
|
255
|
+
try {
|
|
256
|
+
source.start();
|
|
257
|
+
}
|
|
258
|
+
catch {
|
|
259
|
+
// Some runtimes throw if start() called twice; harmless here.
|
|
260
|
+
}
|
|
261
|
+
var handle = {
|
|
262
|
+
stop: function () {
|
|
263
|
+
if (record.stopped)
|
|
264
|
+
return;
|
|
265
|
+
try {
|
|
266
|
+
source.stop();
|
|
267
|
+
}
|
|
268
|
+
catch { /* already stopped */ }
|
|
269
|
+
self.releaseSource(record);
|
|
270
|
+
},
|
|
271
|
+
setPosition: function (nx, ny, nz) {
|
|
272
|
+
if (record.stopped)
|
|
273
|
+
return;
|
|
274
|
+
self.applyPositionTo(record.panner, nx, ny, nz ?? 0);
|
|
275
|
+
},
|
|
276
|
+
fadeOut: function (durationMs) {
|
|
277
|
+
if (record.stopped)
|
|
278
|
+
return Promise.resolve();
|
|
279
|
+
var dur = Math.max(0, durationMs) / 1000;
|
|
280
|
+
var now = self.ctx.currentTime;
|
|
281
|
+
try {
|
|
282
|
+
// setValueAtTime to current then ramp to 0 - prevents the
|
|
283
|
+
// ramp from interpolating from whatever the previous
|
|
284
|
+
// setValueAtTime scheduled (could be a jump).
|
|
285
|
+
record.gain.gain.setValueAtTime(record.gain.gain.value, now);
|
|
286
|
+
record.gain.gain.linearRampToValueAtTime(0, now + dur);
|
|
287
|
+
}
|
|
288
|
+
catch { /* fake AudioParam may not support */ }
|
|
289
|
+
return new Promise(function (resolve) {
|
|
290
|
+
var ms = Math.max(0, durationMs);
|
|
291
|
+
// setTimeout in test environments without a real audio clock.
|
|
292
|
+
setTimeout(function () {
|
|
293
|
+
handle.stop();
|
|
294
|
+
resolve();
|
|
295
|
+
}, ms);
|
|
296
|
+
});
|
|
297
|
+
},
|
|
298
|
+
isPlaying: function () {
|
|
299
|
+
return !record.stopped;
|
|
300
|
+
},
|
|
301
|
+
};
|
|
302
|
+
return handle;
|
|
303
|
+
}
|
|
304
|
+
// Apply x/y/z to a PannerNode. Prefers AudioParam.setValueAtTime when
|
|
305
|
+
// available (modern API); falls back to the deprecated direct
|
|
306
|
+
// assignment via setPosition for older runtimes / mocks.
|
|
307
|
+
applyPositionTo(panner, x, y, z) {
|
|
308
|
+
var asParam = panner;
|
|
309
|
+
if (asParam.positionX && typeof asParam.positionX.setValueAtTime === 'function') {
|
|
310
|
+
var now = this.ctx.currentTime;
|
|
311
|
+
asParam.positionX.setValueAtTime(x, now);
|
|
312
|
+
asParam.positionY.setValueAtTime(y, now);
|
|
313
|
+
asParam.positionZ.setValueAtTime(z, now);
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
var legacy = panner;
|
|
317
|
+
if (typeof legacy.setPosition === 'function') {
|
|
318
|
+
legacy.setPosition(x, y, z);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
// Disconnect + drop one active source. Idempotent.
|
|
322
|
+
releaseSource(record) {
|
|
323
|
+
if (record.stopped)
|
|
324
|
+
return;
|
|
325
|
+
record.stopped = true;
|
|
326
|
+
this.active.delete(record);
|
|
327
|
+
try {
|
|
328
|
+
record.source.disconnect();
|
|
329
|
+
}
|
|
330
|
+
catch { /* ignore */ }
|
|
331
|
+
try {
|
|
332
|
+
record.gain.disconnect();
|
|
333
|
+
}
|
|
334
|
+
catch { /* ignore */ }
|
|
335
|
+
try {
|
|
336
|
+
record.panner.disconnect();
|
|
337
|
+
}
|
|
338
|
+
catch { /* ignore */ }
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
//# sourceMappingURL=spatial-audio-bus.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spatial-audio-bus.js","sourceRoot":"","sources":["../../src/audio/spatial-audio-bus.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { System } from '../system.js';
|
|
2
|
+
import type { World } from '../world.js';
|
|
3
|
+
import type { EntityId } from '../entity.js';
|
|
4
|
+
import type { SpatialAudioBus } from './spatial-audio-bus.js';
|
|
5
|
+
export declare class SpatialAudioSystem implements System {
|
|
6
|
+
readonly name: string;
|
|
7
|
+
private localCharacter;
|
|
8
|
+
private spatialBus;
|
|
9
|
+
constructor(opts?: {
|
|
10
|
+
spatialBus?: SpatialAudioBus;
|
|
11
|
+
});
|
|
12
|
+
setSpatialBus(bus: SpatialAudioBus | null): void;
|
|
13
|
+
setLocalCharacterEntity(entity: EntityId | null): void;
|
|
14
|
+
getLocalCharacterEntity(): EntityId | null;
|
|
15
|
+
update(world: World, _dt: number): void;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=spatial-audio-system.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spatial-audio-system.d.ts","sourceRoot":"","sources":["../../src/audio/spatial-audio-system.ts"],"names":[],"mappings":"AAuCA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAY7C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE9D,qBAAa,kBAAmB,YAAW,MAAM;IAC/C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAmB;IAExC,OAAO,CAAC,cAAc,CAAyB;IAC/C,OAAO,CAAC,UAAU,CAAgC;gBAMtC,IAAI,GAAE;QAAE,UAAU,CAAC,EAAE,eAAe,CAAA;KAAO;IAOvD,aAAa,CAAC,GAAG,EAAE,eAAe,GAAG,IAAI,GAAG,IAAI;IAQhD,uBAAuB,CAAC,MAAM,EAAE,QAAQ,GAAG,IAAI,GAAG,IAAI;IAItD,uBAAuB,IAAI,QAAQ,GAAG,IAAI;IAI1C,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;CA4BxC"}
|