@datamoc/mw_games 0.42.0 → 0.44.2
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 +126 -0
- package/README.md +84 -1
- package/REFERENCE.md +134 -6
- package/api-surface.json +1814 -116
- package/data/microgm-essential.PROVENANCE.md +13 -0
- package/data/microgm-essential.sf2 +0 -0
- package/data/soundfont-catalog.json +8 -0
- package/dist/actors/Resource.d.ts.map +1 -1
- package/dist/actors/Resource.js +2 -3
- package/dist/actors/Resource.js.map +1 -1
- package/dist/audio/AdaptiveMusic.d.ts +85 -0
- package/dist/audio/AdaptiveMusic.d.ts.map +1 -0
- package/dist/audio/AdaptiveMusic.js +230 -0
- package/dist/audio/AdaptiveMusic.js.map +1 -0
- package/dist/audio/AudioLoader.d.ts +33 -0
- package/dist/audio/AudioLoader.d.ts.map +1 -0
- package/dist/audio/AudioLoader.js +58 -0
- package/dist/audio/AudioLoader.js.map +1 -0
- package/dist/audio/AudioViews.d.ts +70 -0
- package/dist/audio/AudioViews.d.ts.map +1 -0
- package/dist/audio/AudioViews.js +119 -0
- package/dist/audio/AudioViews.js.map +1 -0
- package/dist/audio/BusBudget.d.ts +89 -0
- package/dist/audio/BusBudget.d.ts.map +1 -0
- package/dist/audio/BusBudget.js +120 -0
- package/dist/audio/BusBudget.js.map +1 -0
- package/dist/audio/Channels.d.ts +66 -1
- package/dist/audio/Channels.d.ts.map +1 -1
- package/dist/audio/Channels.js +119 -31
- package/dist/audio/Channels.js.map +1 -1
- package/dist/audio/CoreHost.d.ts +114 -0
- package/dist/audio/CoreHost.d.ts.map +1 -0
- package/dist/audio/CoreHost.js +335 -0
- package/dist/audio/CoreHost.js.map +1 -0
- package/dist/audio/DecoderGuard.d.ts +139 -0
- package/dist/audio/DecoderGuard.d.ts.map +1 -0
- package/dist/audio/DecoderGuard.js +208 -0
- package/dist/audio/DecoderGuard.js.map +1 -0
- package/dist/audio/Fft.d.ts +3 -0
- package/dist/audio/Fft.d.ts.map +1 -0
- package/dist/audio/Fft.js +45 -0
- package/dist/audio/Fft.js.map +1 -0
- package/dist/audio/LoopTags.d.ts +18 -0
- package/dist/audio/LoopTags.d.ts.map +1 -1
- package/dist/audio/LoopTags.js +20 -0
- package/dist/audio/LoopTags.js.map +1 -1
- package/dist/audio/Midi.d.ts +35 -0
- package/dist/audio/Midi.d.ts.map +1 -1
- package/dist/audio/Midi.js +71 -1
- package/dist/audio/Midi.js.map +1 -1
- package/dist/audio/MidiRender.d.ts +47 -0
- package/dist/audio/MidiRender.d.ts.map +1 -1
- package/dist/audio/MidiRender.js +100 -2
- package/dist/audio/MidiRender.js.map +1 -1
- package/dist/audio/MidiSynth.d.ts +147 -0
- package/dist/audio/MidiSynth.d.ts.map +1 -0
- package/dist/audio/MidiSynth.js +205 -0
- package/dist/audio/MidiSynth.js.map +1 -0
- package/dist/audio/MusicPlayer.d.ts +80 -0
- package/dist/audio/MusicPlayer.d.ts.map +1 -0
- package/dist/audio/MusicPlayer.js +147 -0
- package/dist/audio/MusicPlayer.js.map +1 -0
- package/dist/audio/Playable.d.ts +7 -0
- package/dist/audio/Playable.d.ts.map +1 -1
- package/dist/audio/Playable.js.map +1 -1
- package/dist/audio/Positional.d.ts +12 -4
- package/dist/audio/Positional.d.ts.map +1 -1
- package/dist/audio/Positional.js +5 -2
- package/dist/audio/Positional.js.map +1 -1
- package/dist/audio/Resample.d.ts +61 -0
- package/dist/audio/Resample.d.ts.map +1 -0
- package/dist/audio/Resample.js +97 -0
- package/dist/audio/Resample.js.map +1 -0
- package/dist/audio/SampleDecoder.d.ts +16 -2
- package/dist/audio/SampleDecoder.d.ts.map +1 -1
- package/dist/audio/SampleDecoder.js +10 -6
- package/dist/audio/SampleDecoder.js.map +1 -1
- package/dist/audio/Settings.d.ts +99 -0
- package/dist/audio/Settings.d.ts.map +1 -0
- package/dist/audio/Settings.js +134 -0
- package/dist/audio/Settings.js.map +1 -0
- package/dist/audio/Sfx.d.ts +148 -0
- package/dist/audio/Sfx.d.ts.map +1 -0
- package/dist/audio/Sfx.js +213 -0
- package/dist/audio/Sfx.js.map +1 -0
- package/dist/audio/Sound.d.ts +2 -0
- package/dist/audio/Sound.d.ts.map +1 -1
- package/dist/audio/Sound.js +3 -0
- package/dist/audio/Sound.js.map +1 -1
- package/dist/audio/SoundFont.d.ts +5 -3
- package/dist/audio/SoundFont.d.ts.map +1 -1
- package/dist/audio/SoundFont.js +10 -8
- package/dist/audio/SoundFont.js.map +1 -1
- package/dist/audio/SpectralDistance.d.ts +34 -0
- package/dist/audio/SpectralDistance.d.ts.map +1 -0
- package/dist/audio/SpectralDistance.js +64 -0
- package/dist/audio/SpectralDistance.js.map +1 -0
- package/dist/audio/StreamChannel.d.ts +150 -0
- package/dist/audio/StreamChannel.d.ts.map +1 -0
- package/dist/audio/StreamChannel.js +390 -0
- package/dist/audio/StreamChannel.js.map +1 -0
- package/dist/audio/StreamPlayable.d.ts +73 -0
- package/dist/audio/StreamPlayable.d.ts.map +1 -0
- package/dist/audio/StreamPlayable.js +130 -0
- package/dist/audio/StreamPlayable.js.map +1 -0
- package/dist/audio/Synth.d.ts +1 -1
- package/dist/audio/Synth.d.ts.map +1 -1
- package/dist/audio/Synth.js +4 -0
- package/dist/audio/Synth.js.map +1 -1
- package/dist/audio/SyxBank.d.ts +73 -0
- package/dist/audio/SyxBank.d.ts.map +1 -0
- package/dist/audio/SyxBank.js +130 -0
- package/dist/audio/SyxBank.js.map +1 -0
- package/dist/audio/Underrun.d.ts +25 -0
- package/dist/audio/Underrun.d.ts.map +1 -0
- package/dist/audio/Underrun.js +18 -0
- package/dist/audio/Underrun.js.map +1 -0
- package/dist/audio/Wav.d.ts +56 -0
- package/dist/audio/Wav.d.ts.map +1 -0
- package/dist/audio/Wav.js +164 -0
- package/dist/audio/Wav.js.map +1 -0
- package/dist/audio/WebMidi.d.ts +58 -0
- package/dist/audio/WebMidi.d.ts.map +1 -0
- package/dist/audio/WebMidi.js +79 -0
- package/dist/audio/WebMidi.js.map +1 -0
- package/dist/audio/humanize/Onsets.d.ts.map +1 -1
- package/dist/audio/humanize/Onsets.js +1 -44
- package/dist/audio/humanize/Onsets.js.map +1 -1
- package/dist/audio/index.d.ts +43 -7
- package/dist/audio/index.d.ts.map +1 -1
- package/dist/audio/index.js +21 -3
- package/dist/audio/index.js.map +1 -1
- package/dist/battle/AttackPreview.d.ts.map +1 -1
- package/dist/battle/AttackPreview.js +8 -8
- package/dist/battle/AttackPreview.js.map +1 -1
- package/dist/battle/StatStages.d.ts.map +1 -1
- package/dist/battle/StatStages.js +2 -1
- package/dist/battle/StatStages.js.map +1 -1
- package/dist/board/Engine.d.ts +2 -0
- package/dist/board/Engine.d.ts.map +1 -1
- package/dist/board/Engine.js +1 -1
- package/dist/board/Engine.js.map +1 -1
- package/dist/board/HexSkirmish.d.ts.map +1 -1
- package/dist/board/HexSkirmish.js +11 -72
- package/dist/board/HexSkirmish.js.map +1 -1
- package/dist/board/Tactics.d.ts.map +1 -1
- package/dist/board/Tactics.js +3 -5
- package/dist/board/Tactics.js.map +1 -1
- package/dist/board/tourney.d.ts.map +1 -1
- package/dist/board/tourney.js +2 -19
- package/dist/board/tourney.js.map +1 -1
- package/dist/core/Handles.js +7 -7
- package/dist/core/Handles.js.map +1 -1
- package/dist/mw_games.global.js +25 -22
- package/dist/mwl/conditions.d.ts +12 -0
- package/dist/mwl/conditions.d.ts.map +1 -1
- package/dist/mwl/conditions.js +49 -8
- package/dist/mwl/conditions.js.map +1 -1
- package/dist/mwl/index.d.ts +13 -0
- package/dist/mwl/index.d.ts.map +1 -1
- package/dist/mwl/index.js +7 -0
- package/dist/mwl/index.js.map +1 -1
- package/dist/mwl/objects.d.ts +31 -0
- package/dist/mwl/objects.d.ts.map +1 -0
- package/dist/mwl/objects.js +83 -0
- package/dist/mwl/objects.js.map +1 -0
- package/dist/mwl/package-container.d.ts +185 -0
- package/dist/mwl/package-container.d.ts.map +1 -0
- package/dist/mwl/package-container.js +446 -0
- package/dist/mwl/package-container.js.map +1 -0
- package/dist/mwl/package-document.d.ts +217 -0
- package/dist/mwl/package-document.d.ts.map +1 -0
- package/dist/mwl/package-document.js +639 -0
- package/dist/mwl/package-document.js.map +1 -0
- package/dist/mwl/package-rom.d.ts +37 -0
- package/dist/mwl/package-rom.d.ts.map +1 -0
- package/dist/mwl/package-rom.js +96 -0
- package/dist/mwl/package-rom.js.map +1 -0
- package/dist/mwl/package-verify.d.ts +34 -0
- package/dist/mwl/package-verify.d.ts.map +1 -0
- package/dist/mwl/package-verify.js +111 -0
- package/dist/mwl/package-verify.js.map +1 -0
- package/dist/mwl/package.d.ts +184 -0
- package/dist/mwl/package.d.ts.map +1 -0
- package/dist/mwl/package.js +382 -0
- package/dist/mwl/package.js.map +1 -0
- package/dist/mwl/schema.d.ts +1 -1
- package/dist/mwl/schema.d.ts.map +1 -1
- package/dist/mwl/tables.d.ts +2 -0
- package/dist/mwl/tables.d.ts.map +1 -1
- package/dist/mwl/tables.js +13 -0
- package/dist/mwl/tables.js.map +1 -1
- package/dist/physics/PhysicsWorld.d.ts.map +1 -1
- package/dist/physics/PhysicsWorld.js +4 -3
- package/dist/physics/PhysicsWorld.js.map +1 -1
- package/dist/physics/XpbdWorld.d.ts +23 -5
- package/dist/physics/XpbdWorld.d.ts.map +1 -1
- package/dist/physics/XpbdWorld.js +91 -6
- package/dist/physics/XpbdWorld.js.map +1 -1
- package/dist/testing/FakeAudio.d.ts +149 -0
- package/dist/testing/FakeAudio.d.ts.map +1 -0
- package/dist/testing/FakeAudio.js +219 -0
- package/dist/testing/FakeAudio.js.map +1 -0
- package/dist/testing/index.d.ts +18 -0
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +22 -0
- package/dist/testing/index.js.map +1 -1
- package/dist/threads/index.d.ts +2 -2
- package/dist/threads/index.d.ts.map +1 -1
- package/dist/threads/index.js +1 -1
- package/dist/threads/index.js.map +1 -1
- package/dist/threads/spawn.d.ts +32 -0
- package/dist/threads/spawn.d.ts.map +1 -1
- package/dist/threads/spawn.js +35 -11
- package/dist/threads/spawn.js.map +1 -1
- package/dist/three-d/Collision3D.d.ts +46 -2
- package/dist/three-d/Collision3D.d.ts.map +1 -1
- package/dist/three-d/Collision3D.js +46 -2
- package/dist/three-d/Collision3D.js.map +1 -1
- package/dist/three-d/Grid.d.ts +12 -1
- package/dist/three-d/Grid.d.ts.map +1 -1
- package/dist/three-d/Grid.js +12 -1
- package/dist/three-d/Grid.js.map +1 -1
- package/dist/three-d/Vox.d.ts +13 -1
- package/dist/three-d/Vox.d.ts.map +1 -1
- package/dist/three-d/Vox.js +13 -1
- package/dist/three-d/Vox.js.map +1 -1
- package/dist/two-d/Game.d.ts +32 -1
- package/dist/two-d/Game.d.ts.map +1 -1
- package/dist/two-d/Game.js +105 -14
- package/dist/two-d/Game.js.map +1 -1
- package/dist/two-d/Scene2D.d.ts +24 -0
- package/dist/two-d/Scene2D.d.ts.map +1 -1
- package/dist/two-d/Scene2D.js +30 -0
- package/dist/two-d/Scene2D.js.map +1 -1
- package/dist/two-d/render/HazeLayer.d.ts.map +1 -1
- package/dist/two-d/render/HazeLayer.js +2 -1
- package/dist/two-d/render/HazeLayer.js.map +1 -1
- package/dist/two-d/render/ImageModifiers.d.ts +4 -2
- package/dist/two-d/render/ImageModifiers.d.ts.map +1 -1
- package/dist/two-d/render/ImageModifiers.js +13 -8
- package/dist/two-d/render/ImageModifiers.js.map +1 -1
- package/dist/two-d/render/NeonGlow.d.ts.map +1 -1
- package/dist/two-d/render/NeonGlow.js +2 -1
- package/dist/two-d/render/NeonGlow.js.map +1 -1
- package/dist/two-d/render/Particles.d.ts.map +1 -1
- package/dist/two-d/render/Particles.js +2 -1
- package/dist/two-d/render/Particles.js.map +1 -1
- package/dist/two-d/render/SceneTransition.d.ts +301 -0
- package/dist/two-d/render/SceneTransition.d.ts.map +1 -0
- package/dist/two-d/render/SceneTransition.js +458 -0
- package/dist/two-d/render/SceneTransition.js.map +1 -0
- package/dist/two-d/render/ScreenEffects.d.ts.map +1 -1
- package/dist/two-d/render/ScreenEffects.js +2 -1
- package/dist/two-d/render/ScreenEffects.js.map +1 -1
- package/dist/two-d/render/SkeletalSprite.d.ts.map +1 -1
- package/dist/two-d/render/SkeletalSprite.js +2 -1
- package/dist/two-d/render/SkeletalSprite.js.map +1 -1
- package/dist/two-d/render/Types2D.d.ts +2 -2
- package/dist/two-d/render/Types2D.d.ts.map +1 -1
- package/dist/two-d/render/Types2D.js +2 -2
- package/dist/two-d/render/Types2D.js.map +1 -1
- package/dist/two-d/render/index.d.ts +2 -0
- package/dist/two-d/render/index.d.ts.map +1 -1
- package/dist/two-d/render/index.js +1 -0
- package/dist/two-d/render/index.js.map +1 -1
- package/dist/two-d/ui/Bar.d.ts.map +1 -1
- package/dist/two-d/ui/Bar.js +3 -5
- package/dist/two-d/ui/Bar.js.map +1 -1
- package/dist/two-d/ui/Button.d.ts +23 -0
- package/dist/two-d/ui/Button.d.ts.map +1 -1
- package/dist/two-d/ui/Button.js +37 -0
- package/dist/two-d/ui/Button.js.map +1 -1
- package/dist/two-d/ui/Dropdown.d.ts +5 -1
- package/dist/two-d/ui/Dropdown.d.ts.map +1 -1
- package/dist/two-d/ui/Dropdown.js +8 -1
- package/dist/two-d/ui/Dropdown.js.map +1 -1
- package/dist/two-d/ui/DropdownView.d.ts +63 -3
- package/dist/two-d/ui/DropdownView.d.ts.map +1 -1
- package/dist/two-d/ui/DropdownView.js +168 -9
- package/dist/two-d/ui/DropdownView.js.map +1 -1
- package/dist/two-d/ui/FloatingText.d.ts.map +1 -1
- package/dist/two-d/ui/FloatingText.js +2 -1
- package/dist/two-d/ui/FloatingText.js.map +1 -1
- package/dist/two-d/ui/IconGrid.d.ts.map +1 -1
- package/dist/two-d/ui/IconGrid.js +2 -1
- package/dist/two-d/ui/IconGrid.js.map +1 -1
- package/dist/two-d/ui/ListView.d.ts.map +1 -1
- package/dist/two-d/ui/ListView.js +2 -1
- package/dist/two-d/ui/ListView.js.map +1 -1
- package/dist/two-d/ui/ScrollBox.d.ts +96 -0
- package/dist/two-d/ui/ScrollBox.d.ts.map +1 -1
- package/dist/two-d/ui/ScrollBox.js +218 -5
- package/dist/two-d/ui/ScrollBox.js.map +1 -1
- package/dist/two-d/ui/ScrollText.d.ts +131 -0
- package/dist/two-d/ui/ScrollText.d.ts.map +1 -0
- package/dist/two-d/ui/ScrollText.js +218 -0
- package/dist/two-d/ui/ScrollText.js.map +1 -0
- package/dist/two-d/ui/Slider.d.ts.map +1 -1
- package/dist/two-d/ui/Slider.js +4 -4
- package/dist/two-d/ui/Slider.js.map +1 -1
- package/dist/two-d/ui/Tooltip.d.ts +70 -1
- package/dist/two-d/ui/Tooltip.d.ts.map +1 -1
- package/dist/two-d/ui/Tooltip.js +115 -3
- package/dist/two-d/ui/Tooltip.js.map +1 -1
- package/dist/two-d/ui/Window.d.ts +35 -2
- package/dist/two-d/ui/Window.d.ts.map +1 -1
- package/dist/two-d/ui/Window.js +58 -3
- package/dist/two-d/ui/Window.js.map +1 -1
- package/dist/two-d/ui/index.d.ts +7 -5
- package/dist/two-d/ui/index.d.ts.map +1 -1
- package/dist/two-d/ui/index.js +3 -2
- package/dist/two-d/ui/index.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +14 -3
- package/sbom.cdx.json +19 -260
- package/tools/audio.d.mts +75 -0
- package/tools/audio.mjs +437 -0
- package/tools/browser-driver.mjs +3 -3
- package/tools/browser-smoke.mjs +19 -2
- package/tools/build-tablebases.mjs +7 -3
- package/tools/compile-openings.mjs +7 -3
- package/tools/compile-resources.d.mts +2 -0
- package/tools/compile-resources.mjs +13 -1
- package/tools/emit-page.d.mts +6 -0
- package/tools/emit-page.mjs +43 -3
- package/tools/find-chrome.mjs +4 -2
- package/tools/init.mjs +11 -3
- package/tools/mwl.mjs +144 -2
- package/tools/play-uci.mjs +9 -5
- package/tools/vite.mjs +9 -1
- package/tools.md +2 -1
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { timedMidiMessages } from './Midi.js';
|
|
2
|
+
/**
|
|
3
|
+
* A waveform reduced to `buckets` min/max pairs, what an oscilloscope or overview strip
|
|
4
|
+
* draws: each bucket covers an equal span of the samples (the last may be shorter), so a
|
|
5
|
+
* peak that lasts one sample still shows, which a plain average would erase.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { waveformEnvelope } from '@datamoc/mw_games/audio';
|
|
10
|
+
*
|
|
11
|
+
* const view = waveformEnvelope(new Float32Array([0, 1, -1, 0.5]), 2);
|
|
12
|
+
* console.log(view); // [{ min: 0, max: 1 }, { min: -1, max: 0.5 }]
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export function waveformEnvelope(samples, buckets) {
|
|
16
|
+
if (buckets < 1 || samples.length === 0)
|
|
17
|
+
return [];
|
|
18
|
+
const out = [];
|
|
19
|
+
for (let bucket = 0; bucket < buckets; bucket++) {
|
|
20
|
+
const from = Math.floor((bucket * samples.length) / buckets);
|
|
21
|
+
const to = Math.max(from + 1, Math.floor(((bucket + 1) * samples.length) / buckets));
|
|
22
|
+
let min = Infinity;
|
|
23
|
+
let max = -Infinity;
|
|
24
|
+
for (let i = from; i < Math.min(to, samples.length); i++) {
|
|
25
|
+
if (samples[i] < min)
|
|
26
|
+
min = samples[i];
|
|
27
|
+
if (samples[i] > max)
|
|
28
|
+
max = samples[i];
|
|
29
|
+
}
|
|
30
|
+
out.push({ min: min === Infinity ? 0 : min, max: max === -Infinity ? 0 : max });
|
|
31
|
+
}
|
|
32
|
+
return out;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Per-channel waveform envelopes of stereo frames: channel 0 is the left, 1 the right,
|
|
36
|
+
* and a view asks each channel for the same number of buckets.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```ts
|
|
40
|
+
* import { channelEnvelopes } from '@datamoc/mw_games/audio';
|
|
41
|
+
*
|
|
42
|
+
* const [left] = channelEnvelopes(new Float32Array([1, -1]), new Float32Array([0.5, -0.5]), 1);
|
|
43
|
+
* console.log(left); // [{ min: -1, max: 1 }]
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export function channelEnvelopes(left, right, buckets) {
|
|
47
|
+
return [waveformEnvelope(left, buckets), waveformEnvelope(right, buckets)];
|
|
48
|
+
}
|
|
49
|
+
const NOTE_NAMES = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'];
|
|
50
|
+
/**
|
|
51
|
+
* A MIDI note number as a tracker spells it: name and octave, middle C as C4.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```ts
|
|
55
|
+
* import { trackerNoteName } from '@datamoc/mw_games/audio';
|
|
56
|
+
*
|
|
57
|
+
* console.log(trackerNoteName(60)); // 'C4'
|
|
58
|
+
* console.log(trackerNoteName(61)); // 'C#4'
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
export function trackerNoteName(note) {
|
|
62
|
+
return `${NOTE_NAMES[((note % 12) + 12) % 12]}${Math.floor(note / 12) - 1}`;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* A MIDI file as tracker pattern rows: `stepsPerQuarter` rows per quarter note, one
|
|
66
|
+
* column per channel that plays, and a cell naming the note that starts on that row
|
|
67
|
+
* (the highest when a channel starts several at once, as a tracker cell holds one).
|
|
68
|
+
* Steps are counted in the file's own ticks, and a row's time follows its tempo map.
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ```ts
|
|
72
|
+
* import { trackerPattern, type MidiFile } from '@datamoc/mw_games/audio';
|
|
73
|
+
*
|
|
74
|
+
* declare const file: MidiFile;
|
|
75
|
+
*
|
|
76
|
+
* const rows = trackerPattern(file);
|
|
77
|
+
* console.log(rows[0].notes); // the first step's notes by channel, or nulls
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
export function trackerPattern(file, stepsPerQuarter = 4) {
|
|
81
|
+
const starts = [];
|
|
82
|
+
for (const event of file.events)
|
|
83
|
+
if (event.type === 'noteOn' && event.velocity > 0)
|
|
84
|
+
starts.push(event);
|
|
85
|
+
if (starts.length === 0)
|
|
86
|
+
return [];
|
|
87
|
+
//note-on times in file order, from the same walk a synth is driven by
|
|
88
|
+
const times = timedMidiMessages(file)
|
|
89
|
+
.filter((message) => (message.status & 0xf0) === 0x90 && message.data2 > 0)
|
|
90
|
+
.map((message) => message.time);
|
|
91
|
+
const channelCount = Math.max(...starts.map((event) => event.channel)) + 1;
|
|
92
|
+
const stepTicks = file.ticksPerQuarter / stepsPerQuarter;
|
|
93
|
+
const cells = new Map();
|
|
94
|
+
let lastStep = 0;
|
|
95
|
+
const stepTime = new Map();
|
|
96
|
+
starts.forEach((event, index) => {
|
|
97
|
+
const step = Math.floor(event.tick / stepTicks);
|
|
98
|
+
lastStep = Math.max(lastStep, step);
|
|
99
|
+
if (!cells.has(step))
|
|
100
|
+
cells.set(step, new Map());
|
|
101
|
+
const row = cells.get(step);
|
|
102
|
+
if (event.note > (row.get(event.channel) ?? -1))
|
|
103
|
+
row.set(event.channel, event.note);
|
|
104
|
+
if (!stepTime.has(step))
|
|
105
|
+
stepTime.set(step, times[index] ?? 0);
|
|
106
|
+
});
|
|
107
|
+
const rows = [];
|
|
108
|
+
let lastTime = 0;
|
|
109
|
+
for (let step = 0; step <= lastStep; step++) {
|
|
110
|
+
if (stepTime.has(step))
|
|
111
|
+
lastTime = stepTime.get(step);
|
|
112
|
+
const notes = Array(channelCount).fill(null);
|
|
113
|
+
for (const [channel, note] of cells.get(step) ?? [])
|
|
114
|
+
notes[channel] = trackerNoteName(note);
|
|
115
|
+
rows.push({ step, time: lastTime, notes });
|
|
116
|
+
}
|
|
117
|
+
return rows;
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=AudioViews.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AudioViews.js","sourceRoot":"","sources":["../../src/audio/AudioViews.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import type { BusLoader, LoadedTrack } from './Channels.ts';
|
|
2
|
+
import type { RenderBudget } from './Resample.ts';
|
|
3
|
+
/**
|
|
4
|
+
* What a bus may spend on decoded tracks. A rendered five-minute stereo track at 44.1 kHz is
|
|
5
|
+
* about 100 MB, so a game that keeps every track it ever played runs a phone out of memory;
|
|
6
|
+
* these are the dials that keep it bounded.
|
|
7
|
+
*/
|
|
8
|
+
export interface BusBudgetPolicy {
|
|
9
|
+
/** evict the least recently used track once the cache holds more than this many megabytes; unlimited when omitted */
|
|
10
|
+
maxMegabytes?: number;
|
|
11
|
+
/** evict once the cache holds more than this many tracks; unlimited when omitted */
|
|
12
|
+
maxEntries?: number;
|
|
13
|
+
/** applied to a rendered MIDI track before it becomes a buffer: a length cap, mono, half rate */
|
|
14
|
+
render?: RenderBudget;
|
|
15
|
+
}
|
|
16
|
+
export interface TrackCacheStats {
|
|
17
|
+
entries: number;
|
|
18
|
+
bytes: number;
|
|
19
|
+
hits: number;
|
|
20
|
+
misses: number;
|
|
21
|
+
evictions: number;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Memory a decoded buffer holds: 32-bit samples on every channel.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```ts
|
|
28
|
+
* import { bufferBytes } from '@datamoc/mw_games/audio';
|
|
29
|
+
*
|
|
30
|
+
* console.log(bufferBytes({ length: 44100, numberOfChannels: 2 })); // 352800, one stereo second
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export declare function bufferBytes(buffer: Pick<AudioBuffer, 'length' | 'numberOfChannels'>): number;
|
|
34
|
+
/**
|
|
35
|
+
* A least-recently-used cache of loaded tracks under a `BusBudgetPolicy`. A load in flight is
|
|
36
|
+
* shared by everyone who asks for the same key, a failure or a `null` answer is not remembered
|
|
37
|
+
* so the next request retries, and a track that is currently playing survives its own eviction
|
|
38
|
+
* because the `Channel` holds the buffer, so evicting only means the next request decodes again.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```ts
|
|
42
|
+
* import { TrackCache, type LoadedTrack } from '@datamoc/mw_games/audio';
|
|
43
|
+
*
|
|
44
|
+
* declare function decode(path: string): Promise<LoadedTrack>;
|
|
45
|
+
*
|
|
46
|
+
* const cache = new TrackCache({ maxMegabytes: 64 });
|
|
47
|
+
* const track = await cache.load('music/town.mid', () => decode('music/town.mid'));
|
|
48
|
+
* console.log(cache.stats().bytes, track?.buffer.duration);
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export declare class TrackCache {
|
|
52
|
+
private readonly entries;
|
|
53
|
+
private readonly policy;
|
|
54
|
+
private hits;
|
|
55
|
+
private misses;
|
|
56
|
+
private evictions;
|
|
57
|
+
constructor(policy?: BusBudgetPolicy);
|
|
58
|
+
/** the cached track for a key, or the one `make` produces; concurrent calls share one `make` */
|
|
59
|
+
load(key: string, make: () => Promise<LoadedTrack | null>): Promise<LoadedTrack | null>;
|
|
60
|
+
/** forgets one track; returns whether it was cached */
|
|
61
|
+
evict(key: string): boolean;
|
|
62
|
+
clear(): void;
|
|
63
|
+
stats(): TrackCacheStats;
|
|
64
|
+
/** drops the oldest tracks until the caps hold, never the one just loaded: a single track bigger than the cap still plays */
|
|
65
|
+
private enforce;
|
|
66
|
+
}
|
|
67
|
+
/** a `BusLoader` with the cache it reads through, so a game can show or reset its memory use */
|
|
68
|
+
export interface BudgetedLoader extends BusLoader {
|
|
69
|
+
readonly cache: TrackCache;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Wraps any `BusLoader` in a `TrackCache`: the bus keeps asking by kind and name, and the
|
|
73
|
+
* cache decides what stays in memory. The key includes the kind, since a jingle and a theme
|
|
74
|
+
* may share a name.
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```ts
|
|
78
|
+
* import { AudioBus, createBudgetedLoader, type BusLoader } from '@datamoc/mw_games/audio';
|
|
79
|
+
*
|
|
80
|
+
* declare const context: AudioContext;
|
|
81
|
+
* declare const decode: BusLoader;
|
|
82
|
+
*
|
|
83
|
+
* const load = createBudgetedLoader(decode, { maxMegabytes: 48, maxEntries: 12 });
|
|
84
|
+
* const bus = new AudioBus(context, { load });
|
|
85
|
+
* console.log(load.cache.stats());
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
export declare function createBudgetedLoader(inner: BusLoader, policy: BusBudgetPolicy): BudgetedLoader;
|
|
89
|
+
//# sourceMappingURL=BusBudget.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BusBudget.d.ts","sourceRoot":"","sources":["../../src/audio/BusBudget.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAA2B,SAAS,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACrF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC/B,qHAAqH;IACrH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oFAAoF;IACpF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iGAAiG;IACjG,MAAM,CAAC,EAAE,YAAY,CAAC;CACtB;AAED,MAAM,WAAW,eAAe;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,WAAW,EAAE,QAAQ,GAAG,kBAAkB,CAAC,GAAG,MAAM,CAE5F;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,UAAU;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA8E;IACtG,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;IACzC,OAAO,CAAC,IAAI,CAAK;IACjB,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,SAAS,CAAK;IAEtB,YAAY,MAAM,GAAE,eAAoB,EAEvC;IAED,gGAAgG;IAC1F,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAyB5F;IAED,uDAAuD;IACvD,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAE1B;IAED,KAAK,IAAI,IAAI,CAEZ;IAED,KAAK,IAAI,eAAe,CAIvB;IAED,6HAA6H;IAC7H,OAAO,CAAC,OAAO;CAWf;AAED,gGAAgG;AAChG,MAAM,WAAW,cAAe,SAAQ,SAAS;IAChD,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,cAAc,CAM9F"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory a decoded buffer holds: 32-bit samples on every channel.
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* ```ts
|
|
6
|
+
* import { bufferBytes } from '@datamoc/mw_games/audio';
|
|
7
|
+
*
|
|
8
|
+
* console.log(bufferBytes({ length: 44100, numberOfChannels: 2 })); // 352800, one stereo second
|
|
9
|
+
* ```
|
|
10
|
+
*/
|
|
11
|
+
export function bufferBytes(buffer) {
|
|
12
|
+
return buffer.length * buffer.numberOfChannels * 4;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* A least-recently-used cache of loaded tracks under a `BusBudgetPolicy`. A load in flight is
|
|
16
|
+
* shared by everyone who asks for the same key, a failure or a `null` answer is not remembered
|
|
17
|
+
* so the next request retries, and a track that is currently playing survives its own eviction
|
|
18
|
+
* because the `Channel` holds the buffer, so evicting only means the next request decodes again.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```ts
|
|
22
|
+
* import { TrackCache, type LoadedTrack } from '@datamoc/mw_games/audio';
|
|
23
|
+
*
|
|
24
|
+
* declare function decode(path: string): Promise<LoadedTrack>;
|
|
25
|
+
*
|
|
26
|
+
* const cache = new TrackCache({ maxMegabytes: 64 });
|
|
27
|
+
* const track = await cache.load('music/town.mid', () => decode('music/town.mid'));
|
|
28
|
+
* console.log(cache.stats().bytes, track?.buffer.duration);
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export class TrackCache {
|
|
32
|
+
constructor(policy = {}) {
|
|
33
|
+
this.entries = new Map();
|
|
34
|
+
this.hits = 0;
|
|
35
|
+
this.misses = 0;
|
|
36
|
+
this.evictions = 0;
|
|
37
|
+
this.policy = policy;
|
|
38
|
+
}
|
|
39
|
+
/** the cached track for a key, or the one `make` produces; concurrent calls share one `make` */
|
|
40
|
+
async load(key, make) {
|
|
41
|
+
const hit = this.entries.get(key);
|
|
42
|
+
if (hit) {
|
|
43
|
+
this.hits++;
|
|
44
|
+
//re-inserting moves it to the most recently used end
|
|
45
|
+
this.entries.delete(key);
|
|
46
|
+
this.entries.set(key, hit);
|
|
47
|
+
return hit.promise;
|
|
48
|
+
}
|
|
49
|
+
this.misses++;
|
|
50
|
+
const entry = { promise: make(), bytes: 0 };
|
|
51
|
+
this.entries.set(key, entry);
|
|
52
|
+
try {
|
|
53
|
+
const track = await entry.promise;
|
|
54
|
+
if (!track) {
|
|
55
|
+
if (this.entries.get(key) === entry)
|
|
56
|
+
this.entries.delete(key);
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
entry.bytes = bufferBytes(track.buffer);
|
|
60
|
+
this.enforce(key);
|
|
61
|
+
return track;
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
if (this.entries.get(key) === entry)
|
|
65
|
+
this.entries.delete(key);
|
|
66
|
+
throw error;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/** forgets one track; returns whether it was cached */
|
|
70
|
+
evict(key) {
|
|
71
|
+
return this.entries.delete(key);
|
|
72
|
+
}
|
|
73
|
+
clear() {
|
|
74
|
+
this.entries.clear();
|
|
75
|
+
}
|
|
76
|
+
stats() {
|
|
77
|
+
let bytes = 0;
|
|
78
|
+
for (const entry of this.entries.values())
|
|
79
|
+
bytes += entry.bytes;
|
|
80
|
+
return { entries: this.entries.size, bytes, hits: this.hits, misses: this.misses, evictions: this.evictions };
|
|
81
|
+
}
|
|
82
|
+
/** drops the oldest tracks until the caps hold, never the one just loaded: a single track bigger than the cap still plays */
|
|
83
|
+
enforce(keep) {
|
|
84
|
+
const maxBytes = (this.policy.maxMegabytes ?? Infinity) * 1024 * 1024;
|
|
85
|
+
const maxEntries = this.policy.maxEntries ?? Infinity;
|
|
86
|
+
for (const key of this.entries.keys()) {
|
|
87
|
+
const { bytes, entries } = this.stats();
|
|
88
|
+
if (bytes <= maxBytes && entries <= maxEntries)
|
|
89
|
+
return;
|
|
90
|
+
if (key === keep)
|
|
91
|
+
continue;
|
|
92
|
+
this.entries.delete(key);
|
|
93
|
+
this.evictions++;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Wraps any `BusLoader` in a `TrackCache`: the bus keeps asking by kind and name, and the
|
|
99
|
+
* cache decides what stays in memory. The key includes the kind, since a jingle and a theme
|
|
100
|
+
* may share a name.
|
|
101
|
+
*
|
|
102
|
+
* @example
|
|
103
|
+
* ```ts
|
|
104
|
+
* import { AudioBus, createBudgetedLoader, type BusLoader } from '@datamoc/mw_games/audio';
|
|
105
|
+
*
|
|
106
|
+
* declare const context: AudioContext;
|
|
107
|
+
* declare const decode: BusLoader;
|
|
108
|
+
*
|
|
109
|
+
* const load = createBudgetedLoader(decode, { maxMegabytes: 48, maxEntries: 12 });
|
|
110
|
+
* const bus = new AudioBus(context, { load });
|
|
111
|
+
* console.log(load.cache.stats());
|
|
112
|
+
* ```
|
|
113
|
+
*/
|
|
114
|
+
export function createBudgetedLoader(inner, policy) {
|
|
115
|
+
const cache = new TrackCache(policy);
|
|
116
|
+
const loader = ((kind, name, context) => cache.load(`${kind}:${name}`, () => inner(kind, name, context)));
|
|
117
|
+
Object.defineProperty(loader, 'cache', { value: cache, enumerable: true });
|
|
118
|
+
return loader;
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=BusBudget.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BusBudget.js","sourceRoot":"","sources":["../../src/audio/BusBudget.ts"],"names":[],"mappings":"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"}
|
package/dist/audio/Channels.d.ts
CHANGED
|
@@ -11,6 +11,9 @@
|
|
|
11
11
|
* for the bus, a `load` function turning a kind and a name into a decoded buffer.
|
|
12
12
|
* Tests hand in fakes for both, the same way `Sound` and `Music` take `create()`.
|
|
13
13
|
*/
|
|
14
|
+
import { Signal } from '../core/Signal.ts';
|
|
15
|
+
import type { SfxArbiter } from './Sfx.ts';
|
|
16
|
+
import { StreamChannel, type BlockSource } from './StreamChannel.ts';
|
|
14
17
|
/** seconds within a buffer: the region a looping track repeats */
|
|
15
18
|
export interface LoopRegion {
|
|
16
19
|
start: number;
|
|
@@ -101,6 +104,14 @@ export interface BusTrack {
|
|
|
101
104
|
pitch?: number;
|
|
102
105
|
pan?: number;
|
|
103
106
|
pos?: number;
|
|
107
|
+
/** identity of the content behind a synthesised track, `id@version#sha256`, so a save replays the same bytes or says it cannot */
|
|
108
|
+
contentId?: string;
|
|
109
|
+
/** the engine that voiced it (`'retro:mt32'`), so a restore picks the same one when it can */
|
|
110
|
+
engine?: string;
|
|
111
|
+
/** playhead in source frames, exact where `pos` in seconds is not; a restore skips to it */
|
|
112
|
+
frame?: number;
|
|
113
|
+
/** for `playSe` only: asks the shared `SfxArbiter` for a voice at this priority; 0 when omitted */
|
|
114
|
+
priority?: number;
|
|
104
115
|
}
|
|
105
116
|
/** a resolved track request: every parameter filled in, ready to store or restore */
|
|
106
117
|
export interface SavedBusTrack {
|
|
@@ -109,14 +120,44 @@ export interface SavedBusTrack {
|
|
|
109
120
|
pitch: number;
|
|
110
121
|
pan: number;
|
|
111
122
|
pos: number;
|
|
123
|
+
contentId?: string;
|
|
124
|
+
engine?: string;
|
|
125
|
+
frame?: number;
|
|
112
126
|
}
|
|
113
127
|
/** a decoded track: its buffer plus the region it repeats, if any */
|
|
114
128
|
export interface LoadedTrack {
|
|
115
129
|
buffer: AudioBuffer;
|
|
116
130
|
loop?: LoopRegion | null;
|
|
117
131
|
}
|
|
132
|
+
/** what a loader may use while it works: a signal that says the request was replaced, and a way to report how far along it is */
|
|
133
|
+
export interface BusLoadContext {
|
|
134
|
+
/** aborted when a newer request for the same kind replaces this one, so a long render can stop early */
|
|
135
|
+
signal: AbortSignal;
|
|
136
|
+
/** reports progress from 0 to 1; `AudioBus.onLoadProgress` forwards it */
|
|
137
|
+
progress(fraction: number): void;
|
|
138
|
+
/** the request being loaded, including the content id, engine and frame a restored save carries */
|
|
139
|
+
track: SavedBusTrack;
|
|
140
|
+
}
|
|
118
141
|
/** turns a kind and a name into a decoded buffer, or null when it cannot */
|
|
119
|
-
export type BusLoader = (kind: BusKind, name: string) => Promise<LoadedTrack | null>;
|
|
142
|
+
export type BusLoader = (kind: BusKind, name: string, context?: BusLoadContext) => Promise<LoadedTrack | null>;
|
|
143
|
+
/** a track played by pulling frames instead of holding a decoded buffer */
|
|
144
|
+
export interface StreamedTrack {
|
|
145
|
+
source: BlockSource;
|
|
146
|
+
/** region the repeat wraps inside, in seconds; the whole source when omitted */
|
|
147
|
+
loop?: LoopRegion | null;
|
|
148
|
+
/** stop an endless source after this many seconds, fading out over `endFadeSeconds` (2 when omitted) */
|
|
149
|
+
endAfterSeconds?: number;
|
|
150
|
+
endFadeSeconds?: number;
|
|
151
|
+
}
|
|
152
|
+
/** turns a kind and a name into a streamed source, or null to let the buffer loader answer instead */
|
|
153
|
+
export type StreamLoader = (kind: 'bgm' | 'bgs', name: string, context: BusLoadContext) => Promise<StreamedTrack | null>;
|
|
154
|
+
/** how far a track's load has got */
|
|
155
|
+
export interface BusLoadProgress {
|
|
156
|
+
kind: BusKind;
|
|
157
|
+
name: string;
|
|
158
|
+
/** 0 to 1 */
|
|
159
|
+
fraction: number;
|
|
160
|
+
}
|
|
120
161
|
/** plain-data bus state for saves and transfers: tracks plus memorized ones */
|
|
121
162
|
export interface BusSnapshot {
|
|
122
163
|
bgm: SavedBusTrack | null;
|
|
@@ -132,7 +173,15 @@ export interface BusMixerLevel {
|
|
|
132
173
|
}
|
|
133
174
|
export interface AudioBusOptions {
|
|
134
175
|
destination?: AudioNode;
|
|
176
|
+
/** Defaults to embedded asset loading, including worker-rendered MIDI; customize with `createAudioLoader`. */
|
|
135
177
|
load?: BusLoader;
|
|
178
|
+
/**
|
|
179
|
+
* asked first for BGM and BGS: a source it returns plays through a `StreamChannel`, so a long
|
|
180
|
+
* or endless track never becomes a whole `AudioBuffer`; null falls through to `load`
|
|
181
|
+
*/
|
|
182
|
+
stream?: StreamLoader;
|
|
183
|
+
/** the voice limit shared with `SfxSound`s: `playSe` asks it for a slot at `BusTrack.priority` */
|
|
184
|
+
arbiter?: SfxArbiter;
|
|
136
185
|
}
|
|
137
186
|
/**
|
|
138
187
|
* The four audio lifetimes of a role-playing game over two `Channel` voices: BGM and
|
|
@@ -155,6 +204,12 @@ export declare class AudioBus {
|
|
|
155
204
|
private readonly context;
|
|
156
205
|
private readonly destination;
|
|
157
206
|
private readonly load;
|
|
207
|
+
private readonly streamLoader;
|
|
208
|
+
private readonly arbiter;
|
|
209
|
+
private readonly streams;
|
|
210
|
+
private readonly aborts;
|
|
211
|
+
/** told as a loader reports progress, for a loading bar over a long render */
|
|
212
|
+
readonly onLoadProgress: Signal<BusLoadProgress>;
|
|
158
213
|
private readonly bgmChannel;
|
|
159
214
|
private readonly bgsChannel;
|
|
160
215
|
private readonly tracks;
|
|
@@ -167,6 +222,15 @@ export declare class AudioBus {
|
|
|
167
222
|
private readonly mixerLevels;
|
|
168
223
|
private readonly kindGains;
|
|
169
224
|
constructor(context: AudioContext, options?: AudioBusOptions);
|
|
225
|
+
/** the streaming voice of a loop kind, for underrun reports and its own controls */
|
|
226
|
+
streamChannel(kind: 'bgm' | 'bgs'): StreamChannel;
|
|
227
|
+
/** a newer request, or a stop, replaces whatever a loop kind is still loading */
|
|
228
|
+
private cancelLoad;
|
|
229
|
+
private stopLoop;
|
|
230
|
+
private loopPlaying;
|
|
231
|
+
private loopPosition;
|
|
232
|
+
/** a stream's playhead in source frames, undefined for a buffered track which has only seconds */
|
|
233
|
+
private loopFrame;
|
|
170
234
|
/**
|
|
171
235
|
* Sets a kind's own volume (0 to 1) and mute, applied on top of every track's volume
|
|
172
236
|
* and to sounds already playing. Tracks keep the level the game asked for, so
|
|
@@ -203,6 +267,7 @@ export declare class AudioBus {
|
|
|
203
267
|
stopMe(resume?: boolean): void;
|
|
204
268
|
/** plays one overlapping sound effect */
|
|
205
269
|
playSe(track: BusTrack): Promise<void>;
|
|
270
|
+
private cutSe;
|
|
206
271
|
stopSe(): void;
|
|
207
272
|
stopAll(): void;
|
|
208
273
|
/** plain-data bus state for saves and transfers */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Channels.d.ts","sourceRoot":"","sources":["../../src/audio/Channels.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,kEAAkE;AAClE,MAAM,WAAW,UAAU;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,kBAAkB;IAClC,oBAAoB;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,6DAA6D;IAC7D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,8BAA8B;IAC9B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,sDAAsD;IACtD,IAAI,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IACzB,yDAAyD;IACzD,MAAM,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,8EAA8E;AAC9E,MAAM,WAAW,YAAY;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACZ;AA8BD;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,OAAO;IACnB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;IACvC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAY;IACxC,OAAO,CAAC,MAAM,CAAsC;IACpD,OAAO,CAAC,QAAQ,CAAyB;IACzC,OAAO,CAAC,UAAU,CAAiC;IACnD,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,MAAM,CAAmC;IACjD,OAAO,CAAC,UAAU,CAA2B;IAC7C,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,MAAM,CAAK;IAEnB,YAAY,OAAO,EAAE,YAAY,EAAE,WAAW,CAAC,EAAE,SAAS,EAGzD;IAED,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED,+EAA+E;IAC/E,IAAI,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,GAAE,kBAAuB,GAAG,IAAI,CA6BhE;IAED,8DAA8D;IAC9D,MAAM,CAAC,MAAM,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAStE;IAED,yEAAyE;IACzE,IAAI,CAAC,WAAW,SAAI,GAAG,IAAI,CAoB1B;IAED,gFAAgF;IAChF,QAAQ,IAAI,MAAM,CAUjB;IAED,6DAA6D;IAC7D,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAEtB;IAED,yEAAyE;IACzE,KAAK,IAAI,YAAY,CAEpB;IAED,mFAAmF;IACnF,OAAO,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,CAejC;IAED,OAAO,CAAC,UAAU;CAMlB;AAED,MAAM,MAAM,OAAO,GAAG,KAAK,GAAG,KAAK,GAAG,IAAI,GAAG,IAAI,CAAC;AAElD;;;GAGG;AACH,MAAM,WAAW,QAAQ;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"Channels.d.ts","sourceRoot":"","sources":["../../src/audio/Channels.ts"],"names":[],"mappings":"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"}
|