@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 @@
1
+ {"version":3,"file":"BeatDetector.js","sources":["../../../../src/audio/BeatDetector.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ export interface EnvelopeOptions {
2
+ /** Attack time in ms — gain ramps from 0 to peak (1.0). Default 10. */
3
+ attackMs?: number;
4
+ /** Decay time in ms — gain ramps from peak to sustain level. Default 100. */
5
+ decayMs?: number;
6
+ /** Sustain level, 0..1. Default 0.7. */
7
+ sustainLevel?: number;
8
+ /** Release time in ms — gain ramps from current to 0 on release(). Default 200. */
9
+ releaseMs?: number;
10
+ }
11
+ /**
12
+ * ADSR (Attack-Decay-Sustain-Release) envelope generator. Schedules a gain
13
+ * curve on a target `AudioParam`:
14
+ *
15
+ * attack: 0 → 1.0 (peak) over attackMs
16
+ * decay: 1.0 → sustainLevel over decayMs
17
+ * sustain: held at sustainLevel
18
+ * release: current → 0 over releaseMs (triggered by `release()`)
19
+ *
20
+ * Use `trigger()` to start the attack/decay/sustain phase, and `release()`
21
+ * to start the release phase. Multiple envelopes can target the same
22
+ * AudioParam; the latest schedule wins (cancel via
23
+ * `gain.cancelScheduledValues` if needed).
24
+ */
25
+ export declare class Envelope {
26
+ attackMs: number;
27
+ decayMs: number;
28
+ sustainLevel: number;
29
+ releaseMs: number;
30
+ constructor(options?: EnvelopeOptions);
31
+ /**
32
+ * Schedule attack → decay → sustain on the target gain param starting
33
+ * at `atTime` (audioContext.currentTime).
34
+ */
35
+ trigger(gainParam: AudioParam, atTime: number): void;
36
+ /**
37
+ * Schedule release → 0 starting at `atTime`. Call this when the note
38
+ * should stop (e.g., key release, sound dismissed).
39
+ */
40
+ release(gainParam: AudioParam, atTime: number): void;
41
+ /** Total time from trigger to fully-released (attack + decay + release). */
42
+ get totalDurationMs(): number;
43
+ destroy(): void;
44
+ }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * ADSR (Attack-Decay-Sustain-Release) envelope generator. Schedules a gain
3
+ * curve on a target `AudioParam`:
4
+ *
5
+ * attack: 0 → 1.0 (peak) over attackMs
6
+ * decay: 1.0 → sustainLevel over decayMs
7
+ * sustain: held at sustainLevel
8
+ * release: current → 0 over releaseMs (triggered by `release()`)
9
+ *
10
+ * Use `trigger()` to start the attack/decay/sustain phase, and `release()`
11
+ * to start the release phase. Multiple envelopes can target the same
12
+ * AudioParam; the latest schedule wins (cancel via
13
+ * `gain.cancelScheduledValues` if needed).
14
+ */
15
+ class Envelope {
16
+ attackMs;
17
+ decayMs;
18
+ sustainLevel;
19
+ releaseMs;
20
+ constructor(options = {}) {
21
+ this.attackMs = Math.max(0, options.attackMs ?? 10);
22
+ this.decayMs = Math.max(0, options.decayMs ?? 100);
23
+ this.sustainLevel = Math.max(0, Math.min(1, options.sustainLevel ?? 0.7));
24
+ this.releaseMs = Math.max(0, options.releaseMs ?? 200);
25
+ }
26
+ /**
27
+ * Schedule attack → decay → sustain on the target gain param starting
28
+ * at `atTime` (audioContext.currentTime).
29
+ */
30
+ trigger(gainParam, atTime) {
31
+ const attackEnd = atTime + this.attackMs / 1000;
32
+ const decayEnd = attackEnd + this.decayMs / 1000;
33
+ gainParam.cancelScheduledValues(atTime);
34
+ gainParam.setValueAtTime(0, atTime);
35
+ gainParam.linearRampToValueAtTime(1.0, attackEnd);
36
+ gainParam.linearRampToValueAtTime(this.sustainLevel, decayEnd);
37
+ // Sustain held at sustainLevel until release()
38
+ }
39
+ /**
40
+ * Schedule release → 0 starting at `atTime`. Call this when the note
41
+ * should stop (e.g., key release, sound dismissed).
42
+ */
43
+ release(gainParam, atTime) {
44
+ atTime + this.releaseMs / 1000;
45
+ gainParam.cancelScheduledValues(atTime);
46
+ // Don't snap to current value; assume gainParam.value is at sustain.
47
+ gainParam.setTargetAtTime(0, atTime, this.releaseMs / 1000 / 3);
48
+ // setTargetAtTime is exponential; tau = releaseMs/3 reaches ~95% of target in releaseMs.
49
+ }
50
+ /** Total time from trigger to fully-released (attack + decay + release). */
51
+ get totalDurationMs() {
52
+ return this.attackMs + this.decayMs + this.releaseMs;
53
+ }
54
+ destroy() {
55
+ // no-op — Envelope is a configuration value, holds no resources
56
+ }
57
+ }
58
+
59
+ export { Envelope };
60
+ //# sourceMappingURL=Envelope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Envelope.js","sources":["../../../../src/audio/Envelope.ts"],"sourcesContent":[null],"names":[],"mappings":"AAWA;;;;;;;;;;;;;AAaG;MACU,QAAQ,CAAA;AACV,IAAA,QAAQ;AACR,IAAA,OAAO;AACP,IAAA,YAAY;AACZ,IAAA,SAAS;AAEhB,IAAA,WAAA,CAAmB,UAA2B,EAAE,EAAA;AAC5C,QAAA,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC;AACnD,QAAA,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,OAAO,IAAI,GAAG,CAAC;QAClD,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,YAAY,IAAI,GAAG,CAAC,CAAC;AACzE,QAAA,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,SAAS,IAAI,GAAG,CAAC;IAC1D;AAEA;;;AAGG;IACI,OAAO,CAAC,SAAqB,EAAE,MAAc,EAAA;QAChD,MAAM,SAAS,GAAG,MAAM,GAAG,IAAI,CAAC,QAAQ,GAAG,IAAI;QAC/C,MAAM,QAAQ,GAAG,SAAS,GAAG,IAAI,CAAC,OAAO,GAAG,IAAI;AAEhD,QAAA,SAAS,CAAC,qBAAqB,CAAC,MAAM,CAAC;AACvC,QAAA,SAAS,CAAC,cAAc,CAAC,CAAC,EAAE,MAAM,CAAC;AACnC,QAAA,SAAS,CAAC,uBAAuB,CAAC,GAAG,EAAE,SAAS,CAAC;QACjD,SAAS,CAAC,uBAAuB,CAAC,IAAI,CAAC,YAAY,EAAE,QAAQ,CAAC;;IAElE;AAEA;;;AAGG;IACI,OAAO,CAAC,SAAqB,EAAE,MAAc,EAAA;QAC7B,MAAM,GAAG,IAAI,CAAC,SAAS,GAAG;AAE7C,QAAA,SAAS,CAAC,qBAAqB,CAAC,MAAM,CAAC;;AAEvC,QAAA,SAAS,CAAC,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,SAAS,GAAG,IAAI,GAAG,CAAC,CAAC;;IAEnE;;AAGA,IAAA,IAAW,eAAe,GAAA;QACtB,OAAO,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,SAAS;IACxD;IAEO,OAAO,GAAA;;IAEd;AACH;;;;"}
@@ -1,5 +1,6 @@
1
1
  import type { PlaybackOptions } from '@/core/types';
2
2
  import { AbstractMedia } from '@/audio/AbstractMedia';
3
+ import type { AudioBus } from '@/audio/AudioBus';
3
4
  export declare class Music extends AbstractMedia {
4
5
  private readonly _audioElement;
5
6
  private _audioSetup;
@@ -15,6 +16,13 @@ export declare class Music extends AbstractMedia {
15
16
  get analyserTarget(): AudioNode | null;
16
17
  play(options?: Partial<PlaybackOptions>): this;
17
18
  pause(options?: Partial<PlaybackOptions>): this;
19
+ protected _getAudioSetup(): {
20
+ audioContext: AudioContext;
21
+ gainNode: GainNode;
22
+ } | null;
23
+ protected _defaultBus(): AudioBus;
24
+ protected _disconnectFromBus(): void;
25
+ protected _connectToBus(): void;
18
26
  destroy(): void;
19
27
  private setupWithAudioContext;
20
28
  }
@@ -1,6 +1,7 @@
1
1
  import { clamp } from '../math/utils.js';
2
2
  import { AbstractMedia } from './AbstractMedia.js';
3
3
  import { isAudioContextReady, getAudioContext, onAudioContextReady } from './audio-context.js';
4
+ import { getAudioManager } from './AudioManager.js';
4
5
 
5
6
  class Music extends AbstractMedia {
6
7
  _audioElement;
@@ -26,7 +27,7 @@ class Music extends AbstractMedia {
26
27
  this._volume = volume;
27
28
  if (this._audioSetup) {
28
29
  const { gainNode, audioContext } = this._audioSetup;
29
- gainNode.gain.setTargetAtTime(this.muted ? 0 : volume, audioContext.currentTime, 10);
30
+ gainNode.gain.setTargetAtTime(this.muted ? 0 : volume, audioContext.currentTime, 0.01);
30
31
  }
31
32
  return this;
32
33
  }
@@ -57,7 +58,7 @@ class Music extends AbstractMedia {
57
58
  this._muted = muted;
58
59
  if (this._audioSetup) {
59
60
  const { gainNode, audioContext } = this._audioSetup;
60
- gainNode.gain.setTargetAtTime(muted ? 0 : this.volume, audioContext.currentTime, 10);
61
+ gainNode.gain.setTargetAtTime(muted ? 0 : this.volume, audioContext.currentTime, 0.01);
61
62
  }
62
63
  }
63
64
  return this;
@@ -96,6 +97,28 @@ class Music extends AbstractMedia {
96
97
  }
97
98
  return this;
98
99
  }
100
+ _getAudioSetup() {
101
+ return this._audioSetup;
102
+ }
103
+ _defaultBus() {
104
+ return getAudioManager().music;
105
+ }
106
+ _disconnectFromBus() {
107
+ if (this._audioSetup) {
108
+ this._audioSetup.gainNode.disconnect();
109
+ }
110
+ }
111
+ _connectToBus() {
112
+ if (this._audioSetup) {
113
+ const inputNode = this.bus._getInputNode();
114
+ if (inputNode) {
115
+ this._audioSetup.gainNode.connect(inputNode);
116
+ }
117
+ else {
118
+ this._audioSetup.gainNode.connect(this._audioSetup.audioContext.destination);
119
+ }
120
+ }
121
+ }
99
122
  destroy() {
100
123
  super.destroy();
101
124
  onAudioContextReady.clearByContext(this);
@@ -107,8 +130,14 @@ class Music extends AbstractMedia {
107
130
  }
108
131
  setupWithAudioContext(audioContext) {
109
132
  const gainNode = audioContext.createGain();
110
- gainNode.gain.setTargetAtTime(this.muted ? 0 : this.volume, audioContext.currentTime, 10);
111
- gainNode.connect(audioContext.destination);
133
+ gainNode.gain.setTargetAtTime(this.muted ? 0 : this.volume, audioContext.currentTime, 0.01);
134
+ const inputNode = this.bus._getInputNode();
135
+ if (inputNode) {
136
+ gainNode.connect(inputNode);
137
+ }
138
+ else {
139
+ gainNode.connect(audioContext.destination);
140
+ }
112
141
  const sourceNode = audioContext.createMediaElementSource(this._audioElement);
113
142
  sourceNode.connect(gainNode);
114
143
  this._audioSetup = { audioContext, gainNode, sourceNode };
@@ -1 +1 @@
1
- {"version":3,"file":"Music.js","sources":["../../../../src/audio/Music.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Music.js","sources":["../../../../src/audio/Music.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
@@ -0,0 +1,98 @@
1
+ import { AbstractMedia } from './AbstractMedia';
2
+ import type { Envelope } from './Envelope';
3
+ import { SoundPoolStrategy } from './Sound';
4
+ import type { AudioBus } from './AudioBus';
5
+ import type { PlaybackOptions } from '@/core/types';
6
+ export type OscillatorType = 'sine' | 'square' | 'sawtooth' | 'triangle';
7
+ export interface OscillatorSoundOptions extends Partial<PlaybackOptions> {
8
+ frequency?: number;
9
+ type?: OscillatorType;
10
+ detune?: number;
11
+ envelope?: Envelope | null;
12
+ poolSize?: number;
13
+ poolStrategy?: SoundPoolStrategy;
14
+ priority?: number;
15
+ }
16
+ export interface OscillatorPlayOptions extends Partial<PlaybackOptions> {
17
+ bus?: AudioBus;
18
+ replace?: boolean;
19
+ /** Override frequency for this play. Reverts to default for next play. */
20
+ frequency?: number;
21
+ /** Override type for this play. */
22
+ type?: OscillatorType;
23
+ /** Override detune for this play. */
24
+ detune?: number;
25
+ }
26
+ /**
27
+ * Procedural tone generator — generates audio without an AudioBuffer asset.
28
+ * Useful for prototyping, game-jam SFX, retro-style sound effects, music
29
+ * apps that need synthesizer-style tones.
30
+ *
31
+ * Each `play()` creates a new OscillatorNode (oscillators are one-shot in
32
+ * Web Audio). Pool semantics match `Sound`: multiple concurrent voices
33
+ * up to `poolSize`, FIFO eviction by default.
34
+ *
35
+ * const tone = new OscillatorSound({ frequency: 440, type: 'sine' });
36
+ * tone.play(); // plays A4 sine wave
37
+ * tone.frequency = 880;
38
+ * tone.play(); // plays A5 (in addition to A4 if pool > 1)
39
+ *
40
+ * For musical applications, use `setNote(midi)`:
41
+ *
42
+ * tone.setNote(69); // MIDI 69 = A4
43
+ * tone.setNote(60); // C4 (middle C)
44
+ *
45
+ * With an envelope for smooth attack/release:
46
+ *
47
+ * const synth = new OscillatorSound({
48
+ * frequency: 440,
49
+ * envelope: new Envelope({ attackMs: 50, decayMs: 100, sustainLevel: 0.7, releaseMs: 300 }),
50
+ * });
51
+ * synth.play();
52
+ * // ... later
53
+ * synth.pause(); // triggers release phase, stops after releaseMs
54
+ */
55
+ export declare class OscillatorSound extends AbstractMedia {
56
+ frequency: number;
57
+ detune: number;
58
+ type: OscillatorType;
59
+ envelope: Envelope | null;
60
+ poolSize: number;
61
+ poolStrategy: SoundPoolStrategy;
62
+ priority: number;
63
+ private _audioSetup;
64
+ private _paused;
65
+ private readonly _pooledSources;
66
+ get paused(): boolean;
67
+ set paused(paused: boolean);
68
+ get analyserTarget(): GainNode | null;
69
+ constructor(options?: OscillatorSoundOptions);
70
+ play(options?: OscillatorPlayOptions): this;
71
+ pause(): this;
72
+ setVolume(value: number): this;
73
+ setLoop(loop: boolean): this;
74
+ setPlaybackRate(value: number): this;
75
+ getTime(): number;
76
+ setTime(_currentTime: number): this;
77
+ setMuted(muted: boolean): this;
78
+ /** Set frequency from MIDI note number. midi 69 = A4 = 440Hz. */
79
+ setNote(midiNote: number): this;
80
+ /** Returns frequency in Hz from MIDI note (without setting it). */
81
+ static midiToFrequency(midiNote: number): number;
82
+ destroy(): void;
83
+ protected _getAudioSetup(): {
84
+ audioContext: AudioContext;
85
+ gainNode: GainNode;
86
+ } | null;
87
+ protected _defaultBus(): AudioBus;
88
+ protected _disconnectFromBus(): void;
89
+ protected _connectToBus(): void;
90
+ private _setupWithAudioContext;
91
+ private _enqueuePooledPlay;
92
+ private _playPooledNow;
93
+ private _pickEvictionVictim;
94
+ private _pickOldestIndex;
95
+ private _trimPooledSources;
96
+ private _stopAllPooled;
97
+ private _stopSource;
98
+ }
@@ -0,0 +1,342 @@
1
+ import { clamp } from '../math/utils.js';
2
+ import { AbstractMedia } from './AbstractMedia.js';
3
+ import { isAudioContextReady, getAudioContext, onAudioContextReady } from './audio-context.js';
4
+ import { getAudioManager } from './AudioManager.js';
5
+ import { SoundPoolStrategy } from './Sound.js';
6
+
7
+ /**
8
+ * Procedural tone generator — generates audio without an AudioBuffer asset.
9
+ * Useful for prototyping, game-jam SFX, retro-style sound effects, music
10
+ * apps that need synthesizer-style tones.
11
+ *
12
+ * Each `play()` creates a new OscillatorNode (oscillators are one-shot in
13
+ * Web Audio). Pool semantics match `Sound`: multiple concurrent voices
14
+ * up to `poolSize`, FIFO eviction by default.
15
+ *
16
+ * const tone = new OscillatorSound({ frequency: 440, type: 'sine' });
17
+ * tone.play(); // plays A4 sine wave
18
+ * tone.frequency = 880;
19
+ * tone.play(); // plays A5 (in addition to A4 if pool > 1)
20
+ *
21
+ * For musical applications, use `setNote(midi)`:
22
+ *
23
+ * tone.setNote(69); // MIDI 69 = A4
24
+ * tone.setNote(60); // C4 (middle C)
25
+ *
26
+ * With an envelope for smooth attack/release:
27
+ *
28
+ * const synth = new OscillatorSound({
29
+ * frequency: 440,
30
+ * envelope: new Envelope({ attackMs: 50, decayMs: 100, sustainLevel: 0.7, releaseMs: 300 }),
31
+ * });
32
+ * synth.play();
33
+ * // ... later
34
+ * synth.pause(); // triggers release phase, stops after releaseMs
35
+ */
36
+ class OscillatorSound extends AbstractMedia {
37
+ frequency;
38
+ detune;
39
+ type;
40
+ envelope;
41
+ poolSize;
42
+ poolStrategy;
43
+ priority;
44
+ _audioSetup = null;
45
+ _paused = true;
46
+ _pooledSources = [];
47
+ get paused() {
48
+ return this._paused;
49
+ }
50
+ set paused(paused) {
51
+ if (paused) {
52
+ this.pause();
53
+ }
54
+ else {
55
+ this.play();
56
+ }
57
+ }
58
+ get analyserTarget() {
59
+ return this._audioSetup?.gainNode ?? null;
60
+ }
61
+ constructor(options = {}) {
62
+ super({
63
+ duration: Infinity,
64
+ volume: clamp(options.volume ?? 1, 0, 2),
65
+ playbackRate: 1,
66
+ loop: false,
67
+ muted: options.muted ?? false,
68
+ });
69
+ this.frequency = options.frequency ?? 440;
70
+ this.type = options.type ?? 'sine';
71
+ this.detune = options.detune ?? 0;
72
+ this.envelope = options.envelope ?? null;
73
+ this.poolSize = Math.max(1, Math.floor(options.poolSize ?? 8));
74
+ this.poolStrategy = options.poolStrategy ?? SoundPoolStrategy.FirstInFirstOut;
75
+ this.priority = options.priority ?? 0;
76
+ if (options.loop !== undefined) {
77
+ this._loop = options.loop;
78
+ }
79
+ if (isAudioContextReady()) {
80
+ this._setupWithAudioContext(getAudioContext());
81
+ }
82
+ else {
83
+ onAudioContextReady.once(this._setupWithAudioContext, this);
84
+ }
85
+ }
86
+ play(options = {}) {
87
+ if (options.bus !== undefined) {
88
+ this.bus = options.bus;
89
+ }
90
+ if (options.volume !== undefined) {
91
+ this.setVolume(options.volume);
92
+ }
93
+ if (options.muted !== undefined) {
94
+ this.setMuted(options.muted);
95
+ }
96
+ if (options.replace) {
97
+ this._stopAllPooled();
98
+ }
99
+ const frequency = options.frequency ?? this.frequency;
100
+ const type = options.type ?? this.type;
101
+ const detune = options.detune ?? this.detune;
102
+ this._enqueuePooledPlay(frequency, type, detune);
103
+ this._paused = false;
104
+ this.onStart.dispatch();
105
+ return this;
106
+ }
107
+ pause() {
108
+ if (this._paused && this._pooledSources.length === 0) {
109
+ return this;
110
+ }
111
+ const wasPlaying = !this._paused || this._pooledSources.length > 0;
112
+ this._stopAllPooled();
113
+ this._paused = true;
114
+ if (wasPlaying) {
115
+ this.onStop.dispatch();
116
+ }
117
+ return this;
118
+ }
119
+ setVolume(value) {
120
+ const volume = clamp(value, 0, 2);
121
+ if (this._volume === volume) {
122
+ return this;
123
+ }
124
+ this._volume = volume;
125
+ if (this._audioSetup) {
126
+ const { gainNode, audioContext } = this._audioSetup;
127
+ gainNode.gain.setTargetAtTime(this.muted ? 0 : volume, audioContext.currentTime, 0.01);
128
+ }
129
+ return this;
130
+ }
131
+ setLoop(loop) {
132
+ this._loop = loop;
133
+ return this;
134
+ }
135
+ setPlaybackRate(value) {
136
+ this._playbackRate = clamp(value, 0.1, 20);
137
+ return this;
138
+ }
139
+ getTime() {
140
+ return 0;
141
+ }
142
+ setTime(_currentTime) {
143
+ return this;
144
+ }
145
+ setMuted(muted) {
146
+ this._muted = muted;
147
+ if (this._audioSetup) {
148
+ const { gainNode, audioContext } = this._audioSetup;
149
+ gainNode.gain.setTargetAtTime(muted ? 0 : this.volume, audioContext.currentTime, 0.01);
150
+ }
151
+ return this;
152
+ }
153
+ /** Set frequency from MIDI note number. midi 69 = A4 = 440Hz. */
154
+ setNote(midiNote) {
155
+ this.frequency = 440 * Math.pow(2, (midiNote - 69) / 12);
156
+ return this;
157
+ }
158
+ /** Returns frequency in Hz from MIDI note (without setting it). */
159
+ static midiToFrequency(midiNote) {
160
+ return 440 * Math.pow(2, (midiNote - 69) / 12);
161
+ }
162
+ destroy() {
163
+ super.destroy();
164
+ onAudioContextReady.clearByContext(this);
165
+ this._stopAllPooled();
166
+ this._audioSetup?.gainNode.disconnect();
167
+ this._audioSetup = null;
168
+ }
169
+ _getAudioSetup() {
170
+ return this._audioSetup;
171
+ }
172
+ _defaultBus() {
173
+ return getAudioManager().sound;
174
+ }
175
+ _disconnectFromBus() {
176
+ if (this._audioSetup) {
177
+ this._audioSetup.gainNode.disconnect();
178
+ }
179
+ }
180
+ _connectToBus() {
181
+ if (this._audioSetup) {
182
+ const inputNode = this.bus._getInputNode();
183
+ if (inputNode) {
184
+ this._audioSetup.gainNode.connect(inputNode);
185
+ }
186
+ else {
187
+ this._audioSetup.gainNode.connect(this._audioSetup.audioContext.destination);
188
+ }
189
+ }
190
+ }
191
+ _setupWithAudioContext(audioContext) {
192
+ const gainNode = audioContext.createGain();
193
+ gainNode.gain.setTargetAtTime(this.muted ? 0 : this.volume, audioContext.currentTime, 0.01);
194
+ const inputNode = this.bus._getInputNode();
195
+ if (inputNode) {
196
+ gainNode.connect(inputNode);
197
+ }
198
+ else {
199
+ gainNode.connect(audioContext.destination);
200
+ }
201
+ this._audioSetup = { audioContext, gainNode };
202
+ }
203
+ _enqueuePooledPlay(frequency, type, detune) {
204
+ if (!this._audioSetup) {
205
+ // AudioContext not yet ready; defer is not supported for oscillators
206
+ // since each play is ephemeral — silently ignore until context is ready.
207
+ return;
208
+ }
209
+ this._playPooledNow(frequency, type, detune);
210
+ }
211
+ _playPooledNow(frequency, type, detune) {
212
+ if (!this._audioSetup)
213
+ return;
214
+ const { audioContext, gainNode } = this._audioSetup;
215
+ // Create per-voice gain node (envelope target)
216
+ const voiceGain = audioContext.createGain();
217
+ const busInput = this.bus._getInputNode();
218
+ if (busInput) {
219
+ voiceGain.connect(busInput);
220
+ }
221
+ else {
222
+ voiceGain.connect(audioContext.destination);
223
+ }
224
+ // Apply volume/mute through the master gain node connection
225
+ // The voiceGain is the envelope target; the main gainNode handles bus-level volume
226
+ gainNode.connect(voiceGain);
227
+ const oscillator = audioContext.createOscillator();
228
+ oscillator.type = type;
229
+ oscillator.frequency.value = frequency;
230
+ oscillator.detune.value = detune;
231
+ oscillator.connect(voiceGain);
232
+ const now = audioContext.currentTime;
233
+ if (this.envelope) {
234
+ this.envelope.trigger(voiceGain.gain, now);
235
+ }
236
+ else {
237
+ voiceGain.gain.value = this.muted ? 0 : this._volume;
238
+ }
239
+ oscillator.start(now);
240
+ const pooledSource = {
241
+ oscillator,
242
+ gain: voiceGain,
243
+ startedAt: now,
244
+ };
245
+ oscillator.onended = () => {
246
+ const index = this._pooledSources.indexOf(pooledSource);
247
+ if (index !== -1) {
248
+ this._pooledSources.splice(index, 1);
249
+ }
250
+ oscillator.disconnect();
251
+ voiceGain.disconnect();
252
+ if (this._pooledSources.length === 0) {
253
+ this._paused = true;
254
+ }
255
+ };
256
+ this._pooledSources.push(pooledSource);
257
+ this._trimPooledSources();
258
+ }
259
+ _pickEvictionVictim() {
260
+ switch (this.poolStrategy) {
261
+ case SoundPoolStrategy.LeastRecentlyUsed: {
262
+ // Evict source closest to its natural end. Since oscillators
263
+ // are infinite by default, use oldest (smallest startedAt).
264
+ return this._pickOldestIndex();
265
+ }
266
+ case SoundPoolStrategy.LowestPriority:
267
+ // All pooled instances share the same priority, degenerates to FIFO.
268
+ // falls through
269
+ case SoundPoolStrategy.FirstInFirstOut:
270
+ default:
271
+ return 0; // oldest
272
+ }
273
+ }
274
+ _pickOldestIndex() {
275
+ let minTime = Infinity;
276
+ let minIndex = 0;
277
+ for (let i = 0; i < this._pooledSources.length; i++) {
278
+ const src = this._pooledSources[i];
279
+ if (src.startedAt < minTime) {
280
+ minTime = src.startedAt;
281
+ minIndex = i;
282
+ }
283
+ }
284
+ return minIndex;
285
+ }
286
+ _trimPooledSources() {
287
+ while (this._pooledSources.length > this.poolSize) {
288
+ const victimIndex = this._pickEvictionVictim();
289
+ const victim = this._pooledSources[victimIndex];
290
+ if (!victim)
291
+ break;
292
+ this._pooledSources.splice(victimIndex, 1);
293
+ victim.oscillator.onended = null;
294
+ this._stopSource(victim);
295
+ }
296
+ }
297
+ _stopAllPooled() {
298
+ for (const source of this._pooledSources) {
299
+ source.oscillator.onended = null;
300
+ this._stopSource(source);
301
+ }
302
+ this._pooledSources.length = 0;
303
+ }
304
+ _stopSource(source) {
305
+ if (!this._audioSetup) {
306
+ try {
307
+ source.oscillator.stop(0);
308
+ }
309
+ catch {
310
+ // already stopped
311
+ }
312
+ source.oscillator.disconnect();
313
+ source.gain.disconnect();
314
+ return;
315
+ }
316
+ const { audioContext } = this._audioSetup;
317
+ const now = audioContext.currentTime;
318
+ if (this.envelope) {
319
+ this.envelope.release(source.gain.gain, now);
320
+ const stopAt = now + this.envelope.releaseMs / 1000;
321
+ try {
322
+ source.oscillator.stop(stopAt);
323
+ }
324
+ catch {
325
+ // already stopped
326
+ }
327
+ }
328
+ else {
329
+ try {
330
+ source.oscillator.stop(now);
331
+ }
332
+ catch {
333
+ // already stopped
334
+ }
335
+ source.oscillator.disconnect();
336
+ source.gain.disconnect();
337
+ }
338
+ }
339
+ }
340
+
341
+ export { OscillatorSound };
342
+ //# sourceMappingURL=OscillatorSound.js.map