libadlmidi-js 2.1.0 → 2.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.
Files changed (75) hide show
  1. package/dist/core.d.ts +34 -0
  2. package/dist/fm_banks/manifest.json +1 -1
  3. package/dist/libadlmidi.d.ts +31 -0
  4. package/dist/libadlmidi.dosbox.browser.js +1 -1
  5. package/dist/libadlmidi.dosbox.browser.wasm +0 -0
  6. package/dist/libadlmidi.dosbox.core.js +1 -1
  7. package/dist/libadlmidi.dosbox.core.wasm +0 -0
  8. package/dist/libadlmidi.dosbox.js +0 -0
  9. package/dist/libadlmidi.dosbox.processor.js +24 -7
  10. package/dist/libadlmidi.dosbox.slim.browser.js +1 -1
  11. package/dist/libadlmidi.dosbox.slim.browser.wasm +0 -0
  12. package/dist/libadlmidi.dosbox.slim.core.js +1 -1
  13. package/dist/libadlmidi.dosbox.slim.core.wasm +0 -0
  14. package/dist/libadlmidi.dosbox.slim.js +0 -0
  15. package/dist/libadlmidi.dosbox.slim.processor.js +24 -7
  16. package/dist/libadlmidi.full.browser.js +1 -1
  17. package/dist/libadlmidi.full.browser.wasm +0 -0
  18. package/dist/libadlmidi.full.core.js +1 -1
  19. package/dist/libadlmidi.full.core.wasm +0 -0
  20. package/dist/libadlmidi.full.js +0 -0
  21. package/dist/libadlmidi.full.processor.js +24 -7
  22. package/dist/libadlmidi.full.slim.browser.js +1 -1
  23. package/dist/libadlmidi.full.slim.browser.wasm +0 -0
  24. package/dist/libadlmidi.full.slim.core.js +1 -1
  25. package/dist/libadlmidi.full.slim.core.wasm +0 -0
  26. package/dist/libadlmidi.full.slim.js +0 -0
  27. package/dist/libadlmidi.full.slim.processor.js +24 -7
  28. package/dist/libadlmidi.js +66 -0
  29. package/dist/libadlmidi.js.map +2 -2
  30. package/dist/libadlmidi.light.browser.js +1 -1
  31. package/dist/libadlmidi.light.browser.wasm +0 -0
  32. package/dist/libadlmidi.light.core.js +1 -1
  33. package/dist/libadlmidi.light.core.wasm +0 -0
  34. package/dist/libadlmidi.light.js +0 -0
  35. package/dist/libadlmidi.light.processor.js +24 -7
  36. package/dist/libadlmidi.light.slim.browser.js +1 -1
  37. package/dist/libadlmidi.light.slim.browser.wasm +0 -0
  38. package/dist/libadlmidi.light.slim.core.js +1 -1
  39. package/dist/libadlmidi.light.slim.core.wasm +0 -0
  40. package/dist/libadlmidi.light.slim.js +0 -0
  41. package/dist/libadlmidi.light.slim.processor.js +24 -7
  42. package/dist/libadlmidi.nuked.browser.js +1 -1
  43. package/dist/libadlmidi.nuked.browser.wasm +0 -0
  44. package/dist/libadlmidi.nuked.core.js +1 -1
  45. package/dist/libadlmidi.nuked.core.wasm +0 -0
  46. package/dist/libadlmidi.nuked.js +0 -0
  47. package/dist/libadlmidi.nuked.processor.js +24 -7
  48. package/dist/libadlmidi.nuked.slim.browser.js +1 -1
  49. package/dist/libadlmidi.nuked.slim.browser.wasm +0 -0
  50. package/dist/libadlmidi.nuked.slim.core.js +1 -1
  51. package/dist/libadlmidi.nuked.slim.core.wasm +0 -0
  52. package/dist/libadlmidi.nuked.slim.js +0 -0
  53. package/dist/libadlmidi.nuked.slim.processor.js +24 -7
  54. package/dist/profiles/dosbox.d.ts +1 -0
  55. package/dist/profiles/dosbox.slim.d.ts +1 -0
  56. package/dist/profiles/full.d.ts +1 -0
  57. package/dist/profiles/full.slim.d.ts +1 -0
  58. package/dist/profiles/light.d.ts +1 -0
  59. package/dist/profiles/light.slim.d.ts +1 -0
  60. package/dist/profiles/nuked.d.ts +1 -0
  61. package/dist/profiles/nuked.slim.d.ts +1 -0
  62. package/dist/utils/opl3.d.ts +157 -0
  63. package/package.json +10 -6
  64. package/src/core.js +54 -0
  65. package/src/libadlmidi.js +58 -0
  66. package/src/processor.js +18 -0
  67. package/src/profiles/dosbox.js +21 -0
  68. package/src/profiles/dosbox.slim.js +21 -0
  69. package/src/profiles/full.js +21 -0
  70. package/src/profiles/full.slim.js +21 -0
  71. package/src/profiles/light.js +21 -0
  72. package/src/profiles/light.slim.js +21 -0
  73. package/src/profiles/nuked.js +21 -0
  74. package/src/profiles/nuked.slim.js +21 -0
  75. package/src/utils/opl3.js +250 -0
@@ -0,0 +1,157 @@
1
+ /**
2
+ * Get the register bank bit for a channel.
3
+ *
4
+ * @param {number} channel - Per-chip channel (0-17)
5
+ * @returns {number} 0x000 for channels 0-8, 0x100 for channels 9-17
6
+ */
7
+ export function channelBank(channel: number): number;
8
+ /**
9
+ * Get the frequency-number low register address (0xA0 series).
10
+ *
11
+ * @param {number} channel - Per-chip channel (0-17)
12
+ * @returns {number} Register address
13
+ */
14
+ export function fnumLoReg(channel: number): number;
15
+ /**
16
+ * Get the key-on / block / fnum-high register address (0xB0 series).
17
+ *
18
+ * @param {number} channel - Per-chip channel (0-17)
19
+ * @returns {number} Register address
20
+ */
21
+ export function keyOnBlockReg(channel: number): number;
22
+ /**
23
+ * Get the feedback / connection register address (0xC0 series).
24
+ *
25
+ * @param {number} channel - Per-chip channel (0-17)
26
+ * @returns {number} Register address
27
+ */
28
+ export function feedbackConnReg(channel: number): number;
29
+ /**
30
+ * Get the register address for an operator parameter.
31
+ *
32
+ * @param {number} baseReg - Register group base: 0x20 (AM/VIB/EG/KSR/MULT),
33
+ * 0x40 (KSL/TL), 0x60 (AR/DR), 0x80 (SL/RR), or 0xE0 (waveform)
34
+ * @param {number} channel - Per-chip channel (0-17)
35
+ * @param {number} operatorSlot - 0 for modulator, 1 for carrier
36
+ * @returns {number} Register address (0x000-0x1FF)
37
+ */
38
+ export function operatorReg(baseReg: number, channel: number, operatorSlot: number): number;
39
+ /**
40
+ * Convert a MIDI note number to OPL3 fnum and block values.
41
+ *
42
+ * Uses the standard OPL3 frequency formula:
43
+ * freq = fnum * OPL3_SAMPLE_RATE / 2^(20 - block)
44
+ *
45
+ * Picks the lowest block where fnum fits in 10 bits (maximum resolution).
46
+ * Notes above ~6.2 kHz (above MIDI 110 or so) will saturate.
47
+ *
48
+ * @param {number} note - MIDI note number (0-127)
49
+ * @returns {{fnum: number, block: number}}
50
+ */
51
+ export function noteToFnumBlock(note: number): {
52
+ fnum: number;
53
+ block: number;
54
+ };
55
+ /**
56
+ * Encode fnum and block into the two register byte values.
57
+ *
58
+ * @param {number} fnum - Frequency number (0-1023)
59
+ * @param {number} block - Block / octave (0-7)
60
+ * @returns {{fnumLo: number, fnumHiBlock: number}} Values for A0h and B0h
61
+ * registers. The B0h value does NOT include the key-on bit.
62
+ */
63
+ export function encodeFnumBlock(fnum: number, block: number): {
64
+ fnumLo: number;
65
+ fnumHiBlock: number;
66
+ };
67
+ /**
68
+ * Encode a key-on register write for a channel.
69
+ *
70
+ * @param {number} channel - Per-chip channel (0-17)
71
+ * @param {number} fnum - Frequency number (0-1023)
72
+ * @param {number} block - Block / octave (0-7)
73
+ * @returns {{reg: number, value: number}}
74
+ */
75
+ export function keyOn(channel: number, fnum: number, block: number): {
76
+ reg: number;
77
+ value: number;
78
+ };
79
+ /**
80
+ * Encode a key-off register write for a channel.
81
+ *
82
+ * @param {number} channel - Per-chip channel (0-17)
83
+ * @param {number} fnum - Frequency number (0-1023)
84
+ * @param {number} block - Block / octave (0-7)
85
+ * @returns {{reg: number, value: number}}
86
+ */
87
+ export function keyOff(channel: number, fnum: number, block: number): {
88
+ reg: number;
89
+ value: number;
90
+ };
91
+ /**
92
+ * Encode an Operator's properties into OPL3 register writes.
93
+ *
94
+ * @param {import('./struct.js').Operator} op
95
+ * @param {number} channel - Per-chip channel (0-17)
96
+ * @param {number} operatorSlot - 0 for modulator, 1 for carrier
97
+ * @returns {Array<{reg: number, value: number}>}
98
+ */
99
+ export function encodeOperatorRegisters(op: import("./struct.js").Operator, channel: number, operatorSlot: number): Array<{
100
+ reg: number;
101
+ value: number;
102
+ }>;
103
+ /**
104
+ * Generate all register writes to program a 2-op channel voice.
105
+ *
106
+ * Writes both operators and the feedback/connection register. Follows
107
+ * the ADL_Instrument convention: operators[0] = carrier (slot 1),
108
+ * operators[1] = modulator (slot 0). Sets stereo output bits (L+R)
109
+ * on the C0h register, which is required for audible output in OPL3 mode.
110
+ *
111
+ * Only handles 2-op instruments. Throws on 4-op or pseudo-4-op
112
+ * instruments, which require two paired channels.
113
+ *
114
+ * @param {import('./struct.js').Instrument} instrument
115
+ * @param {number} channel - Per-chip channel (0-17)
116
+ * @returns {Array<{reg: number, value: number}>}
117
+ */
118
+ export function encodeChannelVoice(instrument: import("./struct.js").Instrument, channel: number): Array<{
119
+ reg: number;
120
+ value: number;
121
+ }>;
122
+ /**
123
+ * Create a channel reservation bitmask from channel indices.
124
+ *
125
+ * @param {...number} channels - Per-chip channel indices (0-22)
126
+ * @returns {number} Bitmask for use with reserveChipChannels()
127
+ */
128
+ export function channelMask(...channels: number[]): number;
129
+ /**
130
+ * OPL3 register helpers for raw chip access.
131
+ *
132
+ * Pure-JS utilities for working with the OPL3 register layout. No WASM
133
+ * dependency. Use alongside AdlMidiCore.rawOPL3() or AdlMidi.rawOPL3()
134
+ * to program the chip directly.
135
+ *
136
+ * @module opl3
137
+ */
138
+ /** Total per-chip channels including rhythm-mode percussion */
139
+ export const CHANNELS_PER_CHIP: 23;
140
+ /** Standard 2-op melodic channels per chip */
141
+ export const CHANNELS_STANDARD: 18;
142
+ /** Rhythm-mode percussion channels (indices 18-22) */
143
+ export const CHANNELS_RHYTHM: 5;
144
+ /** OPL3 internal sample rate (Hz), used for fnum calculation. 14.31818 MHz / 288. */
145
+ export const OPL3_SAMPLE_RATE: 49716;
146
+ /**
147
+ * Operator register offsets per channel.
148
+ *
149
+ * Maps per-chip channel index (0-17) to [modulator, carrier] register
150
+ * offsets. These are the low byte of the register address; for channels
151
+ * 9-17, add 0x100 (use {@link channelBank}).
152
+ *
153
+ * Derived from Nuked OPL3's `ad_slot` and `ch_slot` tables.
154
+ *
155
+ * @type {ReadonlyArray<readonly [number, number]>}
156
+ */
157
+ export const CHANNEL_OPERATORS: ReadonlyArray<readonly [number, number]>;
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "libadlmidi-js",
3
- "version": "2.1.0",
3
+ "version": "2.2.0",
4
4
  "libadlmidi": {
5
5
  "version": "1.6.2",
6
- "commit": "6528dafce641e81ded5d62809445267b82dc0d8d"
6
+ "commit": "ad001c83551779934bacd642fce801c51a5b7b4c"
7
7
  },
8
8
  "description": "WebAssembly build of libADLMIDI - OPL3/FM synthesis for the browser",
9
9
  "main": "dist/libadlmidi.js",
@@ -18,6 +18,10 @@
18
18
  "types": "./dist/utils/struct.d.ts",
19
19
  "import": "./src/utils/struct.js"
20
20
  },
21
+ "./opl3": {
22
+ "types": "./dist/utils/opl3.d.ts",
23
+ "import": "./src/utils/opl3.js"
24
+ },
21
25
  "./nuked": {
22
26
  "types": "./dist/profiles/nuked.d.ts",
23
27
  "import": "./src/profiles/nuked.js"
@@ -100,18 +104,18 @@
100
104
  "@arethetypeswrong/cli": "^0.18.2",
101
105
  "@commitlint/cli": "^21.0.1",
102
106
  "@commitlint/config-conventional": "^21.0.1",
103
- "@emnapi/core": "1.10.0",
104
- "@emnapi/runtime": "1.10.0",
107
+ "@emnapi/core": "1.11.1",
108
+ "@emnapi/runtime": "1.11.1",
105
109
  "@eslint/js": "^10.0.1",
106
110
  "@playwright/test": "^1.57.0",
107
111
  "@types/node": "^25.0.3",
108
- "esbuild": "^0.27.2",
112
+ "esbuild": "^0.28.0",
109
113
  "eslint": "^10.0.3",
110
114
  "globals": "^17.4.0",
111
115
  "husky": "^9.1.7",
112
116
  "lint-staged": "^17.0.5",
113
117
  "playwright": "^1.57.0",
114
- "typescript": "^5.9.3",
118
+ "typescript": "^6.0.3",
115
119
  "vitest": "^4.1.5"
116
120
  },
117
121
  "files": [
package/src/core.js CHANGED
@@ -609,6 +609,60 @@ export class AdlMidiCore {
609
609
  this._module._adl_rt_bankChangeLSB(this._player, channel, lsb);
610
610
  }
611
611
 
612
+ // =========================================================================
613
+ // Raw OPL3 Access
614
+ // =========================================================================
615
+
616
+ /**
617
+ * Write a raw OPL3 register on a specific chip.
618
+ *
619
+ * Bypasses the MIDI voice allocator. The caller is responsible for the
620
+ * state of targeted channels. Reserve channels first via
621
+ * {@link reserveChipChannels} to prevent the MIDI driver from
622
+ * overwriting your register state.
623
+ *
624
+ * @param {number} chipId - Zero-based chip index (0 to getNumChipsObtained()-1)
625
+ * @param {number} reg - OPL3 register address (0x000-0x1FF, bit 8 selects bank)
626
+ * @param {number} value - Register value (0-255)
627
+ * @returns {boolean} True on success, false if chipId is out of range
628
+ */
629
+ rawOPL3(chipId, reg, value) {
630
+ this._ensurePlayer();
631
+ return this._module._adl_rt_rawOPL3(this._player, chipId, reg, value) === 1;
632
+ }
633
+
634
+ /**
635
+ * Reserve chip channels so the MIDI voice allocator will not use them.
636
+ *
637
+ * After reservation, use {@link rawOPL3} to drive those channels
638
+ * directly. Pass channelMask = 0 to release all reservations.
639
+ *
640
+ * @param {number} chipId - Zero-based chip index (0 to getNumChipsObtained()-1)
641
+ * @param {number} channelMask - Bitmask of per-chip channels to reserve
642
+ * (bits 0-22, where bit N reserves per-chip channel N)
643
+ * @returns {boolean} True on success
644
+ * @throws {Error} If the device is invalid
645
+ */
646
+ reserveChipChannels(chipId, channelMask) {
647
+ this._ensurePlayer();
648
+ const result = this._module._adl_reserveChipChannels(this._player, chipId, channelMask);
649
+ if (result === -1) {
650
+ throw new Error('Invalid device');
651
+ }
652
+ return result === 0;
653
+ }
654
+
655
+ /**
656
+ * Read back the chip-channel reservation mask.
657
+ *
658
+ * @param {number} chipId - Zero-based chip index
659
+ * @returns {number} Reservation bitmask (0 if invalid chipId)
660
+ */
661
+ getReservedChipChannels(chipId) {
662
+ this._ensurePlayer();
663
+ return this._module._adl_getReservedChipChannels(this._player, chipId);
664
+ }
665
+
612
666
  /**
613
667
  * Generate audio samples (real-time synthesis).
614
668
  *
package/src/libadlmidi.js CHANGED
@@ -349,6 +349,64 @@ export class AdlMidi {
349
349
  this.#send({ type: 'panic' });
350
350
  }
351
351
 
352
+ // ================== Raw OPL3 API ==================
353
+
354
+ /**
355
+ * Write a raw OPL3 register on a specific chip (fire-and-forget).
356
+ *
357
+ * Bypasses the MIDI voice allocator. Reserve channels first via
358
+ * {@link reserveChipChannels} to prevent the MIDI driver from
359
+ * overwriting your register state.
360
+ *
361
+ * @param {number} chipId - Zero-based chip index (0 to getNumChipsObtained()-1)
362
+ * @param {number} reg - OPL3 register address (0x000-0x1FF, bit 8 selects bank)
363
+ * @param {number} value - Register value (0-255)
364
+ */
365
+ rawOPL3(chipId, reg, value) {
366
+ this.#send({ type: 'rawOPL3', chipId, reg, value });
367
+ }
368
+
369
+ /**
370
+ * Reserve chip channels so the MIDI voice allocator will not use them.
371
+ *
372
+ * After reservation, use {@link rawOPL3} to drive those channels
373
+ * directly. Pass channelMask = 0 to release all reservations.
374
+ *
375
+ * @param {number} chipId - Zero-based chip index (0 to getNumChipsObtained()-1)
376
+ * @param {number} channelMask - Bitmask of per-chip channels to reserve
377
+ * (bits 0-22, where bit N reserves per-chip channel N)
378
+ * @returns {Promise<void>}
379
+ */
380
+ async reserveChipChannels(chipId, channelMask) {
381
+ const reqId = this.#nextRequestId++;
382
+ return new Promise((resolve, reject) => {
383
+ this.#onceCorrelatedMessage('chipChannelsReserved', reqId, /** @param {{success: boolean}} msg */ (msg) => {
384
+ if (msg.success) {
385
+ resolve();
386
+ } else {
387
+ reject(new Error(`Failed to reserve chip channels on chip ${chipId}`));
388
+ }
389
+ });
390
+ this.#send({ type: 'reserveChipChannels', chipId, channelMask, reqId });
391
+ });
392
+ }
393
+
394
+ /**
395
+ * Read back the chip-channel reservation mask.
396
+ *
397
+ * @param {number} chipId - Zero-based chip index
398
+ * @returns {Promise<number>} Reservation bitmask (0 if invalid chipId)
399
+ */
400
+ async getReservedChipChannels(chipId) {
401
+ const reqId = this.#nextRequestId++;
402
+ return new Promise((resolve) => {
403
+ this.#onceCorrelatedMessage('reservedChipChannels', reqId, /** @param {{mask: number}} msg */ (msg) => {
404
+ resolve(msg.mask);
405
+ });
406
+ this.#send({ type: 'getReservedChipChannels', chipId, reqId });
407
+ });
408
+ }
409
+
352
410
  /**
353
411
  * Configure synth settings at runtime
354
412
  * @param {ConfigureSettings} settings - Settings object
package/src/processor.js CHANGED
@@ -701,6 +701,24 @@ class AdlMidiProcessor extends AudioWorkletProcessor {
701
701
  break;
702
702
  }
703
703
 
704
+ // ================== Raw OPL3 ==================
705
+
706
+ case 'rawOPL3':
707
+ this.adl._adl_rt_rawOPL3(this.midi, msg.chipId, msg.reg, msg.value);
708
+ break;
709
+
710
+ case 'reserveChipChannels': {
711
+ const result = this.adl._adl_reserveChipChannels(this.midi, msg.chipId, msg.channelMask);
712
+ this.port.postMessage({ type: 'chipChannelsReserved', success: result === 0, chipId: msg.chipId, reqId: msg.reqId });
713
+ break;
714
+ }
715
+
716
+ case 'getReservedChipChannels': {
717
+ const mask = this.adl._adl_getReservedChipChannels(this.midi, msg.chipId);
718
+ this.port.postMessage({ type: 'reservedChipChannels', mask, chipId: msg.chipId, reqId: msg.reqId });
719
+ break;
720
+ }
721
+
704
722
  // ================== Debug / Diagnostics ==================
705
723
 
706
724
  case 'describeChannels': {
@@ -90,3 +90,24 @@ export {
90
90
 
91
91
  // Re-export enums
92
92
  export { Emulator, TrackOption } from '../utils/constants.js';
93
+
94
+ // Re-export OPL3 register helpers
95
+ export {
96
+ CHANNELS_PER_CHIP,
97
+ CHANNELS_STANDARD,
98
+ CHANNELS_RHYTHM,
99
+ OPL3_SAMPLE_RATE,
100
+ CHANNEL_OPERATORS,
101
+ channelBank,
102
+ fnumLoReg,
103
+ keyOnBlockReg,
104
+ feedbackConnReg,
105
+ operatorReg,
106
+ noteToFnumBlock,
107
+ encodeFnumBlock,
108
+ keyOn,
109
+ keyOff,
110
+ encodeOperatorRegisters,
111
+ encodeChannelVoice,
112
+ channelMask
113
+ } from '../utils/opl3.js';
@@ -90,3 +90,24 @@ export {
90
90
 
91
91
  // Re-export enums
92
92
  export { Emulator, TrackOption } from '../utils/constants.js';
93
+
94
+ // Re-export OPL3 register helpers
95
+ export {
96
+ CHANNELS_PER_CHIP,
97
+ CHANNELS_STANDARD,
98
+ CHANNELS_RHYTHM,
99
+ OPL3_SAMPLE_RATE,
100
+ CHANNEL_OPERATORS,
101
+ channelBank,
102
+ fnumLoReg,
103
+ keyOnBlockReg,
104
+ feedbackConnReg,
105
+ operatorReg,
106
+ noteToFnumBlock,
107
+ encodeFnumBlock,
108
+ keyOn,
109
+ keyOff,
110
+ encodeOperatorRegisters,
111
+ encodeChannelVoice,
112
+ channelMask
113
+ } from '../utils/opl3.js';
@@ -90,3 +90,24 @@ export {
90
90
 
91
91
  // Re-export enums
92
92
  export { Emulator, TrackOption } from '../utils/constants.js';
93
+
94
+ // Re-export OPL3 register helpers
95
+ export {
96
+ CHANNELS_PER_CHIP,
97
+ CHANNELS_STANDARD,
98
+ CHANNELS_RHYTHM,
99
+ OPL3_SAMPLE_RATE,
100
+ CHANNEL_OPERATORS,
101
+ channelBank,
102
+ fnumLoReg,
103
+ keyOnBlockReg,
104
+ feedbackConnReg,
105
+ operatorReg,
106
+ noteToFnumBlock,
107
+ encodeFnumBlock,
108
+ keyOn,
109
+ keyOff,
110
+ encodeOperatorRegisters,
111
+ encodeChannelVoice,
112
+ channelMask
113
+ } from '../utils/opl3.js';
@@ -90,3 +90,24 @@ export {
90
90
 
91
91
  // Re-export enums
92
92
  export { Emulator, TrackOption } from '../utils/constants.js';
93
+
94
+ // Re-export OPL3 register helpers
95
+ export {
96
+ CHANNELS_PER_CHIP,
97
+ CHANNELS_STANDARD,
98
+ CHANNELS_RHYTHM,
99
+ OPL3_SAMPLE_RATE,
100
+ CHANNEL_OPERATORS,
101
+ channelBank,
102
+ fnumLoReg,
103
+ keyOnBlockReg,
104
+ feedbackConnReg,
105
+ operatorReg,
106
+ noteToFnumBlock,
107
+ encodeFnumBlock,
108
+ keyOn,
109
+ keyOff,
110
+ encodeOperatorRegisters,
111
+ encodeChannelVoice,
112
+ channelMask
113
+ } from '../utils/opl3.js';
@@ -90,3 +90,24 @@ export {
90
90
 
91
91
  // Re-export enums
92
92
  export { Emulator, TrackOption } from '../utils/constants.js';
93
+
94
+ // Re-export OPL3 register helpers
95
+ export {
96
+ CHANNELS_PER_CHIP,
97
+ CHANNELS_STANDARD,
98
+ CHANNELS_RHYTHM,
99
+ OPL3_SAMPLE_RATE,
100
+ CHANNEL_OPERATORS,
101
+ channelBank,
102
+ fnumLoReg,
103
+ keyOnBlockReg,
104
+ feedbackConnReg,
105
+ operatorReg,
106
+ noteToFnumBlock,
107
+ encodeFnumBlock,
108
+ keyOn,
109
+ keyOff,
110
+ encodeOperatorRegisters,
111
+ encodeChannelVoice,
112
+ channelMask
113
+ } from '../utils/opl3.js';
@@ -90,3 +90,24 @@ export {
90
90
 
91
91
  // Re-export enums
92
92
  export { Emulator, TrackOption } from '../utils/constants.js';
93
+
94
+ // Re-export OPL3 register helpers
95
+ export {
96
+ CHANNELS_PER_CHIP,
97
+ CHANNELS_STANDARD,
98
+ CHANNELS_RHYTHM,
99
+ OPL3_SAMPLE_RATE,
100
+ CHANNEL_OPERATORS,
101
+ channelBank,
102
+ fnumLoReg,
103
+ keyOnBlockReg,
104
+ feedbackConnReg,
105
+ operatorReg,
106
+ noteToFnumBlock,
107
+ encodeFnumBlock,
108
+ keyOn,
109
+ keyOff,
110
+ encodeOperatorRegisters,
111
+ encodeChannelVoice,
112
+ channelMask
113
+ } from '../utils/opl3.js';
@@ -90,3 +90,24 @@ export {
90
90
 
91
91
  // Re-export enums
92
92
  export { Emulator, TrackOption } from '../utils/constants.js';
93
+
94
+ // Re-export OPL3 register helpers
95
+ export {
96
+ CHANNELS_PER_CHIP,
97
+ CHANNELS_STANDARD,
98
+ CHANNELS_RHYTHM,
99
+ OPL3_SAMPLE_RATE,
100
+ CHANNEL_OPERATORS,
101
+ channelBank,
102
+ fnumLoReg,
103
+ keyOnBlockReg,
104
+ feedbackConnReg,
105
+ operatorReg,
106
+ noteToFnumBlock,
107
+ encodeFnumBlock,
108
+ keyOn,
109
+ keyOff,
110
+ encodeOperatorRegisters,
111
+ encodeChannelVoice,
112
+ channelMask
113
+ } from '../utils/opl3.js';
@@ -90,3 +90,24 @@ export {
90
90
 
91
91
  // Re-export enums
92
92
  export { Emulator, TrackOption } from '../utils/constants.js';
93
+
94
+ // Re-export OPL3 register helpers
95
+ export {
96
+ CHANNELS_PER_CHIP,
97
+ CHANNELS_STANDARD,
98
+ CHANNELS_RHYTHM,
99
+ OPL3_SAMPLE_RATE,
100
+ CHANNEL_OPERATORS,
101
+ channelBank,
102
+ fnumLoReg,
103
+ keyOnBlockReg,
104
+ feedbackConnReg,
105
+ operatorReg,
106
+ noteToFnumBlock,
107
+ encodeFnumBlock,
108
+ keyOn,
109
+ keyOff,
110
+ encodeOperatorRegisters,
111
+ encodeChannelVoice,
112
+ channelMask
113
+ } from '../utils/opl3.js';