@codexo/exojs 0.6.11 → 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 (189) hide show
  1. package/CHANGELOG.md +1356 -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 +29 -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 +2 -0
  145. package/dist/esm/math/swept-collision.d.ts +90 -0
  146. package/dist/esm/math/swept-collision.js +255 -0
  147. package/dist/esm/math/swept-collision.js.map +1 -0
  148. package/dist/esm/particles/ParticleSystem.js +1 -0
  149. package/dist/esm/particles/ParticleSystem.js.map +1 -1
  150. package/dist/esm/particles/affectors/TorqueAffector.js +1 -1
  151. package/dist/esm/rendering/Container.d.ts +1 -0
  152. package/dist/esm/rendering/Container.js +19 -0
  153. package/dist/esm/rendering/Container.js.map +1 -1
  154. package/dist/esm/rendering/RenderNode.d.ts +27 -0
  155. package/dist/esm/rendering/RenderNode.js +44 -0
  156. package/dist/esm/rendering/RenderNode.js.map +1 -1
  157. package/dist/esm/rendering/View.d.ts +6 -4
  158. package/dist/esm/rendering/View.js +12 -2
  159. package/dist/esm/rendering/View.js.map +1 -1
  160. package/dist/esm/rendering/filters/WebGl2ShaderFilter.d.ts +109 -0
  161. package/dist/esm/rendering/filters/WebGl2ShaderFilter.js +268 -0
  162. package/dist/esm/rendering/filters/WebGl2ShaderFilter.js.map +1 -0
  163. package/dist/esm/rendering/filters/WebGpuShaderFilter.d.ts +111 -0
  164. package/dist/esm/rendering/filters/WebGpuShaderFilter.js +397 -0
  165. package/dist/esm/rendering/filters/WebGpuShaderFilter.js.map +1 -0
  166. package/dist/esm/rendering/index.d.ts +3 -0
  167. package/dist/esm/rendering/mesh/Mesh.js +1 -0
  168. package/dist/esm/rendering/mesh/Mesh.js.map +1 -1
  169. package/dist/esm/rendering/shader/upgradeFragmentShaderToGl300.d.ts +34 -0
  170. package/dist/esm/rendering/shader/upgradeFragmentShaderToGl300.js +60 -0
  171. package/dist/esm/rendering/shader/upgradeFragmentShaderToGl300.js.map +1 -0
  172. package/dist/esm/rendering/sprite/Sprite.d.ts +6 -1
  173. package/dist/esm/rendering/sprite/Sprite.js +41 -19
  174. package/dist/esm/rendering/sprite/Sprite.js.map +1 -1
  175. package/dist/esm/rendering/video/Video.d.ts +4 -0
  176. package/dist/esm/rendering/video/Video.js +32 -4
  177. package/dist/esm/rendering/video/Video.js.map +1 -1
  178. package/dist/esm/rendering/webgl2/WebGl2Backend.d.ts +4 -4
  179. package/dist/esm/rendering/webgl2/WebGl2Backend.js +7 -16
  180. package/dist/esm/rendering/webgl2/WebGl2Backend.js.map +1 -1
  181. package/dist/esm/rendering/webgpu/WebGpuBackend.d.ts +10 -8
  182. package/dist/esm/rendering/webgpu/WebGpuBackend.js +30 -40
  183. package/dist/esm/rendering/webgpu/WebGpuBackend.js.map +1 -1
  184. package/dist/exo.esm.js +8021 -2459
  185. package/dist/exo.esm.js.map +1 -1
  186. package/package.json +14 -2
  187. package/dist/esm/core/Quadtree.d.ts +0 -20
  188. package/dist/esm/core/Quadtree.js +0 -86
  189. package/dist/esm/core/Quadtree.js.map +0 -1
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Mel-scale filterbank generator.
3
+ *
4
+ * Generates `numBands` triangular filters log-spaced from `fMin` to `fMax` Hz
5
+ * on the mel scale. Each filter is a typed array of weights for the FFT
6
+ * magnitude bins.
7
+ *
8
+ * These helpers are also inlined inside the beat-detector worklet source
9
+ * string (worklets cannot import modules).
10
+ */
11
+ /** Convert Hz to mel. */
12
+ export declare function hzToMel(hz: number): number;
13
+ /** Convert mel to Hz. */
14
+ export declare function melToHz(mel: number): number;
15
+ export interface MelBand {
16
+ /** Index of the FFT bin where this filter starts (weight 0). */
17
+ readonly startBin: number;
18
+ /** Index of the peak FFT bin (weight 1). */
19
+ readonly peakBin: number;
20
+ /** Index of the FFT bin where this filter ends (weight 0). */
21
+ readonly endBin: number;
22
+ /** Pre-computed triangular weights, indexed from startBin..endBin (inclusive). */
23
+ readonly weights: Float32Array;
24
+ }
25
+ /**
26
+ * Build a mel filterbank.
27
+ *
28
+ * @param numBands Number of mel bands (default 24).
29
+ * @param fMin Lowest frequency in Hz (default 80).
30
+ * @param fMax Highest frequency in Hz (default 8000).
31
+ * @param fftSize Number of FFT points (e.g., 2048).
32
+ * @param sampleRate Audio sample rate in Hz (e.g., 48000).
33
+ */
34
+ export declare function buildMelFilterbank(numBands: number, fMin: number, fMax: number, fftSize: number, sampleRate: number): Array<MelBand>;
35
+ /**
36
+ * Compute mel band energies from a magnitude spectrum.
37
+ *
38
+ * @param mag FFT magnitude spectrum (length = fftSize/2).
39
+ * @param bands Filterbank from `buildMelFilterbank`.
40
+ * @param out Optional pre-allocated output array of length `bands.length`.
41
+ * @returns Log-compressed mel band energies.
42
+ */
43
+ export declare function computeMelBands(mag: Float32Array, bands: Array<MelBand>, out?: Float32Array): Float32Array;
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Autocorrelation-based tempogram.
3
+ *
4
+ * Given a novelty (onset-strength) curve sampled at rate `hopRate = sampleRate / hopSize`,
5
+ * this module computes the autocorrelation function (ACF) over a sliding window
6
+ * and returns the top tempo candidates.
7
+ *
8
+ * These helpers are also inlined inside the beat-detector worklet source string
9
+ * (worklets cannot import modules).
10
+ */
11
+ export interface TempoCandidateResult {
12
+ /** BPM value. */
13
+ bpm: number;
14
+ /** Normalised peak score (0..1). */
15
+ score: number;
16
+ /** ACF lag in hops that produced this peak. */
17
+ lag: number;
18
+ }
19
+ /**
20
+ * Compute the normalised autocorrelation function over a novelty curve.
21
+ *
22
+ * @param flux Recent novelty values (ring-buffer contents, oldest first).
23
+ * @param minLag Minimum lag in samples (inclusive).
24
+ * @param maxLag Maximum lag in samples (inclusive).
25
+ * @returns ACF array indexed by lag (index 0 = lag minLag).
26
+ */
27
+ export declare function computeAcf(flux: Float32Array, minLag: number, maxLag: number): Float32Array;
28
+ /**
29
+ * Find the top-K peaks in the ACF and convert lags to BPM candidates.
30
+ *
31
+ * @param acf Normalised ACF from `computeACF`.
32
+ * @param minLag The lag (in hops) corresponding to acf[0].
33
+ * @param hopSize Number of audio samples per hop.
34
+ * @param sampleRate Audio sample rate in Hz.
35
+ * @param topK Number of peaks to return (default 3).
36
+ * @returns Up to `topK` tempo candidates sorted by score descending.
37
+ */
38
+ export declare function findTempoPeaks(acf: Float32Array, minLag: number, hopSize: number, sampleRate: number, topK?: number): Array<TempoCandidateResult>;
39
+ /**
40
+ * Apply hysteresis to tempo candidate selection.
41
+ *
42
+ * Prevents rapid switching between tempo estimates:
43
+ * - Only switches to a new best if its score is > currentBestScore * 1.15.
44
+ * - Octave-related candidates (2x or 0.5x) require a score > 1.5x to switch.
45
+ *
46
+ * @param candidates Sorted candidates from `findTempoPeaks`.
47
+ * @param currentBpm Currently tracked BPM.
48
+ * @param currentScore Currently tracked best score.
49
+ * @returns The selected best BPM.
50
+ */
51
+ export declare function applyTempoHysteresis(candidates: Array<TempoCandidateResult>, currentBpm: number, currentScore: number): number;
@@ -0,0 +1,47 @@
1
+ import { AudioFilter } from '../AudioFilter';
2
+ export interface ChorusFilterOptions {
3
+ /** Base delay in ms. Typical 15-30ms. Default 25. */
4
+ delayMs?: number;
5
+ /** Modulation depth in ms (peak deviation from base). Default 5. */
6
+ depthMs?: number;
7
+ /** LFO rate in Hz. Typical 0.1-5Hz for chorus, 5-15Hz for vibrato. Default 1.5. */
8
+ rateHz?: number;
9
+ /** Dry/wet mix, 0..1. Default 0.5 (equal mix). */
10
+ wet?: number;
11
+ }
12
+ /**
13
+ * Chorus effect using native WebAudio nodes (no worklet required).
14
+ *
15
+ * The signal splits into a dry path and a wet path. The wet path passes
16
+ * through a DelayNode whose delay time is modulated by a sine-wave LFO,
17
+ * producing the characteristic pitch-wobble / thickening of chorus.
18
+ *
19
+ * Node graph:
20
+ * ```
21
+ * inputGain ┬── dryGain ────────────────┐
22
+ * │ ├── outputGain
23
+ * └── delayNode ── wetGain ────┘
24
+ *
25
+ * lfoOscillator ── lfoGain (depth) ── delayNode.delayTime
26
+ * ```
27
+ */
28
+ export declare class ChorusFilter extends AudioFilter {
29
+ private _nodes;
30
+ private _delayMs;
31
+ private _depthMs;
32
+ private _rateHz;
33
+ private _wet;
34
+ constructor(options?: ChorusFilterOptions);
35
+ get inputNode(): AudioNode;
36
+ get outputNode(): AudioNode;
37
+ get delayMs(): number;
38
+ set delayMs(value: number);
39
+ get depthMs(): number;
40
+ set depthMs(value: number);
41
+ get rateHz(): number;
42
+ set rateHz(value: number);
43
+ get wet(): number;
44
+ set wet(value: number);
45
+ destroy(): void;
46
+ private _setupNodes;
47
+ }
@@ -0,0 +1,139 @@
1
+ import { isAudioContextReady, getAudioContext, onAudioContextReady } from '../audio-context.js';
2
+ import { AudioFilter } from '../AudioFilter.js';
3
+
4
+ /**
5
+ * Chorus effect using native WebAudio nodes (no worklet required).
6
+ *
7
+ * The signal splits into a dry path and a wet path. The wet path passes
8
+ * through a DelayNode whose delay time is modulated by a sine-wave LFO,
9
+ * producing the characteristic pitch-wobble / thickening of chorus.
10
+ *
11
+ * Node graph:
12
+ * ```
13
+ * inputGain ┬── dryGain ────────────────┐
14
+ * │ ├── outputGain
15
+ * └── delayNode ── wetGain ────┘
16
+ *
17
+ * lfoOscillator ── lfoGain (depth) ── delayNode.delayTime
18
+ * ```
19
+ */
20
+ class ChorusFilter extends AudioFilter {
21
+ _nodes = null;
22
+ _delayMs;
23
+ _depthMs;
24
+ _rateHz;
25
+ _wet;
26
+ constructor(options = {}) {
27
+ super();
28
+ this._delayMs = Math.max(0, options.delayMs ?? 25);
29
+ this._depthMs = Math.max(0, options.depthMs ?? 5);
30
+ this._rateHz = Math.max(0, options.rateHz ?? 1.5);
31
+ this._wet = Math.max(0, Math.min(1, options.wet ?? 0.5));
32
+ if (isAudioContextReady()) {
33
+ this._setupNodes(getAudioContext());
34
+ }
35
+ else {
36
+ onAudioContextReady.once(this._setupNodes, this);
37
+ }
38
+ }
39
+ get inputNode() {
40
+ if (!this._nodes)
41
+ throw new Error('ChorusFilter not yet initialized.');
42
+ return this._nodes.inputGain;
43
+ }
44
+ get outputNode() {
45
+ if (!this._nodes)
46
+ throw new Error('ChorusFilter not yet initialized.');
47
+ return this._nodes.outputGain;
48
+ }
49
+ // -------------------------------------------------------------------------
50
+ // Getters / setters
51
+ // -------------------------------------------------------------------------
52
+ get delayMs() { return this._delayMs; }
53
+ set delayMs(value) {
54
+ this._delayMs = Math.max(0, value);
55
+ if (this._nodes) {
56
+ this._nodes.delayNode.delayTime.setTargetAtTime(this._delayMs / 1000, this._nodes.delayNode.context.currentTime, 0.01);
57
+ }
58
+ }
59
+ get depthMs() { return this._depthMs; }
60
+ set depthMs(value) {
61
+ this._depthMs = Math.max(0, value);
62
+ if (this._nodes) {
63
+ this._nodes.lfoGain.gain.setTargetAtTime(this._depthMs / 1000, this._nodes.lfoGain.context.currentTime, 0.01);
64
+ }
65
+ }
66
+ get rateHz() { return this._rateHz; }
67
+ set rateHz(value) {
68
+ this._rateHz = Math.max(0, value);
69
+ if (this._nodes) {
70
+ this._nodes.lfoOscillator.frequency.setTargetAtTime(this._rateHz, this._nodes.inputGain.context.currentTime, 0.01);
71
+ }
72
+ }
73
+ get wet() { return this._wet; }
74
+ set wet(value) {
75
+ this._wet = Math.max(0, Math.min(1, value));
76
+ if (this._nodes) {
77
+ const ctx = this._nodes.wetGain.context;
78
+ this._nodes.wetGain.gain.setTargetAtTime(this._wet, ctx.currentTime, 0.01);
79
+ this._nodes.dryGain.gain.setTargetAtTime(1 - this._wet, ctx.currentTime, 0.01);
80
+ }
81
+ }
82
+ // -------------------------------------------------------------------------
83
+ // Lifecycle
84
+ // -------------------------------------------------------------------------
85
+ destroy() {
86
+ onAudioContextReady.clearByContext(this);
87
+ if (this._nodes) {
88
+ this._nodes.lfoOscillator.stop();
89
+ this._nodes.lfoOscillator.disconnect();
90
+ this._nodes.lfoGain.disconnect();
91
+ this._nodes.delayNode.disconnect();
92
+ this._nodes.dryGain.disconnect();
93
+ this._nodes.wetGain.disconnect();
94
+ this._nodes.inputGain.disconnect();
95
+ this._nodes.outputGain.disconnect();
96
+ this._nodes = null;
97
+ }
98
+ }
99
+ // -------------------------------------------------------------------------
100
+ // Private
101
+ // -------------------------------------------------------------------------
102
+ _setupNodes(ctx) {
103
+ const inputGain = ctx.createGain();
104
+ const outputGain = ctx.createGain();
105
+ const dryGain = ctx.createGain();
106
+ const wetGain = ctx.createGain();
107
+ // maxDelayTime must be larger than base + peak depth, with a small buffer.
108
+ const maxDelay = (this._delayMs + this._depthMs) / 1000 + 0.05;
109
+ const delayNode = ctx.createDelay(maxDelay);
110
+ const lfoGain = ctx.createGain();
111
+ // Initial values
112
+ inputGain.gain.setValueAtTime(1, ctx.currentTime);
113
+ outputGain.gain.setValueAtTime(1, ctx.currentTime);
114
+ dryGain.gain.setValueAtTime(1 - this._wet, ctx.currentTime);
115
+ wetGain.gain.setValueAtTime(this._wet, ctx.currentTime);
116
+ delayNode.delayTime.setValueAtTime(this._delayMs / 1000, ctx.currentTime);
117
+ lfoGain.gain.setValueAtTime(this._depthMs / 1000, ctx.currentTime);
118
+ // LFO
119
+ const lfoOscillator = ctx.createOscillator();
120
+ lfoOscillator.type = 'sine';
121
+ lfoOscillator.frequency.value = this._rateHz;
122
+ // Wiring
123
+ // LFO → lfoGain → delayNode.delayTime (AudioParam)
124
+ lfoOscillator.connect(lfoGain);
125
+ lfoGain.connect(delayNode.delayTime);
126
+ // Dry path: inputGain → dryGain → outputGain
127
+ inputGain.connect(dryGain);
128
+ dryGain.connect(outputGain);
129
+ // Wet path: inputGain → delayNode → wetGain → outputGain
130
+ inputGain.connect(delayNode);
131
+ delayNode.connect(wetGain);
132
+ wetGain.connect(outputGain);
133
+ lfoOscillator.start();
134
+ this._nodes = { inputGain, outputGain, dryGain, wetGain, delayNode, lfoOscillator, lfoGain };
135
+ }
136
+ }
137
+
138
+ export { ChorusFilter };
139
+ //# sourceMappingURL=ChorusFilter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChorusFilter.js","sources":["../../../../../src/audio/filters/ChorusFilter.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ import { AudioFilter } from '../AudioFilter';
2
+ export interface CompressorFilterOptions {
3
+ threshold?: number;
4
+ knee?: number;
5
+ ratio?: number;
6
+ attack?: number;
7
+ release?: number;
8
+ }
9
+ export declare class CompressorFilter extends AudioFilter {
10
+ private _node;
11
+ private _threshold;
12
+ private _knee;
13
+ private _ratio;
14
+ private _attack;
15
+ private _release;
16
+ constructor(options?: CompressorFilterOptions);
17
+ get inputNode(): AudioNode;
18
+ get outputNode(): AudioNode;
19
+ get threshold(): number;
20
+ set threshold(value: number);
21
+ get knee(): number;
22
+ set knee(value: number);
23
+ get ratio(): number;
24
+ set ratio(value: number);
25
+ get attack(): number;
26
+ set attack(value: number);
27
+ get release(): number;
28
+ set release(value: number);
29
+ destroy(): void;
30
+ private _setup;
31
+ }
@@ -0,0 +1,97 @@
1
+ import { isAudioContextReady, getAudioContext, onAudioContextReady } from '../audio-context.js';
2
+ import { AudioFilter } from '../AudioFilter.js';
3
+
4
+ class CompressorFilter extends AudioFilter {
5
+ _node = null;
6
+ _threshold;
7
+ _knee;
8
+ _ratio;
9
+ _attack;
10
+ _release;
11
+ constructor(options = {}) {
12
+ super();
13
+ this._threshold = Math.max(-100, Math.min(0, options.threshold ?? -24));
14
+ this._knee = Math.max(0, Math.min(40, options.knee ?? 30));
15
+ this._ratio = Math.max(1, Math.min(20, options.ratio ?? 12));
16
+ this._attack = Math.max(0, Math.min(1, options.attack ?? 0.003));
17
+ this._release = Math.max(0, Math.min(1, options.release ?? 0.25));
18
+ if (isAudioContextReady()) {
19
+ this._setup(getAudioContext());
20
+ }
21
+ else {
22
+ onAudioContextReady.once(this._setup, this);
23
+ }
24
+ }
25
+ get inputNode() {
26
+ if (!this._node)
27
+ throw new Error('CompressorFilter not yet initialized.');
28
+ return this._node;
29
+ }
30
+ get outputNode() {
31
+ if (!this._node)
32
+ throw new Error('CompressorFilter not yet initialized.');
33
+ return this._node;
34
+ }
35
+ get threshold() {
36
+ return this._threshold;
37
+ }
38
+ set threshold(value) {
39
+ this._threshold = Math.max(-100, Math.min(0, value));
40
+ if (this._node) {
41
+ this._node.threshold.setTargetAtTime(this._threshold, this._node.context.currentTime, 0.01);
42
+ }
43
+ }
44
+ get knee() {
45
+ return this._knee;
46
+ }
47
+ set knee(value) {
48
+ this._knee = Math.max(0, Math.min(40, value));
49
+ if (this._node) {
50
+ this._node.knee.setTargetAtTime(this._knee, this._node.context.currentTime, 0.01);
51
+ }
52
+ }
53
+ get ratio() {
54
+ return this._ratio;
55
+ }
56
+ set ratio(value) {
57
+ this._ratio = Math.max(1, Math.min(20, value));
58
+ if (this._node) {
59
+ this._node.ratio.setTargetAtTime(this._ratio, this._node.context.currentTime, 0.01);
60
+ }
61
+ }
62
+ get attack() {
63
+ return this._attack;
64
+ }
65
+ set attack(value) {
66
+ this._attack = Math.max(0, Math.min(1, value));
67
+ if (this._node) {
68
+ this._node.attack.setTargetAtTime(this._attack, this._node.context.currentTime, 0.01);
69
+ }
70
+ }
71
+ get release() {
72
+ return this._release;
73
+ }
74
+ set release(value) {
75
+ this._release = Math.max(0, Math.min(1, value));
76
+ if (this._node) {
77
+ this._node.release.setTargetAtTime(this._release, this._node.context.currentTime, 0.01);
78
+ }
79
+ }
80
+ destroy() {
81
+ onAudioContextReady.clearByContext(this);
82
+ this._node?.disconnect();
83
+ this._node = null;
84
+ }
85
+ _setup(ctx) {
86
+ const node = ctx.createDynamicsCompressor();
87
+ node.threshold.setValueAtTime(this._threshold, ctx.currentTime);
88
+ node.knee.setValueAtTime(this._knee, ctx.currentTime);
89
+ node.ratio.setValueAtTime(this._ratio, ctx.currentTime);
90
+ node.attack.setValueAtTime(this._attack, ctx.currentTime);
91
+ node.release.setValueAtTime(this._release, ctx.currentTime);
92
+ this._node = node;
93
+ }
94
+ }
95
+
96
+ export { CompressorFilter };
97
+ //# sourceMappingURL=CompressorFilter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CompressorFilter.js","sources":["../../../../../src/audio/filters/CompressorFilter.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import { AudioFilter } from '../AudioFilter';
2
+ export interface DelayFilterOptions {
3
+ delaySeconds?: number;
4
+ feedback?: number;
5
+ wet?: number;
6
+ }
7
+ export declare class DelayFilter extends AudioFilter {
8
+ private _setup;
9
+ private _delaySeconds;
10
+ private _feedback;
11
+ private _wet;
12
+ constructor(options?: DelayFilterOptions);
13
+ get inputNode(): AudioNode;
14
+ get outputNode(): AudioNode;
15
+ get delaySeconds(): number;
16
+ set delaySeconds(value: number);
17
+ get feedback(): number;
18
+ set feedback(value: number);
19
+ get wet(): number;
20
+ set wet(value: number);
21
+ destroy(): void;
22
+ private _setupNodes;
23
+ }
@@ -0,0 +1,100 @@
1
+ import { isAudioContextReady, getAudioContext, onAudioContextReady } from '../audio-context.js';
2
+ import { AudioFilter } from '../AudioFilter.js';
3
+
4
+ class DelayFilter extends AudioFilter {
5
+ _setup = null;
6
+ _delaySeconds;
7
+ _feedback;
8
+ _wet;
9
+ constructor(options = {}) {
10
+ super();
11
+ this._delaySeconds = Math.max(0, Math.min(5, options.delaySeconds ?? 0.3));
12
+ this._feedback = Math.max(0, Math.min(0.95, options.feedback ?? 0.4));
13
+ this._wet = Math.max(0, Math.min(1, options.wet ?? 0.5));
14
+ if (isAudioContextReady()) {
15
+ this._setupNodes(getAudioContext());
16
+ }
17
+ else {
18
+ onAudioContextReady.once(this._setupNodes, this);
19
+ }
20
+ }
21
+ get inputNode() {
22
+ if (!this._setup)
23
+ throw new Error('DelayFilter not yet initialized.');
24
+ return this._setup.inputGain;
25
+ }
26
+ get outputNode() {
27
+ if (!this._setup)
28
+ throw new Error('DelayFilter not yet initialized.');
29
+ return this._setup.outputGain;
30
+ }
31
+ get delaySeconds() {
32
+ return this._delaySeconds;
33
+ }
34
+ set delaySeconds(value) {
35
+ this._delaySeconds = Math.max(0, Math.min(5, value));
36
+ if (this._setup) {
37
+ this._setup.delayNode.delayTime.setTargetAtTime(this._delaySeconds, this._setup.delayNode.context.currentTime, 0.01);
38
+ }
39
+ }
40
+ get feedback() {
41
+ return this._feedback;
42
+ }
43
+ set feedback(value) {
44
+ this._feedback = Math.max(0, Math.min(0.95, value));
45
+ if (this._setup) {
46
+ this._setup.feedbackGain.gain.setTargetAtTime(this._feedback, this._setup.feedbackGain.context.currentTime, 0.01);
47
+ }
48
+ }
49
+ get wet() {
50
+ return this._wet;
51
+ }
52
+ set wet(value) {
53
+ this._wet = Math.max(0, Math.min(1, value));
54
+ if (this._setup) {
55
+ const ctx = this._setup.wetGain.context;
56
+ this._setup.wetGain.gain.setTargetAtTime(this._wet, ctx.currentTime, 0.01);
57
+ this._setup.dryGain.gain.setTargetAtTime(1 - this._wet, ctx.currentTime, 0.01);
58
+ }
59
+ }
60
+ destroy() {
61
+ onAudioContextReady.clearByContext(this);
62
+ if (this._setup) {
63
+ this._setup.inputGain.disconnect();
64
+ this._setup.delayNode.disconnect();
65
+ this._setup.feedbackGain.disconnect();
66
+ this._setup.dryGain.disconnect();
67
+ this._setup.wetGain.disconnect();
68
+ this._setup.outputGain.disconnect();
69
+ this._setup = null;
70
+ }
71
+ }
72
+ _setupNodes(ctx) {
73
+ const inputGain = ctx.createGain();
74
+ const outputGain = ctx.createGain();
75
+ const delayNode = ctx.createDelay(5);
76
+ const feedbackGain = ctx.createGain();
77
+ const dryGain = ctx.createGain();
78
+ const wetGain = ctx.createGain();
79
+ inputGain.gain.setValueAtTime(1, ctx.currentTime);
80
+ outputGain.gain.setValueAtTime(1, ctx.currentTime);
81
+ delayNode.delayTime.setValueAtTime(this._delaySeconds, ctx.currentTime);
82
+ feedbackGain.gain.setValueAtTime(this._feedback, ctx.currentTime);
83
+ dryGain.gain.setValueAtTime(1 - this._wet, ctx.currentTime);
84
+ wetGain.gain.setValueAtTime(this._wet, ctx.currentTime);
85
+ // Dry path: input → dryGain → output
86
+ inputGain.connect(dryGain);
87
+ dryGain.connect(outputGain);
88
+ // Wet path: input → delay → wetGain → output
89
+ inputGain.connect(delayNode);
90
+ delayNode.connect(wetGain);
91
+ wetGain.connect(outputGain);
92
+ // Feedback loop: delay → feedbackGain → delay
93
+ delayNode.connect(feedbackGain);
94
+ feedbackGain.connect(delayNode);
95
+ this._setup = { inputGain, outputGain, delayNode, feedbackGain, dryGain, wetGain };
96
+ }
97
+ }
98
+
99
+ export { DelayFilter };
100
+ //# sourceMappingURL=DelayFilter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DelayFilter.js","sources":["../../../../../src/audio/filters/DelayFilter.ts"],"sourcesContent":[null],"names":[],"mappings":";;;AAkBM,MAAO,WAAY,SAAQ,WAAW,CAAA;IAChC,MAAM,GAA4B,IAAI;AACtC,IAAA,aAAa;AACb,IAAA,SAAS;AACT,IAAA,IAAI;AAEZ,IAAA,WAAA,CAAmB,UAA8B,EAAE,EAAA;AAC/C,QAAA,KAAK,EAAE;QACP,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,YAAY,IAAI,GAAG,CAAC,CAAC;QAC1E,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,QAAQ,IAAI,GAAG,CAAC,CAAC;QACrE,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC;QACxD,IAAI,mBAAmB,EAAE,EAAE;AACvB,YAAA,IAAI,CAAC,WAAW,CAAC,eAAe,EAAE,CAAC;QACvC;aAAO;YACH,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC;QACpD;IACJ;AAEA,IAAA,IAAW,SAAS,GAAA;QAChB,IAAI,CAAC,IAAI,CAAC,MAAM;AAAE,YAAA,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC;AACrE,QAAA,OAAO,IAAI,CAAC,MAAM,CAAC,SAAS;IAChC;AAEA,IAAA,IAAW,UAAU,GAAA;QACjB,IAAI,CAAC,IAAI,CAAC,MAAM;AAAE,YAAA,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC;AACrE,QAAA,OAAO,IAAI,CAAC,MAAM,CAAC,UAAU;IACjC;AAEA,IAAA,IAAW,YAAY,GAAA;QACnB,OAAO,IAAI,CAAC,aAAa;IAC7B;IAEA,IAAW,YAAY,CAAC,KAAa,EAAA;AACjC,QAAA,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;AACpD,QAAA,IAAI,IAAI,CAAC,MAAM,EAAE;YACb,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,SAAS,CAAC,eAAe,CAC3C,IAAI,CAAC,aAAa,EAClB,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,WAAW,EACzC,IAAI,CACP;QACL;IACJ;AAEA,IAAA,IAAW,QAAQ,GAAA;QACf,OAAO,IAAI,CAAC,SAAS;IACzB;IAEA,IAAW,QAAQ,CAAC,KAAa,EAAA;AAC7B,QAAA,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;AACnD,QAAA,IAAI,IAAI,CAAC,MAAM,EAAE;YACb,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,eAAe,CACzC,IAAI,CAAC,SAAS,EACd,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,WAAW,EAC5C,IAAI,CACP;QACL;IACJ;AAEA,IAAA,IAAW,GAAG,GAAA;QACV,OAAO,IAAI,CAAC,IAAI;IACpB;IAEA,IAAW,GAAG,CAAC,KAAa,EAAA;AACxB,QAAA,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;AAC3C,QAAA,IAAI,IAAI,CAAC,MAAM,EAAE;YACb,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO;AACvC,YAAA,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,WAAW,EAAE,IAAI,CAAC;YAC1E,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,WAAW,EAAE,IAAI,CAAC;QAClF;IACJ;IAEgB,OAAO,GAAA;AACnB,QAAA,mBAAmB,CAAC,cAAc,CAAC,IAAI,CAAC;AACxC,QAAA,IAAI,IAAI,CAAC,MAAM,EAAE;AACb,YAAA,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,UAAU,EAAE;AAClC,YAAA,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,UAAU,EAAE;AAClC,YAAA,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,UAAU,EAAE;AACrC,YAAA,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,EAAE;AAChC,YAAA,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,EAAE;AAChC,YAAA,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,UAAU,EAAE;AACnC,YAAA,IAAI,CAAC,MAAM,GAAG,IAAI;QACtB;IACJ;AAEQ,IAAA,WAAW,CAAC,GAAiB,EAAA;AACjC,QAAA,MAAM,SAAS,GAAG,GAAG,CAAC,UAAU,EAAE;AAClC,QAAA,MAAM,UAAU,GAAG,GAAG,CAAC,UAAU,EAAE;QACnC,MAAM,SAAS,GAAG,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC;AACpC,QAAA,MAAM,YAAY,GAAG,GAAG,CAAC,UAAU,EAAE;AACrC,QAAA,MAAM,OAAO,GAAG,GAAG,CAAC,UAAU,EAAE;AAChC,QAAA,MAAM,OAAO,GAAG,GAAG,CAAC,UAAU,EAAE;QAEhC,SAAS,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,EAAE,GAAG,CAAC,WAAW,CAAC;QACjD,UAAU,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,EAAE,GAAG,CAAC,WAAW,CAAC;AAClD,QAAA,SAAS,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,aAAa,EAAE,GAAG,CAAC,WAAW,CAAC;AACvE,QAAA,YAAY,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,CAAC,WAAW,CAAC;AACjE,QAAA,OAAO,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,WAAW,CAAC;AAC3D,QAAA,OAAO,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,WAAW,CAAC;;AAGvD,QAAA,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC;AAC1B,QAAA,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC;;AAG3B,QAAA,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC;AAC5B,QAAA,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC;AAC1B,QAAA,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC;;AAG3B,QAAA,SAAS,CAAC,OAAO,CAAC,YAAY,CAAC;AAC/B,QAAA,YAAY,CAAC,OAAO,CAAC,SAAS,CAAC;AAE/B,QAAA,IAAI,CAAC,MAAM,GAAG,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,EAAE;IACtF;AACH;;;;"}
@@ -0,0 +1,31 @@
1
+ import { WorkletFilter } from './WorkletFilter';
2
+ import type { AudioBus } from '../AudioBus';
3
+ export interface DuckingFilterOptions {
4
+ sidechain: AudioBus;
5
+ threshold?: number;
6
+ ratio?: number;
7
+ attackMs?: number;
8
+ releaseMs?: number;
9
+ }
10
+ export declare class DuckingFilter extends WorkletFilter {
11
+ private readonly _sidechain;
12
+ private _threshold;
13
+ private _ratio;
14
+ private _attackMs;
15
+ private _releaseMs;
16
+ constructor(options: DuckingFilterOptions);
17
+ protected get _workletName(): string;
18
+ protected get _workletSource(): string;
19
+ protected get _workletOptions(): AudioWorkletNodeOptions;
20
+ protected _onWorkletReady(audioContext: AudioContext): void;
21
+ /** Convert ms time-constant to one-pole filter coefficient at given sample rate. */
22
+ private _msToCoeff;
23
+ get threshold(): number;
24
+ set threshold(value: number);
25
+ get ratio(): number;
26
+ set ratio(value: number);
27
+ get attackMs(): number;
28
+ set attackMs(value: number);
29
+ get releaseMs(): number;
30
+ set releaseMs(value: number);
31
+ }