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.
- package/LICENSE +165 -0
- package/README.md +126 -0
- package/dist/core.d.ts +276 -0
- package/dist/fm_banks/ail/MonopolyDeluxe.wopl +0 -0
- package/dist/fm_banks/ail/master_of_magic.wopl +0 -0
- package/dist/fm_banks/manifest.json +60 -0
- package/dist/fm_banks/wopl/Apogee-IMF-90.wopl +0 -0
- package/dist/fm_banks/wopl/DMXOPL3-by-sneakernets-GS.wopl +0 -0
- package/dist/fm_banks/wopl/GM-By-J.A.Nguyen-and-Wohlstand.wopl +0 -0
- package/dist/fm_banks/wopl/Wohlstand's-modded-FatMan.wopl +0 -0
- package/dist/fm_banks/wopl/fatman-2op.wopl +0 -0
- package/dist/fm_banks/wopl/fatman-4op.wopl +0 -0
- package/dist/fm_banks/wopl/msadlib.wopl +0 -0
- package/dist/libadlmidi.d.ts +453 -0
- package/dist/libadlmidi.dosbox.browser.js +2 -0
- package/dist/libadlmidi.dosbox.browser.wasm +0 -0
- package/dist/libadlmidi.dosbox.core.js +2 -0
- package/dist/libadlmidi.dosbox.core.wasm +0 -0
- package/dist/libadlmidi.dosbox.js +0 -0
- package/dist/libadlmidi.dosbox.processor.js +3226 -0
- package/dist/libadlmidi.dosbox.slim.browser.js +2 -0
- package/dist/libadlmidi.dosbox.slim.browser.wasm +0 -0
- package/dist/libadlmidi.dosbox.slim.core.js +2 -0
- package/dist/libadlmidi.dosbox.slim.core.wasm +0 -0
- package/dist/libadlmidi.dosbox.slim.js +0 -0
- package/dist/libadlmidi.dosbox.slim.processor.js +3226 -0
- package/dist/libadlmidi.full.browser.js +2 -0
- package/dist/libadlmidi.full.browser.wasm +0 -0
- package/dist/libadlmidi.full.core.js +2 -0
- package/dist/libadlmidi.full.core.wasm +0 -0
- package/dist/libadlmidi.full.js +0 -0
- package/dist/libadlmidi.full.processor.js +3226 -0
- package/dist/libadlmidi.full.slim.browser.js +2 -0
- package/dist/libadlmidi.full.slim.browser.wasm +0 -0
- package/dist/libadlmidi.full.slim.core.js +2 -0
- package/dist/libadlmidi.full.slim.core.wasm +0 -0
- package/dist/libadlmidi.full.slim.js +0 -0
- package/dist/libadlmidi.full.slim.processor.js +3226 -0
- package/dist/libadlmidi.js +445 -0
- package/dist/libadlmidi.js.map +7 -0
- package/dist/libadlmidi.light.browser.js +2 -0
- package/dist/libadlmidi.light.browser.wasm +0 -0
- package/dist/libadlmidi.light.core.js +2 -0
- package/dist/libadlmidi.light.core.wasm +0 -0
- package/dist/libadlmidi.light.js +0 -0
- package/dist/libadlmidi.light.processor.js +3226 -0
- package/dist/libadlmidi.light.slim.browser.js +2 -0
- package/dist/libadlmidi.light.slim.browser.wasm +0 -0
- package/dist/libadlmidi.light.slim.core.js +2 -0
- package/dist/libadlmidi.light.slim.core.wasm +0 -0
- package/dist/libadlmidi.light.slim.js +0 -0
- package/dist/libadlmidi.light.slim.processor.js +3226 -0
- package/dist/libadlmidi.nuked.browser.js +2 -0
- package/dist/libadlmidi.nuked.browser.wasm +0 -0
- package/dist/libadlmidi.nuked.core.js +2 -0
- package/dist/libadlmidi.nuked.core.wasm +0 -0
- package/dist/libadlmidi.nuked.js +0 -0
- package/dist/libadlmidi.nuked.processor.js +3226 -0
- package/dist/libadlmidi.nuked.slim.browser.js +2 -0
- package/dist/libadlmidi.nuked.slim.browser.wasm +0 -0
- package/dist/libadlmidi.nuked.slim.core.js +2 -0
- package/dist/libadlmidi.nuked.slim.core.wasm +0 -0
- package/dist/libadlmidi.nuked.slim.js +0 -0
- package/dist/libadlmidi.nuked.slim.processor.js +3226 -0
- package/dist/profiles/dosbox.d.ts +49 -0
- package/dist/profiles/dosbox.slim.d.ts +49 -0
- package/dist/profiles/full.d.ts +49 -0
- package/dist/profiles/full.slim.d.ts +49 -0
- package/dist/profiles/light.d.ts +49 -0
- package/dist/profiles/light.slim.d.ts +49 -0
- package/dist/profiles/nuked.d.ts +49 -0
- package/dist/profiles/nuked.slim.d.ts +49 -0
- package/dist/utils/struct.d.ts +209 -0
- package/package.json +103 -0
- package/src/core.js +591 -0
- package/src/libadlmidi.js +524 -0
- package/src/processor.js +517 -0
- package/src/profiles/dosbox.js +82 -0
- package/src/profiles/dosbox.slim.js +82 -0
- package/src/profiles/full.js +82 -0
- package/src/profiles/full.slim.js +82 -0
- package/src/profiles/light.js +82 -0
- package/src/profiles/light.slim.js +82 -0
- package/src/profiles/nuked.js +82 -0
- package/src/profiles/nuked.slim.js +82 -0
- 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
|
+
}
|