libadlmidi-js 1.1.0 → 1.2.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/README.md +36 -1
- package/dist/core.d.ts +148 -0
- package/dist/fm_banks/manifest.json +1 -1
- package/dist/libadlmidi.d.ts +119 -2
- package/dist/libadlmidi.dosbox.browser.js +1 -1
- package/dist/libadlmidi.dosbox.browser.wasm +0 -0
- package/dist/libadlmidi.dosbox.core.js +1 -1
- package/dist/libadlmidi.dosbox.core.wasm +0 -0
- package/dist/libadlmidi.dosbox.js +0 -0
- package/dist/libadlmidi.dosbox.processor.js +152 -53
- package/dist/libadlmidi.dosbox.slim.browser.js +1 -1
- package/dist/libadlmidi.dosbox.slim.browser.wasm +0 -0
- package/dist/libadlmidi.dosbox.slim.core.js +1 -1
- package/dist/libadlmidi.dosbox.slim.core.wasm +0 -0
- package/dist/libadlmidi.dosbox.slim.js +0 -0
- package/dist/libadlmidi.dosbox.slim.processor.js +152 -53
- package/dist/libadlmidi.full.browser.js +1 -1
- package/dist/libadlmidi.full.browser.wasm +0 -0
- package/dist/libadlmidi.full.core.js +1 -1
- package/dist/libadlmidi.full.core.wasm +0 -0
- package/dist/libadlmidi.full.js +0 -0
- package/dist/libadlmidi.full.processor.js +152 -53
- package/dist/libadlmidi.full.slim.browser.js +1 -1
- package/dist/libadlmidi.full.slim.browser.wasm +0 -0
- package/dist/libadlmidi.full.slim.core.js +1 -1
- package/dist/libadlmidi.full.slim.core.wasm +0 -0
- package/dist/libadlmidi.full.slim.js +0 -0
- package/dist/libadlmidi.full.slim.processor.js +152 -53
- package/dist/libadlmidi.js +258 -4
- package/dist/libadlmidi.js.map +2 -2
- package/dist/libadlmidi.light.browser.js +1 -1
- package/dist/libadlmidi.light.browser.wasm +0 -0
- package/dist/libadlmidi.light.core.js +1 -1
- package/dist/libadlmidi.light.core.wasm +0 -0
- package/dist/libadlmidi.light.js +0 -0
- package/dist/libadlmidi.light.processor.js +152 -53
- package/dist/libadlmidi.light.slim.browser.js +1 -1
- package/dist/libadlmidi.light.slim.browser.wasm +0 -0
- package/dist/libadlmidi.light.slim.core.js +1 -1
- package/dist/libadlmidi.light.slim.core.wasm +0 -0
- package/dist/libadlmidi.light.slim.js +0 -0
- package/dist/libadlmidi.light.slim.processor.js +152 -53
- package/dist/libadlmidi.nuked.browser.js +1 -1
- package/dist/libadlmidi.nuked.browser.wasm +0 -0
- package/dist/libadlmidi.nuked.core.js +1 -1
- package/dist/libadlmidi.nuked.core.wasm +0 -0
- package/dist/libadlmidi.nuked.js +0 -0
- package/dist/libadlmidi.nuked.processor.js +152 -53
- package/dist/libadlmidi.nuked.slim.browser.js +1 -1
- package/dist/libadlmidi.nuked.slim.browser.wasm +0 -0
- package/dist/libadlmidi.nuked.slim.core.js +1 -1
- package/dist/libadlmidi.nuked.slim.core.wasm +0 -0
- package/dist/libadlmidi.nuked.slim.js +0 -0
- package/dist/libadlmidi.nuked.slim.processor.js +152 -53
- package/package.json +6 -5
- package/src/core.js +289 -24
- package/src/libadlmidi.js +229 -4
- package/src/processor.js +101 -1
package/src/core.js
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
import {
|
|
12
12
|
SIZEOF_ADL_INSTRUMENT,
|
|
13
13
|
SIZEOF_ADL_BANK_ID,
|
|
14
|
+
SIZEOF_ADL_BANK,
|
|
14
15
|
decodeInstrument,
|
|
15
16
|
encodeInstrument,
|
|
16
17
|
} from './utils/struct.js';
|
|
@@ -131,6 +132,14 @@ export class AdlMidiCore {
|
|
|
131
132
|
this._module._adl_rt_resetState(this._player);
|
|
132
133
|
}
|
|
133
134
|
|
|
135
|
+
/**
|
|
136
|
+
* Full reset to apply instrument/bank changes.
|
|
137
|
+
*/
|
|
138
|
+
resetFull() {
|
|
139
|
+
this._ensurePlayer();
|
|
140
|
+
this._module._adl_reset(this._player);
|
|
141
|
+
}
|
|
142
|
+
|
|
134
143
|
/**
|
|
135
144
|
* Panic - immediately stop all notes.
|
|
136
145
|
*/
|
|
@@ -212,6 +221,87 @@ export class AdlMidiCore {
|
|
|
212
221
|
return this._module._adl_setNumChips(this._player, count) === 0;
|
|
213
222
|
}
|
|
214
223
|
|
|
224
|
+
/**
|
|
225
|
+
* Set the number of 4-operator channels.
|
|
226
|
+
*
|
|
227
|
+
* @param {number} count - Number of channels (-1 for auto)
|
|
228
|
+
* @returns {boolean} True if successful
|
|
229
|
+
*/
|
|
230
|
+
setNumFourOpChannels(count) {
|
|
231
|
+
this._ensurePlayer();
|
|
232
|
+
return this._module._adl_setNumFourOpsChn(this._player, count) === 0;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Get the number of 4-operator channels.
|
|
237
|
+
*
|
|
238
|
+
* @returns {number} Count of channels
|
|
239
|
+
*/
|
|
240
|
+
getNumFourOpChannels() {
|
|
241
|
+
this._ensurePlayer();
|
|
242
|
+
return this._module._adl_getNumFourOpsChn(this._player);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Enable/disable scaling of modulators by volume.
|
|
247
|
+
*
|
|
248
|
+
* @param {boolean} enabled
|
|
249
|
+
*/
|
|
250
|
+
setScaleModulators(enabled) {
|
|
251
|
+
this._ensurePlayer();
|
|
252
|
+
this._module._adl_setScaleModulators(this._player, enabled ? 1 : 0);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Enable/disable full-range brightness (0-127).
|
|
257
|
+
*
|
|
258
|
+
* @param {boolean} enabled
|
|
259
|
+
*/
|
|
260
|
+
setFullRangeBrightness(enabled) {
|
|
261
|
+
this._ensurePlayer();
|
|
262
|
+
this._module._adl_setFullRangeBrightness(this._player, enabled ? 1 : 0);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Enable/disable automatic arpeggio.
|
|
267
|
+
*
|
|
268
|
+
* @param {boolean} enabled
|
|
269
|
+
*/
|
|
270
|
+
setAutoArpeggio(enabled) {
|
|
271
|
+
this._ensurePlayer();
|
|
272
|
+
this._module._adl_setAutoArpeggio(this._player, enabled ? 1 : 0);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Get automatic arpeggio state.
|
|
277
|
+
*
|
|
278
|
+
* @returns {boolean}
|
|
279
|
+
*/
|
|
280
|
+
getAutoArpeggio() {
|
|
281
|
+
this._ensurePlayer();
|
|
282
|
+
return this._module._adl_getAutoArpeggio(this._player) !== 0;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Set channel allocation mode.
|
|
287
|
+
*
|
|
288
|
+
* @param {number} mode - Mode ID
|
|
289
|
+
*/
|
|
290
|
+
setChannelAllocMode(mode) {
|
|
291
|
+
this._ensurePlayer();
|
|
292
|
+
this._module._adl_setChannelAllocMode(this._player, mode);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Get channel allocation mode.
|
|
297
|
+
*
|
|
298
|
+
* @returns {number} Mode ID
|
|
299
|
+
*/
|
|
300
|
+
getChannelAllocMode() {
|
|
301
|
+
this._ensurePlayer();
|
|
302
|
+
return this._module._adl_getChannelAllocMode(this._player);
|
|
303
|
+
}
|
|
304
|
+
|
|
215
305
|
/**
|
|
216
306
|
* Enable/disable soft stereo panning.
|
|
217
307
|
*
|
|
@@ -264,6 +354,81 @@ export class AdlMidiCore {
|
|
|
264
354
|
return this._module.UTF8ToString(ptr);
|
|
265
355
|
}
|
|
266
356
|
|
|
357
|
+
/**
|
|
358
|
+
* Get the version string of the linked libADLMIDI library.
|
|
359
|
+
*
|
|
360
|
+
* @returns {string} Version string (e.g., "1.5.1")
|
|
361
|
+
*/
|
|
362
|
+
getLibraryVersion() {
|
|
363
|
+
const ptr = this._module._adl_linkedLibraryVersion();
|
|
364
|
+
return this._module.UTF8ToString(ptr);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Get the version of the linked libADLMIDI library as an object.
|
|
369
|
+
*
|
|
370
|
+
* @returns {{major: number, minor: number, patch: number}}
|
|
371
|
+
*/
|
|
372
|
+
getVersion() {
|
|
373
|
+
const ptr = this._module._adl_linkedVersion();
|
|
374
|
+
return {
|
|
375
|
+
major: this._module.getValue(ptr, 'i16'),
|
|
376
|
+
minor: this._module.getValue(ptr + 2, 'i16'),
|
|
377
|
+
patch: this._module.getValue(ptr + 4, 'i16')
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Get the number of emulated chips.
|
|
383
|
+
*
|
|
384
|
+
* @returns {number}
|
|
385
|
+
*/
|
|
386
|
+
getNumChips() {
|
|
387
|
+
this._ensurePlayer();
|
|
388
|
+
return this._module._adl_getNumChips(this._player);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* Get the number of emulated chips obtained.
|
|
393
|
+
*
|
|
394
|
+
* @returns {number}
|
|
395
|
+
*/
|
|
396
|
+
getNumChipsObtained() {
|
|
397
|
+
this._ensurePlayer();
|
|
398
|
+
return this._module._adl_getNumChipsObtained(this._player);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* Get the volume range model.
|
|
403
|
+
*
|
|
404
|
+
* @returns {number}
|
|
405
|
+
*/
|
|
406
|
+
getVolumeModel() {
|
|
407
|
+
this._ensurePlayer();
|
|
408
|
+
return this._module._adl_getVolumeRangeModel(this._player);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Set the volume range model.
|
|
413
|
+
*
|
|
414
|
+
* @param {number} model - Volume model type
|
|
415
|
+
*/
|
|
416
|
+
setVolumeModel(model) {
|
|
417
|
+
this._ensurePlayer();
|
|
418
|
+
this._module._adl_setVolumeRangeModel(this._player, model);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
/**
|
|
422
|
+
* Run emulator with PCM rate to reduce CPU usage.
|
|
423
|
+
*
|
|
424
|
+
* @param {boolean} enabled
|
|
425
|
+
* @returns {boolean} True if successful
|
|
426
|
+
*/
|
|
427
|
+
setRunAtPcmRate(enabled) {
|
|
428
|
+
this._ensurePlayer();
|
|
429
|
+
return this._module._adl_setRunAtPcmRate(this._player, enabled ? 1 : 0) === 0;
|
|
430
|
+
}
|
|
431
|
+
|
|
267
432
|
// =========================================================================
|
|
268
433
|
// Real-time Synthesis
|
|
269
434
|
// =========================================================================
|
|
@@ -291,6 +456,29 @@ export class AdlMidiCore {
|
|
|
291
456
|
this._module._adl_rt_noteOff(this._player, channel, note);
|
|
292
457
|
}
|
|
293
458
|
|
|
459
|
+
/**
|
|
460
|
+
* Send a note aftertouch message.
|
|
461
|
+
*
|
|
462
|
+
* @param {number} channel - MIDI channel (0-15)
|
|
463
|
+
* @param {number} note - MIDI note (0-127)
|
|
464
|
+
* @param {number} pressure - Aftertouch pressure (0-127)
|
|
465
|
+
*/
|
|
466
|
+
noteAfterTouch(channel, note, pressure) {
|
|
467
|
+
this._ensurePlayer();
|
|
468
|
+
this._module._adl_rt_noteAfterTouch(this._player, channel, note, pressure);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* Send a channel aftertouch message.
|
|
473
|
+
*
|
|
474
|
+
* @param {number} channel - MIDI channel (0-15)
|
|
475
|
+
* @param {number} pressure - Aftertouch pressure (0-127)
|
|
476
|
+
*/
|
|
477
|
+
channelAfterTouch(channel, pressure) {
|
|
478
|
+
this._ensurePlayer();
|
|
479
|
+
this._module._adl_rt_channelAfterTouch(this._player, channel, pressure);
|
|
480
|
+
}
|
|
481
|
+
|
|
294
482
|
/**
|
|
295
483
|
* Send a pitch bend message.
|
|
296
484
|
*
|
|
@@ -325,6 +513,39 @@ export class AdlMidiCore {
|
|
|
325
513
|
this._module._adl_rt_patchChange(this._player, channel, program);
|
|
326
514
|
}
|
|
327
515
|
|
|
516
|
+
/**
|
|
517
|
+
* Send a bank change message (16-bit).
|
|
518
|
+
*
|
|
519
|
+
* @param {number} channel - MIDI channel (0-15)
|
|
520
|
+
* @param {number} bank - Bank number
|
|
521
|
+
*/
|
|
522
|
+
bankChange(channel, bank) {
|
|
523
|
+
this._ensurePlayer();
|
|
524
|
+
this._module._adl_rt_bankChange(this._player, channel, bank);
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
/**
|
|
528
|
+
* Send a bank change MSB message.
|
|
529
|
+
*
|
|
530
|
+
* @param {number} channel - MIDI channel (0-15)
|
|
531
|
+
* @param {number} msb - Bank MSB (0-127)
|
|
532
|
+
*/
|
|
533
|
+
bankChangeMSB(channel, msb) {
|
|
534
|
+
this._ensurePlayer();
|
|
535
|
+
this._module._adl_rt_bankChangeMSB(this._player, channel, msb);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
/**
|
|
539
|
+
* Send a bank change LSB message.
|
|
540
|
+
*
|
|
541
|
+
* @param {number} channel - MIDI channel (0-15)
|
|
542
|
+
* @param {number} lsb - Bank LSB (0-127)
|
|
543
|
+
*/
|
|
544
|
+
bankChangeLSB(channel, lsb) {
|
|
545
|
+
this._ensurePlayer();
|
|
546
|
+
this._module._adl_rt_bankChangeLSB(this._player, channel, lsb);
|
|
547
|
+
}
|
|
548
|
+
|
|
328
549
|
/**
|
|
329
550
|
* Generate audio samples (real-time synthesis).
|
|
330
551
|
*
|
|
@@ -382,6 +603,28 @@ export class AdlMidiCore {
|
|
|
382
603
|
return result === 0;
|
|
383
604
|
}
|
|
384
605
|
|
|
606
|
+
/**
|
|
607
|
+
* Get the music title of the loaded MIDI file.
|
|
608
|
+
*
|
|
609
|
+
* @returns {string} Title or empty string
|
|
610
|
+
*/
|
|
611
|
+
getMusicTitle() {
|
|
612
|
+
this._ensurePlayer();
|
|
613
|
+
const ptr = this._module._adl_metaMusicTitle(this._player);
|
|
614
|
+
return ptr ? this._module.UTF8ToString(ptr) : '';
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
/**
|
|
618
|
+
* Get the copyright notice of the loaded MIDI file.
|
|
619
|
+
*
|
|
620
|
+
* @returns {string} Copyright or empty string
|
|
621
|
+
*/
|
|
622
|
+
getMusicCopyright() {
|
|
623
|
+
this._ensurePlayer();
|
|
624
|
+
const ptr = this._module._adl_metaMusicCopyright(this._player);
|
|
625
|
+
return ptr ? this._module.UTF8ToString(ptr) : '';
|
|
626
|
+
}
|
|
627
|
+
|
|
385
628
|
/**
|
|
386
629
|
* Play MIDI file and generate audio.
|
|
387
630
|
*
|
|
@@ -504,24 +747,34 @@ export class AdlMidiCore {
|
|
|
504
747
|
this._module.HEAPU8[bankIdPtr + 1] = bankId.msb || 0;
|
|
505
748
|
this._module.HEAPU8[bankIdPtr + 2] = bankId.lsb || 0;
|
|
506
749
|
|
|
507
|
-
// Allocate
|
|
508
|
-
const
|
|
750
|
+
// Allocate bank struct
|
|
751
|
+
const bankPtr = this._module._malloc(SIZEOF_ADL_BANK);
|
|
509
752
|
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
bankIdPtr,
|
|
513
|
-
program,
|
|
514
|
-
instPtr
|
|
515
|
-
);
|
|
753
|
+
// Get bank (create if needed)
|
|
754
|
+
const bankResult = this._module._adl_getBank(this._player, bankIdPtr, 1, bankPtr);
|
|
516
755
|
|
|
517
756
|
let instrument = null;
|
|
518
|
-
if (
|
|
519
|
-
|
|
520
|
-
|
|
757
|
+
if (bankResult === 0) {
|
|
758
|
+
// Allocate instrument struct
|
|
759
|
+
const instPtr = this._module._malloc(SIZEOF_ADL_INSTRUMENT);
|
|
760
|
+
|
|
761
|
+
const result = this._module._adl_getInstrument(
|
|
762
|
+
this._player,
|
|
763
|
+
bankPtr,
|
|
764
|
+
program,
|
|
765
|
+
instPtr
|
|
766
|
+
);
|
|
767
|
+
|
|
768
|
+
if (result === 0) {
|
|
769
|
+
const bytes = this._module.HEAPU8.slice(instPtr, instPtr + SIZEOF_ADL_INSTRUMENT);
|
|
770
|
+
instrument = decodeInstrument(bytes);
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
this._module._free(instPtr);
|
|
521
774
|
}
|
|
522
775
|
|
|
523
776
|
this._module._free(bankIdPtr);
|
|
524
|
-
this._module._free(
|
|
777
|
+
this._module._free(bankPtr);
|
|
525
778
|
|
|
526
779
|
return instrument;
|
|
527
780
|
}
|
|
@@ -546,22 +799,34 @@ export class AdlMidiCore {
|
|
|
546
799
|
this._module.HEAPU8[bankIdPtr + 1] = bankId.msb || 0;
|
|
547
800
|
this._module.HEAPU8[bankIdPtr + 2] = bankId.lsb || 0;
|
|
548
801
|
|
|
549
|
-
//
|
|
550
|
-
const
|
|
551
|
-
|
|
552
|
-
|
|
802
|
+
// Allocate bank struct
|
|
803
|
+
const bankPtr = this._module._malloc(SIZEOF_ADL_BANK);
|
|
804
|
+
|
|
805
|
+
// Get bank (create if needed)
|
|
806
|
+
const bankResult = this._module._adl_getBank(this._player, bankIdPtr, 1, bankPtr);
|
|
553
807
|
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
instPtr
|
|
559
|
-
|
|
808
|
+
let success = false;
|
|
809
|
+
if (bankResult === 0) {
|
|
810
|
+
// Encode and write instrument
|
|
811
|
+
const bytes = encodeInstrument(instrument);
|
|
812
|
+
const instPtr = this._module._malloc(SIZEOF_ADL_INSTRUMENT);
|
|
813
|
+
this._module.HEAPU8.set(bytes, instPtr);
|
|
814
|
+
|
|
815
|
+
const result = this._module._adl_setInstrument(
|
|
816
|
+
this._player,
|
|
817
|
+
bankPtr,
|
|
818
|
+
program,
|
|
819
|
+
instPtr
|
|
820
|
+
);
|
|
821
|
+
|
|
822
|
+
success = result === 0;
|
|
823
|
+
this._module._free(instPtr);
|
|
824
|
+
}
|
|
560
825
|
|
|
561
826
|
this._module._free(bankIdPtr);
|
|
562
|
-
this._module._free(
|
|
827
|
+
this._module._free(bankPtr);
|
|
563
828
|
|
|
564
|
-
return
|
|
829
|
+
return success;
|
|
565
830
|
}
|
|
566
831
|
|
|
567
832
|
// =========================================================================
|
package/src/libadlmidi.js
CHANGED
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
*/
|
|
75
75
|
|
|
76
76
|
/**
|
|
77
|
-
* Available OPL3 emulator cores.
|
|
77
|
+
* Available OPL2/OPL3 emulator cores.
|
|
78
78
|
* Use with switchEmulator() to change the synthesis engine at runtime.
|
|
79
79
|
* Note: Only emulators compiled into the current profile are available.
|
|
80
80
|
* @readonly
|
|
@@ -103,6 +103,8 @@ export const Emulator = Object.freeze({
|
|
|
103
103
|
NUKED_OPL2_LLE: 9,
|
|
104
104
|
/** Nuked OPL3 LLE - Transistor-level emulation */
|
|
105
105
|
NUKED_OPL3_LLE: 10,
|
|
106
|
+
/** Nuked OPL2 Lite - Lightweight OPL2 emulation for AdLib-era music */
|
|
107
|
+
NUKED_OPL2_LITE: 11,
|
|
106
108
|
});
|
|
107
109
|
|
|
108
110
|
export class AdlMidi {
|
|
@@ -156,13 +158,12 @@ export class AdlMidi {
|
|
|
156
158
|
// For split builds, fetch the WASM binary from main thread
|
|
157
159
|
// (AudioWorklet doesn't have fetch access)
|
|
158
160
|
// If wasmUrl not provided, derive it from processorUrl
|
|
159
|
-
let wasmBinary = null;
|
|
160
161
|
const effectiveWasmUrl = wasmUrl || processorUrl.replace('.processor.js', '.core.wasm');
|
|
161
162
|
const response = await fetch(effectiveWasmUrl);
|
|
162
163
|
if (!response.ok) {
|
|
163
164
|
throw new Error(`Failed to fetch WASM: ${response.status}`);
|
|
164
165
|
}
|
|
165
|
-
wasmBinary = await response.arrayBuffer();
|
|
166
|
+
const wasmBinary = await response.arrayBuffer();
|
|
166
167
|
|
|
167
168
|
// Add the AudioWorklet module
|
|
168
169
|
await this.ctx.audioWorklet.addModule(processorUrl);
|
|
@@ -289,6 +290,52 @@ export class AdlMidi {
|
|
|
289
290
|
this.#send({ type: 'programChange', channel, program });
|
|
290
291
|
}
|
|
291
292
|
|
|
293
|
+
/**
|
|
294
|
+
* Send note aftertouch
|
|
295
|
+
* @param {number} channel - MIDI channel (0-15)
|
|
296
|
+
* @param {number} note - Note number (0-127)
|
|
297
|
+
* @param {number} pressure - Pressure (0-127)
|
|
298
|
+
*/
|
|
299
|
+
noteAfterTouch(channel, note, pressure) {
|
|
300
|
+
this.#send({ type: 'noteAfterTouch', channel, note, pressure });
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Send channel aftertouch
|
|
305
|
+
* @param {number} channel - MIDI channel (0-15)
|
|
306
|
+
* @param {number} pressure - Pressure (0-127)
|
|
307
|
+
*/
|
|
308
|
+
channelAfterTouch(channel, pressure) {
|
|
309
|
+
this.#send({ type: 'channelAfterTouch', channel, pressure });
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Change bank (16-bit)
|
|
314
|
+
* @param {number} channel - MIDI channel (0-15)
|
|
315
|
+
* @param {number} bank - Bank number
|
|
316
|
+
*/
|
|
317
|
+
bankChange(channel, bank) {
|
|
318
|
+
this.#send({ type: 'bankChange', channel, bank });
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Change bank MSB
|
|
323
|
+
* @param {number} channel - MIDI channel (0-15)
|
|
324
|
+
* @param {number} msb - Bank MSB (0-127)
|
|
325
|
+
*/
|
|
326
|
+
bankChangeMSB(channel, msb) {
|
|
327
|
+
this.#send({ type: 'bankChangeMSB', channel, msb });
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Change bank LSB
|
|
332
|
+
* @param {number} channel - MIDI channel (0-15)
|
|
333
|
+
* @param {number} lsb - Bank LSB (0-127)
|
|
334
|
+
*/
|
|
335
|
+
bankChangeLSB(channel, lsb) {
|
|
336
|
+
this.#send({ type: 'bankChangeLSB', channel, lsb });
|
|
337
|
+
}
|
|
338
|
+
|
|
292
339
|
/**
|
|
293
340
|
* Reset the real-time state (stops all notes, resets controllers)
|
|
294
341
|
* @returns {void}
|
|
@@ -404,6 +451,85 @@ export class AdlMidi {
|
|
|
404
451
|
this.#send({ type: 'setNumChips', chips });
|
|
405
452
|
}
|
|
406
453
|
|
|
454
|
+
/**
|
|
455
|
+
* Set the number of 4-operator channels
|
|
456
|
+
* @param {number} channels - Number of channels (-1 for auto)
|
|
457
|
+
*/
|
|
458
|
+
setNumFourOpChannels(channels) {
|
|
459
|
+
this.#send({ type: 'setNumFourOpChannels', channels });
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* Get the number of 4-operator channels
|
|
464
|
+
* @returns {Promise<number>}
|
|
465
|
+
*/
|
|
466
|
+
async getNumFourOpChannels() {
|
|
467
|
+
return new Promise((resolve) => {
|
|
468
|
+
this.#onceMessage('numFourOpChannels', /** @param {{channels: number}} msg */(msg) => {
|
|
469
|
+
resolve(msg.channels);
|
|
470
|
+
});
|
|
471
|
+
this.#send({ type: 'getNumFourOpChannels' });
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
/**
|
|
476
|
+
* Enable/disable scaling of modulators by volume
|
|
477
|
+
* @param {boolean} enabled
|
|
478
|
+
*/
|
|
479
|
+
setScaleModulators(enabled) {
|
|
480
|
+
this.#send({ type: 'setScaleModulators', enabled });
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
/**
|
|
484
|
+
* Enable/disable full-range brightness
|
|
485
|
+
* @param {boolean} enabled
|
|
486
|
+
*/
|
|
487
|
+
setFullRangeBrightness(enabled) {
|
|
488
|
+
this.#send({ type: 'setFullRangeBrightness', enabled });
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
/**
|
|
492
|
+
* Enable/disable automatic arpeggio
|
|
493
|
+
* @param {boolean} enabled
|
|
494
|
+
*/
|
|
495
|
+
setAutoArpeggio(enabled) {
|
|
496
|
+
this.#send({ type: 'setAutoArpeggio', enabled });
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/**
|
|
500
|
+
* Get automatic arpeggio state
|
|
501
|
+
* @returns {Promise<boolean>}
|
|
502
|
+
*/
|
|
503
|
+
async getAutoArpeggio() {
|
|
504
|
+
return new Promise((resolve) => {
|
|
505
|
+
this.#onceMessage('autoArpeggio', /** @param {{enabled: boolean}} msg */(msg) => {
|
|
506
|
+
resolve(msg.enabled);
|
|
507
|
+
});
|
|
508
|
+
this.#send({ type: 'getAutoArpeggio' });
|
|
509
|
+
});
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* Set channel allocation mode
|
|
514
|
+
* @param {number} mode - Mode ID
|
|
515
|
+
*/
|
|
516
|
+
setChannelAllocMode(mode) {
|
|
517
|
+
this.#send({ type: 'setChannelAllocMode', mode });
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* Get channel allocation mode
|
|
522
|
+
* @returns {Promise<number>}
|
|
523
|
+
*/
|
|
524
|
+
async getChannelAllocMode() {
|
|
525
|
+
return new Promise((resolve) => {
|
|
526
|
+
this.#onceMessage('channelAllocMode', /** @param {{mode: number}} msg */(msg) => {
|
|
527
|
+
resolve(msg.mode);
|
|
528
|
+
});
|
|
529
|
+
this.#send({ type: 'getChannelAllocMode' });
|
|
530
|
+
});
|
|
531
|
+
}
|
|
532
|
+
|
|
407
533
|
/**
|
|
408
534
|
* Set the volume model
|
|
409
535
|
* @param {number} model - Volume model number
|
|
@@ -436,6 +562,14 @@ export class AdlMidi {
|
|
|
436
562
|
this.#send({ type: 'setTremolo', enabled });
|
|
437
563
|
}
|
|
438
564
|
|
|
565
|
+
/**
|
|
566
|
+
* Run emulator with PCM rate to reduce CPU usage
|
|
567
|
+
* @param {boolean} enabled
|
|
568
|
+
*/
|
|
569
|
+
setRunAtPcmRate(enabled) {
|
|
570
|
+
this.#send({ type: 'setRunAtPcmRate', enabled });
|
|
571
|
+
}
|
|
572
|
+
|
|
439
573
|
/**
|
|
440
574
|
* Switch the OPL3 emulator core at runtime
|
|
441
575
|
*
|
|
@@ -480,6 +614,71 @@ export class AdlMidi {
|
|
|
480
614
|
});
|
|
481
615
|
}
|
|
482
616
|
|
|
617
|
+
/**
|
|
618
|
+
* Get the version string of the linked libADLMIDI library
|
|
619
|
+
* @returns {Promise<string>}
|
|
620
|
+
*/
|
|
621
|
+
async getLibraryVersion() {
|
|
622
|
+
return new Promise((resolve) => {
|
|
623
|
+
this.#onceMessage('libraryVersion', /** @param {{version: string}} msg */(msg) => {
|
|
624
|
+
resolve(msg.version);
|
|
625
|
+
});
|
|
626
|
+
this.#send({ type: 'getLibraryVersion' });
|
|
627
|
+
});
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
/**
|
|
631
|
+
* Get the version of the linked libADLMIDI library as an object
|
|
632
|
+
* @returns {Promise<{major: number, minor: number, patch: number}>}
|
|
633
|
+
*/
|
|
634
|
+
async getVersion() {
|
|
635
|
+
return new Promise((resolve) => {
|
|
636
|
+
this.#onceMessage('version', /** @param {{version: {major: number, minor: number, patch: number}}} msg */(msg) => {
|
|
637
|
+
resolve(msg.version);
|
|
638
|
+
});
|
|
639
|
+
this.#send({ type: 'getVersion' });
|
|
640
|
+
});
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
/**
|
|
644
|
+
* Get the number of emulated chips
|
|
645
|
+
* @returns {Promise<number>}
|
|
646
|
+
*/
|
|
647
|
+
async getNumChips() {
|
|
648
|
+
return new Promise((resolve) => {
|
|
649
|
+
this.#onceMessage('numChips', /** @param {{chips: number}} msg */(msg) => {
|
|
650
|
+
resolve(msg.chips);
|
|
651
|
+
});
|
|
652
|
+
this.#send({ type: 'getNumChips' });
|
|
653
|
+
});
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
/**
|
|
657
|
+
* Get the number of emulated chips obtained
|
|
658
|
+
* @returns {Promise<number>}
|
|
659
|
+
*/
|
|
660
|
+
async getNumChipsObtained() {
|
|
661
|
+
return new Promise((resolve) => {
|
|
662
|
+
this.#onceMessage('numChipsObtained', /** @param {{chips: number}} msg */(msg) => {
|
|
663
|
+
resolve(msg.chips);
|
|
664
|
+
});
|
|
665
|
+
this.#send({ type: 'getNumChipsObtained' });
|
|
666
|
+
});
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
/**
|
|
670
|
+
* Get the volume range model
|
|
671
|
+
* @returns {Promise<number>}
|
|
672
|
+
*/
|
|
673
|
+
async getVolumeModel() {
|
|
674
|
+
return new Promise((resolve) => {
|
|
675
|
+
this.#onceMessage('volumeModel', /** @param {{model: number}} msg */(msg) => {
|
|
676
|
+
resolve(msg.model);
|
|
677
|
+
});
|
|
678
|
+
this.#send({ type: 'getVolumeModel' });
|
|
679
|
+
});
|
|
680
|
+
}
|
|
681
|
+
|
|
483
682
|
/**
|
|
484
683
|
* Get list of embedded banks available in this build
|
|
485
684
|
* Note: Slim builds have no embedded banks and will return an empty array
|
|
@@ -518,7 +717,7 @@ export class AdlMidi {
|
|
|
518
717
|
if (msg.success) {
|
|
519
718
|
resolve({ duration: msg.duration });
|
|
520
719
|
} else {
|
|
521
|
-
reject(new Error(msg.error || 'Failed to
|
|
720
|
+
reject(new Error(msg.error || 'Failed to parse MIDI data'));
|
|
522
721
|
}
|
|
523
722
|
});
|
|
524
723
|
|
|
@@ -526,6 +725,32 @@ export class AdlMidi {
|
|
|
526
725
|
});
|
|
527
726
|
}
|
|
528
727
|
|
|
728
|
+
/**
|
|
729
|
+
* Get the music title of the loaded MIDI file
|
|
730
|
+
* @returns {Promise<string>}
|
|
731
|
+
*/
|
|
732
|
+
async getMusicTitle() {
|
|
733
|
+
return new Promise((resolve) => {
|
|
734
|
+
this.#onceMessage('musicTitle', /** @param {{title: string}} msg */(msg) => {
|
|
735
|
+
resolve(msg.title);
|
|
736
|
+
});
|
|
737
|
+
this.#send({ type: 'getMusicTitle' });
|
|
738
|
+
});
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
/**
|
|
742
|
+
* Get the copyright notice of the loaded MIDI file
|
|
743
|
+
* @returns {Promise<string>}
|
|
744
|
+
*/
|
|
745
|
+
async getMusicCopyright() {
|
|
746
|
+
return new Promise((resolve) => {
|
|
747
|
+
this.#onceMessage('musicCopyright', /** @param {{copyright: string}} msg */(msg) => {
|
|
748
|
+
resolve(msg.copyright);
|
|
749
|
+
});
|
|
750
|
+
this.#send({ type: 'getMusicCopyright' });
|
|
751
|
+
});
|
|
752
|
+
}
|
|
753
|
+
|
|
529
754
|
/**
|
|
530
755
|
* Start or resume MIDI file playback
|
|
531
756
|
* @returns {void}
|