libadlmidi-js 1.0.0

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 (86) hide show
  1. package/LICENSE +165 -0
  2. package/README.md +126 -0
  3. package/dist/core.d.ts +276 -0
  4. package/dist/fm_banks/ail/MonopolyDeluxe.wopl +0 -0
  5. package/dist/fm_banks/ail/master_of_magic.wopl +0 -0
  6. package/dist/fm_banks/manifest.json +60 -0
  7. package/dist/fm_banks/wopl/Apogee-IMF-90.wopl +0 -0
  8. package/dist/fm_banks/wopl/DMXOPL3-by-sneakernets-GS.wopl +0 -0
  9. package/dist/fm_banks/wopl/GM-By-J.A.Nguyen-and-Wohlstand.wopl +0 -0
  10. package/dist/fm_banks/wopl/Wohlstand's-modded-FatMan.wopl +0 -0
  11. package/dist/fm_banks/wopl/fatman-2op.wopl +0 -0
  12. package/dist/fm_banks/wopl/fatman-4op.wopl +0 -0
  13. package/dist/fm_banks/wopl/msadlib.wopl +0 -0
  14. package/dist/libadlmidi.d.ts +453 -0
  15. package/dist/libadlmidi.dosbox.browser.js +2 -0
  16. package/dist/libadlmidi.dosbox.browser.wasm +0 -0
  17. package/dist/libadlmidi.dosbox.core.js +2 -0
  18. package/dist/libadlmidi.dosbox.core.wasm +0 -0
  19. package/dist/libadlmidi.dosbox.js +0 -0
  20. package/dist/libadlmidi.dosbox.processor.js +3226 -0
  21. package/dist/libadlmidi.dosbox.slim.browser.js +2 -0
  22. package/dist/libadlmidi.dosbox.slim.browser.wasm +0 -0
  23. package/dist/libadlmidi.dosbox.slim.core.js +2 -0
  24. package/dist/libadlmidi.dosbox.slim.core.wasm +0 -0
  25. package/dist/libadlmidi.dosbox.slim.js +0 -0
  26. package/dist/libadlmidi.dosbox.slim.processor.js +3226 -0
  27. package/dist/libadlmidi.full.browser.js +2 -0
  28. package/dist/libadlmidi.full.browser.wasm +0 -0
  29. package/dist/libadlmidi.full.core.js +2 -0
  30. package/dist/libadlmidi.full.core.wasm +0 -0
  31. package/dist/libadlmidi.full.js +0 -0
  32. package/dist/libadlmidi.full.processor.js +3226 -0
  33. package/dist/libadlmidi.full.slim.browser.js +2 -0
  34. package/dist/libadlmidi.full.slim.browser.wasm +0 -0
  35. package/dist/libadlmidi.full.slim.core.js +2 -0
  36. package/dist/libadlmidi.full.slim.core.wasm +0 -0
  37. package/dist/libadlmidi.full.slim.js +0 -0
  38. package/dist/libadlmidi.full.slim.processor.js +3226 -0
  39. package/dist/libadlmidi.js +445 -0
  40. package/dist/libadlmidi.js.map +7 -0
  41. package/dist/libadlmidi.light.browser.js +2 -0
  42. package/dist/libadlmidi.light.browser.wasm +0 -0
  43. package/dist/libadlmidi.light.core.js +2 -0
  44. package/dist/libadlmidi.light.core.wasm +0 -0
  45. package/dist/libadlmidi.light.js +0 -0
  46. package/dist/libadlmidi.light.processor.js +3226 -0
  47. package/dist/libadlmidi.light.slim.browser.js +2 -0
  48. package/dist/libadlmidi.light.slim.browser.wasm +0 -0
  49. package/dist/libadlmidi.light.slim.core.js +2 -0
  50. package/dist/libadlmidi.light.slim.core.wasm +0 -0
  51. package/dist/libadlmidi.light.slim.js +0 -0
  52. package/dist/libadlmidi.light.slim.processor.js +3226 -0
  53. package/dist/libadlmidi.nuked.browser.js +2 -0
  54. package/dist/libadlmidi.nuked.browser.wasm +0 -0
  55. package/dist/libadlmidi.nuked.core.js +2 -0
  56. package/dist/libadlmidi.nuked.core.wasm +0 -0
  57. package/dist/libadlmidi.nuked.js +0 -0
  58. package/dist/libadlmidi.nuked.processor.js +3226 -0
  59. package/dist/libadlmidi.nuked.slim.browser.js +2 -0
  60. package/dist/libadlmidi.nuked.slim.browser.wasm +0 -0
  61. package/dist/libadlmidi.nuked.slim.core.js +2 -0
  62. package/dist/libadlmidi.nuked.slim.core.wasm +0 -0
  63. package/dist/libadlmidi.nuked.slim.js +0 -0
  64. package/dist/libadlmidi.nuked.slim.processor.js +3226 -0
  65. package/dist/profiles/dosbox.d.ts +49 -0
  66. package/dist/profiles/dosbox.slim.d.ts +49 -0
  67. package/dist/profiles/full.d.ts +49 -0
  68. package/dist/profiles/full.slim.d.ts +49 -0
  69. package/dist/profiles/light.d.ts +49 -0
  70. package/dist/profiles/light.slim.d.ts +49 -0
  71. package/dist/profiles/nuked.d.ts +49 -0
  72. package/dist/profiles/nuked.slim.d.ts +49 -0
  73. package/dist/utils/struct.d.ts +209 -0
  74. package/package.json +103 -0
  75. package/src/core.js +591 -0
  76. package/src/libadlmidi.js +524 -0
  77. package/src/processor.js +517 -0
  78. package/src/profiles/dosbox.js +82 -0
  79. package/src/profiles/dosbox.slim.js +82 -0
  80. package/src/profiles/full.js +82 -0
  81. package/src/profiles/full.slim.js +82 -0
  82. package/src/profiles/light.js +82 -0
  83. package/src/profiles/light.slim.js +82 -0
  84. package/src/profiles/nuked.js +82 -0
  85. package/src/profiles/nuked.slim.js +82 -0
  86. package/src/utils/struct.js +288 -0
@@ -0,0 +1,445 @@
1
+ var __typeError = (msg) => {
2
+ throw TypeError(msg);
3
+ };
4
+ var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
5
+ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
6
+ var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
7
+ var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
8
+ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
9
+
10
+ // src/libadlmidi.js
11
+ var Emulator = Object.freeze({
12
+ /** Nuked OPL3 v1.8 - Most accurate, higher CPU usage */
13
+ NUKED: 0,
14
+ /** Nuked OPL3 v1.7.4 - Slightly older version */
15
+ NUKED_174: 1,
16
+ /** DosBox OPL3 - Good accuracy, lower CPU usage */
17
+ DOSBOX: 2,
18
+ /** Opal - Reality Adlib Tracker emulator */
19
+ OPAL: 3,
20
+ /** Java OPL3 - Port of emu8950 */
21
+ JAVA: 4,
22
+ /** ESFMu - ESFM chip emulator */
23
+ ESFMU: 5,
24
+ /** MAME OPL2 */
25
+ MAME_OPL2: 6,
26
+ /** YMFM OPL2 */
27
+ YMFM_OPL2: 7,
28
+ /** YMFM OPL3 */
29
+ YMFM_OPL3: 8,
30
+ /** Nuked OPL2 LLE - Transistor-level emulation */
31
+ NUKED_OPL2_LLE: 9,
32
+ /** Nuked OPL3 LLE - Transistor-level emulation */
33
+ NUKED_OPL3_LLE: 10
34
+ });
35
+ var _ready, _messageHandlers, _AdlMidi_instances, handleMessage_fn, onceMessage_fn, send_fn;
36
+ var AdlMidi = class {
37
+ /**
38
+ * Create a new AdlMidi instance
39
+ * @param {AudioContext} [context] - Optional AudioContext to use. Creates one if not provided.
40
+ */
41
+ constructor(context) {
42
+ __privateAdd(this, _AdlMidi_instances);
43
+ /** @type {boolean} */
44
+ __privateAdd(this, _ready, false);
45
+ /** @type {Map<string, Set<Function>>} */
46
+ __privateAdd(this, _messageHandlers, /* @__PURE__ */ new Map());
47
+ this.ctx = context || null;
48
+ this.node = null;
49
+ }
50
+ /**
51
+ * Get the AudioContext (may be null before init)
52
+ * @returns {AudioContext | null}
53
+ */
54
+ get audioContext() {
55
+ return this.ctx;
56
+ }
57
+ /**
58
+ * Check if the synth is ready
59
+ * @returns {boolean}
60
+ */
61
+ get ready() {
62
+ return __privateGet(this, _ready);
63
+ }
64
+ /**
65
+ * Initialize the synthesizer
66
+ * @param {string} processorUrl - URL to the bundled processor JavaScript file
67
+ * @param {string | null} [wasmUrl=null] - Optional URL to the .wasm file for split builds.
68
+ * If not provided, assumes bundled version with embedded WASM.
69
+ * @returns {Promise<void>}
70
+ */
71
+ async init(processorUrl, wasmUrl = null) {
72
+ if (!this.ctx) {
73
+ this.ctx = new AudioContext({ sampleRate: 44100 });
74
+ }
75
+ if (this.ctx.state === "suspended") {
76
+ await this.ctx.resume();
77
+ }
78
+ let wasmBinary = null;
79
+ const effectiveWasmUrl = wasmUrl || processorUrl.replace(".processor.js", ".core.wasm");
80
+ const response = await fetch(effectiveWasmUrl);
81
+ if (!response.ok) {
82
+ throw new Error(`Failed to fetch WASM: ${response.status}`);
83
+ }
84
+ wasmBinary = await response.arrayBuffer();
85
+ await this.ctx.audioWorklet.addModule(processorUrl);
86
+ this.node = new AudioWorkletNode(this.ctx, "adl-midi-processor", {
87
+ processorOptions: {
88
+ sampleRate: this.ctx.sampleRate,
89
+ wasmBinary
90
+ // null for bundled, ArrayBuffer for split
91
+ }
92
+ });
93
+ this.node.connect(this.ctx.destination);
94
+ this.node.port.onmessage = (e) => __privateMethod(this, _AdlMidi_instances, handleMessage_fn).call(this, e.data);
95
+ return new Promise((resolve, reject) => {
96
+ const timeout = setTimeout(() => {
97
+ reject(new Error("Timeout waiting for WASM initialization"));
98
+ }, 1e4);
99
+ __privateMethod(this, _AdlMidi_instances, onceMessage_fn).call(this, "ready", () => {
100
+ clearTimeout(timeout);
101
+ __privateSet(this, _ready, true);
102
+ resolve();
103
+ });
104
+ __privateMethod(this, _AdlMidi_instances, onceMessage_fn).call(
105
+ this,
106
+ "error",
107
+ /** @param {{message: string}} msg */
108
+ (msg) => {
109
+ clearTimeout(timeout);
110
+ reject(new Error(msg.message));
111
+ }
112
+ );
113
+ });
114
+ }
115
+ /**
116
+ * Play a note
117
+ * @param {number} channel - MIDI channel (0-15)
118
+ * @param {number} note - MIDI note number (0-127)
119
+ * @param {number} velocity - Note velocity (0-127)
120
+ */
121
+ noteOn(channel, note, velocity) {
122
+ __privateMethod(this, _AdlMidi_instances, send_fn).call(this, { type: "noteOn", channel, note, velocity });
123
+ }
124
+ /**
125
+ * Stop a note
126
+ * @param {number} channel - MIDI channel (0-15)
127
+ * @param {number} note - MIDI note number (0-127)
128
+ */
129
+ noteOff(channel, note) {
130
+ __privateMethod(this, _AdlMidi_instances, send_fn).call(this, { type: "noteOff", channel, note });
131
+ }
132
+ /**
133
+ * Set pitch bend
134
+ * @param {number} channel - MIDI channel (0-15)
135
+ * @param {number} value - Pitch bend value (0-16383, 8192 = center)
136
+ */
137
+ pitchBend(channel, value) {
138
+ const lsb = value & 127;
139
+ const msb = value >> 7 & 127;
140
+ __privateMethod(this, _AdlMidi_instances, send_fn).call(this, { type: "pitchBend", channel, lsb, msb });
141
+ }
142
+ /**
143
+ * Send a control change
144
+ * @param {number} channel - MIDI channel (0-15)
145
+ * @param {number} controller - Controller number (0-127)
146
+ * @param {number} value - Controller value (0-127)
147
+ */
148
+ controlChange(channel, controller, value) {
149
+ __privateMethod(this, _AdlMidi_instances, send_fn).call(this, { type: "controlChange", channel, controller, value });
150
+ }
151
+ /**
152
+ * Change program (instrument)
153
+ * @param {number} channel - MIDI channel (0-15)
154
+ * @param {number} program - Program number (0-127)
155
+ */
156
+ programChange(channel, program) {
157
+ __privateMethod(this, _AdlMidi_instances, send_fn).call(this, { type: "programChange", channel, program });
158
+ }
159
+ /**
160
+ * Reset the real-time state (stops all notes, resets controllers)
161
+ * @returns {void}
162
+ */
163
+ resetState() {
164
+ __privateMethod(this, _AdlMidi_instances, send_fn).call(this, { type: "resetState" });
165
+ }
166
+ /**
167
+ * Panic - stop all sounds immediately
168
+ * @returns {void}
169
+ */
170
+ panic() {
171
+ __privateMethod(this, _AdlMidi_instances, send_fn).call(this, { type: "panic" });
172
+ }
173
+ /**
174
+ * Configure synth settings at runtime
175
+ * @param {ConfigureSettings} settings - Settings object
176
+ * @returns {Promise<void>}
177
+ */
178
+ async configure(settings) {
179
+ return new Promise((resolve) => {
180
+ __privateMethod(this, _AdlMidi_instances, onceMessage_fn).call(this, "configured", () => resolve());
181
+ __privateMethod(this, _AdlMidi_instances, send_fn).call(this, { type: "configure", settings });
182
+ });
183
+ }
184
+ /**
185
+ * Load a custom bank file (WOPL format)
186
+ * @param {ArrayBuffer} arrayBuffer - Bank file data
187
+ * @returns {Promise<void>}
188
+ */
189
+ async loadBank(arrayBuffer) {
190
+ return new Promise((resolve, reject) => {
191
+ __privateMethod(this, _AdlMidi_instances, onceMessage_fn).call(
192
+ this,
193
+ "bankLoaded",
194
+ /** @param {{success: boolean, error?: string}} msg */
195
+ (msg) => {
196
+ if (msg.success) {
197
+ resolve();
198
+ } else {
199
+ reject(new Error(msg.error || "Failed to load bank"));
200
+ }
201
+ }
202
+ );
203
+ __privateMethod(this, _AdlMidi_instances, send_fn).call(this, { type: "loadBank", data: arrayBuffer });
204
+ });
205
+ }
206
+ /**
207
+ * Set the embedded bank by number
208
+ * @param {number} bank - Bank number
209
+ * @returns {Promise<void>}
210
+ */
211
+ async setBank(bank) {
212
+ return new Promise((resolve, reject) => {
213
+ __privateMethod(this, _AdlMidi_instances, onceMessage_fn).call(
214
+ this,
215
+ "bankSet",
216
+ /** @param {{success: boolean}} msg */
217
+ (msg) => {
218
+ if (msg.success) {
219
+ resolve();
220
+ } else {
221
+ reject(new Error(`Failed to set bank ${bank}`));
222
+ }
223
+ }
224
+ );
225
+ __privateMethod(this, _AdlMidi_instances, send_fn).call(this, { type: "setBank", bank });
226
+ });
227
+ }
228
+ /**
229
+ * Get an instrument from a bank for editing
230
+ * @param {BankId} [bankId] - Bank identifier
231
+ * @param {number} [programNumber] - Program/instrument number (0-127)
232
+ * @returns {Promise<Instrument>} Instrument object with named properties
233
+ */
234
+ async getInstrument(bankId = { percussive: false, msb: 0, lsb: 0 }, programNumber = 0) {
235
+ return new Promise((resolve, reject) => {
236
+ __privateMethod(this, _AdlMidi_instances, onceMessage_fn).call(
237
+ this,
238
+ "instrumentLoaded",
239
+ /** @param {{success: boolean, instrument: Instrument, error?: string}} msg */
240
+ (msg) => {
241
+ if (msg.success) {
242
+ resolve(msg.instrument);
243
+ } else {
244
+ reject(new Error(msg.error || "Failed to get instrument"));
245
+ }
246
+ }
247
+ );
248
+ __privateMethod(this, _AdlMidi_instances, send_fn).call(this, { type: "getInstrument", bankId, programNumber });
249
+ });
250
+ }
251
+ /**
252
+ * Set an instrument in a bank
253
+ * @param {BankId} bankId - Bank identifier
254
+ * @param {number} programNumber - Program/instrument number (0-127)
255
+ * @param {Instrument} instrument - Instrument object with operator parameters
256
+ * @returns {Promise<void>}
257
+ */
258
+ async setInstrument(bankId = { percussive: false, msb: 0, lsb: 0 }, programNumber, instrument) {
259
+ return new Promise((resolve, reject) => {
260
+ __privateMethod(this, _AdlMidi_instances, onceMessage_fn).call(
261
+ this,
262
+ "instrumentSet",
263
+ /** @param {{success: boolean, error?: string}} msg */
264
+ (msg) => {
265
+ if (msg.success) {
266
+ resolve();
267
+ } else {
268
+ reject(new Error(msg.error || "Failed to set instrument"));
269
+ }
270
+ }
271
+ );
272
+ __privateMethod(this, _AdlMidi_instances, send_fn).call(this, { type: "setInstrument", bankId, programNumber, instrument });
273
+ });
274
+ }
275
+ /**
276
+ * Set the number of emulated OPL3 chips
277
+ * @param {number} chips - Number of chips (1-100)
278
+ */
279
+ setNumChips(chips) {
280
+ __privateMethod(this, _AdlMidi_instances, send_fn).call(this, { type: "setNumChips", chips });
281
+ }
282
+ /**
283
+ * Set the volume model
284
+ * @param {number} model - Volume model number
285
+ */
286
+ setVolumeModel(model) {
287
+ __privateMethod(this, _AdlMidi_instances, send_fn).call(this, { type: "setVolumeModel", model });
288
+ }
289
+ /**
290
+ * Enable/disable rhythm mode (percussion)
291
+ * @param {boolean} enabled
292
+ */
293
+ setPercussionMode(enabled) {
294
+ __privateMethod(this, _AdlMidi_instances, send_fn).call(this, { type: "setPercMode", enabled });
295
+ }
296
+ /**
297
+ * Enable/disable deep vibrato
298
+ * @param {boolean} enabled
299
+ */
300
+ setVibrato(enabled) {
301
+ __privateMethod(this, _AdlMidi_instances, send_fn).call(this, { type: "setVibrato", enabled });
302
+ }
303
+ /**
304
+ * Enable/disable deep tremolo
305
+ * @param {boolean} enabled
306
+ */
307
+ setTremolo(enabled) {
308
+ __privateMethod(this, _AdlMidi_instances, send_fn).call(this, { type: "setTremolo", enabled });
309
+ }
310
+ /**
311
+ * Switch the OPL3 emulator core at runtime
312
+ *
313
+ * Only emulators compiled into the current build profile are available:
314
+ * - nuked profile: NUKED only
315
+ * - dosbox profile: DOSBOX only
316
+ * - light profile: NUKED, DOSBOX
317
+ * - full profile: NUKED, DOSBOX, OPAL, JAVA, ESFMU, YMFM_OPL2, YMFM_OPL3
318
+ *
319
+ * @param {number} emulator - Emulator ID from the Emulator enum
320
+ * @returns {Promise<void>} Resolves when emulator is switched, rejects if unavailable
321
+ * @example
322
+ * import { AdlMidi, Emulator } from 'libadlmidi-js';
323
+ * await synth.switchEmulator(Emulator.DOSBOX);
324
+ */
325
+ async switchEmulator(emulator) {
326
+ return new Promise((resolve, reject) => {
327
+ __privateMethod(this, _AdlMidi_instances, onceMessage_fn).call(
328
+ this,
329
+ "emulatorSwitched",
330
+ /** @param {{success: boolean, emulator: number}} msg */
331
+ (msg) => {
332
+ if (msg.success) {
333
+ resolve();
334
+ } else {
335
+ reject(new Error(`Failed to switch to emulator ${emulator}. It may not be available in this build profile.`));
336
+ }
337
+ }
338
+ );
339
+ __privateMethod(this, _AdlMidi_instances, send_fn).call(this, { type: "switchEmulator", emulator });
340
+ });
341
+ }
342
+ /**
343
+ * Get the name of the currently active OPL3 emulator
344
+ * @returns {Promise<string>} Human-readable emulator name (e.g., "Nuked OPL3 (v 1.8)")
345
+ * @example
346
+ * const name = await synth.getEmulatorName();
347
+ * console.log(`Using: ${name}`);
348
+ */
349
+ async getEmulatorName() {
350
+ return new Promise((resolve) => {
351
+ __privateMethod(this, _AdlMidi_instances, onceMessage_fn).call(
352
+ this,
353
+ "emulatorName",
354
+ /** @param {{name: string}} msg */
355
+ (msg) => {
356
+ resolve(msg.name);
357
+ }
358
+ );
359
+ __privateMethod(this, _AdlMidi_instances, send_fn).call(this, { type: "getEmulatorName" });
360
+ });
361
+ }
362
+ /**
363
+ * Reset the synthesizer
364
+ * @returns {void}
365
+ */
366
+ reset() {
367
+ __privateMethod(this, _AdlMidi_instances, send_fn).call(this, { type: "reset" });
368
+ }
369
+ /**
370
+ * Close the synthesizer and release resources
371
+ * @returns {void}
372
+ */
373
+ close() {
374
+ if (this.node) {
375
+ this.node.disconnect();
376
+ this.node = null;
377
+ }
378
+ this._ready = false;
379
+ }
380
+ /**
381
+ * Suspend the AudioContext (save CPU when not in use)
382
+ * @returns {Promise<void>}
383
+ */
384
+ async suspend() {
385
+ if (this.ctx) {
386
+ await this.ctx.suspend();
387
+ }
388
+ }
389
+ /**
390
+ * Resume the AudioContext
391
+ * @returns {Promise<void>}
392
+ */
393
+ async resume() {
394
+ if (this.ctx) {
395
+ await this.ctx.resume();
396
+ }
397
+ }
398
+ };
399
+ _ready = new WeakMap();
400
+ _messageHandlers = new WeakMap();
401
+ _AdlMidi_instances = new WeakSet();
402
+ /**
403
+ * Internal message handler
404
+ * @param {{type: string}} msg - Message from processor
405
+ */
406
+ handleMessage_fn = function(msg) {
407
+ const handlers = __privateGet(this, _messageHandlers).get(msg.type);
408
+ if (handlers) {
409
+ handlers.forEach(
410
+ /** @param {Function} handler */
411
+ (handler) => handler(msg)
412
+ );
413
+ }
414
+ };
415
+ /**
416
+ * Register a one-time message handler
417
+ * @param {string} type - Message type
418
+ * @param {Function} handler - Handler function
419
+ */
420
+ onceMessage_fn = function(type, handler) {
421
+ if (!__privateGet(this, _messageHandlers).has(type)) {
422
+ __privateGet(this, _messageHandlers).set(type, /* @__PURE__ */ new Set());
423
+ }
424
+ const wrappedHandler = (msg) => {
425
+ __privateGet(this, _messageHandlers).get(type)?.delete(wrappedHandler);
426
+ handler(msg);
427
+ };
428
+ __privateGet(this, _messageHandlers).get(type)?.add(wrappedHandler);
429
+ };
430
+ /**
431
+ * Send a message to the processor
432
+ * @param {Object} msg - Message to send
433
+ */
434
+ send_fn = function(msg) {
435
+ if (this.node) {
436
+ this.node.port.postMessage(msg);
437
+ }
438
+ };
439
+ var libadlmidi_default = AdlMidi;
440
+ export {
441
+ AdlMidi,
442
+ Emulator,
443
+ libadlmidi_default as default
444
+ };
445
+ //# sourceMappingURL=libadlmidi.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/libadlmidi.js"],
4
+ "sourcesContent": ["/**\n * libADLMIDI-JS - Main Thread Interface\n * \n * High-level API for real-time OPL3 FM synthesis in the browser.\n * \n * @example\n * ```javascript\n * import { AdlMidi } from 'libadlmidi-js';\n * \n * const synth = new AdlMidi();\n * await synth.init('/path/to/processor.js');\n * \n * synth.noteOn(0, 60, 100); // Middle C on channel 0\n * synth.noteOff(0, 60);\n * ```\n */\n\n/**\n * Bank identifier for instrument access\n * @typedef {Object} BankId\n * @property {boolean} percussive - True for percussion bank, false for melodic\n * @property {number} msb - Bank MSB (0-127)\n * @property {number} lsb - Bank LSB (0-127)\n */\n\n/**\n * OPL3 operator parameters \n * @typedef {Object} Operator\n * @property {boolean} am - Amplitude modulation (tremolo)\n * @property {boolean} vibrato - Vibrato (frequency modulation)\n * @property {boolean} sustaining - Sustaining (EG type)\n * @property {boolean} ksr - Key scale rate\n * @property {number} freqMult - Frequency multiplier (0-15)\n * @property {number} keyScaleLevel - Key scale level (0-3)\n * @property {number} totalLevel - Total level / attenuation (0-63, 0 = loudest)\n * @property {number} attack - Attack rate (0-15)\n * @property {number} decay - Decay rate (0-15)\n * @property {number} sustain - Sustain level (0-15, 0 = loudest)\n * @property {number} release - Release rate (0-15)\n * @property {number} waveform - Waveform select (0-7)\n */\n\n/**\n * Complete OPL3 instrument definition\n * @typedef {Object} Instrument\n * @property {boolean} is4op - 4-operator mode enabled\n * @property {boolean} isPseudo4op - Pseudo 4-op (two 2-op voices)\n * @property {boolean} isBlank - Blank/unused instrument\n * @property {boolean} isRhythmModeCar - Rhythm mode carrier flag\n * @property {boolean} isRhythmModeMod - Rhythm mode modulator flag\n * @property {number} feedback1 - Voice 1 feedback (0-7)\n * @property {number} connection1 - Voice 1 connection (0 = FM, 1 = additive)\n * @property {number} feedback2 - Voice 2 feedback (0-7, 4-op only)\n * @property {number} connection2 - Voice 2 connection (0 = FM, 1 = additive, 4-op only)\n * @property {number} noteOffset1 - Note offset for voice 1 (semitones)\n * @property {number} noteOffset2 - Note offset for voice 2 (semitones)\n * @property {number} velocityOffset - Velocity offset\n * @property {number} secondVoiceDetune - Second voice detune (cents)\n * @property {number} percussionNote - Percussion note number\n * @property {number} delayOnMs - Delay before note-on (ms)\n * @property {number} delayOffMs - Delay before note-off (ms)\n * @property {[Operator, Operator, Operator, Operator]} operators - Four operators\n */\n\n/**\n * Configuration settings for the synthesizer\n * @typedef {Object} ConfigureSettings\n * @property {number} [numChips] - Number of emulated OPL3 chips (1-100)\n * @property {number} [numFourOpChannels] - Number of 4-op channels (-1 = auto)\n * @property {number} [bank] - Embedded bank number\n * @property {boolean} [softPan] - Enable soft stereo panning\n * @property {boolean} [deepVibrato] - Enable deep vibrato\n * @property {boolean} [deepTremolo] - Enable deep tremolo\n */\n\n/**\n * Available OPL3 emulator cores.\n * Use with switchEmulator() to change the synthesis engine at runtime.\n * Note: Only emulators compiled into the current profile are available.\n * @readonly\n * @enum {number}\n */\nexport const Emulator = Object.freeze({\n /** Nuked OPL3 v1.8 - Most accurate, higher CPU usage */\n NUKED: 0,\n /** Nuked OPL3 v1.7.4 - Slightly older version */\n NUKED_174: 1,\n /** DosBox OPL3 - Good accuracy, lower CPU usage */\n DOSBOX: 2,\n /** Opal - Reality Adlib Tracker emulator */\n OPAL: 3,\n /** Java OPL3 - Port of emu8950 */\n JAVA: 4,\n /** ESFMu - ESFM chip emulator */\n ESFMU: 5,\n /** MAME OPL2 */\n MAME_OPL2: 6,\n /** YMFM OPL2 */\n YMFM_OPL2: 7,\n /** YMFM OPL3 */\n YMFM_OPL3: 8,\n /** Nuked OPL2 LLE - Transistor-level emulation */\n NUKED_OPL2_LLE: 9,\n /** Nuked OPL3 LLE - Transistor-level emulation */\n NUKED_OPL3_LLE: 10,\n});\n\nexport class AdlMidi {\n /** @type {boolean} */\n #ready = false;\n /** @type {Map<string, Set<Function>>} */\n #messageHandlers = new Map();\n\n /**\n * Create a new AdlMidi instance\n * @param {AudioContext} [context] - Optional AudioContext to use. Creates one if not provided.\n */\n constructor(context) {\n this.ctx = context || null;\n this.node = null;\n }\n\n /**\n * Get the AudioContext (may be null before init)\n * @returns {AudioContext | null}\n */\n get audioContext() {\n return this.ctx;\n }\n\n /**\n * Check if the synth is ready\n * @returns {boolean}\n */\n get ready() {\n return this.#ready;\n }\n\n /**\n * Initialize the synthesizer\n * @param {string} processorUrl - URL to the bundled processor JavaScript file\n * @param {string | null} [wasmUrl=null] - Optional URL to the .wasm file for split builds.\n * If not provided, assumes bundled version with embedded WASM.\n * @returns {Promise<void>}\n */\n async init(processorUrl, wasmUrl = null) {\n if (!this.ctx) {\n this.ctx = new AudioContext({ sampleRate: 44100 });\n }\n\n // Resume AudioContext if suspended (browser autoplay policy)\n if (this.ctx.state === 'suspended') {\n await this.ctx.resume();\n }\n\n // For split builds, fetch the WASM binary from main thread\n // (AudioWorklet doesn't have fetch access)\n // If wasmUrl not provided, derive it from processorUrl\n let wasmBinary = null;\n const effectiveWasmUrl = wasmUrl || processorUrl.replace('.processor.js', '.core.wasm');\n const response = await fetch(effectiveWasmUrl);\n if (!response.ok) {\n throw new Error(`Failed to fetch WASM: ${response.status}`);\n }\n wasmBinary = await response.arrayBuffer();\n\n // Add the AudioWorklet module\n await this.ctx.audioWorklet.addModule(processorUrl);\n\n // Create the AudioWorkletNode\n this.node = new AudioWorkletNode(this.ctx, 'adl-midi-processor', {\n processorOptions: {\n sampleRate: this.ctx.sampleRate,\n wasmBinary: wasmBinary // null for bundled, ArrayBuffer for split\n }\n });\n\n // Connect to destination\n this.node.connect(this.ctx.destination);\n\n // Set up message handling\n this.node.port.onmessage = (e) => this.#handleMessage(e.data);\n\n // Wait for the processor to be ready\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => {\n reject(new Error('Timeout waiting for WASM initialization'));\n }, 10000);\n\n this.#onceMessage('ready', () => {\n clearTimeout(timeout);\n this.#ready = true;\n resolve();\n });\n\n this.#onceMessage('error', /** @param {{message: string}} msg */(msg) => {\n clearTimeout(timeout);\n reject(new Error(msg.message));\n });\n });\n }\n\n /**\n * Internal message handler\n * @param {{type: string}} msg - Message from processor\n */\n #handleMessage(msg) {\n const handlers = this.#messageHandlers.get(msg.type);\n if (handlers) {\n handlers.forEach(/** @param {Function} handler */ handler => handler(msg));\n }\n }\n\n /**\n * Register a one-time message handler\n * @param {string} type - Message type\n * @param {Function} handler - Handler function\n */\n #onceMessage(type, handler) {\n if (!this.#messageHandlers.has(type)) {\n this.#messageHandlers.set(type, new Set());\n }\n\n /** @param {Object} msg */\n const wrappedHandler = (msg) => {\n this.#messageHandlers.get(type)?.delete(wrappedHandler);\n handler(msg);\n };\n\n this.#messageHandlers.get(type)?.add(wrappedHandler);\n }\n\n /**\n * Send a message to the processor\n * @param {Object} msg - Message to send\n */\n #send(msg) {\n if (this.node) {\n this.node.port.postMessage(msg);\n }\n }\n\n /**\n * Play a note\n * @param {number} channel - MIDI channel (0-15)\n * @param {number} note - MIDI note number (0-127)\n * @param {number} velocity - Note velocity (0-127)\n */\n noteOn(channel, note, velocity) {\n this.#send({ type: 'noteOn', channel, note, velocity });\n }\n\n /**\n * Stop a note\n * @param {number} channel - MIDI channel (0-15)\n * @param {number} note - MIDI note number (0-127)\n */\n noteOff(channel, note) {\n this.#send({ type: 'noteOff', channel, note });\n }\n\n /**\n * Set pitch bend\n * @param {number} channel - MIDI channel (0-15)\n * @param {number} value - Pitch bend value (0-16383, 8192 = center)\n */\n pitchBend(channel, value) {\n const lsb = value & 0x7F;\n const msb = (value >> 7) & 0x7F;\n this.#send({ type: 'pitchBend', channel, lsb, msb });\n }\n\n /**\n * Send a control change\n * @param {number} channel - MIDI channel (0-15)\n * @param {number} controller - Controller number (0-127)\n * @param {number} value - Controller value (0-127)\n */\n controlChange(channel, controller, value) {\n this.#send({ type: 'controlChange', channel, controller, value });\n }\n\n /**\n * Change program (instrument)\n * @param {number} channel - MIDI channel (0-15)\n * @param {number} program - Program number (0-127)\n */\n programChange(channel, program) {\n this.#send({ type: 'programChange', channel, program });\n }\n\n /**\n * Reset the real-time state (stops all notes, resets controllers)\n * @returns {void}\n */\n resetState() {\n this.#send({ type: 'resetState' });\n }\n\n /**\n * Panic - stop all sounds immediately\n * @returns {void}\n */\n panic() {\n this.#send({ type: 'panic' });\n }\n\n /**\n * Configure synth settings at runtime\n * @param {ConfigureSettings} settings - Settings object\n * @returns {Promise<void>}\n */\n async configure(settings) {\n return new Promise((resolve) => {\n this.#onceMessage('configured', () => resolve());\n this.#send({ type: 'configure', settings });\n });\n }\n\n /**\n * Load a custom bank file (WOPL format)\n * @param {ArrayBuffer} arrayBuffer - Bank file data\n * @returns {Promise<void>}\n */\n async loadBank(arrayBuffer) {\n return new Promise((resolve, reject) => {\n this.#onceMessage('bankLoaded', /** @param {{success: boolean, error?: string}} msg */(msg) => {\n if (msg.success) {\n resolve();\n } else {\n reject(new Error(msg.error || 'Failed to load bank'));\n }\n });\n\n this.#send({ type: 'loadBank', data: arrayBuffer });\n });\n }\n\n /**\n * Set the embedded bank by number\n * @param {number} bank - Bank number\n * @returns {Promise<void>}\n */\n async setBank(bank) {\n return new Promise((resolve, reject) => {\n this.#onceMessage('bankSet', /** @param {{success: boolean}} msg */(msg) => {\n if (msg.success) {\n resolve();\n } else {\n reject(new Error(`Failed to set bank ${bank}`));\n }\n });\n\n this.#send({ type: 'setBank', bank });\n });\n }\n\n /**\n * Get an instrument from a bank for editing\n * @param {BankId} [bankId] - Bank identifier\n * @param {number} [programNumber] - Program/instrument number (0-127)\n * @returns {Promise<Instrument>} Instrument object with named properties\n */\n async getInstrument(bankId = { percussive: false, msb: 0, lsb: 0 }, programNumber = 0) {\n return new Promise((resolve, reject) => {\n this.#onceMessage('instrumentLoaded', /** @param {{success: boolean, instrument: Instrument, error?: string}} msg */(msg) => {\n if (msg.success) {\n resolve(msg.instrument);\n } else {\n reject(new Error(msg.error || 'Failed to get instrument'));\n }\n });\n\n this.#send({ type: 'getInstrument', bankId, programNumber });\n });\n }\n\n /**\n * Set an instrument in a bank\n * @param {BankId} bankId - Bank identifier\n * @param {number} programNumber - Program/instrument number (0-127)\n * @param {Instrument} instrument - Instrument object with operator parameters\n * @returns {Promise<void>}\n */\n async setInstrument(bankId = { percussive: false, msb: 0, lsb: 0 }, programNumber, instrument) {\n return new Promise((resolve, reject) => {\n this.#onceMessage('instrumentSet', /** @param {{success: boolean, error?: string}} msg */(msg) => {\n if (msg.success) {\n resolve();\n } else {\n reject(new Error(msg.error || 'Failed to set instrument'));\n }\n });\n\n this.#send({ type: 'setInstrument', bankId, programNumber, instrument });\n });\n }\n\n /**\n * Set the number of emulated OPL3 chips\n * @param {number} chips - Number of chips (1-100)\n */\n setNumChips(chips) {\n this.#send({ type: 'setNumChips', chips });\n }\n\n /**\n * Set the volume model\n * @param {number} model - Volume model number\n */\n setVolumeModel(model) {\n this.#send({ type: 'setVolumeModel', model });\n }\n\n /**\n * Enable/disable rhythm mode (percussion)\n * @param {boolean} enabled\n */\n setPercussionMode(enabled) {\n this.#send({ type: 'setPercMode', enabled });\n }\n\n /**\n * Enable/disable deep vibrato\n * @param {boolean} enabled\n */\n setVibrato(enabled) {\n this.#send({ type: 'setVibrato', enabled });\n }\n\n /**\n * Enable/disable deep tremolo\n * @param {boolean} enabled\n */\n setTremolo(enabled) {\n this.#send({ type: 'setTremolo', enabled });\n }\n\n /**\n * Switch the OPL3 emulator core at runtime\n * \n * Only emulators compiled into the current build profile are available:\n * - nuked profile: NUKED only\n * - dosbox profile: DOSBOX only \n * - light profile: NUKED, DOSBOX\n * - full profile: NUKED, DOSBOX, OPAL, JAVA, ESFMU, YMFM_OPL2, YMFM_OPL3\n * \n * @param {number} emulator - Emulator ID from the Emulator enum\n * @returns {Promise<void>} Resolves when emulator is switched, rejects if unavailable\n * @example\n * import { AdlMidi, Emulator } from 'libadlmidi-js';\n * await synth.switchEmulator(Emulator.DOSBOX);\n */\n async switchEmulator(emulator) {\n return new Promise((resolve, reject) => {\n this.#onceMessage('emulatorSwitched', /** @param {{success: boolean, emulator: number}} msg */(msg) => {\n if (msg.success) {\n resolve();\n } else {\n reject(new Error(`Failed to switch to emulator ${emulator}. It may not be available in this build profile.`));\n }\n });\n this.#send({ type: 'switchEmulator', emulator });\n });\n }\n\n /**\n * Get the name of the currently active OPL3 emulator\n * @returns {Promise<string>} Human-readable emulator name (e.g., \"Nuked OPL3 (v 1.8)\")\n * @example\n * const name = await synth.getEmulatorName();\n * console.log(`Using: ${name}`);\n */\n async getEmulatorName() {\n return new Promise((resolve) => {\n this.#onceMessage('emulatorName', /** @param {{name: string}} msg */(msg) => {\n resolve(msg.name);\n });\n this.#send({ type: 'getEmulatorName' });\n });\n }\n\n /**\n * Reset the synthesizer\n * @returns {void}\n */\n reset() {\n this.#send({ type: 'reset' });\n }\n\n /**\n * Close the synthesizer and release resources\n * @returns {void}\n */\n close() {\n if (this.node) {\n this.node.disconnect();\n this.node = null;\n }\n this._ready = false;\n }\n\n /**\n * Suspend the AudioContext (save CPU when not in use)\n * @returns {Promise<void>}\n */\n async suspend() {\n if (this.ctx) {\n await this.ctx.suspend();\n }\n }\n\n /**\n * Resume the AudioContext\n * @returns {Promise<void>}\n */\n async resume() {\n if (this.ctx) {\n await this.ctx.resume();\n }\n }\n}\n\nexport default AdlMidi;\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }