@babylonjs/lite 1.4.0 → 1.5.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.
Files changed (122) hide show
  1. package/dist/index.js +381 -375
  2. package/dist/index.js.map +1 -1
  3. package/index.d.ts +757 -0
  4. package/lib/audio/analyzer.js +65 -0
  5. package/lib/audio/analyzer.js.map +1 -0
  6. package/lib/audio/audio-bus.js +38 -0
  7. package/lib/audio/audio-bus.js.map +1 -0
  8. package/lib/audio/audio-engine.js +188 -0
  9. package/lib/audio/audio-engine.js.map +1 -0
  10. package/lib/audio/audio-fetch.js +18 -0
  11. package/lib/audio/audio-fetch.js.map +1 -0
  12. package/lib/audio/audio-param.js +96 -0
  13. package/lib/audio/audio-param.js.map +1 -0
  14. package/lib/audio/audio-signal.js +46 -0
  15. package/lib/audio/audio-signal.js.map +1 -0
  16. package/lib/audio/bus.js +33 -0
  17. package/lib/audio/bus.js.map +1 -0
  18. package/lib/audio/host-types.js +2 -0
  19. package/lib/audio/host-types.js.map +1 -0
  20. package/lib/audio/index.js +12 -0
  21. package/lib/audio/index.js.map +1 -0
  22. package/lib/audio/sound-buffer.js +59 -0
  23. package/lib/audio/sound-buffer.js.map +1 -0
  24. package/lib/audio/sound-source.js +57 -0
  25. package/lib/audio/sound-source.js.map +1 -0
  26. package/lib/audio/sound-sub-graph.js +72 -0
  27. package/lib/audio/sound-sub-graph.js.map +1 -0
  28. package/lib/audio/spatial.js +466 -0
  29. package/lib/audio/spatial.js.map +1 -0
  30. package/lib/audio/static-sound.js +313 -0
  31. package/lib/audio/static-sound.js.map +1 -0
  32. package/lib/audio/stereo.js +40 -0
  33. package/lib/audio/stereo.js.map +1 -0
  34. package/lib/audio/streaming-sound.js +377 -0
  35. package/lib/audio/streaming-sound.js.map +1 -0
  36. package/lib/audio/unmute-ui.js +72 -0
  37. package/lib/audio/unmute-ui.js.map +1 -0
  38. package/lib/audio/visualizer.js +101 -0
  39. package/lib/audio/visualizer.js.map +1 -0
  40. package/lib/engine/engine.js +1 -1
  41. package/lib/index.js +11 -0
  42. package/lib/index.js.map +1 -1
  43. package/lib/light/types.js.map +1 -1
  44. package/lib/loader-gltf/animation-pointer-basecolor.js +25 -0
  45. package/lib/loader-gltf/animation-pointer-basecolor.js.map +1 -0
  46. package/lib/loader-gltf/animation-pointer-ext.js +244 -0
  47. package/lib/loader-gltf/animation-pointer-ext.js.map +1 -0
  48. package/lib/loader-gltf/animation-pointer-lights.js +46 -0
  49. package/lib/loader-gltf/animation-pointer-lights.js.map +1 -0
  50. package/lib/loader-gltf/animation-pointer.js +4 -1
  51. package/lib/loader-gltf/animation-pointer.js.map +1 -1
  52. package/lib/loader-gltf/gltf-animation.js +5 -3
  53. package/lib/loader-gltf/gltf-animation.js.map +1 -1
  54. package/lib/loader-gltf/gltf-color-normalize.js +10 -1
  55. package/lib/loader-gltf/gltf-color-normalize.js.map +1 -1
  56. package/lib/loader-gltf/gltf-feature-animation-pointer.js +67 -47
  57. package/lib/loader-gltf/gltf-feature-animation-pointer.js.map +1 -1
  58. package/lib/loader-gltf/gltf-feature-lights-punctual.js +51 -9
  59. package/lib/loader-gltf/gltf-feature-lights-punctual.js.map +1 -1
  60. package/lib/loader-gltf/gltf-feature-primitive.js +20 -0
  61. package/lib/loader-gltf/gltf-feature-primitive.js.map +1 -0
  62. package/lib/loader-gltf/gltf-feature-registry.js +25 -0
  63. package/lib/loader-gltf/gltf-feature-registry.js.map +1 -1
  64. package/lib/loader-gltf/gltf-feature-skeleton.js +18 -3
  65. package/lib/loader-gltf/gltf-feature-skeleton.js.map +1 -1
  66. package/lib/loader-gltf/gltf-interleave.js +3 -2
  67. package/lib/loader-gltf/gltf-interleave.js.map +1 -1
  68. package/lib/loader-gltf/gltf-light-pointer-state.js +18 -0
  69. package/lib/loader-gltf/gltf-light-pointer-state.js.map +1 -0
  70. package/lib/loader-gltf/gltf-parser.js +7 -1
  71. package/lib/loader-gltf/gltf-parser.js.map +1 -1
  72. package/lib/loader-gltf/gltf-pbr-builder-ext.js +1 -1
  73. package/lib/loader-gltf/gltf-pbr-builder-ext.js.map +1 -1
  74. package/lib/loader-gltf/gltf-pbr-builder.js +1 -1
  75. package/lib/loader-gltf/gltf-pbr-builder.js.map +1 -1
  76. package/lib/loader-gltf/gltf-sampler-denorm.js +20 -0
  77. package/lib/loader-gltf/gltf-sampler-denorm.js.map +1 -0
  78. package/lib/loader-gltf/gltf-sampler-desc.js +11 -2
  79. package/lib/loader-gltf/gltf-sampler-desc.js.map +1 -1
  80. package/lib/loader-gltf/gltf-uv-denorm.js +28 -0
  81. package/lib/loader-gltf/gltf-uv-denorm.js.map +1 -0
  82. package/lib/loader-gltf/load-gltf.js +15 -6
  83. package/lib/loader-gltf/load-gltf.js.map +1 -1
  84. package/lib/material/material-rebuild.js +4 -0
  85. package/lib/material/material-rebuild.js.map +1 -1
  86. package/lib/material/mesh-features.js +8 -1
  87. package/lib/material/mesh-features.js.map +1 -1
  88. package/lib/material/pbr/fragments/reflectance-fragment.js +1 -1
  89. package/lib/material/pbr/fragments/reflectance-fragment.js.map +1 -1
  90. package/lib/material/pbr/fragments/refraction-rtt-fragment.js +1 -1
  91. package/lib/material/pbr/fragments/refraction-rtt-fragment.js.map +1 -1
  92. package/lib/material/pbr/pbr-pipeline.js +7 -3
  93. package/lib/material/pbr/pbr-pipeline.js.map +1 -1
  94. package/lib/material/pbr/pbr-primitive-resolver.js +34 -0
  95. package/lib/material/pbr/pbr-primitive-resolver.js.map +1 -0
  96. package/lib/material/pbr/pbr-renderable.js +1 -1
  97. package/lib/material/pbr/pbr-renderable.js.map +1 -1
  98. package/lib/material/shader/shader-material.js +9 -5
  99. package/lib/material/shader/shader-material.js.map +1 -1
  100. package/lib/material/shader/shader-thin-instance.js +1 -1
  101. package/lib/material/shader/shader-thin-instance.js.map +1 -1
  102. package/lib/material/standard/standard-renderable.js +1 -1
  103. package/lib/material/standard/standard-renderable.js.map +1 -1
  104. package/lib/mesh/mesh-dispose.js +1 -0
  105. package/lib/mesh/mesh-dispose.js.map +1 -1
  106. package/lib/mesh/thin-instance-cull-binding.js +15 -6
  107. package/lib/mesh/thin-instance-cull-binding.js.map +1 -1
  108. package/lib/scene/scene-core.js +1 -0
  109. package/lib/scene/scene-core.js.map +1 -1
  110. package/lib/scene/scene-material-swap.js +2 -0
  111. package/lib/scene/scene-material-swap.js.map +1 -1
  112. package/lib/shadow/csm-shadow-task-hooks.js +67 -9
  113. package/lib/shadow/csm-shadow-task-hooks.js.map +1 -1
  114. package/lib/sprite/sprite-2d.js +4 -0
  115. package/lib/sprite/sprite-2d.js.map +1 -1
  116. package/lib/sprite/sprite-pipeline.js +25 -22
  117. package/lib/sprite/sprite-pipeline.js.map +1 -1
  118. package/lib/text/_gpu/text-pipeline.js +1 -1
  119. package/lib/text/_gpu/text-pipeline.js.map +1 -1
  120. package/lib/text/text-renderer.js +3 -1
  121. package/lib/text/text-renderer.js.map +1 -1
  122. package/package.json +3 -3
@@ -0,0 +1,313 @@
1
+ import { getBusInputNode } from './audio-bus.js';
2
+ import { setRampTarget, createRampParam } from './audio-param.js';
3
+ import { createAudioSignal } from './audio-signal.js';
4
+ import { createSoundBufferAsync } from './sound-buffer.js';
5
+ import { createSoundSubGraph, connectSoundSubGraph, disposeSoundSubGraph, setSoundSubGraphVolume } from './sound-sub-graph.js';
6
+
7
+ const SoundState = {
8
+ Stopping: 0,
9
+ Stopped: 1,
10
+ Starting: 2,
11
+ Started: 3,
12
+ FailedToStart: 4,
13
+ Paused: 5
14
+ };
15
+ async function createSoundAsync(engine, source, options = {}) {
16
+ const buffer = await createSoundBufferAsync(engine, source, options);
17
+ const graph = createSoundSubGraph(engine._ctx, engine, options.volume ?? 1);
18
+ const outBus = options.outBus ?? engine._mainBus;
19
+ connectSoundSubGraph(graph, getBusInputNode(outBus));
20
+ const onEnded = createAudioSignal();
21
+ const sound = {
22
+ get state() {
23
+ return sound._state;
24
+ },
25
+ get instanceCount() {
26
+ return sound._instances.size;
27
+ },
28
+ get buffer() {
29
+ return sound._buffer;
30
+ },
31
+ get onEnded() {
32
+ return onEnded;
33
+ },
34
+ _engine: engine,
35
+ _buffer: buffer,
36
+ _graph: graph,
37
+ _outBus: outBus,
38
+ _options: {
39
+ autoplay: options.autoplay ?? false,
40
+ duration: options.duration ?? 0,
41
+ loop: options.loop ?? false,
42
+ loopEnd: options.loopEnd ?? 0,
43
+ loopStart: options.loopStart ?? 0,
44
+ maxInstances: options.maxInstances ?? Infinity,
45
+ pitch: options.pitch ?? 0,
46
+ playbackRate: options.playbackRate ?? 1,
47
+ startOffset: options.startOffset ?? 0
48
+ },
49
+ _instances: /* @__PURE__ */ new Set(),
50
+ _newest: null,
51
+ _state: SoundState.Stopped,
52
+ _onEnded: onEnded,
53
+ _dispose: () => disposeSound(sound)
54
+ };
55
+ engine._sounds.add(sound);
56
+ if (sound._options.autoplay) {
57
+ playSound(sound);
58
+ }
59
+ return sound;
60
+ }
61
+ function setSoundVolume(sound, value, options) {
62
+ setSoundSubGraphVolume(sound._graph, value, options);
63
+ }
64
+ function playSound(sound, options = {}) {
65
+ if (sound._state === SoundState.Paused) {
66
+ resumeSound(sound, options);
67
+ return;
68
+ }
69
+ const opts = {
70
+ duration: options.duration ?? sound._options.duration,
71
+ loop: options.loop ?? sound._options.loop,
72
+ loopStart: options.loopStart ?? sound._options.loopStart,
73
+ loopEnd: options.loopEnd ?? sound._options.loopEnd,
74
+ startOffset: options.startOffset ?? sound._options.startOffset,
75
+ volume: options.volume ?? 1,
76
+ waitTime: options.waitTime ?? 0
77
+ };
78
+ const instance = _createInstance(sound);
79
+ instance._onEnded.addOnce(instance._endedHandler);
80
+ sound._instances.add(instance);
81
+ sound._newest = instance;
82
+ _instancePlay(instance, opts);
83
+ sound._state = instance._state;
84
+ _stopExcessInstances(sound);
85
+ }
86
+ function pauseSound(sound) {
87
+ for (const instance of sound._instances) {
88
+ _instancePause(instance);
89
+ }
90
+ sound._state = SoundState.Paused;
91
+ }
92
+ function resumeSound(sound, options = {}) {
93
+ if (sound._state !== SoundState.Paused) {
94
+ return;
95
+ }
96
+ for (const instance of sound._instances) {
97
+ _instanceResume(instance, options);
98
+ }
99
+ sound._state = SoundState.Started;
100
+ }
101
+ function stopSound(sound, options = {}) {
102
+ sound._state = options.waitTime && options.waitTime > 0 ? SoundState.Stopping : SoundState.Stopped;
103
+ for (const instance of Array.from(sound._instances)) {
104
+ _instanceStop(instance, options);
105
+ }
106
+ }
107
+ function disposeSound(sound) {
108
+ stopSound(sound);
109
+ for (const instance of Array.from(sound._instances)) {
110
+ _instanceDispose(instance);
111
+ }
112
+ sound._instances.clear();
113
+ disposeSoundSubGraph(sound._graph);
114
+ sound._onEnded._clear();
115
+ sound._engine._sounds.delete(sound);
116
+ }
117
+ function _stopExcessInstances(sound) {
118
+ if (sound._options.maxInstances < Infinity) {
119
+ const started = Array.from(sound._instances).filter((i) => i._state === SoundState.Started);
120
+ const toStop = started.length - sound._options.maxInstances;
121
+ for (let i = 0; i < toStop; i++) {
122
+ _instanceStop(started[i]);
123
+ }
124
+ }
125
+ }
126
+ function _onInstanceEnded(sound, instance) {
127
+ if (sound._newest === instance) {
128
+ sound._newest = null;
129
+ }
130
+ sound._instances.delete(instance);
131
+ if (sound._instances.size === 0) {
132
+ sound._state = SoundState.Stopped;
133
+ sound._onEnded._notify(sound);
134
+ }
135
+ _instanceDispose(instance);
136
+ }
137
+ function _createInstance(sound) {
138
+ const engine = sound._engine;
139
+ const instance = {
140
+ _sound: sound,
141
+ _engine: engine,
142
+ _options: {
143
+ duration: sound._options.duration,
144
+ loop: sound._options.loop,
145
+ loopEnd: sound._options.loopEnd,
146
+ loopStart: sound._options.loopStart,
147
+ startOffset: sound._options.startOffset
148
+ },
149
+ _volumeNode: new GainNode(engine._ctx),
150
+ _sourceNode: null,
151
+ _state: SoundState.Stopped,
152
+ _enginePlayTime: 0,
153
+ _enginePauseTime: 0,
154
+ _isConnected: false,
155
+ _pitch: null,
156
+ _playbackRate: null,
157
+ _engineStateUnsub: null,
158
+ _onEnded: createAudioSignal(),
159
+ _onStateChanged: createAudioSignal(),
160
+ _endedHandler: () => _onInstanceEnded(sound, instance),
161
+ _engineStateHandler: () => _onEngineStateChanged(instance)
162
+ };
163
+ return instance;
164
+ }
165
+ function _setInstanceState(instance, state) {
166
+ instance._state = state;
167
+ instance._onStateChanged._notify(instance);
168
+ }
169
+ function _instancePlay(instance, options) {
170
+ if (instance._state === SoundState.Started) {
171
+ return;
172
+ }
173
+ instance._options.duration = options.duration;
174
+ instance._options.loop = options.loop;
175
+ instance._options.loopStart = options.loopStart;
176
+ instance._options.loopEnd = options.loopEnd;
177
+ instance._options.startOffset = options.startOffset;
178
+ let startOffset = instance._options.startOffset;
179
+ if (instance._state === SoundState.Paused) {
180
+ startOffset += instance._enginePauseTime;
181
+ startOffset %= instance._sound._buffer.duration;
182
+ }
183
+ instance._enginePlayTime = instance._engine.currentTime + options.waitTime;
184
+ if (options.volume !== void 0) {
185
+ instance._volumeNode.gain.value = options.volume;
186
+ }
187
+ _initSourceNode(instance);
188
+ if (instance._engine.state === "running") {
189
+ _setInstanceState(instance, SoundState.Started);
190
+ instance._sourceNode?.start(instance._enginePlayTime, startOffset, instance._options.duration > 0 ? instance._options.duration : void 0);
191
+ } else if (instance._options.loop) {
192
+ _setInstanceState(instance, SoundState.Starting);
193
+ instance._engineStateUnsub = instance._engine.onStateChanged.add(instance._engineStateHandler);
194
+ }
195
+ }
196
+ function _instancePause(instance) {
197
+ if (instance._state !== SoundState.Started && instance._state !== SoundState.Starting) {
198
+ return;
199
+ }
200
+ const wasStarted = instance._state === SoundState.Started;
201
+ _setInstanceState(instance, SoundState.Paused);
202
+ instance._enginePauseTime += instance._engine.currentTime - instance._enginePlayTime;
203
+ if (wasStarted) {
204
+ instance._sourceNode?.stop();
205
+ } else {
206
+ instance._engineStateUnsub?.();
207
+ instance._engineStateUnsub = null;
208
+ }
209
+ _deinitSourceNode(instance);
210
+ }
211
+ function _instanceResume(instance, options) {
212
+ if (instance._state === SoundState.Paused) {
213
+ const opts = {
214
+ duration: options.duration ?? instance._options.duration,
215
+ loop: options.loop ?? instance._options.loop,
216
+ loopStart: options.loopStart ?? instance._options.loopStart,
217
+ loopEnd: options.loopEnd ?? instance._options.loopEnd,
218
+ startOffset: options.startOffset ?? instance._options.startOffset,
219
+ volume: options.volume ?? instance._volumeNode.gain.value,
220
+ waitTime: options.waitTime ?? 0
221
+ };
222
+ _instancePlay(instance, opts);
223
+ }
224
+ }
225
+ function _instanceStop(instance, options = {}) {
226
+ if (instance._state === SoundState.Stopped) {
227
+ return;
228
+ }
229
+ if (instance._state === SoundState.Started) {
230
+ const stopTime = instance._engine.currentTime + (options.waitTime ?? 0);
231
+ instance._sourceNode?.stop(stopTime);
232
+ }
233
+ if (options.waitTime === void 0 || options.waitTime <= 0) {
234
+ _setInstanceState(instance, SoundState.Stopped);
235
+ instance._engineStateUnsub?.();
236
+ instance._engineStateUnsub = null;
237
+ }
238
+ }
239
+ function _instanceDispose(instance) {
240
+ _instanceStop(instance);
241
+ _deinitSourceNode(instance);
242
+ instance._engineStateUnsub?.();
243
+ instance._engineStateUnsub = null;
244
+ instance._pitch = null;
245
+ instance._playbackRate = null;
246
+ instance._onEnded._clear();
247
+ instance._onStateChanged._clear();
248
+ }
249
+ function _onEngineStateChanged(instance) {
250
+ if (instance._engine.state !== "running") {
251
+ return;
252
+ }
253
+ if (instance._options.loop && instance._state === SoundState.Starting) {
254
+ const opts = {
255
+ duration: instance._options.duration,
256
+ loop: instance._options.loop,
257
+ loopStart: instance._options.loopStart,
258
+ loopEnd: instance._options.loopEnd,
259
+ startOffset: instance._options.startOffset,
260
+ volume: instance._volumeNode.gain.value,
261
+ waitTime: 0
262
+ };
263
+ instance._state = SoundState.Stopped;
264
+ _instancePlay(instance, opts);
265
+ }
266
+ }
267
+ function _onInstanceEndedEvent(instance) {
268
+ instance._enginePlayTime = 0;
269
+ if (instance._state !== SoundState.Paused) {
270
+ instance._onEnded._notify(instance);
271
+ }
272
+ _deinitSourceNode(instance);
273
+ }
274
+ function _initSourceNode(instance) {
275
+ const sound = instance._sound;
276
+ if (!instance._sourceNode) {
277
+ const sourceNode = new AudioBufferSourceNode(instance._engine._ctx, { buffer: sound._buffer._audioBuffer });
278
+ instance._sourceNode = sourceNode;
279
+ sourceNode.addEventListener("ended", () => _onInstanceEndedEvent(instance), { once: true });
280
+ sourceNode.connect(instance._volumeNode);
281
+ instance._volumeNode.connect(sound._graph._in);
282
+ instance._isConnected = true;
283
+ instance._pitch = createRampParam(sourceNode.detune, instance._engine);
284
+ instance._playbackRate = createRampParam(sourceNode.playbackRate, instance._engine);
285
+ }
286
+ const node = instance._sourceNode;
287
+ node.detune.value = sound._options.pitch;
288
+ node.loop = instance._options.loop;
289
+ node.loopEnd = instance._options.loopEnd;
290
+ node.loopStart = instance._options.loopStart;
291
+ node.playbackRate.value = sound._options.playbackRate;
292
+ }
293
+ function _deinitSourceNode(instance) {
294
+ const node = instance._sourceNode;
295
+ if (!node) {
296
+ return;
297
+ }
298
+ if (instance._isConnected) {
299
+ instance._volumeNode.disconnect(instance._sound._graph._in);
300
+ instance._isConnected = false;
301
+ }
302
+ node.disconnect(instance._volumeNode);
303
+ instance._sourceNode = null;
304
+ }
305
+ function _setNewestInstancePitch(sound, value, options) {
306
+ const instance = sound._newest;
307
+ if (instance?._pitch) {
308
+ setRampTarget(instance._pitch, value, options);
309
+ }
310
+ }
311
+
312
+ export { SoundState, _setNewestInstancePitch, createSoundAsync, disposeSound, pauseSound, playSound, resumeSound, setSoundVolume, stopSound };
313
+ //# sourceMappingURL=static-sound.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"static-sound.js","sources":["../../../src/audio/static-sound.ts"],"sourcesContent":["/**\n * Static sounds (fully-decoded, buffer-backed) and their play instances.\n *\n * Faithful port of AudioV2 `_WebAudioStaticSound` / `_WebAudioStaticSoundInstance`\n * (and the relevant `AbstractSound` instance management), collapsed to pure\n * state + standalone functions.\n *\n * Graph per playing instance (Phase 1):\n *\n * `AudioBufferSourceNode` -\\> `instance._volumeNode` -\\> `sound._graph._in`\n * -\\> `sound._graph._out` -\\> `outBus._in` -\\> `mainBus` -\\> `mainOut` -\\> destination\n *\n * Each `playSound` call spawns a fresh `AudioBufferSourceNode` (Web Audio source\n * nodes are single-use), exactly as Babylon.js does.\n */\n\nimport { type AudioEngine } from \"./audio-engine.js\";\nimport { type PrimaryAudioBus, getBusInputNode } from \"./audio-bus.js\";\nimport { type RampOptions, type RampParam, createRampParam, setRampTarget } from \"./audio-param.js\";\nimport { type AudioSignal, type AudioSignalImpl, createAudioSignal } from \"./audio-signal.js\";\nimport { type SoundBuffer, type SoundBufferOptions, type SoundSource, createSoundBufferAsync } from \"./sound-buffer.js\";\nimport { type SoundSubGraph, connectSoundSubGraph, createSoundSubGraph, disposeSoundSubGraph, setSoundSubGraphVolume } from \"./sound-sub-graph.js\";\n\n/** Playback state of a sound or sound instance. Values match Babylon.js exactly. */\nexport const SoundState = {\n Stopping: 0,\n Stopped: 1,\n Starting: 2,\n Started: 3,\n FailedToStart: 4,\n Paused: 5,\n} as const;\nexport type SoundState = (typeof SoundState)[keyof typeof SoundState];\n\n/** Options for {@link createSoundAsync}. */\nexport interface StaticSoundOptions extends SoundBufferOptions {\n /** Play immediately once ready. Defaults to `false`. */\n autoplay?: boolean;\n /** Play duration in seconds (`0` = full buffer). Defaults to `0`. */\n duration?: number;\n /** Loop playback. Defaults to `false`. */\n loop?: boolean;\n /** Loop end point in seconds. Defaults to `0`. */\n loopEnd?: number;\n /** Loop start point in seconds. Defaults to `0`. */\n loopStart?: number;\n /** Maximum simultaneous instances. Defaults to `Infinity`. */\n maxInstances?: number;\n /** Output bus. Defaults to the engine's default main bus. */\n outBus?: PrimaryAudioBus;\n /** Detune in cents. Defaults to `0`. */\n pitch?: number;\n /** Playback rate multiplier. Defaults to `1`. */\n playbackRate?: number;\n /** Start offset in seconds. Defaults to `0`. */\n startOffset?: number;\n /** Initial volume. Defaults to `1`. */\n volume?: number;\n}\n\n/** Per-play overrides for {@link playSound}. */\nexport interface StaticSoundPlayOptions {\n /** Play duration in seconds (`0` = full buffer). */\n duration?: number;\n /** Loop playback. */\n loop?: boolean;\n /** Loop end point in seconds. */\n loopEnd?: number;\n /** Loop start point in seconds. */\n loopStart?: number;\n /** Start offset in seconds. */\n startOffset?: number;\n /** Per-instance volume. */\n volume?: number;\n /** Delay before playback starts, in seconds. */\n waitTime?: number;\n}\n\n/** Options for {@link stopSound}. */\nexport interface StaticSoundStopOptions {\n /** Delay before stopping, in seconds. */\n waitTime?: number;\n}\n\ninterface StoredOptions {\n autoplay: boolean;\n duration: number;\n loop: boolean;\n loopEnd: number;\n loopStart: number;\n maxInstances: number;\n pitch: number;\n playbackRate: number;\n startOffset: number;\n}\n\n/** A buffer-backed sound. Pure state — drive it with the sound functions. */\nexport interface StaticSound {\n /** Optional name. */\n readonly name?: string;\n /** The decoded buffer this sound plays. */\n readonly buffer: SoundBuffer;\n /** Current playback state. */\n readonly state: SoundState;\n /** Number of live instances. */\n readonly instanceCount: number;\n /** Fires when the sound finishes (all instances ended). */\n readonly onEnded: AudioSignal<StaticSound>;\n\n /** @internal */ _engine: AudioEngine;\n /** @internal */ _buffer: SoundBuffer;\n /** @internal */ _graph: SoundSubGraph;\n /** @internal */ _outBus: PrimaryAudioBus;\n /** @internal */ _options: StoredOptions;\n /** @internal */ _instances: Set<SoundInstance>;\n /** @internal */ _newest: SoundInstance | null;\n /** @internal */ _state: SoundState;\n /** @internal */ _onEnded: AudioSignalImpl<StaticSound>;\n /** @internal */ _dispose(): void;\n}\n\n/** A single in-flight playback of a {@link StaticSound}. @internal */\nexport interface SoundInstance {\n /** @internal */ _sound: StaticSound;\n /** @internal */ _engine: AudioEngine;\n /** @internal */ _options: { duration: number; loop: boolean; loopEnd: number; loopStart: number; startOffset: number };\n /** @internal */ _volumeNode: GainNode;\n /** @internal */ _sourceNode: AudioBufferSourceNode | null;\n /** @internal */ _state: SoundState;\n /** @internal */ _enginePlayTime: number;\n /** @internal */ _enginePauseTime: number;\n /** @internal */ _isConnected: boolean;\n /** @internal */ _pitch: RampParam | null;\n /** @internal */ _playbackRate: RampParam | null;\n /** @internal */ _engineStateUnsub: (() => void) | null;\n /** @internal */ _onEnded: AudioSignalImpl<SoundInstance>;\n /** @internal */ _onStateChanged: AudioSignalImpl<SoundInstance>;\n /** @internal */ _endedHandler: () => void;\n /** @internal */ _engineStateHandler: () => void;\n}\n\n/**\n * Creates a buffer-backed sound, routed to the given output bus (or the\n * engine's default main bus).\n * @param engine - The audio engine.\n * @param source - An `AudioBuffer`, `ArrayBuffer`, URL, URL list, or `SoundBuffer`.\n * @param options - Sound options.\n * @returns A promise that resolves with the ready sound.\n */\nexport async function createSoundAsync(engine: AudioEngine, source: SoundSource, options: StaticSoundOptions = {}): Promise<StaticSound> {\n const buffer = await createSoundBufferAsync(engine, source, options);\n const graph = createSoundSubGraph(engine._ctx, engine, options.volume ?? 1);\n const outBus = options.outBus ?? engine._mainBus;\n connectSoundSubGraph(graph, getBusInputNode(outBus));\n\n const onEnded = createAudioSignal<StaticSound>();\n\n const sound: StaticSound = {\n get state() {\n return sound._state;\n },\n get instanceCount() {\n return sound._instances.size;\n },\n get buffer() {\n return sound._buffer;\n },\n get onEnded(): AudioSignal<StaticSound> {\n return onEnded;\n },\n _engine: engine,\n _buffer: buffer,\n _graph: graph,\n _outBus: outBus,\n _options: {\n autoplay: options.autoplay ?? false,\n duration: options.duration ?? 0,\n loop: options.loop ?? false,\n loopEnd: options.loopEnd ?? 0,\n loopStart: options.loopStart ?? 0,\n maxInstances: options.maxInstances ?? Infinity,\n pitch: options.pitch ?? 0,\n playbackRate: options.playbackRate ?? 1,\n startOffset: options.startOffset ?? 0,\n },\n _instances: new Set<SoundInstance>(),\n _newest: null,\n _state: SoundState.Stopped,\n _onEnded: onEnded,\n _dispose: () => disposeSound(sound),\n };\n\n engine._sounds.add(sound);\n\n if (sound._options.autoplay) {\n playSound(sound);\n }\n\n return sound;\n}\n\n/** Sets the sound's output volume, optionally ramping. */\nexport function setSoundVolume(sound: StaticSound, value: number, options?: RampOptions): void {\n setSoundSubGraphVolume(sound._graph, value, options);\n}\n\n/**\n * Plays the sound. Spawns a new instance per call (subject to `maxInstances`).\n * A paused sound is resumed instead.\n * @param sound - The sound to play.\n * @param options - Per-play overrides.\n */\nexport function playSound(sound: StaticSound, options: StaticSoundPlayOptions = {}): void {\n if (sound._state === SoundState.Paused) {\n resumeSound(sound, options);\n return;\n }\n\n const opts: Required<StaticSoundPlayOptions> = {\n duration: options.duration ?? sound._options.duration,\n loop: options.loop ?? sound._options.loop,\n loopStart: options.loopStart ?? sound._options.loopStart,\n loopEnd: options.loopEnd ?? sound._options.loopEnd,\n startOffset: options.startOffset ?? sound._options.startOffset,\n volume: options.volume ?? 1,\n waitTime: options.waitTime ?? 0,\n };\n\n const instance = _createInstance(sound);\n instance._onEnded.addOnce(instance._endedHandler);\n sound._instances.add(instance);\n sound._newest = instance;\n\n _instancePlay(instance, opts);\n\n sound._state = instance._state;\n _stopExcessInstances(sound);\n}\n\n/** Pauses all of the sound's instances. */\nexport function pauseSound(sound: StaticSound): void {\n for (const instance of sound._instances) {\n _instancePause(instance);\n }\n sound._state = SoundState.Paused;\n}\n\n/** Resumes a paused sound. */\nexport function resumeSound(sound: StaticSound, options: StaticSoundPlayOptions = {}): void {\n if (sound._state !== SoundState.Paused) {\n return;\n }\n for (const instance of sound._instances) {\n _instanceResume(instance, options);\n }\n sound._state = SoundState.Started;\n}\n\n/** Stops the sound (and all its instances). */\nexport function stopSound(sound: StaticSound, options: StaticSoundStopOptions = {}): void {\n sound._state = options.waitTime && options.waitTime > 0 ? SoundState.Stopping : SoundState.Stopped;\n for (const instance of Array.from(sound._instances)) {\n _instanceStop(instance, options);\n }\n}\n\n/** Disposes the sound, stopping playback and releasing its graph. */\nexport function disposeSound(sound: StaticSound): void {\n stopSound(sound);\n for (const instance of Array.from(sound._instances)) {\n _instanceDispose(instance);\n }\n sound._instances.clear();\n disposeSoundSubGraph(sound._graph);\n sound._onEnded._clear();\n sound._engine._sounds.delete(sound);\n}\n\nfunction _stopExcessInstances(sound: StaticSound): void {\n if (sound._options.maxInstances < Infinity) {\n const started = Array.from(sound._instances).filter((i) => i._state === SoundState.Started);\n const toStop = started.length - sound._options.maxInstances;\n for (let i = 0; i < toStop; i++) {\n _instanceStop(started[i]!);\n }\n }\n}\n\nfunction _onInstanceEnded(sound: StaticSound, instance: SoundInstance): void {\n if (sound._newest === instance) {\n sound._newest = null;\n }\n sound._instances.delete(instance);\n if (sound._instances.size === 0) {\n sound._state = SoundState.Stopped;\n sound._onEnded._notify(sound);\n }\n _instanceDispose(instance);\n}\n\n// --- Instance ---------------------------------------------------------------\n\nfunction _createInstance(sound: StaticSound): SoundInstance {\n const engine = sound._engine;\n const instance: SoundInstance = {\n _sound: sound,\n _engine: engine,\n _options: {\n duration: sound._options.duration,\n loop: sound._options.loop,\n loopEnd: sound._options.loopEnd,\n loopStart: sound._options.loopStart,\n startOffset: sound._options.startOffset,\n },\n _volumeNode: new GainNode(engine._ctx),\n _sourceNode: null,\n _state: SoundState.Stopped,\n _enginePlayTime: 0,\n _enginePauseTime: 0,\n _isConnected: false,\n _pitch: null,\n _playbackRate: null,\n _engineStateUnsub: null,\n _onEnded: createAudioSignal<SoundInstance>(),\n _onStateChanged: createAudioSignal<SoundInstance>(),\n _endedHandler: () => _onInstanceEnded(sound, instance),\n _engineStateHandler: () => _onEngineStateChanged(instance),\n };\n return instance;\n}\n\nfunction _setInstanceState(instance: SoundInstance, state: SoundState): void {\n instance._state = state;\n instance._onStateChanged._notify(instance);\n}\n\nfunction _instancePlay(instance: SoundInstance, options: Required<StaticSoundPlayOptions>): void {\n if (instance._state === SoundState.Started) {\n return;\n }\n\n instance._options.duration = options.duration;\n instance._options.loop = options.loop;\n instance._options.loopStart = options.loopStart;\n instance._options.loopEnd = options.loopEnd;\n instance._options.startOffset = options.startOffset;\n\n let startOffset = instance._options.startOffset;\n if (instance._state === SoundState.Paused) {\n startOffset += instance._enginePauseTime;\n startOffset %= instance._sound._buffer.duration;\n }\n\n instance._enginePlayTime = instance._engine.currentTime + options.waitTime;\n\n if (options.volume !== undefined) {\n instance._volumeNode.gain.value = options.volume;\n }\n\n _initSourceNode(instance);\n\n if (instance._engine.state === \"running\") {\n _setInstanceState(instance, SoundState.Started);\n instance._sourceNode?.start(instance._enginePlayTime, startOffset, instance._options.duration > 0 ? instance._options.duration : undefined);\n } else if (instance._options.loop) {\n _setInstanceState(instance, SoundState.Starting);\n instance._engineStateUnsub = instance._engine.onStateChanged.add(instance._engineStateHandler);\n }\n}\n\nfunction _instancePause(instance: SoundInstance): void {\n if (instance._state !== SoundState.Started && instance._state !== SoundState.Starting) {\n return;\n }\n\n const wasStarted = instance._state === SoundState.Started;\n _setInstanceState(instance, SoundState.Paused);\n instance._enginePauseTime += instance._engine.currentTime - instance._enginePlayTime;\n\n if (wasStarted) {\n instance._sourceNode?.stop();\n } else {\n instance._engineStateUnsub?.();\n instance._engineStateUnsub = null;\n }\n\n _deinitSourceNode(instance);\n}\n\nfunction _instanceResume(instance: SoundInstance, options: StaticSoundPlayOptions): void {\n if (instance._state === SoundState.Paused) {\n const opts: Required<StaticSoundPlayOptions> = {\n duration: options.duration ?? instance._options.duration,\n loop: options.loop ?? instance._options.loop,\n loopStart: options.loopStart ?? instance._options.loopStart,\n loopEnd: options.loopEnd ?? instance._options.loopEnd,\n startOffset: options.startOffset ?? instance._options.startOffset,\n volume: options.volume ?? instance._volumeNode.gain.value,\n waitTime: options.waitTime ?? 0,\n };\n _instancePlay(instance, opts);\n }\n}\n\nfunction _instanceStop(instance: SoundInstance, options: StaticSoundStopOptions = {}): void {\n if (instance._state === SoundState.Stopped) {\n return;\n }\n\n if (instance._state === SoundState.Started) {\n const stopTime = instance._engine.currentTime + (options.waitTime ?? 0);\n instance._sourceNode?.stop(stopTime);\n }\n\n if (options.waitTime === undefined || options.waitTime <= 0) {\n _setInstanceState(instance, SoundState.Stopped);\n instance._engineStateUnsub?.();\n instance._engineStateUnsub = null;\n }\n}\n\nfunction _instanceDispose(instance: SoundInstance): void {\n _instanceStop(instance);\n _deinitSourceNode(instance);\n instance._engineStateUnsub?.();\n instance._engineStateUnsub = null;\n instance._pitch = null;\n instance._playbackRate = null;\n instance._onEnded._clear();\n instance._onStateChanged._clear();\n}\n\nfunction _onEngineStateChanged(instance: SoundInstance): void {\n if (instance._engine.state !== \"running\") {\n return;\n }\n if (instance._options.loop && instance._state === SoundState.Starting) {\n const opts: Required<StaticSoundPlayOptions> = {\n duration: instance._options.duration,\n loop: instance._options.loop,\n loopStart: instance._options.loopStart,\n loopEnd: instance._options.loopEnd,\n startOffset: instance._options.startOffset,\n volume: instance._volumeNode.gain.value,\n waitTime: 0,\n };\n // Reset to a non-started state so `_instancePlay` proceeds.\n instance._state = SoundState.Stopped;\n _instancePlay(instance, opts);\n }\n}\n\nfunction _onInstanceEndedEvent(instance: SoundInstance): void {\n instance._enginePlayTime = 0;\n if (instance._state !== SoundState.Paused) {\n instance._onEnded._notify(instance);\n }\n _deinitSourceNode(instance);\n}\n\nfunction _initSourceNode(instance: SoundInstance): void {\n const sound = instance._sound;\n if (!instance._sourceNode) {\n const sourceNode = new AudioBufferSourceNode(instance._engine._ctx, { buffer: sound._buffer._audioBuffer });\n instance._sourceNode = sourceNode;\n\n sourceNode.addEventListener(\"ended\", () => _onInstanceEndedEvent(instance), { once: true });\n sourceNode.connect(instance._volumeNode);\n\n // Connect this instance's output into the sound's sub-graph input.\n instance._volumeNode.connect(sound._graph._in);\n instance._isConnected = true;\n\n instance._pitch = createRampParam(sourceNode.detune, instance._engine);\n instance._playbackRate = createRampParam(sourceNode.playbackRate, instance._engine);\n }\n\n const node = instance._sourceNode;\n node.detune.value = sound._options.pitch;\n node.loop = instance._options.loop;\n node.loopEnd = instance._options.loopEnd;\n node.loopStart = instance._options.loopStart;\n node.playbackRate.value = sound._options.playbackRate;\n}\n\nfunction _deinitSourceNode(instance: SoundInstance): void {\n const node = instance._sourceNode;\n if (!node) {\n return;\n }\n\n if (instance._isConnected) {\n instance._volumeNode.disconnect(instance._sound._graph._in);\n instance._isConnected = false;\n }\n\n node.disconnect(instance._volumeNode);\n instance._sourceNode = null;\n}\n\n/**\n * Sets the detune (pitch) of the newest instance, in cents.\n * Provided for completeness; ramps via the instance's detune param.\n * @internal\n */\nexport function _setNewestInstancePitch(sound: StaticSound, value: number, options?: RampOptions): void {\n const instance = sound._newest;\n if (instance?._pitch) {\n setRampTarget(instance._pitch, value, options);\n }\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ import { setRampTarget, createRampParam } from './audio-param.js';
2
+ import { rebuildSoundSubGraphHead } from './sound-sub-graph.js';
3
+
4
+ const DEFAULT_PAN = 0;
5
+ function createStereoSubNode(engine) {
6
+ const node = new StereoPannerNode(engine._ctx);
7
+ node.pan.value = DEFAULT_PAN;
8
+ return {
9
+ _engine: engine,
10
+ _inputNode: node,
11
+ _pan: createRampParam(node.pan, engine),
12
+ _dispose: () => {
13
+ node.disconnect();
14
+ }
15
+ };
16
+ }
17
+ function ensureStereoSubNode(host) {
18
+ const graph = host._graph;
19
+ if (graph._stereo) {
20
+ return graph._stereo;
21
+ }
22
+ const node = createStereoSubNode(host._engine);
23
+ node._inputNode.connect(graph._volume);
24
+ graph._stereo = node;
25
+ rebuildSoundSubGraphHead(graph, host._instances);
26
+ return node;
27
+ }
28
+ function enableStereo(host, options = {}) {
29
+ const node = ensureStereoSubNode(host);
30
+ if (options.pan !== void 0) {
31
+ setRampTarget(node._pan, options.pan);
32
+ }
33
+ }
34
+ function setStereoPan(host, pan, options) {
35
+ const node = ensureStereoSubNode(host);
36
+ setRampTarget(node._pan, pan, options);
37
+ }
38
+
39
+ export { enableStereo, setStereoPan };
40
+ //# sourceMappingURL=stereo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stereo.js","sources":["../../../src/audio/stereo.ts"],"sourcesContent":["/**\n * Stereo panning — opt-in feature module.\n *\n * Faithful port of AudioV2 `_StereoAudioSubNode` / `_StereoWebAudioSubNode`,\n * re-architected to Lite idioms (pure state + standalone functions). Building\n * the sub-node is lazy, so importing nothing from here costs nothing.\n *\n * The stereo sub-node wraps a Web Audio `StereoPannerNode`. It is spliced into\n * the host's sub-graph in parallel with the optional spatial sub-node (see\n * {@link rebuildSoundSubGraphHead}); when both are present a split gain feeds\n * both branches, exactly as AudioV2 `_onSubNodesChanged` does.\n */\n\nimport { type AudioEngine } from \"./audio-engine.js\";\nimport { type RampOptions, type RampParam, createRampParam, setRampTarget } from \"./audio-param.js\";\nimport { rebuildSoundSubGraphHead } from \"./sound-sub-graph.js\";\nimport { type AudioGraphHost, type AudioGraphHostState } from \"./host-types.js\";\n\n/** Default stereo pan: centered. */\nconst DEFAULT_PAN = 0;\n\n/** Options for {@link enableStereo}. */\nexport interface StereoSoundOptions {\n /** Stereo pan in the range `[-1, 1]` (`-1` = full left, `1` = full right). Defaults to `0`. */\n pan?: number;\n}\n\n/** Stereo-pan sub-node state. Pure state — driven by the stereo functions. @internal */\nexport interface StereoSubNode {\n /** @internal */ _engine: AudioEngine;\n /** Head node — playing instances connect here; also the output to volume. @internal */ _inputNode: StereoPannerNode;\n /** @internal */ _pan: RampParam;\n /** @internal */ _dispose: () => void;\n}\n\nfunction createStereoSubNode(engine: AudioEngine): StereoSubNode {\n const node = new StereoPannerNode(engine._ctx);\n node.pan.value = DEFAULT_PAN;\n return {\n _engine: engine,\n _inputNode: node,\n _pan: createRampParam(node.pan, engine),\n _dispose: () => {\n node.disconnect();\n },\n };\n}\n\n/**\n * Lazily build the stereo sub-node and splice it into the host's sub-graph,\n * reconnecting any live instances. Idempotent.\n */\nfunction ensureStereoSubNode(host: AudioGraphHostState): StereoSubNode {\n const graph = host._graph;\n if (graph._stereo) {\n // The graph stores a structural slot; this feature module owns the full node.\n return graph._stereo as StereoSubNode;\n }\n\n const node = createStereoSubNode(host._engine);\n node._inputNode.connect(graph._volume);\n graph._stereo = node;\n\n // Recompute the head and reconnect live instances (handles spatial+stereo parallel routing).\n rebuildSoundSubGraphHead(graph, host._instances);\n\n return node;\n}\n\n// ─── Public API ──────────────────────────────────────────────────────\n\n/**\n * Enables (or reconfigures) stereo panning on a sound or bus, building the\n * stereo sub-node on first use. Pulls the stereo module only when called.\n * @param host - A `StaticSound`, `StreamingSound`, or `AudioBus`.\n * @param options - Stereo options (pan).\n */\nexport function enableStereo(host: AudioGraphHost, options: StereoSoundOptions = {}): void {\n const node = ensureStereoSubNode(host);\n if (options.pan !== undefined) {\n setRampTarget(node._pan, options.pan);\n }\n}\n\n/**\n * Sets the stereo pan of a sound or bus, building the stereo sub-node on first\n * use.\n * @param host - A `StaticSound`, `StreamingSound`, or `AudioBus`.\n * @param pan - Pan in the range `[-1, 1]` (`-1` = full left, `1` = full right).\n * @param options - Optional ramp options for a smooth transition.\n */\nexport function setStereoPan(host: AudioGraphHost, pan: number, options?: RampOptions): void {\n const node = ensureStereoSubNode(host);\n setRampTarget(node._pan, pan, options);\n}\n"],"names":[],"mappings":";;;AAmBA,MAAM,WAAA,GAAc,CAAA;AAgBpB,SAAS,oBAAoB,MAAA,EAAoC;AAC7D,EAAA,MAAM,IAAA,GAAO,IAAI,gBAAA,CAAiB,MAAA,CAAO,IAAI,CAAA;AAC7C,EAAA,IAAA,CAAK,IAAI,KAAA,GAAQ,WAAA;AACjB,EAAA,OAAO;AAAA,IACH,OAAA,EAAS,MAAA;AAAA,IACT,UAAA,EAAY,IAAA;AAAA,IACZ,IAAA,EAAM,eAAA,CAAgB,IAAA,CAAK,GAAA,EAAK,MAAM,CAAA;AAAA,IACtC,UAAU,MAAM;AACZ,MAAA,IAAA,CAAK,UAAA,EAAW;AAAA,IACpB;AAAA,GACJ;AACJ;AAMA,SAAS,oBAAoB,IAAA,EAA0C;AACnE,EAAA,MAAM,QAAQ,IAAA,CAAK,MAAA;AACnB,EAAA,IAAI,MAAM,OAAA,EAAS;AAEf,IAAA,OAAO,KAAA,CAAM,OAAA;AAAA,EACjB;AAEA,EAAA,MAAM,IAAA,GAAO,mBAAA,CAAoB,IAAA,CAAK,OAAO,CAAA;AAC7C,EAAA,IAAA,CAAK,UAAA,CAAW,OAAA,CAAQ,KAAA,CAAM,OAAO,CAAA;AACrC,EAAA,KAAA,CAAM,OAAA,GAAU,IAAA;AAGhB,EAAA,wBAAA,CAAyB,KAAA,EAAO,KAAK,UAAU,CAAA;AAE/C,EAAA,OAAO,IAAA;AACX;AAUO,SAAS,YAAA,CAAa,IAAA,EAAsB,OAAA,GAA8B,EAAC,EAAS;AACvF,EAAA,MAAM,IAAA,GAAO,oBAAoB,IAAI,CAAA;AACrC,EAAA,IAAI,OAAA,CAAQ,QAAQ,MAAA,EAAW;AAC3B,IAAA,aAAA,CAAc,IAAA,CAAK,IAAA,EAAM,OAAA,CAAQ,GAAG,CAAA;AAAA,EACxC;AACJ;AASO,SAAS,YAAA,CAAa,IAAA,EAAsB,GAAA,EAAa,OAAA,EAA6B;AACzF,EAAA,MAAM,IAAA,GAAO,oBAAoB,IAAI,CAAA;AACrC,EAAA,aAAA,CAAc,IAAA,CAAK,IAAA,EAAM,GAAA,EAAK,OAAO,CAAA;AACzC;;;;"}