midiwire 0.8.0 → 0.10.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 CHANGED
@@ -36,7 +36,7 @@ Or use directly in the browser from a CDN like [jsDelivr](https://www.jsdelivr.c
36
36
 
37
37
  <!-- Or specify a version if needed -->
38
38
  <script type="module">
39
- import { createMIDIController } from "https://cdn.jsdelivr.net/npm/midiwire@0.8.0/+esm";
39
+ import { createMIDIController } from "https://cdn.jsdelivr.net/npm/midiwire@X.Y.Z/+esm";
40
40
  </script>
41
41
  ```
42
42
 
@@ -58,6 +58,52 @@ export class MIDIDeviceManager {
58
58
  * @param {MIDIController} midi
59
59
  */
60
60
  setMIDI(midi: MIDIController): void;
61
+ /**
62
+ * Set up all MIDI device selectors in one call. Handles population, connection
63
+ * handling, channel selection, and automatic refresh on device changes.
64
+ *
65
+ * @param {Object} selectors - Selectors configuration
66
+ * @param {HTMLSelectElement|string} [selectors.output] - Output device dropdown element or CSS selector string (e.g., "#output-select")
67
+ * @param {HTMLSelectElement|string} [selectors.input] - Input device dropdown element or CSS selector string (e.g., "#input-select")
68
+ * @param {HTMLSelectElement|string} [selectors.channel] - MIDI channel dropdown element or CSS selector
69
+ * @param {Object} [options] - Configuration options
70
+ * @param {Function} [options.onConnect] - Called when device connects ({ midi, device, type })
71
+ * @param {Function} [options.onDisconnect] - Called when device disconnects ({ midi, type })
72
+ * @returns {Promise<MIDIController>} The MIDI controller instance for chaining
73
+ *
74
+ * @example
75
+ * // Setup all selectors at once with DOM elements
76
+ * const midi = await manager.setupSelectors({
77
+ * output: document.getElementById("output-select"),
78
+ * input: document.getElementById("input-select"),
79
+ * channel: document.getElementById("channel-select"),
80
+ * onConnect: ({ midi, device, type }) => {
81
+ * console.log(`${type} connected: ${device.name}`);
82
+ * },
83
+ * onDisconnect: ({ midi, type }) => {
84
+ * console.log(`${type} disconnected`);
85
+ * }
86
+ * });
87
+ *
88
+ * @example
89
+ * // Setup with CSS selectors (more concise)
90
+ * const midi = await manager.setupSelectors({
91
+ * output: "#output-select",
92
+ * input: "#input-select",
93
+ * channel: "#channel-select"
94
+ * });
95
+ *
96
+ * // Now use the midi controller directly
97
+ * midi.channel.sendCC(1, 100);
98
+ */
99
+ setupSelectors(selectors?: {
100
+ output?: HTMLSelectElement | string;
101
+ input?: HTMLSelectElement | string;
102
+ channel?: HTMLSelectElement | string;
103
+ }, options?: {
104
+ onConnect?: Function;
105
+ onDisconnect?: Function;
106
+ }): Promise<MIDIController>;
61
107
  /**
62
108
  * Set up device change event listeners for automatic UI updates when devices
63
109
  * connect or disconnect. Handles both successful connections and disconnections,
@@ -65,8 +111,8 @@ export class MIDIDeviceManager {
65
111
  *
66
112
  * @param {Function} [onDeviceListChange] - Optional callback to refresh device list UI when devices change
67
113
  * @param {Object} [selectElements] - Optional select elements to update on disconnect
68
- * @param {HTMLSelectElement} [selectElements.output] - Output device select element
69
- * @param {HTMLSelectElement} [selectElements.input] - Input device select element
114
+ * @param {HTMLSelectElement|string} [selectElements.output] - Output device select element or CSS selector string (e.g., "#output-select")
115
+ * @param {HTMLSelectElement|string} [selectElements.input] - Input device select element or CSS selector string (e.g., "#input-select")
70
116
  * @returns {void}
71
117
  *
72
118
  * @emits CONTROLLER_EVENTS.DEV_OUT_CONNECTED
@@ -88,10 +134,17 @@ export class MIDIDeviceManager {
88
134
  * output: outputSelect,
89
135
  * input: inputSelect
90
136
  * });
137
+ *
138
+ * @example
139
+ * // With CSS selectors
140
+ * manager.setupDeviceListeners(null, {
141
+ * output: "#output-select",
142
+ * input: "#input-select"
143
+ * });
91
144
  */
92
145
  setupDeviceListeners(onDeviceListChange?: Function, selectElements?: {
93
- output?: HTMLSelectElement;
94
- input?: HTMLSelectElement;
146
+ output?: HTMLSelectElement | string;
147
+ input?: HTMLSelectElement | string;
95
148
  }): void;
96
149
  /**
97
150
  * Update status message and trigger status callback
@@ -111,52 +164,6 @@ export class MIDIDeviceManager {
111
164
  * Update connection status
112
165
  */
113
166
  updateConnectionStatus(): void;
114
- /**
115
- * Set up all MIDI device selectors in one call. Handles population, connection
116
- * handling, channel selection, and automatic refresh on device changes.
117
- *
118
- * @param {Object} selectors - Selectors configuration
119
- * @param {HTMLSelectElement|string} [selectors.output] - Output device dropdown element or CSS selector string (e.g., "#output-select")
120
- * @param {HTMLSelectElement|string} [selectors.input] - Input device dropdown element or CSS selector string (e.g., "#input-select")
121
- * @param {HTMLSelectElement|string} [selectors.channel] - MIDI channel dropdown element or CSS selector
122
- * @param {Object} [options] - Configuration options
123
- * @param {Function} [options.onConnect] - Called when device connects ({ midi, device, type })
124
- * @param {Function} [options.onDisconnect] - Called when device disconnects ({ midi, type })
125
- * @returns {Promise<MIDIController>} The MIDI controller instance for chaining
126
- *
127
- * @example
128
- * // Setup all selectors at once with DOM elements
129
- * const midi = await manager.setupSelectors({
130
- * output: document.getElementById("output-select"),
131
- * input: document.getElementById("input-select"),
132
- * channel: document.getElementById("channel-select"),
133
- * onConnect: ({ midi, device, type }) => {
134
- * console.log(`${type} connected: ${device.name}`);
135
- * },
136
- * onDisconnect: ({ midi, type }) => {
137
- * console.log(`${type} disconnected`);
138
- * }
139
- * });
140
- *
141
- * @example
142
- * // Setup with CSS selectors (more concise)
143
- * const midi = await manager.setupSelectors({
144
- * output: "#output-select",
145
- * input: "#input-select",
146
- * channel: "#channel-select"
147
- * });
148
- *
149
- * // Now use the midi controller directly
150
- * midi.channel.sendCC(1, 100);
151
- */
152
- setupSelectors(selectors?: {
153
- output?: HTMLSelectElement | string;
154
- input?: HTMLSelectElement | string;
155
- channel?: HTMLSelectElement | string;
156
- }, options?: {
157
- onConnect?: Function;
158
- onDisconnect?: Function;
159
- }): Promise<MIDIController>;
160
167
  /**
161
168
  * Resolve a selector to a DOM element
162
169
  * @private
@@ -1 +1 @@
1
- {"version":3,"file":"MIDIDeviceManager.d.ts","sourceRoot":"","sources":["../../src/core/MIDIDeviceManager.js"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH;IACE;;;;;;;OAOG;IACH,sBALG;QAAiC,cAAc,GAAvC,cAAc;QACK,cAAc;QACd,kBAAkB;QACpB,OAAO,GAAxB,MAAM;KAChB,EASA;IAPC,UAA0C;IAC1C,yBAA0D;IAC1D,6BAAkE;IAClE,gBAAmC;IACnC,mBAAyB;IACzB,kBAAwB;IACxB,sBAAyB;IAG3B;;;OAGG;IACH,cAFW,cAAc,QAIxB;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8BG;IACH,qEAxBG;QAA2C,MAAM,GAAzC,iBAAiB;QACkB,KAAK,GAAxC,iBAAiB;KACzB,GAAU,IAAI,CAkEhB;IAED;;;;;;;;;;;;OAYG;IACH,sBAVW,MAAM,UACN,MAAM,GACJ,IAAI,CAUhB;IAED;;OAEG;IACH,+BAEC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAqCG;IACH,2BAjCG;QAA6C,MAAM,GAA3C,iBAAiB,GAAC,MAAM;QACa,KAAK,GAA1C,iBAAiB,GAAC,MAAM;QACa,OAAO,GAA5C,iBAAiB,GAAC,MAAM;KAChC,YACA;QAA2B,SAAS;QACT,YAAY;KACvC,GAAU,OAAO,CAAC,cAAc,CAAC,CAkFnC;IAED;;;;;OAKG;IACH,yBASC;IAED;;;;OAIG;IACH,0BAGC;IAED;;;;OAIG;IACH,yBAGC;IAED;;;;;;;;OAQG;IACH,sCA+CC;IAED;;;;;;;;OAQG;IACH,qCAoCC;IAED;;;;;;;;;OASG;IACH,4BAoCC;IAED;;;;;;;;OAQG;IACH,kCAKC;IAED;;;;;;;;OAQG;IACH,iCAMC;IAED;;;;;;;;;;;;;;;;;;;OAmBG;IACH,iCAWC;CACF"}
1
+ {"version":3,"file":"MIDIDeviceManager.d.ts","sourceRoot":"","sources":["../../src/core/MIDIDeviceManager.js"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH;IACE;;;;;;;OAOG;IACH,sBALG;QAAiC,cAAc,GAAvC,cAAc;QACK,cAAc;QACd,kBAAkB;QACpB,OAAO,GAAxB,MAAM;KAChB,EASA;IAPC,UAA0C;IAC1C,yBAA0D;IAC1D,6BAAkE;IAClE,gBAAmC;IACnC,mBAAyB;IACzB,kBAAwB;IACxB,sBAAyB;IAG3B;;;OAGG;IACH,cAFW,cAAc,QAIxB;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAqCG;IACH,2BAjCG;QAA6C,MAAM,GAA3C,iBAAiB,GAAC,MAAM;QACa,KAAK,GAA1C,iBAAiB,GAAC,MAAM;QACa,OAAO,GAA5C,iBAAiB,GAAC,MAAM;KAChC,YACA;QAA2B,SAAS;QACT,YAAY;KACvC,GAAU,OAAO,CAAC,cAAc,CAAC,CAkFnC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAqCG;IACH,qEA/BG;QAAkD,MAAM,GAAhD,iBAAiB,GAAC,MAAM;QACkB,KAAK,GAA/C,iBAAiB,GAAC,MAAM;KAChC,GAAU,IAAI,CAiFhB;IAED;;;;;;;;;;;;OAYG;IACH,sBAVW,MAAM,UACN,MAAM,GACJ,IAAI,CAUhB;IAED;;OAEG;IACH,+BAEC;IAED;;;;;OAKG;IACH,yBASC;IAED;;;;OAIG;IACH,0BAGC;IAED;;;;OAIG;IACH,yBAGC;IAED;;;;;;;;OAQG;IACH,sCA+CC;IAED;;;;;;;;OAQG;IACH,qCAoCC;IAED;;;;;;;;;OASG;IACH,4BAoCC;IAED;;;;;;;;OAQG;IACH,kCAKC;IAED;;;;;;;;OAQG;IACH,iCAMC;IAED;;;;;;;;;;;;;;;;;;;OAmBG;IACH,iCAWC;CACF"}
@@ -2294,70 +2294,6 @@ class q {
2294
2294
  setMIDI(t) {
2295
2295
  this.midi = t;
2296
2296
  }
2297
- /**
2298
- * Set up device change event listeners for automatic UI updates when devices
2299
- * connect or disconnect. Handles both successful connections and disconnections,
2300
- * updating status messages and tracking the current device state.
2301
- *
2302
- * @param {Function} [onDeviceListChange] - Optional callback to refresh device list UI when devices change
2303
- * @param {Object} [selectElements] - Optional select elements to update on disconnect
2304
- * @param {HTMLSelectElement} [selectElements.output] - Output device select element
2305
- * @param {HTMLSelectElement} [selectElements.input] - Input device select element
2306
- * @returns {void}
2307
- *
2308
- * @emits CONTROLLER_EVENTS.DEV_OUT_CONNECTED
2309
- * @emits CONTROLLER_EVENTS.DEV_OUT_DISCONNECTED
2310
- *
2311
- * @example
2312
- * // Basic setup
2313
- * manager.setupDeviceListeners();
2314
- *
2315
- * @example
2316
- * // With device list refresh callback
2317
- * manager.setupDeviceListeners(() => {
2318
- * manager.output.populateDeviceList(deviceSelect);
2319
- * });
2320
- *
2321
- * @example
2322
- * // With select elements to clear on disconnect
2323
- * manager.setupDeviceListeners(null, {
2324
- * output: outputSelect,
2325
- * input: inputSelect
2326
- * });
2327
- */
2328
- setupDeviceListeners(t, s = {}) {
2329
- this.midi && (this.midi.on(C.DEV_OUT_CONNECTED, (e) => {
2330
- this.updateStatus(`Output device connected: ${e?.name || "Unknown"}`, "connected"), t && t();
2331
- }), this.midi.on(C.DEV_OUT_DISCONNECTED, (e) => {
2332
- this.updateStatus(`Output device disconnected: ${e?.name || "Unknown"}`, "error"), this.currentOutput && e?.name === this.currentOutput.name && (this.currentOutput = null, this.updateConnectionStatus(), s.output && (s.output.value = "")), t && t();
2333
- }), this.midi.on(C.DEV_IN_CONNECTED, (e) => {
2334
- this.updateStatus(`Input device connected: ${e?.name || "Unknown"}`, "connected"), t && t();
2335
- }), this.midi.on(C.DEV_IN_DISCONNECTED, (e) => {
2336
- this.updateStatus(`Input device disconnected: ${e?.name || "Unknown"}`, "error"), s.input && (s.input.value = ""), t && t();
2337
- }));
2338
- }
2339
- /**
2340
- * Update status message and trigger status callback
2341
- *
2342
- * @param {string} message - Status message to display
2343
- * @param {string} [state=""] - Status state (e.g., "connected", "error", "warning")
2344
- * @returns {void}
2345
- *
2346
- * @example
2347
- * manager.updateStatus("Connected to MIDI keyboard", "connected");
2348
- *
2349
- * @example
2350
- * manager.updateStatus("Connection failed", "error");
2351
- */
2352
- updateStatus(t, s = "") {
2353
- this.onStatusUpdate(t, s);
2354
- }
2355
- /**
2356
- * Update connection status
2357
- */
2358
- updateConnectionStatus() {
2359
- this.onConnectionUpdate(this.currentOutput, this.currentInput, this.midi);
2360
- }
2361
2297
  /**
2362
2298
  * Set up all MIDI device selectors in one call. Handles population, connection
2363
2299
  * handling, channel selection, and automatic refresh on device changes.
@@ -2416,6 +2352,79 @@ class q {
2416
2352
  }
2417
2353
  return S && this._connectChannelSelection(S, "output"), this.midi;
2418
2354
  }
2355
+ /**
2356
+ * Set up device change event listeners for automatic UI updates when devices
2357
+ * connect or disconnect. Handles both successful connections and disconnections,
2358
+ * updating status messages and tracking the current device state.
2359
+ *
2360
+ * @param {Function} [onDeviceListChange] - Optional callback to refresh device list UI when devices change
2361
+ * @param {Object} [selectElements] - Optional select elements to update on disconnect
2362
+ * @param {HTMLSelectElement|string} [selectElements.output] - Output device select element or CSS selector string (e.g., "#output-select")
2363
+ * @param {HTMLSelectElement|string} [selectElements.input] - Input device select element or CSS selector string (e.g., "#input-select")
2364
+ * @returns {void}
2365
+ *
2366
+ * @emits CONTROLLER_EVENTS.DEV_OUT_CONNECTED
2367
+ * @emits CONTROLLER_EVENTS.DEV_OUT_DISCONNECTED
2368
+ *
2369
+ * @example
2370
+ * // Basic setup
2371
+ * manager.setupDeviceListeners();
2372
+ *
2373
+ * @example
2374
+ * // With device list refresh callback
2375
+ * manager.setupDeviceListeners(() => {
2376
+ * manager.output.populateDeviceList(deviceSelect);
2377
+ * });
2378
+ *
2379
+ * @example
2380
+ * // With select elements to clear on disconnect
2381
+ * manager.setupDeviceListeners(null, {
2382
+ * output: outputSelect,
2383
+ * input: inputSelect
2384
+ * });
2385
+ *
2386
+ * @example
2387
+ * // With CSS selectors
2388
+ * manager.setupDeviceListeners(null, {
2389
+ * output: "#output-select",
2390
+ * input: "#input-select"
2391
+ * });
2392
+ */
2393
+ setupDeviceListeners(t, s = {}) {
2394
+ if (!this.midi) return;
2395
+ const e = {};
2396
+ s.output && (e.output = this._resolveSelector(s.output)), s.input && (e.input = this._resolveSelector(s.input)), this.midi.on(C.DEV_OUT_CONNECTED, (E) => {
2397
+ this.updateStatus(`Output device connected: ${E?.name || "Unknown"}`, "connected"), t && t();
2398
+ }), this.midi.on(C.DEV_OUT_DISCONNECTED, (E) => {
2399
+ this.updateStatus(`Output device disconnected: ${E?.name || "Unknown"}`, "error"), this.currentOutput && E?.name === this.currentOutput.name && (this.currentOutput = null, this.updateConnectionStatus(), e.output && (e.output.value = "")), t && t();
2400
+ }), this.midi.on(C.DEV_IN_CONNECTED, (E) => {
2401
+ this.updateStatus(`Input device connected: ${E?.name || "Unknown"}`, "connected"), t && t();
2402
+ }), this.midi.on(C.DEV_IN_DISCONNECTED, (E) => {
2403
+ this.updateStatus(`Input device disconnected: ${E?.name || "Unknown"}`, "error"), e.input && (e.input.value = ""), t && t();
2404
+ });
2405
+ }
2406
+ /**
2407
+ * Update status message and trigger status callback
2408
+ *
2409
+ * @param {string} message - Status message to display
2410
+ * @param {string} [state=""] - Status state (e.g., "connected", "error", "warning")
2411
+ * @returns {void}
2412
+ *
2413
+ * @example
2414
+ * manager.updateStatus("Connected to MIDI keyboard", "connected");
2415
+ *
2416
+ * @example
2417
+ * manager.updateStatus("Connection failed", "error");
2418
+ */
2419
+ updateStatus(t, s = "") {
2420
+ this.onStatusUpdate(t, s);
2421
+ }
2422
+ /**
2423
+ * Update connection status
2424
+ */
2425
+ updateConnectionStatus() {
2426
+ this.onConnectionUpdate(this.currentOutput, this.currentInput, this.midi);
2427
+ }
2419
2428
  /**
2420
2429
  * Resolve a selector to a DOM element
2421
2430
  * @private
@@ -1 +1 @@
1
- (function(N,p){typeof exports=="object"&&typeof module<"u"?p(exports):typeof define=="function"&&define.amd?define(["exports"],p):(N=typeof globalThis<"u"?globalThis:N||self,p(N.MIDIControls={}))})(this,(function(N){"use strict";class p{constructor(t,s="[data-midi-cc]"){this.controller=t,this.selector=s,this.observer=null}bindAll(){document.querySelectorAll(this.selector==="[data-midi-cc]"?"[data-midi-cc], [data-midi-msb][data-midi-lsb]":this.selector).forEach(s=>{if(s.hasAttribute("data-midi-bound"))return;const e=this._parseAttributes(s);e&&(this.controller.bind(s,e),s.setAttribute("data-midi-bound","true"))})}enableAutoBinding(){if(this.observer)return;const t=this.selector==="[data-midi-cc]"?"[data-midi-cc], [data-midi-msb][data-midi-lsb]":this.selector;this.observer=new MutationObserver(s=>{s.forEach(e=>{e.addedNodes.forEach(E=>{if(E.nodeType===Node.ELEMENT_NODE){if(E.matches?.(t)){const _=this._parseAttributes(E);_&&!E.hasAttribute("data-midi-bound")&&(this.controller.bind(E,_),E.setAttribute("data-midi-bound","true"))}E.querySelectorAll&&E.querySelectorAll(t).forEach(i=>{if(!i.hasAttribute("data-midi-bound")){const r=this._parseAttributes(i);r&&(this.controller.bind(i,r),i.setAttribute("data-midi-bound","true"))}})}}),e.removedNodes.forEach(E=>{E.nodeType===Node.ELEMENT_NODE&&(E.hasAttribute?.("data-midi-bound")&&this.controller.unbind(E),E.querySelectorAll&&E.querySelectorAll("[data-midi-bound]").forEach(i=>{this.controller.unbind(i)}))})})}),this.observer.observe(document.body,{childList:!0,subtree:!0})}disableAutoBinding(){this.observer&&(this.observer.disconnect(),this.observer=null)}_parseAttributes(t){const s=parseInt(t.dataset.midiMsb,10),e=parseInt(t.dataset.midiLsb,10);if(!Number.isNaN(s)&&!Number.isNaN(e)&&s>=0&&s<=127&&e>=0&&e<=127){const _=parseInt(t.dataset.midiCc,10);return!Number.isNaN(_)&&_>=0&&_<=127&&console.warn(`Element has both 7-bit (data-midi-cc="${_}") and 14-bit (data-midi-msb="${s}" data-midi-lsb="${e}") CC attributes. 14-bit takes precedence.`,t),{msb:s,lsb:e,is14Bit:!0,channel:parseInt(t.dataset.midiChannel,10)||void 0,min:parseFloat(t.getAttribute("min"))||0,max:parseFloat(t.getAttribute("max"))||127,invert:t.dataset.midiInvert==="true",label:t.dataset.midiLabel}}const E=parseInt(t.dataset.midiCc,10);return!Number.isNaN(E)&&E>=0&&E<=127?{cc:E,channel:parseInt(t.dataset.midiChannel,10)||void 0,min:parseFloat(t.getAttribute("min"))||0,max:parseFloat(t.getAttribute("max"))||127,invert:t.dataset.midiInvert==="true",label:t.dataset.midiLabel}:((t.dataset.midiCc!==void 0||t.dataset.midiMsb!==void 0&&t.dataset.midiLsb!==void 0)&&console.warn("Invalid MIDI configuration on element:",t),null)}destroy(){this.disableAutoBinding()}}class m extends Error{constructor(t,s){super(t),this.name="MIDIError",this.code=s,Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor)}}class g extends m{constructor(t,s){super(t,"MIDI_ACCESS_ERROR"),this.name="MIDIAccessError",this.reason=s}}class G extends m{constructor(t){super(t,"MIDI_CONNECTION_ERROR"),this.name="MIDIConnectionError"}}class L extends m{constructor(t,s,e){super(t,"MIDI_DEVICE_ERROR"),this.name="MIDIDeviceError",this.deviceType=s,this.deviceId=e}}class R extends m{constructor(t,s){super(t,"MIDI_VALIDATION_ERROR"),this.name="MIDIValidationError",this.validationType=s}}class F extends Error{constructor(t,s){super(t),this.name="DX7Error",this.code=s,Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor)}}class M extends F{constructor(t,s,e){super(t,"DX7_PARSE_ERROR"),this.name="DX7ParseError",this.parseType=s,this.offset=e}}class d extends F{constructor(t,s,e){super(t,"DX7_VALIDATION_ERROR"),this.name="DX7ValidationError",this.validationType=s,this.value=e}}function O(C,t,s){return Math.max(t,Math.min(s,C))}function y(C,t,s,e=!1){const E=(C-t)/(s-t),i=(e?1-E:E)*127;return O(Math.round(i),0,127)}function W(C,t,s,e=!1){let E=O(C,0,127)/127;return e&&(E=1-E),t+E*(s-t)}function Q(C){const t={C:0,"C#":1,DB:1,D:2,"D#":3,EB:3,E:4,F:5,"F#":6,GB:6,G:7,"G#":8,AB:8,A:9,"A#":10,BB:10,B:11},s=C.match(/^([A-G][#b]?)(-?\d+)$/i);if(!s)throw new R(`Invalid note name: ${C}`,"note",C);const[,e,E]=s,_=t[e.toUpperCase()];if(_===void 0)throw new R(`Invalid note: ${e}`,"note",e);const i=(parseInt(E,10)+1)*12+_;return O(i,0,127)}function J(C,t=!1){const E=t?["C","Db","D","Eb","E","F","Gb","G","Ab","A","Bb","B"]:["C","C#","D","D#","E","F","F#","G","G#","A","A#","B"],_=Math.floor(C/12)-1;return`${E[C%12]}${_}`}function j(C){const t=69+12*Math.log2(C/440);return O(Math.round(t),0,127)}function k(C){return 440*2**((C-69)/12)}function V(C){return{0:"Bank Select",1:"Modulation",2:"Breath Controller",4:"Foot Controller",5:"Portamento Time",7:"Volume",8:"Balance",10:"Pan",11:"Expression",64:"Sustain Pedal",65:"Portamento",66:"Sostenuto",67:"Soft Pedal",68:"Legato",71:"Resonance",72:"Release Time",73:"Attack Time",74:"Cutoff",75:"Decay Time",76:"Vibrato Rate",77:"Vibrato Depth",78:"Vibrato Delay",84:"Portamento Control",91:"Reverb",92:"Tremolo",93:"Chorus",94:"Detune",95:"Phaser",120:"All Sound Off",121:"Reset All Controllers",123:"All Notes Off"}[C]||`CC ${C}`}function v(C){const t=O(Math.round(C),0,16383);return{msb:t>>7&127,lsb:t&127}}function w(C,t){return O(C,0,127)<<7|O(t,0,127)}function B(C,t,s,e=!1){const E=(C-t)/(s-t),i=(e?1-E:E)*16383;return v(i)}function X(C,t,s,e,E=!1){let i=w(C,t)/16383;return E&&(i=1-i),s+i*(e-s)}class b{constructor(){this.events=new Map}on(t,s){return this.events.has(t)||this.events.set(t,[]),this.events.get(t).push(s),()=>this.off(t,s)}once(t,s){const e=(...E)=>{s(...E),this.off(t,e)};this.on(t,e)}off(t,s){if(!this.events.has(t))return;const e=this.events.get(t),E=e.indexOf(s);E>-1&&e.splice(E,1),e.length===0&&this.events.delete(t)}emit(t,s){if(!this.events.has(t))return;[...this.events.get(t)].forEach(E=>{try{E(s)}catch(_){console.error(`Error in event handler for "${t}":`,_)}})}removeAllListeners(t){t?this.events.delete(t):this.events.clear()}}const U={DEVICE_CHANGE:"device-change",IN_DEV_CONNECTED:"in-dev-connected",IN_DEV_DISCONNECTED:"in-dev-disconnected",OUT_DEV_CONNECTED:"out-dev-connected",OUT_DEV_DISCONNECTED:"out-dev-disconnected"};class Y extends b{constructor(t={}){super(),this.options={sysex:!1,...t},this.midiAccess=null,this.output=null,this.input=null}async requestAccess(){if(!navigator.requestMIDIAccess)throw new g("Web MIDI API is not supported in this browser","unsupported");try{this.midiAccess=await navigator.requestMIDIAccess({sysex:this.options.sysex}),this.midiAccess.onstatechange=t=>{const s=t.port,e=t.port.state;this.emit(U.DEVICE_CHANGE,{port:s,state:e,type:s.type,device:{id:s.id,name:s.name,manufacturer:s.manufacturer||"Unknown"}}),e==="disconnected"?s.type==="input"?(this.emit(U.IN_DEV_DISCONNECTED,{device:s}),this.input&&this.input.id===s.id&&(this.input=null)):s.type==="output"&&(this.emit(U.OUT_DEV_DISCONNECTED,{device:s}),this.output&&this.output.id===s.id&&(this.output=null)):e==="connected"&&(s.type==="input"?this.emit(U.IN_DEV_CONNECTED,{device:s}):s.type==="output"&&this.emit(U.OUT_DEV_CONNECTED,{device:s}))}}catch(t){throw t.name==="SecurityError"?new g("MIDI access denied. SysEx requires user permission.","denied"):new g(`Failed to get MIDI access: ${t.message}`,"failed")}}async connect(t){if(!this.midiAccess)throw new G("MIDI access not initialized. Call requestAccess() first.");const s=Array.from(this.midiAccess.outputs.values());if(s.length===0)throw new L("No MIDI output devices available","output");if(t===void 0){this.output=s[0];return}if(typeof t=="number"){if(t<0||t>=s.length)throw new L(`Output index ${t} out of range (0-${s.length-1})`,"output",t);this.output=s[t];return}if(this.output=s.find(e=>e.name===t||e.id===t),!this.output){const e=s.map(E=>E.name).join(", ");throw new L(`MIDI output "${t}" not found. Available: ${e}`,"output",t)}}async connectInput(t,s){if(!this.midiAccess)throw new G("MIDI access not initialized. Call requestAccess() first.");if(typeof s!="function")throw new R("onMessage callback must be a function","callback");const e=Array.from(this.midiAccess.inputs.values());if(e.length===0)throw new L("No MIDI input devices available","input");if(this.input&&(this.input.onmidimessage=null),t===void 0)this.input=e[0];else if(typeof t=="number"){if(t<0||t>=e.length)throw new L(`Input index ${t} out of range (0-${e.length-1})`,"input",t);this.input=e[t]}else if(this.input=e.find(E=>E.name===t||E.id===t),!this.input){const E=e.map(_=>_.name).join(", ");throw new L(`MIDI input "${t}" not found. Available: ${E}`,"input",t)}this.input.onmidimessage=E=>{s(E)}}disconnectOutput(){this.output=null}disconnectInput(){this.input&&(this.input.onmidimessage=null,this.input=null)}disconnect(){this.disconnectOutput(),this.disconnectInput()}isConnected(){return this.output!==null}getCurrentOutput(){return this.output?{id:this.output.id,name:this.output.name,manufacturer:this.output.manufacturer||"Unknown"}:null}getCurrentInput(){return this.input?{id:this.input.id,name:this.input.name,manufacturer:this.input.manufacturer||"Unknown"}:null}getOutputs(){if(!this.midiAccess)return[];const t=[];return this.midiAccess.outputs.forEach(s=>{s.state==="connected"&&t.push({id:s.id,name:s.name,manufacturer:s.manufacturer||"Unknown"})}),t}getInputs(){if(!this.midiAccess)return[];const t=[];return this.midiAccess.inputs.forEach(s=>{s.state==="connected"&&t.push({id:s.id,name:s.name,manufacturer:s.manufacturer||"Unknown"})}),t}send(t,s=null){if(!this.output){console.warn("No MIDI output connected. Call connect() first.");return}try{const e=new Uint8Array(t);s===null?this.output.send(e):this.output.send(e,s)}catch(e){console.error("Failed to send MIDI message:",e)}}sendSysEx(t,s=!1){if(!this.options.sysex){console.warn("SysEx not enabled. Initialize with sysex: true");return}let e;s?e=[240,...t,247]:e=t,this.send(e)}}const o={READY:"ready",ERROR:"error",DESTROYED:"destroyed",DEV_OUT_CONNECTED:"dev-out-connected",DEV_OUT_DISCONNECTED:"dev-out-disconnected",DEV_IN_CONNECTED:"dev-in-connected",DEV_IN_DISCONNECTED:"dev-in-disconnected",CH_CC_SEND:"ch-cc-send",CH_CC_RECV:"ch-cc-recv",CH_NOTE_ON_SEND:"ch-note-on-send",CH_NOTE_ON_RECV:"ch-note-on-recv",CH_NOTE_OFF_SEND:"ch-note-off-send",CH_NOTE_OFF_RECV:"ch-note-off-recv",CH_PC_SEND:"ch-pc-send",CH_PC_RECV:"ch-pc-recv",CH_PITCH_BEND_SEND:"ch-pitch-bend-send",CH_PITCH_BEND_RECV:"ch-pitch-bend-recv",CH_MONO_PRESS_SEND:"ch-mono-press-send",CH_MONO_PRESS_RECV:"ch-mono-press-recv",CH_POLY_PRESS_SEND:"ch-poly-press-send",CH_POLY_PRESS_RECV:"ch-poly-press-recv",CH_ALL_SOUNDS_OFF_SEND:"ch-all-sounds-off-send",CH_RESET_CONTROLLERS_SEND:"ch-reset-controllers-send",CH_LOCAL_CONTROL_SEND:"ch-local-control-send",CH_ALL_NOTES_OFF_SEND:"ch-all-notes-off-send",CH_OMNI_OFF_SEND:"ch-omni-off-send",CH_OMNI_ON_SEND:"ch-omni-on-send",CH_MONO_ON_SEND:"ch-mono-on-send",CH_POLY_ON_SEND:"ch-poly-on-send",SYS_EX_SEND:"sys-ex-send",SYS_EX_RECV:"sys-ex-recv",SYS_CLOCK_RECV:"sys-clock-recv",SYS_START_RECV:"sys-start-recv",SYS_CONTINUE_RECV:"sys-continue-recv",SYS_STOP_RECV:"sys-stop-recv",SYS_MTC_RECV:"sys-mtc-recv",SYS_SONG_POS_RECV:"sys-song-pos-recv",SYS_SONG_SEL_RECV:"sys-song-sel-recv",SYS_TUNE_REQ_RECV:"sys-tune-req-recv",SYS_ACT_SENSE_RECV:"sys-act-sense-recv",SYS_RESET_RECV:"sys-reset-recv",MIDI_RAW:"midi-raw",PATCH_SAVED:"patch-saved",PATCH_LOADED:"patch-loaded",PATCH_DELETED:"patch-deleted"};class x extends b{constructor(t={}){super(),this.options={inputChannel:1,outputChannel:1,autoConnect:!0,sysex:!1,...t},this.connection=null,this.bindings=new Map,this.state={controlChange:new Map,programChange:new Map,pitchBend:new Map,monoPressure:new Map,polyPressure:new Map},this.initialized=!1,this._initNamespaces()}async init(){if(this.initialized){console.warn("MIDI Controller already initialized");return}try{this.connection=new Y({sysex:this.options.sysex}),await this.connection.requestAccess(),this.connection.on(U.DEVICE_CHANGE,async({state:t,type:s,device:e})=>{try{if(t==="connected")s==="output"?this.emit(o.DEV_OUT_CONNECTED,e):s==="input"&&this.emit(o.DEV_IN_CONNECTED,e);else if(t==="disconnected"){if(s==="output"&&e){const E=this.connection.getCurrentOutput();E&&E.id===e.id?await this._disconnectOutput():this.emit(o.DEV_OUT_DISCONNECTED,e)}if(s==="input"&&e){const E=this.connection.getCurrentInput();E&&E.id===e.id?await this._disconnectInput():this.emit(o.DEV_IN_DISCONNECTED,e)}}}catch(E){console.error("Error in device change handler:",E),this.emit(o.ERROR,E)}}),this.options.autoConnect&&await this.connection.connect(this.options.output),this.options.input!==void 0&&await this._connectInput(this.options.input),this.initialized=!0,this.emit(o.READY,this),this.options.onReady?.(this)}catch(t){throw this.emit(o.ERROR,t),this.options.onError?.(t),t}}_initNamespaces(){this.device={connect:this._connect.bind(this),disconnect:this._disconnect.bind(this),connectInput:this._connectInput.bind(this),disconnectInput:this._disconnectInput.bind(this),connectOutput:this._connectOutput.bind(this),disconnectOutput:this._disconnectOutput.bind(this),getCurrentOutput:this._getCurrentOutput.bind(this),getCurrentInput:this._getCurrentInput.bind(this),getOutputs:this._getOutputs.bind(this),getInputs:this._getInputs.bind(this)},this.channel={sendNoteOn:this._sendNoteOn.bind(this),sendNoteOff:this._sendNoteOff.bind(this),sendCC:this._sendCC.bind(this),getCC:this._getCC.bind(this),sendPC:this._sendPC.bind(this),getPC:this._getPC.bind(this),sendPitchBend:this._sendPitchBend.bind(this),getPitchBend:this._getPitchBend.bind(this),sendMonoPressure:this._sendMonoPressure.bind(this),getMonoPressure:this._getMonoPressure.bind(this),sendPolyPressure:this._sendPolyPressure.bind(this),getPolyPressure:this._getPolyPressure.bind(this),allSoundsOff:this._allSoundsOff.bind(this),resetControllers:this._resetControllers.bind(this),localControl:this._localControl.bind(this),allNotesOff:this._allNotesOff.bind(this),omniOff:this._omniOff.bind(this),omniOn:this._omniOn.bind(this),monoOn:this._monoOn.bind(this),polyOn:this._polyOn.bind(this)},this.system={sendEx:(function(t,s=!1){return this._sendSysEx(t,s)}).bind(this),sendClock:this._sendClock.bind(this),start:this._sendStart.bind(this),continue:this._sendContinue.bind(this),stop:this._sendStop.bind(this),sendMTC:this._sendMTC.bind(this),sendSongPosition:this._sendSongPosition.bind(this),sendSongSelect:this._sendSongSelect.bind(this),sendTuneRequest:this._sendTuneRequest.bind(this),sendActiveSensing:this._sendActiveSensing.bind(this),sendSystemReset:this._sendSystemReset.bind(this)},this.patch={get:this._getPatch.bind(this),set:this._setPatch.bind(this),save:this._savePatch.bind(this),load:this._loadPatch.bind(this),delete:this._deletePatch.bind(this),list:this._listPatches.bind(this)}}bind(t,s,e={}){if(!t)return console.warn("Cannot bind: element is null or undefined"),()=>{};const E=this._createBinding(t,s,e);return this.bindings.set(t,E),this.initialized&&this.connection?.isConnected()&&E.handler({target:t}),()=>this.unbind(t)}_createBinding(t,s,e={}){const{min:E=parseFloat(t.getAttribute("min"))||0,max:_=parseFloat(t.getAttribute("max"))||127,channel:i,invert:r=!1,onInput:u=void 0}=s,{debounce:S=0}=e,P={...s,min:E,max:_,invert:r,onInput:u};if(i!==void 0&&(P.channel=i),s.is14Bit){const{msb:T,lsb:I}=s,f=H=>{const z=parseFloat(H.target.value);if(Number.isNaN(z))return;const{msb:ht,lsb:Nt}=B(z,E,_,r),q=i||this.options.outputChannel;this._sendCC(T,ht,q),this._sendCC(I,Nt,q)};let K=null;const D=S>0?H=>{K&&clearTimeout(K),K=setTimeout(()=>{f(H),K=null},S)}:f;return t.addEventListener("input",D),t.addEventListener("change",D),{element:t,config:P,handler:f,destroy:()=>{K&&clearTimeout(K),t.removeEventListener("input",D),t.removeEventListener("change",D)}}}const{cc:a}=s,A=T=>{const I=parseFloat(T.target.value);if(Number.isNaN(I))return;const f=y(I,E,_,r),K=i===void 0?this.options.outputChannel:i;this._sendCC(a,f,K)};let l=null;const c=S>0?T=>{l&&clearTimeout(l),l=setTimeout(()=>{A(T),l=null},S)}:A;return t.addEventListener("input",c),t.addEventListener("change",c),{element:t,config:P,handler:A,destroy:()=>{l&&clearTimeout(l),t.removeEventListener("input",c),t.removeEventListener("change",c)}}}unbind(t){const s=this.bindings.get(t);s&&(s.destroy(),this.bindings.delete(t))}async destroy(){for(const t of this.bindings.values())t.destroy();this.bindings.clear(),this.state.controlChange.clear(),this.state.programChange.clear(),this.state.pitchBend.clear(),this.state.monoPressure.clear(),this.state.polyPressure.clear(),await this._disconnect(),this.initialized=!1,this.emit(o.DESTROYED),this.removeAllListeners()}async _connect(t){t?await this.connection.connect(t):this.options.output!==void 0?await this.connection.connect(this.options.output):this.options.autoConnect&&await this.connection.connect()}async _disconnect(){this.connection.disconnect()}async _connectInput(t){await this.connection.connectInput(t,s=>{this._handleMIDIMessage(s)}),this.emit(o.DEV_IN_CONNECTED,this.connection.getCurrentInput())}async _disconnectInput(){const t=this.connection.getCurrentInput();this.connection.disconnectInput(),this.emit(o.DEV_IN_DISCONNECTED,t)}async _connectOutput(t){await this.connection.connect(t),this.emit(o.DEV_OUT_CONNECTED,this.connection.getCurrentOutput())}async _disconnectOutput(){const t=this.connection.getCurrentOutput();this.connection.disconnectOutput(),this.emit(o.DEV_OUT_DISCONNECTED,t)}_getCurrentOutput(){return this.connection?.getCurrentOutput()||null}_getCurrentInput(){return this.connection?.getCurrentInput()||null}_getOutputs(){return this.connection?.getOutputs()||[]}_getInputs(){return this.connection?.getInputs()||[]}send(t){if(!this.initialized){console.warn("MIDI not initialized. Call init() first.");return}this.connection.send(t)}_sendNoteOn(t,s=64,e=this.options.outputChannel){if(!this.initialized)return;t=O(Math.round(t),0,127),s=O(Math.round(s),0,127),e=O(Math.round(e),1,16);const E=144+(e-1);this.connection.send([E,t,s]),this.emit(o.CH_NOTE_ON_SEND,{note:t,velocity:s,channel:e})}_sendNoteOff(t,s=this.options.outputChannel,e=0){if(!this.initialized)return;t=O(Math.round(t),0,127),e=O(Math.round(e),0,127),s=O(Math.round(s),1,16);const E=144+(s-1);this.connection.send([E,t,e]),this.emit(o.CH_NOTE_OFF_SEND,{note:t,channel:s,velocity:e})}_sendCC(t,s,e=this.options.outputChannel){if(!this.initialized){console.warn("MIDI not initialized. Call init() first.");return}t=O(Math.round(t),0,127),s=O(Math.round(s),0,127),e=O(Math.round(e),1,16);const E=176+(e-1);this.connection.send([E,t,s]);const _=`${e}:${t}`;this.state.controlChange.set(_,s),this.emit(o.CH_CC_SEND,{cc:t,value:s,channel:e})}_sendPC(t,s=this.options.outputChannel){if(!this.initialized)return;t=O(Math.round(t),0,127),s=O(Math.round(s),1,16);const e=192+(s-1);this.connection.send([e,t]),this.state.programChange.set(s.toString(),t),this.emit(o.CH_PC_SEND,{program:t,channel:s})}_getPC(t=this.options.inputChannel){return this.state.programChange.get(t.toString())}_getCC(t,s=this.options.inputChannel){const e=`${s}:${t}`;return this.state.controlChange.get(e)}_sendPitchBend(t,s=this.options.outputChannel){if(!this.initialized)return;t=O(Math.round(t),0,16383),s=O(Math.round(s),1,16);const e=224+(s-1),E=t&127,_=t>>7&127;this.connection.send([e,E,_]),this.state.pitchBend.set(s.toString(),t),this.emit(o.CH_PITCH_BEND_SEND,{value:t,channel:s})}_getPitchBend(t=this.options.inputChannel){return this.state.pitchBend.get(t.toString())}_sendMonoPressure(t,s=this.options.outputChannel){if(!this.initialized)return;t=O(Math.round(t),0,127),s=O(Math.round(s),1,16);const e=208+(s-1);this.connection.send([e,t]),this.state.monoPressure.set(s.toString(),t),this.emit(o.CH_MONO_PRESS_SEND,{pressure:t,channel:s})}_getMonoPressure(t=this.options.inputChannel){return this.state.monoPressure.get(t.toString())}_sendPolyPressure(t,s,e=this.options.outputChannel){if(!this.initialized)return;t=O(Math.round(t),0,127),s=O(Math.round(s),0,127),e=O(Math.round(e),1,16);const E=160+(e-1);this.connection.send([E,t,s]);const _=`${e}:${t}`;this.state.polyPressure.set(_,s),this.emit(o.CH_POLY_PRESS_SEND,{note:t,pressure:s,channel:e})}_getPolyPressure(t,s=this.options.inputChannel){const e=`${s}:${t}`;return this.state.polyPressure.get(e)}_allSoundsOff(t){if(!this.initialized){console.warn("MIDI not initialized. Call init() first.");return}if(t!==void 0){t=O(Math.round(t),1,16);const s=176+(t-1);this.connection.send([s,120,0]),this.emit(o.CH_ALL_SOUNDS_OFF_SEND,{channel:t})}else{for(let s=1;s<=16;s++){const e=176+(s-1);this.connection.send([e,120,0])}this.emit(o.CH_ALL_SOUNDS_OFF_SEND,{channel:null})}}_resetControllers(t){if(!this.initialized){console.warn("MIDI not initialized. Call init() first.");return}if(t!==void 0){t=O(Math.round(t),1,16);const s=176+(t-1);this.connection.send([s,121,0]),this.emit(o.CH_RESET_CONTROLLERS_SEND,{channel:t})}else{for(let s=1;s<=16;s++){const e=176+(s-1);this.connection.send([e,121,0])}this.emit(o.CH_RESET_CONTROLLERS_SEND,{channel:null})}}_localControl(t,s){if(!this.initialized){console.warn("MIDI not initialized. Call init() first.");return}const e=t?127:0;if(s!==void 0){s=O(Math.round(s),1,16);const E=176+(s-1);this.connection.send([E,122,e]),this.emit(o.CH_LOCAL_CONTROL_SEND,{enabled:t,channel:s})}else{for(let E=1;E<=16;E++){const _=176+(E-1);this.connection.send([_,122,e])}this.emit(o.CH_LOCAL_CONTROL_SEND,{enabled:t,channel:null})}}_allNotesOff(t){if(!this.initialized){console.warn("MIDI not initialized. Call init() first.");return}if(t!==void 0){t=O(Math.round(t),1,16);const s=176+(t-1);this.connection.send([s,123,0]),this.emit(o.CH_ALL_NOTES_OFF_SEND,{channel:t})}else{for(let s=1;s<=16;s++){const e=176+(s-1);this.connection.send([e,123,0])}this.emit(o.CH_ALL_NOTES_OFF_SEND,{channel:null})}}_omniOff(t){if(!this.initialized){console.warn("MIDI not initialized. Call init() first.");return}if(t!==void 0){t=O(Math.round(t),1,16);const s=176+(t-1);this.connection.send([s,124,0]),this.emit(o.CH_OMNI_OFF_SEND,{channel:t})}else{for(let s=1;s<=16;s++){const e=176+(s-1);this.connection.send([e,124,0])}this.emit(o.CH_OMNI_OFF_SEND,{channel:null})}}_omniOn(t){if(!this.initialized){console.warn("MIDI not initialized. Call init() first.");return}if(t!==void 0){t=O(Math.round(t),1,16);const s=176+(t-1);this.connection.send([s,125,0]),this.emit(o.CH_OMNI_ON_SEND,{channel:t})}else{for(let s=1;s<=16;s++){const e=176+(s-1);this.connection.send([e,125,0])}this.emit(o.CH_OMNI_ON_SEND,{channel:null})}}_monoOn(t=1,s){if(!this.initialized){console.warn("MIDI not initialized. Call init() first.");return}if(t=Math.max(0,Math.min(16,Math.round(t))),s!==void 0){s=O(Math.round(s),1,16);const e=176+(s-1);this.connection.send([e,126,t]),this.emit(o.CH_MONO_ON_SEND,{channels:t,channel:s})}else{for(let e=1;e<=16;e++){const E=176+(e-1);this.connection.send([E,126,t])}this.emit(o.CH_MONO_ON_SEND,{channels:t,channel:null})}}_polyOn(t){if(!this.initialized){console.warn("MIDI not initialized. Call init() first.");return}if(t!==void 0){t=O(Math.round(t),1,16);const s=176+(t-1);this.connection.send([s,127,0]),this.emit(o.CH_POLY_ON_SEND,{channel:t})}else{for(let s=1;s<=16;s++){const e=176+(s-1);this.connection.send([e,127,0])}this.emit(o.CH_POLY_ON_SEND,{channel:null})}}_sendSysEx(t,s=!1){if(!this.initialized){console.warn("MIDI not initialized. Call init() first.");return}if(!this.options.sysex){console.warn("SysEx not enabled. Initialize with sysex: true");return}this.connection.sendSysEx(t,s),this.emit(o.SYS_EX_SEND,{data:t,includeWrapper:s})}_sendClock(){if(!this.initialized){console.warn("MIDI not initialized. Call init() first.");return}this.connection.send([248])}_sendStart(){if(!this.initialized){console.warn("MIDI not initialized. Call init() first.");return}this.connection.send([250])}_sendContinue(){if(!this.initialized){console.warn("MIDI not initialized. Call init() first.");return}this.connection.send([251])}_sendStop(){if(!this.initialized){console.warn("MIDI not initialized. Call init() first.");return}this.connection.send([252])}_sendMTC(t){if(!this.initialized){console.warn("MIDI not initialized. Call init() first.");return}t=O(Math.round(t),0,127),this.connection.send([241,t])}_sendSongPosition(t){if(!this.initialized){console.warn("MIDI not initialized. Call init() first.");return}t=O(Math.round(t),0,16383);const s=t&127,e=t>>7&127;this.connection.send([242,s,e])}_sendSongSelect(t){if(!this.initialized){console.warn("MIDI not initialized. Call init() first.");return}t=O(Math.round(t),0,127),this.connection.send([243,t])}_sendTuneRequest(){if(!this.initialized){console.warn("MIDI not initialized. Call init() first.");return}this.connection.send([246])}_sendActiveSensing(){if(!this.initialized){console.warn("MIDI not initialized. Call init() first.");return}this.connection.send([254])}_sendSystemReset(){if(!this.initialized){console.warn("MIDI not initialized. Call init() first.");return}this.connection.send([255])}_handleMIDIMessage(t){const[s,e,E]=t.data,_=s&240,i=(s&15)+1;if(s===248){this.emit(o.SYS_CLOCK_RECV,{timestamp:t.midiwire});return}if(s===250){this.emit(o.SYS_START_RECV,{timestamp:t.midiwire});return}if(s===251){this.emit(o.SYS_CONTINUE_RECV,{timestamp:t.midiwire});return}if(s===252){this.emit(o.SYS_STOP_RECV,{timestamp:t.midiwire});return}if(s===254){this.emit(o.SYS_ACT_SENSE_RECV,{timestamp:t.midiwire});return}if(s===255){this.emit(o.SYS_RESET_RECV,{timestamp:t.midiwire});return}if(s===240){this.emit(o.SYS_EX_RECV,{data:Array.from(t.data),timestamp:t.midiwire});return}if(s===241){this.emit(o.SYS_MTC_RECV,{data:e,timestamp:t.midiwire});return}if(s===242){const r=e+(E<<7);this.emit(o.SYS_SONG_POS_RECV,{position:r,timestamp:t.midiwire});return}if(s===243){this.emit(o.SYS_SONG_SEL_RECV,{song:e,timestamp:t.midiwire});return}if(s===246){this.emit(o.SYS_TUNE_REQ_RECV,{timestamp:t.midiwire});return}if(s===247){this.emit(o.MIDI_RAW,{status:s,data:[e,E],channel:i,timestamp:t.midiwire});return}if(_===176){const r=`${i}:${e}`;this.state.controlChange.set(r,E),this.emit(o.CH_CC_RECV,{cc:e,value:E,channel:i});return}if(_===192){this.state.programChange.set(i.toString(),e),this.emit(o.CH_PC_RECV,{program:e,channel:i});return}if(_===224){const r=e+(E<<7);this.state.pitchBend.set(i.toString(),r),this.emit(o.CH_PITCH_BEND_RECV,{value:r,channel:i});return}if(_===208){this.state.monoPressure.set(i.toString(),e),this.emit(o.CH_MONO_PRESS_RECV,{pressure:e,channel:i});return}if(_===160){const r=`${i}:${e}`;this.state.polyPressure.set(r,E),this.emit(o.CH_POLY_PRESS_RECV,{note:e,pressure:E,channel:i});return}if(_===144&&E>0){this.emit(o.CH_NOTE_ON_RECV,{note:e,velocity:E,channel:i});return}if(_===128||_===144&&E===0){this.emit(o.CH_NOTE_OFF_RECV,{note:e,channel:i});return}this.emit(o.MIDI_RAW,{status:s,data:[e,E],channel:i,timestamp:t.midiwire})}_getPatch(t="Unnamed Patch"){const s={name:t,device:this._getCurrentOutput()?.name||null,timestamp:new Date().toISOString(),version:"1.0",channels:{},settings:{}};for(const[e,E]of this.state.controlChange.entries()){const[_,i]=e.split(":").map(Number);s.channels[_]||(s.channels[_]={ccs:{},notes:{}}),s.channels[_].ccs[i]=E}for(const[e,E]of this.state.programChange.entries()){const _=parseInt(e,10);s.channels[_]||(s.channels[_]={ccs:{},notes:{}}),s.channels[_].program=E}for(const[e,E]of this.state.pitchBend.entries()){const _=parseInt(e,10);s.channels[_]||(s.channels[_]={ccs:{},notes:{}}),s.channels[_].pitchBend=E}for(const[e,E]of this.state.monoPressure.entries()){const _=parseInt(e,10);s.channels[_]||(s.channels[_]={ccs:{},notes:{}}),s.channels[_].monoPressure=E}for(const[e,E]of this.state.polyPressure.entries()){const[_,i]=e.split(":").map(Number),r=parseInt(_,10);s.channels[r]||(s.channels[r]={ccs:{},notes:{}}),s.channels[r].polyPressure||(s.channels[r].polyPressure={}),s.channels[r].polyPressure[i]=E}for(const[e,E]of this.bindings.entries()){const{config:_}=E;if(_.cc){const i=`cc${_.cc}`;s.settings[i]={min:_.min,max:_.max,invert:_.invert||!1,is14Bit:_.is14Bit||!1,label:e.getAttribute?.("data-midi-label")||null,elementId:e.id||null}}}return s}async _setPatch(t){if(!t||!t.channels)throw new R("Invalid patch format","patch");const s=t.version||"1.0";s==="1.0"?await this._applyPatchV1(t):(console.warn(`Unknown patch version: ${s}. Attempting to apply as v1.0`),await this._applyPatchV1(t)),this.emit(o.PATCH_LOADED,{patch:t})}async _applyPatchV1(t){for(const[s,e]of Object.entries(t.channels)){const E=parseInt(s,10);if(e.ccs)for(const[_,i]of Object.entries(e.ccs)){const r=parseInt(_,10);this._sendCC(r,i,E)}if(e.program!==void 0&&this._sendPC(e.program,E),e.pitchBend!==void 0&&this._sendPitchBend(e.pitchBend,E),e.monoPressure!==void 0&&this._sendMonoPressure(e.monoPressure,E),e.polyPressure)for(const[_,i]of Object.entries(e.polyPressure)){const r=parseInt(_,10);this._sendPolyPressure(r,i,E)}if(e.notes)for(const[_,i]of Object.entries(e.notes)){const r=parseInt(_,10);i>0?this._sendNoteOn(r,i,E):this._sendNoteOff(r,E)}}if(t.settings)for(const[s,e]of Object.entries(t.settings))for(const[E,_]of this.bindings.entries())_.config.cc?.toString()===s.replace("cc","")&&(E.min!==void 0&&e.min!==void 0&&(E.min=String(e.min)),E.max!==void 0&&e.max!==void 0&&(E.max=String(e.max)));for(const[s,e]of this.bindings.entries()){const{config:E}=e;if(E.cc!==void 0){const _=E.channel||this.options.inputChannel,i=t.channels[_];if(i?.ccs){const r=i.ccs[E.cc];if(r!==void 0){const u=E.min!==void 0?E.min:parseFloat(s.getAttribute?.("min"))||0,S=E.max!==void 0?E.max:parseFloat(s.getAttribute?.("max"))||127,P=E.invert||!1;let a;P?a=S-r/127*(S-u):a=u+r/127*(S-u),E.onInput&&typeof E.onInput=="function"?E.onInput(a):(s.value=a,s.dispatchEvent(new Event("input",{bubbles:!0})))}}}}}_savePatch(t,s=null){const e=s||this._getPatch(t),E=`midiwire_patch_${t}`;try{return localStorage.setItem(E,JSON.stringify(e)),this.emit(o.PATCH_SAVED,{name:t,patch:e}),E}catch(_){throw console.error("Failed to save patch:",_),_}}_loadPatch(t){const s=`midiwire_patch_${t}`;try{const e=localStorage.getItem(s);if(!e)return null;const E=JSON.parse(e);return this.emit(o.PATCH_LOADED,{name:t,patch:E}),E}catch(e){return console.error("Failed to load patch:",e),null}}_deletePatch(t){const s=`midiwire_patch_${t}`;try{return localStorage.removeItem(s),this.emit(o.PATCH_DELETED,{name:t}),!0}catch(e){return console.error("Failed to delete patch:",e),!1}}_listPatches(){const t=[];try{for(let s=0;s<localStorage.length;s++){const e=localStorage.key(s);if(e?.startsWith("midiwire_patch_")){const E=e.replace("midiwire_patch_",""),_=this._loadPatch(E);_&&t.push({name:E,patch:_})}}}catch(s){console.error("Failed to list patches:",s)}return t.sort((s,e)=>s.name.localeCompare(e.name))}}class ${constructor(t={}){this.midi=t.midiController||null,this.onStatusUpdate=t.onStatusUpdate||(()=>{}),this.onConnectionUpdate=t.onConnectionUpdate||(()=>{}),this.channel=t.channel||1,this.currentOutput=null,this.currentInput=null,this.isConnecting=!1}setMIDI(t){this.midi=t}setupDeviceListeners(t,s={}){this.midi&&(this.midi.on(o.DEV_OUT_CONNECTED,e=>{this.updateStatus(`Output device connected: ${e?.name||"Unknown"}`,"connected"),t&&t()}),this.midi.on(o.DEV_OUT_DISCONNECTED,e=>{this.updateStatus(`Output device disconnected: ${e?.name||"Unknown"}`,"error"),this.currentOutput&&e?.name===this.currentOutput.name&&(this.currentOutput=null,this.updateConnectionStatus(),s.output&&(s.output.value="")),t&&t()}),this.midi.on(o.DEV_IN_CONNECTED,e=>{this.updateStatus(`Input device connected: ${e?.name||"Unknown"}`,"connected"),t&&t()}),this.midi.on(o.DEV_IN_DISCONNECTED,e=>{this.updateStatus(`Input device disconnected: ${e?.name||"Unknown"}`,"error"),s.input&&(s.input.value=""),t&&t()}))}updateStatus(t,s=""){this.onStatusUpdate(t,s)}updateConnectionStatus(){this.onConnectionUpdate(this.currentOutput,this.currentInput,this.midi)}async setupSelectors(t={},s={}){if(!this.midi)throw new Error("MIDI controller not initialized. Call setMIDI() first.");const e={},{output:E,input:_,channel:i}=t,r=this._resolveSelector(E),u=this._resolveSelector(_),S=this._resolveSelector(i);if(r){e.output=r,this.setupDeviceListeners(async()=>{await this._populateOutputDeviceList(r)},e),await this._populateOutputDeviceList(r);const P=s.onConnect?async(A,l)=>s.onConnect({midi:A,device:l,type:"output"}):void 0,a=s.onDisconnect?async A=>s.onDisconnect({midi:A,type:"output"}):void 0;this._connectOutputDeviceSelection(r,P,a)}if(u){e.input=u,this.setupDeviceListeners(async()=>{await this._populateInputDeviceList(u)},e),await this._populateInputDeviceList(u);const P=s.onConnect?async(A,l)=>s.onConnect({midi:A,device:l,type:"input"}):void 0,a=s.onDisconnect?async A=>s.onDisconnect({midi:A,type:"input"}):void 0;this._connectInputDeviceSelection(u,P,a)}return S&&this._connectChannelSelection(S,"output"),this.midi}_resolveSelector(t){if(typeof t=="string"){const s=document.querySelector(t);return s||console.warn(`MIDIDeviceManager: Selector "${t}" not found`),s}return t||null}_getOutputDevices(){return this.midi?this.midi.device.getOutputs():[]}_getInputDevices(){return this.midi?this.midi.device.getInputs():[]}_connectOutputDeviceSelection(t,s,e){!t||!this.midi||t.addEventListener("change",async E=>{if(this.isConnecting)return;this.isConnecting=!0;const _=E.target.value;if(!_){this.currentOutput&&this.midi&&(await this.midi.device.disconnectOutput(),this.currentOutput=null,this.updateStatus("Output device disconnected",""),this.updateConnectionStatus()),this.isConnecting=!1,e&&await e(this.midi);return}try{if(await this.midi.device.connectOutput(parseInt(_,10)),this.currentOutput=this.midi.device.getCurrentOutput(),this.currentOutput){const r=this.midi.device.getOutputs().findIndex(u=>u.id===this.currentOutput.id);r!==-1&&(t.value=r.toString())}this.updateConnectionStatus(),s&&await s(this.midi,this.currentOutput)}catch(i){this.updateStatus(`Output connection failed: ${i.message}`,"error")}finally{this.isConnecting=!1}})}_connectInputDeviceSelection(t,s,e){!t||!this.midi||t.addEventListener("change",async E=>{const _=E.target.value;if(!_){this.midi&&(await this.midi.device.disconnectInput(),this.updateStatus("Input device disconnected",""),this.updateConnectionStatus()),e&&await e(this.midi);return}if(!this.isConnecting){this.isConnecting=!0;try{await this.midi.device.connectInput(parseInt(_,10));const i=this.midi.device.getCurrentInput();this.updateConnectionStatus(),s&&await s(this.midi,i)}catch(i){this.updateStatus(`Input connection failed: ${i.message}`,"error")}finally{this.isConnecting=!1}}})}_populateDeviceList(t,s,e,E,_){if(s.length>0){if(t.innerHTML='<option value="">Select a device</option>'+s.map((i,r)=>`<option value="${r}">${i.name}</option>`).join(""),e){const i=s.findIndex(r=>r.name===e.name);i!==-1?t.value=i.toString():(t.value="",_&&(this.currentOutput=null,this.updateConnectionStatus()))}else t.value="";t.disabled=!1,_&&!this.currentOutput&&this.updateStatus("Select a device")}else t.innerHTML='<option value="">No devices connected</option>',t.disabled=!0,_&&this.updateStatus("No devices connected","error");E&&E()}async _populateOutputDeviceList(t,s){if(!t||!this.midi)return;const e=this._getOutputDevices();this._populateDeviceList(t,e,this.currentOutput,s,!0)}async _populateInputDeviceList(t,s){if(!t||!this.midi)return;const e=this._getInputDevices(),E=this.midi.device.getCurrentInput();this._populateDeviceList(t,e,E,s,!1)}_connectChannelSelection(t,s){if(!t||!this.midi)return;const e=s==="input"?"inputChannel":"outputChannel";t.addEventListener("change",E=>{this.midi&&(this.midi.options[e]=parseInt(E.target.value,10),this.updateConnectionStatus())})}}class n{static PACKED_SIZE=128;static PACKED_OP_SIZE=17;static NUM_OPERATORS=6;static PACKED_OP_EG_RATE_1=0;static PACKED_OP_EG_RATE_2=1;static PACKED_OP_EG_RATE_3=2;static PACKED_OP_EG_RATE_4=3;static PACKED_OP_EG_LEVEL_1=4;static PACKED_OP_EG_LEVEL_2=5;static PACKED_OP_EG_LEVEL_3=6;static PACKED_OP_EG_LEVEL_4=7;static PACKED_OP_BREAK_POINT=8;static PACKED_OP_L_SCALE_DEPTH=9;static PACKED_OP_R_SCALE_DEPTH=10;static PACKED_OP_CURVES=11;static PACKED_OP_RATE_SCALING=12;static PACKED_OP_MOD_SENS=13;static PACKED_OP_OUTPUT_LEVEL=14;static PACKED_OP_MODE_FREQ=15;static PACKED_OP_DETUNE_FINE=16;static PACKED_PITCH_EG_RATE_1=102;static PACKED_PITCH_EG_RATE_2=103;static PACKED_PITCH_EG_RATE_3=104;static PACKED_PITCH_EG_RATE_4=105;static PACKED_PITCH_EG_LEVEL_1=106;static PACKED_PITCH_EG_LEVEL_2=107;static PACKED_PITCH_EG_LEVEL_3=108;static PACKED_PITCH_EG_LEVEL_4=109;static OFFSET_ALGORITHM=110;static OFFSET_FEEDBACK=111;static OFFSET_LFO_SPEED=112;static OFFSET_LFO_DELAY=113;static OFFSET_LFO_PM_DEPTH=114;static OFFSET_LFO_AM_DEPTH=115;static OFFSET_LFO_SYNC_WAVE=116;static OFFSET_TRANSPOSE=117;static OFFSET_AMP_MOD_SENS=118;static OFFSET_EG_BIAS_SENS=119;static PACKED_NAME_START=118;static NAME_LENGTH=10;static UNPACKED_SIZE=169;static UNPACKED_OP_SIZE=23;static UNPACKED_OP_EG_RATE_1=0;static UNPACKED_OP_EG_RATE_2=1;static UNPACKED_OP_EG_RATE_3=2;static UNPACKED_OP_EG_RATE_4=3;static UNPACKED_OP_EG_LEVEL_1=4;static UNPACKED_OP_EG_LEVEL_2=5;static UNPACKED_OP_EG_LEVEL_3=6;static UNPACKED_OP_EG_LEVEL_4=7;static UNPACKED_OP_BREAK_POINT=8;static UNPACKED_OP_L_SCALE_DEPTH=9;static UNPACKED_OP_R_SCALE_DEPTH=10;static UNPACKED_OP_L_CURVE=11;static UNPACKED_OP_R_CURVE=12;static UNPACKED_OP_RATE_SCALING=13;static UNPACKED_OP_DETUNE=14;static UNPACKED_OP_AMP_MOD_SENS=15;static UNPACKED_OP_OUTPUT_LEVEL=16;static UNPACKED_OP_MODE=17;static UNPACKED_OP_KEY_VEL_SENS=18;static UNPACKED_OP_FREQ_COARSE=19;static UNPACKED_OP_OSC_DETUNE=20;static UNPACKED_OP_FREQ_FINE=21;static UNPACKED_PITCH_EG_RATE_1=138;static UNPACKED_PITCH_EG_RATE_2=139;static UNPACKED_PITCH_EG_RATE_3=140;static UNPACKED_PITCH_EG_RATE_4=141;static UNPACKED_PITCH_EG_LEVEL_1=142;static UNPACKED_PITCH_EG_LEVEL_2=143;static UNPACKED_PITCH_EG_LEVEL_3=144;static UNPACKED_PITCH_EG_LEVEL_4=145;static UNPACKED_ALGORITHM=146;static UNPACKED_FEEDBACK=147;static UNPACKED_OSC_SYNC=148;static UNPACKED_LFO_SPEED=149;static UNPACKED_LFO_DELAY=150;static UNPACKED_LFO_PM_DEPTH=151;static UNPACKED_LFO_AM_DEPTH=152;static UNPACKED_LFO_KEY_SYNC=153;static UNPACKED_LFO_WAVE=154;static UNPACKED_LFO_PM_SENS=155;static UNPACKED_AMP_MOD_SENS=156;static UNPACKED_TRANSPOSE=157;static UNPACKED_EG_BIAS_SENS=158;static UNPACKED_NAME_START=159;static VCED_SIZE=163;static VCED_HEADER_SIZE=6;static VCED_DATA_SIZE=155;static VCED_SYSEX_START=240;static VCED_YAMAHA_ID=67;static VCED_SUB_STATUS=0;static VCED_FORMAT_SINGLE=0;static VCED_BYTE_COUNT_MSB=1;static VCED_BYTE_COUNT_LSB=27;static VCED_SYSEX_END=247;static MASK_7BIT=127;static MASK_2BIT=3;static MASK_3BIT=7;static MASK_4BIT=15;static MASK_5BIT=31;static MASK_1BIT=1;static TRANSPOSE_CENTER=24;static CHAR_YEN=92;static CHAR_ARROW_RIGHT=126;static CHAR_ARROW_LEFT=127;static CHAR_REPLACEMENT_Y=89;static CHAR_REPLACEMENT_GT=62;static CHAR_REPLACEMENT_LT=60;static CHAR_SPACE=32;static CHAR_MIN_PRINTABLE=32;static CHAR_MAX_PRINTABLE=126;static DEFAULT_EG_RATE=99;static DEFAULT_EG_LEVEL_MAX=99;static DEFAULT_EG_LEVEL_MIN=0;static DEFAULT_BREAK_POINT=60;static DEFAULT_OUTPUT_LEVEL=99;static DEFAULT_PITCH_EG_LEVEL=50;static DEFAULT_LFO_SPEED=35;static DEFAULT_LFO_PM_SENS=3;static DEFAULT_ALGORITHM=0;static DEFAULT_FEEDBACK=0;static MIDI_OCTAVE_OFFSET=-2;static MIDI_BREAK_POINT_OFFSET=21;constructor(t,s=0){if(t.length!==n.PACKED_SIZE)throw new d(`Invalid voice data length: expected ${n.PACKED_SIZE} bytes, got ${t.length}`,"length",t.length);this.index=s,this.data=new Uint8Array(t),this.name=this._extractName(),this._unpackedCache=null}_extractName(){const t=this.data.subarray(n.PACKED_NAME_START,n.PACKED_NAME_START+n.NAME_LENGTH);return Array.from(t).map(e=>{let E=e&n.MASK_7BIT;return E===n.CHAR_YEN&&(E=n.CHAR_REPLACEMENT_Y),E===n.CHAR_ARROW_RIGHT&&(E=n.CHAR_REPLACEMENT_GT),E===n.CHAR_ARROW_LEFT&&(E=n.CHAR_REPLACEMENT_LT),(E<n.CHAR_MIN_PRINTABLE||E>n.CHAR_MAX_PRINTABLE)&&(E=n.CHAR_SPACE),String.fromCharCode(E)}).join("").trim()}getParameter(t){if(t<0||t>=n.PACKED_SIZE)throw new d(`Parameter offset out of range: ${t} (must be 0-${n.PACKED_SIZE-1})`,"offset",t);return this.data[t]&n.MASK_7BIT}getUnpackedParameter(t){if(t<0||t>=n.UNPACKED_SIZE)throw new d(`Unpacked parameter offset out of range: ${t} (must be 0-${n.UNPACKED_SIZE-1})`,"offset",t);return this._unpackedCache||(this._unpackedCache=this.unpack()),this._unpackedCache[t]&n.MASK_7BIT}setParameter(t,s){if(t<0||t>=n.PACKED_SIZE)throw new d(`Parameter offset out of range: ${t} (must be 0-${n.PACKED_SIZE-1})`,"offset",t);this.data[t]=s&n.MASK_7BIT,this._unpackedCache=null,t>=n.PACKED_NAME_START&&t<n.PACKED_NAME_START+n.NAME_LENGTH&&(this.name=this._extractName())}unpack(){const t=this.data,s=new Uint8Array(n.UNPACKED_SIZE);return this._unpackOperators(t,s),this._unpackPitchEG(t,s),this._unpackGlobalParams(t,s),this._unpackName(t,s),s}_unpackOperators(t,s){for(let e=0;e<n.NUM_OPERATORS;e++){const E=(n.NUM_OPERATORS-1-e)*n.PACKED_OP_SIZE,_=e*n.UNPACKED_OP_SIZE;this._unpackOperator(t,s,E,_)}}_unpackOperator(t,s,e,E){this._unpackOperatorEG(t,s,e,E),this._unpackOperatorScaling(t,s,e,E),this._unpackOperatorPackedParams(t,s,e,E),this._unpackOperatorFrequency(t,s,e,E)}_unpackOperatorEG(t,s,e,E){s[E+n.UNPACKED_OP_EG_RATE_1]=t[e+n.PACKED_OP_EG_RATE_1]&n.MASK_7BIT,s[E+n.UNPACKED_OP_EG_RATE_2]=t[e+n.PACKED_OP_EG_RATE_2]&n.MASK_7BIT,s[E+n.UNPACKED_OP_EG_RATE_3]=t[e+n.PACKED_OP_EG_RATE_3]&n.MASK_7BIT,s[E+n.UNPACKED_OP_EG_RATE_4]=t[e+n.PACKED_OP_EG_RATE_4]&n.MASK_7BIT,s[E+n.UNPACKED_OP_EG_LEVEL_1]=t[e+n.PACKED_OP_EG_LEVEL_1]&n.MASK_7BIT,s[E+n.UNPACKED_OP_EG_LEVEL_2]=t[e+n.PACKED_OP_EG_LEVEL_2]&n.MASK_7BIT,s[E+n.UNPACKED_OP_EG_LEVEL_3]=t[e+n.PACKED_OP_EG_LEVEL_3]&n.MASK_7BIT,s[E+n.UNPACKED_OP_EG_LEVEL_4]=t[e+n.PACKED_OP_EG_LEVEL_4]&n.MASK_7BIT}_unpackOperatorScaling(t,s,e,E){s[E+n.UNPACKED_OP_BREAK_POINT]=t[e+n.PACKED_OP_BREAK_POINT]&n.MASK_7BIT,s[E+n.UNPACKED_OP_L_SCALE_DEPTH]=t[e+n.PACKED_OP_L_SCALE_DEPTH]&n.MASK_7BIT,s[E+n.UNPACKED_OP_R_SCALE_DEPTH]=t[e+n.PACKED_OP_R_SCALE_DEPTH]&n.MASK_7BIT}_unpackOperatorPackedParams(t,s,e,E){const _=t[e+n.PACKED_OP_CURVES]&n.MASK_7BIT;s[E+n.UNPACKED_OP_L_CURVE]=_&n.MASK_2BIT,s[E+n.UNPACKED_OP_R_CURVE]=_>>2&n.MASK_2BIT;const i=t[e+n.PACKED_OP_RATE_SCALING]&n.MASK_7BIT;s[E+n.UNPACKED_OP_RATE_SCALING]=i&n.MASK_3BIT,s[E+n.UNPACKED_OP_DETUNE]=i>>3&n.MASK_4BIT;const r=t[e+n.PACKED_OP_MOD_SENS]&n.MASK_7BIT;s[E+n.UNPACKED_OP_AMP_MOD_SENS]=r&n.MASK_2BIT,s[E+n.UNPACKED_OP_KEY_VEL_SENS]=r>>2&n.MASK_3BIT,s[E+n.UNPACKED_OP_OUTPUT_LEVEL]=t[e+n.PACKED_OP_OUTPUT_LEVEL]&n.MASK_7BIT}_unpackOperatorFrequency(t,s,e,E){const _=t[e+n.PACKED_OP_MODE_FREQ]&n.MASK_7BIT;s[E+n.UNPACKED_OP_MODE]=_&n.MASK_1BIT,s[E+n.UNPACKED_OP_FREQ_COARSE]=_>>1&n.MASK_5BIT;const i=t[e+n.PACKED_OP_DETUNE_FINE]&n.MASK_7BIT;s[E+n.UNPACKED_OP_OSC_DETUNE]=i&n.MASK_3BIT,s[E+n.UNPACKED_OP_FREQ_FINE]=i>>3&n.MASK_4BIT}_unpackPitchEG(t,s){s[n.UNPACKED_PITCH_EG_RATE_1]=t[n.PACKED_PITCH_EG_RATE_1]&n.MASK_7BIT,s[n.UNPACKED_PITCH_EG_RATE_2]=t[n.PACKED_PITCH_EG_RATE_2]&n.MASK_7BIT,s[n.UNPACKED_PITCH_EG_RATE_3]=t[n.PACKED_PITCH_EG_RATE_3]&n.MASK_7BIT,s[n.UNPACKED_PITCH_EG_RATE_4]=t[n.PACKED_PITCH_EG_RATE_4]&n.MASK_7BIT,s[n.UNPACKED_PITCH_EG_LEVEL_1]=t[n.PACKED_PITCH_EG_LEVEL_1]&n.MASK_7BIT,s[n.UNPACKED_PITCH_EG_LEVEL_2]=t[n.PACKED_PITCH_EG_LEVEL_2]&n.MASK_7BIT,s[n.UNPACKED_PITCH_EG_LEVEL_3]=t[n.PACKED_PITCH_EG_LEVEL_3]&n.MASK_7BIT,s[n.UNPACKED_PITCH_EG_LEVEL_4]=t[n.PACKED_PITCH_EG_LEVEL_4]&n.MASK_7BIT}_unpackGlobalParams(t,s){s[n.UNPACKED_ALGORITHM]=t[n.OFFSET_ALGORITHM]&n.MASK_5BIT;const e=t[n.OFFSET_FEEDBACK]&n.MASK_7BIT;s[n.UNPACKED_FEEDBACK]=e&n.MASK_3BIT,s[n.UNPACKED_OSC_SYNC]=e>>3&n.MASK_1BIT,s[n.UNPACKED_LFO_SPEED]=t[n.OFFSET_LFO_SPEED]&n.MASK_7BIT,s[n.UNPACKED_LFO_DELAY]=t[n.OFFSET_LFO_DELAY]&n.MASK_7BIT,s[n.UNPACKED_LFO_PM_DEPTH]=t[n.OFFSET_LFO_PM_DEPTH]&n.MASK_7BIT,s[n.UNPACKED_LFO_AM_DEPTH]=t[n.OFFSET_LFO_AM_DEPTH]&n.MASK_7BIT;const E=t[n.OFFSET_LFO_SYNC_WAVE]&n.MASK_7BIT;s[n.UNPACKED_LFO_KEY_SYNC]=E&n.MASK_1BIT,s[n.UNPACKED_LFO_WAVE]=E>>1&n.MASK_3BIT,s[n.UNPACKED_LFO_PM_SENS]=E>>4&n.MASK_3BIT,s[n.UNPACKED_AMP_MOD_SENS]=t[n.OFFSET_AMP_MOD_SENS]&n.MASK_7BIT,s[n.UNPACKED_TRANSPOSE]=t[n.OFFSET_TRANSPOSE]&n.MASK_7BIT,s[n.UNPACKED_EG_BIAS_SENS]=t[n.OFFSET_EG_BIAS_SENS]&n.MASK_7BIT}_unpackName(t,s){for(let e=0;e<n.NAME_LENGTH;e++)s[n.UNPACKED_NAME_START+e]=t[n.PACKED_NAME_START+e]&n.MASK_7BIT}static pack(t){if(t.length!==n.UNPACKED_SIZE)throw new d(`Invalid unpacked data length: expected ${n.UNPACKED_SIZE} bytes, got ${t.length}`,"length",t.length);const s=new Uint8Array(n.PACKED_SIZE);return n._packOperators(t,s),n._packPitchEG(t,s),n._packGlobalParams(t,s),n._packName(t,s),s}static _packOperators(t,s){for(let e=0;e<n.NUM_OPERATORS;e++){const E=e*n.UNPACKED_OP_SIZE,_=(n.NUM_OPERATORS-1-e)*n.PACKED_OP_SIZE;n._packOperator(t,s,E,_)}}static _packOperator(t,s,e,E){n._packOperatorEG(t,s,e,E),n._packOperatorScaling(t,s,e,E),n._packOperatorPackedParams(t,s,e,E),n._packOperatorFrequency(t,s,e,E)}static _packOperatorEG(t,s,e,E){s[E+n.PACKED_OP_EG_RATE_1]=t[e+n.UNPACKED_OP_EG_RATE_1],s[E+n.PACKED_OP_EG_RATE_2]=t[e+n.UNPACKED_OP_EG_RATE_2],s[E+n.PACKED_OP_EG_RATE_3]=t[e+n.UNPACKED_OP_EG_RATE_3],s[E+n.PACKED_OP_EG_RATE_4]=t[e+n.UNPACKED_OP_EG_RATE_4],s[E+n.PACKED_OP_EG_LEVEL_1]=t[e+n.UNPACKED_OP_EG_LEVEL_1],s[E+n.PACKED_OP_EG_LEVEL_2]=t[e+n.UNPACKED_OP_EG_LEVEL_2],s[E+n.PACKED_OP_EG_LEVEL_3]=t[e+n.UNPACKED_OP_EG_LEVEL_3],s[E+n.PACKED_OP_EG_LEVEL_4]=t[e+n.UNPACKED_OP_EG_LEVEL_4]}static _packOperatorScaling(t,s,e,E){s[E+n.PACKED_OP_BREAK_POINT]=t[e+n.UNPACKED_OP_BREAK_POINT],s[E+n.PACKED_OP_L_SCALE_DEPTH]=t[e+n.UNPACKED_OP_L_SCALE_DEPTH],s[E+n.PACKED_OP_R_SCALE_DEPTH]=t[e+n.UNPACKED_OP_R_SCALE_DEPTH]}static _packOperatorPackedParams(t,s,e,E){const _=t[e+n.UNPACKED_OP_L_CURVE]&n.MASK_2BIT,i=t[e+n.UNPACKED_OP_R_CURVE]&n.MASK_2BIT;s[E+n.PACKED_OP_CURVES]=_|i<<2;const r=t[e+n.UNPACKED_OP_RATE_SCALING]&n.MASK_3BIT,u=t[e+n.UNPACKED_OP_DETUNE]&n.MASK_4BIT;s[E+n.PACKED_OP_RATE_SCALING]=r|u<<3;const S=t[e+n.UNPACKED_OP_AMP_MOD_SENS]&n.MASK_2BIT,P=t[e+n.UNPACKED_OP_KEY_VEL_SENS]&n.MASK_3BIT;s[E+n.PACKED_OP_MOD_SENS]=S|P<<2,s[E+n.PACKED_OP_OUTPUT_LEVEL]=t[e+n.UNPACKED_OP_OUTPUT_LEVEL]}static _packOperatorFrequency(t,s,e,E){const _=t[e+n.UNPACKED_OP_MODE]&n.MASK_1BIT,i=t[e+n.UNPACKED_OP_FREQ_COARSE]&n.MASK_5BIT;s[E+n.PACKED_OP_MODE_FREQ]=_|i<<1;const r=t[e+n.UNPACKED_OP_OSC_DETUNE]&n.MASK_3BIT,u=t[e+n.UNPACKED_OP_FREQ_FINE]&n.MASK_4BIT;s[E+n.PACKED_OP_DETUNE_FINE]=r|u<<3}static _packPitchEG(t,s){s[n.PACKED_PITCH_EG_RATE_1]=t[n.UNPACKED_PITCH_EG_RATE_1],s[n.PACKED_PITCH_EG_RATE_2]=t[n.UNPACKED_PITCH_EG_RATE_2],s[n.PACKED_PITCH_EG_RATE_3]=t[n.UNPACKED_PITCH_EG_RATE_3],s[n.PACKED_PITCH_EG_RATE_4]=t[n.UNPACKED_PITCH_EG_RATE_4],s[n.PACKED_PITCH_EG_LEVEL_1]=t[n.UNPACKED_PITCH_EG_LEVEL_1],s[n.PACKED_PITCH_EG_LEVEL_2]=t[n.UNPACKED_PITCH_EG_LEVEL_2],s[n.PACKED_PITCH_EG_LEVEL_3]=t[n.UNPACKED_PITCH_EG_LEVEL_3],s[n.PACKED_PITCH_EG_LEVEL_4]=t[n.UNPACKED_PITCH_EG_LEVEL_4]}static _packGlobalParams(t,s){s[n.OFFSET_ALGORITHM]=t[n.UNPACKED_ALGORITHM];const e=t[n.UNPACKED_FEEDBACK]&n.MASK_3BIT,E=t[n.UNPACKED_OSC_SYNC]&n.MASK_1BIT;s[n.OFFSET_FEEDBACK]=e|E<<3,s[n.OFFSET_LFO_SPEED]=t[n.UNPACKED_LFO_SPEED],s[n.OFFSET_LFO_DELAY]=t[n.UNPACKED_LFO_DELAY],s[n.OFFSET_LFO_PM_DEPTH]=t[n.UNPACKED_LFO_PM_DEPTH],s[n.OFFSET_LFO_AM_DEPTH]=t[n.UNPACKED_LFO_AM_DEPTH];const _=t[n.UNPACKED_LFO_KEY_SYNC]&n.MASK_1BIT,i=t[n.UNPACKED_LFO_WAVE]&n.MASK_3BIT,r=t[n.UNPACKED_LFO_PM_SENS]&n.MASK_3BIT;s[n.OFFSET_LFO_SYNC_WAVE]=_|i<<1|r<<4,s[n.OFFSET_AMP_MOD_SENS]=t[n.UNPACKED_AMP_MOD_SENS],s[n.OFFSET_TRANSPOSE]=t[n.UNPACKED_TRANSPOSE],s[n.OFFSET_EG_BIAS_SENS]=t[n.UNPACKED_EG_BIAS_SENS]}static _packName(t,s){for(let e=0;e<n.NAME_LENGTH;e++)s[n.PACKED_NAME_START+e]=t[n.UNPACKED_NAME_START+e]}static createDefault(t=0){const s=new Uint8Array(n.UNPACKED_SIZE);for(let _=0;_<n.NUM_OPERATORS;_++){const i=_*n.UNPACKED_OP_SIZE;s[i+n.UNPACKED_OP_EG_RATE_1]=n.DEFAULT_EG_RATE,s[i+n.UNPACKED_OP_EG_RATE_2]=n.DEFAULT_EG_RATE,s[i+n.UNPACKED_OP_EG_RATE_3]=n.DEFAULT_EG_RATE,s[i+n.UNPACKED_OP_EG_RATE_4]=n.DEFAULT_EG_RATE,s[i+n.UNPACKED_OP_EG_LEVEL_1]=n.DEFAULT_EG_LEVEL_MAX,s[i+n.UNPACKED_OP_EG_LEVEL_2]=n.DEFAULT_EG_LEVEL_MAX,s[i+n.UNPACKED_OP_EG_LEVEL_3]=n.DEFAULT_EG_LEVEL_MAX,s[i+n.UNPACKED_OP_EG_LEVEL_4]=n.DEFAULT_EG_LEVEL_MIN,s[i+n.UNPACKED_OP_BREAK_POINT]=n.DEFAULT_BREAK_POINT,s[i+n.UNPACKED_OP_L_SCALE_DEPTH]=0,s[i+n.UNPACKED_OP_R_SCALE_DEPTH]=0,s[i+n.UNPACKED_OP_L_CURVE]=0,s[i+n.UNPACKED_OP_R_CURVE]=0,s[i+n.UNPACKED_OP_RATE_SCALING]=0,s[i+n.UNPACKED_OP_DETUNE]=7,s[i+n.UNPACKED_OP_AMP_MOD_SENS]=0,s[i+n.UNPACKED_OP_KEY_VEL_SENS]=0,s[i+n.UNPACKED_OP_OUTPUT_LEVEL]=n.DEFAULT_OUTPUT_LEVEL,s[i+n.UNPACKED_OP_MODE]=0,s[i+n.UNPACKED_OP_FREQ_COARSE]=0,s[i+n.UNPACKED_OP_OSC_DETUNE]=0,s[i+n.UNPACKED_OP_FREQ_FINE]=0}s[n.UNPACKED_PITCH_EG_RATE_1]=n.DEFAULT_EG_RATE,s[n.UNPACKED_PITCH_EG_RATE_2]=n.DEFAULT_EG_RATE,s[n.UNPACKED_PITCH_EG_RATE_3]=n.DEFAULT_EG_RATE,s[n.UNPACKED_PITCH_EG_RATE_4]=n.DEFAULT_EG_RATE,s[n.UNPACKED_PITCH_EG_LEVEL_1]=n.DEFAULT_PITCH_EG_LEVEL,s[n.UNPACKED_PITCH_EG_LEVEL_2]=n.DEFAULT_PITCH_EG_LEVEL,s[n.UNPACKED_PITCH_EG_LEVEL_3]=n.DEFAULT_PITCH_EG_LEVEL,s[n.UNPACKED_PITCH_EG_LEVEL_4]=n.DEFAULT_PITCH_EG_LEVEL,s[n.UNPACKED_ALGORITHM]=n.DEFAULT_ALGORITHM,s[n.UNPACKED_FEEDBACK]=n.DEFAULT_FEEDBACK,s[n.UNPACKED_OSC_SYNC]=0,s[n.UNPACKED_LFO_SPEED]=n.DEFAULT_LFO_SPEED,s[n.UNPACKED_LFO_DELAY]=0,s[n.UNPACKED_LFO_PM_DEPTH]=0,s[n.UNPACKED_LFO_AM_DEPTH]=0,s[n.UNPACKED_LFO_KEY_SYNC]=0,s[n.UNPACKED_LFO_WAVE]=0,s[n.UNPACKED_LFO_PM_SENS]=n.DEFAULT_LFO_PM_SENS,s[n.UNPACKED_AMP_MOD_SENS]=0,s[n.UNPACKED_TRANSPOSE]=n.TRANSPOSE_CENTER,s[n.UNPACKED_EG_BIAS_SENS]=0;const e="Init Voice";for(let _=0;_<n.NAME_LENGTH;_++)s[n.UNPACKED_NAME_START+_]=_<e.length?e.charCodeAt(_):n.CHAR_SPACE;const E=n.pack(s);return new n(E,t)}static fromUnpacked(t,s=0){const e=n.pack(t);return new n(e,s)}static async fromFile(t){return new Promise((s,e)=>{const E=new FileReader;E.onload=_=>{try{const i=new Uint8Array(_.target.result);if(i[0]!==n.VCED_SYSEX_START||i[1]!==n.VCED_YAMAHA_ID||i[2]!==n.VCED_SUB_STATUS||i[3]!==n.VCED_FORMAT_SINGLE||i[4]!==n.VCED_BYTE_COUNT_MSB||i[5]!==n.VCED_BYTE_COUNT_LSB)throw new M("Invalid VCED header","header",0);const r=i.subarray(n.VCED_HEADER_SIZE,n.VCED_HEADER_SIZE+n.VCED_DATA_SIZE),u=i[n.VCED_HEADER_SIZE+n.VCED_DATA_SIZE],S=h._calculateChecksum(r,n.VCED_DATA_SIZE);u!==S&&console.warn(`DX7 VCED checksum mismatch (expected ${S.toString(16)}, got ${u.toString(16)}). This is common with vintage SysEx files.`);const P=new Uint8Array(n.UNPACKED_SIZE);let a=0;for(let l=0;l<n.NUM_OPERATORS;l++){const c=(n.NUM_OPERATORS-1-l)*n.UNPACKED_OP_SIZE;P[c+n.UNPACKED_OP_EG_RATE_1]=r[a++],P[c+n.UNPACKED_OP_EG_RATE_2]=r[a++],P[c+n.UNPACKED_OP_EG_RATE_3]=r[a++],P[c+n.UNPACKED_OP_EG_RATE_4]=r[a++],P[c+n.UNPACKED_OP_EG_LEVEL_1]=r[a++],P[c+n.UNPACKED_OP_EG_LEVEL_2]=r[a++],P[c+n.UNPACKED_OP_EG_LEVEL_3]=r[a++],P[c+n.UNPACKED_OP_EG_LEVEL_4]=r[a++],P[c+n.UNPACKED_OP_BREAK_POINT]=r[a++],P[c+n.UNPACKED_OP_L_SCALE_DEPTH]=r[a++],P[c+n.UNPACKED_OP_R_SCALE_DEPTH]=r[a++],P[c+n.UNPACKED_OP_L_CURVE]=r[a++],P[c+n.UNPACKED_OP_R_CURVE]=r[a++],P[c+n.UNPACKED_OP_RATE_SCALING]=r[a++],P[c+n.UNPACKED_OP_DETUNE]=r[a++];const T=r[a++];P[c+n.UNPACKED_OP_AMP_MOD_SENS]=T&n.MASK_2BIT,P[c+n.UNPACKED_OP_KEY_VEL_SENS]=T>>2&n.MASK_3BIT,P[c+n.UNPACKED_OP_OUTPUT_LEVEL]=r[a++],P[c+n.UNPACKED_OP_MODE]=r[a++],P[c+n.UNPACKED_OP_FREQ_COARSE]=r[a++],P[c+n.UNPACKED_OP_FREQ_FINE]=r[a++],P[c+n.UNPACKED_OP_OSC_DETUNE]=r[a++]}P[n.UNPACKED_PITCH_EG_RATE_1]=r[a++],P[n.UNPACKED_PITCH_EG_RATE_2]=r[a++],P[n.UNPACKED_PITCH_EG_RATE_3]=r[a++],P[n.UNPACKED_PITCH_EG_RATE_4]=r[a++],P[n.UNPACKED_PITCH_EG_LEVEL_1]=r[a++],P[n.UNPACKED_PITCH_EG_LEVEL_2]=r[a++],P[n.UNPACKED_PITCH_EG_LEVEL_3]=r[a++],P[n.UNPACKED_PITCH_EG_LEVEL_4]=r[a++],P[n.UNPACKED_ALGORITHM]=r[a++],P[n.UNPACKED_FEEDBACK]=r[a++],P[n.UNPACKED_OSC_SYNC]=r[a++],P[n.UNPACKED_LFO_SPEED]=r[a++],P[n.UNPACKED_LFO_DELAY]=r[a++],P[n.UNPACKED_LFO_PM_DEPTH]=r[a++],P[n.UNPACKED_LFO_AM_DEPTH]=r[a++],P[n.UNPACKED_LFO_KEY_SYNC]=r[a++],P[n.UNPACKED_LFO_WAVE]=r[a++],P[n.UNPACKED_LFO_PM_SENS]=r[a++],P[n.UNPACKED_TRANSPOSE]=r[a++];for(let l=0;l<n.NAME_LENGTH;l++)P[n.UNPACKED_NAME_START+l]=r[a++];const A=n.pack(P);s(new n(A,0))}catch(i){e(i)}},E.onerror=()=>e(new Error("Failed to read file")),E.readAsArrayBuffer(t)})}static fromSysEx(t,s=0){const e=t instanceof Uint8Array?t:new Uint8Array(t);let E;if(e[0]===n.VCED_SYSEX_START){if(e[0]!==n.VCED_SYSEX_START||e[1]!==n.VCED_YAMAHA_ID||e[2]!==n.VCED_SUB_STATUS||e[3]!==n.VCED_FORMAT_SINGLE||e[4]!==n.VCED_BYTE_COUNT_MSB||e[5]!==n.VCED_BYTE_COUNT_LSB)throw new M("Invalid VCED header","header",0);E=e.subarray(n.VCED_HEADER_SIZE,n.VCED_HEADER_SIZE+n.VCED_DATA_SIZE)}else if(e.length===n.PACKED_SIZE)E=e;else throw new d(`Invalid data length: expected ${n.PACKED_SIZE} or ${n.VCED_SIZE} bytes, got ${e.length}`,"length",e.length);if(E.length!==n.VCED_DATA_SIZE&&E.length!==n.PACKED_SIZE)throw new d(`Invalid voice data length: expected ${n.VCED_DATA_SIZE} or ${n.PACKED_SIZE} bytes, got ${E.length}`,"length",E.length);if(E.length===n.VCED_DATA_SIZE){const _=new Uint8Array(n.UNPACKED_SIZE);let i=0;for(let u=0;u<n.NUM_OPERATORS;u++){const S=(n.NUM_OPERATORS-1-u)*n.UNPACKED_OP_SIZE;_[S+n.UNPACKED_OP_EG_RATE_1]=E[i++],_[S+n.UNPACKED_OP_EG_RATE_2]=E[i++],_[S+n.UNPACKED_OP_EG_RATE_3]=E[i++],_[S+n.UNPACKED_OP_EG_RATE_4]=E[i++],_[S+n.UNPACKED_OP_EG_LEVEL_1]=E[i++],_[S+n.UNPACKED_OP_EG_LEVEL_2]=E[i++],_[S+n.UNPACKED_OP_EG_LEVEL_3]=E[i++],_[S+n.UNPACKED_OP_EG_LEVEL_4]=E[i++],_[S+n.UNPACKED_OP_BREAK_POINT]=E[i++],_[S+n.UNPACKED_OP_L_SCALE_DEPTH]=E[i++],_[S+n.UNPACKED_OP_R_SCALE_DEPTH]=E[i++],_[S+n.UNPACKED_OP_L_CURVE]=E[i++],_[S+n.UNPACKED_OP_R_CURVE]=E[i++],_[S+n.UNPACKED_OP_RATE_SCALING]=E[i++],_[S+n.UNPACKED_OP_DETUNE]=E[i++];const P=E[i++];_[S+n.UNPACKED_OP_AMP_MOD_SENS]=P&n.MASK_2BIT,_[S+n.UNPACKED_OP_KEY_VEL_SENS]=P>>2&n.MASK_3BIT,_[S+n.UNPACKED_OP_OUTPUT_LEVEL]=E[i++],_[S+n.UNPACKED_OP_MODE]=E[i++],_[S+n.UNPACKED_OP_FREQ_COARSE]=E[i++],_[S+n.UNPACKED_OP_FREQ_FINE]=E[i++],_[S+n.UNPACKED_OP_OSC_DETUNE]=E[i++]}_[n.UNPACKED_PITCH_EG_RATE_1]=E[i++],_[n.UNPACKED_PITCH_EG_RATE_2]=E[i++],_[n.UNPACKED_PITCH_EG_RATE_3]=E[i++],_[n.UNPACKED_PITCH_EG_RATE_4]=E[i++],_[n.UNPACKED_PITCH_EG_LEVEL_1]=E[i++],_[n.UNPACKED_PITCH_EG_LEVEL_2]=E[i++],_[n.UNPACKED_PITCH_EG_LEVEL_3]=E[i++],_[n.UNPACKED_PITCH_EG_LEVEL_4]=E[i++],_[n.UNPACKED_ALGORITHM]=E[i++],_[n.UNPACKED_FEEDBACK]=E[i++],_[n.UNPACKED_OSC_SYNC]=E[i++],_[n.UNPACKED_LFO_SPEED]=E[i++],_[n.UNPACKED_LFO_DELAY]=E[i++],_[n.UNPACKED_LFO_PM_DEPTH]=E[i++],_[n.UNPACKED_LFO_AM_DEPTH]=E[i++],_[n.UNPACKED_LFO_KEY_SYNC]=E[i++],_[n.UNPACKED_LFO_WAVE]=E[i++],_[n.UNPACKED_LFO_PM_SENS]=E[i++],_[n.UNPACKED_TRANSPOSE]=E[i++];for(let u=0;u<n.NAME_LENGTH;u++)_[n.UNPACKED_NAME_START+u]=E[i++];const r=n.pack(_);return new n(r,s)}return new n(E,s)}static fromJSON(t,s=0){if(!t||typeof t!="object")throw new d("Invalid JSON: expected object","json",t);const e=new Uint8Array(n.UNPACKED_SIZE),E=(a,A,l,c=0,T=127)=>{if(A==null)throw new d(`Missing required parameter: ${l}`,l,A);const I=Number(A);if(Number.isNaN(I))throw new d(`Invalid parameter value for ${l}: ${A}`,l,A);if(I<c||I>T)throw new d(`Parameter ${l} out of range: ${I} (must be ${c}-${T})`,l,I);e[a]=Math.floor(I)},_=a=>{const A={"-LN":0,"-EX":1,"+EX":2,"+LN":3};return A[a]!==void 0?A[a]:0},i=a=>{const A={TRIANGLE:0,"SAW DOWN":1,"SAW UP":2,SQUARE:3,SINE:4,"SAMPLE & HOLD":5};return A[a]!==void 0?A[a]:0},r=a=>{if(!a||typeof a!="string")return 60;const A=a.trim().match(/^([A-G]#?)(-?\d+)$/);if(!A)return 60;const[,l,c]=A,T=parseInt(c,10),f={C:0,"C#":1,D:2,"D#":3,E:4,F:5,"F#":6,G:7,"G#":8,A:9,"A#":10,B:11}[l.toUpperCase()];return f===void 0?60:(T-n.MIDI_OCTAVE_OFFSET)*12+f};if(!Array.isArray(t.operators))throw new d("Invalid operators array: expected array","operators",t.operators);for(let a=0;a<t.operators.length;a++){const A=t.operators[a];if(!A||typeof A!="object")throw new d(`Invalid operator data at index ${a}`,`operators[${a}]`,A);if(!A.eg||!Array.isArray(A.eg.rates)||A.eg.rates.length!==4)throw new d(`Invalid EG rates for operator ${a}`,`operators[${a}].eg.rates`,A.eg?.rates);if(!A.eg||!Array.isArray(A.eg.levels)||A.eg.levels.length!==4)throw new d(`Invalid EG levels for operator ${a}`,`operators[${a}].eg.levels`,A.eg?.levels)}if(t.operators.length!==n.NUM_OPERATORS)throw new d(`Invalid operators array: expected ${n.NUM_OPERATORS} operators`,"operators",t.operators);for(let a=0;a<n.NUM_OPERATORS;a++){const A=t.operators[a],l=a*n.UNPACKED_OP_SIZE;if(!A.eg||!Array.isArray(A.eg.rates)||A.eg.rates.length!==4)throw new d(`Invalid EG rates for operator ${a}`,`operators[${a}].eg.rates`,A.eg?.rates);if(E(l+n.UNPACKED_OP_EG_RATE_1,A.eg.rates[0],`operators[${a}].eg.rates[0]`,0,99),E(l+n.UNPACKED_OP_EG_RATE_2,A.eg.rates[1],`operators[${a}].eg.rates[1]`,0,99),E(l+n.UNPACKED_OP_EG_RATE_3,A.eg.rates[2],`operators[${a}].eg.rates[2]`,0,99),E(l+n.UNPACKED_OP_EG_RATE_4,A.eg.rates[3],`operators[${a}].eg.rates[3]`,0,99),!A.eg||!Array.isArray(A.eg.levels)||A.eg.levels.length!==4)throw new d(`Invalid EG levels for operator ${a}`,`operators[${a}].eg.levels`,A.eg?.levels);E(l+n.UNPACKED_OP_EG_LEVEL_1,A.eg.levels[0],`operators[${a}].eg.levels[0]`,0,99),E(l+n.UNPACKED_OP_EG_LEVEL_2,A.eg.levels[1],`operators[${a}].eg.levels[1]`,0,99),E(l+n.UNPACKED_OP_EG_LEVEL_3,A.eg.levels[2],`operators[${a}].eg.levels[2]`,0,99),E(l+n.UNPACKED_OP_EG_LEVEL_4,A.eg.levels[3],`operators[${a}].eg.levels[3]`,0,99);const c=r(A.key?.breakPoint)-n.MIDI_BREAK_POINT_OFFSET;E(l+n.UNPACKED_OP_BREAK_POINT,c,`operators[${a}].key.breakPoint`,0,127),E(l+n.UNPACKED_OP_L_SCALE_DEPTH,A.scale?.left?.depth||0,`operators[${a}].scale.left.depth`,0,99),E(l+n.UNPACKED_OP_R_SCALE_DEPTH,A.scale?.right?.depth||0,`operators[${a}].scale.right.depth`,0,99),e[l+n.UNPACKED_OP_L_CURVE]=_(A.scale?.left?.curve||"-LN"),e[l+n.UNPACKED_OP_R_CURVE]=_(A.scale?.right?.curve||"-LN"),E(l+n.UNPACKED_OP_RATE_SCALING,A.key?.scaling||0,`operators[${a}].key.scaling`,0,7);const T=Number(A.osc?.detune)||0;E(l+n.UNPACKED_OP_DETUNE,T+7,`operators[${a}].osc.detune`,0,14),E(l+n.UNPACKED_OP_AMP_MOD_SENS,A.output?.ampModSens||0,`operators[${a}].output.ampModSens`,0,3),E(l+n.UNPACKED_OP_OUTPUT_LEVEL,A.output?.level||0,`operators[${a}].output.level`,0,99);const I=A.osc?.freq?.mode?.toUpperCase()==="FIXED"?1:0,f=Number(A.osc?.freq?.coarse)||0,K=Number(A.osc?.freq?.fine)||0;e[l+n.UNPACKED_OP_MODE]=I,E(l+n.UNPACKED_OP_FREQ_COARSE,f,`operators[${a}].osc.freq.coarse`,0,31),E(l+n.UNPACKED_OP_FREQ_FINE,K,`operators[${a}].osc.freq.fine`,0,15),E(l+n.UNPACKED_OP_KEY_VEL_SENS,A.key?.velocity||0,`operators[${a}].key.velocity`,0,7)}if(!t.pitchEG||!Array.isArray(t.pitchEG.rates)||t.pitchEG.rates.length!==4)throw new d("Invalid pitch EG rates","pitchEG.rates",t.pitchEG?.rates);if(!t.pitchEG||!Array.isArray(t.pitchEG.levels)||t.pitchEG.levels.length!==4)throw new d("Invalid pitch EG levels","pitchEG.levels",t.pitchEG?.levels);if(E(n.UNPACKED_PITCH_EG_RATE_1,t.pitchEG.rates[0],"pitchEG.rates[0]",0,99),E(n.UNPACKED_PITCH_EG_RATE_2,t.pitchEG.rates[1],"pitchEG.rates[1]",0,99),E(n.UNPACKED_PITCH_EG_RATE_3,t.pitchEG.rates[2],"pitchEG.rates[2]",0,99),E(n.UNPACKED_PITCH_EG_RATE_4,t.pitchEG.rates[3],"pitchEG.rates[3]",0,99),E(n.UNPACKED_PITCH_EG_LEVEL_1,t.pitchEG.levels[0],"pitchEG.levels[0]",0,99),E(n.UNPACKED_PITCH_EG_LEVEL_2,t.pitchEG.levels[1],"pitchEG.levels[1]",0,99),E(n.UNPACKED_PITCH_EG_LEVEL_3,t.pitchEG.levels[2],"pitchEG.levels[2]",0,99),E(n.UNPACKED_PITCH_EG_LEVEL_4,t.pitchEG.levels[3],"pitchEG.levels[3]",0,99),!t.lfo||typeof t.lfo!="object")throw new d("Invalid LFO data","lfo",t.lfo);if(E(n.UNPACKED_LFO_SPEED,t.lfo.speed,"lfo.speed",0,99),E(n.UNPACKED_LFO_DELAY,t.lfo.delay,"lfo.delay",0,99),E(n.UNPACKED_LFO_PM_DEPTH,t.lfo.pmDepth,"lfo.pmDepth",0,99),E(n.UNPACKED_LFO_AM_DEPTH,t.lfo.amDepth,"lfo.amDepth",0,99),e[n.UNPACKED_LFO_KEY_SYNC]=t.lfo.keySync?1:0,e[n.UNPACKED_LFO_WAVE]=i(t.lfo.wave),!t.global||typeof t.global!="object")throw new d("Invalid global data","global",t.global);const u=Number(t.global.algorithm)||1;E(n.UNPACKED_ALGORITHM,u-1,"global.algorithm",0,31),E(n.UNPACKED_FEEDBACK,t.global.feedback,"global.feedback",0,7),e[n.UNPACKED_OSC_SYNC]=t.global.oscKeySync?1:0,E(n.UNPACKED_LFO_PM_SENS,t.global.pitchModSens,"global.pitchModSens",0,7);const S=Number(t.global.transpose)||0;E(n.UNPACKED_TRANSPOSE,S+n.TRANSPOSE_CENTER,"global.transpose",0,127),E(n.UNPACKED_AMP_MOD_SENS,t.global.ampModSens||0,"global.ampModSens",0,3),E(n.UNPACKED_EG_BIAS_SENS,t.global.egBiasSens||0,"global.egBiasSens",0,7);const P=t.name||"";for(let a=0;a<n.NAME_LENGTH;a++)e[n.UNPACKED_NAME_START+a]=a<P.length?P.charCodeAt(a):n.CHAR_SPACE;return n.fromUnpacked(e,s)}toSysEx(){const t=this.unpack(),s=new Uint8Array(n.VCED_SIZE);let e=0;s[e++]=n.VCED_SYSEX_START,s[e++]=n.VCED_YAMAHA_ID,s[e++]=n.VCED_SUB_STATUS,s[e++]=n.VCED_FORMAT_SINGLE,s[e++]=n.VCED_BYTE_COUNT_MSB,s[e++]=n.VCED_BYTE_COUNT_LSB;for(let _=n.NUM_OPERATORS-1;_>=0;_--){const i=_*n.UNPACKED_OP_SIZE;s[e++]=t[i+n.UNPACKED_OP_EG_RATE_1],s[e++]=t[i+n.UNPACKED_OP_EG_RATE_2],s[e++]=t[i+n.UNPACKED_OP_EG_RATE_3],s[e++]=t[i+n.UNPACKED_OP_EG_RATE_4],s[e++]=t[i+n.UNPACKED_OP_EG_LEVEL_1],s[e++]=t[i+n.UNPACKED_OP_EG_LEVEL_2],s[e++]=t[i+n.UNPACKED_OP_EG_LEVEL_3],s[e++]=t[i+n.UNPACKED_OP_EG_LEVEL_4],s[e++]=t[i+n.UNPACKED_OP_BREAK_POINT],s[e++]=t[i+n.UNPACKED_OP_L_SCALE_DEPTH],s[e++]=t[i+n.UNPACKED_OP_R_SCALE_DEPTH],s[e++]=t[i+n.UNPACKED_OP_L_CURVE],s[e++]=t[i+n.UNPACKED_OP_R_CURVE],s[e++]=t[i+n.UNPACKED_OP_RATE_SCALING],s[e++]=t[i+n.UNPACKED_OP_DETUNE];const r=t[i+n.UNPACKED_OP_AMP_MOD_SENS]&n.MASK_2BIT,u=t[i+n.UNPACKED_OP_KEY_VEL_SENS]&n.MASK_3BIT;s[e++]=r|u<<2,s[e++]=t[i+n.UNPACKED_OP_OUTPUT_LEVEL],s[e++]=t[i+n.UNPACKED_OP_MODE],s[e++]=t[i+n.UNPACKED_OP_FREQ_COARSE],s[e++]=t[i+n.UNPACKED_OP_OSC_DETUNE],s[e++]=t[i+n.UNPACKED_OP_FREQ_FINE]}s[e++]=t[n.UNPACKED_PITCH_EG_RATE_1],s[e++]=t[n.UNPACKED_PITCH_EG_RATE_2],s[e++]=t[n.UNPACKED_PITCH_EG_RATE_3],s[e++]=t[n.UNPACKED_PITCH_EG_RATE_4],s[e++]=t[n.UNPACKED_PITCH_EG_LEVEL_1],s[e++]=t[n.UNPACKED_PITCH_EG_LEVEL_2],s[e++]=t[n.UNPACKED_PITCH_EG_LEVEL_3],s[e++]=t[n.UNPACKED_PITCH_EG_LEVEL_4],s[e++]=t[n.UNPACKED_ALGORITHM],s[e++]=t[n.UNPACKED_FEEDBACK],s[e++]=t[n.UNPACKED_OSC_SYNC],s[e++]=t[n.UNPACKED_LFO_SPEED],s[e++]=t[n.UNPACKED_LFO_DELAY],s[e++]=t[n.UNPACKED_LFO_PM_DEPTH],s[e++]=t[n.UNPACKED_LFO_AM_DEPTH],s[e++]=t[n.UNPACKED_LFO_KEY_SYNC],s[e++]=t[n.UNPACKED_LFO_WAVE],s[e++]=t[n.UNPACKED_LFO_PM_SENS],s[e++]=t[n.UNPACKED_TRANSPOSE];for(let _=0;_<n.NAME_LENGTH;_++)s[e++]=t[n.UNPACKED_NAME_START+_];const E=s.subarray(n.VCED_HEADER_SIZE,n.VCED_HEADER_SIZE+n.VCED_DATA_SIZE);return s[e++]=h._calculateChecksum(E,n.VCED_DATA_SIZE),s[e++]=n.VCED_SYSEX_END,s}toJSON(){const t=this.unpack(),s=[],e=i=>["-LN","-EX","+EX","+LN"][i]||"UNKNOWN",E=i=>["TRIANGLE","SAW DOWN","SAW UP","SQUARE","SINE","SAMPLE & HOLD"][i]||"UNKNOWN",_=i=>{const r=["C","C#","D","D#","E","F","F#","G","G#","A","A#","B"],u=Math.floor(i/12)+n.MIDI_OCTAVE_OFFSET;return`${r[i%12]}${u}`};for(let i=0;i<n.NUM_OPERATORS;i++){const r=i*n.UNPACKED_OP_SIZE,u=t[r+n.UNPACKED_OP_MODE]===0?"RATIO":"FIXED";s.push({id:i+1,osc:{detune:t[r+n.UNPACKED_OP_OSC_DETUNE],freq:{coarse:t[r+n.UNPACKED_OP_FREQ_COARSE],fine:t[r+n.UNPACKED_OP_FREQ_FINE],mode:u}},eg:{rates:[t[r+n.UNPACKED_OP_EG_RATE_1],t[r+n.UNPACKED_OP_EG_RATE_2],t[r+n.UNPACKED_OP_EG_RATE_3],t[r+n.UNPACKED_OP_EG_RATE_4]],levels:[t[r+n.UNPACKED_OP_EG_LEVEL_1],t[r+n.UNPACKED_OP_EG_LEVEL_2],t[r+n.UNPACKED_OP_EG_LEVEL_3],t[r+n.UNPACKED_OP_EG_LEVEL_4]]},key:{velocity:t[r+n.UNPACKED_OP_KEY_VEL_SENS],scaling:t[r+n.UNPACKED_OP_RATE_SCALING],breakPoint:_(t[r+n.UNPACKED_OP_BREAK_POINT]+n.MIDI_BREAK_POINT_OFFSET)},output:{level:t[r+n.UNPACKED_OP_OUTPUT_LEVEL],ampModSens:t[r+n.UNPACKED_OP_AMP_MOD_SENS]},scale:{left:{depth:t[r+n.UNPACKED_OP_L_SCALE_DEPTH],curve:e(t[r+n.UNPACKED_OP_L_CURVE])},right:{depth:t[r+n.UNPACKED_OP_R_SCALE_DEPTH],curve:e(t[r+n.UNPACKED_OP_R_CURVE])}}})}return{name:this.name||"(Empty)",operators:s,pitchEG:{rates:[t[n.UNPACKED_PITCH_EG_RATE_1],t[n.UNPACKED_PITCH_EG_RATE_2],t[n.UNPACKED_PITCH_EG_RATE_3],t[n.UNPACKED_PITCH_EG_RATE_4]],levels:[t[n.UNPACKED_PITCH_EG_LEVEL_1],t[n.UNPACKED_PITCH_EG_LEVEL_2],t[n.UNPACKED_PITCH_EG_LEVEL_3],t[n.UNPACKED_PITCH_EG_LEVEL_4]]},lfo:{speed:t[n.UNPACKED_LFO_SPEED],delay:t[n.UNPACKED_LFO_DELAY],pmDepth:t[n.UNPACKED_LFO_PM_DEPTH],amDepth:t[n.UNPACKED_LFO_AM_DEPTH],keySync:t[n.UNPACKED_LFO_KEY_SYNC]===1,wave:E(t[n.UNPACKED_LFO_WAVE])},global:{algorithm:t[n.UNPACKED_ALGORITHM]+1,feedback:t[n.UNPACKED_FEEDBACK],oscKeySync:t[n.UNPACKED_OSC_SYNC]===1,pitchModSens:t[n.UNPACKED_LFO_PM_SENS],transpose:t[n.UNPACKED_TRANSPOSE]-n.TRANSPOSE_CENTER}}}}class h{static SYSEX_START=240;static SYSEX_END=247;static SYSEX_YAMAHA_ID=67;static SYSEX_SUB_STATUS=0;static SYSEX_FORMAT_32_VOICES=9;static SYSEX_BYTE_COUNT_MSB=32;static SYSEX_BYTE_COUNT_LSB=0;static SYSEX_HEADER=[h.SYSEX_START,h.SYSEX_YAMAHA_ID,h.SYSEX_SUB_STATUS,h.SYSEX_FORMAT_32_VOICES,h.SYSEX_BYTE_COUNT_MSB,h.SYSEX_BYTE_COUNT_LSB];static SYSEX_HEADER_SIZE=6;static VOICE_DATA_SIZE=4096;static SYSEX_SIZE=4104;static VOICE_SIZE=128;static NUM_VOICES=32;static CHECKSUM_MODULO=128;static MASK_7BIT=127;constructor(t,s=""){if(this.voices=new Array(h.NUM_VOICES),this.name=s,t)this._load(t);else for(let e=0;e<h.NUM_VOICES;e++)this.voices[e]=n.createDefault(e)}static _calculateChecksum(t,s){let e=0;for(let E=0;E<s;E++)e+=t[E];return h.CHECKSUM_MODULO-e%h.CHECKSUM_MODULO&h.MASK_7BIT}_load(t){const s=t instanceof Uint8Array?t:new Uint8Array(t);let e,E=0;if(s[0]===h.SYSEX_START){const i=s.subarray(0,h.SYSEX_HEADER_SIZE),r=h.SYSEX_HEADER;for(let u=0;u<h.SYSEX_HEADER_SIZE;u++)if(i[u]!==r[u])throw new M(`Invalid SysEx header at position ${u}: expected ${r[u].toString(16)}, got ${i[u].toString(16)}`,"header",u);e=s.subarray(h.SYSEX_HEADER_SIZE,h.SYSEX_HEADER_SIZE+h.VOICE_DATA_SIZE),E=h.SYSEX_HEADER_SIZE}else if(s.length===h.VOICE_DATA_SIZE)e=s;else throw new d(`Invalid data length: expected ${h.VOICE_DATA_SIZE} or ${h.SYSEX_SIZE} bytes, got ${s.length}`,"length",s.length);if(e.length!==h.VOICE_DATA_SIZE)throw new d(`Invalid voice data length: expected ${h.VOICE_DATA_SIZE} bytes, got ${e.length}`,"length",e.length);const _=h.SYSEX_HEADER_SIZE+h.VOICE_DATA_SIZE;if(E>0&&s.length>=_+1){const i=s[_],r=h._calculateChecksum(e,h.VOICE_DATA_SIZE);i!==r&&console.warn(`DX7 checksum mismatch (expected ${r.toString(16)}, got ${i.toString(16)}). This is common with vintage SysEx files and the data is likely still valid.`)}this.voices=new Array(h.NUM_VOICES);for(let i=0;i<h.NUM_VOICES;i++){const r=i*h.VOICE_SIZE,u=e.subarray(r,r+h.VOICE_SIZE);this.voices[i]=new n(u,i)}}replaceVoice(t,s){if(t<0||t>=h.NUM_VOICES)throw new d(`Invalid voice index: ${t}`,"index",t);const e=new Uint8Array(s.data);this.voices[t]=new n(e,t)}addVoice(t){for(let s=0;s<this.voices.length;s++){const e=this.voices[s];if(e.name===""||e.name==="Init Voice")return this.replaceVoice(s,t),s}return-1}getVoices(){return this.voices}getVoice(t){return t<0||t>=this.voices.length?null:this.voices[t]}getVoiceNames(){return this.voices.map(t=>t.name)}findVoiceByName(t){const s=t.toLowerCase();return this.voices.find(e=>e.name.toLowerCase().includes(s))||null}static async fromFile(t){return new Promise((s,e)=>{const E=new FileReader;E.onload=async _=>{try{const i=t.name||"",r=new Uint8Array(_.target.result);if(r[0]===h.SYSEX_START&&r[3]===n.VCED_FORMAT_SINGLE)e(new M("This is a single voice file. Use DX7Voice.fromFile() instead.","format",3));else{const u=i.replace(/\.[^/.]+$/,""),S=new h(_.target.result,u);s(S)}}catch(i){e(i)}},E.onerror=()=>e(new Error("Failed to read file")),E.readAsArrayBuffer(t)})}static fromSysEx(t,s=""){return new h(t,s)}static fromJSON(t){if(!t||typeof t!="object")throw new d("Invalid JSON: expected object","json",t);const s=new h;if(s.name=t.name||"",!Array.isArray(t.voices))throw new d("Invalid voices array","voices",t.voices);t.voices.length!==h.NUM_VOICES&&console.warn(`Bank JSON has ${t.voices.length} voices, expected ${h.NUM_VOICES}. Missing voices will be filled with defaults.`);const e=Math.min(t.voices.length,h.NUM_VOICES);for(let E=0;E<e;E++){const _=t.voices[E];if(!_||typeof _!="object"){console.warn(`Invalid voice data at index ${E}, using default voice`);continue}try{const{index:i,...r}=_,u=n.fromJSON(r,E);s.replaceVoice(E,u)}catch(i){console.warn(`Failed to load voice at index ${E}: ${i.message}, using default voice`)}}return s}toSysEx(){const t=new Uint8Array(h.SYSEX_SIZE);let s=0;h.SYSEX_HEADER.forEach(E=>{t[s++]=E});for(const E of this.voices)for(let _=0;_<h.VOICE_SIZE;_++)t[s++]=E.data[_];const e=t.subarray(h.SYSEX_HEADER_SIZE,h.SYSEX_HEADER_SIZE+h.VOICE_DATA_SIZE);return t[s++]=h._calculateChecksum(e,h.VOICE_DATA_SIZE),t[s++]=h.SYSEX_END,t}toJSON(){const t=this.voices.map((s,e)=>{const E=s.toJSON();return{index:e+1,...E}});return{version:"1.0",name:this.name||"",voices:t}}}function tt(C){return C[0]!==240||C[C.length-1]!==247?null:{manufacturerId:C[1],payload:C.slice(2,-1),raw:C}}function nt(C,t){return[240,C,...t,247]}function st(C){return C.length>=2&&C[0]===240&&C[C.length-1]===247}function et(C){const t=[];for(let s=0;s<C.length;s+=7){const e=C.slice(s,s+7);let E=0;const _=[];for(let i=0;i<e.length;i++){const r=e[i];r&128&&(E|=1<<i),_.push(r&127)}t.push(E,..._)}return t}function Et(C){const t=[];for(let s=0;s<C.length;s+=8){const e=C[s],E=Math.min(7,C.length-s-1);for(let _=0;_<E;_++){let i=C[s+1+_];e&1<<_&&(i|=128),t.push(i)}}return t}function it(C){return Number.isInteger(C)&&C>=1&&C<=16}function _t(C){return Number.isInteger(C)&&C>=0&&C<=127}function rt(C){return Number.isInteger(C)&&C>=0&&C<=31}function at(C){return Number.isInteger(C)&&C>=0&&C<=127}function Ct(C){return Number.isInteger(C)&&C>=0&&C<=127}function At(C){return Number.isInteger(C)&&C>=0&&C<=127}function ot(C){return Number.isInteger(C)&&C>=0&&C<=127}function Pt(C){return Number.isInteger(C)&&C>=0&&C<=16383}function ut(C,t){return Number.isInteger(C)&&C>=0&&C<=127&&Number.isInteger(t)&&t>=0&&t<=127}async function Z(C={}){const t=new x(C);await t.init();const s=C.selector||"[data-midi-cc]";{const e=new p(t,s);e.bindAll(),C.watchDOM&&e.enableAutoBinding(),t._binder=e}return t}async function lt(C={}){const{onStatusUpdate:t,onConnectionUpdate:s,inputChannel:e=1,outputChannel:E=1,output:_,sysex:i,onReady:r,onError:u,selector:S,watchDOM:P,...a}=C,l=await Z({autoConnect:!1,sysex:i,inputChannel:e,outputChannel:E,selector:S||"[data-midi-cc]",watchDOM:P,onError:u,...a}),c=new $({midiController:l,onStatusUpdate:t||(()=>{}),onConnectionUpdate:s||(()=>{}),channel:E});if(_)try{await l.device.connectOutput(_),c.currentOutput=l.device.getCurrentOutput(),c.updateConnectionStatus()}catch(T){u?u(T):console.error("Failed to connect to MIDI device:",T.message)}return r&&r(l,c),c}N.CONN=U,N.CONNECTION_EVENTS=U,N.CONTROLLER_EVENTS=o,N.CTRL=o,N.DX7Bank=h,N.DX7Error=F,N.DX7ParseError=M,N.DX7ValidationError=d,N.DX7Voice=n,N.DataAttributeBinder=p,N.EventEmitter=b,N.MIDIAccessError=g,N.MIDIConnection=Y,N.MIDIConnectionError=G,N.MIDIController=x,N.MIDIDeviceError=L,N.MIDIDeviceManager=$,N.MIDIError=m,N.MIDIValidationError=R,N.clamp=O,N.createMIDIController=Z,N.createMIDIDeviceManager=lt,N.createSysEx=nt,N.decode14BitValue=w,N.decode7Bit=Et,N.denormalize14BitValue=X,N.denormalizeValue=W,N.encode14BitValue=v,N.encode7Bit=et,N.frequencyToNote=j,N.getCCName=V,N.isSysEx=st,N.isValid14BitCC=rt,N.isValidCC=_t,N.isValidChannel=it,N.isValidMIDIValue=at,N.isValidNote=Ct,N.isValidPitchBend=Pt,N.isValidPitchBendBytes=ut,N.isValidProgramChange=ot,N.isValidVelocity=At,N.normalize14BitValue=B,N.normalizeValue=y,N.noteNameToNumber=Q,N.noteNumberToName=J,N.noteToFrequency=k,N.parseSysEx=tt,Object.defineProperty(N,Symbol.toStringTag,{value:"Module"})}));
1
+ (function(S,p){typeof exports=="object"&&typeof module<"u"?p(exports):typeof define=="function"&&define.amd?define(["exports"],p):(S=typeof globalThis<"u"?globalThis:S||self,p(S.MIDIControls={}))})(this,(function(S){"use strict";class p{constructor(t,s="[data-midi-cc]"){this.controller=t,this.selector=s,this.observer=null}bindAll(){document.querySelectorAll(this.selector==="[data-midi-cc]"?"[data-midi-cc], [data-midi-msb][data-midi-lsb]":this.selector).forEach(s=>{if(s.hasAttribute("data-midi-bound"))return;const e=this._parseAttributes(s);e&&(this.controller.bind(s,e),s.setAttribute("data-midi-bound","true"))})}enableAutoBinding(){if(this.observer)return;const t=this.selector==="[data-midi-cc]"?"[data-midi-cc], [data-midi-msb][data-midi-lsb]":this.selector;this.observer=new MutationObserver(s=>{s.forEach(e=>{e.addedNodes.forEach(E=>{if(E.nodeType===Node.ELEMENT_NODE){if(E.matches?.(t)){const r=this._parseAttributes(E);r&&!E.hasAttribute("data-midi-bound")&&(this.controller.bind(E,r),E.setAttribute("data-midi-bound","true"))}E.querySelectorAll&&E.querySelectorAll(t).forEach(i=>{if(!i.hasAttribute("data-midi-bound")){const _=this._parseAttributes(i);_&&(this.controller.bind(i,_),i.setAttribute("data-midi-bound","true"))}})}}),e.removedNodes.forEach(E=>{E.nodeType===Node.ELEMENT_NODE&&(E.hasAttribute?.("data-midi-bound")&&this.controller.unbind(E),E.querySelectorAll&&E.querySelectorAll("[data-midi-bound]").forEach(i=>{this.controller.unbind(i)}))})})}),this.observer.observe(document.body,{childList:!0,subtree:!0})}disableAutoBinding(){this.observer&&(this.observer.disconnect(),this.observer=null)}_parseAttributes(t){const s=parseInt(t.dataset.midiMsb,10),e=parseInt(t.dataset.midiLsb,10);if(!Number.isNaN(s)&&!Number.isNaN(e)&&s>=0&&s<=127&&e>=0&&e<=127){const r=parseInt(t.dataset.midiCc,10);return!Number.isNaN(r)&&r>=0&&r<=127&&console.warn(`Element has both 7-bit (data-midi-cc="${r}") and 14-bit (data-midi-msb="${s}" data-midi-lsb="${e}") CC attributes. 14-bit takes precedence.`,t),{msb:s,lsb:e,is14Bit:!0,channel:parseInt(t.dataset.midiChannel,10)||void 0,min:parseFloat(t.getAttribute("min"))||0,max:parseFloat(t.getAttribute("max"))||127,invert:t.dataset.midiInvert==="true",label:t.dataset.midiLabel}}const E=parseInt(t.dataset.midiCc,10);return!Number.isNaN(E)&&E>=0&&E<=127?{cc:E,channel:parseInt(t.dataset.midiChannel,10)||void 0,min:parseFloat(t.getAttribute("min"))||0,max:parseFloat(t.getAttribute("max"))||127,invert:t.dataset.midiInvert==="true",label:t.dataset.midiLabel}:((t.dataset.midiCc!==void 0||t.dataset.midiMsb!==void 0&&t.dataset.midiLsb!==void 0)&&console.warn("Invalid MIDI configuration on element:",t),null)}destroy(){this.disableAutoBinding()}}class m extends Error{constructor(t,s){super(t),this.name="MIDIError",this.code=s,Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor)}}class g extends m{constructor(t,s){super(t,"MIDI_ACCESS_ERROR"),this.name="MIDIAccessError",this.reason=s}}class G extends m{constructor(t){super(t,"MIDI_CONNECTION_ERROR"),this.name="MIDIConnectionError"}}class L extends m{constructor(t,s,e){super(t,"MIDI_DEVICE_ERROR"),this.name="MIDIDeviceError",this.deviceType=s,this.deviceId=e}}class R extends m{constructor(t,s){super(t,"MIDI_VALIDATION_ERROR"),this.name="MIDIValidationError",this.validationType=s}}class F extends Error{constructor(t,s){super(t),this.name="DX7Error",this.code=s,Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor)}}class M extends F{constructor(t,s,e){super(t,"DX7_PARSE_ERROR"),this.name="DX7ParseError",this.parseType=s,this.offset=e}}class d extends F{constructor(t,s,e){super(t,"DX7_VALIDATION_ERROR"),this.name="DX7ValidationError",this.validationType=s,this.value=e}}function O(o,t,s){return Math.max(t,Math.min(s,o))}function y(o,t,s,e=!1){const E=(o-t)/(s-t),i=(e?1-E:E)*127;return O(Math.round(i),0,127)}function W(o,t,s,e=!1){let E=O(o,0,127)/127;return e&&(E=1-E),t+E*(s-t)}function Q(o){const t={C:0,"C#":1,DB:1,D:2,"D#":3,EB:3,E:4,F:5,"F#":6,GB:6,G:7,"G#":8,AB:8,A:9,"A#":10,BB:10,B:11},s=o.match(/^([A-G][#b]?)(-?\d+)$/i);if(!s)throw new R(`Invalid note name: ${o}`,"note",o);const[,e,E]=s,r=t[e.toUpperCase()];if(r===void 0)throw new R(`Invalid note: ${e}`,"note",e);const i=(parseInt(E,10)+1)*12+r;return O(i,0,127)}function J(o,t=!1){const E=t?["C","Db","D","Eb","E","F","Gb","G","Ab","A","Bb","B"]:["C","C#","D","D#","E","F","F#","G","G#","A","A#","B"],r=Math.floor(o/12)-1;return`${E[o%12]}${r}`}function j(o){const t=69+12*Math.log2(o/440);return O(Math.round(t),0,127)}function k(o){return 440*2**((o-69)/12)}function V(o){return{0:"Bank Select",1:"Modulation",2:"Breath Controller",4:"Foot Controller",5:"Portamento Time",7:"Volume",8:"Balance",10:"Pan",11:"Expression",64:"Sustain Pedal",65:"Portamento",66:"Sostenuto",67:"Soft Pedal",68:"Legato",71:"Resonance",72:"Release Time",73:"Attack Time",74:"Cutoff",75:"Decay Time",76:"Vibrato Rate",77:"Vibrato Depth",78:"Vibrato Delay",84:"Portamento Control",91:"Reverb",92:"Tremolo",93:"Chorus",94:"Detune",95:"Phaser",120:"All Sound Off",121:"Reset All Controllers",123:"All Notes Off"}[o]||`CC ${o}`}function v(o){const t=O(Math.round(o),0,16383);return{msb:t>>7&127,lsb:t&127}}function w(o,t){return O(o,0,127)<<7|O(t,0,127)}function B(o,t,s,e=!1){const E=(o-t)/(s-t),i=(e?1-E:E)*16383;return v(i)}function X(o,t,s,e,E=!1){let i=w(o,t)/16383;return E&&(i=1-i),s+i*(e-s)}class b{constructor(){this.events=new Map}on(t,s){return this.events.has(t)||this.events.set(t,[]),this.events.get(t).push(s),()=>this.off(t,s)}once(t,s){const e=(...E)=>{s(...E),this.off(t,e)};this.on(t,e)}off(t,s){if(!this.events.has(t))return;const e=this.events.get(t),E=e.indexOf(s);E>-1&&e.splice(E,1),e.length===0&&this.events.delete(t)}emit(t,s){if(!this.events.has(t))return;[...this.events.get(t)].forEach(E=>{try{E(s)}catch(r){console.error(`Error in event handler for "${t}":`,r)}})}removeAllListeners(t){t?this.events.delete(t):this.events.clear()}}const U={DEVICE_CHANGE:"device-change",IN_DEV_CONNECTED:"in-dev-connected",IN_DEV_DISCONNECTED:"in-dev-disconnected",OUT_DEV_CONNECTED:"out-dev-connected",OUT_DEV_DISCONNECTED:"out-dev-disconnected"};class Y extends b{constructor(t={}){super(),this.options={sysex:!1,...t},this.midiAccess=null,this.output=null,this.input=null}async requestAccess(){if(!navigator.requestMIDIAccess)throw new g("Web MIDI API is not supported in this browser","unsupported");try{this.midiAccess=await navigator.requestMIDIAccess({sysex:this.options.sysex}),this.midiAccess.onstatechange=t=>{const s=t.port,e=t.port.state;this.emit(U.DEVICE_CHANGE,{port:s,state:e,type:s.type,device:{id:s.id,name:s.name,manufacturer:s.manufacturer||"Unknown"}}),e==="disconnected"?s.type==="input"?(this.emit(U.IN_DEV_DISCONNECTED,{device:s}),this.input&&this.input.id===s.id&&(this.input=null)):s.type==="output"&&(this.emit(U.OUT_DEV_DISCONNECTED,{device:s}),this.output&&this.output.id===s.id&&(this.output=null)):e==="connected"&&(s.type==="input"?this.emit(U.IN_DEV_CONNECTED,{device:s}):s.type==="output"&&this.emit(U.OUT_DEV_CONNECTED,{device:s}))}}catch(t){throw t.name==="SecurityError"?new g("MIDI access denied. SysEx requires user permission.","denied"):new g(`Failed to get MIDI access: ${t.message}`,"failed")}}async connect(t){if(!this.midiAccess)throw new G("MIDI access not initialized. Call requestAccess() first.");const s=Array.from(this.midiAccess.outputs.values());if(s.length===0)throw new L("No MIDI output devices available","output");if(t===void 0){this.output=s[0];return}if(typeof t=="number"){if(t<0||t>=s.length)throw new L(`Output index ${t} out of range (0-${s.length-1})`,"output",t);this.output=s[t];return}if(this.output=s.find(e=>e.name===t||e.id===t),!this.output){const e=s.map(E=>E.name).join(", ");throw new L(`MIDI output "${t}" not found. Available: ${e}`,"output",t)}}async connectInput(t,s){if(!this.midiAccess)throw new G("MIDI access not initialized. Call requestAccess() first.");if(typeof s!="function")throw new R("onMessage callback must be a function","callback");const e=Array.from(this.midiAccess.inputs.values());if(e.length===0)throw new L("No MIDI input devices available","input");if(this.input&&(this.input.onmidimessage=null),t===void 0)this.input=e[0];else if(typeof t=="number"){if(t<0||t>=e.length)throw new L(`Input index ${t} out of range (0-${e.length-1})`,"input",t);this.input=e[t]}else if(this.input=e.find(E=>E.name===t||E.id===t),!this.input){const E=e.map(r=>r.name).join(", ");throw new L(`MIDI input "${t}" not found. Available: ${E}`,"input",t)}this.input.onmidimessage=E=>{s(E)}}disconnectOutput(){this.output=null}disconnectInput(){this.input&&(this.input.onmidimessage=null,this.input=null)}disconnect(){this.disconnectOutput(),this.disconnectInput()}isConnected(){return this.output!==null}getCurrentOutput(){return this.output?{id:this.output.id,name:this.output.name,manufacturer:this.output.manufacturer||"Unknown"}:null}getCurrentInput(){return this.input?{id:this.input.id,name:this.input.name,manufacturer:this.input.manufacturer||"Unknown"}:null}getOutputs(){if(!this.midiAccess)return[];const t=[];return this.midiAccess.outputs.forEach(s=>{s.state==="connected"&&t.push({id:s.id,name:s.name,manufacturer:s.manufacturer||"Unknown"})}),t}getInputs(){if(!this.midiAccess)return[];const t=[];return this.midiAccess.inputs.forEach(s=>{s.state==="connected"&&t.push({id:s.id,name:s.name,manufacturer:s.manufacturer||"Unknown"})}),t}send(t,s=null){if(!this.output){console.warn("No MIDI output connected. Call connect() first.");return}try{const e=new Uint8Array(t);s===null?this.output.send(e):this.output.send(e,s)}catch(e){console.error("Failed to send MIDI message:",e)}}sendSysEx(t,s=!1){if(!this.options.sysex){console.warn("SysEx not enabled. Initialize with sysex: true");return}let e;s?e=[240,...t,247]:e=t,this.send(e)}}const A={READY:"ready",ERROR:"error",DESTROYED:"destroyed",DEV_OUT_CONNECTED:"dev-out-connected",DEV_OUT_DISCONNECTED:"dev-out-disconnected",DEV_IN_CONNECTED:"dev-in-connected",DEV_IN_DISCONNECTED:"dev-in-disconnected",CH_CC_SEND:"ch-cc-send",CH_CC_RECV:"ch-cc-recv",CH_NOTE_ON_SEND:"ch-note-on-send",CH_NOTE_ON_RECV:"ch-note-on-recv",CH_NOTE_OFF_SEND:"ch-note-off-send",CH_NOTE_OFF_RECV:"ch-note-off-recv",CH_PC_SEND:"ch-pc-send",CH_PC_RECV:"ch-pc-recv",CH_PITCH_BEND_SEND:"ch-pitch-bend-send",CH_PITCH_BEND_RECV:"ch-pitch-bend-recv",CH_MONO_PRESS_SEND:"ch-mono-press-send",CH_MONO_PRESS_RECV:"ch-mono-press-recv",CH_POLY_PRESS_SEND:"ch-poly-press-send",CH_POLY_PRESS_RECV:"ch-poly-press-recv",CH_ALL_SOUNDS_OFF_SEND:"ch-all-sounds-off-send",CH_RESET_CONTROLLERS_SEND:"ch-reset-controllers-send",CH_LOCAL_CONTROL_SEND:"ch-local-control-send",CH_ALL_NOTES_OFF_SEND:"ch-all-notes-off-send",CH_OMNI_OFF_SEND:"ch-omni-off-send",CH_OMNI_ON_SEND:"ch-omni-on-send",CH_MONO_ON_SEND:"ch-mono-on-send",CH_POLY_ON_SEND:"ch-poly-on-send",SYS_EX_SEND:"sys-ex-send",SYS_EX_RECV:"sys-ex-recv",SYS_CLOCK_RECV:"sys-clock-recv",SYS_START_RECV:"sys-start-recv",SYS_CONTINUE_RECV:"sys-continue-recv",SYS_STOP_RECV:"sys-stop-recv",SYS_MTC_RECV:"sys-mtc-recv",SYS_SONG_POS_RECV:"sys-song-pos-recv",SYS_SONG_SEL_RECV:"sys-song-sel-recv",SYS_TUNE_REQ_RECV:"sys-tune-req-recv",SYS_ACT_SENSE_RECV:"sys-act-sense-recv",SYS_RESET_RECV:"sys-reset-recv",MIDI_RAW:"midi-raw",PATCH_SAVED:"patch-saved",PATCH_LOADED:"patch-loaded",PATCH_DELETED:"patch-deleted"};class x extends b{constructor(t={}){super(),this.options={inputChannel:1,outputChannel:1,autoConnect:!0,sysex:!1,...t},this.connection=null,this.bindings=new Map,this.state={controlChange:new Map,programChange:new Map,pitchBend:new Map,monoPressure:new Map,polyPressure:new Map},this.initialized=!1,this._initNamespaces()}async init(){if(this.initialized){console.warn("MIDI Controller already initialized");return}try{this.connection=new Y({sysex:this.options.sysex}),await this.connection.requestAccess(),this.connection.on(U.DEVICE_CHANGE,async({state:t,type:s,device:e})=>{try{if(t==="connected")s==="output"?this.emit(A.DEV_OUT_CONNECTED,e):s==="input"&&this.emit(A.DEV_IN_CONNECTED,e);else if(t==="disconnected"){if(s==="output"&&e){const E=this.connection.getCurrentOutput();E&&E.id===e.id?await this._disconnectOutput():this.emit(A.DEV_OUT_DISCONNECTED,e)}if(s==="input"&&e){const E=this.connection.getCurrentInput();E&&E.id===e.id?await this._disconnectInput():this.emit(A.DEV_IN_DISCONNECTED,e)}}}catch(E){console.error("Error in device change handler:",E),this.emit(A.ERROR,E)}}),this.options.autoConnect&&await this.connection.connect(this.options.output),this.options.input!==void 0&&await this._connectInput(this.options.input),this.initialized=!0,this.emit(A.READY,this),this.options.onReady?.(this)}catch(t){throw this.emit(A.ERROR,t),this.options.onError?.(t),t}}_initNamespaces(){this.device={connect:this._connect.bind(this),disconnect:this._disconnect.bind(this),connectInput:this._connectInput.bind(this),disconnectInput:this._disconnectInput.bind(this),connectOutput:this._connectOutput.bind(this),disconnectOutput:this._disconnectOutput.bind(this),getCurrentOutput:this._getCurrentOutput.bind(this),getCurrentInput:this._getCurrentInput.bind(this),getOutputs:this._getOutputs.bind(this),getInputs:this._getInputs.bind(this)},this.channel={sendNoteOn:this._sendNoteOn.bind(this),sendNoteOff:this._sendNoteOff.bind(this),sendCC:this._sendCC.bind(this),getCC:this._getCC.bind(this),sendPC:this._sendPC.bind(this),getPC:this._getPC.bind(this),sendPitchBend:this._sendPitchBend.bind(this),getPitchBend:this._getPitchBend.bind(this),sendMonoPressure:this._sendMonoPressure.bind(this),getMonoPressure:this._getMonoPressure.bind(this),sendPolyPressure:this._sendPolyPressure.bind(this),getPolyPressure:this._getPolyPressure.bind(this),allSoundsOff:this._allSoundsOff.bind(this),resetControllers:this._resetControllers.bind(this),localControl:this._localControl.bind(this),allNotesOff:this._allNotesOff.bind(this),omniOff:this._omniOff.bind(this),omniOn:this._omniOn.bind(this),monoOn:this._monoOn.bind(this),polyOn:this._polyOn.bind(this)},this.system={sendEx:(function(t,s=!1){return this._sendSysEx(t,s)}).bind(this),sendClock:this._sendClock.bind(this),start:this._sendStart.bind(this),continue:this._sendContinue.bind(this),stop:this._sendStop.bind(this),sendMTC:this._sendMTC.bind(this),sendSongPosition:this._sendSongPosition.bind(this),sendSongSelect:this._sendSongSelect.bind(this),sendTuneRequest:this._sendTuneRequest.bind(this),sendActiveSensing:this._sendActiveSensing.bind(this),sendSystemReset:this._sendSystemReset.bind(this)},this.patch={get:this._getPatch.bind(this),set:this._setPatch.bind(this),save:this._savePatch.bind(this),load:this._loadPatch.bind(this),delete:this._deletePatch.bind(this),list:this._listPatches.bind(this)}}bind(t,s,e={}){if(!t)return console.warn("Cannot bind: element is null or undefined"),()=>{};const E=this._createBinding(t,s,e);return this.bindings.set(t,E),this.initialized&&this.connection?.isConnected()&&E.handler({target:t}),()=>this.unbind(t)}_createBinding(t,s,e={}){const{min:E=parseFloat(t.getAttribute("min"))||0,max:r=parseFloat(t.getAttribute("max"))||127,channel:i,invert:_=!1,onInput:u=void 0}=s,{debounce:N=0}=e,P={...s,min:E,max:r,invert:_,onInput:u};if(i!==void 0&&(P.channel=i),s.is14Bit){const{msb:T,lsb:I}=s,f=H=>{const z=parseFloat(H.target.value);if(Number.isNaN(z))return;const{msb:ht,lsb:St}=B(z,E,r,_),q=i||this.options.outputChannel;this._sendCC(T,ht,q),this._sendCC(I,St,q)};let K=null;const D=N>0?H=>{K&&clearTimeout(K),K=setTimeout(()=>{f(H),K=null},N)}:f;return t.addEventListener("input",D),t.addEventListener("change",D),{element:t,config:P,handler:f,destroy:()=>{K&&clearTimeout(K),t.removeEventListener("input",D),t.removeEventListener("change",D)}}}const{cc:a}=s,C=T=>{const I=parseFloat(T.target.value);if(Number.isNaN(I))return;const f=y(I,E,r,_),K=i===void 0?this.options.outputChannel:i;this._sendCC(a,f,K)};let l=null;const c=N>0?T=>{l&&clearTimeout(l),l=setTimeout(()=>{C(T),l=null},N)}:C;return t.addEventListener("input",c),t.addEventListener("change",c),{element:t,config:P,handler:C,destroy:()=>{l&&clearTimeout(l),t.removeEventListener("input",c),t.removeEventListener("change",c)}}}unbind(t){const s=this.bindings.get(t);s&&(s.destroy(),this.bindings.delete(t))}async destroy(){for(const t of this.bindings.values())t.destroy();this.bindings.clear(),this.state.controlChange.clear(),this.state.programChange.clear(),this.state.pitchBend.clear(),this.state.monoPressure.clear(),this.state.polyPressure.clear(),await this._disconnect(),this.initialized=!1,this.emit(A.DESTROYED),this.removeAllListeners()}async _connect(t){t?await this.connection.connect(t):this.options.output!==void 0?await this.connection.connect(this.options.output):this.options.autoConnect&&await this.connection.connect()}async _disconnect(){this.connection.disconnect()}async _connectInput(t){await this.connection.connectInput(t,s=>{this._handleMIDIMessage(s)}),this.emit(A.DEV_IN_CONNECTED,this.connection.getCurrentInput())}async _disconnectInput(){const t=this.connection.getCurrentInput();this.connection.disconnectInput(),this.emit(A.DEV_IN_DISCONNECTED,t)}async _connectOutput(t){await this.connection.connect(t),this.emit(A.DEV_OUT_CONNECTED,this.connection.getCurrentOutput())}async _disconnectOutput(){const t=this.connection.getCurrentOutput();this.connection.disconnectOutput(),this.emit(A.DEV_OUT_DISCONNECTED,t)}_getCurrentOutput(){return this.connection?.getCurrentOutput()||null}_getCurrentInput(){return this.connection?.getCurrentInput()||null}_getOutputs(){return this.connection?.getOutputs()||[]}_getInputs(){return this.connection?.getInputs()||[]}send(t){if(!this.initialized){console.warn("MIDI not initialized. Call init() first.");return}this.connection.send(t)}_sendNoteOn(t,s=64,e=this.options.outputChannel){if(!this.initialized)return;t=O(Math.round(t),0,127),s=O(Math.round(s),0,127),e=O(Math.round(e),1,16);const E=144+(e-1);this.connection.send([E,t,s]),this.emit(A.CH_NOTE_ON_SEND,{note:t,velocity:s,channel:e})}_sendNoteOff(t,s=this.options.outputChannel,e=0){if(!this.initialized)return;t=O(Math.round(t),0,127),e=O(Math.round(e),0,127),s=O(Math.round(s),1,16);const E=144+(s-1);this.connection.send([E,t,e]),this.emit(A.CH_NOTE_OFF_SEND,{note:t,channel:s,velocity:e})}_sendCC(t,s,e=this.options.outputChannel){if(!this.initialized){console.warn("MIDI not initialized. Call init() first.");return}t=O(Math.round(t),0,127),s=O(Math.round(s),0,127),e=O(Math.round(e),1,16);const E=176+(e-1);this.connection.send([E,t,s]);const r=`${e}:${t}`;this.state.controlChange.set(r,s),this.emit(A.CH_CC_SEND,{cc:t,value:s,channel:e})}_sendPC(t,s=this.options.outputChannel){if(!this.initialized)return;t=O(Math.round(t),0,127),s=O(Math.round(s),1,16);const e=192+(s-1);this.connection.send([e,t]),this.state.programChange.set(s.toString(),t),this.emit(A.CH_PC_SEND,{program:t,channel:s})}_getPC(t=this.options.inputChannel){return this.state.programChange.get(t.toString())}_getCC(t,s=this.options.inputChannel){const e=`${s}:${t}`;return this.state.controlChange.get(e)}_sendPitchBend(t,s=this.options.outputChannel){if(!this.initialized)return;t=O(Math.round(t),0,16383),s=O(Math.round(s),1,16);const e=224+(s-1),E=t&127,r=t>>7&127;this.connection.send([e,E,r]),this.state.pitchBend.set(s.toString(),t),this.emit(A.CH_PITCH_BEND_SEND,{value:t,channel:s})}_getPitchBend(t=this.options.inputChannel){return this.state.pitchBend.get(t.toString())}_sendMonoPressure(t,s=this.options.outputChannel){if(!this.initialized)return;t=O(Math.round(t),0,127),s=O(Math.round(s),1,16);const e=208+(s-1);this.connection.send([e,t]),this.state.monoPressure.set(s.toString(),t),this.emit(A.CH_MONO_PRESS_SEND,{pressure:t,channel:s})}_getMonoPressure(t=this.options.inputChannel){return this.state.monoPressure.get(t.toString())}_sendPolyPressure(t,s,e=this.options.outputChannel){if(!this.initialized)return;t=O(Math.round(t),0,127),s=O(Math.round(s),0,127),e=O(Math.round(e),1,16);const E=160+(e-1);this.connection.send([E,t,s]);const r=`${e}:${t}`;this.state.polyPressure.set(r,s),this.emit(A.CH_POLY_PRESS_SEND,{note:t,pressure:s,channel:e})}_getPolyPressure(t,s=this.options.inputChannel){const e=`${s}:${t}`;return this.state.polyPressure.get(e)}_allSoundsOff(t){if(!this.initialized){console.warn("MIDI not initialized. Call init() first.");return}if(t!==void 0){t=O(Math.round(t),1,16);const s=176+(t-1);this.connection.send([s,120,0]),this.emit(A.CH_ALL_SOUNDS_OFF_SEND,{channel:t})}else{for(let s=1;s<=16;s++){const e=176+(s-1);this.connection.send([e,120,0])}this.emit(A.CH_ALL_SOUNDS_OFF_SEND,{channel:null})}}_resetControllers(t){if(!this.initialized){console.warn("MIDI not initialized. Call init() first.");return}if(t!==void 0){t=O(Math.round(t),1,16);const s=176+(t-1);this.connection.send([s,121,0]),this.emit(A.CH_RESET_CONTROLLERS_SEND,{channel:t})}else{for(let s=1;s<=16;s++){const e=176+(s-1);this.connection.send([e,121,0])}this.emit(A.CH_RESET_CONTROLLERS_SEND,{channel:null})}}_localControl(t,s){if(!this.initialized){console.warn("MIDI not initialized. Call init() first.");return}const e=t?127:0;if(s!==void 0){s=O(Math.round(s),1,16);const E=176+(s-1);this.connection.send([E,122,e]),this.emit(A.CH_LOCAL_CONTROL_SEND,{enabled:t,channel:s})}else{for(let E=1;E<=16;E++){const r=176+(E-1);this.connection.send([r,122,e])}this.emit(A.CH_LOCAL_CONTROL_SEND,{enabled:t,channel:null})}}_allNotesOff(t){if(!this.initialized){console.warn("MIDI not initialized. Call init() first.");return}if(t!==void 0){t=O(Math.round(t),1,16);const s=176+(t-1);this.connection.send([s,123,0]),this.emit(A.CH_ALL_NOTES_OFF_SEND,{channel:t})}else{for(let s=1;s<=16;s++){const e=176+(s-1);this.connection.send([e,123,0])}this.emit(A.CH_ALL_NOTES_OFF_SEND,{channel:null})}}_omniOff(t){if(!this.initialized){console.warn("MIDI not initialized. Call init() first.");return}if(t!==void 0){t=O(Math.round(t),1,16);const s=176+(t-1);this.connection.send([s,124,0]),this.emit(A.CH_OMNI_OFF_SEND,{channel:t})}else{for(let s=1;s<=16;s++){const e=176+(s-1);this.connection.send([e,124,0])}this.emit(A.CH_OMNI_OFF_SEND,{channel:null})}}_omniOn(t){if(!this.initialized){console.warn("MIDI not initialized. Call init() first.");return}if(t!==void 0){t=O(Math.round(t),1,16);const s=176+(t-1);this.connection.send([s,125,0]),this.emit(A.CH_OMNI_ON_SEND,{channel:t})}else{for(let s=1;s<=16;s++){const e=176+(s-1);this.connection.send([e,125,0])}this.emit(A.CH_OMNI_ON_SEND,{channel:null})}}_monoOn(t=1,s){if(!this.initialized){console.warn("MIDI not initialized. Call init() first.");return}if(t=Math.max(0,Math.min(16,Math.round(t))),s!==void 0){s=O(Math.round(s),1,16);const e=176+(s-1);this.connection.send([e,126,t]),this.emit(A.CH_MONO_ON_SEND,{channels:t,channel:s})}else{for(let e=1;e<=16;e++){const E=176+(e-1);this.connection.send([E,126,t])}this.emit(A.CH_MONO_ON_SEND,{channels:t,channel:null})}}_polyOn(t){if(!this.initialized){console.warn("MIDI not initialized. Call init() first.");return}if(t!==void 0){t=O(Math.round(t),1,16);const s=176+(t-1);this.connection.send([s,127,0]),this.emit(A.CH_POLY_ON_SEND,{channel:t})}else{for(let s=1;s<=16;s++){const e=176+(s-1);this.connection.send([e,127,0])}this.emit(A.CH_POLY_ON_SEND,{channel:null})}}_sendSysEx(t,s=!1){if(!this.initialized){console.warn("MIDI not initialized. Call init() first.");return}if(!this.options.sysex){console.warn("SysEx not enabled. Initialize with sysex: true");return}this.connection.sendSysEx(t,s),this.emit(A.SYS_EX_SEND,{data:t,includeWrapper:s})}_sendClock(){if(!this.initialized){console.warn("MIDI not initialized. Call init() first.");return}this.connection.send([248])}_sendStart(){if(!this.initialized){console.warn("MIDI not initialized. Call init() first.");return}this.connection.send([250])}_sendContinue(){if(!this.initialized){console.warn("MIDI not initialized. Call init() first.");return}this.connection.send([251])}_sendStop(){if(!this.initialized){console.warn("MIDI not initialized. Call init() first.");return}this.connection.send([252])}_sendMTC(t){if(!this.initialized){console.warn("MIDI not initialized. Call init() first.");return}t=O(Math.round(t),0,127),this.connection.send([241,t])}_sendSongPosition(t){if(!this.initialized){console.warn("MIDI not initialized. Call init() first.");return}t=O(Math.round(t),0,16383);const s=t&127,e=t>>7&127;this.connection.send([242,s,e])}_sendSongSelect(t){if(!this.initialized){console.warn("MIDI not initialized. Call init() first.");return}t=O(Math.round(t),0,127),this.connection.send([243,t])}_sendTuneRequest(){if(!this.initialized){console.warn("MIDI not initialized. Call init() first.");return}this.connection.send([246])}_sendActiveSensing(){if(!this.initialized){console.warn("MIDI not initialized. Call init() first.");return}this.connection.send([254])}_sendSystemReset(){if(!this.initialized){console.warn("MIDI not initialized. Call init() first.");return}this.connection.send([255])}_handleMIDIMessage(t){const[s,e,E]=t.data,r=s&240,i=(s&15)+1;if(s===248){this.emit(A.SYS_CLOCK_RECV,{timestamp:t.midiwire});return}if(s===250){this.emit(A.SYS_START_RECV,{timestamp:t.midiwire});return}if(s===251){this.emit(A.SYS_CONTINUE_RECV,{timestamp:t.midiwire});return}if(s===252){this.emit(A.SYS_STOP_RECV,{timestamp:t.midiwire});return}if(s===254){this.emit(A.SYS_ACT_SENSE_RECV,{timestamp:t.midiwire});return}if(s===255){this.emit(A.SYS_RESET_RECV,{timestamp:t.midiwire});return}if(s===240){this.emit(A.SYS_EX_RECV,{data:Array.from(t.data),timestamp:t.midiwire});return}if(s===241){this.emit(A.SYS_MTC_RECV,{data:e,timestamp:t.midiwire});return}if(s===242){const _=e+(E<<7);this.emit(A.SYS_SONG_POS_RECV,{position:_,timestamp:t.midiwire});return}if(s===243){this.emit(A.SYS_SONG_SEL_RECV,{song:e,timestamp:t.midiwire});return}if(s===246){this.emit(A.SYS_TUNE_REQ_RECV,{timestamp:t.midiwire});return}if(s===247){this.emit(A.MIDI_RAW,{status:s,data:[e,E],channel:i,timestamp:t.midiwire});return}if(r===176){const _=`${i}:${e}`;this.state.controlChange.set(_,E),this.emit(A.CH_CC_RECV,{cc:e,value:E,channel:i});return}if(r===192){this.state.programChange.set(i.toString(),e),this.emit(A.CH_PC_RECV,{program:e,channel:i});return}if(r===224){const _=e+(E<<7);this.state.pitchBend.set(i.toString(),_),this.emit(A.CH_PITCH_BEND_RECV,{value:_,channel:i});return}if(r===208){this.state.monoPressure.set(i.toString(),e),this.emit(A.CH_MONO_PRESS_RECV,{pressure:e,channel:i});return}if(r===160){const _=`${i}:${e}`;this.state.polyPressure.set(_,E),this.emit(A.CH_POLY_PRESS_RECV,{note:e,pressure:E,channel:i});return}if(r===144&&E>0){this.emit(A.CH_NOTE_ON_RECV,{note:e,velocity:E,channel:i});return}if(r===128||r===144&&E===0){this.emit(A.CH_NOTE_OFF_RECV,{note:e,channel:i});return}this.emit(A.MIDI_RAW,{status:s,data:[e,E],channel:i,timestamp:t.midiwire})}_getPatch(t="Unnamed Patch"){const s={name:t,device:this._getCurrentOutput()?.name||null,timestamp:new Date().toISOString(),version:"1.0",channels:{},settings:{}};for(const[e,E]of this.state.controlChange.entries()){const[r,i]=e.split(":").map(Number);s.channels[r]||(s.channels[r]={ccs:{},notes:{}}),s.channels[r].ccs[i]=E}for(const[e,E]of this.state.programChange.entries()){const r=parseInt(e,10);s.channels[r]||(s.channels[r]={ccs:{},notes:{}}),s.channels[r].program=E}for(const[e,E]of this.state.pitchBend.entries()){const r=parseInt(e,10);s.channels[r]||(s.channels[r]={ccs:{},notes:{}}),s.channels[r].pitchBend=E}for(const[e,E]of this.state.monoPressure.entries()){const r=parseInt(e,10);s.channels[r]||(s.channels[r]={ccs:{},notes:{}}),s.channels[r].monoPressure=E}for(const[e,E]of this.state.polyPressure.entries()){const[r,i]=e.split(":").map(Number),_=parseInt(r,10);s.channels[_]||(s.channels[_]={ccs:{},notes:{}}),s.channels[_].polyPressure||(s.channels[_].polyPressure={}),s.channels[_].polyPressure[i]=E}for(const[e,E]of this.bindings.entries()){const{config:r}=E;if(r.cc){const i=`cc${r.cc}`;s.settings[i]={min:r.min,max:r.max,invert:r.invert||!1,is14Bit:r.is14Bit||!1,label:e.getAttribute?.("data-midi-label")||null,elementId:e.id||null}}}return s}async _setPatch(t){if(!t||!t.channels)throw new R("Invalid patch format","patch");const s=t.version||"1.0";s==="1.0"?await this._applyPatchV1(t):(console.warn(`Unknown patch version: ${s}. Attempting to apply as v1.0`),await this._applyPatchV1(t)),this.emit(A.PATCH_LOADED,{patch:t})}async _applyPatchV1(t){for(const[s,e]of Object.entries(t.channels)){const E=parseInt(s,10);if(e.ccs)for(const[r,i]of Object.entries(e.ccs)){const _=parseInt(r,10);this._sendCC(_,i,E)}if(e.program!==void 0&&this._sendPC(e.program,E),e.pitchBend!==void 0&&this._sendPitchBend(e.pitchBend,E),e.monoPressure!==void 0&&this._sendMonoPressure(e.monoPressure,E),e.polyPressure)for(const[r,i]of Object.entries(e.polyPressure)){const _=parseInt(r,10);this._sendPolyPressure(_,i,E)}if(e.notes)for(const[r,i]of Object.entries(e.notes)){const _=parseInt(r,10);i>0?this._sendNoteOn(_,i,E):this._sendNoteOff(_,E)}}if(t.settings)for(const[s,e]of Object.entries(t.settings))for(const[E,r]of this.bindings.entries())r.config.cc?.toString()===s.replace("cc","")&&(E.min!==void 0&&e.min!==void 0&&(E.min=String(e.min)),E.max!==void 0&&e.max!==void 0&&(E.max=String(e.max)));for(const[s,e]of this.bindings.entries()){const{config:E}=e;if(E.cc!==void 0){const r=E.channel||this.options.inputChannel,i=t.channels[r];if(i?.ccs){const _=i.ccs[E.cc];if(_!==void 0){const u=E.min!==void 0?E.min:parseFloat(s.getAttribute?.("min"))||0,N=E.max!==void 0?E.max:parseFloat(s.getAttribute?.("max"))||127,P=E.invert||!1;let a;P?a=N-_/127*(N-u):a=u+_/127*(N-u),E.onInput&&typeof E.onInput=="function"?E.onInput(a):(s.value=a,s.dispatchEvent(new Event("input",{bubbles:!0})))}}}}}_savePatch(t,s=null){const e=s||this._getPatch(t),E=`midiwire_patch_${t}`;try{return localStorage.setItem(E,JSON.stringify(e)),this.emit(A.PATCH_SAVED,{name:t,patch:e}),E}catch(r){throw console.error("Failed to save patch:",r),r}}_loadPatch(t){const s=`midiwire_patch_${t}`;try{const e=localStorage.getItem(s);if(!e)return null;const E=JSON.parse(e);return this.emit(A.PATCH_LOADED,{name:t,patch:E}),E}catch(e){return console.error("Failed to load patch:",e),null}}_deletePatch(t){const s=`midiwire_patch_${t}`;try{return localStorage.removeItem(s),this.emit(A.PATCH_DELETED,{name:t}),!0}catch(e){return console.error("Failed to delete patch:",e),!1}}_listPatches(){const t=[];try{for(let s=0;s<localStorage.length;s++){const e=localStorage.key(s);if(e?.startsWith("midiwire_patch_")){const E=e.replace("midiwire_patch_",""),r=this._loadPatch(E);r&&t.push({name:E,patch:r})}}}catch(s){console.error("Failed to list patches:",s)}return t.sort((s,e)=>s.name.localeCompare(e.name))}}class ${constructor(t={}){this.midi=t.midiController||null,this.onStatusUpdate=t.onStatusUpdate||(()=>{}),this.onConnectionUpdate=t.onConnectionUpdate||(()=>{}),this.channel=t.channel||1,this.currentOutput=null,this.currentInput=null,this.isConnecting=!1}setMIDI(t){this.midi=t}async setupSelectors(t={},s={}){if(!this.midi)throw new Error("MIDI controller not initialized. Call setMIDI() first.");const e={},{output:E,input:r,channel:i}=t,_=this._resolveSelector(E),u=this._resolveSelector(r),N=this._resolveSelector(i);if(_){e.output=_,this.setupDeviceListeners(async()=>{await this._populateOutputDeviceList(_)},e),await this._populateOutputDeviceList(_);const P=s.onConnect?async(C,l)=>s.onConnect({midi:C,device:l,type:"output"}):void 0,a=s.onDisconnect?async C=>s.onDisconnect({midi:C,type:"output"}):void 0;this._connectOutputDeviceSelection(_,P,a)}if(u){e.input=u,this.setupDeviceListeners(async()=>{await this._populateInputDeviceList(u)},e),await this._populateInputDeviceList(u);const P=s.onConnect?async(C,l)=>s.onConnect({midi:C,device:l,type:"input"}):void 0,a=s.onDisconnect?async C=>s.onDisconnect({midi:C,type:"input"}):void 0;this._connectInputDeviceSelection(u,P,a)}return N&&this._connectChannelSelection(N,"output"),this.midi}setupDeviceListeners(t,s={}){if(!this.midi)return;const e={};s.output&&(e.output=this._resolveSelector(s.output)),s.input&&(e.input=this._resolveSelector(s.input)),this.midi.on(A.DEV_OUT_CONNECTED,E=>{this.updateStatus(`Output device connected: ${E?.name||"Unknown"}`,"connected"),t&&t()}),this.midi.on(A.DEV_OUT_DISCONNECTED,E=>{this.updateStatus(`Output device disconnected: ${E?.name||"Unknown"}`,"error"),this.currentOutput&&E?.name===this.currentOutput.name&&(this.currentOutput=null,this.updateConnectionStatus(),e.output&&(e.output.value="")),t&&t()}),this.midi.on(A.DEV_IN_CONNECTED,E=>{this.updateStatus(`Input device connected: ${E?.name||"Unknown"}`,"connected"),t&&t()}),this.midi.on(A.DEV_IN_DISCONNECTED,E=>{this.updateStatus(`Input device disconnected: ${E?.name||"Unknown"}`,"error"),e.input&&(e.input.value=""),t&&t()})}updateStatus(t,s=""){this.onStatusUpdate(t,s)}updateConnectionStatus(){this.onConnectionUpdate(this.currentOutput,this.currentInput,this.midi)}_resolveSelector(t){if(typeof t=="string"){const s=document.querySelector(t);return s||console.warn(`MIDIDeviceManager: Selector "${t}" not found`),s}return t||null}_getOutputDevices(){return this.midi?this.midi.device.getOutputs():[]}_getInputDevices(){return this.midi?this.midi.device.getInputs():[]}_connectOutputDeviceSelection(t,s,e){!t||!this.midi||t.addEventListener("change",async E=>{if(this.isConnecting)return;this.isConnecting=!0;const r=E.target.value;if(!r){this.currentOutput&&this.midi&&(await this.midi.device.disconnectOutput(),this.currentOutput=null,this.updateStatus("Output device disconnected",""),this.updateConnectionStatus()),this.isConnecting=!1,e&&await e(this.midi);return}try{if(await this.midi.device.connectOutput(parseInt(r,10)),this.currentOutput=this.midi.device.getCurrentOutput(),this.currentOutput){const _=this.midi.device.getOutputs().findIndex(u=>u.id===this.currentOutput.id);_!==-1&&(t.value=_.toString())}this.updateConnectionStatus(),s&&await s(this.midi,this.currentOutput)}catch(i){this.updateStatus(`Output connection failed: ${i.message}`,"error")}finally{this.isConnecting=!1}})}_connectInputDeviceSelection(t,s,e){!t||!this.midi||t.addEventListener("change",async E=>{const r=E.target.value;if(!r){this.midi&&(await this.midi.device.disconnectInput(),this.updateStatus("Input device disconnected",""),this.updateConnectionStatus()),e&&await e(this.midi);return}if(!this.isConnecting){this.isConnecting=!0;try{await this.midi.device.connectInput(parseInt(r,10));const i=this.midi.device.getCurrentInput();this.updateConnectionStatus(),s&&await s(this.midi,i)}catch(i){this.updateStatus(`Input connection failed: ${i.message}`,"error")}finally{this.isConnecting=!1}}})}_populateDeviceList(t,s,e,E,r){if(s.length>0){if(t.innerHTML='<option value="">Select a device</option>'+s.map((i,_)=>`<option value="${_}">${i.name}</option>`).join(""),e){const i=s.findIndex(_=>_.name===e.name);i!==-1?t.value=i.toString():(t.value="",r&&(this.currentOutput=null,this.updateConnectionStatus()))}else t.value="";t.disabled=!1,r&&!this.currentOutput&&this.updateStatus("Select a device")}else t.innerHTML='<option value="">No devices connected</option>',t.disabled=!0,r&&this.updateStatus("No devices connected","error");E&&E()}async _populateOutputDeviceList(t,s){if(!t||!this.midi)return;const e=this._getOutputDevices();this._populateDeviceList(t,e,this.currentOutput,s,!0)}async _populateInputDeviceList(t,s){if(!t||!this.midi)return;const e=this._getInputDevices(),E=this.midi.device.getCurrentInput();this._populateDeviceList(t,e,E,s,!1)}_connectChannelSelection(t,s){if(!t||!this.midi)return;const e=s==="input"?"inputChannel":"outputChannel";t.addEventListener("change",E=>{this.midi&&(this.midi.options[e]=parseInt(E.target.value,10),this.updateConnectionStatus())})}}class n{static PACKED_SIZE=128;static PACKED_OP_SIZE=17;static NUM_OPERATORS=6;static PACKED_OP_EG_RATE_1=0;static PACKED_OP_EG_RATE_2=1;static PACKED_OP_EG_RATE_3=2;static PACKED_OP_EG_RATE_4=3;static PACKED_OP_EG_LEVEL_1=4;static PACKED_OP_EG_LEVEL_2=5;static PACKED_OP_EG_LEVEL_3=6;static PACKED_OP_EG_LEVEL_4=7;static PACKED_OP_BREAK_POINT=8;static PACKED_OP_L_SCALE_DEPTH=9;static PACKED_OP_R_SCALE_DEPTH=10;static PACKED_OP_CURVES=11;static PACKED_OP_RATE_SCALING=12;static PACKED_OP_MOD_SENS=13;static PACKED_OP_OUTPUT_LEVEL=14;static PACKED_OP_MODE_FREQ=15;static PACKED_OP_DETUNE_FINE=16;static PACKED_PITCH_EG_RATE_1=102;static PACKED_PITCH_EG_RATE_2=103;static PACKED_PITCH_EG_RATE_3=104;static PACKED_PITCH_EG_RATE_4=105;static PACKED_PITCH_EG_LEVEL_1=106;static PACKED_PITCH_EG_LEVEL_2=107;static PACKED_PITCH_EG_LEVEL_3=108;static PACKED_PITCH_EG_LEVEL_4=109;static OFFSET_ALGORITHM=110;static OFFSET_FEEDBACK=111;static OFFSET_LFO_SPEED=112;static OFFSET_LFO_DELAY=113;static OFFSET_LFO_PM_DEPTH=114;static OFFSET_LFO_AM_DEPTH=115;static OFFSET_LFO_SYNC_WAVE=116;static OFFSET_TRANSPOSE=117;static OFFSET_AMP_MOD_SENS=118;static OFFSET_EG_BIAS_SENS=119;static PACKED_NAME_START=118;static NAME_LENGTH=10;static UNPACKED_SIZE=169;static UNPACKED_OP_SIZE=23;static UNPACKED_OP_EG_RATE_1=0;static UNPACKED_OP_EG_RATE_2=1;static UNPACKED_OP_EG_RATE_3=2;static UNPACKED_OP_EG_RATE_4=3;static UNPACKED_OP_EG_LEVEL_1=4;static UNPACKED_OP_EG_LEVEL_2=5;static UNPACKED_OP_EG_LEVEL_3=6;static UNPACKED_OP_EG_LEVEL_4=7;static UNPACKED_OP_BREAK_POINT=8;static UNPACKED_OP_L_SCALE_DEPTH=9;static UNPACKED_OP_R_SCALE_DEPTH=10;static UNPACKED_OP_L_CURVE=11;static UNPACKED_OP_R_CURVE=12;static UNPACKED_OP_RATE_SCALING=13;static UNPACKED_OP_DETUNE=14;static UNPACKED_OP_AMP_MOD_SENS=15;static UNPACKED_OP_OUTPUT_LEVEL=16;static UNPACKED_OP_MODE=17;static UNPACKED_OP_KEY_VEL_SENS=18;static UNPACKED_OP_FREQ_COARSE=19;static UNPACKED_OP_OSC_DETUNE=20;static UNPACKED_OP_FREQ_FINE=21;static UNPACKED_PITCH_EG_RATE_1=138;static UNPACKED_PITCH_EG_RATE_2=139;static UNPACKED_PITCH_EG_RATE_3=140;static UNPACKED_PITCH_EG_RATE_4=141;static UNPACKED_PITCH_EG_LEVEL_1=142;static UNPACKED_PITCH_EG_LEVEL_2=143;static UNPACKED_PITCH_EG_LEVEL_3=144;static UNPACKED_PITCH_EG_LEVEL_4=145;static UNPACKED_ALGORITHM=146;static UNPACKED_FEEDBACK=147;static UNPACKED_OSC_SYNC=148;static UNPACKED_LFO_SPEED=149;static UNPACKED_LFO_DELAY=150;static UNPACKED_LFO_PM_DEPTH=151;static UNPACKED_LFO_AM_DEPTH=152;static UNPACKED_LFO_KEY_SYNC=153;static UNPACKED_LFO_WAVE=154;static UNPACKED_LFO_PM_SENS=155;static UNPACKED_AMP_MOD_SENS=156;static UNPACKED_TRANSPOSE=157;static UNPACKED_EG_BIAS_SENS=158;static UNPACKED_NAME_START=159;static VCED_SIZE=163;static VCED_HEADER_SIZE=6;static VCED_DATA_SIZE=155;static VCED_SYSEX_START=240;static VCED_YAMAHA_ID=67;static VCED_SUB_STATUS=0;static VCED_FORMAT_SINGLE=0;static VCED_BYTE_COUNT_MSB=1;static VCED_BYTE_COUNT_LSB=27;static VCED_SYSEX_END=247;static MASK_7BIT=127;static MASK_2BIT=3;static MASK_3BIT=7;static MASK_4BIT=15;static MASK_5BIT=31;static MASK_1BIT=1;static TRANSPOSE_CENTER=24;static CHAR_YEN=92;static CHAR_ARROW_RIGHT=126;static CHAR_ARROW_LEFT=127;static CHAR_REPLACEMENT_Y=89;static CHAR_REPLACEMENT_GT=62;static CHAR_REPLACEMENT_LT=60;static CHAR_SPACE=32;static CHAR_MIN_PRINTABLE=32;static CHAR_MAX_PRINTABLE=126;static DEFAULT_EG_RATE=99;static DEFAULT_EG_LEVEL_MAX=99;static DEFAULT_EG_LEVEL_MIN=0;static DEFAULT_BREAK_POINT=60;static DEFAULT_OUTPUT_LEVEL=99;static DEFAULT_PITCH_EG_LEVEL=50;static DEFAULT_LFO_SPEED=35;static DEFAULT_LFO_PM_SENS=3;static DEFAULT_ALGORITHM=0;static DEFAULT_FEEDBACK=0;static MIDI_OCTAVE_OFFSET=-2;static MIDI_BREAK_POINT_OFFSET=21;constructor(t,s=0){if(t.length!==n.PACKED_SIZE)throw new d(`Invalid voice data length: expected ${n.PACKED_SIZE} bytes, got ${t.length}`,"length",t.length);this.index=s,this.data=new Uint8Array(t),this.name=this._extractName(),this._unpackedCache=null}_extractName(){const t=this.data.subarray(n.PACKED_NAME_START,n.PACKED_NAME_START+n.NAME_LENGTH);return Array.from(t).map(e=>{let E=e&n.MASK_7BIT;return E===n.CHAR_YEN&&(E=n.CHAR_REPLACEMENT_Y),E===n.CHAR_ARROW_RIGHT&&(E=n.CHAR_REPLACEMENT_GT),E===n.CHAR_ARROW_LEFT&&(E=n.CHAR_REPLACEMENT_LT),(E<n.CHAR_MIN_PRINTABLE||E>n.CHAR_MAX_PRINTABLE)&&(E=n.CHAR_SPACE),String.fromCharCode(E)}).join("").trim()}getParameter(t){if(t<0||t>=n.PACKED_SIZE)throw new d(`Parameter offset out of range: ${t} (must be 0-${n.PACKED_SIZE-1})`,"offset",t);return this.data[t]&n.MASK_7BIT}getUnpackedParameter(t){if(t<0||t>=n.UNPACKED_SIZE)throw new d(`Unpacked parameter offset out of range: ${t} (must be 0-${n.UNPACKED_SIZE-1})`,"offset",t);return this._unpackedCache||(this._unpackedCache=this.unpack()),this._unpackedCache[t]&n.MASK_7BIT}setParameter(t,s){if(t<0||t>=n.PACKED_SIZE)throw new d(`Parameter offset out of range: ${t} (must be 0-${n.PACKED_SIZE-1})`,"offset",t);this.data[t]=s&n.MASK_7BIT,this._unpackedCache=null,t>=n.PACKED_NAME_START&&t<n.PACKED_NAME_START+n.NAME_LENGTH&&(this.name=this._extractName())}unpack(){const t=this.data,s=new Uint8Array(n.UNPACKED_SIZE);return this._unpackOperators(t,s),this._unpackPitchEG(t,s),this._unpackGlobalParams(t,s),this._unpackName(t,s),s}_unpackOperators(t,s){for(let e=0;e<n.NUM_OPERATORS;e++){const E=(n.NUM_OPERATORS-1-e)*n.PACKED_OP_SIZE,r=e*n.UNPACKED_OP_SIZE;this._unpackOperator(t,s,E,r)}}_unpackOperator(t,s,e,E){this._unpackOperatorEG(t,s,e,E),this._unpackOperatorScaling(t,s,e,E),this._unpackOperatorPackedParams(t,s,e,E),this._unpackOperatorFrequency(t,s,e,E)}_unpackOperatorEG(t,s,e,E){s[E+n.UNPACKED_OP_EG_RATE_1]=t[e+n.PACKED_OP_EG_RATE_1]&n.MASK_7BIT,s[E+n.UNPACKED_OP_EG_RATE_2]=t[e+n.PACKED_OP_EG_RATE_2]&n.MASK_7BIT,s[E+n.UNPACKED_OP_EG_RATE_3]=t[e+n.PACKED_OP_EG_RATE_3]&n.MASK_7BIT,s[E+n.UNPACKED_OP_EG_RATE_4]=t[e+n.PACKED_OP_EG_RATE_4]&n.MASK_7BIT,s[E+n.UNPACKED_OP_EG_LEVEL_1]=t[e+n.PACKED_OP_EG_LEVEL_1]&n.MASK_7BIT,s[E+n.UNPACKED_OP_EG_LEVEL_2]=t[e+n.PACKED_OP_EG_LEVEL_2]&n.MASK_7BIT,s[E+n.UNPACKED_OP_EG_LEVEL_3]=t[e+n.PACKED_OP_EG_LEVEL_3]&n.MASK_7BIT,s[E+n.UNPACKED_OP_EG_LEVEL_4]=t[e+n.PACKED_OP_EG_LEVEL_4]&n.MASK_7BIT}_unpackOperatorScaling(t,s,e,E){s[E+n.UNPACKED_OP_BREAK_POINT]=t[e+n.PACKED_OP_BREAK_POINT]&n.MASK_7BIT,s[E+n.UNPACKED_OP_L_SCALE_DEPTH]=t[e+n.PACKED_OP_L_SCALE_DEPTH]&n.MASK_7BIT,s[E+n.UNPACKED_OP_R_SCALE_DEPTH]=t[e+n.PACKED_OP_R_SCALE_DEPTH]&n.MASK_7BIT}_unpackOperatorPackedParams(t,s,e,E){const r=t[e+n.PACKED_OP_CURVES]&n.MASK_7BIT;s[E+n.UNPACKED_OP_L_CURVE]=r&n.MASK_2BIT,s[E+n.UNPACKED_OP_R_CURVE]=r>>2&n.MASK_2BIT;const i=t[e+n.PACKED_OP_RATE_SCALING]&n.MASK_7BIT;s[E+n.UNPACKED_OP_RATE_SCALING]=i&n.MASK_3BIT,s[E+n.UNPACKED_OP_DETUNE]=i>>3&n.MASK_4BIT;const _=t[e+n.PACKED_OP_MOD_SENS]&n.MASK_7BIT;s[E+n.UNPACKED_OP_AMP_MOD_SENS]=_&n.MASK_2BIT,s[E+n.UNPACKED_OP_KEY_VEL_SENS]=_>>2&n.MASK_3BIT,s[E+n.UNPACKED_OP_OUTPUT_LEVEL]=t[e+n.PACKED_OP_OUTPUT_LEVEL]&n.MASK_7BIT}_unpackOperatorFrequency(t,s,e,E){const r=t[e+n.PACKED_OP_MODE_FREQ]&n.MASK_7BIT;s[E+n.UNPACKED_OP_MODE]=r&n.MASK_1BIT,s[E+n.UNPACKED_OP_FREQ_COARSE]=r>>1&n.MASK_5BIT;const i=t[e+n.PACKED_OP_DETUNE_FINE]&n.MASK_7BIT;s[E+n.UNPACKED_OP_OSC_DETUNE]=i&n.MASK_3BIT,s[E+n.UNPACKED_OP_FREQ_FINE]=i>>3&n.MASK_4BIT}_unpackPitchEG(t,s){s[n.UNPACKED_PITCH_EG_RATE_1]=t[n.PACKED_PITCH_EG_RATE_1]&n.MASK_7BIT,s[n.UNPACKED_PITCH_EG_RATE_2]=t[n.PACKED_PITCH_EG_RATE_2]&n.MASK_7BIT,s[n.UNPACKED_PITCH_EG_RATE_3]=t[n.PACKED_PITCH_EG_RATE_3]&n.MASK_7BIT,s[n.UNPACKED_PITCH_EG_RATE_4]=t[n.PACKED_PITCH_EG_RATE_4]&n.MASK_7BIT,s[n.UNPACKED_PITCH_EG_LEVEL_1]=t[n.PACKED_PITCH_EG_LEVEL_1]&n.MASK_7BIT,s[n.UNPACKED_PITCH_EG_LEVEL_2]=t[n.PACKED_PITCH_EG_LEVEL_2]&n.MASK_7BIT,s[n.UNPACKED_PITCH_EG_LEVEL_3]=t[n.PACKED_PITCH_EG_LEVEL_3]&n.MASK_7BIT,s[n.UNPACKED_PITCH_EG_LEVEL_4]=t[n.PACKED_PITCH_EG_LEVEL_4]&n.MASK_7BIT}_unpackGlobalParams(t,s){s[n.UNPACKED_ALGORITHM]=t[n.OFFSET_ALGORITHM]&n.MASK_5BIT;const e=t[n.OFFSET_FEEDBACK]&n.MASK_7BIT;s[n.UNPACKED_FEEDBACK]=e&n.MASK_3BIT,s[n.UNPACKED_OSC_SYNC]=e>>3&n.MASK_1BIT,s[n.UNPACKED_LFO_SPEED]=t[n.OFFSET_LFO_SPEED]&n.MASK_7BIT,s[n.UNPACKED_LFO_DELAY]=t[n.OFFSET_LFO_DELAY]&n.MASK_7BIT,s[n.UNPACKED_LFO_PM_DEPTH]=t[n.OFFSET_LFO_PM_DEPTH]&n.MASK_7BIT,s[n.UNPACKED_LFO_AM_DEPTH]=t[n.OFFSET_LFO_AM_DEPTH]&n.MASK_7BIT;const E=t[n.OFFSET_LFO_SYNC_WAVE]&n.MASK_7BIT;s[n.UNPACKED_LFO_KEY_SYNC]=E&n.MASK_1BIT,s[n.UNPACKED_LFO_WAVE]=E>>1&n.MASK_3BIT,s[n.UNPACKED_LFO_PM_SENS]=E>>4&n.MASK_3BIT,s[n.UNPACKED_AMP_MOD_SENS]=t[n.OFFSET_AMP_MOD_SENS]&n.MASK_7BIT,s[n.UNPACKED_TRANSPOSE]=t[n.OFFSET_TRANSPOSE]&n.MASK_7BIT,s[n.UNPACKED_EG_BIAS_SENS]=t[n.OFFSET_EG_BIAS_SENS]&n.MASK_7BIT}_unpackName(t,s){for(let e=0;e<n.NAME_LENGTH;e++)s[n.UNPACKED_NAME_START+e]=t[n.PACKED_NAME_START+e]&n.MASK_7BIT}static pack(t){if(t.length!==n.UNPACKED_SIZE)throw new d(`Invalid unpacked data length: expected ${n.UNPACKED_SIZE} bytes, got ${t.length}`,"length",t.length);const s=new Uint8Array(n.PACKED_SIZE);return n._packOperators(t,s),n._packPitchEG(t,s),n._packGlobalParams(t,s),n._packName(t,s),s}static _packOperators(t,s){for(let e=0;e<n.NUM_OPERATORS;e++){const E=e*n.UNPACKED_OP_SIZE,r=(n.NUM_OPERATORS-1-e)*n.PACKED_OP_SIZE;n._packOperator(t,s,E,r)}}static _packOperator(t,s,e,E){n._packOperatorEG(t,s,e,E),n._packOperatorScaling(t,s,e,E),n._packOperatorPackedParams(t,s,e,E),n._packOperatorFrequency(t,s,e,E)}static _packOperatorEG(t,s,e,E){s[E+n.PACKED_OP_EG_RATE_1]=t[e+n.UNPACKED_OP_EG_RATE_1],s[E+n.PACKED_OP_EG_RATE_2]=t[e+n.UNPACKED_OP_EG_RATE_2],s[E+n.PACKED_OP_EG_RATE_3]=t[e+n.UNPACKED_OP_EG_RATE_3],s[E+n.PACKED_OP_EG_RATE_4]=t[e+n.UNPACKED_OP_EG_RATE_4],s[E+n.PACKED_OP_EG_LEVEL_1]=t[e+n.UNPACKED_OP_EG_LEVEL_1],s[E+n.PACKED_OP_EG_LEVEL_2]=t[e+n.UNPACKED_OP_EG_LEVEL_2],s[E+n.PACKED_OP_EG_LEVEL_3]=t[e+n.UNPACKED_OP_EG_LEVEL_3],s[E+n.PACKED_OP_EG_LEVEL_4]=t[e+n.UNPACKED_OP_EG_LEVEL_4]}static _packOperatorScaling(t,s,e,E){s[E+n.PACKED_OP_BREAK_POINT]=t[e+n.UNPACKED_OP_BREAK_POINT],s[E+n.PACKED_OP_L_SCALE_DEPTH]=t[e+n.UNPACKED_OP_L_SCALE_DEPTH],s[E+n.PACKED_OP_R_SCALE_DEPTH]=t[e+n.UNPACKED_OP_R_SCALE_DEPTH]}static _packOperatorPackedParams(t,s,e,E){const r=t[e+n.UNPACKED_OP_L_CURVE]&n.MASK_2BIT,i=t[e+n.UNPACKED_OP_R_CURVE]&n.MASK_2BIT;s[E+n.PACKED_OP_CURVES]=r|i<<2;const _=t[e+n.UNPACKED_OP_RATE_SCALING]&n.MASK_3BIT,u=t[e+n.UNPACKED_OP_DETUNE]&n.MASK_4BIT;s[E+n.PACKED_OP_RATE_SCALING]=_|u<<3;const N=t[e+n.UNPACKED_OP_AMP_MOD_SENS]&n.MASK_2BIT,P=t[e+n.UNPACKED_OP_KEY_VEL_SENS]&n.MASK_3BIT;s[E+n.PACKED_OP_MOD_SENS]=N|P<<2,s[E+n.PACKED_OP_OUTPUT_LEVEL]=t[e+n.UNPACKED_OP_OUTPUT_LEVEL]}static _packOperatorFrequency(t,s,e,E){const r=t[e+n.UNPACKED_OP_MODE]&n.MASK_1BIT,i=t[e+n.UNPACKED_OP_FREQ_COARSE]&n.MASK_5BIT;s[E+n.PACKED_OP_MODE_FREQ]=r|i<<1;const _=t[e+n.UNPACKED_OP_OSC_DETUNE]&n.MASK_3BIT,u=t[e+n.UNPACKED_OP_FREQ_FINE]&n.MASK_4BIT;s[E+n.PACKED_OP_DETUNE_FINE]=_|u<<3}static _packPitchEG(t,s){s[n.PACKED_PITCH_EG_RATE_1]=t[n.UNPACKED_PITCH_EG_RATE_1],s[n.PACKED_PITCH_EG_RATE_2]=t[n.UNPACKED_PITCH_EG_RATE_2],s[n.PACKED_PITCH_EG_RATE_3]=t[n.UNPACKED_PITCH_EG_RATE_3],s[n.PACKED_PITCH_EG_RATE_4]=t[n.UNPACKED_PITCH_EG_RATE_4],s[n.PACKED_PITCH_EG_LEVEL_1]=t[n.UNPACKED_PITCH_EG_LEVEL_1],s[n.PACKED_PITCH_EG_LEVEL_2]=t[n.UNPACKED_PITCH_EG_LEVEL_2],s[n.PACKED_PITCH_EG_LEVEL_3]=t[n.UNPACKED_PITCH_EG_LEVEL_3],s[n.PACKED_PITCH_EG_LEVEL_4]=t[n.UNPACKED_PITCH_EG_LEVEL_4]}static _packGlobalParams(t,s){s[n.OFFSET_ALGORITHM]=t[n.UNPACKED_ALGORITHM];const e=t[n.UNPACKED_FEEDBACK]&n.MASK_3BIT,E=t[n.UNPACKED_OSC_SYNC]&n.MASK_1BIT;s[n.OFFSET_FEEDBACK]=e|E<<3,s[n.OFFSET_LFO_SPEED]=t[n.UNPACKED_LFO_SPEED],s[n.OFFSET_LFO_DELAY]=t[n.UNPACKED_LFO_DELAY],s[n.OFFSET_LFO_PM_DEPTH]=t[n.UNPACKED_LFO_PM_DEPTH],s[n.OFFSET_LFO_AM_DEPTH]=t[n.UNPACKED_LFO_AM_DEPTH];const r=t[n.UNPACKED_LFO_KEY_SYNC]&n.MASK_1BIT,i=t[n.UNPACKED_LFO_WAVE]&n.MASK_3BIT,_=t[n.UNPACKED_LFO_PM_SENS]&n.MASK_3BIT;s[n.OFFSET_LFO_SYNC_WAVE]=r|i<<1|_<<4,s[n.OFFSET_AMP_MOD_SENS]=t[n.UNPACKED_AMP_MOD_SENS],s[n.OFFSET_TRANSPOSE]=t[n.UNPACKED_TRANSPOSE],s[n.OFFSET_EG_BIAS_SENS]=t[n.UNPACKED_EG_BIAS_SENS]}static _packName(t,s){for(let e=0;e<n.NAME_LENGTH;e++)s[n.PACKED_NAME_START+e]=t[n.UNPACKED_NAME_START+e]}static createDefault(t=0){const s=new Uint8Array(n.UNPACKED_SIZE);for(let r=0;r<n.NUM_OPERATORS;r++){const i=r*n.UNPACKED_OP_SIZE;s[i+n.UNPACKED_OP_EG_RATE_1]=n.DEFAULT_EG_RATE,s[i+n.UNPACKED_OP_EG_RATE_2]=n.DEFAULT_EG_RATE,s[i+n.UNPACKED_OP_EG_RATE_3]=n.DEFAULT_EG_RATE,s[i+n.UNPACKED_OP_EG_RATE_4]=n.DEFAULT_EG_RATE,s[i+n.UNPACKED_OP_EG_LEVEL_1]=n.DEFAULT_EG_LEVEL_MAX,s[i+n.UNPACKED_OP_EG_LEVEL_2]=n.DEFAULT_EG_LEVEL_MAX,s[i+n.UNPACKED_OP_EG_LEVEL_3]=n.DEFAULT_EG_LEVEL_MAX,s[i+n.UNPACKED_OP_EG_LEVEL_4]=n.DEFAULT_EG_LEVEL_MIN,s[i+n.UNPACKED_OP_BREAK_POINT]=n.DEFAULT_BREAK_POINT,s[i+n.UNPACKED_OP_L_SCALE_DEPTH]=0,s[i+n.UNPACKED_OP_R_SCALE_DEPTH]=0,s[i+n.UNPACKED_OP_L_CURVE]=0,s[i+n.UNPACKED_OP_R_CURVE]=0,s[i+n.UNPACKED_OP_RATE_SCALING]=0,s[i+n.UNPACKED_OP_DETUNE]=7,s[i+n.UNPACKED_OP_AMP_MOD_SENS]=0,s[i+n.UNPACKED_OP_KEY_VEL_SENS]=0,s[i+n.UNPACKED_OP_OUTPUT_LEVEL]=n.DEFAULT_OUTPUT_LEVEL,s[i+n.UNPACKED_OP_MODE]=0,s[i+n.UNPACKED_OP_FREQ_COARSE]=0,s[i+n.UNPACKED_OP_OSC_DETUNE]=0,s[i+n.UNPACKED_OP_FREQ_FINE]=0}s[n.UNPACKED_PITCH_EG_RATE_1]=n.DEFAULT_EG_RATE,s[n.UNPACKED_PITCH_EG_RATE_2]=n.DEFAULT_EG_RATE,s[n.UNPACKED_PITCH_EG_RATE_3]=n.DEFAULT_EG_RATE,s[n.UNPACKED_PITCH_EG_RATE_4]=n.DEFAULT_EG_RATE,s[n.UNPACKED_PITCH_EG_LEVEL_1]=n.DEFAULT_PITCH_EG_LEVEL,s[n.UNPACKED_PITCH_EG_LEVEL_2]=n.DEFAULT_PITCH_EG_LEVEL,s[n.UNPACKED_PITCH_EG_LEVEL_3]=n.DEFAULT_PITCH_EG_LEVEL,s[n.UNPACKED_PITCH_EG_LEVEL_4]=n.DEFAULT_PITCH_EG_LEVEL,s[n.UNPACKED_ALGORITHM]=n.DEFAULT_ALGORITHM,s[n.UNPACKED_FEEDBACK]=n.DEFAULT_FEEDBACK,s[n.UNPACKED_OSC_SYNC]=0,s[n.UNPACKED_LFO_SPEED]=n.DEFAULT_LFO_SPEED,s[n.UNPACKED_LFO_DELAY]=0,s[n.UNPACKED_LFO_PM_DEPTH]=0,s[n.UNPACKED_LFO_AM_DEPTH]=0,s[n.UNPACKED_LFO_KEY_SYNC]=0,s[n.UNPACKED_LFO_WAVE]=0,s[n.UNPACKED_LFO_PM_SENS]=n.DEFAULT_LFO_PM_SENS,s[n.UNPACKED_AMP_MOD_SENS]=0,s[n.UNPACKED_TRANSPOSE]=n.TRANSPOSE_CENTER,s[n.UNPACKED_EG_BIAS_SENS]=0;const e="Init Voice";for(let r=0;r<n.NAME_LENGTH;r++)s[n.UNPACKED_NAME_START+r]=r<e.length?e.charCodeAt(r):n.CHAR_SPACE;const E=n.pack(s);return new n(E,t)}static fromUnpacked(t,s=0){const e=n.pack(t);return new n(e,s)}static async fromFile(t){return new Promise((s,e)=>{const E=new FileReader;E.onload=r=>{try{const i=new Uint8Array(r.target.result);if(i[0]!==n.VCED_SYSEX_START||i[1]!==n.VCED_YAMAHA_ID||i[2]!==n.VCED_SUB_STATUS||i[3]!==n.VCED_FORMAT_SINGLE||i[4]!==n.VCED_BYTE_COUNT_MSB||i[5]!==n.VCED_BYTE_COUNT_LSB)throw new M("Invalid VCED header","header",0);const _=i.subarray(n.VCED_HEADER_SIZE,n.VCED_HEADER_SIZE+n.VCED_DATA_SIZE),u=i[n.VCED_HEADER_SIZE+n.VCED_DATA_SIZE],N=h._calculateChecksum(_,n.VCED_DATA_SIZE);u!==N&&console.warn(`DX7 VCED checksum mismatch (expected ${N.toString(16)}, got ${u.toString(16)}). This is common with vintage SysEx files.`);const P=new Uint8Array(n.UNPACKED_SIZE);let a=0;for(let l=0;l<n.NUM_OPERATORS;l++){const c=(n.NUM_OPERATORS-1-l)*n.UNPACKED_OP_SIZE;P[c+n.UNPACKED_OP_EG_RATE_1]=_[a++],P[c+n.UNPACKED_OP_EG_RATE_2]=_[a++],P[c+n.UNPACKED_OP_EG_RATE_3]=_[a++],P[c+n.UNPACKED_OP_EG_RATE_4]=_[a++],P[c+n.UNPACKED_OP_EG_LEVEL_1]=_[a++],P[c+n.UNPACKED_OP_EG_LEVEL_2]=_[a++],P[c+n.UNPACKED_OP_EG_LEVEL_3]=_[a++],P[c+n.UNPACKED_OP_EG_LEVEL_4]=_[a++],P[c+n.UNPACKED_OP_BREAK_POINT]=_[a++],P[c+n.UNPACKED_OP_L_SCALE_DEPTH]=_[a++],P[c+n.UNPACKED_OP_R_SCALE_DEPTH]=_[a++],P[c+n.UNPACKED_OP_L_CURVE]=_[a++],P[c+n.UNPACKED_OP_R_CURVE]=_[a++],P[c+n.UNPACKED_OP_RATE_SCALING]=_[a++],P[c+n.UNPACKED_OP_DETUNE]=_[a++];const T=_[a++];P[c+n.UNPACKED_OP_AMP_MOD_SENS]=T&n.MASK_2BIT,P[c+n.UNPACKED_OP_KEY_VEL_SENS]=T>>2&n.MASK_3BIT,P[c+n.UNPACKED_OP_OUTPUT_LEVEL]=_[a++],P[c+n.UNPACKED_OP_MODE]=_[a++],P[c+n.UNPACKED_OP_FREQ_COARSE]=_[a++],P[c+n.UNPACKED_OP_FREQ_FINE]=_[a++],P[c+n.UNPACKED_OP_OSC_DETUNE]=_[a++]}P[n.UNPACKED_PITCH_EG_RATE_1]=_[a++],P[n.UNPACKED_PITCH_EG_RATE_2]=_[a++],P[n.UNPACKED_PITCH_EG_RATE_3]=_[a++],P[n.UNPACKED_PITCH_EG_RATE_4]=_[a++],P[n.UNPACKED_PITCH_EG_LEVEL_1]=_[a++],P[n.UNPACKED_PITCH_EG_LEVEL_2]=_[a++],P[n.UNPACKED_PITCH_EG_LEVEL_3]=_[a++],P[n.UNPACKED_PITCH_EG_LEVEL_4]=_[a++],P[n.UNPACKED_ALGORITHM]=_[a++],P[n.UNPACKED_FEEDBACK]=_[a++],P[n.UNPACKED_OSC_SYNC]=_[a++],P[n.UNPACKED_LFO_SPEED]=_[a++],P[n.UNPACKED_LFO_DELAY]=_[a++],P[n.UNPACKED_LFO_PM_DEPTH]=_[a++],P[n.UNPACKED_LFO_AM_DEPTH]=_[a++],P[n.UNPACKED_LFO_KEY_SYNC]=_[a++],P[n.UNPACKED_LFO_WAVE]=_[a++],P[n.UNPACKED_LFO_PM_SENS]=_[a++],P[n.UNPACKED_TRANSPOSE]=_[a++];for(let l=0;l<n.NAME_LENGTH;l++)P[n.UNPACKED_NAME_START+l]=_[a++];const C=n.pack(P);s(new n(C,0))}catch(i){e(i)}},E.onerror=()=>e(new Error("Failed to read file")),E.readAsArrayBuffer(t)})}static fromSysEx(t,s=0){const e=t instanceof Uint8Array?t:new Uint8Array(t);let E;if(e[0]===n.VCED_SYSEX_START){if(e[0]!==n.VCED_SYSEX_START||e[1]!==n.VCED_YAMAHA_ID||e[2]!==n.VCED_SUB_STATUS||e[3]!==n.VCED_FORMAT_SINGLE||e[4]!==n.VCED_BYTE_COUNT_MSB||e[5]!==n.VCED_BYTE_COUNT_LSB)throw new M("Invalid VCED header","header",0);E=e.subarray(n.VCED_HEADER_SIZE,n.VCED_HEADER_SIZE+n.VCED_DATA_SIZE)}else if(e.length===n.PACKED_SIZE)E=e;else throw new d(`Invalid data length: expected ${n.PACKED_SIZE} or ${n.VCED_SIZE} bytes, got ${e.length}`,"length",e.length);if(E.length!==n.VCED_DATA_SIZE&&E.length!==n.PACKED_SIZE)throw new d(`Invalid voice data length: expected ${n.VCED_DATA_SIZE} or ${n.PACKED_SIZE} bytes, got ${E.length}`,"length",E.length);if(E.length===n.VCED_DATA_SIZE){const r=new Uint8Array(n.UNPACKED_SIZE);let i=0;for(let u=0;u<n.NUM_OPERATORS;u++){const N=(n.NUM_OPERATORS-1-u)*n.UNPACKED_OP_SIZE;r[N+n.UNPACKED_OP_EG_RATE_1]=E[i++],r[N+n.UNPACKED_OP_EG_RATE_2]=E[i++],r[N+n.UNPACKED_OP_EG_RATE_3]=E[i++],r[N+n.UNPACKED_OP_EG_RATE_4]=E[i++],r[N+n.UNPACKED_OP_EG_LEVEL_1]=E[i++],r[N+n.UNPACKED_OP_EG_LEVEL_2]=E[i++],r[N+n.UNPACKED_OP_EG_LEVEL_3]=E[i++],r[N+n.UNPACKED_OP_EG_LEVEL_4]=E[i++],r[N+n.UNPACKED_OP_BREAK_POINT]=E[i++],r[N+n.UNPACKED_OP_L_SCALE_DEPTH]=E[i++],r[N+n.UNPACKED_OP_R_SCALE_DEPTH]=E[i++],r[N+n.UNPACKED_OP_L_CURVE]=E[i++],r[N+n.UNPACKED_OP_R_CURVE]=E[i++],r[N+n.UNPACKED_OP_RATE_SCALING]=E[i++],r[N+n.UNPACKED_OP_DETUNE]=E[i++];const P=E[i++];r[N+n.UNPACKED_OP_AMP_MOD_SENS]=P&n.MASK_2BIT,r[N+n.UNPACKED_OP_KEY_VEL_SENS]=P>>2&n.MASK_3BIT,r[N+n.UNPACKED_OP_OUTPUT_LEVEL]=E[i++],r[N+n.UNPACKED_OP_MODE]=E[i++],r[N+n.UNPACKED_OP_FREQ_COARSE]=E[i++],r[N+n.UNPACKED_OP_FREQ_FINE]=E[i++],r[N+n.UNPACKED_OP_OSC_DETUNE]=E[i++]}r[n.UNPACKED_PITCH_EG_RATE_1]=E[i++],r[n.UNPACKED_PITCH_EG_RATE_2]=E[i++],r[n.UNPACKED_PITCH_EG_RATE_3]=E[i++],r[n.UNPACKED_PITCH_EG_RATE_4]=E[i++],r[n.UNPACKED_PITCH_EG_LEVEL_1]=E[i++],r[n.UNPACKED_PITCH_EG_LEVEL_2]=E[i++],r[n.UNPACKED_PITCH_EG_LEVEL_3]=E[i++],r[n.UNPACKED_PITCH_EG_LEVEL_4]=E[i++],r[n.UNPACKED_ALGORITHM]=E[i++],r[n.UNPACKED_FEEDBACK]=E[i++],r[n.UNPACKED_OSC_SYNC]=E[i++],r[n.UNPACKED_LFO_SPEED]=E[i++],r[n.UNPACKED_LFO_DELAY]=E[i++],r[n.UNPACKED_LFO_PM_DEPTH]=E[i++],r[n.UNPACKED_LFO_AM_DEPTH]=E[i++],r[n.UNPACKED_LFO_KEY_SYNC]=E[i++],r[n.UNPACKED_LFO_WAVE]=E[i++],r[n.UNPACKED_LFO_PM_SENS]=E[i++],r[n.UNPACKED_TRANSPOSE]=E[i++];for(let u=0;u<n.NAME_LENGTH;u++)r[n.UNPACKED_NAME_START+u]=E[i++];const _=n.pack(r);return new n(_,s)}return new n(E,s)}static fromJSON(t,s=0){if(!t||typeof t!="object")throw new d("Invalid JSON: expected object","json",t);const e=new Uint8Array(n.UNPACKED_SIZE),E=(a,C,l,c=0,T=127)=>{if(C==null)throw new d(`Missing required parameter: ${l}`,l,C);const I=Number(C);if(Number.isNaN(I))throw new d(`Invalid parameter value for ${l}: ${C}`,l,C);if(I<c||I>T)throw new d(`Parameter ${l} out of range: ${I} (must be ${c}-${T})`,l,I);e[a]=Math.floor(I)},r=a=>{const C={"-LN":0,"-EX":1,"+EX":2,"+LN":3};return C[a]!==void 0?C[a]:0},i=a=>{const C={TRIANGLE:0,"SAW DOWN":1,"SAW UP":2,SQUARE:3,SINE:4,"SAMPLE & HOLD":5};return C[a]!==void 0?C[a]:0},_=a=>{if(!a||typeof a!="string")return 60;const C=a.trim().match(/^([A-G]#?)(-?\d+)$/);if(!C)return 60;const[,l,c]=C,T=parseInt(c,10),f={C:0,"C#":1,D:2,"D#":3,E:4,F:5,"F#":6,G:7,"G#":8,A:9,"A#":10,B:11}[l.toUpperCase()];return f===void 0?60:(T-n.MIDI_OCTAVE_OFFSET)*12+f};if(!Array.isArray(t.operators))throw new d("Invalid operators array: expected array","operators",t.operators);for(let a=0;a<t.operators.length;a++){const C=t.operators[a];if(!C||typeof C!="object")throw new d(`Invalid operator data at index ${a}`,`operators[${a}]`,C);if(!C.eg||!Array.isArray(C.eg.rates)||C.eg.rates.length!==4)throw new d(`Invalid EG rates for operator ${a}`,`operators[${a}].eg.rates`,C.eg?.rates);if(!C.eg||!Array.isArray(C.eg.levels)||C.eg.levels.length!==4)throw new d(`Invalid EG levels for operator ${a}`,`operators[${a}].eg.levels`,C.eg?.levels)}if(t.operators.length!==n.NUM_OPERATORS)throw new d(`Invalid operators array: expected ${n.NUM_OPERATORS} operators`,"operators",t.operators);for(let a=0;a<n.NUM_OPERATORS;a++){const C=t.operators[a],l=a*n.UNPACKED_OP_SIZE;if(!C.eg||!Array.isArray(C.eg.rates)||C.eg.rates.length!==4)throw new d(`Invalid EG rates for operator ${a}`,`operators[${a}].eg.rates`,C.eg?.rates);if(E(l+n.UNPACKED_OP_EG_RATE_1,C.eg.rates[0],`operators[${a}].eg.rates[0]`,0,99),E(l+n.UNPACKED_OP_EG_RATE_2,C.eg.rates[1],`operators[${a}].eg.rates[1]`,0,99),E(l+n.UNPACKED_OP_EG_RATE_3,C.eg.rates[2],`operators[${a}].eg.rates[2]`,0,99),E(l+n.UNPACKED_OP_EG_RATE_4,C.eg.rates[3],`operators[${a}].eg.rates[3]`,0,99),!C.eg||!Array.isArray(C.eg.levels)||C.eg.levels.length!==4)throw new d(`Invalid EG levels for operator ${a}`,`operators[${a}].eg.levels`,C.eg?.levels);E(l+n.UNPACKED_OP_EG_LEVEL_1,C.eg.levels[0],`operators[${a}].eg.levels[0]`,0,99),E(l+n.UNPACKED_OP_EG_LEVEL_2,C.eg.levels[1],`operators[${a}].eg.levels[1]`,0,99),E(l+n.UNPACKED_OP_EG_LEVEL_3,C.eg.levels[2],`operators[${a}].eg.levels[2]`,0,99),E(l+n.UNPACKED_OP_EG_LEVEL_4,C.eg.levels[3],`operators[${a}].eg.levels[3]`,0,99);const c=_(C.key?.breakPoint)-n.MIDI_BREAK_POINT_OFFSET;E(l+n.UNPACKED_OP_BREAK_POINT,c,`operators[${a}].key.breakPoint`,0,127),E(l+n.UNPACKED_OP_L_SCALE_DEPTH,C.scale?.left?.depth||0,`operators[${a}].scale.left.depth`,0,99),E(l+n.UNPACKED_OP_R_SCALE_DEPTH,C.scale?.right?.depth||0,`operators[${a}].scale.right.depth`,0,99),e[l+n.UNPACKED_OP_L_CURVE]=r(C.scale?.left?.curve||"-LN"),e[l+n.UNPACKED_OP_R_CURVE]=r(C.scale?.right?.curve||"-LN"),E(l+n.UNPACKED_OP_RATE_SCALING,C.key?.scaling||0,`operators[${a}].key.scaling`,0,7);const T=Number(C.osc?.detune)||0;E(l+n.UNPACKED_OP_DETUNE,T+7,`operators[${a}].osc.detune`,0,14),E(l+n.UNPACKED_OP_AMP_MOD_SENS,C.output?.ampModSens||0,`operators[${a}].output.ampModSens`,0,3),E(l+n.UNPACKED_OP_OUTPUT_LEVEL,C.output?.level||0,`operators[${a}].output.level`,0,99);const I=C.osc?.freq?.mode?.toUpperCase()==="FIXED"?1:0,f=Number(C.osc?.freq?.coarse)||0,K=Number(C.osc?.freq?.fine)||0;e[l+n.UNPACKED_OP_MODE]=I,E(l+n.UNPACKED_OP_FREQ_COARSE,f,`operators[${a}].osc.freq.coarse`,0,31),E(l+n.UNPACKED_OP_FREQ_FINE,K,`operators[${a}].osc.freq.fine`,0,15),E(l+n.UNPACKED_OP_KEY_VEL_SENS,C.key?.velocity||0,`operators[${a}].key.velocity`,0,7)}if(!t.pitchEG||!Array.isArray(t.pitchEG.rates)||t.pitchEG.rates.length!==4)throw new d("Invalid pitch EG rates","pitchEG.rates",t.pitchEG?.rates);if(!t.pitchEG||!Array.isArray(t.pitchEG.levels)||t.pitchEG.levels.length!==4)throw new d("Invalid pitch EG levels","pitchEG.levels",t.pitchEG?.levels);if(E(n.UNPACKED_PITCH_EG_RATE_1,t.pitchEG.rates[0],"pitchEG.rates[0]",0,99),E(n.UNPACKED_PITCH_EG_RATE_2,t.pitchEG.rates[1],"pitchEG.rates[1]",0,99),E(n.UNPACKED_PITCH_EG_RATE_3,t.pitchEG.rates[2],"pitchEG.rates[2]",0,99),E(n.UNPACKED_PITCH_EG_RATE_4,t.pitchEG.rates[3],"pitchEG.rates[3]",0,99),E(n.UNPACKED_PITCH_EG_LEVEL_1,t.pitchEG.levels[0],"pitchEG.levels[0]",0,99),E(n.UNPACKED_PITCH_EG_LEVEL_2,t.pitchEG.levels[1],"pitchEG.levels[1]",0,99),E(n.UNPACKED_PITCH_EG_LEVEL_3,t.pitchEG.levels[2],"pitchEG.levels[2]",0,99),E(n.UNPACKED_PITCH_EG_LEVEL_4,t.pitchEG.levels[3],"pitchEG.levels[3]",0,99),!t.lfo||typeof t.lfo!="object")throw new d("Invalid LFO data","lfo",t.lfo);if(E(n.UNPACKED_LFO_SPEED,t.lfo.speed,"lfo.speed",0,99),E(n.UNPACKED_LFO_DELAY,t.lfo.delay,"lfo.delay",0,99),E(n.UNPACKED_LFO_PM_DEPTH,t.lfo.pmDepth,"lfo.pmDepth",0,99),E(n.UNPACKED_LFO_AM_DEPTH,t.lfo.amDepth,"lfo.amDepth",0,99),e[n.UNPACKED_LFO_KEY_SYNC]=t.lfo.keySync?1:0,e[n.UNPACKED_LFO_WAVE]=i(t.lfo.wave),!t.global||typeof t.global!="object")throw new d("Invalid global data","global",t.global);const u=Number(t.global.algorithm)||1;E(n.UNPACKED_ALGORITHM,u-1,"global.algorithm",0,31),E(n.UNPACKED_FEEDBACK,t.global.feedback,"global.feedback",0,7),e[n.UNPACKED_OSC_SYNC]=t.global.oscKeySync?1:0,E(n.UNPACKED_LFO_PM_SENS,t.global.pitchModSens,"global.pitchModSens",0,7);const N=Number(t.global.transpose)||0;E(n.UNPACKED_TRANSPOSE,N+n.TRANSPOSE_CENTER,"global.transpose",0,127),E(n.UNPACKED_AMP_MOD_SENS,t.global.ampModSens||0,"global.ampModSens",0,3),E(n.UNPACKED_EG_BIAS_SENS,t.global.egBiasSens||0,"global.egBiasSens",0,7);const P=t.name||"";for(let a=0;a<n.NAME_LENGTH;a++)e[n.UNPACKED_NAME_START+a]=a<P.length?P.charCodeAt(a):n.CHAR_SPACE;return n.fromUnpacked(e,s)}toSysEx(){const t=this.unpack(),s=new Uint8Array(n.VCED_SIZE);let e=0;s[e++]=n.VCED_SYSEX_START,s[e++]=n.VCED_YAMAHA_ID,s[e++]=n.VCED_SUB_STATUS,s[e++]=n.VCED_FORMAT_SINGLE,s[e++]=n.VCED_BYTE_COUNT_MSB,s[e++]=n.VCED_BYTE_COUNT_LSB;for(let r=n.NUM_OPERATORS-1;r>=0;r--){const i=r*n.UNPACKED_OP_SIZE;s[e++]=t[i+n.UNPACKED_OP_EG_RATE_1],s[e++]=t[i+n.UNPACKED_OP_EG_RATE_2],s[e++]=t[i+n.UNPACKED_OP_EG_RATE_3],s[e++]=t[i+n.UNPACKED_OP_EG_RATE_4],s[e++]=t[i+n.UNPACKED_OP_EG_LEVEL_1],s[e++]=t[i+n.UNPACKED_OP_EG_LEVEL_2],s[e++]=t[i+n.UNPACKED_OP_EG_LEVEL_3],s[e++]=t[i+n.UNPACKED_OP_EG_LEVEL_4],s[e++]=t[i+n.UNPACKED_OP_BREAK_POINT],s[e++]=t[i+n.UNPACKED_OP_L_SCALE_DEPTH],s[e++]=t[i+n.UNPACKED_OP_R_SCALE_DEPTH],s[e++]=t[i+n.UNPACKED_OP_L_CURVE],s[e++]=t[i+n.UNPACKED_OP_R_CURVE],s[e++]=t[i+n.UNPACKED_OP_RATE_SCALING],s[e++]=t[i+n.UNPACKED_OP_DETUNE];const _=t[i+n.UNPACKED_OP_AMP_MOD_SENS]&n.MASK_2BIT,u=t[i+n.UNPACKED_OP_KEY_VEL_SENS]&n.MASK_3BIT;s[e++]=_|u<<2,s[e++]=t[i+n.UNPACKED_OP_OUTPUT_LEVEL],s[e++]=t[i+n.UNPACKED_OP_MODE],s[e++]=t[i+n.UNPACKED_OP_FREQ_COARSE],s[e++]=t[i+n.UNPACKED_OP_OSC_DETUNE],s[e++]=t[i+n.UNPACKED_OP_FREQ_FINE]}s[e++]=t[n.UNPACKED_PITCH_EG_RATE_1],s[e++]=t[n.UNPACKED_PITCH_EG_RATE_2],s[e++]=t[n.UNPACKED_PITCH_EG_RATE_3],s[e++]=t[n.UNPACKED_PITCH_EG_RATE_4],s[e++]=t[n.UNPACKED_PITCH_EG_LEVEL_1],s[e++]=t[n.UNPACKED_PITCH_EG_LEVEL_2],s[e++]=t[n.UNPACKED_PITCH_EG_LEVEL_3],s[e++]=t[n.UNPACKED_PITCH_EG_LEVEL_4],s[e++]=t[n.UNPACKED_ALGORITHM],s[e++]=t[n.UNPACKED_FEEDBACK],s[e++]=t[n.UNPACKED_OSC_SYNC],s[e++]=t[n.UNPACKED_LFO_SPEED],s[e++]=t[n.UNPACKED_LFO_DELAY],s[e++]=t[n.UNPACKED_LFO_PM_DEPTH],s[e++]=t[n.UNPACKED_LFO_AM_DEPTH],s[e++]=t[n.UNPACKED_LFO_KEY_SYNC],s[e++]=t[n.UNPACKED_LFO_WAVE],s[e++]=t[n.UNPACKED_LFO_PM_SENS],s[e++]=t[n.UNPACKED_TRANSPOSE];for(let r=0;r<n.NAME_LENGTH;r++)s[e++]=t[n.UNPACKED_NAME_START+r];const E=s.subarray(n.VCED_HEADER_SIZE,n.VCED_HEADER_SIZE+n.VCED_DATA_SIZE);return s[e++]=h._calculateChecksum(E,n.VCED_DATA_SIZE),s[e++]=n.VCED_SYSEX_END,s}toJSON(){const t=this.unpack(),s=[],e=i=>["-LN","-EX","+EX","+LN"][i]||"UNKNOWN",E=i=>["TRIANGLE","SAW DOWN","SAW UP","SQUARE","SINE","SAMPLE & HOLD"][i]||"UNKNOWN",r=i=>{const _=["C","C#","D","D#","E","F","F#","G","G#","A","A#","B"],u=Math.floor(i/12)+n.MIDI_OCTAVE_OFFSET;return`${_[i%12]}${u}`};for(let i=0;i<n.NUM_OPERATORS;i++){const _=i*n.UNPACKED_OP_SIZE,u=t[_+n.UNPACKED_OP_MODE]===0?"RATIO":"FIXED";s.push({id:i+1,osc:{detune:t[_+n.UNPACKED_OP_OSC_DETUNE],freq:{coarse:t[_+n.UNPACKED_OP_FREQ_COARSE],fine:t[_+n.UNPACKED_OP_FREQ_FINE],mode:u}},eg:{rates:[t[_+n.UNPACKED_OP_EG_RATE_1],t[_+n.UNPACKED_OP_EG_RATE_2],t[_+n.UNPACKED_OP_EG_RATE_3],t[_+n.UNPACKED_OP_EG_RATE_4]],levels:[t[_+n.UNPACKED_OP_EG_LEVEL_1],t[_+n.UNPACKED_OP_EG_LEVEL_2],t[_+n.UNPACKED_OP_EG_LEVEL_3],t[_+n.UNPACKED_OP_EG_LEVEL_4]]},key:{velocity:t[_+n.UNPACKED_OP_KEY_VEL_SENS],scaling:t[_+n.UNPACKED_OP_RATE_SCALING],breakPoint:r(t[_+n.UNPACKED_OP_BREAK_POINT]+n.MIDI_BREAK_POINT_OFFSET)},output:{level:t[_+n.UNPACKED_OP_OUTPUT_LEVEL],ampModSens:t[_+n.UNPACKED_OP_AMP_MOD_SENS]},scale:{left:{depth:t[_+n.UNPACKED_OP_L_SCALE_DEPTH],curve:e(t[_+n.UNPACKED_OP_L_CURVE])},right:{depth:t[_+n.UNPACKED_OP_R_SCALE_DEPTH],curve:e(t[_+n.UNPACKED_OP_R_CURVE])}}})}return{name:this.name||"(Empty)",operators:s,pitchEG:{rates:[t[n.UNPACKED_PITCH_EG_RATE_1],t[n.UNPACKED_PITCH_EG_RATE_2],t[n.UNPACKED_PITCH_EG_RATE_3],t[n.UNPACKED_PITCH_EG_RATE_4]],levels:[t[n.UNPACKED_PITCH_EG_LEVEL_1],t[n.UNPACKED_PITCH_EG_LEVEL_2],t[n.UNPACKED_PITCH_EG_LEVEL_3],t[n.UNPACKED_PITCH_EG_LEVEL_4]]},lfo:{speed:t[n.UNPACKED_LFO_SPEED],delay:t[n.UNPACKED_LFO_DELAY],pmDepth:t[n.UNPACKED_LFO_PM_DEPTH],amDepth:t[n.UNPACKED_LFO_AM_DEPTH],keySync:t[n.UNPACKED_LFO_KEY_SYNC]===1,wave:E(t[n.UNPACKED_LFO_WAVE])},global:{algorithm:t[n.UNPACKED_ALGORITHM]+1,feedback:t[n.UNPACKED_FEEDBACK],oscKeySync:t[n.UNPACKED_OSC_SYNC]===1,pitchModSens:t[n.UNPACKED_LFO_PM_SENS],transpose:t[n.UNPACKED_TRANSPOSE]-n.TRANSPOSE_CENTER}}}}class h{static SYSEX_START=240;static SYSEX_END=247;static SYSEX_YAMAHA_ID=67;static SYSEX_SUB_STATUS=0;static SYSEX_FORMAT_32_VOICES=9;static SYSEX_BYTE_COUNT_MSB=32;static SYSEX_BYTE_COUNT_LSB=0;static SYSEX_HEADER=[h.SYSEX_START,h.SYSEX_YAMAHA_ID,h.SYSEX_SUB_STATUS,h.SYSEX_FORMAT_32_VOICES,h.SYSEX_BYTE_COUNT_MSB,h.SYSEX_BYTE_COUNT_LSB];static SYSEX_HEADER_SIZE=6;static VOICE_DATA_SIZE=4096;static SYSEX_SIZE=4104;static VOICE_SIZE=128;static NUM_VOICES=32;static CHECKSUM_MODULO=128;static MASK_7BIT=127;constructor(t,s=""){if(this.voices=new Array(h.NUM_VOICES),this.name=s,t)this._load(t);else for(let e=0;e<h.NUM_VOICES;e++)this.voices[e]=n.createDefault(e)}static _calculateChecksum(t,s){let e=0;for(let E=0;E<s;E++)e+=t[E];return h.CHECKSUM_MODULO-e%h.CHECKSUM_MODULO&h.MASK_7BIT}_load(t){const s=t instanceof Uint8Array?t:new Uint8Array(t);let e,E=0;if(s[0]===h.SYSEX_START){const i=s.subarray(0,h.SYSEX_HEADER_SIZE),_=h.SYSEX_HEADER;for(let u=0;u<h.SYSEX_HEADER_SIZE;u++)if(i[u]!==_[u])throw new M(`Invalid SysEx header at position ${u}: expected ${_[u].toString(16)}, got ${i[u].toString(16)}`,"header",u);e=s.subarray(h.SYSEX_HEADER_SIZE,h.SYSEX_HEADER_SIZE+h.VOICE_DATA_SIZE),E=h.SYSEX_HEADER_SIZE}else if(s.length===h.VOICE_DATA_SIZE)e=s;else throw new d(`Invalid data length: expected ${h.VOICE_DATA_SIZE} or ${h.SYSEX_SIZE} bytes, got ${s.length}`,"length",s.length);if(e.length!==h.VOICE_DATA_SIZE)throw new d(`Invalid voice data length: expected ${h.VOICE_DATA_SIZE} bytes, got ${e.length}`,"length",e.length);const r=h.SYSEX_HEADER_SIZE+h.VOICE_DATA_SIZE;if(E>0&&s.length>=r+1){const i=s[r],_=h._calculateChecksum(e,h.VOICE_DATA_SIZE);i!==_&&console.warn(`DX7 checksum mismatch (expected ${_.toString(16)}, got ${i.toString(16)}). This is common with vintage SysEx files and the data is likely still valid.`)}this.voices=new Array(h.NUM_VOICES);for(let i=0;i<h.NUM_VOICES;i++){const _=i*h.VOICE_SIZE,u=e.subarray(_,_+h.VOICE_SIZE);this.voices[i]=new n(u,i)}}replaceVoice(t,s){if(t<0||t>=h.NUM_VOICES)throw new d(`Invalid voice index: ${t}`,"index",t);const e=new Uint8Array(s.data);this.voices[t]=new n(e,t)}addVoice(t){for(let s=0;s<this.voices.length;s++){const e=this.voices[s];if(e.name===""||e.name==="Init Voice")return this.replaceVoice(s,t),s}return-1}getVoices(){return this.voices}getVoice(t){return t<0||t>=this.voices.length?null:this.voices[t]}getVoiceNames(){return this.voices.map(t=>t.name)}findVoiceByName(t){const s=t.toLowerCase();return this.voices.find(e=>e.name.toLowerCase().includes(s))||null}static async fromFile(t){return new Promise((s,e)=>{const E=new FileReader;E.onload=async r=>{try{const i=t.name||"",_=new Uint8Array(r.target.result);if(_[0]===h.SYSEX_START&&_[3]===n.VCED_FORMAT_SINGLE)e(new M("This is a single voice file. Use DX7Voice.fromFile() instead.","format",3));else{const u=i.replace(/\.[^/.]+$/,""),N=new h(r.target.result,u);s(N)}}catch(i){e(i)}},E.onerror=()=>e(new Error("Failed to read file")),E.readAsArrayBuffer(t)})}static fromSysEx(t,s=""){return new h(t,s)}static fromJSON(t){if(!t||typeof t!="object")throw new d("Invalid JSON: expected object","json",t);const s=new h;if(s.name=t.name||"",!Array.isArray(t.voices))throw new d("Invalid voices array","voices",t.voices);t.voices.length!==h.NUM_VOICES&&console.warn(`Bank JSON has ${t.voices.length} voices, expected ${h.NUM_VOICES}. Missing voices will be filled with defaults.`);const e=Math.min(t.voices.length,h.NUM_VOICES);for(let E=0;E<e;E++){const r=t.voices[E];if(!r||typeof r!="object"){console.warn(`Invalid voice data at index ${E}, using default voice`);continue}try{const{index:i,..._}=r,u=n.fromJSON(_,E);s.replaceVoice(E,u)}catch(i){console.warn(`Failed to load voice at index ${E}: ${i.message}, using default voice`)}}return s}toSysEx(){const t=new Uint8Array(h.SYSEX_SIZE);let s=0;h.SYSEX_HEADER.forEach(E=>{t[s++]=E});for(const E of this.voices)for(let r=0;r<h.VOICE_SIZE;r++)t[s++]=E.data[r];const e=t.subarray(h.SYSEX_HEADER_SIZE,h.SYSEX_HEADER_SIZE+h.VOICE_DATA_SIZE);return t[s++]=h._calculateChecksum(e,h.VOICE_DATA_SIZE),t[s++]=h.SYSEX_END,t}toJSON(){const t=this.voices.map((s,e)=>{const E=s.toJSON();return{index:e+1,...E}});return{version:"1.0",name:this.name||"",voices:t}}}function tt(o){return o[0]!==240||o[o.length-1]!==247?null:{manufacturerId:o[1],payload:o.slice(2,-1),raw:o}}function nt(o,t){return[240,o,...t,247]}function st(o){return o.length>=2&&o[0]===240&&o[o.length-1]===247}function et(o){const t=[];for(let s=0;s<o.length;s+=7){const e=o.slice(s,s+7);let E=0;const r=[];for(let i=0;i<e.length;i++){const _=e[i];_&128&&(E|=1<<i),r.push(_&127)}t.push(E,...r)}return t}function Et(o){const t=[];for(let s=0;s<o.length;s+=8){const e=o[s],E=Math.min(7,o.length-s-1);for(let r=0;r<E;r++){let i=o[s+1+r];e&1<<r&&(i|=128),t.push(i)}}return t}function it(o){return Number.isInteger(o)&&o>=1&&o<=16}function rt(o){return Number.isInteger(o)&&o>=0&&o<=127}function _t(o){return Number.isInteger(o)&&o>=0&&o<=31}function at(o){return Number.isInteger(o)&&o>=0&&o<=127}function ot(o){return Number.isInteger(o)&&o>=0&&o<=127}function Ct(o){return Number.isInteger(o)&&o>=0&&o<=127}function At(o){return Number.isInteger(o)&&o>=0&&o<=127}function Pt(o){return Number.isInteger(o)&&o>=0&&o<=16383}function ut(o,t){return Number.isInteger(o)&&o>=0&&o<=127&&Number.isInteger(t)&&t>=0&&t<=127}async function Z(o={}){const t=new x(o);await t.init();const s=o.selector||"[data-midi-cc]";{const e=new p(t,s);e.bindAll(),o.watchDOM&&e.enableAutoBinding(),t._binder=e}return t}async function lt(o={}){const{onStatusUpdate:t,onConnectionUpdate:s,inputChannel:e=1,outputChannel:E=1,output:r,sysex:i,onReady:_,onError:u,selector:N,watchDOM:P,...a}=o,l=await Z({autoConnect:!1,sysex:i,inputChannel:e,outputChannel:E,selector:N||"[data-midi-cc]",watchDOM:P,onError:u,...a}),c=new $({midiController:l,onStatusUpdate:t||(()=>{}),onConnectionUpdate:s||(()=>{}),channel:E});if(r)try{await l.device.connectOutput(r),c.currentOutput=l.device.getCurrentOutput(),c.updateConnectionStatus()}catch(T){u?u(T):console.error("Failed to connect to MIDI device:",T.message)}return _&&_(l,c),c}S.CONN=U,S.CONNECTION_EVENTS=U,S.CONTROLLER_EVENTS=A,S.CTRL=A,S.DX7Bank=h,S.DX7Error=F,S.DX7ParseError=M,S.DX7ValidationError=d,S.DX7Voice=n,S.DataAttributeBinder=p,S.EventEmitter=b,S.MIDIAccessError=g,S.MIDIConnection=Y,S.MIDIConnectionError=G,S.MIDIController=x,S.MIDIDeviceError=L,S.MIDIDeviceManager=$,S.MIDIError=m,S.MIDIValidationError=R,S.clamp=O,S.createMIDIController=Z,S.createMIDIDeviceManager=lt,S.createSysEx=nt,S.decode14BitValue=w,S.decode7Bit=Et,S.denormalize14BitValue=X,S.denormalizeValue=W,S.encode14BitValue=v,S.encode7Bit=et,S.frequencyToNote=j,S.getCCName=V,S.isSysEx=st,S.isValid14BitCC=_t,S.isValidCC=rt,S.isValidChannel=it,S.isValidMIDIValue=at,S.isValidNote=ot,S.isValidPitchBend=Pt,S.isValidPitchBendBytes=ut,S.isValidProgramChange=At,S.isValidVelocity=Ct,S.normalize14BitValue=B,S.normalizeValue=y,S.noteNameToNumber=Q,S.noteNumberToName=J,S.noteToFrequency=k,S.parseSysEx=tt,Object.defineProperty(S,Symbol.toStringTag,{value:"Module"})}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "midiwire",
3
- "version": "0.8.0",
3
+ "version": "0.10.0",
4
4
  "description": "Declarative JavaScript library for browser-based MIDI control",
5
5
  "type": "module",
6
6
  "main": "./dist/midiwire.umd.js",
@@ -64,6 +64,14 @@
64
64
  "vite-plugin-dts": "4.5.4",
65
65
  "vitest": "4.0.17"
66
66
  },
67
+ "peerDependencies": {
68
+ "typescript": ">=5.0.0"
69
+ },
70
+ "peerDependenciesMeta": {
71
+ "typescript": {
72
+ "optional": true
73
+ }
74
+ },
67
75
  "engines": {
68
76
  "node": ">=20.0.0"
69
77
  }
@@ -60,107 +60,6 @@ export class MIDIDeviceManager {
60
60
  this.midi = midi
61
61
  }
62
62
 
63
- /**
64
- * Set up device change event listeners for automatic UI updates when devices
65
- * connect or disconnect. Handles both successful connections and disconnections,
66
- * updating status messages and tracking the current device state.
67
- *
68
- * @param {Function} [onDeviceListChange] - Optional callback to refresh device list UI when devices change
69
- * @param {Object} [selectElements] - Optional select elements to update on disconnect
70
- * @param {HTMLSelectElement} [selectElements.output] - Output device select element
71
- * @param {HTMLSelectElement} [selectElements.input] - Input device select element
72
- * @returns {void}
73
- *
74
- * @emits CONTROLLER_EVENTS.DEV_OUT_CONNECTED
75
- * @emits CONTROLLER_EVENTS.DEV_OUT_DISCONNECTED
76
- *
77
- * @example
78
- * // Basic setup
79
- * manager.setupDeviceListeners();
80
- *
81
- * @example
82
- * // With device list refresh callback
83
- * manager.setupDeviceListeners(() => {
84
- * manager.output.populateDeviceList(deviceSelect);
85
- * });
86
- *
87
- * @example
88
- * // With select elements to clear on disconnect
89
- * manager.setupDeviceListeners(null, {
90
- * output: outputSelect,
91
- * input: inputSelect
92
- * });
93
- */
94
- setupDeviceListeners(onDeviceListChange, selectElements = {}) {
95
- if (!this.midi) return
96
-
97
- this.midi.on(CONTROLLER_EVENTS.DEV_OUT_CONNECTED, (device) => {
98
- this.updateStatus(`Output device connected: ${device?.name || "Unknown"}`, "connected")
99
- if (onDeviceListChange) {
100
- onDeviceListChange()
101
- }
102
- })
103
-
104
- this.midi.on(CONTROLLER_EVENTS.DEV_OUT_DISCONNECTED, (device) => {
105
- this.updateStatus(`Output device disconnected: ${device?.name || "Unknown"}`, "error")
106
-
107
- const wasCurrentDevice = this.currentOutput && device?.name === this.currentOutput.name
108
-
109
- if (wasCurrentDevice) {
110
- this.currentOutput = null
111
- this.updateConnectionStatus()
112
- if (selectElements.output) {
113
- selectElements.output.value = ""
114
- }
115
- }
116
-
117
- if (onDeviceListChange) {
118
- onDeviceListChange()
119
- }
120
- })
121
-
122
- this.midi.on(CONTROLLER_EVENTS.DEV_IN_CONNECTED, (device) => {
123
- this.updateStatus(`Input device connected: ${device?.name || "Unknown"}`, "connected")
124
- if (onDeviceListChange) {
125
- onDeviceListChange()
126
- }
127
- })
128
-
129
- this.midi.on(CONTROLLER_EVENTS.DEV_IN_DISCONNECTED, (device) => {
130
- this.updateStatus(`Input device disconnected: ${device?.name || "Unknown"}`, "error")
131
- if (selectElements.input) {
132
- selectElements.input.value = ""
133
- }
134
- if (onDeviceListChange) {
135
- onDeviceListChange()
136
- }
137
- })
138
- }
139
-
140
- /**
141
- * Update status message and trigger status callback
142
- *
143
- * @param {string} message - Status message to display
144
- * @param {string} [state=""] - Status state (e.g., "connected", "error", "warning")
145
- * @returns {void}
146
- *
147
- * @example
148
- * manager.updateStatus("Connected to MIDI keyboard", "connected");
149
- *
150
- * @example
151
- * manager.updateStatus("Connection failed", "error");
152
- */
153
- updateStatus(message, state = "") {
154
- this.onStatusUpdate(message, state)
155
- }
156
-
157
- /**
158
- * Update connection status
159
- */
160
- updateConnectionStatus() {
161
- this.onConnectionUpdate(this.currentOutput, this.currentInput, this.midi)
162
- }
163
-
164
63
  /**
165
64
  * Set up all MIDI device selectors in one call. Handles population, connection
166
65
  * handling, channel selection, and automatic refresh on device changes.
@@ -256,6 +155,122 @@ export class MIDIDeviceManager {
256
155
  return this.midi
257
156
  }
258
157
 
158
+ /**
159
+ * Set up device change event listeners for automatic UI updates when devices
160
+ * connect or disconnect. Handles both successful connections and disconnections,
161
+ * updating status messages and tracking the current device state.
162
+ *
163
+ * @param {Function} [onDeviceListChange] - Optional callback to refresh device list UI when devices change
164
+ * @param {Object} [selectElements] - Optional select elements to update on disconnect
165
+ * @param {HTMLSelectElement|string} [selectElements.output] - Output device select element or CSS selector string (e.g., "#output-select")
166
+ * @param {HTMLSelectElement|string} [selectElements.input] - Input device select element or CSS selector string (e.g., "#input-select")
167
+ * @returns {void}
168
+ *
169
+ * @emits CONTROLLER_EVENTS.DEV_OUT_CONNECTED
170
+ * @emits CONTROLLER_EVENTS.DEV_OUT_DISCONNECTED
171
+ *
172
+ * @example
173
+ * // Basic setup
174
+ * manager.setupDeviceListeners();
175
+ *
176
+ * @example
177
+ * // With device list refresh callback
178
+ * manager.setupDeviceListeners(() => {
179
+ * manager.output.populateDeviceList(deviceSelect);
180
+ * });
181
+ *
182
+ * @example
183
+ * // With select elements to clear on disconnect
184
+ * manager.setupDeviceListeners(null, {
185
+ * output: outputSelect,
186
+ * input: inputSelect
187
+ * });
188
+ *
189
+ * @example
190
+ * // With CSS selectors
191
+ * manager.setupDeviceListeners(null, {
192
+ * output: "#output-select",
193
+ * input: "#input-select"
194
+ * });
195
+ */
196
+ setupDeviceListeners(onDeviceListChange, selectElements = {}) {
197
+ if (!this.midi) return
198
+
199
+ const resolvedSelectElements = {}
200
+ if (selectElements.output) {
201
+ resolvedSelectElements.output = this._resolveSelector(selectElements.output)
202
+ }
203
+ if (selectElements.input) {
204
+ resolvedSelectElements.input = this._resolveSelector(selectElements.input)
205
+ }
206
+
207
+ this.midi.on(CONTROLLER_EVENTS.DEV_OUT_CONNECTED, (device) => {
208
+ this.updateStatus(`Output device connected: ${device?.name || "Unknown"}`, "connected")
209
+ if (onDeviceListChange) {
210
+ onDeviceListChange()
211
+ }
212
+ })
213
+
214
+ this.midi.on(CONTROLLER_EVENTS.DEV_OUT_DISCONNECTED, (device) => {
215
+ this.updateStatus(`Output device disconnected: ${device?.name || "Unknown"}`, "error")
216
+
217
+ const wasCurrentDevice = this.currentOutput && device?.name === this.currentOutput.name
218
+
219
+ if (wasCurrentDevice) {
220
+ this.currentOutput = null
221
+ this.updateConnectionStatus()
222
+ if (resolvedSelectElements.output) {
223
+ resolvedSelectElements.output.value = ""
224
+ }
225
+ }
226
+
227
+ if (onDeviceListChange) {
228
+ onDeviceListChange()
229
+ }
230
+ })
231
+
232
+ this.midi.on(CONTROLLER_EVENTS.DEV_IN_CONNECTED, (device) => {
233
+ this.updateStatus(`Input device connected: ${device?.name || "Unknown"}`, "connected")
234
+ if (onDeviceListChange) {
235
+ onDeviceListChange()
236
+ }
237
+ })
238
+
239
+ this.midi.on(CONTROLLER_EVENTS.DEV_IN_DISCONNECTED, (device) => {
240
+ this.updateStatus(`Input device disconnected: ${device?.name || "Unknown"}`, "error")
241
+ if (resolvedSelectElements.input) {
242
+ resolvedSelectElements.input.value = ""
243
+ }
244
+ if (onDeviceListChange) {
245
+ onDeviceListChange()
246
+ }
247
+ })
248
+ }
249
+
250
+ /**
251
+ * Update status message and trigger status callback
252
+ *
253
+ * @param {string} message - Status message to display
254
+ * @param {string} [state=""] - Status state (e.g., "connected", "error", "warning")
255
+ * @returns {void}
256
+ *
257
+ * @example
258
+ * manager.updateStatus("Connected to MIDI keyboard", "connected");
259
+ *
260
+ * @example
261
+ * manager.updateStatus("Connection failed", "error");
262
+ */
263
+ updateStatus(message, state = "") {
264
+ this.onStatusUpdate(message, state)
265
+ }
266
+
267
+ /**
268
+ * Update connection status
269
+ */
270
+ updateConnectionStatus() {
271
+ this.onConnectionUpdate(this.currentOutput, this.currentInput, this.midi)
272
+ }
273
+
259
274
  /**
260
275
  * Resolve a selector to a DOM element
261
276
  * @private
@@ -1,4 +1,4 @@
1
- import { beforeEach, describe, expect, it, vi } from "vitest"
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"
2
2
  import { CONTROLLER_EVENTS } from "./MIDIController.js"
3
3
  import { MIDIDeviceManager } from "./MIDIDeviceManager.js"
4
4
 
@@ -658,6 +658,111 @@ describe("MIDIDeviceManager", () => {
658
658
  })
659
659
  })
660
660
 
661
+ // setupDeviceListeners tests
662
+ describe("setupDeviceListeners() - String Selectors", () => {
663
+ let manager
664
+ let mockMidi
665
+ let mockOutputSelect
666
+ let mockInputSelect
667
+
668
+ beforeEach(() => {
669
+ mockOutputSelect = document.createElement("select")
670
+ mockOutputSelect.id = "output-select"
671
+ mockInputSelect = document.createElement("select")
672
+ mockInputSelect.id = "input-select"
673
+ document.body.appendChild(mockOutputSelect)
674
+ document.body.appendChild(mockInputSelect)
675
+
676
+ mockMidi = {
677
+ on: vi.fn(),
678
+ device: {
679
+ getOutputs: vi.fn().mockReturnValue([]),
680
+ getInputs: vi.fn().mockReturnValue([]),
681
+ },
682
+ options: { outputChannel: 1, inputChannel: 1 },
683
+ }
684
+ manager = new MIDIDeviceManager()
685
+ manager.setMIDI(mockMidi)
686
+ })
687
+
688
+ afterEach(() => {
689
+ document.body.removeChild(mockOutputSelect)
690
+ document.body.removeChild(mockInputSelect)
691
+ })
692
+
693
+ it("should accept string selectors for output element", () => {
694
+ manager.setupDeviceListeners(null, {
695
+ output: "#output-select",
696
+ })
697
+
698
+ expect(mockMidi.on).toHaveBeenCalled()
699
+ })
700
+
701
+ it("should accept string selectors for input element", () => {
702
+ manager.setupDeviceListeners(null, {
703
+ input: "#input-select",
704
+ })
705
+
706
+ expect(mockMidi.on).toHaveBeenCalled()
707
+ })
708
+
709
+ it("should accept string selectors for both output and input elements", () => {
710
+ manager.setupDeviceListeners(null, {
711
+ output: "#output-select",
712
+ input: "#input-select",
713
+ })
714
+
715
+ expect(mockMidi.on).toHaveBeenCalled()
716
+ })
717
+
718
+ it("should handle missing elements with string selectors", () => {
719
+ // Suppress console.warn for this test
720
+ const consoleSpy = vi.spyOn(console, "warn").mockImplementation(() => {})
721
+
722
+ manager.setupDeviceListeners(null, {
723
+ output: "#nonexistent",
724
+ input: "#alsononexistent",
725
+ })
726
+
727
+ expect(consoleSpy).toHaveBeenCalled()
728
+ consoleSpy.mockRestore()
729
+ })
730
+
731
+ it("should clear output select value on disconnect when using string selector", () => {
732
+ manager.currentOutput = { name: "Test Output" }
733
+
734
+ manager.setupDeviceListeners(null, {
735
+ output: "#output-select",
736
+ })
737
+
738
+ // Find the disconnect handler for output
739
+ const disconnectCalls = mockMidi.on.mock.calls.filter(
740
+ (call) => call[0] === CONTROLLER_EVENTS.DEV_OUT_DISCONNECTED,
741
+ )
742
+ expect(disconnectCalls.length).toBe(1)
743
+
744
+ const disconnectHandler = disconnectCalls[0][1]
745
+ disconnectHandler({ name: "Test Output" })
746
+
747
+ expect(mockOutputSelect.value).toBe("")
748
+ })
749
+
750
+ it("should clear input select value on disconnect when using string selector", () => {
751
+ manager.setupDeviceListeners(null, {
752
+ input: "#input-select",
753
+ })
754
+
755
+ // Find the disconnect handler for input
756
+ const disconnectCalls = mockMidi.on.mock.calls.filter((call) => call[0] === CONTROLLER_EVENTS.DEV_IN_DISCONNECTED)
757
+ expect(disconnectCalls.length).toBe(1)
758
+
759
+ const disconnectHandler = disconnectCalls[0][1]
760
+ disconnectHandler({ name: "Test Input" })
761
+
762
+ expect(mockInputSelect.value).toBe("")
763
+ })
764
+ })
765
+
661
766
  // Internal method tests
662
767
  describe("Internal Methods - Guard Clauses", () => {
663
768
  it("should return early in setupDeviceListeners without MIDI", () => {