@djodjonx/x32-simulator 0.0.6 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/dist/{SchemaRegistry-D4eIJord.mjs → SchemaRegistry-BBzyicoy.mjs} +1271 -192
- package/dist/{SchemaRegistry-DE6iObDv.cjs → SchemaRegistry-Ddy5AEKs.cjs} +1282 -191
- package/dist/index.cjs +4 -2
- package/dist/index.d.cts +84 -39
- package/dist/index.d.mts +84 -39
- package/dist/index.mjs +2 -2
- package/dist/server.cjs +205 -10
- package/dist/server.mjs +206 -10
- package/package.json +1 -1
|
@@ -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({
|
|
@@ -362,8 +485,9 @@ var NodeDiscoveryStrategy = class {
|
|
|
362
485
|
//#endregion
|
|
363
486
|
//#region src/domain/services/strategies/StaticResponseStrategy.ts
|
|
364
487
|
/**
|
|
365
|
-
* Handles discovery and static information queries.
|
|
366
|
-
* 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.
|
|
367
491
|
*/
|
|
368
492
|
var StaticResponseStrategy = class {
|
|
369
493
|
constructor(serverIp, serverName, serverModel, staticResponseService) {
|
|
@@ -372,7 +496,8 @@ var StaticResponseStrategy = class {
|
|
|
372
496
|
this.serverModel = serverModel;
|
|
373
497
|
this.staticResponseService = staticResponseService;
|
|
374
498
|
}
|
|
375
|
-
canHandle(address) {
|
|
499
|
+
canHandle(address, args) {
|
|
500
|
+
if (args && args.length > 0) return false;
|
|
376
501
|
return !!this.staticResponseService.getResponse(address);
|
|
377
502
|
}
|
|
378
503
|
execute(msg, _source) {
|
|
@@ -543,6 +668,7 @@ var MeterStrategy = class {
|
|
|
543
668
|
* LOGIC:
|
|
544
669
|
* - If no arguments: Treats as a QUERY (GET) and returns the current value.
|
|
545
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.
|
|
546
672
|
*/
|
|
547
673
|
var StateAccessStrategy = class {
|
|
548
674
|
/**
|
|
@@ -550,43 +676,685 @@ var StateAccessStrategy = class {
|
|
|
550
676
|
* @param state - Current mixer state.
|
|
551
677
|
* @param logger - Logger instance.
|
|
552
678
|
* @param schemaRegistry - Registry to validate addresses.
|
|
679
|
+
* @param permissive - If true, store unknown addresses too (default: true).
|
|
553
680
|
*/
|
|
554
|
-
constructor(state, logger, schemaRegistry) {
|
|
681
|
+
constructor(state, logger, schemaRegistry, permissive = true) {
|
|
555
682
|
this.state = state;
|
|
556
683
|
this.logger = logger;
|
|
557
684
|
this.schemaRegistry = schemaRegistry;
|
|
685
|
+
this.permissive = permissive;
|
|
558
686
|
}
|
|
559
687
|
/** @inheritdoc */
|
|
560
688
|
canHandle(address) {
|
|
561
|
-
|
|
689
|
+
if (this.schemaRegistry.has(address)) return true;
|
|
690
|
+
return this.permissive && address.startsWith("/");
|
|
562
691
|
}
|
|
563
692
|
/** @inheritdoc */
|
|
564
693
|
execute(msg, _source) {
|
|
565
694
|
const addr = msg.address;
|
|
566
695
|
const node = this.schemaRegistry.getNode(addr);
|
|
696
|
+
const isKnown = !!node;
|
|
567
697
|
if (msg.args.length === 0) {
|
|
568
698
|
const val$1 = this.state.get(addr);
|
|
569
699
|
if (val$1 !== void 0) return [{
|
|
570
700
|
address: addr,
|
|
571
701
|
args: [val$1]
|
|
572
702
|
}];
|
|
703
|
+
if (!isKnown) this.logger.debug(LogCategory.STATE, `[GET] Unknown address queried: ${addr}`);
|
|
573
704
|
return [];
|
|
574
705
|
}
|
|
575
706
|
const val = msg.args[0];
|
|
576
|
-
if (
|
|
707
|
+
if (isKnown) {
|
|
577
708
|
if (!node.validate(val)) {
|
|
578
709
|
this.logger.warn(LogCategory.DISPATCH, `[TYPE ERR] ${addr} expected ${node.type}, got ${typeof val}`);
|
|
579
710
|
return [];
|
|
580
711
|
}
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
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}`);
|
|
723
|
+
}
|
|
724
|
+
return [];
|
|
725
|
+
}
|
|
726
|
+
};
|
|
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}`);
|
|
587
1271
|
}
|
|
588
1272
|
return [];
|
|
589
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
|
+
}
|
|
590
1358
|
};
|
|
591
1359
|
|
|
592
1360
|
//#endregion
|
|
@@ -621,8 +1389,10 @@ var OscMessageHandler = class {
|
|
|
621
1389
|
new SubscriptionStrategy(subscriptionManager, state, logger),
|
|
622
1390
|
new BatchStrategy(subscriptionManager, logger),
|
|
623
1391
|
new MeterStrategy(subscriptionManager, state, this.meterService),
|
|
624
|
-
new
|
|
625
|
-
new
|
|
1392
|
+
new ShowDumpStrategy(state, logger),
|
|
1393
|
+
new SceneDataStrategy(state, logger),
|
|
1394
|
+
new StaticResponseStrategy(serverIp, serverName, serverModel, this.staticResponseService),
|
|
1395
|
+
new StateAccessStrategy(state, logger, this.schemaRegistry)
|
|
626
1396
|
];
|
|
627
1397
|
}
|
|
628
1398
|
/**
|
|
@@ -632,19 +1402,41 @@ var OscMessageHandler = class {
|
|
|
632
1402
|
* @returns Array of replies generated by the strategy.
|
|
633
1403
|
*/
|
|
634
1404
|
handle(msg, source) {
|
|
635
|
-
|
|
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
|
+
}
|
|
636
1425
|
if (!addr.startsWith("/meters")) this.logger.debug(LogCategory.DISPATCH, `Handling`, {
|
|
637
1426
|
addr,
|
|
638
|
-
args
|
|
1427
|
+
args
|
|
639
1428
|
});
|
|
640
|
-
for (const strategy of this.strategies) if (strategy.canHandle(addr)) {
|
|
641
|
-
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);
|
|
642
1434
|
if (replies.length > 0) this.logger.debug(LogCategory.DISPATCH, `Strategy ${strategy.constructor.name} replied`, { count: replies.length });
|
|
643
1435
|
return replies;
|
|
644
1436
|
}
|
|
645
1437
|
this.logger.warn(LogCategory.DISPATCH, `Unknown Command`, {
|
|
646
1438
|
addr,
|
|
647
|
-
args
|
|
1439
|
+
args,
|
|
648
1440
|
ip: source.address
|
|
649
1441
|
});
|
|
650
1442
|
return [];
|
|
@@ -758,6 +1550,8 @@ var MeterService = class {
|
|
|
758
1550
|
//#region src/domain/services/StaticResponseService.ts
|
|
759
1551
|
/**
|
|
760
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.
|
|
761
1555
|
*/
|
|
762
1556
|
const STATIC_RESPONSES_DATA = {
|
|
763
1557
|
"/xinfo": [
|
|
@@ -776,34 +1570,7 @@ const STATIC_RESPONSES_DATA = {
|
|
|
776
1570
|
"active",
|
|
777
1571
|
"{{ip}}",
|
|
778
1572
|
"{{name}}"
|
|
779
|
-
]
|
|
780
|
-
"/-prefs/invertmutes": [0],
|
|
781
|
-
"/-prefs/fine": [0],
|
|
782
|
-
"/-prefs/bright": [50],
|
|
783
|
-
"/-prefs/contrast": [50],
|
|
784
|
-
"/-prefs/led_bright": [50],
|
|
785
|
-
"/-prefs/lcd_bright": [50],
|
|
786
|
-
"/-stat/userpar/1/value": [0],
|
|
787
|
-
"/-stat/userpar/2/value": [0],
|
|
788
|
-
"/-stat/tape/state": [0],
|
|
789
|
-
"/-stat/aes50/A": [0],
|
|
790
|
-
"/-stat/aes50/B": [0],
|
|
791
|
-
"/-stat/solo": [0],
|
|
792
|
-
"/-stat/rtasource": [0],
|
|
793
|
-
"/-urec/errorcode": [0],
|
|
794
|
-
"/-prefs/rta/gain": [0],
|
|
795
|
-
"/-prefs/rta/autogain": [0],
|
|
796
|
-
"/-prefs/hardmute": [0],
|
|
797
|
-
"/-prefs/dcamute": [0],
|
|
798
|
-
"/config/mono/mode": [0],
|
|
799
|
-
"/config/amixenable/X": [0],
|
|
800
|
-
"/config/amixenable/Y": [0],
|
|
801
|
-
"/-show/prepos/current": [0],
|
|
802
|
-
"/-show/showfile/current": [""],
|
|
803
|
-
"/-action/setrtasrc": [0],
|
|
804
|
-
"/-action/playtrack": [0],
|
|
805
|
-
"/-action/goscene": [0],
|
|
806
|
-
"/-action/setscene": [0]
|
|
1573
|
+
]
|
|
807
1574
|
};
|
|
808
1575
|
/**
|
|
809
1576
|
* Service providing static system responses.
|
|
@@ -833,47 +1600,51 @@ function getLocalIp() {
|
|
|
833
1600
|
return "127.0.0.1";
|
|
834
1601
|
}
|
|
835
1602
|
/**
|
|
836
|
-
* The core service that manages the X32 simulation, including networking,
|
|
1603
|
+
* The core service that manages the X32 simulation, including networking,
|
|
837
1604
|
* state management, and OSC message handling.
|
|
838
1605
|
*/
|
|
839
1606
|
var SimulationService = class {
|
|
840
1607
|
subscriptionManager;
|
|
841
1608
|
messageHandler;
|
|
1609
|
+
state;
|
|
842
1610
|
processPacket;
|
|
843
1611
|
broadcastUpdates;
|
|
844
1612
|
manageSessions;
|
|
845
1613
|
meterService;
|
|
846
1614
|
staticResponseService;
|
|
1615
|
+
config;
|
|
847
1616
|
updateInterval = null;
|
|
848
1617
|
cleanupInterval = null;
|
|
849
1618
|
/**
|
|
850
1619
|
* Creates a new SimulationService instance.
|
|
851
1620
|
* @param gateway - The network gateway for OSC communication.
|
|
852
1621
|
* @param logger - The logger service.
|
|
853
|
-
* @param
|
|
1622
|
+
* @param stateRepository - The repository for state persistence.
|
|
854
1623
|
* @param schemaRegistry - The registry for X32 OSC schema.
|
|
855
|
-
* @param port - UDP port to listen on (default
|
|
856
|
-
* @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).
|
|
857
1626
|
* @param name - Reported console name.
|
|
858
1627
|
* @param model - Reported console model.
|
|
1628
|
+
* @param configOverrides - Optional configuration overrides.
|
|
859
1629
|
*/
|
|
860
|
-
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) {
|
|
861
1631
|
this.gateway = gateway;
|
|
862
1632
|
this.logger = logger;
|
|
863
|
-
this.
|
|
1633
|
+
this.stateRepository = stateRepository;
|
|
864
1634
|
this.schemaRegistry = schemaRegistry;
|
|
865
1635
|
this.port = port;
|
|
866
1636
|
this.ip = ip;
|
|
867
|
-
|
|
868
|
-
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);
|
|
869
1640
|
this.meterService = new MeterService();
|
|
870
1641
|
this.staticResponseService = new StaticResponseService();
|
|
871
1642
|
const reportedIp = this.ip === "0.0.0.0" ? getLocalIp() : this.ip;
|
|
872
|
-
this.messageHandler = new OscMessageHandler(state, this.subscriptionManager, logger, reportedIp, name, model, this.meterService, this.schemaRegistry, this.staticResponseService);
|
|
873
|
-
this.processPacket = new ProcessPacketUseCase(this.messageHandler, gateway);
|
|
874
|
-
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);
|
|
875
1646
|
this.manageSessions = new ManageSessionsUseCase(this.subscriptionManager);
|
|
876
|
-
state.on("change", (evt) => {
|
|
1647
|
+
this.state.on("change", (evt) => {
|
|
877
1648
|
this.logger.info(LogCategory.STATE, `State Changed`, evt);
|
|
878
1649
|
this.broadcastUpdates.broadcastSingleChange(evt.address, evt.value);
|
|
879
1650
|
});
|
|
@@ -883,13 +1654,14 @@ var SimulationService = class {
|
|
|
883
1654
|
* Starts the simulator server and internal loops.
|
|
884
1655
|
*/
|
|
885
1656
|
async start() {
|
|
1657
|
+
await this.state.initialize();
|
|
886
1658
|
await this.gateway.start(this.port, this.ip);
|
|
887
1659
|
this.cleanupInterval = setInterval(() => {
|
|
888
1660
|
this.manageSessions.cleanup();
|
|
889
|
-
},
|
|
1661
|
+
}, this.config.CLEANUP_INTERVAL_MS);
|
|
890
1662
|
this.updateInterval = setInterval(() => {
|
|
891
1663
|
this.broadcastUpdates.execute();
|
|
892
|
-
},
|
|
1664
|
+
}, this.config.BROADCAST_INTERVAL_MS);
|
|
893
1665
|
}
|
|
894
1666
|
/**
|
|
895
1667
|
* Stops the simulator server and stops all internal loops.
|
|
@@ -897,84 +1669,20 @@ var SimulationService = class {
|
|
|
897
1669
|
async stop() {
|
|
898
1670
|
if (this.updateInterval) clearInterval(this.updateInterval);
|
|
899
1671
|
if (this.cleanupInterval) clearInterval(this.cleanupInterval);
|
|
1672
|
+
await this.state.flush();
|
|
900
1673
|
await this.gateway.stop();
|
|
901
1674
|
}
|
|
902
1675
|
/**
|
|
903
1676
|
* Resets the mixer state to default values.
|
|
904
1677
|
*/
|
|
905
1678
|
resetState() {
|
|
906
|
-
this.
|
|
907
|
-
}
|
|
908
|
-
};
|
|
909
|
-
|
|
910
|
-
//#endregion
|
|
911
|
-
//#region src/domain/entities/X32State.ts
|
|
912
|
-
/**
|
|
913
|
-
* Manages the internal "Digital Twin" state of the X32 console.
|
|
914
|
-
* It acts as a single source of truth for all parameters.
|
|
915
|
-
* Emits 'change' events whenever a value is updated.
|
|
916
|
-
*/
|
|
917
|
-
var X32State = class extends EventEmitter {
|
|
918
|
-
/** Map storing all OSC paths and their current values. */
|
|
919
|
-
state = /* @__PURE__ */ new Map();
|
|
920
|
-
defaultState = /* @__PURE__ */ new Map();
|
|
921
|
-
/**
|
|
922
|
-
* Initializes the state with default values from the schema.
|
|
923
|
-
* @param schema - The schema definition map.
|
|
924
|
-
*/
|
|
925
|
-
constructor(schema) {
|
|
926
|
-
super();
|
|
927
|
-
for (const [addr, def] of Object.entries(schema)) this.defaultState.set(addr, def.default);
|
|
928
|
-
this.reset();
|
|
929
|
-
}
|
|
930
|
-
/**
|
|
931
|
-
* Resets all state parameters to their default values defined in the schema.
|
|
932
|
-
*/
|
|
933
|
-
reset() {
|
|
934
|
-
this.state.clear();
|
|
935
|
-
this.defaultState.forEach((val, key) => {
|
|
936
|
-
this.state.set(key, val);
|
|
937
|
-
});
|
|
938
|
-
}
|
|
939
|
-
/**
|
|
940
|
-
* Retrieves the value of a specific OSC node.
|
|
941
|
-
* @param address - The full OSC address path.
|
|
942
|
-
* @returns The stored value (number or string) or undefined if not found.
|
|
943
|
-
*/
|
|
944
|
-
get(address) {
|
|
945
|
-
return this.state.get(address);
|
|
946
|
-
}
|
|
947
|
-
/**
|
|
948
|
-
* Updates the value of a specific OSC node and notifies subscribers.
|
|
949
|
-
* @param address - The full OSC address path.
|
|
950
|
-
* @param value - The new value to store.
|
|
951
|
-
*/
|
|
952
|
-
set(address, value) {
|
|
953
|
-
this.state.set(address, value);
|
|
954
|
-
this.emit("change", {
|
|
955
|
-
address,
|
|
956
|
-
value
|
|
957
|
-
});
|
|
1679
|
+
this.state.reset();
|
|
958
1680
|
}
|
|
959
1681
|
/**
|
|
960
|
-
*
|
|
961
|
-
* When a mute group is toggled, it iterates through all channels
|
|
962
|
-
* assigned to that group and updates their individual mute status.
|
|
963
|
-
* @param groupIdx - The index of the mute group (1-6).
|
|
964
|
-
* @param isOn - The new state of the group master switch (0 or 1).
|
|
1682
|
+
* Forces a save of the current state to storage.
|
|
965
1683
|
*/
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
const ch = i.toString().padStart(2, "0");
|
|
969
|
-
const grpVal = this.get(`/ch/${ch}/grp/mute`);
|
|
970
|
-
if (typeof grpVal === "number") {
|
|
971
|
-
if ((grpVal & 1 << groupIdx - 1) !== 0) {
|
|
972
|
-
const targetMute = isOn === 1 ? 0 : 1;
|
|
973
|
-
const muteAddr = `/ch/${ch}/mix/on`;
|
|
974
|
-
this.set(muteAddr, targetMute);
|
|
975
|
-
}
|
|
976
|
-
}
|
|
977
|
-
}
|
|
1684
|
+
async saveState() {
|
|
1685
|
+
await this.state.flush();
|
|
978
1686
|
}
|
|
979
1687
|
};
|
|
980
1688
|
|
|
@@ -989,69 +1697,106 @@ var X32Node = class X32Node {
|
|
|
989
1697
|
type;
|
|
990
1698
|
/** Default value for reset. */
|
|
991
1699
|
default;
|
|
1700
|
+
/** Optional validation constraints. */
|
|
1701
|
+
options;
|
|
992
1702
|
/**
|
|
993
1703
|
* Creates a new X32Node.
|
|
994
1704
|
* @param type - The OSC data type ('f', 'i', 's').
|
|
995
1705
|
* @param defaultValue - The default value.
|
|
1706
|
+
* @param options - Optional validation constraints.
|
|
996
1707
|
*/
|
|
997
|
-
constructor(type, defaultValue) {
|
|
1708
|
+
constructor(type, defaultValue, options) {
|
|
998
1709
|
this.type = type;
|
|
999
1710
|
this.default = defaultValue;
|
|
1711
|
+
this.options = options;
|
|
1000
1712
|
}
|
|
1001
1713
|
/**
|
|
1002
1714
|
* Validates if a value is compatible with this node's type.
|
|
1003
1715
|
* @param value - The value to check.
|
|
1716
|
+
* @param strict - If true, also validates against min/max constraints.
|
|
1004
1717
|
* @returns True if valid.
|
|
1005
1718
|
*/
|
|
1006
|
-
validate(value) {
|
|
1007
|
-
if (this.type === "f"
|
|
1008
|
-
if (this.type === "i"
|
|
1009
|
-
if (this.type === "s"
|
|
1010
|
-
|
|
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;
|
|
1011
1729
|
}
|
|
1012
1730
|
/**
|
|
1013
1731
|
* Factory method to create from a plain object (for compatibility/migration).
|
|
1014
1732
|
* @param obj - Plain object.
|
|
1015
1733
|
* @param obj.type - OSC data type.
|
|
1016
1734
|
* @param obj.default - Default value.
|
|
1735
|
+
* @param obj.options - Optional validation constraints.
|
|
1017
1736
|
* @returns A new X32Node instance.
|
|
1018
1737
|
*/
|
|
1019
1738
|
static from(obj) {
|
|
1020
|
-
return new X32Node(obj.type, obj.default);
|
|
1739
|
+
return new X32Node(obj.type, obj.default, obj.options);
|
|
1021
1740
|
}
|
|
1022
1741
|
};
|
|
1023
1742
|
|
|
1024
1743
|
//#endregion
|
|
1025
1744
|
//#region src/infrastructure/repositories/InMemoryStateRepository.ts
|
|
1026
1745
|
/**
|
|
1027
|
-
* In-memory
|
|
1028
|
-
* Stores
|
|
1746
|
+
* In-memory state repository.
|
|
1747
|
+
* Stores state in a Map, no persistence across restarts.
|
|
1748
|
+
* This is the default and fastest option.
|
|
1029
1749
|
*/
|
|
1030
1750
|
var InMemoryStateRepository = class {
|
|
1031
|
-
state;
|
|
1751
|
+
state = /* @__PURE__ */ new Map();
|
|
1032
1752
|
/**
|
|
1033
|
-
*
|
|
1034
|
-
*
|
|
1035
|
-
* @param schemaRegistry - Registry providing the initial state schema.
|
|
1753
|
+
* Loads state from memory.
|
|
1754
|
+
* For in-memory storage, this returns current state.
|
|
1036
1755
|
*/
|
|
1037
|
-
|
|
1038
|
-
this.
|
|
1039
|
-
this.state = new X32State(schemaRegistry.getSchema());
|
|
1756
|
+
async load() {
|
|
1757
|
+
return this.getAll();
|
|
1040
1758
|
}
|
|
1041
1759
|
/**
|
|
1042
|
-
*
|
|
1043
|
-
*
|
|
1760
|
+
* Saves state to memory.
|
|
1761
|
+
* For in-memory storage, this replaces current state.
|
|
1044
1762
|
*/
|
|
1045
|
-
|
|
1046
|
-
|
|
1763
|
+
async save(state) {
|
|
1764
|
+
this.state.clear();
|
|
1765
|
+
for (const [key, value] of Object.entries(state)) this.state.set(key, value);
|
|
1047
1766
|
}
|
|
1048
1767
|
/**
|
|
1049
|
-
*
|
|
1768
|
+
* Gets a single value from memory.
|
|
1050
1769
|
*/
|
|
1051
|
-
|
|
1052
|
-
this.
|
|
1053
|
-
this.state.reset();
|
|
1770
|
+
get(address) {
|
|
1771
|
+
return this.state.get(address);
|
|
1054
1772
|
}
|
|
1773
|
+
/**
|
|
1774
|
+
* Sets a single value in memory.
|
|
1775
|
+
*/
|
|
1776
|
+
set(address, value) {
|
|
1777
|
+
this.state.set(address, value);
|
|
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() {}
|
|
1055
1800
|
};
|
|
1056
1801
|
|
|
1057
1802
|
//#endregion
|
|
@@ -1870,41 +2615,215 @@ var SchemaFactory = class {
|
|
|
1870
2615
|
...this.generateRange(128, "/headamp", "/gain", "f", 0, 3, 0),
|
|
1871
2616
|
...this.generateRange(128, "/headamp", "/phantom", "i", 0, 3, 0),
|
|
1872
2617
|
...this.generateRange(6, "/config/mute", "", "i", 0),
|
|
1873
|
-
...this.generateRange(80, "/-stat/solosw", "", "i", 0),
|
|
2618
|
+
...this.generateRange(80, "/-stat/solosw", "", "i", 0, 2, 1),
|
|
1874
2619
|
"/-stat/selidx": this.node("i", 0),
|
|
2620
|
+
"/-stat/chfaderbank": this.node("i", 0),
|
|
2621
|
+
"/-stat/grpfaderbank": this.node("i", 0),
|
|
1875
2622
|
"/-stat/sendsonfader": this.node("i", 0),
|
|
1876
2623
|
"/-stat/bussendbank": this.node("i", 0),
|
|
2624
|
+
"/-stat/eqband": this.node("i", 0),
|
|
1877
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),
|
|
1878
2640
|
"/-stat/screen/screen": this.node("i", 0),
|
|
2641
|
+
"/-stat/screen/mutegrp": this.node("i", 0),
|
|
2642
|
+
"/-stat/screen/utils": this.node("i", 0),
|
|
1879
2643
|
"/-stat/screen/CHAN/page": this.node("i", 0),
|
|
1880
2644
|
"/-stat/screen/METER/page": this.node("i", 0),
|
|
1881
2645
|
"/-stat/screen/ROUTE/page": this.node("i", 0),
|
|
1882
2646
|
"/-stat/screen/SETUP/page": this.node("i", 0),
|
|
2647
|
+
"/-stat/screen/LIB/page": this.node("i", 0),
|
|
1883
2648
|
"/-stat/screen/LIBRARY/page": this.node("i", 0),
|
|
1884
2649
|
"/-stat/screen/FX/page": this.node("i", 0),
|
|
1885
2650
|
"/-stat/screen/MON/page": this.node("i", 0),
|
|
1886
2651
|
"/-stat/screen/USB/page": this.node("i", 0),
|
|
1887
2652
|
"/-stat/screen/SCENE/page": this.node("i", 0),
|
|
1888
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),
|
|
1889
2666
|
"/-stat/talk/A": this.node("i", 0),
|
|
1890
2667
|
"/-stat/talk/B": this.node("i", 0),
|
|
1891
2668
|
"/-stat/osc/on": this.node("i", 0),
|
|
1892
|
-
"/-
|
|
1893
|
-
"/-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),
|
|
1894
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),
|
|
1895
2685
|
"/-action/goscene": this.node("i", 0),
|
|
1896
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),
|
|
1897
2803
|
"/config/routing/AES50A/1-8": this.node("i", 0),
|
|
1898
2804
|
"/config/routing/AES50B/1-8": this.node("i", 0),
|
|
1899
2805
|
"/config/routing/CARD/1-8": this.node("i", 0),
|
|
1900
2806
|
"/config/routing/OUT/1-4": this.node("i", 0),
|
|
1901
|
-
"/-prefs/invertmutes": this.node("i", 0),
|
|
1902
2807
|
...this.generateChannelStrip("/main/st", 6, false),
|
|
1903
2808
|
...this.generateChannelStrip("/main/m", 6, false),
|
|
1904
2809
|
...Object.fromEntries(Array.from({ length: 16 }, (_, i) => [`/config/chlink/${i * 2 + 1}-${i * 2 + 2}`, this.node("i", 0)])),
|
|
1905
2810
|
...Object.fromEntries(Array.from({ length: 8 }, (_, i) => [`/config/buslink/${i * 2 + 1}-${i * 2 + 2}`, this.node("i", 0)])),
|
|
1906
2811
|
...Object.fromEntries(Array.from({ length: 4 }, (_, i) => [`/config/auxlink/${i * 2 + 1}-${i * 2 + 2}`, this.node("i", 0)])),
|
|
1907
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),
|
|
1908
2827
|
...this.generateRange(32, "/config/userrout/in", "", "i", 0),
|
|
1909
2828
|
...this.generateRange(48, "/config/userrout/out", "", "i", 0),
|
|
1910
2829
|
"/config/solo/level": this.node("f", 0),
|
|
@@ -1940,6 +2859,7 @@ var SchemaFactory = class {
|
|
|
1940
2859
|
"/config/osc/f2": this.node("f", .5),
|
|
1941
2860
|
"/config/osc/level": this.node("f", 0),
|
|
1942
2861
|
"/config/osc/dest": this.node("i", 0),
|
|
2862
|
+
...this.generateDP48Config(),
|
|
1943
2863
|
...this.generateOutputs("main", 16),
|
|
1944
2864
|
...this.generateOutputs("aux", 6),
|
|
1945
2865
|
...this.generateOutputs("p16", 16),
|
|
@@ -1947,7 +2867,7 @@ var SchemaFactory = class {
|
|
|
1947
2867
|
...this.generateOutputs("rec", 2)
|
|
1948
2868
|
};
|
|
1949
2869
|
Object.keys(STATIC_RESPONSES_DATA).forEach((key) => {
|
|
1950
|
-
if (key.startsWith("/-")
|
|
2870
|
+
if (key.startsWith("/-")) {
|
|
1951
2871
|
const val = STATIC_RESPONSES_DATA[key][0];
|
|
1952
2872
|
const type = typeof val === "string" ? "s" : Number.isInteger(val) ? "i" : "f";
|
|
1953
2873
|
schema[key] = this.node(type, val);
|
|
@@ -2062,6 +2982,7 @@ var SchemaFactory = class {
|
|
|
2062
2982
|
generateNodes(count, prefix) {
|
|
2063
2983
|
const nodes = {};
|
|
2064
2984
|
const isChannelOrAux = prefix === "ch" || prefix === "auxin";
|
|
2985
|
+
const hasMtxPreamp = prefix === "mtx";
|
|
2065
2986
|
const eqBands = prefix === "bus" || prefix === "mtx" ? 6 : 4;
|
|
2066
2987
|
for (let i = 1; i <= count; i++) {
|
|
2067
2988
|
const padId = i.toString().padStart(2, "0");
|
|
@@ -2073,7 +2994,7 @@ var SchemaFactory = class {
|
|
|
2073
2994
|
nodes[`${base}/fader`] = this.node("f", .75);
|
|
2074
2995
|
nodes[`${base}/on`] = this.node("i", 0);
|
|
2075
2996
|
} else {
|
|
2076
|
-
Object.assign(nodes, this.generateChannelStrip(base, eqBands, isChannelOrAux));
|
|
2997
|
+
Object.assign(nodes, this.generateChannelStrip(base, eqBands, isChannelOrAux || hasMtxPreamp));
|
|
2077
2998
|
if (prefix === "ch" || prefix === "auxin" || prefix === "fxrtn" || prefix === "bus") for (let b = 1; b <= 16; b++) {
|
|
2078
2999
|
const busId = b.toString().padStart(2, "0");
|
|
2079
3000
|
nodes[`${base}/mix/${busId}/level`] = this.node("f", 0);
|
|
@@ -2081,6 +3002,11 @@ var SchemaFactory = class {
|
|
|
2081
3002
|
nodes[`${base}/mix/${busId}/pan`] = this.node("f", .5);
|
|
2082
3003
|
nodes[`${base}/mix/${busId}/type`] = this.node("i", 0);
|
|
2083
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
|
+
}
|
|
2084
3010
|
}
|
|
2085
3011
|
});
|
|
2086
3012
|
}
|
|
@@ -2113,6 +3039,159 @@ var SchemaFactory = class {
|
|
|
2113
3039
|
}
|
|
2114
3040
|
return nodes;
|
|
2115
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
|
+
}
|
|
2116
3195
|
};
|
|
2117
3196
|
|
|
2118
3197
|
//#endregion
|
|
@@ -2177,4 +3256,4 @@ var SchemaRegistry = class {
|
|
|
2177
3256
|
};
|
|
2178
3257
|
|
|
2179
3258
|
//#endregion
|
|
2180
|
-
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 };
|