@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,149 @@
1
+ import type { BlockSource } from '../audio/StreamChannel.ts';
2
+ import type { MidiSynth } from '../audio/MidiSynth.ts';
3
+ /**
4
+ * A WebAudio double whose clock only moves when a test moves it. It records every buffer
5
+ * source that was started and ends them as `advance()` passes their end time, which is exactly
6
+ * the part of an `AudioContext` a streaming voice depends on (the clock, scheduled starts, the
7
+ * `onended` of a source) and nothing else.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * import { StreamChannel } from '@datamoc/mw_games/audio';
12
+ * import { FakeAudioContext, FakeBlockSource } from '@datamoc/mw_games/testing';
13
+ *
14
+ * const context = new FakeAudioContext();
15
+ * const channel = new StreamChannel(context.asContext(), undefined, { pumpMs: 0 });
16
+ * channel.play(new FakeBlockSource({ seconds: 1 }));
17
+ * context.advance(2);
18
+ * ```
19
+ */
20
+ export declare class FakeAudioContext {
21
+ currentTime: number;
22
+ readonly sampleRate: number;
23
+ state: 'running' | 'suspended';
24
+ readonly destination: {
25
+ connect(): void;
26
+ };
27
+ /** every buffer source made, in order, with when it was asked to start */
28
+ readonly sources: FakeBufferSource[];
29
+ resumes: number;
30
+ constructor(sampleRate?: number);
31
+ createBuffer(channels: number, length: number, sampleRate: number): FakeBuffer;
32
+ createBufferSource(): FakeBufferSource;
33
+ createGain(): FakeGain;
34
+ createStereoPanner(): {
35
+ pan: {
36
+ value: number;
37
+ };
38
+ connect(): void;
39
+ };
40
+ resume(): Promise<void>;
41
+ /** moves the clock and ends every started source whose scheduled end has passed */
42
+ advance(seconds: number): void;
43
+ /** the double typed as the context the code under test expects */
44
+ asContext(): AudioContext;
45
+ }
46
+ export declare class FakeBuffer {
47
+ readonly length: number;
48
+ readonly numberOfChannels: number;
49
+ readonly sampleRate: number;
50
+ private readonly data;
51
+ constructor(channels: number, length: number, sampleRate: number);
52
+ get duration(): number;
53
+ getChannelData(channel: number): Float32Array;
54
+ }
55
+ export declare class FakeBufferSource {
56
+ buffer: FakeBuffer | null;
57
+ loop: boolean;
58
+ loopStart: number;
59
+ loopEnd: number;
60
+ readonly playbackRate: {
61
+ value: number;
62
+ };
63
+ onended: (() => void) | null;
64
+ startedAt: number | null;
65
+ /** the offset into the buffer the source was started at */
66
+ offset: number;
67
+ /** when the source was told to stop, if it was */
68
+ stoppedAt: number | null;
69
+ stopped: boolean;
70
+ ended: boolean;
71
+ get duration(): number;
72
+ connect(): void;
73
+ start(when?: number, offset?: number): void;
74
+ stop(when?: number): void;
75
+ }
76
+ /** a gain node that remembers every ramp it was given, so a test can read a fade without listening */
77
+ export declare class FakeGain {
78
+ readonly ramps: {
79
+ value: number;
80
+ time: number;
81
+ }[];
82
+ readonly gain: {
83
+ value: number;
84
+ setTargetAtTime: (value: number) => void;
85
+ setValueAtTime: (value: number) => void;
86
+ cancelScheduledValues: () => void;
87
+ linearRampToValueAtTime: (value: number, time: number) => void;
88
+ };
89
+ connect(): void;
90
+ }
91
+ export interface FakeBlockSourceOptions {
92
+ /** length in seconds; omit for a source with no end */
93
+ seconds?: number;
94
+ sampleRate?: number;
95
+ /** value written to both channels at frame i is `ramp ? i / 1000 : level`; a ramp makes the frame position readable from the output */
96
+ ramp?: boolean;
97
+ level?: number;
98
+ }
99
+ /**
100
+ * A deterministic `BlockSource`: a ramp whose value names its frame, or a flat level, of a known
101
+ * length or none at all. It counts every read and seek so a test can see how the consumer pulled.
102
+ */
103
+ export declare class FakeBlockSource implements BlockSource {
104
+ readonly sampleRate: number;
105
+ readonly length?: number;
106
+ position: number;
107
+ reads: number;
108
+ seeks: number[];
109
+ private readonly ramp;
110
+ private readonly level;
111
+ constructor(options?: FakeBlockSourceOptions);
112
+ read(left: Float32Array, right: Float32Array, start: number, count: number): number;
113
+ seek(frame: number): void;
114
+ }
115
+ /**
116
+ * A `MidiSynth` double for a retro engine: it records every message it was driven with and
117
+ * renders a flat level while any note is on (silence otherwise), so a test can assert what a
118
+ * renderer sent and read the shape of the output without a real synth or clock. Pair it with
119
+ * `FakeAudioContext`, whose `advance()` is the audio clock a test moves by hand.
120
+ *
121
+ * @example
122
+ * ```ts
123
+ * import { FakeRetroPlayer } from '@datamoc/mw_games/testing';
124
+ *
125
+ * const synth = new FakeRetroPlayer(8000);
126
+ * synth.event(0x90, 60, 100); // note on, middle C
127
+ * const left = new Float32Array(4);
128
+ * synth.render(left, new Float32Array(4), 0, 4);
129
+ * console.log(synth.notesOn, left[0] > 0); // 1, true
130
+ * ```
131
+ */
132
+ export declare class FakeRetroPlayer implements MidiSynth {
133
+ readonly sampleRate: number;
134
+ /** every channel message received, as `[status, data1, data2]` in order */
135
+ readonly events: [number, number, number][];
136
+ /** every system-exclusive message received, as a copy */
137
+ readonly sysexMessages: Uint8Array[];
138
+ resets: number;
139
+ renders: number;
140
+ private readonly sounding;
141
+ constructor(sampleRate?: number);
142
+ /** how many notes are currently on */
143
+ get notesOn(): number;
144
+ event(status: number, data1: number, data2: number): void;
145
+ sysex(bytes: Uint8Array): void;
146
+ render(left: Float32Array, right: Float32Array, start: number, count: number): void;
147
+ reset(): void;
148
+ }
149
+ //# sourceMappingURL=FakeAudio.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FakeAudio.d.ts","sourceRoot":"","sources":["../../src/testing/FakeAudio.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,219 @@
1
+ /**
2
+ * A WebAudio double whose clock only moves when a test moves it. It records every buffer
3
+ * source that was started and ends them as `advance()` passes their end time, which is exactly
4
+ * the part of an `AudioContext` a streaming voice depends on (the clock, scheduled starts, the
5
+ * `onended` of a source) and nothing else.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * import { StreamChannel } from '@datamoc/mw_games/audio';
10
+ * import { FakeAudioContext, FakeBlockSource } from '@datamoc/mw_games/testing';
11
+ *
12
+ * const context = new FakeAudioContext();
13
+ * const channel = new StreamChannel(context.asContext(), undefined, { pumpMs: 0 });
14
+ * channel.play(new FakeBlockSource({ seconds: 1 }));
15
+ * context.advance(2);
16
+ * ```
17
+ */
18
+ export class FakeAudioContext {
19
+ constructor(sampleRate = 8000) {
20
+ this.currentTime = 0;
21
+ this.state = 'running';
22
+ this.destination = { connect() { } };
23
+ /** every buffer source made, in order, with when it was asked to start */
24
+ this.sources = [];
25
+ this.resumes = 0;
26
+ this.sampleRate = sampleRate;
27
+ }
28
+ createBuffer(channels, length, sampleRate) {
29
+ return new FakeBuffer(channels, length, sampleRate);
30
+ }
31
+ createBufferSource() {
32
+ const source = new FakeBufferSource();
33
+ this.sources.push(source);
34
+ return source;
35
+ }
36
+ createGain() {
37
+ return new FakeGain();
38
+ }
39
+ createStereoPanner() {
40
+ return { pan: { value: 0 }, connect() { } };
41
+ }
42
+ resume() {
43
+ this.resumes++;
44
+ this.state = 'running';
45
+ return Promise.resolve();
46
+ }
47
+ /** moves the clock and ends every started source whose scheduled end has passed */
48
+ advance(seconds) {
49
+ this.currentTime += seconds;
50
+ for (const source of this.sources) {
51
+ if (source.startedAt === null || source.ended || source.stopped)
52
+ continue;
53
+ if (source.startedAt + source.duration <= this.currentTime) {
54
+ source.ended = true;
55
+ source.onended?.();
56
+ }
57
+ }
58
+ }
59
+ /** the double typed as the context the code under test expects */
60
+ asContext() {
61
+ return this;
62
+ }
63
+ }
64
+ export class FakeBuffer {
65
+ constructor(channels, length, sampleRate) {
66
+ this.numberOfChannels = channels;
67
+ this.length = length;
68
+ this.sampleRate = sampleRate;
69
+ this.data = Array.from({ length: channels }, () => new Float32Array(length));
70
+ }
71
+ get duration() {
72
+ return this.length / this.sampleRate;
73
+ }
74
+ getChannelData(channel) {
75
+ return this.data[channel];
76
+ }
77
+ }
78
+ export class FakeBufferSource {
79
+ constructor() {
80
+ this.buffer = null;
81
+ this.loop = false;
82
+ this.loopStart = 0;
83
+ this.loopEnd = 0;
84
+ this.playbackRate = { value: 1 };
85
+ this.onended = null;
86
+ this.startedAt = null;
87
+ /** the offset into the buffer the source was started at */
88
+ this.offset = 0;
89
+ /** when the source was told to stop, if it was */
90
+ this.stoppedAt = null;
91
+ this.stopped = false;
92
+ this.ended = false;
93
+ }
94
+ get duration() {
95
+ return this.buffer?.duration ?? 0;
96
+ }
97
+ connect() { }
98
+ start(when = 0, offset = 0) {
99
+ this.startedAt = when;
100
+ this.offset = offset;
101
+ }
102
+ stop(when) {
103
+ this.stopped = true;
104
+ this.stoppedAt = when ?? null;
105
+ }
106
+ }
107
+ /** a gain node that remembers every ramp it was given, so a test can read a fade without listening */
108
+ export class FakeGain {
109
+ constructor() {
110
+ this.ramps = [];
111
+ this.gain = {
112
+ value: 1,
113
+ setTargetAtTime: (value) => {
114
+ this.gain.value = value;
115
+ },
116
+ setValueAtTime: (value) => {
117
+ this.gain.value = value;
118
+ },
119
+ cancelScheduledValues: () => {
120
+ this.ramps.length = 0;
121
+ },
122
+ linearRampToValueAtTime: (value, time) => {
123
+ this.ramps.push({ value, time });
124
+ },
125
+ };
126
+ }
127
+ connect() { }
128
+ }
129
+ /**
130
+ * A deterministic `BlockSource`: a ramp whose value names its frame, or a flat level, of a known
131
+ * length or none at all. It counts every read and seek so a test can see how the consumer pulled.
132
+ */
133
+ export class FakeBlockSource {
134
+ constructor(options = {}) {
135
+ this.position = 0;
136
+ this.reads = 0;
137
+ this.seeks = [];
138
+ this.sampleRate = options.sampleRate ?? 8000;
139
+ if (options.seconds !== undefined)
140
+ this.length = Math.round(options.seconds * this.sampleRate);
141
+ this.ramp = options.ramp ?? false;
142
+ this.level = options.level ?? 0.5;
143
+ }
144
+ read(left, right, start, count) {
145
+ this.reads++;
146
+ const available = this.length === undefined ? count : Math.max(0, Math.min(count, this.length - this.position));
147
+ for (let i = 0; i < available; i++) {
148
+ const value = this.ramp ? (this.position + i) / 1000 : this.level;
149
+ left[start + i] = value;
150
+ right[start + i] = value;
151
+ }
152
+ this.position += available;
153
+ return available;
154
+ }
155
+ seek(frame) {
156
+ this.seeks.push(frame);
157
+ this.position = frame;
158
+ }
159
+ }
160
+ /**
161
+ * A `MidiSynth` double for a retro engine: it records every message it was driven with and
162
+ * renders a flat level while any note is on (silence otherwise), so a test can assert what a
163
+ * renderer sent and read the shape of the output without a real synth or clock. Pair it with
164
+ * `FakeAudioContext`, whose `advance()` is the audio clock a test moves by hand.
165
+ *
166
+ * @example
167
+ * ```ts
168
+ * import { FakeRetroPlayer } from '@datamoc/mw_games/testing';
169
+ *
170
+ * const synth = new FakeRetroPlayer(8000);
171
+ * synth.event(0x90, 60, 100); // note on, middle C
172
+ * const left = new Float32Array(4);
173
+ * synth.render(left, new Float32Array(4), 0, 4);
174
+ * console.log(synth.notesOn, left[0] > 0); // 1, true
175
+ * ```
176
+ */
177
+ export class FakeRetroPlayer {
178
+ constructor(sampleRate = 8000) {
179
+ /** every channel message received, as `[status, data1, data2]` in order */
180
+ this.events = [];
181
+ /** every system-exclusive message received, as a copy */
182
+ this.sysexMessages = [];
183
+ this.resets = 0;
184
+ this.renders = 0;
185
+ this.sounding = new Map();
186
+ this.sampleRate = sampleRate;
187
+ }
188
+ /** how many notes are currently on */
189
+ get notesOn() {
190
+ return this.sounding.size;
191
+ }
192
+ event(status, data1, data2) {
193
+ this.events.push([status, data1, data2]);
194
+ const kind = status & 0xf0;
195
+ const key = ((status & 0x0f) << 8) | data1;
196
+ if (kind === 0x90 && data2 > 0)
197
+ this.sounding.set(key, data2);
198
+ else if (kind === 0x80 || kind === 0x90)
199
+ this.sounding.delete(key);
200
+ }
201
+ sysex(bytes) {
202
+ this.sysexMessages.push(new Uint8Array(bytes));
203
+ }
204
+ render(left, right, start, count) {
205
+ this.renders++;
206
+ let level = 0;
207
+ for (const velocity of this.sounding.values())
208
+ level = Math.max(level, velocity / 127);
209
+ for (let i = 0; i < count; i++) {
210
+ left[start + i] += level * 0.5;
211
+ right[start + i] += level * 0.5;
212
+ }
213
+ }
214
+ reset() {
215
+ this.resets++;
216
+ this.sounding.clear();
217
+ }
218
+ }
219
+ //# sourceMappingURL=FakeAudio.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FakeAudio.js","sourceRoot":"","sources":["../../src/testing/FakeAudio.ts"],"names":[],"mappings":"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"}
@@ -103,6 +103,8 @@ export declare function fakeFetch(respond: (url: string, init?: RequestInit) =>
103
103
  */
104
104
  export declare function fakeGamepad(index: number, buttons?: number[], axes?: number[]): Gamepad;
105
105
  export { createSceneControls } from './SceneControls.ts';
106
+ export { FakeAudioContext, FakeBlockSource, FakeBuffer, FakeBufferSource, FakeGain, FakeRetroPlayer, } from './FakeAudio.ts';
107
+ export type { FakeBlockSourceOptions } from './FakeAudio.ts';
106
108
  export type { SceneControls, SceneStep } from './SceneControls.ts';
107
109
  /**
108
110
  * Publishes a game's inspectable state on `window.__mwg_test__[name]`, where a browser test
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAClE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAErD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,aAAa,IAAI,WAAW,CAE3C;AAED,wDAAwD;AACxD,MAAM,WAAW,YAAa,SAAQ,QAAQ;IAC7C,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;CAChB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,SAAS,IAAI,YAAY,CAexC;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,YAAY,CAEjD;AAED;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,UAAW,YAAW,aAAa;IAC/C,UAAU,SAAK;IACf,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,CAAM;IAC7B,MAAM,EAAE,CAAC,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC,GAAG,IAAI,CAAQ;IACjD,OAAO,EAAE,CAAC,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC,GAAG,IAAI,CAAQ;IAClD,OAAO,EAAE,CAAC,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC,GAAG,IAAI,CAAQ;IAClD,SAAS,EAAE,CAAC,CAAC,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC,GAAG,IAAI,CAAQ;IAE7D,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAEvB;IAED,KAAK,IAAI,IAAI,CAGZ;IAED,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAE9B;IAED,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAE7B;CACD;AAED,yCAAyC;AACzC,MAAM,WAAW,aAAa;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,WAAW,CAAC;CACnB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,SAAS,CACxB,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,GACnD,OAAO,UAAU,CAAC,KAAK,GAAG;IAAE,KAAK,EAAE,aAAa,EAAE,CAAA;CAAE,CAStD;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,MAAM,EAAO,EAAE,IAAI,GAAE,MAAM,EAAO,GAAG,OAAO,CAM/F;AAED,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAEnE;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAIjE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAClE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAErD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,aAAa,IAAI,WAAW,CAE3C;AAED,wDAAwD;AACxD,MAAM,WAAW,YAAa,SAAQ,QAAQ;IAC7C,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;CAChB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,SAAS,IAAI,YAAY,CAexC;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,YAAY,CAEjD;AAED;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,UAAW,YAAW,aAAa;IAC/C,UAAU,SAAK;IACf,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,CAAM;IAC7B,MAAM,EAAE,CAAC,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC,GAAG,IAAI,CAAQ;IACjD,OAAO,EAAE,CAAC,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC,GAAG,IAAI,CAAQ;IAClD,OAAO,EAAE,CAAC,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC,GAAG,IAAI,CAAQ;IAClD,SAAS,EAAE,CAAC,CAAC,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC,GAAG,IAAI,CAAQ;IAE7D,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAEvB;IAED,KAAK,IAAI,IAAI,CAGZ;IAED,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAE9B;IAED,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAE7B;CACD;AAED,yCAAyC;AACzC,MAAM,WAAW,aAAa;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,WAAW,CAAC;CACnB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,SAAS,CACxB,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,GACnD,OAAO,UAAU,CAAC,KAAK,GAAG;IAAE,KAAK,EAAE,aAAa,EAAE,CAAA;CAAE,CAStD;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,MAAM,EAAO,EAAE,IAAI,GAAE,MAAM,EAAO,GAAG,OAAO,CAM/F;AAED,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EACN,gBAAgB,EAChB,eAAe,EACf,UAAU,EACV,gBAAgB,EAChB,QAAQ,EACR,eAAe,GACf,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAC7D,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAEnE;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAIjE"}
@@ -132,6 +132,7 @@ export function fakeGamepad(index, buttons = [], axes = []) {
132
132
  };
133
133
  }
134
134
  export { createSceneControls } from './SceneControls.js';
135
+ export { FakeAudioContext, FakeBlockSource, FakeBuffer, FakeBufferSource, FakeGain, FakeRetroPlayer, } from './FakeAudio.js';
135
136
  /**
136
137
  * Publishes a game's inspectable state on `window.__mwg_test__[name]`, where a browser test
137
138
  * (`BrowserDriver.evaluate`) can reach it. One fixed place replaces a hook each game invents;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,3 @@
1
- export { spawn } from './spawn.ts';
2
- export type { SpawnOptions } from './spawn.ts';
1
+ export { openWorker, spawn } from './spawn.ts';
2
+ export type { SpawnOptions, WorkerLink, WorkerLinkEvents } from './spawn.ts';
3
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/threads/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/threads/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAC/C,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC"}
@@ -1,2 +1,2 @@
1
- export { spawn } from './spawn.js';
1
+ export { openWorker, spawn } from './spawn.js';
2
2
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/threads/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/threads/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC"}
@@ -6,6 +6,38 @@ export interface SpawnOptions {
6
6
  /** aborting rejects the promise with the signal's reason and terminates the task's worker */
7
7
  signal?: AbortSignal;
8
8
  }
9
+ /** one open worker: post to it, terminate it */
10
+ export interface WorkerLink {
11
+ post(message: unknown, transfer?: Transferable[]): void;
12
+ terminate(): void;
13
+ }
14
+ export interface WorkerLinkEvents {
15
+ /** a message the worker posted */
16
+ message(data: unknown): void;
17
+ /** the worker failed, died or sent something that could not be read */
18
+ fail(error: Error): void;
19
+ }
20
+ /**
21
+ * Opens a worker running a classic script, in a browser (a blob worker, which the shipped
22
+ * `file://` page's policy allows) or in Node (`worker_threads` in eval mode), and returns null
23
+ * where neither exists. `spawn` is the one-task-per-worker use of this; a long-lived service
24
+ * such as the audio core host keeps its worker and talks to it with messages.
25
+ *
26
+ * The script must be self-contained for the same reason a `spawn` task must: it runs with
27
+ * nothing but its own text in scope.
28
+ *
29
+ * @example
30
+ * ```ts
31
+ * import { openWorker } from '@datamoc/mw_games/threads';
32
+ *
33
+ * const link = openWorker('globalThis.onmessage = (event) => globalThis.postMessage(event.data * 2);', {
34
+ * message: (value) => console.log(value),
35
+ * fail: (error) => console.warn(error.message),
36
+ * });
37
+ * link?.post(21);
38
+ * ```
39
+ */
40
+ export declare function openWorker(source: string, events: WorkerLinkEvents): WorkerLink | null;
9
41
  /**
10
42
  * Runs `fn` on a worker thread and resolves with its value, keeping the caller's thread
11
43
  * free: the one synchronous block a game can never get back is the frame it spends waiting.
@@ -1 +1 @@
1
- {"version":3,"file":"spawn.d.ts","sourceRoot":"","sources":["../../src/threads/spawn.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,YAAY;IAC5B,sGAAsG;IACtG,QAAQ,CAAC,EAAE,YAAY,EAAE,CAAC;IAC1B,0HAA0H;IAC1H,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6FAA6F;IAC7F,MAAM,CAAC,EAAE,WAAW,CAAC;CACrB;AAsED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,KAAK,CAAC,IAAI,SAAS,SAAS,OAAO,EAAE,EAAE,MAAM,EAC5D,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,IAAI,KAAK,MAAM,EAC7B,IAAI,CAAC,EAAE,IAAI,EACX,OAAO,GAAE,YAAiB,GACxB,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CA0D1B"}
1
+ {"version":3,"file":"spawn.d.ts","sourceRoot":"","sources":["../../src/threads/spawn.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,YAAY;IAC5B,sGAAsG;IACtG,QAAQ,CAAC,EAAE,YAAY,EAAE,CAAC;IAC1B,0HAA0H;IAC1H,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6FAA6F;IAC7F,MAAM,CAAC,EAAE,WAAW,CAAC;CACrB;AAED,gDAAgD;AAChD,MAAM,WAAW,UAAU;IAC1B,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,YAAY,EAAE,GAAG,IAAI,CAAC;IACxD,SAAS,IAAI,IAAI,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAChC,kCAAkC;IAClC,OAAO,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAAC;IAC7B,uEAAuE;IACvE,IAAI,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;CACzB;AAoDD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,gBAAgB,GAAG,UAAU,GAAG,IAAI,CAGtF;AASD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,KAAK,CAAC,IAAI,SAAS,SAAS,OAAO,EAAE,EAAE,MAAM,EAC5D,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,IAAI,KAAK,MAAM,EAC7B,IAAI,CAAC,EAAE,IAAI,EACX,OAAO,GAAE,YAAiB,GACxB,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CA0D1B"}
@@ -1,5 +1,5 @@
1
1
  import { nodeThreads, workerMain } from './worker.js';
2
- const browserWorker = (events) => {
2
+ const browserWorker = (source, events) => {
3
3
  if (typeof Worker === 'undefined' ||
4
4
  typeof Blob === 'undefined' ||
5
5
  typeof URL === 'undefined' ||
@@ -8,7 +8,7 @@ const browserWorker = (events) => {
8
8
  }
9
9
  //a blob worker, because the shipped file:// page allows worker-src blob: and because a
10
10
  //file:// module worker is blocked by CORS whatever the policy says
11
- const url = URL.createObjectURL(new Blob([`(${workerMain.toString()})()`], { type: 'text/javascript' }));
11
+ const url = URL.createObjectURL(new Blob([source], { type: 'text/javascript' }));
12
12
  let worker;
13
13
  try {
14
14
  worker = new Worker(url);
@@ -17,34 +17,58 @@ const browserWorker = (events) => {
17
17
  URL.revokeObjectURL(url);
18
18
  throw error;
19
19
  }
20
- worker.onmessage = (event) => events.reply(event.data);
20
+ worker.onmessage = (event) => events.message(event.data);
21
21
  worker.onerror = (event) => events.fail(new Error(event.message || 'the worker failed to run'));
22
22
  worker.onmessageerror = () => events.fail(new Error('the worker sent a reply that could not be deserialized'));
23
23
  return {
24
- post: (message, transfer) => worker.postMessage(message, transfer),
24
+ post: (message, transfer = []) => worker.postMessage(message, transfer),
25
25
  terminate: () => {
26
26
  worker.terminate();
27
27
  URL.revokeObjectURL(url);
28
28
  },
29
29
  };
30
30
  };
31
- const nodeWorker = (events) => {
31
+ const nodeWorker = (source, events) => {
32
32
  const threads = nodeThreads();
33
33
  if (!threads)
34
34
  return null;
35
35
  //the same source string as the browser path, executed as CJS by Node's eval mode
36
- const worker = new threads.Worker(`(${workerMain.toString()})()`, { eval: true });
37
- worker.on('message', (reply) => events.reply(reply));
36
+ const worker = new threads.Worker(source, { eval: true });
37
+ worker.on('message', (reply) => events.message(reply));
38
38
  worker.on('error', (error) => events.fail(error instanceof Error ? error : new Error(String(error))));
39
39
  worker.on('messageerror', () => events.fail(new Error('the worker sent a reply that could not be deserialized')));
40
40
  //a task that kills its worker without answering must reject rather than hang forever -
41
41
  //the failure the multithreading package's pool never reports (T161)
42
42
  worker.on('exit', (code) => events.fail(new Error(`the worker exited with code ${code} before answering`)));
43
43
  return {
44
- post: (message, transfer) => worker.postMessage(message, transfer),
44
+ post: (message, transfer = []) => worker.postMessage(message, transfer),
45
45
  terminate: () => void worker.terminate(),
46
46
  };
47
47
  };
48
+ /**
49
+ * Opens a worker running a classic script, in a browser (a blob worker, which the shipped
50
+ * `file://` page's policy allows) or in Node (`worker_threads` in eval mode), and returns null
51
+ * where neither exists. `spawn` is the one-task-per-worker use of this; a long-lived service
52
+ * such as the audio core host keeps its worker and talks to it with messages.
53
+ *
54
+ * The script must be self-contained for the same reason a `spawn` task must: it runs with
55
+ * nothing but its own text in scope.
56
+ *
57
+ * @example
58
+ * ```ts
59
+ * import { openWorker } from '@datamoc/mw_games/threads';
60
+ *
61
+ * const link = openWorker('globalThis.onmessage = (event) => globalThis.postMessage(event.data * 2);', {
62
+ * message: (value) => console.log(value),
63
+ * fail: (error) => console.warn(error.message),
64
+ * });
65
+ * link?.post(21);
66
+ * ```
67
+ */
68
+ export function openWorker(source, events) {
69
+ //each host returns null when its environment is absent, so they are tried in order
70
+ return browserWorker(source, events) ?? nodeWorker(source, events);
71
+ }
48
72
  /** the error a failed reply carries, with the worker-side stack where there was one */
49
73
  function taskError(reply) {
50
74
  const error = new Error(reply.message);
@@ -107,7 +131,8 @@ export function spawn(fn, args, options = {}) {
107
131
  settle(() => reject(options.signal.reason));
108
132
  }
109
133
  const events = {
110
- reply: (reply) => settle(() => {
134
+ message: (data) => settle(() => {
135
+ const reply = data;
111
136
  if (reply.ok)
112
137
  resolve(reply.value);
113
138
  else
@@ -116,8 +141,7 @@ export function spawn(fn, args, options = {}) {
116
141
  fail: (error) => settle(() => reject(error)),
117
142
  };
118
143
  try {
119
- //each host returns null when its environment is absent, so they are tried in order
120
- worker = browserWorker(events) ?? nodeWorker(events);
144
+ worker = openWorker(`(${workerMain.toString()})()`, events);
121
145
  }
122
146
  catch (error) {
123
147
  reject(error);
@@ -1 +1 @@
1
- {"version":3,"file":"spawn.js","sourceRoot":"","sources":["../../src/threads/spawn.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"spawn.js","sourceRoot":"","sources":["../../src/threads/spawn.ts"],"names":[],"mappings":"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"}