@yam8d/m8-sdk 0.5.1 → 0.5.3
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 +3 -1
- package/dist/index.js +1013 -566
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/types/engine/astar.d.ts +7 -6
- package/types/engine/engine.d.ts +2 -1
- package/types/engine/host/hostMethods.d.ts +1 -1
- package/types/engine/viewGraph.d.ts +18 -2
- package/types/engine/viewNavigation.d.ts +9 -4
- package/types/fxInsight.d.ts +3 -1
- package/types/parameterViews.d.ts +9 -0
package/dist/index.js
CHANGED
|
@@ -705,7 +705,7 @@ var D = (e) => {
|
|
|
705
705
|
down: I.Down,
|
|
706
706
|
left: I.Left,
|
|
707
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) => {
|
|
708
|
+
}, re = I.Up | I.Down | I.Left | I.Right | I.Edit | I.Opt | I.Shift, ie = 24, ae = 150, L = .1, oe = (e) => e === "up" || e === "down" ? "vertical" : "horizontal", se = (e) => {
|
|
709
709
|
switch (e) {
|
|
710
710
|
case "up": return "down";
|
|
711
711
|
case "down": return "up";
|
|
@@ -835,22 +835,22 @@ var D = (e) => {
|
|
|
835
835
|
y(), e.protocol.eventBus.off("key", k), A();
|
|
836
836
|
}
|
|
837
837
|
};
|
|
838
|
-
}, z = (e) => e?.trim().toLowerCase() ?? "",
|
|
838
|
+
}, z = (e) => e?.trim().toLowerCase() ?? "", me = /\.m[a-z0-9]{2}$/i, he = (e) => [
|
|
839
839
|
e.viewName ?? "",
|
|
840
840
|
e.viewTitle ?? "",
|
|
841
841
|
e.cursorPos?.x ?? "",
|
|
842
842
|
e.cursorPos?.y ?? "",
|
|
843
843
|
e.textUnderCursor ?? "",
|
|
844
844
|
e.currentLine ?? ""
|
|
845
|
-
].join("|"),
|
|
845
|
+
].join("|"), ge = (e) => e.textUnderCursor?.trim() || e.currentLine?.trim() || null, _e = (e) => {
|
|
846
846
|
let t = z(e.viewName), n = z(e.viewTitle);
|
|
847
847
|
return t.includes("load") || t.includes("save") || n.includes("load") || n.includes("save");
|
|
848
|
-
},
|
|
848
|
+
}, ve = (e) => z(e) === "/..", ye = (e) => !!e?.trim().startsWith("/"), be = (e) => !!e && !ye(e) && me.test(e.trim()), xe = (e) => {
|
|
849
849
|
let t = e?.trim() ?? "";
|
|
850
850
|
if (!t) return [];
|
|
851
|
-
let n = z(t), r = z(t.replace(
|
|
851
|
+
let n = z(t), r = z(t.replace(me, ""));
|
|
852
852
|
return Array.from(new Set([n, r].filter(Boolean)));
|
|
853
|
-
},
|
|
853
|
+
}, Se = (e) => ve(e) ? "parent" : ye(e) ? /^\/[^/]+$/.test(e.trim()) ? "dir" : "other" : be(e) ? "file" : "other", Ce = (e, t) => {
|
|
854
854
|
let n = (t) => e[t]?.trim() ?? "", r = t.cursorPos?.y ?? null, i = z(t.viewTitle), a = 0, o = e.length - 1;
|
|
855
855
|
if (r !== null && n(r)) {
|
|
856
856
|
for (a = r; a > 0 && n(a - 1);) --a;
|
|
@@ -863,7 +863,7 @@ var D = (e) => {
|
|
|
863
863
|
row: e,
|
|
864
864
|
text: t,
|
|
865
865
|
key: z(t),
|
|
866
|
-
kind:
|
|
866
|
+
kind: Se(t)
|
|
867
867
|
});
|
|
868
868
|
}
|
|
869
869
|
let c = t.textUnderCursor?.trim();
|
|
@@ -874,7 +874,7 @@ var D = (e) => {
|
|
|
874
874
|
hasParent: s.some((e) => e.kind === "parent"),
|
|
875
875
|
consistent: !c || r === null || n(r).includes(c)
|
|
876
876
|
};
|
|
877
|
-
},
|
|
877
|
+
}, we = (e, t) => {
|
|
878
878
|
if (t.length === 0) return {
|
|
879
879
|
order: e,
|
|
880
880
|
consistent: !0
|
|
@@ -908,26 +908,26 @@ var D = (e) => {
|
|
|
908
908
|
order: i,
|
|
909
909
|
consistent: !0
|
|
910
910
|
};
|
|
911
|
-
},
|
|
911
|
+
}, Te = (e) => e.split(/[^a-z0-9]+/).filter((e) => e.length >= 3), Ee = /* @__PURE__ */ new Set([
|
|
912
912
|
"load",
|
|
913
913
|
"save",
|
|
914
914
|
"select",
|
|
915
915
|
"create",
|
|
916
916
|
"directory",
|
|
917
917
|
"new"
|
|
918
|
-
]),
|
|
919
|
-
target:
|
|
920
|
-
title:
|
|
921
|
-
}),
|
|
918
|
+
]), De = (e, t) => ({
|
|
919
|
+
target: Te(z(e).replace(me, "")),
|
|
920
|
+
title: Te(z(t)).filter((e) => !Ee.has(e))
|
|
921
|
+
}), Oe = (e, t) => {
|
|
922
922
|
let n = e.replace(/^\//, "");
|
|
923
923
|
if (n.length < 3) return 0;
|
|
924
924
|
let r = (e) => e.includes(n) || n.includes(e);
|
|
925
925
|
return t.target.some(r) ? 2 : +!!t.title.some(r);
|
|
926
|
-
},
|
|
926
|
+
}, B = (e) => new Promise((t) => setTimeout(t, e)), ke = ({ getKeySink: e, store: t, debugLog: n, getScreenLines: r }) => {
|
|
927
927
|
let i = () => !!e(), a = (t) => {
|
|
928
928
|
e()?.sendKeys(t);
|
|
929
929
|
}, o = async (e, t = 50) => {
|
|
930
|
-
a(e), await
|
|
930
|
+
a(e), await B(t), a(0), await B(t);
|
|
931
931
|
}, s = (e, n = 500) => new Promise((r) => {
|
|
932
932
|
let i = !1, a = null, o = null, s = (e) => {
|
|
933
933
|
i || (i = !0, o !== null && clearTimeout(o), a?.(), r(e));
|
|
@@ -965,21 +965,21 @@ var D = (e) => {
|
|
|
965
965
|
}),
|
|
966
966
|
getFileBrowserSnapshot: c,
|
|
967
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 =
|
|
968
|
+
let i = !1, a = null, o = null, s = null, l = null, u = null, d = null, f = he(e), p = (e) => {
|
|
969
969
|
i || (i = !0, d !== null && clearTimeout(d), a?.(), o?.(), s?.(), l?.(), u?.(), r(e));
|
|
970
970
|
}, m = () => {
|
|
971
971
|
let e = c();
|
|
972
|
-
|
|
972
|
+
he(e) !== f && p(e);
|
|
973
973
|
}, h = c();
|
|
974
|
-
|
|
974
|
+
he(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
975
|
p(c());
|
|
976
976
|
}, n)) : p(h);
|
|
977
977
|
}),
|
|
978
978
|
getScreenLines: r
|
|
979
979
|
};
|
|
980
|
-
},
|
|
980
|
+
}, V = (e, t) => {
|
|
981
981
|
t === void 0 ? console.log("[M8SDK browseFile]", e) : console.log("[M8SDK browseFile]", e, t);
|
|
982
|
-
},
|
|
982
|
+
}, Ae = 8, je = 8, Me = 64, Ne = 512, Pe = () => ({
|
|
983
983
|
order: [],
|
|
984
984
|
kinds: /* @__PURE__ */ new Map(),
|
|
985
985
|
names: /* @__PURE__ */ new Map(),
|
|
@@ -989,40 +989,40 @@ var D = (e) => {
|
|
|
989
989
|
sorted: !1,
|
|
990
990
|
visited: /* @__PURE__ */ new Set(),
|
|
991
991
|
rejected: /* @__PURE__ */ new Set()
|
|
992
|
-
}),
|
|
992
|
+
}), Fe = (e) => e === "up" ? "down" : "up", Ie = (e) => {
|
|
993
993
|
let { hasBus: t, pressAndRelease: n, getFileBrowserSnapshot: r, waitForFileBrowserSnapshotChange: i, getScreenLines: a } = e, o = /* @__PURE__ */ new Map(), s = null, c = null;
|
|
994
994
|
return async (e, l = !0) => {
|
|
995
995
|
if (!t()) return !1;
|
|
996
996
|
let u = z(e);
|
|
997
997
|
if (!u) return !1;
|
|
998
|
-
let d =
|
|
999
|
-
|
|
998
|
+
let d = me.test(u), f = De(e, r().viewTitle);
|
|
999
|
+
V("start", {
|
|
1000
1000
|
targetText: e,
|
|
1001
1001
|
normalizedTarget: u,
|
|
1002
1002
|
exact: l
|
|
1003
1003
|
});
|
|
1004
|
-
let p = () =>
|
|
1004
|
+
let p = () => _e(r()), m = async (e, t = 350) => {
|
|
1005
1005
|
let a = r();
|
|
1006
1006
|
await n(e, 35);
|
|
1007
1007
|
let o = await i(a, t);
|
|
1008
1008
|
return {
|
|
1009
|
-
changed:
|
|
1009
|
+
changed: he(o) !== he(a),
|
|
1010
1010
|
snapshot: o
|
|
1011
1011
|
};
|
|
1012
1012
|
}, h = (e) => e === "up" ? I.Up : I.Down, g = (e) => I.Opt | h(e), _ = async () => {
|
|
1013
1013
|
let e = r();
|
|
1014
|
-
|
|
1015
|
-
}, v = (e) =>
|
|
1014
|
+
V("apply alphabetical sort"), await n(I.Shift | I.Opt, 35), await B(180), await i(e, 300);
|
|
1015
|
+
}, v = (e) => be(e) ? xe(e).some((e) => l ? e === u : e.includes(u)) : !1, y = (e) => {
|
|
1016
1016
|
let t = e.trim();
|
|
1017
|
-
return d ? t : t.replace(
|
|
1017
|
+
return d ? t : t.replace(me, "");
|
|
1018
1018
|
}, b = (e) => z(y(e)), x = y(e), S = async () => {
|
|
1019
1019
|
for (let e = 0;; e += 1) {
|
|
1020
|
-
let t =
|
|
1020
|
+
let t = Ce(a(), r());
|
|
1021
1021
|
if (t.consistent || e >= 2) return t;
|
|
1022
|
-
await
|
|
1022
|
+
await B(40);
|
|
1023
1023
|
}
|
|
1024
1024
|
}, C = (e, t) => {
|
|
1025
|
-
let n = t.entries.map((e) => e.key), i =
|
|
1025
|
+
let n = t.entries.map((e) => e.key), i = we(e.order, n);
|
|
1026
1026
|
e.order = i.order, i.consistent || (e.top = !1, e.bottom = !1);
|
|
1027
1027
|
for (let n of t.entries) e.kinds.set(n.key, n.kind), e.names.set(n.key, n.text);
|
|
1028
1028
|
let a = z(r().viewName);
|
|
@@ -1031,10 +1031,10 @@ var D = (e) => {
|
|
|
1031
1031
|
let e = o.get(a);
|
|
1032
1032
|
(e === void 0 || n.length < e) && o.set(a, n.length);
|
|
1033
1033
|
}
|
|
1034
|
-
n.length < Math.max(
|
|
1034
|
+
n.length < Math.max(je, o.get(a) ?? 0) && (e.top = !0, e.bottom = !0);
|
|
1035
1035
|
}, w = async (e, t, n) => {
|
|
1036
1036
|
let r = (await m(g(n), 280)).changed, i = r, a = !1;
|
|
1037
|
-
if (!r && s !== !0) for (let e = 0; e <
|
|
1037
|
+
if (!r && s !== !0) for (let e = 0; e < Ae; e += 1) {
|
|
1038
1038
|
if (!(await m(h(n), 250)).changed) {
|
|
1039
1039
|
a = !0;
|
|
1040
1040
|
break;
|
|
@@ -1042,11 +1042,11 @@ var D = (e) => {
|
|
|
1042
1042
|
i = !0, s = !1;
|
|
1043
1043
|
}
|
|
1044
1044
|
else r || (a = !0);
|
|
1045
|
-
if (a && (n === "up" ? e.top = !0 : e.bottom = !0,
|
|
1045
|
+
if (a && (n === "up" ? e.top = !0 : e.bottom = !0, V("end of list", { direction: n })), !i) return null;
|
|
1046
1046
|
let o = await S();
|
|
1047
1047
|
C(e, o);
|
|
1048
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 <
|
|
1049
|
+
return r && c >= 0 && l >= 0 && u > 0 && u < Ae && (s = !0), o;
|
|
1050
1050
|
}, T = (e, t, n) => {
|
|
1051
1051
|
if (n === "/..") return "up";
|
|
1052
1052
|
let r = e.order.indexOf(n), i = t.cursorKey ? e.order.indexOf(t.cursorKey) : -1;
|
|
@@ -1060,7 +1060,7 @@ var D = (e) => {
|
|
|
1060
1060
|
let t = n.row - r.cursorRow;
|
|
1061
1061
|
if (t === 0) return r;
|
|
1062
1062
|
let i = t < 0 ? "up" : "down";
|
|
1063
|
-
if (!(await m(Math.abs(t) >=
|
|
1063
|
+
if (!(await m(Math.abs(t) >= Ae ? g(i) : h(i), 250)).changed) return null;
|
|
1064
1064
|
r = await S(), C(e, r);
|
|
1065
1065
|
continue;
|
|
1066
1066
|
}
|
|
@@ -1068,17 +1068,17 @@ var D = (e) => {
|
|
|
1068
1068
|
let o = await w(e, r, i);
|
|
1069
1069
|
if (o) r = o;
|
|
1070
1070
|
else if (a) return null;
|
|
1071
|
-
else a = !0, i =
|
|
1071
|
+
else a = !0, i = Fe(i);
|
|
1072
1072
|
}
|
|
1073
1073
|
return null;
|
|
1074
1074
|
}, D = async (e, t) => {
|
|
1075
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
1076
|
if (!i) return "none";
|
|
1077
|
-
let a = await E(e, i.key, t), o =
|
|
1078
|
-
return a && v(o) ? (
|
|
1077
|
+
let a = await E(e, i.key, t), o = ge(r());
|
|
1078
|
+
return a && v(o) ? (V("match found", {
|
|
1079
1079
|
entry: o,
|
|
1080
1080
|
y: a.cursorRow
|
|
1081
|
-
}), await m(I.Edit, 500), "found") : (
|
|
1081
|
+
}), await m(I.Edit, 500), "found") : (V("match not reachable", { candidate: i.text }), e.rejected.add(i.key), "failed");
|
|
1082
1082
|
}, O = (e) => e.order.filter((t) => e.kinds.get(t) === "file").map((t) => {
|
|
1083
1083
|
let n = e.names.get(t) ?? "";
|
|
1084
1084
|
return {
|
|
@@ -1089,7 +1089,7 @@ var D = (e) => {
|
|
|
1089
1089
|
if (!e.sorted) return;
|
|
1090
1090
|
let t = O(e);
|
|
1091
1091
|
if (t.some((e, n) => n > 0 && (t[n - 1].ci > e.ci || t[n - 1].raw > e.raw))) {
|
|
1092
|
-
e.sorted = !1,
|
|
1092
|
+
e.sorted = !1, V("listing is not alphabetical, order hints disabled");
|
|
1093
1093
|
return;
|
|
1094
1094
|
}
|
|
1095
1095
|
let n = e.order.map((t) => {
|
|
@@ -1109,20 +1109,20 @@ var D = (e) => {
|
|
|
1109
1109
|
let n = t.cursorKey ? e.order.indexOf(t.cursorKey) : -1, r = null;
|
|
1110
1110
|
for (let [i, a] of e.kinds) {
|
|
1111
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 =
|
|
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 = Oe(i, f) * 1e4 - c;
|
|
1113
1113
|
(!r || l > r.rank) && (r = {
|
|
1114
1114
|
key: i,
|
|
1115
1115
|
rank: l
|
|
1116
1116
|
});
|
|
1117
1117
|
}
|
|
1118
1118
|
return r?.key ?? null;
|
|
1119
|
-
}, N = async (e, t) => await E(e, "/..", t) ? (
|
|
1120
|
-
if (e >
|
|
1119
|
+
}, N = async (e, t) => await E(e, "/..", t) ? (V("navigate to parent directory"), (await m(I.Edit, 500)).changed && p()) : (V("parent directory entry unreachable"), !1), P = async (e) => {
|
|
1120
|
+
if (e > Me || !p()) return V("search aborted", {
|
|
1121
1121
|
depth: e,
|
|
1122
1122
|
active: p()
|
|
1123
1123
|
}), "aborted";
|
|
1124
|
-
let t =
|
|
1125
|
-
C(t, n),
|
|
1124
|
+
let t = Pe(), n = await S();
|
|
1125
|
+
C(t, n), V("search directory", {
|
|
1126
1126
|
depth: e,
|
|
1127
1127
|
entries: n.entries.length,
|
|
1128
1128
|
complete: t.top && t.bottom
|
|
@@ -1130,7 +1130,7 @@ var D = (e) => {
|
|
|
1130
1130
|
for (let r = 0;; r += 1) {
|
|
1131
1131
|
let i = await D(t, n);
|
|
1132
1132
|
if (i === "found") return "found";
|
|
1133
|
-
if (i === "failed" && (n = await S(), C(t, n)), k(t), A(t) && (
|
|
1133
|
+
if (i === "failed" && (n = await S(), C(t, n)), k(t), A(t) && (V("rest of listing is past the target", { depth: e }), t.bottom = !0), t.top && t.bottom || r >= Ne) break;
|
|
1134
1134
|
let a = await w(t, n, j(t, n));
|
|
1135
1135
|
a && (n = a);
|
|
1136
1136
|
}
|
|
@@ -1138,10 +1138,10 @@ var D = (e) => {
|
|
|
1138
1138
|
let r = M(t, n);
|
|
1139
1139
|
if (!r) break;
|
|
1140
1140
|
if (t.visited.add(r), !await E(t, r, n)) {
|
|
1141
|
-
|
|
1141
|
+
V("directory unreachable", { directory: r }), n = await S(), C(t, n);
|
|
1142
1142
|
continue;
|
|
1143
1143
|
}
|
|
1144
|
-
|
|
1144
|
+
V("enter directory", {
|
|
1145
1145
|
directory: r,
|
|
1146
1146
|
depth: e
|
|
1147
1147
|
});
|
|
@@ -1160,12 +1160,12 @@ var D = (e) => {
|
|
|
1160
1160
|
if (!p()) return console.warn("[M8SDK] browseFile requires a file browser view (load/save)"), !1;
|
|
1161
1161
|
if (a().length === 0) return console.warn("[M8SDK] browseFile needs the screen reader, which is not available"), !1;
|
|
1162
1162
|
let F = await P(0);
|
|
1163
|
-
return F !== "found" &&
|
|
1163
|
+
return F !== "found" && V("search failed", {
|
|
1164
1164
|
targetText: e,
|
|
1165
1165
|
outcome: F
|
|
1166
1166
|
}), F === "found";
|
|
1167
1167
|
};
|
|
1168
|
-
},
|
|
1168
|
+
}, Le = (e) => {
|
|
1169
1169
|
if (!e) return null;
|
|
1170
1170
|
let t = e.trim();
|
|
1171
1171
|
if (t === "--") return 0;
|
|
@@ -1173,7 +1173,7 @@ var D = (e) => {
|
|
|
1173
1173
|
if (!n) return null;
|
|
1174
1174
|
let r = parseInt(n[0], 16);
|
|
1175
1175
|
return Number.isNaN(r) ? null : r;
|
|
1176
|
-
},
|
|
1176
|
+
}, Re = (e) => {
|
|
1177
1177
|
if (!e) return null;
|
|
1178
1178
|
let t = e.trim();
|
|
1179
1179
|
if (t === "--") return 0;
|
|
@@ -1181,11 +1181,11 @@ var D = (e) => {
|
|
|
1181
1181
|
if (!n) return null;
|
|
1182
1182
|
let r = Number.parseInt(n[0], 10);
|
|
1183
1183
|
return Number.isNaN(r) ? null : r;
|
|
1184
|
-
},
|
|
1184
|
+
}, ze = /[+-]?\d+\.\d+/g, Be = (e) => {
|
|
1185
1185
|
if (!e) return [];
|
|
1186
1186
|
let t = [];
|
|
1187
|
-
|
|
1188
|
-
let n =
|
|
1187
|
+
ze.lastIndex = 0;
|
|
1188
|
+
let n = ze.exec(e);
|
|
1189
1189
|
for (; n !== null;) {
|
|
1190
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
1191
|
!Number.isNaN(l) && !Number.isNaN(u) && t.push({
|
|
@@ -1196,16 +1196,16 @@ var D = (e) => {
|
|
|
1196
1196
|
decScale: d,
|
|
1197
1197
|
tickHundredths: f,
|
|
1198
1198
|
ticks: (i ? -1 : 1) * Math.round(p / f)
|
|
1199
|
-
}), n =
|
|
1199
|
+
}), n = ze.exec(e);
|
|
1200
1200
|
}
|
|
1201
1201
|
return t;
|
|
1202
|
-
},
|
|
1202
|
+
}, Ve = (e, t) => {
|
|
1203
1203
|
if (e.length <= 1) return 0;
|
|
1204
1204
|
let n = t?.trim() ?? "";
|
|
1205
1205
|
if (!n) return 0;
|
|
1206
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
1207
|
return r >= 0 ? r : 0;
|
|
1208
|
-
},
|
|
1208
|
+
}, He = (e, t) => {
|
|
1209
1209
|
if (!e) return null;
|
|
1210
1210
|
let n = t?.trim() ?? "";
|
|
1211
1211
|
if (!n) return null;
|
|
@@ -1219,13 +1219,13 @@ var D = (e) => {
|
|
|
1219
1219
|
if (r && !t) return "dec";
|
|
1220
1220
|
}
|
|
1221
1221
|
return null;
|
|
1222
|
-
},
|
|
1222
|
+
}, Ue = (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, We = (e, t, n) => {
|
|
1223
1223
|
let r = n?.trim() ?? "";
|
|
1224
|
-
return !r || !e[t] ||
|
|
1225
|
-
},
|
|
1224
|
+
return !r || !e[t] || Ue(e[t], r) ? !1 : e.some((e, n) => n !== t && Ue(e, r));
|
|
1225
|
+
}, H = (e, t) => {
|
|
1226
1226
|
let n = Math.round(e * t), r = n < 0 ? "-" : "", i = Math.abs(n), a = Math.floor(i / 100);
|
|
1227
1227
|
return `${r}${a}.${(i - a * 100).toString().padStart(2, "0")}`;
|
|
1228
|
-
},
|
|
1228
|
+
}, Ge = [
|
|
1229
1229
|
"C-",
|
|
1230
1230
|
"C#",
|
|
1231
1231
|
"D-",
|
|
@@ -1238,35 +1238,35 @@ var D = (e) => {
|
|
|
1238
1238
|
"A-",
|
|
1239
1239
|
"A#",
|
|
1240
1240
|
"B-"
|
|
1241
|
-
],
|
|
1241
|
+
], U = (e) => {
|
|
1242
1242
|
if (!e) return null;
|
|
1243
1243
|
let t = e.trim().toUpperCase().match(/([A-G][#-][0-9A-F])/);
|
|
1244
1244
|
if (!t) return null;
|
|
1245
|
-
let n = t[1], r = n.slice(0, 2), i = Number.parseInt(n.slice(2, 3), 16), a =
|
|
1245
|
+
let n = t[1], r = n.slice(0, 2), i = Number.parseInt(n.slice(2, 3), 16), a = Ge.indexOf(r);
|
|
1246
1246
|
return a < 0 || Number.isNaN(i) ? null : {
|
|
1247
1247
|
label: n,
|
|
1248
1248
|
noteName: r,
|
|
1249
1249
|
octave: i,
|
|
1250
1250
|
semitoneIndex: i * 12 + a
|
|
1251
1251
|
};
|
|
1252
|
-
},
|
|
1252
|
+
}, Ke = (e) => {
|
|
1253
1253
|
let { store: t, debugLog: n, hasBus: r, sendKeys: i, pressAndRelease: a, waitForTextUnderCursorChange: o, waitForCurrentLineChange: s } = e;
|
|
1254
1254
|
return async (e) => {
|
|
1255
1255
|
if (!r() || !Number.isFinite(e)) return !1;
|
|
1256
1256
|
let c = 0, l = 1, u = [], d = () => {
|
|
1257
|
-
let e =
|
|
1257
|
+
let e = Be(t.get("currentLine"));
|
|
1258
1258
|
if (u = e, !e.length) return null;
|
|
1259
1259
|
c = Math.min(c, e.length - 1);
|
|
1260
1260
|
let n = e[c];
|
|
1261
1261
|
return n.tickHundredths > 0 && (l = n.tickHundredths), n;
|
|
1262
|
-
}, f =
|
|
1262
|
+
}, f = Be(t.get("currentLine"));
|
|
1263
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 =
|
|
1264
|
+
c = Ve(f, t.get("textUnderCursor")), f.length > 1 && n("[M8SDK] Multiple float values on line, editing:", f[c]?.raw);
|
|
1265
1265
|
let p = f[c];
|
|
1266
1266
|
l = p.tickHundredths;
|
|
1267
1267
|
let m = Math.round(Math.round(e * 100) / l);
|
|
1268
|
-
if (p.ticks === m) return n("[M8SDK] Already at target float value:",
|
|
1269
|
-
n("[M8SDK] Setting float value from",
|
|
1268
|
+
if (p.ticks === m) return n("[M8SDK] Already at target float value:", H(m, l)), !0;
|
|
1269
|
+
n("[M8SDK] Setting float value from", H(p.ticks, l), "to", H(m, l)), await a(I.Edit), await B(80);
|
|
1270
1270
|
let h = () => ({
|
|
1271
1271
|
upDown: {
|
|
1272
1272
|
mag: null,
|
|
@@ -1280,17 +1280,17 @@ var D = (e) => {
|
|
|
1280
1280
|
full: h(),
|
|
1281
1281
|
int: h(),
|
|
1282
1282
|
dec: h()
|
|
1283
|
-
}, _ = p.decScale, v = Date.now(), y =
|
|
1283
|
+
}, _ = p.decScale, v = Date.now(), y = He(p, t.get("textUnderCursor")) ?? "int";
|
|
1284
1284
|
n("[M8SDK] Float cursor focus:", y);
|
|
1285
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
1286
|
let n = e === "upDown" ? I.Up : I.Right, r = e === "upDown" ? I.Down : I.Left;
|
|
1287
1287
|
return I.Edit | (t >= 0 ? n : r);
|
|
1288
1288
|
}, A = async (e, n, r) => {
|
|
1289
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
|
|
1290
|
+
for (let e = 0; e < r; e++) i(o), await B(22);
|
|
1291
1291
|
await s(c, 350);
|
|
1292
1292
|
}, ee = async (e) => {
|
|
1293
|
-
let n = () =>
|
|
1293
|
+
let n = () => He(d(), t.get("textUnderCursor"));
|
|
1294
1294
|
if (n() === e) return y = e, !0;
|
|
1295
1295
|
let r = t.get("textUnderCursor"), i = e === "dec" ? I.Right : I.Left, s = e === "dec" ? I.Left : I.Right;
|
|
1296
1296
|
if (await a(i, 35), await o(r, 250), n() === e) return y = e, !0;
|
|
@@ -1304,7 +1304,7 @@ var D = (e) => {
|
|
|
1304
1304
|
console.warn("[M8SDK] Float value no longer parseable while editing:", t.get("currentLine")), O = !0;
|
|
1305
1305
|
break;
|
|
1306
1306
|
}
|
|
1307
|
-
if (
|
|
1307
|
+
if (We(u, c, t.get("textUnderCursor"))) {
|
|
1308
1308
|
console.warn("[M8SDK] Float cursor drifted to another field, aborting to avoid editing the wrong value"), x = !0, O = !0;
|
|
1309
1309
|
break;
|
|
1310
1310
|
}
|
|
@@ -1323,7 +1323,7 @@ var D = (e) => {
|
|
|
1323
1323
|
if (C = S, S = e.ticks, y !== "full" && !b) {
|
|
1324
1324
|
let e = i >= _ ? "int" : "dec";
|
|
1325
1325
|
if (e !== y && !await ee(e)) {
|
|
1326
|
-
if (
|
|
1326
|
+
if (We(u, c, t.get("textUnderCursor"))) {
|
|
1327
1327
|
console.warn("[M8SDK] Float cursor drifted to another field, aborting to avoid editing the wrong value"), x = !0, O = !0;
|
|
1328
1328
|
break;
|
|
1329
1329
|
}
|
|
@@ -1341,7 +1341,7 @@ var D = (e) => {
|
|
|
1341
1341
|
}
|
|
1342
1342
|
let P = N.ticks - k;
|
|
1343
1343
|
if (P === 0) {
|
|
1344
|
-
E += 1, E >= 4 && (console.warn(`[M8SDK] Float value stopped reacting at ${
|
|
1344
|
+
E += 1, E >= 4 && (console.warn(`[M8SDK] Float value stopped reacting at ${H(N.ticks, l)} (target ${H(m, l)} may be out of range)`), O = !0);
|
|
1345
1345
|
continue;
|
|
1346
1346
|
}
|
|
1347
1347
|
E = 0;
|
|
@@ -1365,9 +1365,9 @@ var D = (e) => {
|
|
|
1365
1365
|
}
|
|
1366
1366
|
x || await a(I.Edit);
|
|
1367
1367
|
let j = d(), M = !!j && j.ticks === m;
|
|
1368
|
-
return n(`[M8SDK] Float setting ${M ? "succeeded" : "failed"}: "${j?.raw ?? "N/A"}" (${j ?
|
|
1368
|
+
return n(`[M8SDK] Float setting ${M ? "succeeded" : "failed"}: "${j?.raw ?? "N/A"}" (${j ? H(j.ticks, l) : "N/A"})`), M;
|
|
1369
1369
|
};
|
|
1370
|
-
},
|
|
1370
|
+
}, qe = {
|
|
1371
1371
|
song: [
|
|
1372
1372
|
{
|
|
1373
1373
|
to: "project",
|
|
@@ -1386,15 +1386,68 @@ var D = (e) => {
|
|
|
1386
1386
|
keys: [20, 0]
|
|
1387
1387
|
}
|
|
1388
1388
|
],
|
|
1389
|
-
project: [
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1389
|
+
project: [
|
|
1390
|
+
{
|
|
1391
|
+
to: "song",
|
|
1392
|
+
dir: "down",
|
|
1393
|
+
keys: [48, 0],
|
|
1394
|
+
back: !0
|
|
1395
|
+
},
|
|
1396
|
+
{
|
|
1397
|
+
to: "chain",
|
|
1398
|
+
dir: "down",
|
|
1399
|
+
keys: [48, 0],
|
|
1400
|
+
back: !0
|
|
1401
|
+
},
|
|
1402
|
+
{
|
|
1403
|
+
to: "midisettings",
|
|
1404
|
+
via: "button",
|
|
1405
|
+
cursor: [14, 11],
|
|
1406
|
+
label: "SETTINGS",
|
|
1407
|
+
keys: [1, 0],
|
|
1408
|
+
weight: 2
|
|
1409
|
+
},
|
|
1410
|
+
{
|
|
1411
|
+
to: "midimapping",
|
|
1412
|
+
via: "button",
|
|
1413
|
+
cursor: [23, 11],
|
|
1414
|
+
label: "MAPPINGS",
|
|
1415
|
+
keys: [1, 0],
|
|
1416
|
+
weight: 2
|
|
1417
|
+
},
|
|
1418
|
+
{
|
|
1419
|
+
to: "renderaudio",
|
|
1420
|
+
via: "button",
|
|
1421
|
+
cursor: [14, 15],
|
|
1422
|
+
label: "RENDER",
|
|
1423
|
+
keys: [1, 0],
|
|
1424
|
+
weight: 2
|
|
1425
|
+
},
|
|
1426
|
+
{
|
|
1427
|
+
to: "instrumentpool",
|
|
1428
|
+
via: "button",
|
|
1429
|
+
cursor: [14, 17],
|
|
1430
|
+
label: "VIEW INST. POOL",
|
|
1431
|
+
keys: [1, 0],
|
|
1432
|
+
weight: 2
|
|
1433
|
+
},
|
|
1434
|
+
{
|
|
1435
|
+
to: "timestats",
|
|
1436
|
+
via: "button",
|
|
1437
|
+
cursor: [14, 19],
|
|
1438
|
+
label: "VIEW TIME STATS",
|
|
1439
|
+
keys: [1, 0],
|
|
1440
|
+
weight: 2
|
|
1441
|
+
},
|
|
1442
|
+
{
|
|
1443
|
+
to: "systemsettings",
|
|
1444
|
+
via: "button",
|
|
1445
|
+
cursor: [14, 20],
|
|
1446
|
+
label: "SETTINGS",
|
|
1447
|
+
keys: [1, 0],
|
|
1448
|
+
weight: 2
|
|
1449
|
+
}
|
|
1450
|
+
],
|
|
1398
1451
|
mixer: [
|
|
1399
1452
|
{
|
|
1400
1453
|
to: "effectsettings",
|
|
@@ -1405,38 +1458,95 @@ var D = (e) => {
|
|
|
1405
1458
|
to: "song",
|
|
1406
1459
|
dir: "up",
|
|
1407
1460
|
keys: [80, 0],
|
|
1408
|
-
weight: 10
|
|
1461
|
+
weight: 10,
|
|
1462
|
+
back: !0
|
|
1409
1463
|
},
|
|
1410
1464
|
{
|
|
1411
1465
|
to: "chain",
|
|
1412
1466
|
dir: "up",
|
|
1413
1467
|
keys: [80, 0],
|
|
1414
|
-
weight: 10
|
|
1468
|
+
weight: 10,
|
|
1469
|
+
back: !0
|
|
1415
1470
|
},
|
|
1416
1471
|
{
|
|
1417
1472
|
to: "phrase",
|
|
1418
1473
|
dir: "up",
|
|
1419
1474
|
keys: [80, 0],
|
|
1420
|
-
weight: 10
|
|
1475
|
+
weight: 10,
|
|
1476
|
+
back: !0
|
|
1421
1477
|
},
|
|
1422
1478
|
{
|
|
1423
1479
|
to: "inst",
|
|
1424
1480
|
dir: "up",
|
|
1425
1481
|
keys: [80, 0],
|
|
1426
|
-
weight: 10
|
|
1482
|
+
weight: 10,
|
|
1483
|
+
back: !0
|
|
1427
1484
|
},
|
|
1428
1485
|
{
|
|
1429
1486
|
to: "table",
|
|
1430
1487
|
dir: "up",
|
|
1431
1488
|
keys: [80, 0],
|
|
1432
|
-
weight: 10
|
|
1489
|
+
weight: 10,
|
|
1490
|
+
back: !0
|
|
1491
|
+
},
|
|
1492
|
+
{
|
|
1493
|
+
to: "mixeq",
|
|
1494
|
+
via: "button",
|
|
1495
|
+
cursor: [28, 17],
|
|
1496
|
+
keys: [
|
|
1497
|
+
64,
|
|
1498
|
+
0,
|
|
1499
|
+
20,
|
|
1500
|
+
0
|
|
1501
|
+
],
|
|
1502
|
+
weight: 2
|
|
1503
|
+
},
|
|
1504
|
+
{
|
|
1505
|
+
to: "mixscope",
|
|
1506
|
+
via: "button",
|
|
1507
|
+
cursor: [28, 17],
|
|
1508
|
+
keys: [20, 0],
|
|
1509
|
+
weight: 2
|
|
1510
|
+
},
|
|
1511
|
+
{
|
|
1512
|
+
to: "limiterscope",
|
|
1513
|
+
via: "button",
|
|
1514
|
+
cursor: [28, 18],
|
|
1515
|
+
keys: [20, 0],
|
|
1516
|
+
weight: 2
|
|
1517
|
+
}
|
|
1518
|
+
],
|
|
1519
|
+
effectsettings: [
|
|
1520
|
+
{
|
|
1521
|
+
to: "mixer",
|
|
1522
|
+
dir: "up",
|
|
1523
|
+
keys: [80, 0]
|
|
1524
|
+
},
|
|
1525
|
+
{
|
|
1526
|
+
to: "modfxeq",
|
|
1527
|
+
via: "button",
|
|
1528
|
+
cursor: [22, 6],
|
|
1529
|
+
label: "EQ",
|
|
1530
|
+
keys: [1, 0],
|
|
1531
|
+
weight: 2
|
|
1532
|
+
},
|
|
1533
|
+
{
|
|
1534
|
+
to: "delayeq",
|
|
1535
|
+
via: "button",
|
|
1536
|
+
cursor: [22, 11],
|
|
1537
|
+
label: "EQ",
|
|
1538
|
+
keys: [1, 0],
|
|
1539
|
+
weight: 2
|
|
1540
|
+
},
|
|
1541
|
+
{
|
|
1542
|
+
to: "reverbeq",
|
|
1543
|
+
via: "button",
|
|
1544
|
+
cursor: [22, 17],
|
|
1545
|
+
label: "EQ",
|
|
1546
|
+
keys: [1, 0],
|
|
1547
|
+
weight: 2
|
|
1433
1548
|
}
|
|
1434
1549
|
],
|
|
1435
|
-
effectsettings: [{
|
|
1436
|
-
to: "mixer",
|
|
1437
|
-
dir: "up",
|
|
1438
|
-
keys: [80, 0]
|
|
1439
|
-
}],
|
|
1440
1550
|
inst: [
|
|
1441
1551
|
{
|
|
1442
1552
|
to: "table",
|
|
@@ -1458,6 +1568,20 @@ var D = (e) => {
|
|
|
1458
1568
|
dir: "down",
|
|
1459
1569
|
keys: [48, 0],
|
|
1460
1570
|
weight: 10
|
|
1571
|
+
},
|
|
1572
|
+
{
|
|
1573
|
+
to: "loadinstrument",
|
|
1574
|
+
via: "button",
|
|
1575
|
+
cursor: [23, 5],
|
|
1576
|
+
label: "LOAD",
|
|
1577
|
+
keys: [1, 0],
|
|
1578
|
+
weight: 2
|
|
1579
|
+
},
|
|
1580
|
+
{
|
|
1581
|
+
to: "instrumentpool",
|
|
1582
|
+
dir: "left",
|
|
1583
|
+
keys: [144, 0],
|
|
1584
|
+
back: !0
|
|
1461
1585
|
}
|
|
1462
1586
|
],
|
|
1463
1587
|
table: [
|
|
@@ -1547,71 +1671,199 @@ var D = (e) => {
|
|
|
1547
1671
|
{
|
|
1548
1672
|
to: "inst",
|
|
1549
1673
|
dir: "down",
|
|
1550
|
-
keys: [48, 0]
|
|
1674
|
+
keys: [48, 0],
|
|
1675
|
+
back: !0
|
|
1551
1676
|
},
|
|
1552
1677
|
{
|
|
1553
1678
|
to: "table",
|
|
1554
1679
|
dir: "down",
|
|
1680
|
+
keys: [48, 0],
|
|
1681
|
+
back: !0
|
|
1682
|
+
}
|
|
1683
|
+
],
|
|
1684
|
+
instrumentpool: [
|
|
1685
|
+
{
|
|
1686
|
+
to: "instmods",
|
|
1687
|
+
dir: "down",
|
|
1555
1688
|
keys: [48, 0]
|
|
1689
|
+
},
|
|
1690
|
+
{
|
|
1691
|
+
to: "inst",
|
|
1692
|
+
dir: "right",
|
|
1693
|
+
keys: [20, 0]
|
|
1694
|
+
},
|
|
1695
|
+
{
|
|
1696
|
+
to: "phrase",
|
|
1697
|
+
dir: "left",
|
|
1698
|
+
keys: [144, 0],
|
|
1699
|
+
weight: 4
|
|
1556
1700
|
}
|
|
1557
1701
|
],
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1702
|
+
systemsettings: [
|
|
1703
|
+
{
|
|
1704
|
+
to: "themesettings",
|
|
1705
|
+
via: "button",
|
|
1706
|
+
cursor: [16, 7],
|
|
1707
|
+
label: "EDIT THEME",
|
|
1708
|
+
keys: [1, 0],
|
|
1709
|
+
weight: 2
|
|
1710
|
+
},
|
|
1711
|
+
{
|
|
1712
|
+
to: "project",
|
|
1713
|
+
via: "exit",
|
|
1714
|
+
keys: [2, 0]
|
|
1715
|
+
},
|
|
1716
|
+
{
|
|
1717
|
+
to: "project",
|
|
1718
|
+
dir: "up",
|
|
1719
|
+
keys: [80, 0],
|
|
1720
|
+
weight: 2
|
|
1721
|
+
}
|
|
1722
|
+
],
|
|
1723
|
+
midisettings: [{
|
|
1724
|
+
to: "project",
|
|
1725
|
+
via: "exit",
|
|
1726
|
+
keys: [2, 0]
|
|
1727
|
+
}, {
|
|
1728
|
+
to: "project",
|
|
1729
|
+
dir: "up",
|
|
1730
|
+
keys: [80, 0],
|
|
1731
|
+
weight: 3
|
|
1732
|
+
}],
|
|
1733
|
+
midimapping: [{
|
|
1734
|
+
to: "project",
|
|
1735
|
+
via: "exit",
|
|
1736
|
+
keys: [2, 0]
|
|
1737
|
+
}, {
|
|
1738
|
+
to: "project",
|
|
1739
|
+
dir: "up",
|
|
1740
|
+
keys: [80, 0],
|
|
1741
|
+
weight: 3
|
|
1742
|
+
}],
|
|
1743
|
+
renderaudio: [{
|
|
1744
|
+
to: "project",
|
|
1745
|
+
via: "exit",
|
|
1746
|
+
keys: [2, 0]
|
|
1747
|
+
}, {
|
|
1748
|
+
to: "project",
|
|
1749
|
+
dir: "up",
|
|
1750
|
+
keys: [80, 0],
|
|
1751
|
+
weight: 3
|
|
1752
|
+
}],
|
|
1753
|
+
timestats: [{
|
|
1754
|
+
to: "project",
|
|
1755
|
+
via: "exit",
|
|
1756
|
+
keys: [2, 0]
|
|
1757
|
+
}, {
|
|
1758
|
+
to: "project",
|
|
1759
|
+
dir: "up",
|
|
1760
|
+
keys: [80, 0],
|
|
1761
|
+
weight: 3
|
|
1762
|
+
}],
|
|
1763
|
+
loadproject: [{
|
|
1764
|
+
to: "project",
|
|
1765
|
+
via: "exit",
|
|
1766
|
+
keys: [2, 0]
|
|
1767
|
+
}],
|
|
1768
|
+
themesettings: [{
|
|
1769
|
+
to: "systemsettings",
|
|
1770
|
+
via: "exit",
|
|
1771
|
+
keys: [2, 0]
|
|
1772
|
+
}],
|
|
1773
|
+
mixeq: [{
|
|
1774
|
+
to: "mixer",
|
|
1775
|
+
via: "exit",
|
|
1776
|
+
keys: [2, 0]
|
|
1777
|
+
}, {
|
|
1778
|
+
to: "mixer",
|
|
1779
|
+
dir: "left",
|
|
1780
|
+
keys: [144, 0],
|
|
1781
|
+
weight: 3
|
|
1782
|
+
}],
|
|
1783
|
+
mixscope: [{
|
|
1784
|
+
to: "mixer",
|
|
1785
|
+
via: "exit",
|
|
1786
|
+
keys: [2, 0]
|
|
1787
|
+
}, {
|
|
1788
|
+
to: "mixer",
|
|
1789
|
+
dir: "left",
|
|
1790
|
+
keys: [144, 0],
|
|
1791
|
+
weight: 3
|
|
1792
|
+
}],
|
|
1793
|
+
limiterscope: [{
|
|
1794
|
+
to: "mixer",
|
|
1795
|
+
via: "exit",
|
|
1796
|
+
keys: [2, 0]
|
|
1797
|
+
}, {
|
|
1798
|
+
to: "mixer",
|
|
1799
|
+
dir: "left",
|
|
1800
|
+
keys: [144, 0],
|
|
1801
|
+
weight: 3
|
|
1802
|
+
}],
|
|
1803
|
+
modfxeq: [{
|
|
1804
|
+
to: "effectsettings",
|
|
1805
|
+
via: "exit",
|
|
1806
|
+
keys: [2, 0]
|
|
1807
|
+
}],
|
|
1808
|
+
delayeq: [{
|
|
1809
|
+
to: "effectsettings",
|
|
1810
|
+
via: "exit",
|
|
1811
|
+
keys: [2, 0]
|
|
1812
|
+
}],
|
|
1813
|
+
reverbeq: [{
|
|
1814
|
+
to: "effectsettings",
|
|
1815
|
+
via: "exit",
|
|
1816
|
+
keys: [2, 0]
|
|
1817
|
+
}],
|
|
1818
|
+
loadinstrument: [{
|
|
1819
|
+
to: "inst",
|
|
1820
|
+
via: "exit",
|
|
1821
|
+
keys: [2, 0]
|
|
1562
1822
|
}]
|
|
1563
|
-
},
|
|
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) => {
|
|
1823
|
+
}, Je = { views: /* @__PURE__ */ "chain.effectsettings.groove.instmods.inst.instrumentpool.mixer.phrase.project.scale.song.table.mixeq.limiterscope.mixscope.modfxeq.delayeq.reverbeq.loadinstrument.selectsavedirectory.createdirectory.systemsettings.midisettings.midimapping.renderaudio.timestats.themesettings.loadproject".split(".") }, Ye = (e) => {
|
|
1587
1824
|
let t = /* @__PURE__ */ new Map(), n = /* @__PURE__ */ new Map();
|
|
1588
1825
|
for (let [r, i] of Object.entries(e)) {
|
|
1589
1826
|
let e = r.toLowerCase(), a = [], o = /* @__PURE__ */ new Map();
|
|
1590
|
-
for (let
|
|
1591
|
-
|
|
1592
|
-
dir
|
|
1593
|
-
|
|
1594
|
-
|
|
1827
|
+
for (let t of i) {
|
|
1828
|
+
let n = t.via ?? "shift";
|
|
1829
|
+
if (n === "shift" && !t.dir || n === "button" && !t.cursor) continue;
|
|
1830
|
+
let r = t.keys?.slice() ?? [];
|
|
1831
|
+
a.push({
|
|
1832
|
+
from: e,
|
|
1833
|
+
to: t.to.toLowerCase(),
|
|
1834
|
+
dir: t.dir,
|
|
1835
|
+
weight: t.weight,
|
|
1836
|
+
kind: n,
|
|
1837
|
+
keys: r,
|
|
1838
|
+
cursor: t.cursor ? {
|
|
1839
|
+
x: t.cursor[0],
|
|
1840
|
+
y: t.cursor[1]
|
|
1841
|
+
} : void 0,
|
|
1842
|
+
label: t.label,
|
|
1843
|
+
back: t.back
|
|
1844
|
+
}), n === "shift" && r.length && o.set(t.to, r);
|
|
1845
|
+
}
|
|
1595
1846
|
t.set(e, a), o.size && n.set(e, o);
|
|
1596
1847
|
}
|
|
1848
|
+
for (let e of [...t.values()]) for (let n of e) t.has(n.to) || t.set(n.to, []);
|
|
1597
1849
|
return {
|
|
1598
1850
|
graph: t,
|
|
1599
1851
|
edgeKeys: n
|
|
1600
1852
|
};
|
|
1601
|
-
},
|
|
1602
|
-
if (!
|
|
1603
|
-
let e = Array.isArray(
|
|
1604
|
-
|
|
1853
|
+
}, Xe = null, Ze = null, Qe = () => (Xe ??= Ye(qe), Xe), $e = () => {
|
|
1854
|
+
if (!Ze) {
|
|
1855
|
+
let e = Array.isArray(Je.views) ? Je.views : [];
|
|
1856
|
+
Ze = new Set(e.map((e) => String(e).trim().toLowerCase()).filter((e) => !!e));
|
|
1605
1857
|
}
|
|
1606
|
-
return
|
|
1607
|
-
},
|
|
1858
|
+
return Ze;
|
|
1859
|
+
}, et = 50, tt = {
|
|
1608
1860
|
x: 0,
|
|
1609
1861
|
y: 0,
|
|
1610
1862
|
w: 1,
|
|
1611
1863
|
h: 1
|
|
1612
|
-
},
|
|
1864
|
+
}, nt = class {
|
|
1613
1865
|
constructor() {
|
|
1614
|
-
this.assemblies = [], this.selectionRectSamples = [], this.lastCursor =
|
|
1866
|
+
this.assemblies = [], this.selectionRectSamples = [], this.lastCursor = tt, 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
1867
|
}
|
|
1616
1868
|
processRect(e) {
|
|
1617
1869
|
if (!e) return {
|
|
@@ -1803,7 +2055,7 @@ var D = (e) => {
|
|
|
1803
2055
|
].filter((e) => e.foundVert || e.foundTip).length >= 2;
|
|
1804
2056
|
}
|
|
1805
2057
|
buildCursorFromAssembly(e) {
|
|
1806
|
-
if (!e.tr || !e.bl || !e.br) return
|
|
2058
|
+
if (!e.tr || !e.bl || !e.br) return tt;
|
|
1807
2059
|
let t = e.tr.x - e.tl.x - 1, n = e.bl.y - e.tl.y - 1;
|
|
1808
2060
|
return {
|
|
1809
2061
|
x: e.tl.x + 1,
|
|
@@ -1820,19 +2072,19 @@ var D = (e) => {
|
|
|
1820
2072
|
h: 1
|
|
1821
2073
|
}, this.lastSelectionCursor = null, this.lastSelectionMode = !1, this.lastSelectionSeenAt = 0;
|
|
1822
2074
|
}
|
|
1823
|
-
},
|
|
2075
|
+
}, rt = (e) => e ? `#${[
|
|
1824
2076
|
e.r,
|
|
1825
2077
|
e.g,
|
|
1826
2078
|
e.b
|
|
1827
2079
|
].map((e) => e.toString(16).padStart(2, "0")).join("")}` : null;
|
|
1828
|
-
function
|
|
1829
|
-
let n = new
|
|
2080
|
+
function it(e, t) {
|
|
2081
|
+
let n = new nt();
|
|
1830
2082
|
class r {
|
|
1831
2083
|
constructor() {
|
|
1832
2084
|
this.rowChars = /* @__PURE__ */ new Map(), this.timer = null, this.knownViews = [], this.earlyAccepted = !1;
|
|
1833
2085
|
}
|
|
1834
2086
|
init() {
|
|
1835
|
-
this.knownViews = Array.from(
|
|
2087
|
+
this.knownViews = Array.from($e());
|
|
1836
2088
|
}
|
|
1837
2089
|
normForCompare(e) {
|
|
1838
2090
|
return e = e.includes("live") ? "song" : e, e.toLowerCase().trim().replace(/[{}]/g, "0");
|
|
@@ -1876,7 +2128,7 @@ function rt(e, t) {
|
|
|
1876
2128
|
bg: e.background
|
|
1877
2129
|
}), this.tryEarlyAccept(o), this.timer && clearTimeout(this.timer), this.timer = setTimeout(() => {
|
|
1878
2130
|
this.emitStable();
|
|
1879
|
-
},
|
|
2131
|
+
}, et)));
|
|
1880
2132
|
}
|
|
1881
2133
|
reset() {
|
|
1882
2134
|
this.rowChars.clear(), this.timer &&= (clearTimeout(this.timer), null), this.earlyAccepted = !1;
|
|
@@ -1955,7 +2207,7 @@ function rt(e, t) {
|
|
|
1955
2207
|
let e = this.grid.get(i), a = [], o = [];
|
|
1956
2208
|
for (let n = 0; n < t; n += 1) {
|
|
1957
2209
|
let t = e?.get(n);
|
|
1958
|
-
a.push(
|
|
2210
|
+
a.push(rt(t?.fg)), o.push(rt(t?.bg));
|
|
1959
2211
|
}
|
|
1960
2212
|
n.push(a), r.push(o);
|
|
1961
2213
|
}
|
|
@@ -1982,7 +2234,7 @@ function rt(e, t) {
|
|
|
1982
2234
|
if (!e) return;
|
|
1983
2235
|
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
2236
|
let { cellW: r, cellH: i, offX: a, offY: o } = t.get("cellMetrics"), { cursor: c, cursorColor: l, selectionMode: u } = n.processRect(e);
|
|
1985
|
-
l &&
|
|
2237
|
+
l && rt(l) !== rt(t.get("cursorColor")) && t.set("cursorColor", l);
|
|
1986
2238
|
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
2239
|
if (u) {
|
|
1988
2240
|
let e = t.get("cursorRect");
|
|
@@ -2038,7 +2290,7 @@ function rt(e, t) {
|
|
|
2038
2290
|
}
|
|
2039
2291
|
//#endregion
|
|
2040
2292
|
//#region src/engine/host/hostState.ts
|
|
2041
|
-
var
|
|
2293
|
+
var at = (e) => {
|
|
2042
2294
|
let t = e.get("macroStatus");
|
|
2043
2295
|
return {
|
|
2044
2296
|
viewName: e.get("viewName"),
|
|
@@ -2060,13 +2312,13 @@ var it = (e) => {
|
|
|
2060
2312
|
macroCurrentStep: t.currentStep,
|
|
2061
2313
|
macroSequenceLength: t.sequenceLength
|
|
2062
2314
|
};
|
|
2063
|
-
},
|
|
2315
|
+
}, ot = (e, t, n) => {
|
|
2064
2316
|
let r = e.get("cellMetrics");
|
|
2065
2317
|
return {
|
|
2066
2318
|
x: t * r.cellW + r.offX + r.cellW / 2,
|
|
2067
2319
|
y: n * r.cellH + r.offY + r.cellH / 2
|
|
2068
2320
|
};
|
|
2069
|
-
},
|
|
2321
|
+
}, st = (e) => te({
|
|
2070
2322
|
left: e.includes("left"),
|
|
2071
2323
|
right: e.includes("right"),
|
|
2072
2324
|
up: e.includes("up"),
|
|
@@ -2075,12 +2327,12 @@ var it = (e) => {
|
|
|
2075
2327
|
play: e.includes("play"),
|
|
2076
2328
|
opt: e.includes("opt"),
|
|
2077
2329
|
edit: e.includes("edit")
|
|
2078
|
-
}),
|
|
2330
|
+
}), ct = ({ io: e, editors: t, setValueFloat: n, browseFile: r, navigateToView: i, navigateTo: a, enableMidiTransport: o, getScreenCellColors: s }) => {
|
|
2079
2331
|
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
2332
|
return {
|
|
2081
|
-
navigateToView: m("navigateToView", !1, async (e) => (c("[M8SDK] Executing navigateToView:", e),
|
|
2333
|
+
navigateToView: m("navigateToView", !1, async (e) => (c("[M8SDK] Executing navigateToView:", e), i(e))),
|
|
2082
2334
|
navigateTo: m("navigateTo", void 0, async (e, t) => {
|
|
2083
|
-
await a(
|
|
2335
|
+
await a(ot(f, e, t));
|
|
2084
2336
|
}),
|
|
2085
2337
|
setValueToHex: m("setValueToHex", !1, async (e) => (c("[M8SDK] Executing setValueToHex:", e), t.setValueToHex(e))),
|
|
2086
2338
|
setValueToInt: m("setValueToInt", !1, async (e) => (c("[M8SDK] Executing setValueToInt:", e), t.setValueToInt(e))),
|
|
@@ -2096,15 +2348,15 @@ var it = (e) => {
|
|
|
2096
2348
|
exact: t
|
|
2097
2349
|
}), r(e, t))),
|
|
2098
2350
|
sendKeyDown: m("sendKeyDown", void 0, async (e) => {
|
|
2099
|
-
c("[M8SDK] Executing sendKeyDown:", e), u(
|
|
2351
|
+
c("[M8SDK] Executing sendKeyDown:", e), u(st(e));
|
|
2100
2352
|
}),
|
|
2101
2353
|
sendKeyUp: m("sendKeyUp", void 0, async () => {
|
|
2102
2354
|
c("[M8SDK] Executing sendKeyUp"), u(0);
|
|
2103
2355
|
}),
|
|
2104
2356
|
sendKeyPress: m("sendKeyPress", void 0, async (e) => {
|
|
2105
|
-
c("[M8SDK] Executing sendKeyPress:", e), await d(
|
|
2357
|
+
c("[M8SDK] Executing sendKeyPress:", e), await d(st(e));
|
|
2106
2358
|
}),
|
|
2107
|
-
getState: async () =>
|
|
2359
|
+
getState: async () => at(f),
|
|
2108
2360
|
getScreen: async () => ({
|
|
2109
2361
|
width: 40,
|
|
2110
2362
|
height: 24,
|
|
@@ -2118,7 +2370,7 @@ var it = (e) => {
|
|
|
2118
2370
|
}),
|
|
2119
2371
|
enableMidiTransport: async () => o()
|
|
2120
2372
|
};
|
|
2121
|
-
},
|
|
2373
|
+
}, lt = 6, ut = (e) => {
|
|
2122
2374
|
let t = null, n = 0, r = null, i = null, a = (e) => performance.timeOrigin + e, o = (t) => {
|
|
2123
2375
|
let o = t.data;
|
|
2124
2376
|
if (!o || o.length === 0) return;
|
|
@@ -2129,7 +2381,7 @@ var it = (e) => {
|
|
|
2129
2381
|
let e = s - r;
|
|
2130
2382
|
e > 0 && e < 200 && (i = i == null ? e : i * .9 + e * .1);
|
|
2131
2383
|
}
|
|
2132
|
-
r = s, n += 1, n %
|
|
2384
|
+
r = s, n += 1, n % lt === 0 && e({
|
|
2133
2385
|
kind: "clock",
|
|
2134
2386
|
ticks: n,
|
|
2135
2387
|
at: s,
|
|
@@ -2197,7 +2449,7 @@ var it = (e) => {
|
|
|
2197
2449
|
t?.removeEventListener("midimessage", o), t = null;
|
|
2198
2450
|
}
|
|
2199
2451
|
};
|
|
2200
|
-
},
|
|
2452
|
+
}, dt = (e, t) => {
|
|
2201
2453
|
let n = [], r = e, i = t;
|
|
2202
2454
|
for (; r !== i;) {
|
|
2203
2455
|
let e = i - r, t = Math.abs(e), a = e > 0 ? 1 : -1;
|
|
@@ -2210,7 +2462,7 @@ var it = (e) => {
|
|
|
2210
2462
|
} else break;
|
|
2211
2463
|
}
|
|
2212
2464
|
return n;
|
|
2213
|
-
},
|
|
2465
|
+
}, ft = (e, t) => {
|
|
2214
2466
|
let n = [], r = e;
|
|
2215
2467
|
for (; r !== t;) {
|
|
2216
2468
|
let e = t - r, i = e > 0 ? 1 : -1;
|
|
@@ -2224,13 +2476,13 @@ var it = (e) => {
|
|
|
2224
2476
|
if (n.length > 2048) break;
|
|
2225
2477
|
}
|
|
2226
2478
|
return n;
|
|
2227
|
-
},
|
|
2479
|
+
}, pt = (e) => {
|
|
2228
2480
|
let { store: t, debugLog: n, hasBus: r, sendKeys: i, pressAndRelease: a, waitForTextUnderCursorChange: o } = e;
|
|
2229
2481
|
return {
|
|
2230
2482
|
setValueToHex: async (e) => {
|
|
2231
2483
|
if (!r()) return !1;
|
|
2232
2484
|
e = Math.max(0, Math.min(255, e));
|
|
2233
|
-
let s = t.get("textUnderCursor"), c =
|
|
2485
|
+
let s = t.get("textUnderCursor"), c = Le(s), l = s?.trim() === "--";
|
|
2234
2486
|
if (c === null) return console.warn("[M8SDK] Could not parse current value under cursor:", s), !1;
|
|
2235
2487
|
if (c === e && !l) return n("[M8SDK] Already at target value:", e.toString(16).padStart(2, "0").toUpperCase()), !0;
|
|
2236
2488
|
n(`[M8SDK] Setting value from "${s?.trim() ?? "N/A"}" (${c.toString(16).padStart(2, "0").toUpperCase()}) to ${e.toString(16).padStart(2, "0").toUpperCase()}`);
|
|
@@ -2239,18 +2491,18 @@ var it = (e) => {
|
|
|
2239
2491
|
n("[M8SDK] Initial value is \"--\", pressing edit to recall last value");
|
|
2240
2492
|
let e = s;
|
|
2241
2493
|
await a(I.Edit), await o(e, 250);
|
|
2242
|
-
let r = t.get("textUnderCursor"), i =
|
|
2494
|
+
let r = t.get("textUnderCursor"), i = Le(r);
|
|
2243
2495
|
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
2496
|
u = i;
|
|
2245
2497
|
} else {
|
|
2246
2498
|
let e = s;
|
|
2247
2499
|
await a(I.Edit), await o(e, 250);
|
|
2248
2500
|
}
|
|
2249
|
-
let d =
|
|
2501
|
+
let d = dt(u, e);
|
|
2250
2502
|
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
|
|
2503
|
+
for (let e of d) i(e), await B(30);
|
|
2252
2504
|
await o(s, 250);
|
|
2253
|
-
let f = t.get("textUnderCursor"), p =
|
|
2505
|
+
let f = t.get("textUnderCursor"), p = Le(f);
|
|
2254
2506
|
if (p !== e) {
|
|
2255
2507
|
n("[M8SDK] Precomputation missed target, falling back to iterative mode");
|
|
2256
2508
|
let r = p ?? u, i = Date.now();
|
|
@@ -2264,10 +2516,10 @@ var it = (e) => {
|
|
|
2264
2516
|
await a(t);
|
|
2265
2517
|
}
|
|
2266
2518
|
await o(l, 250);
|
|
2267
|
-
let u =
|
|
2519
|
+
let u = Le(t.get("textUnderCursor"));
|
|
2268
2520
|
u !== null && (r = u, n(`[M8SDK] Iterative: current value: ${r.toString(16).padStart(2, "0").toUpperCase()}`));
|
|
2269
2521
|
}
|
|
2270
|
-
p =
|
|
2522
|
+
p = Le(t.get("textUnderCursor"));
|
|
2271
2523
|
}
|
|
2272
2524
|
await a(I.Edit);
|
|
2273
2525
|
let m = p === e;
|
|
@@ -2276,7 +2528,7 @@ var it = (e) => {
|
|
|
2276
2528
|
setValueToInt: async (e) => {
|
|
2277
2529
|
if (!r()) return !1;
|
|
2278
2530
|
e = Math.floor(e);
|
|
2279
|
-
let n = t.get("textUnderCursor"), i =
|
|
2531
|
+
let n = t.get("textUnderCursor"), i = Re(n);
|
|
2280
2532
|
if (i === null) return console.warn("[M8SDK] Could not parse current integer value under cursor:", n), !1;
|
|
2281
2533
|
if (i === e) return !0;
|
|
2282
2534
|
await a(I.Edit), await o(n, 250);
|
|
@@ -2291,7 +2543,7 @@ var it = (e) => {
|
|
|
2291
2543
|
await a(I.Edit | e, 35);
|
|
2292
2544
|
}
|
|
2293
2545
|
await o(d, 250);
|
|
2294
|
-
let p =
|
|
2546
|
+
let p = Re(t.get("textUnderCursor"));
|
|
2295
2547
|
if (p === null || p === s) break;
|
|
2296
2548
|
let m = Math.abs(p - e);
|
|
2297
2549
|
m < l && (l = m, c = p);
|
|
@@ -2311,12 +2563,12 @@ var it = (e) => {
|
|
|
2311
2563
|
await a(I.Edit | e, 35);
|
|
2312
2564
|
}
|
|
2313
2565
|
await o(i, 250);
|
|
2314
|
-
let l =
|
|
2566
|
+
let l = Re(t.get("textUnderCursor"));
|
|
2315
2567
|
if (l === null || l === s) break;
|
|
2316
2568
|
s = l;
|
|
2317
2569
|
}
|
|
2318
2570
|
}
|
|
2319
|
-
return await a(I.Edit),
|
|
2571
|
+
return await a(I.Edit), Re(t.get("textUnderCursor")) === e;
|
|
2320
2572
|
},
|
|
2321
2573
|
setNote: async (e) => {
|
|
2322
2574
|
if (!r()) return !1;
|
|
@@ -2331,19 +2583,19 @@ var it = (e) => {
|
|
|
2331
2583
|
let i = t.get("textUnderCursor")?.trim().toUpperCase();
|
|
2332
2584
|
return n("[M8SDK] setNote special value result:", i), i === s;
|
|
2333
2585
|
}
|
|
2334
|
-
let c =
|
|
2586
|
+
let c = U(e);
|
|
2335
2587
|
if (!c) return console.warn("[M8SDK] Invalid note format. Expected like C-1, C#1, D#A, ---, OFF:", e), !1;
|
|
2336
2588
|
let l = t.get("textUnderCursor");
|
|
2337
2589
|
(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 =
|
|
2590
|
+
let u = U(l);
|
|
2339
2591
|
if (!u) return console.warn("[M8SDK] Could not parse current note under cursor:", l), !1;
|
|
2340
2592
|
if (u.semitoneIndex === c.semitoneIndex) return !0;
|
|
2341
2593
|
await a(I.Edit), await o(l, 250);
|
|
2342
|
-
let d =
|
|
2594
|
+
let d = ft(u.semitoneIndex, c.semitoneIndex);
|
|
2343
2595
|
if (d.length > 0) {
|
|
2344
|
-
for (let e of d) i(e), await
|
|
2596
|
+
for (let e of d) i(e), await B(25);
|
|
2345
2597
|
await o(l, 280);
|
|
2346
|
-
let e =
|
|
2598
|
+
let e = U(t.get("textUnderCursor"));
|
|
2347
2599
|
if (e?.semitoneIndex === c.semitoneIndex) return await a(I.Edit), !0;
|
|
2348
2600
|
u = e ?? u;
|
|
2349
2601
|
}
|
|
@@ -2355,19 +2607,19 @@ var it = (e) => {
|
|
|
2355
2607
|
if (e === 0) break;
|
|
2356
2608
|
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
2609
|
await a(I.Edit | i, 35), await o(p, 250);
|
|
2358
|
-
let m =
|
|
2610
|
+
let m = U(t.get("textUnderCursor"));
|
|
2359
2611
|
if (!m || m.label === l.label) break;
|
|
2360
2612
|
if (u = m, Math.abs(u.semitoneIndex - c.semitoneIndex) > d) {
|
|
2361
2613
|
let e = t.get("textUnderCursor");
|
|
2362
2614
|
await a(I.Edit | s, 35), await o(e, 250);
|
|
2363
|
-
let n =
|
|
2615
|
+
let n = U(t.get("textUnderCursor"));
|
|
2364
2616
|
n && (u = n);
|
|
2365
2617
|
break;
|
|
2366
2618
|
}
|
|
2367
2619
|
if (f.has(u.label)) break;
|
|
2368
2620
|
f.add(u.label);
|
|
2369
2621
|
}
|
|
2370
|
-
return await a(I.Edit),
|
|
2622
|
+
return await a(I.Edit), U(t.get("textUnderCursor"))?.semitoneIndex === c.semitoneIndex;
|
|
2371
2623
|
},
|
|
2372
2624
|
setValueToString: async (e, i = !0, s = !1) => {
|
|
2373
2625
|
if (!r()) return !1;
|
|
@@ -2416,7 +2668,7 @@ var it = (e) => {
|
|
|
2416
2668
|
return await a(I.Edit), !1;
|
|
2417
2669
|
}
|
|
2418
2670
|
};
|
|
2419
|
-
},
|
|
2671
|
+
}, mt = ({ bus: e, store: t, cancelOnKeydown: n = !1 }) => {
|
|
2420
2672
|
let r = [], i = null, a = !1, o = () => {
|
|
2421
2673
|
a && u("preempted by keyboard");
|
|
2422
2674
|
}, s = () => {
|
|
@@ -2442,8 +2694,8 @@ var it = (e) => {
|
|
|
2442
2694
|
});
|
|
2443
2695
|
} else c(), i = null, t.set("macroStatus", { running: !1 });
|
|
2444
2696
|
}
|
|
2445
|
-
function u(
|
|
2446
|
-
(a || r.length !== 0 || t.get("macroStatus").running) && (r = [], i = null, c(), t.set("macroStatus", { running: !1 }));
|
|
2697
|
+
function u(n) {
|
|
2698
|
+
(a || r.length !== 0 || t.get("macroStatus").running) && (i && e.commands.sendKeys(0), r = [], i = null, c(), t.set("macroStatus", { running: !1 }));
|
|
2447
2699
|
}
|
|
2448
2700
|
return {
|
|
2449
2701
|
start: (n) => {
|
|
@@ -2464,7 +2716,7 @@ var it = (e) => {
|
|
|
2464
2716
|
r = [], i = null, c();
|
|
2465
2717
|
}
|
|
2466
2718
|
};
|
|
2467
|
-
},
|
|
2719
|
+
}, ht = () => ({
|
|
2468
2720
|
viewName: null,
|
|
2469
2721
|
viewTitle: null,
|
|
2470
2722
|
minimapKey: null,
|
|
@@ -2487,9 +2739,9 @@ var it = (e) => {
|
|
|
2487
2739
|
},
|
|
2488
2740
|
systemInfo: null,
|
|
2489
2741
|
macroStatus: { running: !1 }
|
|
2490
|
-
}),
|
|
2742
|
+
}), gt = (e = {}) => {
|
|
2491
2743
|
let t = {
|
|
2492
|
-
...
|
|
2744
|
+
...ht(),
|
|
2493
2745
|
...e
|
|
2494
2746
|
}, n = /* @__PURE__ */ new Map(), r = /* @__PURE__ */ new Set();
|
|
2495
2747
|
return {
|
|
@@ -2512,8 +2764,8 @@ var it = (e) => {
|
|
|
2512
2764
|
}),
|
|
2513
2765
|
snapshot: () => ({ ...t })
|
|
2514
2766
|
};
|
|
2515
|
-
},
|
|
2516
|
-
function
|
|
2767
|
+
}, _t = () => 0, vt = () => 1;
|
|
2768
|
+
function yt(e, t, n, r = _t, i = vt) {
|
|
2517
2769
|
let a = t.trim(), o = n.trim();
|
|
2518
2770
|
if (!e.has(a) || !e.has(o)) return null;
|
|
2519
2771
|
let s = /* @__PURE__ */ new Set([a]), c = /* @__PURE__ */ new Map(), l = /* @__PURE__ */ new Map(), u = /* @__PURE__ */ new Map();
|
|
@@ -2535,12 +2787,13 @@ function vt(e, t, n, r = gt, i = _t) {
|
|
|
2535
2787
|
for (; n !== a;) {
|
|
2536
2788
|
let r = c.get(n);
|
|
2537
2789
|
if (!r) break;
|
|
2538
|
-
t.unshift(r.
|
|
2790
|
+
t.unshift(r.via), e.unshift(r.prev), n = r.prev;
|
|
2539
2791
|
}
|
|
2540
2792
|
return {
|
|
2541
2793
|
pages: e,
|
|
2542
|
-
directions: t,
|
|
2543
|
-
|
|
2794
|
+
directions: t.map((e) => e.dir),
|
|
2795
|
+
edges: t,
|
|
2796
|
+
cost: l.get(o) ?? t.length
|
|
2544
2797
|
};
|
|
2545
2798
|
}
|
|
2546
2799
|
s.delete(t);
|
|
@@ -2549,7 +2802,7 @@ function vt(e, t, n, r = gt, i = _t) {
|
|
|
2549
2802
|
let n = e.weight ?? i(t, e.to, e.dir), a = (l.get(t) ?? Infinity) + n;
|
|
2550
2803
|
a < (l.get(e.to) ?? Infinity) && (c.set(e.to, {
|
|
2551
2804
|
prev: t,
|
|
2552
|
-
|
|
2805
|
+
via: e
|
|
2553
2806
|
}), l.set(e.to, a), u.set(e.to, a + r(e.to, o)), s.has(e.to) || s.add(e.to));
|
|
2554
2807
|
}
|
|
2555
2808
|
}
|
|
@@ -2557,7 +2810,7 @@ function vt(e, t, n, r = gt, i = _t) {
|
|
|
2557
2810
|
}
|
|
2558
2811
|
//#endregion
|
|
2559
2812
|
//#region src/engine/viewNavigation.ts
|
|
2560
|
-
var
|
|
2813
|
+
var bt = 20, xt = 700, St = 80, Ct = 4e3, wt = 120, Tt = (e, t) => {
|
|
2561
2814
|
let n = !!t?.shift, r = I.Shift, i = {
|
|
2562
2815
|
up: (n ? r : 0) | I.Up,
|
|
2563
2816
|
down: (n ? r : 0) | I.Down,
|
|
@@ -2567,96 +2820,203 @@ var yt = 20, bt = (e, t) => {
|
|
|
2567
2820
|
n && a.push(r);
|
|
2568
2821
|
for (let t of e) a.push(i[t], n ? r : 0);
|
|
2569
2822
|
return a.push(0), a;
|
|
2570
|
-
},
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2823
|
+
}, Et = (e) => [{
|
|
2824
|
+
from: e,
|
|
2825
|
+
to: "",
|
|
2826
|
+
kind: "exit",
|
|
2827
|
+
keys: [I.Opt, 0]
|
|
2828
|
+
}, {
|
|
2829
|
+
from: e,
|
|
2830
|
+
to: "",
|
|
2831
|
+
kind: "shift",
|
|
2832
|
+
dir: "up",
|
|
2833
|
+
keys: [I.Shift | I.Up, 0]
|
|
2834
|
+
}], Dt = (e) => `${e.kind}:${e.dir ?? ""}:${e.keys.join(",")}:${e.cursor ? `${e.cursor.x},${e.cursor.y}` : ""}`, Ot = (e) => e[e.length - 1] === 0 ? e.slice() : [...e, 0], kt = "#goal", At = (e, t) => `${e}<${t}`, jt = (e) => new Promise((t) => setTimeout(t, e)), Mt = ({ store: e, runner: t, getScreenLines: n, moveCursor: r }) => {
|
|
2835
|
+
let i = $e(), a = null, o = 0, s = null, c = 0, l = /* @__PURE__ */ new Map(), u = "", d = e.get("viewName") || "", f = e.sub("viewName", () => {
|
|
2836
|
+
let t = e.get("viewName") || "";
|
|
2837
|
+
t && t !== d && (d && (u = d), d = t);
|
|
2838
|
+
}), p = null, m = null, h = () => {
|
|
2839
|
+
m && clearTimeout(m), m = null;
|
|
2840
|
+
}, g = (e) => {
|
|
2841
|
+
let t = (e || "").toLowerCase().trim();
|
|
2842
|
+
return i.has(t) || console.warn("Target not in viewlist", { goal: t }), t;
|
|
2843
|
+
}, _ = (e, t) => `${e.from}<${t}|${Dt(e)}`, v = (e, t) => {
|
|
2844
|
+
let n = /* @__PURE__ */ new Map();
|
|
2845
|
+
for (let t of Qe().graph.get(e) ?? []) {
|
|
2846
|
+
if (t.kind === "button" && !r) continue;
|
|
2847
|
+
let e = Dt(t);
|
|
2848
|
+
n.set(e, [...n.get(e) ?? [], t]);
|
|
2585
2849
|
}
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2850
|
+
let i = [];
|
|
2851
|
+
for (let r of n.values()) {
|
|
2852
|
+
if (l.get(_(r[0], "*")) === e) continue;
|
|
2853
|
+
let n = l.get(_(r[0], t));
|
|
2854
|
+
if (n !== void 0) {
|
|
2855
|
+
n !== e && i.push({
|
|
2856
|
+
...r[0],
|
|
2857
|
+
to: n
|
|
2858
|
+
});
|
|
2859
|
+
continue;
|
|
2860
|
+
}
|
|
2861
|
+
let a = r.find((e) => e.back && e.to === t);
|
|
2862
|
+
if (a) {
|
|
2863
|
+
i.push(a);
|
|
2864
|
+
continue;
|
|
2865
|
+
}
|
|
2866
|
+
let o = r.filter((e) => !e.back);
|
|
2867
|
+
i.push(...o.length ? o : r);
|
|
2596
2868
|
}
|
|
2597
|
-
return
|
|
2598
|
-
},
|
|
2599
|
-
let r =
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2869
|
+
return i;
|
|
2870
|
+
}, y = (e, t, n) => {
|
|
2871
|
+
let r = /* @__PURE__ */ new Map([[kt, []]]), i = [[e, t]];
|
|
2872
|
+
for (r.set(At(e, t), []); i.length;) {
|
|
2873
|
+
let [e, t] = i.shift(), a = r.get(At(e, t));
|
|
2874
|
+
if (e === n) a.push({
|
|
2875
|
+
to: kt,
|
|
2876
|
+
weight: 0,
|
|
2877
|
+
nav: {
|
|
2878
|
+
from: e,
|
|
2879
|
+
to: e,
|
|
2880
|
+
kind: "shift",
|
|
2881
|
+
keys: []
|
|
2882
|
+
}
|
|
2883
|
+
});
|
|
2884
|
+
else for (let n of v(e, t)) {
|
|
2885
|
+
let t = At(n.to, e);
|
|
2886
|
+
a.push({
|
|
2887
|
+
to: t,
|
|
2888
|
+
weight: n.weight,
|
|
2889
|
+
nav: n
|
|
2890
|
+
}), r.has(t) || (r.set(t, []), i.push([n.to, e]));
|
|
2891
|
+
}
|
|
2892
|
+
}
|
|
2893
|
+
return r;
|
|
2894
|
+
}, b = (e, t) => {
|
|
2895
|
+
let n = yt(y(e, u, t), At(e, u), kt);
|
|
2896
|
+
if (n?.edges.length) return n.edges[0].nav;
|
|
2897
|
+
let r = Qe().graph.get(e) ?? [];
|
|
2898
|
+
return r.length && !r.some((e) => e.kind === "exit") ? null : Et(e).find((e) => !l.has(_(e, u)) && !l.has(_(e, "*"))) ?? null;
|
|
2899
|
+
}, x = (e) => {
|
|
2900
|
+
let t = e.cursor;
|
|
2901
|
+
if (!e.label || !n) return t;
|
|
2902
|
+
let r = null, i = n();
|
|
2903
|
+
for (let n = 4; n < i.length; n++) {
|
|
2904
|
+
let a = (i[n] ?? "").slice(0, 33);
|
|
2905
|
+
for (let i = a.indexOf(e.label); i >= 0; i = a.indexOf(e.label, i + 1)) {
|
|
2906
|
+
let e = Math.hypot(i - t.x, (n - t.y) * 1.5);
|
|
2907
|
+
(!r || e < r.d) && (r = {
|
|
2908
|
+
x: i,
|
|
2909
|
+
y: n,
|
|
2910
|
+
d: e
|
|
2911
|
+
});
|
|
2912
|
+
}
|
|
2605
2913
|
}
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2914
|
+
return r ? {
|
|
2915
|
+
x: r.x,
|
|
2916
|
+
y: r.y
|
|
2917
|
+
} : t;
|
|
2918
|
+
}, S = (t) => {
|
|
2919
|
+
let n = e.get("cursorPos"), r = e.get("cursorRect");
|
|
2920
|
+
if (!n || n.y !== t.y) return !1;
|
|
2921
|
+
let i = r ? Math.max(1, Math.round(r.w / e.get("cellMetrics").cellW)) : 1;
|
|
2922
|
+
return t.x >= n.x && t.x < n.x + i;
|
|
2923
|
+
}, C = (e) => {
|
|
2924
|
+
if (a = null, o = 0, p = null, h(), s) {
|
|
2925
|
+
let t = s;
|
|
2926
|
+
s = null, t(e);
|
|
2927
|
+
}
|
|
2928
|
+
}, w = (e) => {
|
|
2929
|
+
if (!p) return;
|
|
2930
|
+
let { edge: t, from: n, prev: r } = p, i = !!e && e !== n;
|
|
2931
|
+
l.set(_(t, i ? r : "*"), i ? e : n), p = null, h(), e && e !== n && t.to && e !== t.to ? console.log("Navigation step landed elsewhere", {
|
|
2932
|
+
from: n,
|
|
2933
|
+
expected: t.to,
|
|
2934
|
+
reached: e
|
|
2935
|
+
}) : (!e || e === n) && console.log("Navigation step blocked", {
|
|
2936
|
+
from: n,
|
|
2937
|
+
to: t.to || "?",
|
|
2938
|
+
kind: t.kind,
|
|
2939
|
+
dir: t.dir
|
|
2940
|
+
}), E();
|
|
2941
|
+
}, T = async (n, i) => {
|
|
2942
|
+
let a = x(n.edge);
|
|
2943
|
+
S(a) || (await Promise.race([r(a.x, a.y), jt(Ct)]), await jt(wt)), i === c && p === n && (e.get("viewName") !== n.from || !S(a) ? (console.warn("Navigation: button not reached", {
|
|
2944
|
+
from: n.from,
|
|
2945
|
+
to: n.edge.to,
|
|
2946
|
+
cell: a,
|
|
2947
|
+
cursor: e.get("cursorPos")
|
|
2948
|
+
}), w(e.get("viewName") === n.from ? n.from : e.get("viewName") || "")) : (n.phase = "keys", t.cancel("navigation button"), t.start(Ot(n.edge.keys))));
|
|
2949
|
+
}, E = () => {
|
|
2950
|
+
let n = a, r = e.get("viewName") || "";
|
|
2951
|
+
if (!n) return;
|
|
2952
|
+
if (!r) {
|
|
2953
|
+
console.warn("Navigation aborted: no view name (a dialog?)", { goal: n }), C(!1);
|
|
2610
2954
|
return;
|
|
2611
2955
|
}
|
|
2612
|
-
if (
|
|
2956
|
+
if (r === n) {
|
|
2613
2957
|
console.log("Navigation complete:", {
|
|
2614
2958
|
goal: n,
|
|
2615
|
-
steps:
|
|
2616
|
-
}),
|
|
2959
|
+
steps: o
|
|
2960
|
+
}), C(!0);
|
|
2617
2961
|
return;
|
|
2618
2962
|
}
|
|
2619
|
-
if (
|
|
2963
|
+
if (o >= bt) {
|
|
2620
2964
|
console.warn("Navigation aborted: max steps reached", {
|
|
2621
|
-
startTitle:
|
|
2965
|
+
startTitle: r,
|
|
2622
2966
|
goalTitle: n,
|
|
2623
|
-
steps:
|
|
2624
|
-
}),
|
|
2967
|
+
steps: o
|
|
2968
|
+
}), C(!1);
|
|
2625
2969
|
return;
|
|
2626
2970
|
}
|
|
2627
|
-
let
|
|
2628
|
-
if (!
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2971
|
+
let i = b(r, n);
|
|
2972
|
+
if (!i) {
|
|
2973
|
+
console.warn("No path found", {
|
|
2974
|
+
startTitle: r,
|
|
2975
|
+
goalTitle: n,
|
|
2976
|
+
step: o
|
|
2977
|
+
}), C(!1);
|
|
2978
|
+
return;
|
|
2979
|
+
}
|
|
2980
|
+
o += 1, console.log("Navigation step", {
|
|
2981
|
+
step: o,
|
|
2982
|
+
from: r,
|
|
2983
|
+
to: i.to || "?",
|
|
2984
|
+
kind: i.kind,
|
|
2985
|
+
dir: i.dir,
|
|
2986
|
+
goal: n
|
|
2987
|
+
});
|
|
2988
|
+
let s = {
|
|
2989
|
+
from: r,
|
|
2990
|
+
prev: u,
|
|
2991
|
+
edge: i,
|
|
2992
|
+
phase: i.kind === "button" ? "cursor" : "keys"
|
|
2993
|
+
};
|
|
2994
|
+
if (p = s, i.kind === "button") {
|
|
2995
|
+
T(s, c);
|
|
2996
|
+
return;
|
|
2643
2997
|
}
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
},
|
|
2998
|
+
let l = i.keys.length ? Ot(i.keys) : Tt([i.dir], { shift: !0 });
|
|
2999
|
+
t.cancel("iterative navigation step"), t.start(l);
|
|
3000
|
+
}, D = () => {
|
|
3001
|
+
if (p?.phase !== "keys") return;
|
|
3002
|
+
let n = e.get("macroStatus").running, r = e.get("viewName") || "", i = !!r && r !== p.from;
|
|
3003
|
+
(!n || i) && (h(), m = n ? setTimeout(() => {
|
|
3004
|
+
t.cancel("navigation: no release echo"), t.start([0]), w(e.get("viewName") || "");
|
|
3005
|
+
}, xt) : setTimeout(() => w(e.get("viewName") || ""), i ? St : xt));
|
|
3006
|
+
}, O = e.sub("viewName", D), k = e.sub("macroStatus", D);
|
|
2647
3007
|
return {
|
|
2648
3008
|
navigateToView: (t) => new Promise((n) => {
|
|
2649
|
-
let
|
|
2650
|
-
|
|
2651
|
-
goal:
|
|
3009
|
+
let r = g(t);
|
|
3010
|
+
r ? (C(!1), c += 1, l = /* @__PURE__ */ new Map(), s = n, a = r, o = 0, console.log("Starting iterative navigation", {
|
|
3011
|
+
goal: r,
|
|
2652
3012
|
from: e.get("viewName") || "unknown"
|
|
2653
|
-
}),
|
|
3013
|
+
}), E()) : n(!1);
|
|
2654
3014
|
}),
|
|
2655
3015
|
dispose: () => {
|
|
2656
|
-
|
|
3016
|
+
f(), O(), k(), c += 1, C(!1);
|
|
2657
3017
|
}
|
|
2658
3018
|
};
|
|
2659
|
-
},
|
|
3019
|
+
}, Nt = /* @__PURE__ */ new Set([
|
|
2660
3020
|
"macroStatus",
|
|
2661
3021
|
"deviceModel",
|
|
2662
3022
|
"fontMode",
|
|
@@ -2664,31 +3024,33 @@ var yt = 20, bt = (e, t) => {
|
|
|
2664
3024
|
"titleColor",
|
|
2665
3025
|
"backgroundColor",
|
|
2666
3026
|
"minimapKey"
|
|
2667
|
-
]),
|
|
2668
|
-
let n = t.store ??
|
|
3027
|
+
]), Pt = (e, t = {}) => {
|
|
3028
|
+
let n = t.store ?? gt(), r = (...e) => {
|
|
2669
3029
|
t.debug && console.log(...e);
|
|
2670
3030
|
}, i = /* @__PURE__ */ new Map(), a = (e, t) => {
|
|
2671
3031
|
for (let n of [...i.get(e) ?? []]) n(t);
|
|
2672
|
-
}, o =
|
|
3032
|
+
}, o = it(e.protocol.eventBus, n), s = mt({
|
|
2673
3033
|
bus: e,
|
|
2674
3034
|
store: n,
|
|
2675
3035
|
cancelOnKeydown: t.cancelMacroOnKeydown
|
|
2676
3036
|
}), c = pe({
|
|
2677
3037
|
bus: e,
|
|
2678
3038
|
store: n
|
|
2679
|
-
}), l =
|
|
3039
|
+
}), l = Mt({
|
|
2680
3040
|
store: n,
|
|
2681
|
-
runner: s
|
|
2682
|
-
|
|
3041
|
+
runner: s,
|
|
3042
|
+
getScreenLines: o.getScreenLines,
|
|
3043
|
+
moveCursor: (e, t) => c.navigateTo(ot(n, e, t))
|
|
3044
|
+
}), u = ut((e) => a("transport", e)), d = ke({
|
|
2683
3045
|
getKeySink: () => e.commands,
|
|
2684
3046
|
store: n,
|
|
2685
3047
|
debugLog: r,
|
|
2686
3048
|
getScreenLines: o.getScreenLines
|
|
2687
|
-
}), f =
|
|
3049
|
+
}), f = ct({
|
|
2688
3050
|
io: d,
|
|
2689
|
-
editors:
|
|
2690
|
-
setValueFloat:
|
|
2691
|
-
browseFile:
|
|
3051
|
+
editors: pt(d),
|
|
3052
|
+
setValueFloat: Ke(d),
|
|
3053
|
+
browseFile: Ie(d),
|
|
2692
3054
|
navigateToView: (e) => l.navigateToView(e),
|
|
2693
3055
|
navigateTo: (e) => c.navigateTo(e),
|
|
2694
3056
|
enableMidiTransport: () => u.enable(),
|
|
@@ -2718,7 +3080,7 @@ var yt = 20, bt = (e, t) => {
|
|
|
2718
3080
|
};
|
|
2719
3081
|
(!_ || _.textUnderCursor !== e.textUnderCursor || _.currentLine !== e.currentLine) && (_ = e, r("[M8SDK] Text updated:", e.textUnderCursor, e.currentLine), a("textUpdated", e));
|
|
2720
3082
|
}
|
|
2721
|
-
[...e].some((e) =>
|
|
3083
|
+
[...e].some((e) => Nt.has(e)) && a("stateChanged", at(n));
|
|
2722
3084
|
}, y = n.subAll((e) => {
|
|
2723
3085
|
p.add(e), m || (m = !0, queueMicrotask(v));
|
|
2724
3086
|
}), b = (e) => {
|
|
@@ -2731,7 +3093,7 @@ var yt = 20, bt = (e, t) => {
|
|
|
2731
3093
|
macro: s,
|
|
2732
3094
|
navigateTo: (e) => c.navigateTo(e),
|
|
2733
3095
|
navigateToView: (e) => l.navigateToView(e),
|
|
2734
|
-
getState: () =>
|
|
3096
|
+
getState: () => at(n),
|
|
2735
3097
|
getScreenLines: o.getScreenLines,
|
|
2736
3098
|
getScreenCellColors: o.getScreenCellColors,
|
|
2737
3099
|
on: (e, t) => {
|
|
@@ -2744,7 +3106,7 @@ var yt = 20, bt = (e, t) => {
|
|
|
2744
3106
|
e.protocol.eventBus.off("key", b), y(), l.dispose(), c.dispose(), s.dispose(), u.disable(), o.dispose(), i.clear();
|
|
2745
3107
|
}
|
|
2746
3108
|
};
|
|
2747
|
-
},
|
|
3109
|
+
}, W = {
|
|
2748
3110
|
version: "1.0",
|
|
2749
3111
|
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.",
|
|
2750
3112
|
notes: {
|
|
@@ -2911,17 +3273,17 @@ var yt = 20, bt = (e, t) => {
|
|
|
2911
3273
|
},
|
|
2912
3274
|
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." }
|
|
2913
3275
|
}
|
|
2914
|
-
},
|
|
3276
|
+
}, Ft = {
|
|
2915
3277
|
version: "1.0",
|
|
2916
3278
|
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.",
|
|
2917
3279
|
notes: {
|
|
2918
3280
|
rows: "A row is recognised by 'match' conditions on the line text (x = column, text = exact text, regex = pattern on the value.width chars). The first matching row wins; its cells give the field columns.",
|
|
2919
3281
|
zones: "Views whose labels change (instrument parameters depend on the instrument type, modulation slots on the modulation type) use two label/value zones instead: the label text is read at labelX and the value at x. The label is then looked up in the vocabulary.",
|
|
2920
|
-
formats: "hex = 2 hex digits; hexOption = 2 hex digits followed by the option name ('00CHORUS'); hexPair = 'XX:YY'; decimal / decimalPair = base-10 numbers ('120', '150:45'); float = decimal with a fraction ('-05.00'); text = free text or option name; auto = detect from the text.",
|
|
3282
|
+
formats: "hex = 2 hex digits; hexOption = 2 hex digits followed by the option name ('00CHORUS'); hexPair = 'XX:YY' (or 'XX/YY'); decimal / decimalPair = base-10 numbers ('120', '150:45'); float = decimal with a fraction ('-05.00'); text = free text or option name; auto = detect from the text.",
|
|
2921
3283
|
unverified: "Positions are read off the manual's screenshots, not from a device capture. Instrument-type specific layouts other than the Wavsynth header/parameter grid (Sampler SAMPLE row, FM operators, Hypersynth chord, MIDI CC rows) are only reached through the generic label/value zones."
|
|
2922
3284
|
},
|
|
2923
|
-
views: /* @__PURE__ */ JSON.parse("{\"project\":{\"rows\":[{\"id\":\"tempo\",\"match\":[{\"x\":0,\"text\":\"TEMPO\"}],\"cells\":[{\"x\":13,\"width\":6,\"key\":\"tempo\",\"type\":\"parameter\",\"format\":\"float\",\"unit\":\" BPM\",\"label\":\"Tempo (TEMPO)\",\"description\":\"Song speed in beats per minute. [EDIT] pressed rhythmically sets the tempo by tapping.\"}]},{\"id\":\"transpose\",\"match\":[{\"x\":0,\"text\":\"TRANSPOSE\"}],\"cells\":[{\"x\":13,\"width\":2,\"key\":\"transpose\",\"type\":\"transpose\",\"format\":\"hex\",\"label\":\"Project Transpose (TRANSPOSE)\",\"description\":\"Transposes the whole song in semitones (same as the TSP command). Only affects instruments with TRANSP. enabled; applied when [EDIT] is released.\"}]},{\"id\":\"groove\",\"match\":[{\"x\":0,\"text\":\"GROOVE\"}],\"cells\":[{\"x\":13,\"width\":14,\"key\":\"groove\",\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"Default Groove (GROOVE)\",\"description\":\"Groove used when the song plays (number and name); applied when [EDIT] is released. See Groove View.\"}]},{\"id\":\"scale\",\"match\":[{\"x\":0,\"text\":\"SCALE\"}],\"cells\":[{\"x\":13,\"width\":16,\"key\":\"scale\",\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"Default Scale (SCALE)\",\"description\":\"Scale (number, key and name) used when the song plays; applied when [EDIT] is released. See Scale View.\"}]},{\"id\":\"liveQuantize\",\"match\":[{\"x\":0,\"text\":\"LIVE QUANTIZ\"}],\"cells\":[{\"x\":13,\"width\":14,\"key\":\"liveQuantize\",\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"Live Quantize (LIVE QUANTIZE)\",\"description\":\"How long a cued chain waits before starting when playing in live mode.\"}]},{\"id\":\"midi\",\"match\":[{\"x\":0,\"text\":\"MIDI\"},{\"x\":13,\"text\":\"SETTINGS\"}],\"cells\":[{\"x\":13,\"width\":8,\"key\":\"midiSettings\",\"type\":\"action\",\"format\":\"text\",\"label\":\"MIDI Settings\",\"description\":\"Open the MIDI Settings View.\"},{\"x\":22,\"width\":8,\"key\":\"midiMappings\",\"type\":\"action\",\"format\":\"text\",\"label\":\"MIDI Mappings\",\"description\":\"Open the MIDI Mappings View.\"}]},{\"id\":\"name\",\"match\":[{\"x\":0,\"text\":\"NAME\"}],\"cells\":[{\"x\":13,\"width\":12,\"key\":\"name\",\"type\":\"name\",\"format\":\"text\",\"label\":\"Song Name (NAME)\",\"description\":\"Name of the current song, entered before saving.\"}]},{\"id\":\"file\",\"match\":[{\"x\":0,\"text\":\"PROJECT\"},{\"x\":13,\"text\":\"LOAD\"}],\"cells\":[{\"x\":13,\"width\":4,\"key\":\"load\",\"type\":\"action\",\"format\":\"text\",\"label\":\"Load Song\",\"description\":\"Load a song from the SD card.\"},{\"x\":18,\"width\":4,\"key\":\"save\",\"type\":\"action\",\"format\":\"text\",\"label\":\"Save Song\",\"description\":\"Save the current song.\"},{\"x\":23,\"width\":3,\"key\":\"new\",\"type\":\"action\",\"format\":\"text\",\"label\":\"New Song\",\"description\":\"Create a new song.\"}]},{\"id\":\"export\",\"match\":[{\"x\":0,\"text\":\"EXPORT/SHARE\"}],\"cells\":[{\"x\":13,\"width\":6,\"key\":\"render\",\"type\":\"action\",\"format\":\"text\",\"label\":\"Render\",\"description\":\"Open the Render View to render audio.\"},{\"x\":20,\"width\":6,\"key\":\"bundle\",\"type\":\"action\",\"format\":\"text\",\"label\":\"Bundle\",\"description\":\"Bundle the song with the instruments and samples it uses.\"}]},{\"id\":\"clearUnused\",\"match\":[{\"x\":0,\"text\":\"CLEAR UNUSED\"}],\"cells\":[{\"x\":13,\"width\":7,\"key\":\"clearPhrases\",\"type\":\"action\",\"format\":\"text\",\"label\":\"Clear Unused Phrases\",\"description\":\"Frees chains and phrases that are not used in the song.\"},{\"x\":21,\"width\":8,\"key\":\"clearInstTbl\",\"type\":\"action\",\"format\":\"text\",\"label\":\"Clear Unused Instruments/Tables\",\"description\":\"Frees instruments, EQs and tables that are not used in the song.\"}]},{\"id\":\"instPool\",\"match\":[{\"x\":0,\"text\":\"INST. POOL\"}],\"cells\":[{\"x\":13,\"width\":15,\"key\":\"viewInstPool\",\"type\":\"action\",\"format\":\"text\",\"label\":\"View Instrument Pool\",\"description\":\"Go to the Instrument Pool View.\"}]},{\"id\":\"timeStats\",\"match\":[{\"x\":0,\"text\":\"TIME STATS\"}],\"cells\":[{\"x\":13,\"width\":15,\"key\":\"viewTimeStats\",\"type\":\"action\",\"format\":\"text\",\"label\":\"View Time Stats\",\"description\":\"Open the Time Stats View (time spent on the song).\"}]},{\"id\":\"system\",\"match\":[{\"x\":0,\"text\":\"SYSTEM\"},{\"x\":13,\"text\":\"SETTINGS\"}],\"cells\":[{\"x\":13,\"width\":8,\"key\":\"systemSettings\",\"type\":\"action\",\"format\":\"text\",\"label\":\"System Settings\",\"description\":\"Go to the System Settings View.\"},{\"x\":22,\"width\":9,\"key\":\"usbDrive\",\"type\":\"action\",\"format\":\"text\",\"label\":\"USB Drive\",\"description\":\"Puts the M8 in USB drive mode so SD card files can be transferred to a computer.\"}]}]},\"systemsettings\":{\"rows\":[{\"id\":\"backlight\",\"match\":[{\"x\":0,\"text\":\"BACKLIGHT\"}],\"cells\":[{\"x\":15,\"width\":2,\"key\":\"backlight\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Backlight (BACKLIGHT)\",\"description\":\"Backlight LED brightness of the display.\"}]},{\"id\":\"fontOptions\",\"match\":[{\"x\":0,\"text\":\"FONT OPTIONS\"}],\"cells\":[{\"x\":15,\"width\":15,\"key\":\"fontOptions\",\"type\":\"option\",\"format\":\"text\",\"label\":\"Font Options (FONT OPTIONS)\",\"description\":\"Font settings, including a large font mode for readability.\"}]},{\"id\":\"theme\",\"match\":[{\"x\":0,\"text\":\"THEME\"}],\"cells\":[{\"x\":15,\"width\":10,\"key\":\"editTheme\",\"type\":\"action\",\"format\":\"text\",\"label\":\"Theme (EDIT THEME)\",\"description\":\"Open the Theme View.\"}]},{\"id\":\"notePreview\",\"match\":[{\"x\":0,\"text\":\"NOTE PREVIEW\"}],\"cells\":[{\"x\":15,\"width\":3,\"key\":\"notePreview\",\"type\":\"onOff\",\"format\":\"text\",\"label\":\"Note Preview (NOTE PREVIEW)\",\"description\":\"Plays the note when editing notes in the phrase view.\"}]},{\"id\":\"recCountIn\",\"match\":[{\"x\":0,\"regex\":\"^REC\\\\.\\\\s?(COUNT IN|METRONOME)\\\\s*$\",\"width\":13}],\"cells\":[{\"x\":15,\"width\":6,\"key\":\"recCountIn\",\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"Recording Count-in (REC. COUNT IN)\",\"description\":\"Number of phrases/measures of metronome count-in before recording audio in the Sample Editor or Selection to Sample.\"}]},{\"id\":\"metronomeVol\",\"match\":[{\"x\":0,\"text\":\"METRONOME VOL\"}],\"cells\":[{\"x\":15,\"width\":2,\"key\":\"metronomeVol\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Metronome Volume (METRONOME VOL)\",\"description\":\"Volume of the metronome sound (edit /System/Metronome.m8i to change the sound).\"}]},{\"id\":\"songTemplate\",\"match\":[{\"x\":0,\"text\":\"SONG TEMPLATE\"}],\"cells\":[{\"x\":15,\"width\":4,\"key\":\"songTemplateSave\",\"type\":\"action\",\"format\":\"text\",\"label\":\"Song Template (SAVE)\",\"description\":\"Use the currently opened song as the template for new songs.\"},{\"x\":20,\"width\":5,\"key\":\"songTemplateClear\",\"type\":\"action\",\"format\":\"text\",\"label\":\"Song Template (CLEAR)\",\"description\":\"Clear the song template.\"}]},{\"id\":\"usbAudioMode\",\"match\":[{\"x\":0,\"text\":\"USB AUDIO MODE\"}],\"cells\":[{\"x\":15,\"width\":14,\"key\":\"usbAudioMode\",\"type\":\"option\",\"format\":\"text\",\"label\":\"USB Audio Mode (USB AUDIO MODE)\",\"description\":\"USB output as stereo or multi-channel (multi-channel sends all 8 tracks and the effects individually, 12 stereo channels).\",\"options\":{\"STEREO OUT\":\"Stereo mix over USB.\"}}]},{\"id\":\"usbMainOut\",\"match\":[{\"x\":0,\"text\":\"USB MAIN OUT\"}],\"cells\":[{\"x\":15,\"width\":6,\"key\":\"usbMainOut\",\"type\":\"option\",\"format\":\"text\",\"label\":\"USB Main Out (USB MAIN OUT)\",\"description\":\"Routing behaviour of USB audio (see the USB audio routing options).\"}]},{\"id\":\"lineInGate\",\"match\":[{\"x\":0,\"text\":\"LINE-IN GATE\"}],\"cells\":[{\"x\":15,\"width\":6,\"key\":\"lineInGate\",\"type\":\"option\",\"format\":\"text\",\"label\":\"Line-in Gate (LINE-IN GATE)\",\"description\":\"Noise gate threshold for the line input, adjustable from -70 dB to -10 dB (OFF disables it).\"}]},{\"id\":\"splashScreen\",\"match\":[{\"x\":0,\"text\":\"SPLASH SCREEN\"}],\"cells\":[{\"x\":15,\"width\":3,\"key\":\"splashScreen\",\"type\":\"onOff\",\"format\":\"text\",\"label\":\"Splash Screen (SPLASH SCREEN)\",\"description\":\"Show the M8 logo and play the start-up sound when turning on the device.\"}]},{\"id\":\"hpProtection\",\"match\":[{\"x\":0,\"text\":\"HP PROTECTION\"}],\"cells\":[{\"x\":15,\"width\":3,\"key\":\"hpProtection\",\"type\":\"onOff\",\"format\":\"text\",\"label\":\"Headphone Protection (HP PROTECTION)\",\"description\":\"Limits the headphone output volume to F0 when a pack is unplugged and re-inserted.\"}]},{\"id\":\"keyDelayRep\",\"match\":[{\"x\":0,\"text\":\"KEY DELAY:REP\"}],\"cells\":[{\"x\":15,\"width\":7,\"key\":\"keyDelayRep\",\"type\":\"parameter\",\"format\":\"decimalPair\",\"unit\":\" ms\",\"parts\":[\"delay\",\"repeat\"],\"label\":\"Key Delay:Repeat (KEY DELAY:REP)\",\"description\":\"Key repeat timing in milliseconds: delay before a held key starts repeating, then the time between repeats.\"}]},{\"id\":\"battCharging\",\"match\":[{\"x\":0,\"regex\":\"^BATT\\\\.\\\\s?(CHARGING|STATUS)\\\\s*$\",\"width\":14}],\"cells\":[{\"x\":15,\"width\":14,\"key\":\"battCharging\",\"type\":\"option\",\"format\":\"text\",\"label\":\"Battery Charging (BATT. CHARGING / STATUS)\",\"description\":\"Whether the battery charges while the M8 is on and USB is connected (turn off to reduce power drawn from the host); also shows the current charging status.\"}]}]},\"effectsettings\":{\"sections\":[\"MODFX\",\"DELAY\",\"REVERB\"],\"rows\":[{\"id\":\"modfxType\",\"section\":\"MODFX\",\"match\":[{\"x\":7,\"text\":\"MOD TYPE\"}],\"cells\":[{\"x\":21,\"width\":10,\"key\":\"modfxType\",\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"ModFX Type (MOD TYPE)\",\"description\":\"ModFX effect: Chorus, Phaser or Flanger (also sets the phase position).\",\"options\":{\"CHORUS\":\"Stereo chorus.\",\"PHASER\":\"Stereo phaser.\",\"FLANGER\":\"Stereo flanger.\"}}]},{\"id\":\"modfxInputEq\",\"section\":\"MODFX\",\"match\":[{\"x\":7,\"text\":\"INPUT EQ\"}],\"cells\":[{\"x\":21,\"width\":2,\"key\":\"modfxInputEq\",\"type\":\"action\",\"format\":\"text\",\"label\":\"Input EQ (INPUT EQ)\",\"description\":\"Open the EQ editor for this effect's input.\"}]},{\"id\":\"modfxDepthFreq\",\"section\":\"MODFX\",\"match\":[{\"x\":7,\"text\":\"MOD DEPTH:FRQ\"}],\"cells\":[{\"x\":21,\"width\":5,\"key\":\"modfxDepthFreq\",\"type\":\"parameter\",\"format\":\"hexPair\",\"parts\":[\"mod depth\",\"mod frequency\"],\"label\":\"ModFX Mod Depth:Frequency (MOD DEPTH:FRQ)\",\"description\":\"Amount of modulation in the stereo signal (first value) and speed of the modulation (second value).\"}]},{\"id\":\"modfxWidth\",\"section\":\"MODFX\",\"match\":[{\"x\":7,\"text\":\"STEREO WIDTH\"}],\"cells\":[{\"x\":21,\"width\":2,\"key\":\"modfxWidth\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Stereo Width (STEREO WIDTH)\",\"description\":\"Stereo width: 00 is mono, FF is stereo.\"}]},{\"id\":\"modfxReverbSend\",\"section\":\"MODFX\",\"match\":[{\"x\":7,\"text\":\"REVERB SEND\"}],\"cells\":[{\"x\":21,\"width\":2,\"key\":\"modfxReverbSend\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Reverb Send (REVERB SEND)\",\"description\":\"Amount of this effect sent to the reverb.\"}]},{\"id\":\"delayInputEq\",\"section\":\"DELAY\",\"match\":[{\"x\":7,\"text\":\"INPUT EQ\"}],\"cells\":[{\"x\":21,\"width\":2,\"key\":\"delayInputEq\",\"type\":\"action\",\"format\":\"text\",\"label\":\"Input EQ (INPUT EQ)\",\"description\":\"Open the EQ editor for this effect's input.\"}]},{\"id\":\"delayTime\",\"section\":\"DELAY\",\"match\":[{\"x\":7,\"text\":\"TIME L:R\"}],\"cells\":[{\"x\":21,\"width\":5,\"key\":\"delayTime\",\"type\":\"parameter\",\"format\":\"hexPair\",\"parts\":[\"left time\",\"right time\"],\"label\":\"Delay Time L:R (TIME L:R)\",\"description\":\"Delay time for the left and right channels: first digit in beats, second digit in fractions of a beat (40 is 4 beats).\"}]},{\"id\":\"delayFeedback\",\"section\":\"DELAY\",\"match\":[{\"x\":7,\"text\":\"FEEDBACK\"}],\"cells\":[{\"x\":21,\"width\":2,\"key\":\"delayFeedback\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Feedback (FEEDBACK)\",\"description\":\"Amount of the delayed signal fed back into the delay.\"}]},{\"id\":\"delayWidth\",\"section\":\"DELAY\",\"match\":[{\"x\":7,\"text\":\"STEREO WIDTH\"}],\"cells\":[{\"x\":21,\"width\":2,\"key\":\"delayWidth\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Stereo Width (STEREO WIDTH)\",\"description\":\"Stereo width: 00 is mono, FF is stereo.\"}]},{\"id\":\"delayReverbSend\",\"section\":\"DELAY\",\"match\":[{\"x\":7,\"text\":\"REVERB SEND\"}],\"cells\":[{\"x\":21,\"width\":2,\"key\":\"delayReverbSend\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Reverb Send (REVERB SEND)\",\"description\":\"Amount of this effect sent to the reverb.\"}]},{\"id\":\"reverbInputEq\",\"section\":\"REVERB\",\"match\":[{\"x\":7,\"text\":\"INPUT EQ\"}],\"cells\":[{\"x\":21,\"width\":2,\"key\":\"reverbInputEq\",\"type\":\"action\",\"format\":\"text\",\"label\":\"Input EQ (INPUT EQ)\",\"description\":\"Open the EQ editor for this effect's input.\"}]},{\"id\":\"reverbRoomSize\",\"section\":\"REVERB\",\"match\":[{\"x\":7,\"text\":\"ROOM SIZE\"}],\"cells\":[{\"x\":21,\"width\":2,\"key\":\"reverbRoomSize\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Room Size (ROOM SIZE)\",\"description\":\"Size of the reverb room.\"}]},{\"id\":\"reverbDecayShimmer\",\"section\":\"REVERB\",\"match\":[{\"x\":7,\"text\":\"DECAY:SHIMMER\"}],\"cells\":[{\"x\":21,\"width\":5,\"key\":\"reverbDecayShimmer\",\"type\":\"parameter\",\"format\":\"hexPair\",\"parts\":[\"decay\",\"shimmer\"],\"label\":\"Reverb Decay:Shimmer (DECAY:SHIMMER)\",\"description\":\"Reverb decay time (first value) and shimmer amount (second value).\"}]},{\"id\":\"reverbDepthFreq\",\"section\":\"REVERB\",\"match\":[{\"x\":7,\"text\":\"MOD DEPTH:FRQ\"}],\"cells\":[{\"x\":21,\"width\":5,\"key\":\"reverbDepthFreq\",\"type\":\"parameter\",\"format\":\"hexPair\",\"parts\":[\"mod depth\",\"mod frequency\"],\"label\":\"Reverb Mod Depth:Frequency (MOD DEPTH:FRQ)\",\"description\":\"Reverb modulation depth (first value) and frequency (second value).\"}]},{\"id\":\"reverbWidth\",\"section\":\"REVERB\",\"match\":[{\"x\":7,\"text\":\"STEREO WIDTH\"}],\"cells\":[{\"x\":21,\"width\":2,\"key\":\"reverbWidth\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Stereo Width (STEREO WIDTH)\",\"description\":\"Stereo width: 00 is mono, FF is stereo.\"}]}]},\"mixer\":{\"rows\":[{\"id\":\"speaker\",\"match\":[{\"x\":0,\"text\":\"SPEAKER\"}],\"cells\":[{\"x\":12,\"width\":2,\"key\":\"speakerVol\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Speaker Volume (SPEAKER VOL)\",\"description\":\"Volume of the built-in speaker.\"}]},{\"id\":\"outputVol\",\"match\":[{\"x\":0,\"text\":\"OUTPUT VOL\"}],\"cells\":[{\"x\":12,\"width\":2,\"key\":\"outputVol\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Output Volume (OUTPUT VOL)\",\"description\":\"Volume of the audio output (headphones / line out).\"}]},{\"id\":\"tracks\",\"match\":[{\"x\":0,\"regex\":\"^[0-9A-F]{2}$\",\"width\":2},{\"x\":21,\"regex\":\"^[0-9A-F]{2}$\",\"width\":2}],\"cells\":[{\"x\":0,\"width\":2,\"key\":\"track1\",\"type\":\"volume\",\"format\":\"hex\",\"label\":\"Track 1 Volume\",\"meta\":{\"trackIndex\":1},\"description\":\"Volume of track 1. Instrument volumes are applied on top; the track's send levels are set in the instruments.\"},{\"x\":3,\"width\":2,\"key\":\"track2\",\"type\":\"volume\",\"format\":\"hex\",\"label\":\"Track 2 Volume\",\"meta\":{\"trackIndex\":2},\"description\":\"Volume of track 2.\"},{\"x\":6,\"width\":2,\"key\":\"track3\",\"type\":\"volume\",\"format\":\"hex\",\"label\":\"Track 3 Volume\",\"meta\":{\"trackIndex\":3},\"description\":\"Volume of track 3.\"},{\"x\":9,\"width\":2,\"key\":\"track4\",\"type\":\"volume\",\"format\":\"hex\",\"label\":\"Track 4 Volume\",\"meta\":{\"trackIndex\":4},\"description\":\"Volume of track 4.\"},{\"x\":12,\"width\":2,\"key\":\"track5\",\"type\":\"volume\",\"format\":\"hex\",\"label\":\"Track 5 Volume\",\"meta\":{\"trackIndex\":5},\"description\":\"Volume of track 5.\"},{\"x\":15,\"width\":2,\"key\":\"track6\",\"type\":\"volume\",\"format\":\"hex\",\"label\":\"Track 6 Volume\",\"meta\":{\"trackIndex\":6},\"description\":\"Volume of track 6.\"},{\"x\":18,\"width\":2,\"key\":\"track7\",\"type\":\"volume\",\"format\":\"hex\",\"label\":\"Track 7 Volume\",\"meta\":{\"trackIndex\":7},\"description\":\"Volume of track 7.\"},{\"x\":21,\"width\":2,\"key\":\"track8\",\"type\":\"volume\",\"format\":\"hex\",\"label\":\"Track 8 Volume\",\"meta\":{\"trackIndex\":8},\"description\":\"Volume of track 8.\"}]},{\"id\":\"eq\",\"match\":[{\"x\":27,\"text\":\"EQ\"}],\"cells\":[{\"x\":27,\"width\":2,\"key\":\"mixEq\",\"type\":\"action\",\"format\":\"text\",\"label\":\"Main Mix EQ (EQ)\",\"description\":\"Open the main mix EQ editor ([EDIT] or [SHIFT]+[RIGHT]).\"}]},{\"id\":\"levels\",\"match\":[{\"x\":0,\"regex\":\"^[0-9A-F]{2}$\",\"width\":2},{\"x\":3,\"regex\":\"^[0-9A-F]{2}$\",\"width\":2},{\"x\":6,\"regex\":\"^[0-9A-F]{2}$\",\"width\":2},{\"x\":12,\"regex\":\"^[0-9A-F]{2}$\",\"width\":2}],\"cells\":[{\"x\":0,\"width\":2,\"key\":\"modfxVol\",\"type\":\"volume\",\"format\":\"hex\",\"label\":\"ModFX Volume (MX)\",\"description\":\"Output level of the ModFX send effect.\"},{\"x\":3,\"width\":2,\"key\":\"delayVol\",\"type\":\"volume\",\"format\":\"hex\",\"label\":\"Delay Volume (DE)\",\"description\":\"Output level of the delay send effect.\"},{\"x\":6,\"width\":2,\"key\":\"reverbVol\",\"type\":\"volume\",\"format\":\"hex\",\"label\":\"Reverb Volume (RE)\",\"description\":\"Output level of the reverb send effect.\"},{\"x\":12,\"width\":2,\"key\":\"inputVol\",\"type\":\"volume\",\"format\":\"hex\",\"label\":\"Analog Input Volume (INPUT)\",\"description\":\"Volume of the analog input for monitoring. In dual-mono mode this is the left channel.\"},{\"x\":15,\"width\":2,\"key\":\"inputVol2\",\"type\":\"volume\",\"format\":\"hex\",\"label\":\"Analog Input Volume, 2nd channel\",\"description\":\"Enables dual-mono input mode when set (right channel volume); clear with [EDIT]+[OPTION] to disable.\"},{\"x\":18,\"width\":2,\"key\":\"usbVol\",\"type\":\"volume\",\"format\":\"hex\",\"label\":\"USB Input Volume (USB)\",\"description\":\"Volume of anything the USB host computer sends to the M8.\"},{\"x\":27,\"width\":2,\"key\":\"mainVol\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Main Volume (MIX)\",\"description\":\"Main song volume, applied after the limiter, DJ filter and OTT. [EDIT] or [SHIFT]+[RIGHT] opens the Mix Scope.\"}]},{\"id\":\"limiter\",\"match\":[{\"x\":0,\"text\":\"MX\"},{\"x\":3,\"text\":\"DE\"},{\"x\":6,\"text\":\"RE\"}],\"cells\":[{\"x\":27,\"width\":2,\"key\":\"limiter\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Limiter (LIM)\",\"description\":\"Main mix limiter amount; the limiter is engaged when the value is above 00. [EDIT] or [SHIFT]+[RIGHT] opens the Limiter Scope.\"}]},{\"id\":\"sendModfx\",\"match\":[{\"x\":9,\"text\":\"MX\"}],\"cells\":[{\"x\":12,\"width\":2,\"key\":\"inputModfx\",\"type\":\"volume\",\"format\":\"hex\",\"label\":\"Analog Input ModFX Send (INPUT MX)\",\"description\":\"How much of the analog input goes to the ModFX effect.\"},{\"x\":18,\"width\":2,\"key\":\"usbModfx\",\"type\":\"volume\",\"format\":\"hex\",\"label\":\"USB Input ModFX Send (USB MX)\",\"description\":\"How much of the USB input goes to the ModFX effect.\"},{\"x\":27,\"width\":2,\"key\":\"djFilter\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"DJ Filter (DJF)\",\"description\":\"DJ filter cutoff: 80 is off, below 80 low-pass (or band-stop), above 80 high-pass. Mode and options are in the Scope View.\"}]},{\"id\":\"sendDelay\",\"match\":[{\"x\":9,\"text\":\"DE\"}],\"cells\":[{\"x\":12,\"width\":2,\"key\":\"inputDelay\",\"type\":\"volume\",\"format\":\"hex\",\"label\":\"Analog Input Delay Send (INPUT DE)\",\"description\":\"How much of the analog input goes to the delay effect.\"},{\"x\":18,\"width\":2,\"key\":\"usbDelay\",\"type\":\"volume\",\"format\":\"hex\",\"label\":\"USB Input Delay Send (USB DE)\",\"description\":\"How much of the USB input goes to the delay effect.\"},{\"x\":27,\"width\":2,\"key\":\"ott\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"OTT (OTT)\",\"description\":\"Over The Top multi-band compression mixed in parallel: 00 to 80 mixes it in; from 80 and above the main mix is faded out.\"}]},{\"id\":\"sendReverb\",\"match\":[{\"x\":9,\"text\":\"RE\"}],\"cells\":[{\"x\":12,\"width\":2,\"key\":\"inputReverb\",\"type\":\"volume\",\"format\":\"hex\",\"label\":\"Analog Input Reverb Send (INPUT RE)\",\"description\":\"How much of the analog input goes to the reverb effect.\"},{\"x\":18,\"width\":2,\"key\":\"usbReverb\",\"type\":\"volume\",\"format\":\"hex\",\"label\":\"USB Input Reverb Send (USB RE)\",\"description\":\"How much of the USB input goes to the reverb effect.\"}]}]},\"mixeq\":{\"rows\":[{\"id\":\"gain\",\"match\":[{\"x\":0,\"text\":\"GAIN\"}],\"cells\":[{\"x\":5,\"width\":6,\"key\":\"lowGain\",\"type\":\"parameter\",\"format\":\"float\",\"unit\":\" dB\",\"label\":\"LOW Gain\",\"description\":\"Boost (positive) or cut (negative) applied by the LOW band, in decibels.\"},{\"x\":16,\"width\":6,\"key\":\"midGain\",\"type\":\"parameter\",\"format\":\"float\",\"unit\":\" dB\",\"label\":\"MID Gain\",\"description\":\"Boost (positive) or cut (negative) applied by the MID band, in decibels.\"},{\"x\":27,\"width\":6,\"key\":\"highGain\",\"type\":\"parameter\",\"format\":\"float\",\"unit\":\" dB\",\"label\":\"HIGH Gain\",\"description\":\"Boost (positive) or cut (negative) applied by the HIGH band, in decibels.\"}]},{\"id\":\"freq\",\"match\":[{\"x\":0,\"text\":\"FREQ\"}],\"cells\":[{\"x\":6,\"width\":5,\"key\":\"lowFreq\",\"type\":\"parameter\",\"format\":\"decimal\",\"unit\":\" Hz\",\"label\":\"LOW Frequency\",\"description\":\"Centre (or corner) frequency of the LOW band.\"},{\"x\":17,\"width\":5,\"key\":\"midFreq\",\"type\":\"parameter\",\"format\":\"decimal\",\"unit\":\" Hz\",\"label\":\"MID Frequency\",\"description\":\"Centre (or corner) frequency of the MID band.\"},{\"x\":28,\"width\":5,\"key\":\"highFreq\",\"type\":\"parameter\",\"format\":\"decimal\",\"unit\":\" Hz\",\"label\":\"HIGH Frequency\",\"description\":\"Centre (or corner) frequency of the HIGH band.\"}]},{\"id\":\"q\",\"match\":[{\"x\":0,\"text\":\"Q\"},{\"x\":1,\"regex\":\"^\\\\s?$\",\"width\":1}],\"cells\":[{\"x\":6,\"width\":3,\"key\":\"lowQ\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"LOW Q\",\"description\":\"Quality factor (bandwidth) of the LOW band: higher values narrow it.\"},{\"x\":17,\"width\":3,\"key\":\"midQ\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"MID Q\",\"description\":\"Quality factor (bandwidth) of the MID band: higher values narrow it.\"},{\"x\":28,\"width\":3,\"key\":\"highQ\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"HIGH Q\",\"description\":\"Quality factor (bandwidth) of the HIGH band: higher values narrow it.\"}]},{\"id\":\"type\",\"match\":[{\"x\":0,\"text\":\"TYPE\"}],\"cells\":[{\"x\":6,\"width\":9,\"key\":\"lowType\",\"type\":\"option\",\"format\":\"text\",\"label\":\"LOW Type\",\"description\":\"Filter shape of the LOW band.\",\"options\":{\"LOWCUT\":\"Removes frequencies below the cutoff.\",\"LOWSHELF\":\"Boosts or cuts frequencies below the shelf frequency.\",\"BELL\":\"Peaking filter: boosts or cuts around the centre frequency.\",\"BANDPASS\":\"Passes frequencies around the centre frequency, attenuating both sides.\",\"HI.SHELF\":\"Boosts or cuts frequencies above the shelf frequency.\",\"HI.CUT\":\"Attenuates or removes frequencies above the cutoff.\",\"ALLPASS\":\"Passes all frequencies at equal gain while shifting their phase.\"}},{\"x\":17,\"width\":9,\"key\":\"midType\",\"type\":\"option\",\"format\":\"text\",\"label\":\"MID Type\",\"description\":\"Filter shape of the MID band.\",\"options\":{\"LOWCUT\":\"Removes frequencies below the cutoff.\",\"LOWSHELF\":\"Boosts or cuts frequencies below the shelf frequency.\",\"BELL\":\"Peaking filter: boosts or cuts around the centre frequency.\",\"BANDPASS\":\"Passes frequencies around the centre frequency, attenuating both sides.\",\"HI.SHELF\":\"Boosts or cuts frequencies above the shelf frequency.\",\"HI.CUT\":\"Attenuates or removes frequencies above the cutoff.\",\"ALLPASS\":\"Passes all frequencies at equal gain while shifting their phase.\"}},{\"x\":28,\"width\":9,\"key\":\"highType\",\"type\":\"option\",\"format\":\"text\",\"label\":\"HIGH Type\",\"description\":\"Filter shape of the HIGH band.\",\"options\":{\"LOWCUT\":\"Removes frequencies below the cutoff.\",\"LOWSHELF\":\"Boosts or cuts frequencies below the shelf frequency.\",\"BELL\":\"Peaking filter: boosts or cuts around the centre frequency.\",\"BANDPASS\":\"Passes frequencies around the centre frequency, attenuating both sides.\",\"HI.SHELF\":\"Boosts or cuts frequencies above the shelf frequency.\",\"HI.CUT\":\"Attenuates or removes frequencies above the cutoff.\",\"ALLPASS\":\"Passes all frequencies at equal gain while shifting their phase.\"}}]},{\"id\":\"mode\",\"match\":[{\"x\":0,\"text\":\"MODE\"}],\"cells\":[{\"x\":6,\"width\":6,\"key\":\"lowMode\",\"type\":\"option\",\"format\":\"text\",\"label\":\"LOW Mode\",\"description\":\"How the LOW band is applied to the stereo signal.\",\"options\":{\"STEREO\":\"Processes left and right identically.\",\"MID\":\"Affects only the mid (centre) information.\",\"SIDE\":\"Affects only the side information (difference between left and right).\",\"LEFT\":\"Affects only the left channel.\",\"RIGHT\":\"Affects only the right channel.\"}},{\"x\":17,\"width\":6,\"key\":\"midMode\",\"type\":\"option\",\"format\":\"text\",\"label\":\"MID Mode\",\"description\":\"How the MID band is applied to the stereo signal.\",\"options\":{\"STEREO\":\"Processes left and right identically.\",\"MID\":\"Affects only the mid (centre) information.\",\"SIDE\":\"Affects only the side information (difference between left and right).\",\"LEFT\":\"Affects only the left channel.\",\"RIGHT\":\"Affects only the right channel.\"}},{\"x\":28,\"width\":6,\"key\":\"highMode\",\"type\":\"option\",\"format\":\"text\",\"label\":\"HIGH Mode\",\"description\":\"How the HIGH band is applied to the stereo signal.\",\"options\":{\"STEREO\":\"Processes left and right identically.\",\"MID\":\"Affects only the mid (centre) information.\",\"SIDE\":\"Affects only the side information (difference between left and right).\",\"LEFT\":\"Affects only the left channel.\",\"RIGHT\":\"Affects only the right channel.\"}}]}]},\"modfxeq\":{\"extends\":\"mixeq\"},\"delayeq\":{\"extends\":\"mixeq\"},\"reverbeq\":{\"extends\":\"mixeq\"},\"mixscope\":{\"rows\":[{\"id\":\"limiterAtkRel\",\"match\":[{\"x\":9,\"text\":\"ATK\"},{\"x\":16,\"text\":\"REL\"},{\"x\":23,\"text\":\"LIM\"}],\"cells\":[{\"x\":13,\"width\":2,\"key\":\"attack\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Limiter Attack (ATK)\",\"description\":\"Limiter attack time from 0 to 100 ms (see the on-screen help text for the conversion to milliseconds).\"},{\"x\":20,\"width\":2,\"key\":\"release\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Limiter Release (REL)\",\"description\":\"Limiter release time from 4 to 1000 ms; 00 activates AUTO mode (100-900 ms depending on the compression amount).\"},{\"x\":27,\"width\":2,\"key\":\"limiter\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Limiter (LIM)\",\"description\":\"Limiter amount.\"}]},{\"id\":\"zoomPeak\",\"match\":[{\"x\":0,\"text\":\"ZOOM\"}],\"cells\":[{\"x\":5,\"width\":5,\"key\":\"zoom\",\"type\":\"parameter\",\"format\":\"text\",\"label\":\"Zoom (ZOOM)\",\"description\":\"Lower limit of the scope histogram, in decibels.\"},{\"x\":20,\"width\":6,\"key\":\"peak\",\"type\":\"parameter\",\"format\":\"float\",\"unit\":\" dB\",\"label\":\"Peak (PEAK)\",\"description\":\"Current peak level of the main mix in dB. Resets when MIX or LIM change; clear it with [OPT]+[EDIT].\"}]},{\"id\":\"eq\",\"match\":[{\"x\":27,\"text\":\"EQ\"}],\"cells\":[{\"x\":27,\"width\":2,\"key\":\"mixEq\",\"type\":\"action\",\"format\":\"text\",\"label\":\"Main Mix EQ (EQ)\",\"description\":\"Open the main mix EQ editor.\"}]},{\"id\":\"softClip\",\"match\":[{\"x\":9,\"text\":\"SOFT CLIP\"}],\"cells\":[{\"x\":19,\"width\":3,\"key\":\"softClip\",\"type\":\"onOff\",\"format\":\"text\",\"label\":\"Soft Clip (SOFT CLIP)\",\"description\":\"Gentle saturation after the limiter to prevent harsh clipping; raise MIX to exaggerate it.\"},{\"x\":27,\"width\":2,\"key\":\"mainVol\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Main Volume (MIX)\",\"description\":\"Main mix / song volume, applied after the limiter stage.\"}]},{\"id\":\"mix\",\"match\":[{\"x\":23,\"text\":\"MIX\"}],\"cells\":[{\"x\":27,\"width\":2,\"key\":\"mainVol\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Main Volume (MIX)\",\"description\":\"Main mix / song volume, applied after the limiter stage.\"}]},{\"id\":\"lim\",\"match\":[{\"x\":23,\"text\":\"LIM\"}],\"cells\":[{\"x\":27,\"width\":2,\"key\":\"limiter\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Limiter (LIM)\",\"description\":\"Limiter amount.\"}]},{\"id\":\"djf\",\"match\":[{\"x\":23,\"text\":\"DJF\"}],\"cells\":[{\"x\":27,\"width\":2,\"key\":\"djFilter\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"DJ Filter (DJF)\",\"description\":\"DJ filter cutoff: 80 is off, 00-80 low-pass, 80-FF high-pass (mode set with TYPE).\"}]},{\"id\":\"ott\",\"match\":[{\"x\":23,\"text\":\"OTT\"}],\"cells\":[{\"x\":27,\"width\":2,\"key\":\"ott\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"OTT (OTT)\",\"description\":\"OTT mix amount; from 80 and above the main mix volume is faded out.\"}]}],\"zones\":[{\"id\":\"right\",\"labelX\":23,\"labelWidth\":4,\"x\":27,\"width\":6}],\"vocabulary\":{\"ATK\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Limiter Attack (ATK)\",\"description\":\"Limiter attack time from 0 to 100 ms (see the on-screen help text for the conversion).\"},\"REL\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Limiter Release (REL)\",\"description\":\"Limiter release time from 4 to 1000 ms; 00 activates AUTO mode (100-900 ms depending on the compression amount).\"},\"TYPE\":{\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"DJ Filter Type (TYPE)\",\"description\":\"DJ filter type: low-pass/high-pass, low-pass/band-stop or band-stop/high-pass.\"},\"RES\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"DJ Filter Resonance (RES)\",\"description\":\"Resonance of the DJ filter.\"},\"TIME\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"OTT Time (TIME)\",\"description\":\"OTT compressor envelope time as a percentage from 10% to 1000%.\"},\"COLOR\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"OTT Color (COLOR)\",\"description\":\"OTT compressor bands and low/high gains: above 80 shifts toward treble, below 80 toward bass.\"}}},\"limiterscope\":{\"extends\":\"mixscope\"},\"inst\":{\"rows\":[{\"id\":\"type\",\"match\":[{\"x\":0,\"text\":\"TYPE\"}],\"cells\":[{\"x\":8,\"width\":13,\"key\":\"instrumentType\",\"type\":\"instrumentType\",\"format\":\"text\",\"label\":\"Instrument Type (TYPE)\",\"description\":\"Kind of instrument in this slot: Wavsynth, Macrosynth, Sampler, FM Synth, Hypersynth, External Instrument, MIDI Out (or NONE for an unused slot). Changing it changes the parameters below.\"},{\"x\":22,\"width\":4,\"key\":\"load\",\"type\":\"action\",\"format\":\"text\",\"label\":\"Load Preset (LOAD)\",\"description\":\"Load an instrument preset from the SD card.\"},{\"x\":27,\"width\":4,\"key\":\"save\",\"type\":\"action\",\"format\":\"text\",\"label\":\"Save Preset (SAVE)\",\"description\":\"Save this instrument as a preset on the SD card.\"}]},{\"id\":\"name\",\"match\":[{\"x\":0,\"text\":\"NAME\"}],\"cells\":[{\"x\":8,\"width\":12,\"key\":\"name\",\"type\":\"name\",\"format\":\"text\",\"label\":\"Instrument Name (NAME)\",\"description\":\"Name of the instrument: helps keep the song organised when browsing, saving or bundling instruments.\"}]},{\"id\":\"transp\",\"match\":[{\"x\":0,\"text\":\"TRANSP.\"}],\"cells\":[{\"x\":8,\"width\":3,\"key\":\"transpose\",\"type\":\"onOff\",\"format\":\"text\",\"label\":\"Transpose Enabled (TRANSP.)\",\"description\":\"Enable or disable note transposition from scales, chain transpose columns and the project transpose for this instrument (turn off for percussive or effect instruments).\"},{\"x\":21,\"width\":2,\"key\":\"tableTic\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Table Tick (TBL. TIC)\",\"description\":\"Default speed at which this instrument's table advances: 01 is one tick per step, 02 two ticks per step. Can be overridden by the TIC command.\"},{\"x\":29,\"width\":2,\"key\":\"eq\",\"type\":\"eqSlot\",\"format\":\"hex\",\"label\":\"EQ Slot (EQ)\",\"description\":\"EQ bank assigned to this instrument (-- for none). [EDIT] or [SHIFT]+[RIGHT] opens the EQ editor.\"}]}],\"zones\":[{\"id\":\"left\",\"labelX\":0,\"labelWidth\":8,\"x\":8,\"width\":20},{\"id\":\"right\",\"labelX\":18,\"labelWidth\":4,\"x\":22,\"width\":11}],\"vocabularyFrom\":\"instrumentTypes\"},\"instmods\":{\"slotLabel\":\"MOD\\\\d\",\"zones\":[{\"id\":\"left\",\"labelX\":0,\"labelWidth\":4,\"x\":5,\"width\":10},{\"id\":\"right\",\"labelX\":16,\"labelWidth\":4,\"x\":21,\"width\":10}],\"vocabulary\":{\"MOD#\":{\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"Modulator Type\",\"description\":\"Type of this modulation slot: AHD envelope, ADSR envelope, DRUM envelope, LFO, TRIG envelope or TRACKING. Slots can modulate their neighbour (Mod 1 affects Mod 2, 2→3, 3→4, 4→1).\",\"options\":{\"AHD ENV\":\"Attack Hold Decay envelope based on tempo.\",\"ADSR ENV\":\"Traditional Attack Decay Sustain Release envelope.\",\"DRUM ENV\":\"Sharp peak and swelling hold envelope for percussive elements.\",\"LFO\":\"Tempo-synced low frequency oscillator.\",\"TRIG ENV\":\"AHD envelope triggered by another playing track or instrument.\",\"TRACKING\":\"Modulates an instrument parameter from notes or velocities.\",\"OFF\":\"Slot unused.\"}},\"DEST\":{\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"Destination (DEST)\",\"description\":\"Instrument parameter this modulator controls. MOD AMT, MOD RATE or MOD BOTH modulate the neighbouring modulator's amount, rate or both.\"},\"SRC\":{\"type\":\"parameter\",\"format\":\"hexOption\",\"label\":\"Source (SRC)\",\"description\":\"Modulation source. Trig envelope: an instrument number (00-7F) or a whole track (80-87 = tracks 1-8). Tracking: NOTE, VELOCITY or VELOCITY TAKEOVER (velocity no longer affects instrument volume).\"},\"AMT\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Amount (AMT)\",\"description\":\"How strongly the modulator is applied to the destination.\"},\"ATK\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Attack (ATK)\",\"description\":\"Time to reach the amount (in ticks, relative to tempo).\"},\"HOLD\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Hold (HOLD)\",\"description\":\"Time to wait after the attack before decaying (in ticks).\"},\"DEC\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Decay (DEC)\",\"description\":\"Time to fall back (AHD/Drum: to zero; ADSR: to the sustain level), in ticks.\"},\"SUS\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Sustain (SUS)\",\"description\":\"Level held while the note is playing (ADSR).\"},\"REL\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Release (REL)\",\"description\":\"Time to fall back to zero after the note is released (ADSR); needs an OFF note or FX command.\"},\"PEAK\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Peak (PEAK)\",\"description\":\"Shape of the initial transient (drum envelope); modifies the duck amount and peak time.\"},\"BODY\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Body (BODY)\",\"description\":\"Time to hold the modulation before decaying (drum envelope).\"},\"OSC\":{\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"LFO Shape (OSC)\",\"description\":\"LFO shape: triangle, sine, ramp down/up, exponential down/up, square down/up, random, drunk. The 'T' variants run in ticks (much faster).\",\"options\":{\"TRI\":\"Triangle.\",\"SIN\":\"Sine.\",\"RAMP DN\":\"Ramp down.\",\"RAMP UP\":\"Ramp up.\",\"EXP DN\":\"Exponential down.\",\"EXP UP\":\"Exponential up.\",\"SQU DN\":\"Square down.\",\"SQU UP\":\"Square up.\",\"RANDOM\":\"Random values.\",\"DRUNK\":\"Random walk.\"}},\"TRIG\":{\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"LFO Trigger (TRIG)\",\"description\":\"How the LFO reacts when the instrument triggers and when the shape ends.\",\"options\":{\"FREE\":\"Loop the shape and don't reset on new notes.\",\"RETRIG\":\"Loop the shape and reset on each instrument trigger.\",\"HOLD\":\"Hold the last value of the shape.\",\"ONCE\":\"Play the shape once and reset to the start value.\"}},\"FREQ\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"LFO Frequency (FREQ)\",\"description\":\"Rate of the LFO in steps (16th notes), or in ticks for the 'T' shapes.\"},\"LVAL\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Low Value (LVAL)\",\"description\":\"Lowest value of the source range scaled to the destination (tracking). Can be higher than HVAL to invert the range.\"},\"HVAL\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"High Value (HVAL)\",\"description\":\"Highest value of the source range scaled to the destination (tracking).\"}}},\"scale\":{\"notes\":\"Only the rows below the 12 interval rows; the intervals themselves are grid columns in m8-view-context.json.\",\"rows\":[{\"id\":\"key\",\"match\":[{\"x\":0,\"text\":\"KEY\"}],\"cells\":[{\"x\":6,\"width\":2,\"key\":\"key\",\"type\":\"option\",\"format\":\"text\",\"label\":\"Key (KEY)\",\"description\":\"Global key: the root note of the default scale (can be overridden per track with SCA / SCG).\"}]},{\"id\":\"tune\",\"match\":[{\"x\":0,\"text\":\"TUNE\"}],\"cells\":[{\"x\":6,\"width\":6,\"key\":\"tune\",\"type\":\"parameter\",\"format\":\"float\",\"unit\":\" Hz\",\"label\":\"Tuning (TUNE)\",\"description\":\"Reference pitch of A4 in Hz (440.00 is standard).\"}]},{\"id\":\"name\",\"match\":[{\"x\":0,\"text\":\"NAME\"}],\"cells\":[{\"x\":6,\"width\":16,\"key\":\"name\",\"type\":\"name\",\"format\":\"text\",\"label\":\"Scale Name (NAME)\",\"description\":\"Name of this scale (up to 16 characters); 92 factory scales load from /Scales/Factory.\"}]},{\"id\":\"file\",\"match\":[{\"x\":6,\"text\":\"LOAD\"},{\"x\":11,\"text\":\"SAVE\"}],\"cells\":[{\"x\":6,\"width\":4,\"key\":\"load\",\"type\":\"action\",\"format\":\"text\",\"label\":\"Load Scale (LOAD)\",\"description\":\"Load a scale from the SD card.\"},{\"x\":11,\"width\":4,\"key\":\"save\",\"type\":\"action\",\"format\":\"text\",\"label\":\"Save Scale (SAVE)\",\"description\":\"Save this scale to the SD card.\"}]}]},\"loadinstrument\":{\"kind\":\"browser\",\"browserFor\":\"instrument preset\"},\"selectsavedirectory\":{\"kind\":\"browser\",\"browserFor\":\"save location\"},\"createdirectory\":{\"kind\":\"text\",\"fieldLabel\":\"Directory Name\",\"description\":\"Name of the directory to create on the SD card.\"}}"),
|
|
2924
|
-
instrumentTypes: /* @__PURE__ */ JSON.parse("{\"common\":{\"name\":\"Common\",\"description\":\"Parameters shared by most instrument types.\",\"params\":{\"FILTER\":{\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"Filter Type (FILTER)\",\"description\":\"Multi-mode filter type: low-pass, high-pass, band-pass, band-stop, LP>HP (low-pass with RES controlling a 1-pole high-pass), ZDF low-pass, ZDF high-pass.\"},\"CUTOFF\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Filter Cutoff (CUTOFF)\",\"description\":\"Filter cutoff frequency.\"},\"RES\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Filter Resonance (RES)\",\"description\":\"Filter resonance amount.\"},\"AMP\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Amplification (AMP)\",\"description\":\"Amplifies the signal; values above the maximum level are handled according to LIM.\"},\"LIM\":{\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"Limit Mode (LIM)\",\"description\":\"Limit / clipping behaviour of the amplified signal.\",\"options\":{\"CLIP\":\"Values above the maximum level are clipped.\",\"SIN\":\"The waveform is fed through a sine function.\",\"FOLD\":\"Values above the maximum level are folded back into themselves.\",\"WRAP\":\"Values above the maximum level are wrapped vertically.\",\"POST\":\"Amplification applied with hard-clipping after the filter stage.\",\"POST:AD\":\"Post filter amplification with soft-clipping.\",\"POST:W1\":\"Post filter folding distortion.\",\"POST:W2\":\"Post filter folding distortion.\",\"POST:W3\":\"Post filter folding distortion.\"}},\"PAN\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Pan (PAN)\",\"description\":\"Stereo position of the instrument (80 is centre).\"},\"DRY\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Dry Volume (DRY)\",\"description\":\"Dry volume sent to the mixer channel.\"},\"MFX\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"ModFX Send (MFX)\",\"description\":\"ModFX send effect volume.\"},\"DEL\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Delay Send (DEL)\",\"description\":\"Delay send effect volume.\"},\"REV\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Reverb Send (REV)\",\"description\":\"Reverb send effect volume.\"}}},\"wavsynth\":{\"name\":\"Wavsynth\",\"description\":\"Wave table synthesizer and noise generator: an 8-bit sample buffer generated in real time from one of 9 basic shapes (repeated, skewed, mirrored, filtered, overdriven) or one of 61 built-in wave tables of 64 waveforms each.\",\"params\":{\"SHAPE\":{\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"Shape (SHAPE)\",\"description\":\"Base waveform: PULSE 12% to 75%, SAW, TRIANGLE, SINE, NOISE PITCHED, NOISE, or WT wave tables. For PWM set PULSE 50% and adjust MIRROR (smoothness set by SIZE).\"},\"SIZE\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Size (SIZE)\",\"description\":\"Horizontal size of the waveform (number of samples).\"},\"MULT\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Multiply (MULT)\",\"description\":\"Multiplies the waveform by adding repeats of the shape; can sound like hard sync.\"},\"WARP\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Warp (WARP)\",\"description\":\"Pushes the shape to one side of the wave table.\"},\"SCAN\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Scan / Mirror (SCAN)\",\"description\":\"Shapes 0-8: mirrors the waveform at the given position (0-200%). Wave tables: scans through the 64 waveforms.\"},\"FILTER\":{\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"Filter Type (FILTER)\",\"description\":\"Multi-mode filter type, plus 4 modes that apply the filter into the waveform: WAV LP, WAV HP, WAV BP, WAV BS.\"}}},\"macrosynth\":{\"name\":\"Macrosynth\",\"description\":\"44 engines ('shapes') from basic analog to 2-op FM, physical modelling and percussion; TIMBRE and COLOR change meaning per shape.\",\"params\":{\"SHAPE\":{\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"Shape (SHAPE)\",\"description\":\"One of the 44 Macrosynth engines (see the Macrosynth Models appendix).\"},\"TIMBRE\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Timbre (TIMBRE)\",\"description\":\"First parameter of the selected shape.\"},\"COLOR\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Color (COLOR)\",\"description\":\"Second parameter of the selected shape.\"},\"DEGRADE\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Degrade (DEGRADE)\",\"description\":\"Sample rate reduction effect.\"},\"REDUX\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Redux (REDUX)\",\"description\":\"Bit rate reduction effect.\"}}},\"sampler\":{\"name\":\"Sampler\",\"description\":\"Sample player, editor and recorder for 1 or 2 channel PCM .wav files.\",\"params\":{\"SAMPLE\":{\"type\":\"name\",\"format\":\"text\",\"label\":\"Sample (SAMPLE)\",\"description\":\"The loaded sample; use LOAD to browse for one, REC. to record or EDIT to open the Sample Editor.\"},\"SLICE\":{\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"Slice (SLICE)\",\"description\":\"Slices the sample into equal sections, mapped from the lowest octave (C-1); 01 FILE uses the markers stored in the file.\"},\"PLAY\":{\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"Play Mode (PLAY)\",\"description\":\"Play direction and loop mode.\",\"options\":{\"FWD\":\"Forward, no loop.\",\"REV\":\"Reverse, no loop.\",\"FWDLOOP\":\"Looping forward.\",\"REVLOOP\":\"Looping reverse.\",\"FWD PP\":\"Ping-pong looping, forward first.\",\"REV PP\":\"Ping-pong looping, reverse first.\",\"OSC\":\"Oscillator mode: ignores the start position and doesn't restart on retrigger.\",\"OSC REV\":\"Oscillator mode, reverse.\",\"OSC PP\":\"Oscillator mode, ping-pong.\",\"REPITCH\":\"Pitches the sample from the song tempo (adjust with STEPS/BPM).\"}},\"START\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Start (START)\",\"description\":\"Sample start position (ignored in OSC play modes).\"},\"LOOP ST.\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Loop Start (LOOP ST.)\",\"description\":\"Where the sample loops back to when it reaches the end in a looping play mode.\"},\"LEN\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Length (LEN)\",\"description\":\"Sample length.\"},\"DETUNE\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Detune (DETUNE)\",\"description\":\"Detune with 80 as the centre frequency: first digit steps semitones, second digit 1/16 semitone.\"},\"DEGRADE\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Degrade (DEGRADE)\",\"description\":\"Sample rate reduction; any value above 00 disables sample interpolation.\"}}},\"fmsynth\":{\"name\":\"FM Synth\",\"description\":\"Four-operator, 12-algorithm FM synthesizer. Each operator has a base shape, ratio, level, feedback and two modulation slots.\",\"params\":{\"ALGO\":{\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"Algorithm (ALGO)\",\"description\":\"One of 12 algorithms (oscillator routing); the last one is additive mode.\"},\"A\":{\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"Operator A (A)\",\"description\":\"Operator letter with optional shape (SIN, SW2-SW6, SAW, SQU, PUL, IMP, TRI, NOISE, then wave tables).\"},\"B\":{\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"Operator B (B)\",\"description\":\"Operator letter with optional shape.\"},\"C\":{\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"Operator C (C)\",\"description\":\"Operator letter with optional shape.\"},\"D\":{\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"Operator D (D)\",\"description\":\"Operator letter with optional shape.\"},\"RATIO\":{\"type\":\"parameter\",\"format\":\"float\",\"label\":\"Ratio (RATIO)\",\"description\":\"Operator frequency ratio relative to the played note (2.00 is an octave up, 0.50 an octave down).\"},\"LEV/FB\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Level / Feedback (LEV/FB)\",\"description\":\"Operator volume and feedback.\"},\"MOD\":{\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"Modulation Slot (MOD)\",\"description\":\"Assigns one of MOD1-MOD4 to control a destination on the operator.\"},\"LEV\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Level Mod (LEV)\",\"description\":\"Controls the level from 00 to the currently set level.\"},\"RAT\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Ratio Mod (RAT)\",\"description\":\"Adds 0.00 to +16.00 to the current ratio.\"},\"PIT\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Pitch Mod (PIT)\",\"description\":\"Adds to the note pitch, in semitones, for the operator.\"},\"FBK\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Feedback Mod (FBK)\",\"description\":\"Controls feedback from 00 to the currently set feedback.\"},\"MOD#\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Modulation Source\",\"description\":\"Modulation source value freely assigned to operators through the MOD slots.\"}}},\"hypersynth\":{\"name\":\"Hypersynth\",\"description\":\"Six-note saw wave chord synthesizer with 16 chord banks of up to 6 intervals, detune (swarm), stereo width and a square sub-oscillator.\",\"params\":{\"SCALE\":{\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"Scale (SCALE)\",\"description\":\"One of the song's scales, or 00 to use the song/track scale settings.\"},\"CHORD\":{\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"Chord (CHORD)\",\"description\":\"Chord bank and its intervals (copy with [SHIFT]+[OPTION], paste with [SHIFT]+[EDIT]).\"},\"SHIFT\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Shift (SHIFT)\",\"description\":\"Cross-fades volume between the first 3 intervals and the second 3.\"},\"SWARM\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Swarm (SWARM)\",\"description\":\"Detunes the oscillators relative to their interval.\"},\"WIDTH\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Stereo Width (WIDTH)\",\"description\":\"Stereo width of the oscillators, from mono 00 to full stereo FF.\"},\"SUBOSC\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Sub Oscillator (SUBOSC)\",\"description\":\"Mixes in a sub-oscillator 2 octaves below the root (below 80) or 1 octave below (above 80).\"}}},\"external\":{\"name\":\"External Instrument\",\"description\":\"Hybrid MIDI output and audio input device: notes and MIDI FX are sent to the chosen port and channel, audio returns through its filter and amp stage.\",\"params\":{\"INPUT\":{\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"Audio Input (INPUT)\",\"description\":\"Audio input: line-in (stereo, left, right), USB (stereo, left, right), or line-in and USB.\"},\"PORT\":{\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"MIDI Port (PORT)\",\"description\":\"MIDI output port: MIDI and USB, MIDI only, USB only, or Internal (track MIDI input / global MIDI CCs from the MIDI Settings View).\"},\"CHANNEL\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"MIDI Channel (CHANNEL)\",\"description\":\"MIDI channel, 1 to 16.\"},\"BANK:PG\":{\"type\":\"parameter\",\"format\":\"hexPair\",\"parts\":[\"bank\",\"program\"],\"label\":\"Bank / Program (BANK:PG)\",\"description\":\"Optional MIDI bank select and program change (program change can also be sent as an FX command).\"},\"CC#\":{\"type\":\"parameter\",\"format\":\"hexPair\",\"parts\":[\"CC number\",\"value\"],\"label\":\"Custom CC (CC:VAL)\",\"description\":\"A custom MIDI CC number with an optional default value, sent with the note-on after program change messages.\"}}},\"midiout\":{\"name\":\"MIDI Out\",\"description\":\"Controls external devices over USB MIDI or the TRS (type A) MIDI output.\",\"params\":{\"PORT\":{\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"MIDI Port (PORT)\",\"description\":\"MIDI output port: MIDI and USB, MIDI only, USB only, or Internal (track MIDI input / global MIDI CCs from the MIDI Settings View).\"},\"CHANNEL\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"MIDI Channel (CHANNEL)\",\"description\":\"MIDI channel, 1 to 16.\"},\"BANK:PG\":{\"type\":\"parameter\",\"format\":\"hexPair\",\"parts\":[\"bank\",\"program\"],\"label\":\"Bank / Program (BANK:PG)\",\"description\":\"Optional MIDI bank select and program change (program change can also be sent as an FX command).\"},\"CC#\":{\"type\":\"parameter\",\"format\":\"hexPair\",\"parts\":[\"CC number\",\"value\"],\"label\":\"Custom CC (CC:VAL)\",\"description\":\"One of up to 10 custom MIDI CC numbers per instrument with an optional default value, sent with the note-on after program change messages.\"}}}}"),
|
|
3285
|
+
views: /* @__PURE__ */ JSON.parse("{\"project\":{\"rows\":[{\"id\":\"tempo\",\"match\":[{\"x\":0,\"text\":\"TEMPO\"}],\"cells\":[{\"x\":13,\"width\":6,\"key\":\"tempo\",\"type\":\"parameter\",\"format\":\"float\",\"unit\":\" BPM\",\"label\":\"Tempo (TEMPO)\",\"description\":\"Song speed in beats per minute. [EDIT] pressed rhythmically sets the tempo by tapping.\"}]},{\"id\":\"transpose\",\"match\":[{\"x\":0,\"text\":\"TRANSPOSE\"}],\"cells\":[{\"x\":13,\"width\":2,\"key\":\"transpose\",\"type\":\"transpose\",\"format\":\"hex\",\"label\":\"Project Transpose (TRANSPOSE)\",\"description\":\"Transposes the whole song in semitones (same as the TSP command). Only affects instruments with TRANSP. enabled; applied when [EDIT] is released.\"}]},{\"id\":\"groove\",\"match\":[{\"x\":0,\"text\":\"GROOVE\"}],\"cells\":[{\"x\":13,\"width\":14,\"key\":\"groove\",\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"Default Groove (GROOVE)\",\"description\":\"Groove used when the song plays (number and name); applied when [EDIT] is released. See Groove View.\"}]},{\"id\":\"scale\",\"match\":[{\"x\":0,\"text\":\"SCALE\"}],\"cells\":[{\"x\":13,\"width\":16,\"key\":\"scale\",\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"Default Scale (SCALE)\",\"description\":\"Scale (number, key and name) used when the song plays; applied when [EDIT] is released. See Scale View.\"}]},{\"id\":\"liveQuantize\",\"match\":[{\"x\":0,\"text\":\"LIVE QUANTIZ\"}],\"cells\":[{\"x\":13,\"width\":14,\"key\":\"liveQuantize\",\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"Live Quantize (LIVE QUANTIZE)\",\"description\":\"How long a cued chain waits before starting when playing in live mode.\"}]},{\"id\":\"midi\",\"match\":[{\"x\":0,\"text\":\"MIDI\"},{\"x\":13,\"text\":\"SETTINGS\"}],\"cells\":[{\"x\":13,\"width\":8,\"key\":\"midiSettings\",\"type\":\"action\",\"format\":\"text\",\"label\":\"MIDI Settings\",\"description\":\"Open the MIDI Settings View.\"},{\"x\":22,\"width\":8,\"key\":\"midiMappings\",\"type\":\"action\",\"format\":\"text\",\"label\":\"MIDI Mappings\",\"description\":\"Open the MIDI Mappings View.\"}]},{\"id\":\"name\",\"match\":[{\"x\":0,\"text\":\"NAME\"}],\"cells\":[{\"x\":13,\"width\":12,\"key\":\"name\",\"type\":\"name\",\"format\":\"text\",\"label\":\"Song Name (NAME)\",\"description\":\"Name of the current song, entered before saving.\"}]},{\"id\":\"file\",\"match\":[{\"x\":0,\"text\":\"PROJECT\"},{\"x\":13,\"text\":\"LOAD\"}],\"cells\":[{\"x\":13,\"width\":4,\"key\":\"load\",\"type\":\"action\",\"format\":\"text\",\"label\":\"Load Song\",\"description\":\"Load a song from the SD card.\"},{\"x\":18,\"width\":4,\"key\":\"save\",\"type\":\"action\",\"format\":\"text\",\"label\":\"Save Song\",\"description\":\"Save the current song.\"},{\"x\":23,\"width\":3,\"key\":\"new\",\"type\":\"action\",\"format\":\"text\",\"label\":\"New Song\",\"description\":\"Create a new song.\"}]},{\"id\":\"export\",\"match\":[{\"x\":0,\"text\":\"EXPORT/SHARE\"}],\"cells\":[{\"x\":13,\"width\":6,\"key\":\"render\",\"type\":\"action\",\"format\":\"text\",\"label\":\"Render\",\"description\":\"Open the Render View to render audio.\"},{\"x\":20,\"width\":6,\"key\":\"bundle\",\"type\":\"action\",\"format\":\"text\",\"label\":\"Bundle\",\"description\":\"Bundle the song with the instruments and samples it uses.\"}]},{\"id\":\"clearUnused\",\"match\":[{\"x\":0,\"text\":\"CLEAR UNUSED\"}],\"cells\":[{\"x\":13,\"width\":7,\"key\":\"clearPhrases\",\"type\":\"action\",\"format\":\"text\",\"label\":\"Clear Unused Phrases\",\"description\":\"Frees chains and phrases that are not used in the song.\"},{\"x\":21,\"width\":8,\"key\":\"clearInstTbl\",\"type\":\"action\",\"format\":\"text\",\"label\":\"Clear Unused Instruments/Tables\",\"description\":\"Frees instruments, EQs and tables that are not used in the song.\"}]},{\"id\":\"instPool\",\"match\":[{\"x\":0,\"text\":\"INST. POOL\"}],\"cells\":[{\"x\":13,\"width\":15,\"key\":\"viewInstPool\",\"type\":\"action\",\"format\":\"text\",\"label\":\"View Instrument Pool\",\"description\":\"Go to the Instrument Pool View.\"}]},{\"id\":\"timeStats\",\"match\":[{\"x\":0,\"text\":\"TIME STATS\"}],\"cells\":[{\"x\":13,\"width\":15,\"key\":\"viewTimeStats\",\"type\":\"action\",\"format\":\"text\",\"label\":\"View Time Stats\",\"description\":\"Open the Time Stats View (time spent on the song).\"}]},{\"id\":\"system\",\"match\":[{\"x\":0,\"text\":\"SYSTEM\"},{\"x\":13,\"text\":\"SETTINGS\"}],\"cells\":[{\"x\":13,\"width\":8,\"key\":\"systemSettings\",\"type\":\"action\",\"format\":\"text\",\"label\":\"System Settings\",\"description\":\"Go to the System Settings View.\"},{\"x\":22,\"width\":9,\"key\":\"usbDrive\",\"type\":\"action\",\"format\":\"text\",\"label\":\"USB Drive\",\"description\":\"Puts the M8 in USB drive mode so SD card files can be transferred to a computer.\"}]}]},\"systemsettings\":{\"rows\":[{\"id\":\"backlight\",\"match\":[{\"x\":0,\"text\":\"BACKLIGHT\"}],\"cells\":[{\"x\":15,\"width\":2,\"key\":\"backlight\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Backlight (BACKLIGHT)\",\"description\":\"Backlight LED brightness of the display.\"}]},{\"id\":\"fontOptions\",\"match\":[{\"x\":0,\"text\":\"FONT OPTIONS\"}],\"cells\":[{\"x\":15,\"width\":15,\"key\":\"fontOptions\",\"type\":\"option\",\"format\":\"text\",\"label\":\"Font Options (FONT OPTIONS)\",\"description\":\"Font settings, including a large font mode for readability.\"}]},{\"id\":\"theme\",\"match\":[{\"x\":0,\"text\":\"THEME\"}],\"cells\":[{\"x\":15,\"width\":10,\"key\":\"editTheme\",\"type\":\"action\",\"format\":\"text\",\"label\":\"Theme (EDIT THEME)\",\"description\":\"Open the Theme View.\"}]},{\"id\":\"notePreview\",\"match\":[{\"x\":0,\"text\":\"NOTE PREVIEW\"}],\"cells\":[{\"x\":15,\"width\":3,\"key\":\"notePreview\",\"type\":\"onOff\",\"format\":\"text\",\"label\":\"Note Preview (NOTE PREVIEW)\",\"description\":\"Plays the note when editing notes in the phrase view.\"}]},{\"id\":\"recCountIn\",\"match\":[{\"x\":0,\"regex\":\"^REC\\\\.\\\\s?(COUNT IN|METRONOME)\\\\s*$\",\"width\":13}],\"cells\":[{\"x\":15,\"width\":6,\"key\":\"recCountIn\",\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"Recording Count-in (REC. COUNT IN)\",\"description\":\"Number of phrases/measures of metronome count-in before recording audio in the Sample Editor or Selection to Sample.\"}]},{\"id\":\"metronomeVol\",\"match\":[{\"x\":0,\"text\":\"METRONOME VOL\"}],\"cells\":[{\"x\":15,\"width\":2,\"key\":\"metronomeVol\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Metronome Volume (METRONOME VOL)\",\"description\":\"Volume of the metronome sound (edit /System/Metronome.m8i to change the sound).\"}]},{\"id\":\"songTemplate\",\"match\":[{\"x\":0,\"text\":\"SONG TEMPLATE\"}],\"cells\":[{\"x\":15,\"width\":4,\"key\":\"songTemplateSave\",\"type\":\"action\",\"format\":\"text\",\"label\":\"Song Template (SAVE)\",\"description\":\"Use the currently opened song as the template for new songs.\"},{\"x\":20,\"width\":5,\"key\":\"songTemplateClear\",\"type\":\"action\",\"format\":\"text\",\"label\":\"Song Template (CLEAR)\",\"description\":\"Clear the song template.\"}]},{\"id\":\"usbAudioMode\",\"match\":[{\"x\":0,\"text\":\"USB AUDIO MODE\"}],\"cells\":[{\"x\":15,\"width\":14,\"key\":\"usbAudioMode\",\"type\":\"option\",\"format\":\"text\",\"label\":\"USB Audio Mode (USB AUDIO MODE)\",\"description\":\"USB output as stereo or multi-channel (multi-channel sends all 8 tracks and the effects individually, 12 stereo channels).\",\"options\":{\"STEREO OUT\":\"Stereo mix over USB.\"}}]},{\"id\":\"usbMainOut\",\"match\":[{\"x\":0,\"text\":\"USB MAIN OUT\"}],\"cells\":[{\"x\":15,\"width\":6,\"key\":\"usbMainOut\",\"type\":\"option\",\"format\":\"text\",\"label\":\"USB Main Out (USB MAIN OUT)\",\"description\":\"Routing behaviour of USB audio (see the USB audio routing options).\"}]},{\"id\":\"lineInGate\",\"match\":[{\"x\":0,\"text\":\"LINE-IN GATE\"}],\"cells\":[{\"x\":15,\"width\":6,\"key\":\"lineInGate\",\"type\":\"option\",\"format\":\"text\",\"label\":\"Line-in Gate (LINE-IN GATE)\",\"description\":\"Noise gate threshold for the line input, adjustable from -70 dB to -10 dB (OFF disables it).\"}]},{\"id\":\"splashScreen\",\"match\":[{\"x\":0,\"text\":\"SPLASH SCREEN\"}],\"cells\":[{\"x\":15,\"width\":3,\"key\":\"splashScreen\",\"type\":\"onOff\",\"format\":\"text\",\"label\":\"Splash Screen (SPLASH SCREEN)\",\"description\":\"Show the M8 logo and play the start-up sound when turning on the device.\"}]},{\"id\":\"hpProtection\",\"match\":[{\"x\":0,\"text\":\"HP PROTECTION\"}],\"cells\":[{\"x\":15,\"width\":3,\"key\":\"hpProtection\",\"type\":\"onOff\",\"format\":\"text\",\"label\":\"Headphone Protection (HP PROTECTION)\",\"description\":\"Limits the headphone output volume to F0 when a pack is unplugged and re-inserted.\"}]},{\"id\":\"keyDelayRep\",\"match\":[{\"x\":0,\"text\":\"KEY DELAY:REP\"}],\"cells\":[{\"x\":15,\"width\":7,\"key\":\"keyDelayRep\",\"type\":\"parameter\",\"format\":\"decimalPair\",\"unit\":\" ms\",\"parts\":[\"delay\",\"repeat\"],\"label\":\"Key Delay:Repeat (KEY DELAY:REP)\",\"description\":\"Key repeat timing in milliseconds: delay before a held key starts repeating, then the time between repeats.\"}]},{\"id\":\"battCharging\",\"match\":[{\"x\":0,\"regex\":\"^BATT\\\\.\\\\s?(CHARGING|STATUS)\\\\s*$\",\"width\":14}],\"cells\":[{\"x\":15,\"width\":14,\"key\":\"battCharging\",\"type\":\"option\",\"format\":\"text\",\"label\":\"Battery Charging (BATT. CHARGING / STATUS)\",\"description\":\"Whether the battery charges while the M8 is on and USB is connected (turn off to reduce power drawn from the host); also shows the current charging status.\"}]}]},\"effectsettings\":{\"sections\":[\"MODFX\",\"DELAY\",\"REVERB\"],\"rows\":[{\"id\":\"modfxType\",\"section\":\"MODFX\",\"match\":[{\"x\":7,\"text\":\"MOD TYPE\"}],\"cells\":[{\"x\":21,\"width\":10,\"key\":\"modfxType\",\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"ModFX Type (MOD TYPE)\",\"description\":\"ModFX effect: Chorus, Phaser or Flanger (also sets the phase position).\",\"options\":{\"CHORUS\":\"Stereo chorus.\",\"PHASER\":\"Stereo phaser.\",\"FLANGER\":\"Stereo flanger.\"}}]},{\"id\":\"modfxInputEq\",\"section\":\"MODFX\",\"match\":[{\"x\":7,\"text\":\"INPUT EQ\"}],\"cells\":[{\"x\":21,\"width\":2,\"key\":\"modfxInputEq\",\"type\":\"action\",\"format\":\"text\",\"label\":\"Input EQ (INPUT EQ)\",\"description\":\"Open the EQ editor for this effect's input.\"}]},{\"id\":\"modfxDepthFreq\",\"section\":\"MODFX\",\"match\":[{\"x\":7,\"text\":\"MOD DEPTH:FRQ\"}],\"cells\":[{\"x\":21,\"width\":5,\"key\":\"modfxDepthFreq\",\"type\":\"parameter\",\"format\":\"hexPair\",\"parts\":[\"mod depth\",\"mod frequency\"],\"label\":\"ModFX Mod Depth:Frequency (MOD DEPTH:FRQ)\",\"description\":\"Amount of modulation in the stereo signal (first value) and speed of the modulation (second value).\"}]},{\"id\":\"modfxWidth\",\"section\":\"MODFX\",\"match\":[{\"x\":7,\"text\":\"STEREO WIDTH\"}],\"cells\":[{\"x\":21,\"width\":2,\"key\":\"modfxWidth\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Stereo Width (STEREO WIDTH)\",\"description\":\"Stereo width: 00 is mono, FF is stereo.\"}]},{\"id\":\"modfxReverbSend\",\"section\":\"MODFX\",\"match\":[{\"x\":7,\"text\":\"REVERB SEND\"}],\"cells\":[{\"x\":21,\"width\":2,\"key\":\"modfxReverbSend\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Reverb Send (REVERB SEND)\",\"description\":\"Amount of this effect sent to the reverb.\"}]},{\"id\":\"delayInputEq\",\"section\":\"DELAY\",\"match\":[{\"x\":7,\"text\":\"INPUT EQ\"}],\"cells\":[{\"x\":21,\"width\":2,\"key\":\"delayInputEq\",\"type\":\"action\",\"format\":\"text\",\"label\":\"Input EQ (INPUT EQ)\",\"description\":\"Open the EQ editor for this effect's input.\"}]},{\"id\":\"delayTime\",\"section\":\"DELAY\",\"match\":[{\"x\":7,\"text\":\"TIME L:R\"}],\"cells\":[{\"x\":21,\"width\":5,\"key\":\"delayTime\",\"type\":\"parameter\",\"format\":\"hexPair\",\"parts\":[\"left time\",\"right time\"],\"label\":\"Delay Time L:R (TIME L:R)\",\"description\":\"Delay time for the left and right channels: first digit in beats, second digit in fractions of a beat (40 is 4 beats).\"}]},{\"id\":\"delayFeedback\",\"section\":\"DELAY\",\"match\":[{\"x\":7,\"text\":\"FEEDBACK\"}],\"cells\":[{\"x\":21,\"width\":2,\"key\":\"delayFeedback\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Feedback (FEEDBACK)\",\"description\":\"Amount of the delayed signal fed back into the delay.\"}]},{\"id\":\"delayWidth\",\"section\":\"DELAY\",\"match\":[{\"x\":7,\"text\":\"STEREO WIDTH\"}],\"cells\":[{\"x\":21,\"width\":2,\"key\":\"delayWidth\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Stereo Width (STEREO WIDTH)\",\"description\":\"Stereo width: 00 is mono, FF is stereo.\"}]},{\"id\":\"delayReverbSend\",\"section\":\"DELAY\",\"match\":[{\"x\":7,\"text\":\"REVERB SEND\"}],\"cells\":[{\"x\":21,\"width\":2,\"key\":\"delayReverbSend\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Reverb Send (REVERB SEND)\",\"description\":\"Amount of this effect sent to the reverb.\"}]},{\"id\":\"reverbInputEq\",\"section\":\"REVERB\",\"match\":[{\"x\":7,\"text\":\"INPUT EQ\"}],\"cells\":[{\"x\":21,\"width\":2,\"key\":\"reverbInputEq\",\"type\":\"action\",\"format\":\"text\",\"label\":\"Input EQ (INPUT EQ)\",\"description\":\"Open the EQ editor for this effect's input.\"}]},{\"id\":\"reverbRoomSize\",\"section\":\"REVERB\",\"match\":[{\"x\":7,\"text\":\"ROOM SIZE\"}],\"cells\":[{\"x\":21,\"width\":2,\"key\":\"reverbRoomSize\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Room Size (ROOM SIZE)\",\"description\":\"Size of the reverb room.\"}]},{\"id\":\"reverbDecayShimmer\",\"section\":\"REVERB\",\"match\":[{\"x\":7,\"text\":\"DECAY:SHIMMER\"}],\"cells\":[{\"x\":21,\"width\":5,\"key\":\"reverbDecayShimmer\",\"type\":\"parameter\",\"format\":\"hexPair\",\"parts\":[\"decay\",\"shimmer\"],\"label\":\"Reverb Decay:Shimmer (DECAY:SHIMMER)\",\"description\":\"Reverb decay time (first value) and shimmer amount (second value).\"}]},{\"id\":\"reverbDepthFreq\",\"section\":\"REVERB\",\"match\":[{\"x\":7,\"text\":\"MOD DEPTH:FRQ\"}],\"cells\":[{\"x\":21,\"width\":5,\"key\":\"reverbDepthFreq\",\"type\":\"parameter\",\"format\":\"hexPair\",\"parts\":[\"mod depth\",\"mod frequency\"],\"label\":\"Reverb Mod Depth:Frequency (MOD DEPTH:FRQ)\",\"description\":\"Reverb modulation depth (first value) and frequency (second value).\"}]},{\"id\":\"reverbWidth\",\"section\":\"REVERB\",\"match\":[{\"x\":7,\"text\":\"STEREO WIDTH\"}],\"cells\":[{\"x\":21,\"width\":2,\"key\":\"reverbWidth\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Stereo Width (STEREO WIDTH)\",\"description\":\"Stereo width: 00 is mono, FF is stereo.\"}]}]},\"mixer\":{\"rows\":[{\"id\":\"speaker\",\"match\":[{\"x\":0,\"text\":\"SPEAKER\"}],\"cells\":[{\"x\":12,\"width\":2,\"key\":\"speakerVol\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Speaker Volume (SPEAKER VOL)\",\"description\":\"Volume of the built-in speaker.\"}]},{\"id\":\"outputVol\",\"match\":[{\"x\":0,\"text\":\"OUTPUT VOL\"}],\"cells\":[{\"x\":12,\"width\":2,\"key\":\"outputVol\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Output Volume (OUTPUT VOL)\",\"description\":\"Volume of the audio output (headphones / line out).\"}]},{\"id\":\"tracks\",\"match\":[{\"x\":0,\"regex\":\"^[0-9A-F]{2}$\",\"width\":2},{\"x\":21,\"regex\":\"^[0-9A-F]{2}$\",\"width\":2}],\"cells\":[{\"x\":0,\"width\":2,\"key\":\"track1\",\"type\":\"volume\",\"format\":\"hex\",\"label\":\"Track 1 Volume\",\"meta\":{\"trackIndex\":1},\"description\":\"Volume of track 1. Instrument volumes are applied on top; the track's send levels are set in the instruments.\"},{\"x\":3,\"width\":2,\"key\":\"track2\",\"type\":\"volume\",\"format\":\"hex\",\"label\":\"Track 2 Volume\",\"meta\":{\"trackIndex\":2},\"description\":\"Volume of track 2.\"},{\"x\":6,\"width\":2,\"key\":\"track3\",\"type\":\"volume\",\"format\":\"hex\",\"label\":\"Track 3 Volume\",\"meta\":{\"trackIndex\":3},\"description\":\"Volume of track 3.\"},{\"x\":9,\"width\":2,\"key\":\"track4\",\"type\":\"volume\",\"format\":\"hex\",\"label\":\"Track 4 Volume\",\"meta\":{\"trackIndex\":4},\"description\":\"Volume of track 4.\"},{\"x\":12,\"width\":2,\"key\":\"track5\",\"type\":\"volume\",\"format\":\"hex\",\"label\":\"Track 5 Volume\",\"meta\":{\"trackIndex\":5},\"description\":\"Volume of track 5.\"},{\"x\":15,\"width\":2,\"key\":\"track6\",\"type\":\"volume\",\"format\":\"hex\",\"label\":\"Track 6 Volume\",\"meta\":{\"trackIndex\":6},\"description\":\"Volume of track 6.\"},{\"x\":18,\"width\":2,\"key\":\"track7\",\"type\":\"volume\",\"format\":\"hex\",\"label\":\"Track 7 Volume\",\"meta\":{\"trackIndex\":7},\"description\":\"Volume of track 7.\"},{\"x\":21,\"width\":2,\"key\":\"track8\",\"type\":\"volume\",\"format\":\"hex\",\"label\":\"Track 8 Volume\",\"meta\":{\"trackIndex\":8},\"description\":\"Volume of track 8.\"}]},{\"id\":\"eq\",\"match\":[{\"x\":27,\"text\":\"EQ\"}],\"cells\":[{\"x\":27,\"width\":2,\"key\":\"mixEq\",\"type\":\"action\",\"format\":\"text\",\"label\":\"Main Mix EQ (EQ)\",\"description\":\"Open the main mix EQ editor ([EDIT] or [SHIFT]+[RIGHT]).\"}]},{\"id\":\"levels\",\"match\":[{\"x\":0,\"regex\":\"^[0-9A-F]{2}$\",\"width\":2},{\"x\":3,\"regex\":\"^[0-9A-F]{2}$\",\"width\":2},{\"x\":6,\"regex\":\"^[0-9A-F]{2}$\",\"width\":2},{\"x\":12,\"regex\":\"^[0-9A-F]{2}$\",\"width\":2}],\"cells\":[{\"x\":0,\"width\":2,\"key\":\"modfxVol\",\"type\":\"volume\",\"format\":\"hex\",\"label\":\"ModFX Volume (MX)\",\"description\":\"Output level of the ModFX send effect.\"},{\"x\":3,\"width\":2,\"key\":\"delayVol\",\"type\":\"volume\",\"format\":\"hex\",\"label\":\"Delay Volume (DE)\",\"description\":\"Output level of the delay send effect.\"},{\"x\":6,\"width\":2,\"key\":\"reverbVol\",\"type\":\"volume\",\"format\":\"hex\",\"label\":\"Reverb Volume (RE)\",\"description\":\"Output level of the reverb send effect.\"},{\"x\":12,\"width\":2,\"key\":\"inputVol\",\"type\":\"volume\",\"format\":\"hex\",\"label\":\"Analog Input Volume (INPUT)\",\"description\":\"Volume of the analog input for monitoring. In dual-mono mode this is the left channel.\"},{\"x\":15,\"width\":2,\"key\":\"inputVol2\",\"type\":\"volume\",\"format\":\"hex\",\"label\":\"Analog Input Volume, 2nd channel\",\"description\":\"Enables dual-mono input mode when set (right channel volume); clear with [EDIT]+[OPTION] to disable.\"},{\"x\":18,\"width\":2,\"key\":\"usbVol\",\"type\":\"volume\",\"format\":\"hex\",\"label\":\"USB Input Volume (USB)\",\"description\":\"Volume of anything the USB host computer sends to the M8.\"},{\"x\":27,\"width\":2,\"key\":\"mainVol\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Main Volume (MIX)\",\"description\":\"Main song volume, applied after the limiter, DJ filter and OTT. [EDIT] or [SHIFT]+[RIGHT] opens the Mix Scope.\"}]},{\"id\":\"limiter\",\"match\":[{\"x\":0,\"text\":\"MX\"},{\"x\":3,\"text\":\"DE\"},{\"x\":6,\"text\":\"RE\"}],\"cells\":[{\"x\":27,\"width\":2,\"key\":\"limiter\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Limiter (LIM)\",\"description\":\"Main mix limiter amount; the limiter is engaged when the value is above 00. [EDIT] or [SHIFT]+[RIGHT] opens the Limiter Scope.\"}]},{\"id\":\"sendModfx\",\"match\":[{\"x\":9,\"text\":\"MX\"}],\"cells\":[{\"x\":12,\"width\":2,\"key\":\"inputModfx\",\"type\":\"volume\",\"format\":\"hex\",\"label\":\"Analog Input ModFX Send (INPUT MX)\",\"description\":\"How much of the analog input goes to the ModFX effect.\"},{\"x\":18,\"width\":2,\"key\":\"usbModfx\",\"type\":\"volume\",\"format\":\"hex\",\"label\":\"USB Input ModFX Send (USB MX)\",\"description\":\"How much of the USB input goes to the ModFX effect.\"},{\"x\":27,\"width\":2,\"key\":\"djFilter\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"DJ Filter (DJF)\",\"description\":\"DJ filter cutoff: 80 is off, below 80 low-pass (or band-stop), above 80 high-pass. Mode and options are in the Scope View.\"}]},{\"id\":\"sendDelay\",\"match\":[{\"x\":9,\"text\":\"DE\"}],\"cells\":[{\"x\":12,\"width\":2,\"key\":\"inputDelay\",\"type\":\"volume\",\"format\":\"hex\",\"label\":\"Analog Input Delay Send (INPUT DE)\",\"description\":\"How much of the analog input goes to the delay effect.\"},{\"x\":18,\"width\":2,\"key\":\"usbDelay\",\"type\":\"volume\",\"format\":\"hex\",\"label\":\"USB Input Delay Send (USB DE)\",\"description\":\"How much of the USB input goes to the delay effect.\"},{\"x\":27,\"width\":2,\"key\":\"ott\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"OTT (OTT)\",\"description\":\"Over The Top multi-band compression mixed in parallel: 00 to 80 mixes it in; from 80 and above the main mix is faded out.\"}]},{\"id\":\"sendReverb\",\"match\":[{\"x\":9,\"text\":\"RE\"}],\"cells\":[{\"x\":12,\"width\":2,\"key\":\"inputReverb\",\"type\":\"volume\",\"format\":\"hex\",\"label\":\"Analog Input Reverb Send (INPUT RE)\",\"description\":\"How much of the analog input goes to the reverb effect.\"},{\"x\":18,\"width\":2,\"key\":\"usbReverb\",\"type\":\"volume\",\"format\":\"hex\",\"label\":\"USB Input Reverb Send (USB RE)\",\"description\":\"How much of the USB input goes to the reverb effect.\"}]}]},\"mixeq\":{\"rows\":[{\"id\":\"gain\",\"match\":[{\"x\":0,\"text\":\"GAIN\"}],\"cells\":[{\"x\":5,\"width\":6,\"key\":\"lowGain\",\"type\":\"parameter\",\"format\":\"float\",\"unit\":\" dB\",\"label\":\"LOW Gain\",\"description\":\"Boost (positive) or cut (negative) applied by the LOW band, in decibels.\"},{\"x\":16,\"width\":6,\"key\":\"midGain\",\"type\":\"parameter\",\"format\":\"float\",\"unit\":\" dB\",\"label\":\"MID Gain\",\"description\":\"Boost (positive) or cut (negative) applied by the MID band, in decibels.\"},{\"x\":27,\"width\":6,\"key\":\"highGain\",\"type\":\"parameter\",\"format\":\"float\",\"unit\":\" dB\",\"label\":\"HIGH Gain\",\"description\":\"Boost (positive) or cut (negative) applied by the HIGH band, in decibels.\"}]},{\"id\":\"freq\",\"match\":[{\"x\":0,\"text\":\"FREQ\"}],\"cells\":[{\"x\":6,\"width\":5,\"key\":\"lowFreq\",\"type\":\"parameter\",\"format\":\"decimal\",\"unit\":\" Hz\",\"label\":\"LOW Frequency\",\"description\":\"Centre (or corner) frequency of the LOW band.\"},{\"x\":17,\"width\":5,\"key\":\"midFreq\",\"type\":\"parameter\",\"format\":\"decimal\",\"unit\":\" Hz\",\"label\":\"MID Frequency\",\"description\":\"Centre (or corner) frequency of the MID band.\"},{\"x\":28,\"width\":5,\"key\":\"highFreq\",\"type\":\"parameter\",\"format\":\"decimal\",\"unit\":\" Hz\",\"label\":\"HIGH Frequency\",\"description\":\"Centre (or corner) frequency of the HIGH band.\"}]},{\"id\":\"q\",\"match\":[{\"x\":0,\"text\":\"Q\"},{\"x\":1,\"regex\":\"^\\\\s?$\",\"width\":1}],\"cells\":[{\"x\":6,\"width\":3,\"key\":\"lowQ\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"LOW Q\",\"description\":\"Quality factor (bandwidth) of the LOW band: higher values narrow it.\"},{\"x\":17,\"width\":3,\"key\":\"midQ\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"MID Q\",\"description\":\"Quality factor (bandwidth) of the MID band: higher values narrow it.\"},{\"x\":28,\"width\":3,\"key\":\"highQ\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"HIGH Q\",\"description\":\"Quality factor (bandwidth) of the HIGH band: higher values narrow it.\"}]},{\"id\":\"type\",\"match\":[{\"x\":0,\"text\":\"TYPE\"}],\"cells\":[{\"x\":6,\"width\":9,\"key\":\"lowType\",\"type\":\"option\",\"format\":\"text\",\"label\":\"LOW Type\",\"description\":\"Filter shape of the LOW band.\",\"options\":{\"LOWCUT\":\"Removes frequencies below the cutoff.\",\"LOWSHELF\":\"Boosts or cuts frequencies below the shelf frequency.\",\"BELL\":\"Peaking filter: boosts or cuts around the centre frequency.\",\"BANDPASS\":\"Passes frequencies around the centre frequency, attenuating both sides.\",\"HI.SHELF\":\"Boosts or cuts frequencies above the shelf frequency.\",\"HI.CUT\":\"Attenuates or removes frequencies above the cutoff.\",\"ALLPASS\":\"Passes all frequencies at equal gain while shifting their phase.\"}},{\"x\":17,\"width\":9,\"key\":\"midType\",\"type\":\"option\",\"format\":\"text\",\"label\":\"MID Type\",\"description\":\"Filter shape of the MID band.\",\"options\":{\"LOWCUT\":\"Removes frequencies below the cutoff.\",\"LOWSHELF\":\"Boosts or cuts frequencies below the shelf frequency.\",\"BELL\":\"Peaking filter: boosts or cuts around the centre frequency.\",\"BANDPASS\":\"Passes frequencies around the centre frequency, attenuating both sides.\",\"HI.SHELF\":\"Boosts or cuts frequencies above the shelf frequency.\",\"HI.CUT\":\"Attenuates or removes frequencies above the cutoff.\",\"ALLPASS\":\"Passes all frequencies at equal gain while shifting their phase.\"}},{\"x\":28,\"width\":9,\"key\":\"highType\",\"type\":\"option\",\"format\":\"text\",\"label\":\"HIGH Type\",\"description\":\"Filter shape of the HIGH band.\",\"options\":{\"LOWCUT\":\"Removes frequencies below the cutoff.\",\"LOWSHELF\":\"Boosts or cuts frequencies below the shelf frequency.\",\"BELL\":\"Peaking filter: boosts or cuts around the centre frequency.\",\"BANDPASS\":\"Passes frequencies around the centre frequency, attenuating both sides.\",\"HI.SHELF\":\"Boosts or cuts frequencies above the shelf frequency.\",\"HI.CUT\":\"Attenuates or removes frequencies above the cutoff.\",\"ALLPASS\":\"Passes all frequencies at equal gain while shifting their phase.\"}}]},{\"id\":\"mode\",\"match\":[{\"x\":0,\"text\":\"MODE\"}],\"cells\":[{\"x\":6,\"width\":6,\"key\":\"lowMode\",\"type\":\"option\",\"format\":\"text\",\"label\":\"LOW Mode\",\"description\":\"How the LOW band is applied to the stereo signal.\",\"options\":{\"STEREO\":\"Processes left and right identically.\",\"MID\":\"Affects only the mid (centre) information.\",\"SIDE\":\"Affects only the side information (difference between left and right).\",\"LEFT\":\"Affects only the left channel.\",\"RIGHT\":\"Affects only the right channel.\"}},{\"x\":17,\"width\":6,\"key\":\"midMode\",\"type\":\"option\",\"format\":\"text\",\"label\":\"MID Mode\",\"description\":\"How the MID band is applied to the stereo signal.\",\"options\":{\"STEREO\":\"Processes left and right identically.\",\"MID\":\"Affects only the mid (centre) information.\",\"SIDE\":\"Affects only the side information (difference between left and right).\",\"LEFT\":\"Affects only the left channel.\",\"RIGHT\":\"Affects only the right channel.\"}},{\"x\":28,\"width\":6,\"key\":\"highMode\",\"type\":\"option\",\"format\":\"text\",\"label\":\"HIGH Mode\",\"description\":\"How the HIGH band is applied to the stereo signal.\",\"options\":{\"STEREO\":\"Processes left and right identically.\",\"MID\":\"Affects only the mid (centre) information.\",\"SIDE\":\"Affects only the side information (difference between left and right).\",\"LEFT\":\"Affects only the left channel.\",\"RIGHT\":\"Affects only the right channel.\"}}]}]},\"modfxeq\":{\"extends\":\"mixeq\"},\"delayeq\":{\"extends\":\"mixeq\"},\"reverbeq\":{\"extends\":\"mixeq\"},\"mixscope\":{\"rows\":[{\"id\":\"limiterAtkRel\",\"match\":[{\"x\":9,\"text\":\"ATK\"},{\"x\":16,\"text\":\"REL\"},{\"x\":23,\"text\":\"LIM\"}],\"cells\":[{\"x\":13,\"width\":2,\"key\":\"attack\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Limiter Attack (ATK)\",\"description\":\"Limiter attack time from 0 to 100 ms (see the on-screen help text for the conversion to milliseconds).\"},{\"x\":20,\"width\":2,\"key\":\"release\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Limiter Release (REL)\",\"description\":\"Limiter release time from 4 to 1000 ms; 00 activates AUTO mode (100-900 ms depending on the compression amount).\"},{\"x\":27,\"width\":2,\"key\":\"limiter\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Limiter (LIM)\",\"description\":\"Limiter amount.\"}]},{\"id\":\"zoomPeak\",\"match\":[{\"x\":0,\"text\":\"ZOOM\"}],\"cells\":[{\"x\":5,\"width\":5,\"key\":\"zoom\",\"type\":\"parameter\",\"format\":\"text\",\"label\":\"Zoom (ZOOM)\",\"description\":\"Lower limit of the scope histogram, in decibels.\"},{\"x\":20,\"width\":6,\"key\":\"peak\",\"type\":\"parameter\",\"format\":\"float\",\"unit\":\" dB\",\"label\":\"Peak (PEAK)\",\"description\":\"Current peak level of the main mix in dB. Resets when MIX or LIM change; clear it with [OPT]+[EDIT].\"}]},{\"id\":\"eq\",\"match\":[{\"x\":27,\"text\":\"EQ\"}],\"cells\":[{\"x\":27,\"width\":2,\"key\":\"mixEq\",\"type\":\"action\",\"format\":\"text\",\"label\":\"Main Mix EQ (EQ)\",\"description\":\"Open the main mix EQ editor.\"}]},{\"id\":\"softClip\",\"match\":[{\"x\":9,\"text\":\"SOFT CLIP\"}],\"cells\":[{\"x\":19,\"width\":3,\"key\":\"softClip\",\"type\":\"onOff\",\"format\":\"text\",\"label\":\"Soft Clip (SOFT CLIP)\",\"description\":\"Gentle saturation after the limiter to prevent harsh clipping; raise MIX to exaggerate it.\"},{\"x\":27,\"width\":2,\"key\":\"mainVol\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Main Volume (MIX)\",\"description\":\"Main mix / song volume, applied after the limiter stage.\"}]},{\"id\":\"mix\",\"match\":[{\"x\":23,\"text\":\"MIX\"}],\"cells\":[{\"x\":27,\"width\":2,\"key\":\"mainVol\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Main Volume (MIX)\",\"description\":\"Main mix / song volume, applied after the limiter stage.\"}]},{\"id\":\"lim\",\"match\":[{\"x\":23,\"text\":\"LIM\"}],\"cells\":[{\"x\":27,\"width\":2,\"key\":\"limiter\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Limiter (LIM)\",\"description\":\"Limiter amount.\"}]},{\"id\":\"djf\",\"match\":[{\"x\":23,\"text\":\"DJF\"}],\"cells\":[{\"x\":27,\"width\":2,\"key\":\"djFilter\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"DJ Filter (DJF)\",\"description\":\"DJ filter cutoff: 80 is off, 00-80 low-pass, 80-FF high-pass (mode set with TYPE).\"}]},{\"id\":\"ott\",\"match\":[{\"x\":23,\"text\":\"OTT\"}],\"cells\":[{\"x\":27,\"width\":2,\"key\":\"ott\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"OTT (OTT)\",\"description\":\"OTT mix amount; from 80 and above the main mix volume is faded out.\"}]}],\"zones\":[{\"id\":\"right\",\"labelX\":23,\"labelWidth\":4,\"x\":27,\"width\":6}],\"vocabulary\":{\"ATK\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Limiter Attack (ATK)\",\"description\":\"Limiter attack time from 0 to 100 ms (see the on-screen help text for the conversion).\"},\"REL\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Limiter Release (REL)\",\"description\":\"Limiter release time from 4 to 1000 ms; 00 activates AUTO mode (100-900 ms depending on the compression amount).\"},\"TYPE\":{\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"DJ Filter Type (TYPE)\",\"description\":\"DJ filter type: low-pass/high-pass, low-pass/band-stop or band-stop/high-pass.\"},\"RES\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"DJ Filter Resonance (RES)\",\"description\":\"Resonance of the DJ filter.\"},\"TIME\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"OTT Time (TIME)\",\"description\":\"OTT compressor envelope time as a percentage from 10% to 1000%.\"},\"COLOR\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"OTT Color (COLOR)\",\"description\":\"OTT compressor bands and low/high gains: above 80 shifts toward treble, below 80 toward bass.\"}}},\"limiterscope\":{\"extends\":\"mixscope\"},\"inst\":{\"rows\":[{\"id\":\"type\",\"match\":[{\"x\":0,\"text\":\"TYPE\"}],\"cells\":[{\"x\":8,\"width\":13,\"key\":\"instrumentType\",\"type\":\"instrumentType\",\"format\":\"text\",\"label\":\"Instrument Type (TYPE)\",\"description\":\"Kind of instrument in this slot: Wavsynth, Macrosynth, Sampler, FM Synth, Hypersynth, External Instrument, MIDI Out (or NONE for an unused slot). Changing it changes the parameters below.\"},{\"x\":22,\"width\":4,\"key\":\"load\",\"type\":\"action\",\"format\":\"text\",\"label\":\"Load Preset (LOAD)\",\"description\":\"Load an instrument preset from the SD card.\"},{\"x\":27,\"width\":4,\"key\":\"save\",\"type\":\"action\",\"format\":\"text\",\"label\":\"Save Preset (SAVE)\",\"description\":\"Save this instrument as a preset on the SD card.\"}]},{\"id\":\"name\",\"match\":[{\"x\":0,\"text\":\"NAME\"}],\"cells\":[{\"x\":8,\"width\":12,\"key\":\"name\",\"type\":\"name\",\"format\":\"text\",\"label\":\"Instrument Name (NAME)\",\"description\":\"Name of the instrument: helps keep the song organised when browsing, saving or bundling instruments.\"}]},{\"id\":\"transp\",\"match\":[{\"x\":0,\"text\":\"TRANSP.\"}],\"cells\":[{\"x\":8,\"width\":3,\"key\":\"transpose\",\"type\":\"onOff\",\"format\":\"text\",\"label\":\"Transpose Enabled (TRANSP.)\",\"description\":\"Enable or disable note transposition from scales, chain transpose columns and the project transpose for this instrument (turn off for percussive or effect instruments).\"},{\"x\":21,\"width\":2,\"key\":\"tableTic\",\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Table Tick (TBL. TIC)\",\"description\":\"Default speed at which this instrument's table advances: 01 is one tick per step, 02 two ticks per step. Can be overridden by the TIC command.\"},{\"x\":29,\"width\":2,\"key\":\"eq\",\"type\":\"eqSlot\",\"format\":\"hex\",\"label\":\"EQ Slot (EQ)\",\"description\":\"EQ bank assigned to this instrument (-- for none). [EDIT] or [SHIFT]+[RIGHT] opens the EQ editor.\"}]}],\"zones\":[{\"id\":\"left\",\"labelX\":0,\"labelWidth\":8,\"x\":8,\"width\":24},{\"id\":\"right\",\"labelX\":18,\"labelWidth\":4,\"x\":22,\"width\":11}],\"operators\":{\"instrument\":\"fmsynth\",\"x\":8,\"step\":6,\"width\":5,\"letters\":[\"A\",\"B\",\"C\",\"D\"]},\"vocabularyFrom\":\"instrumentTypes\"},\"instmods\":{\"slotLabel\":\"MOD\\\\d\",\"zones\":[{\"id\":\"left\",\"labelX\":0,\"labelWidth\":4,\"x\":5,\"width\":10},{\"id\":\"right\",\"labelX\":16,\"labelWidth\":4,\"x\":21,\"width\":10}],\"vocabulary\":{\"MOD#\":{\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"Modulator Type\",\"description\":\"Type of this modulation slot: AHD envelope, ADSR envelope, DRUM envelope, LFO, TRIG envelope or TRACKING. Slots can modulate their neighbour (Mod 1 affects Mod 2, 2→3, 3→4, 4→1).\",\"options\":{\"AHD ENV\":\"Attack Hold Decay envelope based on tempo.\",\"ADSR ENV\":\"Traditional Attack Decay Sustain Release envelope.\",\"DRUM ENV\":\"Sharp peak and swelling hold envelope for percussive elements.\",\"LFO\":\"Tempo-synced low frequency oscillator.\",\"TRIG ENV\":\"AHD envelope triggered by another playing track or instrument.\",\"TRACKING\":\"Modulates an instrument parameter from notes or velocities.\",\"OFF\":\"Slot unused.\"}},\"DEST\":{\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"Destination (DEST)\",\"description\":\"Instrument parameter this modulator controls. MOD AMT, MOD RATE or MOD BOTH modulate the neighbouring modulator's amount, rate or both.\"},\"SRC\":{\"type\":\"parameter\",\"format\":\"hexOption\",\"label\":\"Source (SRC)\",\"description\":\"Modulation source. Trig envelope: an instrument number (00-7F) or a whole track (80-87 = tracks 1-8). Tracking: NOTE, VELOCITY or VELOCITY TAKEOVER (velocity no longer affects instrument volume).\"},\"AMT\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Amount (AMT)\",\"description\":\"How strongly the modulator is applied to the destination.\"},\"ATK\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Attack (ATK)\",\"description\":\"Time to reach the amount (in ticks, relative to tempo).\"},\"HOLD\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Hold (HOLD)\",\"description\":\"Time to wait after the attack before decaying (in ticks).\"},\"DEC\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Decay (DEC)\",\"description\":\"Time to fall back (AHD/Drum: to zero; ADSR: to the sustain level), in ticks.\"},\"SUS\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Sustain (SUS)\",\"description\":\"Level held while the note is playing (ADSR).\"},\"REL\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Release (REL)\",\"description\":\"Time to fall back to zero after the note is released (ADSR); needs an OFF note or FX command.\"},\"PEAK\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Peak (PEAK)\",\"description\":\"Shape of the initial transient (drum envelope); modifies the duck amount and peak time.\"},\"BODY\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Body (BODY)\",\"description\":\"Time to hold the modulation before decaying (drum envelope).\"},\"OSC\":{\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"LFO Shape (OSC)\",\"description\":\"LFO shape: triangle, sine, ramp down/up, exponential down/up, square down/up, random, drunk. The 'T' variants run in ticks (much faster).\",\"options\":{\"TRI\":\"Triangle.\",\"SIN\":\"Sine.\",\"RAMP DN\":\"Ramp down.\",\"RAMP UP\":\"Ramp up.\",\"EXP DN\":\"Exponential down.\",\"EXP UP\":\"Exponential up.\",\"SQU DN\":\"Square down.\",\"SQU UP\":\"Square up.\",\"RANDOM\":\"Random values.\",\"DRUNK\":\"Random walk.\"}},\"TRIG\":{\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"LFO Trigger (TRIG)\",\"description\":\"How the LFO reacts when the instrument triggers and when the shape ends.\",\"options\":{\"FREE\":\"Loop the shape and don't reset on new notes.\",\"RETRIG\":\"Loop the shape and reset on each instrument trigger.\",\"HOLD\":\"Hold the last value of the shape.\",\"ONCE\":\"Play the shape once and reset to the start value.\"}},\"FREQ\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"LFO Frequency (FREQ)\",\"description\":\"Rate of the LFO in steps (16th notes), or in ticks for the 'T' shapes.\"},\"LVAL\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Low Value (LVAL)\",\"description\":\"Lowest value of the source range scaled to the destination (tracking). Can be higher than HVAL to invert the range.\"},\"HVAL\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"High Value (HVAL)\",\"description\":\"Highest value of the source range scaled to the destination (tracking).\"}}},\"scale\":{\"notes\":\"Only the rows below the 12 interval rows; the intervals themselves are grid columns in m8-view-context.json.\",\"rows\":[{\"id\":\"key\",\"match\":[{\"x\":0,\"text\":\"KEY\"}],\"cells\":[{\"x\":6,\"width\":2,\"key\":\"key\",\"type\":\"option\",\"format\":\"text\",\"label\":\"Key (KEY)\",\"description\":\"Global key: the root note of the default scale (can be overridden per track with SCA / SCG).\"}]},{\"id\":\"tune\",\"match\":[{\"x\":0,\"text\":\"TUNE\"}],\"cells\":[{\"x\":6,\"width\":6,\"key\":\"tune\",\"type\":\"parameter\",\"format\":\"float\",\"unit\":\" Hz\",\"label\":\"Tuning (TUNE)\",\"description\":\"Reference pitch of A4 in Hz (440.00 is standard).\"}]},{\"id\":\"name\",\"match\":[{\"x\":0,\"text\":\"NAME\"}],\"cells\":[{\"x\":6,\"width\":16,\"key\":\"name\",\"type\":\"name\",\"format\":\"text\",\"label\":\"Scale Name (NAME)\",\"description\":\"Name of this scale (up to 16 characters); 92 factory scales load from /Scales/Factory.\"}]},{\"id\":\"file\",\"match\":[{\"x\":6,\"text\":\"LOAD\"},{\"x\":11,\"text\":\"SAVE\"}],\"cells\":[{\"x\":6,\"width\":4,\"key\":\"load\",\"type\":\"action\",\"format\":\"text\",\"label\":\"Load Scale (LOAD)\",\"description\":\"Load a scale from the SD card.\"},{\"x\":11,\"width\":4,\"key\":\"save\",\"type\":\"action\",\"format\":\"text\",\"label\":\"Save Scale (SAVE)\",\"description\":\"Save this scale to the SD card.\"}]}]},\"loadinstrument\":{\"kind\":\"browser\",\"browserFor\":\"instrument preset\"},\"selectsavedirectory\":{\"kind\":\"browser\",\"browserFor\":\"save location\"},\"createdirectory\":{\"kind\":\"text\",\"fieldLabel\":\"Directory Name\",\"description\":\"Name of the directory to create on the SD card.\"}}"),
|
|
3286
|
+
instrumentTypes: /* @__PURE__ */ JSON.parse("{\"common\":{\"name\":\"Common\",\"description\":\"Parameters shared by most instrument types.\",\"params\":{\"FILTER\":{\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"Filter Type (FILTER)\",\"description\":\"Multi-mode filter type: low-pass, high-pass, band-pass, band-stop, LP>HP (low-pass with RES controlling a 1-pole high-pass), ZDF low-pass, ZDF high-pass.\"},\"CUTOFF\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Filter Cutoff (CUTOFF)\",\"description\":\"Filter cutoff frequency.\"},\"RES\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Filter Resonance (RES)\",\"description\":\"Filter resonance amount.\"},\"AMP\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Amplification (AMP)\",\"description\":\"Amplifies the signal; values above the maximum level are handled according to LIM.\"},\"LIM\":{\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"Limit Mode (LIM)\",\"description\":\"Limit / clipping behaviour of the amplified signal.\",\"options\":{\"CLIP\":\"Values above the maximum level are clipped.\",\"SIN\":\"The waveform is fed through a sine function.\",\"FOLD\":\"Values above the maximum level are folded back into themselves.\",\"WRAP\":\"Values above the maximum level are wrapped vertically.\",\"POST\":\"Amplification applied with hard-clipping after the filter stage.\",\"POST:AD\":\"Post filter amplification with soft-clipping.\",\"POST:W1\":\"Post filter folding distortion.\",\"POST:W2\":\"Post filter folding distortion.\",\"POST:W3\":\"Post filter folding distortion.\"}},\"PAN\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Pan (PAN)\",\"description\":\"Stereo position of the instrument (80 is centre).\"},\"DRY\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Dry Volume (DRY)\",\"description\":\"Dry volume sent to the mixer channel.\"},\"MFX\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"ModFX Send (MFX)\",\"description\":\"ModFX send effect volume.\"},\"DEL\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Delay Send (DEL)\",\"description\":\"Delay send effect volume.\"},\"REV\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Reverb Send (REV)\",\"description\":\"Reverb send effect volume.\"}}},\"wavsynth\":{\"name\":\"Wavsynth\",\"description\":\"Wave table synthesizer and noise generator: an 8-bit sample buffer generated in real time from one of 9 basic shapes (repeated, skewed, mirrored, filtered, overdriven) or one of 61 built-in wave tables of 64 waveforms each.\",\"params\":{\"SHAPE\":{\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"Shape (SHAPE)\",\"description\":\"Base waveform: PULSE 12% to 75%, SAW, TRIANGLE, SINE, NOISE PITCHED, NOISE, or WT wave tables. For PWM set PULSE 50% and adjust MIRROR (smoothness set by SIZE).\"},\"SIZE\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Size (SIZE)\",\"description\":\"Horizontal size of the waveform (number of samples).\"},\"MULT\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Multiply (MULT)\",\"description\":\"Multiplies the waveform by adding repeats of the shape; can sound like hard sync.\"},\"WARP\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Warp (WARP)\",\"description\":\"Pushes the shape to one side of the wave table.\"},\"SCAN\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Scan / Mirror (SCAN)\",\"description\":\"Shapes 0-8: mirrors the waveform at the given position (0-200%). Wave tables: scans through the 64 waveforms.\"},\"FILTER\":{\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"Filter Type (FILTER)\",\"description\":\"Multi-mode filter type, plus 4 modes that apply the filter into the waveform: WAV LP, WAV HP, WAV BP, WAV BS.\"}}},\"macrosynth\":{\"name\":\"Macrosynth\",\"description\":\"44 engines ('shapes') from basic analog to 2-op FM, physical modelling and percussion; TIMBRE and COLOR change meaning per shape.\",\"params\":{\"SHAPE\":{\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"Shape (SHAPE)\",\"description\":\"One of the 44 Macrosynth engines (see the Macrosynth Models appendix).\"},\"TIMBRE\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Timbre (TIMBRE)\",\"description\":\"First parameter of the selected shape.\"},\"COLOR\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Color (COLOR)\",\"description\":\"Second parameter of the selected shape.\"},\"DEGRADE\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Degrade (DEGRADE)\",\"description\":\"Sample rate reduction effect.\"},\"REDUX\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Redux (REDUX)\",\"description\":\"Bit rate reduction effect.\"}}},\"sampler\":{\"name\":\"Sampler\",\"description\":\"Sample player, editor and recorder for 1 or 2 channel PCM .wav files.\",\"params\":{\"SAMPLE\":{\"type\":\"name\",\"format\":\"text\",\"label\":\"Sample (SAMPLE)\",\"description\":\"The loaded sample; use LOAD to browse for one, REC. to record or EDIT to open the Sample Editor.\"},\"SLICE\":{\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"Slice (SLICE)\",\"description\":\"Slices the sample into equal sections, mapped from the lowest octave (C-1); 01 FILE uses the markers stored in the file.\"},\"PLAY\":{\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"Play Mode (PLAY)\",\"description\":\"Play direction and loop mode.\",\"options\":{\"FWD\":\"Forward, no loop.\",\"REV\":\"Reverse, no loop.\",\"FWDLOOP\":\"Looping forward.\",\"REVLOOP\":\"Looping reverse.\",\"FWD PP\":\"Ping-pong looping, forward first.\",\"REV PP\":\"Ping-pong looping, reverse first.\",\"OSC\":\"Oscillator mode: ignores the start position and doesn't restart on retrigger.\",\"OSC REV\":\"Oscillator mode, reverse.\",\"OSC PP\":\"Oscillator mode, ping-pong.\",\"REPITCH\":\"Pitches the sample from the song tempo (adjust with STEPS/BPM).\"}},\"START\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Start (START)\",\"description\":\"Sample start position (ignored in OSC play modes).\"},\"LOOP ST.\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Loop Start (LOOP ST.)\",\"description\":\"Where the sample loops back to when it reaches the end in a looping play mode.\"},\"LOOP ST\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Loop Start (LOOP ST)\",\"description\":\"Where the sample loops back to when it reaches the end in a looping play mode.\"},\"LEN\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Length (LEN)\",\"description\":\"Sample length.\"},\"LENGTH\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Length (LENGTH)\",\"description\":\"Sample length.\"},\"DETUNE\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Detune (DETUNE)\",\"description\":\"Detune with 80 as the centre frequency: first digit steps semitones, second digit 1/16 semitone.\"},\"DEGRADE\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Degrade (DEGRADE)\",\"description\":\"Sample rate reduction; any value above 00 disables sample interpolation.\"}}},\"fmsynth\":{\"name\":\"FM Synth\",\"description\":\"Four-operator, 12-algorithm FM synthesizer. Each operator has a base shape, ratio, level, feedback and two modulation slots.\",\"operatorDestinations\":{\"LEV\":\"controls the level from 00 to the currently set level.\",\"RAT\":\"adds 0.00 to +16.00 to the current ratio.\",\"PIT\":\"adds to the note pitch, in semitones, for this operator.\",\"FBK\":\"controls the feedback from 00 to the currently set feedback.\"},\"params\":{\"ALGO\":{\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"Algorithm (ALGO)\",\"description\":\"One of 12 algorithms (oscillator routing); the last one is additive mode.\"},\"A\":{\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"Operator A (A)\",\"description\":\"Operator letter with optional shape (SIN, SW2-SW6, SAW, SQU, PUL, IMP, TRI, NOISE, then wave tables).\"},\"B\":{\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"Operator B (B)\",\"description\":\"Operator letter with optional shape.\"},\"C\":{\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"Operator C (C)\",\"description\":\"Operator letter with optional shape.\"},\"D\":{\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"Operator D (D)\",\"description\":\"Operator letter with optional shape.\"},\"RATIO\":{\"type\":\"parameter\",\"format\":\"float\",\"label\":\"Ratio (RATIO)\",\"description\":\"Operator frequency ratio relative to the played note (2.00 is an octave up, 0.50 an octave down).\"},\"LEV/FB\":{\"type\":\"parameter\",\"format\":\"hexPair\",\"parts\":[\"level\",\"feedback\"],\"label\":\"Level / Feedback (LEV/FB)\",\"description\":\"Operator volume and feedback.\"},\"MOD\":{\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"Modulation Slot (MOD)\",\"description\":\"Assigns one of MOD1-MOD4 to control a destination on the operator.\"},\"LEV\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Level Mod (LEV)\",\"description\":\"Controls the level from 00 to the currently set level.\"},\"RAT\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Ratio Mod (RAT)\",\"description\":\"Adds 0.00 to +16.00 to the current ratio.\"},\"PIT\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Pitch Mod (PIT)\",\"description\":\"Adds to the note pitch, in semitones, for the operator.\"},\"FBK\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Feedback Mod (FBK)\",\"description\":\"Controls feedback from 00 to the currently set feedback.\"},\"MOD#\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Modulation Source\",\"description\":\"Modulation source value freely assigned to operators through the MOD slots.\"}}},\"hypersynth\":{\"name\":\"Hypersynth\",\"description\":\"Six-note saw wave chord synthesizer with 16 chord banks of up to 6 intervals, detune (swarm), stereo width and a square sub-oscillator.\",\"params\":{\"SCALE\":{\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"Scale (SCALE)\",\"description\":\"One of the song's scales, or 00 to use the song/track scale settings.\"},\"CHORD\":{\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"Chord (CHORD)\",\"description\":\"Chord bank and its intervals (copy with [SHIFT]+[OPTION], paste with [SHIFT]+[EDIT]).\"},\"SHIFT\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Shift (SHIFT)\",\"description\":\"Cross-fades volume between the first 3 intervals and the second 3.\"},\"SHAPE\":{\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"Shape (SHAPE)\",\"description\":\"Waveform of the chord oscillators (SAW by default; not in the manual, seen on a Model:02, firmware 6.5).\"},\"SWARM\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Swarm (SWARM)\",\"description\":\"Detunes the oscillators relative to their interval.\"},\"WIDTH\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Stereo Width (WIDTH)\",\"description\":\"Stereo width of the oscillators, from mono 00 to full stereo FF.\"},\"SUBOSC\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"Sub Oscillator (SUBOSC)\",\"description\":\"Mixes in a sub-oscillator 2 octaves below the root (below 80) or 1 octave below (above 80).\"}}},\"external\":{\"name\":\"External Instrument\",\"description\":\"Hybrid MIDI output and audio input device: notes and MIDI FX are sent to the chosen port and channel, audio returns through its filter and amp stage.\",\"params\":{\"INPUT\":{\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"Audio Input (INPUT)\",\"description\":\"Audio input: line-in (stereo, left, right), USB (stereo, left, right), or line-in and USB.\"},\"PORT\":{\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"MIDI Port (PORT)\",\"description\":\"MIDI output port: MIDI and USB, MIDI only, USB only, or Internal (track MIDI input / global MIDI CCs from the MIDI Settings View).\"},\"CHANNEL\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"MIDI Channel (CHANNEL)\",\"description\":\"MIDI channel, 1 to 16.\"},\"BANK:PG\":{\"type\":\"parameter\",\"format\":\"hexPair\",\"parts\":[\"bank\",\"program\"],\"label\":\"Bank / Program (BANK:PG)\",\"description\":\"Optional MIDI bank select and program change (program change can also be sent as an FX command).\"},\"CC#\":{\"type\":\"parameter\",\"format\":\"text\",\"label\":\"Custom CC (CC:VAL)\",\"description\":\"A custom MIDI CC number, then an optional default value (-- for none), sent with the note-on after program change messages.\"}}},\"midiout\":{\"name\":\"MIDI Out\",\"description\":\"Controls external devices over USB MIDI or the TRS (type A) MIDI output.\",\"params\":{\"PORT\":{\"type\":\"option\",\"format\":\"hexOption\",\"label\":\"MIDI Port (PORT)\",\"description\":\"MIDI output port: MIDI and USB, MIDI only, USB only, or Internal (track MIDI input / global MIDI CCs from the MIDI Settings View).\"},\"CHANNEL\":{\"type\":\"parameter\",\"format\":\"hex\",\"label\":\"MIDI Channel (CHANNEL)\",\"description\":\"MIDI channel, 1 to 16.\"},\"BANK:PG\":{\"type\":\"parameter\",\"format\":\"hexPair\",\"parts\":[\"bank\",\"program\"],\"label\":\"Bank / Program (BANK:PG)\",\"description\":\"Optional MIDI bank select and program change (program change can also be sent as an FX command).\"},\"CC#\":{\"type\":\"parameter\",\"format\":\"text\",\"label\":\"Custom CC (CC:VAL)\",\"description\":\"One of up to 10 custom MIDI CC numbers per instrument, then an optional default value (-- for none), sent with the note-on after program change messages.\"}}}}"),
|
|
2925
3287
|
instrumentTypeNames: {
|
|
2926
3288
|
WAVS: "wavsynth",
|
|
2927
3289
|
MACRO: "macrosynth",
|
|
@@ -2931,23 +3293,23 @@ var yt = 20, bt = (e, t) => {
|
|
|
2931
3293
|
EXTERN: "external",
|
|
2932
3294
|
MIDI: "midiout"
|
|
2933
3295
|
}
|
|
2934
|
-
},
|
|
2935
|
-
for (let [e, t] of Object.entries(
|
|
3296
|
+
}, It = Ft.views, Lt = Ft.instrumentTypes, Rt = Ft.instrumentTypeNames, zt = {};
|
|
3297
|
+
for (let [e, t] of Object.entries(It)) {
|
|
2936
3298
|
let { extends: n, ...r } = t;
|
|
2937
|
-
|
|
2938
|
-
...
|
|
3299
|
+
zt[e] = n ? {
|
|
3300
|
+
...It[n],
|
|
2939
3301
|
...r
|
|
2940
3302
|
} : r;
|
|
2941
3303
|
}
|
|
2942
|
-
function
|
|
2943
|
-
return
|
|
3304
|
+
function Bt(e) {
|
|
3305
|
+
return zt[e] ?? null;
|
|
2944
3306
|
}
|
|
2945
|
-
var
|
|
2946
|
-
function
|
|
2947
|
-
let n = e.width ?? e.text?.length ?? 1, r =
|
|
3307
|
+
var G = (e, t, n) => t >= e.length ? "" : e.slice(t, t + n);
|
|
3308
|
+
function Vt(e, t) {
|
|
3309
|
+
let n = e.width ?? e.text?.length ?? 1, r = G(t, e.x, n);
|
|
2948
3310
|
return e.text == null ? e.regex != null && new RegExp(e.regex, "i").test(r) : r.toUpperCase() === e.text.toUpperCase();
|
|
2949
3311
|
}
|
|
2950
|
-
function
|
|
3312
|
+
function Ht(e, t) {
|
|
2951
3313
|
let n = e.sections;
|
|
2952
3314
|
if (!n) return null;
|
|
2953
3315
|
for (let e of t) {
|
|
@@ -2956,52 +3318,111 @@ function jt(e, t) {
|
|
|
2956
3318
|
}
|
|
2957
3319
|
return null;
|
|
2958
3320
|
}
|
|
2959
|
-
function
|
|
3321
|
+
function Ut(e, t, n) {
|
|
2960
3322
|
let r = e.zones?.find((e) => e.id === t);
|
|
2961
3323
|
if (!e.slotLabel || !r) return null;
|
|
2962
3324
|
let i = RegExp(`^${e.slotLabel}$`, "i");
|
|
2963
3325
|
for (let e of n) {
|
|
2964
|
-
let t =
|
|
3326
|
+
let t = G(e, r.labelX, r.labelWidth).trim();
|
|
2965
3327
|
if (i.test(t)) return t.toUpperCase();
|
|
2966
3328
|
}
|
|
2967
3329
|
return null;
|
|
2968
3330
|
}
|
|
2969
|
-
function
|
|
3331
|
+
function Wt(e) {
|
|
2970
3332
|
let t = e.toUpperCase().replace(/[^A-Z]/g, "");
|
|
2971
3333
|
if (!t) return null;
|
|
2972
|
-
let n = Object.keys(
|
|
2973
|
-
return n ?
|
|
3334
|
+
let n = Object.keys(Rt).find((e) => t.startsWith(e));
|
|
3335
|
+
return n ? Rt[n] : null;
|
|
2974
3336
|
}
|
|
2975
|
-
function
|
|
3337
|
+
function Gt(e) {
|
|
2976
3338
|
for (let t of e) if (t.toUpperCase().startsWith("TYPE")) {
|
|
2977
|
-
let e =
|
|
3339
|
+
let e = G(t, 8, 13).trim();
|
|
2978
3340
|
return e ? {
|
|
2979
3341
|
text: e,
|
|
2980
|
-
key:
|
|
3342
|
+
key: Wt(e)
|
|
2981
3343
|
} : null;
|
|
2982
3344
|
}
|
|
2983
3345
|
return null;
|
|
2984
3346
|
}
|
|
2985
|
-
function
|
|
2986
|
-
let t =
|
|
3347
|
+
function Kt(e) {
|
|
3348
|
+
let t = Lt[e];
|
|
2987
3349
|
return t ? {
|
|
2988
3350
|
name: t.name,
|
|
2989
3351
|
description: t.description
|
|
2990
3352
|
} : null;
|
|
2991
3353
|
}
|
|
2992
|
-
function
|
|
3354
|
+
function qt(e, t, n) {
|
|
2993
3355
|
let r = t.replace(/^MOD\d$/, "MOD#").replace(/^CC[A-J]$/, "CC#");
|
|
2994
3356
|
if (e.vocabulary) return e.vocabulary[r] ?? null;
|
|
2995
3357
|
if (e.vocabularyFrom !== "instrumentTypes") return null;
|
|
2996
|
-
let i = n ? [n, "common"] : ["common", ...Object.keys(
|
|
3358
|
+
let i = n ? [n, "common"] : ["common", ...Object.keys(Lt).filter((e) => e !== "common")];
|
|
2997
3359
|
for (let e of i) {
|
|
2998
|
-
let t =
|
|
3360
|
+
let t = Lt[e]?.params[r];
|
|
2999
3361
|
if (t) return t;
|
|
3000
3362
|
}
|
|
3001
3363
|
return null;
|
|
3002
3364
|
}
|
|
3003
|
-
var
|
|
3004
|
-
|
|
3365
|
+
var Jt = (e) => e.toLowerCase().replace(/[^a-z0-9]+(.)?/g, (e, t) => t ? t.toUpperCase() : "").replace(/^[^a-z]+/, ""), Yt = /^[A-Z][A-Z0-9.:#/ -]*$/, Xt = {
|
|
3366
|
+
RATIO: "ratio",
|
|
3367
|
+
"LEV/FB": "levFb",
|
|
3368
|
+
MOD: "mod"
|
|
3369
|
+
}, Zt = /^(?:-----|[1-4]>[A-Z]{3})$/i;
|
|
3370
|
+
function Qt(e, t, n) {
|
|
3371
|
+
let r = G(t, 0, e.x).trim().toUpperCase(), i = e.letters.map((t, n) => ({
|
|
3372
|
+
letter: t,
|
|
3373
|
+
x: e.x + n * e.step
|
|
3374
|
+
})), a = (e, t, n, i, a) => ({
|
|
3375
|
+
...i,
|
|
3376
|
+
x: t,
|
|
3377
|
+
width: n,
|
|
3378
|
+
key: `${e}${a}`,
|
|
3379
|
+
label: `${i.label} · operator ${a}`,
|
|
3380
|
+
meta: {
|
|
3381
|
+
paramLabel: r || e,
|
|
3382
|
+
operator: a
|
|
3383
|
+
}
|
|
3384
|
+
}), o = Xt[r];
|
|
3385
|
+
if (o) {
|
|
3386
|
+
let t = n.params[r];
|
|
3387
|
+
return t ? i.map(({ letter: i, x: s }) => a(o, s, e.width, r === "MOD" ? $t(t, 1, n) : t, i)) : null;
|
|
3388
|
+
}
|
|
3389
|
+
if (r) return null;
|
|
3390
|
+
if (/^\s+[A-D] \S/i.test(t)) {
|
|
3391
|
+
let r = [];
|
|
3392
|
+
for (let i of t.matchAll(/([A-D]) (\S+)/gi)) {
|
|
3393
|
+
let t = i[1].toUpperCase(), a = n.params[t];
|
|
3394
|
+
a && e.letters.includes(t) && r.push({
|
|
3395
|
+
...a,
|
|
3396
|
+
type: "option",
|
|
3397
|
+
format: "text",
|
|
3398
|
+
x: (i.index ?? 0) + 2,
|
|
3399
|
+
width: i[2].length,
|
|
3400
|
+
key: `shape${t}`,
|
|
3401
|
+
label: `Shape · operator ${t}`,
|
|
3402
|
+
meta: {
|
|
3403
|
+
paramLabel: "SHAPE",
|
|
3404
|
+
operator: t
|
|
3405
|
+
}
|
|
3406
|
+
});
|
|
3407
|
+
}
|
|
3408
|
+
return r.length ? r : null;
|
|
3409
|
+
}
|
|
3410
|
+
let s = i.map(({ x: n }) => G(t, n, e.width).trim()), c = n.params.MOD;
|
|
3411
|
+
return c && s.every((e) => Zt.test(e)) && !G(t, 0, e.x).trim() ? i.map(({ letter: t, x: r }) => a("mod2", r, e.width, $t(c, 2, n), t)) : null;
|
|
3412
|
+
}
|
|
3413
|
+
function $t(e, t, n) {
|
|
3414
|
+
let r = {};
|
|
3415
|
+
for (let [e, t] of Object.entries(n.operatorDestinations ?? {})) for (let n = 1; n <= 4; n += 1) r[`${n}>${e}`] = `MOD${n} ${e}: ${t}`;
|
|
3416
|
+
return {
|
|
3417
|
+
...e,
|
|
3418
|
+
type: "option",
|
|
3419
|
+
format: "text",
|
|
3420
|
+
label: `Modulation Slot ${t} (MOD)`,
|
|
3421
|
+
options: r
|
|
3422
|
+
};
|
|
3423
|
+
}
|
|
3424
|
+
var en = /^(CC[A-J])(?: CC:VAL)? +(?=\S)/i, tn = 6;
|
|
3425
|
+
function nn(e, t, n) {
|
|
3005
3426
|
if (e.kind === "browser") {
|
|
3006
3427
|
let r = n.entryText?.trim() || t.trim();
|
|
3007
3428
|
return r ? {
|
|
@@ -3039,28 +3460,35 @@ function zt(e, t, n) {
|
|
|
3039
3460
|
}]
|
|
3040
3461
|
};
|
|
3041
3462
|
}
|
|
3042
|
-
for (let r of e.rows ?? []) if (!(r.section && n.section && r.section !== n.section) && r.match.every((e) =>
|
|
3463
|
+
for (let r of e.rows ?? []) if (!(r.section && n.section && r.section !== n.section) && r.match.every((e) => Vt(e, t))) return {
|
|
3043
3464
|
rowId: r.id,
|
|
3044
3465
|
cells: r.cells
|
|
3045
3466
|
};
|
|
3467
|
+
if (e.operators && n.instrumentKey === e.operators.instrument) {
|
|
3468
|
+
let n = Qt(e.operators, t, Lt[e.operators.instrument]);
|
|
3469
|
+
if (n) return {
|
|
3470
|
+
rowId: "operators",
|
|
3471
|
+
cells: n
|
|
3472
|
+
};
|
|
3473
|
+
}
|
|
3046
3474
|
let r = e.zones ?? [], i = [];
|
|
3047
3475
|
return r.forEach((a, o) => {
|
|
3048
|
-
let s =
|
|
3049
|
-
if (!
|
|
3050
|
-
let
|
|
3051
|
-
if (!
|
|
3052
|
-
let
|
|
3476
|
+
let s = G(t, a.labelX, a.labelWidth).trim().toUpperCase(), c = a.x, l = null, u = o === 0 ? en.exec(t) : null;
|
|
3477
|
+
if (u && (s = u[1].toUpperCase(), c = u[0].length, l = tn), !Yt.test(s)) return;
|
|
3478
|
+
let d = r[o + 1], f = d != null && G(t, d.labelX - 1, 1).trim() === "" && Yt.test(G(t, d.labelX, d.labelWidth).trim().toUpperCase()), p = l ?? (d && f ? Math.max(1, d.labelX - 1 - c) : a.width);
|
|
3479
|
+
if (!G(t, c, p).trim()) return;
|
|
3480
|
+
let m = qt(e, s, n.instrumentKey), h = Jt(s) || a.id, g = i.some((e) => e.key === h) ? `${h}${a.id[0].toUpperCase()}${a.id.slice(1)}` : h;
|
|
3053
3481
|
i.push({
|
|
3054
|
-
x:
|
|
3055
|
-
width:
|
|
3056
|
-
key:
|
|
3057
|
-
type:
|
|
3058
|
-
format:
|
|
3059
|
-
label:
|
|
3060
|
-
description:
|
|
3061
|
-
parts:
|
|
3062
|
-
options:
|
|
3063
|
-
unit:
|
|
3482
|
+
x: c,
|
|
3483
|
+
width: p,
|
|
3484
|
+
key: g,
|
|
3485
|
+
type: m?.type ?? "parameter",
|
|
3486
|
+
format: m?.format ?? "auto",
|
|
3487
|
+
label: m?.label ?? s,
|
|
3488
|
+
description: m?.description,
|
|
3489
|
+
parts: m?.parts,
|
|
3490
|
+
options: m?.options,
|
|
3491
|
+
unit: m?.unit,
|
|
3064
3492
|
meta: {
|
|
3065
3493
|
paramLabel: s,
|
|
3066
3494
|
zone: a.id
|
|
@@ -3071,19 +3499,19 @@ function zt(e, t, n) {
|
|
|
3071
3499
|
cells: i
|
|
3072
3500
|
};
|
|
3073
3501
|
}
|
|
3074
|
-
var
|
|
3502
|
+
var K = {
|
|
3075
3503
|
hexValue: null,
|
|
3076
3504
|
numericValue: null,
|
|
3077
3505
|
values: null,
|
|
3078
3506
|
text: null
|
|
3079
3507
|
};
|
|
3080
|
-
function
|
|
3508
|
+
function rn(e) {
|
|
3081
3509
|
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";
|
|
3082
3510
|
}
|
|
3083
|
-
function
|
|
3511
|
+
function an(e, t) {
|
|
3084
3512
|
let n = e.trim();
|
|
3085
|
-
if (!n) return
|
|
3086
|
-
switch (t === "auto" ?
|
|
3513
|
+
if (!n) return K;
|
|
3514
|
+
switch (t === "auto" ? rn(n) : t) {
|
|
3087
3515
|
case "hex": {
|
|
3088
3516
|
let e = /^([0-9A-F]{2})/i.exec(n), t = e ? parseInt(e[1], 16) : null;
|
|
3089
3517
|
return {
|
|
@@ -3096,7 +3524,7 @@ function Vt(e, t) {
|
|
|
3096
3524
|
case "hexOption": {
|
|
3097
3525
|
let e = /^([0-9A-F]{2})\s?(.*)$/i.exec(n);
|
|
3098
3526
|
if (!e) return {
|
|
3099
|
-
...
|
|
3527
|
+
...K,
|
|
3100
3528
|
text: n
|
|
3101
3529
|
};
|
|
3102
3530
|
let t = parseInt(e[1], 16);
|
|
@@ -3108,9 +3536,9 @@ function Vt(e, t) {
|
|
|
3108
3536
|
};
|
|
3109
3537
|
}
|
|
3110
3538
|
case "hexPair": {
|
|
3111
|
-
let e = /^([0-9A-F]{2})
|
|
3539
|
+
let e = /^([0-9A-F]{2})[:/]([0-9A-F]{2})/i.exec(n);
|
|
3112
3540
|
if (!e) return {
|
|
3113
|
-
...
|
|
3541
|
+
...K,
|
|
3114
3542
|
text: n
|
|
3115
3543
|
};
|
|
3116
3544
|
let t = [parseInt(e[1], 16), parseInt(e[2], 16)];
|
|
@@ -3124,7 +3552,7 @@ function Vt(e, t) {
|
|
|
3124
3552
|
case "decimal": {
|
|
3125
3553
|
let e = parseInt(n, 10);
|
|
3126
3554
|
return Number.isNaN(e) ? {
|
|
3127
|
-
...
|
|
3555
|
+
...K,
|
|
3128
3556
|
text: n
|
|
3129
3557
|
} : {
|
|
3130
3558
|
hexValue: null,
|
|
@@ -3136,7 +3564,7 @@ function Vt(e, t) {
|
|
|
3136
3564
|
case "decimalPair": {
|
|
3137
3565
|
let e = /^(\d+):(\d+)/.exec(n);
|
|
3138
3566
|
if (!e) return {
|
|
3139
|
-
...
|
|
3567
|
+
...K,
|
|
3140
3568
|
text: n
|
|
3141
3569
|
};
|
|
3142
3570
|
let t = [parseInt(e[1], 10), parseInt(e[2], 10)];
|
|
@@ -3150,7 +3578,7 @@ function Vt(e, t) {
|
|
|
3150
3578
|
case "float": {
|
|
3151
3579
|
let e = parseFloat(n.replace(",", "."));
|
|
3152
3580
|
return Number.isNaN(e) ? {
|
|
3153
|
-
...
|
|
3581
|
+
...K,
|
|
3154
3582
|
text: n
|
|
3155
3583
|
} : {
|
|
3156
3584
|
hexValue: null,
|
|
@@ -3160,12 +3588,12 @@ function Vt(e, t) {
|
|
|
3160
3588
|
};
|
|
3161
3589
|
}
|
|
3162
3590
|
default: return {
|
|
3163
|
-
...
|
|
3591
|
+
...K,
|
|
3164
3592
|
text: n
|
|
3165
3593
|
};
|
|
3166
3594
|
}
|
|
3167
3595
|
}
|
|
3168
|
-
function
|
|
3596
|
+
function on(e, t) {
|
|
3169
3597
|
if (!e || !t) return null;
|
|
3170
3598
|
let n = t.toUpperCase().trim();
|
|
3171
3599
|
if (e[n]) return e[n];
|
|
@@ -3174,28 +3602,28 @@ function Ht(e, t) {
|
|
|
3174
3602
|
}
|
|
3175
3603
|
//#endregion
|
|
3176
3604
|
//#region src/fxCommands.ts
|
|
3177
|
-
var
|
|
3178
|
-
function
|
|
3179
|
-
let t =
|
|
3180
|
-
return t.length === 0 || t.length ===
|
|
3605
|
+
var sn = W.fxCommands, cn = W.instrumentFx.types, ln = Object.entries(cn).filter(([, e]) => e.verified).map(([e]) => e);
|
|
3606
|
+
function un(e) {
|
|
3607
|
+
let t = ln.filter((t) => cn[t].commands.includes(e));
|
|
3608
|
+
return t.length === 0 || t.length === ln.length ? null : t;
|
|
3181
3609
|
}
|
|
3182
|
-
function
|
|
3610
|
+
function dn(e) {
|
|
3183
3611
|
let t = e.toUpperCase();
|
|
3184
3612
|
for (let e of [
|
|
3185
3613
|
"sequencer",
|
|
3186
3614
|
"instrument",
|
|
3187
3615
|
"mixer"
|
|
3188
3616
|
]) {
|
|
3189
|
-
let n =
|
|
3617
|
+
let n = sn[e][t];
|
|
3190
3618
|
if (n) return {
|
|
3191
3619
|
description: n.description,
|
|
3192
3620
|
category: e,
|
|
3193
3621
|
relative: n.relative === !0,
|
|
3194
|
-
instrumentTypes: e === "instrument" ?
|
|
3622
|
+
instrumentTypes: e === "instrument" ? un(t) : null,
|
|
3195
3623
|
slot: null
|
|
3196
3624
|
};
|
|
3197
3625
|
}
|
|
3198
|
-
let n = /^([A-Z]{2})([1-4])$/.exec(t), r = n ?
|
|
3626
|
+
let n = /^([A-Z]{2})([1-4])$/.exec(t), r = n ? sn.modulation[n[1]] : void 0;
|
|
3199
3627
|
if (n && r) return {
|
|
3200
3628
|
description: r.description.replace("modulator N", `modulator ${n[2]}`),
|
|
3201
3629
|
category: "modulation",
|
|
@@ -3204,25 +3632,25 @@ function qt(e) {
|
|
|
3204
3632
|
slot: Number(n[2])
|
|
3205
3633
|
};
|
|
3206
3634
|
}
|
|
3207
|
-
function
|
|
3208
|
-
return
|
|
3635
|
+
function q(e) {
|
|
3636
|
+
return dn(e)?.relative === !0;
|
|
3209
3637
|
}
|
|
3210
|
-
function
|
|
3211
|
-
let t =
|
|
3638
|
+
function fn(e) {
|
|
3639
|
+
let t = cn[e.toLowerCase()];
|
|
3212
3640
|
return t ? {
|
|
3213
3641
|
type: e.toLowerCase(),
|
|
3214
3642
|
verified: t.verified,
|
|
3215
3643
|
commands: [...t.commands]
|
|
3216
3644
|
} : null;
|
|
3217
3645
|
}
|
|
3218
|
-
var
|
|
3219
|
-
function
|
|
3220
|
-
return
|
|
3646
|
+
var pn = W.instrumentFx.relativeCommands.description, J = (e) => e.toString(16).toUpperCase().padStart(2, "0"), Y = (e) => e.toString(16).toUpperCase(), mn = (e) => e === 1 ? "once" : e === 2 ? "twice" : `${e} times`, X = (e) => e > 127 ? e - 256 : e, hn = (e) => `${e > 0 ? "+" : e < 0 ? "−" : "±"}${Math.abs(e)}`;
|
|
3647
|
+
function gn(e, t) {
|
|
3648
|
+
return q(e) && t > 127 ? `${J(t)} (${X(t)})` : J(t);
|
|
3221
3649
|
}
|
|
3222
|
-
function
|
|
3223
|
-
return e > 127 ? `−${
|
|
3650
|
+
function _n(e) {
|
|
3651
|
+
return e > 127 ? `−${J(256 - e)}` : `+${J(e)}`;
|
|
3224
3652
|
}
|
|
3225
|
-
var
|
|
3653
|
+
var vn = [
|
|
3226
3654
|
"C-",
|
|
3227
3655
|
"C#",
|
|
3228
3656
|
"D-",
|
|
@@ -3236,16 +3664,16 @@ var $t = [
|
|
|
3236
3664
|
"A#",
|
|
3237
3665
|
"B-"
|
|
3238
3666
|
];
|
|
3239
|
-
function
|
|
3667
|
+
function yn(e) {
|
|
3240
3668
|
let t = /^([A-G])([#-])(\d)$/.exec((e ?? "").trim().toUpperCase());
|
|
3241
3669
|
if (!t) return null;
|
|
3242
|
-
let n =
|
|
3670
|
+
let n = vn.indexOf(`${t[1]}${t[2]}`);
|
|
3243
3671
|
return n < 0 ? null : Number(t[3]) * 12 + n;
|
|
3244
3672
|
}
|
|
3245
|
-
function
|
|
3246
|
-
return `${
|
|
3673
|
+
function bn(e) {
|
|
3674
|
+
return `${vn[(e % 12 + 12) % 12]}${Math.floor(e / 12)}`;
|
|
3247
3675
|
}
|
|
3248
|
-
var
|
|
3676
|
+
var xn = [
|
|
3249
3677
|
"C",
|
|
3250
3678
|
"C#",
|
|
3251
3679
|
"D",
|
|
@@ -3258,27 +3686,46 @@ var nn = [
|
|
|
3258
3686
|
"A",
|
|
3259
3687
|
"A#",
|
|
3260
3688
|
"B"
|
|
3261
|
-
];
|
|
3262
|
-
function
|
|
3689
|
+
], Sn = 6;
|
|
3690
|
+
function Cn(e) {
|
|
3691
|
+
return e === Sn ? "one row per step" : Sn % e === 0 ? `${Sn / e} rows per step` : e % Sn === 0 ? `one row every ${e / Sn} steps` : "";
|
|
3692
|
+
}
|
|
3693
|
+
function wn(e, t) {
|
|
3694
|
+
if (e === 0) return `${t} moves one row each time the instrument is triggered`;
|
|
3695
|
+
if (e <= 251) {
|
|
3696
|
+
let n = Cn(e);
|
|
3697
|
+
return `${t} moves one row every ${e} tick${e === 1 ? "" : "s"}${n ? ` (${n})` : ""}`;
|
|
3698
|
+
}
|
|
3699
|
+
return [
|
|
3700
|
+
"octave map: the octave played picks the table row (instrument tables only)",
|
|
3701
|
+
"velocity map: the velocity played picks the table row (instrument tables only)",
|
|
3702
|
+
"note map: the note played picks the table row (instrument tables only)",
|
|
3703
|
+
`${t} moves one row every 5 ms (200 Hz)`
|
|
3704
|
+
][e - 252] ?? null;
|
|
3705
|
+
}
|
|
3706
|
+
function Tn(e, t, n = {}) {
|
|
3263
3707
|
let r = e.toUpperCase(), i = t >> 4, a = t & 15, o = (e) => `${e} tick${e === 1 ? "" : "s"}`;
|
|
3264
3708
|
switch (r) {
|
|
3265
3709
|
case "ARP": {
|
|
3266
|
-
let e =
|
|
3267
|
-
return e == null ? `plays the note, then ${t}` : `${t}: ${
|
|
3710
|
+
let e = yn(n.note), t = `+${i} and +${a} semitones`;
|
|
3711
|
+
return e == null ? `plays the note, then ${t}` : `${t}: ${bn(e)} ${bn(e + i)} ${bn(e + a)}`;
|
|
3268
3712
|
}
|
|
3269
3713
|
case "ARC": return `arp mode ${i}, speed ${o(a)}`;
|
|
3270
3714
|
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)`;
|
|
3271
|
-
case "DEL": return `delays this row by ${o(t)}`;
|
|
3715
|
+
case "DEL": return n.inTable ? `holds the table's playhead for ${o(t)}` : `delays this row by ${o(t)}`;
|
|
3272
3716
|
case "KIL": return `stops the note after ${o(t)}`;
|
|
3273
3717
|
case "OFF": return `note off after ${o(t)}`;
|
|
3274
3718
|
case "PSL": return `portamento over ${o(t)}`;
|
|
3275
|
-
case "GRV": return `track uses groove ${
|
|
3276
|
-
case "GGR": return `all tracks use groove ${
|
|
3277
|
-
case "INS": return `switches to instrument ${
|
|
3278
|
-
case "TBL": return `instrument uses table ${
|
|
3279
|
-
case "TBX": return t === 0 ? "stops the auxiliary table" : `plays table ${
|
|
3280
|
-
case "THO": return `table jumps to
|
|
3281
|
-
case "HOP": return n.inTable ? `
|
|
3719
|
+
case "GRV": return `track uses groove ${J(t)}`;
|
|
3720
|
+
case "GGR": return `all tracks use groove ${J(t)}`;
|
|
3721
|
+
case "INS": return `switches to instrument ${J(t)}`;
|
|
3722
|
+
case "TBL": return `instrument uses table ${J(t)}`;
|
|
3723
|
+
case "TBX": return t === 0 ? "stops the auxiliary table" : `plays table ${J(t)} alongside the instrument table`;
|
|
3724
|
+
case "THO": return n.inTable ? `every column of the table jumps to row ${Y(a)}` : `the instrument's table jumps to row ${Y(a)} (the aux table when a TBX is on this step)`;
|
|
3725
|
+
case "HOP": return n.inTable ? a === n.row ? i === 0 ? `this column stops on row ${Y(a)}` : `holds this column on row ${Y(a)} ${mn(i)}` : i === 0 ? `always jumps back to row ${Y(a)}: the rows in between loop` : `jumps to row ${Y(a)} ${mn(i)}, then the column runs on past it` : t === 255 ? "stops this track" : `jumps to row ${Y(a)} of the next phrase`;
|
|
3726
|
+
case "REP": return !n.inTable || t === 0 ? null : `plays the command above it ${t} more time${t === 1 ? "" : "s"}, one row each`;
|
|
3727
|
+
case "RTO": return n.inTable ? `repeats the relative command above it until it has added ${t > 127 ? `${J(t)} (${X(t)})` : J(t)} in total` : null;
|
|
3728
|
+
case "RMX": return `tracks to its left (selection ${Y(i)}) jump to phrase row ${Y(a)}`;
|
|
3282
3729
|
case "RND": return `randomises the previous FX: left range ${i}, right range ${a} (0 none, F full)`;
|
|
3283
3730
|
case "RNL": return `randomises the FX to its left: left range ${i}, right range ${a} (0 none, F full)`;
|
|
3284
3731
|
case "RET": return a === 0 ? `single retrig after ${o(i)}` : `retrigs every ${o(a)}, volume ${i < 8 ? "falls" : "rises"} on each retrig (ramp ${i})`;
|
|
@@ -3287,51 +3734,47 @@ function rn(e, t, n = {}) {
|
|
|
3287
3734
|
case "PBN": return t < 128 ? `pitch slides up by ${t}` : `pitch slides down by ${256 - t}`;
|
|
3288
3735
|
case "SCA":
|
|
3289
3736
|
case "SCG": {
|
|
3290
|
-
let e =
|
|
3737
|
+
let e = xn[i];
|
|
3291
3738
|
return `${r === "SCA" ? "track" : "song"} scale ${a.toString(16).toUpperCase()}${e ? `, key ${e}` : ""}`;
|
|
3292
3739
|
}
|
|
3293
|
-
case "SNG": return `moves the song position by ${
|
|
3294
|
-
case "SED": return `random seed ${
|
|
3295
|
-
case "NXT": return `plays instrument ${
|
|
3740
|
+
case "SNG": return `moves the song position by ${hn(X(t))} row(s)`;
|
|
3741
|
+
case "SED": return `random seed ${J(t)}`;
|
|
3742
|
+
case "NXT": return `plays instrument ${J(t)} on the next track`;
|
|
3296
3743
|
case "MTT": {
|
|
3744
|
+
if (n.inTable) return "no effect in a table";
|
|
3297
3745
|
let e = X(t);
|
|
3298
|
-
return e === 0 ? "no timing shift" : `shifts the row by ${
|
|
3746
|
+
return e < 0 && n.row === 0 ? "no effect: a row cannot be moved earlier on the first step" : e === 0 ? "no timing shift" : `shifts the row by ${hn(e)}/8 tick`;
|
|
3299
3747
|
}
|
|
3300
3748
|
case "TPO": return `${t} BPM`;
|
|
3301
|
-
case "TSP": return `transposes the song by ${
|
|
3302
|
-
case "TIC": return t
|
|
3303
|
-
252: "octave map: playing octave picks the table row",
|
|
3304
|
-
253: "velocity map",
|
|
3305
|
-
254: "note map",
|
|
3306
|
-
255: "table advances at 200 Hz"
|
|
3307
|
-
}[t] ?? null;
|
|
3749
|
+
case "TSP": return `transposes the song by ${hn(X(t))} semitones`;
|
|
3750
|
+
case "TIC": return wn(t, n.inTable ? "this column" : "the instrument's table");
|
|
3308
3751
|
case "XRZ": return t > 0 ? "reverb freeze on" : "reverb freeze off";
|
|
3309
3752
|
}
|
|
3310
|
-
if (
|
|
3753
|
+
if (q(r)) {
|
|
3311
3754
|
let e = X(t);
|
|
3312
|
-
return r === "PIT" ? e === 0 ? "no change" : `${
|
|
3755
|
+
return r === "PIT" ? e === 0 ? "no change" : `${hn(e)} semitones` : e === 0 ? "no change" : hn(e);
|
|
3313
3756
|
}
|
|
3314
3757
|
return null;
|
|
3315
3758
|
}
|
|
3316
|
-
function
|
|
3759
|
+
function En(e, t, n) {
|
|
3317
3760
|
let r = e + t & 255;
|
|
3318
3761
|
return n != null && (t < 128 ? r < e || r > n : r > e || r < n) && (r = n), {
|
|
3319
3762
|
value: r,
|
|
3320
3763
|
atLimit: n != null && r === n
|
|
3321
3764
|
};
|
|
3322
3765
|
}
|
|
3323
|
-
function
|
|
3766
|
+
function Dn(e, t, n, r = !1) {
|
|
3324
3767
|
let i = null, a = null, o = null, s = null, c = r, l = !1, u = null, d = "none", f = Math.min(n, e.length - 1);
|
|
3325
3768
|
for (let n = 0; n <= f; n += 1) {
|
|
3326
3769
|
let f = e[n].fields[`fx${t}cmd`], p = e[n].fields[`fx${t}val`];
|
|
3327
3770
|
if (d = "none", f && !f.isEmpty) {
|
|
3328
3771
|
let e = f.rawValue.toUpperCase(), t = p && !p.isEmpty ? p.hexValue : null;
|
|
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} =
|
|
3772
|
+
e === "REP" ? t ? !i && !r ? d = "orphan" : (d = c ? "repChange" : "rep", c || (u = n), c = !0, o = t, a != null && ({value: a, atLimit: l} = En(a, o, s))) : (d = "repStop", c = !1, o = null, l = !1) : e === "RTO" ? (d = "rto", s = t) : (d = c ? "replace" : "set", i = {
|
|
3330
3773
|
cmd: e,
|
|
3331
3774
|
value: t,
|
|
3332
3775
|
step: n
|
|
3333
3776
|
}, a = t, c = !1, o = null, s = null, l = !1, u = null);
|
|
3334
|
-
} else c && (d = "continue", a != null && o != null && ({value: a, atLimit: l} =
|
|
3777
|
+
} else c && (d = "continue", a != null && o != null && ({value: a, atLimit: l} = En(a, o, s)));
|
|
3335
3778
|
}
|
|
3336
3779
|
return {
|
|
3337
3780
|
lane: t,
|
|
@@ -3347,20 +3790,20 @@ function on(e, t, n, r = !1) {
|
|
|
3347
3790
|
carried: c && !i
|
|
3348
3791
|
};
|
|
3349
3792
|
}
|
|
3350
|
-
function
|
|
3351
|
-
let t = e.source, n = (e) => e == null ? "??" : t ?
|
|
3793
|
+
function On(e) {
|
|
3794
|
+
let t = e.source, n = (e) => e == null ? "??" : t ? gn(t.cmd, e) : J(e), r = e.increment == null ? "" : _n(e.increment), i = e.atLimit && e.limit != null ? `, held at the RTO limit ${J(e.limit)}` : "";
|
|
3352
3795
|
switch (e.event) {
|
|
3353
3796
|
case "rep":
|
|
3354
3797
|
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}`;
|
|
3355
3798
|
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}`;
|
|
3356
3799
|
case "repStop": return t ? `REP00 stops the repeat of ${t.cmd}` : "REP00 stops the repeat";
|
|
3357
3800
|
case "orphan": return "REP has no earlier command in this lane of the phrase to repeat";
|
|
3358
|
-
case "rto": return e.active && e.limit != null ? `sets the value the running REP stops at (${
|
|
3801
|
+
case "rto": return e.active && e.limit != null ? `sets the value the running REP stops at (${J(e.limit)})` : "sets the stop value for a REP";
|
|
3359
3802
|
case "replace": return t ? `replaces the running REP (${t.cmd} is no longer repeated)` : null;
|
|
3360
3803
|
default: return null;
|
|
3361
3804
|
}
|
|
3362
3805
|
}
|
|
3363
|
-
function
|
|
3806
|
+
function kn(e) {
|
|
3364
3807
|
let t = e.fields.inst;
|
|
3365
3808
|
return t && !t.isEmpty ? "instrument" : [
|
|
3366
3809
|
1,
|
|
@@ -3371,10 +3814,10 @@ function cn(e) {
|
|
|
3371
3814
|
return n != null && !n.isEmpty && n.rawValue.toUpperCase() === "RET";
|
|
3372
3815
|
}) ? "ret" : null;
|
|
3373
3816
|
}
|
|
3374
|
-
function
|
|
3817
|
+
function An(e, t, n = null) {
|
|
3375
3818
|
let r = {}, i = null, a = null, o = Math.min(t, e.length - 1);
|
|
3376
3819
|
for (let t = 0; t <= o; t += 1) {
|
|
3377
|
-
let o =
|
|
3820
|
+
let o = kn(e[t]);
|
|
3378
3821
|
if (o) {
|
|
3379
3822
|
for (let e of Object.keys(r)) delete r[e];
|
|
3380
3823
|
i = t, a = o;
|
|
@@ -3384,8 +3827,8 @@ function ln(e, t, n = null) {
|
|
|
3384
3827
|
2,
|
|
3385
3828
|
3
|
|
3386
3829
|
]) {
|
|
3387
|
-
let s =
|
|
3388
|
-
if (!c || s.carried || !
|
|
3830
|
+
let s = Dn(e, o, t, n === o), c = s.source;
|
|
3831
|
+
if (!c || s.carried || !q(c.cmd)) continue;
|
|
3389
3832
|
let l = null, u = !1;
|
|
3390
3833
|
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;
|
|
3391
3834
|
let d = r[c.cmd];
|
|
@@ -3401,21 +3844,21 @@ function ln(e, t, n = null) {
|
|
|
3401
3844
|
}
|
|
3402
3845
|
return r;
|
|
3403
3846
|
}
|
|
3404
|
-
var
|
|
3405
|
-
function
|
|
3847
|
+
var jn = (e) => e === 0 ? "±00" : `${e > 0 ? "+" : "−"}${J(Math.abs(e))}`;
|
|
3848
|
+
function Mn(e) {
|
|
3406
3849
|
if (e.resetStep == null) return "the start of this phrase (earlier state unknown)";
|
|
3407
3850
|
let t = e.resetStep.toString(16).toUpperCase();
|
|
3408
3851
|
return e.resetBy === "ret" ? `the RET on step ${t}` : `the instrument number on step ${t}`;
|
|
3409
3852
|
}
|
|
3410
|
-
var
|
|
3411
|
-
function
|
|
3412
|
-
if (!e || e.count <= 1) return `relative: ${
|
|
3413
|
-
let t = e.viaRep ? ", including REP repeats" : "", n = e.total === 0 ? "has had no net effect" : `has moved by ${
|
|
3414
|
-
return `relative: ${e.cmd} ${n} over ${e.count} steps since ${
|
|
3853
|
+
var Nn = "stays until a note with an instrument number (I) or a RET resets it";
|
|
3854
|
+
function Pn(e) {
|
|
3855
|
+
if (!e || e.count <= 1) return `relative: ${Nn}`;
|
|
3856
|
+
let t = e.viaRep ? ", including REP repeats" : "", n = e.total === 0 ? "has had no net effect" : `has moved by ${jn(e.total)}`;
|
|
3857
|
+
return `relative: ${e.cmd} ${n} over ${e.count} steps since ${Mn(e)}${t}; ${Nn}`;
|
|
3415
3858
|
}
|
|
3416
|
-
function
|
|
3859
|
+
function Fn(e) {
|
|
3417
3860
|
let t = Object.values(e).filter((e) => e.total !== 0);
|
|
3418
|
-
return t.length ? `triggers the instrument again: resets the relative changes still in force (${t.map((e) => `${e.cmd} ${
|
|
3861
|
+
return t.length ? `triggers the instrument again: resets the relative changes still in force (${t.map((e) => `${e.cmd} ${jn(e.total)}`).join(", ")})` : null;
|
|
3419
3862
|
}
|
|
3420
3863
|
//#endregion
|
|
3421
3864
|
//#region src/scaleInsight.ts
|
|
@@ -3432,7 +3875,7 @@ var Z = [
|
|
|
3432
3875
|
"A",
|
|
3433
3876
|
"A#",
|
|
3434
3877
|
"B"
|
|
3435
|
-
],
|
|
3878
|
+
], In = [
|
|
3436
3879
|
{
|
|
3437
3880
|
name: "Major (Ionian)",
|
|
3438
3881
|
steps: [
|
|
@@ -3650,7 +4093,7 @@ var Z = [
|
|
|
3650
4093
|
11
|
|
3651
4094
|
]
|
|
3652
4095
|
}
|
|
3653
|
-
],
|
|
4096
|
+
], Ln = [
|
|
3654
4097
|
"the root",
|
|
3655
4098
|
"a minor 2nd",
|
|
3656
4099
|
"a major 2nd",
|
|
@@ -3664,26 +4107,26 @@ var Z = [
|
|
|
3664
4107
|
"a minor 7th",
|
|
3665
4108
|
"a major 7th"
|
|
3666
4109
|
];
|
|
3667
|
-
function
|
|
4110
|
+
function Rn(e) {
|
|
3668
4111
|
let t = e.replace(/[-\s]/g, "").toUpperCase();
|
|
3669
4112
|
return Z.includes(t) ? t : null;
|
|
3670
4113
|
}
|
|
3671
|
-
function
|
|
4114
|
+
function zn(e) {
|
|
3672
4115
|
let t = Z.indexOf(e);
|
|
3673
|
-
return t <= 0 ? t === 0 ? "the first row (the scale root)" : e : `${
|
|
4116
|
+
return t <= 0 ? t === 0 ? "the first row (the scale root)" : e : `${Ln[t]} (+${t} semitones above C)`;
|
|
3674
4117
|
}
|
|
3675
|
-
function
|
|
4118
|
+
function Bn(e) {
|
|
3676
4119
|
let t = new Set(e);
|
|
3677
4120
|
if (t.size === 0) return [];
|
|
3678
4121
|
let n = [];
|
|
3679
|
-
for (let e of
|
|
4122
|
+
for (let e of In) 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({
|
|
3680
4123
|
root: r,
|
|
3681
4124
|
name: e.name
|
|
3682
4125
|
});
|
|
3683
4126
|
return n.sort((e, t) => e.root - t.root), n.map((e) => e.root === 0 ? e.name : `${e.name} from ${Z[e.root]}`);
|
|
3684
4127
|
}
|
|
3685
|
-
function
|
|
3686
|
-
let t = e.filter((e) => e.enabled === !0), n = t.map((e) => e.interval), r =
|
|
4128
|
+
function Vn(e) {
|
|
4129
|
+
let t = e.filter((e) => e.enabled === !0), n = t.map((e) => e.interval), r = Bn(t.map((e) => e.semitone)), i = e.filter((e) => e.enabled === !0 && e.offset != null && e.offset !== 0).map((e) => ({
|
|
3687
4130
|
interval: e.interval,
|
|
3688
4131
|
offset: e.offset
|
|
3689
4132
|
}));
|
|
@@ -3692,47 +4135,47 @@ function bn(e) {
|
|
|
3692
4135
|
enabled: n,
|
|
3693
4136
|
shapes: r,
|
|
3694
4137
|
detuned: i,
|
|
3695
|
-
summary:
|
|
4138
|
+
summary: Hn({
|
|
3696
4139
|
enabled: n,
|
|
3697
4140
|
shapes: r,
|
|
3698
4141
|
detuned: i
|
|
3699
4142
|
}).join(" — ")
|
|
3700
4143
|
};
|
|
3701
4144
|
}
|
|
3702
|
-
function
|
|
4145
|
+
function Hn(e) {
|
|
3703
4146
|
let { enabled: t, shapes: n, detuned: r } = e;
|
|
3704
4147
|
if (!t.length) return ["no notes enabled"];
|
|
3705
4148
|
let i = n[0] ?? `${t.length} notes, custom scale`;
|
|
3706
|
-
return r.length && (i += `; detuned: ${r.map((e) => `${e.interval} ${
|
|
4149
|
+
return r.length && (i += `; detuned: ${r.map((e) => `${e.interval} ${Un(e.offset)}`).join(", ")}`), [t.join(" "), i];
|
|
3707
4150
|
}
|
|
3708
|
-
function
|
|
4151
|
+
function Un(e) {
|
|
3709
4152
|
return `${e > 0 ? "+" : e < 0 ? "−" : ""}${Math.abs(e).toFixed(2)} st`;
|
|
3710
4153
|
}
|
|
3711
4154
|
//#endregion
|
|
3712
4155
|
//#region src/viewContext.ts
|
|
3713
|
-
var
|
|
4156
|
+
var Wn = /* @__PURE__ */ new Set([
|
|
3714
4157
|
"--",
|
|
3715
4158
|
"---",
|
|
3716
4159
|
"---00",
|
|
3717
4160
|
"----",
|
|
3718
4161
|
"-"
|
|
3719
4162
|
]);
|
|
3720
|
-
function
|
|
3721
|
-
return !e ||
|
|
4163
|
+
function Gn(e) {
|
|
4164
|
+
return !e || Wn.has(e) || /^-+$/.test(e);
|
|
3722
4165
|
}
|
|
3723
|
-
function
|
|
4166
|
+
function Kn(e) {
|
|
3724
4167
|
let t = e.trim();
|
|
3725
|
-
if (!t ||
|
|
4168
|
+
if (!t || Gn(t)) return null;
|
|
3726
4169
|
let n = parseInt(t, 16);
|
|
3727
4170
|
return Number.isNaN(n) ? null : n;
|
|
3728
4171
|
}
|
|
3729
|
-
function
|
|
4172
|
+
function qn(e, t, n) {
|
|
3730
4173
|
return t >= e.length ? "" : e.slice(t, Math.min(t + n, e.length));
|
|
3731
4174
|
}
|
|
3732
|
-
function
|
|
3733
|
-
return
|
|
4175
|
+
function Jn(e) {
|
|
4176
|
+
return Yn(e);
|
|
3734
4177
|
}
|
|
3735
|
-
function
|
|
4178
|
+
function Yn(e) {
|
|
3736
4179
|
if (!e) return {
|
|
3737
4180
|
viewId: null,
|
|
3738
4181
|
isUnsaved: !1,
|
|
@@ -3745,7 +4188,7 @@ function On(e) {
|
|
|
3745
4188
|
marker: r
|
|
3746
4189
|
};
|
|
3747
4190
|
}
|
|
3748
|
-
function
|
|
4191
|
+
function Xn(e) {
|
|
3749
4192
|
return e.length > 0 && /^[^a-zA-Z0-9 ]/.test(e[0]) ? {
|
|
3750
4193
|
line: e.slice(1),
|
|
3751
4194
|
offset: 1
|
|
@@ -3754,12 +4197,12 @@ function kn(e) {
|
|
|
3754
4197
|
offset: 0
|
|
3755
4198
|
};
|
|
3756
4199
|
}
|
|
3757
|
-
function
|
|
3758
|
-
let n =
|
|
4200
|
+
function Zn(e, t) {
|
|
4201
|
+
let n = qn(t, e.x, e.width).trim();
|
|
3759
4202
|
n.includes("^") && (e.type === "fxCommand" || e.type === "fxValue") && (n = "");
|
|
3760
|
-
let r =
|
|
4203
|
+
let r = Gn(n);
|
|
3761
4204
|
if (e.format) {
|
|
3762
|
-
let t = r ? null :
|
|
4205
|
+
let t = r ? null : an(n, e.format), i = e.type === "name" || e.type === "fileEntry", a = t?.text != null && !i ? t.text.toUpperCase() : t?.text ?? null;
|
|
3763
4206
|
return {
|
|
3764
4207
|
key: e.key,
|
|
3765
4208
|
label: e.label,
|
|
@@ -3774,8 +4217,8 @@ function An(e, t) {
|
|
|
3774
4217
|
values: t?.values ?? null,
|
|
3775
4218
|
parts: e.parts,
|
|
3776
4219
|
unit: e.unit,
|
|
3777
|
-
valueDescription: !r &&
|
|
3778
|
-
fileKind: e.type === "fileEntry" ?
|
|
4220
|
+
valueDescription: !r && on(e.options, a ?? n) || void 0,
|
|
4221
|
+
fileKind: e.type === "fileEntry" ? Qn(n) : void 0
|
|
3779
4222
|
};
|
|
3780
4223
|
}
|
|
3781
4224
|
let i = [
|
|
@@ -3795,7 +4238,7 @@ function An(e, t) {
|
|
|
3795
4238
|
if (a.includes(e.type)) {
|
|
3796
4239
|
let e = parseInt(n, 10);
|
|
3797
4240
|
o = Number.isNaN(e) ? null : e;
|
|
3798
|
-
} else o =
|
|
4241
|
+
} else o = Kn(n);
|
|
3799
4242
|
}
|
|
3800
4243
|
return {
|
|
3801
4244
|
key: e.key,
|
|
@@ -3807,20 +4250,20 @@ function An(e, t) {
|
|
|
3807
4250
|
meta: e.meta
|
|
3808
4251
|
};
|
|
3809
4252
|
}
|
|
3810
|
-
function
|
|
4253
|
+
function Qn(e) {
|
|
3811
4254
|
if (e === "/..") return "parent";
|
|
3812
4255
|
if (e.startsWith("/")) return "directory";
|
|
3813
4256
|
let t = /\.([a-z0-9]+)$/i.exec(e)?.[1]?.toLowerCase();
|
|
3814
4257
|
return t === "m8i" ? "instrumentPreset" : t === "wav" ? "sample" : t?.startsWith("m8") ? "m8file" : "file";
|
|
3815
4258
|
}
|
|
3816
|
-
function
|
|
3817
|
-
let n =
|
|
4259
|
+
function $n(e, t) {
|
|
4260
|
+
let n = qn(e, t.x, t.width).trim();
|
|
3818
4261
|
if (!n) return null;
|
|
3819
|
-
if (t.parse === "hex") return
|
|
4262
|
+
if (t.parse === "hex") return Kn(n);
|
|
3820
4263
|
let r = parseInt(n, 10);
|
|
3821
4264
|
return Number.isNaN(r) ? null : r;
|
|
3822
4265
|
}
|
|
3823
|
-
function
|
|
4266
|
+
function er(e, t) {
|
|
3824
4267
|
for (let n of e) if (t >= n.x && t < n.x + n.width) return n;
|
|
3825
4268
|
let n = null, r = 2;
|
|
3826
4269
|
for (let i of e) {
|
|
@@ -3829,9 +4272,9 @@ function Nn(e, t) {
|
|
|
3829
4272
|
}
|
|
3830
4273
|
return n;
|
|
3831
4274
|
}
|
|
3832
|
-
function
|
|
4275
|
+
function tr(e, t) {
|
|
3833
4276
|
let n = {};
|
|
3834
|
-
for (let r of e.columns ?? []) n[r.key] =
|
|
4277
|
+
for (let r of e.columns ?? []) n[r.key] = Zn(r, t);
|
|
3835
4278
|
for (let e of Object.keys(n)) {
|
|
3836
4279
|
let t = /^fx(\d)cmd$/.exec(e)?.[1], r = t ? n[`fx${t}val`] : void 0;
|
|
3837
4280
|
r && n[e].isEmpty && (n[`fx${t}val`] = {
|
|
@@ -3840,27 +4283,27 @@ function Pn(e, t) {
|
|
|
3840
4283
|
});
|
|
3841
4284
|
}
|
|
3842
4285
|
return {
|
|
3843
|
-
rowIndex: e.rowField ?
|
|
4286
|
+
rowIndex: e.rowField ? $n(t, e.rowField) : null,
|
|
3844
4287
|
rowKey: e.rowField?.key ?? "row",
|
|
3845
4288
|
rowId: null,
|
|
3846
4289
|
fields: n
|
|
3847
4290
|
};
|
|
3848
4291
|
}
|
|
3849
|
-
var
|
|
3850
|
-
function
|
|
4292
|
+
var nr = (e) => e.replace(/\s+/g, ""), rr = 1, Q = (e) => e.slice(1);
|
|
4293
|
+
function ir(e, t) {
|
|
3851
4294
|
if (!t || !e.cursorPos || !e.currentLine) return !1;
|
|
3852
4295
|
let n = t.lines[e.cursorPos.y];
|
|
3853
|
-
return n != null &&
|
|
4296
|
+
return n != null && nr(n) === nr(e.currentLine);
|
|
3854
4297
|
}
|
|
3855
|
-
var
|
|
3856
|
-
function
|
|
3857
|
-
let n =
|
|
4298
|
+
var ar = 16, or = 4, sr = 21;
|
|
4299
|
+
function cr(e, t) {
|
|
4300
|
+
let n = W.views[e];
|
|
3858
4301
|
if (n?.type !== "grid" || !n.rowField) return [];
|
|
3859
|
-
let r = [], i = Math.min(
|
|
3860
|
-
for (let e =
|
|
4302
|
+
let r = [], i = Math.min(sr, t.lines.length - 1);
|
|
4303
|
+
for (let e = or; e <= i; e += 1) {
|
|
3861
4304
|
let i = Q(t.lines[e] ?? ""), a = n.rowField;
|
|
3862
|
-
if (i.length <= a.x + a.width || !
|
|
3863
|
-
let o =
|
|
4305
|
+
if (i.length <= a.x + a.width || !lr(i[a.x + a.width])) continue;
|
|
4306
|
+
let o = tr(n, i);
|
|
3864
4307
|
o.rowIndex != null && r.push({
|
|
3865
4308
|
...o,
|
|
3866
4309
|
screenRow: e
|
|
@@ -3868,11 +4311,11 @@ function Vn(e, t) {
|
|
|
3868
4311
|
}
|
|
3869
4312
|
return r;
|
|
3870
4313
|
}
|
|
3871
|
-
var
|
|
3872
|
-
function
|
|
3873
|
-
let n =
|
|
4314
|
+
var lr = (e) => e === " " || /^[^a-zA-Z0-9-]$/.test(e);
|
|
4315
|
+
function ur(e, t) {
|
|
4316
|
+
let n = W.views[e];
|
|
3874
4317
|
if (n?.type !== "grid") return null;
|
|
3875
|
-
let r =
|
|
4318
|
+
let r = cr(e, t), i = (e) => !!e && e !== " " && lr(e);
|
|
3876
4319
|
if (e === "song") return {
|
|
3877
4320
|
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
4321
|
row: null
|
|
@@ -3886,25 +4329,25 @@ function Un(e, t) {
|
|
|
3886
4329
|
row: null
|
|
3887
4330
|
};
|
|
3888
4331
|
}
|
|
3889
|
-
function
|
|
4332
|
+
function dr(e, t, n, r) {
|
|
3890
4333
|
let i = (t.cursorPos?.y ?? -1) - r;
|
|
3891
4334
|
if (i < 0) return null;
|
|
3892
4335
|
let a = [], o = null;
|
|
3893
|
-
for (let t = 0; t <
|
|
4336
|
+
for (let t = 0; t < ar; t += 1) {
|
|
3894
4337
|
let r = n.lines[i + t];
|
|
3895
4338
|
if (r == null) return null;
|
|
3896
|
-
let s = Q(r), c =
|
|
4339
|
+
let s = Q(r), c = tr(e, s);
|
|
3897
4340
|
if (c.rowIndex !== t) return null;
|
|
3898
4341
|
a.push(c);
|
|
3899
4342
|
let l = s.indexOf("^^");
|
|
3900
|
-
o == null && l >= 0 && (o =
|
|
4343
|
+
o == null && l >= 0 && (o = fr(e, l));
|
|
3901
4344
|
}
|
|
3902
4345
|
return {
|
|
3903
4346
|
steps: a,
|
|
3904
4347
|
carriedRepLane: o
|
|
3905
4348
|
};
|
|
3906
4349
|
}
|
|
3907
|
-
function
|
|
4350
|
+
function fr(e, t) {
|
|
3908
4351
|
let n = [];
|
|
3909
4352
|
for (let r = 1; r <= 3; r += 1) {
|
|
3910
4353
|
let i = e.columns?.find((e) => e.key === `fx${r}cmd`), a = e.columns?.find((e) => e.key === `fx${r}val`);
|
|
@@ -3918,8 +4361,8 @@ function Gn(e, t) {
|
|
|
3918
4361
|
let r = Math.min(...n.map((e) => e.dist)), i = n.filter((e) => e.dist === r);
|
|
3919
4362
|
return r <= 1 && i.length === 1 ? i[0].lane : null;
|
|
3920
4363
|
}
|
|
3921
|
-
function
|
|
3922
|
-
let t =
|
|
4364
|
+
function pr(e) {
|
|
4365
|
+
let t = Rn(e.fields.interval?.rawValue ?? "");
|
|
3923
4366
|
if (!t) return null;
|
|
3924
4367
|
let n = e.fields.en?.rawValue.toUpperCase(), r = parseFloat(e.fields.offset?.rawValue ?? "");
|
|
3925
4368
|
return {
|
|
@@ -3929,15 +4372,15 @@ function Kn(e) {
|
|
|
3929
4372
|
offset: Number.isNaN(r) ? null : r
|
|
3930
4373
|
};
|
|
3931
4374
|
}
|
|
3932
|
-
function
|
|
4375
|
+
function mr(e, t) {
|
|
3933
4376
|
let n = /* @__PURE__ */ new Map();
|
|
3934
4377
|
for (let r of t.lines) {
|
|
3935
|
-
let t =
|
|
4378
|
+
let t = tr(e, Q(r)), i = pr(t), a = t.fields.en?.rawValue.toUpperCase();
|
|
3936
4379
|
!i || a !== "ON" && a !== "OFF" && a !== "--" || n.has(i.interval) || n.set(i.interval, i);
|
|
3937
4380
|
}
|
|
3938
4381
|
return n.size === Z.length ? Z.map((e) => n.get(e)) : null;
|
|
3939
4382
|
}
|
|
3940
|
-
function
|
|
4383
|
+
function hr(e, t, n, r) {
|
|
3941
4384
|
let i = {
|
|
3942
4385
|
...r,
|
|
3943
4386
|
isGridView: !1,
|
|
@@ -3954,40 +4397,40 @@ function Jn(e, t, n, r) {
|
|
|
3954
4397
|
resetsRelative: null,
|
|
3955
4398
|
scaleNote: null,
|
|
3956
4399
|
scale: null
|
|
3957
|
-
}, a = e.cursorPos, o = a ? a.x - 1 : 0, s = a &&
|
|
4400
|
+
}, a = e.cursorPos, o = a ? a.x - 1 : 0, s = a && ir(e, t) ? t : null, c = s && a ? Q(s.lines[a.y] ?? "") : e.currentLine ?? "";
|
|
3958
4401
|
if (!c.trim()) return i;
|
|
3959
|
-
let l = s && a ? s.lines.slice(0, a.y + 1).reverse().map(Q) : [c], u = r.viewName === "inst" ?
|
|
4402
|
+
let l = s && a ? s.lines.slice(0, a.y + 1).reverse().map(Q) : [c], u = r.viewName === "inst" ? Gt(s ? s.lines.map(Q) : [c]) : null, d = {
|
|
3960
4403
|
instrumentKey: u?.key ?? null,
|
|
3961
4404
|
entryText: e.textUnderCursor
|
|
3962
4405
|
};
|
|
3963
4406
|
if (!s && a && n.kind == null) for (let e = 0; e <= Math.min(o, 24); e += 1) {
|
|
3964
4407
|
let t = " ".repeat(e) + c;
|
|
3965
|
-
if (
|
|
4408
|
+
if (nn(n, t, {
|
|
3966
4409
|
...d,
|
|
3967
|
-
section:
|
|
4410
|
+
section: Ht(n, [t])
|
|
3968
4411
|
}).cells.some((e) => o >= e.x && o < e.x + e.width)) {
|
|
3969
4412
|
c = t;
|
|
3970
4413
|
break;
|
|
3971
4414
|
}
|
|
3972
4415
|
}
|
|
3973
|
-
let f =
|
|
4416
|
+
let f = Ht(n, s ? l : [c]), { rowId: p, cells: m } = nn(n, c, {
|
|
3974
4417
|
...d,
|
|
3975
4418
|
section: f
|
|
3976
4419
|
}), h = {};
|
|
3977
|
-
for (let e of m) h[e.key] =
|
|
4420
|
+
for (let e of m) h[e.key] = Zn(e, c);
|
|
3978
4421
|
let g = {
|
|
3979
4422
|
rowIndex: null,
|
|
3980
4423
|
rowKey: "param",
|
|
3981
4424
|
rowId: p,
|
|
3982
4425
|
fields: h
|
|
3983
|
-
}, _ = null, v = a ?
|
|
4426
|
+
}, _ = null, v = a ? er(m, o) : null;
|
|
3984
4427
|
v && (_ = {
|
|
3985
4428
|
...h[v.key],
|
|
3986
4429
|
viewName: r.viewName,
|
|
3987
4430
|
rowIndex: null
|
|
3988
4431
|
});
|
|
3989
4432
|
let y = v?.meta?.zone;
|
|
3990
|
-
return s && typeof y == "string" && (f =
|
|
4433
|
+
return s && typeof y == "string" && (f = Ut(n, y, l) ?? f), {
|
|
3991
4434
|
...i,
|
|
3992
4435
|
section: f,
|
|
3993
4436
|
instrumentType: u,
|
|
@@ -3996,10 +4439,10 @@ function Jn(e, t, n, r) {
|
|
|
3996
4439
|
lineText: c.trim()
|
|
3997
4440
|
};
|
|
3998
4441
|
}
|
|
3999
|
-
function
|
|
4442
|
+
function gr(e, t) {
|
|
4000
4443
|
let n = e.viewName;
|
|
4001
4444
|
if (!n) return null;
|
|
4002
|
-
let r =
|
|
4445
|
+
let r = W.views[n] ?? null, i = r?.type === "grid", a = r?.title ?? null, o = r?.description ?? null, { viewId: s, isUnsaved: c } = Yn(e.viewTitle), l = {
|
|
4003
4446
|
viewName: n,
|
|
4004
4447
|
viewTitle: a,
|
|
4005
4448
|
viewDescription: o,
|
|
@@ -4018,8 +4461,8 @@ function Yn(e, t) {
|
|
|
4018
4461
|
resetsRelative: null,
|
|
4019
4462
|
scaleNote: null,
|
|
4020
4463
|
scale: null
|
|
4021
|
-
}, d = r?.type === "parameter" ?
|
|
4022
|
-
if (d) return
|
|
4464
|
+
}, d = r?.type === "parameter" ? Bt(n) : null;
|
|
4465
|
+
if (d) return hr(e, t, d, l);
|
|
4023
4466
|
if (!i || !r) return {
|
|
4024
4467
|
...u,
|
|
4025
4468
|
isGridView: !1,
|
|
@@ -4033,11 +4476,11 @@ function Yn(e, t) {
|
|
|
4033
4476
|
row: null,
|
|
4034
4477
|
activeField: null
|
|
4035
4478
|
};
|
|
4036
|
-
let { line: p } =
|
|
4037
|
-
if (g) return
|
|
4479
|
+
let { line: p } = Xn(f), m = e.cursorPos ? e.cursorPos.x - 1 : 0, h = tr(r, p), g = n === "scale" && !Rn(h.fields.interval?.rawValue ?? "") ? Bt(n) : null;
|
|
4480
|
+
if (g) return hr(e, t, g, l);
|
|
4038
4481
|
let _ = null;
|
|
4039
4482
|
if (e.cursorPos) {
|
|
4040
|
-
let e =
|
|
4483
|
+
let e = er(r.columns ?? [], m);
|
|
4041
4484
|
if (e) {
|
|
4042
4485
|
let t = h.fields[e.key];
|
|
4043
4486
|
t && (_ = {
|
|
@@ -4048,20 +4491,20 @@ function Yn(e, t) {
|
|
|
4048
4491
|
}
|
|
4049
4492
|
}
|
|
4050
4493
|
let v = null, y = null, b = null, x = null, S = null, C = null;
|
|
4051
|
-
if (
|
|
4494
|
+
if (ir(e, t)) {
|
|
4052
4495
|
if (n === "phrase" && h.rowIndex != null) {
|
|
4053
|
-
let n =
|
|
4496
|
+
let n = dr(r, e, t, h.rowIndex);
|
|
4054
4497
|
if (n) {
|
|
4055
4498
|
v = n.steps, y = n.carriedRepLane;
|
|
4056
4499
|
let e = _ ? /^fx(\d)(cmd|val)$/.exec(_.key)?.[1] : void 0;
|
|
4057
|
-
e && (b =
|
|
4500
|
+
e && (b = Dn(v, Number(e), h.rowIndex, y === Number(e))), x = An(v, h.rowIndex, y), h.rowIndex > 0 && kn(h) && (S = An(v, h.rowIndex - 1, y));
|
|
4058
4501
|
}
|
|
4059
4502
|
} else if (n === "scale") {
|
|
4060
|
-
let e =
|
|
4061
|
-
e && (C =
|
|
4503
|
+
let e = mr(r, t);
|
|
4504
|
+
e && (C = Vn(e));
|
|
4062
4505
|
}
|
|
4063
4506
|
}
|
|
4064
|
-
let w = n === "scale" ?
|
|
4507
|
+
let w = n === "scale" ? pr(h) : null;
|
|
4065
4508
|
return {
|
|
4066
4509
|
...u,
|
|
4067
4510
|
isGridView: !0,
|
|
@@ -4077,25 +4520,25 @@ function Yn(e, t) {
|
|
|
4077
4520
|
scale: C
|
|
4078
4521
|
};
|
|
4079
4522
|
}
|
|
4080
|
-
function
|
|
4081
|
-
if (e.isParameterView) return
|
|
4523
|
+
function _r(e) {
|
|
4524
|
+
if (e.isParameterView) return Er(e);
|
|
4082
4525
|
if (e.viewName === "scale") {
|
|
4083
|
-
let t =
|
|
4526
|
+
let t = Dr(e);
|
|
4084
4527
|
if (t) return t;
|
|
4085
4528
|
}
|
|
4086
4529
|
if (!e.activeField) return $(["location", e.viewTitle ?? e.viewName]);
|
|
4087
|
-
let { activeField: t, row: n } = e, r = $(["field", `${t.label}: ${
|
|
4530
|
+
let { activeField: t, row: n } = e, r = $(["field", `${t.label}: ${kr(t)}`]), i = (t.type === "fxCommand" || t.type === "fxValue") && n ? yr(e, t, n) : [...Sr(e, t), ...Cr(e, t)], a = i.length > 0;
|
|
4088
4531
|
if (t.type === "fxCommand" && !t.isEmpty) {
|
|
4089
|
-
let e = a && /^(REP|RTO)$/i.test(t.rawValue) ? void 0 :
|
|
4532
|
+
let e = a && /^(REP|RTO)$/i.test(t.rawValue) ? void 0 : dn(t.rawValue);
|
|
4090
4533
|
e && r.push({
|
|
4091
4534
|
kind: "fxInfo",
|
|
4092
|
-
text: `(${
|
|
4535
|
+
text: `(${br(e)})`
|
|
4093
4536
|
});
|
|
4094
4537
|
}
|
|
4095
4538
|
if (t.type === "fxValue" && n) {
|
|
4096
4539
|
let e = t.key.replace("val", "cmd"), i = n.fields[e];
|
|
4097
4540
|
if (i && !i.isEmpty) {
|
|
4098
|
-
let e = a && /^(REP|RTO)$/i.test(i.rawValue) ? void 0 :
|
|
4541
|
+
let e = a && /^(REP|RTO)$/i.test(i.rawValue) ? void 0 : dn(i.rawValue), t = e ? `${i.rawValue} (${br(e)})` : i.rawValue;
|
|
4099
4542
|
r.push({
|
|
4100
4543
|
kind: "fxTarget",
|
|
4101
4544
|
text: `for ${t}`
|
|
@@ -4114,8 +4557,8 @@ function Xn(e) {
|
|
|
4114
4557
|
}
|
|
4115
4558
|
return r;
|
|
4116
4559
|
}
|
|
4117
|
-
function
|
|
4118
|
-
return
|
|
4560
|
+
function vr(e) {
|
|
4561
|
+
return _r(e).map((e) => e.text).join(" — ");
|
|
4119
4562
|
}
|
|
4120
4563
|
function $(...e) {
|
|
4121
4564
|
return e.flatMap(([e, t]) => t ? [{
|
|
@@ -4123,32 +4566,33 @@ function $(...e) {
|
|
|
4123
4566
|
text: t
|
|
4124
4567
|
}] : []);
|
|
4125
4568
|
}
|
|
4126
|
-
function
|
|
4569
|
+
function yr(e, t, n) {
|
|
4127
4570
|
let r = /^fx(\d)/.exec(t.key)?.[1];
|
|
4128
4571
|
if (!r) return [];
|
|
4129
4572
|
let i = n.fields[`fx${r}cmd`], a = n.fields[`fx${r}val`];
|
|
4130
4573
|
if (!i || i.isEmpty) {
|
|
4131
4574
|
if (e.fxLane?.event !== "continue") return [];
|
|
4132
|
-
let t = e.fxLane.source?.cmd, n = t &&
|
|
4133
|
-
return $(["fxLane",
|
|
4575
|
+
let t = e.fxLane.source?.cmd, n = t && q(t) ? Pn(e.relativeFx?.[t]) : null;
|
|
4576
|
+
return $(["fxLane", On(e.fxLane)], ["relative", n]);
|
|
4134
4577
|
}
|
|
4135
|
-
let o = i.rawValue.toUpperCase(), s = e.fxLane && e.fxLane.event !== "none" && e.fxLane.event !== "set" ?
|
|
4136
|
-
if (o === "REP" || o === "RTO") {
|
|
4137
|
-
let t = e.fxLane?.source?.cmd, n = o === "REP" && e.fxLane?.active && t &&
|
|
4578
|
+
let o = i.rawValue.toUpperCase(), s = e.fxLane && e.fxLane.event !== "none" && e.fxLane.event !== "set" ? On(e.fxLane) : null;
|
|
4579
|
+
if ((o === "REP" || o === "RTO") && e.viewName !== "table") {
|
|
4580
|
+
let t = e.fxLane?.source?.cmd, n = o === "REP" && e.fxLane?.active && t && q(t) ? Pn(e.relativeFx?.[t]) : null;
|
|
4138
4581
|
return $(["fxLane", s], ["relative", n]);
|
|
4139
4582
|
}
|
|
4140
4583
|
if (!a || a.isEmpty || a.hexValue == null) return $(["fxLane", s]);
|
|
4141
|
-
let c = t.type === "fxCommand" ? `value ${
|
|
4584
|
+
let c = t.type === "fxCommand" ? `value ${gn(o, a.hexValue)}: ` : "", l = Tn(o, a.hexValue, {
|
|
4142
4585
|
note: n.fields.note?.isEmpty ? null : n.fields.note?.rawValue,
|
|
4143
|
-
inTable: e.viewName === "table"
|
|
4586
|
+
inTable: e.viewName === "table",
|
|
4587
|
+
row: n.rowIndex
|
|
4144
4588
|
}), u = null;
|
|
4145
|
-
return
|
|
4589
|
+
return q(o) ? u = Pn(e.relativeFx?.[o]) : o === "RET" && e.resetsRelative && (u = Fn(e.resetsRelative)), $(["meaning", l ? `${c}${l}` : null], ["fxLane", s], ["relative", u]);
|
|
4146
4590
|
}
|
|
4147
|
-
function
|
|
4591
|
+
function br(e) {
|
|
4148
4592
|
let t = e.description.replace(/\.$/, "");
|
|
4149
|
-
return e.instrumentTypes ? `${t}; offered by ${e.instrumentTypes.map((e) =>
|
|
4593
|
+
return e.instrumentTypes ? `${t}; offered by ${e.instrumentTypes.map((e) => xr[e] ?? e).join(", ")} instruments` : t;
|
|
4150
4594
|
}
|
|
4151
|
-
var
|
|
4595
|
+
var xr = {
|
|
4152
4596
|
sampler: "Sampler",
|
|
4153
4597
|
macrosynth: "Macrosynth",
|
|
4154
4598
|
fmsynth: "FM Synth",
|
|
@@ -4157,14 +4601,17 @@ var er = {
|
|
|
4157
4601
|
external: "External",
|
|
4158
4602
|
midiout: "MIDI Out"
|
|
4159
4603
|
};
|
|
4160
|
-
function
|
|
4161
|
-
return t.type !== "instrumentRef" || t.isEmpty || !e.resetsRelative ? [] : $(["relative",
|
|
4604
|
+
function Sr(e, t) {
|
|
4605
|
+
return t.type !== "instrumentRef" || t.isEmpty || !e.resetsRelative ? [] : $(["relative", Fn(e.resetsRelative)]);
|
|
4162
4606
|
}
|
|
4163
|
-
|
|
4607
|
+
function Cr(e, t) {
|
|
4608
|
+
return e.viewName !== "table" || t.key !== "volume" || t.isEmpty || t.hexValue == null || t.hexValue > 127 ? [] : $(["meaning", `plays at ${Math.round(t.hexValue / 127 * 100)}% of the step's velocity`]);
|
|
4609
|
+
}
|
|
4610
|
+
var wr = {
|
|
4164
4611
|
MODFX: "ModFX",
|
|
4165
4612
|
DELAY: "Delay",
|
|
4166
4613
|
REVERB: "Reverb"
|
|
4167
|
-
},
|
|
4614
|
+
}, Tr = {
|
|
4168
4615
|
parent: "goes up to the parent directory",
|
|
4169
4616
|
directory: "directory: [EDIT] opens it",
|
|
4170
4617
|
instrumentPreset: "instrument preset: [EDIT] selects it",
|
|
@@ -4172,38 +4619,38 @@ var nr = {
|
|
|
4172
4619
|
m8file: "M8 file: [EDIT] selects it",
|
|
4173
4620
|
file: "file: [EDIT] selects it"
|
|
4174
4621
|
};
|
|
4175
|
-
function
|
|
4622
|
+
function Er(e) {
|
|
4176
4623
|
let t = `${e.viewTitle ?? e.viewName}${e.viewId ? ` ${e.viewId}` : ""}`, n = e.activeField;
|
|
4177
4624
|
if (!n) return $(["location", t], ["line", e.lineText]);
|
|
4178
|
-
let r = e.instrumentType?.key ?
|
|
4179
|
-
return $(["field", `${n.label}: ${
|
|
4625
|
+
let r = e.instrumentType?.key ? Kt(e.instrumentType.key) : null;
|
|
4626
|
+
return $(["field", `${n.label}: ${kr(n)}`], ["optionInfo", n.valueDescription], ["fieldInfo", n.description], ["fileInfo", n.fileKind && Tr[n.fileKind]], ["instrument", e.instrumentType && `${r?.name ?? e.instrumentType.text} instrument`], ["section", e.section && (wr[e.section] ?? e.section)], ["location", t]);
|
|
4180
4627
|
}
|
|
4181
|
-
function
|
|
4628
|
+
function Dr(e) {
|
|
4182
4629
|
let t = `${e.viewTitle ?? e.viewName}${e.viewId ? ` ${e.viewId}` : ""}`, n = e.activeField, r = e.scaleNote;
|
|
4183
4630
|
if (!n || !r) return e.lineText ? $(["location", t], ["line", e.lineText]) : null;
|
|
4184
4631
|
let { interval: i, enabled: a, offset: o } = r, s;
|
|
4185
4632
|
if (n.key === "offset") {
|
|
4186
|
-
let e = o == null ? `detune of ${i}` : o === 0 ? `${i} is not detuned` : `${i} is detuned by ${
|
|
4633
|
+
let e = o == null ? `detune of ${i}` : o === 0 ? `${i} is not detuned` : `${i} is detuned by ${Un(o)}`;
|
|
4187
4634
|
s = $(["field", `${n.label}: ${n.rawValue || "(empty)"}`], ["meaning", e], ["meaning", a === !1 ? "(note is OFF)" : null]);
|
|
4188
4635
|
} else {
|
|
4189
4636
|
let e = a === !0 ? "is in" : a === !1 ? "is not in" : "is not yet set in";
|
|
4190
|
-
s = $(["field", `${n.label}: ${n.key === "en" ? n.rawValue.toUpperCase() || "(unset)" : i}`], ["meaning", i], ["meaning",
|
|
4637
|
+
s = $(["field", `${n.label}: ${n.key === "en" ? n.rawValue.toUpperCase() || "(unset)" : i}`], ["meaning", i], ["meaning", zn(i)], ["meaning", `${e} the scale`]);
|
|
4191
4638
|
}
|
|
4192
4639
|
if (e.scale) {
|
|
4193
|
-
let [t, n] =
|
|
4640
|
+
let [t, n] = Hn(e.scale);
|
|
4194
4641
|
s.push(...$(["scale", `Scale: ${t}`], ["scale", n]));
|
|
4195
4642
|
}
|
|
4196
4643
|
return [...s, ...$(["location", `${t} row ${i}`])];
|
|
4197
4644
|
}
|
|
4198
|
-
function
|
|
4645
|
+
function Or(e) {
|
|
4199
4646
|
let t = e.unit ?? "";
|
|
4200
4647
|
if (e.values && e.parts) {
|
|
4201
4648
|
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(", ");
|
|
4202
|
-
return `${r.join(":")} (${i})`;
|
|
4649
|
+
return `${r.join(e.rawValue.includes("/") ? "/" : ":")} (${i})`;
|
|
4203
4650
|
}
|
|
4204
4651
|
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}` : ""}`;
|
|
4205
4652
|
}
|
|
4206
|
-
function
|
|
4653
|
+
function kr(e) {
|
|
4207
4654
|
if (e.isEmpty) return "(empty)";
|
|
4208
4655
|
let t = e.type === "name" || e.type === "fileEntry" ? e : {
|
|
4209
4656
|
...e,
|
|
@@ -4230,26 +4677,26 @@ function sr(e) {
|
|
|
4230
4677
|
case "fileEntry": return t.text ?? t.rawValue;
|
|
4231
4678
|
case "name": return `"${t.rawValue}"`;
|
|
4232
4679
|
case "option": return t.hexValue != null && t.text ? `${t.rawValue.slice(0, 2)} ${t.text}` : t.text ?? t.rawValue;
|
|
4233
|
-
case "parameter": return
|
|
4234
|
-
case "noteInterval": return `Interval ${
|
|
4680
|
+
case "parameter": return Or(t);
|
|
4681
|
+
case "noteInterval": return `Interval ${Rn(t.rawValue) ?? t.rawValue}`;
|
|
4235
4682
|
case "semitoneOffset": return t.isEmpty ? "(empty)" : `${t.rawValue} st`;
|
|
4236
4683
|
default: return t.rawValue;
|
|
4237
4684
|
}
|
|
4238
4685
|
}
|
|
4239
4686
|
//#endregion
|
|
4240
4687
|
//#region src/client.ts
|
|
4241
|
-
var
|
|
4688
|
+
var Ar = "yam8d-external-app", jr = 3e3, Mr = (e) => {
|
|
4242
4689
|
let t = e.remoteHandle();
|
|
4243
4690
|
return {
|
|
4244
4691
|
call: (e, ...n) => t.call(e, ...n),
|
|
4245
4692
|
on: (e, n) => (t.addEventListener(e, n), () => t.removeEventListener(e, n)),
|
|
4246
4693
|
close: () => e.close()
|
|
4247
4694
|
};
|
|
4248
|
-
},
|
|
4695
|
+
}, Nr = (e) => ({
|
|
4249
4696
|
call: (t, ...n) => e.methods[t](...n),
|
|
4250
4697
|
on: (t, n) => e.on(t, n),
|
|
4251
4698
|
close: () => e.dispose()
|
|
4252
|
-
}),
|
|
4699
|
+
}), Pr = (e) => {
|
|
4253
4700
|
let t = [];
|
|
4254
4701
|
return {
|
|
4255
4702
|
messenger: {
|
|
@@ -4263,21 +4710,21 @@ var cr = "yam8d-external-app", lr = 3e3, ur = (e) => {
|
|
|
4263
4710
|
for (let e of t.splice(0)) e();
|
|
4264
4711
|
}
|
|
4265
4712
|
};
|
|
4266
|
-
},
|
|
4713
|
+
}, Fr = () => {
|
|
4267
4714
|
if (typeof window > "u") return !1;
|
|
4268
4715
|
try {
|
|
4269
4716
|
return window.parent !== window;
|
|
4270
4717
|
} catch {
|
|
4271
4718
|
return !0;
|
|
4272
4719
|
}
|
|
4273
|
-
},
|
|
4720
|
+
}, Ir = (e) => e instanceof DOMException && (e.name === "NotFoundError" || e.name === "AbortError"), Lr = () => {
|
|
4274
4721
|
let e = typeof navigator > "u" ? null : navigator;
|
|
4275
4722
|
return {
|
|
4276
4723
|
serial: !!e && "serial" in e,
|
|
4277
4724
|
usb: !!e && "usb" in e,
|
|
4278
4725
|
midi: !!e && "requestMIDIAccess" in e
|
|
4279
4726
|
};
|
|
4280
|
-
},
|
|
4727
|
+
}, Rr = () => ({
|
|
4281
4728
|
viewName: null,
|
|
4282
4729
|
viewTitle: null,
|
|
4283
4730
|
minimapKey: null,
|
|
@@ -4294,9 +4741,9 @@ var cr = "yam8d-external-app", lr = 3e3, ur = (e) => {
|
|
|
4294
4741
|
fontMode: null,
|
|
4295
4742
|
systemInfo: null,
|
|
4296
4743
|
macroRunning: !1
|
|
4297
|
-
}),
|
|
4744
|
+
}), zr = class {
|
|
4298
4745
|
constructor(e = {}) {
|
|
4299
|
-
this.backend = null, this.backendUnsubscribers = [], this.device = null, this._mode = null, this.audio = null, this.connecting = null, this.stateCallbacks = /* @__PURE__ */ new Set(), this.viewCallbacks = /* @__PURE__ */ new Set(), this.cursorCallbacks = /* @__PURE__ */ new Set(), this.textCallbacks = /* @__PURE__ */ new Set(), this.keyCallbacks = /* @__PURE__ */ new Set(), this.transportCallbacks = /* @__PURE__ */ new Set(), this.connectionCallbacks = /* @__PURE__ */ new Set(), this._state =
|
|
4746
|
+
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 = Rr(), this._screen = null, this.screenRefreshing = !1, this.screenDirty = !1, this.config = e;
|
|
4300
4747
|
}
|
|
4301
4748
|
get state() {
|
|
4302
4749
|
return this._state;
|
|
@@ -4318,11 +4765,11 @@ var cr = "yam8d-external-app", lr = 3e3, ur = (e) => {
|
|
|
4318
4765
|
}
|
|
4319
4766
|
async resolveMode() {
|
|
4320
4767
|
let e = this.config.mode ?? "auto";
|
|
4321
|
-
if (e === "standalone" || e === "auto" && !
|
|
4768
|
+
if (e === "standalone" || e === "auto" && !Fr()) {
|
|
4322
4769
|
await this.startStandalone();
|
|
4323
4770
|
return;
|
|
4324
4771
|
}
|
|
4325
|
-
let t = typeof window < "u" && window.name === "yam8d-external-app", n = e === "host" || t ? null : this.config.handshakeTimeoutMs ??
|
|
4772
|
+
let t = typeof window < "u" && window.name === "yam8d-external-app", n = e === "host" || t ? null : this.config.handshakeTimeoutMs ?? jr;
|
|
4326
4773
|
await this.handshake(n) || (this.config.debug && console.log("[M8 SDK] No yam8d host answered, switching to standalone mode"), await this.startStandalone());
|
|
4327
4774
|
}
|
|
4328
4775
|
async handshake(r) {
|
|
@@ -4334,10 +4781,10 @@ var cr = "yam8d-external-app", lr = 3e3, ur = (e) => {
|
|
|
4334
4781
|
this.config.debug && (i = t(i, (e, ...t) => {
|
|
4335
4782
|
console.log("[M8 SDK]", e, ...t);
|
|
4336
4783
|
}));
|
|
4337
|
-
let a =
|
|
4784
|
+
let a = Pr(i), o = e(a.messenger, { ping: async () => "pong" }), s, c = new Promise((e) => {
|
|
4338
4785
|
r !== null && (s = setTimeout(() => e(null), r));
|
|
4339
4786
|
}), l = await Promise.race([o, c]);
|
|
4340
|
-
return clearTimeout(s), l ? (this._mode = "host", await this.attach(
|
|
4787
|
+
return clearTimeout(s), l ? (this._mode = "host", await this.attach(Mr(l)), l.localHandle().emit("ready", void 0), !0) : (a.dispose(), !1);
|
|
4341
4788
|
}
|
|
4342
4789
|
async startStandalone() {
|
|
4343
4790
|
if (this._mode = "standalone", this.config.autoConnect !== !1) try {
|
|
@@ -4363,14 +4810,14 @@ var cr = "yam8d-external-app", lr = 3e3, ur = (e) => {
|
|
|
4363
4810
|
});
|
|
4364
4811
|
break;
|
|
4365
4812
|
} catch (r) {
|
|
4366
|
-
if (a = r, t && !
|
|
4813
|
+
if (a = r, t && !Ir(r) && (i = await ee(() => n.connect({
|
|
4367
4814
|
transport: e,
|
|
4368
4815
|
prompt: !1
|
|
4369
4816
|
}), { maxAttempts: 2 }), i)) break;
|
|
4370
4817
|
}
|
|
4371
4818
|
if (!i) throw a;
|
|
4372
|
-
let o =
|
|
4373
|
-
this.device = i, await this.attach(
|
|
4819
|
+
let o = Pt(i, { debug: this.config.debug });
|
|
4820
|
+
this.device = i, await this.attach(Nr(o)), i.commands.resetScreen();
|
|
4374
4821
|
let s = i;
|
|
4375
4822
|
i.closed.then(() => {
|
|
4376
4823
|
this.device === s && (this.config.debug && console.log("[M8 SDK] Device connection ended"), this.device = null, this.detach());
|
|
@@ -4520,7 +4967,7 @@ var cr = "yam8d-external-app", lr = 3e3, ur = (e) => {
|
|
|
4520
4967
|
}, e;
|
|
4521
4968
|
}
|
|
4522
4969
|
async captureSnapshot() {
|
|
4523
|
-
let [e, t] = await Promise.all([this.fetchState(), this.getScreen()]), n =
|
|
4970
|
+
let [e, t] = await Promise.all([this.fetchState(), this.getScreen()]), n = gr(e, t);
|
|
4524
4971
|
return {
|
|
4525
4972
|
capturedAt: Date.now(),
|
|
4526
4973
|
state: {
|
|
@@ -4533,8 +4980,8 @@ var cr = "yam8d-external-app", lr = 3e3, ur = (e) => {
|
|
|
4533
4980
|
deviceModel: e.deviceModel
|
|
4534
4981
|
},
|
|
4535
4982
|
semantic: n,
|
|
4536
|
-
description: n ?
|
|
4537
|
-
descriptionParts: n ?
|
|
4983
|
+
description: n ? vr(n) : null,
|
|
4984
|
+
descriptionParts: n ? _r(n) : null,
|
|
4538
4985
|
screen: t
|
|
4539
4986
|
};
|
|
4540
4987
|
}
|
|
@@ -4563,23 +5010,23 @@ var cr = "yam8d-external-app", lr = 3e3, ur = (e) => {
|
|
|
4563
5010
|
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();
|
|
4564
5011
|
}
|
|
4565
5012
|
getSemanticContext() {
|
|
4566
|
-
return
|
|
5013
|
+
return gr(this._state, this._screen);
|
|
4567
5014
|
}
|
|
4568
5015
|
describeContext() {
|
|
4569
|
-
let e =
|
|
4570
|
-
return e ?
|
|
5016
|
+
let e = gr(this._state, this._screen);
|
|
5017
|
+
return e ? vr(e) : null;
|
|
4571
5018
|
}
|
|
4572
5019
|
describeContextParts() {
|
|
4573
|
-
let e =
|
|
4574
|
-
return e ?
|
|
5020
|
+
let e = gr(this._state, this._screen);
|
|
5021
|
+
return e ? _r(e) : null;
|
|
4575
5022
|
}
|
|
4576
5023
|
};
|
|
4577
|
-
async function
|
|
4578
|
-
let t = new
|
|
5024
|
+
async function Br(e = {}) {
|
|
5025
|
+
let t = new zr(e);
|
|
4579
5026
|
return await t.connect(), t;
|
|
4580
5027
|
}
|
|
4581
|
-
function
|
|
4582
|
-
let t = new
|
|
5028
|
+
function Vr(e = {}) {
|
|
5029
|
+
let t = new zr(e);
|
|
4583
5030
|
return {
|
|
4584
5031
|
client: t,
|
|
4585
5032
|
connect: async () => {
|
|
@@ -4587,10 +5034,10 @@ function yr(e = {}) {
|
|
|
4587
5034
|
}
|
|
4588
5035
|
};
|
|
4589
5036
|
}
|
|
4590
|
-
var
|
|
4591
|
-
createM8Client:
|
|
4592
|
-
createM8ClientSync:
|
|
4593
|
-
},
|
|
5037
|
+
var Hr = {
|
|
5038
|
+
createM8Client: Br,
|
|
5039
|
+
createM8ClientSync: Vr
|
|
5040
|
+
}, Ur = [
|
|
4594
5041
|
{
|
|
4595
5042
|
role: "background",
|
|
4596
5043
|
label: "BACKGROUND"
|
|
@@ -4643,7 +5090,7 @@ var br = {
|
|
|
4643
5090
|
role: "meterPeak",
|
|
4644
5091
|
label: "METER PEAK"
|
|
4645
5092
|
}
|
|
4646
|
-
],
|
|
5093
|
+
], Wr = "themesettings", Gr = (e) => e.replace(/\s+/g, "").toUpperCase(), Kr = (e) => Math.max(0, Math.min(255, Math.round(e))).toString(16).padStart(2, "0"), qr = (e, t, n) => `#${Kr(e)}${Kr(t)}${Kr(n)}`, Jr = (e, t, n) => {
|
|
4647
5094
|
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
5095
|
[
|
|
4649
5096
|
a,
|
|
@@ -4676,14 +5123,14 @@ var br = {
|
|
|
4676
5123
|
l
|
|
4677
5124
|
]
|
|
4678
5125
|
][o];
|
|
4679
|
-
return
|
|
4680
|
-
},
|
|
4681
|
-
function
|
|
5126
|
+
return qr(d * 255, f * 255, p * 255);
|
|
5127
|
+
}, Yr = new Map(Ur.map(({ role: e, label: t }) => [Gr(t), e]));
|
|
5128
|
+
function Xr(e) {
|
|
4682
5129
|
let t = "rgb", n = null, r = {};
|
|
4683
5130
|
for (let i of e.lines) {
|
|
4684
5131
|
let e = i.replace(/[{}]/g, "0"), a = /^\s*MODE\s+([A-Z])\s+([A-Z])\s+([A-Z])\b/i.exec(e);
|
|
4685
5132
|
if (a) {
|
|
4686
|
-
t =
|
|
5133
|
+
t = Gr(a.slice(1).join("")) === "HSV" ? "hsv" : "rgb";
|
|
4687
5134
|
continue;
|
|
4688
5135
|
}
|
|
4689
5136
|
let o = /^\s*THEME\s+NAME\s+(\S.*?)\s*$/i.exec(e);
|
|
@@ -4694,23 +5141,23 @@ function Or(e) {
|
|
|
4694
5141
|
}
|
|
4695
5142
|
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
5143
|
if (!s) continue;
|
|
4697
|
-
let c =
|
|
5144
|
+
let c = Yr.get(Gr(s[1]));
|
|
4698
5145
|
if (!c || r[c]) continue;
|
|
4699
5146
|
let [l, u, d] = s.slice(2, 5).map((e) => parseInt(e, 16));
|
|
4700
|
-
r[c] = t === "hsv" ?
|
|
5147
|
+
r[c] = t === "hsv" ? Jr(l, u, d) : qr(l, u, d);
|
|
4701
5148
|
}
|
|
4702
|
-
return
|
|
5149
|
+
return Ur.some(({ role: e }) => !r[e]) ? null : {
|
|
4703
5150
|
colors: r,
|
|
4704
5151
|
mode: t,
|
|
4705
5152
|
name: n
|
|
4706
5153
|
};
|
|
4707
5154
|
}
|
|
4708
|
-
var
|
|
4709
|
-
function
|
|
4710
|
-
let t = {}, n =
|
|
5155
|
+
var Zr = (e) => e ? qr(e.r, e.g, e.b) : void 0;
|
|
5156
|
+
function Qr(e) {
|
|
5157
|
+
let t = {}, n = Zr(e.backgroundColor), r = Zr(e.titleColor);
|
|
4711
5158
|
return n && (t.background = n), r && (t.textTitles = r), t;
|
|
4712
5159
|
}
|
|
4713
5160
|
//#endregion
|
|
4714
|
-
export { I as M8KeyMask, j as M8_AUDIO_CAPTURE_CONSTRAINTS,
|
|
5161
|
+
export { I as M8KeyMask, j as M8_AUDIO_CAPTURE_CONSTRAINTS, Ur as M8_THEME_ROLES, Wr as M8_THEME_VIEW, pn as RELATIVE_FX_RULE, rr as SCREEN_MARGIN, Ar as YAM8D_FRAME_NAME, F as createM8Audio, Br as createM8Client, Vr as createM8ClientSync, A as createM8Connection, Pt as createM8Engine, Hr as default, vr as describeContext, _r as describeContextParts, kr as formatFieldValue, Lr as getDeviceSupport, fn as getInstrumentFxCommands, P as getM8InputStream, gr as getSemanticContext, dn as lookupFxCommand, Qr as observeThemeColors, cr as parseGridScreen, Xr as parseThemeScreen, Jn as parseViewTitle, te as pressKeys, ur as readPlayPositions };
|
|
4715
5162
|
|
|
4716
5163
|
//# sourceMappingURL=index.js.map
|