@djodjonx/x32-simulator 0.0.6 → 0.0.7
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/CHANGELOG.md +20 -0
- package/dist/{SchemaRegistry-D4eIJord.mjs → SchemaRegistry-BBzyicoy.mjs} +1271 -192
- package/dist/{SchemaRegistry-DE6iObDv.cjs → SchemaRegistry-Ddy5AEKs.cjs} +1282 -191
- package/dist/index.cjs +4 -2
- package/dist/index.d.cts +84 -39
- package/dist/index.d.mts +84 -39
- package/dist/index.mjs +2 -2
- package/dist/server.cjs +205 -10
- package/dist/server.mjs +206 -10
- package/package.json +1 -1
|
@@ -25,37 +25,13 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
25
25
|
}) : target, mod));
|
|
26
26
|
|
|
27
27
|
//#endregion
|
|
28
|
+
let node_events = require("node:events");
|
|
28
29
|
let os = require("os");
|
|
29
30
|
os = __toESM(os);
|
|
30
|
-
let node_events = require("node:events");
|
|
31
31
|
let node_dgram = require("node:dgram");
|
|
32
32
|
node_dgram = __toESM(node_dgram);
|
|
33
33
|
let node_buffer = require("node:buffer");
|
|
34
34
|
|
|
35
|
-
//#region src/application/use-cases/ProcessPacketUseCase.ts
|
|
36
|
-
var ProcessPacketUseCase = class {
|
|
37
|
-
constructor(messageHandler, gateway) {
|
|
38
|
-
this.messageHandler = messageHandler;
|
|
39
|
-
this.gateway = gateway;
|
|
40
|
-
}
|
|
41
|
-
execute(packet, rinfo) {
|
|
42
|
-
if (packet.oscType === "bundle") packet.elements?.forEach((el) => this.execute(el, rinfo));
|
|
43
|
-
else if (packet.oscType === "message") {
|
|
44
|
-
const args = packet.args.map((arg) => {
|
|
45
|
-
if (typeof arg === "object" && arg !== null && "value" in arg) return arg.value;
|
|
46
|
-
return arg;
|
|
47
|
-
});
|
|
48
|
-
this.messageHandler.handle({
|
|
49
|
-
address: packet.address,
|
|
50
|
-
args
|
|
51
|
-
}, rinfo).forEach((reply) => {
|
|
52
|
-
this.gateway.send(rinfo, reply.address, reply.args);
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
//#endregion
|
|
59
35
|
//#region src/domain/ports/ILogger.ts
|
|
60
36
|
/**
|
|
61
37
|
* Standard log categories for the domain.
|
|
@@ -71,6 +47,35 @@ let LogCategory = /* @__PURE__ */ function(LogCategory$1) {
|
|
|
71
47
|
return LogCategory$1;
|
|
72
48
|
}({});
|
|
73
49
|
|
|
50
|
+
//#endregion
|
|
51
|
+
//#region src/application/use-cases/ProcessPacketUseCase.ts
|
|
52
|
+
var ProcessPacketUseCase = class {
|
|
53
|
+
constructor(messageHandler, gateway, logger) {
|
|
54
|
+
this.messageHandler = messageHandler;
|
|
55
|
+
this.gateway = gateway;
|
|
56
|
+
this.logger = logger;
|
|
57
|
+
}
|
|
58
|
+
execute(packet, rinfo) {
|
|
59
|
+
try {
|
|
60
|
+
if (packet.oscType === "bundle") packet.elements?.forEach((el) => this.execute(el, rinfo));
|
|
61
|
+
else if (packet.oscType === "message") {
|
|
62
|
+
const args = packet.args.map((arg) => {
|
|
63
|
+
if (typeof arg === "object" && arg !== null && "value" in arg) return arg.value;
|
|
64
|
+
return arg;
|
|
65
|
+
});
|
|
66
|
+
this.messageHandler.handle({
|
|
67
|
+
address: packet.address,
|
|
68
|
+
args
|
|
69
|
+
}, rinfo).forEach((reply) => {
|
|
70
|
+
this.gateway.send(rinfo, reply.address, reply.args);
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
} catch (err) {
|
|
74
|
+
this.logger?.error(LogCategory.DISPATCH, `Error processing packet from ${rinfo.address}:${rinfo.port}`, err instanceof Error ? err : new Error(String(err)));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
|
|
74
79
|
//#endregion
|
|
75
80
|
//#region src/application/use-cases/BroadcastUpdatesUseCase.ts
|
|
76
81
|
var BroadcastUpdatesUseCase = class {
|
|
@@ -188,16 +193,134 @@ var ManageSessionsUseCase = class {
|
|
|
188
193
|
}
|
|
189
194
|
};
|
|
190
195
|
|
|
196
|
+
//#endregion
|
|
197
|
+
//#region src/domain/entities/X32State.ts
|
|
198
|
+
/**
|
|
199
|
+
* Manages the internal "Digital Twin" state of the X32 console.
|
|
200
|
+
* It acts as a single source of truth for all parameters.
|
|
201
|
+
* Emits 'change' events whenever a value is updated.
|
|
202
|
+
* Uses an injectable repository for storage (memory or persistent).
|
|
203
|
+
*/
|
|
204
|
+
var X32State = class extends node_events.EventEmitter {
|
|
205
|
+
defaultState = /* @__PURE__ */ new Map();
|
|
206
|
+
/**
|
|
207
|
+
* Initializes the state with default values from the schema.
|
|
208
|
+
* @param schema - The schema definition map.
|
|
209
|
+
* @param repository - The storage repository (injectable).
|
|
210
|
+
*/
|
|
211
|
+
constructor(schema, repository) {
|
|
212
|
+
super();
|
|
213
|
+
this.repository = repository;
|
|
214
|
+
for (const [addr, def] of Object.entries(schema)) this.defaultState.set(addr, def.default);
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Initializes the state - loads from repository or resets to defaults.
|
|
218
|
+
*/
|
|
219
|
+
async initialize() {
|
|
220
|
+
const stored = await this.repository.load();
|
|
221
|
+
if (Object.keys(stored).length === 0) this.reset();
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Resets all state parameters to their default values defined in the schema.
|
|
225
|
+
*/
|
|
226
|
+
reset() {
|
|
227
|
+
const defaults = {};
|
|
228
|
+
this.defaultState.forEach((val, key) => {
|
|
229
|
+
defaults[key] = val;
|
|
230
|
+
});
|
|
231
|
+
this.repository.reset(defaults);
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Retrieves the value of a specific OSC node.
|
|
235
|
+
* @param address - The full OSC address path.
|
|
236
|
+
* @returns The stored value (number or string) or undefined if not found.
|
|
237
|
+
*/
|
|
238
|
+
get(address) {
|
|
239
|
+
return this.repository.get(address);
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Retrieves all state entries as a plain object.
|
|
243
|
+
* @returns A record of all OSC addresses and their current values.
|
|
244
|
+
*/
|
|
245
|
+
getAll() {
|
|
246
|
+
return this.repository.getAll();
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Updates the value of a specific OSC node and notifies subscribers.
|
|
250
|
+
* @param address - The full OSC address path.
|
|
251
|
+
* @param value - The new value to store.
|
|
252
|
+
*/
|
|
253
|
+
set(address, value) {
|
|
254
|
+
this.repository.set(address, value);
|
|
255
|
+
this.emit("change", {
|
|
256
|
+
address,
|
|
257
|
+
value
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Flushes pending changes to persistent storage.
|
|
262
|
+
*/
|
|
263
|
+
async flush() {
|
|
264
|
+
await this.repository.flush();
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Specialized logic to handle X32 Mute Groups side-effects.
|
|
268
|
+
* When a mute group is toggled, it iterates through all channels
|
|
269
|
+
* assigned to that group and updates their individual mute status.
|
|
270
|
+
* @param groupIdx - The index of the mute group (1-6).
|
|
271
|
+
* @param isOn - The new state of the group master switch (0 or 1).
|
|
272
|
+
*/
|
|
273
|
+
handleMuteGroupChange(groupIdx, isOn) {
|
|
274
|
+
for (let i = 1; i <= 32; i++) {
|
|
275
|
+
const ch = i.toString().padStart(2, "0");
|
|
276
|
+
const grpVal = this.get(`/ch/${ch}/grp/mute`);
|
|
277
|
+
if (typeof grpVal === "number") {
|
|
278
|
+
if ((grpVal & 1 << groupIdx - 1) !== 0) {
|
|
279
|
+
const targetMute = isOn === 1 ? 0 : 1;
|
|
280
|
+
const muteAddr = `/ch/${ch}/mix/on`;
|
|
281
|
+
this.set(muteAddr, targetMute);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
//#endregion
|
|
289
|
+
//#region src/domain/models/Config.ts
|
|
290
|
+
/**
|
|
291
|
+
* Default configuration values for the simulator.
|
|
292
|
+
*/
|
|
293
|
+
const DEFAULT_CONFIG = {
|
|
294
|
+
SUBSCRIPTION_TTL_MS: 1e4,
|
|
295
|
+
CLEANUP_INTERVAL_MS: 5e3,
|
|
296
|
+
BROADCAST_INTERVAL_MS: 100,
|
|
297
|
+
DEFAULT_PORT: 10023,
|
|
298
|
+
DEFAULT_HOST: "0.0.0.0",
|
|
299
|
+
DEFAULT_NAME: "osc-server",
|
|
300
|
+
DEFAULT_MODEL: "X32"
|
|
301
|
+
};
|
|
302
|
+
/**
|
|
303
|
+
* Merges user-provided configuration with defaults.
|
|
304
|
+
* @param partial - Partial configuration to merge.
|
|
305
|
+
* @returns Complete configuration with defaults applied.
|
|
306
|
+
*/
|
|
307
|
+
function mergeConfig(partial) {
|
|
308
|
+
return {
|
|
309
|
+
...DEFAULT_CONFIG,
|
|
310
|
+
...partial
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
|
|
191
314
|
//#endregion
|
|
192
315
|
//#region src/domain/entities/SubscriptionManager.ts
|
|
193
316
|
/**
|
|
194
317
|
* Manages OSC client subscriptions and their lifecycle.
|
|
195
318
|
*/
|
|
196
319
|
var SubscriptionManager = class {
|
|
197
|
-
logger;
|
|
198
320
|
subscribers = [];
|
|
199
|
-
constructor(logger) {
|
|
321
|
+
constructor(logger, subscriptionTtlMs = DEFAULT_CONFIG.SUBSCRIPTION_TTL_MS) {
|
|
200
322
|
this.logger = logger;
|
|
323
|
+
this.subscriptionTtlMs = subscriptionTtlMs;
|
|
201
324
|
}
|
|
202
325
|
/**
|
|
203
326
|
* Cleans up expired subscriptions.
|
|
@@ -235,7 +358,7 @@ var SubscriptionManager = class {
|
|
|
235
358
|
*/
|
|
236
359
|
addPathSubscriber(rinfo, path) {
|
|
237
360
|
const key = `${rinfo.address}:${rinfo.port}:${path}`;
|
|
238
|
-
const expires = Date.now() +
|
|
361
|
+
const expires = Date.now() + this.subscriptionTtlMs;
|
|
239
362
|
const existing = this.subscribers.find((s) => s.type === "path" && `${s.address}:${s.port}:${s.path}` === key);
|
|
240
363
|
if (existing) {
|
|
241
364
|
existing.expires = expires;
|
|
@@ -268,7 +391,7 @@ var SubscriptionManager = class {
|
|
|
268
391
|
* @param args - Command arguments.
|
|
269
392
|
*/
|
|
270
393
|
addBatchSubscriber(rinfo, alias, paths, start, count, factor, args) {
|
|
271
|
-
const expires = Date.now() +
|
|
394
|
+
const expires = Date.now() + this.subscriptionTtlMs;
|
|
272
395
|
this.subscribers = this.subscribers.filter((s) => !(s.type === "batch" && s.alias === alias && s.address === rinfo.address));
|
|
273
396
|
this.subscribers.push({
|
|
274
397
|
type: "batch",
|
|
@@ -300,7 +423,7 @@ var SubscriptionManager = class {
|
|
|
300
423
|
* @param factor - Frequency factor.
|
|
301
424
|
*/
|
|
302
425
|
addFormatSubscriber(rinfo, alias, pattern, start, count, factor) {
|
|
303
|
-
const expires = Date.now() +
|
|
426
|
+
const expires = Date.now() + this.subscriptionTtlMs;
|
|
304
427
|
this.subscribers = this.subscribers.filter((s) => !(s.type === "format" && s.alias === alias && s.address === rinfo.address));
|
|
305
428
|
this.subscribers.push({
|
|
306
429
|
type: "format",
|
|
@@ -326,7 +449,7 @@ var SubscriptionManager = class {
|
|
|
326
449
|
* @param meterPath - Target meter path.
|
|
327
450
|
*/
|
|
328
451
|
addMeterSubscriber(rinfo, meterPath) {
|
|
329
|
-
const expires = Date.now() +
|
|
452
|
+
const expires = Date.now() + this.subscriptionTtlMs;
|
|
330
453
|
const existing = this.subscribers.find((s) => s.type === "meter" && s.meterPath === meterPath && s.address === rinfo.address);
|
|
331
454
|
this.subscribers = this.subscribers.filter((s) => !(s.type === "meter" && s.meterPath === meterPath && s.address === rinfo.address));
|
|
332
455
|
this.subscribers.push({
|
|
@@ -391,8 +514,9 @@ var NodeDiscoveryStrategy = class {
|
|
|
391
514
|
//#endregion
|
|
392
515
|
//#region src/domain/services/strategies/StaticResponseStrategy.ts
|
|
393
516
|
/**
|
|
394
|
-
* Handles discovery and static information queries.
|
|
395
|
-
* e.g., /status, /xinfo
|
|
517
|
+
* Handles discovery and static information queries (GET only).
|
|
518
|
+
* e.g., /status, /xinfo
|
|
519
|
+
* Note: Only handles queries without arguments. SET commands pass through to StateAccessStrategy.
|
|
396
520
|
*/
|
|
397
521
|
var StaticResponseStrategy = class {
|
|
398
522
|
constructor(serverIp, serverName, serverModel, staticResponseService) {
|
|
@@ -401,7 +525,8 @@ var StaticResponseStrategy = class {
|
|
|
401
525
|
this.serverModel = serverModel;
|
|
402
526
|
this.staticResponseService = staticResponseService;
|
|
403
527
|
}
|
|
404
|
-
canHandle(address) {
|
|
528
|
+
canHandle(address, args) {
|
|
529
|
+
if (args && args.length > 0) return false;
|
|
405
530
|
return !!this.staticResponseService.getResponse(address);
|
|
406
531
|
}
|
|
407
532
|
execute(msg, _source) {
|
|
@@ -572,6 +697,7 @@ var MeterStrategy = class {
|
|
|
572
697
|
* LOGIC:
|
|
573
698
|
* - If no arguments: Treats as a QUERY (GET) and returns the current value.
|
|
574
699
|
* - If arguments provided: Treats as an UPDATE (SET) and stores the new value.
|
|
700
|
+
* - Unknown addresses are also stored in permissive mode for compatibility.
|
|
575
701
|
*/
|
|
576
702
|
var StateAccessStrategy = class {
|
|
577
703
|
/**
|
|
@@ -579,45 +705,687 @@ var StateAccessStrategy = class {
|
|
|
579
705
|
* @param state - Current mixer state.
|
|
580
706
|
* @param logger - Logger instance.
|
|
581
707
|
* @param schemaRegistry - Registry to validate addresses.
|
|
708
|
+
* @param permissive - If true, store unknown addresses too (default: true).
|
|
582
709
|
*/
|
|
583
|
-
constructor(state, logger, schemaRegistry) {
|
|
710
|
+
constructor(state, logger, schemaRegistry, permissive = true) {
|
|
584
711
|
this.state = state;
|
|
585
712
|
this.logger = logger;
|
|
586
713
|
this.schemaRegistry = schemaRegistry;
|
|
714
|
+
this.permissive = permissive;
|
|
587
715
|
}
|
|
588
716
|
/** @inheritdoc */
|
|
589
717
|
canHandle(address) {
|
|
590
|
-
|
|
718
|
+
if (this.schemaRegistry.has(address)) return true;
|
|
719
|
+
return this.permissive && address.startsWith("/");
|
|
591
720
|
}
|
|
592
721
|
/** @inheritdoc */
|
|
593
722
|
execute(msg, _source) {
|
|
594
723
|
const addr = msg.address;
|
|
595
724
|
const node = this.schemaRegistry.getNode(addr);
|
|
725
|
+
const isKnown = !!node;
|
|
596
726
|
if (msg.args.length === 0) {
|
|
597
727
|
const val$1 = this.state.get(addr);
|
|
598
728
|
if (val$1 !== void 0) return [{
|
|
599
729
|
address: addr,
|
|
600
730
|
args: [val$1]
|
|
601
731
|
}];
|
|
732
|
+
if (!isKnown) this.logger.debug(LogCategory.STATE, `[GET] Unknown address queried: ${addr}`);
|
|
602
733
|
return [];
|
|
603
734
|
}
|
|
604
735
|
const val = msg.args[0];
|
|
605
|
-
if (
|
|
736
|
+
if (isKnown) {
|
|
606
737
|
if (!node.validate(val)) {
|
|
607
738
|
this.logger.warn(LogCategory.DISPATCH, `[TYPE ERR] ${addr} expected ${node.type}, got ${typeof val}`);
|
|
608
739
|
return [];
|
|
609
740
|
}
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
741
|
+
} else this.logger.warn(LogCategory.STATE, `[UNKNOWN] Storing unknown address: ${addr} = ${val}`);
|
|
742
|
+
this.state.set(addr, val);
|
|
743
|
+
this.logger.debug(LogCategory.STATE, `[SET] ${addr} -> ${val}`);
|
|
744
|
+
if (addr.startsWith("/config/mute/")) {
|
|
745
|
+
const groupIdx = parseInt(addr.split("/").pop(), 10);
|
|
746
|
+
if (!isNaN(groupIdx)) this.state.handleMuteGroupChange(groupIdx, val);
|
|
747
|
+
}
|
|
748
|
+
if (addr === "/-action/undopt" && val === 1) {
|
|
749
|
+
const timeStr = (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", { hour12: false });
|
|
750
|
+
this.state.set("/-undo/time", timeStr);
|
|
751
|
+
this.logger.debug(LogCategory.STATE, `[UNDO] Checkpoint created at ${timeStr}`);
|
|
616
752
|
}
|
|
617
753
|
return [];
|
|
618
754
|
}
|
|
619
755
|
};
|
|
620
756
|
|
|
757
|
+
//#endregion
|
|
758
|
+
//#region src/domain/services/strategies/ShowDumpStrategy.ts
|
|
759
|
+
/**
|
|
760
|
+
* Handles the /showdump command which requests a full state dump.
|
|
761
|
+
* Used by X32-Edit during synchronization to retrieve all console parameters.
|
|
762
|
+
*/
|
|
763
|
+
var ShowDumpStrategy = class {
|
|
764
|
+
constructor(state, logger) {
|
|
765
|
+
this.state = state;
|
|
766
|
+
this.logger = logger;
|
|
767
|
+
}
|
|
768
|
+
/** @inheritdoc */
|
|
769
|
+
canHandle(address) {
|
|
770
|
+
return address === "/showdump";
|
|
771
|
+
}
|
|
772
|
+
/** @inheritdoc */
|
|
773
|
+
execute(_msg, _source) {
|
|
774
|
+
this.logger.debug(LogCategory.DISPATCH, "[SHOWDUMP] Full state dump requested");
|
|
775
|
+
const replies = [];
|
|
776
|
+
const allState = this.state.getAll();
|
|
777
|
+
for (const [address, value] of Object.entries(allState)) replies.push({
|
|
778
|
+
address,
|
|
779
|
+
args: [value]
|
|
780
|
+
});
|
|
781
|
+
this.logger.debug(LogCategory.DISPATCH, `[SHOWDUMP] Sending ${replies.length} state entries`);
|
|
782
|
+
return replies;
|
|
783
|
+
}
|
|
784
|
+
};
|
|
785
|
+
|
|
786
|
+
//#endregion
|
|
787
|
+
//#region src/domain/services/strategies/SceneDataStrategy.ts
|
|
788
|
+
/**
|
|
789
|
+
* Maps scene file format (batch values) to individual OSC addresses.
|
|
790
|
+
* The X32 scene format sends multiple values for a parent address.
|
|
791
|
+
* Example: /ch/01/mix ON -0.2 ON -100 OFF -oo
|
|
792
|
+
* Maps to: /ch/01/mix/on, /ch/01/mix/fader, /ch/01/mix/st, /ch/01/mix/pan, /ch/01/mix/mono, /ch/01/mix/mlevel
|
|
793
|
+
*/
|
|
794
|
+
const SCENE_MAPPINGS = {
|
|
795
|
+
"headamp": ["gain", "phantom"],
|
|
796
|
+
"config": [
|
|
797
|
+
"name",
|
|
798
|
+
"icon",
|
|
799
|
+
"color",
|
|
800
|
+
"source"
|
|
801
|
+
],
|
|
802
|
+
"delay": ["on", "time"],
|
|
803
|
+
"preamp": [
|
|
804
|
+
"trim",
|
|
805
|
+
"invert",
|
|
806
|
+
"hpon",
|
|
807
|
+
"hpslope",
|
|
808
|
+
"hpf"
|
|
809
|
+
],
|
|
810
|
+
"gate": [
|
|
811
|
+
"on",
|
|
812
|
+
"mode",
|
|
813
|
+
"thr",
|
|
814
|
+
"range",
|
|
815
|
+
"attack",
|
|
816
|
+
"hold",
|
|
817
|
+
"release",
|
|
818
|
+
"keysrc"
|
|
819
|
+
],
|
|
820
|
+
"gate/filter": [
|
|
821
|
+
"on",
|
|
822
|
+
"type",
|
|
823
|
+
"f"
|
|
824
|
+
],
|
|
825
|
+
"dyn": [
|
|
826
|
+
"on",
|
|
827
|
+
"mode",
|
|
828
|
+
"det",
|
|
829
|
+
"env",
|
|
830
|
+
"thr",
|
|
831
|
+
"ratio",
|
|
832
|
+
"knee",
|
|
833
|
+
"mgain",
|
|
834
|
+
"attack",
|
|
835
|
+
"hold",
|
|
836
|
+
"release",
|
|
837
|
+
"pos",
|
|
838
|
+
"keysrc",
|
|
839
|
+
"mix",
|
|
840
|
+
"auto"
|
|
841
|
+
],
|
|
842
|
+
"dyn/filter": [
|
|
843
|
+
"on",
|
|
844
|
+
"type",
|
|
845
|
+
"f"
|
|
846
|
+
],
|
|
847
|
+
"insert": [
|
|
848
|
+
"on",
|
|
849
|
+
"pos",
|
|
850
|
+
"sel"
|
|
851
|
+
],
|
|
852
|
+
"eq": ["on"],
|
|
853
|
+
"eq/1": [
|
|
854
|
+
"type",
|
|
855
|
+
"f",
|
|
856
|
+
"g",
|
|
857
|
+
"q"
|
|
858
|
+
],
|
|
859
|
+
"eq/2": [
|
|
860
|
+
"type",
|
|
861
|
+
"f",
|
|
862
|
+
"g",
|
|
863
|
+
"q"
|
|
864
|
+
],
|
|
865
|
+
"eq/3": [
|
|
866
|
+
"type",
|
|
867
|
+
"f",
|
|
868
|
+
"g",
|
|
869
|
+
"q"
|
|
870
|
+
],
|
|
871
|
+
"eq/4": [
|
|
872
|
+
"type",
|
|
873
|
+
"f",
|
|
874
|
+
"g",
|
|
875
|
+
"q"
|
|
876
|
+
],
|
|
877
|
+
"eq/5": [
|
|
878
|
+
"type",
|
|
879
|
+
"f",
|
|
880
|
+
"g",
|
|
881
|
+
"q"
|
|
882
|
+
],
|
|
883
|
+
"eq/6": [
|
|
884
|
+
"type",
|
|
885
|
+
"f",
|
|
886
|
+
"g",
|
|
887
|
+
"q"
|
|
888
|
+
],
|
|
889
|
+
"mix": [
|
|
890
|
+
"on",
|
|
891
|
+
"fader",
|
|
892
|
+
"st",
|
|
893
|
+
"pan",
|
|
894
|
+
"mono",
|
|
895
|
+
"mlevel"
|
|
896
|
+
],
|
|
897
|
+
"mix/01": [
|
|
898
|
+
"on",
|
|
899
|
+
"level",
|
|
900
|
+
"pan",
|
|
901
|
+
"type",
|
|
902
|
+
"panFollow"
|
|
903
|
+
],
|
|
904
|
+
"mix/02": ["on", "level"],
|
|
905
|
+
"mix/03": [
|
|
906
|
+
"on",
|
|
907
|
+
"level",
|
|
908
|
+
"pan",
|
|
909
|
+
"type",
|
|
910
|
+
"panFollow"
|
|
911
|
+
],
|
|
912
|
+
"mix/04": ["on", "level"],
|
|
913
|
+
"mix/05": [
|
|
914
|
+
"on",
|
|
915
|
+
"level",
|
|
916
|
+
"pan",
|
|
917
|
+
"type",
|
|
918
|
+
"panFollow"
|
|
919
|
+
],
|
|
920
|
+
"mix/06": ["on", "level"],
|
|
921
|
+
"mix/07": [
|
|
922
|
+
"on",
|
|
923
|
+
"level",
|
|
924
|
+
"pan",
|
|
925
|
+
"type",
|
|
926
|
+
"panFollow"
|
|
927
|
+
],
|
|
928
|
+
"mix/08": ["on", "level"],
|
|
929
|
+
"mix/09": [
|
|
930
|
+
"on",
|
|
931
|
+
"level",
|
|
932
|
+
"pan",
|
|
933
|
+
"type",
|
|
934
|
+
"panFollow"
|
|
935
|
+
],
|
|
936
|
+
"mix/10": ["on", "level"],
|
|
937
|
+
"mix/11": [
|
|
938
|
+
"on",
|
|
939
|
+
"level",
|
|
940
|
+
"pan",
|
|
941
|
+
"type",
|
|
942
|
+
"panFollow"
|
|
943
|
+
],
|
|
944
|
+
"mix/12": ["on", "level"],
|
|
945
|
+
"mix/13": [
|
|
946
|
+
"on",
|
|
947
|
+
"level",
|
|
948
|
+
"pan",
|
|
949
|
+
"type",
|
|
950
|
+
"panFollow"
|
|
951
|
+
],
|
|
952
|
+
"mix/14": ["on", "level"],
|
|
953
|
+
"mix/15": [
|
|
954
|
+
"on",
|
|
955
|
+
"level",
|
|
956
|
+
"pan",
|
|
957
|
+
"type",
|
|
958
|
+
"panFollow"
|
|
959
|
+
],
|
|
960
|
+
"mix/16": ["on", "level"],
|
|
961
|
+
"grp": ["dca", "mute"],
|
|
962
|
+
"automix": ["group", "weight"],
|
|
963
|
+
"chlink": [
|
|
964
|
+
"1-2",
|
|
965
|
+
"3-4",
|
|
966
|
+
"5-6",
|
|
967
|
+
"7-8",
|
|
968
|
+
"9-10",
|
|
969
|
+
"11-12",
|
|
970
|
+
"13-14",
|
|
971
|
+
"15-16",
|
|
972
|
+
"17-18",
|
|
973
|
+
"19-20",
|
|
974
|
+
"21-22",
|
|
975
|
+
"23-24",
|
|
976
|
+
"25-26",
|
|
977
|
+
"27-28",
|
|
978
|
+
"29-30",
|
|
979
|
+
"31-32"
|
|
980
|
+
],
|
|
981
|
+
"auxlink": [
|
|
982
|
+
"1-2",
|
|
983
|
+
"3-4",
|
|
984
|
+
"5-6",
|
|
985
|
+
"7-8"
|
|
986
|
+
],
|
|
987
|
+
"fxlink": [
|
|
988
|
+
"1-2",
|
|
989
|
+
"3-4",
|
|
990
|
+
"5-6",
|
|
991
|
+
"7-8"
|
|
992
|
+
],
|
|
993
|
+
"buslink": [
|
|
994
|
+
"1-2",
|
|
995
|
+
"3-4",
|
|
996
|
+
"5-6",
|
|
997
|
+
"7-8",
|
|
998
|
+
"9-10",
|
|
999
|
+
"11-12",
|
|
1000
|
+
"13-14",
|
|
1001
|
+
"15-16"
|
|
1002
|
+
],
|
|
1003
|
+
"mtxlink": [
|
|
1004
|
+
"1-2",
|
|
1005
|
+
"3-4",
|
|
1006
|
+
"5-6"
|
|
1007
|
+
],
|
|
1008
|
+
"mute": [
|
|
1009
|
+
"1",
|
|
1010
|
+
"2",
|
|
1011
|
+
"3",
|
|
1012
|
+
"4",
|
|
1013
|
+
"5",
|
|
1014
|
+
"6"
|
|
1015
|
+
],
|
|
1016
|
+
"linkcfg": [
|
|
1017
|
+
"hadly",
|
|
1018
|
+
"eq",
|
|
1019
|
+
"dyn",
|
|
1020
|
+
"fdrmute"
|
|
1021
|
+
],
|
|
1022
|
+
"mono": ["mode", "link"],
|
|
1023
|
+
"solo": [
|
|
1024
|
+
"level",
|
|
1025
|
+
"source",
|
|
1026
|
+
"sourcetrim",
|
|
1027
|
+
"chmode",
|
|
1028
|
+
"busmode",
|
|
1029
|
+
"dcamode",
|
|
1030
|
+
"exclusive",
|
|
1031
|
+
"followsel",
|
|
1032
|
+
"followsolo",
|
|
1033
|
+
"dimatt",
|
|
1034
|
+
"dim",
|
|
1035
|
+
"mono",
|
|
1036
|
+
"delay",
|
|
1037
|
+
"delaytime",
|
|
1038
|
+
"masterctrl",
|
|
1039
|
+
"mute",
|
|
1040
|
+
"dimmute"
|
|
1041
|
+
],
|
|
1042
|
+
"talk": ["enable", "source"],
|
|
1043
|
+
"talk/A": [
|
|
1044
|
+
"level",
|
|
1045
|
+
"dim",
|
|
1046
|
+
"latch",
|
|
1047
|
+
"destmap"
|
|
1048
|
+
],
|
|
1049
|
+
"talk/B": [
|
|
1050
|
+
"level",
|
|
1051
|
+
"dim",
|
|
1052
|
+
"latch",
|
|
1053
|
+
"destmap"
|
|
1054
|
+
],
|
|
1055
|
+
"osc": [
|
|
1056
|
+
"level",
|
|
1057
|
+
"f1",
|
|
1058
|
+
"f2",
|
|
1059
|
+
"type",
|
|
1060
|
+
"dest"
|
|
1061
|
+
],
|
|
1062
|
+
"tape": [
|
|
1063
|
+
"gainL",
|
|
1064
|
+
"gainR",
|
|
1065
|
+
"autoplay"
|
|
1066
|
+
],
|
|
1067
|
+
"amixenable": ["X", "Y"],
|
|
1068
|
+
"dp48": [
|
|
1069
|
+
"broadcast",
|
|
1070
|
+
"bundles",
|
|
1071
|
+
"assign"
|
|
1072
|
+
],
|
|
1073
|
+
"dp48/assign": Array.from({ length: 48 }, (_, i) => String(i + 1)),
|
|
1074
|
+
"dp48/link": Array.from({ length: 24 }, (_, i) => String(i + 1)),
|
|
1075
|
+
"dp48/grpname": Array.from({ length: 12 }, (_, i) => String(i + 1)),
|
|
1076
|
+
"userrout/out": Array.from({ length: 48 }, (_, i) => String(i + 1)),
|
|
1077
|
+
"userrout/in": Array.from({ length: 32 }, (_, i) => String(i + 1)),
|
|
1078
|
+
"routing": ["routswitch"],
|
|
1079
|
+
"routing/IN": [
|
|
1080
|
+
"1-8",
|
|
1081
|
+
"9-16",
|
|
1082
|
+
"17-24",
|
|
1083
|
+
"25-32",
|
|
1084
|
+
"AUX"
|
|
1085
|
+
],
|
|
1086
|
+
"routing/AES50A": [
|
|
1087
|
+
"1-8",
|
|
1088
|
+
"9-16",
|
|
1089
|
+
"17-24",
|
|
1090
|
+
"25-32",
|
|
1091
|
+
"33-40",
|
|
1092
|
+
"41-48"
|
|
1093
|
+
],
|
|
1094
|
+
"routing/AES50B": [
|
|
1095
|
+
"1-8",
|
|
1096
|
+
"9-16",
|
|
1097
|
+
"17-24",
|
|
1098
|
+
"25-32",
|
|
1099
|
+
"33-40",
|
|
1100
|
+
"41-48"
|
|
1101
|
+
],
|
|
1102
|
+
"routing/CARD": [
|
|
1103
|
+
"1-8",
|
|
1104
|
+
"9-16",
|
|
1105
|
+
"17-24",
|
|
1106
|
+
"25-32"
|
|
1107
|
+
],
|
|
1108
|
+
"routing/OUT": [
|
|
1109
|
+
"1-4",
|
|
1110
|
+
"5-8",
|
|
1111
|
+
"9-12",
|
|
1112
|
+
"13-16"
|
|
1113
|
+
],
|
|
1114
|
+
"routing/PLAY": [
|
|
1115
|
+
"1-8",
|
|
1116
|
+
"9-16",
|
|
1117
|
+
"17-24",
|
|
1118
|
+
"25-32",
|
|
1119
|
+
"AUX"
|
|
1120
|
+
],
|
|
1121
|
+
"userctrl/A": ["color"],
|
|
1122
|
+
"userctrl/A/enc": [
|
|
1123
|
+
"1",
|
|
1124
|
+
"2",
|
|
1125
|
+
"3",
|
|
1126
|
+
"4"
|
|
1127
|
+
],
|
|
1128
|
+
"userctrl/A/btn": [
|
|
1129
|
+
"1",
|
|
1130
|
+
"2",
|
|
1131
|
+
"3",
|
|
1132
|
+
"4",
|
|
1133
|
+
"5",
|
|
1134
|
+
"6",
|
|
1135
|
+
"7",
|
|
1136
|
+
"8"
|
|
1137
|
+
],
|
|
1138
|
+
"userctrl/B": ["color"],
|
|
1139
|
+
"userctrl/B/enc": [
|
|
1140
|
+
"1",
|
|
1141
|
+
"2",
|
|
1142
|
+
"3",
|
|
1143
|
+
"4"
|
|
1144
|
+
],
|
|
1145
|
+
"userctrl/B/btn": [
|
|
1146
|
+
"1",
|
|
1147
|
+
"2",
|
|
1148
|
+
"3",
|
|
1149
|
+
"4",
|
|
1150
|
+
"5",
|
|
1151
|
+
"6",
|
|
1152
|
+
"7",
|
|
1153
|
+
"8"
|
|
1154
|
+
],
|
|
1155
|
+
"userctrl/C": ["color"],
|
|
1156
|
+
"userctrl/C/enc": [
|
|
1157
|
+
"1",
|
|
1158
|
+
"2",
|
|
1159
|
+
"3",
|
|
1160
|
+
"4"
|
|
1161
|
+
],
|
|
1162
|
+
"userctrl/C/btn": [
|
|
1163
|
+
"1",
|
|
1164
|
+
"2",
|
|
1165
|
+
"3",
|
|
1166
|
+
"4",
|
|
1167
|
+
"5",
|
|
1168
|
+
"6",
|
|
1169
|
+
"7",
|
|
1170
|
+
"8",
|
|
1171
|
+
"9",
|
|
1172
|
+
"10",
|
|
1173
|
+
"11",
|
|
1174
|
+
"12"
|
|
1175
|
+
],
|
|
1176
|
+
"dca": ["on", "fader"],
|
|
1177
|
+
"bus/config": [
|
|
1178
|
+
"name",
|
|
1179
|
+
"icon",
|
|
1180
|
+
"color"
|
|
1181
|
+
],
|
|
1182
|
+
"bus/mix": [
|
|
1183
|
+
"on",
|
|
1184
|
+
"fader",
|
|
1185
|
+
"st",
|
|
1186
|
+
"pan",
|
|
1187
|
+
"mono",
|
|
1188
|
+
"mlevel"
|
|
1189
|
+
],
|
|
1190
|
+
"main/st/config": [
|
|
1191
|
+
"name",
|
|
1192
|
+
"icon",
|
|
1193
|
+
"color"
|
|
1194
|
+
],
|
|
1195
|
+
"main/st/mix": [
|
|
1196
|
+
"on",
|
|
1197
|
+
"fader",
|
|
1198
|
+
"st",
|
|
1199
|
+
"pan"
|
|
1200
|
+
],
|
|
1201
|
+
"main/m/config": [
|
|
1202
|
+
"name",
|
|
1203
|
+
"icon",
|
|
1204
|
+
"color"
|
|
1205
|
+
],
|
|
1206
|
+
"main/m/mix": ["on", "fader"],
|
|
1207
|
+
"fx/source": ["inL", "inR"],
|
|
1208
|
+
"fx": ["type"],
|
|
1209
|
+
"fx/par": Array.from({ length: 64 }, (_, i) => String(i + 1)),
|
|
1210
|
+
"outputs/main": [
|
|
1211
|
+
"src",
|
|
1212
|
+
"pos",
|
|
1213
|
+
"invert"
|
|
1214
|
+
],
|
|
1215
|
+
"outputs/main/delay": ["on", "time"],
|
|
1216
|
+
"outputs/aux": [
|
|
1217
|
+
"src",
|
|
1218
|
+
"pos",
|
|
1219
|
+
"invert"
|
|
1220
|
+
],
|
|
1221
|
+
"outputs/p16": [
|
|
1222
|
+
"src",
|
|
1223
|
+
"pos",
|
|
1224
|
+
"invert"
|
|
1225
|
+
],
|
|
1226
|
+
"outputs/p16/iQ": [
|
|
1227
|
+
"model",
|
|
1228
|
+
"eqset",
|
|
1229
|
+
"sound"
|
|
1230
|
+
],
|
|
1231
|
+
"outputs/aes": [
|
|
1232
|
+
"src",
|
|
1233
|
+
"pos",
|
|
1234
|
+
"invert"
|
|
1235
|
+
],
|
|
1236
|
+
"outputs/rec": [
|
|
1237
|
+
"src",
|
|
1238
|
+
"pos",
|
|
1239
|
+
"invert"
|
|
1240
|
+
]
|
|
1241
|
+
};
|
|
1242
|
+
/**
|
|
1243
|
+
* Converts scene file values to proper OSC types.
|
|
1244
|
+
*/
|
|
1245
|
+
function parseSceneValue(val) {
|
|
1246
|
+
if (val === "ON") return 1;
|
|
1247
|
+
if (val === "OFF") return 0;
|
|
1248
|
+
if (val === "-oo" || val === "-inf") return -90;
|
|
1249
|
+
if (val === "+oo" || val === "+inf") return 90;
|
|
1250
|
+
if (val.startsWith("%")) return parseInt(val.slice(1), 2);
|
|
1251
|
+
const freqMatch = val.match(/^(\d+)k(\d+)$/);
|
|
1252
|
+
if (freqMatch) return parseFloat(freqMatch[1] + "." + freqMatch[2]) * 1e3;
|
|
1253
|
+
if (val.startsWith("+") || val.startsWith("-")) {
|
|
1254
|
+
const num$1 = parseFloat(val);
|
|
1255
|
+
if (!isNaN(num$1)) return num$1;
|
|
1256
|
+
}
|
|
1257
|
+
const num = parseFloat(val);
|
|
1258
|
+
if (!isNaN(num)) return num;
|
|
1259
|
+
const int = parseInt(val, 10);
|
|
1260
|
+
if (!isNaN(int)) return int;
|
|
1261
|
+
return val.replace(/^"|"$/g, "");
|
|
1262
|
+
}
|
|
1263
|
+
/**
|
|
1264
|
+
* Strategy to handle X32 scene file format (batch multi-value commands).
|
|
1265
|
+
* Expands parent addresses with multiple values into individual parameter sets.
|
|
1266
|
+
*/
|
|
1267
|
+
var SceneDataStrategy = class {
|
|
1268
|
+
constructor(state, logger) {
|
|
1269
|
+
this.state = state;
|
|
1270
|
+
this.logger = logger;
|
|
1271
|
+
}
|
|
1272
|
+
canHandle(address, args) {
|
|
1273
|
+
if (!args || args.length === 0) return false;
|
|
1274
|
+
if (args.length === 1) {
|
|
1275
|
+
if (address.match(/^\/fx\/\d$/)) return true;
|
|
1276
|
+
return false;
|
|
1277
|
+
}
|
|
1278
|
+
if (args.length === 2) {
|
|
1279
|
+
if (address.match(/^\/dca\/\d$/)) return true;
|
|
1280
|
+
}
|
|
1281
|
+
return this.findMapping(address) !== null;
|
|
1282
|
+
}
|
|
1283
|
+
execute(msg, _source) {
|
|
1284
|
+
const { address, args } = msg;
|
|
1285
|
+
const mapping = this.findMapping(address);
|
|
1286
|
+
if (!mapping) return [];
|
|
1287
|
+
const { basePath, fields } = mapping;
|
|
1288
|
+
this.logger.debug(LogCategory.STATE, `[SCENE] Expanding batch command`, {
|
|
1289
|
+
address,
|
|
1290
|
+
argCount: args.length,
|
|
1291
|
+
fields: fields.length
|
|
1292
|
+
});
|
|
1293
|
+
for (let i = 0; i < args.length && i < fields.length; i++) {
|
|
1294
|
+
const fieldName = fields[i];
|
|
1295
|
+
const rawValue = args[i];
|
|
1296
|
+
const value = typeof rawValue === "string" ? parseSceneValue(rawValue) : rawValue;
|
|
1297
|
+
const fullPath = `${basePath}/${fieldName}`;
|
|
1298
|
+
this.state.set(fullPath, value);
|
|
1299
|
+
this.logger.debug(LogCategory.STATE, `[SCENE] Set ${fullPath} = ${value}`);
|
|
1300
|
+
}
|
|
1301
|
+
return [];
|
|
1302
|
+
}
|
|
1303
|
+
findMapping(address) {
|
|
1304
|
+
if (address.match(/^\/headamp\/\d{3}$/) && SCENE_MAPPINGS["headamp"]) return {
|
|
1305
|
+
basePath: address,
|
|
1306
|
+
fields: SCENE_MAPPINGS["headamp"]
|
|
1307
|
+
};
|
|
1308
|
+
if (address.match(/^\/fx\/\d\/source$/) && SCENE_MAPPINGS["fx/source"]) return {
|
|
1309
|
+
basePath: address,
|
|
1310
|
+
fields: SCENE_MAPPINGS["fx/source"]
|
|
1311
|
+
};
|
|
1312
|
+
if (address.match(/^\/fx\/\d\/par$/) && SCENE_MAPPINGS["fx/par"]) return {
|
|
1313
|
+
basePath: address,
|
|
1314
|
+
fields: SCENE_MAPPINGS["fx/par"]
|
|
1315
|
+
};
|
|
1316
|
+
if (address.match(/^\/fx\/\d$/) && SCENE_MAPPINGS["fx"]) return {
|
|
1317
|
+
basePath: address,
|
|
1318
|
+
fields: SCENE_MAPPINGS["fx"]
|
|
1319
|
+
};
|
|
1320
|
+
if (address.match(/^\/dca\/\d$/) && SCENE_MAPPINGS["dca"]) return {
|
|
1321
|
+
basePath: address,
|
|
1322
|
+
fields: SCENE_MAPPINGS["dca"]
|
|
1323
|
+
};
|
|
1324
|
+
if (address.match(/^\/dca\/\d\/config$/)) return {
|
|
1325
|
+
basePath: address,
|
|
1326
|
+
fields: [
|
|
1327
|
+
"name",
|
|
1328
|
+
"icon",
|
|
1329
|
+
"color"
|
|
1330
|
+
]
|
|
1331
|
+
};
|
|
1332
|
+
if (address.match(/^\/outputs\/main\/\d{2}\/delay$/) && SCENE_MAPPINGS["outputs/main/delay"]) return {
|
|
1333
|
+
basePath: address,
|
|
1334
|
+
fields: SCENE_MAPPINGS["outputs/main/delay"]
|
|
1335
|
+
};
|
|
1336
|
+
if (address.match(/^\/outputs\/p16\/\d{2}\/iQ$/) && SCENE_MAPPINGS["outputs/p16/iQ"]) return {
|
|
1337
|
+
basePath: address,
|
|
1338
|
+
fields: SCENE_MAPPINGS["outputs/p16/iQ"]
|
|
1339
|
+
};
|
|
1340
|
+
if (address.match(/^\/outputs\/main\/\d{2}$/) && SCENE_MAPPINGS["outputs/main"]) return {
|
|
1341
|
+
basePath: address,
|
|
1342
|
+
fields: SCENE_MAPPINGS["outputs/main"]
|
|
1343
|
+
};
|
|
1344
|
+
if (address.match(/^\/outputs\/aux\/\d{2}$/) && SCENE_MAPPINGS["outputs/aux"]) return {
|
|
1345
|
+
basePath: address,
|
|
1346
|
+
fields: SCENE_MAPPINGS["outputs/aux"]
|
|
1347
|
+
};
|
|
1348
|
+
if (address.match(/^\/outputs\/p16\/\d{2}$/) && SCENE_MAPPINGS["outputs/p16"]) return {
|
|
1349
|
+
basePath: address,
|
|
1350
|
+
fields: SCENE_MAPPINGS["outputs/p16"]
|
|
1351
|
+
};
|
|
1352
|
+
if (address.match(/^\/outputs\/aes\/\d{2}$/) && SCENE_MAPPINGS["outputs/aes"]) return {
|
|
1353
|
+
basePath: address,
|
|
1354
|
+
fields: SCENE_MAPPINGS["outputs/aes"]
|
|
1355
|
+
};
|
|
1356
|
+
if (address.match(/^\/outputs\/rec\/\d{2}$/) && SCENE_MAPPINGS["outputs/rec"]) return {
|
|
1357
|
+
basePath: address,
|
|
1358
|
+
fields: SCENE_MAPPINGS["outputs/rec"]
|
|
1359
|
+
};
|
|
1360
|
+
if (address.startsWith("/config/")) {
|
|
1361
|
+
const suffix = address.replace("/config/", "");
|
|
1362
|
+
if (SCENE_MAPPINGS[suffix]) return {
|
|
1363
|
+
basePath: address,
|
|
1364
|
+
fields: SCENE_MAPPINGS[suffix]
|
|
1365
|
+
};
|
|
1366
|
+
}
|
|
1367
|
+
for (const [pattern, fields] of Object.entries(SCENE_MAPPINGS)) {
|
|
1368
|
+
if (address.endsWith("/" + pattern)) return {
|
|
1369
|
+
basePath: address,
|
|
1370
|
+
fields
|
|
1371
|
+
};
|
|
1372
|
+
if ((/* @__PURE__ */ new RegExp(`/${pattern.replace(/\//g, "/")}$`)).test(address)) return {
|
|
1373
|
+
basePath: address,
|
|
1374
|
+
fields
|
|
1375
|
+
};
|
|
1376
|
+
}
|
|
1377
|
+
const numberedPathMatch = address.match(/^\/\w+\/\d+\/(.+)$/);
|
|
1378
|
+
if (numberedPathMatch) {
|
|
1379
|
+
const suffix = numberedPathMatch[1];
|
|
1380
|
+
if (SCENE_MAPPINGS[suffix]) return {
|
|
1381
|
+
basePath: address,
|
|
1382
|
+
fields: SCENE_MAPPINGS[suffix]
|
|
1383
|
+
};
|
|
1384
|
+
}
|
|
1385
|
+
return null;
|
|
1386
|
+
}
|
|
1387
|
+
};
|
|
1388
|
+
|
|
621
1389
|
//#endregion
|
|
622
1390
|
//#region src/domain/services/OscMessageHandler.ts
|
|
623
1391
|
/**
|
|
@@ -650,8 +1418,10 @@ var OscMessageHandler = class {
|
|
|
650
1418
|
new SubscriptionStrategy(subscriptionManager, state, logger),
|
|
651
1419
|
new BatchStrategy(subscriptionManager, logger),
|
|
652
1420
|
new MeterStrategy(subscriptionManager, state, this.meterService),
|
|
653
|
-
new
|
|
654
|
-
new
|
|
1421
|
+
new ShowDumpStrategy(state, logger),
|
|
1422
|
+
new SceneDataStrategy(state, logger),
|
|
1423
|
+
new StaticResponseStrategy(serverIp, serverName, serverModel, this.staticResponseService),
|
|
1424
|
+
new StateAccessStrategy(state, logger, this.schemaRegistry)
|
|
655
1425
|
];
|
|
656
1426
|
}
|
|
657
1427
|
/**
|
|
@@ -661,19 +1431,41 @@ var OscMessageHandler = class {
|
|
|
661
1431
|
* @returns Array of replies generated by the strategy.
|
|
662
1432
|
*/
|
|
663
1433
|
handle(msg, source) {
|
|
664
|
-
|
|
1434
|
+
let addr = msg.address;
|
|
1435
|
+
let args = msg.args;
|
|
1436
|
+
if (addr === "/" && args.length === 1 && typeof args[0] === "string") {
|
|
1437
|
+
const parts = args[0].trim().match(/(?:[^\s"]+|"[^"]*")+/g) || [];
|
|
1438
|
+
if (parts.length > 0 && parts[0]) {
|
|
1439
|
+
let innerAddr = parts[0];
|
|
1440
|
+
if (!innerAddr.startsWith("/")) innerAddr = "/" + innerAddr;
|
|
1441
|
+
const innerArgs = parts.slice(1).map((arg) => {
|
|
1442
|
+
let val = arg.replace(/^"|"$/g, "");
|
|
1443
|
+
if (/^-?\d+$/.test(val)) return parseInt(val, 10);
|
|
1444
|
+
if (/^-?\d+\.\d+$/.test(val)) return parseFloat(val);
|
|
1445
|
+
return val;
|
|
1446
|
+
});
|
|
1447
|
+
this.logger.debug(LogCategory.DISPATCH, `Unwrapped X32-Edit command: ${innerAddr}`, { innerArgs });
|
|
1448
|
+
return this.handle({
|
|
1449
|
+
address: innerAddr,
|
|
1450
|
+
args: innerArgs
|
|
1451
|
+
}, source);
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
665
1454
|
if (!addr.startsWith("/meters")) this.logger.debug(LogCategory.DISPATCH, `Handling`, {
|
|
666
1455
|
addr,
|
|
667
|
-
args
|
|
1456
|
+
args
|
|
668
1457
|
});
|
|
669
|
-
for (const strategy of this.strategies) if (strategy.canHandle(addr)) {
|
|
670
|
-
const replies = strategy.execute(
|
|
1458
|
+
for (const strategy of this.strategies) if (strategy.canHandle(addr, args)) {
|
|
1459
|
+
const replies = strategy.execute({
|
|
1460
|
+
address: addr,
|
|
1461
|
+
args
|
|
1462
|
+
}, source);
|
|
671
1463
|
if (replies.length > 0) this.logger.debug(LogCategory.DISPATCH, `Strategy ${strategy.constructor.name} replied`, { count: replies.length });
|
|
672
1464
|
return replies;
|
|
673
1465
|
}
|
|
674
1466
|
this.logger.warn(LogCategory.DISPATCH, `Unknown Command`, {
|
|
675
1467
|
addr,
|
|
676
|
-
args
|
|
1468
|
+
args,
|
|
677
1469
|
ip: source.address
|
|
678
1470
|
});
|
|
679
1471
|
return [];
|
|
@@ -787,6 +1579,8 @@ var MeterService = class {
|
|
|
787
1579
|
//#region src/domain/services/StaticResponseService.ts
|
|
788
1580
|
/**
|
|
789
1581
|
* Static OSC responses for X32 Discovery and System status.
|
|
1582
|
+
* These are read-only informational endpoints that return system info.
|
|
1583
|
+
* All other parameters are handled by StateAccessStrategy from the schema.
|
|
790
1584
|
*/
|
|
791
1585
|
const STATIC_RESPONSES_DATA = {
|
|
792
1586
|
"/xinfo": [
|
|
@@ -805,34 +1599,7 @@ const STATIC_RESPONSES_DATA = {
|
|
|
805
1599
|
"active",
|
|
806
1600
|
"{{ip}}",
|
|
807
1601
|
"{{name}}"
|
|
808
|
-
]
|
|
809
|
-
"/-prefs/invertmutes": [0],
|
|
810
|
-
"/-prefs/fine": [0],
|
|
811
|
-
"/-prefs/bright": [50],
|
|
812
|
-
"/-prefs/contrast": [50],
|
|
813
|
-
"/-prefs/led_bright": [50],
|
|
814
|
-
"/-prefs/lcd_bright": [50],
|
|
815
|
-
"/-stat/userpar/1/value": [0],
|
|
816
|
-
"/-stat/userpar/2/value": [0],
|
|
817
|
-
"/-stat/tape/state": [0],
|
|
818
|
-
"/-stat/aes50/A": [0],
|
|
819
|
-
"/-stat/aes50/B": [0],
|
|
820
|
-
"/-stat/solo": [0],
|
|
821
|
-
"/-stat/rtasource": [0],
|
|
822
|
-
"/-urec/errorcode": [0],
|
|
823
|
-
"/-prefs/rta/gain": [0],
|
|
824
|
-
"/-prefs/rta/autogain": [0],
|
|
825
|
-
"/-prefs/hardmute": [0],
|
|
826
|
-
"/-prefs/dcamute": [0],
|
|
827
|
-
"/config/mono/mode": [0],
|
|
828
|
-
"/config/amixenable/X": [0],
|
|
829
|
-
"/config/amixenable/Y": [0],
|
|
830
|
-
"/-show/prepos/current": [0],
|
|
831
|
-
"/-show/showfile/current": [""],
|
|
832
|
-
"/-action/setrtasrc": [0],
|
|
833
|
-
"/-action/playtrack": [0],
|
|
834
|
-
"/-action/goscene": [0],
|
|
835
|
-
"/-action/setscene": [0]
|
|
1602
|
+
]
|
|
836
1603
|
};
|
|
837
1604
|
/**
|
|
838
1605
|
* Service providing static system responses.
|
|
@@ -862,47 +1629,51 @@ function getLocalIp() {
|
|
|
862
1629
|
return "127.0.0.1";
|
|
863
1630
|
}
|
|
864
1631
|
/**
|
|
865
|
-
* The core service that manages the X32 simulation, including networking,
|
|
1632
|
+
* The core service that manages the X32 simulation, including networking,
|
|
866
1633
|
* state management, and OSC message handling.
|
|
867
1634
|
*/
|
|
868
1635
|
var SimulationService = class {
|
|
869
1636
|
subscriptionManager;
|
|
870
1637
|
messageHandler;
|
|
1638
|
+
state;
|
|
871
1639
|
processPacket;
|
|
872
1640
|
broadcastUpdates;
|
|
873
1641
|
manageSessions;
|
|
874
1642
|
meterService;
|
|
875
1643
|
staticResponseService;
|
|
1644
|
+
config;
|
|
876
1645
|
updateInterval = null;
|
|
877
1646
|
cleanupInterval = null;
|
|
878
1647
|
/**
|
|
879
1648
|
* Creates a new SimulationService instance.
|
|
880
1649
|
* @param gateway - The network gateway for OSC communication.
|
|
881
1650
|
* @param logger - The logger service.
|
|
882
|
-
* @param
|
|
1651
|
+
* @param stateRepository - The repository for state persistence.
|
|
883
1652
|
* @param schemaRegistry - The registry for X32 OSC schema.
|
|
884
|
-
* @param port - UDP port to listen on (default
|
|
885
|
-
* @param ip - IP address to bind to (default
|
|
1653
|
+
* @param port - UDP port to listen on (default from config).
|
|
1654
|
+
* @param ip - IP address to bind to (default from config).
|
|
886
1655
|
* @param name - Reported console name.
|
|
887
1656
|
* @param model - Reported console model.
|
|
1657
|
+
* @param configOverrides - Optional configuration overrides.
|
|
888
1658
|
*/
|
|
889
|
-
constructor(gateway, logger,
|
|
1659
|
+
constructor(gateway, logger, stateRepository, schemaRegistry, port = DEFAULT_CONFIG.DEFAULT_PORT, ip = DEFAULT_CONFIG.DEFAULT_HOST, name = DEFAULT_CONFIG.DEFAULT_NAME, model = DEFAULT_CONFIG.DEFAULT_MODEL, configOverrides) {
|
|
890
1660
|
this.gateway = gateway;
|
|
891
1661
|
this.logger = logger;
|
|
892
|
-
this.
|
|
1662
|
+
this.stateRepository = stateRepository;
|
|
893
1663
|
this.schemaRegistry = schemaRegistry;
|
|
894
1664
|
this.port = port;
|
|
895
1665
|
this.ip = ip;
|
|
896
|
-
|
|
897
|
-
this.
|
|
1666
|
+
this.config = mergeConfig(configOverrides);
|
|
1667
|
+
this.state = new X32State(schemaRegistry.getSchema(), stateRepository);
|
|
1668
|
+
this.subscriptionManager = new SubscriptionManager(logger, this.config.SUBSCRIPTION_TTL_MS);
|
|
898
1669
|
this.meterService = new MeterService();
|
|
899
1670
|
this.staticResponseService = new StaticResponseService();
|
|
900
1671
|
const reportedIp = this.ip === "0.0.0.0" ? getLocalIp() : this.ip;
|
|
901
|
-
this.messageHandler = new OscMessageHandler(state, this.subscriptionManager, logger, reportedIp, name, model, this.meterService, this.schemaRegistry, this.staticResponseService);
|
|
902
|
-
this.processPacket = new ProcessPacketUseCase(this.messageHandler, gateway);
|
|
903
|
-
this.broadcastUpdates = new BroadcastUpdatesUseCase(this.subscriptionManager, state, gateway, logger, this.meterService, this.schemaRegistry);
|
|
1672
|
+
this.messageHandler = new OscMessageHandler(this.state, this.subscriptionManager, logger, reportedIp, name, model, this.meterService, this.schemaRegistry, this.staticResponseService);
|
|
1673
|
+
this.processPacket = new ProcessPacketUseCase(this.messageHandler, gateway, logger);
|
|
1674
|
+
this.broadcastUpdates = new BroadcastUpdatesUseCase(this.subscriptionManager, this.state, gateway, logger, this.meterService, this.schemaRegistry);
|
|
904
1675
|
this.manageSessions = new ManageSessionsUseCase(this.subscriptionManager);
|
|
905
|
-
state.on("change", (evt) => {
|
|
1676
|
+
this.state.on("change", (evt) => {
|
|
906
1677
|
this.logger.info(LogCategory.STATE, `State Changed`, evt);
|
|
907
1678
|
this.broadcastUpdates.broadcastSingleChange(evt.address, evt.value);
|
|
908
1679
|
});
|
|
@@ -912,13 +1683,14 @@ var SimulationService = class {
|
|
|
912
1683
|
* Starts the simulator server and internal loops.
|
|
913
1684
|
*/
|
|
914
1685
|
async start() {
|
|
1686
|
+
await this.state.initialize();
|
|
915
1687
|
await this.gateway.start(this.port, this.ip);
|
|
916
1688
|
this.cleanupInterval = setInterval(() => {
|
|
917
1689
|
this.manageSessions.cleanup();
|
|
918
|
-
},
|
|
1690
|
+
}, this.config.CLEANUP_INTERVAL_MS);
|
|
919
1691
|
this.updateInterval = setInterval(() => {
|
|
920
1692
|
this.broadcastUpdates.execute();
|
|
921
|
-
},
|
|
1693
|
+
}, this.config.BROADCAST_INTERVAL_MS);
|
|
922
1694
|
}
|
|
923
1695
|
/**
|
|
924
1696
|
* Stops the simulator server and stops all internal loops.
|
|
@@ -926,84 +1698,20 @@ var SimulationService = class {
|
|
|
926
1698
|
async stop() {
|
|
927
1699
|
if (this.updateInterval) clearInterval(this.updateInterval);
|
|
928
1700
|
if (this.cleanupInterval) clearInterval(this.cleanupInterval);
|
|
1701
|
+
await this.state.flush();
|
|
929
1702
|
await this.gateway.stop();
|
|
930
1703
|
}
|
|
931
1704
|
/**
|
|
932
1705
|
* Resets the mixer state to default values.
|
|
933
1706
|
*/
|
|
934
1707
|
resetState() {
|
|
935
|
-
this.
|
|
936
|
-
}
|
|
937
|
-
};
|
|
938
|
-
|
|
939
|
-
//#endregion
|
|
940
|
-
//#region src/domain/entities/X32State.ts
|
|
941
|
-
/**
|
|
942
|
-
* Manages the internal "Digital Twin" state of the X32 console.
|
|
943
|
-
* It acts as a single source of truth for all parameters.
|
|
944
|
-
* Emits 'change' events whenever a value is updated.
|
|
945
|
-
*/
|
|
946
|
-
var X32State = class extends node_events.EventEmitter {
|
|
947
|
-
/** Map storing all OSC paths and their current values. */
|
|
948
|
-
state = /* @__PURE__ */ new Map();
|
|
949
|
-
defaultState = /* @__PURE__ */ new Map();
|
|
950
|
-
/**
|
|
951
|
-
* Initializes the state with default values from the schema.
|
|
952
|
-
* @param schema - The schema definition map.
|
|
953
|
-
*/
|
|
954
|
-
constructor(schema) {
|
|
955
|
-
super();
|
|
956
|
-
for (const [addr, def] of Object.entries(schema)) this.defaultState.set(addr, def.default);
|
|
957
|
-
this.reset();
|
|
958
|
-
}
|
|
959
|
-
/**
|
|
960
|
-
* Resets all state parameters to their default values defined in the schema.
|
|
961
|
-
*/
|
|
962
|
-
reset() {
|
|
963
|
-
this.state.clear();
|
|
964
|
-
this.defaultState.forEach((val, key) => {
|
|
965
|
-
this.state.set(key, val);
|
|
966
|
-
});
|
|
967
|
-
}
|
|
968
|
-
/**
|
|
969
|
-
* Retrieves the value of a specific OSC node.
|
|
970
|
-
* @param address - The full OSC address path.
|
|
971
|
-
* @returns The stored value (number or string) or undefined if not found.
|
|
972
|
-
*/
|
|
973
|
-
get(address) {
|
|
974
|
-
return this.state.get(address);
|
|
1708
|
+
this.state.reset();
|
|
975
1709
|
}
|
|
976
1710
|
/**
|
|
977
|
-
*
|
|
978
|
-
* @param address - The full OSC address path.
|
|
979
|
-
* @param value - The new value to store.
|
|
1711
|
+
* Forces a save of the current state to storage.
|
|
980
1712
|
*/
|
|
981
|
-
|
|
982
|
-
this.state.
|
|
983
|
-
this.emit("change", {
|
|
984
|
-
address,
|
|
985
|
-
value
|
|
986
|
-
});
|
|
987
|
-
}
|
|
988
|
-
/**
|
|
989
|
-
* Specialized logic to handle X32 Mute Groups side-effects.
|
|
990
|
-
* When a mute group is toggled, it iterates through all channels
|
|
991
|
-
* assigned to that group and updates their individual mute status.
|
|
992
|
-
* @param groupIdx - The index of the mute group (1-6).
|
|
993
|
-
* @param isOn - The new state of the group master switch (0 or 1).
|
|
994
|
-
*/
|
|
995
|
-
handleMuteGroupChange(groupIdx, isOn) {
|
|
996
|
-
for (let i = 1; i <= 32; i++) {
|
|
997
|
-
const ch = i.toString().padStart(2, "0");
|
|
998
|
-
const grpVal = this.get(`/ch/${ch}/grp/mute`);
|
|
999
|
-
if (typeof grpVal === "number") {
|
|
1000
|
-
if ((grpVal & 1 << groupIdx - 1) !== 0) {
|
|
1001
|
-
const targetMute = isOn === 1 ? 0 : 1;
|
|
1002
|
-
const muteAddr = `/ch/${ch}/mix/on`;
|
|
1003
|
-
this.set(muteAddr, targetMute);
|
|
1004
|
-
}
|
|
1005
|
-
}
|
|
1006
|
-
}
|
|
1713
|
+
async saveState() {
|
|
1714
|
+
await this.state.flush();
|
|
1007
1715
|
}
|
|
1008
1716
|
};
|
|
1009
1717
|
|
|
@@ -1018,69 +1726,106 @@ var X32Node = class X32Node {
|
|
|
1018
1726
|
type;
|
|
1019
1727
|
/** Default value for reset. */
|
|
1020
1728
|
default;
|
|
1729
|
+
/** Optional validation constraints. */
|
|
1730
|
+
options;
|
|
1021
1731
|
/**
|
|
1022
1732
|
* Creates a new X32Node.
|
|
1023
1733
|
* @param type - The OSC data type ('f', 'i', 's').
|
|
1024
1734
|
* @param defaultValue - The default value.
|
|
1735
|
+
* @param options - Optional validation constraints.
|
|
1025
1736
|
*/
|
|
1026
|
-
constructor(type, defaultValue) {
|
|
1737
|
+
constructor(type, defaultValue, options) {
|
|
1027
1738
|
this.type = type;
|
|
1028
1739
|
this.default = defaultValue;
|
|
1740
|
+
this.options = options;
|
|
1029
1741
|
}
|
|
1030
1742
|
/**
|
|
1031
1743
|
* Validates if a value is compatible with this node's type.
|
|
1032
1744
|
* @param value - The value to check.
|
|
1745
|
+
* @param strict - If true, also validates against min/max constraints.
|
|
1033
1746
|
* @returns True if valid.
|
|
1034
1747
|
*/
|
|
1035
|
-
validate(value) {
|
|
1036
|
-
if (this.type === "f"
|
|
1037
|
-
if (this.type === "i"
|
|
1038
|
-
if (this.type === "s"
|
|
1039
|
-
|
|
1748
|
+
validate(value, strict = false) {
|
|
1749
|
+
if (this.type === "f" && typeof value !== "number") return false;
|
|
1750
|
+
if (this.type === "i" && typeof value !== "number") return false;
|
|
1751
|
+
if (this.type === "s" && typeof value !== "string") return false;
|
|
1752
|
+
if (strict && this.options && typeof value === "number") {
|
|
1753
|
+
if (this.options.min !== void 0 && value < this.options.min) return false;
|
|
1754
|
+
if (this.options.max !== void 0 && value > this.options.max) return false;
|
|
1755
|
+
if (this.type === "i" && this.options.strictInteger && !Number.isInteger(value)) return false;
|
|
1756
|
+
}
|
|
1757
|
+
return true;
|
|
1040
1758
|
}
|
|
1041
1759
|
/**
|
|
1042
1760
|
* Factory method to create from a plain object (for compatibility/migration).
|
|
1043
1761
|
* @param obj - Plain object.
|
|
1044
1762
|
* @param obj.type - OSC data type.
|
|
1045
1763
|
* @param obj.default - Default value.
|
|
1764
|
+
* @param obj.options - Optional validation constraints.
|
|
1046
1765
|
* @returns A new X32Node instance.
|
|
1047
1766
|
*/
|
|
1048
1767
|
static from(obj) {
|
|
1049
|
-
return new X32Node(obj.type, obj.default);
|
|
1768
|
+
return new X32Node(obj.type, obj.default, obj.options);
|
|
1050
1769
|
}
|
|
1051
1770
|
};
|
|
1052
1771
|
|
|
1053
1772
|
//#endregion
|
|
1054
1773
|
//#region src/infrastructure/repositories/InMemoryStateRepository.ts
|
|
1055
1774
|
/**
|
|
1056
|
-
* In-memory
|
|
1057
|
-
* Stores
|
|
1775
|
+
* In-memory state repository.
|
|
1776
|
+
* Stores state in a Map, no persistence across restarts.
|
|
1777
|
+
* This is the default and fastest option.
|
|
1058
1778
|
*/
|
|
1059
1779
|
var InMemoryStateRepository = class {
|
|
1060
|
-
state;
|
|
1780
|
+
state = /* @__PURE__ */ new Map();
|
|
1061
1781
|
/**
|
|
1062
|
-
*
|
|
1063
|
-
*
|
|
1064
|
-
* @param schemaRegistry - Registry providing the initial state schema.
|
|
1782
|
+
* Loads state from memory.
|
|
1783
|
+
* For in-memory storage, this returns current state.
|
|
1065
1784
|
*/
|
|
1066
|
-
|
|
1067
|
-
this.
|
|
1068
|
-
this.state = new X32State(schemaRegistry.getSchema());
|
|
1785
|
+
async load() {
|
|
1786
|
+
return this.getAll();
|
|
1069
1787
|
}
|
|
1070
1788
|
/**
|
|
1071
|
-
*
|
|
1072
|
-
*
|
|
1789
|
+
* Saves state to memory.
|
|
1790
|
+
* For in-memory storage, this replaces current state.
|
|
1073
1791
|
*/
|
|
1074
|
-
|
|
1075
|
-
|
|
1792
|
+
async save(state) {
|
|
1793
|
+
this.state.clear();
|
|
1794
|
+
for (const [key, value] of Object.entries(state)) this.state.set(key, value);
|
|
1076
1795
|
}
|
|
1077
1796
|
/**
|
|
1078
|
-
*
|
|
1797
|
+
* Gets a single value from memory.
|
|
1079
1798
|
*/
|
|
1080
|
-
|
|
1081
|
-
this.
|
|
1082
|
-
|
|
1799
|
+
get(address) {
|
|
1800
|
+
return this.state.get(address);
|
|
1801
|
+
}
|
|
1802
|
+
/**
|
|
1803
|
+
* Sets a single value in memory.
|
|
1804
|
+
*/
|
|
1805
|
+
set(address, value) {
|
|
1806
|
+
this.state.set(address, value);
|
|
1807
|
+
}
|
|
1808
|
+
/**
|
|
1809
|
+
* Gets all entries from memory.
|
|
1810
|
+
*/
|
|
1811
|
+
getAll() {
|
|
1812
|
+
const result = {};
|
|
1813
|
+
this.state.forEach((value, key) => {
|
|
1814
|
+
result[key] = value;
|
|
1815
|
+
});
|
|
1816
|
+
return result;
|
|
1817
|
+
}
|
|
1818
|
+
/**
|
|
1819
|
+
* Resets state to provided defaults.
|
|
1820
|
+
*/
|
|
1821
|
+
reset(defaults) {
|
|
1822
|
+
this.state.clear();
|
|
1823
|
+
for (const [key, value] of Object.entries(defaults)) this.state.set(key, value);
|
|
1083
1824
|
}
|
|
1825
|
+
/**
|
|
1826
|
+
* No-op for in-memory storage.
|
|
1827
|
+
*/
|
|
1828
|
+
async flush() {}
|
|
1084
1829
|
};
|
|
1085
1830
|
|
|
1086
1831
|
//#endregion
|
|
@@ -1899,41 +2644,215 @@ var SchemaFactory = class {
|
|
|
1899
2644
|
...this.generateRange(128, "/headamp", "/gain", "f", 0, 3, 0),
|
|
1900
2645
|
...this.generateRange(128, "/headamp", "/phantom", "i", 0, 3, 0),
|
|
1901
2646
|
...this.generateRange(6, "/config/mute", "", "i", 0),
|
|
1902
|
-
...this.generateRange(80, "/-stat/solosw", "", "i", 0),
|
|
2647
|
+
...this.generateRange(80, "/-stat/solosw", "", "i", 0, 2, 1),
|
|
1903
2648
|
"/-stat/selidx": this.node("i", 0),
|
|
2649
|
+
"/-stat/chfaderbank": this.node("i", 0),
|
|
2650
|
+
"/-stat/grpfaderbank": this.node("i", 0),
|
|
1904
2651
|
"/-stat/sendsonfader": this.node("i", 0),
|
|
1905
2652
|
"/-stat/bussendbank": this.node("i", 0),
|
|
2653
|
+
"/-stat/eqband": this.node("i", 0),
|
|
1906
2654
|
"/-stat/keysolo": this.node("i", 0),
|
|
2655
|
+
"/-stat/userbank": this.node("i", 0),
|
|
2656
|
+
"/-stat/autosave": this.node("i", 0),
|
|
2657
|
+
"/-stat/lock": this.node("i", 0),
|
|
2658
|
+
"/-stat/usbmounted": this.node("i", 0),
|
|
2659
|
+
"/-stat/remote": this.node("i", 0),
|
|
2660
|
+
"/-stat/rtamodeeq": this.node("i", 0),
|
|
2661
|
+
"/-stat/rtamodegeq": this.node("i", 0),
|
|
2662
|
+
"/-stat/rtaeqpre": this.node("i", 0),
|
|
2663
|
+
"/-stat/rtageqpost": this.node("i", 0),
|
|
2664
|
+
"/-stat/rtasource": this.node("i", 0),
|
|
2665
|
+
"/-stat/xcardtype": this.node("i", 0),
|
|
2666
|
+
"/-stat/xcardsync": this.node("i", 0),
|
|
2667
|
+
"/-stat/geqonfdr": this.node("i", 0),
|
|
2668
|
+
"/-stat/geqpos": this.node("i", 0),
|
|
1907
2669
|
"/-stat/screen/screen": this.node("i", 0),
|
|
2670
|
+
"/-stat/screen/mutegrp": this.node("i", 0),
|
|
2671
|
+
"/-stat/screen/utils": this.node("i", 0),
|
|
1908
2672
|
"/-stat/screen/CHAN/page": this.node("i", 0),
|
|
1909
2673
|
"/-stat/screen/METER/page": this.node("i", 0),
|
|
1910
2674
|
"/-stat/screen/ROUTE/page": this.node("i", 0),
|
|
1911
2675
|
"/-stat/screen/SETUP/page": this.node("i", 0),
|
|
2676
|
+
"/-stat/screen/LIB/page": this.node("i", 0),
|
|
1912
2677
|
"/-stat/screen/LIBRARY/page": this.node("i", 0),
|
|
1913
2678
|
"/-stat/screen/FX/page": this.node("i", 0),
|
|
1914
2679
|
"/-stat/screen/MON/page": this.node("i", 0),
|
|
1915
2680
|
"/-stat/screen/USB/page": this.node("i", 0),
|
|
1916
2681
|
"/-stat/screen/SCENE/page": this.node("i", 0),
|
|
1917
2682
|
"/-stat/screen/ASSIGN/page": this.node("i", 0),
|
|
2683
|
+
"/-stat/aes50/state": this.node("i", 0),
|
|
2684
|
+
"/-stat/aes50/A": this.node("i", 0),
|
|
2685
|
+
"/-stat/aes50/B": this.node("i", 0),
|
|
2686
|
+
"/-stat/aes50/stats/A": this.node("i", 0),
|
|
2687
|
+
"/-stat/aes50/stats/B": this.node("i", 0),
|
|
2688
|
+
"/-stat/tape/state": this.node("i", 0),
|
|
2689
|
+
"/-stat/tape/file": this.node("s", ""),
|
|
2690
|
+
"/-stat/tape/etime": this.node("i", 0),
|
|
2691
|
+
"/-stat/tape/rtime": this.node("i", 0),
|
|
2692
|
+
"/-stat/urec/state": this.node("i", 0),
|
|
2693
|
+
"/-stat/urec/etime": this.node("i", 0),
|
|
2694
|
+
"/-stat/urec/rtime": this.node("i", 0),
|
|
1918
2695
|
"/-stat/talk/A": this.node("i", 0),
|
|
1919
2696
|
"/-stat/talk/B": this.node("i", 0),
|
|
1920
2697
|
"/-stat/osc/on": this.node("i", 0),
|
|
1921
|
-
"/-
|
|
1922
|
-
"/-action/
|
|
2698
|
+
"/-action/setip": this.node("i", 0),
|
|
2699
|
+
"/-action/setclock": this.node("i", 0),
|
|
2700
|
+
"/-action/initall": this.node("i", 0),
|
|
2701
|
+
"/-action/initlib": this.node("i", 0),
|
|
2702
|
+
"/-action/initshow": this.node("i", 0),
|
|
2703
|
+
"/-action/savestate": this.node("i", 0),
|
|
2704
|
+
"/-action/undopt": this.node("i", 0),
|
|
2705
|
+
"/-action/doundo": this.node("i", 0),
|
|
1923
2706
|
"/-action/playtrack": this.node("i", 0),
|
|
2707
|
+
"/-action/newscreen": this.node("i", 0),
|
|
2708
|
+
"/-action/clearsolo": this.node("i", 0),
|
|
2709
|
+
"/-action/setprebus": this.node("i", 0),
|
|
2710
|
+
"/-action/setsrate": this.node("i", 0),
|
|
2711
|
+
"/-action/setrtasrc": this.node("i", 0),
|
|
2712
|
+
"/-action/recselect": this.node("i", 0),
|
|
2713
|
+
"/-action/gocue": this.node("i", 0),
|
|
1924
2714
|
"/-action/goscene": this.node("i", 0),
|
|
1925
2715
|
"/-action/setscene": this.node("i", 0),
|
|
2716
|
+
"/-action/gosnippet": this.node("i", 0),
|
|
2717
|
+
"/-action/selsession": this.node("i", 0),
|
|
2718
|
+
"/-action/delsession": this.node("i", 0),
|
|
2719
|
+
"/-action/selmarker": this.node("i", 0),
|
|
2720
|
+
"/-action/delmarker": this.node("i", 0),
|
|
2721
|
+
"/-action/savemarker": this.node("i", 0),
|
|
2722
|
+
"/-action/addmarker": this.node("i", 0),
|
|
2723
|
+
"/-action/selposition": this.node("i", 0),
|
|
2724
|
+
"/-action/clearalert": this.node("i", 0),
|
|
2725
|
+
"/-action/formatcard": this.node("i", 0),
|
|
2726
|
+
"/-undo/time": this.node("s", ""),
|
|
2727
|
+
"/-show": this.node("i", 0),
|
|
2728
|
+
"/-show/prepos": this.node("i", 0),
|
|
2729
|
+
"/-show/prepos/current": this.node("i", 0),
|
|
2730
|
+
"/-show/showfile": this.node("s", ""),
|
|
2731
|
+
"/-show/showfile/inputs": this.node("i", 0),
|
|
2732
|
+
"/-show/showfile/mxsends": this.node("i", 0),
|
|
2733
|
+
"/-show/showfile/mxbuses": this.node("i", 0),
|
|
2734
|
+
"/-show/showfile/console": this.node("i", 0),
|
|
2735
|
+
"/-show/showfile/chan16": this.node("i", 0),
|
|
2736
|
+
"/-show/showfile/chan32": this.node("i", 0),
|
|
2737
|
+
"/-show/showfile/return": this.node("i", 0),
|
|
2738
|
+
"/-show/showfile/buses": this.node("i", 0),
|
|
2739
|
+
"/-show/showfile/lrmtxdca": this.node("i", 0),
|
|
2740
|
+
"/-show/showfile/effects": this.node("i", 0),
|
|
2741
|
+
...this.generateShowfileCues(),
|
|
2742
|
+
...this.generateShowfileScenes(),
|
|
2743
|
+
...this.generateShowfileSnippets(),
|
|
2744
|
+
"/-usb/path": this.node("s", ""),
|
|
2745
|
+
"/-usb/title": this.node("s", ""),
|
|
2746
|
+
"/-usb/dir": this.node("i", 0),
|
|
2747
|
+
"/-usb/dirpos": this.node("i", 0),
|
|
2748
|
+
"/-usb/maxpos": this.node("i", 0),
|
|
2749
|
+
...this.generateUSBDir(),
|
|
2750
|
+
"/-urec/sessionmax": this.node("i", 0),
|
|
2751
|
+
"/-urec/markermax": this.node("i", 0),
|
|
2752
|
+
"/-urec/sessionlen": this.node("i", 0),
|
|
2753
|
+
"/-urec/sessionpos": this.node("i", 0),
|
|
2754
|
+
"/-urec/markerpos": this.node("i", 0),
|
|
2755
|
+
"/-urec/batterystate": this.node("i", 0),
|
|
2756
|
+
"/-urec/srate": this.node("i", 0),
|
|
2757
|
+
"/-urec/tracks": this.node("i", 0),
|
|
2758
|
+
"/-urec/sessionspan": this.node("i", 0),
|
|
2759
|
+
"/-urec/sessionoffs": this.node("i", 0),
|
|
2760
|
+
"/-urec/sd1state": this.node("i", 0),
|
|
2761
|
+
"/-urec/sd2state": this.node("i", 0),
|
|
2762
|
+
"/-urec/sd1info": this.node("s", ""),
|
|
2763
|
+
"/-urec/sd2info": this.node("s", ""),
|
|
2764
|
+
"/-urec/errormessage": this.node("s", ""),
|
|
2765
|
+
"/-urec/errorcode": this.node("i", 0),
|
|
2766
|
+
...this.generateURecSessions(),
|
|
2767
|
+
...this.generateLibraries(),
|
|
2768
|
+
"/-insert": this.node("i", 0),
|
|
2769
|
+
"/-prefs/style": this.node("i", 0),
|
|
2770
|
+
"/-prefs/bright": this.node("i", 50),
|
|
2771
|
+
"/-prefs/lcdcont": this.node("i", 50),
|
|
2772
|
+
"/-prefs/ledbright": this.node("i", 50),
|
|
2773
|
+
"/-prefs/lamp": this.node("i", 50),
|
|
2774
|
+
"/-prefs/lampon": this.node("i", 0),
|
|
2775
|
+
"/-prefs/clockrate": this.node("i", 0),
|
|
2776
|
+
"/-prefs/clocksource": this.node("i", 0),
|
|
2777
|
+
"/-prefs/confirm_general": this.node("i", 1),
|
|
2778
|
+
"/-prefs/confirm_overwrite": this.node("i", 1),
|
|
2779
|
+
"/-prefs/confirm_sceneload": this.node("i", 1),
|
|
2780
|
+
"/-prefs/viewrtn": this.node("i", 0),
|
|
2781
|
+
"/-prefs/selfollowsbank": this.node("i", 0),
|
|
2782
|
+
"/-prefs/scene_advance": this.node("i", 0),
|
|
2783
|
+
"/-prefs/safe_masterlevels": this.node("i", 0),
|
|
2784
|
+
"/-prefs/haflags": this.node("i", 0),
|
|
2785
|
+
"/-prefs/autosel": this.node("i", 1),
|
|
2786
|
+
"/-prefs/show_control": this.node("i", 0),
|
|
2787
|
+
"/-prefs/clockmode": this.node("i", 0),
|
|
2788
|
+
"/-prefs/hardmute": this.node("i", 0),
|
|
2789
|
+
"/-prefs/dcamute": this.node("i", 0),
|
|
2790
|
+
"/-prefs/invertmutes": this.node("i", 0),
|
|
2791
|
+
"/-prefs/name": this.node("s", "X32-Simulator"),
|
|
2792
|
+
"/-prefs/rec_control": this.node("i", 0),
|
|
2793
|
+
"/-prefs/fastFaders": this.node("i", 0),
|
|
2794
|
+
"/-prefs/ip": this.node("s", ""),
|
|
2795
|
+
"/-prefs/ip/dhcp": this.node("i", 0),
|
|
2796
|
+
"/-prefs/ip/addr": this.node("s", "192.168.1.1"),
|
|
2797
|
+
"/-prefs/ip/mask": this.node("s", "255.255.255.0"),
|
|
2798
|
+
"/-prefs/ip/gateway": this.node("s", "192.168.1.1"),
|
|
2799
|
+
"/-prefs/remote": this.node("i", 0),
|
|
2800
|
+
"/-prefs/remote/enable": this.node("i", 0),
|
|
2801
|
+
"/-prefs/remote/protocol": this.node("i", 0),
|
|
2802
|
+
"/-prefs/remote/port": this.node("i", 10023),
|
|
2803
|
+
"/-prefs/remote/ioenable": this.node("i", 0),
|
|
2804
|
+
"/-prefs/card": this.node("i", 0),
|
|
2805
|
+
"/-prefs/card/UFifc": this.node("i", 0),
|
|
2806
|
+
"/-prefs/card/UFmode": this.node("i", 0),
|
|
2807
|
+
"/-prefs/card/USBmode": this.node("i", 0),
|
|
2808
|
+
"/-prefs/card/ADATwc": this.node("i", 0),
|
|
2809
|
+
"/-prefs/card/ADATsync": this.node("i", 0),
|
|
2810
|
+
"/-prefs/card/MADImode": this.node("i", 0),
|
|
2811
|
+
"/-prefs/card/MADIin": this.node("i", 0),
|
|
2812
|
+
"/-prefs/card/MADIout": this.node("i", 0),
|
|
2813
|
+
"/-prefs/card/MADIsrc": this.node("i", 0),
|
|
2814
|
+
"/-prefs/card/URECtracks": this.node("i", 0),
|
|
2815
|
+
"/-prefs/card/URECplayb": this.node("i", 0),
|
|
2816
|
+
"/-prefs/card/URECrout": this.node("i", 0),
|
|
2817
|
+
"/-prefs/card/URECsdsel": this.node("i", 0),
|
|
2818
|
+
"/-prefs/rta": this.node("i", 0),
|
|
2819
|
+
"/-prefs/rta/visibility": this.node("s", "70%"),
|
|
2820
|
+
"/-prefs/rta/gain": this.node("f", 0),
|
|
2821
|
+
"/-prefs/rta/autogain": this.node("i", 0),
|
|
2822
|
+
"/-prefs/rta/source": this.node("i", 0),
|
|
2823
|
+
"/-prefs/rta/pos": this.node("i", 0),
|
|
2824
|
+
"/-prefs/rta/mode": this.node("i", 0),
|
|
2825
|
+
"/-prefs/rta/option": this.node("i", 0),
|
|
2826
|
+
"/-prefs/rta/det": this.node("i", 0),
|
|
2827
|
+
"/-prefs/rta/decay": this.node("i", 0),
|
|
2828
|
+
"/-prefs/rta/peakhold": this.node("i", 0),
|
|
2829
|
+
...this.generatePrefsIQ(),
|
|
2830
|
+
"/-prefs/key/layout": this.node("i", 0),
|
|
2831
|
+
...this.generateRange(100, "/-prefs/key", "", "i", 0, 2, 0),
|
|
1926
2832
|
"/config/routing/AES50A/1-8": this.node("i", 0),
|
|
1927
2833
|
"/config/routing/AES50B/1-8": this.node("i", 0),
|
|
1928
2834
|
"/config/routing/CARD/1-8": this.node("i", 0),
|
|
1929
2835
|
"/config/routing/OUT/1-4": this.node("i", 0),
|
|
1930
|
-
"/-prefs/invertmutes": this.node("i", 0),
|
|
1931
2836
|
...this.generateChannelStrip("/main/st", 6, false),
|
|
1932
2837
|
...this.generateChannelStrip("/main/m", 6, false),
|
|
1933
2838
|
...Object.fromEntries(Array.from({ length: 16 }, (_, i) => [`/config/chlink/${i * 2 + 1}-${i * 2 + 2}`, this.node("i", 0)])),
|
|
1934
2839
|
...Object.fromEntries(Array.from({ length: 8 }, (_, i) => [`/config/buslink/${i * 2 + 1}-${i * 2 + 2}`, this.node("i", 0)])),
|
|
1935
2840
|
...Object.fromEntries(Array.from({ length: 4 }, (_, i) => [`/config/auxlink/${i * 2 + 1}-${i * 2 + 2}`, this.node("i", 0)])),
|
|
1936
2841
|
...Object.fromEntries(Array.from({ length: 4 }, (_, i) => [`/config/fxlink/${i * 2 + 1}-${i * 2 + 2}`, this.node("i", 0)])),
|
|
2842
|
+
...Object.fromEntries(Array.from({ length: 3 }, (_, i) => [`/config/mtxlink/${i * 2 + 1}-${i * 2 + 2}`, this.node("i", 0)])),
|
|
2843
|
+
"/config/linkcfg/hadly": this.node("i", 0),
|
|
2844
|
+
"/config/linkcfg/eq": this.node("i", 0),
|
|
2845
|
+
"/config/linkcfg/dyn": this.node("i", 0),
|
|
2846
|
+
"/config/linkcfg/fdrmute": this.node("i", 0),
|
|
2847
|
+
"/config/mono/mode": this.node("i", 0),
|
|
2848
|
+
"/config/mono/link": this.node("i", 0),
|
|
2849
|
+
"/config/tape/autoplay": this.node("i", 0),
|
|
2850
|
+
"/config/tape/gainL": this.node("f", .5),
|
|
2851
|
+
"/config/tape/gainR": this.node("f", .5),
|
|
2852
|
+
"/config/amixenable/X": this.node("i", 0),
|
|
2853
|
+
"/config/amixenable/Y": this.node("i", 0),
|
|
2854
|
+
...this.generateUserCtrl(),
|
|
2855
|
+
"/config/routing/routswitch": this.node("i", 0),
|
|
1937
2856
|
...this.generateRange(32, "/config/userrout/in", "", "i", 0),
|
|
1938
2857
|
...this.generateRange(48, "/config/userrout/out", "", "i", 0),
|
|
1939
2858
|
"/config/solo/level": this.node("f", 0),
|
|
@@ -1969,6 +2888,7 @@ var SchemaFactory = class {
|
|
|
1969
2888
|
"/config/osc/f2": this.node("f", .5),
|
|
1970
2889
|
"/config/osc/level": this.node("f", 0),
|
|
1971
2890
|
"/config/osc/dest": this.node("i", 0),
|
|
2891
|
+
...this.generateDP48Config(),
|
|
1972
2892
|
...this.generateOutputs("main", 16),
|
|
1973
2893
|
...this.generateOutputs("aux", 6),
|
|
1974
2894
|
...this.generateOutputs("p16", 16),
|
|
@@ -1976,7 +2896,7 @@ var SchemaFactory = class {
|
|
|
1976
2896
|
...this.generateOutputs("rec", 2)
|
|
1977
2897
|
};
|
|
1978
2898
|
Object.keys(STATIC_RESPONSES_DATA).forEach((key) => {
|
|
1979
|
-
if (key.startsWith("/-")
|
|
2899
|
+
if (key.startsWith("/-")) {
|
|
1980
2900
|
const val = STATIC_RESPONSES_DATA[key][0];
|
|
1981
2901
|
const type = typeof val === "string" ? "s" : Number.isInteger(val) ? "i" : "f";
|
|
1982
2902
|
schema[key] = this.node(type, val);
|
|
@@ -2091,6 +3011,7 @@ var SchemaFactory = class {
|
|
|
2091
3011
|
generateNodes(count, prefix) {
|
|
2092
3012
|
const nodes = {};
|
|
2093
3013
|
const isChannelOrAux = prefix === "ch" || prefix === "auxin";
|
|
3014
|
+
const hasMtxPreamp = prefix === "mtx";
|
|
2094
3015
|
const eqBands = prefix === "bus" || prefix === "mtx" ? 6 : 4;
|
|
2095
3016
|
for (let i = 1; i <= count; i++) {
|
|
2096
3017
|
const padId = i.toString().padStart(2, "0");
|
|
@@ -2102,7 +3023,7 @@ var SchemaFactory = class {
|
|
|
2102
3023
|
nodes[`${base}/fader`] = this.node("f", .75);
|
|
2103
3024
|
nodes[`${base}/on`] = this.node("i", 0);
|
|
2104
3025
|
} else {
|
|
2105
|
-
Object.assign(nodes, this.generateChannelStrip(base, eqBands, isChannelOrAux));
|
|
3026
|
+
Object.assign(nodes, this.generateChannelStrip(base, eqBands, isChannelOrAux || hasMtxPreamp));
|
|
2106
3027
|
if (prefix === "ch" || prefix === "auxin" || prefix === "fxrtn" || prefix === "bus") for (let b = 1; b <= 16; b++) {
|
|
2107
3028
|
const busId = b.toString().padStart(2, "0");
|
|
2108
3029
|
nodes[`${base}/mix/${busId}/level`] = this.node("f", 0);
|
|
@@ -2110,6 +3031,11 @@ var SchemaFactory = class {
|
|
|
2110
3031
|
nodes[`${base}/mix/${busId}/pan`] = this.node("f", .5);
|
|
2111
3032
|
nodes[`${base}/mix/${busId}/type`] = this.node("i", 0);
|
|
2112
3033
|
}
|
|
3034
|
+
if (prefix === "ch") {
|
|
3035
|
+
nodes[`${base}/automix`] = this.node("i", 0);
|
|
3036
|
+
nodes[`${base}/automix/group`] = this.node("i", 0);
|
|
3037
|
+
nodes[`${base}/automix/weight`] = this.node("f", 0);
|
|
3038
|
+
}
|
|
2113
3039
|
}
|
|
2114
3040
|
});
|
|
2115
3041
|
}
|
|
@@ -2142,6 +3068,159 @@ var SchemaFactory = class {
|
|
|
2142
3068
|
}
|
|
2143
3069
|
return nodes;
|
|
2144
3070
|
}
|
|
3071
|
+
/**
|
|
3072
|
+
* Generates showfile cue entries (100 cues: 000-099)
|
|
3073
|
+
*/
|
|
3074
|
+
generateShowfileCues() {
|
|
3075
|
+
const nodes = {};
|
|
3076
|
+
for (let i = 0; i < 100; i++) {
|
|
3077
|
+
const base = `/-show/showfile/cue/${i.toString().padStart(3, "0")}`;
|
|
3078
|
+
nodes[base] = this.node("s", "");
|
|
3079
|
+
nodes[`${base}/numb`] = this.node("i", 0);
|
|
3080
|
+
nodes[`${base}/name`] = this.node("s", "");
|
|
3081
|
+
nodes[`${base}/skip`] = this.node("i", 0);
|
|
3082
|
+
nodes[`${base}/scene`] = this.node("i", 0);
|
|
3083
|
+
nodes[`${base}/bit`] = this.node("i", 0);
|
|
3084
|
+
nodes[`${base}/miditype`] = this.node("i", 0);
|
|
3085
|
+
nodes[`${base}/midichan`] = this.node("i", 0);
|
|
3086
|
+
nodes[`${base}/midipara1`] = this.node("i", 0);
|
|
3087
|
+
nodes[`${base}/midipara2`] = this.node("i", 0);
|
|
3088
|
+
}
|
|
3089
|
+
return nodes;
|
|
3090
|
+
}
|
|
3091
|
+
/**
|
|
3092
|
+
* Generates showfile scene entries (100 scenes: 000-099)
|
|
3093
|
+
*/
|
|
3094
|
+
generateShowfileScenes() {
|
|
3095
|
+
const nodes = {};
|
|
3096
|
+
for (let i = 0; i < 100; i++) {
|
|
3097
|
+
const base = `/-show/showfile/scene/${i.toString().padStart(3, "0")}`;
|
|
3098
|
+
nodes[base] = this.node("s", "");
|
|
3099
|
+
nodes[`${base}/name`] = this.node("s", "");
|
|
3100
|
+
nodes[`${base}/notes`] = this.node("s", "");
|
|
3101
|
+
nodes[`${base}/safes`] = this.node("i", 0);
|
|
3102
|
+
nodes[`${base}/hasdata`] = this.node("i", 0);
|
|
3103
|
+
}
|
|
3104
|
+
return nodes;
|
|
3105
|
+
}
|
|
3106
|
+
/**
|
|
3107
|
+
* Generates showfile snippet entries (100 snippets: 000-099)
|
|
3108
|
+
*/
|
|
3109
|
+
generateShowfileSnippets() {
|
|
3110
|
+
const nodes = {};
|
|
3111
|
+
for (let i = 0; i < 100; i++) {
|
|
3112
|
+
const base = `/-show/showfile/snippet/${i.toString().padStart(3, "0")}`;
|
|
3113
|
+
nodes[base] = this.node("s", "");
|
|
3114
|
+
nodes[`${base}/name`] = this.node("s", "");
|
|
3115
|
+
nodes[`${base}/eventtyp`] = this.node("i", 0);
|
|
3116
|
+
nodes[`${base}/channels`] = this.node("i", 0);
|
|
3117
|
+
nodes[`${base}/auxbuses`] = this.node("i", 0);
|
|
3118
|
+
nodes[`${base}/maingrps`] = this.node("i", 0);
|
|
3119
|
+
nodes[`${base}/hasdata`] = this.node("i", 0);
|
|
3120
|
+
}
|
|
3121
|
+
return nodes;
|
|
3122
|
+
}
|
|
3123
|
+
/**
|
|
3124
|
+
* Generates preferences iQ entries (16 entries: 01-16)
|
|
3125
|
+
*/
|
|
3126
|
+
generatePrefsIQ() {
|
|
3127
|
+
const nodes = {};
|
|
3128
|
+
for (let i = 1; i <= 16; i++) {
|
|
3129
|
+
const base = `/-prefs/iQ/${i.toString().padStart(2, "0")}`;
|
|
3130
|
+
nodes[base] = this.node("i", 0);
|
|
3131
|
+
nodes[`${base}/iQmodel`] = this.node("i", 0);
|
|
3132
|
+
nodes[`${base}/iQeqset`] = this.node("i", 0);
|
|
3133
|
+
nodes[`${base}/iQsound`] = this.node("i", 0);
|
|
3134
|
+
}
|
|
3135
|
+
return nodes;
|
|
3136
|
+
}
|
|
3137
|
+
/**
|
|
3138
|
+
* Generates DP48 Personal Monitor config entries (48 channels)
|
|
3139
|
+
*/
|
|
3140
|
+
generateDP48Config() {
|
|
3141
|
+
const nodes = {};
|
|
3142
|
+
for (let i = 1; i <= 48; i++) {
|
|
3143
|
+
const id = i.toString().padStart(2, "0");
|
|
3144
|
+
nodes[`/config/dp48/link/${id}`] = this.node("i", 0);
|
|
3145
|
+
}
|
|
3146
|
+
nodes["/config/dp48/assign"] = this.node("i", 0);
|
|
3147
|
+
nodes["/config/dp48/grpname/01"] = this.node("s", "");
|
|
3148
|
+
nodes["/config/dp48/grpname/02"] = this.node("s", "");
|
|
3149
|
+
nodes["/config/dp48/grpname/03"] = this.node("s", "");
|
|
3150
|
+
nodes["/config/dp48/grpname/04"] = this.node("s", "");
|
|
3151
|
+
nodes["/config/dp48/grpname/05"] = this.node("s", "");
|
|
3152
|
+
nodes["/config/dp48/grpname/06"] = this.node("s", "");
|
|
3153
|
+
nodes["/config/dp48/grpname/07"] = this.node("s", "");
|
|
3154
|
+
nodes["/config/dp48/grpname/08"] = this.node("s", "");
|
|
3155
|
+
nodes["/config/dp48/grpname/09"] = this.node("s", "");
|
|
3156
|
+
nodes["/config/dp48/grpname/10"] = this.node("s", "");
|
|
3157
|
+
nodes["/config/dp48/grpname/11"] = this.node("s", "");
|
|
3158
|
+
nodes["/config/dp48/grpname/12"] = this.node("s", "");
|
|
3159
|
+
return nodes;
|
|
3160
|
+
}
|
|
3161
|
+
/**
|
|
3162
|
+
* Generates USB directory entries (1000 entries: 000-999)
|
|
3163
|
+
*/
|
|
3164
|
+
generateUSBDir() {
|
|
3165
|
+
const nodes = {};
|
|
3166
|
+
for (let i = 0; i < 1e3; i++) {
|
|
3167
|
+
const id = i.toString().padStart(3, "0");
|
|
3168
|
+
nodes[`/-usb/dir/${id}`] = this.node("s", "");
|
|
3169
|
+
nodes[`/-usb/dir/${id}/name`] = this.node("s", "");
|
|
3170
|
+
}
|
|
3171
|
+
return nodes;
|
|
3172
|
+
}
|
|
3173
|
+
/**
|
|
3174
|
+
* Generates USB recording session and marker entries
|
|
3175
|
+
*/
|
|
3176
|
+
generateURecSessions() {
|
|
3177
|
+
const nodes = {};
|
|
3178
|
+
for (let i = 1; i <= 100; i++) {
|
|
3179
|
+
const id = i.toString().padStart(3, "0");
|
|
3180
|
+
nodes[`/-urec/session/${id}/name`] = this.node("s", "");
|
|
3181
|
+
nodes[`/-urec/marker/${id}/time`] = this.node("i", 0);
|
|
3182
|
+
}
|
|
3183
|
+
return nodes;
|
|
3184
|
+
}
|
|
3185
|
+
/**
|
|
3186
|
+
* Generates library entries (ch, fx, r, mon - 100 each)
|
|
3187
|
+
*/
|
|
3188
|
+
generateLibraries() {
|
|
3189
|
+
const nodes = {};
|
|
3190
|
+
for (const lib of [
|
|
3191
|
+
"ch",
|
|
3192
|
+
"fx",
|
|
3193
|
+
"r",
|
|
3194
|
+
"mon"
|
|
3195
|
+
]) {
|
|
3196
|
+
nodes[`/-libs/${lib}`] = this.node("i", 0);
|
|
3197
|
+
for (let i = 1; i <= 100; i++) {
|
|
3198
|
+
const base = `/-libs/${lib}/${i.toString().padStart(3, "0")}`;
|
|
3199
|
+
nodes[base] = this.node("s", "");
|
|
3200
|
+
nodes[`${base}/pos`] = this.node("i", 0);
|
|
3201
|
+
nodes[`${base}/name`] = this.node("s", "");
|
|
3202
|
+
nodes[`${base}/flags`] = this.node("i", 0);
|
|
3203
|
+
nodes[`${base}/hasdata`] = this.node("i", 0);
|
|
3204
|
+
}
|
|
3205
|
+
}
|
|
3206
|
+
return nodes;
|
|
3207
|
+
}
|
|
3208
|
+
/**
|
|
3209
|
+
* Generates user control entries (A, B, C with enc and btn)
|
|
3210
|
+
*/
|
|
3211
|
+
generateUserCtrl() {
|
|
3212
|
+
const nodes = {};
|
|
3213
|
+
for (const bank of [
|
|
3214
|
+
"A",
|
|
3215
|
+
"B",
|
|
3216
|
+
"C"
|
|
3217
|
+
]) {
|
|
3218
|
+
nodes[`/config/userctrl/${bank}`] = this.node("i", 0);
|
|
3219
|
+
for (let i = 1; i <= 4; i++) nodes[`/config/userctrl/${bank}/enc/${i}`] = this.node("i", 0);
|
|
3220
|
+
for (let i = 1; i <= 12; i++) nodes[`/config/userctrl/${bank}/btn/${i}`] = this.node("i", 0);
|
|
3221
|
+
}
|
|
3222
|
+
return nodes;
|
|
3223
|
+
}
|
|
2145
3224
|
};
|
|
2146
3225
|
|
|
2147
3226
|
//#endregion
|
|
@@ -2212,6 +3291,12 @@ Object.defineProperty(exports, 'ConsoleLogger', {
|
|
|
2212
3291
|
return ConsoleLogger;
|
|
2213
3292
|
}
|
|
2214
3293
|
});
|
|
3294
|
+
Object.defineProperty(exports, 'DEFAULT_CONFIG', {
|
|
3295
|
+
enumerable: true,
|
|
3296
|
+
get: function () {
|
|
3297
|
+
return DEFAULT_CONFIG;
|
|
3298
|
+
}
|
|
3299
|
+
});
|
|
2215
3300
|
Object.defineProperty(exports, 'InMemoryStateRepository', {
|
|
2216
3301
|
enumerable: true,
|
|
2217
3302
|
get: function () {
|
|
@@ -2295,4 +3380,10 @@ Object.defineProperty(exports, '__toESM', {
|
|
|
2295
3380
|
get: function () {
|
|
2296
3381
|
return __toESM;
|
|
2297
3382
|
}
|
|
3383
|
+
});
|
|
3384
|
+
Object.defineProperty(exports, 'mergeConfig', {
|
|
3385
|
+
enumerable: true,
|
|
3386
|
+
get: function () {
|
|
3387
|
+
return mergeConfig;
|
|
3388
|
+
}
|
|
2298
3389
|
});
|