@datamoc/mw_games 0.43.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 +67 -0
- package/README.md +22 -0
- package/REFERENCE.md +82 -6
- package/api-surface.json +1028 -2
- 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 +7 -2
- package/dist/audio/AudioLoader.d.ts.map +1 -1
- package/dist/audio/AudioLoader.js +23 -18
- package/dist/audio/AudioLoader.js.map +1 -1
- 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 +65 -1
- package/dist/audio/Channels.d.ts.map +1 -1
- package/dist/audio/Channels.js +117 -30
- 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 +31 -0
- package/dist/audio/MidiRender.d.ts.map +1 -1
- package/dist/audio/MidiRender.js +79 -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/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/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/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/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 +38 -6
- package/dist/audio/index.d.ts.map +1 -1
- package/dist/audio/index.js +19 -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 +11 -0
- package/dist/mwl/index.d.ts.map +1 -1
- package/dist/mwl/index.js +6 -0
- package/dist/mwl/index.js.map +1 -1
- 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/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.map +1 -1
- package/dist/physics/XpbdWorld.js +2 -1
- 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 +2 -0
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +1 -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/two-d/Game.d.ts +13 -2
- package/dist/two-d/Game.d.ts.map +1 -1
- package/dist/two-d/Game.js +42 -18
- package/dist/two-d/Game.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 +29 -0
- package/dist/two-d/render/SceneTransition.d.ts.map +1 -1
- package/dist/two-d/render/SceneTransition.js +27 -0
- package/dist/two-d/render/SceneTransition.js.map +1 -1
- 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 -2
- package/dist/two-d/render/index.d.ts.map +1 -1
- package/dist/two-d/render/index.js +1 -1
- 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/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 +15 -1
- package/dist/two-d/ui/DropdownView.d.ts.map +1 -1
- package/dist/two-d/ui/DropdownView.js +21 -3
- 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 +6 -0
- package/dist/two-d/ui/ScrollBox.d.ts.map +1 -1
- package/dist/two-d/ui/ScrollBox.js +12 -1
- package/dist/two-d/ui/ScrollBox.js.map +1 -1
- package/dist/two-d/ui/ScrollText.d.ts +11 -2
- package/dist/two-d/ui/ScrollText.d.ts.map +1 -1
- package/dist/two-d/ui/ScrollText.js +18 -2
- package/dist/two-d/ui/ScrollText.js.map +1 -1
- 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/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +8 -1
- package/sbom.cdx.json +6 -6
- package/tools/audio.d.mts +75 -0
- package/tools/audio.mjs +437 -0
- package/tools/mwl.mjs +144 -2
- package/tools.md +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Resource.d.ts","sourceRoot":"","sources":["../../src/actors/Resource.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,WAAW,YAAY;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CACf;AAoBD,yFAAyF;AACzF,wBAAgB,SAAS,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,YAAY,GAAG,SAAS,YAAY,EAAE,GAAG,OAAO,CAEjG;AAED;;;;;GAKG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,YAAY,GAAG,SAAS,YAAY,EAAE,GAAG,OAAO,
|
|
1
|
+
{"version":3,"file":"Resource.d.ts","sourceRoot":"","sources":["../../src/actors/Resource.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,WAAW,YAAY;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CACf;AAoBD,yFAAyF;AACzF,wBAAgB,SAAS,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,YAAY,GAAG,SAAS,YAAY,EAAE,GAAG,OAAO,CAEjG;AAED;;;;;GAKG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,YAAY,GAAG,SAAS,YAAY,EAAE,GAAG,OAAO,CAI7F;AAED;;;;;GAKG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,YAAY,GAAG,SAAS,YAAY,EAAE,EAAE,QAAQ,SAAI,GAAG,IAAI,CAEzG;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAG7G"}
|
package/dist/actors/Resource.js
CHANGED
|
@@ -26,10 +26,9 @@ export function canAfford(stats, cost) {
|
|
|
26
26
|
* this returns false. A zero cost is always affordable and deducts nothing.
|
|
27
27
|
*/
|
|
28
28
|
export function spend(stats, cost) {
|
|
29
|
-
|
|
30
|
-
if (![...combined].every(([stat, amount]) => stats.base(stat) >= amount))
|
|
29
|
+
if (!canAfford(stats, cost))
|
|
31
30
|
return false;
|
|
32
|
-
for (const [stat, amount] of
|
|
31
|
+
for (const [stat, amount] of totals(all(cost)))
|
|
33
32
|
stats.setBase(stat, stats.base(stat) - amount);
|
|
34
33
|
return true;
|
|
35
34
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Resource.js","sourceRoot":"","sources":["../../src/actors/Resource.ts"],"names":[],"mappings":"AA8BA,SAAS,GAAG,CAAC,IAA4C;IACxD,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACjD,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QACtB,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAChD,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC,IAAI,WAAW,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;QACjG,CAAC;IACF,CAAC;IACD,OAAO,IAAI,CAAC;AACb,CAAC;AAED,qFAAqF;AACrF,qFAAqF;AACrF,SAAS,MAAM,CAAC,IAA6B;IAC5C,MAAM,GAAG,GAAG,IAAI,GAAG,EAAkB,CAAC;IACtC,KAAK,MAAM,CAAC,IAAI,IAAI;QAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC;IACzE,OAAO,GAAG,CAAC;AACZ,CAAC;AAED,yFAAyF;AACzF,MAAM,UAAU,SAAS,CAAC,KAAgB,EAAE,IAA4C;IACvF,OAAO,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,CAAC;AACrF,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,KAAK,CAAC,KAAgB,EAAE,IAA4C;IACnF,
|
|
1
|
+
{"version":3,"file":"Resource.js","sourceRoot":"","sources":["../../src/actors/Resource.ts"],"names":[],"mappings":"AA8BA,SAAS,GAAG,CAAC,IAA4C;IACxD,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACjD,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QACtB,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAChD,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC,IAAI,WAAW,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;QACjG,CAAC;IACF,CAAC;IACD,OAAO,IAAI,CAAC;AACb,CAAC;AAED,qFAAqF;AACrF,qFAAqF;AACrF,SAAS,MAAM,CAAC,IAA6B;IAC5C,MAAM,GAAG,GAAG,IAAI,GAAG,EAAkB,CAAC;IACtC,KAAK,MAAM,CAAC,IAAI,IAAI;QAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC;IACzE,OAAO,GAAG,CAAC;AACZ,CAAC;AAED,yFAAyF;AACzF,MAAM,UAAU,SAAS,CAAC,KAAgB,EAAE,IAA4C;IACvF,OAAO,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,CAAC;AACrF,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,KAAK,CAAC,KAAgB,EAAE,IAA4C;IACnF,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IAC1C,KAAK,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAAE,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,CAAC;IAC/F,OAAO,IAAI,CAAC;AACb,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,MAAM,CAAC,KAAgB,EAAE,IAA4C,EAAE,QAAQ,GAAG,CAAC;IAClG,KAAK,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAAE,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,MAAM,GAAG,QAAQ,CAAC,CAAC;AAC3G,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAgB,EAAE,IAAkB,EAAE,OAAgB,EAAE,IAAY;IACpG,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC;QAAE,OAAO,CAAC,CAAC;IAClC,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;AACvD,CAAC"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type { LoopRegion } from './Channels.ts';
|
|
2
|
+
/** a set of stems that line up: same length, same rate, so they can be mixed and swapped in step */
|
|
3
|
+
export type StemSet = Readonly<Record<string, AudioBuffer>>;
|
|
4
|
+
export interface AdaptiveMusicOptions {
|
|
5
|
+
destination?: AudioNode;
|
|
6
|
+
/** seconds of fade for a level change or a version switch when the call gives none; 1 when omitted */
|
|
7
|
+
fadeSeconds?: number;
|
|
8
|
+
}
|
|
9
|
+
export interface AdaptiveLoadOptions {
|
|
10
|
+
/** names a group of stems so one call sets them all: `{ combat: ['drums', 'brass'] }` */
|
|
11
|
+
groups?: Readonly<Record<string, readonly string[]>>;
|
|
12
|
+
/** the region the whole set repeats; the whole buffer when omitted */
|
|
13
|
+
loop?: LoopRegion | null;
|
|
14
|
+
}
|
|
15
|
+
export interface AdaptivePlayOptions {
|
|
16
|
+
/** the version to start with; the first one loaded when omitted */
|
|
17
|
+
version?: string;
|
|
18
|
+
/** start offset in seconds */
|
|
19
|
+
pos?: number;
|
|
20
|
+
/** starting level of each stem or group, 0 to 1; a stem not named starts at 0 */
|
|
21
|
+
levels?: Readonly<Record<string, number>>;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Adaptive music from stems that play in lockstep: every stem of a version starts on the same
|
|
25
|
+
* clock tick at the same offset, each through its own gain, so raising or lowering a stem (or a
|
|
26
|
+
* named group of them) with a fade changes the intensity without changing the file or losing the
|
|
27
|
+
* beat. Several versions of the arrangement can be loaded; switching between them crossfades at
|
|
28
|
+
* the same position, counted in frames, so a calm version and a combat version stay in step. Stems
|
|
29
|
+
* come from `renderMidiStems` or from separately recorded layers; all stems of a version must have
|
|
30
|
+
* the same length and sample rate, and versions must agree on the sample rate.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```ts
|
|
34
|
+
* import { AdaptiveMusic, renderMidiStems, parseMidi, toAudioBuffer } from '@datamoc/mw_games/audio';
|
|
35
|
+
*
|
|
36
|
+
* declare const context: AudioContext;
|
|
37
|
+
* declare const midiBytes: ArrayBuffer;
|
|
38
|
+
*
|
|
39
|
+
* const rendered = renderMidiStems(parseMidi(midiBytes), { rhythm: [9], melody: [0], pads: [1] });
|
|
40
|
+
* const stems = Object.fromEntries(Object.entries(rendered).map(([name, r]) => [name, toAudioBuffer(context, r)]));
|
|
41
|
+
*
|
|
42
|
+
* const music = new AdaptiveMusic(context);
|
|
43
|
+
* music.load('calm', stems, { groups: { intensity: ['rhythm', 'melody'] } });
|
|
44
|
+
* music.play({ levels: { pads: 1 } });
|
|
45
|
+
* music.setLevel('intensity', 1, 2); // fade the fight in over two seconds
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export declare class AdaptiveMusic {
|
|
49
|
+
private readonly context;
|
|
50
|
+
private readonly destination;
|
|
51
|
+
private readonly defaultFade;
|
|
52
|
+
private readonly versions;
|
|
53
|
+
private running;
|
|
54
|
+
private startedAt;
|
|
55
|
+
private offsetFrames;
|
|
56
|
+
private levels_;
|
|
57
|
+
constructor(context: AudioContext, options?: AdaptiveMusicOptions);
|
|
58
|
+
get isPlaying(): boolean;
|
|
59
|
+
/** the version that sounds now, or null */
|
|
60
|
+
get version(): string | null;
|
|
61
|
+
/** loads one arrangement under a name; throws when its stems do not line up */
|
|
62
|
+
load(name: string, stems: StemSet, options?: AdaptiveLoadOptions): void;
|
|
63
|
+
/** starts the set from the beginning, or from `pos` */
|
|
64
|
+
play(options?: AdaptivePlayOptions): void;
|
|
65
|
+
/** sets a stem's or group's level (0 to 1), fading over `fadeSeconds` */
|
|
66
|
+
setLevel(target: string, level: number, fadeSeconds?: number): void;
|
|
67
|
+
/** the level each stem is heading to */
|
|
68
|
+
levels(): Record<string, number>;
|
|
69
|
+
/** frame position inside the buffers, wrapping inside the loop region */
|
|
70
|
+
positionFrames(): number;
|
|
71
|
+
position(): number;
|
|
72
|
+
/**
|
|
73
|
+
* Crossfades to another loaded version at the position the current one has reached, in
|
|
74
|
+
* frames, so the beat carries over. Levels carry over too: a stem or group of the same name
|
|
75
|
+
* keeps the level it had.
|
|
76
|
+
*/
|
|
77
|
+
switchVersion(name: string, fadeSeconds?: number): void;
|
|
78
|
+
/** stops every stem, fading over `fadeSeconds` first when positive; the position is forgotten */
|
|
79
|
+
stop(fadeSeconds?: number): void;
|
|
80
|
+
private startVersion;
|
|
81
|
+
private membersOf;
|
|
82
|
+
private ramp;
|
|
83
|
+
private stopAt;
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=AdaptiveMusic.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdaptiveMusic.d.ts","sourceRoot":"","sources":["../../src/audio/AdaptiveMusic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD,oGAAoG;AACpG,MAAM,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;AAE5D,MAAM,WAAW,oBAAoB;IACpC,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,sGAAsG;IACtG,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,mBAAmB;IACnC,yFAAyF;IACzF,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC,CAAC;IACrD,sEAAsE;IACtE,IAAI,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;CACzB;AAED,MAAM,WAAW,mBAAmB;IACnC,mEAAmE;IACnE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,8BAA8B;IAC9B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,iFAAiF;IACjF,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAC1C;AAqBD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,qBAAa,aAAa;IACzB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;IACvC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAY;IACxC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA8B;IACvD,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,OAAO,CAA8B;IAE7C,YAAY,OAAO,EAAE,YAAY,EAAE,OAAO,GAAE,oBAAyB,EAIpE;IAED,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED,2CAA2C;IAC3C,IAAI,OAAO,IAAI,MAAM,GAAG,IAAI,CAE3B;IAED,+EAA+E;IAC/E,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,GAAE,mBAAwB,GAAG,IAAI,CA8B1E;IAED,uDAAuD;IACvD,IAAI,CAAC,OAAO,GAAE,mBAAwB,GAAG,IAAI,CAU5C;IAED,yEAAyE;IACzE,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAYlE;IAED,wCAAwC;IACxC,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAE/B;IAED,yEAAyE;IACzE,cAAc,IAAI,MAAM,CASvB;IAED,QAAQ,IAAI,MAAM,CAGjB;IAED;;;;OAIG;IACH,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAetD;IAED,iGAAiG;IACjG,IAAI,CAAC,WAAW,SAAI,GAAG,IAAI,CAS1B;IAED,OAAO,CAAC,YAAY;IAyCpB,OAAO,CAAC,SAAS;IAOjB,OAAO,CAAC,IAAI;IAWZ,OAAO,CAAC,MAAM;CAOd"}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adaptive music from stems that play in lockstep: every stem of a version starts on the same
|
|
3
|
+
* clock tick at the same offset, each through its own gain, so raising or lowering a stem (or a
|
|
4
|
+
* named group of them) with a fade changes the intensity without changing the file or losing the
|
|
5
|
+
* beat. Several versions of the arrangement can be loaded; switching between them crossfades at
|
|
6
|
+
* the same position, counted in frames, so a calm version and a combat version stay in step. Stems
|
|
7
|
+
* come from `renderMidiStems` or from separately recorded layers; all stems of a version must have
|
|
8
|
+
* the same length and sample rate, and versions must agree on the sample rate.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* import { AdaptiveMusic, renderMidiStems, parseMidi, toAudioBuffer } from '@datamoc/mw_games/audio';
|
|
13
|
+
*
|
|
14
|
+
* declare const context: AudioContext;
|
|
15
|
+
* declare const midiBytes: ArrayBuffer;
|
|
16
|
+
*
|
|
17
|
+
* const rendered = renderMidiStems(parseMidi(midiBytes), { rhythm: [9], melody: [0], pads: [1] });
|
|
18
|
+
* const stems = Object.fromEntries(Object.entries(rendered).map(([name, r]) => [name, toAudioBuffer(context, r)]));
|
|
19
|
+
*
|
|
20
|
+
* const music = new AdaptiveMusic(context);
|
|
21
|
+
* music.load('calm', stems, { groups: { intensity: ['rhythm', 'melody'] } });
|
|
22
|
+
* music.play({ levels: { pads: 1 } });
|
|
23
|
+
* music.setLevel('intensity', 1, 2); // fade the fight in over two seconds
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export class AdaptiveMusic {
|
|
27
|
+
constructor(context, options = {}) {
|
|
28
|
+
this.versions = new Map();
|
|
29
|
+
this.running = null;
|
|
30
|
+
this.startedAt = 0;
|
|
31
|
+
this.offsetFrames = 0;
|
|
32
|
+
this.levels_ = {};
|
|
33
|
+
this.context = context;
|
|
34
|
+
this.destination = options.destination ?? context.destination;
|
|
35
|
+
this.defaultFade = Math.max(0, options.fadeSeconds ?? 1);
|
|
36
|
+
}
|
|
37
|
+
get isPlaying() {
|
|
38
|
+
return this.running !== null;
|
|
39
|
+
}
|
|
40
|
+
/** the version that sounds now, or null */
|
|
41
|
+
get version() {
|
|
42
|
+
return this.running?.version ?? null;
|
|
43
|
+
}
|
|
44
|
+
/** loads one arrangement under a name; throws when its stems do not line up */
|
|
45
|
+
load(name, stems, options = {}) {
|
|
46
|
+
const names = Object.keys(stems);
|
|
47
|
+
if (names.length === 0)
|
|
48
|
+
throw new Error(`adaptive version "${name}" has no stems`);
|
|
49
|
+
const first = stems[names[0]];
|
|
50
|
+
for (const stem of names) {
|
|
51
|
+
const buffer = stems[stem];
|
|
52
|
+
if (buffer.length !== first.length || buffer.sampleRate !== first.sampleRate) {
|
|
53
|
+
throw new Error(`stem "${stem}" of "${name}" differs in length or sample rate from "${names[0]}"`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
const other = [...this.versions.values()][0];
|
|
57
|
+
if (other && other.sampleRate !== first.sampleRate) {
|
|
58
|
+
throw new Error(`version "${name}" is at ${first.sampleRate} Hz but the others are at ${other.sampleRate} Hz`);
|
|
59
|
+
}
|
|
60
|
+
const groups = options.groups ?? {};
|
|
61
|
+
for (const [group, members] of Object.entries(groups)) {
|
|
62
|
+
const missing = members.find((member) => !(member in stems));
|
|
63
|
+
if (missing !== undefined)
|
|
64
|
+
throw new Error(`group "${group}" names stem "${missing}", which "${name}" lacks`);
|
|
65
|
+
if (group in stems)
|
|
66
|
+
throw new Error(`group "${group}" has the name of a stem`);
|
|
67
|
+
}
|
|
68
|
+
this.versions.set(name, {
|
|
69
|
+
stems,
|
|
70
|
+
groups,
|
|
71
|
+
loop: options.loop ?? null,
|
|
72
|
+
frames: first.length,
|
|
73
|
+
sampleRate: first.sampleRate,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
/** starts the set from the beginning, or from `pos` */
|
|
77
|
+
play(options = {}) {
|
|
78
|
+
this.stop();
|
|
79
|
+
const name = options.version ?? [...this.versions.keys()][0];
|
|
80
|
+
const version = name === undefined ? undefined : this.versions.get(name);
|
|
81
|
+
if (!version || name === undefined)
|
|
82
|
+
throw new Error(`no adaptive version "${options.version ?? ''}" is loaded`);
|
|
83
|
+
this.levels_ = {};
|
|
84
|
+
const offset = Math.min(Math.max(0, Math.floor((options.pos ?? 0) * version.sampleRate)), version.frames - 1);
|
|
85
|
+
this.offsetFrames = offset;
|
|
86
|
+
this.startedAt = this.context.currentTime;
|
|
87
|
+
this.running = this.startVersion(name, version, offset, options.levels ?? {}, 0);
|
|
88
|
+
}
|
|
89
|
+
/** sets a stem's or group's level (0 to 1), fading over `fadeSeconds` */
|
|
90
|
+
setLevel(target, level, fadeSeconds) {
|
|
91
|
+
const running = this.running;
|
|
92
|
+
if (!running)
|
|
93
|
+
throw new Error('adaptive music is not playing');
|
|
94
|
+
const version = this.versions.get(running.version);
|
|
95
|
+
const members = this.membersOf(version, target);
|
|
96
|
+
const value = Math.min(1, Math.max(0, level));
|
|
97
|
+
const fade = Math.max(0, fadeSeconds ?? this.defaultFade);
|
|
98
|
+
for (const member of members) {
|
|
99
|
+
this.levels_[member] = value;
|
|
100
|
+
const gain = running.voices.get(member)?.gain.gain;
|
|
101
|
+
if (gain)
|
|
102
|
+
this.ramp(gain, value, fade);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/** the level each stem is heading to */
|
|
106
|
+
levels() {
|
|
107
|
+
return { ...this.levels_ };
|
|
108
|
+
}
|
|
109
|
+
/** frame position inside the buffers, wrapping inside the loop region */
|
|
110
|
+
positionFrames() {
|
|
111
|
+
const running = this.running;
|
|
112
|
+
if (!running)
|
|
113
|
+
return 0;
|
|
114
|
+
const version = this.versions.get(running.version);
|
|
115
|
+
let frame = this.offsetFrames + Math.max(0, this.context.currentTime - this.startedAt) * version.sampleRate;
|
|
116
|
+
const start = version.loop ? Math.floor(version.loop.start * version.sampleRate) : 0;
|
|
117
|
+
const end = version.loop ? Math.floor(version.loop.end * version.sampleRate) : version.frames;
|
|
118
|
+
if (end > start && frame >= end)
|
|
119
|
+
frame = start + ((frame - start) % (end - start));
|
|
120
|
+
return Math.floor(frame);
|
|
121
|
+
}
|
|
122
|
+
position() {
|
|
123
|
+
const running = this.running;
|
|
124
|
+
return running ? this.positionFrames() / this.versions.get(running.version).sampleRate : 0;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Crossfades to another loaded version at the position the current one has reached, in
|
|
128
|
+
* frames, so the beat carries over. Levels carry over too: a stem or group of the same name
|
|
129
|
+
* keeps the level it had.
|
|
130
|
+
*/
|
|
131
|
+
switchVersion(name, fadeSeconds) {
|
|
132
|
+
const running = this.running;
|
|
133
|
+
if (!running)
|
|
134
|
+
throw new Error('adaptive music is not playing');
|
|
135
|
+
const next = this.versions.get(name);
|
|
136
|
+
if (!next)
|
|
137
|
+
throw new Error(`no adaptive version "${name}" is loaded`);
|
|
138
|
+
if (name === running.version)
|
|
139
|
+
return;
|
|
140
|
+
const fade = Math.max(0, fadeSeconds ?? this.defaultFade);
|
|
141
|
+
const frame = this.positionFrames();
|
|
142
|
+
const retired = running;
|
|
143
|
+
const now = this.context.currentTime;
|
|
144
|
+
this.ramp(retired.master.gain, 0, fade);
|
|
145
|
+
for (const { source } of retired.voices.values())
|
|
146
|
+
this.stopAt(source, now + fade + 0.05);
|
|
147
|
+
this.offsetFrames = Math.min(frame, next.frames - 1);
|
|
148
|
+
this.startedAt = now;
|
|
149
|
+
this.running = this.startVersion(name, next, this.offsetFrames, this.levels_, fade);
|
|
150
|
+
}
|
|
151
|
+
/** stops every stem, fading over `fadeSeconds` first when positive; the position is forgotten */
|
|
152
|
+
stop(fadeSeconds = 0) {
|
|
153
|
+
const running = this.running;
|
|
154
|
+
this.running = null;
|
|
155
|
+
this.levels_ = {};
|
|
156
|
+
if (!running)
|
|
157
|
+
return;
|
|
158
|
+
const now = this.context.currentTime;
|
|
159
|
+
if (fadeSeconds > 0)
|
|
160
|
+
this.ramp(running.master.gain, 0, fadeSeconds);
|
|
161
|
+
for (const { source } of running.voices.values())
|
|
162
|
+
this.stopAt(source, fadeSeconds > 0 ? now + fadeSeconds + 0.05 : undefined);
|
|
163
|
+
}
|
|
164
|
+
startVersion(name, version, offsetFrames, levels, fadeInSeconds) {
|
|
165
|
+
const master = this.context.createGain();
|
|
166
|
+
master.gain.value = fadeInSeconds > 0 ? 0 : 1;
|
|
167
|
+
master.connect(this.destination);
|
|
168
|
+
if (fadeInSeconds > 0)
|
|
169
|
+
this.ramp(master.gain, 1, fadeInSeconds);
|
|
170
|
+
const voices = new Map();
|
|
171
|
+
const when = this.context.currentTime;
|
|
172
|
+
const offset = offsetFrames / version.sampleRate;
|
|
173
|
+
//levels given by group name apply to every member; a stem named directly overrides its group
|
|
174
|
+
const resolved = {};
|
|
175
|
+
for (const [target, level] of Object.entries(levels)) {
|
|
176
|
+
if (target in version.groups)
|
|
177
|
+
for (const member of version.groups[target])
|
|
178
|
+
resolved[member] = level;
|
|
179
|
+
}
|
|
180
|
+
for (const [target, level] of Object.entries(levels))
|
|
181
|
+
if (target in version.stems)
|
|
182
|
+
resolved[target] = level;
|
|
183
|
+
for (const [stem, buffer] of Object.entries(version.stems)) {
|
|
184
|
+
const gain = this.context.createGain();
|
|
185
|
+
const level = Math.min(1, Math.max(0, resolved[stem] ?? 0));
|
|
186
|
+
gain.gain.value = level;
|
|
187
|
+
this.levels_[stem] = level;
|
|
188
|
+
gain.connect(master);
|
|
189
|
+
const source = this.context.createBufferSource();
|
|
190
|
+
source.buffer = buffer;
|
|
191
|
+
source.loop = true;
|
|
192
|
+
if (version.loop) {
|
|
193
|
+
source.loopStart = version.loop.start;
|
|
194
|
+
source.loopEnd = version.loop.end;
|
|
195
|
+
}
|
|
196
|
+
source.connect(gain);
|
|
197
|
+
//every stem on the same tick at the same offset is what keeps them in step
|
|
198
|
+
source.start(when, offset);
|
|
199
|
+
voices.set(stem, { source, gain });
|
|
200
|
+
}
|
|
201
|
+
return { version: name, voices, master };
|
|
202
|
+
}
|
|
203
|
+
membersOf(version, target) {
|
|
204
|
+
if (target in version.stems)
|
|
205
|
+
return [target];
|
|
206
|
+
const group = version.groups[target];
|
|
207
|
+
if (!group)
|
|
208
|
+
throw new Error(`"${target}" is neither a stem nor a group of "${this.running?.version}"`);
|
|
209
|
+
return group;
|
|
210
|
+
}
|
|
211
|
+
ramp(param, value, seconds) {
|
|
212
|
+
if (seconds <= 0) {
|
|
213
|
+
param.value = value;
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
const now = this.context.currentTime;
|
|
217
|
+
param.cancelScheduledValues(now);
|
|
218
|
+
param.setValueAtTime(param.value, now);
|
|
219
|
+
param.linearRampToValueAtTime(value, now + seconds);
|
|
220
|
+
}
|
|
221
|
+
stopAt(source, when) {
|
|
222
|
+
try {
|
|
223
|
+
source.stop(when);
|
|
224
|
+
}
|
|
225
|
+
catch {
|
|
226
|
+
//already stopped
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
//# sourceMappingURL=AdaptiveMusic.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdaptiveMusic.js","sourceRoot":"","sources":["../../src/audio/AdaptiveMusic.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type BusBudgetPolicy } from './BusBudget.ts';
|
|
1
2
|
import type { BusLoader } from './Channels.ts';
|
|
2
3
|
import { type RenderMidiAsyncOptions } from './MidiRender.ts';
|
|
3
4
|
export interface AudioLoaderOptions {
|
|
@@ -5,12 +6,16 @@ export interface AudioLoaderOptions {
|
|
|
5
6
|
midi?: RenderMidiAsyncOptions;
|
|
6
7
|
/** Reads embedded assets by default; inject a byte source for a custom archive or a test. */
|
|
7
8
|
read?: (path: string) => Promise<ArrayBuffer>;
|
|
9
|
+
/** keeps decoded tracks inside a memory budget, evicting the least recently used; every track stays cached when omitted */
|
|
10
|
+
budget?: BusBudgetPolicy;
|
|
8
11
|
}
|
|
9
12
|
/**
|
|
10
13
|
* One loader for `AudioBus` music, jingles and effects: MIDI is rendered on a worker,
|
|
11
14
|
* other formats use the browser's audio decoder. MIDI detection uses the file header,
|
|
12
|
-
* so an archive alias does not need a filename extension. Results are cached by path
|
|
13
|
-
*
|
|
15
|
+
* so an archive alias does not need a filename extension. Results are cached by path
|
|
16
|
+
* (under `budget` when one is given, which also caps and shrinks rendered MIDI); a failed
|
|
17
|
+
* load can be retried. A load reports 0, 0.5 and 1 through the bus's progress context, and
|
|
18
|
+
* skips its render when the request was replaced before the bytes arrived. Returned buffers can also be used by a `MusicPlayer`.
|
|
14
19
|
*
|
|
15
20
|
* @example
|
|
16
21
|
* ```ts
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AudioLoader.d.ts","sourceRoot":"","sources":["../../src/audio/AudioLoader.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAe,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"AudioLoader.d.ts","sourceRoot":"","sources":["../../src/audio/AudioLoader.ts"],"names":[],"mappings":"AACA,OAAO,EAAc,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAClE,OAAO,KAAK,EAAkB,SAAS,EAAe,MAAM,eAAe,CAAC;AAC5E,OAAO,EAA0C,KAAK,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAGtG,MAAM,WAAW,kBAAkB;IAClC,mEAAmE;IACnE,IAAI,CAAC,EAAE,sBAAsB,CAAC;IAC9B,6FAA6F;IAC7F,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;IAC9C,2HAA2H;IAC3H,MAAM,CAAC,EAAE,eAAe,CAAC;CACzB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,gBAAgB,EAAE,OAAO,GAAE,kBAAuB,GAAG,SAAS,CAyBxG"}
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import { getBinary, loadBinary } from '../assets/binary.js';
|
|
2
|
+
import { TrackCache } from './BusBudget.js';
|
|
2
3
|
import { renderMidiToBufferAsync, toAudioBuffer } from './MidiRender.js';
|
|
4
|
+
import { fitToBudget } from './Resample.js';
|
|
3
5
|
/**
|
|
4
6
|
* One loader for `AudioBus` music, jingles and effects: MIDI is rendered on a worker,
|
|
5
7
|
* other formats use the browser's audio decoder. MIDI detection uses the file header,
|
|
6
|
-
* so an archive alias does not need a filename extension. Results are cached by path
|
|
7
|
-
*
|
|
8
|
+
* so an archive alias does not need a filename extension. Results are cached by path
|
|
9
|
+
* (under `budget` when one is given, which also caps and shrinks rendered MIDI); a failed
|
|
10
|
+
* load can be retried. A load reports 0, 0.5 and 1 through the bus's progress context, and
|
|
11
|
+
* skips its render when the request was replaced before the bytes arrived. Returned buffers can also be used by a `MusicPlayer`.
|
|
8
12
|
*
|
|
9
13
|
* @example
|
|
10
14
|
* ```ts
|
|
@@ -19,32 +23,33 @@ import { renderMidiToBufferAsync, toAudioBuffer } from './MidiRender.js';
|
|
|
19
23
|
* ```
|
|
20
24
|
*/
|
|
21
25
|
export function createAudioLoader(context, options = {}) {
|
|
22
|
-
const
|
|
26
|
+
const cache = new TrackCache(options.budget);
|
|
23
27
|
const read = options.read ?? readAsset;
|
|
24
|
-
async function decode(path) {
|
|
28
|
+
async function decode(path, loadContext) {
|
|
29
|
+
loadContext?.progress(0);
|
|
25
30
|
const bytes = await read(path);
|
|
31
|
+
if (loadContext?.signal.aborted)
|
|
32
|
+
return null;
|
|
33
|
+
loadContext?.progress(0.5);
|
|
26
34
|
const header = new Uint8Array(bytes, 0, Math.min(4, bytes.byteLength));
|
|
35
|
+
let loaded;
|
|
27
36
|
if (header[0] === 77 && header[1] === 84 && header[2] === 104 && header[3] === 100) {
|
|
28
|
-
|
|
29
|
-
|
|
37
|
+
let rendered = await renderMidiToBufferAsync(bytes, options.midi);
|
|
38
|
+
if (options.budget?.render)
|
|
39
|
+
rendered = fitToBudget(rendered, options.budget.render);
|
|
40
|
+
loaded = {
|
|
30
41
|
buffer: toAudioBuffer(context, rendered),
|
|
31
42
|
loop: { start: rendered.loopStart, end: rendered.loopEnd },
|
|
32
43
|
};
|
|
33
44
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
return (_kind, path) => {
|
|
38
|
-
let loaded = pending.get(path);
|
|
39
|
-
if (!loaded) {
|
|
40
|
-
loaded = decode(path).catch((error) => {
|
|
41
|
-
pending.delete(path);
|
|
42
|
-
throw error;
|
|
43
|
-
});
|
|
44
|
-
pending.set(path, loaded);
|
|
45
|
+
else {
|
|
46
|
+
// decodeAudioData can detach its input; the asset cache still owns the original bytes.
|
|
47
|
+
loaded = { buffer: await context.decodeAudioData(bytes.slice(0)) };
|
|
45
48
|
}
|
|
49
|
+
loadContext?.progress(1);
|
|
46
50
|
return loaded;
|
|
47
|
-
}
|
|
51
|
+
}
|
|
52
|
+
return (_kind, path, loadContext) => cache.load(path, () => decode(path, loadContext));
|
|
48
53
|
}
|
|
49
54
|
async function readAsset(path) {
|
|
50
55
|
await loadBinary([path]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AudioLoader.js","sourceRoot":"","sources":["../../src/audio/AudioLoader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"AudioLoader.js","sourceRoot":"","sources":["../../src/audio/AudioLoader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAwB,MAAM,gBAAgB,CAAC;AAElE,OAAO,EAAE,uBAAuB,EAAE,aAAa,EAA+B,MAAM,iBAAiB,CAAC;AACtG,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAW5C;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAyB,EAAE,OAAO,GAAuB,EAAE;IAC5F,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAC7C,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,SAAS,CAAC;IACvC,KAAK,UAAU,MAAM,CAAC,IAAY,EAAE,WAA4B;QAC/D,WAAW,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;QACzB,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,IAAI,WAAW,EAAE,MAAM,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC;QAC7C,WAAW,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC;QAC3B,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,KAAK,EAAE,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC;QACvE,IAAI,MAAmB,CAAC;QACxB,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;YACpF,IAAI,QAAQ,GAAG,MAAM,uBAAuB,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;YAClE,IAAI,OAAO,CAAC,MAAM,EAAE,MAAM;gBAAE,QAAQ,GAAG,WAAW,CAAC,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YACpF,MAAM,GAAG;gBACR,MAAM,EAAE,aAAa,CAAC,OAAO,EAAE,QAAQ,CAAC;gBACxC,IAAI,EAAE,EAAE,KAAK,EAAE,QAAQ,CAAC,SAAS,EAAE,GAAG,EAAE,QAAQ,CAAC,OAAO,EAAE;aAC1D,CAAC;QACH,CAAC;aAAM,CAAC;YACP,uFAAuF;YACvF,MAAM,GAAG,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC,eAAe,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACpE,CAAC;QACD,WAAW,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;QACzB,OAAO,MAAM,CAAC;IACf,CAAC;IACD,OAAO,CAAC,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC;AACxF,CAAC;AAED,KAAK,UAAU,SAAS,CAAC,IAAY;IACpC,MAAM,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IACzB,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC;AACxB,CAAC"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { type MidiFile } from './Midi.ts';
|
|
2
|
+
/** one bucket of a waveform view: the lowest and highest sample it covers */
|
|
3
|
+
export interface WaveformBucket {
|
|
4
|
+
min: number;
|
|
5
|
+
max: number;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* A waveform reduced to `buckets` min/max pairs, what an oscilloscope or overview strip
|
|
9
|
+
* draws: each bucket covers an equal span of the samples (the last may be shorter), so a
|
|
10
|
+
* peak that lasts one sample still shows, which a plain average would erase.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* import { waveformEnvelope } from '@datamoc/mw_games/audio';
|
|
15
|
+
*
|
|
16
|
+
* const view = waveformEnvelope(new Float32Array([0, 1, -1, 0.5]), 2);
|
|
17
|
+
* console.log(view); // [{ min: 0, max: 1 }, { min: -1, max: 0.5 }]
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export declare function waveformEnvelope(samples: Float32Array, buckets: number): WaveformBucket[];
|
|
21
|
+
/**
|
|
22
|
+
* Per-channel waveform envelopes of stereo frames: channel 0 is the left, 1 the right,
|
|
23
|
+
* and a view asks each channel for the same number of buckets.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```ts
|
|
27
|
+
* import { channelEnvelopes } from '@datamoc/mw_games/audio';
|
|
28
|
+
*
|
|
29
|
+
* const [left] = channelEnvelopes(new Float32Array([1, -1]), new Float32Array([0.5, -0.5]), 1);
|
|
30
|
+
* console.log(left); // [{ min: -1, max: 1 }]
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export declare function channelEnvelopes(left: Float32Array, right: Float32Array, buckets: number): [WaveformBucket[], WaveformBucket[]];
|
|
34
|
+
/**
|
|
35
|
+
* A MIDI note number as a tracker spells it: name and octave, middle C as C4.
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```ts
|
|
39
|
+
* import { trackerNoteName } from '@datamoc/mw_games/audio';
|
|
40
|
+
*
|
|
41
|
+
* console.log(trackerNoteName(60)); // 'C4'
|
|
42
|
+
* console.log(trackerNoteName(61)); // 'C#4'
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export declare function trackerNoteName(note: number): string;
|
|
46
|
+
/** one row of a tracker pattern: its step, and the note each channel starts on it (null for none) */
|
|
47
|
+
export interface TrackerRow {
|
|
48
|
+
step: number;
|
|
49
|
+
/** seconds from the start, of the first note on the row (the previous note's time for an empty row) */
|
|
50
|
+
time: number;
|
|
51
|
+
notes: (string | null)[];
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* A MIDI file as tracker pattern rows: `stepsPerQuarter` rows per quarter note, one
|
|
55
|
+
* column per channel that plays, and a cell naming the note that starts on that row
|
|
56
|
+
* (the highest when a channel starts several at once, as a tracker cell holds one).
|
|
57
|
+
* Steps are counted in the file's own ticks, and a row's time follows its tempo map.
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```ts
|
|
61
|
+
* import { trackerPattern, type MidiFile } from '@datamoc/mw_games/audio';
|
|
62
|
+
*
|
|
63
|
+
* declare const file: MidiFile;
|
|
64
|
+
*
|
|
65
|
+
* const rows = trackerPattern(file);
|
|
66
|
+
* console.log(rows[0].notes); // the first step's notes by channel, or nulls
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
export declare function trackerPattern(file: MidiFile, stepsPerQuarter?: number): TrackerRow[];
|
|
70
|
+
//# sourceMappingURL=AudioViews.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AudioViews.d.ts","sourceRoot":"","sources":["../../src/audio/AudioViews.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,QAAQ,EAAsB,MAAM,WAAW,CAAC;AAEjF,6EAA6E;AAC7E,MAAM,WAAW,cAAc;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACZ;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,GAAG,cAAc,EAAE,CAezF;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAC/B,IAAI,EAAE,YAAY,EAClB,KAAK,EAAE,YAAY,EACnB,OAAO,EAAE,MAAM,GACb,CAAC,cAAc,EAAE,EAAE,cAAc,EAAE,CAAC,CAEtC;AAID;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,qGAAqG;AACrG,MAAM,WAAW,UAAU;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,uGAAuG;IACvG,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC;CACzB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,QAAQ,EAAE,eAAe,SAAI,GAAG,UAAU,EAAE,CA8BhF"}
|