@yam8d/m8-sdk 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +898 -796
- package/dist/index.js +3411 -363
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/types/client.d.ts +58 -2
- package/types/engine/astar.d.ts +15 -0
- package/types/engine/audio.d.ts +29 -0
- package/types/engine/bus.d.ts +13 -0
- package/types/engine/connectWithRetry.d.ts +9 -0
- package/types/engine/connection.d.ts +56 -0
- package/types/engine/cursorNavigator.d.ts +15 -0
- package/types/engine/engine.d.ts +30 -0
- package/types/engine/eventBus.d.ts +5 -0
- package/types/engine/host/fileBrowserHelpers.d.ts +59 -0
- package/types/engine/host/fileBrowserSearch.d.ts +13 -0
- package/types/engine/host/floatEditor.d.ts +2 -0
- package/types/engine/host/hostIO.d.ts +30 -0
- package/types/engine/host/hostMethods.d.ts +22 -0
- package/types/engine/host/hostState.d.ts +7 -0
- package/types/engine/host/keySequences.d.ts +2 -0
- package/types/engine/host/midiTransport.d.ts +10 -0
- package/types/engine/host/valueEditors.d.ts +7 -0
- package/types/engine/host/valueParsers.d.ts +24 -0
- package/types/engine/index.d.ts +14 -0
- package/types/engine/keys.d.ts +28 -0
- package/types/engine/macroRunner.d.ts +15 -0
- package/types/engine/protocol.d.ts +138 -0
- package/types/engine/queuedReaders.d.ts +18 -0
- package/types/engine/store.d.ts +65 -0
- package/types/engine/viewExtractor.d.ts +27 -0
- package/types/engine/viewGraph.d.ts +9 -0
- package/types/engine/viewNavigation.d.ts +16 -0
- package/types/index.d.ts +9 -3
- package/types/scaleInsight.d.ts +1 -1
- package/types/theme.d.ts +42 -0
- package/types/types.d.ts +124 -0
- 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
|
-
|
|
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'
|
|
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
|
-
},
|
|
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
|
-
},
|
|
190
|
-
for (let [e, t] of Object.entries(
|
|
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
|
-
|
|
193
|
-
...
|
|
2937
|
+
Ot[e] = n ? {
|
|
2938
|
+
...Tt[n],
|
|
194
2939
|
...r
|
|
195
2940
|
} : r;
|
|
196
2941
|
}
|
|
197
|
-
function
|
|
198
|
-
return
|
|
2942
|
+
function kt(e) {
|
|
2943
|
+
return Ot[e] ?? null;
|
|
199
2944
|
}
|
|
200
|
-
var
|
|
201
|
-
function
|
|
202
|
-
let n = e.width ?? e.text?.length ?? 1, r =
|
|
203
|
-
return e.text == null ? e.regex
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
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(
|
|
228
|
-
return n ?
|
|
2972
|
+
let n = Object.keys(Dt).find((e) => t.startsWith(e));
|
|
2973
|
+
return n ? Dt[n] : null;
|
|
229
2974
|
}
|
|
230
|
-
function
|
|
2975
|
+
function Pt(e) {
|
|
231
2976
|
for (let t of e) if (t.toUpperCase().startsWith("TYPE")) {
|
|
232
|
-
let e =
|
|
2977
|
+
let e = K(t, 8, 13).trim();
|
|
233
2978
|
return e ? {
|
|
234
2979
|
text: e,
|
|
235
|
-
key:
|
|
2980
|
+
key: Nt(e)
|
|
236
2981
|
} : null;
|
|
237
2982
|
}
|
|
238
2983
|
return null;
|
|
239
2984
|
}
|
|
240
|
-
function
|
|
241
|
-
let t =
|
|
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
|
|
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(
|
|
2996
|
+
let i = n ? [n, "common"] : ["common", ...Object.keys(Et).filter((e) => e !== "common")];
|
|
252
2997
|
for (let e of i) {
|
|
253
|
-
let t =
|
|
2998
|
+
let t = Et[e]?.params[r];
|
|
254
2999
|
if (t) return t;
|
|
255
3000
|
}
|
|
256
3001
|
return null;
|
|
257
3002
|
}
|
|
258
|
-
var
|
|
259
|
-
function
|
|
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) =>
|
|
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 =
|
|
304
|
-
if (!
|
|
305
|
-
let c = r[o + 1], l = c != null &&
|
|
306
|
-
if (!
|
|
307
|
-
let
|
|
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:
|
|
311
|
-
key:
|
|
312
|
-
type:
|
|
313
|
-
format:
|
|
314
|
-
label:
|
|
315
|
-
description:
|
|
316
|
-
parts:
|
|
317
|
-
options:
|
|
318
|
-
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
|
|
3074
|
+
var q = {
|
|
330
3075
|
hexValue: null,
|
|
331
3076
|
numericValue: null,
|
|
332
3077
|
values: null,
|
|
333
3078
|
text: null
|
|
334
3079
|
};
|
|
335
|
-
function
|
|
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
|
|
3083
|
+
function Vt(e, t) {
|
|
339
3084
|
let n = e.trim();
|
|
340
|
-
if (!n) return
|
|
341
|
-
switch (t === "auto" ?
|
|
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
|
-
...
|
|
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
|
-
...
|
|
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
|
-
...
|
|
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
|
-
...
|
|
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
|
-
...
|
|
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
|
-
...
|
|
3163
|
+
...q,
|
|
419
3164
|
text: n
|
|
420
3165
|
};
|
|
421
3166
|
}
|
|
422
3167
|
}
|
|
423
|
-
function
|
|
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
|
|
433
|
-
function
|
|
434
|
-
let t =
|
|
435
|
-
return t.length === 0 || t.length ===
|
|
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
|
|
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 =
|
|
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" ?
|
|
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 ?
|
|
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
|
|
463
|
-
return
|
|
3207
|
+
function J(e) {
|
|
3208
|
+
return qt(e)?.relative === !0;
|
|
464
3209
|
}
|
|
465
|
-
function
|
|
466
|
-
let t =
|
|
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
|
|
474
|
-
function
|
|
475
|
-
return
|
|
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
|
|
478
|
-
return e > 127 ? `−${
|
|
3222
|
+
function Qt(e) {
|
|
3223
|
+
return e > 127 ? `−${Y(256 - e)}` : `+${Y(e)}`;
|
|
479
3224
|
}
|
|
480
|
-
var
|
|
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
|
|
3239
|
+
function en(e) {
|
|
495
3240
|
let t = /^([A-G])([#-])(\d)$/.exec((e ?? "").trim().toUpperCase());
|
|
496
3241
|
if (!t) return null;
|
|
497
|
-
let n =
|
|
3242
|
+
let n = $t.indexOf(`${t[1]}${t[2]}`);
|
|
498
3243
|
return n < 0 ? null : Number(t[3]) * 12 + n;
|
|
499
3244
|
}
|
|
500
|
-
function
|
|
501
|
-
return `${
|
|
3245
|
+
function tn(e) {
|
|
3246
|
+
return `${$t[(e % 12 + 12) % 12]}${Math.floor(e / 12)}`;
|
|
502
3247
|
}
|
|
503
|
-
var
|
|
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
|
|
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 =
|
|
522
|
-
return e == null ? `plays the note, then ${t}` : `${t}: ${
|
|
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 ${
|
|
531
|
-
case "GGR": return `all tracks use groove ${
|
|
532
|
-
case "INS": return `switches to instrument ${
|
|
533
|
-
case "TBL": return `instrument uses table ${
|
|
534
|
-
case "TBX": return t === 0 ? "stops the auxiliary table" : `plays 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 =
|
|
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 ${
|
|
549
|
-
case "SED": return `random seed ${
|
|
550
|
-
case "NXT": return `plays instrument ${
|
|
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 =
|
|
553
|
-
return e === 0 ? "no timing shift" : `shifts the row by ${
|
|
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 ${
|
|
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 (
|
|
567
|
-
let e =
|
|
568
|
-
return r === "PIT" ? e === 0 ? "no change" : `${
|
|
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
|
|
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
|
|
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} =
|
|
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} =
|
|
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
|
|
607
|
-
let t = e.source, n = (e) => e == null ? "??" : t ?
|
|
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 (${
|
|
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
|
|
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
|
|
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 =
|
|
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 =
|
|
644
|
-
if (!c || s.carried || !
|
|
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
|
|
661
|
-
function
|
|
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
|
|
667
|
-
function
|
|
668
|
-
if (!e || e.count <= 1) return `relative: ${
|
|
669
|
-
let t = e.viaRep ? ", including REP repeats" : "", n = e.total === 0 ? "has had no net effect" : `has moved by ${
|
|
670
|
-
return `relative: ${e.cmd} ${n} over ${e.count} steps since ${
|
|
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
|
|
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} ${
|
|
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
|
|
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
|
-
],
|
|
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
|
-
],
|
|
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
|
|
3667
|
+
function _n(e) {
|
|
924
3668
|
let t = e.replace(/[-\s]/g, "").toUpperCase();
|
|
925
|
-
return
|
|
3669
|
+
return Z.includes(t) ? t : null;
|
|
926
3670
|
}
|
|
927
|
-
function
|
|
928
|
-
let t =
|
|
929
|
-
return t <= 0 ? t === 0 ? "the first row (the scale root)" : e : `${
|
|
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
|
|
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
|
|
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 ${
|
|
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
|
|
942
|
-
let t = e.filter((e) => e.enabled === !0), n = t.map((e) => e.interval), r =
|
|
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:
|
|
3695
|
+
summary: xn({
|
|
952
3696
|
enabled: n,
|
|
953
3697
|
shapes: r,
|
|
954
3698
|
detuned: i
|
|
955
3699
|
}).join(" — ")
|
|
956
3700
|
};
|
|
957
3701
|
}
|
|
958
|
-
function
|
|
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} ${
|
|
3706
|
+
return r.length && (i += `; detuned: ${r.map((e) => `${e.interval} ${Sn(e.offset)}`).join(", ")}`), [t.join(" "), i];
|
|
963
3707
|
}
|
|
964
|
-
function
|
|
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
|
|
3713
|
+
var Cn = /* @__PURE__ */ new Set([
|
|
970
3714
|
"--",
|
|
971
3715
|
"---",
|
|
972
3716
|
"---00",
|
|
973
3717
|
"----",
|
|
974
3718
|
"-"
|
|
975
3719
|
]);
|
|
976
|
-
function
|
|
977
|
-
return e
|
|
3720
|
+
function wn(e) {
|
|
3721
|
+
return !e || Cn.has(e) || /^-+$/.test(e);
|
|
978
3722
|
}
|
|
979
|
-
function
|
|
3723
|
+
function Tn(e) {
|
|
980
3724
|
let t = e.trim();
|
|
981
|
-
if (!t ||
|
|
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
|
|
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
|
|
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 =
|
|
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(
|
|
996
|
-
isUnsaved:
|
|
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
|
|
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
|
|
1009
|
-
let n =
|
|
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 =
|
|
3760
|
+
let r = wn(n);
|
|
1012
3761
|
if (e.format) {
|
|
1013
|
-
let t = r ? 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 &&
|
|
1029
|
-
fileKind: e.type === "fileEntry" ?
|
|
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))
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
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
|
|
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
|
|
1066
|
-
let n =
|
|
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
|
|
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
|
|
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
|
|
3832
|
+
function Pn(e, t) {
|
|
1082
3833
|
let n = {};
|
|
1083
|
-
for (let r of e.columns ?? []) n[r.key] =
|
|
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 ?
|
|
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
|
|
1099
|
-
function
|
|
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 &&
|
|
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
|
-
|
|
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 <
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
|
1138
|
-
let t =
|
|
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:
|
|
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
|
|
3932
|
+
function qn(e, t) {
|
|
1149
3933
|
let n = /* @__PURE__ */ new Map();
|
|
1150
3934
|
for (let r of t.lines) {
|
|
1151
|
-
let t =
|
|
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 ===
|
|
3938
|
+
return n.size === Z.length ? Z.map((e) => n.get(e)) : null;
|
|
1155
3939
|
}
|
|
1156
|
-
function
|
|
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 &&
|
|
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(
|
|
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 (
|
|
3965
|
+
if (zt(n, t, {
|
|
1182
3966
|
...d,
|
|
1183
|
-
section:
|
|
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
|
|
3973
|
+
let f = jt(n, s ? l : [c]), { rowId: p, cells: m } = zt(n, c, {
|
|
1190
3974
|
...d,
|
|
1191
|
-
section:
|
|
1192
|
-
}),
|
|
1193
|
-
for (let e of
|
|
1194
|
-
let
|
|
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:
|
|
1198
|
-
fields:
|
|
1199
|
-
},
|
|
1200
|
-
|
|
1201
|
-
...v
|
|
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
|
|
1206
|
-
return s && typeof
|
|
3989
|
+
let y = v?.meta?.zone;
|
|
3990
|
+
return s && typeof y == "string" && (f = Mt(n, y, l) ?? f), {
|
|
1207
3991
|
...i,
|
|
1208
|
-
section:
|
|
3992
|
+
section: f,
|
|
1209
3993
|
instrumentType: u,
|
|
1210
|
-
row:
|
|
1211
|
-
activeField:
|
|
3994
|
+
row: g,
|
|
3995
|
+
activeField: _,
|
|
1212
3996
|
lineText: c.trim()
|
|
1213
3997
|
};
|
|
1214
3998
|
}
|
|
1215
|
-
function
|
|
3999
|
+
function Yn(e, t) {
|
|
1216
4000
|
let n = e.viewName;
|
|
1217
4001
|
if (!n) return null;
|
|
1218
|
-
let
|
|
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:
|
|
1221
|
-
viewDescription:
|
|
1222
|
-
viewId:
|
|
1223
|
-
isUnsaved:
|
|
1224
|
-
},
|
|
1225
|
-
...
|
|
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
|
-
},
|
|
1238
|
-
if (
|
|
1239
|
-
if (!
|
|
1240
|
-
...
|
|
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
|
|
1246
|
-
if (!
|
|
1247
|
-
...
|
|
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:
|
|
1253
|
-
if (
|
|
1254
|
-
let
|
|
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 =
|
|
4040
|
+
let e = Nn(r.columns ?? [], m);
|
|
1257
4041
|
if (e) {
|
|
1258
|
-
let t =
|
|
1259
|
-
t && (
|
|
4042
|
+
let t = h.fields[e.key];
|
|
4043
|
+
t && (_ = {
|
|
1260
4044
|
...t,
|
|
1261
4045
|
viewName: n,
|
|
1262
|
-
rowIndex:
|
|
4046
|
+
rowIndex: h.rowIndex
|
|
1263
4047
|
});
|
|
1264
4048
|
}
|
|
1265
4049
|
}
|
|
1266
|
-
let
|
|
1267
|
-
if (
|
|
1268
|
-
if (n === "phrase" &&
|
|
1269
|
-
let n =
|
|
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
|
-
|
|
1272
|
-
let e =
|
|
1273
|
-
e && (
|
|
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 =
|
|
1277
|
-
e && (
|
|
4060
|
+
let e = qn(r, t);
|
|
4061
|
+
e && (C = bn(e));
|
|
1278
4062
|
}
|
|
1279
4063
|
}
|
|
1280
|
-
let
|
|
4064
|
+
let w = n === "scale" ? Kn(h) : null;
|
|
1281
4065
|
return {
|
|
1282
|
-
...
|
|
4066
|
+
...u,
|
|
1283
4067
|
isGridView: !0,
|
|
1284
|
-
row:
|
|
1285
|
-
activeField:
|
|
1286
|
-
lineText:
|
|
1287
|
-
steps:
|
|
1288
|
-
carriedRepLane:
|
|
1289
|
-
fxLane:
|
|
1290
|
-
relativeFx:
|
|
1291
|
-
resetsRelative:
|
|
1292
|
-
scaleNote:
|
|
1293
|
-
scale:
|
|
1294
|
-
};
|
|
1295
|
-
}
|
|
1296
|
-
function
|
|
1297
|
-
if (e.isParameterView) return
|
|
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 =
|
|
4083
|
+
let t = ar(e);
|
|
1300
4084
|
if (t) return t;
|
|
1301
4085
|
}
|
|
1302
|
-
if (!e.activeField) return
|
|
1303
|
-
let { activeField: t, row: n } = e, r =
|
|
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 :
|
|
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: `(${
|
|
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 :
|
|
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
|
|
1334
|
-
return
|
|
4117
|
+
function Zn(e) {
|
|
4118
|
+
return Xn(e).map((e) => e.text).join(" — ");
|
|
1335
4119
|
}
|
|
1336
|
-
function
|
|
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
|
|
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 &&
|
|
1349
|
-
return
|
|
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" ?
|
|
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 &&
|
|
1354
|
-
return
|
|
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
|
|
1357
|
-
let c = t.type === "fxCommand" ? `value ${
|
|
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
|
|
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
|
|
4147
|
+
function $n(e) {
|
|
1364
4148
|
let t = e.description.replace(/\.$/, "");
|
|
1365
|
-
return e.instrumentTypes ? `${t}; offered by ${e.instrumentTypes.map((e) =>
|
|
4149
|
+
return e.instrumentTypes ? `${t}; offered by ${e.instrumentTypes.map((e) => er[e] ?? e).join(", ")} instruments` : t;
|
|
1366
4150
|
}
|
|
1367
|
-
var
|
|
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
|
|
1377
|
-
return t.type !== "instrumentRef" || t.isEmpty || !e.resetsRelative ? [] :
|
|
4160
|
+
function tr(e, t) {
|
|
4161
|
+
return t.type !== "instrumentRef" || t.isEmpty || !e.resetsRelative ? [] : $(["relative", mn(e.resetsRelative)]);
|
|
1378
4162
|
}
|
|
1379
|
-
var
|
|
4163
|
+
var nr = {
|
|
1380
4164
|
MODFX: "ModFX",
|
|
1381
4165
|
DELAY: "Delay",
|
|
1382
4166
|
REVERB: "Reverb"
|
|
1383
|
-
},
|
|
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
|
|
4175
|
+
function ir(e) {
|
|
1392
4176
|
let t = `${e.viewTitle ?? e.viewName}${e.viewId ? ` ${e.viewId}` : ""}`, n = e.activeField;
|
|
1393
|
-
if (!n) return
|
|
1394
|
-
let r = e.instrumentType?.key ?
|
|
1395
|
-
return
|
|
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
|
|
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 ?
|
|
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 ${
|
|
1403
|
-
s =
|
|
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 =
|
|
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] =
|
|
1410
|
-
s.push(
|
|
4193
|
+
let [t, n] = xn(e.scale);
|
|
4194
|
+
s.push(...$(["scale", `Scale: ${t}`], ["scale", n]));
|
|
1411
4195
|
}
|
|
1412
|
-
return [...s,
|
|
4196
|
+
return [...s, ...$(["location", `${t} row ${i}`])];
|
|
1413
4197
|
}
|
|
1414
|
-
function
|
|
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
|
|
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
|
|
1450
|
-
case "noteInterval": return `Interval ${
|
|
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
|
|
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
|
-
}),
|
|
4297
|
+
}), _r = class {
|
|
1474
4298
|
constructor(e = {}) {
|
|
1475
|
-
this.
|
|
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.
|
|
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
|
-
|
|
1485
|
-
|
|
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 && (
|
|
4334
|
+
this.config.debug && (i = t(i, (e, ...t) => {
|
|
1491
4335
|
console.log("[M8 SDK]", e, ...t);
|
|
1492
4336
|
}));
|
|
1493
|
-
let i =
|
|
1494
|
-
|
|
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
|
-
}),
|
|
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
|
-
}),
|
|
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
|
-
}),
|
|
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
|
-
}),
|
|
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
|
-
})
|
|
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
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
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
|
-
|
|
1544
|
-
return this.remoteHandle.call("navigateToView", e);
|
|
4471
|
+
return this.requireBackend().call("navigateToView", e);
|
|
1545
4472
|
}
|
|
1546
4473
|
async navigateTo(e, t) {
|
|
1547
|
-
|
|
1548
|
-
return this.remoteHandle.call("navigateTo", e, t);
|
|
4474
|
+
return this.requireBackend().call("navigateTo", e, t);
|
|
1549
4475
|
}
|
|
1550
4476
|
async setValueToHex(e) {
|
|
1551
|
-
|
|
1552
|
-
return this.remoteHandle.call("setValueToHex", e);
|
|
4477
|
+
return this.requireBackend().call("setValueToHex", e);
|
|
1553
4478
|
}
|
|
1554
4479
|
async setValueToInt(e) {
|
|
1555
|
-
|
|
1556
|
-
return this.remoteHandle.call("setValueToInt", e);
|
|
4480
|
+
return this.requireBackend().call("setValueToInt", e);
|
|
1557
4481
|
}
|
|
1558
4482
|
async setValueFloat(e) {
|
|
1559
|
-
|
|
1560
|
-
return this.remoteHandle.call("setValueFloat", e);
|
|
4483
|
+
return this.requireBackend().call("setValueFloat", e);
|
|
1561
4484
|
}
|
|
1562
4485
|
async setNote(e) {
|
|
1563
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1572
|
-
return this.remoteHandle.call("browseFile", e, t);
|
|
4492
|
+
return this.requireBackend().call("browseFile", e, t);
|
|
1573
4493
|
}
|
|
1574
4494
|
async sendKeyPress(e) {
|
|
1575
|
-
|
|
1576
|
-
return this.remoteHandle.call("sendKeyPress", e);
|
|
4495
|
+
return this.requireBackend().call("sendKeyPress", e);
|
|
1577
4496
|
}
|
|
1578
4497
|
async sendKeyDown(e) {
|
|
1579
|
-
|
|
1580
|
-
return this.remoteHandle.call("sendKeyDown", e);
|
|
4498
|
+
return this.requireBackend().call("sendKeyDown", e);
|
|
1581
4499
|
}
|
|
1582
4500
|
async sendKeyUp() {
|
|
1583
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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 ?
|
|
1614
|
-
descriptionParts: n ?
|
|
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.
|
|
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
|
|
4566
|
+
return Yn(this._state, this._screen);
|
|
1638
4567
|
}
|
|
1639
4568
|
describeContext() {
|
|
1640
|
-
let e =
|
|
1641
|
-
return e ?
|
|
4569
|
+
let e = Yn(this._state, this._screen);
|
|
4570
|
+
return e ? Zn(e) : null;
|
|
1642
4571
|
}
|
|
1643
4572
|
describeContextParts() {
|
|
1644
|
-
let e =
|
|
1645
|
-
return e ?
|
|
4573
|
+
let e = Yn(this._state, this._screen);
|
|
4574
|
+
return e ? Xn(e) : null;
|
|
1646
4575
|
}
|
|
1647
4576
|
};
|
|
1648
|
-
async function
|
|
1649
|
-
let t = new
|
|
4577
|
+
async function vr(e = {}) {
|
|
4578
|
+
let t = new _r(e);
|
|
1650
4579
|
return await t.connect(), t;
|
|
1651
4580
|
}
|
|
1652
|
-
function
|
|
1653
|
-
let t = new
|
|
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
|
|
1662
|
-
createM8Client:
|
|
1663
|
-
createM8ClientSync:
|
|
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 {
|
|
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
|