@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
package/dist/audio/Playable.d.ts
CHANGED
|
@@ -3,6 +3,13 @@
|
|
|
3
3
|
* already provides, named here so a test (or a game with its own audio backend) can supply
|
|
4
4
|
* a fake without a real `Audio` element existing, which nothing outside a browser can
|
|
5
5
|
* create.
|
|
6
|
+
*
|
|
7
|
+
* A backend that synthesises its sound instead of decoding a file (see `StreamPlayable`) has to
|
|
8
|
+
* answer the questions `HTMLAudioElement` answers implicitly: `currentTime` reads and seeks the
|
|
9
|
+
* playhead and holds the duration once a track that does not loop has ended; `playbackRate` is
|
|
10
|
+
* honoured (by resampling) or ignored but never throws; `onended` fires once at the end of a
|
|
11
|
+
* track that does not loop and never for one that does; and `play()` may return a promise that
|
|
12
|
+
* settles when the audio is allowed to start.
|
|
6
13
|
*/
|
|
7
14
|
export interface Playable {
|
|
8
15
|
play(): void | Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Playable.d.ts","sourceRoot":"","sources":["../../src/audio/Playable.ts"],"names":[],"mappings":"AAEA
|
|
1
|
+
{"version":3,"file":"Playable.d.ts","sourceRoot":"","sources":["../../src/audio/Playable.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,QAAQ;IACxB,IAAI,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,KAAK,IAAI,IAAI,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;IACd,yFAAyF;IACzF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;+EAC2E;IAC3E,OAAO,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,GAAG,IAAI,CAAC;CAC7C;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,CAUlD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Playable.js","sourceRoot":"","sources":["../../src/audio/Playable.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,SAAS,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"Playable.js","sourceRoot":"","sources":["../../src/audio/Playable.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,SAAS,MAAM,oBAAoB,CAAC;AA4BhD;;;;;;;;;;GAUG;AACH,MAAM,UAAU,WAAW,CAAC,IAAY;IACvC,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACJ,GAAG,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,0FAA0F;QAC1F,OAAO,CAAC,IAAI,CAAC,GAAI,KAAe,CAAC,OAAO,OAAO,IAAI,kBAAkB,CAAC,CAAC;QACvE,OAAO,cAAc,EAAE,CAAC;IACzB,CAAC;IACD,OAAO,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC;AACvB,CAAC;AAED,4FAA4F;AAC5F,SAAS,cAAc;IACtB,OAAO,EAAE,IAAI,KAAI,CAAC,EAAE,KAAK,KAAI,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;AAC1E,CAAC"}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
/** anything a `SoundSource` can play at a mix: a `Sound`, or an `SfxSound` that also takes a pan */
|
|
2
|
+
export interface PositionalSound {
|
|
3
|
+
play(gain?: number, pitch?: number, pan?: number): unknown;
|
|
4
|
+
}
|
|
2
5
|
/** A point in the same 2D space the game's camera works in, in world units. */
|
|
3
6
|
export interface AudioPoint {
|
|
4
7
|
x: number;
|
|
@@ -113,13 +116,18 @@ export declare class SoundSource implements AudioPoint {
|
|
|
113
116
|
y: number;
|
|
114
117
|
private readonly sound;
|
|
115
118
|
private readonly falloff;
|
|
116
|
-
constructor(sound:
|
|
119
|
+
constructor(sound: PositionalSound, options?: SoundSourceOptions);
|
|
117
120
|
moveTo(x: number, y: number): void;
|
|
118
121
|
gainTo(listener: AudioPoint): number;
|
|
119
122
|
panTo(listener: AudioPoint & {
|
|
120
123
|
facing: number;
|
|
121
124
|
}): number;
|
|
122
|
-
/**
|
|
123
|
-
|
|
125
|
+
/**
|
|
126
|
+
* Plays the source at the gain the listener hears it; returns the gain actually used. A listener
|
|
127
|
+
* with a `facing` also pans the sound, for a sound that takes a pan (a `Sound` ignores it).
|
|
128
|
+
*/
|
|
129
|
+
playFor(listener: AudioPoint | (AudioPoint & {
|
|
130
|
+
facing: number;
|
|
131
|
+
})): number;
|
|
124
132
|
}
|
|
125
133
|
//# sourceMappingURL=Positional.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Positional.d.ts","sourceRoot":"","sources":["../../src/audio/Positional.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"Positional.d.ts","sourceRoot":"","sources":["../../src/audio/Positional.ts"],"names":[],"mappings":"AAAA,oGAAoG;AACpG,MAAM,WAAW,eAAe;IAC/B,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CAC3D;AAED,+EAA+E;AAC/E,MAAM,WAAW,UAAU;IAC1B,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACV;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,YAAY;IAC5B,oEAAoE;IACpE,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,mEAAmE;IACnE,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,2DAA2D;IAC3D,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,MAAM,CAU9E;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,UAAU,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM,CAW9F;AAED;;;;;;;;;;;;GAYG;AACH,qBAAa,aAAc,YAAW,UAAU;IAC/C,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IAEV,8EAA8E;IAC9E,MAAM,EAAE,MAAM,CAAC;IAEf,YAAY,OAAO,GAAE;QAAE,CAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAO,EAIpE;IAED,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAGjC;IAED,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAE1B;CACD;AAED,MAAM,WAAW,kBAAmB,SAAQ,YAAY;IACvD,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,CAAC,CAAC,EAAE,MAAM,CAAC;CACX;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,WAAY,YAAW,UAAU;IAC7C,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IAEV,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAkB;IACxC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;IAEvC,YAAY,KAAK,EAAE,eAAe,EAAE,OAAO,GAAE,kBAAuB,EASnE;IAED,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAGjC;IAED,MAAM,CAAC,QAAQ,EAAE,UAAU,GAAG,MAAM,CAEnC;IAED,KAAK,CAAC,QAAQ,EAAE,UAAU,GAAG;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM,CAEvD;IAED;;;OAGG;IACH,OAAO,CAAC,QAAQ,EAAE,UAAU,GAAG,CAAC,UAAU,GAAG;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,MAAM,CAKxE;CACD"}
|
package/dist/audio/Positional.js
CHANGED
|
@@ -123,12 +123,15 @@ export class SoundSource {
|
|
|
123
123
|
panTo(listener) {
|
|
124
124
|
return audioPan(listener, this);
|
|
125
125
|
}
|
|
126
|
-
/**
|
|
126
|
+
/**
|
|
127
|
+
* Plays the source at the gain the listener hears it; returns the gain actually used. A listener
|
|
128
|
+
* with a `facing` also pans the sound, for a sound that takes a pan (a `Sound` ignores it).
|
|
129
|
+
*/
|
|
127
130
|
playFor(listener) {
|
|
128
131
|
const gain = this.gainTo(listener);
|
|
129
132
|
if (gain <= 0)
|
|
130
133
|
return 0;
|
|
131
|
-
this.sound.play(gain);
|
|
134
|
+
this.sound.play(gain, 1, 'facing' in listener ? this.panTo(listener) : 0);
|
|
132
135
|
return gain;
|
|
133
136
|
}
|
|
134
137
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Positional.js","sourceRoot":"","sources":["../../src/audio/Positional.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Positional.js","sourceRoot":"","sources":["../../src/audio/Positional.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plain-array helpers for fitting rendered audio to a budget: cut to a length with a fade,
|
|
3
|
+
* fold to mono, halve the rate, convert between rates. They work on the `Float32Array`
|
|
4
|
+
* pairs a render produces, so nothing here needs an `AudioContext`.
|
|
5
|
+
*/
|
|
6
|
+
/** stereo frames at a sample rate: the shape every renderer in this module hands back */
|
|
7
|
+
export interface StereoFrames {
|
|
8
|
+
sampleRate: number;
|
|
9
|
+
left: Float32Array;
|
|
10
|
+
right: Float32Array;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Converts stereo frames to another sample rate by linear interpolation. Linear is audibly
|
|
14
|
+
* soft above the new Nyquist, which is the right trade for ambience and background music where
|
|
15
|
+
* this is used to save memory; a game that needs a clean conversion renders at the target
|
|
16
|
+
* rate instead.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* import { resampleStereo } from '@datamoc/mw_games/audio';
|
|
21
|
+
*
|
|
22
|
+
* declare const frames: { sampleRate: number; left: Float32Array; right: Float32Array };
|
|
23
|
+
*
|
|
24
|
+
* const half = resampleStereo(frames, frames.sampleRate / 2);
|
|
25
|
+
* console.log(half.left.length);
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export declare function resampleStereo<T extends StereoFrames>(frames: T, sampleRate: number): T;
|
|
29
|
+
/** what a track may cost: every field optional, an omitted one leaves that dimension alone */
|
|
30
|
+
export interface RenderBudget {
|
|
31
|
+
/** cut the track to this many seconds, fading the cut so it does not click */
|
|
32
|
+
maxSeconds?: number;
|
|
33
|
+
/** seconds of fade at a cut; 0.5 when omitted */
|
|
34
|
+
fadeSeconds?: number;
|
|
35
|
+
/** fold both channels into one, stored twice-referenced so a stereo consumer still works */
|
|
36
|
+
mono?: boolean;
|
|
37
|
+
/** halve the sample rate, for ambience that carries no high frequencies */
|
|
38
|
+
halfRate?: boolean;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Fits a rendered track to a budget: cuts it to `maxSeconds` with a fade, folds it to mono
|
|
42
|
+
* and halves its rate, in that order. A mono track shares one array between both channels, so
|
|
43
|
+
* it costs half the memory in the renderer's hands even though a stereo `AudioBuffer` made
|
|
44
|
+
* from it later still has two. Loop points past the cut are pulled back to the new end.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```ts
|
|
48
|
+
* import { fitToBudget, renderMidiToBuffer, parseMidi } from '@datamoc/mw_games/audio';
|
|
49
|
+
*
|
|
50
|
+
* declare const midiBytes: ArrayBuffer;
|
|
51
|
+
*
|
|
52
|
+
* const ambience = fitToBudget(renderMidiToBuffer(parseMidi(midiBytes)), { maxSeconds: 60, mono: true, halfRate: true });
|
|
53
|
+
* console.log(ambience.duration);
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
export declare function fitToBudget<T extends StereoFrames & {
|
|
57
|
+
loopStart?: number;
|
|
58
|
+
loopEnd?: number;
|
|
59
|
+
duration?: number;
|
|
60
|
+
}>(track: T, budget: RenderBudget): T;
|
|
61
|
+
//# sourceMappingURL=Resample.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Resample.d.ts","sourceRoot":"","sources":["../../src/audio/Resample.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,yFAAyF;AACzF,MAAM,WAAW,YAAY;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,YAAY,CAAC;IACnB,KAAK,EAAE,YAAY,CAAC;CACpB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,YAAY,EAAE,MAAM,EAAE,CAAC,EAAE,UAAU,EAAE,MAAM,GAAG,CAAC,CAiBvF;AAED,8FAA8F;AAC9F,MAAM,WAAW,YAAY;IAC5B,8EAA8E;IAC9E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iDAAiD;IACjD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4FAA4F;IAC5F,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,YAAY,GAAG;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,EAC/G,KAAK,EAAE,CAAC,EACR,MAAM,EAAE,YAAY,GAClB,CAAC,CAyBH"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plain-array helpers for fitting rendered audio to a budget: cut to a length with a fade,
|
|
3
|
+
* fold to mono, halve the rate, convert between rates. They work on the `Float32Array`
|
|
4
|
+
* pairs a render produces, so nothing here needs an `AudioContext`.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Converts stereo frames to another sample rate by linear interpolation. Linear is audibly
|
|
8
|
+
* soft above the new Nyquist, which is the right trade for ambience and background music where
|
|
9
|
+
* this is used to save memory; a game that needs a clean conversion renders at the target
|
|
10
|
+
* rate instead.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* import { resampleStereo } from '@datamoc/mw_games/audio';
|
|
15
|
+
*
|
|
16
|
+
* declare const frames: { sampleRate: number; left: Float32Array; right: Float32Array };
|
|
17
|
+
*
|
|
18
|
+
* const half = resampleStereo(frames, frames.sampleRate / 2);
|
|
19
|
+
* console.log(half.left.length);
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export function resampleStereo(frames, sampleRate) {
|
|
23
|
+
if (!(sampleRate > 0))
|
|
24
|
+
throw new Error('target sample rate must be positive');
|
|
25
|
+
if (sampleRate === frames.sampleRate)
|
|
26
|
+
return frames;
|
|
27
|
+
const length = Math.max(1, Math.round((frames.left.length * sampleRate) / frames.sampleRate));
|
|
28
|
+
const step = frames.sampleRate / sampleRate;
|
|
29
|
+
const left = new Float32Array(length);
|
|
30
|
+
const right = new Float32Array(length);
|
|
31
|
+
const last = frames.left.length - 1;
|
|
32
|
+
for (let i = 0; i < length; i++) {
|
|
33
|
+
const position = i * step;
|
|
34
|
+
const floor = Math.min(last, Math.floor(position));
|
|
35
|
+
const next = Math.min(last, floor + 1);
|
|
36
|
+
const fraction = position - floor;
|
|
37
|
+
left[i] = frames.left[floor] + (frames.left[next] - frames.left[floor]) * fraction;
|
|
38
|
+
right[i] = frames.right[floor] + (frames.right[next] - frames.right[floor]) * fraction;
|
|
39
|
+
}
|
|
40
|
+
return { ...frames, sampleRate, left, right };
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Fits a rendered track to a budget: cuts it to `maxSeconds` with a fade, folds it to mono
|
|
44
|
+
* and halves its rate, in that order. A mono track shares one array between both channels, so
|
|
45
|
+
* it costs half the memory in the renderer's hands even though a stereo `AudioBuffer` made
|
|
46
|
+
* from it later still has two. Loop points past the cut are pulled back to the new end.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```ts
|
|
50
|
+
* import { fitToBudget, renderMidiToBuffer, parseMidi } from '@datamoc/mw_games/audio';
|
|
51
|
+
*
|
|
52
|
+
* declare const midiBytes: ArrayBuffer;
|
|
53
|
+
*
|
|
54
|
+
* const ambience = fitToBudget(renderMidiToBuffer(parseMidi(midiBytes)), { maxSeconds: 60, mono: true, halfRate: true });
|
|
55
|
+
* console.log(ambience.duration);
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
export function fitToBudget(track, budget) {
|
|
59
|
+
let result = track;
|
|
60
|
+
if (budget.maxSeconds !== undefined) {
|
|
61
|
+
if (!(budget.maxSeconds > 0))
|
|
62
|
+
throw new Error('budget maxSeconds must be positive');
|
|
63
|
+
const limit = Math.max(1, Math.floor(budget.maxSeconds * result.sampleRate));
|
|
64
|
+
if (result.left.length > limit) {
|
|
65
|
+
const left = result.left.slice(0, limit);
|
|
66
|
+
const right = result.right.slice(0, limit);
|
|
67
|
+
const fade = Math.min(limit, Math.floor((budget.fadeSeconds ?? 0.5) * result.sampleRate));
|
|
68
|
+
for (let i = 0; i < fade; i++) {
|
|
69
|
+
const gain = i / fade;
|
|
70
|
+
left[limit - 1 - i] *= gain;
|
|
71
|
+
right[limit - 1 - i] *= gain;
|
|
72
|
+
}
|
|
73
|
+
const seconds = limit / result.sampleRate;
|
|
74
|
+
result = withEnd({ ...result, left, right }, seconds);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (budget.mono) {
|
|
78
|
+
const mixed = new Float32Array(result.left.length);
|
|
79
|
+
for (let i = 0; i < mixed.length; i++)
|
|
80
|
+
mixed[i] = (result.left[i] + result.right[i]) / 2;
|
|
81
|
+
result = { ...result, left: mixed, right: mixed };
|
|
82
|
+
}
|
|
83
|
+
if (budget.halfRate)
|
|
84
|
+
result = resampleStereo(result, result.sampleRate / 2);
|
|
85
|
+
return result;
|
|
86
|
+
}
|
|
87
|
+
function withEnd(track, seconds) {
|
|
88
|
+
const next = { ...track };
|
|
89
|
+
if (next.duration !== undefined)
|
|
90
|
+
next.duration = seconds;
|
|
91
|
+
if (next.loopEnd !== undefined)
|
|
92
|
+
next.loopEnd = Math.min(next.loopEnd, seconds);
|
|
93
|
+
if (next.loopStart !== undefined)
|
|
94
|
+
next.loopStart = Math.min(next.loopStart, Math.max(0, seconds - 0.1));
|
|
95
|
+
return next;
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=Resample.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Resample.js","sourceRoot":"","sources":["../../src/audio/Resample.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import type { AudioBus, BusKind } from './Channels.ts';
|
|
2
|
+
/** the television standard a retro machine ran at: it sets the clock its music was timed by */
|
|
3
|
+
export type AudioRegion = 'pal' | 'ntsc';
|
|
4
|
+
/**
|
|
5
|
+
* How a machine profile's output stage is treated: `faithful` keeps what the hardware did
|
|
6
|
+
* (DC offset, aliasing and all), `clean` removes the DC and softens the top end.
|
|
7
|
+
*/
|
|
8
|
+
export type OutputStage = 'faithful' | 'clean';
|
|
9
|
+
/** player-facing audio settings as plain data, the shape a save or a settings file holds */
|
|
10
|
+
export interface AudioSettingsData {
|
|
11
|
+
/** volume per bus kind, 0 to 100 like every other volume in the bus API */
|
|
12
|
+
busVolumes: Record<BusKind, number>;
|
|
13
|
+
/** the MIDI engine name content is voiced by first, or null for the internal path */
|
|
14
|
+
preferredEngine: string | null;
|
|
15
|
+
region: AudioRegion;
|
|
16
|
+
outputStage: OutputStage;
|
|
17
|
+
/** whether caption text is shown for captioned sounds */
|
|
18
|
+
captions: boolean;
|
|
19
|
+
/** dynamics control, 0 (untouched) to 1 (a soft limiter at full), for loudness comfort */
|
|
20
|
+
dynamics: number;
|
|
21
|
+
/** softening of bright or broadband sounds, 0 (untouched) to 1 (most softened) */
|
|
22
|
+
soften: number;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The playback rate a tune authored for one region runs at on the other: a PAL machine's
|
|
26
|
+
* 50 Hz clock against NTSC's 60 Hz makes the same file slower and lower, which is the
|
|
27
|
+
* difference a player who grew up with the other standard hears first.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```ts
|
|
31
|
+
* import { regionPlaybackRate } from '@datamoc/mw_games/audio';
|
|
32
|
+
*
|
|
33
|
+
* console.log(regionPlaybackRate('pal', 'ntsc')); // 0.8333..., slower on PAL
|
|
34
|
+
* console.log(regionPlaybackRate('ntsc', 'ntsc')); // 1, its own region
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export declare function regionPlaybackRate(region: AudioRegion, authored?: AudioRegion): number;
|
|
38
|
+
/**
|
|
39
|
+
* The low-pass cutoff, in hertz, that a `soften` amount asks an output stage for: nothing
|
|
40
|
+
* at 0, down to a muffled 3.5 kHz at 1, never above what the sample rate can represent.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```ts
|
|
44
|
+
* import { softenCutoff } from '@datamoc/mw_games/audio';
|
|
45
|
+
*
|
|
46
|
+
* console.log(softenCutoff(0, 44100)); // 18000, effectively open
|
|
47
|
+
* console.log(softenCutoff(1, 44100) < softenCutoff(0.5, 44100)); // true, more soften, lower cutoff
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export declare function softenCutoff(soften: number, sampleRate: number): number;
|
|
51
|
+
/**
|
|
52
|
+
* One sample through the dynamics control: at 0 the sample is untouched, and as the amount
|
|
53
|
+
* rises a soft knee pulls peaks toward full scale without ever passing it, so a loud game
|
|
54
|
+
* gets quieter peaks rather than clipped ones.
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```ts
|
|
58
|
+
* import { dynamicsLimit } from '@datamoc/mw_games/audio';
|
|
59
|
+
*
|
|
60
|
+
* console.log(dynamicsLimit(0.5, 0)); // 0.5, untouched
|
|
61
|
+
* console.log(dynamicsLimit(4, 1) < 1); // true, a hot sample is pulled under full scale
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
export declare function dynamicsLimit(sample: number, dynamics: number): number;
|
|
65
|
+
/**
|
|
66
|
+
* The player's audio settings in one place, over the pieces that already exist: bus
|
|
67
|
+
* volumes apply to an `AudioBus` (`applyToBus`), the preferred engine names what
|
|
68
|
+
* `resolveMidiSynth` is asked for first, the region and output stage describe the machine
|
|
69
|
+
* profile a retro package renders for, and captions, dynamics and soften are the
|
|
70
|
+
* accessibility dials. Everything clamps on the way in, and `snapshot`/`restore` round-trip
|
|
71
|
+
* the plain-data shape a settings screen persists.
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* ```ts
|
|
75
|
+
* import { AudioSettings } from '@datamoc/mw_games/audio';
|
|
76
|
+
*
|
|
77
|
+
* const settings = new AudioSettings({ preferredEngine: 'retro:mt32', soften: 0.4 });
|
|
78
|
+
* settings.setBusVolume('se', 130);
|
|
79
|
+
* console.log(settings.snapshot().busVolumes.se); // 100, clamped
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
export declare class AudioSettings {
|
|
83
|
+
private data;
|
|
84
|
+
constructor(initial?: Partial<AudioSettingsData>);
|
|
85
|
+
/** a copy of the current settings, safe to store */
|
|
86
|
+
snapshot(): AudioSettingsData;
|
|
87
|
+
/** takes settings in, clamping every dial; a partial update keeps the rest */
|
|
88
|
+
restore(data: Partial<AudioSettingsData>): void;
|
|
89
|
+
setBusVolume(kind: BusKind, volume: number): void;
|
|
90
|
+
/** pushes the per-bus volumes onto a bus's mixer, the settings' one live connection */
|
|
91
|
+
applyToBus(bus: AudioBus): void;
|
|
92
|
+
/** the rate content authored for `authored` should play at under this region */
|
|
93
|
+
playbackRate(authored?: AudioRegion): number;
|
|
94
|
+
/** the cutoff the current soften amount (and a clean stage's extra softening) asks for */
|
|
95
|
+
cutoff(sampleRate: number): number;
|
|
96
|
+
/** one sample through the current dynamics amount */
|
|
97
|
+
limit(sample: number): number;
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=Settings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Settings.d.ts","sourceRoot":"","sources":["../../src/audio/Settings.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAEvD,+FAA+F;AAC/F,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,MAAM,CAAC;AAEzC;;;GAGG;AACH,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,OAAO,CAAC;AAE/C,4FAA4F;AAC5F,MAAM,WAAW,iBAAiB;IACjC,2EAA2E;IAC3E,UAAU,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IACpC,qFAAqF;IACrF,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,MAAM,EAAE,WAAW,CAAC;IACpB,WAAW,EAAE,WAAW,CAAC;IACzB,yDAAyD;IACzD,QAAQ,EAAE,OAAO,CAAC;IAClB,0FAA0F;IAC1F,QAAQ,EAAE,MAAM,CAAC;IACjB,kFAAkF;IAClF,MAAM,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,GAAE,WAAoB,GAAG,MAAM,CAG9F;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAIvE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAKtE;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,aAAa;IACzB,OAAO,CAAC,IAAI,CAAoB;IAEhC,YAAY,OAAO,GAAE,OAAO,CAAC,iBAAiB,CAAM,EAWnD;IAED,oDAAoD;IACpD,QAAQ,IAAI,iBAAiB,CAE5B;IAED,8EAA8E;IAC9E,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,iBAAiB,CAAC,GAAG,IAAI,CAY9C;IAED,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAEhD;IAED,uFAAuF;IACvF,UAAU,CAAC,GAAG,EAAE,QAAQ,GAAG,IAAI,CAI9B;IAED,gFAAgF;IAChF,YAAY,CAAC,QAAQ,GAAE,WAAoB,GAAG,MAAM,CAEnD;IAED,0FAA0F;IAC1F,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAGjC;IAED,qDAAqD;IACrD,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAE5B;CACD"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { clamp } from '../core/Math.js';
|
|
2
|
+
/**
|
|
3
|
+
* The playback rate a tune authored for one region runs at on the other: a PAL machine's
|
|
4
|
+
* 50 Hz clock against NTSC's 60 Hz makes the same file slower and lower, which is the
|
|
5
|
+
* difference a player who grew up with the other standard hears first.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { regionPlaybackRate } from '@datamoc/mw_games/audio';
|
|
10
|
+
*
|
|
11
|
+
* console.log(regionPlaybackRate('pal', 'ntsc')); // 0.8333..., slower on PAL
|
|
12
|
+
* console.log(regionPlaybackRate('ntsc', 'ntsc')); // 1, its own region
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export function regionPlaybackRate(region, authored = 'ntsc') {
|
|
16
|
+
if (region === authored)
|
|
17
|
+
return 1;
|
|
18
|
+
return region === 'pal' ? 50 / 60 : 60 / 50;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* The low-pass cutoff, in hertz, that a `soften` amount asks an output stage for: nothing
|
|
22
|
+
* at 0, down to a muffled 3.5 kHz at 1, never above what the sample rate can represent.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* import { softenCutoff } from '@datamoc/mw_games/audio';
|
|
27
|
+
*
|
|
28
|
+
* console.log(softenCutoff(0, 44100)); // 18000, effectively open
|
|
29
|
+
* console.log(softenCutoff(1, 44100) < softenCutoff(0.5, 44100)); // true, more soften, lower cutoff
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export function softenCutoff(soften, sampleRate) {
|
|
33
|
+
const amount = clamp(soften, 0, 1);
|
|
34
|
+
const cutoff = 18000 * (3500 / 18000) ** amount;
|
|
35
|
+
return Math.min(cutoff, sampleRate / 2);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* One sample through the dynamics control: at 0 the sample is untouched, and as the amount
|
|
39
|
+
* rises a soft knee pulls peaks toward full scale without ever passing it, so a loud game
|
|
40
|
+
* gets quieter peaks rather than clipped ones.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```ts
|
|
44
|
+
* import { dynamicsLimit } from '@datamoc/mw_games/audio';
|
|
45
|
+
*
|
|
46
|
+
* console.log(dynamicsLimit(0.5, 0)); // 0.5, untouched
|
|
47
|
+
* console.log(dynamicsLimit(4, 1) < 1); // true, a hot sample is pulled under full scale
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export function dynamicsLimit(sample, dynamics) {
|
|
51
|
+
const amount = clamp(dynamics, 0, 1);
|
|
52
|
+
if (amount === 0)
|
|
53
|
+
return sample;
|
|
54
|
+
const limited = Math.tanh(sample);
|
|
55
|
+
return sample * (1 - amount) + limited * amount;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* The player's audio settings in one place, over the pieces that already exist: bus
|
|
59
|
+
* volumes apply to an `AudioBus` (`applyToBus`), the preferred engine names what
|
|
60
|
+
* `resolveMidiSynth` is asked for first, the region and output stage describe the machine
|
|
61
|
+
* profile a retro package renders for, and captions, dynamics and soften are the
|
|
62
|
+
* accessibility dials. Everything clamps on the way in, and `snapshot`/`restore` round-trip
|
|
63
|
+
* the plain-data shape a settings screen persists.
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```ts
|
|
67
|
+
* import { AudioSettings } from '@datamoc/mw_games/audio';
|
|
68
|
+
*
|
|
69
|
+
* const settings = new AudioSettings({ preferredEngine: 'retro:mt32', soften: 0.4 });
|
|
70
|
+
* settings.setBusVolume('se', 130);
|
|
71
|
+
* console.log(settings.snapshot().busVolumes.se); // 100, clamped
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
export class AudioSettings {
|
|
75
|
+
constructor(initial = {}) {
|
|
76
|
+
this.data = {
|
|
77
|
+
busVolumes: { bgm: 90, bgs: 90, me: 90, se: 90 },
|
|
78
|
+
preferredEngine: null,
|
|
79
|
+
region: 'ntsc',
|
|
80
|
+
outputStage: 'faithful',
|
|
81
|
+
captions: false,
|
|
82
|
+
dynamics: 0,
|
|
83
|
+
soften: 0,
|
|
84
|
+
};
|
|
85
|
+
this.restore(initial);
|
|
86
|
+
}
|
|
87
|
+
/** a copy of the current settings, safe to store */
|
|
88
|
+
snapshot() {
|
|
89
|
+
return { ...this.data, busVolumes: { ...this.data.busVolumes } };
|
|
90
|
+
}
|
|
91
|
+
/** takes settings in, clamping every dial; a partial update keeps the rest */
|
|
92
|
+
restore(data) {
|
|
93
|
+
if (data.busVolumes) {
|
|
94
|
+
for (const kind of Object.keys(data.busVolumes)) {
|
|
95
|
+
this.data.busVolumes[kind] = clamp(data.busVolumes[kind], 0, 100);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (data.preferredEngine !== undefined)
|
|
99
|
+
this.data.preferredEngine = data.preferredEngine;
|
|
100
|
+
if (data.region !== undefined)
|
|
101
|
+
this.data.region = data.region;
|
|
102
|
+
if (data.outputStage !== undefined)
|
|
103
|
+
this.data.outputStage = data.outputStage;
|
|
104
|
+
if (data.captions !== undefined)
|
|
105
|
+
this.data.captions = data.captions;
|
|
106
|
+
if (data.dynamics !== undefined)
|
|
107
|
+
this.data.dynamics = clamp(data.dynamics, 0, 1);
|
|
108
|
+
if (data.soften !== undefined)
|
|
109
|
+
this.data.soften = clamp(data.soften, 0, 1);
|
|
110
|
+
}
|
|
111
|
+
setBusVolume(kind, volume) {
|
|
112
|
+
this.data.busVolumes[kind] = clamp(volume, 0, 100);
|
|
113
|
+
}
|
|
114
|
+
/** pushes the per-bus volumes onto a bus's mixer, the settings' one live connection */
|
|
115
|
+
applyToBus(bus) {
|
|
116
|
+
for (const kind of Object.keys(this.data.busVolumes)) {
|
|
117
|
+
bus.setMixer(kind, { volume: this.data.busVolumes[kind] / 100 });
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
/** the rate content authored for `authored` should play at under this region */
|
|
121
|
+
playbackRate(authored = 'ntsc') {
|
|
122
|
+
return regionPlaybackRate(this.data.region, authored);
|
|
123
|
+
}
|
|
124
|
+
/** the cutoff the current soften amount (and a clean stage's extra softening) asks for */
|
|
125
|
+
cutoff(sampleRate) {
|
|
126
|
+
const extra = this.data.outputStage === 'clean' ? 0.25 : 0;
|
|
127
|
+
return softenCutoff(clamp(this.data.soften + extra, 0, 1), sampleRate);
|
|
128
|
+
}
|
|
129
|
+
/** one sample through the current dynamics amount */
|
|
130
|
+
limit(sample) {
|
|
131
|
+
return dynamicsLimit(sample, this.data.dynamics);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=Settings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Settings.js","sourceRoot":"","sources":["../../src/audio/Settings.ts"],"names":[],"mappings":"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"}
|