@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.
Files changed (255) hide show
  1. package/CHANGELOG.md +67 -0
  2. package/README.md +22 -0
  3. package/REFERENCE.md +82 -6
  4. package/api-surface.json +1028 -2
  5. package/dist/actors/Resource.d.ts.map +1 -1
  6. package/dist/actors/Resource.js +2 -3
  7. package/dist/actors/Resource.js.map +1 -1
  8. package/dist/audio/AdaptiveMusic.d.ts +85 -0
  9. package/dist/audio/AdaptiveMusic.d.ts.map +1 -0
  10. package/dist/audio/AdaptiveMusic.js +230 -0
  11. package/dist/audio/AdaptiveMusic.js.map +1 -0
  12. package/dist/audio/AudioLoader.d.ts +7 -2
  13. package/dist/audio/AudioLoader.d.ts.map +1 -1
  14. package/dist/audio/AudioLoader.js +23 -18
  15. package/dist/audio/AudioLoader.js.map +1 -1
  16. package/dist/audio/AudioViews.d.ts +70 -0
  17. package/dist/audio/AudioViews.d.ts.map +1 -0
  18. package/dist/audio/AudioViews.js +119 -0
  19. package/dist/audio/AudioViews.js.map +1 -0
  20. package/dist/audio/BusBudget.d.ts +89 -0
  21. package/dist/audio/BusBudget.d.ts.map +1 -0
  22. package/dist/audio/BusBudget.js +120 -0
  23. package/dist/audio/BusBudget.js.map +1 -0
  24. package/dist/audio/Channels.d.ts +65 -1
  25. package/dist/audio/Channels.d.ts.map +1 -1
  26. package/dist/audio/Channels.js +117 -30
  27. package/dist/audio/Channels.js.map +1 -1
  28. package/dist/audio/CoreHost.d.ts +114 -0
  29. package/dist/audio/CoreHost.d.ts.map +1 -0
  30. package/dist/audio/CoreHost.js +335 -0
  31. package/dist/audio/CoreHost.js.map +1 -0
  32. package/dist/audio/DecoderGuard.d.ts +139 -0
  33. package/dist/audio/DecoderGuard.d.ts.map +1 -0
  34. package/dist/audio/DecoderGuard.js +208 -0
  35. package/dist/audio/DecoderGuard.js.map +1 -0
  36. package/dist/audio/Fft.d.ts +3 -0
  37. package/dist/audio/Fft.d.ts.map +1 -0
  38. package/dist/audio/Fft.js +45 -0
  39. package/dist/audio/Fft.js.map +1 -0
  40. package/dist/audio/LoopTags.d.ts +18 -0
  41. package/dist/audio/LoopTags.d.ts.map +1 -1
  42. package/dist/audio/LoopTags.js +20 -0
  43. package/dist/audio/LoopTags.js.map +1 -1
  44. package/dist/audio/Midi.d.ts +35 -0
  45. package/dist/audio/Midi.d.ts.map +1 -1
  46. package/dist/audio/Midi.js +71 -1
  47. package/dist/audio/Midi.js.map +1 -1
  48. package/dist/audio/MidiRender.d.ts +31 -0
  49. package/dist/audio/MidiRender.d.ts.map +1 -1
  50. package/dist/audio/MidiRender.js +79 -2
  51. package/dist/audio/MidiRender.js.map +1 -1
  52. package/dist/audio/MidiSynth.d.ts +147 -0
  53. package/dist/audio/MidiSynth.d.ts.map +1 -0
  54. package/dist/audio/MidiSynth.js +205 -0
  55. package/dist/audio/MidiSynth.js.map +1 -0
  56. package/dist/audio/Playable.d.ts +7 -0
  57. package/dist/audio/Playable.d.ts.map +1 -1
  58. package/dist/audio/Playable.js.map +1 -1
  59. package/dist/audio/Positional.d.ts +12 -4
  60. package/dist/audio/Positional.d.ts.map +1 -1
  61. package/dist/audio/Positional.js +5 -2
  62. package/dist/audio/Positional.js.map +1 -1
  63. package/dist/audio/Resample.d.ts +61 -0
  64. package/dist/audio/Resample.d.ts.map +1 -0
  65. package/dist/audio/Resample.js +97 -0
  66. package/dist/audio/Resample.js.map +1 -0
  67. package/dist/audio/Settings.d.ts +99 -0
  68. package/dist/audio/Settings.d.ts.map +1 -0
  69. package/dist/audio/Settings.js +134 -0
  70. package/dist/audio/Settings.js.map +1 -0
  71. package/dist/audio/Sfx.d.ts +148 -0
  72. package/dist/audio/Sfx.d.ts.map +1 -0
  73. package/dist/audio/Sfx.js +213 -0
  74. package/dist/audio/Sfx.js.map +1 -0
  75. package/dist/audio/SpectralDistance.d.ts +34 -0
  76. package/dist/audio/SpectralDistance.d.ts.map +1 -0
  77. package/dist/audio/SpectralDistance.js +64 -0
  78. package/dist/audio/SpectralDistance.js.map +1 -0
  79. package/dist/audio/StreamChannel.d.ts +150 -0
  80. package/dist/audio/StreamChannel.d.ts.map +1 -0
  81. package/dist/audio/StreamChannel.js +390 -0
  82. package/dist/audio/StreamChannel.js.map +1 -0
  83. package/dist/audio/StreamPlayable.d.ts +73 -0
  84. package/dist/audio/StreamPlayable.d.ts.map +1 -0
  85. package/dist/audio/StreamPlayable.js +130 -0
  86. package/dist/audio/StreamPlayable.js.map +1 -0
  87. package/dist/audio/SyxBank.d.ts +73 -0
  88. package/dist/audio/SyxBank.d.ts.map +1 -0
  89. package/dist/audio/SyxBank.js +130 -0
  90. package/dist/audio/SyxBank.js.map +1 -0
  91. package/dist/audio/Underrun.d.ts +25 -0
  92. package/dist/audio/Underrun.d.ts.map +1 -0
  93. package/dist/audio/Underrun.js +18 -0
  94. package/dist/audio/Underrun.js.map +1 -0
  95. package/dist/audio/Wav.d.ts +56 -0
  96. package/dist/audio/Wav.d.ts.map +1 -0
  97. package/dist/audio/Wav.js +164 -0
  98. package/dist/audio/Wav.js.map +1 -0
  99. package/dist/audio/WebMidi.d.ts +58 -0
  100. package/dist/audio/WebMidi.d.ts.map +1 -0
  101. package/dist/audio/WebMidi.js +79 -0
  102. package/dist/audio/WebMidi.js.map +1 -0
  103. package/dist/audio/humanize/Onsets.d.ts.map +1 -1
  104. package/dist/audio/humanize/Onsets.js +1 -44
  105. package/dist/audio/humanize/Onsets.js.map +1 -1
  106. package/dist/audio/index.d.ts +38 -6
  107. package/dist/audio/index.d.ts.map +1 -1
  108. package/dist/audio/index.js +19 -3
  109. package/dist/audio/index.js.map +1 -1
  110. package/dist/battle/AttackPreview.d.ts.map +1 -1
  111. package/dist/battle/AttackPreview.js +8 -8
  112. package/dist/battle/AttackPreview.js.map +1 -1
  113. package/dist/battle/StatStages.d.ts.map +1 -1
  114. package/dist/battle/StatStages.js +2 -1
  115. package/dist/battle/StatStages.js.map +1 -1
  116. package/dist/board/Engine.d.ts +2 -0
  117. package/dist/board/Engine.d.ts.map +1 -1
  118. package/dist/board/Engine.js +1 -1
  119. package/dist/board/Engine.js.map +1 -1
  120. package/dist/board/HexSkirmish.d.ts.map +1 -1
  121. package/dist/board/HexSkirmish.js +11 -72
  122. package/dist/board/HexSkirmish.js.map +1 -1
  123. package/dist/board/Tactics.d.ts.map +1 -1
  124. package/dist/board/Tactics.js +3 -5
  125. package/dist/board/Tactics.js.map +1 -1
  126. package/dist/board/tourney.d.ts.map +1 -1
  127. package/dist/board/tourney.js +2 -19
  128. package/dist/board/tourney.js.map +1 -1
  129. package/dist/core/Handles.js +7 -7
  130. package/dist/core/Handles.js.map +1 -1
  131. package/dist/mw_games.global.js +25 -22
  132. package/dist/mwl/conditions.d.ts +12 -0
  133. package/dist/mwl/conditions.d.ts.map +1 -1
  134. package/dist/mwl/conditions.js +49 -8
  135. package/dist/mwl/conditions.js.map +1 -1
  136. package/dist/mwl/index.d.ts +11 -0
  137. package/dist/mwl/index.d.ts.map +1 -1
  138. package/dist/mwl/index.js +6 -0
  139. package/dist/mwl/index.js.map +1 -1
  140. package/dist/mwl/package-container.d.ts +185 -0
  141. package/dist/mwl/package-container.d.ts.map +1 -0
  142. package/dist/mwl/package-container.js +446 -0
  143. package/dist/mwl/package-container.js.map +1 -0
  144. package/dist/mwl/package-document.d.ts +217 -0
  145. package/dist/mwl/package-document.d.ts.map +1 -0
  146. package/dist/mwl/package-document.js +639 -0
  147. package/dist/mwl/package-document.js.map +1 -0
  148. package/dist/mwl/package-rom.d.ts +37 -0
  149. package/dist/mwl/package-rom.d.ts.map +1 -0
  150. package/dist/mwl/package-rom.js +96 -0
  151. package/dist/mwl/package-rom.js.map +1 -0
  152. package/dist/mwl/package-verify.d.ts +34 -0
  153. package/dist/mwl/package-verify.d.ts.map +1 -0
  154. package/dist/mwl/package-verify.js +111 -0
  155. package/dist/mwl/package-verify.js.map +1 -0
  156. package/dist/mwl/package.d.ts +184 -0
  157. package/dist/mwl/package.d.ts.map +1 -0
  158. package/dist/mwl/package.js +382 -0
  159. package/dist/mwl/package.js.map +1 -0
  160. package/dist/physics/PhysicsWorld.d.ts.map +1 -1
  161. package/dist/physics/PhysicsWorld.js +4 -3
  162. package/dist/physics/PhysicsWorld.js.map +1 -1
  163. package/dist/physics/XpbdWorld.d.ts.map +1 -1
  164. package/dist/physics/XpbdWorld.js +2 -1
  165. package/dist/physics/XpbdWorld.js.map +1 -1
  166. package/dist/testing/FakeAudio.d.ts +149 -0
  167. package/dist/testing/FakeAudio.d.ts.map +1 -0
  168. package/dist/testing/FakeAudio.js +219 -0
  169. package/dist/testing/FakeAudio.js.map +1 -0
  170. package/dist/testing/index.d.ts +2 -0
  171. package/dist/testing/index.d.ts.map +1 -1
  172. package/dist/testing/index.js +1 -0
  173. package/dist/testing/index.js.map +1 -1
  174. package/dist/threads/index.d.ts +2 -2
  175. package/dist/threads/index.d.ts.map +1 -1
  176. package/dist/threads/index.js +1 -1
  177. package/dist/threads/index.js.map +1 -1
  178. package/dist/threads/spawn.d.ts +32 -0
  179. package/dist/threads/spawn.d.ts.map +1 -1
  180. package/dist/threads/spawn.js +35 -11
  181. package/dist/threads/spawn.js.map +1 -1
  182. package/dist/two-d/Game.d.ts +13 -2
  183. package/dist/two-d/Game.d.ts.map +1 -1
  184. package/dist/two-d/Game.js +42 -18
  185. package/dist/two-d/Game.js.map +1 -1
  186. package/dist/two-d/render/HazeLayer.d.ts.map +1 -1
  187. package/dist/two-d/render/HazeLayer.js +2 -1
  188. package/dist/two-d/render/HazeLayer.js.map +1 -1
  189. package/dist/two-d/render/ImageModifiers.d.ts +4 -2
  190. package/dist/two-d/render/ImageModifiers.d.ts.map +1 -1
  191. package/dist/two-d/render/ImageModifiers.js +13 -8
  192. package/dist/two-d/render/ImageModifiers.js.map +1 -1
  193. package/dist/two-d/render/NeonGlow.d.ts.map +1 -1
  194. package/dist/two-d/render/NeonGlow.js +2 -1
  195. package/dist/two-d/render/NeonGlow.js.map +1 -1
  196. package/dist/two-d/render/Particles.d.ts.map +1 -1
  197. package/dist/two-d/render/Particles.js +2 -1
  198. package/dist/two-d/render/Particles.js.map +1 -1
  199. package/dist/two-d/render/SceneTransition.d.ts +29 -0
  200. package/dist/two-d/render/SceneTransition.d.ts.map +1 -1
  201. package/dist/two-d/render/SceneTransition.js +27 -0
  202. package/dist/two-d/render/SceneTransition.js.map +1 -1
  203. package/dist/two-d/render/ScreenEffects.d.ts.map +1 -1
  204. package/dist/two-d/render/ScreenEffects.js +2 -1
  205. package/dist/two-d/render/ScreenEffects.js.map +1 -1
  206. package/dist/two-d/render/SkeletalSprite.d.ts.map +1 -1
  207. package/dist/two-d/render/SkeletalSprite.js +2 -1
  208. package/dist/two-d/render/SkeletalSprite.js.map +1 -1
  209. package/dist/two-d/render/Types2D.d.ts +2 -2
  210. package/dist/two-d/render/Types2D.d.ts.map +1 -1
  211. package/dist/two-d/render/Types2D.js +2 -2
  212. package/dist/two-d/render/Types2D.js.map +1 -1
  213. package/dist/two-d/render/index.d.ts +2 -2
  214. package/dist/two-d/render/index.d.ts.map +1 -1
  215. package/dist/two-d/render/index.js +1 -1
  216. package/dist/two-d/render/index.js.map +1 -1
  217. package/dist/two-d/ui/Bar.d.ts.map +1 -1
  218. package/dist/two-d/ui/Bar.js +3 -5
  219. package/dist/two-d/ui/Bar.js.map +1 -1
  220. package/dist/two-d/ui/Dropdown.d.ts +5 -1
  221. package/dist/two-d/ui/Dropdown.d.ts.map +1 -1
  222. package/dist/two-d/ui/Dropdown.js +8 -1
  223. package/dist/two-d/ui/Dropdown.js.map +1 -1
  224. package/dist/two-d/ui/DropdownView.d.ts +15 -1
  225. package/dist/two-d/ui/DropdownView.d.ts.map +1 -1
  226. package/dist/two-d/ui/DropdownView.js +21 -3
  227. package/dist/two-d/ui/DropdownView.js.map +1 -1
  228. package/dist/two-d/ui/FloatingText.d.ts.map +1 -1
  229. package/dist/two-d/ui/FloatingText.js +2 -1
  230. package/dist/two-d/ui/FloatingText.js.map +1 -1
  231. package/dist/two-d/ui/IconGrid.d.ts.map +1 -1
  232. package/dist/two-d/ui/IconGrid.js +2 -1
  233. package/dist/two-d/ui/IconGrid.js.map +1 -1
  234. package/dist/two-d/ui/ListView.d.ts.map +1 -1
  235. package/dist/two-d/ui/ListView.js +2 -1
  236. package/dist/two-d/ui/ListView.js.map +1 -1
  237. package/dist/two-d/ui/ScrollBox.d.ts +6 -0
  238. package/dist/two-d/ui/ScrollBox.d.ts.map +1 -1
  239. package/dist/two-d/ui/ScrollBox.js +12 -1
  240. package/dist/two-d/ui/ScrollBox.js.map +1 -1
  241. package/dist/two-d/ui/ScrollText.d.ts +11 -2
  242. package/dist/two-d/ui/ScrollText.d.ts.map +1 -1
  243. package/dist/two-d/ui/ScrollText.js +18 -2
  244. package/dist/two-d/ui/ScrollText.js.map +1 -1
  245. package/dist/two-d/ui/Slider.d.ts.map +1 -1
  246. package/dist/two-d/ui/Slider.js +4 -4
  247. package/dist/two-d/ui/Slider.js.map +1 -1
  248. package/dist/version.d.ts +1 -1
  249. package/dist/version.js +1 -1
  250. package/package.json +8 -1
  251. package/sbom.cdx.json +6 -6
  252. package/tools/audio.d.mts +75 -0
  253. package/tools/audio.mjs +437 -0
  254. package/tools/mwl.mjs +144 -2
  255. package/tools.md +1 -1
@@ -0,0 +1,73 @@
1
+ import type { MidiSynth } from './MidiSynth.ts';
2
+ import type { RenderedMidi } from './MidiRender.ts';
3
+ /**
4
+ * The system-exclusive messages of a `.syx` file, in file order, each framed by its 0xF0
5
+ * and 0xF7. Bytes before the first 0xF0 and an unterminated final message are not
6
+ * messages and are left out, because a bank file a player dropped is likelier truncated
7
+ * or padded than malicious, and the messages that are whole are still usable.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * import { splitSysex } from '@datamoc/mw_games/audio';
12
+ *
13
+ * const messages = splitSysex(new Uint8Array([0xf0, 0x41, 0xf7, 0xf0, 0x42, 0xf7]));
14
+ * console.log(messages.length); // 2
15
+ * ```
16
+ */
17
+ export declare function splitSysex(bytes: Uint8Array): Uint8Array[];
18
+ /** one named patch inside a bank: which message carries it and where its voice sits in it */
19
+ export interface SyxPatch {
20
+ name: string;
21
+ /** index into `splitSysex(bytes)` of the message the patch belongs to */
22
+ message: number;
23
+ /** the voice's number inside that message's bank, 0-based */
24
+ voice: number;
25
+ }
26
+ /**
27
+ * The patch names of a `.syx` bank: every DX7 32-voice bulk dump in it contributes its
28
+ * 32 voices, whose names are the last ten bytes of each packed voice. Messages that are
29
+ * not whole, checksummed DX7 banks contribute nothing (their names would be guesses).
30
+ *
31
+ * @example
32
+ * ```ts
33
+ * import { dx7PatchNames } from '@datamoc/mw_games/audio';
34
+ *
35
+ * declare const bankBytes: Uint8Array;
36
+ *
37
+ * console.log(dx7PatchNames(bankBytes)); // ['BRASS1', 'STRINGS', ...] or [] for another maker's bank
38
+ * ```
39
+ */
40
+ export declare function dx7PatchNames(bytes: Uint8Array): SyxPatch[];
41
+ /**
42
+ * A `.syx` bank a player dropped: its messages, the DX7 patch names in it, and an
43
+ * audition that loads a patch into a `MidiSynth` and renders one note through it, so a
44
+ * settings screen can show the names and let the player hear one before committing.
45
+ * Auditioning sends the whole bank message (a DX7 loads voices as a bank, and the synth
46
+ * owns which voice it then plays), then a single note for `seconds` plus a short tail.
47
+ *
48
+ * @example
49
+ * ```ts
50
+ * import { SyxBank, type MidiSynth } from '@datamoc/mw_games/audio';
51
+ *
52
+ * declare const bankBytes: Uint8Array;
53
+ * declare const synth: MidiSynth;
54
+ *
55
+ * const bank = new SyxBank(bankBytes);
56
+ * console.log(bank.patches.map((patch) => patch.name));
57
+ * const heard = bank.audition(synth, bank.patches[0]);
58
+ * console.log(heard.duration > 0); // true
59
+ * ```
60
+ */
61
+ export declare class SyxBank {
62
+ /** every whole sysex message in the file, in order */
63
+ readonly messages: Uint8Array[];
64
+ /** the DX7 patches in it, in bank order; empty for another maker's bank */
65
+ readonly patches: SyxPatch[];
66
+ constructor(bytes: Uint8Array);
67
+ /**
68
+ * Renders one note with `patch` loaded into `synth`: the patch's bank message goes to
69
+ * the synth as sysex, then the note sounds for `seconds` and decays over a short tail.
70
+ */
71
+ audition(synth: MidiSynth, patch: SyxPatch, note?: number, seconds?: number): RenderedMidi;
72
+ }
73
+ //# sourceMappingURL=SyxBank.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SyxBank.d.ts","sourceRoot":"","sources":["../../src/audio/SyxBank.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAEpD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,UAAU,EAAE,CAW1D;AAED,6FAA6F;AAC7F,MAAM,WAAW,QAAQ;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,yEAAyE;IACzE,OAAO,EAAE,MAAM,CAAC;IAChB,6DAA6D;IAC7D,KAAK,EAAE,MAAM,CAAC;CACd;AAuBD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,QAAQ,EAAE,CAc3D;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,OAAO;IACnB,sDAAsD;IACtD,QAAQ,CAAC,QAAQ,EAAE,UAAU,EAAE,CAAC;IAChC,2EAA2E;IAC3E,QAAQ,CAAC,OAAO,EAAE,QAAQ,EAAE,CAAC;IAE7B,YAAY,KAAK,EAAE,UAAU,EAG5B;IAED;;;OAGG;IACH,QAAQ,CAAC,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,SAAK,EAAE,OAAO,SAAM,GAAG,YAAY,CAgBlF;CACD"}
@@ -0,0 +1,130 @@
1
+ /**
2
+ * The system-exclusive messages of a `.syx` file, in file order, each framed by its 0xF0
3
+ * and 0xF7. Bytes before the first 0xF0 and an unterminated final message are not
4
+ * messages and are left out, because a bank file a player dropped is likelier truncated
5
+ * or padded than malicious, and the messages that are whole are still usable.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * import { splitSysex } from '@datamoc/mw_games/audio';
10
+ *
11
+ * const messages = splitSysex(new Uint8Array([0xf0, 0x41, 0xf7, 0xf0, 0x42, 0xf7]));
12
+ * console.log(messages.length); // 2
13
+ * ```
14
+ */
15
+ export function splitSysex(bytes) {
16
+ const messages = [];
17
+ let start = -1;
18
+ for (let i = 0; i < bytes.length; i++) {
19
+ if (bytes[i] === 0xf0)
20
+ start = i;
21
+ else if (bytes[i] === 0xf7 && start >= 0) {
22
+ messages.push(bytes.slice(start, i + 1));
23
+ start = -1;
24
+ }
25
+ }
26
+ return messages;
27
+ }
28
+ const DX7_BULK_DATA = 4096;
29
+ const DX7_VOICES = 32;
30
+ const DX7_PACKED_VOICE = 128;
31
+ /**
32
+ * Whether a message is a DX7 32-voice bulk dump, and its data checked: the header names
33
+ * Yamaha and the bulk format, the length is one whole bank, and the checksum (the data
34
+ * bytes and the checksum together summing to a multiple of 128) holds. A bank whose
35
+ * checksum fails is not a bank whose names can be trusted.
36
+ */
37
+ function dx7BankData(message) {
38
+ //F0 43 0n 09 20 00, then the data, a checksum and F7
39
+ if (message.length !== 6 + DX7_BULK_DATA + 2)
40
+ return null;
41
+ if (message[0] !== 0xf0 || message[1] !== 0x43 || (message[2] & 0xf0) !== 0x00)
42
+ return null;
43
+ if (message[3] !== 0x09 || message[4] !== 0x20 || message[5] !== 0x00)
44
+ return null;
45
+ const data = message.subarray(6, 6 + DX7_BULK_DATA);
46
+ let sum = message[6 + DX7_BULK_DATA];
47
+ for (const byte of data)
48
+ sum += byte;
49
+ return sum % 128 === 0 ? data : null;
50
+ }
51
+ /**
52
+ * The patch names of a `.syx` bank: every DX7 32-voice bulk dump in it contributes its
53
+ * 32 voices, whose names are the last ten bytes of each packed voice. Messages that are
54
+ * not whole, checksummed DX7 banks contribute nothing (their names would be guesses).
55
+ *
56
+ * @example
57
+ * ```ts
58
+ * import { dx7PatchNames } from '@datamoc/mw_games/audio';
59
+ *
60
+ * declare const bankBytes: Uint8Array;
61
+ *
62
+ * console.log(dx7PatchNames(bankBytes)); // ['BRASS1', 'STRINGS', ...] or [] for another maker's bank
63
+ * ```
64
+ */
65
+ export function dx7PatchNames(bytes) {
66
+ const patches = [];
67
+ splitSysex(bytes).forEach((message, index) => {
68
+ const data = dx7BankData(message);
69
+ if (!data)
70
+ return;
71
+ for (let voice = 0; voice < DX7_VOICES; voice++) {
72
+ const at = voice * DX7_PACKED_VOICE + 118;
73
+ const name = String.fromCharCode(...data.subarray(at, at + 10))
74
+ .replaceAll('\0', ' ')
75
+ .trim();
76
+ patches.push({ name, message: index, voice });
77
+ }
78
+ });
79
+ return patches;
80
+ }
81
+ /**
82
+ * A `.syx` bank a player dropped: its messages, the DX7 patch names in it, and an
83
+ * audition that loads a patch into a `MidiSynth` and renders one note through it, so a
84
+ * settings screen can show the names and let the player hear one before committing.
85
+ * Auditioning sends the whole bank message (a DX7 loads voices as a bank, and the synth
86
+ * owns which voice it then plays), then a single note for `seconds` plus a short tail.
87
+ *
88
+ * @example
89
+ * ```ts
90
+ * import { SyxBank, type MidiSynth } from '@datamoc/mw_games/audio';
91
+ *
92
+ * declare const bankBytes: Uint8Array;
93
+ * declare const synth: MidiSynth;
94
+ *
95
+ * const bank = new SyxBank(bankBytes);
96
+ * console.log(bank.patches.map((patch) => patch.name));
97
+ * const heard = bank.audition(synth, bank.patches[0]);
98
+ * console.log(heard.duration > 0); // true
99
+ * ```
100
+ */
101
+ export class SyxBank {
102
+ constructor(bytes) {
103
+ this.messages = splitSysex(bytes);
104
+ this.patches = dx7PatchNames(bytes);
105
+ }
106
+ /**
107
+ * Renders one note with `patch` loaded into `synth`: the patch's bank message goes to
108
+ * the synth as sysex, then the note sounds for `seconds` and decays over a short tail.
109
+ */
110
+ audition(synth, patch, note = 60, seconds = 0.5) {
111
+ const sampleRate = synth.sampleRate;
112
+ const tail = 0.25;
113
+ const frames = Math.max(1, Math.ceil((seconds + tail) * sampleRate));
114
+ const left = new Float32Array(frames);
115
+ const right = new Float32Array(frames);
116
+ synth.reset();
117
+ const message = this.messages[patch.message];
118
+ if (message)
119
+ synth.sysex(message);
120
+ synth.event(0x90, note, 96);
121
+ const sounding = Math.min(frames, Math.ceil(seconds * sampleRate));
122
+ synth.render(left, right, 0, sounding);
123
+ synth.event(0x80, note, 0);
124
+ if (frames > sounding)
125
+ synth.render(left, right, sounding, frames - sounding);
126
+ synth.reset();
127
+ return { sampleRate, left, right, loopStart: 0, loopEnd: seconds + tail, duration: seconds + tail };
128
+ }
129
+ }
130
+ //# sourceMappingURL=SyxBank.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SyxBank.js","sourceRoot":"","sources":["../../src/audio/SyxBank.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import { Signal } from '../core/Signal.ts';
2
+ /** audio that ran out before the next block was ready: a gap the player hears as a click or a dropout */
3
+ export interface AudioUnderrun {
4
+ /** what ran dry: `'stream'` for a `StreamChannel`, `'core'` for an `AudioCoreHost` */
5
+ source: 'stream' | 'core';
6
+ /** how much audio was missing, in seconds */
7
+ lateSeconds: number;
8
+ }
9
+ /**
10
+ * The one place every audio underrun is reported, whichever voice had it. A game forwards this to
11
+ * its telemetry (`TelemetryClient`, which bounds what it sends) or shows it in a settings panel;
12
+ * the voices also have their own signals for code that cares about a single one.
13
+ *
14
+ * @example
15
+ * ```ts
16
+ * import { onAudioUnderrun } from '@datamoc/mw_games/audio';
17
+ *
18
+ * let dropouts = 0;
19
+ * onAudioUnderrun.add(() => {
20
+ * dropouts++;
21
+ * });
22
+ * ```
23
+ */
24
+ export declare const onAudioUnderrun: Signal<AudioUnderrun>;
25
+ //# sourceMappingURL=Underrun.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Underrun.d.ts","sourceRoot":"","sources":["../../src/audio/Underrun.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3C,yGAAyG;AACzG,MAAM,WAAW,aAAa;IAC7B,sFAAsF;IACtF,MAAM,EAAE,QAAQ,GAAG,MAAM,CAAC;IAC1B,6CAA6C;IAC7C,WAAW,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,eAAe,uBAA8B,CAAC"}
@@ -0,0 +1,18 @@
1
+ import { Signal } from '../core/Signal.js';
2
+ /**
3
+ * The one place every audio underrun is reported, whichever voice had it. A game forwards this to
4
+ * its telemetry (`TelemetryClient`, which bounds what it sends) or shows it in a settings panel;
5
+ * the voices also have their own signals for code that cares about a single one.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * import { onAudioUnderrun } from '@datamoc/mw_games/audio';
10
+ *
11
+ * let dropouts = 0;
12
+ * onAudioUnderrun.add(() => {
13
+ * dropouts++;
14
+ * });
15
+ * ```
16
+ */
17
+ export const onAudioUnderrun = new Signal();
18
+ //# sourceMappingURL=Underrun.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Underrun.js","sourceRoot":"","sources":["../../src/audio/Underrun.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAU3C;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,MAAM,EAAiB,CAAC"}
@@ -0,0 +1,56 @@
1
+ import type { StereoFrames } from './Resample.ts';
2
+ /**
3
+ * Writes stereo frames as a canonical RIFF/WAVE file: 16-bit PCM by default, or 32-bit float
4
+ * when the samples must survive unclipped. The one container every tool and browser reads, which
5
+ * is why the offline renders of this module go out through it.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * import { encodeWav, renderMidiToBuffer, parseMidi } from '@datamoc/mw_games/audio';
10
+ *
11
+ * declare const midiBytes: ArrayBuffer;
12
+ *
13
+ * const wav = encodeWav(renderMidiToBuffer(parseMidi(midiBytes)));
14
+ * console.log(wav.byteLength);
15
+ * ```
16
+ */
17
+ export declare function encodeWav(frames: StereoFrames, format?: 'pcm16' | 'float32'): Uint8Array;
18
+ /** what a WAVE header says, without decoding the samples */
19
+ export interface WavInfo {
20
+ channels: number;
21
+ sampleRate: number;
22
+ bitsPerSample: number;
23
+ /** `'pcm'` for integer samples, `'float'` for IEEE float */
24
+ encoding: 'pcm' | 'float';
25
+ frames: number;
26
+ seconds: number;
27
+ }
28
+ /**
29
+ * Reads a WAVE header: layout and length, no samples.
30
+ *
31
+ * @example
32
+ * ```ts
33
+ * import { wavInfo } from '@datamoc/mw_games/audio';
34
+ *
35
+ * declare const bytes: Uint8Array;
36
+ *
37
+ * console.log(wavInfo(bytes).sampleRate);
38
+ * ```
39
+ */
40
+ export declare function wavInfo(bytes: Uint8Array): WavInfo;
41
+ /**
42
+ * Decodes a PCM (8, 16, 24 or 32 bit) or float32 WAVE file to stereo frames: a mono file is
43
+ * duplicated to both channels, and channels past the second are dropped.
44
+ *
45
+ * @example
46
+ * ```ts
47
+ * import { decodeWav } from '@datamoc/mw_games/audio';
48
+ *
49
+ * declare const bytes: Uint8Array;
50
+ *
51
+ * const { sampleRate, left } = decodeWav(bytes);
52
+ * console.log(sampleRate, left.length);
53
+ * ```
54
+ */
55
+ export declare function decodeWav(bytes: Uint8Array): StereoFrames;
56
+ //# sourceMappingURL=Wav.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Wav.d.ts","sourceRoot":"","sources":["../../src/audio/Wav.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,YAAY,EAAE,MAAM,GAAE,OAAO,GAAG,SAAmB,GAAG,UAAU,CAmCjG;AAED,4DAA4D;AAC5D,MAAM,WAAW,OAAO;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,4DAA4D;IAC5D,QAAQ,EAAE,KAAK,GAAG,OAAO,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CAChB;AA8CD;;;;;;;;;;;GAWG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAElD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,UAAU,GAAG,YAAY,CA8BzD"}
@@ -0,0 +1,164 @@
1
+ /**
2
+ * Writes stereo frames as a canonical RIFF/WAVE file: 16-bit PCM by default, or 32-bit float
3
+ * when the samples must survive unclipped. The one container every tool and browser reads, which
4
+ * is why the offline renders of this module go out through it.
5
+ *
6
+ * @example
7
+ * ```ts
8
+ * import { encodeWav, renderMidiToBuffer, parseMidi } from '@datamoc/mw_games/audio';
9
+ *
10
+ * declare const midiBytes: ArrayBuffer;
11
+ *
12
+ * const wav = encodeWav(renderMidiToBuffer(parseMidi(midiBytes)));
13
+ * console.log(wav.byteLength);
14
+ * ```
15
+ */
16
+ export function encodeWav(frames, format = 'pcm16') {
17
+ const count = frames.left.length;
18
+ if (frames.right.length !== count)
19
+ throw new Error('the two channels must have the same length');
20
+ const bytesPerSample = format === 'pcm16' ? 2 : 4;
21
+ const dataBytes = count * 2 * bytesPerSample;
22
+ const out = new Uint8Array(44 + dataBytes);
23
+ const view = new DataView(out.buffer);
24
+ const text = (offset, value) => {
25
+ for (let i = 0; i < value.length; i++)
26
+ out[offset + i] = value.charCodeAt(i);
27
+ };
28
+ text(0, 'RIFF');
29
+ view.setUint32(4, 36 + dataBytes, true);
30
+ text(8, 'WAVE');
31
+ text(12, 'fmt ');
32
+ view.setUint32(16, 16, true);
33
+ view.setUint16(20, format === 'pcm16' ? 1 : 3, true);
34
+ view.setUint16(22, 2, true);
35
+ view.setUint32(24, Math.round(frames.sampleRate), true);
36
+ view.setUint32(28, Math.round(frames.sampleRate) * 2 * bytesPerSample, true);
37
+ view.setUint16(32, 2 * bytesPerSample, true);
38
+ view.setUint16(34, bytesPerSample * 8, true);
39
+ text(36, 'data');
40
+ view.setUint32(40, dataBytes, true);
41
+ let at = 44;
42
+ for (let i = 0; i < count; i++) {
43
+ for (const sample of [frames.left[i], frames.right[i]]) {
44
+ if (format === 'pcm16') {
45
+ view.setInt16(at, Math.round(Math.max(-1, Math.min(1, sample)) * 32767), true);
46
+ }
47
+ else {
48
+ view.setFloat32(at, sample, true);
49
+ }
50
+ at += bytesPerSample;
51
+ }
52
+ }
53
+ return out;
54
+ }
55
+ function wavChunks(bytes) {
56
+ if (bytes.length < 12 || String.fromCharCode(...bytes.subarray(0, 4)) !== 'RIFF')
57
+ throw new Error('not a RIFF file');
58
+ if (String.fromCharCode(...bytes.subarray(8, 12)) !== 'WAVE')
59
+ throw new Error('not a WAVE file');
60
+ const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
61
+ let format = null;
62
+ let offset = 12;
63
+ while (offset + 8 <= bytes.length) {
64
+ const id = String.fromCharCode(...bytes.subarray(offset, offset + 4));
65
+ const size = view.getUint32(offset + 4, true);
66
+ const body = offset + 8;
67
+ if (id === 'fmt ') {
68
+ if (size < 16 || body + 16 > bytes.length)
69
+ throw new Error('truncated fmt chunk');
70
+ format = {
71
+ tag: view.getUint16(body, true),
72
+ channels: view.getUint16(body + 2, true),
73
+ rate: view.getUint32(body + 4, true),
74
+ bits: view.getUint16(body + 14, true),
75
+ };
76
+ }
77
+ else if (id === 'data') {
78
+ if (!format)
79
+ throw new Error('data chunk before fmt chunk');
80
+ const available = Math.min(size, bytes.length - body);
81
+ const encoding = format.tag === 3 ? 'float' : 'pcm';
82
+ if (format.tag !== 1 && format.tag !== 3)
83
+ throw new Error(`unsupported WAVE format tag ${format.tag}`);
84
+ if (format.channels < 1 || format.bits % 8 !== 0 || format.bits < 8)
85
+ throw new Error('unsupported sample layout');
86
+ const frames = Math.floor(available / (format.channels * (format.bits / 8)));
87
+ return {
88
+ info: {
89
+ channels: format.channels,
90
+ sampleRate: format.rate,
91
+ bitsPerSample: format.bits,
92
+ encoding,
93
+ frames,
94
+ seconds: format.rate > 0 ? frames / format.rate : 0,
95
+ },
96
+ dataOffset: body,
97
+ };
98
+ }
99
+ offset = body + size + (size % 2);
100
+ }
101
+ throw new Error('no data chunk');
102
+ }
103
+ /**
104
+ * Reads a WAVE header: layout and length, no samples.
105
+ *
106
+ * @example
107
+ * ```ts
108
+ * import { wavInfo } from '@datamoc/mw_games/audio';
109
+ *
110
+ * declare const bytes: Uint8Array;
111
+ *
112
+ * console.log(wavInfo(bytes).sampleRate);
113
+ * ```
114
+ */
115
+ export function wavInfo(bytes) {
116
+ return wavChunks(bytes).info;
117
+ }
118
+ /**
119
+ * Decodes a PCM (8, 16, 24 or 32 bit) or float32 WAVE file to stereo frames: a mono file is
120
+ * duplicated to both channels, and channels past the second are dropped.
121
+ *
122
+ * @example
123
+ * ```ts
124
+ * import { decodeWav } from '@datamoc/mw_games/audio';
125
+ *
126
+ * declare const bytes: Uint8Array;
127
+ *
128
+ * const { sampleRate, left } = decodeWav(bytes);
129
+ * console.log(sampleRate, left.length);
130
+ * ```
131
+ */
132
+ export function decodeWav(bytes) {
133
+ const { info, dataOffset } = wavChunks(bytes);
134
+ const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
135
+ const width = info.bitsPerSample / 8;
136
+ const left = new Float32Array(info.frames);
137
+ const right = new Float32Array(info.frames);
138
+ const read = (at) => {
139
+ if (info.encoding === 'float') {
140
+ if (width !== 4)
141
+ throw new Error('only 32-bit float is supported');
142
+ return view.getFloat32(at, true);
143
+ }
144
+ switch (width) {
145
+ case 1:
146
+ return (view.getUint8(at) - 128) / 128;
147
+ case 2:
148
+ return view.getInt16(at, true) / 32768;
149
+ case 3:
150
+ return (view.getUint8(at) | (view.getUint8(at + 1) << 8) | (view.getInt8(at + 2) << 16) | 0) / 8388608;
151
+ case 4:
152
+ return view.getInt32(at, true) / 2147483648;
153
+ default:
154
+ throw new Error(`unsupported sample width ${info.bitsPerSample}`);
155
+ }
156
+ };
157
+ for (let i = 0; i < info.frames; i++) {
158
+ const at = dataOffset + i * info.channels * width;
159
+ left[i] = read(at);
160
+ right[i] = info.channels > 1 ? read(at + width) : left[i];
161
+ }
162
+ return { sampleRate: info.sampleRate, left, right };
163
+ }
164
+ //# sourceMappingURL=Wav.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Wav.js","sourceRoot":"","sources":["../../src/audio/Wav.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,58 @@
1
+ import type { MidiSynth } from './MidiSynth.ts';
2
+ /** one live input port, the part of `MIDIInput` this adapter reads */
3
+ export interface WebMidiInputPort {
4
+ readonly name?: string | null;
5
+ onmidimessage: ((event: {
6
+ data: Uint8Array | null;
7
+ }) => void) | null;
8
+ }
9
+ /** the part of `MIDIAccess` this adapter reads: its input ports, by id */
10
+ export interface WebMidiAccess {
11
+ readonly inputs: ReadonlyMap<string, WebMidiInputPort>;
12
+ }
13
+ /** a live Web MIDI connection: how many ports feed the synth, and how to stop them */
14
+ export interface WebMidiConnection {
15
+ /** how many input ports are wired to the synth */
16
+ readonly ports: number;
17
+ /** detaches every port; a port wired again afterwards is a new connection */
18
+ disconnect(): void;
19
+ }
20
+ /**
21
+ * Wires every input of a Web MIDI access to a `MidiSynth`: channel messages go to
22
+ * `event`, system-exclusive ones (framed by 0xF0 and 0xF7) to `sysex`, and everything
23
+ * else (clock, active sensing, a message with no data) is dropped, because a synth
24
+ * voices notes, not transport. The access is taken as a value, so a test hands in a
25
+ * fake and a browser hands in `navigator.requestMIDIAccess()`'s answer through
26
+ * `requestWebMidiInput`.
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * import { connectWebMidi, type MidiSynth, type WebMidiAccess } from '@datamoc/mw_games/audio';
31
+ *
32
+ * declare const access: WebMidiAccess;
33
+ * declare const synth: MidiSynth;
34
+ *
35
+ * const link = connectWebMidi(access, synth);
36
+ * console.log(link.ports); // how many keyboards are playing into the synth
37
+ * link.disconnect();
38
+ * ```
39
+ */
40
+ export declare function connectWebMidi(access: WebMidiAccess, synth: MidiSynth): WebMidiConnection;
41
+ /**
42
+ * Asks the browser for Web MIDI and wires it to `synth`: null where the browser has no
43
+ * Web MIDI (or the player refused it), so a game offers the live keyboard only where it
44
+ * can exist. System-exclusive is requested, since a bank dump arrives as sysex; a refusal
45
+ * of sysex alone still connects, without it.
46
+ *
47
+ * @example
48
+ * ```ts
49
+ * import { requestWebMidiInput, type MidiSynth } from '@datamoc/mw_games/audio';
50
+ *
51
+ * declare const synth: MidiSynth;
52
+ *
53
+ * const link = await requestWebMidiInput(synth);
54
+ * console.log(link === null ? 'no live input here' : `${link.ports} port(s) live`);
55
+ * ```
56
+ */
57
+ export declare function requestWebMidiInput(synth: MidiSynth): Promise<WebMidiConnection | null>;
58
+ //# sourceMappingURL=WebMidi.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WebMidi.d.ts","sourceRoot":"","sources":["../../src/audio/WebMidi.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEhD,sEAAsE;AACtE,MAAM,WAAW,gBAAgB;IAChC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,aAAa,EAAE,CAAC,CAAC,KAAK,EAAE;QAAE,IAAI,EAAE,UAAU,GAAG,IAAI,CAAA;KAAE,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC;CACrE;AAED,0EAA0E;AAC1E,MAAM,WAAW,aAAa;IAC7B,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;CACvD;AAED,sFAAsF;AACtF,MAAM,WAAW,iBAAiB;IACjC,kDAAkD;IAClD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,6EAA6E;IAC7E,UAAU,IAAI,IAAI,CAAC;CACnB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,SAAS,GAAG,iBAAiB,CAoBzF;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,mBAAmB,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAc7F"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Wires every input of a Web MIDI access to a `MidiSynth`: channel messages go to
3
+ * `event`, system-exclusive ones (framed by 0xF0 and 0xF7) to `sysex`, and everything
4
+ * else (clock, active sensing, a message with no data) is dropped, because a synth
5
+ * voices notes, not transport. The access is taken as a value, so a test hands in a
6
+ * fake and a browser hands in `navigator.requestMIDIAccess()`'s answer through
7
+ * `requestWebMidiInput`.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * import { connectWebMidi, type MidiSynth, type WebMidiAccess } from '@datamoc/mw_games/audio';
12
+ *
13
+ * declare const access: WebMidiAccess;
14
+ * declare const synth: MidiSynth;
15
+ *
16
+ * const link = connectWebMidi(access, synth);
17
+ * console.log(link.ports); // how many keyboards are playing into the synth
18
+ * link.disconnect();
19
+ * ```
20
+ */
21
+ export function connectWebMidi(access, synth) {
22
+ const wired = [];
23
+ for (const input of access.inputs.values()) {
24
+ input.onmidimessage = (event) => {
25
+ const data = event.data;
26
+ if (!data || data.length === 0)
27
+ return;
28
+ if (data[0] === 0xf0)
29
+ synth.sysex(data);
30
+ else if ((data[0] & 0xf0) !== 0xf0)
31
+ synth.event(data[0], data[1] ?? 0, data[2] ?? 0);
32
+ };
33
+ wired.push(input);
34
+ }
35
+ let connected = true;
36
+ return {
37
+ ports: wired.length,
38
+ disconnect() {
39
+ if (!connected)
40
+ return;
41
+ connected = false;
42
+ for (const input of wired)
43
+ input.onmidimessage = null;
44
+ },
45
+ };
46
+ }
47
+ /**
48
+ * Asks the browser for Web MIDI and wires it to `synth`: null where the browser has no
49
+ * Web MIDI (or the player refused it), so a game offers the live keyboard only where it
50
+ * can exist. System-exclusive is requested, since a bank dump arrives as sysex; a refusal
51
+ * of sysex alone still connects, without it.
52
+ *
53
+ * @example
54
+ * ```ts
55
+ * import { requestWebMidiInput, type MidiSynth } from '@datamoc/mw_games/audio';
56
+ *
57
+ * declare const synth: MidiSynth;
58
+ *
59
+ * const link = await requestWebMidiInput(synth);
60
+ * console.log(link === null ? 'no live input here' : `${link.ports} port(s) live`);
61
+ * ```
62
+ */
63
+ export async function requestWebMidiInput(synth) {
64
+ const nav = navigator;
65
+ if (typeof nav.requestMIDIAccess !== 'function')
66
+ return null;
67
+ try {
68
+ return connectWebMidi((await nav.requestMIDIAccess({ sysex: true })), synth);
69
+ }
70
+ catch {
71
+ try {
72
+ return connectWebMidi((await nav.requestMIDIAccess()), synth);
73
+ }
74
+ catch {
75
+ return null;
76
+ }
77
+ }
78
+ }
79
+ //# sourceMappingURL=WebMidi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WebMidi.js","sourceRoot":"","sources":["../../src/audio/WebMidi.ts"],"names":[],"mappings":"AAqBA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,cAAc,CAAC,MAAqB,EAAE,KAAgB;IACrE,MAAM,KAAK,GAAuB,EAAE,CAAC;IACrC,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC;QAC5C,KAAK,CAAC,aAAa,GAAG,CAAC,KAAK,EAAE,EAAE;YAC/B,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;YACxB,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO;YACvC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI;gBAAE,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;iBACnC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,IAAI;gBAAE,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QACtF,CAAC,CAAC;QACF,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACnB,CAAC;IACD,IAAI,SAAS,GAAG,IAAI,CAAC;IACrB,OAAO;QACN,KAAK,EAAE,KAAK,CAAC,MAAM;QACnB,UAAU;YACT,IAAI,CAAC,SAAS;gBAAE,OAAO;YACvB,SAAS,GAAG,KAAK,CAAC;YAClB,KAAK,MAAM,KAAK,IAAI,KAAK;gBAAE,KAAK,CAAC,aAAa,GAAG,IAAI,CAAC;QACvD,CAAC;KACD,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,KAAgB;IACzD,MAAM,GAAG,GAAG,SAEX,CAAC;IACF,IAAI,OAAO,GAAG,CAAC,iBAAiB,KAAK,UAAU;QAAE,OAAO,IAAI,CAAC;IAC7D,IAAI,CAAC;QACJ,OAAO,cAAc,CAAC,CAAC,MAAM,GAAG,CAAC,iBAAiB,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAkB,EAAE,KAAK,CAAC,CAAC;IAC/F,CAAC;IAAC,MAAM,CAAC;QACR,IAAI,CAAC;YACJ,OAAO,cAAc,CAAC,CAAC,MAAM,GAAG,CAAC,iBAAiB,EAAE,CAAkB,EAAE,KAAK,CAAC,CAAC;QAChF,CAAC;QAAC,MAAM,CAAC;YACR,OAAO,IAAI,CAAC;QACb,CAAC;IACF,CAAC;AACF,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"Onsets.d.ts","sourceRoot":"","sources":["../../../src/audio/humanize/Onsets.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AA0EH;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE,CAwEhF"}
1
+ {"version":3,"file":"Onsets.d.ts","sourceRoot":"","sources":["../../../src/audio/humanize/Onsets.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AA4BH;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE,CAwEhF"}