@yam8d/m8-sdk 0.4.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/README.md +798 -796
  2. package/dist/index.js +3411 -363
  3. package/dist/index.js.map +1 -1
  4. package/package.json +2 -2
  5. package/types/client.d.ts +58 -2
  6. package/types/engine/astar.d.ts +15 -0
  7. package/types/engine/audio.d.ts +29 -0
  8. package/types/engine/bus.d.ts +13 -0
  9. package/types/engine/connectWithRetry.d.ts +9 -0
  10. package/types/engine/connection.d.ts +56 -0
  11. package/types/engine/cursorNavigator.d.ts +15 -0
  12. package/types/engine/engine.d.ts +30 -0
  13. package/types/engine/eventBus.d.ts +5 -0
  14. package/types/engine/host/fileBrowserHelpers.d.ts +59 -0
  15. package/types/engine/host/fileBrowserSearch.d.ts +13 -0
  16. package/types/engine/host/floatEditor.d.ts +2 -0
  17. package/types/engine/host/hostIO.d.ts +30 -0
  18. package/types/engine/host/hostMethods.d.ts +22 -0
  19. package/types/engine/host/hostState.d.ts +7 -0
  20. package/types/engine/host/keySequences.d.ts +2 -0
  21. package/types/engine/host/midiTransport.d.ts +10 -0
  22. package/types/engine/host/valueEditors.d.ts +7 -0
  23. package/types/engine/host/valueParsers.d.ts +24 -0
  24. package/types/engine/index.d.ts +14 -0
  25. package/types/engine/keys.d.ts +28 -0
  26. package/types/engine/macroRunner.d.ts +15 -0
  27. package/types/engine/protocol.d.ts +138 -0
  28. package/types/engine/queuedReaders.d.ts +18 -0
  29. package/types/engine/store.d.ts +65 -0
  30. package/types/engine/viewExtractor.d.ts +27 -0
  31. package/types/engine/viewGraph.d.ts +9 -0
  32. package/types/engine/viewNavigation.d.ts +16 -0
  33. package/types/index.d.ts +9 -3
  34. package/types/scaleInsight.d.ts +1 -1
  35. package/types/theme.d.ts +42 -0
  36. package/types/types.d.ts +124 -0
  37. package/types/viewContext.d.ts +37 -0
package/dist/index.js CHANGED
@@ -1,5 +1,2750 @@
1
1
  import { ChildHandshake as e, DebugMessenger as t, WindowMessenger as n } from "post-me";
2
- var r = {
2
+ //#region src/engine/eventBus.ts
3
+ var r = () => {
4
+ let e = {};
5
+ return {
6
+ emit: (t, ...n) => {
7
+ if (t in e) for (let r of [...e[t]]) r(...n);
8
+ },
9
+ on: (t, n) => {
10
+ e[t] || (e[t] = /* @__PURE__ */ new Set()), e[t].add(n);
11
+ },
12
+ off: (t, n) => {
13
+ e[t] && e[t].delete(n);
14
+ }
15
+ };
16
+ }, i = !0, a = (e, t) => {
17
+ let n = e.getUint16(1, i), r = e.getUint16(3, i);
18
+ switch (t) {
19
+ case 5: return {
20
+ type: 1,
21
+ pos: {
22
+ x: n,
23
+ y: r
24
+ },
25
+ size: {
26
+ width: 1,
27
+ height: 1
28
+ }
29
+ };
30
+ case 8: return {
31
+ type: 2,
32
+ pos: {
33
+ x: n,
34
+ y: r
35
+ },
36
+ size: {
37
+ width: 1,
38
+ height: 1
39
+ },
40
+ color: {
41
+ r: e.getUint8(5),
42
+ g: e.getUint8(6),
43
+ b: e.getUint8(7)
44
+ }
45
+ };
46
+ case 9: return {
47
+ type: 3,
48
+ pos: {
49
+ x: n,
50
+ y: r
51
+ },
52
+ size: {
53
+ width: e.getUint16(5, i),
54
+ height: e.getUint16(7, i)
55
+ }
56
+ };
57
+ case 12: return {
58
+ type: 4,
59
+ pos: {
60
+ x: n,
61
+ y: r
62
+ },
63
+ size: {
64
+ width: e.getUint16(5, i),
65
+ height: e.getUint16(7, i)
66
+ },
67
+ color: {
68
+ r: e.getUint8(9),
69
+ g: e.getUint8(10),
70
+ b: e.getUint8(11)
71
+ }
72
+ };
73
+ }
74
+ let a = [];
75
+ for (let n = 0; n < t; n += 1) a.push(e.getUint8(n).toString(16).padStart(2, "0"));
76
+ return console.error(`Invalid length (${t}) of rect command data: ${a.join(" ")}`), {
77
+ type: 0,
78
+ pos: {
79
+ x: n,
80
+ y: r
81
+ },
82
+ size: {
83
+ width: 0,
84
+ height: 0
85
+ }
86
+ };
87
+ }, o = (e, t) => {
88
+ if (t !== 12) throw Error(`Invalid length (${t}) of char command data`);
89
+ return {
90
+ character: String.fromCharCode(e.getUint8(1)),
91
+ pos: {
92
+ x: e.getUint16(2, i),
93
+ y: e.getUint16(4, i)
94
+ },
95
+ foreground: {
96
+ r: e.getUint8(6),
97
+ g: e.getUint8(7),
98
+ b: e.getUint8(8)
99
+ },
100
+ background: {
101
+ r: e.getUint8(9),
102
+ g: e.getUint8(10),
103
+ b: e.getUint8(11)
104
+ }
105
+ };
106
+ }, s = (e, t) => {
107
+ if (t < 4 || t > 484) throw Error(`Invalid length (${t}) of wave command data`);
108
+ let n = [];
109
+ for (let r = 4; r < t; r += 1) n.push(e.getUint8(r));
110
+ return {
111
+ color: {
112
+ r: e.getUint8(1),
113
+ g: e.getUint8(2),
114
+ b: e.getUint8(3)
115
+ },
116
+ wave: n
117
+ };
118
+ }, c = (e, t) => {
119
+ if (t !== 3) throw Error(`Invalid length (${t}) of key command data`);
120
+ return { keys: e.getUint8(1) };
121
+ }, l = [
122
+ "Headless",
123
+ "Beta M8",
124
+ "M8 Model:01",
125
+ "M8 Model:02"
126
+ ], u = (e, t) => {
127
+ if (t !== 6) throw Error(`Invalid length (${t}) of system command data`);
128
+ return {
129
+ model: l[e.getUint8(1)],
130
+ version: `v${e.getUint8(2)}.${e.getUint8(3)}.${e.getUint8(4)}`,
131
+ fontMode: e.getUint8(5)
132
+ };
133
+ }, d = () => {
134
+ let e, t = r(), n, i = (e) => {
135
+ let t = 12, n = 14, r = 0, i = 480, a = 320, o = 0;
136
+ if (!e) return {
137
+ spacingX: t,
138
+ spacingY: n,
139
+ offX: 0,
140
+ offY: r,
141
+ screenWidth: i,
142
+ screenHeight: a,
143
+ rectOffset: o
144
+ };
145
+ let s = e.model === "M8 Model:02" || e.model === "Beta M8", c = e.fontMode;
146
+ return s ? (i = 480, a = 320, c === 0 || c === 1 ? (t = 12, n = 14, r = 0, o = 0) : (t = 15, n = 16, r = 0, o = -45)) : (i = 320, a = 240, c === 0 ? (t = 8, n = 10, r = 0, o = 0) : (t = 10, n = 12, r = 0, o = -40)), {
147
+ spacingX: t,
148
+ spacingY: n,
149
+ offX: 0,
150
+ offY: r,
151
+ screenWidth: i,
152
+ screenHeight: a,
153
+ rectOffset: o
154
+ };
155
+ };
156
+ return {
157
+ eventBus: t,
158
+ dispatch: (r, l) => {
159
+ try {
160
+ if (l <= 0) return;
161
+ let d = new Uint8Array(r.buffer, r.byteOffset, l);
162
+ switch (t.emit("any", d), r.getUint8(0)) {
163
+ case 254: {
164
+ let e = a(r, l);
165
+ e && t.emit("rect", e);
166
+ break;
167
+ }
168
+ case 253:
169
+ t.emit("text", o(r, l));
170
+ break;
171
+ case 252:
172
+ t.emit("wave", s(r, l));
173
+ break;
174
+ case 251:
175
+ t.emit("key", c(r, l));
176
+ break;
177
+ case 255: {
178
+ e = u(r, l), t.emit("system", e);
179
+ let a = i(e);
180
+ n = {
181
+ model: e.model,
182
+ fontMode: e.fontMode,
183
+ ...a
184
+ }, t.emit("systemInfo", n);
185
+ break;
186
+ }
187
+ default: console.warn(`Unknown byte 0x${r.getUint8(0).toString(16).padStart(2, "0")} as command`);
188
+ }
189
+ } catch {}
190
+ },
191
+ getSystemInfo: () => e,
192
+ getSystemInfos: () => {
193
+ if (!n) {
194
+ let t = i(e);
195
+ n = e ? {
196
+ model: e.model,
197
+ fontMode: e.fontMode,
198
+ ...t
199
+ } : {
200
+ model: "Headless",
201
+ fontMode: 0,
202
+ ...t
203
+ };
204
+ }
205
+ return n;
206
+ }
207
+ };
208
+ }, f = () => {
209
+ let e = /* @__PURE__ */ new Uint8Array(1024), t = new DataView(e.buffer), n = 0, r = "read", i = () => {
210
+ if (n <= 0) {
211
+ n = 0;
212
+ return;
213
+ }
214
+ let t = new Uint8Array(n);
215
+ t.set(e.subarray(0, n));
216
+ let r = new DataView(t.buffer);
217
+ return n = 0, r;
218
+ }, a = (i) => {
219
+ n >= e.length ? (n = 0, r = "error") : t.setUint8(n++, i);
220
+ };
221
+ return { feed: (e) => {
222
+ switch (r) {
223
+ case "read": switch (e) {
224
+ case 192: return i();
225
+ case 219:
226
+ r = "escape";
227
+ return;
228
+ default:
229
+ a(e);
230
+ return;
231
+ }
232
+ case "escape": switch (e) {
233
+ case 220:
234
+ a(192), r = "read";
235
+ return;
236
+ case 221:
237
+ a(219), r = "read";
238
+ return;
239
+ default:
240
+ r = "error";
241
+ return;
242
+ }
243
+ case "error":
244
+ e === 192 && (r = "read", n = 0);
245
+ return;
246
+ }
247
+ } };
248
+ }, p = (e) => {
249
+ let t = f(), n = [], r = !1, i;
250
+ return (async () => {
251
+ try {
252
+ for (;;) {
253
+ let a = await e.transferIn(3, 512);
254
+ if (a.status === "stall") {
255
+ r = !0, i && n.length === 0 && (i({ terminated: !0 }), i = void 0);
256
+ break;
257
+ }
258
+ let o = a.data;
259
+ if (o) for (let e = 0; e < o.byteLength; e++) {
260
+ let r = t.feed(o.getUint8(e));
261
+ if (r && (n.push(r), i)) {
262
+ let e = n.shift();
263
+ e && (i({
264
+ terminated: !1,
265
+ data: e
266
+ }), i = void 0);
267
+ }
268
+ }
269
+ }
270
+ } catch {
271
+ r = !0, i && n.length === 0 && (i({ terminated: !0 }), i = void 0);
272
+ }
273
+ })(), async () => {
274
+ if (r && n.length === 0) return { terminated: !0 };
275
+ if (n.length > 0) {
276
+ let e = n.shift();
277
+ if (e) return {
278
+ terminated: !1,
279
+ data: e
280
+ };
281
+ }
282
+ return new Promise((e) => {
283
+ i = e;
284
+ });
285
+ };
286
+ }, m = (e) => {
287
+ let t = f(), n = [], r = !1, i;
288
+ return (async () => {
289
+ try {
290
+ for (;;) {
291
+ let { value: a, done: o } = await e.read();
292
+ if (o) {
293
+ r = !0, i && n.length === 0 && (i({ terminated: !0 }), i = void 0);
294
+ break;
295
+ }
296
+ if (!a) continue;
297
+ let s = a;
298
+ for (let e = 0; e < s.byteLength; e++) {
299
+ let r = t.feed(s[e]);
300
+ if (r && (n.push(r), i)) {
301
+ let e = n.shift();
302
+ e && (i({
303
+ terminated: !1,
304
+ data: e
305
+ }), i = void 0);
306
+ }
307
+ }
308
+ }
309
+ } catch {
310
+ r = !0, i && n.length === 0 && (i({ terminated: !0 }), i = void 0);
311
+ }
312
+ })(), async () => {
313
+ if (r && n.length === 0) return { terminated: !0 };
314
+ if (n.length > 0) {
315
+ let e = n.shift();
316
+ if (e) return {
317
+ terminated: !1,
318
+ data: e
319
+ };
320
+ }
321
+ return new Promise((e) => {
322
+ i = e;
323
+ });
324
+ };
325
+ }, h = 5824, g = 1162, _ = 20, v = (e) => (t) => e.transferOut(3, t), y = (e) => (t) => e.write(t), b = (e) => {
326
+ let t = [], n = setInterval(() => {
327
+ let n = t.shift();
328
+ n && e.send(n);
329
+ }, _);
330
+ return {
331
+ stop: () => clearInterval(n),
332
+ resetScreen: () => {
333
+ t.push(new Uint8Array([
334
+ 240,
335
+ 0,
336
+ 2,
337
+ 97,
338
+ 0,
339
+ 0,
340
+ 68,
341
+ 247
342
+ ])), t.push(new Uint8Array([
343
+ 240,
344
+ 0,
345
+ 2,
346
+ 97,
347
+ 0,
348
+ 0,
349
+ 69,
350
+ 82,
351
+ 247
352
+ ]));
353
+ },
354
+ sendKeys: (e) => {
355
+ let n = e, r = 0 | (n & 128 ? 4 : 0);
356
+ t.push(new Uint8Array([
357
+ 240,
358
+ 0,
359
+ 2,
360
+ 97,
361
+ 0,
362
+ r,
363
+ 0,
364
+ 67,
365
+ n & 127,
366
+ 247
367
+ ]));
368
+ },
369
+ sendNoteOn: (e, n) => {
370
+ n = Math.min(127, Math.max(0, n));
371
+ let r = 0 | (e & 128 ? 4 : 0) | (n & 128 ? 8 : 0);
372
+ t.push(new Uint8Array([
373
+ 240,
374
+ 0,
375
+ 2,
376
+ 97,
377
+ 0,
378
+ r,
379
+ 0,
380
+ 72,
381
+ e & 127,
382
+ n & 127,
383
+ 247
384
+ ]));
385
+ },
386
+ sendNoteOff: () => {
387
+ t.push(new Uint8Array([
388
+ 240,
389
+ 0,
390
+ 2,
391
+ 97,
392
+ 0,
393
+ 4,
394
+ 72,
395
+ 127,
396
+ 247
397
+ ]));
398
+ },
399
+ sendProgramChange: (e, n = 0) => {
400
+ let r = Math.min(15, Math.max(0, n)), i = Math.min(127, Math.max(0, e)), a = 192 | r;
401
+ t.push(new Uint8Array([a, i]));
402
+ }
403
+ };
404
+ }, x = (e) => {
405
+ let t = [], n = setInterval(() => {
406
+ let n = t.shift();
407
+ n && Promise.resolve(e(n)).catch(() => {});
408
+ }, _);
409
+ return {
410
+ stop: () => clearInterval(n),
411
+ resetScreen: async () => {
412
+ t.push(new Uint8Array([68])), t.push(new Uint8Array([69, 82]));
413
+ },
414
+ sendKeys: (e) => {
415
+ let n = e;
416
+ t.push(new Uint8Array([67, n]));
417
+ },
418
+ sendNoteOn: async (e, n) => {
419
+ t.push(new Uint8Array([
420
+ 75,
421
+ e,
422
+ n
423
+ ]));
424
+ },
425
+ sendNoteOff: async () => {
426
+ t.push(new Uint8Array([75, 255]));
427
+ },
428
+ sendProgramChange: async (e, n = 0) => {
429
+ let r = Math.min(127, Math.max(0, e));
430
+ t.push(new Uint8Array([76, r]));
431
+ }
432
+ };
433
+ }, S = [
434
+ 240,
435
+ 0,
436
+ 2,
437
+ 97,
438
+ 0
439
+ ], C = 247;
440
+ function w(e) {
441
+ if (e.length < 5) return !1;
442
+ for (let t = 0; t < S.length; t++) if (e[t] !== S[t]) return !1;
443
+ return !0;
444
+ }
445
+ function T(e) {
446
+ let t = [], n = 0;
447
+ for (; n < e.length;) {
448
+ let r = e[n++];
449
+ if (n >= e.length) break;
450
+ let i = e.length - n, a = Math.min(7, i);
451
+ for (let i = 0; i < a; i++) {
452
+ let a = e[n++], o = r >> i & 1;
453
+ t.push(o << 7 | a);
454
+ }
455
+ }
456
+ return new Uint8Array(t);
457
+ }
458
+ function E(e) {
459
+ if (!w(e)) console.log("not M8Sysex");
460
+ else if (e[e.length - 1] !== C) console.log("Unterminated SysEx");
461
+ else return [...e].map((e, t) => e === C ? `${t}` : void 0).filter((e) => !!e).length > 1 && console.warn(e), T(e.slice(S.length, e.length - 1));
462
+ }
463
+ var D = (e) => {
464
+ let t = [], n = /* @__PURE__ */ new Uint8Array(), r, i = (e, t = 0) => {
465
+ let n = S;
466
+ for (let r = t; r <= e.length - n.length; r++) {
467
+ let t = !0;
468
+ for (let i = 0; i < n.length; i++) if (e[r + i] !== n[i]) {
469
+ t = !1;
470
+ break;
471
+ }
472
+ if (t) return r;
473
+ }
474
+ return -1;
475
+ }, a = (e, t) => {
476
+ let n = new Uint8Array(e.length + t.length);
477
+ return n.set(e, 0), n.set(t, e.length), n;
478
+ }, o = (e) => {
479
+ for (n = a(n, e);;) {
480
+ let e = i(n, 0);
481
+ if (e === -1) {
482
+ n.length > S.length - 1 && (n = n.slice(n.length - (S.length - 1)));
483
+ break;
484
+ }
485
+ e > 0 && (n = n.slice(e), e = 0);
486
+ let r = n.indexOf(C, S.length);
487
+ if (r === -1) break;
488
+ let a = E(n.slice(0, r + 1));
489
+ a && t.push(new DataView(a.buffer, a.byteOffset, a.byteLength)), n = n.slice(r + 1);
490
+ }
491
+ }, s = (e) => {
492
+ if (e.data && e.data.length !== 0 && (o(e.data), r && t.length > 0)) {
493
+ let e = t.shift();
494
+ e && (r({
495
+ terminated: !1,
496
+ data: e
497
+ }), r = void 0);
498
+ }
499
+ };
500
+ e.addEventListener("midimessage", s);
501
+ let c = !1, l = () => {
502
+ c || (c = !0, e.removeEventListener("midimessage", s), e.removeEventListener("statechange", u), r &&= (r({ terminated: !0 }), void 0));
503
+ }, u = () => {
504
+ e.state === "disconnected" && l();
505
+ };
506
+ return e.addEventListener("statechange", u), {
507
+ read: async () => c || e.state === "disconnected" ? { terminated: !0 } : t.length > 0 ? {
508
+ terminated: !1,
509
+ data: t.shift()
510
+ } : new Promise((e) => {
511
+ r = e;
512
+ }),
513
+ stop: l
514
+ };
515
+ }, O = async (e, t) => {
516
+ for (;;) {
517
+ let { terminated: n, data: r } = await e();
518
+ if (r && t.dispatch(r, r.byteLength), n) break;
519
+ }
520
+ }, k = {
521
+ serial: "Web Serial",
522
+ usb: "WebUSB",
523
+ midi: "Web MIDI"
524
+ }, A = () => {
525
+ let e = "requestMIDIAccess" in navigator, t = "serial" in navigator, n = "usb" in navigator;
526
+ if (!e && !t && !n) return { browserSupport: !1 };
527
+ let r = async (e) => {
528
+ let t = (await navigator.usb.getDevices()).filter((e) => e);
529
+ if (t.length > 1 && console.warn("Suspicious: there is more than one device, are multiple devices connected?"), t.length <= 0 && !e) throw Error("No M8 USB device was granted to this page yet");
530
+ let n = t.length <= 0 ? await navigator.usb.requestDevice({ filters: [{
531
+ vendorId: h,
532
+ productId: g
533
+ }] }) : t.find((e) => e.vendorId === h) ?? t[0];
534
+ if (!n) throw Error("No devices found");
535
+ await n.open(), await n.selectConfiguration(1), await n.claimInterface(1), await n.controlTransferOut({
536
+ requestType: "class",
537
+ recipient: "interface",
538
+ request: 34,
539
+ value: 3,
540
+ index: 1
541
+ }), await n.controlTransferOut({
542
+ requestType: "class",
543
+ recipient: "interface",
544
+ request: 32,
545
+ value: 0,
546
+ index: 1
547
+ });
548
+ let r = x(v(n));
549
+ return {
550
+ transport: "usb",
551
+ commands: r,
552
+ reader: p(n),
553
+ close: async () => {
554
+ r.stop(), await n.close();
555
+ }
556
+ };
557
+ }, i = async (e) => {
558
+ let t = (await navigator.serial.getPorts()).filter(() => !0);
559
+ if (t.length > 1 && console.warn("Suspicious: there are more than one port, when expecting just one."), t.length <= 0 && !e) throw Error("No M8 serial port was granted to this page yet");
560
+ let n = t.length <= 0 ? await navigator.serial.requestPort({ filters: [{ usbVendorId: h }] }) : t.find((e) => e.getInfo().usbVendorId === h) ?? t[0];
561
+ if (await n.open({
562
+ baudRate: 115200,
563
+ dataBits: 8,
564
+ stopBits: 1,
565
+ parity: "none",
566
+ bufferSize: 4096
567
+ }), !n.readable || !n.writable) throw Error("Ports should've been read/writeable, but apparently they're not");
568
+ let r = n.writable.getWriter(), i = n.readable.getReader(), a = x(y(r));
569
+ return {
570
+ transport: "serial",
571
+ commands: a,
572
+ reader: m(i),
573
+ close: async () => {
574
+ a.stop(), await i.cancel().catch(() => void 0), i.releaseLock(), r.releaseLock(), await n.close();
575
+ }
576
+ };
577
+ }, a = async (e) => {
578
+ if (!e && (await navigator.permissions?.query({
579
+ name: "midi",
580
+ sysex: !0
581
+ }).catch(() => null))?.state !== "granted") throw Error("Web MIDI SysEx access was not granted to this page yet");
582
+ let t = await navigator.requestMIDIAccess({ sysex: !0 }), n = (e) => {
583
+ e.forEach((e) => {
584
+ e.name === "M8" && e.state === "connected" && (e.close(), console.log(`Disconnected existing M8: ${e.name} (${e.id})`));
585
+ });
586
+ };
587
+ n([...t.inputs.values()]), n([...t.outputs.values()]);
588
+ let r = [...t.inputs.values()].filter((e) => e.name === "M8"), i = [...t.outputs.values()].filter((e) => e.name === "M8");
589
+ if (r.length === 0 || i.length === 0) throw Error("M8 device not found. Please ensure your M8 is connected and powered on.");
590
+ r.length > 1 && console.warn(`Multiple M8 inputs detected. Using first device: ${r[0].name}`), i.length > 1 && console.warn(`Multiple M8 outputs detected. Using first device: ${i[0].name}`);
591
+ let a = r[0], o = i[0];
592
+ a.connection === "open" ? console.log("M8 input is already open") : await a.open(), o.connection === "open" ? console.log("M8 output is already open") : await o.open(), console.log(`Connected to M8 - Input: ${a.id}, Output: ${o.id}`);
593
+ let s = b(o), c = D(a);
594
+ return {
595
+ transport: "midi",
596
+ commands: s,
597
+ reader: c.read,
598
+ close: async () => {
599
+ s.stop(), c.stop(), await a.close(), await o.close();
600
+ }
601
+ };
602
+ }, o = {
603
+ serial: t,
604
+ usb: n,
605
+ midi: e
606
+ };
607
+ return {
608
+ browserSupport: !0,
609
+ available: o,
610
+ connect: async ({ transport: e = "auto", prompt: s = !0 } = {}) => {
611
+ let c = e === "auto" ? t ? "serial" : n ? "usb" : "midi" : e;
612
+ if (!o[c]) throw Error(`This browser does not support ${k[c]}`);
613
+ let l = await (c === "serial" ? i(s) : c === "usb" ? r(s) : a(s)), u = d(), f = !1, p = O(l.reader, u);
614
+ return {
615
+ transport: l.transport,
616
+ commands: l.commands,
617
+ reader: l.reader,
618
+ protocol: u,
619
+ closed: p,
620
+ close: async () => {
621
+ if (f) return p;
622
+ f = !0, await l.close().catch((e) => console.warn("[M8] close failed:", e)), await p;
623
+ }
624
+ };
625
+ }
626
+ };
627
+ }, ee = async (e, { maxAttempts: t = 3, retryDelayMs: n = 1500 } = {}) => {
628
+ for (let r = 1; r <= t; r++) try {
629
+ return await e();
630
+ } catch (e) {
631
+ console.warn(`Connection attempt ${r}/${t} failed:`, e), r < t ? await new Promise((e) => setTimeout(e, n)) : console.error("Could not connect to M8 after all attempts:", e);
632
+ }
633
+ }, j = {
634
+ autoGainControl: !1,
635
+ channelCount: { ideal: 2 },
636
+ echoCancellation: !1,
637
+ noiseSuppression: !1
638
+ }, M = async () => {
639
+ let e = (await navigator.mediaDevices.enumerateDevices()).filter((e) => e.kind === "audioinput" && e.label.includes("M8") && e.deviceId !== "default" && e.deviceId !== "communications");
640
+ return e.length > 1 && console.warn("Suspicious: More than one M8 audio input found"), e[0] ?? null;
641
+ }, N = async () => navigator.mediaDevices?.enumerateDevices ? M() : null, P = async ({ requireM8: e = !1 } = {}) => {
642
+ if (!navigator.mediaDevices?.getUserMedia) throw Error("Audio capture is not supported in this browser");
643
+ let t = await N();
644
+ if (!t) {
645
+ let n = await navigator.mediaDevices.getUserMedia({ audio: j });
646
+ if (t = await N(), !t) {
647
+ if (!e) return n;
648
+ for (let e of n.getTracks()) e.stop();
649
+ throw Error("No M8 audio input found (is the M8 connected over USB?)");
650
+ }
651
+ for (let e of n.getTracks()) e.stop();
652
+ }
653
+ return navigator.mediaDevices.getUserMedia({ audio: {
654
+ ...j,
655
+ deviceId: { exact: t.deviceId }
656
+ } });
657
+ }, F = () => {
658
+ let e = null, t = null, n = null, r = null, i = (e) => {
659
+ if (e.state !== "suspended" || typeof window > "u") return;
660
+ let t = () => {
661
+ e.resume(), window.removeEventListener("pointerdown", t), window.removeEventListener("keydown", t);
662
+ };
663
+ window.addEventListener("pointerdown", t), window.addEventListener("keydown", t);
664
+ }, a = async () => {
665
+ for (let e of t?.getTracks() ?? []) e.stop();
666
+ let r = e;
667
+ e = null, t = null, n = null, await r?.close().catch(() => void 0);
668
+ }, o = async (r) => {
669
+ let o = await P({ requireM8: r }), s = new AudioContext(), c = s.createMediaStreamSource(o), l = s.createMediaStreamDestination();
670
+ c.connect(s.destination), c.connect(l), e = s, t = o, n = l.stream;
671
+ for (let e of o.getAudioTracks()) e.addEventListener("ended", () => {
672
+ t === o && a();
673
+ });
674
+ await s.resume().catch(() => void 0), i(s);
675
+ };
676
+ return {
677
+ connect: async ({ requireM8: t = !1 } = {}) => {
678
+ if (!e) return r ??= o(t).finally(() => {
679
+ r = null;
680
+ }), r;
681
+ },
682
+ disconnect: a,
683
+ get connected() {
684
+ return e !== null;
685
+ },
686
+ getOutputCaptureStream: () => {
687
+ let e = n?.getAudioTracks() ?? [];
688
+ return e.length <= 0 ? null : new MediaStream(e.map((e) => e.clone()));
689
+ }
690
+ };
691
+ }, I = {
692
+ Left: 128,
693
+ Up: 64,
694
+ Down: 32,
695
+ Shift: 16,
696
+ Play: 8,
697
+ Right: 4,
698
+ Opt: 2,
699
+ Edit: 1
700
+ }, te = ({ left: e, right: t, up: n, down: r, shift: i, play: a, opt: o, edit: s }) => {
701
+ let c = 0;
702
+ return e && (c |= I.Left), t && (c |= I.Right), n && (c |= I.Up), r && (c |= I.Down), i && (c |= I.Shift), a && (c |= I.Play), o && (c |= I.Opt), s && (c |= I.Edit), c;
703
+ }, ne = {
704
+ up: I.Up,
705
+ down: I.Down,
706
+ left: I.Left,
707
+ right: I.Right
708
+ }, re = I.Up | I.Down | I.Left | I.Right, ie = 24, ae = 150, L = .1, oe = (e) => e === "up" || e === "down" ? "vertical" : "horizontal", se = (e) => {
709
+ switch (e) {
710
+ case "up": return "down";
711
+ case "down": return "up";
712
+ case "left": return "right";
713
+ case "right": return "left";
714
+ }
715
+ }, R = (e, t) => e ? e.rx === t.rx && e.ry === t.ry && e.rw === t.rw && e.rh === t.rh : !1, ce = (e) => ({
716
+ x: e.rx + e.rw / 2,
717
+ y: e.ry + e.rh / 2
718
+ }), le = (e, t) => t.x >= e.rx - L && t.x <= e.rx + e.rw + L, ue = (e, t) => t.y >= e.ry - L && t.y <= e.ry + e.rh + L, de = (e, t) => {
719
+ let n = ce(e), r = n.x - t.x, i = n.y - t.y;
720
+ return Math.sqrt(r * r + i * i);
721
+ }, fe = (e, t, n) => e === "vertical" ? n.y < t.ry - L ? "up" : n.y > t.ry + t.rh + L ? "down" : null : n.x < t.rx - L ? "left" : n.x > t.rx + t.rw + L ? "right" : null, pe = ({ bus: e, store: t }) => {
722
+ let n = null, r = null, i = 0, a = 0, o = !1, s = "vertical", c = {
723
+ vertical: !1,
724
+ horizontal: !1
725
+ }, l = null, u = null, d = !1, f = null, p = [], m = [], h = [], g = () => {
726
+ f &&= (clearTimeout(f), null);
727
+ }, _ = () => {
728
+ g(), f = setTimeout(() => {
729
+ O("timeout");
730
+ }, ae);
731
+ }, v = () => {
732
+ r = null, s = "vertical", c = {
733
+ vertical: !1,
734
+ horizontal: !1
735
+ }, l = null, u = null, d = !1, p = [], m = [], h = [], o = !1, a = i & ~re, g();
736
+ }, y = () => {
737
+ g(), n &&= (n(), null), v();
738
+ }, b = () => {
739
+ let e = t.get("cursorRect");
740
+ return e ? {
741
+ rx: e.x,
742
+ ry: e.y,
743
+ rw: e.w,
744
+ rh: e.h
745
+ } : null;
746
+ }, x = (e, t) => {
747
+ let n = de(e, t), r = le(e, t) || ue(e, t);
748
+ m.push({
749
+ rect: e,
750
+ index: p.length,
751
+ dist: n,
752
+ axisAligned: r
753
+ }), h.push(e), h.length > 4 && h.shift();
754
+ }, S = (e) => {
755
+ let t = null;
756
+ for (let n of m) (!e || n.axisAligned) && (!t || n.dist < t.dist) && (t = n);
757
+ if (!t && e) for (let e of m) (!t || e.dist < t.dist) && (t = e);
758
+ return t?.index ?? p.length;
759
+ }, C = (t) => {
760
+ let n = a, r = n | ne[t];
761
+ e.commands.sendKeys(r), e.commands.sendKeys(n);
762
+ }, w = (e) => {
763
+ for (let t = p.length - 1; t >= e; --t) C(se(p[t]));
764
+ }, T = () => {
765
+ if (h.length < 3 || p.length < 2) return !1;
766
+ let e = h[h.length - 1], t = h[h.length - 2], n = h[h.length - 3], r = p[p.length - 1], i = p[p.length - 2];
767
+ if (R(e, n) && !R(e, t) && se(i) === r) return !0;
768
+ if (h.length >= 4) {
769
+ let e = h[h.length - 4], t = h[h.length - 3], n = h[h.length - 2], r = h[h.length - 1];
770
+ if (R(e, n) && R(t, r) && !R(e, t)) return !0;
771
+ }
772
+ return !1;
773
+ }, E = (e, t) => {
774
+ let n = le(e, t), r = ue(e, t);
775
+ if (n && r) return null;
776
+ if (n && !r) return c.vertical ? null : fe("vertical", e, t);
777
+ if (r && !n) return c.horizontal ? null : fe("horizontal", e, t);
778
+ let i = s, a = i === "vertical" ? "horizontal" : "vertical";
779
+ return (c[i] ? null : fe(i, e, t)) || (c[a] ? null : fe(a, e, t));
780
+ }, D = (e, t) => {
781
+ C(e), p.push(e), l = e, u = t, d = !0, o = !0;
782
+ };
783
+ function O(e) {
784
+ if (!r) return;
785
+ let t = b();
786
+ if (!t) return;
787
+ let n = r;
788
+ if ((m.length === 0 || !R(m[m.length - 1].rect, t)) && x(t, n), T()) {
789
+ w(S(!0)), y();
790
+ return;
791
+ }
792
+ if (le(t, n) && ue(t, n)) {
793
+ y();
794
+ return;
795
+ }
796
+ if (p.length >= ie) {
797
+ w(S(!0)), y();
798
+ return;
799
+ }
800
+ if (d && l && u) {
801
+ if (!R(u, t)) d = !1, o = !1, c[oe(l)] = !1;
802
+ else if (e === "timeout") {
803
+ let e = oe(l);
804
+ c[e] = !0, s = e === "vertical" ? "horizontal" : "vertical", d = !1, o = !1;
805
+ } else return;
806
+ }
807
+ let i = E(t, n);
808
+ if (i) s = oe(i), D(i, t), _();
809
+ else {
810
+ if (e === "timeout") {
811
+ y();
812
+ return;
813
+ }
814
+ w(S(!0)), y();
815
+ }
816
+ }
817
+ let k = (e) => {
818
+ i = e.keys ?? 0, r || (a = i & ~re), r && o && (o = !1, e.keys, d && _());
819
+ };
820
+ e.protocol.eventBus.on("key", k);
821
+ let A = t.sub("cursorRect", () => {
822
+ r && O("rect");
823
+ });
824
+ return {
825
+ navigateTo: (e) => new Promise((i) => {
826
+ if (!t.get("cursorPos")) {
827
+ i();
828
+ return;
829
+ }
830
+ n &&= (n(), null), v(), n = i, r = e;
831
+ let a = b();
832
+ a ? (x(a, e), O("start")) : y();
833
+ }),
834
+ dispose: () => {
835
+ y(), e.protocol.eventBus.off("key", k), A();
836
+ }
837
+ };
838
+ }, z = (e) => e?.trim().toLowerCase() ?? "", B = /\.m[a-z0-9]{2}$/i, me = (e) => [
839
+ e.viewName ?? "",
840
+ e.viewTitle ?? "",
841
+ e.cursorPos?.x ?? "",
842
+ e.cursorPos?.y ?? "",
843
+ e.textUnderCursor ?? "",
844
+ e.currentLine ?? ""
845
+ ].join("|"), he = (e) => e.textUnderCursor?.trim() || e.currentLine?.trim() || null, ge = (e) => {
846
+ let t = z(e.viewName), n = z(e.viewTitle);
847
+ return t.includes("load") || t.includes("save") || n.includes("load") || n.includes("save");
848
+ }, _e = (e) => z(e) === "/..", ve = (e) => !!e?.trim().startsWith("/"), ye = (e) => !!e && !ve(e) && B.test(e.trim()), be = (e) => {
849
+ let t = e?.trim() ?? "";
850
+ if (!t) return [];
851
+ let n = z(t), r = z(t.replace(B, ""));
852
+ return Array.from(new Set([n, r].filter(Boolean)));
853
+ }, xe = (e) => _e(e) ? "parent" : ve(e) ? /^\/[^/]+$/.test(e.trim()) ? "dir" : "other" : ye(e) ? "file" : "other", Se = (e, t) => {
854
+ let n = (t) => e[t]?.trim() ?? "", r = t.cursorPos?.y ?? null, i = z(t.viewTitle), a = 0, o = e.length - 1;
855
+ if (r !== null && n(r)) {
856
+ for (a = r; a > 0 && n(a - 1);) --a;
857
+ for (o = r; o < e.length - 1 && n(o + 1);) o += 1;
858
+ }
859
+ let s = [];
860
+ for (let e = a; e <= o; e += 1) {
861
+ let t = n(e);
862
+ !t || i && z(t) === i || s.push({
863
+ row: e,
864
+ text: t,
865
+ key: z(t),
866
+ kind: xe(t)
867
+ });
868
+ }
869
+ let c = t.textUnderCursor?.trim();
870
+ return {
871
+ entries: s,
872
+ cursorRow: r,
873
+ cursorKey: r === null ? null : s.find((e) => e.row === r)?.key ?? null,
874
+ hasParent: s.some((e) => e.kind === "parent"),
875
+ consistent: !c || r === null || n(r).includes(c)
876
+ };
877
+ }, Ce = (e, t) => {
878
+ if (t.length === 0) return {
879
+ order: e,
880
+ consistent: !0
881
+ };
882
+ if (e.length === 0) return {
883
+ order: [...t],
884
+ consistent: !0
885
+ };
886
+ let n = t.findIndex((t) => e.includes(t));
887
+ if (n === -1) return {
888
+ order: [...t],
889
+ consistent: !1
890
+ };
891
+ let r = e.indexOf(t[n]) - n, i = r < 0 ? [...Array(-r).fill(""), ...e] : [...e], a = Math.max(0, r);
892
+ for (let e = 0; e < t.length; e += 1) {
893
+ let n = a + e;
894
+ if (n < i.length && i[n] !== "") {
895
+ if (i[n] !== t[e]) return {
896
+ order: [...t],
897
+ consistent: !1
898
+ };
899
+ } else {
900
+ if (i.includes(t[e])) return {
901
+ order: [...t],
902
+ consistent: !1
903
+ };
904
+ n >= i.length ? i.push(t[e]) : i[n] = t[e];
905
+ }
906
+ }
907
+ return {
908
+ order: i,
909
+ consistent: !0
910
+ };
911
+ }, we = (e) => e.split(/[^a-z0-9]+/).filter((e) => e.length >= 3), Te = /* @__PURE__ */ new Set([
912
+ "load",
913
+ "save",
914
+ "select",
915
+ "create",
916
+ "directory",
917
+ "new"
918
+ ]), Ee = (e, t) => ({
919
+ target: we(z(e).replace(B, "")),
920
+ title: we(z(t)).filter((e) => !Te.has(e))
921
+ }), De = (e, t) => {
922
+ let n = e.replace(/^\//, "");
923
+ if (n.length < 3) return 0;
924
+ let r = (e) => e.includes(n) || n.includes(e);
925
+ return t.target.some(r) ? 2 : +!!t.title.some(r);
926
+ }, V = (e) => new Promise((t) => setTimeout(t, e)), Oe = ({ getKeySink: e, store: t, debugLog: n, getScreenLines: r }) => {
927
+ let i = () => !!e(), a = (t) => {
928
+ e()?.sendKeys(t);
929
+ }, o = async (e, t = 50) => {
930
+ a(e), await V(t), a(0), await V(t);
931
+ }, s = (e, n = 500) => new Promise((r) => {
932
+ let i = !1, a = null, o = null, s = (e) => {
933
+ i || (i = !0, o !== null && clearTimeout(o), a?.(), r(e));
934
+ }, c = t.get("textUnderCursor");
935
+ c === e ? (a = t.sub("textUnderCursor", () => {
936
+ let n = t.get("textUnderCursor");
937
+ n !== e && s(n);
938
+ }), o = setTimeout(() => {
939
+ s(t.get("textUnderCursor"));
940
+ }, n)) : s(c);
941
+ }), c = () => ({
942
+ viewName: t.get("viewName"),
943
+ viewTitle: t.get("viewTitle"),
944
+ cursorPos: t.get("cursorPos"),
945
+ textUnderCursor: t.get("textUnderCursor"),
946
+ currentLine: t.get("currentLine")
947
+ });
948
+ return {
949
+ store: t,
950
+ debugLog: n,
951
+ hasBus: i,
952
+ sendKeys: a,
953
+ pressAndRelease: o,
954
+ waitForTextUnderCursorChange: s,
955
+ waitForCurrentLineChange: (e, n = 500) => new Promise((r) => {
956
+ let i = !1, a = null, o = null, s = (e) => {
957
+ i || (i = !0, o !== null && clearTimeout(o), a?.(), r(e));
958
+ }, c = t.get("currentLine");
959
+ c === e ? (a = t.sub("currentLine", () => {
960
+ let n = t.get("currentLine");
961
+ n !== e && s(n);
962
+ }), o = setTimeout(() => {
963
+ s(t.get("currentLine"));
964
+ }, n)) : s(c);
965
+ }),
966
+ getFileBrowserSnapshot: c,
967
+ waitForFileBrowserSnapshotChange: (e, n = 500) => new Promise((r) => {
968
+ let i = !1, a = null, o = null, s = null, l = null, u = null, d = null, f = me(e), p = (e) => {
969
+ i || (i = !0, d !== null && clearTimeout(d), a?.(), o?.(), s?.(), l?.(), u?.(), r(e));
970
+ }, m = () => {
971
+ let e = c();
972
+ me(e) !== f && p(e);
973
+ }, h = c();
974
+ me(h) === f ? (a = t.sub("textUnderCursor", m), o = t.sub("currentLine", m), s = t.sub("cursorPos", m), l = t.sub("viewName", m), u = t.sub("viewTitle", m), d = setTimeout(() => {
975
+ p(c());
976
+ }, n)) : p(h);
977
+ }),
978
+ getScreenLines: r
979
+ };
980
+ }, H = (e, t) => {
981
+ t === void 0 ? console.log("[M8SDK browseFile]", e) : console.log("[M8SDK browseFile]", e, t);
982
+ }, ke = 8, Ae = 8, je = 64, Me = 512, Ne = () => ({
983
+ order: [],
984
+ kinds: /* @__PURE__ */ new Map(),
985
+ names: /* @__PURE__ */ new Map(),
986
+ top: !1,
987
+ bottom: !1,
988
+ hasParent: !1,
989
+ sorted: !1,
990
+ visited: /* @__PURE__ */ new Set(),
991
+ rejected: /* @__PURE__ */ new Set()
992
+ }), Pe = (e) => e === "up" ? "down" : "up", Fe = (e) => {
993
+ let { hasBus: t, pressAndRelease: n, getFileBrowserSnapshot: r, waitForFileBrowserSnapshotChange: i, getScreenLines: a } = e, o = /* @__PURE__ */ new Map(), s = null, c = null;
994
+ return async (e, l = !0) => {
995
+ if (!t()) return !1;
996
+ let u = z(e);
997
+ if (!u) return !1;
998
+ let d = B.test(u), f = Ee(e, r().viewTitle);
999
+ H("start", {
1000
+ targetText: e,
1001
+ normalizedTarget: u,
1002
+ exact: l
1003
+ });
1004
+ let p = () => ge(r()), m = async (e, t = 350) => {
1005
+ let a = r();
1006
+ await n(e, 35);
1007
+ let o = await i(a, t);
1008
+ return {
1009
+ changed: me(o) !== me(a),
1010
+ snapshot: o
1011
+ };
1012
+ }, h = (e) => e === "up" ? I.Up : I.Down, g = (e) => I.Opt | h(e), _ = async () => {
1013
+ let e = r();
1014
+ H("apply alphabetical sort"), await n(I.Shift | I.Opt, 35), await V(180), await i(e, 300);
1015
+ }, v = (e) => ye(e) ? be(e).some((e) => l ? e === u : e.includes(u)) : !1, y = (e) => {
1016
+ let t = e.trim();
1017
+ return d ? t : t.replace(B, "");
1018
+ }, b = (e) => z(y(e)), x = y(e), S = async () => {
1019
+ for (let e = 0;; e += 1) {
1020
+ let t = Se(a(), r());
1021
+ if (t.consistent || e >= 2) return t;
1022
+ await V(40);
1023
+ }
1024
+ }, C = (e, t) => {
1025
+ let n = t.entries.map((e) => e.key), i = Ce(e.order, n);
1026
+ e.order = i.order, i.consistent || (e.top = !1, e.bottom = !1);
1027
+ for (let n of t.entries) e.kinds.set(n.key, n.kind), e.names.set(n.key, n.text);
1028
+ let a = z(r().viewName);
1029
+ if (t.hasParent) e.hasParent = !0, e.top = !0;
1030
+ else if (e.hasParent && n.length > 0) {
1031
+ let e = o.get(a);
1032
+ (e === void 0 || n.length < e) && o.set(a, n.length);
1033
+ }
1034
+ n.length < Math.max(Ae, o.get(a) ?? 0) && (e.top = !0, e.bottom = !0);
1035
+ }, w = async (e, t, n) => {
1036
+ let r = (await m(g(n), 280)).changed, i = r, a = !1;
1037
+ if (!r && s !== !0) for (let e = 0; e < ke; e += 1) {
1038
+ if (!(await m(h(n), 250)).changed) {
1039
+ a = !0;
1040
+ break;
1041
+ }
1042
+ i = !0, s = !1;
1043
+ }
1044
+ else r || (a = !0);
1045
+ if (a && (n === "up" ? e.top = !0 : e.bottom = !0, H("end of list", { direction: n })), !i) return null;
1046
+ let o = await S();
1047
+ C(e, o);
1048
+ let c = t.cursorKey ? e.order.indexOf(t.cursorKey) : -1, l = o.cursorKey ? e.order.indexOf(o.cursorKey) : -1, u = Math.abs(l - c);
1049
+ return r && c >= 0 && l >= 0 && u > 0 && u < ke && (s = !0), o;
1050
+ }, T = (e, t, n) => {
1051
+ if (n === "/..") return "up";
1052
+ let r = e.order.indexOf(n), i = t.cursorKey ? e.order.indexOf(t.cursorKey) : -1;
1053
+ return r >= 0 && i >= 0 ? r < i ? "up" : "down" : e.top && !e.bottom ? "down" : "up";
1054
+ }, E = async (e, t, n) => {
1055
+ let r = n, i = null, a = !1;
1056
+ for (let n = 0; n < 96; n += 1) {
1057
+ let n = r.entries.find((e) => e.key === t);
1058
+ if (n) {
1059
+ if (r.cursorRow === null) return null;
1060
+ let t = n.row - r.cursorRow;
1061
+ if (t === 0) return r;
1062
+ let i = t < 0 ? "up" : "down";
1063
+ if (!(await m(Math.abs(t) >= ke ? g(i) : h(i), 250)).changed) return null;
1064
+ r = await S(), C(e, r);
1065
+ continue;
1066
+ }
1067
+ i ??= T(e, r, t);
1068
+ let o = await w(e, r, i);
1069
+ if (o) r = o;
1070
+ else if (a) return null;
1071
+ else a = !0, i = Pe(i);
1072
+ }
1073
+ return null;
1074
+ }, D = async (e, t) => {
1075
+ let n = t.cursorRow ?? 0, i = t.entries.filter((t) => t.kind === "file" && !e.rejected.has(t.key) && v(t.text)).sort((e, t) => Math.abs(e.row - n) - Math.abs(t.row - n))[0];
1076
+ if (!i) return "none";
1077
+ let a = await E(e, i.key, t), o = he(r());
1078
+ return a && v(o) ? (H("match found", {
1079
+ entry: o,
1080
+ y: a.cursorRow
1081
+ }), await m(I.Edit, 500), "found") : (H("match not reachable", { candidate: i.text }), e.rejected.add(i.key), "failed");
1082
+ }, O = (e) => e.order.filter((t) => e.kinds.get(t) === "file").map((t) => {
1083
+ let n = e.names.get(t) ?? "";
1084
+ return {
1085
+ ci: b(n),
1086
+ raw: y(n)
1087
+ };
1088
+ }), k = (e) => {
1089
+ if (!e.sorted) return;
1090
+ let t = O(e);
1091
+ if (t.some((e, n) => n > 0 && (t[n - 1].ci > e.ci || t[n - 1].raw > e.raw))) {
1092
+ e.sorted = !1, H("listing is not alphabetical, order hints disabled");
1093
+ return;
1094
+ }
1095
+ let n = e.order.map((t) => {
1096
+ let n = (e.names.get(t) ?? "").trim();
1097
+ return {
1098
+ kind: e.kinds.get(t),
1099
+ ci: z(n).replace(/^\//, ""),
1100
+ raw: n.replace(/^\//, "")
1101
+ };
1102
+ }), r = n.findIndex((e) => e.kind === "file");
1103
+ r < 0 || (n.slice(r).some((e) => e.kind === "dir") ? c = !1 : n.some((e, t) => e.kind === "dir" && n.slice(t + 1).some((t) => t.kind === "file" && e.ci > t.ci && e.raw > t.raw)) && c === null && (c = !0));
1104
+ }, A = (e) => !l || !e.sorted || c !== !0 || !e.top || e.bottom ? !1 : O(e).some((e) => /^[a-z0-9]/.test(e.ci) && e.ci > u && e.raw > x && e.raw > u), ee = (e, t) => {
1105
+ if (!l || !e.sorted) return null;
1106
+ let n = t.entries.filter((e) => e.kind === "file").map((e) => b(e.text)), r = n[0], i = n[n.length - 1];
1107
+ return r === void 0 || i === void 0 ? null : u < r ? "up" : u > i ? "down" : null;
1108
+ }, j = (e, t) => e.top === e.bottom ? ee(e, t) ?? "up" : e.top ? "down" : "up", M = (e, t) => {
1109
+ let n = t.cursorKey ? e.order.indexOf(t.cursorKey) : -1, r = null;
1110
+ for (let [i, a] of e.kinds) {
1111
+ if (a !== "dir" || e.visited.has(i)) continue;
1112
+ let o = t.entries.find((e) => e.key === i), s = e.order.indexOf(i), c = o && t.cursorRow !== null ? Math.abs(o.row - t.cursorRow) : 100 + (n >= 0 && s >= 0 ? Math.abs(s - n) : 500), l = De(i, f) * 1e4 - c;
1113
+ (!r || l > r.rank) && (r = {
1114
+ key: i,
1115
+ rank: l
1116
+ });
1117
+ }
1118
+ return r?.key ?? null;
1119
+ }, N = async (e, t) => await E(e, "/..", t) ? (H("navigate to parent directory"), (await m(I.Edit, 500)).changed && p()) : (H("parent directory entry unreachable"), !1), P = async (e) => {
1120
+ if (e > je || !p()) return H("search aborted", {
1121
+ depth: e,
1122
+ active: p()
1123
+ }), "aborted";
1124
+ let t = Ne(), n = await S();
1125
+ C(t, n), H("search directory", {
1126
+ depth: e,
1127
+ entries: n.entries.length,
1128
+ complete: t.top && t.bottom
1129
+ }), l && !(t.top && t.bottom) && (await _(), t.order = [], t.top = !1, t.bottom = !1, t.sorted = !0, n = await S(), C(t, n));
1130
+ for (let r = 0;; r += 1) {
1131
+ let i = await D(t, n);
1132
+ if (i === "found") return "found";
1133
+ if (i === "failed" && (n = await S(), C(t, n)), k(t), A(t) && (H("rest of listing is past the target", { depth: e }), t.bottom = !0), t.top && t.bottom || r >= Me) break;
1134
+ let a = await w(t, n, j(t, n));
1135
+ a && (n = a);
1136
+ }
1137
+ for (;;) {
1138
+ let r = M(t, n);
1139
+ if (!r) break;
1140
+ if (t.visited.add(r), !await E(t, r, n)) {
1141
+ H("directory unreachable", { directory: r }), n = await S(), C(t, n);
1142
+ continue;
1143
+ }
1144
+ H("enter directory", {
1145
+ directory: r,
1146
+ depth: e
1147
+ });
1148
+ let i = await m(I.Edit, 500);
1149
+ if (!p()) return "aborted";
1150
+ if (!i.changed) {
1151
+ n = await S(), C(t, n);
1152
+ continue;
1153
+ }
1154
+ let a = await P(e + 1);
1155
+ if (a !== "missed") return a;
1156
+ n = await S(), C(t, n);
1157
+ }
1158
+ return e === 0 || await N(t, n) ? "missed" : "aborted";
1159
+ };
1160
+ if (!p()) return console.warn("[M8SDK] browseFile requires a file browser view (load/save)"), !1;
1161
+ if (a().length === 0) return console.warn("[M8SDK] browseFile needs the screen reader, which is not available"), !1;
1162
+ let F = await P(0);
1163
+ return F !== "found" && H("search failed", {
1164
+ targetText: e,
1165
+ outcome: F
1166
+ }), F === "found";
1167
+ };
1168
+ }, Ie = (e) => {
1169
+ if (!e) return null;
1170
+ let t = e.trim();
1171
+ if (t === "--") return 0;
1172
+ let n = t.replace(/^0x/i, "").match(/^[0-9A-Fa-f]+/);
1173
+ if (!n) return null;
1174
+ let r = parseInt(n[0], 16);
1175
+ return Number.isNaN(r) ? null : r;
1176
+ }, Le = (e) => {
1177
+ if (!e) return null;
1178
+ let t = e.trim();
1179
+ if (t === "--") return 0;
1180
+ let n = t.match(/^[+-]?\d+/);
1181
+ if (!n) return null;
1182
+ let r = Number.parseInt(n[0], 10);
1183
+ return Number.isNaN(r) ? null : r;
1184
+ }, Re = /[+-]?\d+\.\d+/g, ze = (e) => {
1185
+ if (!e) return [];
1186
+ let t = [];
1187
+ Re.lastIndex = 0;
1188
+ let n = Re.exec(e);
1189
+ for (; n !== null;) {
1190
+ let r = n[0], i = r.startsWith("-"), a = i || r.startsWith("+") ? r.slice(1) : r, o = a.indexOf("."), s = a.slice(0, o), c = a.slice(o + 1), l = Number.parseInt(s || "0", 10), u = Number.parseInt(c || "0", 10), d = 10 ** c.length, f = d > 0 ? 100 / d : 1, p = l * 100 + u * 100 / d;
1191
+ !Number.isNaN(l) && !Number.isNaN(u) && t.push({
1192
+ raw: r,
1193
+ negative: i,
1194
+ intDigits: s,
1195
+ decDigits: c,
1196
+ decScale: d,
1197
+ tickHundredths: f,
1198
+ ticks: (i ? -1 : 1) * Math.round(p / f)
1199
+ }), n = Re.exec(e);
1200
+ }
1201
+ return t;
1202
+ }, Be = (e, t) => {
1203
+ if (e.length <= 1) return 0;
1204
+ let n = t?.trim() ?? "";
1205
+ if (!n) return 0;
1206
+ let r = e.findIndex((e) => e.raw === n || e.raw.replace(/^[+-]/, "") === n || `${e.negative ? "-" : ""}${e.intDigits}` === n || e.intDigits === n || e.decDigits === n);
1207
+ return r >= 0 ? r : 0;
1208
+ }, Ve = (e, t) => {
1209
+ if (!e) return null;
1210
+ let n = t?.trim() ?? "";
1211
+ if (!n) return null;
1212
+ let r = e.raw.replace(/^[+-]/, "");
1213
+ if (e.raw === n || r === n) return "full";
1214
+ if (`${e.negative ? "-" : ""}${e.intDigits}` === n || e.intDigits === n) return "int";
1215
+ if (e.decDigits === n) return "dec";
1216
+ if (n.length === 1) {
1217
+ let t = e.intDigits.includes(n), r = e.decDigits.includes(n);
1218
+ if (t && !r) return "int";
1219
+ if (r && !t) return "dec";
1220
+ }
1221
+ return null;
1222
+ }, He = (e, t) => t.length === 1 ? e.raw === t || e.raw.replace(/^[+-]/, "") === t : e.raw === t || e.raw.replace(/^[+-]/, "") === t || `${e.negative ? "-" : ""}${e.intDigits}` === t || e.intDigits === t || e.decDigits === t, Ue = (e, t, n) => {
1223
+ let r = n?.trim() ?? "";
1224
+ return !r || !e[t] || He(e[t], r) ? !1 : e.some((e, n) => n !== t && He(e, r));
1225
+ }, U = (e, t) => {
1226
+ let n = Math.round(e * t), r = n < 0 ? "-" : "", i = Math.abs(n), a = Math.floor(i / 100);
1227
+ return `${r}${a}.${(i - a * 100).toString().padStart(2, "0")}`;
1228
+ }, We = [
1229
+ "C-",
1230
+ "C#",
1231
+ "D-",
1232
+ "D#",
1233
+ "E-",
1234
+ "F-",
1235
+ "F#",
1236
+ "G-",
1237
+ "G#",
1238
+ "A-",
1239
+ "A#",
1240
+ "B-"
1241
+ ], W = (e) => {
1242
+ if (!e) return null;
1243
+ let t = e.trim().toUpperCase().match(/([A-G][#-][0-9A-F])/);
1244
+ if (!t) return null;
1245
+ let n = t[1], r = n.slice(0, 2), i = Number.parseInt(n.slice(2, 3), 16), a = We.indexOf(r);
1246
+ return a < 0 || Number.isNaN(i) ? null : {
1247
+ label: n,
1248
+ noteName: r,
1249
+ octave: i,
1250
+ semitoneIndex: i * 12 + a
1251
+ };
1252
+ }, Ge = (e) => {
1253
+ let { store: t, debugLog: n, hasBus: r, sendKeys: i, pressAndRelease: a, waitForTextUnderCursorChange: o, waitForCurrentLineChange: s } = e;
1254
+ return async (e) => {
1255
+ if (!r() || !Number.isFinite(e)) return !1;
1256
+ let c = 0, l = 1, u = [], d = () => {
1257
+ let e = ze(t.get("currentLine"));
1258
+ if (u = e, !e.length) return null;
1259
+ c = Math.min(c, e.length - 1);
1260
+ let n = e[c];
1261
+ return n.tickHundredths > 0 && (l = n.tickHundredths), n;
1262
+ }, f = ze(t.get("currentLine"));
1263
+ if (!f.length) return console.warn("[M8SDK] Could not find a float value like \"440.00\" or \"-10.69\" on the current line:", t.get("currentLine")), !1;
1264
+ c = Be(f, t.get("textUnderCursor")), f.length > 1 && n("[M8SDK] Multiple float values on line, editing:", f[c]?.raw);
1265
+ let p = f[c];
1266
+ l = p.tickHundredths;
1267
+ let m = Math.round(Math.round(e * 100) / l);
1268
+ if (p.ticks === m) return n("[M8SDK] Already at target float value:", U(m, l)), !0;
1269
+ n("[M8SDK] Setting float value from", U(p.ticks, l), "to", U(m, l)), await a(I.Edit), await V(80);
1270
+ let h = () => ({
1271
+ upDown: {
1272
+ mag: null,
1273
+ bias: 1
1274
+ },
1275
+ leftRight: {
1276
+ mag: null,
1277
+ bias: 1
1278
+ }
1279
+ }), g = {
1280
+ full: h(),
1281
+ int: h(),
1282
+ dec: h()
1283
+ }, _ = p.decScale, v = Date.now(), y = Ve(p, t.get("textUnderCursor")) ?? "int";
1284
+ n("[M8SDK] Float cursor focus:", y);
1285
+ let b = !1, x = !1, S = p.ticks, C = null, w = p.ticks, T = Math.abs(p.ticks - m), E = 0, D = !1, O = !1, k = (e, t) => {
1286
+ let n = e === "upDown" ? I.Up : I.Right, r = e === "upDown" ? I.Down : I.Left;
1287
+ return I.Edit | (t >= 0 ? n : r);
1288
+ }, A = async (e, n, r) => {
1289
+ let a = g[y][e], o = k(e, n * a.bias), c = t.get("currentLine");
1290
+ for (let e = 0; e < r; e++) i(o), await V(22);
1291
+ await s(c, 350);
1292
+ }, ee = async (e) => {
1293
+ let n = () => Ve(d(), t.get("textUnderCursor"));
1294
+ if (n() === e) return y = e, !0;
1295
+ let r = t.get("textUnderCursor"), i = e === "dec" ? I.Right : I.Left, s = e === "dec" ? I.Left : I.Right;
1296
+ if (await a(i, 35), await o(r, 250), n() === e) return y = e, !0;
1297
+ await a(s, 35), await o(r, 250);
1298
+ let c = n() === e;
1299
+ return c && (y = e), c;
1300
+ };
1301
+ for (; !D && !O && Date.now() - v < 15e3;) {
1302
+ let e = d();
1303
+ if (!e) {
1304
+ console.warn("[M8SDK] Float value no longer parseable while editing:", t.get("currentLine")), O = !0;
1305
+ break;
1306
+ }
1307
+ if (Ue(u, c, t.get("textUnderCursor"))) {
1308
+ console.warn("[M8SDK] Float cursor drifted to another field, aborting to avoid editing the wrong value"), x = !0, O = !0;
1309
+ break;
1310
+ }
1311
+ let r = m - e.ticks;
1312
+ if (r === 0) {
1313
+ D = !0;
1314
+ break;
1315
+ }
1316
+ let i = Math.abs(r);
1317
+ i < T && (T = i, w = e.ticks);
1318
+ let a = C !== null && e.ticks === C, o = (S - m) * (e.ticks - m) < 0;
1319
+ if (a && o) {
1320
+ n("[M8SDK] Float adjustment bouncing around target, stopping");
1321
+ break;
1322
+ }
1323
+ if (C = S, S = e.ticks, y !== "full" && !b) {
1324
+ let e = i >= _ ? "int" : "dec";
1325
+ if (e !== y && !await ee(e)) {
1326
+ if (Ue(u, c, t.get("textUnderCursor"))) {
1327
+ console.warn("[M8SDK] Float cursor drifted to another field, aborting to avoid editing the wrong value"), x = !0, O = !0;
1328
+ break;
1329
+ }
1330
+ n("[M8SDK] Could not relocate float cursor, continuing on current digit group"), b = !0;
1331
+ }
1332
+ }
1333
+ let s = g[y], f = y === "int" ? Math.max(32, 3 * _) : y === "full" ? _ : 8, p, h = 1;
1334
+ s.upDown.mag !== null && s.upDown.mag > 0 && i >= s.upDown.mag ? (p = "upDown", h = Math.min(Math.max(1, Math.floor(i / s.upDown.mag)), 96)) : s.upDown.mag === null && i >= f ? (p = "upDown", h = 1) : s.leftRight.mag !== null && s.leftRight.mag > 0 ? (p = "leftRight", h = Math.min(Math.max(1, Math.floor(i / s.leftRight.mag)), 96)) : (p = "leftRight", h = 1);
1335
+ let v = r > 0 ? 1 : -1, k = e.ticks, j = y, M = p;
1336
+ await A(p, v, h);
1337
+ let N = d();
1338
+ if (!N) {
1339
+ O = !0;
1340
+ break;
1341
+ }
1342
+ let P = N.ticks - k;
1343
+ if (P === 0) {
1344
+ E += 1, E >= 4 && (console.warn(`[M8SDK] Float value stopped reacting at ${U(N.ticks, l)} (target ${U(m, l)} may be out of range)`), O = !0);
1345
+ continue;
1346
+ }
1347
+ E = 0;
1348
+ let F = g[j][M];
1349
+ F.mag = Math.max(1, Math.round(Math.abs(P) / h)), Math.sign(P) !== Math.sign(r) && (n(`[M8SDK] Float ${M} arrows move oppositely in '${j}' focus, inverting mapping`), F.bias *= -1, C = null);
1350
+ }
1351
+ if (!D && !x) {
1352
+ let e = Date.now();
1353
+ for (; Date.now() - e < 1800;) {
1354
+ let e = d();
1355
+ if (!e || e.ticks === w) break;
1356
+ let t = w - e.ticks, n = Math.abs(t);
1357
+ y !== "full" && !b && n >= _ != (y === "int") && (await ee(n >= _ ? "int" : "dec") || (b = !0));
1358
+ let r = g[y], i, a = 1;
1359
+ r.upDown.mag !== null && r.upDown.mag > 0 && n >= r.upDown.mag ? (i = "upDown", a = Math.min(Math.max(1, Math.floor(n / r.upDown.mag)), 16)) : r.leftRight.mag !== null && r.leftRight.mag > 0 ? (i = "leftRight", a = Math.min(Math.max(1, Math.floor(n / r.leftRight.mag)), 16)) : i = "leftRight";
1360
+ let o = e.ticks;
1361
+ await A(i, t > 0 ? 1 : -1, a);
1362
+ let s = d();
1363
+ if (!s || s.ticks === o) break;
1364
+ }
1365
+ }
1366
+ x || await a(I.Edit);
1367
+ let j = d(), M = !!j && j.ticks === m;
1368
+ return n(`[M8SDK] Float setting ${M ? "succeeded" : "failed"}: "${j?.raw ?? "N/A"}" (${j ? U(j.ticks, l) : "N/A"})`), M;
1369
+ };
1370
+ }, Ke = {
1371
+ song: [
1372
+ {
1373
+ to: "project",
1374
+ dir: "up",
1375
+ keys: [80, 0]
1376
+ },
1377
+ {
1378
+ to: "mixer",
1379
+ dir: "down",
1380
+ keys: [48, 0],
1381
+ weight: 10
1382
+ },
1383
+ {
1384
+ to: "chain",
1385
+ dir: "right",
1386
+ keys: [20, 0]
1387
+ }
1388
+ ],
1389
+ project: [{
1390
+ to: "song",
1391
+ dir: "down",
1392
+ keys: [48, 0]
1393
+ }, {
1394
+ to: "chain",
1395
+ dir: "down",
1396
+ keys: [48, 0]
1397
+ }],
1398
+ mixer: [
1399
+ {
1400
+ to: "effectsettings",
1401
+ dir: "down",
1402
+ keys: [48, 0]
1403
+ },
1404
+ {
1405
+ to: "song",
1406
+ dir: "up",
1407
+ keys: [80, 0],
1408
+ weight: 10
1409
+ },
1410
+ {
1411
+ to: "chain",
1412
+ dir: "up",
1413
+ keys: [80, 0],
1414
+ weight: 10
1415
+ },
1416
+ {
1417
+ to: "phrase",
1418
+ dir: "up",
1419
+ keys: [80, 0],
1420
+ weight: 10
1421
+ },
1422
+ {
1423
+ to: "inst",
1424
+ dir: "up",
1425
+ keys: [80, 0],
1426
+ weight: 10
1427
+ },
1428
+ {
1429
+ to: "table",
1430
+ dir: "up",
1431
+ keys: [80, 0],
1432
+ weight: 10
1433
+ }
1434
+ ],
1435
+ effectsettings: [{
1436
+ to: "mixer",
1437
+ dir: "up",
1438
+ keys: [80, 0]
1439
+ }],
1440
+ inst: [
1441
+ {
1442
+ to: "table",
1443
+ dir: "right",
1444
+ keys: [20, 0]
1445
+ },
1446
+ {
1447
+ to: "phrase",
1448
+ dir: "left",
1449
+ keys: [144, 0]
1450
+ },
1451
+ {
1452
+ to: "instmods",
1453
+ dir: "up",
1454
+ keys: [80, 0]
1455
+ },
1456
+ {
1457
+ to: "mixer",
1458
+ dir: "down",
1459
+ keys: [48, 0],
1460
+ weight: 10
1461
+ }
1462
+ ],
1463
+ table: [
1464
+ {
1465
+ to: "inst",
1466
+ dir: "left",
1467
+ keys: [144, 0]
1468
+ },
1469
+ {
1470
+ to: "instmods",
1471
+ dir: "up",
1472
+ keys: [80, 0]
1473
+ },
1474
+ {
1475
+ to: "mixer",
1476
+ dir: "down",
1477
+ keys: [48, 0],
1478
+ weight: 10
1479
+ }
1480
+ ],
1481
+ phrase: [
1482
+ {
1483
+ to: "inst",
1484
+ dir: "right",
1485
+ keys: [20, 0]
1486
+ },
1487
+ {
1488
+ to: "chain",
1489
+ dir: "left",
1490
+ keys: [144, 0]
1491
+ },
1492
+ {
1493
+ to: "groove",
1494
+ dir: "up",
1495
+ keys: [80, 0]
1496
+ },
1497
+ {
1498
+ to: "mixer",
1499
+ dir: "down",
1500
+ keys: [48, 0],
1501
+ weight: 10
1502
+ }
1503
+ ],
1504
+ chain: [
1505
+ {
1506
+ to: "phrase",
1507
+ dir: "right",
1508
+ keys: [20, 0]
1509
+ },
1510
+ {
1511
+ to: "song",
1512
+ dir: "left",
1513
+ keys: [144, 0]
1514
+ },
1515
+ {
1516
+ to: "project",
1517
+ dir: "up",
1518
+ keys: [80, 0]
1519
+ },
1520
+ {
1521
+ to: "mixer",
1522
+ dir: "down",
1523
+ keys: [48, 0],
1524
+ weight: 10
1525
+ }
1526
+ ],
1527
+ groove: [{
1528
+ to: "scale",
1529
+ dir: "up",
1530
+ keys: [80, 0]
1531
+ }, {
1532
+ to: "phrase",
1533
+ dir: "down",
1534
+ keys: [48, 0]
1535
+ }],
1536
+ scale: [{
1537
+ to: "groove",
1538
+ dir: "down",
1539
+ keys: [48, 0]
1540
+ }],
1541
+ instmods: [
1542
+ {
1543
+ to: "instrumentpool",
1544
+ dir: "up",
1545
+ keys: [80, 0]
1546
+ },
1547
+ {
1548
+ to: "inst",
1549
+ dir: "down",
1550
+ keys: [48, 0]
1551
+ },
1552
+ {
1553
+ to: "table",
1554
+ dir: "down",
1555
+ keys: [48, 0]
1556
+ }
1557
+ ],
1558
+ instrumentpool: [{
1559
+ to: "instmods",
1560
+ dir: "down",
1561
+ keys: [48, 0]
1562
+ }]
1563
+ }, qe = { views: [
1564
+ "chain",
1565
+ "effectsettings",
1566
+ "groove",
1567
+ "instmods",
1568
+ "inst",
1569
+ "instrumentpool",
1570
+ "mixer",
1571
+ "phrase",
1572
+ "project",
1573
+ "scale",
1574
+ "song",
1575
+ "table",
1576
+ "mixeq",
1577
+ "limiterscope",
1578
+ "mixscope",
1579
+ "modfxeq",
1580
+ "delayeq",
1581
+ "reverbeq",
1582
+ "loadinstrument",
1583
+ "selectsavedirectory",
1584
+ "createdirectory",
1585
+ "systemsettings"
1586
+ ] }, Je = (e) => {
1587
+ let t = /* @__PURE__ */ new Map(), n = /* @__PURE__ */ new Map();
1588
+ for (let [r, i] of Object.entries(e)) {
1589
+ let e = r.toLowerCase(), a = [], o = /* @__PURE__ */ new Map();
1590
+ for (let e of i) e.dir && a.push({
1591
+ to: e.to,
1592
+ dir: e.dir,
1593
+ weight: e.weight
1594
+ }), e.keys?.length && o.set(e.to, e.keys.slice());
1595
+ t.set(e, a), o.size && n.set(e, o);
1596
+ }
1597
+ return {
1598
+ graph: t,
1599
+ edgeKeys: n
1600
+ };
1601
+ }, Ye = null, Xe = null, Ze = () => (Ye ??= Je(Ke), Ye), Qe = () => {
1602
+ if (!Xe) {
1603
+ let e = Array.isArray(qe.views) ? qe.views : [];
1604
+ Xe = new Set(e.map((e) => String(e).trim().toLowerCase()).filter((e) => !!e));
1605
+ }
1606
+ return Xe;
1607
+ }, $e = 50, et = {
1608
+ x: 0,
1609
+ y: 0,
1610
+ w: 1,
1611
+ h: 1
1612
+ }, tt = class {
1613
+ constructor() {
1614
+ this.assemblies = [], this.selectionRectSamples = [], this.lastCursor = et, this.lastSelectionCursor = null, this.lastCursorColor = null, this.lastSelectionMode = !1, this.lastSelectionSeenAt = 0, this.ASSEMBLY_TIMEOUT = 100, this.SELECTION_SAMPLE_WINDOW = 50, this.SELECTION_HOLD_DURATION = 150;
1615
+ }
1616
+ processRect(e) {
1617
+ if (!e) return {
1618
+ cursor: this.lastSelectionMode && this.lastSelectionCursor ? this.lastSelectionCursor : this.lastCursor,
1619
+ cursorColor: this.lastCursorColor,
1620
+ selectionMode: this.lastSelectionMode
1621
+ };
1622
+ let t = Date.now();
1623
+ this.assemblies = this.assemblies.filter((e) => t - e.startTime < this.ASSEMBLY_TIMEOUT);
1624
+ let n = null;
1625
+ for (let t of this.assemblies) t.state !== "complete" && (this.processRectAgainstAssembly(e, t), this.isAssemblyComplete(t) && (n = this.buildCursorFromAssembly(t), t.state = "complete"));
1626
+ if (n) return this.lastCursor = n, this.assemblies = [], this.lastSelectionMode = !1, this.lastSelectionCursor = null, this.selectionRectSamples = [], {
1627
+ cursor: n,
1628
+ cursorColor: this.lastCursorColor,
1629
+ selectionMode: !1
1630
+ };
1631
+ if (e.type === 4 && e.size.width === 3 && e.size.height === 1) {
1632
+ let t = this.createNewAssembly(e);
1633
+ this.assemblies.push(t), "color" in e && e.color && (this.lastCursorColor = e.color), this.assemblies.length > 2 && (this.assemblies = this.assemblies.slice(-2));
1634
+ }
1635
+ this.recordSelectionSample(e, t);
1636
+ let r = this.detectSelectionCursor(t);
1637
+ if (r) return this.lastSelectionCursor = r, this.lastSelectionMode = !0, this.lastSelectionSeenAt = t, this.selectionRectSamples = [], {
1638
+ cursor: r,
1639
+ cursorColor: this.lastCursorColor,
1640
+ selectionMode: !0
1641
+ };
1642
+ let i = this.updateSelectionFromPartialRect(e);
1643
+ if (i) return this.lastSelectionCursor = i, this.lastSelectionMode = !0, this.lastSelectionSeenAt = t, {
1644
+ cursor: i,
1645
+ cursorColor: this.lastCursorColor,
1646
+ selectionMode: !0
1647
+ };
1648
+ if (this.lastSelectionMode) {
1649
+ if (t - this.lastSelectionSeenAt > this.SELECTION_HOLD_DURATION) this.lastSelectionMode = !1, this.lastSelectionCursor = null;
1650
+ else if (this.lastSelectionCursor) return {
1651
+ cursor: this.lastSelectionCursor,
1652
+ cursorColor: this.lastCursorColor,
1653
+ selectionMode: !0
1654
+ };
1655
+ }
1656
+ return {
1657
+ cursor: this.lastCursor,
1658
+ cursorColor: this.lastCursorColor,
1659
+ selectionMode: !1
1660
+ };
1661
+ }
1662
+ updateSelectionFromPartialRect(e) {
1663
+ if (!this.lastSelectionMode || !this.lastSelectionCursor) return null;
1664
+ let t = e.size.width, n = e.size.height, r = n === 1 && t >= 5;
1665
+ if (!r && !(t === 1 && n >= 3)) return null;
1666
+ let i = this.lastSelectionCursor, a = i.x - 1, o = i.y - 1, s = i.x + i.w, c = i.y + i.h;
1667
+ if (r) {
1668
+ let n = e.pos.x, r = e.pos.x + t - 1, i = s - a + 1;
1669
+ if (Math.min(r, s) - Math.max(n, a) + 1 < Math.max(3, Math.floor(i * .6))) return null;
1670
+ let l = e.pos.y;
1671
+ Math.abs(l - o) <= Math.abs(l - c) ? o = l : c = l, r - n > s - a && (a = n, s = r);
1672
+ } else {
1673
+ let t = e.pos.y, r = e.pos.y + n - 1, i = c - o + 1;
1674
+ if (Math.min(r, c) - Math.max(t, o) + 1 < Math.max(3, Math.floor(i * .6))) return null;
1675
+ let l = e.pos.x;
1676
+ Math.abs(l - a) <= Math.abs(l - s) ? a = l : s = l, r - t > c - o && (o = t, c = r);
1677
+ }
1678
+ let l = s - a + 1, u = c - o + 1;
1679
+ return l < 3 || u < 3 ? null : {
1680
+ x: a + 1,
1681
+ y: o + 1,
1682
+ w: l - 2,
1683
+ h: u - 2
1684
+ };
1685
+ }
1686
+ recordSelectionSample(e, t) {
1687
+ let n = e.size.width, r = e.size.height;
1688
+ (r === 1 && n >= 5 || n === 1 && r >= 3) && (this.selectionRectSamples.push({
1689
+ x: e.pos.x,
1690
+ y: e.pos.y,
1691
+ w: n,
1692
+ h: r,
1693
+ ts: t,
1694
+ hasColor: e.type === 2 || e.type === 4
1695
+ }), this.selectionRectSamples = this.selectionRectSamples.filter((e) => t - e.ts <= this.SELECTION_SAMPLE_WINDOW));
1696
+ }
1697
+ detectSelectionCursor(e) {
1698
+ if (this.selectionRectSamples = this.selectionRectSamples.filter((t) => e - t.ts <= this.SELECTION_SAMPLE_WINDOW), this.selectionRectSamples.length < 4) return null;
1699
+ let t = this.selectionRectSamples.filter((e) => e.h === 1 && e.w >= 3), n = this.selectionRectSamples.filter((e) => e.w === 1 && e.h >= 3);
1700
+ if (t.length === 0 || n.length === 0) return null;
1701
+ let r = this.lastSelectionMode && this.lastSelectionCursor ? this.lastSelectionCursor : this.lastCursor, i = r.x + r.w / 2, a = r.y + r.h / 2, o = null;
1702
+ for (let e of t) for (let r of t) {
1703
+ if (r.y <= e.y || r.x !== e.x || r.w !== e.w) continue;
1704
+ let t = r.y - e.y + 1;
1705
+ if (t < 3) continue;
1706
+ let s = n.find((t) => t.x === e.x && t.y >= e.y && t.y <= e.y + 2 && t.y + t.h - 1 >= r.y - 1);
1707
+ if (!s) continue;
1708
+ let c = e.x + e.w - 1, l = n.find((t) => t.x === c && t.y >= e.y && t.y <= e.y + 2 && t.y + t.h - 1 >= r.y - 1);
1709
+ if (!l) continue;
1710
+ let u = {
1711
+ x: e.x + 1,
1712
+ y: e.y + 1,
1713
+ w: e.w - 2,
1714
+ h: t - 2
1715
+ };
1716
+ if (u.w <= 0 || u.h <= 0) continue;
1717
+ let d = Math.max(e.ts, r.ts, s.ts, l.ts), f = u.x + u.w / 2, p = u.y + u.h / 2, m = f - i, h = p - a, g = m * m + h * h;
1718
+ (!o || d > o.latestTs || d === o.latestTs && g < o.score) && (o = {
1719
+ cursor: u,
1720
+ score: g,
1721
+ latestTs: d
1722
+ });
1723
+ }
1724
+ return o?.cursor ?? null;
1725
+ }
1726
+ createNewAssembly(e) {
1727
+ let t = e?.pos.x ?? 0, n = e?.pos.y ?? 0;
1728
+ return {
1729
+ tl: {
1730
+ x: t,
1731
+ y: n,
1732
+ expectedVert: {
1733
+ x: t,
1734
+ y: n + 1
1735
+ },
1736
+ expectedTip: {
1737
+ x: t + 1,
1738
+ y: n + 1
1739
+ },
1740
+ foundVert: !1,
1741
+ foundTip: !1
1742
+ },
1743
+ tr: null,
1744
+ bl: null,
1745
+ br: null,
1746
+ startTime: Date.now(),
1747
+ state: "building"
1748
+ };
1749
+ }
1750
+ processRectAgainstAssembly(e, t) {
1751
+ this.checkCornerVerification(e, t.tl), !t.tr && e.type === 3 && e.size.width === 3 && e.size.height === 1 && e.pos.y === t.tl.y && e.pos.x > t.tl.x && (t.tr = {
1752
+ x: e.pos.x,
1753
+ y: e.pos.y,
1754
+ expectedVert: {
1755
+ x: e.pos.x + 2,
1756
+ y: e.pos.y + 1
1757
+ },
1758
+ expectedTip: {
1759
+ x: e.pos.x + 1,
1760
+ y: e.pos.y + 1
1761
+ },
1762
+ foundVert: !1,
1763
+ foundTip: !1
1764
+ }), !t.bl && e.type === 3 && e.size.width === 3 && e.size.height === 1 && e.pos.x === t.tl.x && e.pos.y > t.tl.y && (t.bl = {
1765
+ x: e.pos.x,
1766
+ y: e.pos.y,
1767
+ expectedVert: {
1768
+ x: e.pos.x,
1769
+ y: e.pos.y - 2
1770
+ },
1771
+ expectedTip: {
1772
+ x: e.pos.x + 1,
1773
+ y: e.pos.y - 1
1774
+ },
1775
+ foundVert: !1,
1776
+ foundTip: !1
1777
+ }), t.tr && t.bl && !t.br && e.type === 3 && e.size.width === 3 && e.size.height === 1 && e.pos.x === t.tr.x && e.pos.y === t.bl.y && (t.br = {
1778
+ x: e.pos.x,
1779
+ y: e.pos.y,
1780
+ expectedVert: {
1781
+ x: e.pos.x + 2,
1782
+ y: e.pos.y - 2
1783
+ },
1784
+ expectedTip: {
1785
+ x: e.pos.x + 1,
1786
+ y: e.pos.y - 1
1787
+ },
1788
+ foundVert: !1,
1789
+ foundTip: !1
1790
+ }), t.tr && this.checkCornerVerification(e, t.tr), t.bl && this.checkCornerVerification(e, t.bl), t.br && this.checkCornerVerification(e, t.br);
1791
+ }
1792
+ checkCornerVerification(e, t) {
1793
+ t.expectedVert && t.expectedTip && (!t.foundVert && e.type === 3 && e.size.width === 1 && e.size.height === 2 && e.pos.x === t.expectedVert.x && e.pos.y === t.expectedVert.y && (t.foundVert = !0), !t.foundTip && e.type === 1 && e.size.width === 1 && e.size.height === 1 && e.pos.x === t.expectedTip.x && e.pos.y === t.expectedTip.y && (t.foundTip = !0));
1794
+ }
1795
+ isAssemblyComplete(e) {
1796
+ if (!e.tr || !e.bl || !e.br) return !1;
1797
+ let t = e.tr.x - e.tl.x, n = e.bl.y - e.tl.y;
1798
+ return t <= 0 || n <= 0 || e.br.x !== e.tr.x || e.br.y !== e.bl.y ? !1 : [
1799
+ e.tl,
1800
+ e.tr,
1801
+ e.bl,
1802
+ e.br
1803
+ ].filter((e) => e.foundVert || e.foundTip).length >= 2;
1804
+ }
1805
+ buildCursorFromAssembly(e) {
1806
+ if (!e.tr || !e.bl || !e.br) return et;
1807
+ let t = e.tr.x - e.tl.x - 1, n = e.bl.y - e.tl.y - 1;
1808
+ return {
1809
+ x: e.tl.x + 1,
1810
+ y: e.tl.y + 1,
1811
+ w: t,
1812
+ h: n
1813
+ };
1814
+ }
1815
+ reset() {
1816
+ this.assemblies = [], this.selectionRectSamples = [], this.lastCursor = {
1817
+ x: 0,
1818
+ y: 0,
1819
+ w: 1,
1820
+ h: 1
1821
+ }, this.lastSelectionCursor = null, this.lastSelectionMode = !1, this.lastSelectionSeenAt = 0;
1822
+ }
1823
+ }, nt = (e) => e ? `#${[
1824
+ e.r,
1825
+ e.g,
1826
+ e.b
1827
+ ].map((e) => e.toString(16).padStart(2, "0")).join("")}` : null;
1828
+ function rt(e, t) {
1829
+ let n = new tt();
1830
+ class r {
1831
+ constructor() {
1832
+ this.rowChars = /* @__PURE__ */ new Map(), this.timer = null, this.knownViews = [], this.earlyAccepted = !1;
1833
+ }
1834
+ init() {
1835
+ this.knownViews = Array.from(Qe());
1836
+ }
1837
+ normForCompare(e) {
1838
+ return e = e.includes("live") ? "song" : e, e.toLowerCase().trim().replace(/[{}]/g, "0");
1839
+ }
1840
+ normalizeFinal(e) {
1841
+ let t = e.trim().replace(/[{}]/g, "0").replace(/\s[0-9a-fA-F]{1,2}[\^\*]?\s*$/, "").replace(/[^a-z0-9 ]/gi, "").replace(/\s+/g, " ").trim().replace(/\s+/g, "").toLowerCase().slice(0, 20);
1842
+ return t.includes("live") ? "song" : t;
1843
+ }
1844
+ pickColors() {
1845
+ let e = Array.from(this.rowChars.entries()).sort((e, t) => e[0] - t[0]);
1846
+ for (let [, t] of e) if (t.ch?.trim()) return {
1847
+ fg: t.fg,
1848
+ bg: t.bg
1849
+ };
1850
+ return {
1851
+ fg: null,
1852
+ bg: null
1853
+ };
1854
+ }
1855
+ emitStable() {
1856
+ let e = Array.from(this.rowChars.entries()).sort((e, t) => e[0] - t[0]).map(([, e]) => e.ch || " ").join(""), n = this.normalizeFinal(e), { fg: r, bg: i } = this.pickColors();
1857
+ t.set("viewTitle", e || null), t.set("titleColor", r), t.set("backgroundColor", i), t.set("viewName", n || null);
1858
+ }
1859
+ tryEarlyAccept(e) {
1860
+ if (this.earlyAccepted) return !0;
1861
+ if (!this.knownViews || this.knownViews.length === 0) return !1;
1862
+ let n = Math.max(0, Math.min(e, 39)), r = Array.from({ length: n + 1 }, (e, t) => this.rowChars.get(t)?.ch || " ").join(""), i = this.normForCompare(r);
1863
+ if (!i || i.length < 2) return !1;
1864
+ let a = this.knownViews.filter((e) => e.startsWith(i));
1865
+ if (a.length === 1) {
1866
+ let e = a[0].slice(0, 20), { fg: n, bg: r } = this.pickColors();
1867
+ return t.set("viewTitle", i), t.set("titleColor", n), t.set("backgroundColor", r), t.set("viewName", e), this.earlyAccepted = !0, !0;
1868
+ }
1869
+ return !1;
1870
+ }
1871
+ processChar(e) {
1872
+ let { cellW: n, cellH: r, offX: i, offY: a } = t.get("cellMetrics"), o = Math.floor((e.pos.x - i) / n), s = Math.floor((e.pos.y - a) / r);
1873
+ s > 4 ? this.rowChars.size > 0 && (this.timer &&= (clearTimeout(this.timer), null), this.emitStable()) : s === 3 && (o >= 30 || (this.rowChars.set(o, {
1874
+ ch: e.character,
1875
+ fg: e.foreground,
1876
+ bg: e.background
1877
+ }), this.tryEarlyAccept(o), this.timer && clearTimeout(this.timer), this.timer = setTimeout(() => {
1878
+ this.emitStable();
1879
+ }, $e)));
1880
+ }
1881
+ reset() {
1882
+ this.rowChars.clear(), this.timer &&= (clearTimeout(this.timer), null), this.earlyAccepted = !1;
1883
+ }
1884
+ }
1885
+ let i = new r();
1886
+ i.init();
1887
+ class a {
1888
+ constructor() {
1889
+ this.grid = /* @__PURE__ */ new Map();
1890
+ }
1891
+ processChar(e) {
1892
+ let { cellW: n, cellH: r, offX: i, offY: a } = t.get("cellMetrics"), o = Math.floor((e.pos.x - i) / n), s = Math.floor((e.pos.y - a) / r);
1893
+ if (this.grid.has(s) || this.grid.set(s, /* @__PURE__ */ new Map()), this.grid.get(s)?.set(o, {
1894
+ ch: e.character.replace(/[{}]/g, "0"),
1895
+ fg: e.foreground,
1896
+ bg: e.background
1897
+ }), this.grid.size > 30) {
1898
+ console.log("too much rows", this.grid.size);
1899
+ let e = Array.from(this.grid.keys()).sort((e, t) => e - t), t = e.slice(0, e.length - 30);
1900
+ for (let e of t) this.grid.delete(e);
1901
+ }
1902
+ this.updateHighlightAtCursor();
1903
+ }
1904
+ updateHighlightAtCursor() {
1905
+ let e = t.get("cursorRect"), n = t.get("cursorPos");
1906
+ if (!n || !e) {
1907
+ t.set("textUnderCursor", null), t.set("currentLine", null), t.set("highlightColor", null);
1908
+ return;
1909
+ }
1910
+ let { cellW: r, offX: i } = t.get("cellMetrics"), a = Math.round((e.x - i) / r), o = Math.floor((e.x + e.w - 1 - i) / r), s = n.y, c = this.getTextUnderCursor(a, o, s), l = this.getHighlightColorFromText(a, o, s), u = this.getCurrentLine(s);
1911
+ t.set("textUnderCursor", c), t.set("currentLine", u), l && t.set("highlightColor", l);
1912
+ }
1913
+ getTextUnderCursor(e, t, n) {
1914
+ let r = this.grid.get(n);
1915
+ if (!r) return null;
1916
+ let i = [];
1917
+ for (let n = e; n <= t; n++) {
1918
+ let e = r.get(n);
1919
+ e && i.push(e.ch);
1920
+ }
1921
+ return i.join("").trim() || null;
1922
+ }
1923
+ getHighlightColorFromText(e, t, n) {
1924
+ let r = this.grid.get(n);
1925
+ if (!r) return null;
1926
+ for (let n = e; n <= t; n++) {
1927
+ let e = r.get(n);
1928
+ if (e?.ch.trim()) return e.fg;
1929
+ }
1930
+ return null;
1931
+ }
1932
+ getCurrentLine(e) {
1933
+ let t = this.grid.get(e);
1934
+ return !t || t.size === 0 ? null : Array.from(t.entries()).sort((e, t) => e[0] - t[0]).map(([, e]) => e.ch).join("").trim() || null;
1935
+ }
1936
+ getScreenLines(e) {
1937
+ let t = [];
1938
+ for (let n = 0; n < e; n += 1) {
1939
+ let e = this.grid.get(n);
1940
+ if (!e || e.size === 0) {
1941
+ t.push("");
1942
+ continue;
1943
+ }
1944
+ let r = 0;
1945
+ for (let t of e.keys()) t > r && (r = t);
1946
+ let i = [];
1947
+ for (let t = 0; t <= r; t += 1) i.push(e.get(t)?.ch ?? " ");
1948
+ t.push(i.join("").trimEnd());
1949
+ }
1950
+ return t;
1951
+ }
1952
+ getCellColors(e, t) {
1953
+ let n = [], r = [];
1954
+ for (let i = 0; i < e; i += 1) {
1955
+ let e = this.grid.get(i), a = [], o = [];
1956
+ for (let n = 0; n < t; n += 1) {
1957
+ let t = e?.get(n);
1958
+ a.push(nt(t?.fg)), o.push(nt(t?.bg));
1959
+ }
1960
+ n.push(a), r.push(o);
1961
+ }
1962
+ return {
1963
+ fg: n,
1964
+ bg: r
1965
+ };
1966
+ }
1967
+ reset() {
1968
+ this.grid.clear();
1969
+ }
1970
+ }
1971
+ let o = new a(), s = 0;
1972
+ if (typeof window < "u") {
1973
+ let e = window;
1974
+ e.__debugRects = !1, Object.defineProperty(e, "__debugRects", {
1975
+ configurable: !0,
1976
+ set(e) {
1977
+ e && (s = Date.now() + 1e3);
1978
+ }
1979
+ });
1980
+ }
1981
+ let c = (e) => {
1982
+ if (!e) return;
1983
+ Date.now() < s && console.log(`[rect] type=${e.type} pos=(${e.pos.x},${e.pos.y}) size=${e.size.width}x${e.size.height}`);
1984
+ let { cellW: r, cellH: i, offX: a, offY: o } = t.get("cellMetrics"), { cursor: c, cursorColor: l, selectionMode: u } = n.processRect(e);
1985
+ l && nt(l) !== nt(t.get("cursorColor")) && t.set("cursorColor", l);
1986
+ let { x: d, y: f, w: p, h: m } = c, h = Math.round((d - a) / r), g = Math.round((f - o) / i), _ = t.get("cursorPos"), v = t.get("selectionMode");
1987
+ if (u) {
1988
+ let e = t.get("cursorRect");
1989
+ (!_ || _.x !== h || _.y !== g) && t.set("cursorPos", {
1990
+ x: h,
1991
+ y: g
1992
+ }), (!e || e.x !== d || e.y !== f || e.w !== p || e.h !== m) && t.set("cursorRect", {
1993
+ x: d,
1994
+ y: f,
1995
+ w: p,
1996
+ h: m
1997
+ });
1998
+ } else {
1999
+ let e = v !== u;
2000
+ (!_ || _.x !== h || _.y !== g || e) && (t.set("cursorPos", {
2001
+ x: h,
2002
+ y: g
2003
+ }), t.set("cursorRect", {
2004
+ x: d,
2005
+ y: f,
2006
+ w: p,
2007
+ h: m
2008
+ }));
2009
+ }
2010
+ v !== u && t.set("selectionMode", u);
2011
+ }, l = (e) => {
2012
+ t.set("deviceModel", e.model), t.set("fontMode", e.fontMode), t.set("cellMetrics", {
2013
+ cellW: e.spacingX,
2014
+ cellH: e.spacingY,
2015
+ offX: e.offX,
2016
+ offY: e.offY
2017
+ }), t.set("systemInfo", {
2018
+ model: e.model,
2019
+ fontMode: e.fontMode,
2020
+ spacingX: e.spacingX,
2021
+ spacingY: e.spacingY,
2022
+ offX: e.offX,
2023
+ offY: e.offY,
2024
+ screenWidth: e.screenWidth ?? 480,
2025
+ screenHeight: e.screenHeight ?? 320,
2026
+ rectOffset: e.rectOffset
2027
+ });
2028
+ }, u = (e) => {
2029
+ i.processChar(e), o.processChar(e);
2030
+ };
2031
+ return e.on("text", u), e.on("rect", c), e.on("systemInfo", l), {
2032
+ getScreenLines: () => o.getScreenLines(24),
2033
+ getScreenCellColors: () => o.getCellColors(24, 40),
2034
+ dispose: () => {
2035
+ e.off("text", u), e.off("rect", c), e.off("systemInfo", l), i.reset(), o.reset();
2036
+ }
2037
+ };
2038
+ }
2039
+ //#endregion
2040
+ //#region src/engine/host/hostState.ts
2041
+ var it = (e) => {
2042
+ let t = e.get("macroStatus");
2043
+ return {
2044
+ viewName: e.get("viewName"),
2045
+ viewTitle: e.get("viewTitle"),
2046
+ minimapKey: e.get("minimapKey"),
2047
+ cursorPos: e.get("cursorPos"),
2048
+ cursorRect: e.get("cursorRect"),
2049
+ selectionMode: e.get("selectionMode"),
2050
+ highlightColor: e.get("highlightColor"),
2051
+ titleColor: e.get("titleColor"),
2052
+ backgroundColor: e.get("backgroundColor"),
2053
+ cursorColor: e.get("cursorColor"),
2054
+ textUnderCursor: e.get("textUnderCursor"),
2055
+ currentLine: e.get("currentLine"),
2056
+ deviceModel: e.get("deviceModel"),
2057
+ fontMode: e.get("fontMode"),
2058
+ systemInfo: e.get("systemInfo"),
2059
+ macroRunning: t.running,
2060
+ macroCurrentStep: t.currentStep,
2061
+ macroSequenceLength: t.sequenceLength
2062
+ };
2063
+ }, at = (e, t, n) => {
2064
+ let r = e.get("cellMetrics");
2065
+ return {
2066
+ x: t * r.cellW + r.offX + r.cellW / 2,
2067
+ y: n * r.cellH + r.offY + r.cellH / 2
2068
+ };
2069
+ }, ot = (e) => te({
2070
+ left: e.includes("left"),
2071
+ right: e.includes("right"),
2072
+ up: e.includes("up"),
2073
+ down: e.includes("down"),
2074
+ shift: e.includes("shift"),
2075
+ play: e.includes("play"),
2076
+ opt: e.includes("opt"),
2077
+ edit: e.includes("edit")
2078
+ }), st = ({ io: e, editors: t, setValueFloat: n, browseFile: r, navigateToView: i, navigateTo: a, enableMidiTransport: o, getScreenCellColors: s }) => {
2079
+ let { debugLog: c, hasBus: l, sendKeys: u, pressAndRelease: d, store: f, getScreenLines: p } = e, m = (e, t, n) => async (...r) => l() ? n(...r) : (console.warn(`[M8SDK] ${e}: no bus connection`), t);
2080
+ return {
2081
+ navigateToView: m("navigateToView", !1, async (e) => (c("[M8SDK] Executing navigateToView:", e), await i(e), !0)),
2082
+ navigateTo: m("navigateTo", void 0, async (e, t) => {
2083
+ await a(at(f, e, t));
2084
+ }),
2085
+ setValueToHex: m("setValueToHex", !1, async (e) => (c("[M8SDK] Executing setValueToHex:", e), t.setValueToHex(e))),
2086
+ setValueToInt: m("setValueToInt", !1, async (e) => (c("[M8SDK] Executing setValueToInt:", e), t.setValueToInt(e))),
2087
+ setValueFloat: m("setValueFloat", !1, async (e) => (c("[M8SDK] Executing setValueFloat:", e), n(e))),
2088
+ setNote: m("setNote", !1, async (e) => (c("[M8SDK] Executing setNote:", e), t.setNote(e))),
2089
+ setValueToString: m("setValueToString", !1, async (e, n = !0, r = !1) => (c("[M8SDK] Executing setValueToString:", {
2090
+ targetString: e,
2091
+ exact: n,
2092
+ searchInCurrentLine: r
2093
+ }), t.setValueToString(e, n, r))),
2094
+ browseFile: m("browseFile", !1, async (e, t = !0) => (c("[M8SDK] Executing browseFile:", {
2095
+ targetText: e,
2096
+ exact: t
2097
+ }), r(e, t))),
2098
+ sendKeyDown: m("sendKeyDown", void 0, async (e) => {
2099
+ c("[M8SDK] Executing sendKeyDown:", e), u(ot(e));
2100
+ }),
2101
+ sendKeyUp: m("sendKeyUp", void 0, async () => {
2102
+ c("[M8SDK] Executing sendKeyUp"), u(0);
2103
+ }),
2104
+ sendKeyPress: m("sendKeyPress", void 0, async (e) => {
2105
+ c("[M8SDK] Executing sendKeyPress:", e), await d(ot(e));
2106
+ }),
2107
+ getState: async () => it(f),
2108
+ getScreen: async () => ({
2109
+ width: 40,
2110
+ height: 24,
2111
+ lines: p()
2112
+ }),
2113
+ getScreenCells: async () => ({
2114
+ width: 40,
2115
+ height: 24,
2116
+ lines: p(),
2117
+ ...s()
2118
+ }),
2119
+ enableMidiTransport: async () => o()
2120
+ };
2121
+ }, ct = 6, lt = (e) => {
2122
+ let t = null, n = 0, r = null, i = null, a = (e) => performance.timeOrigin + e, o = (t) => {
2123
+ let o = t.data;
2124
+ if (!o || o.length === 0) return;
2125
+ let s = a(t.timeStamp);
2126
+ switch (o[0]) {
2127
+ case 248:
2128
+ if (r != null) {
2129
+ let e = s - r;
2130
+ e > 0 && e < 200 && (i = i == null ? e : i * .9 + e * .1);
2131
+ }
2132
+ r = s, n += 1, n % ct === 0 && e({
2133
+ kind: "clock",
2134
+ ticks: n,
2135
+ at: s,
2136
+ msPerTick: i
2137
+ });
2138
+ return;
2139
+ case 250:
2140
+ e({
2141
+ kind: "start",
2142
+ ticks: n,
2143
+ at: s,
2144
+ msPerTick: i
2145
+ });
2146
+ return;
2147
+ case 251:
2148
+ e({
2149
+ kind: "continue",
2150
+ ticks: n,
2151
+ at: s,
2152
+ msPerTick: i
2153
+ });
2154
+ return;
2155
+ case 252:
2156
+ e({
2157
+ kind: "stop",
2158
+ ticks: n,
2159
+ at: s,
2160
+ msPerTick: i
2161
+ });
2162
+ return;
2163
+ case 242: {
2164
+ let t = (o[1] ?? 0) | (o[2] ?? 0) << 7;
2165
+ e({
2166
+ kind: "position",
2167
+ ticks: n,
2168
+ at: s,
2169
+ msPerTick: i,
2170
+ spp: t
2171
+ });
2172
+ return;
2173
+ }
2174
+ }
2175
+ };
2176
+ return {
2177
+ enable: async () => {
2178
+ if (t) return { ok: !0 };
2179
+ if (!("requestMIDIAccess" in navigator)) return {
2180
+ ok: !1,
2181
+ error: "Web MIDI is not available in this browser"
2182
+ };
2183
+ try {
2184
+ let e = [...(await navigator.requestMIDIAccess()).inputs.values()].find((e) => e.name === "M8");
2185
+ return e ? (await e.open(), e.addEventListener("midimessage", o), t = e, { ok: !0 }) : {
2186
+ ok: !1,
2187
+ error: "no MIDI input named M8"
2188
+ };
2189
+ } catch (e) {
2190
+ return {
2191
+ ok: !1,
2192
+ error: e instanceof Error ? e.message : String(e)
2193
+ };
2194
+ }
2195
+ },
2196
+ disable: () => {
2197
+ t?.removeEventListener("midimessage", o), t = null;
2198
+ }
2199
+ };
2200
+ }, ut = (e, t) => {
2201
+ let n = [], r = e, i = t;
2202
+ for (; r !== i;) {
2203
+ let e = i - r, t = Math.abs(e), a = e > 0 ? 1 : -1;
2204
+ if (t >= 16) {
2205
+ let e = Math.floor(t / 16), o = a > 0 ? I.Up : I.Down, s = I.Edit | o, c = Math.min(e, 10);
2206
+ for (let e = 0; e < c && (n.push(s), n.push(0), r += a * 16, r !== i); e++);
2207
+ } else if (t > 0) {
2208
+ let e = a > 0 ? I.Right : I.Left, t = I.Edit | e;
2209
+ n.push(t), n.push(0), r += a * 1;
2210
+ } else break;
2211
+ }
2212
+ return n;
2213
+ }, dt = (e, t) => {
2214
+ let n = [], r = e;
2215
+ for (; r !== t;) {
2216
+ let e = t - r, i = e > 0 ? 1 : -1;
2217
+ if (Math.abs(e) >= 12) {
2218
+ let e = i > 0 ? I.Up : I.Down;
2219
+ n.push(I.Edit | e), n.push(0), r += i * 12;
2220
+ } else {
2221
+ let e = i > 0 ? I.Right : I.Left;
2222
+ n.push(I.Edit | e), n.push(0), r += i;
2223
+ }
2224
+ if (n.length > 2048) break;
2225
+ }
2226
+ return n;
2227
+ }, ft = (e) => {
2228
+ let { store: t, debugLog: n, hasBus: r, sendKeys: i, pressAndRelease: a, waitForTextUnderCursorChange: o } = e;
2229
+ return {
2230
+ setValueToHex: async (e) => {
2231
+ if (!r()) return !1;
2232
+ e = Math.max(0, Math.min(255, e));
2233
+ let s = t.get("textUnderCursor"), c = Ie(s), l = s?.trim() === "--";
2234
+ if (c === null) return console.warn("[M8SDK] Could not parse current value under cursor:", s), !1;
2235
+ if (c === e && !l) return n("[M8SDK] Already at target value:", e.toString(16).padStart(2, "0").toUpperCase()), !0;
2236
+ n(`[M8SDK] Setting value from "${s?.trim() ?? "N/A"}" (${c.toString(16).padStart(2, "0").toUpperCase()}) to ${e.toString(16).padStart(2, "0").toUpperCase()}`);
2237
+ let u = c;
2238
+ if (l) {
2239
+ n("[M8SDK] Initial value is \"--\", pressing edit to recall last value");
2240
+ let e = s;
2241
+ await a(I.Edit), await o(e, 250);
2242
+ let r = t.get("textUnderCursor"), i = Ie(r);
2243
+ if (n(`[M8SDK] After edit press, value is now: "${r?.trim() ?? "N/A"}" (${i?.toString(16).padStart(2, "0").toUpperCase() ?? "N/A"})`), i === null) return console.warn("[M8SDK] Failed to read value after edit press on \"--\""), await a(I.Edit), !1;
2244
+ u = i;
2245
+ } else {
2246
+ let e = s;
2247
+ await a(I.Edit), await o(e, 250);
2248
+ }
2249
+ let d = ut(u, e);
2250
+ n(`[M8SDK] Precalculated ${d.length / 2} key presses from ${u.toString(16).padStart(2, "0").toUpperCase()} to ${e.toString(16).padStart(2, "0").toUpperCase()}`);
2251
+ for (let e of d) i(e), await V(30);
2252
+ await o(s, 250);
2253
+ let f = t.get("textUnderCursor"), p = Ie(f);
2254
+ if (p !== e) {
2255
+ n("[M8SDK] Precomputation missed target, falling back to iterative mode");
2256
+ let r = p ?? u, i = Date.now();
2257
+ for (; r !== e && Date.now() - i < 5e3;) {
2258
+ let i = e - r, s = Math.abs(i), c = i > 0 ? 1 : -1, l = t.get("textUnderCursor");
2259
+ if (s >= 16) {
2260
+ let e = c > 0 ? I.Up : I.Down, t = I.Edit | e;
2261
+ await a(t);
2262
+ } else if (s > 0) {
2263
+ let e = c > 0 ? I.Right : I.Left, t = I.Edit | e;
2264
+ await a(t);
2265
+ }
2266
+ await o(l, 250);
2267
+ let u = Ie(t.get("textUnderCursor"));
2268
+ u !== null && (r = u, n(`[M8SDK] Iterative: current value: ${r.toString(16).padStart(2, "0").toUpperCase()}`));
2269
+ }
2270
+ p = Ie(t.get("textUnderCursor"));
2271
+ }
2272
+ await a(I.Edit);
2273
+ let m = p === e;
2274
+ return n(`[M8SDK] Value setting ${m ? "succeeded" : "failed"}. Final value: "${f?.trim() ?? "N/A"}" (${p?.toString(16).padStart(2, "0").toUpperCase() ?? "N/A"})`), m;
2275
+ },
2276
+ setValueToInt: async (e) => {
2277
+ if (!r()) return !1;
2278
+ e = Math.floor(e);
2279
+ let n = t.get("textUnderCursor"), i = Le(n);
2280
+ if (i === null) return console.warn("[M8SDK] Could not parse current integer value under cursor:", n), !1;
2281
+ if (i === e) return !0;
2282
+ await a(I.Edit), await o(n, 250);
2283
+ let s = i, c = i, l = Math.abs(i - e), u = null, d = Date.now();
2284
+ for (; s !== e && Date.now() - d < 5e3;) {
2285
+ let n = e - s, r = Math.abs(n), i = n > 0 ? 1 : -1, d = t.get("textUnderCursor"), f = s;
2286
+ if (r >= 16) {
2287
+ let e = i > 0 ? I.Up : I.Down;
2288
+ await a(I.Edit | e, 35);
2289
+ } else {
2290
+ let e = i > 0 ? I.Right : I.Left;
2291
+ await a(I.Edit | e, 35);
2292
+ }
2293
+ await o(d, 250);
2294
+ let p = Le(t.get("textUnderCursor"));
2295
+ if (p === null || p === s) break;
2296
+ let m = Math.abs(p - e);
2297
+ m < l && (l = m, c = p);
2298
+ let h = u !== null && p === u, g = (f - e) * (p - e) < 0;
2299
+ if (s = p, h && g) break;
2300
+ u = f;
2301
+ }
2302
+ if (s !== c) {
2303
+ let e = Date.now();
2304
+ for (; s !== c && Date.now() - e < 1500;) {
2305
+ let e = c - s, n = Math.abs(e), r = e > 0 ? 1 : -1, i = t.get("textUnderCursor");
2306
+ if (n >= 16) {
2307
+ let e = r > 0 ? I.Up : I.Down;
2308
+ await a(I.Edit | e, 35);
2309
+ } else {
2310
+ let e = r > 0 ? I.Right : I.Left;
2311
+ await a(I.Edit | e, 35);
2312
+ }
2313
+ await o(i, 250);
2314
+ let l = Le(t.get("textUnderCursor"));
2315
+ if (l === null || l === s) break;
2316
+ s = l;
2317
+ }
2318
+ }
2319
+ return await a(I.Edit), Le(t.get("textUnderCursor")) === e;
2320
+ },
2321
+ setNote: async (e) => {
2322
+ if (!r()) return !1;
2323
+ let s = e.trim().toUpperCase();
2324
+ if (s === "---" || s === "OFF") {
2325
+ let e = t.get("textUnderCursor"), r = e?.trim().toUpperCase() ?? "";
2326
+ if (r === s) return !0;
2327
+ if (await a(I.Opt | I.Edit), await o(e, 250), s === "OFF" && r !== "---") {
2328
+ let e = t.get("textUnderCursor");
2329
+ e?.trim().toUpperCase() === "---" && (await a(I.Opt | I.Edit), await o(e, 250));
2330
+ }
2331
+ let i = t.get("textUnderCursor")?.trim().toUpperCase();
2332
+ return n("[M8SDK] setNote special value result:", i), i === s;
2333
+ }
2334
+ let c = W(e);
2335
+ if (!c) return console.warn("[M8SDK] Invalid note format. Expected like C-1, C#1, D#A, ---, OFF:", e), !1;
2336
+ let l = t.get("textUnderCursor");
2337
+ (l?.trim() === "---" || l?.trim().toUpperCase() === "OFF") && (n("[M8SDK] Initial note is \"---\" or \"OFF\", priming with edit key"), await a(I.Edit), await o(l, 250), l = t.get("textUnderCursor"));
2338
+ let u = W(l);
2339
+ if (!u) return console.warn("[M8SDK] Could not parse current note under cursor:", l), !1;
2340
+ if (u.semitoneIndex === c.semitoneIndex) return !0;
2341
+ await a(I.Edit), await o(l, 250);
2342
+ let d = dt(u.semitoneIndex, c.semitoneIndex);
2343
+ if (d.length > 0) {
2344
+ for (let e of d) i(e), await V(25);
2345
+ await o(l, 280);
2346
+ let e = W(t.get("textUnderCursor"));
2347
+ if (e?.semitoneIndex === c.semitoneIndex) return await a(I.Edit), !0;
2348
+ u = e ?? u;
2349
+ }
2350
+ let f = /* @__PURE__ */ new Set();
2351
+ f.add(u.label);
2352
+ let p = Date.now();
2353
+ for (; Date.now() - p < 7e3;) {
2354
+ let e = c.semitoneIndex - u.semitoneIndex;
2355
+ if (e === 0) break;
2356
+ let n = Math.abs(e) >= 12, r = e > 0, i = n ? r ? I.Up : I.Down : r ? I.Right : I.Left, s = n ? r ? I.Down : I.Up : r ? I.Left : I.Right, l = u, d = Math.abs(l.semitoneIndex - c.semitoneIndex), p = t.get("textUnderCursor");
2357
+ await a(I.Edit | i, 35), await o(p, 250);
2358
+ let m = W(t.get("textUnderCursor"));
2359
+ if (!m || m.label === l.label) break;
2360
+ if (u = m, Math.abs(u.semitoneIndex - c.semitoneIndex) > d) {
2361
+ let e = t.get("textUnderCursor");
2362
+ await a(I.Edit | s, 35), await o(e, 250);
2363
+ let n = W(t.get("textUnderCursor"));
2364
+ n && (u = n);
2365
+ break;
2366
+ }
2367
+ if (f.has(u.label)) break;
2368
+ f.add(u.label);
2369
+ }
2370
+ return await a(I.Edit), W(t.get("textUnderCursor"))?.semitoneIndex === c.semitoneIndex;
2371
+ },
2372
+ setValueToString: async (e, i = !0, s = !1) => {
2373
+ if (!r()) return !1;
2374
+ let c = z(e);
2375
+ if (!c) return !1;
2376
+ let l = () => s ? t.get("currentLine") : t.get("textUnderCursor"), u = (e) => {
2377
+ let t = z(e);
2378
+ return t ? i ? t === c : t.includes(c) : !1;
2379
+ };
2380
+ if (u(l())) return !0;
2381
+ let d = t.get("textUnderCursor");
2382
+ d?.trim() === "---" && (n("[M8SDK] Initial string value is \"---\", priming with edit key"), await a(I.Edit), await o(d, 250));
2383
+ let f = t.get("textUnderCursor");
2384
+ if (await a(I.Edit), await o(f, 250), u(l())) return await a(I.Edit), !0;
2385
+ let p = t.get("textUnderCursor"), m = 0, h = Date.now(), g = [];
2386
+ for (let e = 0; e < 512; e++) {
2387
+ if (Date.now() - h > 2e3) {
2388
+ n("[M8SDK] Timeout reached while seeking bottom of list");
2389
+ break;
2390
+ }
2391
+ let t = z(p);
2392
+ if (t) {
2393
+ if (e < 4) g.push(t);
2394
+ else if (g.includes(t)) {
2395
+ n("[M8SDK] Circular list detected while seeking bottom, treating current position as start");
2396
+ break;
2397
+ }
2398
+ }
2399
+ let r = p;
2400
+ await a(I.Edit | I.Down, 35);
2401
+ let i = await o(r, 250);
2402
+ if (z(i) === z(p) ? m += 1 : (m = 0, p = i), m > 1) break;
2403
+ }
2404
+ let _ = /* @__PURE__ */ new Set();
2405
+ for (let e = 0; e < 1024; e++) {
2406
+ let e = l();
2407
+ if (u(e)) return await a(I.Edit), !0;
2408
+ let n = z(e);
2409
+ if (n) {
2410
+ if (_.has(n)) break;
2411
+ _.add(n);
2412
+ }
2413
+ let r = t.get("textUnderCursor");
2414
+ if (await a(I.Edit | I.Right, 35), z(await o(r, 250)) === n) break;
2415
+ }
2416
+ return await a(I.Edit), !1;
2417
+ }
2418
+ };
2419
+ }, pt = ({ bus: e, store: t, cancelOnKeydown: n = !1 }) => {
2420
+ let r = [], i = null, a = !1, o = () => {
2421
+ a && u("preempted by keyboard");
2422
+ }, s = () => {
2423
+ a || (a = !0, e.protocol.eventBus.on("key", l), n && typeof window < "u" && window.addEventListener("keydown", o));
2424
+ }, c = () => {
2425
+ a && (a = !1, e.protocol.eventBus.off("key", l), n && typeof window < "u" && window.removeEventListener("keydown", o));
2426
+ };
2427
+ function l(n) {
2428
+ if (!a) return;
2429
+ let o = n.keys;
2430
+ if (i !== null && o !== i) {
2431
+ u("external key event");
2432
+ return;
2433
+ }
2434
+ let s = r.shift();
2435
+ if (s !== void 0) {
2436
+ i = s, e.commands.sendKeys(s);
2437
+ let n = (t.get("macroStatus").currentStep ?? 0) + 1;
2438
+ t.set("macroStatus", {
2439
+ running: !0,
2440
+ currentStep: n,
2441
+ sequenceLength: r.length + n
2442
+ });
2443
+ } else c(), i = null, t.set("macroStatus", { running: !1 });
2444
+ }
2445
+ function u(e) {
2446
+ (a || r.length !== 0 || t.get("macroStatus").running) && (r = [], i = null, c(), t.set("macroStatus", { running: !1 }));
2447
+ }
2448
+ return {
2449
+ start: (n) => {
2450
+ if (r = Array.isArray(n) ? n.slice() : [], r.length === 0 || (t.set("macroStatus", {
2451
+ running: !0,
2452
+ currentStep: 0,
2453
+ sequenceLength: r.length
2454
+ }), a)) return;
2455
+ s();
2456
+ let o = r.shift();
2457
+ i = o, e.commands.sendKeys(o);
2458
+ },
2459
+ cancel: u,
2460
+ get running() {
2461
+ return a;
2462
+ },
2463
+ dispose: () => {
2464
+ r = [], i = null, c();
2465
+ }
2466
+ };
2467
+ }, mt = () => ({
2468
+ viewName: null,
2469
+ viewTitle: null,
2470
+ minimapKey: null,
2471
+ cursorPos: null,
2472
+ cursorRect: null,
2473
+ selectionMode: !1,
2474
+ highlightColor: null,
2475
+ cursorColor: null,
2476
+ textUnderCursor: null,
2477
+ currentLine: null,
2478
+ titleColor: null,
2479
+ backgroundColor: null,
2480
+ deviceModel: null,
2481
+ fontMode: null,
2482
+ cellMetrics: {
2483
+ cellW: 12,
2484
+ cellH: 14,
2485
+ offX: 0,
2486
+ offY: 0
2487
+ },
2488
+ systemInfo: null,
2489
+ macroStatus: { running: !1 }
2490
+ }), ht = (e = {}) => {
2491
+ let t = {
2492
+ ...mt(),
2493
+ ...e
2494
+ }, n = /* @__PURE__ */ new Map(), r = /* @__PURE__ */ new Set();
2495
+ return {
2496
+ get: (e) => t[e],
2497
+ set: (e, i) => {
2498
+ if (!Object.is(t[e], i)) {
2499
+ t[e] = i;
2500
+ for (let t of [...n.get(e) ?? []]) t();
2501
+ for (let t of [...r]) t(e);
2502
+ }
2503
+ },
2504
+ sub: (e, t) => {
2505
+ let r = n.get(e);
2506
+ return r || (r = /* @__PURE__ */ new Set(), n.set(e, r)), r.add(t), () => {
2507
+ r.delete(t);
2508
+ };
2509
+ },
2510
+ subAll: (e) => (r.add(e), () => {
2511
+ r.delete(e);
2512
+ }),
2513
+ snapshot: () => ({ ...t })
2514
+ };
2515
+ }, gt = () => 0, _t = () => 1;
2516
+ function vt(e, t, n, r = gt, i = _t) {
2517
+ let a = t.trim(), o = n.trim();
2518
+ if (!e.has(a) || !e.has(o)) return null;
2519
+ let s = /* @__PURE__ */ new Set([a]), c = /* @__PURE__ */ new Map(), l = /* @__PURE__ */ new Map(), u = /* @__PURE__ */ new Map();
2520
+ for (let t of e.keys()) l.set(t, Infinity), u.set(t, Infinity);
2521
+ l.set(a, 0), u.set(a, r(a, o));
2522
+ function d() {
2523
+ let e = null, t = Infinity;
2524
+ for (let n of s) {
2525
+ let r = u.get(n) ?? Infinity;
2526
+ r < t && (t = r, e = n);
2527
+ }
2528
+ return e;
2529
+ }
2530
+ for (; s.size;) {
2531
+ let t = d();
2532
+ if (!t) break;
2533
+ if (t === o) {
2534
+ let e = [o], t = [], n = o;
2535
+ for (; n !== a;) {
2536
+ let r = c.get(n);
2537
+ if (!r) break;
2538
+ t.unshift(r.viaDir), e.unshift(r.prev), n = r.prev;
2539
+ }
2540
+ return {
2541
+ pages: e,
2542
+ directions: t,
2543
+ cost: t.length
2544
+ };
2545
+ }
2546
+ s.delete(t);
2547
+ let n = e.get(t) ?? [];
2548
+ for (let e of n) {
2549
+ let n = e.weight ?? i(t, e.to, e.dir), a = (l.get(t) ?? Infinity) + n;
2550
+ a < (l.get(e.to) ?? Infinity) && (c.set(e.to, {
2551
+ prev: t,
2552
+ viaDir: e.dir
2553
+ }), l.set(e.to, a), u.set(e.to, a + r(e.to, o)), s.has(e.to) || s.add(e.to));
2554
+ }
2555
+ }
2556
+ return null;
2557
+ }
2558
+ //#endregion
2559
+ //#region src/engine/viewNavigation.ts
2560
+ var yt = 20, bt = (e, t) => {
2561
+ let n = !!t?.shift, r = I.Shift, i = {
2562
+ up: (n ? r : 0) | I.Up,
2563
+ down: (n ? r : 0) | I.Down,
2564
+ left: (n ? r : 0) | I.Left,
2565
+ right: (n ? r : 0) | I.Right
2566
+ }, a = [];
2567
+ n && a.push(r);
2568
+ for (let t of e) a.push(i[t], n ? r : 0);
2569
+ return a.push(0), a;
2570
+ }, xt = ({ store: e, runner: t }) => {
2571
+ let n = Qe(), r = null, i = 0, a = null, o = (e) => {
2572
+ let t = (e || "").toLowerCase();
2573
+ if (n.has(t)) return t;
2574
+ for (let e of n) if (e.toLowerCase() === t) return e;
2575
+ return console.warn("Target not in viewlist", { goal: t }), t;
2576
+ }, s = (e) => {
2577
+ let t = (e || "").toLowerCase(), r = "";
2578
+ for (let e of n) t.startsWith(e) && e.length > r.length && (r = e);
2579
+ return r;
2580
+ }, c = (t) => {
2581
+ let { graph: n } = Ze(), r = e.get("viewName") || "", i = [], a = [];
2582
+ for (let e of n.keys()) {
2583
+ let n = s(e);
2584
+ n && (n === r && i.push(e), n === t && a.push(e));
2585
+ }
2586
+ if (!a.length) return null;
2587
+ if (!i.length) return {
2588
+ pages: ["unknown", "fallback"],
2589
+ directions: ["up"],
2590
+ cost: 1
2591
+ };
2592
+ let o = null;
2593
+ for (let e of i) for (let t of a) {
2594
+ let r = vt(n, e, t);
2595
+ r && (!o || r.cost < o.cost) && (o = r);
2596
+ }
2597
+ return o;
2598
+ }, l = (e, t, n) => {
2599
+ let r = Ze().edgeKeys.get(e.toLowerCase())?.get(t);
2600
+ return r?.length ? r[r.length - 1] === 0 ? r.slice() : [...r, 0] : bt([n], { shift: !0 });
2601
+ }, u = () => {
2602
+ if (r = null, i = 0, a) {
2603
+ let e = a;
2604
+ a = null, e();
2605
+ }
2606
+ }, d = () => {
2607
+ let n = r, a = e.get("viewName") || "";
2608
+ if (!n || !a) {
2609
+ u();
2610
+ return;
2611
+ }
2612
+ if (a === n) {
2613
+ console.log("Navigation complete:", {
2614
+ goal: n,
2615
+ steps: i
2616
+ }), u();
2617
+ return;
2618
+ }
2619
+ if (i >= yt) {
2620
+ console.warn("Navigation aborted: max steps reached", {
2621
+ startTitle: a,
2622
+ goalTitle: n,
2623
+ steps: i
2624
+ }), u();
2625
+ return;
2626
+ }
2627
+ let o = c(n);
2628
+ if (!o) console.warn("No path found (iterative)", {
2629
+ startTitle: a,
2630
+ goalTitle: n,
2631
+ step: i
2632
+ }), u();
2633
+ else if (o.pages.length > 1) {
2634
+ let e = o.pages[0], r = o.pages[1], c = o.directions[0], u = l(e, r, c);
2635
+ i += 1, console.log("Navigation step", {
2636
+ step: i,
2637
+ from: a,
2638
+ to: s(r),
2639
+ dir: c,
2640
+ goal: n,
2641
+ frames: u
2642
+ }), t.cancel("iterative navigation step"), t.start(u);
2643
+ }
2644
+ }, f = () => {
2645
+ r && e.get("viewName") && !e.get("macroStatus").running && d();
2646
+ }, p = e.sub("viewName", f), m = e.sub("macroStatus", f);
2647
+ return {
2648
+ navigateToView: (t) => new Promise((n) => {
2649
+ let s = o(t);
2650
+ s ? (a?.(), a = n, r = s, i = 0, console.log("Starting iterative navigation", {
2651
+ goal: s,
2652
+ from: e.get("viewName") || "unknown"
2653
+ }), d()) : n();
2654
+ }),
2655
+ dispose: () => {
2656
+ p(), m(), u();
2657
+ }
2658
+ };
2659
+ }, St = /* @__PURE__ */ new Set([
2660
+ "macroStatus",
2661
+ "deviceModel",
2662
+ "fontMode",
2663
+ "systemInfo",
2664
+ "titleColor",
2665
+ "backgroundColor",
2666
+ "minimapKey"
2667
+ ]), Ct = (e, t = {}) => {
2668
+ let n = t.store ?? ht(), r = (...e) => {
2669
+ t.debug && console.log(...e);
2670
+ }, i = /* @__PURE__ */ new Map(), a = (e, t) => {
2671
+ for (let n of [...i.get(e) ?? []]) n(t);
2672
+ }, o = rt(e.protocol.eventBus, n), s = pt({
2673
+ bus: e,
2674
+ store: n,
2675
+ cancelOnKeydown: t.cancelMacroOnKeydown
2676
+ }), c = pe({
2677
+ bus: e,
2678
+ store: n
2679
+ }), l = xt({
2680
+ store: n,
2681
+ runner: s
2682
+ }), u = lt((e) => a("transport", e)), d = Oe({
2683
+ getKeySink: () => e.commands,
2684
+ store: n,
2685
+ debugLog: r,
2686
+ getScreenLines: o.getScreenLines
2687
+ }), f = st({
2688
+ io: d,
2689
+ editors: ft(d),
2690
+ setValueFloat: Ge(d),
2691
+ browseFile: Fe(d),
2692
+ navigateToView: (e) => l.navigateToView(e),
2693
+ navigateTo: (e) => c.navigateTo(e),
2694
+ enableMidiTransport: () => u.enable(),
2695
+ getScreenCellColors: o.getScreenCellColors
2696
+ }), p = /* @__PURE__ */ new Set(), m = !1, h = null, g = null, _ = null, v = () => {
2697
+ m = !1;
2698
+ let e = new Set(p);
2699
+ if (p.clear(), e.has("viewName") || e.has("viewTitle")) {
2700
+ let e = {
2701
+ viewName: n.get("viewName"),
2702
+ viewTitle: n.get("viewTitle")
2703
+ };
2704
+ (!h || h.viewName !== e.viewName || h.viewTitle !== e.viewTitle) && (h = e, r("[M8SDK] View changed:", e.viewName, e.viewTitle), a("viewChanged", e));
2705
+ }
2706
+ if (e.has("cursorPos") || e.has("cursorRect") || e.has("selectionMode")) {
2707
+ let e = {
2708
+ pos: n.get("cursorPos"),
2709
+ rect: n.get("cursorRect"),
2710
+ selectionMode: n.get("selectionMode")
2711
+ }, t = g;
2712
+ t && t.pos?.x === e.pos?.x && t.pos?.y === e.pos?.y && t.rect?.x === e.rect?.x && t.rect?.y === e.rect?.y && t.rect?.w === e.rect?.w && t.rect?.h === e.rect?.h && t.selectionMode === e.selectionMode || (g = e, r("[M8SDK] Cursor moved:", e.pos, e.rect, "selection:", e.selectionMode), a("cursorMoved", e));
2713
+ }
2714
+ if (e.has("textUnderCursor") || e.has("currentLine")) {
2715
+ let e = {
2716
+ textUnderCursor: n.get("textUnderCursor"),
2717
+ currentLine: n.get("currentLine")
2718
+ };
2719
+ (!_ || _.textUnderCursor !== e.textUnderCursor || _.currentLine !== e.currentLine) && (_ = e, r("[M8SDK] Text updated:", e.textUnderCursor, e.currentLine), a("textUpdated", e));
2720
+ }
2721
+ [...e].some((e) => St.has(e)) && a("stateChanged", it(n));
2722
+ }, y = n.subAll((e) => {
2723
+ p.add(e), m || (m = !0, queueMicrotask(v));
2724
+ }), b = (e) => {
2725
+ r("[M8SDK] Key event:", e.keys), a("keyPressed", { keys: e.keys });
2726
+ };
2727
+ return e.protocol.eventBus.on("key", b), {
2728
+ bus: e,
2729
+ store: n,
2730
+ methods: f,
2731
+ macro: s,
2732
+ navigateTo: (e) => c.navigateTo(e),
2733
+ navigateToView: (e) => l.navigateToView(e),
2734
+ getState: () => it(n),
2735
+ getScreenLines: o.getScreenLines,
2736
+ getScreenCellColors: o.getScreenCellColors,
2737
+ on: (e, t) => {
2738
+ let n = i.get(e);
2739
+ return n || (n = /* @__PURE__ */ new Set(), i.set(e, n)), n.add(t), () => {
2740
+ n.delete(t);
2741
+ };
2742
+ },
2743
+ dispose: () => {
2744
+ e.protocol.eventBus.off("key", b), y(), l.dispose(), c.dispose(), s.dispose(), u.disable(), o.dispose(), i.clear();
2745
+ }
2746
+ };
2747
+ }, G = {
3
2748
  version: "1.0",
4
2749
  description: "Semantic mapping of M8 tracker views: defines the structure of each grid view so cursor position + line text can be interpreted as typed field values.",
5
2750
  notes: {
@@ -27,7 +2772,7 @@ var r = {
27
2772
  eqSlot: "EQ slot assignment (hex). '--' = no EQ applied to this instrument.",
28
2773
  rowIndex: "The positional index of this row in the current view (song row, chain position, phrase step, etc.).",
29
2774
  noteInterval: "Scale row label: one of the 12 note intervals C, C#, D, D#, E, F, F#, G, G#, A, A#, B (sharps use '#', naturals may render a dim '-' pad, e.g. 'C-').",
30
- onOff: "Toggle field displayed as 'ON' or 'OFF' ('--' = unset). Used by the scale view 'EN' column.",
2775
+ onOff: "Toggle field displayed as 'ON' or 'OFF'; the scale view 'EN' column shows '--' for a note out of the scale. Used by the scale view 'EN' column.",
31
2776
  semitoneOffset: "Signed semitone offset in decimal notation with two decimals (-24.00 to +24.00), e.g. '00.00', '-00.50', '12.00'. Used by the scale view 'OFFSET' column.",
32
2777
  swing: "Groove swing amount as a percentage with one decimal, e.g. '50.0%' = straight timing, higher = swung. Shown on every second groove row (0, 2, 4, …): the swing of that pair of steps (ticks 07,05 → 58.3%).",
33
2778
  instrumentType: "Instrument engine chosen with the TYPE field of the Instrument view: WAVSYNTH, MACROSYN, SAMPLER, FMSYNTH, HYPERSYNTH, EXTERNAL INST, MIDI OUT (NONE for an unused slot). Text value; changes which parameters the view shows.",
@@ -37,7 +2782,7 @@ var r = {
37
2782
  action: "Button-like text that does something when [EDIT] is pressed on it (LOAD, SAVE, RENDER, SETTINGS, VIEW INST. POOL, EQ, …). The text is the caption.",
38
2783
  fileEntry: "Row of a file browser: '/name' is a directory, '/..' the parent directory, anything else a file (e.g. 'Bass.m8i')."
39
2784
  },
40
- views: /* @__PURE__ */ JSON.parse("{\"song\":{\"title\":\"Song View\",\"type\":\"grid\",\"description\":\"Arranges chains across 8 independent tracks to form the song structure. Each row is a song position (up to 256 rows); each column is a track. Each track advances vertically until it reaches an empty column ('--'), then loops back to row 00. Chains containing no notes are grayed out; chains '00' or 'FE' are commonly used as silent spacers. On row '00', [UP][UP] enters track reordering mode.\",\"rowField\":{\"x\":0,\"width\":2,\"parse\":\"hex\",\"type\":\"rowIndex\",\"key\":\"songRow\",\"description\":\"Song row 00-FF. Each track loops back to row 00 when it reaches '--'.\"},\"columns\":[{\"x\":3,\"width\":2,\"key\":\"track1\",\"type\":\"chainRef\",\"label\":\"Track 1\",\"meta\":{\"trackIndex\":1}},{\"x\":6,\"width\":2,\"key\":\"track2\",\"type\":\"chainRef\",\"label\":\"Track 2\",\"meta\":{\"trackIndex\":2}},{\"x\":9,\"width\":2,\"key\":\"track3\",\"type\":\"chainRef\",\"label\":\"Track 3\",\"meta\":{\"trackIndex\":3}},{\"x\":12,\"width\":2,\"key\":\"track4\",\"type\":\"chainRef\",\"label\":\"Track 4\",\"meta\":{\"trackIndex\":4}},{\"x\":15,\"width\":2,\"key\":\"track5\",\"type\":\"chainRef\",\"label\":\"Track 5\",\"meta\":{\"trackIndex\":5}},{\"x\":18,\"width\":2,\"key\":\"track6\",\"type\":\"chainRef\",\"label\":\"Track 6\",\"meta\":{\"trackIndex\":6}},{\"x\":21,\"width\":2,\"key\":\"track7\",\"type\":\"chainRef\",\"label\":\"Track 7\",\"meta\":{\"trackIndex\":7}},{\"x\":24,\"width\":2,\"key\":\"track8\",\"type\":\"chainRef\",\"label\":\"Track 8\",\"meta\":{\"trackIndex\":8}}]},\"chain\":{\"title\":\"Chain View\",\"type\":\"grid\",\"description\":\"An ordered list of up to 16 phrases (256 steps). The first '--' phrase ends the chain and the song continues on to the next chain in the song view. The 'TSP' column optionally transposes every note in the phrase in semitones (relative hex).\",\"rowField\":{\"x\":0,\"width\":1,\"parse\":\"hex\",\"type\":\"rowIndex\",\"key\":\"chainPos\",\"description\":\"Position within the chain (0-F, max 16 entries).\"},\"columns\":[{\"x\":2,\"width\":2,\"key\":\"phrase\",\"type\":\"phraseRef\",\"label\":\"Phrase (PH)\",\"description\":\"Phrase number to play at this chain position.\"},{\"x\":5,\"width\":2,\"key\":\"transpose\",\"type\":\"transpose\",\"label\":\"Transpose (TSP)\",\"description\":\"Optional note transpose in semitones applied to every note in the phrase (relative hex).\"}]},\"phrase\":{\"title\":\"Phrase View\",\"type\":\"grid\",\"description\":\"A 16-step sequence. Each step holds a note, velocity, instrument assignment, and up to 3 FX command+value pairs. Notes cover 11 octaves (the full 128 MIDI note range); velocity defaults to 64 (hex); an empty instrument column plays the note without retriggering the instrument. A '*' next to the phrase number indicates the phrase is used elsewhere in the chain or song.\",\"rowField\":{\"x\":0,\"width\":1,\"parse\":\"hex\",\"type\":\"rowIndex\",\"key\":\"step\",\"description\":\"Step index 0-F (16th note by default; altered by groove).\"},\"columns\":[{\"x\":2,\"width\":3,\"key\":\"note\",\"type\":\"note\",\"label\":\"Note (N)\"},{\"x\":6,\"width\":2,\"key\":\"vel\",\"type\":\"velocity\",\"label\":\"Velocity (V)\"},{\"x\":9,\"width\":2,\"key\":\"inst\",\"type\":\"instrumentRef\",\"label\":\"Instrument (I)\"},{\"x\":12,\"width\":3,\"key\":\"fx1cmd\",\"type\":\"fxCommand\",\"label\":\"FX1 Command\"},{\"x\":15,\"width\":2,\"key\":\"fx1val\",\"type\":\"fxValue\",\"label\":\"FX1 Value\"},{\"x\":18,\"width\":3,\"key\":\"fx2cmd\",\"type\":\"fxCommand\",\"label\":\"FX2 Command\"},{\"x\":21,\"width\":2,\"key\":\"fx2val\",\"type\":\"fxValue\",\"label\":\"FX2 Value\"},{\"x\":24,\"width\":3,\"key\":\"fx3cmd\",\"type\":\"fxCommand\",\"label\":\"FX3 Command\"},{\"x\":27,\"width\":2,\"key\":\"fx3val\",\"type\":\"fxValue\",\"label\":\"FX3 Value\"}]},\"table\":{\"title\":\"Table View\",\"type\":\"grid\",\"description\":\"A 16-step mini-sequencer that runs alongside an instrument. Used for arpeggios, multi-stage envelopes, and automated FX. The 'N' column transposes the instrument for the step (relative hex); 'V' multiplies with the phrase-row velocity. Each instrument has a dedicated table plus 128 assignable tables (TBL command). FX columns can run at independent speeds via TIC; a TIC on the last table row affects all rows. HOP shortens or loops the table.\",\"rowField\":{\"x\":0,\"width\":1,\"parse\":\"hex\",\"type\":\"rowIndex\",\"key\":\"step\",\"description\":\"Table step 0-F. Loops from bottom unless a HOP command redirects.\"},\"columns\":[{\"x\":2,\"width\":2,\"key\":\"transpose\",\"type\":\"transpose\",\"label\":\"Transpose (N)\",\"description\":\"Transposes the instrument for this step (relative hex). '--' = no transpose.\"},{\"x\":5,\"width\":2,\"key\":\"volume\",\"type\":\"volume\",\"label\":\"Volume (V)\",\"description\":\"Volume multiplier applied on top of the phrase velocity (hex). '--' = no override.\"},{\"x\":8,\"width\":3,\"key\":\"fx1cmd\",\"type\":\"fxCommand\",\"label\":\"FX1 Command\",\"description\":\"3-char command name for table FX slot 1.\"},{\"x\":11,\"width\":2,\"key\":\"fx1val\",\"type\":\"fxValue\",\"label\":\"FX1 Value\",\"description\":\"Value for table FX1.\"},{\"x\":14,\"width\":3,\"key\":\"fx2cmd\",\"type\":\"fxCommand\",\"label\":\"FX2 Command\",\"description\":\"3-char command name for table FX slot 2.\"},{\"x\":17,\"width\":2,\"key\":\"fx2val\",\"type\":\"fxValue\",\"label\":\"FX2 Value\",\"description\":\"Value for table FX2.\"},{\"x\":20,\"width\":3,\"key\":\"fx3cmd\",\"type\":\"fxCommand\",\"label\":\"FX3 Command\",\"description\":\"3-char command name for table FX slot 3.\"},{\"x\":23,\"width\":2,\"key\":\"fx3val\",\"type\":\"fxValue\",\"label\":\"FX3 Value\",\"description\":\"Value for table FX3.\"}]},\"groove\":{\"title\":\"Groove View\",\"type\":\"grid\",\"description\":\"Defines the timing of each phrase step in ticks. Used to create swing, shuffle, triplets, and other rhythmic feels. At the default 24 PPQ a step is 6 ticks and a full phrase totals 96 ticks. The groove loops when a '--' entry is reached; a '00' entry skips the phrase step. Row 0 also holds the PPQ resolution (24/48/96/192) and the SWING percentage; editing the row 0 tick value alters rows 0 and 1 together (a common swing setting is 07,05 or 08,04).\",\"rowField\":{\"x\":0,\"width\":1,\"parse\":\"hex\",\"type\":\"rowIndex\",\"key\":\"step\",\"description\":\"Groove step 0-F. The groove loops when a '--' entry is reached.\"},\"columns\":[{\"x\":2,\"width\":2,\"key\":\"ticks\",\"type\":\"ticks\",\"label\":\"Ticks (TIC)\",\"description\":\"Number of ticks this step takes. Default is 06 (at 24 PPQN = 1 sixteenth note). '00' skips the step.\"},{\"x\":6,\"width\":2,\"key\":\"ppq\",\"type\":\"ppq\",\"label\":\"PPQ\",\"description\":\"Pulses Per Quarter note: 24, 48, 96 or 192. Only present on groove row 0; absent on all other rows.\"},{\"x\":10,\"width\":5,\"key\":\"swing\",\"type\":\"swing\",\"label\":\"Swing\",\"description\":\"Swing amount as a percentage (e.g. '50.0%' = straight). Shown on every second row (0, 2, 4, …) for that pair of steps; empty on the others.\"}]},\"scale\":{\"title\":\"Scale View\",\"type\":\"grid\",\"description\":\"Defines and quantizes note-related events (project/chain transpose, note entry, ARP, PIT, and the MIDIOUT instrument CHD and ADD commands). Up to 16 user-defined scales per project; scale '00' is the default for all 8 tracks and can be overridden per track with SCA/SCG FX commands. Each of the 12 note intervals can be enabled ('EN' = ON) with an optional detuning offset (-24.00 to +24.00 semitones). Rows below the 12 intervals (not column-mapped) hold: KEY (global root note for the default scale), TUNE (A4 reference in Hz, e.g. '440.00'), NAME (up to 16 characters, 92 factory scales load from /Scales/Factory), and the LOAD/SAVE actions.\",\"columns\":[{\"x\":0,\"width\":2,\"key\":\"interval\",\"type\":\"noteInterval\",\"label\":\"Note Interval\",\"description\":\"Note interval row label: C, C#, D, D#, E, F, F#, G, G#, A, A#, B.\"},{\"x\":3,\"width\":3,\"key\":\"en\",\"type\":\"onOff\",\"label\":\"Enabled (EN)\",\"description\":\"Enables this note interval in the scale: 'ON' or 'OFF' ('--' = unset).\"},{\"x\":6,\"width\":6,\"key\":\"offset\",\"type\":\"semitoneOffset\",\"label\":\"Offset (OFFSET)\",\"description\":\"Detune offset in semitones, decimal with two decimals (-24.00 to +24.00), e.g. '00.00'.\"}]},\"instrumentpool\":{\"title\":\"Instrument Pool\",\"type\":\"grid\",\"description\":\"Lists all 128 instrument slots with their mix routing. Each row shows the instrument name (up to 12 chars, '------------' = empty slot) and its dry/FX send levels. Mixer-related settings can be adjusted per instrument here; [EDIT] on an empty slot loads an instrument or sample.\",\"rowField\":{\"x\":0,\"width\":2,\"parse\":\"hex\",\"type\":\"rowIndex\",\"key\":\"instIndex\",\"description\":\"Instrument slot index 00-7F.\"},\"columns\":[{\"x\":3,\"width\":12,\"key\":\"name\",\"type\":\"instrumentName\",\"label\":\"Instrument Name\",\"description\":\"Name of the instrument in this slot (up to 12 chars). '------------' = empty slot.\"},{\"x\":16,\"width\":2,\"key\":\"dry\",\"type\":\"volume\",\"label\":\"Dry (DRY)\",\"description\":\"Direct output volume for this instrument (hex 00-FF).\"},{\"x\":19,\"width\":2,\"key\":\"mx\",\"type\":\"volume\",\"label\":\"ModFX (MX)\",\"description\":\"ModFX send level (hex 00-FF).\"},{\"x\":22,\"width\":2,\"key\":\"de\",\"type\":\"volume\",\"label\":\"Delay (DE)\",\"description\":\"Delay send level (hex 00-FF).\"},{\"x\":25,\"width\":2,\"key\":\"rv\",\"type\":\"volume\",\"label\":\"Reverb (RV)\",\"description\":\"Reverb send level (hex 00-FF).\"},{\"x\":28,\"width\":2,\"key\":\"eq\",\"type\":\"eqSlot\",\"label\":\"EQ Slot (EQ)\",\"description\":\"EQ slot assignment. '--' = no EQ.\"}]},\"inst\":{\"title\":\"Instrument View\",\"type\":\"parameter\",\"description\":\"Per-instrument parameters for the selected slot: TYPE (Wavsynth, Macrosynth, Sampler, FM Synth, Hypersynth, External Instrument, MIDI Out), LOAD/SAVE presets, NAME, TRANSP. (enable/disable transposition from scales and transpose columns), TABLE TIC (default table speed), and EQ slot, plus the synth engine parameters. Almost every parameter has an associated FX command; highlighting a parameter and navigating to the phrase or table view sets that parameter's FX command as default.\"},\"instmods\":{\"title\":\"Instrument Modulation View\",\"type\":\"parameter\",\"description\":\"Four configurable modulation slots per instrument: AHD envelope, ADSR envelope, DRUM envelope, LFO, TRIG envelope, or TRACKING, each with a destination parameter (DEST) and optional source (SRC).\"},\"mixer\":{\"title\":\"Mixer View\",\"type\":\"parameter\",\"description\":\"Mix levels for the 8 tracks, the 3 send effects (MX/DE/RE), the analog input (INPUT, with dual-mono mode) and USB input, the DJ filter (DJF), OTT compression, main EQ, limiter (LIM) and main volume (MIX). All signals are summed through OTT, main EQ, limiter, DJ filter and main volume. Most values are also exposed as FX commands (VMV, VMX, VDE, VRE, VT1-8, DJC/DJR/DJT, IVO/IMX/IDE/IRV, USB, ...).\"},\"project\":{\"title\":\"Project View\",\"type\":\"parameter\",\"description\":\"Song-wide settings such as tempo, project transpose (identical to the TSP FX command), and LIVE QUANTIZE behavior for cueing tracks in live mode. [SHIFT]+[OPTION] stores a song snapshot; [SHIFT]+[EDIT] recalls it.\"},\"effectsettings\":{\"title\":\"Effect Settings View\",\"type\":\"parameter\",\"description\":\"Settings for the 3 send effects: ModFX type/depth/frequency/width, Delay time/feedback/width, and Reverb size/decay/modulation/width/freeze — all addressable via the XMT-XMW, XDT-XDR and XRS-XRZ FX commands.\"},\"mixeq\":{\"title\":\"Mix EQ View\",\"type\":\"parameter\",\"description\":\"EQ editor for the main mix EQ slot (assign with the EQM FX command). Selecting EQ in the Mixer view and pressing [EDIT] or [SHIFT]+[RIGHT] opens this view.\"},\"modfxeq\":{\"title\":\"ModFX EQ View\",\"type\":\"parameter\",\"description\":\"EQ editor for the ModFX send path.\"},\"delayeq\":{\"title\":\"Delay EQ View\",\"type\":\"parameter\",\"description\":\"EQ editor for the Delay send path.\"},\"reverbeq\":{\"title\":\"Reverb EQ View\",\"type\":\"parameter\",\"description\":\"EQ editor for the Reverb send path.\"},\"mixscope\":{\"title\":\"Mix Scope View\",\"type\":\"parameter\",\"description\":\"Graphical scope of the main mix activity. Opened from the Mixer view with MIX selected via [EDIT] or [SHIFT]+[RIGHT].\"},\"limiterscope\":{\"title\":\"Limiter Scope View\",\"type\":\"parameter\",\"description\":\"Graphical scope of the limiter's compression activity (the white line on the MIX indicator). Opened from the Mixer view with LIM selected via [EDIT] or [SHIFT]+[RIGHT].\"},\"systemsettings\":{\"title\":\"System Settings View\",\"type\":\"parameter\",\"description\":\"System-level settings for the device.\"},\"loadinstrument\":{\"title\":\"Load Instrument\",\"type\":\"parameter\",\"description\":\"File browser for loading an instrument preset from the SD card ([EDIT] on an empty instrument slot, or LOAD in the Instrument view).\"},\"selectsavedirectory\":{\"title\":\"Select Save Directory\",\"type\":\"parameter\",\"description\":\"File browser directory-selection step when saving a preset or project.\"},\"createdirectory\":{\"title\":\"Create Directory\",\"type\":\"parameter\",\"description\":\"File browser dialog for creating a new directory on the SD card.\"}}"),
2785
+ views: /* @__PURE__ */ JSON.parse("{\"song\":{\"title\":\"Song View\",\"type\":\"grid\",\"description\":\"Arranges chains across 8 independent tracks to form the song structure. Each row is a song position (up to 256 rows); each column is a track. Each track advances vertically until it reaches an empty column ('--'), then loops back to row 00. Chains containing no notes are grayed out; chains '00' or 'FE' are commonly used as silent spacers. On row '00', [UP][UP] enters track reordering mode.\",\"rowField\":{\"x\":0,\"width\":2,\"parse\":\"hex\",\"type\":\"rowIndex\",\"key\":\"songRow\",\"description\":\"Song row 00-FF. Each track loops back to row 00 when it reaches '--'.\"},\"columns\":[{\"x\":3,\"width\":2,\"key\":\"track1\",\"type\":\"chainRef\",\"label\":\"Track 1\",\"meta\":{\"trackIndex\":1}},{\"x\":6,\"width\":2,\"key\":\"track2\",\"type\":\"chainRef\",\"label\":\"Track 2\",\"meta\":{\"trackIndex\":2}},{\"x\":9,\"width\":2,\"key\":\"track3\",\"type\":\"chainRef\",\"label\":\"Track 3\",\"meta\":{\"trackIndex\":3}},{\"x\":12,\"width\":2,\"key\":\"track4\",\"type\":\"chainRef\",\"label\":\"Track 4\",\"meta\":{\"trackIndex\":4}},{\"x\":15,\"width\":2,\"key\":\"track5\",\"type\":\"chainRef\",\"label\":\"Track 5\",\"meta\":{\"trackIndex\":5}},{\"x\":18,\"width\":2,\"key\":\"track6\",\"type\":\"chainRef\",\"label\":\"Track 6\",\"meta\":{\"trackIndex\":6}},{\"x\":21,\"width\":2,\"key\":\"track7\",\"type\":\"chainRef\",\"label\":\"Track 7\",\"meta\":{\"trackIndex\":7}},{\"x\":24,\"width\":2,\"key\":\"track8\",\"type\":\"chainRef\",\"label\":\"Track 8\",\"meta\":{\"trackIndex\":8}}]},\"chain\":{\"title\":\"Chain View\",\"type\":\"grid\",\"description\":\"An ordered list of up to 16 phrases (256 steps). The first '--' phrase ends the chain and the song continues on to the next chain in the song view. The 'TSP' column optionally transposes every note in the phrase in semitones (relative hex).\",\"rowField\":{\"x\":0,\"width\":1,\"parse\":\"hex\",\"type\":\"rowIndex\",\"key\":\"chainPos\",\"description\":\"Position within the chain (0-F, max 16 entries).\"},\"columns\":[{\"x\":2,\"width\":2,\"key\":\"phrase\",\"type\":\"phraseRef\",\"label\":\"Phrase (PH)\",\"description\":\"Phrase number to play at this chain position.\"},{\"x\":5,\"width\":2,\"key\":\"transpose\",\"type\":\"transpose\",\"label\":\"Transpose (TSP)\",\"description\":\"Optional note transpose in semitones applied to every note in the phrase (relative hex).\"}]},\"phrase\":{\"title\":\"Phrase View\",\"type\":\"grid\",\"description\":\"A 16-step sequence. Each step holds a note, velocity, instrument assignment, and up to 3 FX command+value pairs. Notes cover 11 octaves (the full 128 MIDI note range); velocity defaults to 64 (hex); an empty instrument column plays the note without retriggering the instrument. A '*' next to the phrase number indicates the phrase is used elsewhere in the chain or song.\",\"rowField\":{\"x\":0,\"width\":1,\"parse\":\"hex\",\"type\":\"rowIndex\",\"key\":\"step\",\"description\":\"Step index 0-F (16th note by default; altered by groove).\"},\"columns\":[{\"x\":2,\"width\":3,\"key\":\"note\",\"type\":\"note\",\"label\":\"Note (N)\"},{\"x\":6,\"width\":2,\"key\":\"vel\",\"type\":\"velocity\",\"label\":\"Velocity (V)\"},{\"x\":9,\"width\":2,\"key\":\"inst\",\"type\":\"instrumentRef\",\"label\":\"Instrument (I)\"},{\"x\":12,\"width\":3,\"key\":\"fx1cmd\",\"type\":\"fxCommand\",\"label\":\"FX1 Command\"},{\"x\":15,\"width\":2,\"key\":\"fx1val\",\"type\":\"fxValue\",\"label\":\"FX1 Value\"},{\"x\":18,\"width\":3,\"key\":\"fx2cmd\",\"type\":\"fxCommand\",\"label\":\"FX2 Command\"},{\"x\":21,\"width\":2,\"key\":\"fx2val\",\"type\":\"fxValue\",\"label\":\"FX2 Value\"},{\"x\":24,\"width\":3,\"key\":\"fx3cmd\",\"type\":\"fxCommand\",\"label\":\"FX3 Command\"},{\"x\":27,\"width\":2,\"key\":\"fx3val\",\"type\":\"fxValue\",\"label\":\"FX3 Value\"}]},\"table\":{\"title\":\"Table View\",\"type\":\"grid\",\"description\":\"A 16-step mini-sequencer that runs alongside an instrument. Used for arpeggios, multi-stage envelopes, and automated FX. The 'N' column transposes the instrument for the step (relative hex); 'V' multiplies with the phrase-row velocity. Each instrument has a dedicated table plus 128 assignable tables (TBL command). FX columns can run at independent speeds via TIC; a TIC on the last table row affects all rows. HOP shortens or loops the table.\",\"rowField\":{\"x\":0,\"width\":1,\"parse\":\"hex\",\"type\":\"rowIndex\",\"key\":\"step\",\"description\":\"Table step 0-F. Loops from bottom unless a HOP command redirects.\"},\"columns\":[{\"x\":2,\"width\":2,\"key\":\"transpose\",\"type\":\"transpose\",\"label\":\"Transpose (N)\",\"description\":\"Transposes the instrument for this step (relative hex). '--' = no transpose.\"},{\"x\":5,\"width\":2,\"key\":\"volume\",\"type\":\"volume\",\"label\":\"Volume (V)\",\"description\":\"Volume multiplier applied on top of the phrase velocity (hex). '--' = no override.\"},{\"x\":8,\"width\":3,\"key\":\"fx1cmd\",\"type\":\"fxCommand\",\"label\":\"FX1 Command\",\"description\":\"3-char command name for table FX slot 1.\"},{\"x\":11,\"width\":2,\"key\":\"fx1val\",\"type\":\"fxValue\",\"label\":\"FX1 Value\",\"description\":\"Value for table FX1.\"},{\"x\":14,\"width\":3,\"key\":\"fx2cmd\",\"type\":\"fxCommand\",\"label\":\"FX2 Command\",\"description\":\"3-char command name for table FX slot 2.\"},{\"x\":17,\"width\":2,\"key\":\"fx2val\",\"type\":\"fxValue\",\"label\":\"FX2 Value\",\"description\":\"Value for table FX2.\"},{\"x\":20,\"width\":3,\"key\":\"fx3cmd\",\"type\":\"fxCommand\",\"label\":\"FX3 Command\",\"description\":\"3-char command name for table FX slot 3.\"},{\"x\":23,\"width\":2,\"key\":\"fx3val\",\"type\":\"fxValue\",\"label\":\"FX3 Value\",\"description\":\"Value for table FX3.\"}]},\"groove\":{\"title\":\"Groove View\",\"type\":\"grid\",\"description\":\"Defines the timing of each phrase step in ticks. Used to create swing, shuffle, triplets, and other rhythmic feels. At the default 24 PPQ a step is 6 ticks and a full phrase totals 96 ticks. The groove loops when a '--' entry is reached; a '00' entry skips the phrase step. Row 0 also holds the PPQ resolution (24/48/96/192) and the SWING percentage; editing the row 0 tick value alters rows 0 and 1 together (a common swing setting is 07,05 or 08,04).\",\"rowField\":{\"x\":0,\"width\":1,\"parse\":\"hex\",\"type\":\"rowIndex\",\"key\":\"step\",\"description\":\"Groove step 0-F. The groove loops when a '--' entry is reached.\"},\"columns\":[{\"x\":2,\"width\":2,\"key\":\"ticks\",\"type\":\"ticks\",\"label\":\"Ticks (TIC)\",\"description\":\"Number of ticks this step takes. Default is 06 (at 24 PPQN = 1 sixteenth note). '00' skips the step.\"},{\"x\":6,\"width\":2,\"key\":\"ppq\",\"type\":\"ppq\",\"label\":\"PPQ\",\"description\":\"Pulses Per Quarter note: 24, 48, 96 or 192. Only present on groove row 0; absent on all other rows.\"},{\"x\":10,\"width\":5,\"key\":\"swing\",\"type\":\"swing\",\"label\":\"Swing\",\"description\":\"Swing amount as a percentage (e.g. '50.0%' = straight). Shown on every second row (0, 2, 4, …) for that pair of steps; empty on the others.\"}]},\"scale\":{\"title\":\"Scale View\",\"type\":\"grid\",\"description\":\"Defines and quantizes note-related events (project/chain transpose, note entry, ARP, PIT, and the MIDIOUT instrument CHD and ADD commands). Up to 16 user-defined scales per project; scale '00' is the default for all 8 tracks and can be overridden per track with SCA/SCG FX commands. Each of the 12 note intervals can be enabled ('EN' = ON) with an optional detuning offset (-24.00 to +24.00 semitones); a note out of the scale reads '-- -- --'. Rows that are not column-mapped (Model:02, fw 6.5): KEY under the title (global root note for the default scale, the same on every scale), then after the intervals TUNE (A4 reference in Hz, e.g. '440.00'), NAME (up to 16 characters, 92 factory scales load from /Scales/Factory), and the LOAD/SAVE actions.\",\"columns\":[{\"x\":0,\"width\":2,\"key\":\"interval\",\"type\":\"noteInterval\",\"label\":\"Note Interval\",\"description\":\"Note interval row label: C, C#, D, D#, E, F, F#, G, G#, A, A#, B.\"},{\"x\":3,\"width\":3,\"key\":\"en\",\"type\":\"onOff\",\"label\":\"Enabled (EN)\",\"description\":\"Enables this note interval in the scale: 'ON', or '--' when the note is out of the scale (the device draws the row '-- -- --').\"},{\"x\":6,\"width\":6,\"key\":\"offset\",\"type\":\"semitoneOffset\",\"label\":\"Offset (OFFSET)\",\"description\":\"Detune offset in semitones, decimal with two decimals (-24.00 to +24.00), e.g. '00.00'.\"}]},\"instrumentpool\":{\"title\":\"Instrument Pool\",\"type\":\"grid\",\"description\":\"Lists all 128 instrument slots with their mix routing. Each row shows the instrument name (up to 12 chars, '------------' = empty slot) and its dry/FX send levels. Mixer-related settings can be adjusted per instrument here; [EDIT] on an empty slot loads an instrument or sample.\",\"rowField\":{\"x\":0,\"width\":2,\"parse\":\"hex\",\"type\":\"rowIndex\",\"key\":\"instIndex\",\"description\":\"Instrument slot index 00-7F.\"},\"columns\":[{\"x\":3,\"width\":12,\"key\":\"name\",\"type\":\"instrumentName\",\"label\":\"Instrument Name\",\"description\":\"Name of the instrument in this slot (up to 12 chars). '------------' = empty slot.\"},{\"x\":16,\"width\":2,\"key\":\"dry\",\"type\":\"volume\",\"label\":\"Dry (DRY)\",\"description\":\"Direct output volume for this instrument (hex 00-FF).\"},{\"x\":19,\"width\":2,\"key\":\"mx\",\"type\":\"volume\",\"label\":\"ModFX (MX)\",\"description\":\"ModFX send level (hex 00-FF).\"},{\"x\":22,\"width\":2,\"key\":\"de\",\"type\":\"volume\",\"label\":\"Delay (DE)\",\"description\":\"Delay send level (hex 00-FF).\"},{\"x\":25,\"width\":2,\"key\":\"rv\",\"type\":\"volume\",\"label\":\"Reverb (RV)\",\"description\":\"Reverb send level (hex 00-FF).\"},{\"x\":28,\"width\":2,\"key\":\"eq\",\"type\":\"eqSlot\",\"label\":\"EQ Slot (EQ)\",\"description\":\"EQ slot assignment. '--' = no EQ.\"}]},\"inst\":{\"title\":\"Instrument View\",\"type\":\"parameter\",\"description\":\"Per-instrument parameters for the selected slot: TYPE (Wavsynth, Macrosynth, Sampler, FM Synth, Hypersynth, External Instrument, MIDI Out), LOAD/SAVE presets, NAME, TRANSP. (enable/disable transposition from scales and transpose columns), TABLE TIC (default table speed), and EQ slot, plus the synth engine parameters. Almost every parameter has an associated FX command; highlighting a parameter and navigating to the phrase or table view sets that parameter's FX command as default.\"},\"instmods\":{\"title\":\"Instrument Modulation View\",\"type\":\"parameter\",\"description\":\"Four configurable modulation slots per instrument: AHD envelope, ADSR envelope, DRUM envelope, LFO, TRIG envelope, or TRACKING, each with a destination parameter (DEST) and optional source (SRC).\"},\"mixer\":{\"title\":\"Mixer View\",\"type\":\"parameter\",\"description\":\"Mix levels for the 8 tracks, the 3 send effects (MX/DE/RE), the analog input (INPUT, with dual-mono mode) and USB input, the DJ filter (DJF), OTT compression, main EQ, limiter (LIM) and main volume (MIX). All signals are summed through OTT, main EQ, limiter, DJ filter and main volume. Most values are also exposed as FX commands (VMV, VMX, VDE, VRE, VT1-8, DJC/DJR/DJT, IVO/IMX/IDE/IRV, USB, ...).\"},\"project\":{\"title\":\"Project View\",\"type\":\"parameter\",\"description\":\"Song-wide settings such as tempo, project transpose (identical to the TSP FX command), and LIVE QUANTIZE behavior for cueing tracks in live mode. [SHIFT]+[OPTION] stores a song snapshot; [SHIFT]+[EDIT] recalls it.\"},\"effectsettings\":{\"title\":\"Effect Settings View\",\"type\":\"parameter\",\"description\":\"Settings for the 3 send effects: ModFX type/depth/frequency/width, Delay time/feedback/width, and Reverb size/decay/modulation/width/freeze — all addressable via the XMT-XMW, XDT-XDR and XRS-XRZ FX commands.\"},\"mixeq\":{\"title\":\"Mix EQ View\",\"type\":\"parameter\",\"description\":\"EQ editor for the main mix EQ slot (assign with the EQM FX command). Selecting EQ in the Mixer view and pressing [EDIT] or [SHIFT]+[RIGHT] opens this view.\"},\"modfxeq\":{\"title\":\"ModFX EQ View\",\"type\":\"parameter\",\"description\":\"EQ editor for the ModFX send path.\"},\"delayeq\":{\"title\":\"Delay EQ View\",\"type\":\"parameter\",\"description\":\"EQ editor for the Delay send path.\"},\"reverbeq\":{\"title\":\"Reverb EQ View\",\"type\":\"parameter\",\"description\":\"EQ editor for the Reverb send path.\"},\"mixscope\":{\"title\":\"Mix Scope View\",\"type\":\"parameter\",\"description\":\"Graphical scope of the main mix activity. Opened from the Mixer view with MIX selected via [EDIT] or [SHIFT]+[RIGHT].\"},\"limiterscope\":{\"title\":\"Limiter Scope View\",\"type\":\"parameter\",\"description\":\"Graphical scope of the limiter's compression activity (the white line on the MIX indicator). Opened from the Mixer view with LIM selected via [EDIT] or [SHIFT]+[RIGHT].\"},\"systemsettings\":{\"title\":\"System Settings View\",\"type\":\"parameter\",\"description\":\"System-level settings for the device.\"},\"loadinstrument\":{\"title\":\"Load Instrument\",\"type\":\"parameter\",\"description\":\"File browser for loading an instrument preset from the SD card ([EDIT] on an empty instrument slot, or LOAD in the Instrument view).\"},\"selectsavedirectory\":{\"title\":\"Select Save Directory\",\"type\":\"parameter\",\"description\":\"File browser directory-selection step when saving a preset or project.\"},\"createdirectory\":{\"title\":\"Create Directory\",\"type\":\"parameter\",\"description\":\"File browser dialog for creating a new directory on the SD card.\"}}"),
41
2786
  fxCommands: /* @__PURE__ */ JSON.parse("{\"sequencer\":{\"ARP\":{\"description\":\"Arpeggio: plays 3 notes rapidly. X=first interval semitones, Y=second interval semitones.\"},\"ARC\":{\"description\":\"Arpeggio Config: X=direction and number of octaves, Y=speed in ticks.\"},\"CHA\":{\"description\":\"Chance: X=probability left of command (0=never, F=always), Y=probability right. In a table: probability for everything to the left of CHA from 00 (never) to FF (always).\"},\"DEL\":{\"description\":\"Delay: in phrase delays entire row by XX ticks; in table delays table playhead.\"},\"GRV\":{\"description\":\"Groove: sets groove number XX for the current track.\"},\"GGR\":{\"description\":\"Global Groove: sets groove XX for all tracks.\"},\"HOP\":{\"description\":\"Hop: in phrase jumps to row Y of next phrase; HOPFF stops track. In table loops to row Y X times.\"},\"INS\":{\"description\":\"Instrument: changes active instrument to XX as an FX command.\"},\"KIL\":{\"description\":\"Kill: stops the playing instrument after XX ticks.\"},\"RND\":{\"description\":\"Random: randomises the preceding FX command. X=left range, Y=right range (0=none, F=full).\"},\"RNL\":{\"description\":\"Randomise Left: randomises the FX command to the left (X=left range, Y=right range). In the first column RNL randomises the note and instrument number in phrase, or note and velocity in table.\"},\"RET\":{\"description\":\"Retrig: retriggers current row. Y≠0: retrig every Y ticks with X volume ramp. Y=0: single retrig after X ticks.\"},\"REP\":{\"description\":\"Repeat: repeats and increments the last FX command by XX each step. Active until a new command or REP00 stops it; it does not need to appear on every row. In a table: loops the last row XX times. A double-caret '^^' appears next to an FX lane while a REP from a previous phrase is active.\"},\"RTO\":{\"description\":\"Repeat To: use after REP to hold at the given value (the min/max REP stops at). In a table, used alone: loops until the relative value is reached.\"},\"RMX\":{\"description\":\"Remix: repositions the phrase playhead (Y) on tracks to the left (selected by X).\"},\"NTH\":{\"description\":\"Nth Trigger: conditional trigger on the loop count. X=affects what is left of the command, Y=what is right (in a table: what is left).\"},\"PSL\":{\"description\":\"Pitch Slide (portamento): slides to the given note over XX ticks.\"},\"PBN\":{\"description\":\"Pitch Bend: continuous pitch slide up (00-7F) or down (80-FF).\"},\"PVB\":{\"description\":\"Vibrato: X=speed, Y=depth.\"},\"PVX\":{\"description\":\"Extreme Vibrato: like PVB but with higher range.\"},\"SCA\":{\"description\":\"Track Scale: X=key signature, Y=scale number for this track.\"},\"SCG\":{\"description\":\"Global Scale: X=key, Y=scale number for the whole song.\"},\"SNG\":{\"description\":\"Song Hop: moves this track's song position by XX rows relative to current. Ignored if the resulting song position is not playable.\"},\"SED\":{\"description\":\"Random Seed: sets the random seed XX for this track.\"},\"TBL\":{\"description\":\"Table: assigns table number XX to the current instrument.\"},\"THO\":{\"description\":\"Table Hop: jumps all table columns to position 0X.\"},\"TIC\":{\"description\":\"Table Tick: sets the table tick rate. 00 = increment row on each instrument trigger; 01-FB = ticks per row; FC = Octave Map (playing octave maps to table row); FD = Velocity Map; FE = Note Map (pair with HOP00 on row 0C to limit to 12 notes/octave); FF = increment at 200 Hz. In a table each FX column can run independently; a TIC on the last table row affects all rows.\"},\"TBX\":{\"description\":\"Aux Table: runs table XX in parallel with the instrument table. 00=stop aux table. A TIC in the same row as a TBX affects the auxiliary table's tick rate.\"},\"TPO\":{\"description\":\"Tempo: sets song BPM to XX. In a table the tempo is relative.\"},\"TSP\":{\"description\":\"Global Song Transpose: transposes the entire song by XX semitones. Identical to the transpose value in the Project View.\"},\"NXT\":{\"description\":\"Next Track Trigger: plays instrument XX on the track to the right using the current note/velocity. Does not work on track 8.\"},\"OFF\":{\"description\":\"Note Off: stops the playing instrument after XX ticks. Triggers ADSR release stage.\"},\"MTT\":{\"description\":\"Micro Time: adjusts row playback timing in positive or negative sub-tick (1/8 tick) amounts. Negative amounts do not work on the first phrase row. Currently has no action in tables.\"}},\"instrument\":{\"VOL\":{\"description\":\"Volume (relative).\",\"relative\":true},\"PIT\":{\"description\":\"Pitch in semitones (relative).\",\"relative\":true},\"FIN\":{\"description\":\"Fine tune: pitch shift of up to about one semitone (relative).\",\"relative\":true},\"PLY\":{\"description\":\"Sampler play mode (FWD, REV, loop modes…).\"},\"STA\":{\"description\":\"Sampler start position.\"},\"LOP\":{\"description\":\"Sampler loop start (relative).\",\"relative\":true},\"LEN\":{\"description\":\"Sampler length (relative).\",\"relative\":true},\"DEG\":{\"description\":\"Degrade amount (relative).\",\"relative\":true},\"SLI\":{\"description\":\"Sampler slice to play.\"},\"ERR\":{\"description\":\"Error: randomizes pitch and parameters by the given amount.\"},\"FLT\":{\"description\":\"Filter type.\"},\"FIL\":{\"description\":\"Filter type.\"},\"ALG\":{\"description\":\"FM algorithm.\"},\"FM1\":{\"description\":\"FM modulation amount 1 (relative).\",\"relative\":true},\"FM2\":{\"description\":\"FM modulation amount 2 (relative).\",\"relative\":true},\"FM3\":{\"description\":\"FM modulation amount 3 (relative).\",\"relative\":true},\"FM4\":{\"description\":\"FM modulation amount 4 (relative).\",\"relative\":true},\"SNC\":{\"description\":\"Sync: on an FM synth the FM sync phase position; on a Hypersynth it offsets the sync of the oscillators by the given amount.\"},\"CRD\":{\"description\":\"Hypersynth chord set.\"},\"CVO\":{\"description\":\"Hypersynth chord voice offset: X=voice, Y=offset.\"},\"SWM\":{\"description\":\"Hypersynth oscillator swarm (relative).\",\"relative\":true},\"WID\":{\"description\":\"Hypersynth stereo width (relative).\",\"relative\":true},\"SUB\":{\"description\":\"Hypersynth sub-oscillator amount (relative).\",\"relative\":true},\"OSC\":{\"description\":\"Macrosynth oscillator shape.\"},\"TBR\":{\"description\":\"Macrosynth timbre (relative).\",\"relative\":true},\"COL\":{\"description\":\"Macrosynth color (relative).\",\"relative\":true},\"RED\":{\"description\":\"Macrosynth bit reduction (relative).\",\"relative\":true},\"TRG\":{\"description\":\"Macrosynth trigger/strike.\"},\"CUT\":{\"description\":\"Filter cutoff (relative).\",\"relative\":true},\"RES\":{\"description\":\"Filter resonance (relative).\",\"relative\":true},\"AMP\":{\"description\":\"Amp level (relative).\",\"relative\":true},\"LIM\":{\"description\":\"Limit mode: how the amp stage clips.\"},\"PAN\":{\"description\":\"Pan (relative).\",\"relative\":true},\"DRY\":{\"description\":\"Dry volume: the instrument's level in the main mix.\"},\"SMX\":{\"description\":\"Send to ModFX.\"},\"SDL\":{\"description\":\"Send to Delay.\"},\"SRV\":{\"description\":\"Send to Reverb.\"},\"CHD\":{\"description\":\"Chord (MIDIOUT instrument): triggers a chord. Quantized by the active scale.\"},\"ADD\":{\"description\":\"Add Note (MIDIOUT instrument): adds a note to the chord. Quantized by the active scale.\"}},\"modulation\":{\"EA\":{\"description\":\"Envelope amount of modulator N (relative).\",\"relative\":true},\"AT\":{\"description\":\"Envelope attack of modulator N.\"},\"HO\":{\"description\":\"Envelope hold of modulator N.\"},\"DE\":{\"description\":\"Envelope decay of modulator N.\"},\"ET\":{\"description\":\"Envelope trigger of modulator N: retriggers the envelope.\"},\"LA\":{\"description\":\"LFO amount of modulator N (relative).\",\"relative\":true},\"LO\":{\"description\":\"LFO oscillator shape of modulator N.\"},\"LS\":{\"description\":\"LFO trigger settings of modulator N.\"},\"LF\":{\"description\":\"LFO frequency of modulator N.\"},\"LT\":{\"description\":\"LFO trigger of modulator N: at the given offset, resets the LFO to that position.\"}},\"mixer\":{\"VMV\":{\"description\":\"Main Volume: sets the main song output volume.\"},\"VMX\":{\"description\":\"ModFX Volume.\"},\"VDE\":{\"description\":\"Delay Volume.\"},\"VRE\":{\"description\":\"Reverb Volume.\"},\"VT1\":{\"description\":\"Track 1 Volume.\"},\"VT2\":{\"description\":\"Track 2 Volume.\"},\"VT3\":{\"description\":\"Track 3 Volume.\"},\"VT4\":{\"description\":\"Track 4 Volume.\"},\"VT5\":{\"description\":\"Track 5 Volume.\"},\"VT6\":{\"description\":\"Track 6 Volume.\"},\"VT7\":{\"description\":\"Track 7 Volume.\"},\"VT8\":{\"description\":\"Track 8 Volume.\"},\"DJC\":{\"description\":\"DJ Filter Cutoff.\"},\"DJR\":{\"description\":\"DJ Filter Resonance.\"},\"DJT\":{\"description\":\"DJ Filter Type.\"},\"EQM\":{\"description\":\"Assign main mix EQ slot.\"},\"EQI\":{\"description\":\"Assign current instrument EQ slot.\"},\"XMT\":{\"description\":\"Send Effect: ModFX mod type and phase position (Effect Settings view).\"},\"XMM\":{\"description\":\"Send Effect: ModFX mod depth (Effect Settings view).\"},\"XMF\":{\"description\":\"Send Effect: ModFX mod frequency (Effect Settings view).\"},\"XMW\":{\"description\":\"Send Effect: ModFX stereo width (Effect Settings view).\"},\"XMR\":{\"description\":\"Send Effect: ModFX to reverb mix (Effect Settings view).\"},\"XDT\":{\"description\":\"Send Effect: Delay time — X = left, Y = right, in large increments (Effect Settings view).\"},\"XDF\":{\"description\":\"Send Effect: Delay feedback (Effect Settings view).\"},\"XDW\":{\"description\":\"Send Effect: Delay stereo width (Effect Settings view).\"},\"XDR\":{\"description\":\"Send Effect: Delay to reverb mix (Effect Settings view).\"},\"XRS\":{\"description\":\"Send Effect: Reverb room size (Effect Settings view).\"},\"XRD\":{\"description\":\"Send Effect: Reverb decay (Effect Settings view).\"},\"XRM\":{\"description\":\"Send Effect: Reverb mod depth (Effect Settings view).\"},\"XRF\":{\"description\":\"Send Effect: Reverb mod frequency (Effect Settings view).\"},\"XRW\":{\"description\":\"Send Effect: Reverb stereo width (Effect Settings view).\"},\"XRZ\":{\"description\":\"Send Effect: Reverb freeze — enabled with a value greater than 00, disabled at 00.\"},\"VIN\":{\"description\":\"Line Input Mixer: analog input volume (Mixer view).\"},\"XRH\":{\"description\":\"Send Effect: Reverb shimmer (Effect Settings view).\"},\"OTT\":{\"description\":\"OTT mix amount (Mixer OTT settings; OTC and OTI default to 80).\"},\"OTC\":{\"description\":\"OTT color (default 80).\"},\"OTI\":{\"description\":\"OTT time (default 80).\"},\"IVO\":{\"description\":\"Alias of VIN as named in the manual: analog input volume (Mixer view).\"},\"IMX\":{\"description\":\"Line Input Mixer: analog input ModFX send (Mixer view).\"},\"IDE\":{\"description\":\"Line Input Mixer: analog input delay send (Mixer view).\"},\"IRV\":{\"description\":\"Line Input Mixer: analog input reverb send (Mixer view). Also referenced as 'IRE' in the manual text.\"},\"IRE\":{\"description\":\"Alias of IRV: analog input reverb send (Mixer view).\"},\"IV2\":{\"description\":\"Line Input Mixer: volume for the 2nd input (right channel in dual-mono input mode, set in the Mixer view).\"},\"IM2\":{\"description\":\"Line Input Mixer: ModFX send for the 2nd input (right channel in dual-mono input mode).\"},\"ID2\":{\"description\":\"Line Input Mixer: delay send for the 2nd input (right channel in dual-mono input mode).\"},\"IR2\":{\"description\":\"Line Input Mixer: reverb send for the 2nd input (right channel in dual-mono input mode).\"},\"USB\":{\"description\":\"USB input volume (Mixer view).\"}}}"),
42
2787
  instrumentFx: {
43
2788
  _note: "Instrument commands offered by [EDIT]+[UP/DOWN] (Effect Command Help view) in the Current Instrument section depend on the instrument type; the Instrument Mods section depends on the modulators of that instrument, and Sequencer FX and Mixer/Effects are the same for every type. Lists marked verified were read from a real M8 (Model:02). Wavsynth, External and MIDI Out were not available on that device: their lists are not known here.",
@@ -166,7 +2911,7 @@ var r = {
166
2911
  },
167
2912
  relativeCommands: { description: "Relative commands add to the instrument parameter's current value (01-7F add, 80-FF subtract) and keep accumulating until a note is triggered with a RET command or with an instrument number in the I column; that resets every parameter to the instrument's own value." }
168
2913
  }
169
- }, i = {
2914
+ }, wt = {
170
2915
  version: "1.0",
171
2916
  description: "Layouts of the non-grid ('parameter') views: which text at which column is an instrument type, name, parameter, option or action. Column positions were measured on the manual's screenshots (font mode 0, 40 columns) and cross-checked with the phrase view grid; descriptions come from the manual.",
172
2917
  notes: {
@@ -186,23 +2931,23 @@ var r = {
186
2931
  EXTERN: "external",
187
2932
  MIDI: "midiout"
188
2933
  }
189
- }, a = i.views, o = i.instrumentTypes, s = i.instrumentTypeNames, c = {};
190
- for (let [e, t] of Object.entries(a)) {
2934
+ }, Tt = wt.views, Et = wt.instrumentTypes, Dt = wt.instrumentTypeNames, Ot = {};
2935
+ for (let [e, t] of Object.entries(Tt)) {
191
2936
  let { extends: n, ...r } = t;
192
- c[e] = n ? {
193
- ...a[n],
2937
+ Ot[e] = n ? {
2938
+ ...Tt[n],
194
2939
  ...r
195
2940
  } : r;
196
2941
  }
197
- function l(e) {
198
- return c[e] ?? null;
2942
+ function kt(e) {
2943
+ return Ot[e] ?? null;
199
2944
  }
200
- var u = (e, t, n) => t >= e.length ? "" : e.slice(t, t + n);
201
- function d(e, t) {
202
- let n = e.width ?? e.text?.length ?? 1, r = u(t, e.x, n);
203
- return e.text == null ? e.regex == null ? !1 : new RegExp(e.regex, "i").test(r) : r.toUpperCase() === e.text.toUpperCase();
2945
+ var K = (e, t, n) => t >= e.length ? "" : e.slice(t, t + n);
2946
+ function At(e, t) {
2947
+ let n = e.width ?? e.text?.length ?? 1, r = K(t, e.x, n);
2948
+ return e.text == null ? e.regex != null && new RegExp(e.regex, "i").test(r) : r.toUpperCase() === e.text.toUpperCase();
204
2949
  }
205
- function f(e, t) {
2950
+ function jt(e, t) {
206
2951
  let n = e.sections;
207
2952
  if (!n) return null;
208
2953
  for (let e of t) {
@@ -211,52 +2956,52 @@ function f(e, t) {
211
2956
  }
212
2957
  return null;
213
2958
  }
214
- function p(e, t, n) {
2959
+ function Mt(e, t, n) {
215
2960
  let r = e.zones?.find((e) => e.id === t);
216
2961
  if (!e.slotLabel || !r) return null;
217
2962
  let i = RegExp(`^${e.slotLabel}$`, "i");
218
2963
  for (let e of n) {
219
- let t = u(e, r.labelX, r.labelWidth).trim();
2964
+ let t = K(e, r.labelX, r.labelWidth).trim();
220
2965
  if (i.test(t)) return t.toUpperCase();
221
2966
  }
222
2967
  return null;
223
2968
  }
224
- function m(e) {
2969
+ function Nt(e) {
225
2970
  let t = e.toUpperCase().replace(/[^A-Z]/g, "");
226
2971
  if (!t) return null;
227
- let n = Object.keys(s).find((e) => t.startsWith(e));
228
- return n ? s[n] : null;
2972
+ let n = Object.keys(Dt).find((e) => t.startsWith(e));
2973
+ return n ? Dt[n] : null;
229
2974
  }
230
- function h(e) {
2975
+ function Pt(e) {
231
2976
  for (let t of e) if (t.toUpperCase().startsWith("TYPE")) {
232
- let e = u(t, 8, 13).trim();
2977
+ let e = K(t, 8, 13).trim();
233
2978
  return e ? {
234
2979
  text: e,
235
- key: m(e)
2980
+ key: Nt(e)
236
2981
  } : null;
237
2982
  }
238
2983
  return null;
239
2984
  }
240
- function g(e) {
241
- let t = o[e];
2985
+ function Ft(e) {
2986
+ let t = Et[e];
242
2987
  return t ? {
243
2988
  name: t.name,
244
2989
  description: t.description
245
2990
  } : null;
246
2991
  }
247
- function _(e, t, n) {
2992
+ function It(e, t, n) {
248
2993
  let r = t.replace(/^MOD\d$/, "MOD#").replace(/^CC[A-J]$/, "CC#");
249
2994
  if (e.vocabulary) return e.vocabulary[r] ?? null;
250
2995
  if (e.vocabularyFrom !== "instrumentTypes") return null;
251
- let i = n ? [n, "common"] : ["common", ...Object.keys(o).filter((e) => e !== "common")];
2996
+ let i = n ? [n, "common"] : ["common", ...Object.keys(Et).filter((e) => e !== "common")];
252
2997
  for (let e of i) {
253
- let t = o[e]?.params[r];
2998
+ let t = Et[e]?.params[r];
254
2999
  if (t) return t;
255
3000
  }
256
3001
  return null;
257
3002
  }
258
- var v = (e) => e.toLowerCase().replace(/[^a-z0-9]+(.)?/g, (e, t) => t ? t.toUpperCase() : "").replace(/^[^a-z]+/, ""), y = /^[A-Z][A-Z0-9.:#/ -]*$/;
259
- function b(e, t, n) {
3003
+ var Lt = (e) => e.toLowerCase().replace(/[^a-z0-9]+(.)?/g, (e, t) => t ? t.toUpperCase() : "").replace(/^[^a-z]+/, ""), Rt = /^[A-Z][A-Z0-9.:#/ -]*$/;
3004
+ function zt(e, t, n) {
260
3005
  if (e.kind === "browser") {
261
3006
  let r = n.entryText?.trim() || t.trim();
262
3007
  return r ? {
@@ -294,28 +3039,28 @@ function b(e, t, n) {
294
3039
  }]
295
3040
  };
296
3041
  }
297
- for (let r of e.rows ?? []) if (!(r.section && n.section && r.section !== n.section) && r.match.every((e) => d(e, t))) return {
3042
+ for (let r of e.rows ?? []) if (!(r.section && n.section && r.section !== n.section) && r.match.every((e) => At(e, t))) return {
298
3043
  rowId: r.id,
299
3044
  cells: r.cells
300
3045
  };
301
3046
  let r = e.zones ?? [], i = [];
302
3047
  return r.forEach((a, o) => {
303
- let s = u(t, a.labelX, a.labelWidth).trim().toUpperCase();
304
- if (!y.test(s)) return;
305
- let c = r[o + 1], l = c != null && u(t, c.labelX - 1, 1).trim() === "" && y.test(u(t, c.labelX, c.labelWidth).trim().toUpperCase()), d = c && l ? Math.max(1, c.labelX - 1 - a.x) : a.width;
306
- if (!u(t, a.x, d).trim()) return;
307
- let f = _(e, s, n.instrumentKey), p = v(s) || a.id, m = i.some((e) => e.key === p) ? `${p}${a.id[0].toUpperCase()}${a.id.slice(1)}` : p;
3048
+ let s = K(t, a.labelX, a.labelWidth).trim().toUpperCase();
3049
+ if (!Rt.test(s)) return;
3050
+ let c = r[o + 1], l = c != null && K(t, c.labelX - 1, 1).trim() === "" && Rt.test(K(t, c.labelX, c.labelWidth).trim().toUpperCase()), u = c && l ? Math.max(1, c.labelX - 1 - a.x) : a.width;
3051
+ if (!K(t, a.x, u).trim()) return;
3052
+ let d = It(e, s, n.instrumentKey), f = Lt(s) || a.id, p = i.some((e) => e.key === f) ? `${f}${a.id[0].toUpperCase()}${a.id.slice(1)}` : f;
308
3053
  i.push({
309
3054
  x: a.x,
310
- width: d,
311
- key: m,
312
- type: f?.type ?? "parameter",
313
- format: f?.format ?? "auto",
314
- label: f?.label ?? s,
315
- description: f?.description,
316
- parts: f?.parts,
317
- options: f?.options,
318
- unit: f?.unit,
3055
+ width: u,
3056
+ key: p,
3057
+ type: d?.type ?? "parameter",
3058
+ format: d?.format ?? "auto",
3059
+ label: d?.label ?? s,
3060
+ description: d?.description,
3061
+ parts: d?.parts,
3062
+ options: d?.options,
3063
+ unit: d?.unit,
319
3064
  meta: {
320
3065
  paramLabel: s,
321
3066
  zone: a.id
@@ -326,19 +3071,19 @@ function b(e, t, n) {
326
3071
  cells: i
327
3072
  };
328
3073
  }
329
- var x = {
3074
+ var q = {
330
3075
  hexValue: null,
331
3076
  numericValue: null,
332
3077
  values: null,
333
3078
  text: null
334
3079
  };
335
- function S(e) {
3080
+ function Bt(e) {
336
3081
  return /^[0-9A-F]{2}$/i.test(e) ? "hex" : /^[0-9A-F]{2}:[0-9A-F]{2}$/i.test(e) ? "hexPair" : /^[+-]?\d+([.,]\d+)?$/.test(e) ? "float" : /^[0-9A-F]{2}\S/i.test(e) ? "hexOption" : "text";
337
3082
  }
338
- function C(e, t) {
3083
+ function Vt(e, t) {
339
3084
  let n = e.trim();
340
- if (!n) return x;
341
- switch (t === "auto" ? S(n) : t) {
3085
+ if (!n) return q;
3086
+ switch (t === "auto" ? Bt(n) : t) {
342
3087
  case "hex": {
343
3088
  let e = /^([0-9A-F]{2})/i.exec(n), t = e ? parseInt(e[1], 16) : null;
344
3089
  return {
@@ -351,7 +3096,7 @@ function C(e, t) {
351
3096
  case "hexOption": {
352
3097
  let e = /^([0-9A-F]{2})\s?(.*)$/i.exec(n);
353
3098
  if (!e) return {
354
- ...x,
3099
+ ...q,
355
3100
  text: n
356
3101
  };
357
3102
  let t = parseInt(e[1], 16);
@@ -365,7 +3110,7 @@ function C(e, t) {
365
3110
  case "hexPair": {
366
3111
  let e = /^([0-9A-F]{2}):([0-9A-F]{2})/i.exec(n);
367
3112
  if (!e) return {
368
- ...x,
3113
+ ...q,
369
3114
  text: n
370
3115
  };
371
3116
  let t = [parseInt(e[1], 16), parseInt(e[2], 16)];
@@ -379,7 +3124,7 @@ function C(e, t) {
379
3124
  case "decimal": {
380
3125
  let e = parseInt(n, 10);
381
3126
  return Number.isNaN(e) ? {
382
- ...x,
3127
+ ...q,
383
3128
  text: n
384
3129
  } : {
385
3130
  hexValue: null,
@@ -391,7 +3136,7 @@ function C(e, t) {
391
3136
  case "decimalPair": {
392
3137
  let e = /^(\d+):(\d+)/.exec(n);
393
3138
  if (!e) return {
394
- ...x,
3139
+ ...q,
395
3140
  text: n
396
3141
  };
397
3142
  let t = [parseInt(e[1], 10), parseInt(e[2], 10)];
@@ -405,7 +3150,7 @@ function C(e, t) {
405
3150
  case "float": {
406
3151
  let e = parseFloat(n.replace(",", "."));
407
3152
  return Number.isNaN(e) ? {
408
- ...x,
3153
+ ...q,
409
3154
  text: n
410
3155
  } : {
411
3156
  hexValue: null,
@@ -415,12 +3160,12 @@ function C(e, t) {
415
3160
  };
416
3161
  }
417
3162
  default: return {
418
- ...x,
3163
+ ...q,
419
3164
  text: n
420
3165
  };
421
3166
  }
422
3167
  }
423
- function w(e, t) {
3168
+ function Ht(e, t) {
424
3169
  if (!e || !t) return null;
425
3170
  let n = t.toUpperCase().trim();
426
3171
  if (e[n]) return e[n];
@@ -429,28 +3174,28 @@ function w(e, t) {
429
3174
  }
430
3175
  //#endregion
431
3176
  //#region src/fxCommands.ts
432
- var T = r.fxCommands, E = r.instrumentFx.types, D = Object.entries(E).filter(([, e]) => e.verified).map(([e]) => e);
433
- function ee(e) {
434
- let t = D.filter((t) => E[t].commands.includes(e));
435
- return t.length === 0 || t.length === D.length ? null : t;
3177
+ var Ut = G.fxCommands, Wt = G.instrumentFx.types, Gt = Object.entries(Wt).filter(([, e]) => e.verified).map(([e]) => e);
3178
+ function Kt(e) {
3179
+ let t = Gt.filter((t) => Wt[t].commands.includes(e));
3180
+ return t.length === 0 || t.length === Gt.length ? null : t;
436
3181
  }
437
- function O(e) {
3182
+ function qt(e) {
438
3183
  let t = e.toUpperCase();
439
3184
  for (let e of [
440
3185
  "sequencer",
441
3186
  "instrument",
442
3187
  "mixer"
443
3188
  ]) {
444
- let n = T[e][t];
3189
+ let n = Ut[e][t];
445
3190
  if (n) return {
446
3191
  description: n.description,
447
3192
  category: e,
448
3193
  relative: n.relative === !0,
449
- instrumentTypes: e === "instrument" ? ee(t) : null,
3194
+ instrumentTypes: e === "instrument" ? Kt(t) : null,
450
3195
  slot: null
451
3196
  };
452
3197
  }
453
- let n = /^([A-Z]{2})([1-4])$/.exec(t), r = n ? T.modulation[n[1]] : void 0;
3198
+ let n = /^([A-Z]{2})([1-4])$/.exec(t), r = n ? Ut.modulation[n[1]] : void 0;
454
3199
  if (n && r) return {
455
3200
  description: r.description.replace("modulator N", `modulator ${n[2]}`),
456
3201
  category: "modulation",
@@ -459,25 +3204,25 @@ function O(e) {
459
3204
  slot: Number(n[2])
460
3205
  };
461
3206
  }
462
- function k(e) {
463
- return O(e)?.relative === !0;
3207
+ function J(e) {
3208
+ return qt(e)?.relative === !0;
464
3209
  }
465
- function te(e) {
466
- let t = E[e.toLowerCase()];
3210
+ function Jt(e) {
3211
+ let t = Wt[e.toLowerCase()];
467
3212
  return t ? {
468
3213
  type: e.toLowerCase(),
469
3214
  verified: t.verified,
470
3215
  commands: [...t.commands]
471
3216
  } : null;
472
3217
  }
473
- var ne = r.instrumentFx.relativeCommands.description, A = (e) => e.toString(16).toUpperCase().padStart(2, "0"), j = (e) => e > 127 ? e - 256 : e, M = (e) => `${e > 0 ? "+" : e < 0 ? "−" : "±"}${Math.abs(e)}`;
474
- function N(e, t) {
475
- return k(e) && t > 127 ? `${A(t)} (${j(t)})` : A(t);
3218
+ var Yt = G.instrumentFx.relativeCommands.description, Y = (e) => e.toString(16).toUpperCase().padStart(2, "0"), X = (e) => e > 127 ? e - 256 : e, Xt = (e) => `${e > 0 ? "+" : e < 0 ? "−" : "±"}${Math.abs(e)}`;
3219
+ function Zt(e, t) {
3220
+ return J(e) && t > 127 ? `${Y(t)} (${X(t)})` : Y(t);
476
3221
  }
477
- function re(e) {
478
- return e > 127 ? `−${A(256 - e)}` : `+${A(e)}`;
3222
+ function Qt(e) {
3223
+ return e > 127 ? `−${Y(256 - e)}` : `+${Y(e)}`;
479
3224
  }
480
- var ie = [
3225
+ var $t = [
481
3226
  "C-",
482
3227
  "C#",
483
3228
  "D-",
@@ -491,16 +3236,16 @@ var ie = [
491
3236
  "A#",
492
3237
  "B-"
493
3238
  ];
494
- function ae(e) {
3239
+ function en(e) {
495
3240
  let t = /^([A-G])([#-])(\d)$/.exec((e ?? "").trim().toUpperCase());
496
3241
  if (!t) return null;
497
- let n = ie.indexOf(`${t[1]}${t[2]}`);
3242
+ let n = $t.indexOf(`${t[1]}${t[2]}`);
498
3243
  return n < 0 ? null : Number(t[3]) * 12 + n;
499
3244
  }
500
- function P(e) {
501
- return `${ie[(e % 12 + 12) % 12]}${Math.floor(e / 12)}`;
3245
+ function tn(e) {
3246
+ return `${$t[(e % 12 + 12) % 12]}${Math.floor(e / 12)}`;
502
3247
  }
503
- var oe = [
3248
+ var nn = [
504
3249
  "C",
505
3250
  "C#",
506
3251
  "D",
@@ -514,12 +3259,12 @@ var oe = [
514
3259
  "A#",
515
3260
  "B"
516
3261
  ];
517
- function se(e, t, n = {}) {
3262
+ function rn(e, t, n = {}) {
518
3263
  let r = e.toUpperCase(), i = t >> 4, a = t & 15, o = (e) => `${e} tick${e === 1 ? "" : "s"}`;
519
3264
  switch (r) {
520
3265
  case "ARP": {
521
- let e = ae(n.note), t = `+${i} and +${a} semitones`;
522
- return e == null ? `plays the note, then ${t}` : `${t}: ${P(e)} ${P(e + i)} ${P(e + a)}`;
3266
+ let e = en(n.note), t = `+${i} and +${a} semitones`;
3267
+ return e == null ? `plays the note, then ${t}` : `${t}: ${tn(e)} ${tn(e + i)} ${tn(e + a)}`;
523
3268
  }
524
3269
  case "ARC": return `arp mode ${i}, speed ${o(a)}`;
525
3270
  case "CHA": return n.inTable ? `everything left of it plays with probability ${t}/255 (00 never, FF always)` : `${i}/15 chance for what is left of it, ${a}/15 for what is right (0 never, F always)`;
@@ -527,11 +3272,11 @@ function se(e, t, n = {}) {
527
3272
  case "KIL": return `stops the note after ${o(t)}`;
528
3273
  case "OFF": return `note off after ${o(t)}`;
529
3274
  case "PSL": return `portamento over ${o(t)}`;
530
- case "GRV": return `track uses groove ${A(t)}`;
531
- case "GGR": return `all tracks use groove ${A(t)}`;
532
- case "INS": return `switches to instrument ${A(t)}`;
533
- case "TBL": return `instrument uses table ${A(t)}`;
534
- case "TBX": return t === 0 ? "stops the auxiliary table" : `plays table ${A(t)} alongside the instrument table`;
3275
+ case "GRV": return `track uses groove ${Y(t)}`;
3276
+ case "GGR": return `all tracks use groove ${Y(t)}`;
3277
+ case "INS": return `switches to instrument ${Y(t)}`;
3278
+ case "TBL": return `instrument uses table ${Y(t)}`;
3279
+ case "TBX": return t === 0 ? "stops the auxiliary table" : `plays table ${Y(t)} alongside the instrument table`;
535
3280
  case "THO": return `table jumps to position ${a.toString(16).toUpperCase()}`;
536
3281
  case "HOP": return n.inTable ? `jumps to row ${a.toString(16).toUpperCase()}, ${i} time${i === 1 ? "" : "s"}` : t === 255 ? "stops this track" : `jumps to row ${a.toString(16).toUpperCase()} of the next phrase`;
537
3282
  case "RND": return `randomises the previous FX: left range ${i}, right range ${a} (0 none, F full)`;
@@ -542,18 +3287,18 @@ function se(e, t, n = {}) {
542
3287
  case "PBN": return t < 128 ? `pitch slides up by ${t}` : `pitch slides down by ${256 - t}`;
543
3288
  case "SCA":
544
3289
  case "SCG": {
545
- let e = oe[i];
3290
+ let e = nn[i];
546
3291
  return `${r === "SCA" ? "track" : "song"} scale ${a.toString(16).toUpperCase()}${e ? `, key ${e}` : ""}`;
547
3292
  }
548
- case "SNG": return `moves the song position by ${M(j(t))} row(s)`;
549
- case "SED": return `random seed ${A(t)}`;
550
- case "NXT": return `plays instrument ${A(t)} on the next track`;
3293
+ case "SNG": return `moves the song position by ${Xt(X(t))} row(s)`;
3294
+ case "SED": return `random seed ${Y(t)}`;
3295
+ case "NXT": return `plays instrument ${Y(t)} on the next track`;
551
3296
  case "MTT": {
552
- let e = j(t);
553
- return e === 0 ? "no timing shift" : `shifts the row by ${M(e)}/8 tick`;
3297
+ let e = X(t);
3298
+ return e === 0 ? "no timing shift" : `shifts the row by ${Xt(e)}/8 tick`;
554
3299
  }
555
3300
  case "TPO": return `${t} BPM`;
556
- case "TSP": return `transposes the song by ${M(j(t))} semitones`;
3301
+ case "TSP": return `transposes the song by ${Xt(X(t))} semitones`;
557
3302
  case "TIC": return t === 0 ? "table advances on each instrument trigger" : t <= 251 ? `table advances every ${o(t)}` : {
558
3303
  252: "octave map: playing octave picks the table row",
559
3304
  253: "velocity map",
@@ -561,33 +3306,32 @@ function se(e, t, n = {}) {
561
3306
  255: "table advances at 200 Hz"
562
3307
  }[t] ?? null;
563
3308
  case "XRZ": return t > 0 ? "reverb freeze on" : "reverb freeze off";
564
- default: break;
565
3309
  }
566
- if (k(r)) {
567
- let e = j(t);
568
- return r === "PIT" ? e === 0 ? "no change" : `${M(e)} semitones` : e === 0 ? "no change" : M(e);
3310
+ if (J(r)) {
3311
+ let e = X(t);
3312
+ return r === "PIT" ? e === 0 ? "no change" : `${Xt(e)} semitones` : e === 0 ? "no change" : Xt(e);
569
3313
  }
570
3314
  return null;
571
3315
  }
572
- function ce(e, t, n) {
3316
+ function an(e, t, n) {
573
3317
  let r = e + t & 255;
574
3318
  return n != null && (t < 128 ? r < e || r > n : r > e || r < n) && (r = n), {
575
3319
  value: r,
576
3320
  atLimit: n != null && r === n
577
3321
  };
578
3322
  }
579
- function le(e, t, n, r = !1) {
3323
+ function on(e, t, n, r = !1) {
580
3324
  let i = null, a = null, o = null, s = null, c = r, l = !1, u = null, d = "none", f = Math.min(n, e.length - 1);
581
3325
  for (let n = 0; n <= f; n += 1) {
582
3326
  let f = e[n].fields[`fx${t}cmd`], p = e[n].fields[`fx${t}val`];
583
3327
  if (d = "none", f && !f.isEmpty) {
584
3328
  let e = f.rawValue.toUpperCase(), t = p && !p.isEmpty ? p.hexValue : null;
585
- e === "REP" ? t ? !i && !r ? d = "orphan" : (d = c ? "repChange" : "rep", c || (u = n), c = !0, o = t, a != null && ({value: a, atLimit: l} = ce(a, o, s))) : (d = "repStop", c = !1, o = null, l = !1) : e === "RTO" ? (d = "rto", s = t) : (d = c ? "replace" : "set", i = {
3329
+ e === "REP" ? t ? !i && !r ? d = "orphan" : (d = c ? "repChange" : "rep", c || (u = n), c = !0, o = t, a != null && ({value: a, atLimit: l} = an(a, o, s))) : (d = "repStop", c = !1, o = null, l = !1) : e === "RTO" ? (d = "rto", s = t) : (d = c ? "replace" : "set", i = {
586
3330
  cmd: e,
587
3331
  value: t,
588
3332
  step: n
589
3333
  }, a = t, c = !1, o = null, s = null, l = !1, u = null);
590
- } else c && (d = "continue", a != null && o != null && ({value: a, atLimit: l} = ce(a, o, s)));
3334
+ } else c && (d = "continue", a != null && o != null && ({value: a, atLimit: l} = an(a, o, s)));
591
3335
  }
592
3336
  return {
593
3337
  lane: t,
@@ -603,20 +3347,20 @@ function le(e, t, n, r = !1) {
603
3347
  carried: c && !i
604
3348
  };
605
3349
  }
606
- function F(e) {
607
- let t = e.source, n = (e) => e == null ? "??" : t ? N(t.cmd, e) : A(e), r = e.increment == null ? "" : re(e.increment), i = e.atLimit && e.limit != null ? `, held at the RTO limit ${A(e.limit)}` : "";
3350
+ function sn(e) {
3351
+ let t = e.source, n = (e) => e == null ? "??" : t ? Zt(t.cmd, e) : Y(e), r = e.increment == null ? "" : Qt(e.increment), i = e.atLimit && e.limit != null ? `, held at the RTO limit ${Y(e.limit)}` : "";
608
3352
  switch (e.event) {
609
3353
  case "rep":
610
3354
  case "repChange": return e.carried ? `REP ${r} per step continues the repeat from the previous phrase` : `${e.event === "rep" ? "repeats" : "now repeats"} ${t?.cmd} from ${n(t?.value ?? null)} (step ${t?.step.toString(16).toUpperCase()}), ${r} per step → ${n(e.value)} on this step${i}`;
611
3355
  case "continue": return e.carried ? "REP from a previous phrase is still active in this lane (^^)" : `REP still active: ${t?.cmd} reaches ${n(e.value)} on this step (${r} per step since step ${e.repStartStep?.toString(16).toUpperCase()})${i}`;
612
3356
  case "repStop": return t ? `REP00 stops the repeat of ${t.cmd}` : "REP00 stops the repeat";
613
3357
  case "orphan": return "REP has no earlier command in this lane of the phrase to repeat";
614
- case "rto": return e.active && e.limit != null ? `sets the value the running REP stops at (${A(e.limit)})` : "sets the stop value for a REP";
3358
+ case "rto": return e.active && e.limit != null ? `sets the value the running REP stops at (${Y(e.limit)})` : "sets the stop value for a REP";
615
3359
  case "replace": return t ? `replaces the running REP (${t.cmd} is no longer repeated)` : null;
616
3360
  default: return null;
617
3361
  }
618
3362
  }
619
- function I(e) {
3363
+ function cn(e) {
620
3364
  let t = e.fields.inst;
621
3365
  return t && !t.isEmpty ? "instrument" : [
622
3366
  1,
@@ -627,10 +3371,10 @@ function I(e) {
627
3371
  return n != null && !n.isEmpty && n.rawValue.toUpperCase() === "RET";
628
3372
  }) ? "ret" : null;
629
3373
  }
630
- function L(e, t, n = null) {
3374
+ function ln(e, t, n = null) {
631
3375
  let r = {}, i = null, a = null, o = Math.min(t, e.length - 1);
632
3376
  for (let t = 0; t <= o; t += 1) {
633
- let o = I(e[t]);
3377
+ let o = cn(e[t]);
634
3378
  if (o) {
635
3379
  for (let e of Object.keys(r)) delete r[e];
636
3380
  i = t, a = o;
@@ -640,42 +3384,42 @@ function L(e, t, n = null) {
640
3384
  2,
641
3385
  3
642
3386
  ]) {
643
- let s = le(e, o, t, n === o), c = s.source;
644
- if (!c || s.carried || !k(c.cmd)) continue;
3387
+ let s = on(e, o, t, n === o), c = s.source;
3388
+ if (!c || s.carried || !J(c.cmd)) continue;
645
3389
  let l = null, u = !1;
646
3390
  if (s.event === "set" || s.event === "replace" ? l = c.value : (s.event === "rep" || s.event === "repChange" || s.event === "continue") && (l = s.value, u = !0), l == null) continue;
647
- let d = r[c.cmd] ??= {
3391
+ let d = r[c.cmd];
3392
+ d || (d = {
648
3393
  cmd: c.cmd,
649
3394
  total: 0,
650
3395
  count: 0,
651
3396
  resetStep: i,
652
3397
  resetBy: a,
653
3398
  viaRep: !1
654
- };
655
- d.total += j(l), d.count += 1, d.viaRep ||= u;
3399
+ }, r[c.cmd] = d), d.total += X(l), d.count += 1, d.viaRep ||= u;
656
3400
  }
657
3401
  }
658
3402
  return r;
659
3403
  }
660
- var R = (e) => e === 0 ? "±00" : `${e > 0 ? "+" : "−"}${A(Math.abs(e))}`;
661
- function ue(e) {
3404
+ var un = (e) => e === 0 ? "±00" : `${e > 0 ? "+" : "−"}${Y(Math.abs(e))}`;
3405
+ function dn(e) {
662
3406
  if (e.resetStep == null) return "the start of this phrase (earlier state unknown)";
663
3407
  let t = e.resetStep.toString(16).toUpperCase();
664
3408
  return e.resetBy === "ret" ? `the RET on step ${t}` : `the instrument number on step ${t}`;
665
3409
  }
666
- var z = "stays until a note with an instrument number (I) or a RET resets it";
667
- function B(e) {
668
- if (!e || e.count <= 1) return `relative: ${z}`;
669
- let t = e.viaRep ? ", including REP repeats" : "", n = e.total === 0 ? "has had no net effect" : `has moved by ${R(e.total)}`;
670
- return `relative: ${e.cmd} ${n} over ${e.count} steps since ${ue(e)}${t}; ${z}`;
3410
+ var fn = "stays until a note with an instrument number (I) or a RET resets it";
3411
+ function pn(e) {
3412
+ if (!e || e.count <= 1) return `relative: ${fn}`;
3413
+ let t = e.viaRep ? ", including REP repeats" : "", n = e.total === 0 ? "has had no net effect" : `has moved by ${un(e.total)}`;
3414
+ return `relative: ${e.cmd} ${n} over ${e.count} steps since ${dn(e)}${t}; ${fn}`;
671
3415
  }
672
- function V(e) {
3416
+ function mn(e) {
673
3417
  let t = Object.values(e).filter((e) => e.total !== 0);
674
- return t.length ? `triggers the instrument again: resets the relative changes still in force (${t.map((e) => `${e.cmd} ${R(e.total)}`).join(", ")})` : null;
3418
+ return t.length ? `triggers the instrument again: resets the relative changes still in force (${t.map((e) => `${e.cmd} ${un(e.total)}`).join(", ")})` : null;
675
3419
  }
676
3420
  //#endregion
677
3421
  //#region src/scaleInsight.ts
678
- var H = [
3422
+ var Z = [
679
3423
  "C",
680
3424
  "C#",
681
3425
  "D",
@@ -688,7 +3432,7 @@ var H = [
688
3432
  "A",
689
3433
  "A#",
690
3434
  "B"
691
- ], de = [
3435
+ ], hn = [
692
3436
  {
693
3437
  name: "Major (Ionian)",
694
3438
  steps: [
@@ -906,7 +3650,7 @@ var H = [
906
3650
  11
907
3651
  ]
908
3652
  }
909
- ], fe = [
3653
+ ], gn = [
910
3654
  "the root",
911
3655
  "a minor 2nd",
912
3656
  "a major 2nd",
@@ -920,26 +3664,26 @@ var H = [
920
3664
  "a minor 7th",
921
3665
  "a major 7th"
922
3666
  ];
923
- function U(e) {
3667
+ function _n(e) {
924
3668
  let t = e.replace(/[-\s]/g, "").toUpperCase();
925
- return H.includes(t) ? t : null;
3669
+ return Z.includes(t) ? t : null;
926
3670
  }
927
- function pe(e) {
928
- let t = H.indexOf(e);
929
- return t <= 0 ? t === 0 ? "the first row (the scale root)" : e : `${fe[t]} (+${t} semitones above C)`;
3671
+ function vn(e) {
3672
+ let t = Z.indexOf(e);
3673
+ return t <= 0 ? t === 0 ? "the first row (the scale root)" : e : `${gn[t]} (+${t} semitones above C)`;
930
3674
  }
931
- function me(e) {
3675
+ function yn(e) {
932
3676
  let t = new Set(e);
933
3677
  if (t.size === 0) return [];
934
3678
  let n = [];
935
- for (let e of de) if (e.steps.length === t.size) for (let r = 0; r < 12; r += 1) e.steps.every((e) => t.has((e + r) % 12)) && n.push({
3679
+ for (let e of hn) if (e.steps.length === t.size) for (let r = 0; r < 12; r += 1) e.steps.every((e) => t.has((e + r) % 12)) && n.push({
936
3680
  root: r,
937
3681
  name: e.name
938
3682
  });
939
- return n.sort((e, t) => e.root - t.root), n.map((e) => e.root === 0 ? e.name : `${e.name} from ${H[e.root]}`);
3683
+ return n.sort((e, t) => e.root - t.root), n.map((e) => e.root === 0 ? e.name : `${e.name} from ${Z[e.root]}`);
940
3684
  }
941
- function he(e) {
942
- let t = e.filter((e) => e.enabled === !0), n = t.map((e) => e.interval), r = me(t.map((e) => e.semitone)), i = e.filter((e) => e.enabled === !0 && e.offset != null && e.offset !== 0).map((e) => ({
3685
+ function bn(e) {
3686
+ let t = e.filter((e) => e.enabled === !0), n = t.map((e) => e.interval), r = yn(t.map((e) => e.semitone)), i = e.filter((e) => e.enabled === !0 && e.offset != null && e.offset !== 0).map((e) => ({
943
3687
  interval: e.interval,
944
3688
  offset: e.offset
945
3689
  }));
@@ -948,55 +3692,60 @@ function he(e) {
948
3692
  enabled: n,
949
3693
  shapes: r,
950
3694
  detuned: i,
951
- summary: W({
3695
+ summary: xn({
952
3696
  enabled: n,
953
3697
  shapes: r,
954
3698
  detuned: i
955
3699
  }).join(" — ")
956
3700
  };
957
3701
  }
958
- function W(e) {
3702
+ function xn(e) {
959
3703
  let { enabled: t, shapes: n, detuned: r } = e;
960
3704
  if (!t.length) return ["no notes enabled"];
961
3705
  let i = n[0] ?? `${t.length} notes, custom scale`;
962
- return r.length && (i += `; detuned: ${r.map((e) => `${e.interval} ${G(e.offset)}`).join(", ")}`), [t.join(" "), i];
3706
+ return r.length && (i += `; detuned: ${r.map((e) => `${e.interval} ${Sn(e.offset)}`).join(", ")}`), [t.join(" "), i];
963
3707
  }
964
- function G(e) {
3708
+ function Sn(e) {
965
3709
  return `${e > 0 ? "+" : e < 0 ? "−" : ""}${Math.abs(e).toFixed(2)} st`;
966
3710
  }
967
3711
  //#endregion
968
3712
  //#region src/viewContext.ts
969
- var ge = new Set([
3713
+ var Cn = /* @__PURE__ */ new Set([
970
3714
  "--",
971
3715
  "---",
972
3716
  "---00",
973
3717
  "----",
974
3718
  "-"
975
3719
  ]);
976
- function K(e) {
977
- return e ? ge.has(e) || /^-+$/.test(e) : !0;
3720
+ function wn(e) {
3721
+ return !e || Cn.has(e) || /^-+$/.test(e);
978
3722
  }
979
- function _e(e) {
3723
+ function Tn(e) {
980
3724
  let t = e.trim();
981
- if (!t || K(t)) return null;
3725
+ if (!t || wn(t)) return null;
982
3726
  let n = parseInt(t, 16);
983
3727
  return Number.isNaN(n) ? null : n;
984
3728
  }
985
- function ve(e, t, n) {
3729
+ function En(e, t, n) {
986
3730
  return t >= e.length ? "" : e.slice(t, Math.min(t + n, e.length));
987
3731
  }
988
- function ye(e) {
3732
+ function Dn(e) {
3733
+ return On(e);
3734
+ }
3735
+ function On(e) {
989
3736
  if (!e) return {
990
3737
  viewId: null,
991
- isUnsaved: !1
3738
+ isUnsaved: !1,
3739
+ marker: null
992
3740
  };
993
- let t = e.replace(/[{}]/g, "0").trim(), n = t.endsWith("*"), r = (n ? t.slice(0, -1).trimEnd() : t).split(/\s+/), i = r[r.length - 1] ?? "";
3741
+ let t = e.replace(/[{}]/g, "0").trim(), n = /\s*([*^])$/.exec(t), r = n?.[1] ?? null, i = (n ? t.slice(0, n.index) : t).split(/\s+/), a = i[i.length - 1] ?? "";
994
3742
  return {
995
- viewId: /^[0-9A-Fa-f]{1,2}$/.test(i) ? i.toUpperCase() : null,
996
- isUnsaved: n
3743
+ viewId: /^[0-9A-Fa-f]{1,2}$/.test(a) ? a.toUpperCase() : null,
3744
+ isUnsaved: r === "*",
3745
+ marker: r
997
3746
  };
998
3747
  }
999
- function be(e) {
3748
+ function kn(e) {
1000
3749
  return e.length > 0 && /^[^a-zA-Z0-9 ]/.test(e[0]) ? {
1001
3750
  line: e.slice(1),
1002
3751
  offset: 1
@@ -1005,12 +3754,12 @@ function be(e) {
1005
3754
  offset: 0
1006
3755
  };
1007
3756
  }
1008
- function xe(e, t) {
1009
- let n = ve(t, e.x, e.width).trim();
3757
+ function An(e, t) {
3758
+ let n = En(t, e.x, e.width).trim();
1010
3759
  n.includes("^") && (e.type === "fxCommand" || e.type === "fxValue") && (n = "");
1011
- let r = K(n);
3760
+ let r = wn(n);
1012
3761
  if (e.format) {
1013
- let t = r ? null : C(n, e.format), i = e.type === "name" || e.type === "fileEntry", a = t?.text != null && !i ? t.text.toUpperCase() : t?.text ?? null;
3762
+ let t = r ? null : Vt(n, e.format), i = e.type === "name" || e.type === "fileEntry", a = t?.text != null && !i ? t.text.toUpperCase() : t?.text ?? null;
1014
3763
  return {
1015
3764
  key: e.key,
1016
3765
  label: e.label,
@@ -1025,8 +3774,8 @@ function xe(e, t) {
1025
3774
  values: t?.values ?? null,
1026
3775
  parts: e.parts,
1027
3776
  unit: e.unit,
1028
- valueDescription: !r && w(e.options, a ?? n) || void 0,
1029
- fileKind: e.type === "fileEntry" ? Se(n) : void 0
3777
+ valueDescription: !r && Ht(e.options, a ?? n) || void 0,
3778
+ fileKind: e.type === "fileEntry" ? jn(n) : void 0
1030
3779
  };
1031
3780
  }
1032
3781
  let i = [
@@ -1042,10 +3791,12 @@ function xe(e, t) {
1042
3791
  "eqSlot",
1043
3792
  "rowIndex"
1044
3793
  ], a = ["ppq"], o = null;
1045
- if (!r && i.includes(e.type)) if (a.includes(e.type)) {
1046
- let e = parseInt(n, 10);
1047
- o = Number.isNaN(e) ? null : e;
1048
- } else o = _e(n);
3794
+ if (!r && i.includes(e.type)) {
3795
+ if (a.includes(e.type)) {
3796
+ let e = parseInt(n, 10);
3797
+ o = Number.isNaN(e) ? null : e;
3798
+ } else o = Tn(n);
3799
+ }
1049
3800
  return {
1050
3801
  key: e.key,
1051
3802
  label: e.label,
@@ -1056,20 +3807,20 @@ function xe(e, t) {
1056
3807
  meta: e.meta
1057
3808
  };
1058
3809
  }
1059
- function Se(e) {
3810
+ function jn(e) {
1060
3811
  if (e === "/..") return "parent";
1061
3812
  if (e.startsWith("/")) return "directory";
1062
3813
  let t = /\.([a-z0-9]+)$/i.exec(e)?.[1]?.toLowerCase();
1063
3814
  return t === "m8i" ? "instrumentPreset" : t === "wav" ? "sample" : t?.startsWith("m8") ? "m8file" : "file";
1064
3815
  }
1065
- function Ce(e, t) {
1066
- let n = ve(e, t.x, t.width).trim();
3816
+ function Mn(e, t) {
3817
+ let n = En(e, t.x, t.width).trim();
1067
3818
  if (!n) return null;
1068
- if (t.parse === "hex") return _e(n);
3819
+ if (t.parse === "hex") return Tn(n);
1069
3820
  let r = parseInt(n, 10);
1070
3821
  return Number.isNaN(r) ? null : r;
1071
3822
  }
1072
- function we(e, t) {
3823
+ function Nn(e, t) {
1073
3824
  for (let n of e) if (t >= n.x && t < n.x + n.width) return n;
1074
3825
  let n = null, r = 2;
1075
3826
  for (let i of e) {
@@ -1078,9 +3829,9 @@ function we(e, t) {
1078
3829
  }
1079
3830
  return n;
1080
3831
  }
1081
- function q(e, t) {
3832
+ function Pn(e, t) {
1082
3833
  let n = {};
1083
- for (let r of e.columns ?? []) n[r.key] = xe(r, t);
3834
+ for (let r of e.columns ?? []) n[r.key] = An(r, t);
1084
3835
  for (let e of Object.keys(n)) {
1085
3836
  let t = /^fx(\d)cmd$/.exec(e)?.[1], r = t ? n[`fx${t}val`] : void 0;
1086
3837
  r && n[e].isEmpty && (n[`fx${t}val`] = {
@@ -1089,38 +3840,71 @@ function q(e, t) {
1089
3840
  });
1090
3841
  }
1091
3842
  return {
1092
- rowIndex: e.rowField ? Ce(t, e.rowField) : null,
3843
+ rowIndex: e.rowField ? Mn(t, e.rowField) : null,
1093
3844
  rowKey: e.rowField?.key ?? "row",
1094
3845
  rowId: null,
1095
3846
  fields: n
1096
3847
  };
1097
3848
  }
1098
- var Te = (e) => e.replace(/\s+/g, ""), J = (e) => e.slice(1);
1099
- function Ee(e, t) {
3849
+ var Fn = (e) => e.replace(/\s+/g, ""), In = 1, Q = (e) => e.slice(1);
3850
+ function Ln(e, t) {
1100
3851
  if (!t || !e.cursorPos || !e.currentLine) return !1;
1101
3852
  let n = t.lines[e.cursorPos.y];
1102
- return n != null && Te(n) === Te(e.currentLine);
3853
+ return n != null && Fn(n) === Fn(e.currentLine);
3854
+ }
3855
+ var Rn = 16, zn = 4, Bn = 21;
3856
+ function Vn(e, t) {
3857
+ let n = G.views[e];
3858
+ if (n?.type !== "grid" || !n.rowField) return [];
3859
+ let r = [], i = Math.min(Bn, t.lines.length - 1);
3860
+ for (let e = zn; e <= i; e += 1) {
3861
+ let i = Q(t.lines[e] ?? ""), a = n.rowField;
3862
+ if (i.length <= a.x + a.width || !Hn(i[a.x + a.width])) continue;
3863
+ let o = Pn(n, i);
3864
+ o.rowIndex != null && r.push({
3865
+ ...o,
3866
+ screenRow: e
3867
+ });
3868
+ }
3869
+ return r;
3870
+ }
3871
+ var Hn = (e) => e === " " || /^[^a-zA-Z0-9-]$/.test(e);
3872
+ function Un(e, t) {
3873
+ let n = G.views[e];
3874
+ if (n?.type !== "grid") return null;
3875
+ let r = Vn(e, t), i = (e) => !!e && e !== " " && Hn(e);
3876
+ if (e === "song") return {
3877
+ tracks: (n.columns ?? []).filter((e) => e.type === "chainRef").map((e) => r.find((n) => i(Q(t.lines[n.screenRow] ?? "")[e.x - 1]))?.rowIndex ?? null),
3878
+ row: null
3879
+ };
3880
+ let a = n.rowField;
3881
+ return a ? {
3882
+ tracks: null,
3883
+ row: r.find((e) => i(Q(t.lines[e.screenRow] ?? "")[a.x + a.width]))?.rowIndex ?? null
3884
+ } : {
3885
+ tracks: null,
3886
+ row: null
3887
+ };
1103
3888
  }
1104
- var De = 16;
1105
- function Oe(e, t, n, r) {
3889
+ function Wn(e, t, n, r) {
1106
3890
  let i = (t.cursorPos?.y ?? -1) - r;
1107
3891
  if (i < 0) return null;
1108
3892
  let a = [], o = null;
1109
- for (let t = 0; t < De; t += 1) {
3893
+ for (let t = 0; t < Rn; t += 1) {
1110
3894
  let r = n.lines[i + t];
1111
3895
  if (r == null) return null;
1112
- let s = J(r), c = q(e, s);
3896
+ let s = Q(r), c = Pn(e, s);
1113
3897
  if (c.rowIndex !== t) return null;
1114
3898
  a.push(c);
1115
3899
  let l = s.indexOf("^^");
1116
- o == null && l >= 0 && (o = ke(e, l));
3900
+ o == null && l >= 0 && (o = Gn(e, l));
1117
3901
  }
1118
3902
  return {
1119
3903
  steps: a,
1120
3904
  carriedRepLane: o
1121
3905
  };
1122
3906
  }
1123
- function ke(e, t) {
3907
+ function Gn(e, t) {
1124
3908
  let n = [];
1125
3909
  for (let r = 1; r <= 3; r += 1) {
1126
3910
  let i = e.columns?.find((e) => e.key === `fx${r}cmd`), a = e.columns?.find((e) => e.key === `fx${r}val`);
@@ -1134,26 +3918,26 @@ function ke(e, t) {
1134
3918
  let r = Math.min(...n.map((e) => e.dist)), i = n.filter((e) => e.dist === r);
1135
3919
  return r <= 1 && i.length === 1 ? i[0].lane : null;
1136
3920
  }
1137
- function Ae(e) {
1138
- let t = U(e.fields.interval?.rawValue ?? "");
3921
+ function Kn(e) {
3922
+ let t = _n(e.fields.interval?.rawValue ?? "");
1139
3923
  if (!t) return null;
1140
3924
  let n = e.fields.en?.rawValue.toUpperCase(), r = parseFloat(e.fields.offset?.rawValue ?? "");
1141
3925
  return {
1142
3926
  interval: t,
1143
- semitone: H.indexOf(t),
1144
- enabled: n === "ON" ? !0 : n === "OFF" ? !1 : null,
3927
+ semitone: Z.indexOf(t),
3928
+ enabled: n === "ON" ? !0 : n === "OFF" || n === "--" ? !1 : null,
1145
3929
  offset: Number.isNaN(r) ? null : r
1146
3930
  };
1147
3931
  }
1148
- function je(e, t) {
3932
+ function qn(e, t) {
1149
3933
  let n = /* @__PURE__ */ new Map();
1150
3934
  for (let r of t.lines) {
1151
- let t = q(e, J(r)), i = Ae(t), a = t.fields.en?.rawValue.toUpperCase();
3935
+ let t = Pn(e, Q(r)), i = Kn(t), a = t.fields.en?.rawValue.toUpperCase();
1152
3936
  !i || a !== "ON" && a !== "OFF" && a !== "--" || n.has(i.interval) || n.set(i.interval, i);
1153
3937
  }
1154
- return n.size === H.length ? H.map((e) => n.get(e)) : null;
3938
+ return n.size === Z.length ? Z.map((e) => n.get(e)) : null;
1155
3939
  }
1156
- function Me(e, t, n, r) {
3940
+ function Jn(e, t, n, r) {
1157
3941
  let i = {
1158
3942
  ...r,
1159
3943
  isGridView: !1,
@@ -1170,59 +3954,59 @@ function Me(e, t, n, r) {
1170
3954
  resetsRelative: null,
1171
3955
  scaleNote: null,
1172
3956
  scale: null
1173
- }, a = e.cursorPos, o = a ? a.x - 1 : 0, s = a && Ee(e, t) ? t : null, c = s && a ? J(s.lines[a.y] ?? "") : e.currentLine ?? "";
3957
+ }, a = e.cursorPos, o = a ? a.x - 1 : 0, s = a && Ln(e, t) ? t : null, c = s && a ? Q(s.lines[a.y] ?? "") : e.currentLine ?? "";
1174
3958
  if (!c.trim()) return i;
1175
- let l = s && a ? s.lines.slice(0, a.y + 1).reverse().map(J) : [c], u = r.viewName === "inst" ? h(s ? s.lines.map(J) : [c]) : null, d = {
3959
+ let l = s && a ? s.lines.slice(0, a.y + 1).reverse().map(Q) : [c], u = r.viewName === "inst" ? Pt(s ? s.lines.map(Q) : [c]) : null, d = {
1176
3960
  instrumentKey: u?.key ?? null,
1177
3961
  entryText: e.textUnderCursor
1178
3962
  };
1179
3963
  if (!s && a && n.kind == null) for (let e = 0; e <= Math.min(o, 24); e += 1) {
1180
3964
  let t = " ".repeat(e) + c;
1181
- if (b(n, t, {
3965
+ if (zt(n, t, {
1182
3966
  ...d,
1183
- section: f(n, [t])
3967
+ section: jt(n, [t])
1184
3968
  }).cells.some((e) => o >= e.x && o < e.x + e.width)) {
1185
3969
  c = t;
1186
3970
  break;
1187
3971
  }
1188
3972
  }
1189
- let m = f(n, s ? l : [c]), { rowId: g, cells: _ } = b(n, c, {
3973
+ let f = jt(n, s ? l : [c]), { rowId: p, cells: m } = zt(n, c, {
1190
3974
  ...d,
1191
- section: m
1192
- }), v = {};
1193
- for (let e of _) v[e.key] = xe(e, c);
1194
- let y = {
3975
+ section: f
3976
+ }), h = {};
3977
+ for (let e of m) h[e.key] = An(e, c);
3978
+ let g = {
1195
3979
  rowIndex: null,
1196
3980
  rowKey: "param",
1197
- rowId: g,
1198
- fields: v
1199
- }, x = null, S = a ? we(_, o) : null;
1200
- S && (x = {
1201
- ...v[S.key],
3981
+ rowId: p,
3982
+ fields: h
3983
+ }, _ = null, v = a ? Nn(m, o) : null;
3984
+ v && (_ = {
3985
+ ...h[v.key],
1202
3986
  viewName: r.viewName,
1203
3987
  rowIndex: null
1204
3988
  });
1205
- let C = S?.meta?.zone;
1206
- return s && typeof C == "string" && (m = p(n, C, l) ?? m), {
3989
+ let y = v?.meta?.zone;
3990
+ return s && typeof y == "string" && (f = Mt(n, y, l) ?? f), {
1207
3991
  ...i,
1208
- section: m,
3992
+ section: f,
1209
3993
  instrumentType: u,
1210
- row: y,
1211
- activeField: x,
3994
+ row: g,
3995
+ activeField: _,
1212
3996
  lineText: c.trim()
1213
3997
  };
1214
3998
  }
1215
- function Y(e, t) {
3999
+ function Yn(e, t) {
1216
4000
  let n = e.viewName;
1217
4001
  if (!n) return null;
1218
- let i = r.views[n] ?? null, a = i?.type === "grid", o = i?.title ?? null, s = i?.description ?? null, { viewId: c, isUnsaved: u } = ye(e.viewTitle), d = {
4002
+ let r = G.views[n] ?? null, i = r?.type === "grid", a = r?.title ?? null, o = r?.description ?? null, { viewId: s, isUnsaved: c } = On(e.viewTitle), l = {
1219
4003
  viewName: n,
1220
- viewTitle: o,
1221
- viewDescription: s,
1222
- viewId: c,
1223
- isUnsaved: u
1224
- }, f = {
1225
- ...d,
4004
+ viewTitle: a,
4005
+ viewDescription: o,
4006
+ viewId: s,
4007
+ isUnsaved: c
4008
+ }, u = {
4009
+ ...l,
1226
4010
  isParameterView: !1,
1227
4011
  section: null,
1228
4012
  instrumentType: null,
@@ -1234,84 +4018,84 @@ function Y(e, t) {
1234
4018
  resetsRelative: null,
1235
4019
  scaleNote: null,
1236
4020
  scale: null
1237
- }, p = i?.type === "parameter" ? l(n) : null;
1238
- if (p) return Me(e, t, p, d);
1239
- if (!a || !i) return {
1240
- ...f,
4021
+ }, d = r?.type === "parameter" ? kt(n) : null;
4022
+ if (d) return Jn(e, t, d, l);
4023
+ if (!i || !r) return {
4024
+ ...u,
1241
4025
  isGridView: !1,
1242
4026
  row: null,
1243
4027
  activeField: null
1244
4028
  };
1245
- let m = e.currentLine;
1246
- if (!m) return {
1247
- ...f,
4029
+ let f = e.currentLine;
4030
+ if (!f) return {
4031
+ ...u,
1248
4032
  isGridView: !0,
1249
4033
  row: null,
1250
4034
  activeField: null
1251
4035
  };
1252
- let { line: h } = be(m), g = e.cursorPos ? e.cursorPos.x - 1 : 0, _ = q(i, h), v = n === "scale" && !U(_.fields.interval?.rawValue ?? "") ? l(n) : null;
1253
- if (v) return Me(e, t, v, d);
1254
- let y = null;
4036
+ let { line: p } = kn(f), m = e.cursorPos ? e.cursorPos.x - 1 : 0, h = Pn(r, p), g = n === "scale" && !_n(h.fields.interval?.rawValue ?? "") ? kt(n) : null;
4037
+ if (g) return Jn(e, t, g, l);
4038
+ let _ = null;
1255
4039
  if (e.cursorPos) {
1256
- let e = we(i.columns ?? [], g);
4040
+ let e = Nn(r.columns ?? [], m);
1257
4041
  if (e) {
1258
- let t = _.fields[e.key];
1259
- t && (y = {
4042
+ let t = h.fields[e.key];
4043
+ t && (_ = {
1260
4044
  ...t,
1261
4045
  viewName: n,
1262
- rowIndex: _.rowIndex
4046
+ rowIndex: h.rowIndex
1263
4047
  });
1264
4048
  }
1265
4049
  }
1266
- let b = null, x = null, S = null, C = null, w = null, T = null;
1267
- if (Ee(e, t)) {
1268
- if (n === "phrase" && _.rowIndex != null) {
1269
- let n = Oe(i, e, t, _.rowIndex);
4050
+ let v = null, y = null, b = null, x = null, S = null, C = null;
4051
+ if (Ln(e, t)) {
4052
+ if (n === "phrase" && h.rowIndex != null) {
4053
+ let n = Wn(r, e, t, h.rowIndex);
1270
4054
  if (n) {
1271
- b = n.steps, x = n.carriedRepLane;
1272
- let e = y ? /^fx(\d)(cmd|val)$/.exec(y.key)?.[1] : void 0;
1273
- e && (S = le(b, Number(e), _.rowIndex, x === Number(e))), C = L(b, _.rowIndex, x), _.rowIndex > 0 && I(_) && (w = L(b, _.rowIndex - 1, x));
4055
+ v = n.steps, y = n.carriedRepLane;
4056
+ let e = _ ? /^fx(\d)(cmd|val)$/.exec(_.key)?.[1] : void 0;
4057
+ e && (b = on(v, Number(e), h.rowIndex, y === Number(e))), x = ln(v, h.rowIndex, y), h.rowIndex > 0 && cn(h) && (S = ln(v, h.rowIndex - 1, y));
1274
4058
  }
1275
4059
  } else if (n === "scale") {
1276
- let e = je(i, t);
1277
- e && (T = he(e));
4060
+ let e = qn(r, t);
4061
+ e && (C = bn(e));
1278
4062
  }
1279
4063
  }
1280
- let E = n === "scale" ? Ae(_) : null;
4064
+ let w = n === "scale" ? Kn(h) : null;
1281
4065
  return {
1282
- ...f,
4066
+ ...u,
1283
4067
  isGridView: !0,
1284
- row: _,
1285
- activeField: y,
1286
- lineText: h.trim() || null,
1287
- steps: b,
1288
- carriedRepLane: x,
1289
- fxLane: S,
1290
- relativeFx: C,
1291
- resetsRelative: w,
1292
- scaleNote: E,
1293
- scale: T
1294
- };
1295
- }
1296
- function X(e) {
1297
- if (e.isParameterView) return ze(e);
4068
+ row: h,
4069
+ activeField: _,
4070
+ lineText: p.trim() || null,
4071
+ steps: v,
4072
+ carriedRepLane: y,
4073
+ fxLane: b,
4074
+ relativeFx: x,
4075
+ resetsRelative: S,
4076
+ scaleNote: w,
4077
+ scale: C
4078
+ };
4079
+ }
4080
+ function Xn(e) {
4081
+ if (e.isParameterView) return ir(e);
1298
4082
  if (e.viewName === "scale") {
1299
- let t = Be(e);
4083
+ let t = ar(e);
1300
4084
  if (t) return t;
1301
4085
  }
1302
- if (!e.activeField) return Q(["location", e.viewTitle ?? e.viewName]);
1303
- let { activeField: t, row: n } = e, r = Q(["field", `${t.label}: ${$(t)}`]), i = (t.type === "fxCommand" || t.type === "fxValue") && n ? Ne(e, t, n) : Ie(e, t), a = i.length > 0;
4086
+ if (!e.activeField) return $(["location", e.viewTitle ?? e.viewName]);
4087
+ let { activeField: t, row: n } = e, r = $(["field", `${t.label}: ${sr(t)}`]), i = (t.type === "fxCommand" || t.type === "fxValue") && n ? Qn(e, t, n) : tr(e, t), a = i.length > 0;
1304
4088
  if (t.type === "fxCommand" && !t.isEmpty) {
1305
- let e = a && /^(REP|RTO)$/i.test(t.rawValue) ? void 0 : O(t.rawValue);
4089
+ let e = a && /^(REP|RTO)$/i.test(t.rawValue) ? void 0 : qt(t.rawValue);
1306
4090
  e && r.push({
1307
4091
  kind: "fxInfo",
1308
- text: `(${Pe(e)})`
4092
+ text: `(${$n(e)})`
1309
4093
  });
1310
4094
  }
1311
4095
  if (t.type === "fxValue" && n) {
1312
4096
  let e = t.key.replace("val", "cmd"), i = n.fields[e];
1313
4097
  if (i && !i.isEmpty) {
1314
- let e = a && /^(REP|RTO)$/i.test(i.rawValue) ? void 0 : O(i.rawValue), t = e ? `${i.rawValue} (${Pe(e)})` : i.rawValue;
4098
+ let e = a && /^(REP|RTO)$/i.test(i.rawValue) ? void 0 : qt(i.rawValue), t = e ? `${i.rawValue} (${$n(e)})` : i.rawValue;
1315
4099
  r.push({
1316
4100
  kind: "fxTarget",
1317
4101
  text: `for ${t}`
@@ -1330,41 +4114,41 @@ function X(e) {
1330
4114
  }
1331
4115
  return r;
1332
4116
  }
1333
- function Z(e) {
1334
- return X(e).map((e) => e.text).join(" — ");
4117
+ function Zn(e) {
4118
+ return Xn(e).map((e) => e.text).join(" — ");
1335
4119
  }
1336
- function Q(...e) {
4120
+ function $(...e) {
1337
4121
  return e.flatMap(([e, t]) => t ? [{
1338
4122
  kind: e,
1339
4123
  text: t
1340
4124
  }] : []);
1341
4125
  }
1342
- function Ne(e, t, n) {
4126
+ function Qn(e, t, n) {
1343
4127
  let r = /^fx(\d)/.exec(t.key)?.[1];
1344
4128
  if (!r) return [];
1345
4129
  let i = n.fields[`fx${r}cmd`], a = n.fields[`fx${r}val`];
1346
4130
  if (!i || i.isEmpty) {
1347
4131
  if (e.fxLane?.event !== "continue") return [];
1348
- let t = e.fxLane.source?.cmd, n = t && k(t) ? B(e.relativeFx?.[t]) : null;
1349
- return Q(["fxLane", F(e.fxLane)], ["relative", n]);
4132
+ let t = e.fxLane.source?.cmd, n = t && J(t) ? pn(e.relativeFx?.[t]) : null;
4133
+ return $(["fxLane", sn(e.fxLane)], ["relative", n]);
1350
4134
  }
1351
- let o = i.rawValue.toUpperCase(), s = e.fxLane && e.fxLane.event !== "none" && e.fxLane.event !== "set" ? F(e.fxLane) : null;
4135
+ let o = i.rawValue.toUpperCase(), s = e.fxLane && e.fxLane.event !== "none" && e.fxLane.event !== "set" ? sn(e.fxLane) : null;
1352
4136
  if (o === "REP" || o === "RTO") {
1353
- let t = e.fxLane?.source?.cmd, n = o === "REP" && e.fxLane?.active && t && k(t) ? B(e.relativeFx?.[t]) : null;
1354
- return Q(["fxLane", s], ["relative", n]);
4137
+ let t = e.fxLane?.source?.cmd, n = o === "REP" && e.fxLane?.active && t && J(t) ? pn(e.relativeFx?.[t]) : null;
4138
+ return $(["fxLane", s], ["relative", n]);
1355
4139
  }
1356
- if (!a || a.isEmpty || a.hexValue == null) return Q(["fxLane", s]);
1357
- let c = t.type === "fxCommand" ? `value ${N(o, a.hexValue)}: ` : "", l = se(o, a.hexValue, {
4140
+ if (!a || a.isEmpty || a.hexValue == null) return $(["fxLane", s]);
4141
+ let c = t.type === "fxCommand" ? `value ${Zt(o, a.hexValue)}: ` : "", l = rn(o, a.hexValue, {
1358
4142
  note: n.fields.note?.isEmpty ? null : n.fields.note?.rawValue,
1359
4143
  inTable: e.viewName === "table"
1360
4144
  }), u = null;
1361
- return k(o) ? u = B(e.relativeFx?.[o]) : o === "RET" && e.resetsRelative && (u = V(e.resetsRelative)), Q(["meaning", l ? `${c}${l}` : null], ["fxLane", s], ["relative", u]);
4145
+ return J(o) ? u = pn(e.relativeFx?.[o]) : o === "RET" && e.resetsRelative && (u = mn(e.resetsRelative)), $(["meaning", l ? `${c}${l}` : null], ["fxLane", s], ["relative", u]);
1362
4146
  }
1363
- function Pe(e) {
4147
+ function $n(e) {
1364
4148
  let t = e.description.replace(/\.$/, "");
1365
- return e.instrumentTypes ? `${t}; offered by ${e.instrumentTypes.map((e) => Fe[e] ?? e).join(", ")} instruments` : t;
4149
+ return e.instrumentTypes ? `${t}; offered by ${e.instrumentTypes.map((e) => er[e] ?? e).join(", ")} instruments` : t;
1366
4150
  }
1367
- var Fe = {
4151
+ var er = {
1368
4152
  sampler: "Sampler",
1369
4153
  macrosynth: "Macrosynth",
1370
4154
  fmsynth: "FM Synth",
@@ -1373,14 +4157,14 @@ var Fe = {
1373
4157
  external: "External",
1374
4158
  midiout: "MIDI Out"
1375
4159
  };
1376
- function Ie(e, t) {
1377
- return t.type !== "instrumentRef" || t.isEmpty || !e.resetsRelative ? [] : Q(["relative", V(e.resetsRelative)]);
4160
+ function tr(e, t) {
4161
+ return t.type !== "instrumentRef" || t.isEmpty || !e.resetsRelative ? [] : $(["relative", mn(e.resetsRelative)]);
1378
4162
  }
1379
- var Le = {
4163
+ var nr = {
1380
4164
  MODFX: "ModFX",
1381
4165
  DELAY: "Delay",
1382
4166
  REVERB: "Reverb"
1383
- }, Re = {
4167
+ }, rr = {
1384
4168
  parent: "goes up to the parent directory",
1385
4169
  directory: "directory: [EDIT] opens it",
1386
4170
  instrumentPreset: "instrument preset: [EDIT] selects it",
@@ -1388,30 +4172,30 @@ var Le = {
1388
4172
  m8file: "M8 file: [EDIT] selects it",
1389
4173
  file: "file: [EDIT] selects it"
1390
4174
  };
1391
- function ze(e) {
4175
+ function ir(e) {
1392
4176
  let t = `${e.viewTitle ?? e.viewName}${e.viewId ? ` ${e.viewId}` : ""}`, n = e.activeField;
1393
- if (!n) return Q(["location", t], ["line", e.lineText]);
1394
- let r = e.instrumentType?.key ? g(e.instrumentType.key) : null;
1395
- return Q(["field", `${n.label}: ${$(n)}`], ["optionInfo", n.valueDescription], ["fieldInfo", n.description], ["fileInfo", n.fileKind && Re[n.fileKind]], ["instrument", e.instrumentType && `${r?.name ?? e.instrumentType.text} instrument`], ["section", e.section && (Le[e.section] ?? e.section)], ["location", t]);
4177
+ if (!n) return $(["location", t], ["line", e.lineText]);
4178
+ let r = e.instrumentType?.key ? Ft(e.instrumentType.key) : null;
4179
+ return $(["field", `${n.label}: ${sr(n)}`], ["optionInfo", n.valueDescription], ["fieldInfo", n.description], ["fileInfo", n.fileKind && rr[n.fileKind]], ["instrument", e.instrumentType && `${r?.name ?? e.instrumentType.text} instrument`], ["section", e.section && (nr[e.section] ?? e.section)], ["location", t]);
1396
4180
  }
1397
- function Be(e) {
4181
+ function ar(e) {
1398
4182
  let t = `${e.viewTitle ?? e.viewName}${e.viewId ? ` ${e.viewId}` : ""}`, n = e.activeField, r = e.scaleNote;
1399
- if (!n || !r) return e.lineText ? Q(["location", t], ["line", e.lineText]) : null;
4183
+ if (!n || !r) return e.lineText ? $(["location", t], ["line", e.lineText]) : null;
1400
4184
  let { interval: i, enabled: a, offset: o } = r, s;
1401
4185
  if (n.key === "offset") {
1402
- let e = o == null ? `detune of ${i}` : o === 0 ? `${i} is not detuned` : `${i} is detuned by ${G(o)}`;
1403
- s = Q(["field", `${n.label}: ${n.rawValue || "(empty)"}`], ["meaning", e], ["meaning", a === !1 ? "(note is OFF)" : null]);
4186
+ let e = o == null ? `detune of ${i}` : o === 0 ? `${i} is not detuned` : `${i} is detuned by ${Sn(o)}`;
4187
+ s = $(["field", `${n.label}: ${n.rawValue || "(empty)"}`], ["meaning", e], ["meaning", a === !1 ? "(note is OFF)" : null]);
1404
4188
  } else {
1405
4189
  let e = a === !0 ? "is in" : a === !1 ? "is not in" : "is not yet set in";
1406
- s = Q(["field", `${n.label}: ${n.key === "en" ? n.rawValue.toUpperCase() || "(unset)" : i}`], ["meaning", i], ["meaning", pe(i)], ["meaning", `${e} the scale`]);
4190
+ s = $(["field", `${n.label}: ${n.key === "en" ? n.rawValue.toUpperCase() || "(unset)" : i}`], ["meaning", i], ["meaning", vn(i)], ["meaning", `${e} the scale`]);
1407
4191
  }
1408
4192
  if (e.scale) {
1409
- let [t, n] = W(e.scale);
1410
- s.push(...Q(["scale", `Scale: ${t}`], ["scale", n]));
4193
+ let [t, n] = xn(e.scale);
4194
+ s.push(...$(["scale", `Scale: ${t}`], ["scale", n]));
1411
4195
  }
1412
- return [...s, ...Q(["location", `${t} row ${i}`])];
4196
+ return [...s, ...$(["location", `${t} row ${i}`])];
1413
4197
  }
1414
- function Ve(e) {
4198
+ function or(e) {
1415
4199
  let t = e.unit ?? "";
1416
4200
  if (e.values && e.parts) {
1417
4201
  let n = e.hexValue != null, r = e.values.map((e) => n ? e.toString(16).toUpperCase().padStart(2, "0") : String(e)), i = e.parts.map((e, n) => `${e} ${r[n] ?? "?"}${t}`).join(", ");
@@ -1419,7 +4203,7 @@ function Ve(e) {
1419
4203
  }
1420
4204
  return e.hexValue == null ? e.numericValue == null ? e.text ?? e.rawValue : `${e.rawValue}${t}` : `${e.rawValue.slice(0, 2)}h (dec ${e.hexValue})${e.text ? ` ${e.text}` : ""}`;
1421
4205
  }
1422
- function $(e) {
4206
+ function sr(e) {
1423
4207
  if (e.isEmpty) return "(empty)";
1424
4208
  let t = e.type === "name" || e.type === "fileEntry" ? e : {
1425
4209
  ...e,
@@ -1446,15 +4230,54 @@ function $(e) {
1446
4230
  case "fileEntry": return t.text ?? t.rawValue;
1447
4231
  case "name": return `"${t.rawValue}"`;
1448
4232
  case "option": return t.hexValue != null && t.text ? `${t.rawValue.slice(0, 2)} ${t.text}` : t.text ?? t.rawValue;
1449
- case "parameter": return Ve(t);
1450
- case "noteInterval": return `Interval ${U(t.rawValue) ?? t.rawValue}`;
4233
+ case "parameter": return or(t);
4234
+ case "noteInterval": return `Interval ${_n(t.rawValue) ?? t.rawValue}`;
1451
4235
  case "semitoneOffset": return t.isEmpty ? "(empty)" : `${t.rawValue} st`;
1452
4236
  default: return t.rawValue;
1453
4237
  }
1454
4238
  }
1455
4239
  //#endregion
1456
4240
  //#region src/client.ts
1457
- var He = () => ({
4241
+ var cr = "yam8d-external-app", lr = 3e3, ur = (e) => {
4242
+ let t = e.remoteHandle();
4243
+ return {
4244
+ call: (e, ...n) => t.call(e, ...n),
4245
+ on: (e, n) => (t.addEventListener(e, n), () => t.removeEventListener(e, n)),
4246
+ close: () => e.close()
4247
+ };
4248
+ }, dr = (e) => ({
4249
+ call: (t, ...n) => e.methods[t](...n),
4250
+ on: (t, n) => e.on(t, n),
4251
+ close: () => e.dispose()
4252
+ }), fr = (e) => {
4253
+ let t = [];
4254
+ return {
4255
+ messenger: {
4256
+ postMessage: (t, n) => e.postMessage(t, n),
4257
+ addMessageListener: (n) => {
4258
+ let r = e.addMessageListener(n);
4259
+ return t.push(r), r;
4260
+ }
4261
+ },
4262
+ dispose: () => {
4263
+ for (let e of t.splice(0)) e();
4264
+ }
4265
+ };
4266
+ }, pr = () => {
4267
+ if (typeof window > "u") return !1;
4268
+ try {
4269
+ return window.parent !== window;
4270
+ } catch {
4271
+ return !0;
4272
+ }
4273
+ }, mr = (e) => e instanceof DOMException && (e.name === "NotFoundError" || e.name === "AbortError"), hr = () => {
4274
+ let e = typeof navigator > "u" ? null : navigator;
4275
+ return {
4276
+ serial: !!e && "serial" in e,
4277
+ usb: !!e && "usb" in e,
4278
+ midi: !!e && "requestMIDIAccess" in e
4279
+ };
4280
+ }, gr = () => ({
1458
4281
  viewName: null,
1459
4282
  viewTitle: null,
1460
4283
  minimapKey: null,
@@ -1464,38 +4287,107 @@ var He = () => ({
1464
4287
  highlightColor: null,
1465
4288
  titleColor: null,
1466
4289
  backgroundColor: null,
4290
+ cursorColor: null,
1467
4291
  textUnderCursor: null,
1468
4292
  currentLine: null,
1469
4293
  deviceModel: null,
1470
4294
  fontMode: null,
1471
4295
  systemInfo: null,
1472
4296
  macroRunning: !1
1473
- }), Ue = class {
4297
+ }), _r = class {
1474
4298
  constructor(e = {}) {
1475
- this.connection = null, this.remoteHandle = null, this.localHandle = null, this.stateCallbacks = /* @__PURE__ */ new Set(), this.viewCallbacks = /* @__PURE__ */ new Set(), this.cursorCallbacks = /* @__PURE__ */ new Set(), this.textCallbacks = /* @__PURE__ */ new Set(), this.keyCallbacks = /* @__PURE__ */ new Set(), this._state = He(), this._screen = null, this.screenRefreshing = !1, this.screenDirty = !1, this._isConnected = !1, this.config = e;
4299
+ this.backend = null, this.backendUnsubscribers = [], this.device = null, this._mode = null, this.audio = null, this.connecting = null, this.stateCallbacks = /* @__PURE__ */ new Set(), this.viewCallbacks = /* @__PURE__ */ new Set(), this.cursorCallbacks = /* @__PURE__ */ new Set(), this.textCallbacks = /* @__PURE__ */ new Set(), this.keyCallbacks = /* @__PURE__ */ new Set(), this.transportCallbacks = /* @__PURE__ */ new Set(), this.connectionCallbacks = /* @__PURE__ */ new Set(), this._state = gr(), this._screen = null, this.screenRefreshing = !1, this.screenDirty = !1, this.config = e;
1476
4300
  }
1477
4301
  get state() {
1478
4302
  return this._state;
1479
4303
  }
1480
4304
  get isConnected() {
1481
- return this._isConnected;
4305
+ return this.backend !== null;
4306
+ }
4307
+ get mode() {
4308
+ return this._mode;
4309
+ }
4310
+ get isAudioConnected() {
4311
+ return this.audio?.connected ?? !1;
4312
+ }
4313
+ get deviceTransport() {
4314
+ return this.device?.transport ?? null;
1482
4315
  }
1483
4316
  async connect() {
1484
- if (this.connection) return;
1485
- let r = new n({
4317
+ return this.connecting ??= this.resolveMode(), this.connecting;
4318
+ }
4319
+ async resolveMode() {
4320
+ let e = this.config.mode ?? "auto";
4321
+ if (e === "standalone" || e === "auto" && !pr()) {
4322
+ await this.startStandalone();
4323
+ return;
4324
+ }
4325
+ let t = typeof window < "u" && window.name === "yam8d-external-app", n = e === "host" || t ? null : this.config.handshakeTimeoutMs ?? lr;
4326
+ await this.handshake(n) || (this.config.debug && console.log("[M8 SDK] No yam8d host answered, switching to standalone mode"), await this.startStandalone());
4327
+ }
4328
+ async handshake(r) {
4329
+ let i = new n({
1486
4330
  localWindow: window,
1487
4331
  remoteWindow: window.parent,
1488
4332
  remoteOrigin: "*"
1489
4333
  });
1490
- this.config.debug && (r = t(r, (e, ...t) => {
4334
+ this.config.debug && (i = t(i, (e, ...t) => {
1491
4335
  console.log("[M8 SDK]", e, ...t);
1492
4336
  }));
1493
- let i = await e(r, { ping: async () => "pong" });
1494
- this.connection = i, this.remoteHandle = i.remoteHandle(), this.localHandle = i.localHandle(), this._isConnected = !0, this.remoteHandle.addEventListener("stateChanged", (e) => {
4337
+ let a = fr(i), o = e(a.messenger, { ping: async () => "pong" }), s, c = new Promise((e) => {
4338
+ r !== null && (s = setTimeout(() => e(null), r));
4339
+ }), l = await Promise.race([o, c]);
4340
+ return clearTimeout(s), l ? (this._mode = "host", await this.attach(ur(l)), l.localHandle().emit("ready", void 0), !0) : (a.dispose(), !1);
4341
+ }
4342
+ async startStandalone() {
4343
+ if (this._mode = "standalone", this.config.autoConnect !== !1) try {
4344
+ await this.openDevice("auto", !1);
4345
+ } catch (e) {
4346
+ this.config.debug && console.log("[M8 SDK] No device reopened automatically:", e);
4347
+ }
4348
+ }
4349
+ async openDevice(e, t) {
4350
+ let n = A();
4351
+ if (!n.browserSupport) throw Error("This browser has no Web Serial, WebUSB or Web MIDI: the M8 cannot be reached from this page");
4352
+ let r = e === "auto" && !t ? [
4353
+ "serial",
4354
+ "usb",
4355
+ "midi"
4356
+ ].filter((e) => n.available[e]) : [e];
4357
+ await this.closeDevice();
4358
+ let i, a = /* @__PURE__ */ Error("No M8 device available");
4359
+ for (let e of r) try {
4360
+ i = await n.connect({
4361
+ transport: e,
4362
+ prompt: t
4363
+ });
4364
+ break;
4365
+ } catch (r) {
4366
+ if (a = r, t && !mr(r) && (i = await ee(() => n.connect({
4367
+ transport: e,
4368
+ prompt: !1
4369
+ }), { maxAttempts: 2 }), i)) break;
4370
+ }
4371
+ if (!i) throw a;
4372
+ let o = Ct(i, { debug: this.config.debug });
4373
+ this.device = i, await this.attach(dr(o)), i.commands.resetScreen();
4374
+ let s = i;
4375
+ i.closed.then(() => {
4376
+ this.device === s && (this.config.debug && console.log("[M8 SDK] Device connection ended"), this.device = null, this.detach());
4377
+ });
4378
+ }
4379
+ async closeDevice() {
4380
+ let e = this.device;
4381
+ e && (this.device = null, this.detach(), await e.close());
4382
+ }
4383
+ async attach(e) {
4384
+ this.detach(), this.backend = e;
4385
+ let t = this.backendUnsubscribers;
4386
+ t.push(e.on("stateChanged", (e) => {
1495
4387
  this._state = e, this.refreshScreen(), this.stateCallbacks.forEach((t) => {
1496
4388
  t(e);
1497
4389
  });
1498
- }), this.remoteHandle.addEventListener("viewChanged", ({ viewName: e, viewTitle: t }) => {
4390
+ })), t.push(e.on("viewChanged", ({ viewName: e, viewTitle: t }) => {
1499
4391
  this._state = {
1500
4392
  ...this._state,
1501
4393
  viewName: e,
@@ -1503,7 +4395,7 @@ var He = () => ({
1503
4395
  }, this.refreshScreen(), this.viewCallbacks.forEach((n) => {
1504
4396
  n(e, t);
1505
4397
  });
1506
- }), this.remoteHandle.addEventListener("cursorMoved", ({ pos: e, rect: t, selectionMode: n }) => {
4398
+ })), t.push(e.on("cursorMoved", ({ pos: e, rect: t, selectionMode: n }) => {
1507
4399
  this._state = {
1508
4400
  ...this._state,
1509
4401
  cursorPos: e,
@@ -1512,7 +4404,7 @@ var He = () => ({
1512
4404
  }, this.refreshScreen(), this.cursorCallbacks.forEach((r) => {
1513
4405
  r(e, t, n);
1514
4406
  });
1515
- }), this.remoteHandle.addEventListener("textUpdated", ({ textUnderCursor: e, currentLine: t }) => {
4407
+ })), t.push(e.on("textUpdated", ({ textUnderCursor: e, currentLine: t }) => {
1516
4408
  this._state = {
1517
4409
  ...this._state,
1518
4410
  textUnderCursor: e,
@@ -1520,84 +4412,115 @@ var He = () => ({
1520
4412
  }, this.refreshScreen(), this.textCallbacks.forEach((n) => {
1521
4413
  n(e, t);
1522
4414
  });
1523
- }), this.remoteHandle.addEventListener("keyPressed", ({ keys: e }) => {
4415
+ })), t.push(e.on("transport", (e) => {
4416
+ this.transportCallbacks.forEach((t) => {
4417
+ t(e);
4418
+ });
4419
+ })), t.push(e.on("keyPressed", ({ keys: e }) => {
1524
4420
  this.keyCallbacks.forEach((t) => {
1525
4421
  t(e);
1526
4422
  });
1527
- }), await this.fetchState(), this.refreshScreen(), this.localHandle.emit("ready", void 0);
4423
+ })), this.connectionCallbacks.forEach((e) => {
4424
+ e(!0);
4425
+ }), await this.fetchState(), this.refreshScreen();
4426
+ }
4427
+ detach() {
4428
+ let e = this.backend;
4429
+ e && (this.backend = null, this.backendUnsubscribers.splice(0).forEach((e) => {
4430
+ e();
4431
+ }), e.close(), this._screen = null, this.connectionCallbacks.forEach((e) => {
4432
+ e(!1);
4433
+ }));
4434
+ }
4435
+ requireBackend() {
4436
+ if (this.backend) return this.backend;
4437
+ throw this._mode === "standalone" ? Error("No M8 device connected: call connectDevice() first") : Error("M8 SDK client is not connected");
1528
4438
  }
1529
4439
  refreshScreen() {
1530
- if (this.remoteHandle) {
1531
- if (this.screenRefreshing) {
1532
- this.screenDirty = !0;
1533
- return;
1534
- }
1535
- this.screenRefreshing = !0, this.remoteHandle.call("getScreen").then((e) => {
1536
- this._screen = e;
1537
- }).catch(() => {}).finally(() => {
1538
- this.screenRefreshing = !1, this.screenDirty && (this.screenDirty = !1, this.refreshScreen());
1539
- });
1540
- }
4440
+ let e = this.backend;
4441
+ e && (this.screenRefreshing ? this.screenDirty = !0 : (this.screenRefreshing = !0, e.call("getScreen").then((t) => {
4442
+ this.backend === e && (this._screen = t);
4443
+ }).catch(() => {}).finally(() => {
4444
+ this.screenRefreshing = !1, this.screenDirty && (this.screenDirty = !1, this.refreshScreen());
4445
+ })));
4446
+ }
4447
+ async connectDevice(e = {}) {
4448
+ await this.connect(), this._mode !== "host" && (await this.openDevice(e.transport ?? "auto", !0), e.audio && await this.connectAudio().catch((e) => console.warn("[M8 SDK] M8 audio not started:", e)));
4449
+ }
4450
+ async disconnectDevice() {
4451
+ await this.disconnectAudio(), await this.closeDevice();
4452
+ }
4453
+ async connectAudio() {
4454
+ await this.connect(), this._mode !== "host" && (this.audio ??= F(), await this.audio.connect({ requireM8: !0 }));
4455
+ }
4456
+ async disconnectAudio() {
4457
+ await this.audio?.disconnect();
4458
+ }
4459
+ getDevice() {
4460
+ let e = this.device;
4461
+ return e ? {
4462
+ transport: e.transport,
4463
+ events: e.protocol.eventBus,
4464
+ commands: e.commands
4465
+ } : null;
4466
+ }
4467
+ onConnectionChange(e) {
4468
+ return this.connectionCallbacks.add(e), () => this.connectionCallbacks.delete(e);
1541
4469
  }
1542
4470
  async navigateToView(e) {
1543
- if (!this.remoteHandle) throw Error("M8 SDK client is not connected");
1544
- return this.remoteHandle.call("navigateToView", e);
4471
+ return this.requireBackend().call("navigateToView", e);
1545
4472
  }
1546
4473
  async navigateTo(e, t) {
1547
- if (!this.remoteHandle) throw Error("M8 SDK client is not connected");
1548
- return this.remoteHandle.call("navigateTo", e, t);
4474
+ return this.requireBackend().call("navigateTo", e, t);
1549
4475
  }
1550
4476
  async setValueToHex(e) {
1551
- if (!this.remoteHandle) throw Error("M8 SDK client is not connected");
1552
- return this.remoteHandle.call("setValueToHex", e);
4477
+ return this.requireBackend().call("setValueToHex", e);
1553
4478
  }
1554
4479
  async setValueToInt(e) {
1555
- if (!this.remoteHandle) throw Error("M8 SDK client is not connected");
1556
- return this.remoteHandle.call("setValueToInt", e);
4480
+ return this.requireBackend().call("setValueToInt", e);
1557
4481
  }
1558
4482
  async setValueFloat(e) {
1559
- if (!this.remoteHandle) throw Error("M8 SDK client is not connected");
1560
- return this.remoteHandle.call("setValueFloat", e);
4483
+ return this.requireBackend().call("setValueFloat", e);
1561
4484
  }
1562
4485
  async setNote(e) {
1563
- if (!this.remoteHandle) throw Error("M8 SDK client is not connected");
1564
- return this.remoteHandle.call("setNote", e);
4486
+ return this.requireBackend().call("setNote", e);
1565
4487
  }
1566
4488
  async setValueToString(e, t = !0, n = !1) {
1567
- if (!this.remoteHandle) throw Error("M8 SDK client is not connected");
1568
- return this.remoteHandle.call("setValueToString", e, t, n);
4489
+ return this.requireBackend().call("setValueToString", e, t, n);
1569
4490
  }
1570
4491
  async browseFile(e, t = !0) {
1571
- if (!this.remoteHandle) throw Error("M8 SDK client is not connected");
1572
- return this.remoteHandle.call("browseFile", e, t);
4492
+ return this.requireBackend().call("browseFile", e, t);
1573
4493
  }
1574
4494
  async sendKeyPress(e) {
1575
- if (!this.remoteHandle) throw Error("M8 SDK client is not connected");
1576
- return this.remoteHandle.call("sendKeyPress", e);
4495
+ return this.requireBackend().call("sendKeyPress", e);
1577
4496
  }
1578
4497
  async sendKeyDown(e) {
1579
- if (!this.remoteHandle) throw Error("M8 SDK client is not connected");
1580
- return this.remoteHandle.call("sendKeyDown", e);
4498
+ return this.requireBackend().call("sendKeyDown", e);
1581
4499
  }
1582
4500
  async sendKeyUp() {
1583
- if (!this.remoteHandle) throw Error("M8 SDK client is not connected");
1584
- return this.remoteHandle.call("sendKeyUp");
4501
+ return this.requireBackend().call("sendKeyUp");
1585
4502
  }
1586
4503
  getState() {
1587
4504
  return this._state;
1588
4505
  }
1589
4506
  async fetchState() {
1590
- if (!this.remoteHandle) throw Error("M8 SDK client is not connected");
1591
- let e = await this.remoteHandle.call("getState");
4507
+ let e = await this.requireBackend().call("getState");
1592
4508
  return this._state = e, e;
1593
4509
  }
1594
4510
  async getScreen() {
1595
- if (!this.remoteHandle) throw Error("M8 SDK client is not connected");
1596
- let e = await this.remoteHandle.call("getScreen");
4511
+ let e = await this.requireBackend().call("getScreen");
1597
4512
  return this._screen = e, e;
1598
4513
  }
4514
+ async getScreenCells() {
4515
+ let e = await this.requireBackend().call("getScreenCells");
4516
+ return this._screen = {
4517
+ width: e.width,
4518
+ height: e.height,
4519
+ lines: e.lines
4520
+ }, e;
4521
+ }
1599
4522
  async captureSnapshot() {
1600
- let [e, t] = await Promise.all([this.fetchState(), this.getScreen()]), n = Y(e, t);
4523
+ let [e, t] = await Promise.all([this.fetchState(), this.getScreen()]), n = Yn(e, t);
1601
4524
  return {
1602
4525
  capturedAt: Date.now(),
1603
4526
  state: {
@@ -1610,8 +4533,8 @@ var He = () => ({
1610
4533
  deviceModel: e.deviceModel
1611
4534
  },
1612
4535
  semantic: n,
1613
- description: n ? Z(n) : null,
1614
- descriptionParts: n ? X(n) : null,
4536
+ description: n ? Zn(n) : null,
4537
+ descriptionParts: n ? Xn(n) : null,
1615
4538
  screen: t
1616
4539
  };
1617
4540
  }
@@ -1630,27 +4553,33 @@ var He = () => ({
1630
4553
  onKeyPress(e) {
1631
4554
  return this.keyCallbacks.add(e), () => this.keyCallbacks.delete(e);
1632
4555
  }
4556
+ async enableMidiTransport() {
4557
+ return this.requireBackend().call("enableMidiTransport");
4558
+ }
4559
+ onTransport(e) {
4560
+ return this.transportCallbacks.add(e), () => this.transportCallbacks.delete(e);
4561
+ }
1633
4562
  disconnect() {
1634
- this.connection?.close(), this.connection = null, this.remoteHandle = null, this.localHandle = null, this._isConnected = !1, this._screen = null, this.stateCallbacks.clear(), this.viewCallbacks.clear(), this.cursorCallbacks.clear(), this.textCallbacks.clear(), this.keyCallbacks.clear();
4563
+ this.audio?.disconnect(), this.closeDevice(), this.detach(), this.stateCallbacks.clear(), this.viewCallbacks.clear(), this.cursorCallbacks.clear(), this.textCallbacks.clear(), this.keyCallbacks.clear(), this.transportCallbacks.clear(), this.connectionCallbacks.clear();
1635
4564
  }
1636
4565
  getSemanticContext() {
1637
- return Y(this._state, this._screen);
4566
+ return Yn(this._state, this._screen);
1638
4567
  }
1639
4568
  describeContext() {
1640
- let e = Y(this._state, this._screen);
1641
- return e ? Z(e) : null;
4569
+ let e = Yn(this._state, this._screen);
4570
+ return e ? Zn(e) : null;
1642
4571
  }
1643
4572
  describeContextParts() {
1644
- let e = Y(this._state, this._screen);
1645
- return e ? X(e) : null;
4573
+ let e = Yn(this._state, this._screen);
4574
+ return e ? Xn(e) : null;
1646
4575
  }
1647
4576
  };
1648
- async function We(e = {}) {
1649
- let t = new Ue(e);
4577
+ async function vr(e = {}) {
4578
+ let t = new _r(e);
1650
4579
  return await t.connect(), t;
1651
4580
  }
1652
- function Ge(e = {}) {
1653
- let t = new Ue(e);
4581
+ function yr(e = {}) {
4582
+ let t = new _r(e);
1654
4583
  return {
1655
4584
  client: t,
1656
4585
  connect: async () => {
@@ -1658,11 +4587,130 @@ function Ge(e = {}) {
1658
4587
  }
1659
4588
  };
1660
4589
  }
1661
- var Ke = {
1662
- createM8Client: We,
1663
- createM8ClientSync: Ge
1664
- };
4590
+ var br = {
4591
+ createM8Client: vr,
4592
+ createM8ClientSync: yr
4593
+ }, xr = [
4594
+ {
4595
+ role: "background",
4596
+ label: "BACKGROUND"
4597
+ },
4598
+ {
4599
+ role: "textEmpty",
4600
+ label: "TEXT:EMPTY"
4601
+ },
4602
+ {
4603
+ role: "textInfo",
4604
+ label: "TEXT:INFO"
4605
+ },
4606
+ {
4607
+ role: "textDefault",
4608
+ label: "TEXT:DEFAULT"
4609
+ },
4610
+ {
4611
+ role: "textValue",
4612
+ label: "TEXT:VALUE"
4613
+ },
4614
+ {
4615
+ role: "textTitles",
4616
+ label: "TEXT:TITLES"
4617
+ },
4618
+ {
4619
+ role: "playMarkers",
4620
+ label: "PLAY MARKERS"
4621
+ },
4622
+ {
4623
+ role: "cursor",
4624
+ label: "CURSOR"
4625
+ },
4626
+ {
4627
+ role: "selection",
4628
+ label: "SELECTION"
4629
+ },
4630
+ {
4631
+ role: "scopeSlider",
4632
+ label: "SCOPE/SLIDER"
4633
+ },
4634
+ {
4635
+ role: "meterLow",
4636
+ label: "METER LOW"
4637
+ },
4638
+ {
4639
+ role: "meterMid",
4640
+ label: "METER MID"
4641
+ },
4642
+ {
4643
+ role: "meterPeak",
4644
+ label: "METER PEAK"
4645
+ }
4646
+ ], Sr = "themesettings", Cr = (e) => e.replace(/\s+/g, "").toUpperCase(), wr = (e) => Math.max(0, Math.min(255, Math.round(e))).toString(16).padStart(2, "0"), Tr = (e, t, n) => `#${wr(e)}${wr(t)}${wr(n)}`, Er = (e, t, n) => {
4647
+ let r = e / 256 * 6, i = t / 255, a = n / 255, o = Math.floor(r) % 6, s = r - Math.floor(r), c = a * (1 - i), l = a * (1 - s * i), u = a * (1 - (1 - s) * i), [d, f, p] = [
4648
+ [
4649
+ a,
4650
+ u,
4651
+ c
4652
+ ],
4653
+ [
4654
+ l,
4655
+ a,
4656
+ c
4657
+ ],
4658
+ [
4659
+ c,
4660
+ a,
4661
+ u
4662
+ ],
4663
+ [
4664
+ c,
4665
+ l,
4666
+ a
4667
+ ],
4668
+ [
4669
+ u,
4670
+ c,
4671
+ a
4672
+ ],
4673
+ [
4674
+ a,
4675
+ c,
4676
+ l
4677
+ ]
4678
+ ][o];
4679
+ return Tr(d * 255, f * 255, p * 255);
4680
+ }, Dr = new Map(xr.map(({ role: e, label: t }) => [Cr(t), e]));
4681
+ function Or(e) {
4682
+ let t = "rgb", n = null, r = {};
4683
+ for (let i of e.lines) {
4684
+ let e = i.replace(/[{}]/g, "0"), a = /^\s*MODE\s+([A-Z])\s+([A-Z])\s+([A-Z])\b/i.exec(e);
4685
+ if (a) {
4686
+ t = Cr(a.slice(1).join("")) === "HSV" ? "hsv" : "rgb";
4687
+ continue;
4688
+ }
4689
+ let o = /^\s*THEME\s+NAME\s+(\S.*?)\s*$/i.exec(e);
4690
+ if (o) {
4691
+ let e = o[1].split(/\s{2,}/)[0];
4692
+ n = /^-+$/.test(e) ? null : e;
4693
+ continue;
4694
+ }
4695
+ let s = /^\s*([A-Z][A-Z:/. ]*?)\s+([0-9A-F]{2})\s+([0-9A-F]{2})\s+([0-9A-F]{2})(?:\s|$)/i.exec(e);
4696
+ if (!s) continue;
4697
+ let c = Dr.get(Cr(s[1]));
4698
+ if (!c || r[c]) continue;
4699
+ let [l, u, d] = s.slice(2, 5).map((e) => parseInt(e, 16));
4700
+ r[c] = t === "hsv" ? Er(l, u, d) : Tr(l, u, d);
4701
+ }
4702
+ return xr.some(({ role: e }) => !r[e]) ? null : {
4703
+ colors: r,
4704
+ mode: t,
4705
+ name: n
4706
+ };
4707
+ }
4708
+ var kr = (e) => e ? Tr(e.r, e.g, e.b) : void 0;
4709
+ function Ar(e) {
4710
+ let t = {}, n = kr(e.backgroundColor), r = kr(e.titleColor);
4711
+ return n && (t.background = n), r && (t.textTitles = r), t;
4712
+ }
1665
4713
  //#endregion
1666
- export { ne as RELATIVE_FX_RULE, We as createM8Client, Ge as createM8ClientSync, Ke as default, Z as describeContext, X as describeContextParts, $ as formatFieldValue, te as getInstrumentFxCommands, Y as getSemanticContext, O as lookupFxCommand };
4714
+ export { I as M8KeyMask, j as M8_AUDIO_CAPTURE_CONSTRAINTS, xr as M8_THEME_ROLES, Sr as M8_THEME_VIEW, Yt as RELATIVE_FX_RULE, In as SCREEN_MARGIN, cr as YAM8D_FRAME_NAME, F as createM8Audio, vr as createM8Client, yr as createM8ClientSync, A as createM8Connection, Ct as createM8Engine, br as default, Zn as describeContext, Xn as describeContextParts, sr as formatFieldValue, hr as getDeviceSupport, Jt as getInstrumentFxCommands, P as getM8InputStream, Yn as getSemanticContext, qt as lookupFxCommand, Ar as observeThemeColors, Vn as parseGridScreen, Or as parseThemeScreen, Dn as parseViewTitle, te as pressKeys, Un as readPlayPositions };
1667
4715
 
1668
4716
  //# sourceMappingURL=index.js.map