@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,119 @@
1
+ import { timedMidiMessages } from './Midi.js';
2
+ /**
3
+ * A waveform reduced to `buckets` min/max pairs, what an oscilloscope or overview strip
4
+ * draws: each bucket covers an equal span of the samples (the last may be shorter), so a
5
+ * peak that lasts one sample still shows, which a plain average would erase.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * import { waveformEnvelope } from '@datamoc/mw_games/audio';
10
+ *
11
+ * const view = waveformEnvelope(new Float32Array([0, 1, -1, 0.5]), 2);
12
+ * console.log(view); // [{ min: 0, max: 1 }, { min: -1, max: 0.5 }]
13
+ * ```
14
+ */
15
+ export function waveformEnvelope(samples, buckets) {
16
+ if (buckets < 1 || samples.length === 0)
17
+ return [];
18
+ const out = [];
19
+ for (let bucket = 0; bucket < buckets; bucket++) {
20
+ const from = Math.floor((bucket * samples.length) / buckets);
21
+ const to = Math.max(from + 1, Math.floor(((bucket + 1) * samples.length) / buckets));
22
+ let min = Infinity;
23
+ let max = -Infinity;
24
+ for (let i = from; i < Math.min(to, samples.length); i++) {
25
+ if (samples[i] < min)
26
+ min = samples[i];
27
+ if (samples[i] > max)
28
+ max = samples[i];
29
+ }
30
+ out.push({ min: min === Infinity ? 0 : min, max: max === -Infinity ? 0 : max });
31
+ }
32
+ return out;
33
+ }
34
+ /**
35
+ * Per-channel waveform envelopes of stereo frames: channel 0 is the left, 1 the right,
36
+ * and a view asks each channel for the same number of buckets.
37
+ *
38
+ * @example
39
+ * ```ts
40
+ * import { channelEnvelopes } from '@datamoc/mw_games/audio';
41
+ *
42
+ * const [left] = channelEnvelopes(new Float32Array([1, -1]), new Float32Array([0.5, -0.5]), 1);
43
+ * console.log(left); // [{ min: -1, max: 1 }]
44
+ * ```
45
+ */
46
+ export function channelEnvelopes(left, right, buckets) {
47
+ return [waveformEnvelope(left, buckets), waveformEnvelope(right, buckets)];
48
+ }
49
+ const NOTE_NAMES = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'];
50
+ /**
51
+ * A MIDI note number as a tracker spells it: name and octave, middle C as C4.
52
+ *
53
+ * @example
54
+ * ```ts
55
+ * import { trackerNoteName } from '@datamoc/mw_games/audio';
56
+ *
57
+ * console.log(trackerNoteName(60)); // 'C4'
58
+ * console.log(trackerNoteName(61)); // 'C#4'
59
+ * ```
60
+ */
61
+ export function trackerNoteName(note) {
62
+ return `${NOTE_NAMES[((note % 12) + 12) % 12]}${Math.floor(note / 12) - 1}`;
63
+ }
64
+ /**
65
+ * A MIDI file as tracker pattern rows: `stepsPerQuarter` rows per quarter note, one
66
+ * column per channel that plays, and a cell naming the note that starts on that row
67
+ * (the highest when a channel starts several at once, as a tracker cell holds one).
68
+ * Steps are counted in the file's own ticks, and a row's time follows its tempo map.
69
+ *
70
+ * @example
71
+ * ```ts
72
+ * import { trackerPattern, type MidiFile } from '@datamoc/mw_games/audio';
73
+ *
74
+ * declare const file: MidiFile;
75
+ *
76
+ * const rows = trackerPattern(file);
77
+ * console.log(rows[0].notes); // the first step's notes by channel, or nulls
78
+ * ```
79
+ */
80
+ export function trackerPattern(file, stepsPerQuarter = 4) {
81
+ const starts = [];
82
+ for (const event of file.events)
83
+ if (event.type === 'noteOn' && event.velocity > 0)
84
+ starts.push(event);
85
+ if (starts.length === 0)
86
+ return [];
87
+ //note-on times in file order, from the same walk a synth is driven by
88
+ const times = timedMidiMessages(file)
89
+ .filter((message) => (message.status & 0xf0) === 0x90 && message.data2 > 0)
90
+ .map((message) => message.time);
91
+ const channelCount = Math.max(...starts.map((event) => event.channel)) + 1;
92
+ const stepTicks = file.ticksPerQuarter / stepsPerQuarter;
93
+ const cells = new Map();
94
+ let lastStep = 0;
95
+ const stepTime = new Map();
96
+ starts.forEach((event, index) => {
97
+ const step = Math.floor(event.tick / stepTicks);
98
+ lastStep = Math.max(lastStep, step);
99
+ if (!cells.has(step))
100
+ cells.set(step, new Map());
101
+ const row = cells.get(step);
102
+ if (event.note > (row.get(event.channel) ?? -1))
103
+ row.set(event.channel, event.note);
104
+ if (!stepTime.has(step))
105
+ stepTime.set(step, times[index] ?? 0);
106
+ });
107
+ const rows = [];
108
+ let lastTime = 0;
109
+ for (let step = 0; step <= lastStep; step++) {
110
+ if (stepTime.has(step))
111
+ lastTime = stepTime.get(step);
112
+ const notes = Array(channelCount).fill(null);
113
+ for (const [channel, note] of cells.get(step) ?? [])
114
+ notes[channel] = trackerNoteName(note);
115
+ rows.push({ step, time: lastTime, notes });
116
+ }
117
+ return rows;
118
+ }
119
+ //# sourceMappingURL=AudioViews.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AudioViews.js","sourceRoot":"","sources":["../../src/audio/AudioViews.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,89 @@
1
+ import type { BusLoader, LoadedTrack } from './Channels.ts';
2
+ import type { RenderBudget } from './Resample.ts';
3
+ /**
4
+ * What a bus may spend on decoded tracks. A rendered five-minute stereo track at 44.1 kHz is
5
+ * about 100 MB, so a game that keeps every track it ever played runs a phone out of memory;
6
+ * these are the dials that keep it bounded.
7
+ */
8
+ export interface BusBudgetPolicy {
9
+ /** evict the least recently used track once the cache holds more than this many megabytes; unlimited when omitted */
10
+ maxMegabytes?: number;
11
+ /** evict once the cache holds more than this many tracks; unlimited when omitted */
12
+ maxEntries?: number;
13
+ /** applied to a rendered MIDI track before it becomes a buffer: a length cap, mono, half rate */
14
+ render?: RenderBudget;
15
+ }
16
+ export interface TrackCacheStats {
17
+ entries: number;
18
+ bytes: number;
19
+ hits: number;
20
+ misses: number;
21
+ evictions: number;
22
+ }
23
+ /**
24
+ * Memory a decoded buffer holds: 32-bit samples on every channel.
25
+ *
26
+ * @example
27
+ * ```ts
28
+ * import { bufferBytes } from '@datamoc/mw_games/audio';
29
+ *
30
+ * console.log(bufferBytes({ length: 44100, numberOfChannels: 2 })); // 352800, one stereo second
31
+ * ```
32
+ */
33
+ export declare function bufferBytes(buffer: Pick<AudioBuffer, 'length' | 'numberOfChannels'>): number;
34
+ /**
35
+ * A least-recently-used cache of loaded tracks under a `BusBudgetPolicy`. A load in flight is
36
+ * shared by everyone who asks for the same key, a failure or a `null` answer is not remembered
37
+ * so the next request retries, and a track that is currently playing survives its own eviction
38
+ * because the `Channel` holds the buffer, so evicting only means the next request decodes again.
39
+ *
40
+ * @example
41
+ * ```ts
42
+ * import { TrackCache, type LoadedTrack } from '@datamoc/mw_games/audio';
43
+ *
44
+ * declare function decode(path: string): Promise<LoadedTrack>;
45
+ *
46
+ * const cache = new TrackCache({ maxMegabytes: 64 });
47
+ * const track = await cache.load('music/town.mid', () => decode('music/town.mid'));
48
+ * console.log(cache.stats().bytes, track?.buffer.duration);
49
+ * ```
50
+ */
51
+ export declare class TrackCache {
52
+ private readonly entries;
53
+ private readonly policy;
54
+ private hits;
55
+ private misses;
56
+ private evictions;
57
+ constructor(policy?: BusBudgetPolicy);
58
+ /** the cached track for a key, or the one `make` produces; concurrent calls share one `make` */
59
+ load(key: string, make: () => Promise<LoadedTrack | null>): Promise<LoadedTrack | null>;
60
+ /** forgets one track; returns whether it was cached */
61
+ evict(key: string): boolean;
62
+ clear(): void;
63
+ stats(): TrackCacheStats;
64
+ /** drops the oldest tracks until the caps hold, never the one just loaded: a single track bigger than the cap still plays */
65
+ private enforce;
66
+ }
67
+ /** a `BusLoader` with the cache it reads through, so a game can show or reset its memory use */
68
+ export interface BudgetedLoader extends BusLoader {
69
+ readonly cache: TrackCache;
70
+ }
71
+ /**
72
+ * Wraps any `BusLoader` in a `TrackCache`: the bus keeps asking by kind and name, and the
73
+ * cache decides what stays in memory. The key includes the kind, since a jingle and a theme
74
+ * may share a name.
75
+ *
76
+ * @example
77
+ * ```ts
78
+ * import { AudioBus, createBudgetedLoader, type BusLoader } from '@datamoc/mw_games/audio';
79
+ *
80
+ * declare const context: AudioContext;
81
+ * declare const decode: BusLoader;
82
+ *
83
+ * const load = createBudgetedLoader(decode, { maxMegabytes: 48, maxEntries: 12 });
84
+ * const bus = new AudioBus(context, { load });
85
+ * console.log(load.cache.stats());
86
+ * ```
87
+ */
88
+ export declare function createBudgetedLoader(inner: BusLoader, policy: BusBudgetPolicy): BudgetedLoader;
89
+ //# sourceMappingURL=BusBudget.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BusBudget.d.ts","sourceRoot":"","sources":["../../src/audio/BusBudget.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAA2B,SAAS,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACrF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC/B,qHAAqH;IACrH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oFAAoF;IACpF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iGAAiG;IACjG,MAAM,CAAC,EAAE,YAAY,CAAC;CACtB;AAED,MAAM,WAAW,eAAe;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,WAAW,EAAE,QAAQ,GAAG,kBAAkB,CAAC,GAAG,MAAM,CAE5F;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,UAAU;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA8E;IACtG,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;IACzC,OAAO,CAAC,IAAI,CAAK;IACjB,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,SAAS,CAAK;IAEtB,YAAY,MAAM,GAAE,eAAoB,EAEvC;IAED,gGAAgG;IAC1F,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAyB5F;IAED,uDAAuD;IACvD,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAE1B;IAED,KAAK,IAAI,IAAI,CAEZ;IAED,KAAK,IAAI,eAAe,CAIvB;IAED,6HAA6H;IAC7H,OAAO,CAAC,OAAO;CAWf;AAED,gGAAgG;AAChG,MAAM,WAAW,cAAe,SAAQ,SAAS;IAChD,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,cAAc,CAM9F"}
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Memory a decoded buffer holds: 32-bit samples on every channel.
3
+ *
4
+ * @example
5
+ * ```ts
6
+ * import { bufferBytes } from '@datamoc/mw_games/audio';
7
+ *
8
+ * console.log(bufferBytes({ length: 44100, numberOfChannels: 2 })); // 352800, one stereo second
9
+ * ```
10
+ */
11
+ export function bufferBytes(buffer) {
12
+ return buffer.length * buffer.numberOfChannels * 4;
13
+ }
14
+ /**
15
+ * A least-recently-used cache of loaded tracks under a `BusBudgetPolicy`. A load in flight is
16
+ * shared by everyone who asks for the same key, a failure or a `null` answer is not remembered
17
+ * so the next request retries, and a track that is currently playing survives its own eviction
18
+ * because the `Channel` holds the buffer, so evicting only means the next request decodes again.
19
+ *
20
+ * @example
21
+ * ```ts
22
+ * import { TrackCache, type LoadedTrack } from '@datamoc/mw_games/audio';
23
+ *
24
+ * declare function decode(path: string): Promise<LoadedTrack>;
25
+ *
26
+ * const cache = new TrackCache({ maxMegabytes: 64 });
27
+ * const track = await cache.load('music/town.mid', () => decode('music/town.mid'));
28
+ * console.log(cache.stats().bytes, track?.buffer.duration);
29
+ * ```
30
+ */
31
+ export class TrackCache {
32
+ constructor(policy = {}) {
33
+ this.entries = new Map();
34
+ this.hits = 0;
35
+ this.misses = 0;
36
+ this.evictions = 0;
37
+ this.policy = policy;
38
+ }
39
+ /** the cached track for a key, or the one `make` produces; concurrent calls share one `make` */
40
+ async load(key, make) {
41
+ const hit = this.entries.get(key);
42
+ if (hit) {
43
+ this.hits++;
44
+ //re-inserting moves it to the most recently used end
45
+ this.entries.delete(key);
46
+ this.entries.set(key, hit);
47
+ return hit.promise;
48
+ }
49
+ this.misses++;
50
+ const entry = { promise: make(), bytes: 0 };
51
+ this.entries.set(key, entry);
52
+ try {
53
+ const track = await entry.promise;
54
+ if (!track) {
55
+ if (this.entries.get(key) === entry)
56
+ this.entries.delete(key);
57
+ return null;
58
+ }
59
+ entry.bytes = bufferBytes(track.buffer);
60
+ this.enforce(key);
61
+ return track;
62
+ }
63
+ catch (error) {
64
+ if (this.entries.get(key) === entry)
65
+ this.entries.delete(key);
66
+ throw error;
67
+ }
68
+ }
69
+ /** forgets one track; returns whether it was cached */
70
+ evict(key) {
71
+ return this.entries.delete(key);
72
+ }
73
+ clear() {
74
+ this.entries.clear();
75
+ }
76
+ stats() {
77
+ let bytes = 0;
78
+ for (const entry of this.entries.values())
79
+ bytes += entry.bytes;
80
+ return { entries: this.entries.size, bytes, hits: this.hits, misses: this.misses, evictions: this.evictions };
81
+ }
82
+ /** drops the oldest tracks until the caps hold, never the one just loaded: a single track bigger than the cap still plays */
83
+ enforce(keep) {
84
+ const maxBytes = (this.policy.maxMegabytes ?? Infinity) * 1024 * 1024;
85
+ const maxEntries = this.policy.maxEntries ?? Infinity;
86
+ for (const key of this.entries.keys()) {
87
+ const { bytes, entries } = this.stats();
88
+ if (bytes <= maxBytes && entries <= maxEntries)
89
+ return;
90
+ if (key === keep)
91
+ continue;
92
+ this.entries.delete(key);
93
+ this.evictions++;
94
+ }
95
+ }
96
+ }
97
+ /**
98
+ * Wraps any `BusLoader` in a `TrackCache`: the bus keeps asking by kind and name, and the
99
+ * cache decides what stays in memory. The key includes the kind, since a jingle and a theme
100
+ * may share a name.
101
+ *
102
+ * @example
103
+ * ```ts
104
+ * import { AudioBus, createBudgetedLoader, type BusLoader } from '@datamoc/mw_games/audio';
105
+ *
106
+ * declare const context: AudioContext;
107
+ * declare const decode: BusLoader;
108
+ *
109
+ * const load = createBudgetedLoader(decode, { maxMegabytes: 48, maxEntries: 12 });
110
+ * const bus = new AudioBus(context, { load });
111
+ * console.log(load.cache.stats());
112
+ * ```
113
+ */
114
+ export function createBudgetedLoader(inner, policy) {
115
+ const cache = new TrackCache(policy);
116
+ const loader = ((kind, name, context) => cache.load(`${kind}:${name}`, () => inner(kind, name, context)));
117
+ Object.defineProperty(loader, 'cache', { value: cache, enumerable: true });
118
+ return loader;
119
+ }
120
+ //# sourceMappingURL=BusBudget.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BusBudget.js","sourceRoot":"","sources":["../../src/audio/BusBudget.ts"],"names":[],"mappings":"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"}
@@ -11,6 +11,9 @@
11
11
  * for the bus, a `load` function turning a kind and a name into a decoded buffer.
12
12
  * Tests hand in fakes for both, the same way `Sound` and `Music` take `create()`.
13
13
  */
14
+ import { Signal } from '../core/Signal.ts';
15
+ import type { SfxArbiter } from './Sfx.ts';
16
+ import { StreamChannel, type BlockSource } from './StreamChannel.ts';
14
17
  /** seconds within a buffer: the region a looping track repeats */
15
18
  export interface LoopRegion {
16
19
  start: number;
@@ -101,6 +104,14 @@ export interface BusTrack {
101
104
  pitch?: number;
102
105
  pan?: number;
103
106
  pos?: number;
107
+ /** identity of the content behind a synthesised track, `id@version#sha256`, so a save replays the same bytes or says it cannot */
108
+ contentId?: string;
109
+ /** the engine that voiced it (`'retro:mt32'`), so a restore picks the same one when it can */
110
+ engine?: string;
111
+ /** playhead in source frames, exact where `pos` in seconds is not; a restore skips to it */
112
+ frame?: number;
113
+ /** for `playSe` only: asks the shared `SfxArbiter` for a voice at this priority; 0 when omitted */
114
+ priority?: number;
104
115
  }
105
116
  /** a resolved track request: every parameter filled in, ready to store or restore */
106
117
  export interface SavedBusTrack {
@@ -109,14 +120,44 @@ export interface SavedBusTrack {
109
120
  pitch: number;
110
121
  pan: number;
111
122
  pos: number;
123
+ contentId?: string;
124
+ engine?: string;
125
+ frame?: number;
112
126
  }
113
127
  /** a decoded track: its buffer plus the region it repeats, if any */
114
128
  export interface LoadedTrack {
115
129
  buffer: AudioBuffer;
116
130
  loop?: LoopRegion | null;
117
131
  }
132
+ /** what a loader may use while it works: a signal that says the request was replaced, and a way to report how far along it is */
133
+ export interface BusLoadContext {
134
+ /** aborted when a newer request for the same kind replaces this one, so a long render can stop early */
135
+ signal: AbortSignal;
136
+ /** reports progress from 0 to 1; `AudioBus.onLoadProgress` forwards it */
137
+ progress(fraction: number): void;
138
+ /** the request being loaded, including the content id, engine and frame a restored save carries */
139
+ track: SavedBusTrack;
140
+ }
118
141
  /** turns a kind and a name into a decoded buffer, or null when it cannot */
119
- export type BusLoader = (kind: BusKind, name: string) => Promise<LoadedTrack | null>;
142
+ export type BusLoader = (kind: BusKind, name: string, context?: BusLoadContext) => Promise<LoadedTrack | null>;
143
+ /** a track played by pulling frames instead of holding a decoded buffer */
144
+ export interface StreamedTrack {
145
+ source: BlockSource;
146
+ /** region the repeat wraps inside, in seconds; the whole source when omitted */
147
+ loop?: LoopRegion | null;
148
+ /** stop an endless source after this many seconds, fading out over `endFadeSeconds` (2 when omitted) */
149
+ endAfterSeconds?: number;
150
+ endFadeSeconds?: number;
151
+ }
152
+ /** turns a kind and a name into a streamed source, or null to let the buffer loader answer instead */
153
+ export type StreamLoader = (kind: 'bgm' | 'bgs', name: string, context: BusLoadContext) => Promise<StreamedTrack | null>;
154
+ /** how far a track's load has got */
155
+ export interface BusLoadProgress {
156
+ kind: BusKind;
157
+ name: string;
158
+ /** 0 to 1 */
159
+ fraction: number;
160
+ }
120
161
  /** plain-data bus state for saves and transfers: tracks plus memorized ones */
121
162
  export interface BusSnapshot {
122
163
  bgm: SavedBusTrack | null;
@@ -134,6 +175,13 @@ export interface AudioBusOptions {
134
175
  destination?: AudioNode;
135
176
  /** Defaults to embedded asset loading, including worker-rendered MIDI; customize with `createAudioLoader`. */
136
177
  load?: BusLoader;
178
+ /**
179
+ * asked first for BGM and BGS: a source it returns plays through a `StreamChannel`, so a long
180
+ * or endless track never becomes a whole `AudioBuffer`; null falls through to `load`
181
+ */
182
+ stream?: StreamLoader;
183
+ /** the voice limit shared with `SfxSound`s: `playSe` asks it for a slot at `BusTrack.priority` */
184
+ arbiter?: SfxArbiter;
137
185
  }
138
186
  /**
139
187
  * The four audio lifetimes of a role-playing game over two `Channel` voices: BGM and
@@ -156,6 +204,12 @@ export declare class AudioBus {
156
204
  private readonly context;
157
205
  private readonly destination;
158
206
  private readonly load;
207
+ private readonly streamLoader;
208
+ private readonly arbiter;
209
+ private readonly streams;
210
+ private readonly aborts;
211
+ /** told as a loader reports progress, for a loading bar over a long render */
212
+ readonly onLoadProgress: Signal<BusLoadProgress>;
159
213
  private readonly bgmChannel;
160
214
  private readonly bgsChannel;
161
215
  private readonly tracks;
@@ -168,6 +222,15 @@ export declare class AudioBus {
168
222
  private readonly mixerLevels;
169
223
  private readonly kindGains;
170
224
  constructor(context: AudioContext, options?: AudioBusOptions);
225
+ /** the streaming voice of a loop kind, for underrun reports and its own controls */
226
+ streamChannel(kind: 'bgm' | 'bgs'): StreamChannel;
227
+ /** a newer request, or a stop, replaces whatever a loop kind is still loading */
228
+ private cancelLoad;
229
+ private stopLoop;
230
+ private loopPlaying;
231
+ private loopPosition;
232
+ /** a stream's playhead in source frames, undefined for a buffered track which has only seconds */
233
+ private loopFrame;
171
234
  /**
172
235
  * Sets a kind's own volume (0 to 1) and mute, applied on top of every track's volume
173
236
  * and to sounds already playing. Tracks keep the level the game asked for, so
@@ -204,6 +267,7 @@ export declare class AudioBus {
204
267
  stopMe(resume?: boolean): void;
205
268
  /** plays one overlapping sound effect */
206
269
  playSe(track: BusTrack): Promise<void>;
270
+ private cutSe;
207
271
  stopSe(): void;
208
272
  stopAll(): void;
209
273
  /** plain-data bus state for saves and transfers */
@@ -1 +1 @@
1
- {"version":3,"file":"Channels.d.ts","sourceRoot":"","sources":["../../src/audio/Channels.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Channels.d.ts","sourceRoot":"","sources":["../../src/audio/Channels.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAErE,kEAAkE;AAClE,MAAM,WAAW,UAAU;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,kBAAkB;IAClC,oBAAoB;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,6DAA6D;IAC7D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,8BAA8B;IAC9B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,sDAAsD;IACtD,IAAI,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IACzB,yDAAyD;IACzD,MAAM,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,8EAA8E;AAC9E,MAAM,WAAW,YAAY;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACZ;AA8BD;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,OAAO;IACnB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;IACvC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAY;IACxC,OAAO,CAAC,MAAM,CAAsC;IACpD,OAAO,CAAC,QAAQ,CAAyB;IACzC,OAAO,CAAC,UAAU,CAAiC;IACnD,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,MAAM,CAAmC;IACjD,OAAO,CAAC,UAAU,CAA2B;IAC7C,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,MAAM,CAAK;IAEnB,YAAY,OAAO,EAAE,YAAY,EAAE,WAAW,CAAC,EAAE,SAAS,EAGzD;IAED,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED,+EAA+E;IAC/E,IAAI,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,GAAE,kBAAuB,GAAG,IAAI,CA6BhE;IAED,8DAA8D;IAC9D,MAAM,CAAC,MAAM,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAStE;IAED,yEAAyE;IACzE,IAAI,CAAC,WAAW,SAAI,GAAG,IAAI,CAoB1B;IAED,gFAAgF;IAChF,QAAQ,IAAI,MAAM,CAUjB;IAED,6DAA6D;IAC7D,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAEtB;IAED,yEAAyE;IACzE,KAAK,IAAI,YAAY,CAEpB;IAED,mFAAmF;IACnF,OAAO,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,CAejC;IAED,OAAO,CAAC,UAAU;CAMlB;AAED,MAAM,MAAM,OAAO,GAAG,KAAK,GAAG,KAAK,GAAG,IAAI,GAAG,IAAI,CAAC;AAElD;;;GAGG;AACH,MAAM,WAAW,QAAQ;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,kIAAkI;IAClI,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8FAA8F;IAC9F,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4FAA4F;IAC5F,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mGAAmG;IACnG,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,qFAAqF;AACrF,MAAM,WAAW,aAAa;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED,qEAAqE;AACrE,MAAM,WAAW,WAAW;IAC3B,MAAM,EAAE,WAAW,CAAC;IACpB,IAAI,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;CACzB;AAED,iIAAiI;AACjI,MAAM,WAAW,cAAc;IAC9B,wGAAwG;IACxG,MAAM,EAAE,WAAW,CAAC;IACpB,0EAA0E;IAC1E,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,mGAAmG;IACnG,KAAK,EAAE,aAAa,CAAC;CACrB;AAED,4EAA4E;AAC5E,MAAM,MAAM,SAAS,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc,KAAK,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;AAE/G,2EAA2E;AAC3E,MAAM,WAAW,aAAa;IAC7B,MAAM,EAAE,WAAW,CAAC;IACpB,gFAAgF;IAChF,IAAI,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IACzB,wGAAwG;IACxG,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,sGAAsG;AACtG,MAAM,MAAM,YAAY,GAAG,CAC1B,IAAI,EAAE,KAAK,GAAG,KAAK,EACnB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,cAAc,KACnB,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC;AAEnC,qCAAqC;AACrC,MAAM,WAAW,eAAe;IAC/B,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,aAAa;IACb,QAAQ,EAAE,MAAM,CAAC;CACjB;AAED,+EAA+E;AAC/E,MAAM,WAAW,WAAW;IAC3B,GAAG,EAAE,aAAa,GAAG,IAAI,CAAC;IAC1B,GAAG,EAAE,aAAa,GAAG,IAAI,CAAC;IAC1B,QAAQ,EAAE,aAAa,GAAG,IAAI,CAAC;IAC/B,QAAQ,EAAE,aAAa,GAAG,IAAI,CAAC;CAC/B;AAED,yEAAyE;AACzE,MAAM,WAAW,aAAa;IAC7B,aAAa;IACb,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,eAAe;IAC/B,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,8GAA8G;IAC9G,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB;;;OAGG;IACH,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,kGAAkG;IAClG,OAAO,CAAC,EAAE,UAAU,CAAC;CACrB;AAOD;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,QAAQ;IACpB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;IACvC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAY;IACxC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAY;IACjC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAsB;IACnD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoB;IAC5C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuC;IAC/D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA2E;IAClG,8EAA8E;IAC9E,QAAQ,CAAC,cAAc,0BAAiC;IACxD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAU;IACrC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAU;IACrC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsF;IAC7G,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAsF;IAC5G,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAsB;IAC/C,OAAO,CAAC,EAAE,CAAiE;IAC3E,OAAO,CAAC,OAAO,CAAK;IACpB,OAAO,CAAC,YAAY,CAA8B;IAClD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgD;IACxE,OAAO,CAAC,QAAQ,CAAC,WAAW,CAK1B;IACF,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA4B;IAEtD,YAAY,OAAO,EAAE,YAAY,EAAE,OAAO,GAAE,eAAoB,EAkB/D;IAED,oFAAoF;IACpF,aAAa,CAAC,IAAI,EAAE,KAAK,GAAG,KAAK,GAAG,aAAa,CAEhD;IAED,iFAAiF;IACjF,OAAO,CAAC,UAAU;IAMlB,OAAO,CAAC,QAAQ;IAKhB,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,YAAY;IAMpB,kGAAkG;IAClG,OAAO,CAAC,SAAS;IAIjB;;;;OAIG;IACH,QAAQ,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAKzE;IAED,mCAAmC;IACnC,KAAK,CAAC,IAAI,EAAE,OAAO,GAAG,aAAa,CAElC;IAED,0DAA0D;IAC1D,OAAO,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAEtC;IAED,0DAA0D;IAC1D,OAAO,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAEtC;IAED,OAAO,IAAI,IAAI,CAKd;IAED,OAAO,IAAI,IAAI,CAId;IAED,UAAU,CAAC,OAAO,SAAI,GAAG,IAAI,CAK5B;IAED,UAAU,CAAC,OAAO,SAAI,GAAG,IAAI,CAI5B;IAED,4EAA4E;IAC5E,YAAY,CAAC,IAAI,EAAE,KAAK,GAAG,KAAK,GAAG,aAAa,GAAG,IAAI,CAWtD;IAED,sEAAsE;IACtE,OAAO,IAAI,aAAa,GAAG,IAAI,CAG9B;IAED,sEAAsE;IACtE,OAAO,IAAI,aAAa,GAAG,IAAI,CAG9B;IAED,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAGzB;IAED,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAGzB;IAED;;;OAGG;IACG,MAAM,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CA2B3C;IAED,sEAAsE;IACtE,MAAM,CAAC,MAAM,UAAO,GAAG,IAAI,CAG1B;IAED,yCAAyC;IACnC,MAAM,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CA8B3C;IAED,OAAO,CAAC,KAAK;IAUb,MAAM,IAAI,IAAI,CAUb;IAED,OAAO,IAAI,IAAI,CAUd;IAED,mDAAmD;IACnD,QAAQ,IAAI,WAAW,CAOtB;IAED,gEAAgE;IAChE,OAAO,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI,GAAG,SAAS,GAAG,IAAI,CAMnD;IAED,OAAO,CAAC,MAAM,CAAC,SAAS;YAaV,QAAQ;IAmEtB,OAAO,CAAC,WAAW;IAYnB,OAAO,CAAC,QAAQ;CAMhB"}