@djodjonx/x32-simulator 0.0.5 → 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 +28 -0
- package/dist/{SchemaRegistry-BRVgnyaA.mjs → SchemaRegistry-BBzyicoy.mjs} +1275 -193
- package/dist/{SchemaRegistry-CfDtw84j.cjs → SchemaRegistry-Ddy5AEKs.cjs} +1286 -192
- 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({
|
|
@@ -374,8 +497,7 @@ var NodeDiscoveryStrategy = class {
|
|
|
374
497
|
return address === "/node";
|
|
375
498
|
}
|
|
376
499
|
execute(msg, _source) {
|
|
377
|
-
const queryPath = msg.args[0];
|
|
378
|
-
if (!queryPath) return [];
|
|
500
|
+
const queryPath = msg.args[0] || "/";
|
|
379
501
|
const children = /* @__PURE__ */ new Set();
|
|
380
502
|
const prefix = queryPath.endsWith("/") ? queryPath : `${queryPath}/`;
|
|
381
503
|
for (const key of this.schemaRegistry.getAllPaths()) if (key.startsWith(prefix)) {
|
|
@@ -392,8 +514,9 @@ var NodeDiscoveryStrategy = class {
|
|
|
392
514
|
//#endregion
|
|
393
515
|
//#region src/domain/services/strategies/StaticResponseStrategy.ts
|
|
394
516
|
/**
|
|
395
|
-
* Handles discovery and static information queries.
|
|
396
|
-
* 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.
|
|
397
520
|
*/
|
|
398
521
|
var StaticResponseStrategy = class {
|
|
399
522
|
constructor(serverIp, serverName, serverModel, staticResponseService) {
|
|
@@ -402,7 +525,8 @@ var StaticResponseStrategy = class {
|
|
|
402
525
|
this.serverModel = serverModel;
|
|
403
526
|
this.staticResponseService = staticResponseService;
|
|
404
527
|
}
|
|
405
|
-
canHandle(address) {
|
|
528
|
+
canHandle(address, args) {
|
|
529
|
+
if (args && args.length > 0) return false;
|
|
406
530
|
return !!this.staticResponseService.getResponse(address);
|
|
407
531
|
}
|
|
408
532
|
execute(msg, _source) {
|
|
@@ -573,6 +697,7 @@ var MeterStrategy = class {
|
|
|
573
697
|
* LOGIC:
|
|
574
698
|
* - If no arguments: Treats as a QUERY (GET) and returns the current value.
|
|
575
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.
|
|
576
701
|
*/
|
|
577
702
|
var StateAccessStrategy = class {
|
|
578
703
|
/**
|
|
@@ -580,43 +705,685 @@ var StateAccessStrategy = class {
|
|
|
580
705
|
* @param state - Current mixer state.
|
|
581
706
|
* @param logger - Logger instance.
|
|
582
707
|
* @param schemaRegistry - Registry to validate addresses.
|
|
708
|
+
* @param permissive - If true, store unknown addresses too (default: true).
|
|
583
709
|
*/
|
|
584
|
-
constructor(state, logger, schemaRegistry) {
|
|
710
|
+
constructor(state, logger, schemaRegistry, permissive = true) {
|
|
585
711
|
this.state = state;
|
|
586
712
|
this.logger = logger;
|
|
587
713
|
this.schemaRegistry = schemaRegistry;
|
|
714
|
+
this.permissive = permissive;
|
|
588
715
|
}
|
|
589
716
|
/** @inheritdoc */
|
|
590
717
|
canHandle(address) {
|
|
591
|
-
|
|
718
|
+
if (this.schemaRegistry.has(address)) return true;
|
|
719
|
+
return this.permissive && address.startsWith("/");
|
|
592
720
|
}
|
|
593
721
|
/** @inheritdoc */
|
|
594
722
|
execute(msg, _source) {
|
|
595
723
|
const addr = msg.address;
|
|
596
724
|
const node = this.schemaRegistry.getNode(addr);
|
|
725
|
+
const isKnown = !!node;
|
|
597
726
|
if (msg.args.length === 0) {
|
|
598
727
|
const val$1 = this.state.get(addr);
|
|
599
728
|
if (val$1 !== void 0) return [{
|
|
600
729
|
address: addr,
|
|
601
730
|
args: [val$1]
|
|
602
731
|
}];
|
|
732
|
+
if (!isKnown) this.logger.debug(LogCategory.STATE, `[GET] Unknown address queried: ${addr}`);
|
|
603
733
|
return [];
|
|
604
734
|
}
|
|
605
735
|
const val = msg.args[0];
|
|
606
|
-
if (
|
|
736
|
+
if (isKnown) {
|
|
607
737
|
if (!node.validate(val)) {
|
|
608
738
|
this.logger.warn(LogCategory.DISPATCH, `[TYPE ERR] ${addr} expected ${node.type}, got ${typeof val}`);
|
|
609
739
|
return [];
|
|
610
740
|
}
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
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}`);
|
|
752
|
+
}
|
|
753
|
+
return [];
|
|
754
|
+
}
|
|
755
|
+
};
|
|
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}`);
|
|
617
1300
|
}
|
|
618
1301
|
return [];
|
|
619
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
|
+
}
|
|
620
1387
|
};
|
|
621
1388
|
|
|
622
1389
|
//#endregion
|
|
@@ -648,10 +1415,12 @@ var OscMessageHandler = class {
|
|
|
648
1415
|
this.staticResponseService = staticResponseService;
|
|
649
1416
|
this.strategies = [
|
|
650
1417
|
new NodeDiscoveryStrategy(this.schemaRegistry),
|
|
651
|
-
new StaticResponseStrategy(serverIp, serverName, serverModel, this.staticResponseService),
|
|
652
1418
|
new SubscriptionStrategy(subscriptionManager, state, logger),
|
|
653
1419
|
new BatchStrategy(subscriptionManager, logger),
|
|
654
1420
|
new MeterStrategy(subscriptionManager, state, this.meterService),
|
|
1421
|
+
new ShowDumpStrategy(state, logger),
|
|
1422
|
+
new SceneDataStrategy(state, logger),
|
|
1423
|
+
new StaticResponseStrategy(serverIp, serverName, serverModel, this.staticResponseService),
|
|
655
1424
|
new StateAccessStrategy(state, logger, this.schemaRegistry)
|
|
656
1425
|
];
|
|
657
1426
|
}
|
|
@@ -662,19 +1431,41 @@ var OscMessageHandler = class {
|
|
|
662
1431
|
* @returns Array of replies generated by the strategy.
|
|
663
1432
|
*/
|
|
664
1433
|
handle(msg, source) {
|
|
665
|
-
|
|
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
|
+
}
|
|
666
1454
|
if (!addr.startsWith("/meters")) this.logger.debug(LogCategory.DISPATCH, `Handling`, {
|
|
667
1455
|
addr,
|
|
668
|
-
args
|
|
1456
|
+
args
|
|
669
1457
|
});
|
|
670
|
-
for (const strategy of this.strategies) if (strategy.canHandle(addr)) {
|
|
671
|
-
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);
|
|
672
1463
|
if (replies.length > 0) this.logger.debug(LogCategory.DISPATCH, `Strategy ${strategy.constructor.name} replied`, { count: replies.length });
|
|
673
1464
|
return replies;
|
|
674
1465
|
}
|
|
675
1466
|
this.logger.warn(LogCategory.DISPATCH, `Unknown Command`, {
|
|
676
1467
|
addr,
|
|
677
|
-
args
|
|
1468
|
+
args,
|
|
678
1469
|
ip: source.address
|
|
679
1470
|
});
|
|
680
1471
|
return [];
|
|
@@ -788,6 +1579,8 @@ var MeterService = class {
|
|
|
788
1579
|
//#region src/domain/services/StaticResponseService.ts
|
|
789
1580
|
/**
|
|
790
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.
|
|
791
1584
|
*/
|
|
792
1585
|
const STATIC_RESPONSES_DATA = {
|
|
793
1586
|
"/xinfo": [
|
|
@@ -806,34 +1599,7 @@ const STATIC_RESPONSES_DATA = {
|
|
|
806
1599
|
"active",
|
|
807
1600
|
"{{ip}}",
|
|
808
1601
|
"{{name}}"
|
|
809
|
-
]
|
|
810
|
-
"/-prefs/invertmutes": [0],
|
|
811
|
-
"/-prefs/fine": [0],
|
|
812
|
-
"/-prefs/bright": [50],
|
|
813
|
-
"/-prefs/contrast": [50],
|
|
814
|
-
"/-prefs/led_bright": [50],
|
|
815
|
-
"/-prefs/lcd_bright": [50],
|
|
816
|
-
"/-stat/userpar/1/value": [0],
|
|
817
|
-
"/-stat/userpar/2/value": [0],
|
|
818
|
-
"/-stat/tape/state": [0],
|
|
819
|
-
"/-stat/aes50/A": [0],
|
|
820
|
-
"/-stat/aes50/B": [0],
|
|
821
|
-
"/-stat/solo": [0],
|
|
822
|
-
"/-stat/rtasource": [0],
|
|
823
|
-
"/-urec/errorcode": [0],
|
|
824
|
-
"/-prefs/rta/gain": [0],
|
|
825
|
-
"/-prefs/rta/autogain": [0],
|
|
826
|
-
"/-prefs/hardmute": [0],
|
|
827
|
-
"/-prefs/dcamute": [0],
|
|
828
|
-
"/config/mono/mode": [0],
|
|
829
|
-
"/config/amixenable/X": [0],
|
|
830
|
-
"/config/amixenable/Y": [0],
|
|
831
|
-
"/-show/prepos/current": [0],
|
|
832
|
-
"/-show/showfile/current": [""],
|
|
833
|
-
"/-action/setrtasrc": [0],
|
|
834
|
-
"/-action/playtrack": [0],
|
|
835
|
-
"/-action/goscene": [0],
|
|
836
|
-
"/-action/setscene": [0]
|
|
1602
|
+
]
|
|
837
1603
|
};
|
|
838
1604
|
/**
|
|
839
1605
|
* Service providing static system responses.
|
|
@@ -863,47 +1629,51 @@ function getLocalIp() {
|
|
|
863
1629
|
return "127.0.0.1";
|
|
864
1630
|
}
|
|
865
1631
|
/**
|
|
866
|
-
* The core service that manages the X32 simulation, including networking,
|
|
1632
|
+
* The core service that manages the X32 simulation, including networking,
|
|
867
1633
|
* state management, and OSC message handling.
|
|
868
1634
|
*/
|
|
869
1635
|
var SimulationService = class {
|
|
870
1636
|
subscriptionManager;
|
|
871
1637
|
messageHandler;
|
|
1638
|
+
state;
|
|
872
1639
|
processPacket;
|
|
873
1640
|
broadcastUpdates;
|
|
874
1641
|
manageSessions;
|
|
875
1642
|
meterService;
|
|
876
1643
|
staticResponseService;
|
|
1644
|
+
config;
|
|
877
1645
|
updateInterval = null;
|
|
878
1646
|
cleanupInterval = null;
|
|
879
1647
|
/**
|
|
880
1648
|
* Creates a new SimulationService instance.
|
|
881
1649
|
* @param gateway - The network gateway for OSC communication.
|
|
882
1650
|
* @param logger - The logger service.
|
|
883
|
-
* @param
|
|
1651
|
+
* @param stateRepository - The repository for state persistence.
|
|
884
1652
|
* @param schemaRegistry - The registry for X32 OSC schema.
|
|
885
|
-
* @param port - UDP port to listen on (default
|
|
886
|
-
* @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).
|
|
887
1655
|
* @param name - Reported console name.
|
|
888
1656
|
* @param model - Reported console model.
|
|
1657
|
+
* @param configOverrides - Optional configuration overrides.
|
|
889
1658
|
*/
|
|
890
|
-
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) {
|
|
891
1660
|
this.gateway = gateway;
|
|
892
1661
|
this.logger = logger;
|
|
893
|
-
this.
|
|
1662
|
+
this.stateRepository = stateRepository;
|
|
894
1663
|
this.schemaRegistry = schemaRegistry;
|
|
895
1664
|
this.port = port;
|
|
896
1665
|
this.ip = ip;
|
|
897
|
-
|
|
898
|
-
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);
|
|
899
1669
|
this.meterService = new MeterService();
|
|
900
1670
|
this.staticResponseService = new StaticResponseService();
|
|
901
1671
|
const reportedIp = this.ip === "0.0.0.0" ? getLocalIp() : this.ip;
|
|
902
|
-
this.messageHandler = new OscMessageHandler(state, this.subscriptionManager, logger, reportedIp, name, model, this.meterService, this.schemaRegistry, this.staticResponseService);
|
|
903
|
-
this.processPacket = new ProcessPacketUseCase(this.messageHandler, gateway);
|
|
904
|
-
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);
|
|
905
1675
|
this.manageSessions = new ManageSessionsUseCase(this.subscriptionManager);
|
|
906
|
-
state.on("change", (evt) => {
|
|
1676
|
+
this.state.on("change", (evt) => {
|
|
907
1677
|
this.logger.info(LogCategory.STATE, `State Changed`, evt);
|
|
908
1678
|
this.broadcastUpdates.broadcastSingleChange(evt.address, evt.value);
|
|
909
1679
|
});
|
|
@@ -913,13 +1683,14 @@ var SimulationService = class {
|
|
|
913
1683
|
* Starts the simulator server and internal loops.
|
|
914
1684
|
*/
|
|
915
1685
|
async start() {
|
|
1686
|
+
await this.state.initialize();
|
|
916
1687
|
await this.gateway.start(this.port, this.ip);
|
|
917
1688
|
this.cleanupInterval = setInterval(() => {
|
|
918
1689
|
this.manageSessions.cleanup();
|
|
919
|
-
},
|
|
1690
|
+
}, this.config.CLEANUP_INTERVAL_MS);
|
|
920
1691
|
this.updateInterval = setInterval(() => {
|
|
921
1692
|
this.broadcastUpdates.execute();
|
|
922
|
-
},
|
|
1693
|
+
}, this.config.BROADCAST_INTERVAL_MS);
|
|
923
1694
|
}
|
|
924
1695
|
/**
|
|
925
1696
|
* Stops the simulator server and stops all internal loops.
|
|
@@ -927,84 +1698,20 @@ var SimulationService = class {
|
|
|
927
1698
|
async stop() {
|
|
928
1699
|
if (this.updateInterval) clearInterval(this.updateInterval);
|
|
929
1700
|
if (this.cleanupInterval) clearInterval(this.cleanupInterval);
|
|
1701
|
+
await this.state.flush();
|
|
930
1702
|
await this.gateway.stop();
|
|
931
1703
|
}
|
|
932
1704
|
/**
|
|
933
1705
|
* Resets the mixer state to default values.
|
|
934
1706
|
*/
|
|
935
1707
|
resetState() {
|
|
936
|
-
this.
|
|
937
|
-
}
|
|
938
|
-
};
|
|
939
|
-
|
|
940
|
-
//#endregion
|
|
941
|
-
//#region src/domain/entities/X32State.ts
|
|
942
|
-
/**
|
|
943
|
-
* Manages the internal "Digital Twin" state of the X32 console.
|
|
944
|
-
* It acts as a single source of truth for all parameters.
|
|
945
|
-
* Emits 'change' events whenever a value is updated.
|
|
946
|
-
*/
|
|
947
|
-
var X32State = class extends node_events.EventEmitter {
|
|
948
|
-
/** Map storing all OSC paths and their current values. */
|
|
949
|
-
state = /* @__PURE__ */ new Map();
|
|
950
|
-
defaultState = /* @__PURE__ */ new Map();
|
|
951
|
-
/**
|
|
952
|
-
* Initializes the state with default values from the schema.
|
|
953
|
-
* @param schema - The schema definition map.
|
|
954
|
-
*/
|
|
955
|
-
constructor(schema) {
|
|
956
|
-
super();
|
|
957
|
-
for (const [addr, def] of Object.entries(schema)) this.defaultState.set(addr, def.default);
|
|
958
|
-
this.reset();
|
|
959
|
-
}
|
|
960
|
-
/**
|
|
961
|
-
* Resets all state parameters to their default values defined in the schema.
|
|
962
|
-
*/
|
|
963
|
-
reset() {
|
|
964
|
-
this.state.clear();
|
|
965
|
-
this.defaultState.forEach((val, key) => {
|
|
966
|
-
this.state.set(key, val);
|
|
967
|
-
});
|
|
1708
|
+
this.state.reset();
|
|
968
1709
|
}
|
|
969
1710
|
/**
|
|
970
|
-
*
|
|
971
|
-
* @param address - The full OSC address path.
|
|
972
|
-
* @returns The stored value (number or string) or undefined if not found.
|
|
1711
|
+
* Forces a save of the current state to storage.
|
|
973
1712
|
*/
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
}
|
|
977
|
-
/**
|
|
978
|
-
* Updates the value of a specific OSC node and notifies subscribers.
|
|
979
|
-
* @param address - The full OSC address path.
|
|
980
|
-
* @param value - The new value to store.
|
|
981
|
-
*/
|
|
982
|
-
set(address, value) {
|
|
983
|
-
this.state.set(address, value);
|
|
984
|
-
this.emit("change", {
|
|
985
|
-
address,
|
|
986
|
-
value
|
|
987
|
-
});
|
|
988
|
-
}
|
|
989
|
-
/**
|
|
990
|
-
* Specialized logic to handle X32 Mute Groups side-effects.
|
|
991
|
-
* When a mute group is toggled, it iterates through all channels
|
|
992
|
-
* assigned to that group and updates their individual mute status.
|
|
993
|
-
* @param groupIdx - The index of the mute group (1-6).
|
|
994
|
-
* @param isOn - The new state of the group master switch (0 or 1).
|
|
995
|
-
*/
|
|
996
|
-
handleMuteGroupChange(groupIdx, isOn) {
|
|
997
|
-
for (let i = 1; i <= 32; i++) {
|
|
998
|
-
const ch = i.toString().padStart(2, "0");
|
|
999
|
-
const grpVal = this.get(`/ch/${ch}/grp/mute`);
|
|
1000
|
-
if (typeof grpVal === "number") {
|
|
1001
|
-
if ((grpVal & 1 << groupIdx - 1) !== 0) {
|
|
1002
|
-
const targetMute = isOn === 1 ? 0 : 1;
|
|
1003
|
-
const muteAddr = `/ch/${ch}/mix/on`;
|
|
1004
|
-
this.set(muteAddr, targetMute);
|
|
1005
|
-
}
|
|
1006
|
-
}
|
|
1007
|
-
}
|
|
1713
|
+
async saveState() {
|
|
1714
|
+
await this.state.flush();
|
|
1008
1715
|
}
|
|
1009
1716
|
};
|
|
1010
1717
|
|
|
@@ -1019,69 +1726,106 @@ var X32Node = class X32Node {
|
|
|
1019
1726
|
type;
|
|
1020
1727
|
/** Default value for reset. */
|
|
1021
1728
|
default;
|
|
1729
|
+
/** Optional validation constraints. */
|
|
1730
|
+
options;
|
|
1022
1731
|
/**
|
|
1023
1732
|
* Creates a new X32Node.
|
|
1024
1733
|
* @param type - The OSC data type ('f', 'i', 's').
|
|
1025
1734
|
* @param defaultValue - The default value.
|
|
1735
|
+
* @param options - Optional validation constraints.
|
|
1026
1736
|
*/
|
|
1027
|
-
constructor(type, defaultValue) {
|
|
1737
|
+
constructor(type, defaultValue, options) {
|
|
1028
1738
|
this.type = type;
|
|
1029
1739
|
this.default = defaultValue;
|
|
1740
|
+
this.options = options;
|
|
1030
1741
|
}
|
|
1031
1742
|
/**
|
|
1032
1743
|
* Validates if a value is compatible with this node's type.
|
|
1033
1744
|
* @param value - The value to check.
|
|
1745
|
+
* @param strict - If true, also validates against min/max constraints.
|
|
1034
1746
|
* @returns True if valid.
|
|
1035
1747
|
*/
|
|
1036
|
-
validate(value) {
|
|
1037
|
-
if (this.type === "f"
|
|
1038
|
-
if (this.type === "i"
|
|
1039
|
-
if (this.type === "s"
|
|
1040
|
-
|
|
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;
|
|
1041
1758
|
}
|
|
1042
1759
|
/**
|
|
1043
1760
|
* Factory method to create from a plain object (for compatibility/migration).
|
|
1044
1761
|
* @param obj - Plain object.
|
|
1045
1762
|
* @param obj.type - OSC data type.
|
|
1046
1763
|
* @param obj.default - Default value.
|
|
1764
|
+
* @param obj.options - Optional validation constraints.
|
|
1047
1765
|
* @returns A new X32Node instance.
|
|
1048
1766
|
*/
|
|
1049
1767
|
static from(obj) {
|
|
1050
|
-
return new X32Node(obj.type, obj.default);
|
|
1768
|
+
return new X32Node(obj.type, obj.default, obj.options);
|
|
1051
1769
|
}
|
|
1052
1770
|
};
|
|
1053
1771
|
|
|
1054
1772
|
//#endregion
|
|
1055
1773
|
//#region src/infrastructure/repositories/InMemoryStateRepository.ts
|
|
1056
1774
|
/**
|
|
1057
|
-
* In-memory
|
|
1058
|
-
* Stores
|
|
1775
|
+
* In-memory state repository.
|
|
1776
|
+
* Stores state in a Map, no persistence across restarts.
|
|
1777
|
+
* This is the default and fastest option.
|
|
1059
1778
|
*/
|
|
1060
1779
|
var InMemoryStateRepository = class {
|
|
1061
|
-
state;
|
|
1780
|
+
state = /* @__PURE__ */ new Map();
|
|
1062
1781
|
/**
|
|
1063
|
-
*
|
|
1064
|
-
*
|
|
1065
|
-
* @param schemaRegistry - Registry providing the initial state schema.
|
|
1782
|
+
* Loads state from memory.
|
|
1783
|
+
* For in-memory storage, this returns current state.
|
|
1066
1784
|
*/
|
|
1067
|
-
|
|
1068
|
-
this.
|
|
1069
|
-
this.state = new X32State(schemaRegistry.getSchema());
|
|
1785
|
+
async load() {
|
|
1786
|
+
return this.getAll();
|
|
1070
1787
|
}
|
|
1071
1788
|
/**
|
|
1072
|
-
*
|
|
1073
|
-
*
|
|
1789
|
+
* Saves state to memory.
|
|
1790
|
+
* For in-memory storage, this replaces current state.
|
|
1074
1791
|
*/
|
|
1075
|
-
|
|
1076
|
-
|
|
1792
|
+
async save(state) {
|
|
1793
|
+
this.state.clear();
|
|
1794
|
+
for (const [key, value] of Object.entries(state)) this.state.set(key, value);
|
|
1077
1795
|
}
|
|
1078
1796
|
/**
|
|
1079
|
-
*
|
|
1797
|
+
* Gets a single value from memory.
|
|
1080
1798
|
*/
|
|
1081
|
-
|
|
1082
|
-
this.
|
|
1083
|
-
|
|
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);
|
|
1084
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);
|
|
1824
|
+
}
|
|
1825
|
+
/**
|
|
1826
|
+
* No-op for in-memory storage.
|
|
1827
|
+
*/
|
|
1828
|
+
async flush() {}
|
|
1085
1829
|
};
|
|
1086
1830
|
|
|
1087
1831
|
//#endregion
|
|
@@ -1900,41 +2644,215 @@ var SchemaFactory = class {
|
|
|
1900
2644
|
...this.generateRange(128, "/headamp", "/gain", "f", 0, 3, 0),
|
|
1901
2645
|
...this.generateRange(128, "/headamp", "/phantom", "i", 0, 3, 0),
|
|
1902
2646
|
...this.generateRange(6, "/config/mute", "", "i", 0),
|
|
1903
|
-
...this.generateRange(80, "/-stat/solosw", "", "i", 0),
|
|
2647
|
+
...this.generateRange(80, "/-stat/solosw", "", "i", 0, 2, 1),
|
|
1904
2648
|
"/-stat/selidx": this.node("i", 0),
|
|
2649
|
+
"/-stat/chfaderbank": this.node("i", 0),
|
|
2650
|
+
"/-stat/grpfaderbank": this.node("i", 0),
|
|
1905
2651
|
"/-stat/sendsonfader": this.node("i", 0),
|
|
1906
2652
|
"/-stat/bussendbank": this.node("i", 0),
|
|
2653
|
+
"/-stat/eqband": this.node("i", 0),
|
|
1907
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),
|
|
1908
2669
|
"/-stat/screen/screen": this.node("i", 0),
|
|
2670
|
+
"/-stat/screen/mutegrp": this.node("i", 0),
|
|
2671
|
+
"/-stat/screen/utils": this.node("i", 0),
|
|
1909
2672
|
"/-stat/screen/CHAN/page": this.node("i", 0),
|
|
1910
2673
|
"/-stat/screen/METER/page": this.node("i", 0),
|
|
1911
2674
|
"/-stat/screen/ROUTE/page": this.node("i", 0),
|
|
1912
2675
|
"/-stat/screen/SETUP/page": this.node("i", 0),
|
|
2676
|
+
"/-stat/screen/LIB/page": this.node("i", 0),
|
|
1913
2677
|
"/-stat/screen/LIBRARY/page": this.node("i", 0),
|
|
1914
2678
|
"/-stat/screen/FX/page": this.node("i", 0),
|
|
1915
2679
|
"/-stat/screen/MON/page": this.node("i", 0),
|
|
1916
2680
|
"/-stat/screen/USB/page": this.node("i", 0),
|
|
1917
2681
|
"/-stat/screen/SCENE/page": this.node("i", 0),
|
|
1918
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),
|
|
1919
2695
|
"/-stat/talk/A": this.node("i", 0),
|
|
1920
2696
|
"/-stat/talk/B": this.node("i", 0),
|
|
1921
2697
|
"/-stat/osc/on": this.node("i", 0),
|
|
1922
|
-
"/-
|
|
1923
|
-
"/-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),
|
|
1924
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),
|
|
1925
2714
|
"/-action/goscene": this.node("i", 0),
|
|
1926
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),
|
|
1927
2832
|
"/config/routing/AES50A/1-8": this.node("i", 0),
|
|
1928
2833
|
"/config/routing/AES50B/1-8": this.node("i", 0),
|
|
1929
2834
|
"/config/routing/CARD/1-8": this.node("i", 0),
|
|
1930
2835
|
"/config/routing/OUT/1-4": this.node("i", 0),
|
|
1931
|
-
"/-prefs/invertmutes": this.node("i", 0),
|
|
1932
2836
|
...this.generateChannelStrip("/main/st", 6, false),
|
|
1933
2837
|
...this.generateChannelStrip("/main/m", 6, false),
|
|
1934
2838
|
...Object.fromEntries(Array.from({ length: 16 }, (_, i) => [`/config/chlink/${i * 2 + 1}-${i * 2 + 2}`, this.node("i", 0)])),
|
|
1935
2839
|
...Object.fromEntries(Array.from({ length: 8 }, (_, i) => [`/config/buslink/${i * 2 + 1}-${i * 2 + 2}`, this.node("i", 0)])),
|
|
1936
2840
|
...Object.fromEntries(Array.from({ length: 4 }, (_, i) => [`/config/auxlink/${i * 2 + 1}-${i * 2 + 2}`, this.node("i", 0)])),
|
|
1937
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),
|
|
1938
2856
|
...this.generateRange(32, "/config/userrout/in", "", "i", 0),
|
|
1939
2857
|
...this.generateRange(48, "/config/userrout/out", "", "i", 0),
|
|
1940
2858
|
"/config/solo/level": this.node("f", 0),
|
|
@@ -1970,6 +2888,7 @@ var SchemaFactory = class {
|
|
|
1970
2888
|
"/config/osc/f2": this.node("f", .5),
|
|
1971
2889
|
"/config/osc/level": this.node("f", 0),
|
|
1972
2890
|
"/config/osc/dest": this.node("i", 0),
|
|
2891
|
+
...this.generateDP48Config(),
|
|
1973
2892
|
...this.generateOutputs("main", 16),
|
|
1974
2893
|
...this.generateOutputs("aux", 6),
|
|
1975
2894
|
...this.generateOutputs("p16", 16),
|
|
@@ -1977,7 +2896,11 @@ var SchemaFactory = class {
|
|
|
1977
2896
|
...this.generateOutputs("rec", 2)
|
|
1978
2897
|
};
|
|
1979
2898
|
Object.keys(STATIC_RESPONSES_DATA).forEach((key) => {
|
|
1980
|
-
if (key.startsWith("/-")
|
|
2899
|
+
if (key.startsWith("/-")) {
|
|
2900
|
+
const val = STATIC_RESPONSES_DATA[key][0];
|
|
2901
|
+
const type = typeof val === "string" ? "s" : Number.isInteger(val) ? "i" : "f";
|
|
2902
|
+
schema[key] = this.node(type, val);
|
|
2903
|
+
}
|
|
1981
2904
|
});
|
|
1982
2905
|
[
|
|
1983
2906
|
"/config/routing/IN/1-8",
|
|
@@ -2088,6 +3011,7 @@ var SchemaFactory = class {
|
|
|
2088
3011
|
generateNodes(count, prefix) {
|
|
2089
3012
|
const nodes = {};
|
|
2090
3013
|
const isChannelOrAux = prefix === "ch" || prefix === "auxin";
|
|
3014
|
+
const hasMtxPreamp = prefix === "mtx";
|
|
2091
3015
|
const eqBands = prefix === "bus" || prefix === "mtx" ? 6 : 4;
|
|
2092
3016
|
for (let i = 1; i <= count; i++) {
|
|
2093
3017
|
const padId = i.toString().padStart(2, "0");
|
|
@@ -2099,7 +3023,7 @@ var SchemaFactory = class {
|
|
|
2099
3023
|
nodes[`${base}/fader`] = this.node("f", .75);
|
|
2100
3024
|
nodes[`${base}/on`] = this.node("i", 0);
|
|
2101
3025
|
} else {
|
|
2102
|
-
Object.assign(nodes, this.generateChannelStrip(base, eqBands, isChannelOrAux));
|
|
3026
|
+
Object.assign(nodes, this.generateChannelStrip(base, eqBands, isChannelOrAux || hasMtxPreamp));
|
|
2103
3027
|
if (prefix === "ch" || prefix === "auxin" || prefix === "fxrtn" || prefix === "bus") for (let b = 1; b <= 16; b++) {
|
|
2104
3028
|
const busId = b.toString().padStart(2, "0");
|
|
2105
3029
|
nodes[`${base}/mix/${busId}/level`] = this.node("f", 0);
|
|
@@ -2107,6 +3031,11 @@ var SchemaFactory = class {
|
|
|
2107
3031
|
nodes[`${base}/mix/${busId}/pan`] = this.node("f", .5);
|
|
2108
3032
|
nodes[`${base}/mix/${busId}/type`] = this.node("i", 0);
|
|
2109
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
|
+
}
|
|
2110
3039
|
}
|
|
2111
3040
|
});
|
|
2112
3041
|
}
|
|
@@ -2139,6 +3068,159 @@ var SchemaFactory = class {
|
|
|
2139
3068
|
}
|
|
2140
3069
|
return nodes;
|
|
2141
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
|
+
}
|
|
2142
3224
|
};
|
|
2143
3225
|
|
|
2144
3226
|
//#endregion
|
|
@@ -2209,6 +3291,12 @@ Object.defineProperty(exports, 'ConsoleLogger', {
|
|
|
2209
3291
|
return ConsoleLogger;
|
|
2210
3292
|
}
|
|
2211
3293
|
});
|
|
3294
|
+
Object.defineProperty(exports, 'DEFAULT_CONFIG', {
|
|
3295
|
+
enumerable: true,
|
|
3296
|
+
get: function () {
|
|
3297
|
+
return DEFAULT_CONFIG;
|
|
3298
|
+
}
|
|
3299
|
+
});
|
|
2212
3300
|
Object.defineProperty(exports, 'InMemoryStateRepository', {
|
|
2213
3301
|
enumerable: true,
|
|
2214
3302
|
get: function () {
|
|
@@ -2292,4 +3380,10 @@ Object.defineProperty(exports, '__toESM', {
|
|
|
2292
3380
|
get: function () {
|
|
2293
3381
|
return __toESM;
|
|
2294
3382
|
}
|
|
3383
|
+
});
|
|
3384
|
+
Object.defineProperty(exports, 'mergeConfig', {
|
|
3385
|
+
enumerable: true,
|
|
3386
|
+
get: function () {
|
|
3387
|
+
return mergeConfig;
|
|
3388
|
+
}
|
|
2295
3389
|
});
|