@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.
- package/CHANGELOG.md +1316 -0
- package/dist/esm/audio/AbstractMedia.d.ts +18 -0
- package/dist/esm/audio/AbstractMedia.js +66 -0
- package/dist/esm/audio/AbstractMedia.js.map +1 -1
- package/dist/esm/audio/AudioAnalyser.d.ts +62 -23
- package/dist/esm/audio/AudioAnalyser.js +261 -57
- package/dist/esm/audio/AudioAnalyser.js.map +1 -1
- package/dist/esm/audio/AudioBus.d.ts +45 -0
- package/dist/esm/audio/AudioBus.js +219 -0
- package/dist/esm/audio/AudioBus.js.map +1 -0
- package/dist/esm/audio/AudioFilter.d.ts +9 -0
- package/dist/esm/audio/AudioFilter.js +7 -0
- package/dist/esm/audio/AudioFilter.js.map +1 -0
- package/dist/esm/audio/AudioListener.d.ts +20 -0
- package/dist/esm/audio/AudioListener.js +86 -0
- package/dist/esm/audio/AudioListener.js.map +1 -0
- package/dist/esm/audio/AudioManager.d.ts +31 -0
- package/dist/esm/audio/AudioManager.js +102 -0
- package/dist/esm/audio/AudioManager.js.map +1 -0
- package/dist/esm/audio/BeatDetector.d.ts +121 -0
- package/dist/esm/audio/BeatDetector.js +936 -0
- package/dist/esm/audio/BeatDetector.js.map +1 -0
- package/dist/esm/audio/Envelope.d.ts +44 -0
- package/dist/esm/audio/Envelope.js +60 -0
- package/dist/esm/audio/Envelope.js.map +1 -0
- package/dist/esm/audio/Music.d.ts +8 -0
- package/dist/esm/audio/Music.js +33 -4
- package/dist/esm/audio/Music.js.map +1 -1
- package/dist/esm/audio/OscillatorSound.d.ts +98 -0
- package/dist/esm/audio/OscillatorSound.js +342 -0
- package/dist/esm/audio/OscillatorSound.js.map +1 -0
- package/dist/esm/audio/Sound.d.ts +94 -9
- package/dist/esm/audio/Sound.js +283 -117
- package/dist/esm/audio/Sound.js.map +1 -1
- package/dist/esm/audio/crossFade.d.ts +19 -0
- package/dist/esm/audio/crossFade.js +26 -0
- package/dist/esm/audio/crossFade.js.map +1 -0
- package/dist/esm/audio/dsp/fft.d.ts +22 -0
- package/dist/esm/audio/dsp/mel.d.ts +43 -0
- package/dist/esm/audio/dsp/tempogram.d.ts +51 -0
- package/dist/esm/audio/filters/ChorusFilter.d.ts +47 -0
- package/dist/esm/audio/filters/ChorusFilter.js +139 -0
- package/dist/esm/audio/filters/ChorusFilter.js.map +1 -0
- package/dist/esm/audio/filters/CompressorFilter.d.ts +31 -0
- package/dist/esm/audio/filters/CompressorFilter.js +97 -0
- package/dist/esm/audio/filters/CompressorFilter.js.map +1 -0
- package/dist/esm/audio/filters/DelayFilter.d.ts +23 -0
- package/dist/esm/audio/filters/DelayFilter.js +100 -0
- package/dist/esm/audio/filters/DelayFilter.js.map +1 -0
- package/dist/esm/audio/filters/DuckingFilter.d.ts +31 -0
- package/dist/esm/audio/filters/DuckingFilter.js +152 -0
- package/dist/esm/audio/filters/DuckingFilter.js.map +1 -0
- package/dist/esm/audio/filters/EqualizerFilter.d.ts +29 -0
- package/dist/esm/audio/filters/EqualizerFilter.js +94 -0
- package/dist/esm/audio/filters/EqualizerFilter.js.map +1 -0
- package/dist/esm/audio/filters/GranularFilter.d.ts +56 -0
- package/dist/esm/audio/filters/GranularFilter.js +170 -0
- package/dist/esm/audio/filters/GranularFilter.js.map +1 -0
- package/dist/esm/audio/filters/HighpassFilter.d.ts +19 -0
- package/dist/esm/audio/filters/HighpassFilter.js +62 -0
- package/dist/esm/audio/filters/HighpassFilter.js.map +1 -0
- package/dist/esm/audio/filters/LowpassFilter.d.ts +19 -0
- package/dist/esm/audio/filters/LowpassFilter.js +62 -0
- package/dist/esm/audio/filters/LowpassFilter.js.map +1 -0
- package/dist/esm/audio/filters/PitchShiftFilter.d.ts +42 -0
- package/dist/esm/audio/filters/PitchShiftFilter.js +130 -0
- package/dist/esm/audio/filters/PitchShiftFilter.js.map +1 -0
- package/dist/esm/audio/filters/ReverbFilter.d.ts +24 -0
- package/dist/esm/audio/filters/ReverbFilter.js +107 -0
- package/dist/esm/audio/filters/ReverbFilter.js.map +1 -0
- package/dist/esm/audio/filters/VocoderFilter.d.ts +38 -0
- package/dist/esm/audio/filters/VocoderFilter.js +163 -0
- package/dist/esm/audio/filters/VocoderFilter.js.map +1 -0
- package/dist/esm/audio/filters/WorkletFilter.d.ts +46 -0
- package/dist/esm/audio/filters/WorkletFilter.js +101 -0
- package/dist/esm/audio/filters/WorkletFilter.js.map +1 -0
- package/dist/esm/audio/filters/index.d.ts +12 -0
- package/dist/esm/audio/index.d.ts +15 -1
- package/dist/esm/audio/worklet/registerWorklet.d.ts +10 -0
- package/dist/esm/audio/worklet/registerWorklet.js +44 -0
- package/dist/esm/audio/worklet/registerWorklet.js.map +1 -0
- package/dist/esm/core/Application.d.ts +19 -0
- package/dist/esm/core/Application.js +76 -2
- package/dist/esm/core/Application.js.map +1 -1
- package/dist/esm/core/SceneNode.d.ts +9 -1
- package/dist/esm/core/SceneNode.js +44 -6
- package/dist/esm/core/SceneNode.js.map +1 -1
- package/dist/esm/core/Time.js +1 -1
- package/dist/esm/core/index.d.ts +0 -1
- package/dist/esm/debug/BoundingBoxesLayer.d.ts +18 -0
- package/dist/esm/debug/BoundingBoxesLayer.js +128 -0
- package/dist/esm/debug/BoundingBoxesLayer.js.map +1 -0
- package/dist/esm/debug/DebugLayer.d.ts +29 -0
- package/dist/esm/debug/DebugLayer.js +26 -0
- package/dist/esm/debug/DebugLayer.js.map +1 -0
- package/dist/esm/debug/DebugOverlay.d.ts +48 -0
- package/dist/esm/debug/DebugOverlay.js +117 -0
- package/dist/esm/debug/DebugOverlay.js.map +1 -0
- package/dist/esm/debug/HitTestLayer.d.ts +23 -0
- package/dist/esm/debug/HitTestLayer.js +109 -0
- package/dist/esm/debug/HitTestLayer.js.map +1 -0
- package/dist/esm/debug/PerformanceLayer.d.ts +21 -0
- package/dist/esm/debug/PerformanceLayer.js +175 -0
- package/dist/esm/debug/PerformanceLayer.js.map +1 -0
- package/dist/esm/debug/PointerStackLayer.d.ts +23 -0
- package/dist/esm/debug/PointerStackLayer.js +152 -0
- package/dist/esm/debug/PointerStackLayer.js.map +1 -0
- package/dist/esm/debug/index.d.ts +6 -0
- package/dist/esm/debug/index.js +7 -0
- package/dist/esm/debug/index.js.map +1 -0
- package/dist/esm/index.js +28 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/input/InputManager.d.ts +10 -0
- package/dist/esm/input/InputManager.js +35 -5
- package/dist/esm/input/InputManager.js.map +1 -1
- package/dist/esm/input/InteractionEvent.d.ts +18 -0
- package/dist/esm/input/InteractionEvent.js +29 -0
- package/dist/esm/input/InteractionEvent.js.map +1 -0
- package/dist/esm/input/InteractionManager.d.ts +134 -0
- package/dist/esm/input/InteractionManager.js +546 -0
- package/dist/esm/input/InteractionManager.js.map +1 -0
- package/dist/esm/input/index.d.ts +2 -0
- package/dist/esm/input/interaction-hooks.d.ts +34 -0
- package/dist/esm/input/interaction-hooks.js +35 -0
- package/dist/esm/input/interaction-hooks.js.map +1 -0
- package/dist/esm/math/Circle.d.ts +12 -2
- package/dist/esm/math/Circle.js +82 -14
- package/dist/esm/math/Circle.js.map +1 -1
- package/dist/esm/math/Interval.js +1 -1
- package/dist/esm/math/ObservableVector.d.ts +2 -2
- package/dist/esm/math/ObservableVector.js +4 -2
- package/dist/esm/math/ObservableVector.js.map +1 -1
- package/dist/esm/math/Polygon.d.ts +15 -1
- package/dist/esm/math/Polygon.js +58 -6
- package/dist/esm/math/Polygon.js.map +1 -1
- package/dist/esm/math/Quadtree.d.ts +47 -0
- package/dist/esm/math/Quadtree.js +168 -0
- package/dist/esm/math/Quadtree.js.map +1 -0
- package/dist/esm/math/Random.js +1 -1
- package/dist/esm/math/Size.js +1 -1
- package/dist/esm/math/Vector.js +1 -1
- package/dist/esm/math/collision-detection.js +4 -1
- package/dist/esm/math/collision-detection.js.map +1 -1
- package/dist/esm/math/index.d.ts +1 -0
- package/dist/esm/particles/ParticleSystem.js +1 -0
- package/dist/esm/particles/ParticleSystem.js.map +1 -1
- package/dist/esm/particles/affectors/TorqueAffector.js +1 -1
- package/dist/esm/rendering/Container.d.ts +1 -0
- package/dist/esm/rendering/Container.js +19 -0
- package/dist/esm/rendering/Container.js.map +1 -1
- package/dist/esm/rendering/RenderNode.d.ts +27 -0
- package/dist/esm/rendering/RenderNode.js +44 -0
- package/dist/esm/rendering/RenderNode.js.map +1 -1
- package/dist/esm/rendering/View.d.ts +6 -4
- package/dist/esm/rendering/View.js +12 -2
- package/dist/esm/rendering/View.js.map +1 -1
- package/dist/esm/rendering/filters/WebGl2ShaderFilter.d.ts +109 -0
- package/dist/esm/rendering/filters/WebGl2ShaderFilter.js +268 -0
- package/dist/esm/rendering/filters/WebGl2ShaderFilter.js.map +1 -0
- package/dist/esm/rendering/filters/WebGpuShaderFilter.d.ts +111 -0
- package/dist/esm/rendering/filters/WebGpuShaderFilter.js +397 -0
- package/dist/esm/rendering/filters/WebGpuShaderFilter.js.map +1 -0
- package/dist/esm/rendering/index.d.ts +3 -0
- package/dist/esm/rendering/mesh/Mesh.js +1 -0
- package/dist/esm/rendering/mesh/Mesh.js.map +1 -1
- package/dist/esm/rendering/shader/upgradeFragmentShaderToGl300.d.ts +34 -0
- package/dist/esm/rendering/shader/upgradeFragmentShaderToGl300.js +60 -0
- package/dist/esm/rendering/shader/upgradeFragmentShaderToGl300.js.map +1 -0
- package/dist/esm/rendering/sprite/Sprite.d.ts +6 -1
- package/dist/esm/rendering/sprite/Sprite.js +41 -19
- package/dist/esm/rendering/sprite/Sprite.js.map +1 -1
- package/dist/esm/rendering/video/Video.d.ts +4 -0
- package/dist/esm/rendering/video/Video.js +32 -4
- package/dist/esm/rendering/video/Video.js.map +1 -1
- package/dist/esm/rendering/webgl2/WebGl2Backend.d.ts +4 -4
- package/dist/esm/rendering/webgl2/WebGl2Backend.js +7 -16
- package/dist/esm/rendering/webgl2/WebGl2Backend.js.map +1 -1
- package/dist/esm/rendering/webgpu/WebGpuBackend.d.ts +10 -8
- package/dist/esm/rendering/webgpu/WebGpuBackend.js +30 -40
- package/dist/esm/rendering/webgpu/WebGpuBackend.js.map +1 -1
- package/dist/exo.esm.js +7764 -2453
- package/dist/exo.esm.js.map +1 -1
- package/package.json +14 -2
- package/dist/esm/core/Quadtree.d.ts +0 -20
- package/dist/esm/core/Quadtree.js +0 -86
- 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
|
}
|
package/dist/esm/audio/Music.js
CHANGED
|
@@ -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,
|
|
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,
|
|
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,
|
|
111
|
-
|
|
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":"
|
|
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
|