libadlmidi-js 1.2.0 → 2.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/dist/core.d.ts +186 -4
- package/dist/fm_banks/manifest.json +1 -1
- package/dist/libadlmidi.d.ts +143 -65
- 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 +242 -74
- 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 +242 -74
- 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 +242 -74
- 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 +242 -74
- package/dist/libadlmidi.js +465 -21
- package/dist/libadlmidi.js.map +3 -3
- 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 +242 -74
- 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 +242 -74
- 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 +242 -74
- 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 +242 -74
- package/dist/profiles/dosbox.d.ts +1 -0
- package/dist/profiles/dosbox.slim.d.ts +1 -0
- package/dist/profiles/full.d.ts +1 -0
- package/dist/profiles/full.slim.d.ts +1 -0
- package/dist/profiles/light.d.ts +1 -0
- package/dist/profiles/light.slim.d.ts +1 -0
- package/dist/profiles/nuked.d.ts +1 -0
- package/dist/profiles/nuked.slim.d.ts +1 -0
- package/dist/utils/constants.d.ts +59 -0
- package/package.json +1 -1
- package/src/core.js +352 -4
- package/src/libadlmidi.js +374 -56
- package/src/processor.js +204 -12
- package/src/profiles/dosbox.js +7 -4
- package/src/profiles/dosbox.slim.js +7 -4
- package/src/profiles/full.js +7 -4
- package/src/profiles/full.slim.js +7 -4
- package/src/profiles/light.js +7 -4
- package/src/profiles/light.slim.js +7 -4
- package/src/profiles/nuked.js +7 -4
- package/src/profiles/nuked.slim.js +7 -4
- package/src/utils/constants.js +51 -0
package/src/core.js
CHANGED
|
@@ -16,6 +16,9 @@ import {
|
|
|
16
16
|
encodeInstrument,
|
|
17
17
|
} from './utils/struct.js';
|
|
18
18
|
|
|
19
|
+
import { Emulator, TrackOption } from './utils/constants.js';
|
|
20
|
+
export { Emulator, TrackOption };
|
|
21
|
+
|
|
19
22
|
/**
|
|
20
23
|
* Low-level OPL3 synthesis interface.
|
|
21
24
|
*
|
|
@@ -242,6 +245,16 @@ export class AdlMidiCore {
|
|
|
242
245
|
return this._module._adl_getNumFourOpsChn(this._player);
|
|
243
246
|
}
|
|
244
247
|
|
|
248
|
+
/**
|
|
249
|
+
* Get the number of 4-operator channels obtained.
|
|
250
|
+
*
|
|
251
|
+
* @returns {number} Count of channels obtained
|
|
252
|
+
*/
|
|
253
|
+
getNumFourOpChannelsObtained() {
|
|
254
|
+
this._ensurePlayer();
|
|
255
|
+
return this._module._adl_getNumFourOpsChnObtained(this._player);
|
|
256
|
+
}
|
|
257
|
+
|
|
245
258
|
/**
|
|
246
259
|
* Enable/disable scaling of modulators by volume.
|
|
247
260
|
*
|
|
@@ -307,7 +320,7 @@ export class AdlMidiCore {
|
|
|
307
320
|
*
|
|
308
321
|
* @param {boolean} enabled
|
|
309
322
|
*/
|
|
310
|
-
|
|
323
|
+
setSoftPanEnabled(enabled) {
|
|
311
324
|
this._ensurePlayer();
|
|
312
325
|
this._module._adl_setSoftPanEnabled(this._player, enabled ? 1 : 0);
|
|
313
326
|
}
|
|
@@ -322,6 +335,16 @@ export class AdlMidiCore {
|
|
|
322
335
|
this._module._adl_setHVibrato(this._player, enabled ? 1 : 0);
|
|
323
336
|
}
|
|
324
337
|
|
|
338
|
+
/**
|
|
339
|
+
* Get deep vibrato state.
|
|
340
|
+
*
|
|
341
|
+
* @returns {boolean}
|
|
342
|
+
*/
|
|
343
|
+
getDeepVibrato() {
|
|
344
|
+
this._ensurePlayer();
|
|
345
|
+
return this._module._adl_getHVibrato(this._player) !== 0;
|
|
346
|
+
}
|
|
347
|
+
|
|
325
348
|
/**
|
|
326
349
|
* Enable/disable deep tremolo.
|
|
327
350
|
*
|
|
@@ -332,6 +355,16 @@ export class AdlMidiCore {
|
|
|
332
355
|
this._module._adl_setHTremolo(this._player, enabled ? 1 : 0);
|
|
333
356
|
}
|
|
334
357
|
|
|
358
|
+
/**
|
|
359
|
+
* Get deep tremolo state.
|
|
360
|
+
*
|
|
361
|
+
* @returns {boolean}
|
|
362
|
+
*/
|
|
363
|
+
getDeepTremolo() {
|
|
364
|
+
this._ensurePlayer();
|
|
365
|
+
return this._module._adl_getHTremolo(this._player) !== 0;
|
|
366
|
+
}
|
|
367
|
+
|
|
335
368
|
/**
|
|
336
369
|
* Switch OPL3 emulator (if multiple are compiled in).
|
|
337
370
|
*
|
|
@@ -354,6 +387,27 @@ export class AdlMidiCore {
|
|
|
354
387
|
return this._module.UTF8ToString(ptr);
|
|
355
388
|
}
|
|
356
389
|
|
|
390
|
+
/**
|
|
391
|
+
* Get the last global error string (static, no player needed).
|
|
392
|
+
*
|
|
393
|
+
* @returns {string} Error string or empty string
|
|
394
|
+
*/
|
|
395
|
+
getErrorString() {
|
|
396
|
+
const ptr = this._module._adl_errorString();
|
|
397
|
+
return ptr ? this._module.UTF8ToString(ptr) : '';
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* Get the last error info for this player instance.
|
|
402
|
+
*
|
|
403
|
+
* @returns {string} Error info string or empty string
|
|
404
|
+
*/
|
|
405
|
+
getErrorInfo() {
|
|
406
|
+
this._ensurePlayer();
|
|
407
|
+
const ptr = this._module._adl_errorInfo(this._player);
|
|
408
|
+
return ptr ? this._module.UTF8ToString(ptr) : '';
|
|
409
|
+
}
|
|
410
|
+
|
|
357
411
|
/**
|
|
358
412
|
* Get the version string of the linked libADLMIDI library.
|
|
359
413
|
*
|
|
@@ -403,7 +457,7 @@ export class AdlMidiCore {
|
|
|
403
457
|
*
|
|
404
458
|
* @returns {number}
|
|
405
459
|
*/
|
|
406
|
-
|
|
460
|
+
getVolumeRangeModel() {
|
|
407
461
|
this._ensurePlayer();
|
|
408
462
|
return this._module._adl_getVolumeRangeModel(this._player);
|
|
409
463
|
}
|
|
@@ -413,7 +467,7 @@ export class AdlMidiCore {
|
|
|
413
467
|
*
|
|
414
468
|
* @param {number} model - Volume model type
|
|
415
469
|
*/
|
|
416
|
-
|
|
470
|
+
setVolumeRangeModel(model) {
|
|
417
471
|
this._ensurePlayer();
|
|
418
472
|
this._module._adl_setVolumeRangeModel(this._player, model);
|
|
419
473
|
}
|
|
@@ -625,6 +679,38 @@ export class AdlMidiCore {
|
|
|
625
679
|
return ptr ? this._module.UTF8ToString(ptr) : '';
|
|
626
680
|
}
|
|
627
681
|
|
|
682
|
+
/**
|
|
683
|
+
* Get the number of track titles in the loaded MIDI file.
|
|
684
|
+
*
|
|
685
|
+
* @returns {number} Number of track titles
|
|
686
|
+
*/
|
|
687
|
+
getTrackTitleCount() {
|
|
688
|
+
this._ensurePlayer();
|
|
689
|
+
return this._module._adl_metaTrackTitleCount(this._player);
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
/**
|
|
693
|
+
* Get a track title by index.
|
|
694
|
+
*
|
|
695
|
+
* @param {number} index - Track title index
|
|
696
|
+
* @returns {string} Track title or empty string
|
|
697
|
+
*/
|
|
698
|
+
getTrackTitle(index) {
|
|
699
|
+
this._ensurePlayer();
|
|
700
|
+
const ptr = this._module._adl_metaTrackTitle(this._player, index);
|
|
701
|
+
return ptr ? this._module.UTF8ToString(ptr) : '';
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
/**
|
|
705
|
+
* Get the number of MIDI markers in the loaded file.
|
|
706
|
+
*
|
|
707
|
+
* @returns {number} Number of markers
|
|
708
|
+
*/
|
|
709
|
+
getMarkerCount() {
|
|
710
|
+
this._ensurePlayer();
|
|
711
|
+
return this._module._adl_metaMarkerCount(this._player);
|
|
712
|
+
}
|
|
713
|
+
|
|
628
714
|
/**
|
|
629
715
|
* Play MIDI file and generate audio.
|
|
630
716
|
*
|
|
@@ -709,11 +795,107 @@ export class AdlMidiCore {
|
|
|
709
795
|
*
|
|
710
796
|
* @param {boolean} enabled
|
|
711
797
|
*/
|
|
712
|
-
|
|
798
|
+
setLoopEnabled(enabled) {
|
|
713
799
|
this._ensurePlayer();
|
|
714
800
|
this._module._adl_setLoopEnabled(this._player, enabled ? 1 : 0);
|
|
715
801
|
}
|
|
716
802
|
|
|
803
|
+
/**
|
|
804
|
+
* Set the number of loop repetitions.
|
|
805
|
+
*
|
|
806
|
+
* @param {number} count - Loop count (-1 = infinite, 0 = no loops, 1+ = number of loops)
|
|
807
|
+
*/
|
|
808
|
+
setLoopCount(count) {
|
|
809
|
+
this._ensurePlayer();
|
|
810
|
+
this._module._adl_setLoopCount(this._player, count);
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
/**
|
|
814
|
+
* Enable/disable loop hooks only mode.
|
|
815
|
+
*
|
|
816
|
+
* @param {boolean} enabled
|
|
817
|
+
*/
|
|
818
|
+
setLoopHooksOnly(enabled) {
|
|
819
|
+
this._ensurePlayer();
|
|
820
|
+
this._module._adl_setLoopHooksOnly(this._player, enabled ? 1 : 0);
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
/**
|
|
824
|
+
* Get the loop start time in seconds.
|
|
825
|
+
*
|
|
826
|
+
* @returns {number} Loop start time in seconds
|
|
827
|
+
*/
|
|
828
|
+
getLoopStartTime() {
|
|
829
|
+
this._ensurePlayer();
|
|
830
|
+
return this._module._adl_loopStartTime(this._player);
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
/**
|
|
834
|
+
* Get the loop end time in seconds.
|
|
835
|
+
*
|
|
836
|
+
* @returns {number} Loop end time in seconds
|
|
837
|
+
*/
|
|
838
|
+
getLoopEndTime() {
|
|
839
|
+
this._ensurePlayer();
|
|
840
|
+
return this._module._adl_loopEndTime(this._player);
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
/**
|
|
844
|
+
* Select a song number for multi-song MIDI files.
|
|
845
|
+
*
|
|
846
|
+
* @param {number} num - Song number (0-based)
|
|
847
|
+
*/
|
|
848
|
+
selectSongNum(num) {
|
|
849
|
+
this._ensurePlayer();
|
|
850
|
+
this._module._adl_selectSongNum(this._player, num);
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
/**
|
|
854
|
+
* Get the number of songs in the loaded MIDI file.
|
|
855
|
+
*
|
|
856
|
+
* @returns {number} Number of songs
|
|
857
|
+
*/
|
|
858
|
+
getSongsCount() {
|
|
859
|
+
this._ensurePlayer();
|
|
860
|
+
return this._module._adl_getSongsCount(this._player);
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
/**
|
|
864
|
+
* Get the number of tracks in the loaded MIDI file.
|
|
865
|
+
*
|
|
866
|
+
* @returns {number} Number of tracks
|
|
867
|
+
*/
|
|
868
|
+
getTrackCount() {
|
|
869
|
+
this._ensurePlayer();
|
|
870
|
+
return this._module._adl_trackCount(this._player);
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
/**
|
|
874
|
+
* Set track options (enable, mute, or solo).
|
|
875
|
+
* Use the TrackOption enum: TrackOption.ON (1), TrackOption.OFF (2), TrackOption.SOLO (3).
|
|
876
|
+
* Note: Passing 0 is a silent no-op that returns true without changing state.
|
|
877
|
+
*
|
|
878
|
+
* @param {number} track - Track index
|
|
879
|
+
* @param {number} options - Track option from TrackOption enum
|
|
880
|
+
* @returns {boolean} True if successful
|
|
881
|
+
*/
|
|
882
|
+
setTrackOptions(track, options) {
|
|
883
|
+
this._ensurePlayer();
|
|
884
|
+
return this._module._adl_setTrackOptions(this._player, track, options) === 0;
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
/**
|
|
888
|
+
* Enable or disable a MIDI channel.
|
|
889
|
+
*
|
|
890
|
+
* @param {number} channel - MIDI channel (0-15)
|
|
891
|
+
* @param {boolean} enabled - Whether to enable the channel
|
|
892
|
+
* @returns {boolean} True if successful
|
|
893
|
+
*/
|
|
894
|
+
setChannelEnabled(channel, enabled) {
|
|
895
|
+
this._ensurePlayer();
|
|
896
|
+
return this._module._adl_setChannelEnabled(this._player, channel, enabled ? 1 : 0) === 0;
|
|
897
|
+
}
|
|
898
|
+
|
|
717
899
|
/**
|
|
718
900
|
* Set playback tempo multiplier.
|
|
719
901
|
*
|
|
@@ -724,6 +906,126 @@ export class AdlMidiCore {
|
|
|
724
906
|
this._module._adl_setTempo(this._player, tempo);
|
|
725
907
|
}
|
|
726
908
|
|
|
909
|
+
// =========================================================================
|
|
910
|
+
// Bank Management
|
|
911
|
+
// =========================================================================
|
|
912
|
+
|
|
913
|
+
/**
|
|
914
|
+
* Reserve a number of banks.
|
|
915
|
+
*
|
|
916
|
+
* @param {number} count - Number of banks to reserve
|
|
917
|
+
* @returns {boolean} True if successful
|
|
918
|
+
*/
|
|
919
|
+
reserveBanks(count) {
|
|
920
|
+
this._ensurePlayer();
|
|
921
|
+
// adl_reserveBanks returns the resulting capacity (>= 0), not 0 on success
|
|
922
|
+
return this._module._adl_reserveBanks(this._player, count) >= 0;
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
/**
|
|
926
|
+
* Get the bank ID for a given bank identifier.
|
|
927
|
+
*
|
|
928
|
+
* @param {Object} bankId - Bank identifier
|
|
929
|
+
* @param {boolean|number} bankId.percussive - True/1 for percussion, false/0 for melodic
|
|
930
|
+
* @param {number} bankId.msb - Bank MSB
|
|
931
|
+
* @param {number} bankId.lsb - Bank LSB
|
|
932
|
+
* @returns {{percussive: number, msb: number, lsb: number}|null} Bank ID or null if not found
|
|
933
|
+
*/
|
|
934
|
+
getBankId(bankId) {
|
|
935
|
+
this._ensurePlayer();
|
|
936
|
+
const bankIdPtr = this._module._malloc(SIZEOF_ADL_BANK_ID);
|
|
937
|
+
this._module.HEAPU8[bankIdPtr] = bankId.percussive ? 1 : 0;
|
|
938
|
+
this._module.HEAPU8[bankIdPtr + 1] = bankId.msb || 0;
|
|
939
|
+
this._module.HEAPU8[bankIdPtr + 2] = bankId.lsb || 0;
|
|
940
|
+
|
|
941
|
+
const bankPtr = this._module._malloc(SIZEOF_ADL_BANK);
|
|
942
|
+
const bankResult = this._module._adl_getBank(this._player, bankIdPtr, 0, bankPtr);
|
|
943
|
+
|
|
944
|
+
let result = null;
|
|
945
|
+
if (bankResult === 0) {
|
|
946
|
+
const outIdPtr = this._module._malloc(SIZEOF_ADL_BANK_ID);
|
|
947
|
+
const idResult = this._module._adl_getBankId(this._player, bankPtr, outIdPtr);
|
|
948
|
+
if (idResult === 0) {
|
|
949
|
+
result = {
|
|
950
|
+
percussive: this._module.HEAPU8[outIdPtr],
|
|
951
|
+
msb: this._module.HEAPU8[outIdPtr + 1],
|
|
952
|
+
lsb: this._module.HEAPU8[outIdPtr + 2],
|
|
953
|
+
};
|
|
954
|
+
}
|
|
955
|
+
this._module._free(outIdPtr);
|
|
956
|
+
}
|
|
957
|
+
this._module._free(bankIdPtr);
|
|
958
|
+
this._module._free(bankPtr);
|
|
959
|
+
return result;
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
/**
|
|
963
|
+
* Remove a bank by its identifier.
|
|
964
|
+
*
|
|
965
|
+
* @param {Object} bankId - Bank identifier
|
|
966
|
+
* @param {boolean|number} bankId.percussive - True/1 for percussion, false/0 for melodic
|
|
967
|
+
* @param {number} bankId.msb - Bank MSB
|
|
968
|
+
* @param {number} bankId.lsb - Bank LSB
|
|
969
|
+
* @returns {boolean} True if successfully removed
|
|
970
|
+
*/
|
|
971
|
+
removeBank(bankId) {
|
|
972
|
+
this._ensurePlayer();
|
|
973
|
+
const bankIdPtr = this._module._malloc(SIZEOF_ADL_BANK_ID);
|
|
974
|
+
this._module.HEAPU8[bankIdPtr] = bankId.percussive ? 1 : 0;
|
|
975
|
+
this._module.HEAPU8[bankIdPtr + 1] = bankId.msb || 0;
|
|
976
|
+
this._module.HEAPU8[bankIdPtr + 2] = bankId.lsb || 0;
|
|
977
|
+
|
|
978
|
+
const bankPtr = this._module._malloc(SIZEOF_ADL_BANK);
|
|
979
|
+
const bankResult = this._module._adl_getBank(this._player, bankIdPtr, 0, bankPtr);
|
|
980
|
+
|
|
981
|
+
let success = false;
|
|
982
|
+
if (bankResult === 0) {
|
|
983
|
+
success = this._module._adl_removeBank(this._player, bankPtr) === 0;
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
this._module._free(bankIdPtr);
|
|
987
|
+
this._module._free(bankPtr);
|
|
988
|
+
return success;
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
/**
|
|
992
|
+
* Load an embedded bank into a custom bank slot.
|
|
993
|
+
*
|
|
994
|
+
* @param {Object} bankId - Target bank identifier
|
|
995
|
+
* @param {boolean|number} bankId.percussive - True/1 for percussion, false/0 for melodic
|
|
996
|
+
* @param {number} bankId.msb - Bank MSB
|
|
997
|
+
* @param {number} bankId.lsb - Bank LSB
|
|
998
|
+
* @param {number} num - Embedded bank number to load
|
|
999
|
+
* @returns {boolean} True if successful
|
|
1000
|
+
*/
|
|
1001
|
+
loadEmbeddedBank(bankId, num) {
|
|
1002
|
+
this._ensurePlayer();
|
|
1003
|
+
const bankIdPtr = this._module._malloc(SIZEOF_ADL_BANK_ID);
|
|
1004
|
+
this._module.HEAPU8[bankIdPtr] = bankId.percussive ? 1 : 0;
|
|
1005
|
+
this._module.HEAPU8[bankIdPtr + 1] = bankId.msb || 0;
|
|
1006
|
+
this._module.HEAPU8[bankIdPtr + 2] = bankId.lsb || 0;
|
|
1007
|
+
|
|
1008
|
+
const bankPtr = this._module._malloc(SIZEOF_ADL_BANK);
|
|
1009
|
+
|
|
1010
|
+
// Check if bank already exists (flag=0) before creating
|
|
1011
|
+
const existed = this._module._adl_getBank(this._player, bankIdPtr, 0, bankPtr) === 0;
|
|
1012
|
+
// Get or create the bank slot (flag=1)
|
|
1013
|
+
const bankResult = existed ? 0 : this._module._adl_getBank(this._player, bankIdPtr, 1, bankPtr);
|
|
1014
|
+
|
|
1015
|
+
let success = false;
|
|
1016
|
+
if (bankResult === 0) {
|
|
1017
|
+
success = this._module._adl_loadEmbeddedBank(this._player, bankPtr, num) === 0;
|
|
1018
|
+
// Clean up: if we created a new slot but load failed, remove it
|
|
1019
|
+
if (!success && !existed) {
|
|
1020
|
+
this._module._adl_removeBank(this._player, bankPtr);
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
this._module._free(bankIdPtr);
|
|
1025
|
+
this._module._free(bankPtr);
|
|
1026
|
+
return success;
|
|
1027
|
+
}
|
|
1028
|
+
|
|
727
1029
|
// =========================================================================
|
|
728
1030
|
// Instrument Access
|
|
729
1031
|
// =========================================================================
|
|
@@ -829,6 +1131,52 @@ export class AdlMidiCore {
|
|
|
829
1131
|
return success;
|
|
830
1132
|
}
|
|
831
1133
|
|
|
1134
|
+
// =========================================================================
|
|
1135
|
+
// Real-time SysEx
|
|
1136
|
+
// =========================================================================
|
|
1137
|
+
|
|
1138
|
+
/**
|
|
1139
|
+
* Send a System Exclusive (SysEx) message.
|
|
1140
|
+
*
|
|
1141
|
+
* @param {Uint8Array|ArrayBuffer} data - SysEx message data
|
|
1142
|
+
* @returns {boolean} True if successful
|
|
1143
|
+
*/
|
|
1144
|
+
systemExclusive(data) {
|
|
1145
|
+
this._ensurePlayer();
|
|
1146
|
+
const bytes = data instanceof ArrayBuffer ? new Uint8Array(data) : data;
|
|
1147
|
+
const ptr = this._module._malloc(bytes.length);
|
|
1148
|
+
this._module.HEAPU8.set(bytes, ptr);
|
|
1149
|
+
const result = this._module._adl_rt_systemExclusive(this._player, ptr, bytes.length);
|
|
1150
|
+
this._module._free(ptr);
|
|
1151
|
+
// adl_rt_systemExclusive returns 1 when processed, 0 when rejected
|
|
1152
|
+
return result !== 0;
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
// =========================================================================
|
|
1156
|
+
// Debug / Diagnostics
|
|
1157
|
+
// =========================================================================
|
|
1158
|
+
|
|
1159
|
+
/**
|
|
1160
|
+
* Describe the current state of all channels (debug utility).
|
|
1161
|
+
*
|
|
1162
|
+
* @returns {{text: string, attr: Uint8Array}} Channel state text and raw per-channel attribute bytes
|
|
1163
|
+
*/
|
|
1164
|
+
describeChannels() {
|
|
1165
|
+
this._ensurePlayer();
|
|
1166
|
+
// Size buffers based on actual chip count (~23 channels per OPL3 chip)
|
|
1167
|
+
const numChips = this._module._adl_getNumChipsObtained(this._player);
|
|
1168
|
+
const size = Math.max(256, (numChips + 1) * 23);
|
|
1169
|
+
const textPtr = this._module._malloc(size);
|
|
1170
|
+
const attrPtr = this._module._malloc(size);
|
|
1171
|
+
this._module._adl_describeChannels(this._player, textPtr, attrPtr, size);
|
|
1172
|
+
const text = this._module.UTF8ToString(textPtr);
|
|
1173
|
+
// attr contains raw per-channel bytes; one byte per channel char in text
|
|
1174
|
+
const attr = this._module.HEAPU8.slice(attrPtr, attrPtr + text.length);
|
|
1175
|
+
this._module._free(textPtr);
|
|
1176
|
+
this._module._free(attrPtr);
|
|
1177
|
+
return { text, attr };
|
|
1178
|
+
}
|
|
1179
|
+
|
|
832
1180
|
// =========================================================================
|
|
833
1181
|
// Direct Module Access
|
|
834
1182
|
// =========================================================================
|