@codexo/exojs 0.6.12 → 0.7.11

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 (186) hide show
  1. package/CHANGELOG.md +1316 -0
  2. package/dist/esm/audio/AbstractMedia.d.ts +18 -0
  3. package/dist/esm/audio/AbstractMedia.js +66 -0
  4. package/dist/esm/audio/AbstractMedia.js.map +1 -1
  5. package/dist/esm/audio/AudioAnalyser.d.ts +62 -23
  6. package/dist/esm/audio/AudioAnalyser.js +261 -57
  7. package/dist/esm/audio/AudioAnalyser.js.map +1 -1
  8. package/dist/esm/audio/AudioBus.d.ts +45 -0
  9. package/dist/esm/audio/AudioBus.js +219 -0
  10. package/dist/esm/audio/AudioBus.js.map +1 -0
  11. package/dist/esm/audio/AudioFilter.d.ts +9 -0
  12. package/dist/esm/audio/AudioFilter.js +7 -0
  13. package/dist/esm/audio/AudioFilter.js.map +1 -0
  14. package/dist/esm/audio/AudioListener.d.ts +20 -0
  15. package/dist/esm/audio/AudioListener.js +86 -0
  16. package/dist/esm/audio/AudioListener.js.map +1 -0
  17. package/dist/esm/audio/AudioManager.d.ts +31 -0
  18. package/dist/esm/audio/AudioManager.js +102 -0
  19. package/dist/esm/audio/AudioManager.js.map +1 -0
  20. package/dist/esm/audio/BeatDetector.d.ts +121 -0
  21. package/dist/esm/audio/BeatDetector.js +936 -0
  22. package/dist/esm/audio/BeatDetector.js.map +1 -0
  23. package/dist/esm/audio/Envelope.d.ts +44 -0
  24. package/dist/esm/audio/Envelope.js +60 -0
  25. package/dist/esm/audio/Envelope.js.map +1 -0
  26. package/dist/esm/audio/Music.d.ts +8 -0
  27. package/dist/esm/audio/Music.js +33 -4
  28. package/dist/esm/audio/Music.js.map +1 -1
  29. package/dist/esm/audio/OscillatorSound.d.ts +98 -0
  30. package/dist/esm/audio/OscillatorSound.js +342 -0
  31. package/dist/esm/audio/OscillatorSound.js.map +1 -0
  32. package/dist/esm/audio/Sound.d.ts +94 -9
  33. package/dist/esm/audio/Sound.js +283 -117
  34. package/dist/esm/audio/Sound.js.map +1 -1
  35. package/dist/esm/audio/crossFade.d.ts +19 -0
  36. package/dist/esm/audio/crossFade.js +26 -0
  37. package/dist/esm/audio/crossFade.js.map +1 -0
  38. package/dist/esm/audio/dsp/fft.d.ts +22 -0
  39. package/dist/esm/audio/dsp/mel.d.ts +43 -0
  40. package/dist/esm/audio/dsp/tempogram.d.ts +51 -0
  41. package/dist/esm/audio/filters/ChorusFilter.d.ts +47 -0
  42. package/dist/esm/audio/filters/ChorusFilter.js +139 -0
  43. package/dist/esm/audio/filters/ChorusFilter.js.map +1 -0
  44. package/dist/esm/audio/filters/CompressorFilter.d.ts +31 -0
  45. package/dist/esm/audio/filters/CompressorFilter.js +97 -0
  46. package/dist/esm/audio/filters/CompressorFilter.js.map +1 -0
  47. package/dist/esm/audio/filters/DelayFilter.d.ts +23 -0
  48. package/dist/esm/audio/filters/DelayFilter.js +100 -0
  49. package/dist/esm/audio/filters/DelayFilter.js.map +1 -0
  50. package/dist/esm/audio/filters/DuckingFilter.d.ts +31 -0
  51. package/dist/esm/audio/filters/DuckingFilter.js +152 -0
  52. package/dist/esm/audio/filters/DuckingFilter.js.map +1 -0
  53. package/dist/esm/audio/filters/EqualizerFilter.d.ts +29 -0
  54. package/dist/esm/audio/filters/EqualizerFilter.js +94 -0
  55. package/dist/esm/audio/filters/EqualizerFilter.js.map +1 -0
  56. package/dist/esm/audio/filters/GranularFilter.d.ts +56 -0
  57. package/dist/esm/audio/filters/GranularFilter.js +170 -0
  58. package/dist/esm/audio/filters/GranularFilter.js.map +1 -0
  59. package/dist/esm/audio/filters/HighpassFilter.d.ts +19 -0
  60. package/dist/esm/audio/filters/HighpassFilter.js +62 -0
  61. package/dist/esm/audio/filters/HighpassFilter.js.map +1 -0
  62. package/dist/esm/audio/filters/LowpassFilter.d.ts +19 -0
  63. package/dist/esm/audio/filters/LowpassFilter.js +62 -0
  64. package/dist/esm/audio/filters/LowpassFilter.js.map +1 -0
  65. package/dist/esm/audio/filters/PitchShiftFilter.d.ts +42 -0
  66. package/dist/esm/audio/filters/PitchShiftFilter.js +130 -0
  67. package/dist/esm/audio/filters/PitchShiftFilter.js.map +1 -0
  68. package/dist/esm/audio/filters/ReverbFilter.d.ts +24 -0
  69. package/dist/esm/audio/filters/ReverbFilter.js +107 -0
  70. package/dist/esm/audio/filters/ReverbFilter.js.map +1 -0
  71. package/dist/esm/audio/filters/VocoderFilter.d.ts +38 -0
  72. package/dist/esm/audio/filters/VocoderFilter.js +163 -0
  73. package/dist/esm/audio/filters/VocoderFilter.js.map +1 -0
  74. package/dist/esm/audio/filters/WorkletFilter.d.ts +46 -0
  75. package/dist/esm/audio/filters/WorkletFilter.js +101 -0
  76. package/dist/esm/audio/filters/WorkletFilter.js.map +1 -0
  77. package/dist/esm/audio/filters/index.d.ts +12 -0
  78. package/dist/esm/audio/index.d.ts +15 -1
  79. package/dist/esm/audio/worklet/registerWorklet.d.ts +10 -0
  80. package/dist/esm/audio/worklet/registerWorklet.js +44 -0
  81. package/dist/esm/audio/worklet/registerWorklet.js.map +1 -0
  82. package/dist/esm/core/Application.d.ts +19 -0
  83. package/dist/esm/core/Application.js +76 -2
  84. package/dist/esm/core/Application.js.map +1 -1
  85. package/dist/esm/core/SceneNode.d.ts +9 -1
  86. package/dist/esm/core/SceneNode.js +44 -6
  87. package/dist/esm/core/SceneNode.js.map +1 -1
  88. package/dist/esm/core/Time.js +1 -1
  89. package/dist/esm/core/index.d.ts +0 -1
  90. package/dist/esm/debug/BoundingBoxesLayer.d.ts +18 -0
  91. package/dist/esm/debug/BoundingBoxesLayer.js +128 -0
  92. package/dist/esm/debug/BoundingBoxesLayer.js.map +1 -0
  93. package/dist/esm/debug/DebugLayer.d.ts +29 -0
  94. package/dist/esm/debug/DebugLayer.js +26 -0
  95. package/dist/esm/debug/DebugLayer.js.map +1 -0
  96. package/dist/esm/debug/DebugOverlay.d.ts +48 -0
  97. package/dist/esm/debug/DebugOverlay.js +117 -0
  98. package/dist/esm/debug/DebugOverlay.js.map +1 -0
  99. package/dist/esm/debug/HitTestLayer.d.ts +23 -0
  100. package/dist/esm/debug/HitTestLayer.js +109 -0
  101. package/dist/esm/debug/HitTestLayer.js.map +1 -0
  102. package/dist/esm/debug/PerformanceLayer.d.ts +21 -0
  103. package/dist/esm/debug/PerformanceLayer.js +175 -0
  104. package/dist/esm/debug/PerformanceLayer.js.map +1 -0
  105. package/dist/esm/debug/PointerStackLayer.d.ts +23 -0
  106. package/dist/esm/debug/PointerStackLayer.js +152 -0
  107. package/dist/esm/debug/PointerStackLayer.js.map +1 -0
  108. package/dist/esm/debug/index.d.ts +6 -0
  109. package/dist/esm/debug/index.js +7 -0
  110. package/dist/esm/debug/index.js.map +1 -0
  111. package/dist/esm/index.js +28 -2
  112. package/dist/esm/index.js.map +1 -1
  113. package/dist/esm/input/InputManager.d.ts +10 -0
  114. package/dist/esm/input/InputManager.js +35 -5
  115. package/dist/esm/input/InputManager.js.map +1 -1
  116. package/dist/esm/input/InteractionEvent.d.ts +18 -0
  117. package/dist/esm/input/InteractionEvent.js +29 -0
  118. package/dist/esm/input/InteractionEvent.js.map +1 -0
  119. package/dist/esm/input/InteractionManager.d.ts +134 -0
  120. package/dist/esm/input/InteractionManager.js +546 -0
  121. package/dist/esm/input/InteractionManager.js.map +1 -0
  122. package/dist/esm/input/index.d.ts +2 -0
  123. package/dist/esm/input/interaction-hooks.d.ts +34 -0
  124. package/dist/esm/input/interaction-hooks.js +35 -0
  125. package/dist/esm/input/interaction-hooks.js.map +1 -0
  126. package/dist/esm/math/Circle.d.ts +12 -2
  127. package/dist/esm/math/Circle.js +82 -14
  128. package/dist/esm/math/Circle.js.map +1 -1
  129. package/dist/esm/math/Interval.js +1 -1
  130. package/dist/esm/math/ObservableVector.d.ts +2 -2
  131. package/dist/esm/math/ObservableVector.js +4 -2
  132. package/dist/esm/math/ObservableVector.js.map +1 -1
  133. package/dist/esm/math/Polygon.d.ts +15 -1
  134. package/dist/esm/math/Polygon.js +58 -6
  135. package/dist/esm/math/Polygon.js.map +1 -1
  136. package/dist/esm/math/Quadtree.d.ts +47 -0
  137. package/dist/esm/math/Quadtree.js +168 -0
  138. package/dist/esm/math/Quadtree.js.map +1 -0
  139. package/dist/esm/math/Random.js +1 -1
  140. package/dist/esm/math/Size.js +1 -1
  141. package/dist/esm/math/Vector.js +1 -1
  142. package/dist/esm/math/collision-detection.js +4 -1
  143. package/dist/esm/math/collision-detection.js.map +1 -1
  144. package/dist/esm/math/index.d.ts +1 -0
  145. package/dist/esm/particles/ParticleSystem.js +1 -0
  146. package/dist/esm/particles/ParticleSystem.js.map +1 -1
  147. package/dist/esm/particles/affectors/TorqueAffector.js +1 -1
  148. package/dist/esm/rendering/Container.d.ts +1 -0
  149. package/dist/esm/rendering/Container.js +19 -0
  150. package/dist/esm/rendering/Container.js.map +1 -1
  151. package/dist/esm/rendering/RenderNode.d.ts +27 -0
  152. package/dist/esm/rendering/RenderNode.js +44 -0
  153. package/dist/esm/rendering/RenderNode.js.map +1 -1
  154. package/dist/esm/rendering/View.d.ts +6 -4
  155. package/dist/esm/rendering/View.js +12 -2
  156. package/dist/esm/rendering/View.js.map +1 -1
  157. package/dist/esm/rendering/filters/WebGl2ShaderFilter.d.ts +109 -0
  158. package/dist/esm/rendering/filters/WebGl2ShaderFilter.js +268 -0
  159. package/dist/esm/rendering/filters/WebGl2ShaderFilter.js.map +1 -0
  160. package/dist/esm/rendering/filters/WebGpuShaderFilter.d.ts +111 -0
  161. package/dist/esm/rendering/filters/WebGpuShaderFilter.js +397 -0
  162. package/dist/esm/rendering/filters/WebGpuShaderFilter.js.map +1 -0
  163. package/dist/esm/rendering/index.d.ts +3 -0
  164. package/dist/esm/rendering/mesh/Mesh.js +1 -0
  165. package/dist/esm/rendering/mesh/Mesh.js.map +1 -1
  166. package/dist/esm/rendering/shader/upgradeFragmentShaderToGl300.d.ts +34 -0
  167. package/dist/esm/rendering/shader/upgradeFragmentShaderToGl300.js +60 -0
  168. package/dist/esm/rendering/shader/upgradeFragmentShaderToGl300.js.map +1 -0
  169. package/dist/esm/rendering/sprite/Sprite.d.ts +6 -1
  170. package/dist/esm/rendering/sprite/Sprite.js +41 -19
  171. package/dist/esm/rendering/sprite/Sprite.js.map +1 -1
  172. package/dist/esm/rendering/video/Video.d.ts +4 -0
  173. package/dist/esm/rendering/video/Video.js +32 -4
  174. package/dist/esm/rendering/video/Video.js.map +1 -1
  175. package/dist/esm/rendering/webgl2/WebGl2Backend.d.ts +4 -4
  176. package/dist/esm/rendering/webgl2/WebGl2Backend.js +7 -16
  177. package/dist/esm/rendering/webgl2/WebGl2Backend.js.map +1 -1
  178. package/dist/esm/rendering/webgpu/WebGpuBackend.d.ts +10 -8
  179. package/dist/esm/rendering/webgpu/WebGpuBackend.js +30 -40
  180. package/dist/esm/rendering/webgpu/WebGpuBackend.js.map +1 -1
  181. package/dist/exo.esm.js +7764 -2453
  182. package/dist/exo.esm.js.map +1 -1
  183. package/package.json +14 -2
  184. package/dist/esm/core/Quadtree.d.ts +0 -20
  185. package/dist/esm/core/Quadtree.js +0 -86
  186. package/dist/esm/core/Quadtree.js.map +0 -1
@@ -0,0 +1,45 @@
1
+ import type { AudioFilter } from './AudioFilter';
2
+ export interface AudioBusOptions {
3
+ parent?: AudioBus | null;
4
+ volume?: number;
5
+ muted?: boolean;
6
+ pan?: number;
7
+ filters?: ReadonlyArray<AudioFilter>;
8
+ }
9
+ export declare class AudioBus {
10
+ readonly name: string;
11
+ private _parent;
12
+ private _volume;
13
+ private _muted;
14
+ private _pan;
15
+ private readonly _filters;
16
+ private _setup;
17
+ private _scheduledStopId;
18
+ constructor(name: string, options?: AudioBusOptions);
19
+ get parent(): AudioBus | null;
20
+ get volume(): number;
21
+ set volume(value: number);
22
+ get muted(): boolean;
23
+ set muted(value: boolean);
24
+ get pan(): number;
25
+ set pan(value: number);
26
+ get inputNode(): GainNode | null;
27
+ addFilter(filter: AudioFilter): this;
28
+ removeFilter(filter: AudioFilter): this;
29
+ fadeIn(durationMs: number): this;
30
+ fadeOut(durationMs: number, options?: {
31
+ stopAfter?: boolean;
32
+ }): this;
33
+ destroy(): void;
34
+ /** Internal: returns the input GainNode where children should connect. */
35
+ _getInputNode(): GainNode | null;
36
+ /** Internal: returns the output GainNode that connects upstream. */
37
+ _getOutputNode(): GainNode | null;
38
+ private _setupAudio;
39
+ private _connectUpstream;
40
+ /** Subscribe to the moment this bus's audio nodes are ready. Internal use. */
41
+ onceSetup(callback: () => void): void;
42
+ private _rebuildFilterChain;
43
+ private _applyVolume;
44
+ private _clearScheduledStop;
45
+ }
@@ -0,0 +1,219 @@
1
+ import { clamp } from '../math/utils.js';
2
+ import { isAudioContextReady, getAudioContext, onAudioContextReady } from './audio-context.js';
3
+
4
+ class AudioBus {
5
+ name;
6
+ _parent;
7
+ _volume;
8
+ _muted;
9
+ _pan;
10
+ _filters = [];
11
+ _setup = null;
12
+ _scheduledStopId = null;
13
+ constructor(name, options = {}) {
14
+ if (!name || typeof name !== 'string') {
15
+ throw new Error('AudioBus requires a non-empty string name.');
16
+ }
17
+ this.name = name;
18
+ this._parent = options.parent ?? null;
19
+ this._volume = clamp(options.volume ?? 1, 0, 2);
20
+ this._muted = options.muted ?? false;
21
+ this._pan = clamp(options.pan ?? 0, -1, 1);
22
+ if (options.filters) {
23
+ this._filters.push(...options.filters);
24
+ }
25
+ if (isAudioContextReady()) {
26
+ this._setupAudio(getAudioContext());
27
+ }
28
+ else {
29
+ onAudioContextReady.once(this._setupAudio, this);
30
+ }
31
+ }
32
+ get parent() {
33
+ return this._parent;
34
+ }
35
+ get volume() {
36
+ return this._volume;
37
+ }
38
+ set volume(value) {
39
+ const clamped = clamp(value, 0, 2);
40
+ if (this._volume === clamped)
41
+ return;
42
+ this._volume = clamped;
43
+ this._applyVolume();
44
+ }
45
+ get muted() {
46
+ return this._muted;
47
+ }
48
+ set muted(value) {
49
+ if (this._muted === value)
50
+ return;
51
+ this._muted = value;
52
+ this._applyVolume();
53
+ }
54
+ get pan() {
55
+ return this._pan;
56
+ }
57
+ set pan(value) {
58
+ const clamped = clamp(value, -1, 1);
59
+ if (this._pan === clamped)
60
+ return;
61
+ this._pan = clamped;
62
+ if (this._setup) {
63
+ this._setup.panNode.pan.setTargetAtTime(clamped, this._setup.audioContext.currentTime, 0.01);
64
+ }
65
+ }
66
+ get inputNode() {
67
+ return this._setup?.inputNode ?? null;
68
+ }
69
+ addFilter(filter) {
70
+ this._filters.push(filter);
71
+ this._rebuildFilterChain();
72
+ return this;
73
+ }
74
+ removeFilter(filter) {
75
+ const index = this._filters.indexOf(filter);
76
+ if (index !== -1) {
77
+ this._filters.splice(index, 1);
78
+ this._rebuildFilterChain();
79
+ }
80
+ return this;
81
+ }
82
+ fadeIn(durationMs) {
83
+ this._clearScheduledStop();
84
+ if (durationMs <= 0 || !this._setup) {
85
+ return this;
86
+ }
87
+ const ctx = this._setup.audioContext;
88
+ const node = this._setup.outputNode;
89
+ const target = this._muted ? 0 : this._volume;
90
+ node.gain.cancelScheduledValues(ctx.currentTime);
91
+ node.gain.setValueAtTime(0, ctx.currentTime);
92
+ node.gain.linearRampToValueAtTime(target, ctx.currentTime + durationMs / 1000);
93
+ return this;
94
+ }
95
+ fadeOut(durationMs, options = {}) {
96
+ const stopAfter = options.stopAfter ?? true;
97
+ this._clearScheduledStop();
98
+ if (durationMs <= 0 || !this._setup) {
99
+ if (stopAfter)
100
+ this.muted = true;
101
+ return this;
102
+ }
103
+ const ctx = this._setup.audioContext;
104
+ const node = this._setup.outputNode;
105
+ node.gain.cancelScheduledValues(ctx.currentTime);
106
+ node.gain.setValueAtTime(node.gain.value, ctx.currentTime);
107
+ node.gain.linearRampToValueAtTime(0, ctx.currentTime + durationMs / 1000);
108
+ if (stopAfter) {
109
+ this._scheduledStopId = setTimeout(() => {
110
+ this._scheduledStopId = null;
111
+ this.muted = true;
112
+ }, durationMs);
113
+ }
114
+ return this;
115
+ }
116
+ destroy() {
117
+ onAudioContextReady.clearByContext(this);
118
+ this._clearScheduledStop();
119
+ for (const filter of this._filters) {
120
+ filter.destroy();
121
+ }
122
+ this._filters.length = 0;
123
+ if (this._setup) {
124
+ this._setup.inputNode.disconnect();
125
+ this._setup.outputNode.disconnect();
126
+ this._setup.panNode.disconnect();
127
+ this._setup = null;
128
+ }
129
+ }
130
+ /** Internal: returns the input GainNode where children should connect. */
131
+ _getInputNode() {
132
+ return this._setup?.inputNode ?? null;
133
+ }
134
+ /** Internal: returns the output GainNode that connects upstream. */
135
+ _getOutputNode() {
136
+ return this._setup?.outputNode ?? null;
137
+ }
138
+ _setupAudio(audioContext) {
139
+ const inputNode = audioContext.createGain();
140
+ const panNode = audioContext.createStereoPanner();
141
+ const outputNode = audioContext.createGain();
142
+ // Internal chain: input → [filters...] → pan → output
143
+ outputNode.gain.setTargetAtTime(this._muted ? 0 : this._volume, audioContext.currentTime, 0.01);
144
+ panNode.pan.setTargetAtTime(this._pan, audioContext.currentTime, 0.01);
145
+ this._setup = { audioContext, inputNode, outputNode, panNode };
146
+ this._rebuildFilterChain();
147
+ this._connectUpstream();
148
+ }
149
+ _connectUpstream() {
150
+ if (!this._setup)
151
+ return;
152
+ if (this._parent) {
153
+ const parentInput = this._parent._getInputNode();
154
+ if (parentInput) {
155
+ this._setup.outputNode.connect(parentInput);
156
+ }
157
+ else {
158
+ // Parent not yet ready — subscribe to parent's setup
159
+ this._parent.onceSetup(() => {
160
+ if (this._setup && this._parent) {
161
+ const node = this._parent._getInputNode();
162
+ if (node)
163
+ this._setup.outputNode.connect(node);
164
+ }
165
+ });
166
+ }
167
+ }
168
+ else {
169
+ this._setup.outputNode.connect(this._setup.audioContext.destination);
170
+ }
171
+ }
172
+ /** Subscribe to the moment this bus's audio nodes are ready. Internal use. */
173
+ onceSetup(callback) {
174
+ if (this._setup) {
175
+ callback();
176
+ }
177
+ else {
178
+ onAudioContextReady.once(() => {
179
+ if (this._setup)
180
+ callback();
181
+ }, this);
182
+ }
183
+ }
184
+ _rebuildFilterChain() {
185
+ if (!this._setup)
186
+ return;
187
+ const { inputNode, panNode } = this._setup;
188
+ // Disconnect current chain
189
+ inputNode.disconnect();
190
+ for (const filter of this._filters) {
191
+ filter.inputNode.disconnect();
192
+ filter.outputNode.disconnect();
193
+ }
194
+ panNode.disconnect();
195
+ // Rebuild: input → filter[0].input → filter[0].output → filter[1].input → ... → pan → output
196
+ let prev = inputNode;
197
+ for (const filter of this._filters) {
198
+ prev.connect(filter.inputNode);
199
+ prev = filter.outputNode;
200
+ }
201
+ prev.connect(panNode);
202
+ panNode.connect(this._setup.outputNode);
203
+ }
204
+ _applyVolume() {
205
+ if (!this._setup)
206
+ return;
207
+ const target = this._muted ? 0 : this._volume;
208
+ this._setup.outputNode.gain.setTargetAtTime(target, this._setup.audioContext.currentTime, 0.01);
209
+ }
210
+ _clearScheduledStop() {
211
+ if (this._scheduledStopId !== null) {
212
+ clearTimeout(this._scheduledStopId);
213
+ this._scheduledStopId = null;
214
+ }
215
+ }
216
+ }
217
+
218
+ export { AudioBus };
219
+ //# sourceMappingURL=AudioBus.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AudioBus.js","sources":["../../../../src/audio/AudioBus.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ export declare abstract class AudioFilter {
2
+ /** The node where audio enters this filter. */
3
+ abstract get inputNode(): AudioNode;
4
+ /** The node where audio exits this filter. */
5
+ abstract get outputNode(): AudioNode;
6
+ /** Resolves when the filter is fully initialized. Defaults to immediately-resolved for sync filters. */
7
+ get ready(): Promise<void>;
8
+ abstract destroy(): void;
9
+ }
@@ -0,0 +1,7 @@
1
+ class AudioFilter {
2
+ /** Resolves when the filter is fully initialized. Defaults to immediately-resolved for sync filters. */
3
+ get ready() { return Promise.resolve(); }
4
+ }
5
+
6
+ export { AudioFilter };
7
+ //# sourceMappingURL=AudioFilter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AudioFilter.js","sources":["../../../../src/audio/AudioFilter.ts"],"sourcesContent":[null],"names":[],"mappings":"MAAsB,WAAW,CAAA;;IAM7B,IAAW,KAAK,KAAoB,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;AAEjE;;;;"}
@@ -0,0 +1,20 @@
1
+ import { Vector } from '@/math/Vector';
2
+ import type { SceneNode } from '@/core/SceneNode';
3
+ import type { View } from '@/rendering/View';
4
+ export type AudioListenerTarget = SceneNode | View | {
5
+ x: number;
6
+ y: number;
7
+ } | null;
8
+ export declare class AudioListener {
9
+ readonly position: Vector;
10
+ readonly velocity: Vector;
11
+ target: AudioListenerTarget;
12
+ private _audioListener;
13
+ private _ctx;
14
+ constructor();
15
+ /** Internal: called by AudioManager.update() once per frame. */
16
+ _tick(): void;
17
+ destroy(): void;
18
+ private _readTargetPosition;
19
+ private _setup;
20
+ }
@@ -0,0 +1,86 @@
1
+ import { Vector } from '../math/Vector.js';
2
+ import { isAudioContextReady, getAudioContext, onAudioContextReady } from './audio-context.js';
3
+
4
+ class AudioListener {
5
+ position = new Vector(0, 0);
6
+ velocity = new Vector(0, 0);
7
+ target = null;
8
+ _audioListener = null;
9
+ _ctx = null;
10
+ constructor() {
11
+ if (isAudioContextReady()) {
12
+ this._setup(getAudioContext());
13
+ }
14
+ else {
15
+ onAudioContextReady.once(this._setup, this);
16
+ }
17
+ }
18
+ /** Internal: called by AudioManager.update() once per frame. */
19
+ _tick() {
20
+ if (this.target !== null) {
21
+ this._readTargetPosition();
22
+ }
23
+ if (this._audioListener !== null && this._ctx !== null) {
24
+ const t = this._ctx.currentTime;
25
+ const listener = this._audioListener;
26
+ if (listener.positionX) {
27
+ listener.positionX.setValueAtTime(this.position.x, t);
28
+ listener.positionY.setValueAtTime(this.position.y, t);
29
+ listener.positionZ.setValueAtTime(0, t);
30
+ }
31
+ else if (listener.setPosition) {
32
+ listener.setPosition(this.position.x, this.position.y, 0);
33
+ }
34
+ }
35
+ }
36
+ destroy() {
37
+ onAudioContextReady.clearByContext(this);
38
+ this.position.destroy();
39
+ this.velocity.destroy();
40
+ this.target = null;
41
+ this._audioListener = null;
42
+ this._ctx = null;
43
+ }
44
+ _readTargetPosition() {
45
+ const target = this.target;
46
+ if (target === null)
47
+ return;
48
+ // Check for SceneNode (has getGlobalTransform)
49
+ const asSceneNode = target;
50
+ if (typeof asSceneNode.getGlobalTransform === 'function') {
51
+ const m = asSceneNode.getGlobalTransform();
52
+ this.position.set(m.x, m.y);
53
+ return;
54
+ }
55
+ // Check for View (has center with x/y)
56
+ const asView = target;
57
+ if (asView.center !== undefined && typeof asView.center === 'object') {
58
+ this.position.set(asView.center.x, asView.center.y);
59
+ return;
60
+ }
61
+ // Plain { x, y } object
62
+ const plain = target;
63
+ this.position.set(plain.x, plain.y);
64
+ }
65
+ _setup(ctx) {
66
+ this._ctx = ctx;
67
+ this._audioListener = ctx.listener;
68
+ const t = ctx.currentTime;
69
+ const listener = ctx.listener;
70
+ // Set 2D orientation: forward = -Z (into screen), up = +Y (screen up)
71
+ if (listener.forwardX) {
72
+ listener.forwardX.setValueAtTime(0, t);
73
+ listener.forwardY.setValueAtTime(0, t);
74
+ listener.forwardZ.setValueAtTime(-1, t);
75
+ listener.upX.setValueAtTime(0, t);
76
+ listener.upY.setValueAtTime(1, t);
77
+ listener.upZ.setValueAtTime(0, t);
78
+ }
79
+ else if (listener.setOrientation) {
80
+ listener.setOrientation(0, 0, -1, 0, 1, 0);
81
+ }
82
+ }
83
+ }
84
+
85
+ export { AudioListener };
86
+ //# sourceMappingURL=AudioListener.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AudioListener.js","sources":["../../../../src/audio/AudioListener.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ import { AudioBus } from './AudioBus';
2
+ import { AudioListener } from './AudioListener';
3
+ import type { Sound } from './Sound';
4
+ export declare class AudioManager {
5
+ readonly master: AudioBus;
6
+ readonly music: AudioBus;
7
+ readonly sound: AudioBus;
8
+ readonly listener: AudioListener;
9
+ private readonly _registered;
10
+ private readonly _spatialSounds;
11
+ private _muteOnHidden;
12
+ constructor();
13
+ get muteOnHidden(): boolean;
14
+ set muteOnHidden(value: boolean);
15
+ /** Called once per frame from Application.update(). */
16
+ update(): void;
17
+ /** Internal: called by Sound when it becomes spatial. */
18
+ _registerSpatialSound(sound: Sound): void;
19
+ /** Internal: called by Sound when it stops being spatial. */
20
+ _unregisterSpatialSound(sound: Sound): void;
21
+ /** Internal: called by Application when visibility changes. */
22
+ _applyVisibility(visible: boolean): void;
23
+ registerBus(bus: AudioBus): this;
24
+ unregisterBus(bus: AudioBus): this;
25
+ getBus(name: string): AudioBus;
26
+ hasBus(name: string): boolean;
27
+ destroy(): void;
28
+ }
29
+ export declare function getAudioManager(): AudioManager;
30
+ /** For tests: reset the singleton so fresh instances can be created. */
31
+ export declare function _resetAudioManagerForTesting(): void;
@@ -0,0 +1,102 @@
1
+ import { AudioBus } from './AudioBus.js';
2
+ import { AudioListener } from './AudioListener.js';
3
+
4
+ class AudioManager {
5
+ master;
6
+ music;
7
+ sound;
8
+ listener;
9
+ _registered = new Map();
10
+ _spatialSounds = new Set();
11
+ _muteOnHidden = false;
12
+ constructor() {
13
+ this.master = new AudioBus('master', { parent: null });
14
+ this.music = new AudioBus('music', { parent: this.master });
15
+ this.sound = new AudioBus('sound', { parent: this.master });
16
+ this.listener = new AudioListener();
17
+ // Built-ins are also lookup-able via getBus.
18
+ this._registered.set('master', this.master);
19
+ this._registered.set('music', this.music);
20
+ this._registered.set('sound', this.sound);
21
+ }
22
+ get muteOnHidden() {
23
+ return this._muteOnHidden;
24
+ }
25
+ set muteOnHidden(value) {
26
+ this._muteOnHidden = value;
27
+ // Wiring to app.onVisibilityChange happens externally — the
28
+ // Application is responsible for calling _applyVisibility() when
29
+ // visibility changes.
30
+ }
31
+ /** Called once per frame from Application.update(). */
32
+ update() {
33
+ this.listener._tick();
34
+ for (const sound of this._spatialSounds) {
35
+ sound._tickSpatial();
36
+ }
37
+ }
38
+ /** Internal: called by Sound when it becomes spatial. */
39
+ _registerSpatialSound(sound) {
40
+ this._spatialSounds.add(sound);
41
+ }
42
+ /** Internal: called by Sound when it stops being spatial. */
43
+ _unregisterSpatialSound(sound) {
44
+ this._spatialSounds.delete(sound);
45
+ }
46
+ /** Internal: called by Application when visibility changes. */
47
+ _applyVisibility(visible) {
48
+ if (this._muteOnHidden) {
49
+ this.master.muted = !visible;
50
+ }
51
+ }
52
+ registerBus(bus) {
53
+ if (this._registered.has(bus.name)) {
54
+ throw new Error(`Audio bus "${bus.name}" is already registered.`);
55
+ }
56
+ this._registered.set(bus.name, bus);
57
+ return this;
58
+ }
59
+ unregisterBus(bus) {
60
+ if (bus === this.master || bus === this.music || bus === this.sound) {
61
+ throw new Error(`Cannot unregister built-in bus "${bus.name}".`);
62
+ }
63
+ const existing = this._registered.get(bus.name);
64
+ if (existing !== bus) {
65
+ // Either not registered, or different instance with same name.
66
+ return this;
67
+ }
68
+ this._registered.delete(bus.name);
69
+ bus.destroy();
70
+ return this;
71
+ }
72
+ getBus(name) {
73
+ const bus = this._registered.get(name);
74
+ if (!bus) {
75
+ throw new Error(`Audio bus "${name}" is not registered.`);
76
+ }
77
+ return bus;
78
+ }
79
+ hasBus(name) {
80
+ return this._registered.has(name);
81
+ }
82
+ destroy() {
83
+ this.listener.destroy();
84
+ this._spatialSounds.clear();
85
+ for (const bus of this._registered.values()) {
86
+ // Note: destroying built-ins too — AudioManager is destroyed only when app shuts down.
87
+ bus.destroy();
88
+ }
89
+ this._registered.clear();
90
+ }
91
+ }
92
+ // Module-level singleton (lazy)
93
+ let _manager = null;
94
+ function getAudioManager() {
95
+ if (_manager === null) {
96
+ _manager = new AudioManager();
97
+ }
98
+ return _manager;
99
+ }
100
+
101
+ export { AudioManager, getAudioManager };
102
+ //# sourceMappingURL=AudioManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AudioManager.js","sources":["../../../../src/audio/AudioManager.ts"],"sourcesContent":[null],"names":[],"mappings":";;;MAIa,YAAY,CAAA;AACL,IAAA,MAAM;AACN,IAAA,KAAK;AACL,IAAA,KAAK;AACL,IAAA,QAAQ;AAEP,IAAA,WAAW,GAAG,IAAI,GAAG,EAAoB;AACzC,IAAA,cAAc,GAAe,IAAI,GAAG,EAAE;IAC/C,aAAa,GAAY,KAAK;AAEtC,IAAA,WAAA,GAAA;AACI,QAAA,IAAI,CAAC,MAAM,GAAG,IAAI,QAAQ,CAAC,QAAQ,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;AACtD,QAAA,IAAI,CAAC,KAAK,GAAG,IAAI,QAAQ,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC;AAC3D,QAAA,IAAI,CAAC,KAAK,GAAG,IAAI,QAAQ,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC;AAC3D,QAAA,IAAI,CAAC,QAAQ,GAAG,IAAI,aAAa,EAAE;;QAGnC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC;QAC3C,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC;QACzC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC;IAC7C;AAEA,IAAA,IAAW,YAAY,GAAA;QACnB,OAAO,IAAI,CAAC,aAAa;IAC7B;IAEA,IAAW,YAAY,CAAC,KAAc,EAAA;AAClC,QAAA,IAAI,CAAC,aAAa,GAAG,KAAK;;;;IAI9B;;IAGO,MAAM,GAAA;AACT,QAAA,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE;AACrB,QAAA,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,cAAc,EAAE;YACrC,KAAK,CAAC,YAAY,EAAE;QACxB;IACJ;;AAGO,IAAA,qBAAqB,CAAC,KAAY,EAAA;AACrC,QAAA,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC;IAClC;;AAGO,IAAA,uBAAuB,CAAC,KAAY,EAAA;AACvC,QAAA,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,KAAK,CAAC;IACrC;;AAGO,IAAA,gBAAgB,CAAC,OAAgB,EAAA;AACpC,QAAA,IAAI,IAAI,CAAC,aAAa,EAAE;AACpB,YAAA,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,OAAO;QAChC;IACJ;AAEO,IAAA,WAAW,CAAC,GAAa,EAAA;QAC5B,IAAI,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;YAChC,MAAM,IAAI,KAAK,CAAC,CAAA,WAAA,EAAc,GAAG,CAAC,IAAI,CAAA,wBAAA,CAA0B,CAAC;QACrE;QACA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC;AACnC,QAAA,OAAO,IAAI;IACf;AAEO,IAAA,aAAa,CAAC,GAAa,EAAA;AAC9B,QAAA,IAAI,GAAG,KAAK,IAAI,CAAC,MAAM,IAAI,GAAG,KAAK,IAAI,CAAC,KAAK,IAAI,GAAG,KAAK,IAAI,CAAC,KAAK,EAAE;YACjE,MAAM,IAAI,KAAK,CAAC,CAAA,gCAAA,EAAmC,GAAG,CAAC,IAAI,CAAA,EAAA,CAAI,CAAC;QACpE;AACA,QAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC;AAC/C,QAAA,IAAI,QAAQ,KAAK,GAAG,EAAE;;AAElB,YAAA,OAAO,IAAI;QACf;QACA,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC;QACjC,GAAG,CAAC,OAAO,EAAE;AACb,QAAA,OAAO,IAAI;IACf;AAEO,IAAA,MAAM,CAAC,IAAY,EAAA;QACtB,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC;QACtC,IAAI,CAAC,GAAG,EAAE;AACN,YAAA,MAAM,IAAI,KAAK,CAAC,cAAc,IAAI,CAAA,oBAAA,CAAsB,CAAC;QAC7D;AACA,QAAA,OAAO,GAAG;IACd;AAEO,IAAA,MAAM,CAAC,IAAY,EAAA;QACtB,OAAO,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC;IACrC;IAEO,OAAO,GAAA;AACV,QAAA,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE;AACvB,QAAA,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE;QAC3B,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,EAAE;;YAEzC,GAAG,CAAC,OAAO,EAAE;QACjB;AACA,QAAA,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE;IAC5B;AACH;AAED;AACA,IAAI,QAAQ,GAAwB,IAAI;SAExB,eAAe,GAAA;AAC3B,IAAA,IAAI,QAAQ,KAAK,IAAI,EAAE;AACnB,QAAA,QAAQ,GAAG,IAAI,YAAY,EAAE;IACjC;AACA,IAAA,OAAO,QAAQ;AACnB;;;;"}
@@ -0,0 +1,121 @@
1
+ import { Signal } from '@/core/Signal';
2
+ import type { AudioBus } from '@/audio/AudioBus';
3
+ import type { Sound } from '@/audio/Sound';
4
+ import type { Music } from '@/audio/Music';
5
+ export type BeatDetectorSource = AudioBus | Sound | Music | MediaStream | AudioNode | null;
6
+ export interface BeatDetectorOptions {
7
+ /** Minimum detectable BPM. Default 50. */
8
+ minBpm?: number;
9
+ /** Maximum detectable BPM. Default 250. */
10
+ maxBpm?: number;
11
+ /** FFT size for onset detection. Default 2048. */
12
+ fftSize?: number;
13
+ /** Hop size in samples between successive FFTs. Default 512. */
14
+ hopSize?: number;
15
+ /** Sliding window duration for tempogram (seconds). Default 6. */
16
+ tempoWindowSec?: number;
17
+ /** Initial suppression period before beats are emitted (ms). Default 1500. */
18
+ settlingMs?: number;
19
+ /** Number of mel filterbank bands. Default 24. */
20
+ melBands?: number;
21
+ /**
22
+ * When true (default), the worklet runs parallel 3/4 and 4/4 posteriors and
23
+ * switches active time signature via hysteresis. Set false to lock to 4/4.
24
+ */
25
+ enableTimeSignatureDetection?: boolean;
26
+ }
27
+ export interface BeatInfo {
28
+ /** audioContext.currentTime when the beat occurred. */
29
+ audioTime: number;
30
+ /** BPM at this beat. */
31
+ tempo: number;
32
+ /** Confidence 0..1. */
33
+ confidence: number;
34
+ /** Phase within beat (0 = start). */
35
+ beatPhase: number;
36
+ /** Novelty/onset strength at the beat. */
37
+ energy: number;
38
+ /** Is this beat the first in a bar? */
39
+ isDownbeat: boolean;
40
+ /** Beat position within the bar (1..N). */
41
+ beatInBar: number;
42
+ }
43
+ export interface UpcomingBeat {
44
+ audioTime: number;
45
+ tempo: number;
46
+ isDownbeat: boolean;
47
+ beatInBar: number;
48
+ }
49
+ export interface BarInfo {
50
+ audioTime: number;
51
+ tempo: number;
52
+ confidence: number;
53
+ /** Monotonically increasing bar counter since detector start. */
54
+ barNumber: number;
55
+ }
56
+ export interface TimeSignature {
57
+ numerator: number;
58
+ denominator: number;
59
+ }
60
+ export interface TempoCandidate {
61
+ bpm: number;
62
+ /** Peak strength 0..1. */
63
+ score: number;
64
+ }
65
+ export interface BandEnergy {
66
+ low: number;
67
+ mid: number;
68
+ high: number;
69
+ }
70
+ export declare class BeatDetector {
71
+ readonly onBeat: Signal<[BeatInfo]>;
72
+ readonly onTempoChange: Signal<[number, number]>;
73
+ readonly onDownbeat: Signal<[BeatInfo]>;
74
+ readonly onBarStart: Signal<[BarInfo]>;
75
+ readonly onBeatPredicted: Signal<[UpcomingBeat]>;
76
+ private readonly _options;
77
+ private _workletNode;
78
+ private _source;
79
+ private _tapSource;
80
+ private _streamSource;
81
+ private _ready;
82
+ private _tempo;
83
+ private _beatPhase;
84
+ private _nextBeatTime;
85
+ private _confidence;
86
+ private _gridStability;
87
+ private _tempoCandidates;
88
+ private _rms;
89
+ private _onsetStrength;
90
+ private _bandEnergy;
91
+ private _barPosition;
92
+ private _barLength;
93
+ private _timeSignature;
94
+ private _nextDownbeatTime;
95
+ private _lookahead;
96
+ constructor(options?: BeatDetectorOptions);
97
+ get source(): BeatDetectorSource;
98
+ set source(value: BeatDetectorSource);
99
+ get ready(): Promise<void>;
100
+ get tempo(): number;
101
+ get beatPhase(): number;
102
+ get nextBeatTime(): number;
103
+ get confidence(): number;
104
+ get gridStability(): number;
105
+ get rms(): number;
106
+ get onsetStrength(): number;
107
+ get bandEnergy(): BandEnergy;
108
+ get tempoCandidates(): ReadonlyArray<TempoCandidate>;
109
+ get barPosition(): number;
110
+ get barLength(): number;
111
+ get timeSignature(): TimeSignature;
112
+ get nextDownbeatTime(): number;
113
+ get lookahead(): ReadonlyArray<UpcomingBeat>;
114
+ destroy(): void;
115
+ private _setup;
116
+ private _onWorkletMessage;
117
+ private _connectSource;
118
+ private _resolveToAudioNode;
119
+ private _deferConnectionViaBus;
120
+ private _disconnectTap;
121
+ }