@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
|
@@ -1,32 +1,8 @@
|
|
|
1
|
-
import * as os from "os";
|
|
2
1
|
import { EventEmitter } from "node:events";
|
|
2
|
+
import * as os from "os";
|
|
3
3
|
import * as dgram from "node:dgram";
|
|
4
4
|
import { Buffer as Buffer$1 } from "node:buffer";
|
|
5
5
|
|
|
6
|
-
//#region src/application/use-cases/ProcessPacketUseCase.ts
|
|
7
|
-
var ProcessPacketUseCase = class {
|
|
8
|
-
constructor(messageHandler, gateway) {
|
|
9
|
-
this.messageHandler = messageHandler;
|
|
10
|
-
this.gateway = gateway;
|
|
11
|
-
}
|
|
12
|
-
execute(packet, rinfo) {
|
|
13
|
-
if (packet.oscType === "bundle") packet.elements?.forEach((el) => this.execute(el, rinfo));
|
|
14
|
-
else if (packet.oscType === "message") {
|
|
15
|
-
const args = packet.args.map((arg) => {
|
|
16
|
-
if (typeof arg === "object" && arg !== null && "value" in arg) return arg.value;
|
|
17
|
-
return arg;
|
|
18
|
-
});
|
|
19
|
-
this.messageHandler.handle({
|
|
20
|
-
address: packet.address,
|
|
21
|
-
args
|
|
22
|
-
}, rinfo).forEach((reply) => {
|
|
23
|
-
this.gateway.send(rinfo, reply.address, reply.args);
|
|
24
|
-
});
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
//#endregion
|
|
30
6
|
//#region src/domain/ports/ILogger.ts
|
|
31
7
|
/**
|
|
32
8
|
* Standard log categories for the domain.
|
|
@@ -42,6 +18,35 @@ let LogCategory = /* @__PURE__ */ function(LogCategory$1) {
|
|
|
42
18
|
return LogCategory$1;
|
|
43
19
|
}({});
|
|
44
20
|
|
|
21
|
+
//#endregion
|
|
22
|
+
//#region src/application/use-cases/ProcessPacketUseCase.ts
|
|
23
|
+
var ProcessPacketUseCase = class {
|
|
24
|
+
constructor(messageHandler, gateway, logger) {
|
|
25
|
+
this.messageHandler = messageHandler;
|
|
26
|
+
this.gateway = gateway;
|
|
27
|
+
this.logger = logger;
|
|
28
|
+
}
|
|
29
|
+
execute(packet, rinfo) {
|
|
30
|
+
try {
|
|
31
|
+
if (packet.oscType === "bundle") packet.elements?.forEach((el) => this.execute(el, rinfo));
|
|
32
|
+
else if (packet.oscType === "message") {
|
|
33
|
+
const args = packet.args.map((arg) => {
|
|
34
|
+
if (typeof arg === "object" && arg !== null && "value" in arg) return arg.value;
|
|
35
|
+
return arg;
|
|
36
|
+
});
|
|
37
|
+
this.messageHandler.handle({
|
|
38
|
+
address: packet.address,
|
|
39
|
+
args
|
|
40
|
+
}, rinfo).forEach((reply) => {
|
|
41
|
+
this.gateway.send(rinfo, reply.address, reply.args);
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
} catch (err) {
|
|
45
|
+
this.logger?.error(LogCategory.DISPATCH, `Error processing packet from ${rinfo.address}:${rinfo.port}`, err instanceof Error ? err : new Error(String(err)));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
|
|
45
50
|
//#endregion
|
|
46
51
|
//#region src/application/use-cases/BroadcastUpdatesUseCase.ts
|
|
47
52
|
var BroadcastUpdatesUseCase = class {
|
|
@@ -159,16 +164,134 @@ var ManageSessionsUseCase = class {
|
|
|
159
164
|
}
|
|
160
165
|
};
|
|
161
166
|
|
|
167
|
+
//#endregion
|
|
168
|
+
//#region src/domain/entities/X32State.ts
|
|
169
|
+
/**
|
|
170
|
+
* Manages the internal "Digital Twin" state of the X32 console.
|
|
171
|
+
* It acts as a single source of truth for all parameters.
|
|
172
|
+
* Emits 'change' events whenever a value is updated.
|
|
173
|
+
* Uses an injectable repository for storage (memory or persistent).
|
|
174
|
+
*/
|
|
175
|
+
var X32State = class extends EventEmitter {
|
|
176
|
+
defaultState = /* @__PURE__ */ new Map();
|
|
177
|
+
/**
|
|
178
|
+
* Initializes the state with default values from the schema.
|
|
179
|
+
* @param schema - The schema definition map.
|
|
180
|
+
* @param repository - The storage repository (injectable).
|
|
181
|
+
*/
|
|
182
|
+
constructor(schema, repository) {
|
|
183
|
+
super();
|
|
184
|
+
this.repository = repository;
|
|
185
|
+
for (const [addr, def] of Object.entries(schema)) this.defaultState.set(addr, def.default);
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Initializes the state - loads from repository or resets to defaults.
|
|
189
|
+
*/
|
|
190
|
+
async initialize() {
|
|
191
|
+
const stored = await this.repository.load();
|
|
192
|
+
if (Object.keys(stored).length === 0) this.reset();
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Resets all state parameters to their default values defined in the schema.
|
|
196
|
+
*/
|
|
197
|
+
reset() {
|
|
198
|
+
const defaults = {};
|
|
199
|
+
this.defaultState.forEach((val, key) => {
|
|
200
|
+
defaults[key] = val;
|
|
201
|
+
});
|
|
202
|
+
this.repository.reset(defaults);
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Retrieves the value of a specific OSC node.
|
|
206
|
+
* @param address - The full OSC address path.
|
|
207
|
+
* @returns The stored value (number or string) or undefined if not found.
|
|
208
|
+
*/
|
|
209
|
+
get(address) {
|
|
210
|
+
return this.repository.get(address);
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Retrieves all state entries as a plain object.
|
|
214
|
+
* @returns A record of all OSC addresses and their current values.
|
|
215
|
+
*/
|
|
216
|
+
getAll() {
|
|
217
|
+
return this.repository.getAll();
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Updates the value of a specific OSC node and notifies subscribers.
|
|
221
|
+
* @param address - The full OSC address path.
|
|
222
|
+
* @param value - The new value to store.
|
|
223
|
+
*/
|
|
224
|
+
set(address, value) {
|
|
225
|
+
this.repository.set(address, value);
|
|
226
|
+
this.emit("change", {
|
|
227
|
+
address,
|
|
228
|
+
value
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Flushes pending changes to persistent storage.
|
|
233
|
+
*/
|
|
234
|
+
async flush() {
|
|
235
|
+
await this.repository.flush();
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Specialized logic to handle X32 Mute Groups side-effects.
|
|
239
|
+
* When a mute group is toggled, it iterates through all channels
|
|
240
|
+
* assigned to that group and updates their individual mute status.
|
|
241
|
+
* @param groupIdx - The index of the mute group (1-6).
|
|
242
|
+
* @param isOn - The new state of the group master switch (0 or 1).
|
|
243
|
+
*/
|
|
244
|
+
handleMuteGroupChange(groupIdx, isOn) {
|
|
245
|
+
for (let i = 1; i <= 32; i++) {
|
|
246
|
+
const ch = i.toString().padStart(2, "0");
|
|
247
|
+
const grpVal = this.get(`/ch/${ch}/grp/mute`);
|
|
248
|
+
if (typeof grpVal === "number") {
|
|
249
|
+
if ((grpVal & 1 << groupIdx - 1) !== 0) {
|
|
250
|
+
const targetMute = isOn === 1 ? 0 : 1;
|
|
251
|
+
const muteAddr = `/ch/${ch}/mix/on`;
|
|
252
|
+
this.set(muteAddr, targetMute);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
//#endregion
|
|
260
|
+
//#region src/domain/models/Config.ts
|
|
261
|
+
/**
|
|
262
|
+
* Default configuration values for the simulator.
|
|
263
|
+
*/
|
|
264
|
+
const DEFAULT_CONFIG = {
|
|
265
|
+
SUBSCRIPTION_TTL_MS: 1e4,
|
|
266
|
+
CLEANUP_INTERVAL_MS: 5e3,
|
|
267
|
+
BROADCAST_INTERVAL_MS: 100,
|
|
268
|
+
DEFAULT_PORT: 10023,
|
|
269
|
+
DEFAULT_HOST: "0.0.0.0",
|
|
270
|
+
DEFAULT_NAME: "osc-server",
|
|
271
|
+
DEFAULT_MODEL: "X32"
|
|
272
|
+
};
|
|
273
|
+
/**
|
|
274
|
+
* Merges user-provided configuration with defaults.
|
|
275
|
+
* @param partial - Partial configuration to merge.
|
|
276
|
+
* @returns Complete configuration with defaults applied.
|
|
277
|
+
*/
|
|
278
|
+
function mergeConfig(partial) {
|
|
279
|
+
return {
|
|
280
|
+
...DEFAULT_CONFIG,
|
|
281
|
+
...partial
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
|
|
162
285
|
//#endregion
|
|
163
286
|
//#region src/domain/entities/SubscriptionManager.ts
|
|
164
287
|
/**
|
|
165
288
|
* Manages OSC client subscriptions and their lifecycle.
|
|
166
289
|
*/
|
|
167
290
|
var SubscriptionManager = class {
|
|
168
|
-
logger;
|
|
169
291
|
subscribers = [];
|
|
170
|
-
constructor(logger) {
|
|
292
|
+
constructor(logger, subscriptionTtlMs = DEFAULT_CONFIG.SUBSCRIPTION_TTL_MS) {
|
|
171
293
|
this.logger = logger;
|
|
294
|
+
this.subscriptionTtlMs = subscriptionTtlMs;
|
|
172
295
|
}
|
|
173
296
|
/**
|
|
174
297
|
* Cleans up expired subscriptions.
|
|
@@ -206,7 +329,7 @@ var SubscriptionManager = class {
|
|
|
206
329
|
*/
|
|
207
330
|
addPathSubscriber(rinfo, path) {
|
|
208
331
|
const key = `${rinfo.address}:${rinfo.port}:${path}`;
|
|
209
|
-
const expires = Date.now() +
|
|
332
|
+
const expires = Date.now() + this.subscriptionTtlMs;
|
|
210
333
|
const existing = this.subscribers.find((s) => s.type === "path" && `${s.address}:${s.port}:${s.path}` === key);
|
|
211
334
|
if (existing) {
|
|
212
335
|
existing.expires = expires;
|
|
@@ -239,7 +362,7 @@ var SubscriptionManager = class {
|
|
|
239
362
|
* @param args - Command arguments.
|
|
240
363
|
*/
|
|
241
364
|
addBatchSubscriber(rinfo, alias, paths, start, count, factor, args) {
|
|
242
|
-
const expires = Date.now() +
|
|
365
|
+
const expires = Date.now() + this.subscriptionTtlMs;
|
|
243
366
|
this.subscribers = this.subscribers.filter((s) => !(s.type === "batch" && s.alias === alias && s.address === rinfo.address));
|
|
244
367
|
this.subscribers.push({
|
|
245
368
|
type: "batch",
|
|
@@ -271,7 +394,7 @@ var SubscriptionManager = class {
|
|
|
271
394
|
* @param factor - Frequency factor.
|
|
272
395
|
*/
|
|
273
396
|
addFormatSubscriber(rinfo, alias, pattern, start, count, factor) {
|
|
274
|
-
const expires = Date.now() +
|
|
397
|
+
const expires = Date.now() + this.subscriptionTtlMs;
|
|
275
398
|
this.subscribers = this.subscribers.filter((s) => !(s.type === "format" && s.alias === alias && s.address === rinfo.address));
|
|
276
399
|
this.subscribers.push({
|
|
277
400
|
type: "format",
|
|
@@ -297,7 +420,7 @@ var SubscriptionManager = class {
|
|
|
297
420
|
* @param meterPath - Target meter path.
|
|
298
421
|
*/
|
|
299
422
|
addMeterSubscriber(rinfo, meterPath) {
|
|
300
|
-
const expires = Date.now() +
|
|
423
|
+
const expires = Date.now() + this.subscriptionTtlMs;
|
|
301
424
|
const existing = this.subscribers.find((s) => s.type === "meter" && s.meterPath === meterPath && s.address === rinfo.address);
|
|
302
425
|
this.subscribers = this.subscribers.filter((s) => !(s.type === "meter" && s.meterPath === meterPath && s.address === rinfo.address));
|
|
303
426
|
this.subscribers.push({
|
|
@@ -345,8 +468,7 @@ var NodeDiscoveryStrategy = class {
|
|
|
345
468
|
return address === "/node";
|
|
346
469
|
}
|
|
347
470
|
execute(msg, _source) {
|
|
348
|
-
const queryPath = msg.args[0];
|
|
349
|
-
if (!queryPath) return [];
|
|
471
|
+
const queryPath = msg.args[0] || "/";
|
|
350
472
|
const children = /* @__PURE__ */ new Set();
|
|
351
473
|
const prefix = queryPath.endsWith("/") ? queryPath : `${queryPath}/`;
|
|
352
474
|
for (const key of this.schemaRegistry.getAllPaths()) if (key.startsWith(prefix)) {
|
|
@@ -363,8 +485,9 @@ var NodeDiscoveryStrategy = class {
|
|
|
363
485
|
//#endregion
|
|
364
486
|
//#region src/domain/services/strategies/StaticResponseStrategy.ts
|
|
365
487
|
/**
|
|
366
|
-
* Handles discovery and static information queries.
|
|
367
|
-
* e.g., /status, /xinfo
|
|
488
|
+
* Handles discovery and static information queries (GET only).
|
|
489
|
+
* e.g., /status, /xinfo
|
|
490
|
+
* Note: Only handles queries without arguments. SET commands pass through to StateAccessStrategy.
|
|
368
491
|
*/
|
|
369
492
|
var StaticResponseStrategy = class {
|
|
370
493
|
constructor(serverIp, serverName, serverModel, staticResponseService) {
|
|
@@ -373,7 +496,8 @@ var StaticResponseStrategy = class {
|
|
|
373
496
|
this.serverModel = serverModel;
|
|
374
497
|
this.staticResponseService = staticResponseService;
|
|
375
498
|
}
|
|
376
|
-
canHandle(address) {
|
|
499
|
+
canHandle(address, args) {
|
|
500
|
+
if (args && args.length > 0) return false;
|
|
377
501
|
return !!this.staticResponseService.getResponse(address);
|
|
378
502
|
}
|
|
379
503
|
execute(msg, _source) {
|
|
@@ -544,6 +668,7 @@ var MeterStrategy = class {
|
|
|
544
668
|
* LOGIC:
|
|
545
669
|
* - If no arguments: Treats as a QUERY (GET) and returns the current value.
|
|
546
670
|
* - If arguments provided: Treats as an UPDATE (SET) and stores the new value.
|
|
671
|
+
* - Unknown addresses are also stored in permissive mode for compatibility.
|
|
547
672
|
*/
|
|
548
673
|
var StateAccessStrategy = class {
|
|
549
674
|
/**
|
|
@@ -551,45 +676,687 @@ var StateAccessStrategy = class {
|
|
|
551
676
|
* @param state - Current mixer state.
|
|
552
677
|
* @param logger - Logger instance.
|
|
553
678
|
* @param schemaRegistry - Registry to validate addresses.
|
|
679
|
+
* @param permissive - If true, store unknown addresses too (default: true).
|
|
554
680
|
*/
|
|
555
|
-
constructor(state, logger, schemaRegistry) {
|
|
681
|
+
constructor(state, logger, schemaRegistry, permissive = true) {
|
|
556
682
|
this.state = state;
|
|
557
683
|
this.logger = logger;
|
|
558
684
|
this.schemaRegistry = schemaRegistry;
|
|
685
|
+
this.permissive = permissive;
|
|
559
686
|
}
|
|
560
687
|
/** @inheritdoc */
|
|
561
688
|
canHandle(address) {
|
|
562
|
-
|
|
689
|
+
if (this.schemaRegistry.has(address)) return true;
|
|
690
|
+
return this.permissive && address.startsWith("/");
|
|
563
691
|
}
|
|
564
692
|
/** @inheritdoc */
|
|
565
693
|
execute(msg, _source) {
|
|
566
694
|
const addr = msg.address;
|
|
567
695
|
const node = this.schemaRegistry.getNode(addr);
|
|
696
|
+
const isKnown = !!node;
|
|
568
697
|
if (msg.args.length === 0) {
|
|
569
698
|
const val$1 = this.state.get(addr);
|
|
570
699
|
if (val$1 !== void 0) return [{
|
|
571
700
|
address: addr,
|
|
572
701
|
args: [val$1]
|
|
573
702
|
}];
|
|
703
|
+
if (!isKnown) this.logger.debug(LogCategory.STATE, `[GET] Unknown address queried: ${addr}`);
|
|
574
704
|
return [];
|
|
575
705
|
}
|
|
576
706
|
const val = msg.args[0];
|
|
577
|
-
if (
|
|
707
|
+
if (isKnown) {
|
|
578
708
|
if (!node.validate(val)) {
|
|
579
709
|
this.logger.warn(LogCategory.DISPATCH, `[TYPE ERR] ${addr} expected ${node.type}, got ${typeof val}`);
|
|
580
710
|
return [];
|
|
581
711
|
}
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
712
|
+
} else this.logger.warn(LogCategory.STATE, `[UNKNOWN] Storing unknown address: ${addr} = ${val}`);
|
|
713
|
+
this.state.set(addr, val);
|
|
714
|
+
this.logger.debug(LogCategory.STATE, `[SET] ${addr} -> ${val}`);
|
|
715
|
+
if (addr.startsWith("/config/mute/")) {
|
|
716
|
+
const groupIdx = parseInt(addr.split("/").pop(), 10);
|
|
717
|
+
if (!isNaN(groupIdx)) this.state.handleMuteGroupChange(groupIdx, val);
|
|
718
|
+
}
|
|
719
|
+
if (addr === "/-action/undopt" && val === 1) {
|
|
720
|
+
const timeStr = (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", { hour12: false });
|
|
721
|
+
this.state.set("/-undo/time", timeStr);
|
|
722
|
+
this.logger.debug(LogCategory.STATE, `[UNDO] Checkpoint created at ${timeStr}`);
|
|
588
723
|
}
|
|
589
724
|
return [];
|
|
590
725
|
}
|
|
591
726
|
};
|
|
592
727
|
|
|
728
|
+
//#endregion
|
|
729
|
+
//#region src/domain/services/strategies/ShowDumpStrategy.ts
|
|
730
|
+
/**
|
|
731
|
+
* Handles the /showdump command which requests a full state dump.
|
|
732
|
+
* Used by X32-Edit during synchronization to retrieve all console parameters.
|
|
733
|
+
*/
|
|
734
|
+
var ShowDumpStrategy = class {
|
|
735
|
+
constructor(state, logger) {
|
|
736
|
+
this.state = state;
|
|
737
|
+
this.logger = logger;
|
|
738
|
+
}
|
|
739
|
+
/** @inheritdoc */
|
|
740
|
+
canHandle(address) {
|
|
741
|
+
return address === "/showdump";
|
|
742
|
+
}
|
|
743
|
+
/** @inheritdoc */
|
|
744
|
+
execute(_msg, _source) {
|
|
745
|
+
this.logger.debug(LogCategory.DISPATCH, "[SHOWDUMP] Full state dump requested");
|
|
746
|
+
const replies = [];
|
|
747
|
+
const allState = this.state.getAll();
|
|
748
|
+
for (const [address, value] of Object.entries(allState)) replies.push({
|
|
749
|
+
address,
|
|
750
|
+
args: [value]
|
|
751
|
+
});
|
|
752
|
+
this.logger.debug(LogCategory.DISPATCH, `[SHOWDUMP] Sending ${replies.length} state entries`);
|
|
753
|
+
return replies;
|
|
754
|
+
}
|
|
755
|
+
};
|
|
756
|
+
|
|
757
|
+
//#endregion
|
|
758
|
+
//#region src/domain/services/strategies/SceneDataStrategy.ts
|
|
759
|
+
/**
|
|
760
|
+
* Maps scene file format (batch values) to individual OSC addresses.
|
|
761
|
+
* The X32 scene format sends multiple values for a parent address.
|
|
762
|
+
* Example: /ch/01/mix ON -0.2 ON -100 OFF -oo
|
|
763
|
+
* 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
|
|
764
|
+
*/
|
|
765
|
+
const SCENE_MAPPINGS = {
|
|
766
|
+
"headamp": ["gain", "phantom"],
|
|
767
|
+
"config": [
|
|
768
|
+
"name",
|
|
769
|
+
"icon",
|
|
770
|
+
"color",
|
|
771
|
+
"source"
|
|
772
|
+
],
|
|
773
|
+
"delay": ["on", "time"],
|
|
774
|
+
"preamp": [
|
|
775
|
+
"trim",
|
|
776
|
+
"invert",
|
|
777
|
+
"hpon",
|
|
778
|
+
"hpslope",
|
|
779
|
+
"hpf"
|
|
780
|
+
],
|
|
781
|
+
"gate": [
|
|
782
|
+
"on",
|
|
783
|
+
"mode",
|
|
784
|
+
"thr",
|
|
785
|
+
"range",
|
|
786
|
+
"attack",
|
|
787
|
+
"hold",
|
|
788
|
+
"release",
|
|
789
|
+
"keysrc"
|
|
790
|
+
],
|
|
791
|
+
"gate/filter": [
|
|
792
|
+
"on",
|
|
793
|
+
"type",
|
|
794
|
+
"f"
|
|
795
|
+
],
|
|
796
|
+
"dyn": [
|
|
797
|
+
"on",
|
|
798
|
+
"mode",
|
|
799
|
+
"det",
|
|
800
|
+
"env",
|
|
801
|
+
"thr",
|
|
802
|
+
"ratio",
|
|
803
|
+
"knee",
|
|
804
|
+
"mgain",
|
|
805
|
+
"attack",
|
|
806
|
+
"hold",
|
|
807
|
+
"release",
|
|
808
|
+
"pos",
|
|
809
|
+
"keysrc",
|
|
810
|
+
"mix",
|
|
811
|
+
"auto"
|
|
812
|
+
],
|
|
813
|
+
"dyn/filter": [
|
|
814
|
+
"on",
|
|
815
|
+
"type",
|
|
816
|
+
"f"
|
|
817
|
+
],
|
|
818
|
+
"insert": [
|
|
819
|
+
"on",
|
|
820
|
+
"pos",
|
|
821
|
+
"sel"
|
|
822
|
+
],
|
|
823
|
+
"eq": ["on"],
|
|
824
|
+
"eq/1": [
|
|
825
|
+
"type",
|
|
826
|
+
"f",
|
|
827
|
+
"g",
|
|
828
|
+
"q"
|
|
829
|
+
],
|
|
830
|
+
"eq/2": [
|
|
831
|
+
"type",
|
|
832
|
+
"f",
|
|
833
|
+
"g",
|
|
834
|
+
"q"
|
|
835
|
+
],
|
|
836
|
+
"eq/3": [
|
|
837
|
+
"type",
|
|
838
|
+
"f",
|
|
839
|
+
"g",
|
|
840
|
+
"q"
|
|
841
|
+
],
|
|
842
|
+
"eq/4": [
|
|
843
|
+
"type",
|
|
844
|
+
"f",
|
|
845
|
+
"g",
|
|
846
|
+
"q"
|
|
847
|
+
],
|
|
848
|
+
"eq/5": [
|
|
849
|
+
"type",
|
|
850
|
+
"f",
|
|
851
|
+
"g",
|
|
852
|
+
"q"
|
|
853
|
+
],
|
|
854
|
+
"eq/6": [
|
|
855
|
+
"type",
|
|
856
|
+
"f",
|
|
857
|
+
"g",
|
|
858
|
+
"q"
|
|
859
|
+
],
|
|
860
|
+
"mix": [
|
|
861
|
+
"on",
|
|
862
|
+
"fader",
|
|
863
|
+
"st",
|
|
864
|
+
"pan",
|
|
865
|
+
"mono",
|
|
866
|
+
"mlevel"
|
|
867
|
+
],
|
|
868
|
+
"mix/01": [
|
|
869
|
+
"on",
|
|
870
|
+
"level",
|
|
871
|
+
"pan",
|
|
872
|
+
"type",
|
|
873
|
+
"panFollow"
|
|
874
|
+
],
|
|
875
|
+
"mix/02": ["on", "level"],
|
|
876
|
+
"mix/03": [
|
|
877
|
+
"on",
|
|
878
|
+
"level",
|
|
879
|
+
"pan",
|
|
880
|
+
"type",
|
|
881
|
+
"panFollow"
|
|
882
|
+
],
|
|
883
|
+
"mix/04": ["on", "level"],
|
|
884
|
+
"mix/05": [
|
|
885
|
+
"on",
|
|
886
|
+
"level",
|
|
887
|
+
"pan",
|
|
888
|
+
"type",
|
|
889
|
+
"panFollow"
|
|
890
|
+
],
|
|
891
|
+
"mix/06": ["on", "level"],
|
|
892
|
+
"mix/07": [
|
|
893
|
+
"on",
|
|
894
|
+
"level",
|
|
895
|
+
"pan",
|
|
896
|
+
"type",
|
|
897
|
+
"panFollow"
|
|
898
|
+
],
|
|
899
|
+
"mix/08": ["on", "level"],
|
|
900
|
+
"mix/09": [
|
|
901
|
+
"on",
|
|
902
|
+
"level",
|
|
903
|
+
"pan",
|
|
904
|
+
"type",
|
|
905
|
+
"panFollow"
|
|
906
|
+
],
|
|
907
|
+
"mix/10": ["on", "level"],
|
|
908
|
+
"mix/11": [
|
|
909
|
+
"on",
|
|
910
|
+
"level",
|
|
911
|
+
"pan",
|
|
912
|
+
"type",
|
|
913
|
+
"panFollow"
|
|
914
|
+
],
|
|
915
|
+
"mix/12": ["on", "level"],
|
|
916
|
+
"mix/13": [
|
|
917
|
+
"on",
|
|
918
|
+
"level",
|
|
919
|
+
"pan",
|
|
920
|
+
"type",
|
|
921
|
+
"panFollow"
|
|
922
|
+
],
|
|
923
|
+
"mix/14": ["on", "level"],
|
|
924
|
+
"mix/15": [
|
|
925
|
+
"on",
|
|
926
|
+
"level",
|
|
927
|
+
"pan",
|
|
928
|
+
"type",
|
|
929
|
+
"panFollow"
|
|
930
|
+
],
|
|
931
|
+
"mix/16": ["on", "level"],
|
|
932
|
+
"grp": ["dca", "mute"],
|
|
933
|
+
"automix": ["group", "weight"],
|
|
934
|
+
"chlink": [
|
|
935
|
+
"1-2",
|
|
936
|
+
"3-4",
|
|
937
|
+
"5-6",
|
|
938
|
+
"7-8",
|
|
939
|
+
"9-10",
|
|
940
|
+
"11-12",
|
|
941
|
+
"13-14",
|
|
942
|
+
"15-16",
|
|
943
|
+
"17-18",
|
|
944
|
+
"19-20",
|
|
945
|
+
"21-22",
|
|
946
|
+
"23-24",
|
|
947
|
+
"25-26",
|
|
948
|
+
"27-28",
|
|
949
|
+
"29-30",
|
|
950
|
+
"31-32"
|
|
951
|
+
],
|
|
952
|
+
"auxlink": [
|
|
953
|
+
"1-2",
|
|
954
|
+
"3-4",
|
|
955
|
+
"5-6",
|
|
956
|
+
"7-8"
|
|
957
|
+
],
|
|
958
|
+
"fxlink": [
|
|
959
|
+
"1-2",
|
|
960
|
+
"3-4",
|
|
961
|
+
"5-6",
|
|
962
|
+
"7-8"
|
|
963
|
+
],
|
|
964
|
+
"buslink": [
|
|
965
|
+
"1-2",
|
|
966
|
+
"3-4",
|
|
967
|
+
"5-6",
|
|
968
|
+
"7-8",
|
|
969
|
+
"9-10",
|
|
970
|
+
"11-12",
|
|
971
|
+
"13-14",
|
|
972
|
+
"15-16"
|
|
973
|
+
],
|
|
974
|
+
"mtxlink": [
|
|
975
|
+
"1-2",
|
|
976
|
+
"3-4",
|
|
977
|
+
"5-6"
|
|
978
|
+
],
|
|
979
|
+
"mute": [
|
|
980
|
+
"1",
|
|
981
|
+
"2",
|
|
982
|
+
"3",
|
|
983
|
+
"4",
|
|
984
|
+
"5",
|
|
985
|
+
"6"
|
|
986
|
+
],
|
|
987
|
+
"linkcfg": [
|
|
988
|
+
"hadly",
|
|
989
|
+
"eq",
|
|
990
|
+
"dyn",
|
|
991
|
+
"fdrmute"
|
|
992
|
+
],
|
|
993
|
+
"mono": ["mode", "link"],
|
|
994
|
+
"solo": [
|
|
995
|
+
"level",
|
|
996
|
+
"source",
|
|
997
|
+
"sourcetrim",
|
|
998
|
+
"chmode",
|
|
999
|
+
"busmode",
|
|
1000
|
+
"dcamode",
|
|
1001
|
+
"exclusive",
|
|
1002
|
+
"followsel",
|
|
1003
|
+
"followsolo",
|
|
1004
|
+
"dimatt",
|
|
1005
|
+
"dim",
|
|
1006
|
+
"mono",
|
|
1007
|
+
"delay",
|
|
1008
|
+
"delaytime",
|
|
1009
|
+
"masterctrl",
|
|
1010
|
+
"mute",
|
|
1011
|
+
"dimmute"
|
|
1012
|
+
],
|
|
1013
|
+
"talk": ["enable", "source"],
|
|
1014
|
+
"talk/A": [
|
|
1015
|
+
"level",
|
|
1016
|
+
"dim",
|
|
1017
|
+
"latch",
|
|
1018
|
+
"destmap"
|
|
1019
|
+
],
|
|
1020
|
+
"talk/B": [
|
|
1021
|
+
"level",
|
|
1022
|
+
"dim",
|
|
1023
|
+
"latch",
|
|
1024
|
+
"destmap"
|
|
1025
|
+
],
|
|
1026
|
+
"osc": [
|
|
1027
|
+
"level",
|
|
1028
|
+
"f1",
|
|
1029
|
+
"f2",
|
|
1030
|
+
"type",
|
|
1031
|
+
"dest"
|
|
1032
|
+
],
|
|
1033
|
+
"tape": [
|
|
1034
|
+
"gainL",
|
|
1035
|
+
"gainR",
|
|
1036
|
+
"autoplay"
|
|
1037
|
+
],
|
|
1038
|
+
"amixenable": ["X", "Y"],
|
|
1039
|
+
"dp48": [
|
|
1040
|
+
"broadcast",
|
|
1041
|
+
"bundles",
|
|
1042
|
+
"assign"
|
|
1043
|
+
],
|
|
1044
|
+
"dp48/assign": Array.from({ length: 48 }, (_, i) => String(i + 1)),
|
|
1045
|
+
"dp48/link": Array.from({ length: 24 }, (_, i) => String(i + 1)),
|
|
1046
|
+
"dp48/grpname": Array.from({ length: 12 }, (_, i) => String(i + 1)),
|
|
1047
|
+
"userrout/out": Array.from({ length: 48 }, (_, i) => String(i + 1)),
|
|
1048
|
+
"userrout/in": Array.from({ length: 32 }, (_, i) => String(i + 1)),
|
|
1049
|
+
"routing": ["routswitch"],
|
|
1050
|
+
"routing/IN": [
|
|
1051
|
+
"1-8",
|
|
1052
|
+
"9-16",
|
|
1053
|
+
"17-24",
|
|
1054
|
+
"25-32",
|
|
1055
|
+
"AUX"
|
|
1056
|
+
],
|
|
1057
|
+
"routing/AES50A": [
|
|
1058
|
+
"1-8",
|
|
1059
|
+
"9-16",
|
|
1060
|
+
"17-24",
|
|
1061
|
+
"25-32",
|
|
1062
|
+
"33-40",
|
|
1063
|
+
"41-48"
|
|
1064
|
+
],
|
|
1065
|
+
"routing/AES50B": [
|
|
1066
|
+
"1-8",
|
|
1067
|
+
"9-16",
|
|
1068
|
+
"17-24",
|
|
1069
|
+
"25-32",
|
|
1070
|
+
"33-40",
|
|
1071
|
+
"41-48"
|
|
1072
|
+
],
|
|
1073
|
+
"routing/CARD": [
|
|
1074
|
+
"1-8",
|
|
1075
|
+
"9-16",
|
|
1076
|
+
"17-24",
|
|
1077
|
+
"25-32"
|
|
1078
|
+
],
|
|
1079
|
+
"routing/OUT": [
|
|
1080
|
+
"1-4",
|
|
1081
|
+
"5-8",
|
|
1082
|
+
"9-12",
|
|
1083
|
+
"13-16"
|
|
1084
|
+
],
|
|
1085
|
+
"routing/PLAY": [
|
|
1086
|
+
"1-8",
|
|
1087
|
+
"9-16",
|
|
1088
|
+
"17-24",
|
|
1089
|
+
"25-32",
|
|
1090
|
+
"AUX"
|
|
1091
|
+
],
|
|
1092
|
+
"userctrl/A": ["color"],
|
|
1093
|
+
"userctrl/A/enc": [
|
|
1094
|
+
"1",
|
|
1095
|
+
"2",
|
|
1096
|
+
"3",
|
|
1097
|
+
"4"
|
|
1098
|
+
],
|
|
1099
|
+
"userctrl/A/btn": [
|
|
1100
|
+
"1",
|
|
1101
|
+
"2",
|
|
1102
|
+
"3",
|
|
1103
|
+
"4",
|
|
1104
|
+
"5",
|
|
1105
|
+
"6",
|
|
1106
|
+
"7",
|
|
1107
|
+
"8"
|
|
1108
|
+
],
|
|
1109
|
+
"userctrl/B": ["color"],
|
|
1110
|
+
"userctrl/B/enc": [
|
|
1111
|
+
"1",
|
|
1112
|
+
"2",
|
|
1113
|
+
"3",
|
|
1114
|
+
"4"
|
|
1115
|
+
],
|
|
1116
|
+
"userctrl/B/btn": [
|
|
1117
|
+
"1",
|
|
1118
|
+
"2",
|
|
1119
|
+
"3",
|
|
1120
|
+
"4",
|
|
1121
|
+
"5",
|
|
1122
|
+
"6",
|
|
1123
|
+
"7",
|
|
1124
|
+
"8"
|
|
1125
|
+
],
|
|
1126
|
+
"userctrl/C": ["color"],
|
|
1127
|
+
"userctrl/C/enc": [
|
|
1128
|
+
"1",
|
|
1129
|
+
"2",
|
|
1130
|
+
"3",
|
|
1131
|
+
"4"
|
|
1132
|
+
],
|
|
1133
|
+
"userctrl/C/btn": [
|
|
1134
|
+
"1",
|
|
1135
|
+
"2",
|
|
1136
|
+
"3",
|
|
1137
|
+
"4",
|
|
1138
|
+
"5",
|
|
1139
|
+
"6",
|
|
1140
|
+
"7",
|
|
1141
|
+
"8",
|
|
1142
|
+
"9",
|
|
1143
|
+
"10",
|
|
1144
|
+
"11",
|
|
1145
|
+
"12"
|
|
1146
|
+
],
|
|
1147
|
+
"dca": ["on", "fader"],
|
|
1148
|
+
"bus/config": [
|
|
1149
|
+
"name",
|
|
1150
|
+
"icon",
|
|
1151
|
+
"color"
|
|
1152
|
+
],
|
|
1153
|
+
"bus/mix": [
|
|
1154
|
+
"on",
|
|
1155
|
+
"fader",
|
|
1156
|
+
"st",
|
|
1157
|
+
"pan",
|
|
1158
|
+
"mono",
|
|
1159
|
+
"mlevel"
|
|
1160
|
+
],
|
|
1161
|
+
"main/st/config": [
|
|
1162
|
+
"name",
|
|
1163
|
+
"icon",
|
|
1164
|
+
"color"
|
|
1165
|
+
],
|
|
1166
|
+
"main/st/mix": [
|
|
1167
|
+
"on",
|
|
1168
|
+
"fader",
|
|
1169
|
+
"st",
|
|
1170
|
+
"pan"
|
|
1171
|
+
],
|
|
1172
|
+
"main/m/config": [
|
|
1173
|
+
"name",
|
|
1174
|
+
"icon",
|
|
1175
|
+
"color"
|
|
1176
|
+
],
|
|
1177
|
+
"main/m/mix": ["on", "fader"],
|
|
1178
|
+
"fx/source": ["inL", "inR"],
|
|
1179
|
+
"fx": ["type"],
|
|
1180
|
+
"fx/par": Array.from({ length: 64 }, (_, i) => String(i + 1)),
|
|
1181
|
+
"outputs/main": [
|
|
1182
|
+
"src",
|
|
1183
|
+
"pos",
|
|
1184
|
+
"invert"
|
|
1185
|
+
],
|
|
1186
|
+
"outputs/main/delay": ["on", "time"],
|
|
1187
|
+
"outputs/aux": [
|
|
1188
|
+
"src",
|
|
1189
|
+
"pos",
|
|
1190
|
+
"invert"
|
|
1191
|
+
],
|
|
1192
|
+
"outputs/p16": [
|
|
1193
|
+
"src",
|
|
1194
|
+
"pos",
|
|
1195
|
+
"invert"
|
|
1196
|
+
],
|
|
1197
|
+
"outputs/p16/iQ": [
|
|
1198
|
+
"model",
|
|
1199
|
+
"eqset",
|
|
1200
|
+
"sound"
|
|
1201
|
+
],
|
|
1202
|
+
"outputs/aes": [
|
|
1203
|
+
"src",
|
|
1204
|
+
"pos",
|
|
1205
|
+
"invert"
|
|
1206
|
+
],
|
|
1207
|
+
"outputs/rec": [
|
|
1208
|
+
"src",
|
|
1209
|
+
"pos",
|
|
1210
|
+
"invert"
|
|
1211
|
+
]
|
|
1212
|
+
};
|
|
1213
|
+
/**
|
|
1214
|
+
* Converts scene file values to proper OSC types.
|
|
1215
|
+
*/
|
|
1216
|
+
function parseSceneValue(val) {
|
|
1217
|
+
if (val === "ON") return 1;
|
|
1218
|
+
if (val === "OFF") return 0;
|
|
1219
|
+
if (val === "-oo" || val === "-inf") return -90;
|
|
1220
|
+
if (val === "+oo" || val === "+inf") return 90;
|
|
1221
|
+
if (val.startsWith("%")) return parseInt(val.slice(1), 2);
|
|
1222
|
+
const freqMatch = val.match(/^(\d+)k(\d+)$/);
|
|
1223
|
+
if (freqMatch) return parseFloat(freqMatch[1] + "." + freqMatch[2]) * 1e3;
|
|
1224
|
+
if (val.startsWith("+") || val.startsWith("-")) {
|
|
1225
|
+
const num$1 = parseFloat(val);
|
|
1226
|
+
if (!isNaN(num$1)) return num$1;
|
|
1227
|
+
}
|
|
1228
|
+
const num = parseFloat(val);
|
|
1229
|
+
if (!isNaN(num)) return num;
|
|
1230
|
+
const int = parseInt(val, 10);
|
|
1231
|
+
if (!isNaN(int)) return int;
|
|
1232
|
+
return val.replace(/^"|"$/g, "");
|
|
1233
|
+
}
|
|
1234
|
+
/**
|
|
1235
|
+
* Strategy to handle X32 scene file format (batch multi-value commands).
|
|
1236
|
+
* Expands parent addresses with multiple values into individual parameter sets.
|
|
1237
|
+
*/
|
|
1238
|
+
var SceneDataStrategy = class {
|
|
1239
|
+
constructor(state, logger) {
|
|
1240
|
+
this.state = state;
|
|
1241
|
+
this.logger = logger;
|
|
1242
|
+
}
|
|
1243
|
+
canHandle(address, args) {
|
|
1244
|
+
if (!args || args.length === 0) return false;
|
|
1245
|
+
if (args.length === 1) {
|
|
1246
|
+
if (address.match(/^\/fx\/\d$/)) return true;
|
|
1247
|
+
return false;
|
|
1248
|
+
}
|
|
1249
|
+
if (args.length === 2) {
|
|
1250
|
+
if (address.match(/^\/dca\/\d$/)) return true;
|
|
1251
|
+
}
|
|
1252
|
+
return this.findMapping(address) !== null;
|
|
1253
|
+
}
|
|
1254
|
+
execute(msg, _source) {
|
|
1255
|
+
const { address, args } = msg;
|
|
1256
|
+
const mapping = this.findMapping(address);
|
|
1257
|
+
if (!mapping) return [];
|
|
1258
|
+
const { basePath, fields } = mapping;
|
|
1259
|
+
this.logger.debug(LogCategory.STATE, `[SCENE] Expanding batch command`, {
|
|
1260
|
+
address,
|
|
1261
|
+
argCount: args.length,
|
|
1262
|
+
fields: fields.length
|
|
1263
|
+
});
|
|
1264
|
+
for (let i = 0; i < args.length && i < fields.length; i++) {
|
|
1265
|
+
const fieldName = fields[i];
|
|
1266
|
+
const rawValue = args[i];
|
|
1267
|
+
const value = typeof rawValue === "string" ? parseSceneValue(rawValue) : rawValue;
|
|
1268
|
+
const fullPath = `${basePath}/${fieldName}`;
|
|
1269
|
+
this.state.set(fullPath, value);
|
|
1270
|
+
this.logger.debug(LogCategory.STATE, `[SCENE] Set ${fullPath} = ${value}`);
|
|
1271
|
+
}
|
|
1272
|
+
return [];
|
|
1273
|
+
}
|
|
1274
|
+
findMapping(address) {
|
|
1275
|
+
if (address.match(/^\/headamp\/\d{3}$/) && SCENE_MAPPINGS["headamp"]) return {
|
|
1276
|
+
basePath: address,
|
|
1277
|
+
fields: SCENE_MAPPINGS["headamp"]
|
|
1278
|
+
};
|
|
1279
|
+
if (address.match(/^\/fx\/\d\/source$/) && SCENE_MAPPINGS["fx/source"]) return {
|
|
1280
|
+
basePath: address,
|
|
1281
|
+
fields: SCENE_MAPPINGS["fx/source"]
|
|
1282
|
+
};
|
|
1283
|
+
if (address.match(/^\/fx\/\d\/par$/) && SCENE_MAPPINGS["fx/par"]) return {
|
|
1284
|
+
basePath: address,
|
|
1285
|
+
fields: SCENE_MAPPINGS["fx/par"]
|
|
1286
|
+
};
|
|
1287
|
+
if (address.match(/^\/fx\/\d$/) && SCENE_MAPPINGS["fx"]) return {
|
|
1288
|
+
basePath: address,
|
|
1289
|
+
fields: SCENE_MAPPINGS["fx"]
|
|
1290
|
+
};
|
|
1291
|
+
if (address.match(/^\/dca\/\d$/) && SCENE_MAPPINGS["dca"]) return {
|
|
1292
|
+
basePath: address,
|
|
1293
|
+
fields: SCENE_MAPPINGS["dca"]
|
|
1294
|
+
};
|
|
1295
|
+
if (address.match(/^\/dca\/\d\/config$/)) return {
|
|
1296
|
+
basePath: address,
|
|
1297
|
+
fields: [
|
|
1298
|
+
"name",
|
|
1299
|
+
"icon",
|
|
1300
|
+
"color"
|
|
1301
|
+
]
|
|
1302
|
+
};
|
|
1303
|
+
if (address.match(/^\/outputs\/main\/\d{2}\/delay$/) && SCENE_MAPPINGS["outputs/main/delay"]) return {
|
|
1304
|
+
basePath: address,
|
|
1305
|
+
fields: SCENE_MAPPINGS["outputs/main/delay"]
|
|
1306
|
+
};
|
|
1307
|
+
if (address.match(/^\/outputs\/p16\/\d{2}\/iQ$/) && SCENE_MAPPINGS["outputs/p16/iQ"]) return {
|
|
1308
|
+
basePath: address,
|
|
1309
|
+
fields: SCENE_MAPPINGS["outputs/p16/iQ"]
|
|
1310
|
+
};
|
|
1311
|
+
if (address.match(/^\/outputs\/main\/\d{2}$/) && SCENE_MAPPINGS["outputs/main"]) return {
|
|
1312
|
+
basePath: address,
|
|
1313
|
+
fields: SCENE_MAPPINGS["outputs/main"]
|
|
1314
|
+
};
|
|
1315
|
+
if (address.match(/^\/outputs\/aux\/\d{2}$/) && SCENE_MAPPINGS["outputs/aux"]) return {
|
|
1316
|
+
basePath: address,
|
|
1317
|
+
fields: SCENE_MAPPINGS["outputs/aux"]
|
|
1318
|
+
};
|
|
1319
|
+
if (address.match(/^\/outputs\/p16\/\d{2}$/) && SCENE_MAPPINGS["outputs/p16"]) return {
|
|
1320
|
+
basePath: address,
|
|
1321
|
+
fields: SCENE_MAPPINGS["outputs/p16"]
|
|
1322
|
+
};
|
|
1323
|
+
if (address.match(/^\/outputs\/aes\/\d{2}$/) && SCENE_MAPPINGS["outputs/aes"]) return {
|
|
1324
|
+
basePath: address,
|
|
1325
|
+
fields: SCENE_MAPPINGS["outputs/aes"]
|
|
1326
|
+
};
|
|
1327
|
+
if (address.match(/^\/outputs\/rec\/\d{2}$/) && SCENE_MAPPINGS["outputs/rec"]) return {
|
|
1328
|
+
basePath: address,
|
|
1329
|
+
fields: SCENE_MAPPINGS["outputs/rec"]
|
|
1330
|
+
};
|
|
1331
|
+
if (address.startsWith("/config/")) {
|
|
1332
|
+
const suffix = address.replace("/config/", "");
|
|
1333
|
+
if (SCENE_MAPPINGS[suffix]) return {
|
|
1334
|
+
basePath: address,
|
|
1335
|
+
fields: SCENE_MAPPINGS[suffix]
|
|
1336
|
+
};
|
|
1337
|
+
}
|
|
1338
|
+
for (const [pattern, fields] of Object.entries(SCENE_MAPPINGS)) {
|
|
1339
|
+
if (address.endsWith("/" + pattern)) return {
|
|
1340
|
+
basePath: address,
|
|
1341
|
+
fields
|
|
1342
|
+
};
|
|
1343
|
+
if ((/* @__PURE__ */ new RegExp(`/${pattern.replace(/\//g, "/")}$`)).test(address)) return {
|
|
1344
|
+
basePath: address,
|
|
1345
|
+
fields
|
|
1346
|
+
};
|
|
1347
|
+
}
|
|
1348
|
+
const numberedPathMatch = address.match(/^\/\w+\/\d+\/(.+)$/);
|
|
1349
|
+
if (numberedPathMatch) {
|
|
1350
|
+
const suffix = numberedPathMatch[1];
|
|
1351
|
+
if (SCENE_MAPPINGS[suffix]) return {
|
|
1352
|
+
basePath: address,
|
|
1353
|
+
fields: SCENE_MAPPINGS[suffix]
|
|
1354
|
+
};
|
|
1355
|
+
}
|
|
1356
|
+
return null;
|
|
1357
|
+
}
|
|
1358
|
+
};
|
|
1359
|
+
|
|
593
1360
|
//#endregion
|
|
594
1361
|
//#region src/domain/services/OscMessageHandler.ts
|
|
595
1362
|
/**
|
|
@@ -619,10 +1386,12 @@ var OscMessageHandler = class {
|
|
|
619
1386
|
this.staticResponseService = staticResponseService;
|
|
620
1387
|
this.strategies = [
|
|
621
1388
|
new NodeDiscoveryStrategy(this.schemaRegistry),
|
|
622
|
-
new StaticResponseStrategy(serverIp, serverName, serverModel, this.staticResponseService),
|
|
623
1389
|
new SubscriptionStrategy(subscriptionManager, state, logger),
|
|
624
1390
|
new BatchStrategy(subscriptionManager, logger),
|
|
625
1391
|
new MeterStrategy(subscriptionManager, state, this.meterService),
|
|
1392
|
+
new ShowDumpStrategy(state, logger),
|
|
1393
|
+
new SceneDataStrategy(state, logger),
|
|
1394
|
+
new StaticResponseStrategy(serverIp, serverName, serverModel, this.staticResponseService),
|
|
626
1395
|
new StateAccessStrategy(state, logger, this.schemaRegistry)
|
|
627
1396
|
];
|
|
628
1397
|
}
|
|
@@ -633,19 +1402,41 @@ var OscMessageHandler = class {
|
|
|
633
1402
|
* @returns Array of replies generated by the strategy.
|
|
634
1403
|
*/
|
|
635
1404
|
handle(msg, source) {
|
|
636
|
-
|
|
1405
|
+
let addr = msg.address;
|
|
1406
|
+
let args = msg.args;
|
|
1407
|
+
if (addr === "/" && args.length === 1 && typeof args[0] === "string") {
|
|
1408
|
+
const parts = args[0].trim().match(/(?:[^\s"]+|"[^"]*")+/g) || [];
|
|
1409
|
+
if (parts.length > 0 && parts[0]) {
|
|
1410
|
+
let innerAddr = parts[0];
|
|
1411
|
+
if (!innerAddr.startsWith("/")) innerAddr = "/" + innerAddr;
|
|
1412
|
+
const innerArgs = parts.slice(1).map((arg) => {
|
|
1413
|
+
let val = arg.replace(/^"|"$/g, "");
|
|
1414
|
+
if (/^-?\d+$/.test(val)) return parseInt(val, 10);
|
|
1415
|
+
if (/^-?\d+\.\d+$/.test(val)) return parseFloat(val);
|
|
1416
|
+
return val;
|
|
1417
|
+
});
|
|
1418
|
+
this.logger.debug(LogCategory.DISPATCH, `Unwrapped X32-Edit command: ${innerAddr}`, { innerArgs });
|
|
1419
|
+
return this.handle({
|
|
1420
|
+
address: innerAddr,
|
|
1421
|
+
args: innerArgs
|
|
1422
|
+
}, source);
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
637
1425
|
if (!addr.startsWith("/meters")) this.logger.debug(LogCategory.DISPATCH, `Handling`, {
|
|
638
1426
|
addr,
|
|
639
|
-
args
|
|
1427
|
+
args
|
|
640
1428
|
});
|
|
641
|
-
for (const strategy of this.strategies) if (strategy.canHandle(addr)) {
|
|
642
|
-
const replies = strategy.execute(
|
|
1429
|
+
for (const strategy of this.strategies) if (strategy.canHandle(addr, args)) {
|
|
1430
|
+
const replies = strategy.execute({
|
|
1431
|
+
address: addr,
|
|
1432
|
+
args
|
|
1433
|
+
}, source);
|
|
643
1434
|
if (replies.length > 0) this.logger.debug(LogCategory.DISPATCH, `Strategy ${strategy.constructor.name} replied`, { count: replies.length });
|
|
644
1435
|
return replies;
|
|
645
1436
|
}
|
|
646
1437
|
this.logger.warn(LogCategory.DISPATCH, `Unknown Command`, {
|
|
647
1438
|
addr,
|
|
648
|
-
args
|
|
1439
|
+
args,
|
|
649
1440
|
ip: source.address
|
|
650
1441
|
});
|
|
651
1442
|
return [];
|
|
@@ -759,6 +1550,8 @@ var MeterService = class {
|
|
|
759
1550
|
//#region src/domain/services/StaticResponseService.ts
|
|
760
1551
|
/**
|
|
761
1552
|
* Static OSC responses for X32 Discovery and System status.
|
|
1553
|
+
* These are read-only informational endpoints that return system info.
|
|
1554
|
+
* All other parameters are handled by StateAccessStrategy from the schema.
|
|
762
1555
|
*/
|
|
763
1556
|
const STATIC_RESPONSES_DATA = {
|
|
764
1557
|
"/xinfo": [
|
|
@@ -777,34 +1570,7 @@ const STATIC_RESPONSES_DATA = {
|
|
|
777
1570
|
"active",
|
|
778
1571
|
"{{ip}}",
|
|
779
1572
|
"{{name}}"
|
|
780
|
-
]
|
|
781
|
-
"/-prefs/invertmutes": [0],
|
|
782
|
-
"/-prefs/fine": [0],
|
|
783
|
-
"/-prefs/bright": [50],
|
|
784
|
-
"/-prefs/contrast": [50],
|
|
785
|
-
"/-prefs/led_bright": [50],
|
|
786
|
-
"/-prefs/lcd_bright": [50],
|
|
787
|
-
"/-stat/userpar/1/value": [0],
|
|
788
|
-
"/-stat/userpar/2/value": [0],
|
|
789
|
-
"/-stat/tape/state": [0],
|
|
790
|
-
"/-stat/aes50/A": [0],
|
|
791
|
-
"/-stat/aes50/B": [0],
|
|
792
|
-
"/-stat/solo": [0],
|
|
793
|
-
"/-stat/rtasource": [0],
|
|
794
|
-
"/-urec/errorcode": [0],
|
|
795
|
-
"/-prefs/rta/gain": [0],
|
|
796
|
-
"/-prefs/rta/autogain": [0],
|
|
797
|
-
"/-prefs/hardmute": [0],
|
|
798
|
-
"/-prefs/dcamute": [0],
|
|
799
|
-
"/config/mono/mode": [0],
|
|
800
|
-
"/config/amixenable/X": [0],
|
|
801
|
-
"/config/amixenable/Y": [0],
|
|
802
|
-
"/-show/prepos/current": [0],
|
|
803
|
-
"/-show/showfile/current": [""],
|
|
804
|
-
"/-action/setrtasrc": [0],
|
|
805
|
-
"/-action/playtrack": [0],
|
|
806
|
-
"/-action/goscene": [0],
|
|
807
|
-
"/-action/setscene": [0]
|
|
1573
|
+
]
|
|
808
1574
|
};
|
|
809
1575
|
/**
|
|
810
1576
|
* Service providing static system responses.
|
|
@@ -834,47 +1600,51 @@ function getLocalIp() {
|
|
|
834
1600
|
return "127.0.0.1";
|
|
835
1601
|
}
|
|
836
1602
|
/**
|
|
837
|
-
* The core service that manages the X32 simulation, including networking,
|
|
1603
|
+
* The core service that manages the X32 simulation, including networking,
|
|
838
1604
|
* state management, and OSC message handling.
|
|
839
1605
|
*/
|
|
840
1606
|
var SimulationService = class {
|
|
841
1607
|
subscriptionManager;
|
|
842
1608
|
messageHandler;
|
|
1609
|
+
state;
|
|
843
1610
|
processPacket;
|
|
844
1611
|
broadcastUpdates;
|
|
845
1612
|
manageSessions;
|
|
846
1613
|
meterService;
|
|
847
1614
|
staticResponseService;
|
|
1615
|
+
config;
|
|
848
1616
|
updateInterval = null;
|
|
849
1617
|
cleanupInterval = null;
|
|
850
1618
|
/**
|
|
851
1619
|
* Creates a new SimulationService instance.
|
|
852
1620
|
* @param gateway - The network gateway for OSC communication.
|
|
853
1621
|
* @param logger - The logger service.
|
|
854
|
-
* @param
|
|
1622
|
+
* @param stateRepository - The repository for state persistence.
|
|
855
1623
|
* @param schemaRegistry - The registry for X32 OSC schema.
|
|
856
|
-
* @param port - UDP port to listen on (default
|
|
857
|
-
* @param ip - IP address to bind to (default
|
|
1624
|
+
* @param port - UDP port to listen on (default from config).
|
|
1625
|
+
* @param ip - IP address to bind to (default from config).
|
|
858
1626
|
* @param name - Reported console name.
|
|
859
1627
|
* @param model - Reported console model.
|
|
1628
|
+
* @param configOverrides - Optional configuration overrides.
|
|
860
1629
|
*/
|
|
861
|
-
constructor(gateway, logger,
|
|
1630
|
+
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) {
|
|
862
1631
|
this.gateway = gateway;
|
|
863
1632
|
this.logger = logger;
|
|
864
|
-
this.
|
|
1633
|
+
this.stateRepository = stateRepository;
|
|
865
1634
|
this.schemaRegistry = schemaRegistry;
|
|
866
1635
|
this.port = port;
|
|
867
1636
|
this.ip = ip;
|
|
868
|
-
|
|
869
|
-
this.
|
|
1637
|
+
this.config = mergeConfig(configOverrides);
|
|
1638
|
+
this.state = new X32State(schemaRegistry.getSchema(), stateRepository);
|
|
1639
|
+
this.subscriptionManager = new SubscriptionManager(logger, this.config.SUBSCRIPTION_TTL_MS);
|
|
870
1640
|
this.meterService = new MeterService();
|
|
871
1641
|
this.staticResponseService = new StaticResponseService();
|
|
872
1642
|
const reportedIp = this.ip === "0.0.0.0" ? getLocalIp() : this.ip;
|
|
873
|
-
this.messageHandler = new OscMessageHandler(state, this.subscriptionManager, logger, reportedIp, name, model, this.meterService, this.schemaRegistry, this.staticResponseService);
|
|
874
|
-
this.processPacket = new ProcessPacketUseCase(this.messageHandler, gateway);
|
|
875
|
-
this.broadcastUpdates = new BroadcastUpdatesUseCase(this.subscriptionManager, state, gateway, logger, this.meterService, this.schemaRegistry);
|
|
1643
|
+
this.messageHandler = new OscMessageHandler(this.state, this.subscriptionManager, logger, reportedIp, name, model, this.meterService, this.schemaRegistry, this.staticResponseService);
|
|
1644
|
+
this.processPacket = new ProcessPacketUseCase(this.messageHandler, gateway, logger);
|
|
1645
|
+
this.broadcastUpdates = new BroadcastUpdatesUseCase(this.subscriptionManager, this.state, gateway, logger, this.meterService, this.schemaRegistry);
|
|
876
1646
|
this.manageSessions = new ManageSessionsUseCase(this.subscriptionManager);
|
|
877
|
-
state.on("change", (evt) => {
|
|
1647
|
+
this.state.on("change", (evt) => {
|
|
878
1648
|
this.logger.info(LogCategory.STATE, `State Changed`, evt);
|
|
879
1649
|
this.broadcastUpdates.broadcastSingleChange(evt.address, evt.value);
|
|
880
1650
|
});
|
|
@@ -884,13 +1654,14 @@ var SimulationService = class {
|
|
|
884
1654
|
* Starts the simulator server and internal loops.
|
|
885
1655
|
*/
|
|
886
1656
|
async start() {
|
|
1657
|
+
await this.state.initialize();
|
|
887
1658
|
await this.gateway.start(this.port, this.ip);
|
|
888
1659
|
this.cleanupInterval = setInterval(() => {
|
|
889
1660
|
this.manageSessions.cleanup();
|
|
890
|
-
},
|
|
1661
|
+
}, this.config.CLEANUP_INTERVAL_MS);
|
|
891
1662
|
this.updateInterval = setInterval(() => {
|
|
892
1663
|
this.broadcastUpdates.execute();
|
|
893
|
-
},
|
|
1664
|
+
}, this.config.BROADCAST_INTERVAL_MS);
|
|
894
1665
|
}
|
|
895
1666
|
/**
|
|
896
1667
|
* Stops the simulator server and stops all internal loops.
|
|
@@ -898,84 +1669,20 @@ var SimulationService = class {
|
|
|
898
1669
|
async stop() {
|
|
899
1670
|
if (this.updateInterval) clearInterval(this.updateInterval);
|
|
900
1671
|
if (this.cleanupInterval) clearInterval(this.cleanupInterval);
|
|
1672
|
+
await this.state.flush();
|
|
901
1673
|
await this.gateway.stop();
|
|
902
1674
|
}
|
|
903
1675
|
/**
|
|
904
1676
|
* Resets the mixer state to default values.
|
|
905
1677
|
*/
|
|
906
1678
|
resetState() {
|
|
907
|
-
this.
|
|
908
|
-
}
|
|
909
|
-
};
|
|
910
|
-
|
|
911
|
-
//#endregion
|
|
912
|
-
//#region src/domain/entities/X32State.ts
|
|
913
|
-
/**
|
|
914
|
-
* Manages the internal "Digital Twin" state of the X32 console.
|
|
915
|
-
* It acts as a single source of truth for all parameters.
|
|
916
|
-
* Emits 'change' events whenever a value is updated.
|
|
917
|
-
*/
|
|
918
|
-
var X32State = class extends EventEmitter {
|
|
919
|
-
/** Map storing all OSC paths and their current values. */
|
|
920
|
-
state = /* @__PURE__ */ new Map();
|
|
921
|
-
defaultState = /* @__PURE__ */ new Map();
|
|
922
|
-
/**
|
|
923
|
-
* Initializes the state with default values from the schema.
|
|
924
|
-
* @param schema - The schema definition map.
|
|
925
|
-
*/
|
|
926
|
-
constructor(schema) {
|
|
927
|
-
super();
|
|
928
|
-
for (const [addr, def] of Object.entries(schema)) this.defaultState.set(addr, def.default);
|
|
929
|
-
this.reset();
|
|
930
|
-
}
|
|
931
|
-
/**
|
|
932
|
-
* Resets all state parameters to their default values defined in the schema.
|
|
933
|
-
*/
|
|
934
|
-
reset() {
|
|
935
|
-
this.state.clear();
|
|
936
|
-
this.defaultState.forEach((val, key) => {
|
|
937
|
-
this.state.set(key, val);
|
|
938
|
-
});
|
|
939
|
-
}
|
|
940
|
-
/**
|
|
941
|
-
* Retrieves the value of a specific OSC node.
|
|
942
|
-
* @param address - The full OSC address path.
|
|
943
|
-
* @returns The stored value (number or string) or undefined if not found.
|
|
944
|
-
*/
|
|
945
|
-
get(address) {
|
|
946
|
-
return this.state.get(address);
|
|
1679
|
+
this.state.reset();
|
|
947
1680
|
}
|
|
948
1681
|
/**
|
|
949
|
-
*
|
|
950
|
-
* @param address - The full OSC address path.
|
|
951
|
-
* @param value - The new value to store.
|
|
1682
|
+
* Forces a save of the current state to storage.
|
|
952
1683
|
*/
|
|
953
|
-
|
|
954
|
-
this.state.
|
|
955
|
-
this.emit("change", {
|
|
956
|
-
address,
|
|
957
|
-
value
|
|
958
|
-
});
|
|
959
|
-
}
|
|
960
|
-
/**
|
|
961
|
-
* Specialized logic to handle X32 Mute Groups side-effects.
|
|
962
|
-
* When a mute group is toggled, it iterates through all channels
|
|
963
|
-
* assigned to that group and updates their individual mute status.
|
|
964
|
-
* @param groupIdx - The index of the mute group (1-6).
|
|
965
|
-
* @param isOn - The new state of the group master switch (0 or 1).
|
|
966
|
-
*/
|
|
967
|
-
handleMuteGroupChange(groupIdx, isOn) {
|
|
968
|
-
for (let i = 1; i <= 32; i++) {
|
|
969
|
-
const ch = i.toString().padStart(2, "0");
|
|
970
|
-
const grpVal = this.get(`/ch/${ch}/grp/mute`);
|
|
971
|
-
if (typeof grpVal === "number") {
|
|
972
|
-
if ((grpVal & 1 << groupIdx - 1) !== 0) {
|
|
973
|
-
const targetMute = isOn === 1 ? 0 : 1;
|
|
974
|
-
const muteAddr = `/ch/${ch}/mix/on`;
|
|
975
|
-
this.set(muteAddr, targetMute);
|
|
976
|
-
}
|
|
977
|
-
}
|
|
978
|
-
}
|
|
1684
|
+
async saveState() {
|
|
1685
|
+
await this.state.flush();
|
|
979
1686
|
}
|
|
980
1687
|
};
|
|
981
1688
|
|
|
@@ -990,69 +1697,106 @@ var X32Node = class X32Node {
|
|
|
990
1697
|
type;
|
|
991
1698
|
/** Default value for reset. */
|
|
992
1699
|
default;
|
|
1700
|
+
/** Optional validation constraints. */
|
|
1701
|
+
options;
|
|
993
1702
|
/**
|
|
994
1703
|
* Creates a new X32Node.
|
|
995
1704
|
* @param type - The OSC data type ('f', 'i', 's').
|
|
996
1705
|
* @param defaultValue - The default value.
|
|
1706
|
+
* @param options - Optional validation constraints.
|
|
997
1707
|
*/
|
|
998
|
-
constructor(type, defaultValue) {
|
|
1708
|
+
constructor(type, defaultValue, options) {
|
|
999
1709
|
this.type = type;
|
|
1000
1710
|
this.default = defaultValue;
|
|
1711
|
+
this.options = options;
|
|
1001
1712
|
}
|
|
1002
1713
|
/**
|
|
1003
1714
|
* Validates if a value is compatible with this node's type.
|
|
1004
1715
|
* @param value - The value to check.
|
|
1716
|
+
* @param strict - If true, also validates against min/max constraints.
|
|
1005
1717
|
* @returns True if valid.
|
|
1006
1718
|
*/
|
|
1007
|
-
validate(value) {
|
|
1008
|
-
if (this.type === "f"
|
|
1009
|
-
if (this.type === "i"
|
|
1010
|
-
if (this.type === "s"
|
|
1011
|
-
|
|
1719
|
+
validate(value, strict = false) {
|
|
1720
|
+
if (this.type === "f" && typeof value !== "number") return false;
|
|
1721
|
+
if (this.type === "i" && typeof value !== "number") return false;
|
|
1722
|
+
if (this.type === "s" && typeof value !== "string") return false;
|
|
1723
|
+
if (strict && this.options && typeof value === "number") {
|
|
1724
|
+
if (this.options.min !== void 0 && value < this.options.min) return false;
|
|
1725
|
+
if (this.options.max !== void 0 && value > this.options.max) return false;
|
|
1726
|
+
if (this.type === "i" && this.options.strictInteger && !Number.isInteger(value)) return false;
|
|
1727
|
+
}
|
|
1728
|
+
return true;
|
|
1012
1729
|
}
|
|
1013
1730
|
/**
|
|
1014
1731
|
* Factory method to create from a plain object (for compatibility/migration).
|
|
1015
1732
|
* @param obj - Plain object.
|
|
1016
1733
|
* @param obj.type - OSC data type.
|
|
1017
1734
|
* @param obj.default - Default value.
|
|
1735
|
+
* @param obj.options - Optional validation constraints.
|
|
1018
1736
|
* @returns A new X32Node instance.
|
|
1019
1737
|
*/
|
|
1020
1738
|
static from(obj) {
|
|
1021
|
-
return new X32Node(obj.type, obj.default);
|
|
1739
|
+
return new X32Node(obj.type, obj.default, obj.options);
|
|
1022
1740
|
}
|
|
1023
1741
|
};
|
|
1024
1742
|
|
|
1025
1743
|
//#endregion
|
|
1026
1744
|
//#region src/infrastructure/repositories/InMemoryStateRepository.ts
|
|
1027
1745
|
/**
|
|
1028
|
-
* In-memory
|
|
1029
|
-
* Stores
|
|
1746
|
+
* In-memory state repository.
|
|
1747
|
+
* Stores state in a Map, no persistence across restarts.
|
|
1748
|
+
* This is the default and fastest option.
|
|
1030
1749
|
*/
|
|
1031
1750
|
var InMemoryStateRepository = class {
|
|
1032
|
-
state;
|
|
1751
|
+
state = /* @__PURE__ */ new Map();
|
|
1033
1752
|
/**
|
|
1034
|
-
*
|
|
1035
|
-
*
|
|
1036
|
-
* @param schemaRegistry - Registry providing the initial state schema.
|
|
1753
|
+
* Loads state from memory.
|
|
1754
|
+
* For in-memory storage, this returns current state.
|
|
1037
1755
|
*/
|
|
1038
|
-
|
|
1039
|
-
this.
|
|
1040
|
-
this.state = new X32State(schemaRegistry.getSchema());
|
|
1756
|
+
async load() {
|
|
1757
|
+
return this.getAll();
|
|
1041
1758
|
}
|
|
1042
1759
|
/**
|
|
1043
|
-
*
|
|
1044
|
-
*
|
|
1760
|
+
* Saves state to memory.
|
|
1761
|
+
* For in-memory storage, this replaces current state.
|
|
1045
1762
|
*/
|
|
1046
|
-
|
|
1047
|
-
|
|
1763
|
+
async save(state) {
|
|
1764
|
+
this.state.clear();
|
|
1765
|
+
for (const [key, value] of Object.entries(state)) this.state.set(key, value);
|
|
1048
1766
|
}
|
|
1049
1767
|
/**
|
|
1050
|
-
*
|
|
1768
|
+
* Gets a single value from memory.
|
|
1051
1769
|
*/
|
|
1052
|
-
|
|
1053
|
-
this.
|
|
1054
|
-
|
|
1770
|
+
get(address) {
|
|
1771
|
+
return this.state.get(address);
|
|
1772
|
+
}
|
|
1773
|
+
/**
|
|
1774
|
+
* Sets a single value in memory.
|
|
1775
|
+
*/
|
|
1776
|
+
set(address, value) {
|
|
1777
|
+
this.state.set(address, value);
|
|
1055
1778
|
}
|
|
1779
|
+
/**
|
|
1780
|
+
* Gets all entries from memory.
|
|
1781
|
+
*/
|
|
1782
|
+
getAll() {
|
|
1783
|
+
const result = {};
|
|
1784
|
+
this.state.forEach((value, key) => {
|
|
1785
|
+
result[key] = value;
|
|
1786
|
+
});
|
|
1787
|
+
return result;
|
|
1788
|
+
}
|
|
1789
|
+
/**
|
|
1790
|
+
* Resets state to provided defaults.
|
|
1791
|
+
*/
|
|
1792
|
+
reset(defaults) {
|
|
1793
|
+
this.state.clear();
|
|
1794
|
+
for (const [key, value] of Object.entries(defaults)) this.state.set(key, value);
|
|
1795
|
+
}
|
|
1796
|
+
/**
|
|
1797
|
+
* No-op for in-memory storage.
|
|
1798
|
+
*/
|
|
1799
|
+
async flush() {}
|
|
1056
1800
|
};
|
|
1057
1801
|
|
|
1058
1802
|
//#endregion
|
|
@@ -1871,41 +2615,215 @@ var SchemaFactory = class {
|
|
|
1871
2615
|
...this.generateRange(128, "/headamp", "/gain", "f", 0, 3, 0),
|
|
1872
2616
|
...this.generateRange(128, "/headamp", "/phantom", "i", 0, 3, 0),
|
|
1873
2617
|
...this.generateRange(6, "/config/mute", "", "i", 0),
|
|
1874
|
-
...this.generateRange(80, "/-stat/solosw", "", "i", 0),
|
|
2618
|
+
...this.generateRange(80, "/-stat/solosw", "", "i", 0, 2, 1),
|
|
1875
2619
|
"/-stat/selidx": this.node("i", 0),
|
|
2620
|
+
"/-stat/chfaderbank": this.node("i", 0),
|
|
2621
|
+
"/-stat/grpfaderbank": this.node("i", 0),
|
|
1876
2622
|
"/-stat/sendsonfader": this.node("i", 0),
|
|
1877
2623
|
"/-stat/bussendbank": this.node("i", 0),
|
|
2624
|
+
"/-stat/eqband": this.node("i", 0),
|
|
1878
2625
|
"/-stat/keysolo": this.node("i", 0),
|
|
2626
|
+
"/-stat/userbank": this.node("i", 0),
|
|
2627
|
+
"/-stat/autosave": this.node("i", 0),
|
|
2628
|
+
"/-stat/lock": this.node("i", 0),
|
|
2629
|
+
"/-stat/usbmounted": this.node("i", 0),
|
|
2630
|
+
"/-stat/remote": this.node("i", 0),
|
|
2631
|
+
"/-stat/rtamodeeq": this.node("i", 0),
|
|
2632
|
+
"/-stat/rtamodegeq": this.node("i", 0),
|
|
2633
|
+
"/-stat/rtaeqpre": this.node("i", 0),
|
|
2634
|
+
"/-stat/rtageqpost": this.node("i", 0),
|
|
2635
|
+
"/-stat/rtasource": this.node("i", 0),
|
|
2636
|
+
"/-stat/xcardtype": this.node("i", 0),
|
|
2637
|
+
"/-stat/xcardsync": this.node("i", 0),
|
|
2638
|
+
"/-stat/geqonfdr": this.node("i", 0),
|
|
2639
|
+
"/-stat/geqpos": this.node("i", 0),
|
|
1879
2640
|
"/-stat/screen/screen": this.node("i", 0),
|
|
2641
|
+
"/-stat/screen/mutegrp": this.node("i", 0),
|
|
2642
|
+
"/-stat/screen/utils": this.node("i", 0),
|
|
1880
2643
|
"/-stat/screen/CHAN/page": this.node("i", 0),
|
|
1881
2644
|
"/-stat/screen/METER/page": this.node("i", 0),
|
|
1882
2645
|
"/-stat/screen/ROUTE/page": this.node("i", 0),
|
|
1883
2646
|
"/-stat/screen/SETUP/page": this.node("i", 0),
|
|
2647
|
+
"/-stat/screen/LIB/page": this.node("i", 0),
|
|
1884
2648
|
"/-stat/screen/LIBRARY/page": this.node("i", 0),
|
|
1885
2649
|
"/-stat/screen/FX/page": this.node("i", 0),
|
|
1886
2650
|
"/-stat/screen/MON/page": this.node("i", 0),
|
|
1887
2651
|
"/-stat/screen/USB/page": this.node("i", 0),
|
|
1888
2652
|
"/-stat/screen/SCENE/page": this.node("i", 0),
|
|
1889
2653
|
"/-stat/screen/ASSIGN/page": this.node("i", 0),
|
|
2654
|
+
"/-stat/aes50/state": this.node("i", 0),
|
|
2655
|
+
"/-stat/aes50/A": this.node("i", 0),
|
|
2656
|
+
"/-stat/aes50/B": this.node("i", 0),
|
|
2657
|
+
"/-stat/aes50/stats/A": this.node("i", 0),
|
|
2658
|
+
"/-stat/aes50/stats/B": this.node("i", 0),
|
|
2659
|
+
"/-stat/tape/state": this.node("i", 0),
|
|
2660
|
+
"/-stat/tape/file": this.node("s", ""),
|
|
2661
|
+
"/-stat/tape/etime": this.node("i", 0),
|
|
2662
|
+
"/-stat/tape/rtime": this.node("i", 0),
|
|
2663
|
+
"/-stat/urec/state": this.node("i", 0),
|
|
2664
|
+
"/-stat/urec/etime": this.node("i", 0),
|
|
2665
|
+
"/-stat/urec/rtime": this.node("i", 0),
|
|
1890
2666
|
"/-stat/talk/A": this.node("i", 0),
|
|
1891
2667
|
"/-stat/talk/B": this.node("i", 0),
|
|
1892
2668
|
"/-stat/osc/on": this.node("i", 0),
|
|
1893
|
-
"/-
|
|
1894
|
-
"/-action/
|
|
2669
|
+
"/-action/setip": this.node("i", 0),
|
|
2670
|
+
"/-action/setclock": this.node("i", 0),
|
|
2671
|
+
"/-action/initall": this.node("i", 0),
|
|
2672
|
+
"/-action/initlib": this.node("i", 0),
|
|
2673
|
+
"/-action/initshow": this.node("i", 0),
|
|
2674
|
+
"/-action/savestate": this.node("i", 0),
|
|
2675
|
+
"/-action/undopt": this.node("i", 0),
|
|
2676
|
+
"/-action/doundo": this.node("i", 0),
|
|
1895
2677
|
"/-action/playtrack": this.node("i", 0),
|
|
2678
|
+
"/-action/newscreen": this.node("i", 0),
|
|
2679
|
+
"/-action/clearsolo": this.node("i", 0),
|
|
2680
|
+
"/-action/setprebus": this.node("i", 0),
|
|
2681
|
+
"/-action/setsrate": this.node("i", 0),
|
|
2682
|
+
"/-action/setrtasrc": this.node("i", 0),
|
|
2683
|
+
"/-action/recselect": this.node("i", 0),
|
|
2684
|
+
"/-action/gocue": this.node("i", 0),
|
|
1896
2685
|
"/-action/goscene": this.node("i", 0),
|
|
1897
2686
|
"/-action/setscene": this.node("i", 0),
|
|
2687
|
+
"/-action/gosnippet": this.node("i", 0),
|
|
2688
|
+
"/-action/selsession": this.node("i", 0),
|
|
2689
|
+
"/-action/delsession": this.node("i", 0),
|
|
2690
|
+
"/-action/selmarker": this.node("i", 0),
|
|
2691
|
+
"/-action/delmarker": this.node("i", 0),
|
|
2692
|
+
"/-action/savemarker": this.node("i", 0),
|
|
2693
|
+
"/-action/addmarker": this.node("i", 0),
|
|
2694
|
+
"/-action/selposition": this.node("i", 0),
|
|
2695
|
+
"/-action/clearalert": this.node("i", 0),
|
|
2696
|
+
"/-action/formatcard": this.node("i", 0),
|
|
2697
|
+
"/-undo/time": this.node("s", ""),
|
|
2698
|
+
"/-show": this.node("i", 0),
|
|
2699
|
+
"/-show/prepos": this.node("i", 0),
|
|
2700
|
+
"/-show/prepos/current": this.node("i", 0),
|
|
2701
|
+
"/-show/showfile": this.node("s", ""),
|
|
2702
|
+
"/-show/showfile/inputs": this.node("i", 0),
|
|
2703
|
+
"/-show/showfile/mxsends": this.node("i", 0),
|
|
2704
|
+
"/-show/showfile/mxbuses": this.node("i", 0),
|
|
2705
|
+
"/-show/showfile/console": this.node("i", 0),
|
|
2706
|
+
"/-show/showfile/chan16": this.node("i", 0),
|
|
2707
|
+
"/-show/showfile/chan32": this.node("i", 0),
|
|
2708
|
+
"/-show/showfile/return": this.node("i", 0),
|
|
2709
|
+
"/-show/showfile/buses": this.node("i", 0),
|
|
2710
|
+
"/-show/showfile/lrmtxdca": this.node("i", 0),
|
|
2711
|
+
"/-show/showfile/effects": this.node("i", 0),
|
|
2712
|
+
...this.generateShowfileCues(),
|
|
2713
|
+
...this.generateShowfileScenes(),
|
|
2714
|
+
...this.generateShowfileSnippets(),
|
|
2715
|
+
"/-usb/path": this.node("s", ""),
|
|
2716
|
+
"/-usb/title": this.node("s", ""),
|
|
2717
|
+
"/-usb/dir": this.node("i", 0),
|
|
2718
|
+
"/-usb/dirpos": this.node("i", 0),
|
|
2719
|
+
"/-usb/maxpos": this.node("i", 0),
|
|
2720
|
+
...this.generateUSBDir(),
|
|
2721
|
+
"/-urec/sessionmax": this.node("i", 0),
|
|
2722
|
+
"/-urec/markermax": this.node("i", 0),
|
|
2723
|
+
"/-urec/sessionlen": this.node("i", 0),
|
|
2724
|
+
"/-urec/sessionpos": this.node("i", 0),
|
|
2725
|
+
"/-urec/markerpos": this.node("i", 0),
|
|
2726
|
+
"/-urec/batterystate": this.node("i", 0),
|
|
2727
|
+
"/-urec/srate": this.node("i", 0),
|
|
2728
|
+
"/-urec/tracks": this.node("i", 0),
|
|
2729
|
+
"/-urec/sessionspan": this.node("i", 0),
|
|
2730
|
+
"/-urec/sessionoffs": this.node("i", 0),
|
|
2731
|
+
"/-urec/sd1state": this.node("i", 0),
|
|
2732
|
+
"/-urec/sd2state": this.node("i", 0),
|
|
2733
|
+
"/-urec/sd1info": this.node("s", ""),
|
|
2734
|
+
"/-urec/sd2info": this.node("s", ""),
|
|
2735
|
+
"/-urec/errormessage": this.node("s", ""),
|
|
2736
|
+
"/-urec/errorcode": this.node("i", 0),
|
|
2737
|
+
...this.generateURecSessions(),
|
|
2738
|
+
...this.generateLibraries(),
|
|
2739
|
+
"/-insert": this.node("i", 0),
|
|
2740
|
+
"/-prefs/style": this.node("i", 0),
|
|
2741
|
+
"/-prefs/bright": this.node("i", 50),
|
|
2742
|
+
"/-prefs/lcdcont": this.node("i", 50),
|
|
2743
|
+
"/-prefs/ledbright": this.node("i", 50),
|
|
2744
|
+
"/-prefs/lamp": this.node("i", 50),
|
|
2745
|
+
"/-prefs/lampon": this.node("i", 0),
|
|
2746
|
+
"/-prefs/clockrate": this.node("i", 0),
|
|
2747
|
+
"/-prefs/clocksource": this.node("i", 0),
|
|
2748
|
+
"/-prefs/confirm_general": this.node("i", 1),
|
|
2749
|
+
"/-prefs/confirm_overwrite": this.node("i", 1),
|
|
2750
|
+
"/-prefs/confirm_sceneload": this.node("i", 1),
|
|
2751
|
+
"/-prefs/viewrtn": this.node("i", 0),
|
|
2752
|
+
"/-prefs/selfollowsbank": this.node("i", 0),
|
|
2753
|
+
"/-prefs/scene_advance": this.node("i", 0),
|
|
2754
|
+
"/-prefs/safe_masterlevels": this.node("i", 0),
|
|
2755
|
+
"/-prefs/haflags": this.node("i", 0),
|
|
2756
|
+
"/-prefs/autosel": this.node("i", 1),
|
|
2757
|
+
"/-prefs/show_control": this.node("i", 0),
|
|
2758
|
+
"/-prefs/clockmode": this.node("i", 0),
|
|
2759
|
+
"/-prefs/hardmute": this.node("i", 0),
|
|
2760
|
+
"/-prefs/dcamute": this.node("i", 0),
|
|
2761
|
+
"/-prefs/invertmutes": this.node("i", 0),
|
|
2762
|
+
"/-prefs/name": this.node("s", "X32-Simulator"),
|
|
2763
|
+
"/-prefs/rec_control": this.node("i", 0),
|
|
2764
|
+
"/-prefs/fastFaders": this.node("i", 0),
|
|
2765
|
+
"/-prefs/ip": this.node("s", ""),
|
|
2766
|
+
"/-prefs/ip/dhcp": this.node("i", 0),
|
|
2767
|
+
"/-prefs/ip/addr": this.node("s", "192.168.1.1"),
|
|
2768
|
+
"/-prefs/ip/mask": this.node("s", "255.255.255.0"),
|
|
2769
|
+
"/-prefs/ip/gateway": this.node("s", "192.168.1.1"),
|
|
2770
|
+
"/-prefs/remote": this.node("i", 0),
|
|
2771
|
+
"/-prefs/remote/enable": this.node("i", 0),
|
|
2772
|
+
"/-prefs/remote/protocol": this.node("i", 0),
|
|
2773
|
+
"/-prefs/remote/port": this.node("i", 10023),
|
|
2774
|
+
"/-prefs/remote/ioenable": this.node("i", 0),
|
|
2775
|
+
"/-prefs/card": this.node("i", 0),
|
|
2776
|
+
"/-prefs/card/UFifc": this.node("i", 0),
|
|
2777
|
+
"/-prefs/card/UFmode": this.node("i", 0),
|
|
2778
|
+
"/-prefs/card/USBmode": this.node("i", 0),
|
|
2779
|
+
"/-prefs/card/ADATwc": this.node("i", 0),
|
|
2780
|
+
"/-prefs/card/ADATsync": this.node("i", 0),
|
|
2781
|
+
"/-prefs/card/MADImode": this.node("i", 0),
|
|
2782
|
+
"/-prefs/card/MADIin": this.node("i", 0),
|
|
2783
|
+
"/-prefs/card/MADIout": this.node("i", 0),
|
|
2784
|
+
"/-prefs/card/MADIsrc": this.node("i", 0),
|
|
2785
|
+
"/-prefs/card/URECtracks": this.node("i", 0),
|
|
2786
|
+
"/-prefs/card/URECplayb": this.node("i", 0),
|
|
2787
|
+
"/-prefs/card/URECrout": this.node("i", 0),
|
|
2788
|
+
"/-prefs/card/URECsdsel": this.node("i", 0),
|
|
2789
|
+
"/-prefs/rta": this.node("i", 0),
|
|
2790
|
+
"/-prefs/rta/visibility": this.node("s", "70%"),
|
|
2791
|
+
"/-prefs/rta/gain": this.node("f", 0),
|
|
2792
|
+
"/-prefs/rta/autogain": this.node("i", 0),
|
|
2793
|
+
"/-prefs/rta/source": this.node("i", 0),
|
|
2794
|
+
"/-prefs/rta/pos": this.node("i", 0),
|
|
2795
|
+
"/-prefs/rta/mode": this.node("i", 0),
|
|
2796
|
+
"/-prefs/rta/option": this.node("i", 0),
|
|
2797
|
+
"/-prefs/rta/det": this.node("i", 0),
|
|
2798
|
+
"/-prefs/rta/decay": this.node("i", 0),
|
|
2799
|
+
"/-prefs/rta/peakhold": this.node("i", 0),
|
|
2800
|
+
...this.generatePrefsIQ(),
|
|
2801
|
+
"/-prefs/key/layout": this.node("i", 0),
|
|
2802
|
+
...this.generateRange(100, "/-prefs/key", "", "i", 0, 2, 0),
|
|
1898
2803
|
"/config/routing/AES50A/1-8": this.node("i", 0),
|
|
1899
2804
|
"/config/routing/AES50B/1-8": this.node("i", 0),
|
|
1900
2805
|
"/config/routing/CARD/1-8": this.node("i", 0),
|
|
1901
2806
|
"/config/routing/OUT/1-4": this.node("i", 0),
|
|
1902
|
-
"/-prefs/invertmutes": this.node("i", 0),
|
|
1903
2807
|
...this.generateChannelStrip("/main/st", 6, false),
|
|
1904
2808
|
...this.generateChannelStrip("/main/m", 6, false),
|
|
1905
2809
|
...Object.fromEntries(Array.from({ length: 16 }, (_, i) => [`/config/chlink/${i * 2 + 1}-${i * 2 + 2}`, this.node("i", 0)])),
|
|
1906
2810
|
...Object.fromEntries(Array.from({ length: 8 }, (_, i) => [`/config/buslink/${i * 2 + 1}-${i * 2 + 2}`, this.node("i", 0)])),
|
|
1907
2811
|
...Object.fromEntries(Array.from({ length: 4 }, (_, i) => [`/config/auxlink/${i * 2 + 1}-${i * 2 + 2}`, this.node("i", 0)])),
|
|
1908
2812
|
...Object.fromEntries(Array.from({ length: 4 }, (_, i) => [`/config/fxlink/${i * 2 + 1}-${i * 2 + 2}`, this.node("i", 0)])),
|
|
2813
|
+
...Object.fromEntries(Array.from({ length: 3 }, (_, i) => [`/config/mtxlink/${i * 2 + 1}-${i * 2 + 2}`, this.node("i", 0)])),
|
|
2814
|
+
"/config/linkcfg/hadly": this.node("i", 0),
|
|
2815
|
+
"/config/linkcfg/eq": this.node("i", 0),
|
|
2816
|
+
"/config/linkcfg/dyn": this.node("i", 0),
|
|
2817
|
+
"/config/linkcfg/fdrmute": this.node("i", 0),
|
|
2818
|
+
"/config/mono/mode": this.node("i", 0),
|
|
2819
|
+
"/config/mono/link": this.node("i", 0),
|
|
2820
|
+
"/config/tape/autoplay": this.node("i", 0),
|
|
2821
|
+
"/config/tape/gainL": this.node("f", .5),
|
|
2822
|
+
"/config/tape/gainR": this.node("f", .5),
|
|
2823
|
+
"/config/amixenable/X": this.node("i", 0),
|
|
2824
|
+
"/config/amixenable/Y": this.node("i", 0),
|
|
2825
|
+
...this.generateUserCtrl(),
|
|
2826
|
+
"/config/routing/routswitch": this.node("i", 0),
|
|
1909
2827
|
...this.generateRange(32, "/config/userrout/in", "", "i", 0),
|
|
1910
2828
|
...this.generateRange(48, "/config/userrout/out", "", "i", 0),
|
|
1911
2829
|
"/config/solo/level": this.node("f", 0),
|
|
@@ -1941,6 +2859,7 @@ var SchemaFactory = class {
|
|
|
1941
2859
|
"/config/osc/f2": this.node("f", .5),
|
|
1942
2860
|
"/config/osc/level": this.node("f", 0),
|
|
1943
2861
|
"/config/osc/dest": this.node("i", 0),
|
|
2862
|
+
...this.generateDP48Config(),
|
|
1944
2863
|
...this.generateOutputs("main", 16),
|
|
1945
2864
|
...this.generateOutputs("aux", 6),
|
|
1946
2865
|
...this.generateOutputs("p16", 16),
|
|
@@ -1948,7 +2867,11 @@ var SchemaFactory = class {
|
|
|
1948
2867
|
...this.generateOutputs("rec", 2)
|
|
1949
2868
|
};
|
|
1950
2869
|
Object.keys(STATIC_RESPONSES_DATA).forEach((key) => {
|
|
1951
|
-
if (key.startsWith("/-")
|
|
2870
|
+
if (key.startsWith("/-")) {
|
|
2871
|
+
const val = STATIC_RESPONSES_DATA[key][0];
|
|
2872
|
+
const type = typeof val === "string" ? "s" : Number.isInteger(val) ? "i" : "f";
|
|
2873
|
+
schema[key] = this.node(type, val);
|
|
2874
|
+
}
|
|
1952
2875
|
});
|
|
1953
2876
|
[
|
|
1954
2877
|
"/config/routing/IN/1-8",
|
|
@@ -2059,6 +2982,7 @@ var SchemaFactory = class {
|
|
|
2059
2982
|
generateNodes(count, prefix) {
|
|
2060
2983
|
const nodes = {};
|
|
2061
2984
|
const isChannelOrAux = prefix === "ch" || prefix === "auxin";
|
|
2985
|
+
const hasMtxPreamp = prefix === "mtx";
|
|
2062
2986
|
const eqBands = prefix === "bus" || prefix === "mtx" ? 6 : 4;
|
|
2063
2987
|
for (let i = 1; i <= count; i++) {
|
|
2064
2988
|
const padId = i.toString().padStart(2, "0");
|
|
@@ -2070,7 +2994,7 @@ var SchemaFactory = class {
|
|
|
2070
2994
|
nodes[`${base}/fader`] = this.node("f", .75);
|
|
2071
2995
|
nodes[`${base}/on`] = this.node("i", 0);
|
|
2072
2996
|
} else {
|
|
2073
|
-
Object.assign(nodes, this.generateChannelStrip(base, eqBands, isChannelOrAux));
|
|
2997
|
+
Object.assign(nodes, this.generateChannelStrip(base, eqBands, isChannelOrAux || hasMtxPreamp));
|
|
2074
2998
|
if (prefix === "ch" || prefix === "auxin" || prefix === "fxrtn" || prefix === "bus") for (let b = 1; b <= 16; b++) {
|
|
2075
2999
|
const busId = b.toString().padStart(2, "0");
|
|
2076
3000
|
nodes[`${base}/mix/${busId}/level`] = this.node("f", 0);
|
|
@@ -2078,6 +3002,11 @@ var SchemaFactory = class {
|
|
|
2078
3002
|
nodes[`${base}/mix/${busId}/pan`] = this.node("f", .5);
|
|
2079
3003
|
nodes[`${base}/mix/${busId}/type`] = this.node("i", 0);
|
|
2080
3004
|
}
|
|
3005
|
+
if (prefix === "ch") {
|
|
3006
|
+
nodes[`${base}/automix`] = this.node("i", 0);
|
|
3007
|
+
nodes[`${base}/automix/group`] = this.node("i", 0);
|
|
3008
|
+
nodes[`${base}/automix/weight`] = this.node("f", 0);
|
|
3009
|
+
}
|
|
2081
3010
|
}
|
|
2082
3011
|
});
|
|
2083
3012
|
}
|
|
@@ -2110,6 +3039,159 @@ var SchemaFactory = class {
|
|
|
2110
3039
|
}
|
|
2111
3040
|
return nodes;
|
|
2112
3041
|
}
|
|
3042
|
+
/**
|
|
3043
|
+
* Generates showfile cue entries (100 cues: 000-099)
|
|
3044
|
+
*/
|
|
3045
|
+
generateShowfileCues() {
|
|
3046
|
+
const nodes = {};
|
|
3047
|
+
for (let i = 0; i < 100; i++) {
|
|
3048
|
+
const base = `/-show/showfile/cue/${i.toString().padStart(3, "0")}`;
|
|
3049
|
+
nodes[base] = this.node("s", "");
|
|
3050
|
+
nodes[`${base}/numb`] = this.node("i", 0);
|
|
3051
|
+
nodes[`${base}/name`] = this.node("s", "");
|
|
3052
|
+
nodes[`${base}/skip`] = this.node("i", 0);
|
|
3053
|
+
nodes[`${base}/scene`] = this.node("i", 0);
|
|
3054
|
+
nodes[`${base}/bit`] = this.node("i", 0);
|
|
3055
|
+
nodes[`${base}/miditype`] = this.node("i", 0);
|
|
3056
|
+
nodes[`${base}/midichan`] = this.node("i", 0);
|
|
3057
|
+
nodes[`${base}/midipara1`] = this.node("i", 0);
|
|
3058
|
+
nodes[`${base}/midipara2`] = this.node("i", 0);
|
|
3059
|
+
}
|
|
3060
|
+
return nodes;
|
|
3061
|
+
}
|
|
3062
|
+
/**
|
|
3063
|
+
* Generates showfile scene entries (100 scenes: 000-099)
|
|
3064
|
+
*/
|
|
3065
|
+
generateShowfileScenes() {
|
|
3066
|
+
const nodes = {};
|
|
3067
|
+
for (let i = 0; i < 100; i++) {
|
|
3068
|
+
const base = `/-show/showfile/scene/${i.toString().padStart(3, "0")}`;
|
|
3069
|
+
nodes[base] = this.node("s", "");
|
|
3070
|
+
nodes[`${base}/name`] = this.node("s", "");
|
|
3071
|
+
nodes[`${base}/notes`] = this.node("s", "");
|
|
3072
|
+
nodes[`${base}/safes`] = this.node("i", 0);
|
|
3073
|
+
nodes[`${base}/hasdata`] = this.node("i", 0);
|
|
3074
|
+
}
|
|
3075
|
+
return nodes;
|
|
3076
|
+
}
|
|
3077
|
+
/**
|
|
3078
|
+
* Generates showfile snippet entries (100 snippets: 000-099)
|
|
3079
|
+
*/
|
|
3080
|
+
generateShowfileSnippets() {
|
|
3081
|
+
const nodes = {};
|
|
3082
|
+
for (let i = 0; i < 100; i++) {
|
|
3083
|
+
const base = `/-show/showfile/snippet/${i.toString().padStart(3, "0")}`;
|
|
3084
|
+
nodes[base] = this.node("s", "");
|
|
3085
|
+
nodes[`${base}/name`] = this.node("s", "");
|
|
3086
|
+
nodes[`${base}/eventtyp`] = this.node("i", 0);
|
|
3087
|
+
nodes[`${base}/channels`] = this.node("i", 0);
|
|
3088
|
+
nodes[`${base}/auxbuses`] = this.node("i", 0);
|
|
3089
|
+
nodes[`${base}/maingrps`] = this.node("i", 0);
|
|
3090
|
+
nodes[`${base}/hasdata`] = this.node("i", 0);
|
|
3091
|
+
}
|
|
3092
|
+
return nodes;
|
|
3093
|
+
}
|
|
3094
|
+
/**
|
|
3095
|
+
* Generates preferences iQ entries (16 entries: 01-16)
|
|
3096
|
+
*/
|
|
3097
|
+
generatePrefsIQ() {
|
|
3098
|
+
const nodes = {};
|
|
3099
|
+
for (let i = 1; i <= 16; i++) {
|
|
3100
|
+
const base = `/-prefs/iQ/${i.toString().padStart(2, "0")}`;
|
|
3101
|
+
nodes[base] = this.node("i", 0);
|
|
3102
|
+
nodes[`${base}/iQmodel`] = this.node("i", 0);
|
|
3103
|
+
nodes[`${base}/iQeqset`] = this.node("i", 0);
|
|
3104
|
+
nodes[`${base}/iQsound`] = this.node("i", 0);
|
|
3105
|
+
}
|
|
3106
|
+
return nodes;
|
|
3107
|
+
}
|
|
3108
|
+
/**
|
|
3109
|
+
* Generates DP48 Personal Monitor config entries (48 channels)
|
|
3110
|
+
*/
|
|
3111
|
+
generateDP48Config() {
|
|
3112
|
+
const nodes = {};
|
|
3113
|
+
for (let i = 1; i <= 48; i++) {
|
|
3114
|
+
const id = i.toString().padStart(2, "0");
|
|
3115
|
+
nodes[`/config/dp48/link/${id}`] = this.node("i", 0);
|
|
3116
|
+
}
|
|
3117
|
+
nodes["/config/dp48/assign"] = this.node("i", 0);
|
|
3118
|
+
nodes["/config/dp48/grpname/01"] = this.node("s", "");
|
|
3119
|
+
nodes["/config/dp48/grpname/02"] = this.node("s", "");
|
|
3120
|
+
nodes["/config/dp48/grpname/03"] = this.node("s", "");
|
|
3121
|
+
nodes["/config/dp48/grpname/04"] = this.node("s", "");
|
|
3122
|
+
nodes["/config/dp48/grpname/05"] = this.node("s", "");
|
|
3123
|
+
nodes["/config/dp48/grpname/06"] = this.node("s", "");
|
|
3124
|
+
nodes["/config/dp48/grpname/07"] = this.node("s", "");
|
|
3125
|
+
nodes["/config/dp48/grpname/08"] = this.node("s", "");
|
|
3126
|
+
nodes["/config/dp48/grpname/09"] = this.node("s", "");
|
|
3127
|
+
nodes["/config/dp48/grpname/10"] = this.node("s", "");
|
|
3128
|
+
nodes["/config/dp48/grpname/11"] = this.node("s", "");
|
|
3129
|
+
nodes["/config/dp48/grpname/12"] = this.node("s", "");
|
|
3130
|
+
return nodes;
|
|
3131
|
+
}
|
|
3132
|
+
/**
|
|
3133
|
+
* Generates USB directory entries (1000 entries: 000-999)
|
|
3134
|
+
*/
|
|
3135
|
+
generateUSBDir() {
|
|
3136
|
+
const nodes = {};
|
|
3137
|
+
for (let i = 0; i < 1e3; i++) {
|
|
3138
|
+
const id = i.toString().padStart(3, "0");
|
|
3139
|
+
nodes[`/-usb/dir/${id}`] = this.node("s", "");
|
|
3140
|
+
nodes[`/-usb/dir/${id}/name`] = this.node("s", "");
|
|
3141
|
+
}
|
|
3142
|
+
return nodes;
|
|
3143
|
+
}
|
|
3144
|
+
/**
|
|
3145
|
+
* Generates USB recording session and marker entries
|
|
3146
|
+
*/
|
|
3147
|
+
generateURecSessions() {
|
|
3148
|
+
const nodes = {};
|
|
3149
|
+
for (let i = 1; i <= 100; i++) {
|
|
3150
|
+
const id = i.toString().padStart(3, "0");
|
|
3151
|
+
nodes[`/-urec/session/${id}/name`] = this.node("s", "");
|
|
3152
|
+
nodes[`/-urec/marker/${id}/time`] = this.node("i", 0);
|
|
3153
|
+
}
|
|
3154
|
+
return nodes;
|
|
3155
|
+
}
|
|
3156
|
+
/**
|
|
3157
|
+
* Generates library entries (ch, fx, r, mon - 100 each)
|
|
3158
|
+
*/
|
|
3159
|
+
generateLibraries() {
|
|
3160
|
+
const nodes = {};
|
|
3161
|
+
for (const lib of [
|
|
3162
|
+
"ch",
|
|
3163
|
+
"fx",
|
|
3164
|
+
"r",
|
|
3165
|
+
"mon"
|
|
3166
|
+
]) {
|
|
3167
|
+
nodes[`/-libs/${lib}`] = this.node("i", 0);
|
|
3168
|
+
for (let i = 1; i <= 100; i++) {
|
|
3169
|
+
const base = `/-libs/${lib}/${i.toString().padStart(3, "0")}`;
|
|
3170
|
+
nodes[base] = this.node("s", "");
|
|
3171
|
+
nodes[`${base}/pos`] = this.node("i", 0);
|
|
3172
|
+
nodes[`${base}/name`] = this.node("s", "");
|
|
3173
|
+
nodes[`${base}/flags`] = this.node("i", 0);
|
|
3174
|
+
nodes[`${base}/hasdata`] = this.node("i", 0);
|
|
3175
|
+
}
|
|
3176
|
+
}
|
|
3177
|
+
return nodes;
|
|
3178
|
+
}
|
|
3179
|
+
/**
|
|
3180
|
+
* Generates user control entries (A, B, C with enc and btn)
|
|
3181
|
+
*/
|
|
3182
|
+
generateUserCtrl() {
|
|
3183
|
+
const nodes = {};
|
|
3184
|
+
for (const bank of [
|
|
3185
|
+
"A",
|
|
3186
|
+
"B",
|
|
3187
|
+
"C"
|
|
3188
|
+
]) {
|
|
3189
|
+
nodes[`/config/userctrl/${bank}`] = this.node("i", 0);
|
|
3190
|
+
for (let i = 1; i <= 4; i++) nodes[`/config/userctrl/${bank}/enc/${i}`] = this.node("i", 0);
|
|
3191
|
+
for (let i = 1; i <= 12; i++) nodes[`/config/userctrl/${bank}/btn/${i}`] = this.node("i", 0);
|
|
3192
|
+
}
|
|
3193
|
+
return nodes;
|
|
3194
|
+
}
|
|
2113
3195
|
};
|
|
2114
3196
|
|
|
2115
3197
|
//#endregion
|
|
@@ -2174,4 +3256,4 @@ var SchemaRegistry = class {
|
|
|
2174
3256
|
};
|
|
2175
3257
|
|
|
2176
3258
|
//#endregion
|
|
2177
|
-
export { ConsoleLogger as a, X32Node as c,
|
|
3259
|
+
export { ConsoleLogger as a, X32Node as c, MeterData as d, SubscriptionManager as f, LogCategory as g, X32State as h, UdpNetworkGateway as i, SimulationService as l, mergeConfig as m, SchemaFactory as n, LogLevel as o, DEFAULT_CONFIG as p, OscCodec as r, InMemoryStateRepository as s, SchemaRegistry as t, METER_COUNTS as u };
|