@djodjonx/x32-simulator 0.0.1 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,7 @@
1
1
  import * as os from "os";
2
2
  import { EventEmitter } from "node:events";
3
3
  import * as dgram from "node:dgram";
4
+ import { Buffer as Buffer$1 } from "node:buffer";
4
5
 
5
6
  //#region src/application/use-cases/ProcessPacketUseCase.ts
6
7
  var ProcessPacketUseCase = class {
@@ -832,6 +833,10 @@ function getLocalIp() {
832
833
  for (const name of Object.keys(interfaces)) for (const iface of interfaces[name]) if (iface.family === "IPv4" && !iface.internal) return iface.address;
833
834
  return "127.0.0.1";
834
835
  }
836
+ /**
837
+ * The core service that manages the X32 simulation, including networking,
838
+ * state management, and OSC message handling.
839
+ */
835
840
  var SimulationService = class {
836
841
  subscriptionManager;
837
842
  messageHandler;
@@ -842,6 +847,17 @@ var SimulationService = class {
842
847
  staticResponseService;
843
848
  updateInterval = null;
844
849
  cleanupInterval = null;
850
+ /**
851
+ * Creates a new SimulationService instance.
852
+ * @param gateway - The network gateway for OSC communication.
853
+ * @param logger - The logger service.
854
+ * @param stateRepo - The repository managing the mixer state.
855
+ * @param schemaRegistry - The registry for X32 OSC schema.
856
+ * @param port - UDP port to listen on (default 10023).
857
+ * @param ip - IP address to bind to (default '0.0.0.0').
858
+ * @param name - Reported console name.
859
+ * @param model - Reported console model.
860
+ */
845
861
  constructor(gateway, logger, stateRepo, schemaRegistry, port = 10023, ip = "0.0.0.0", name = "osc-server", model = "X32") {
846
862
  this.gateway = gateway;
847
863
  this.logger = logger;
@@ -864,6 +880,9 @@ var SimulationService = class {
864
880
  });
865
881
  this.gateway.onPacket((packet, source) => this.processPacket.execute(packet, source));
866
882
  }
883
+ /**
884
+ * Starts the simulator server and internal loops.
885
+ */
867
886
  async start() {
868
887
  await this.gateway.start(this.port, this.ip);
869
888
  this.cleanupInterval = setInterval(() => {
@@ -873,11 +892,17 @@ var SimulationService = class {
873
892
  this.broadcastUpdates.execute();
874
893
  }, 100);
875
894
  }
895
+ /**
896
+ * Stops the simulator server and stops all internal loops.
897
+ */
876
898
  async stop() {
877
899
  if (this.updateInterval) clearInterval(this.updateInterval);
878
900
  if (this.cleanupInterval) clearInterval(this.cleanupInterval);
879
901
  await this.gateway.stop();
880
902
  }
903
+ /**
904
+ * Resets the mixer state to default values.
905
+ */
881
906
  resetState() {
882
907
  this.stateRepo.reset();
883
908
  }
@@ -887,7 +912,7 @@ var SimulationService = class {
887
912
  //#region src/domain/entities/X32State.ts
888
913
  /**
889
914
  * Manages the internal "Digital Twin" state of the X32 console.
890
- * acts as a single source of truth for all parameters.
915
+ * It acts as a single source of truth for all parameters.
891
916
  * Emits 'change' events whenever a value is updated.
892
917
  */
893
918
  var X32State = class extends EventEmitter {
@@ -954,17 +979,76 @@ var X32State = class extends EventEmitter {
954
979
  }
955
980
  };
956
981
 
982
+ //#endregion
983
+ //#region src/domain/models/X32Node.ts
984
+ /**
985
+ * Metadata for a single state node in the X32 schema.
986
+ * Represents a "Knob" or "Variable" on the console.
987
+ */
988
+ var X32Node = class X32Node {
989
+ /** Value type (f=float, i=int, s=string). */
990
+ type;
991
+ /** Default value for reset. */
992
+ default;
993
+ /**
994
+ * Creates a new X32Node.
995
+ * @param type - The OSC data type ('f', 'i', 's').
996
+ * @param defaultValue - The default value.
997
+ */
998
+ constructor(type, defaultValue) {
999
+ this.type = type;
1000
+ this.default = defaultValue;
1001
+ }
1002
+ /**
1003
+ * Validates if a value is compatible with this node's type.
1004
+ * @param value - The value to check.
1005
+ * @returns True if valid.
1006
+ */
1007
+ validate(value) {
1008
+ if (this.type === "f") return typeof value === "number";
1009
+ if (this.type === "i") return typeof value === "number";
1010
+ if (this.type === "s") return typeof value === "string";
1011
+ return false;
1012
+ }
1013
+ /**
1014
+ * Factory method to create from a plain object (for compatibility/migration).
1015
+ * @param obj - Plain object.
1016
+ * @param obj.type - OSC data type.
1017
+ * @param obj.default - Default value.
1018
+ * @returns A new X32Node instance.
1019
+ */
1020
+ static from(obj) {
1021
+ return new X32Node(obj.type, obj.default);
1022
+ }
1023
+ };
1024
+
957
1025
  //#endregion
958
1026
  //#region src/infrastructure/repositories/InMemoryStateRepository.ts
1027
+ /**
1028
+ * In-memory implementation of the state repository.
1029
+ * Stores the mixer state in volatile memory during the simulator's execution.
1030
+ */
959
1031
  var InMemoryStateRepository = class {
960
1032
  state;
1033
+ /**
1034
+ * Creates a new InMemoryStateRepository.
1035
+ * @param logger - Logger service.
1036
+ * @param schemaRegistry - Registry providing the initial state schema.
1037
+ */
961
1038
  constructor(logger, schemaRegistry) {
962
1039
  this.logger = logger;
963
1040
  this.state = new X32State(schemaRegistry.getSchema());
964
1041
  }
1042
+ /**
1043
+ * Returns the current mixer state instance.
1044
+ * @returns The X32State entity.
1045
+ */
965
1046
  getState() {
966
1047
  return this.state;
967
1048
  }
1049
+ /**
1050
+ * Resets the entire state to its default values.
1051
+ */
968
1052
  reset() {
969
1053
  this.logger.info(LogCategory.SYSTEM, "Resetting state to defaults");
970
1054
  this.state.reset();
@@ -1125,18 +1209,37 @@ var ConsoleLogger = class ConsoleLogger {
1125
1209
 
1126
1210
  //#endregion
1127
1211
  //#region src/infrastructure/services/UdpNetworkGateway.ts
1212
+ /**
1213
+ * Node.js UDP implementation of the network gateway.
1214
+ * Handles the low-level socket communication and OSC packet routing.
1215
+ */
1128
1216
  var UdpNetworkGateway = class {
1129
1217
  socket;
1130
1218
  isRunning = false;
1131
1219
  packetCallback = null;
1220
+ /**
1221
+ * Creates a new UdpNetworkGateway.
1222
+ * @param logger - Logger service.
1223
+ * @param codec - OSC codec for encoding/decoding.
1224
+ */
1132
1225
  constructor(logger, codec) {
1133
1226
  this.logger = logger;
1134
1227
  this.codec = codec;
1135
1228
  this.socket = dgram.createSocket("udp4");
1136
1229
  }
1230
+ /**
1231
+ * Registers a callback to be executed whenever a new OSC packet arrives.
1232
+ * @param callback - Function called with decoded packet and source info.
1233
+ */
1137
1234
  onPacket(callback) {
1138
1235
  this.packetCallback = callback;
1139
1236
  }
1237
+ /**
1238
+ * Starts the UDP server on the specified port and IP.
1239
+ * @param port - UDP port.
1240
+ * @param ip - IP address to bind to.
1241
+ * @returns Promise resolving when the socket is bound.
1242
+ */
1140
1243
  start(port, ip) {
1141
1244
  return new Promise((resolve, reject) => {
1142
1245
  this.socket.on("error", (err) => {
@@ -1162,6 +1265,10 @@ var UdpNetworkGateway = class {
1162
1265
  });
1163
1266
  });
1164
1267
  }
1268
+ /**
1269
+ * Shuts down the UDP server.
1270
+ * @returns Promise resolving when the socket is closed.
1271
+ */
1165
1272
  stop() {
1166
1273
  return new Promise((resolve) => {
1167
1274
  if (!this.isRunning) return resolve();
@@ -1172,6 +1279,12 @@ var UdpNetworkGateway = class {
1172
1279
  });
1173
1280
  });
1174
1281
  }
1282
+ /**
1283
+ * Sends an OSC message to a specific remote client.
1284
+ * @param target - Target client info (IP/port).
1285
+ * @param address - OSC address pattern.
1286
+ * @param args - Array of arguments.
1287
+ */
1175
1288
  send(target, address, args) {
1176
1289
  const buf = this.codec.encode(address, args);
1177
1290
  const cat = address.startsWith("/meters") ? LogCategory.METER : LogCategory.OSC_OUT;
@@ -1186,4 +1299,879 @@ var UdpNetworkGateway = class {
1186
1299
  };
1187
1300
 
1188
1301
  //#endregion
1189
- export { SimulationService as a, InMemoryStateRepository as i, ConsoleLogger as n, STATIC_RESPONSES_DATA as o, LogLevel as r, LogCategory as s, UdpNetworkGateway as t };
1302
+ //#region node_modules/node-osc/lib/Message.mjs
1303
+ const typeTags = {
1304
+ s: "string",
1305
+ f: "float",
1306
+ i: "integer",
1307
+ b: "blob",
1308
+ m: "midi"
1309
+ };
1310
+ /**
1311
+ * Represents a typed argument for an OSC message.
1312
+ *
1313
+ * @class
1314
+ * @private
1315
+ */
1316
+ var Argument = class {
1317
+ /**
1318
+ * @param {string} type - The type of the argument (string, float, integer, blob, boolean).
1319
+ * @param {*} value - The value of the argument.
1320
+ */
1321
+ constructor(type, value) {
1322
+ this.type = type;
1323
+ this.value = value;
1324
+ }
1325
+ };
1326
+ /**
1327
+ * Represents an OSC message with an address and arguments.
1328
+ *
1329
+ * OSC messages consist of an address pattern (string starting with '/')
1330
+ * and zero or more arguments of various types.
1331
+ *
1332
+ * @class
1333
+ *
1334
+ * @example
1335
+ * // Create a message with constructor arguments
1336
+ * const msg = new Message('/test', 1, 2, 'hello');
1337
+ *
1338
+ * @example
1339
+ * // Create a message and append arguments
1340
+ * const msg = new Message('/test');
1341
+ * msg.append(1);
1342
+ * msg.append('hello');
1343
+ * msg.append(3.14);
1344
+ */
1345
+ var Message = class {
1346
+ /**
1347
+ * Create an OSC Message.
1348
+ *
1349
+ * @param {string} address - The OSC address pattern (e.g., '/oscillator/frequency').
1350
+ * @param {...*} args - Optional arguments to include in the message.
1351
+ *
1352
+ * @example
1353
+ * const msg = new Message('/test');
1354
+ *
1355
+ * @example
1356
+ * const msg = new Message('/test', 1, 2, 3);
1357
+ *
1358
+ * @example
1359
+ * const msg = new Message('/synth', 'note', 60, 0.5);
1360
+ */
1361
+ constructor(address, ...args) {
1362
+ this.oscType = "message";
1363
+ this.address = address;
1364
+ this.args = args;
1365
+ }
1366
+ /**
1367
+ * Append an argument to the message.
1368
+ *
1369
+ * Automatically detects the type based on the JavaScript type:
1370
+ * - Integers are encoded as OSC integers
1371
+ * - Floats are encoded as OSC floats
1372
+ * - Strings are encoded as OSC strings
1373
+ * - Booleans are encoded as OSC booleans
1374
+ * - Buffers are encoded as OSC blobs
1375
+ * - Arrays are recursively appended
1376
+ * - Objects with a 'type' property are used as-is
1377
+ *
1378
+ * @param {*} arg - The argument to append. Can be:
1379
+ * - A primitive value (number, string, boolean)
1380
+ * - A Buffer (encoded as blob)
1381
+ * - An array of values (will be recursively appended)
1382
+ * - An object with 'type' and 'value' properties for explicit type control
1383
+ *
1384
+ * @throws {Error} If the argument type cannot be encoded.
1385
+ *
1386
+ * @example
1387
+ * const msg = new Message('/test');
1388
+ * msg.append(42); // Integer
1389
+ * msg.append(3.14); // Float
1390
+ * msg.append('hello'); // String
1391
+ * msg.append(true); // Boolean
1392
+ *
1393
+ * @example
1394
+ * // Append multiple values at once
1395
+ * msg.append([1, 2, 3]);
1396
+ *
1397
+ * @example
1398
+ * // Explicitly specify type
1399
+ * msg.append({ type: 'float', value: 42 });
1400
+ * msg.append({ type: 'blob', value: Buffer.from('data') });
1401
+ *
1402
+ * @example
1403
+ * // MIDI messages (4 bytes: port, status, data1, data2)
1404
+ * msg.append({ type: 'midi', value: { port: 0, status: 144, data1: 60, data2: 127 } });
1405
+ * msg.append({ type: 'm', value: Buffer.from([0, 144, 60, 127]) });
1406
+ */
1407
+ append(arg) {
1408
+ let argOut;
1409
+ switch (typeof arg) {
1410
+ case "object":
1411
+ if (Buffer.isBuffer(arg)) this.args.push(arg);
1412
+ else if (arg instanceof Array) arg.forEach((a) => this.append(a));
1413
+ else if (arg.type) {
1414
+ if (typeTags[arg.type]) arg.type = typeTags[arg.type];
1415
+ this.args.push(arg);
1416
+ } else throw new Error(`don't know how to encode object ${arg}`);
1417
+ break;
1418
+ case "number":
1419
+ if (Math.floor(arg) === arg) argOut = new Argument("integer", arg);
1420
+ else argOut = new Argument("float", arg);
1421
+ break;
1422
+ case "string":
1423
+ argOut = new Argument("string", arg);
1424
+ break;
1425
+ case "boolean":
1426
+ argOut = new Argument("boolean", arg);
1427
+ break;
1428
+ default: throw new Error(`don't know how to encode ${arg}`);
1429
+ }
1430
+ if (argOut) this.args.push(argOut);
1431
+ }
1432
+ };
1433
+ var Message_default = Message;
1434
+
1435
+ //#endregion
1436
+ //#region node_modules/node-osc/lib/osc.mjs
1437
+ function padString(str) {
1438
+ const nullTerminated = str + "\0";
1439
+ const padding = (4 - Buffer$1.byteLength(nullTerminated) % 4) % 4;
1440
+ return nullTerminated + "\0".repeat(padding);
1441
+ }
1442
+ function readString(buffer, offset) {
1443
+ let end = offset;
1444
+ while (end < buffer.length && buffer[end] !== 0) end++;
1445
+ if (end >= buffer.length) throw new Error("Malformed Packet: Missing null terminator for string");
1446
+ return {
1447
+ value: buffer.subarray(offset, end).toString("utf8"),
1448
+ offset: offset + Math.ceil((end - offset + 1) / 4) * 4
1449
+ };
1450
+ }
1451
+ function writeInt32(value) {
1452
+ const buffer = Buffer$1.alloc(4);
1453
+ buffer.writeInt32BE(value, 0);
1454
+ return buffer;
1455
+ }
1456
+ function readInt32(buffer, offset) {
1457
+ if (offset + 4 > buffer.length) throw new Error("Malformed Packet: Not enough bytes for int32");
1458
+ return {
1459
+ value: buffer.readInt32BE(offset),
1460
+ offset: offset + 4
1461
+ };
1462
+ }
1463
+ function writeFloat32(value) {
1464
+ const buffer = Buffer$1.alloc(4);
1465
+ buffer.writeFloatBE(value, 0);
1466
+ return buffer;
1467
+ }
1468
+ function readFloat32(buffer, offset) {
1469
+ if (offset + 4 > buffer.length) throw new Error("Malformed Packet: Not enough bytes for float32");
1470
+ return {
1471
+ value: buffer.readFloatBE(offset),
1472
+ offset: offset + 4
1473
+ };
1474
+ }
1475
+ function writeBlob(value) {
1476
+ const length = value.length;
1477
+ const lengthBuffer = writeInt32(length);
1478
+ const padding = 4 - length % 4;
1479
+ const paddingBuffer = Buffer$1.alloc(padding === 4 ? 0 : padding);
1480
+ return Buffer$1.concat([
1481
+ lengthBuffer,
1482
+ value,
1483
+ paddingBuffer
1484
+ ]);
1485
+ }
1486
+ function readBlob(buffer, offset) {
1487
+ const lengthResult = readInt32(buffer, offset);
1488
+ const length = lengthResult.value;
1489
+ if (length < 0) throw new Error("Malformed Packet: Invalid blob length");
1490
+ if (lengthResult.offset + length > buffer.length) throw new Error("Malformed Packet: Not enough bytes for blob");
1491
+ const data = buffer.subarray(lengthResult.offset, lengthResult.offset + length);
1492
+ const padding = 4 - length % 4;
1493
+ const nextOffset = lengthResult.offset + length + (padding === 4 ? 0 : padding);
1494
+ if (nextOffset > buffer.length) throw new Error("Malformed Packet: Not enough bytes for blob padding");
1495
+ return {
1496
+ value: data,
1497
+ offset: nextOffset
1498
+ };
1499
+ }
1500
+ function writeTimeTag(value) {
1501
+ const buffer = Buffer$1.alloc(8);
1502
+ if (value === 0 || value === null || value === void 0) {
1503
+ buffer.writeUInt32BE(0, 0);
1504
+ buffer.writeUInt32BE(1, 4);
1505
+ } else if (typeof value === "number") {
1506
+ const seconds = Math.floor(value);
1507
+ const fraction = Math.floor((value - seconds) * 4294967296);
1508
+ buffer.writeUInt32BE(seconds + 2208988800, 0);
1509
+ buffer.writeUInt32BE(fraction, 4);
1510
+ } else {
1511
+ buffer.writeUInt32BE(0, 0);
1512
+ buffer.writeUInt32BE(1, 4);
1513
+ }
1514
+ return buffer;
1515
+ }
1516
+ function readTimeTag(buffer, offset) {
1517
+ if (offset + 8 > buffer.length) throw new Error("Malformed Packet: Not enough bytes for timetag");
1518
+ const seconds = buffer.readUInt32BE(offset);
1519
+ const fraction = buffer.readUInt32BE(offset + 4);
1520
+ let value;
1521
+ if (seconds === 0 && fraction === 1) value = 0;
1522
+ else value = seconds - 2208988800 + fraction / 4294967296;
1523
+ return {
1524
+ value,
1525
+ offset: offset + 8
1526
+ };
1527
+ }
1528
+ function writeMidi(value) {
1529
+ const buffer = Buffer$1.alloc(4);
1530
+ if (Buffer$1.isBuffer(value)) {
1531
+ if (value.length !== 4) throw new Error("MIDI message must be exactly 4 bytes");
1532
+ value.copy(buffer);
1533
+ } else if (typeof value === "object" && value !== null) {
1534
+ buffer.writeUInt8(value.port || 0, 0);
1535
+ buffer.writeUInt8(value.status || 0, 1);
1536
+ buffer.writeUInt8(value.data1 || 0, 2);
1537
+ buffer.writeUInt8(value.data2 || 0, 3);
1538
+ } else throw new Error("MIDI value must be a 4-byte Buffer or object with port, status, data1, data2 properties");
1539
+ return buffer;
1540
+ }
1541
+ function readMidi(buffer, offset) {
1542
+ if (offset + 4 > buffer.length) throw new Error("Not enough bytes for MIDI message");
1543
+ return {
1544
+ value: buffer.subarray(offset, offset + 4),
1545
+ offset: offset + 4
1546
+ };
1547
+ }
1548
+ function encodeArgument(arg) {
1549
+ if (typeof arg === "object" && arg.type && arg.value !== void 0) switch (arg.type) {
1550
+ case "i":
1551
+ case "integer": return {
1552
+ tag: "i",
1553
+ data: writeInt32(arg.value)
1554
+ };
1555
+ case "f":
1556
+ case "float": return {
1557
+ tag: "f",
1558
+ data: writeFloat32(arg.value)
1559
+ };
1560
+ case "s":
1561
+ case "string": return {
1562
+ tag: "s",
1563
+ data: Buffer$1.from(padString(arg.value))
1564
+ };
1565
+ case "b":
1566
+ case "blob": return {
1567
+ tag: "b",
1568
+ data: writeBlob(arg.value)
1569
+ };
1570
+ case "d":
1571
+ case "double": return {
1572
+ tag: "f",
1573
+ data: writeFloat32(arg.value)
1574
+ };
1575
+ case "T": return {
1576
+ tag: "T",
1577
+ data: Buffer$1.alloc(0)
1578
+ };
1579
+ case "F": return {
1580
+ tag: "F",
1581
+ data: Buffer$1.alloc(0)
1582
+ };
1583
+ case "boolean": return arg.value ? {
1584
+ tag: "T",
1585
+ data: Buffer$1.alloc(0)
1586
+ } : {
1587
+ tag: "F",
1588
+ data: Buffer$1.alloc(0)
1589
+ };
1590
+ case "m":
1591
+ case "midi": return {
1592
+ tag: "m",
1593
+ data: writeMidi(arg.value)
1594
+ };
1595
+ default: throw new Error(`Unknown argument type: ${arg.type}`);
1596
+ }
1597
+ switch (typeof arg) {
1598
+ case "number": if (Number.isInteger(arg)) return {
1599
+ tag: "i",
1600
+ data: writeInt32(arg)
1601
+ };
1602
+ else return {
1603
+ tag: "f",
1604
+ data: writeFloat32(arg)
1605
+ };
1606
+ case "string": return {
1607
+ tag: "s",
1608
+ data: Buffer$1.from(padString(arg))
1609
+ };
1610
+ case "boolean": return arg ? {
1611
+ tag: "T",
1612
+ data: Buffer$1.alloc(0)
1613
+ } : {
1614
+ tag: "F",
1615
+ data: Buffer$1.alloc(0)
1616
+ };
1617
+ default:
1618
+ if (Buffer$1.isBuffer(arg)) return {
1619
+ tag: "b",
1620
+ data: writeBlob(arg)
1621
+ };
1622
+ throw new Error(`Don't know how to encode argument: ${arg}`);
1623
+ }
1624
+ }
1625
+ function decodeArgument(tag, buffer, offset) {
1626
+ switch (tag) {
1627
+ case "i": return readInt32(buffer, offset);
1628
+ case "f": return readFloat32(buffer, offset);
1629
+ case "s": return readString(buffer, offset);
1630
+ case "b": return readBlob(buffer, offset);
1631
+ case "T": return {
1632
+ value: true,
1633
+ offset
1634
+ };
1635
+ case "F": return {
1636
+ value: false,
1637
+ offset
1638
+ };
1639
+ case "N": return {
1640
+ value: null,
1641
+ offset
1642
+ };
1643
+ case "m": return readMidi(buffer, offset);
1644
+ default: throw new Error(`I don't understand the argument code ${tag}`);
1645
+ }
1646
+ }
1647
+ /**
1648
+ * Encode an OSC message or bundle to a Buffer.
1649
+ *
1650
+ * This low-level function converts OSC messages and bundles into binary format
1651
+ * for transmission or storage. Useful for sending OSC over custom transports
1652
+ * (WebSocket, TCP, HTTP), storing to files, or implementing custom OSC routers.
1653
+ *
1654
+ * @param {Object} message - OSC message or bundle object with oscType property
1655
+ * @returns {Buffer} The encoded OSC data ready for transmission
1656
+ *
1657
+ * @example
1658
+ * // Encode a message
1659
+ * import { Message, encode } from 'node-osc';
1660
+ *
1661
+ * const message = new Message('/oscillator/frequency', 440);
1662
+ * const buffer = encode(message);
1663
+ * console.log('Encoded bytes:', buffer.length);
1664
+ *
1665
+ * @example
1666
+ * // Encode a bundle
1667
+ * import { Bundle, encode } from 'node-osc';
1668
+ *
1669
+ * const bundle = new Bundle(['/one', 1], ['/two', 2]);
1670
+ * const buffer = encode(bundle);
1671
+ *
1672
+ * @example
1673
+ * // Send over WebSocket
1674
+ * const buffer = encode(message);
1675
+ * websocket.send(buffer);
1676
+ */
1677
+ function encode(message) {
1678
+ if (message.oscType === "bundle") return encodeBundleToBuffer(message);
1679
+ else return encodeMessageToBuffer(message);
1680
+ }
1681
+ function encodeMessageToBuffer(message) {
1682
+ const address = padString(message.address);
1683
+ const addressBuffer = Buffer$1.from(address);
1684
+ const encodedArgs = message.args.map(encodeArgument);
1685
+ const typeTags$1 = "," + encodedArgs.map((arg) => arg.tag).join("");
1686
+ const typeTagsBuffer = Buffer$1.from(padString(typeTags$1));
1687
+ const argumentBuffers = encodedArgs.map((arg) => arg.data);
1688
+ return Buffer$1.concat([
1689
+ addressBuffer,
1690
+ typeTagsBuffer,
1691
+ ...argumentBuffers
1692
+ ]);
1693
+ }
1694
+ function encodeBundleToBuffer(bundle) {
1695
+ const bundleString = padString("#bundle");
1696
+ const bundleStringBuffer = Buffer$1.from(bundleString);
1697
+ const timetagBuffer = writeTimeTag(bundle.timetag);
1698
+ const elementBuffers = bundle.elements.map((element) => {
1699
+ let elementBuffer;
1700
+ if (element.oscType === "bundle") elementBuffer = encodeBundleToBuffer(element);
1701
+ else elementBuffer = encodeMessageToBuffer(element);
1702
+ const sizeBuffer = writeInt32(elementBuffer.length);
1703
+ return Buffer$1.concat([sizeBuffer, elementBuffer]);
1704
+ });
1705
+ return Buffer$1.concat([
1706
+ bundleStringBuffer,
1707
+ timetagBuffer,
1708
+ ...elementBuffers
1709
+ ]);
1710
+ }
1711
+ /**
1712
+ * Decode a Buffer containing OSC data into a message or bundle object.
1713
+ *
1714
+ * This low-level function parses binary OSC data back into JavaScript objects.
1715
+ * Useful for receiving OSC over custom transports, reading from files,
1716
+ * or implementing custom OSC routers.
1717
+ *
1718
+ * @param {Buffer} buffer - The Buffer containing OSC data
1719
+ * @returns {Object} The decoded OSC message or bundle. Messages have
1720
+ * {oscType: 'message', address: string, args: Array}, bundles have
1721
+ * {oscType: 'bundle', timetag: number, elements: Array}
1722
+ * @throws {Error} If the buffer contains malformed OSC data
1723
+ *
1724
+ * @example
1725
+ * // Decode received data
1726
+ * import { decode } from 'node-osc';
1727
+ *
1728
+ * const decoded = decode(buffer);
1729
+ * if (decoded.oscType === 'message') {
1730
+ * console.log('Address:', decoded.address);
1731
+ * console.log('Arguments:', decoded.args);
1732
+ * }
1733
+ *
1734
+ * @example
1735
+ * // Round-trip encode/decode
1736
+ * import { Message, encode, decode } from 'node-osc';
1737
+ *
1738
+ * const original = new Message('/test', 42, 'hello');
1739
+ * const buffer = encode(original);
1740
+ * const decoded = decode(buffer);
1741
+ * console.log(decoded.address); // '/test'
1742
+ */
1743
+ function decode(buffer) {
1744
+ if (buffer.length >= 8 && buffer.subarray(0, 8).toString() === "#bundle\0") return decodeBundleFromBuffer(buffer);
1745
+ else return decodeMessageFromBuffer(buffer);
1746
+ }
1747
+ function decodeMessageFromBuffer(buffer) {
1748
+ let offset = 0;
1749
+ const addressResult = readString(buffer, offset);
1750
+ const address = addressResult.value;
1751
+ offset = addressResult.offset;
1752
+ const typeTagsResult = readString(buffer, offset);
1753
+ const typeTags$1 = typeTagsResult.value;
1754
+ offset = typeTagsResult.offset;
1755
+ if (!typeTags$1.startsWith(",")) throw new Error("Malformed Packet");
1756
+ const tags = typeTags$1.slice(1);
1757
+ const args = [];
1758
+ for (const tag of tags) {
1759
+ const argResult = decodeArgument(tag, buffer, offset);
1760
+ args.push({ value: argResult.value });
1761
+ offset = argResult.offset;
1762
+ }
1763
+ return {
1764
+ oscType: "message",
1765
+ address,
1766
+ args
1767
+ };
1768
+ }
1769
+ function decodeBundleFromBuffer(buffer) {
1770
+ let offset = 8;
1771
+ const timetagResult = readTimeTag(buffer, offset);
1772
+ const timetag = timetagResult.value;
1773
+ offset = timetagResult.offset;
1774
+ const elements = [];
1775
+ while (offset < buffer.length) {
1776
+ const sizeResult = readInt32(buffer, offset);
1777
+ const size = sizeResult.value;
1778
+ offset = sizeResult.offset;
1779
+ if (size <= 0 || offset + size > buffer.length) throw new Error("Malformed Packet");
1780
+ const element = decode(buffer.subarray(offset, offset + size));
1781
+ elements.push(element);
1782
+ offset += size;
1783
+ }
1784
+ return {
1785
+ oscType: "bundle",
1786
+ timetag,
1787
+ elements
1788
+ };
1789
+ }
1790
+
1791
+ //#endregion
1792
+ //#region src/infrastructure/mappers/OscCodec.ts
1793
+ /**
1794
+ * Handles encoding and decoding of X32 OSC messages.
1795
+ */
1796
+ var OscCodec = class {
1797
+ constructor(schemaRegistry) {
1798
+ this.schemaRegistry = schemaRegistry;
1799
+ }
1800
+ /**
1801
+ * Decodes a binary OSC message into a packet object.
1802
+ * @param msg - Raw UDP buffer.
1803
+ * @returns Decoded OscPacket.
1804
+ */
1805
+ decode(msg) {
1806
+ return decode(msg);
1807
+ }
1808
+ /**
1809
+ * Encodes an address and arguments into a binary OSC message.
1810
+ * @param address - OSC address pattern.
1811
+ * @param args - Array of arguments.
1812
+ * @returns Binary buffer.
1813
+ */
1814
+ encode(address, args) {
1815
+ return encode(this.createMessage(address, args));
1816
+ }
1817
+ /**
1818
+ * Creates a typed node-osc Message based on X32 schema.
1819
+ * @param address - Target address.
1820
+ * @param args - Untyped arguments.
1821
+ * @returns Typed Message.
1822
+ */
1823
+ createMessage(address, args) {
1824
+ return new Message_default(address, ...args.map((arg) => {
1825
+ if (typeof arg === "object" && arg !== null && "type" in arg && "value" in arg) return arg;
1826
+ if (Buffer.isBuffer(arg)) return arg;
1827
+ const node = this.schemaRegistry.getNode(address);
1828
+ if (node) {
1829
+ if (node.type === "f" && typeof arg === "number") return {
1830
+ type: "f",
1831
+ value: arg
1832
+ };
1833
+ if (node.type === "i" && typeof arg === "number") return {
1834
+ type: "i",
1835
+ value: Math.round(arg)
1836
+ };
1837
+ if (node.type === "s" && typeof arg === "string") return {
1838
+ type: "s",
1839
+ value: arg
1840
+ };
1841
+ }
1842
+ return arg;
1843
+ }));
1844
+ }
1845
+ };
1846
+
1847
+ //#endregion
1848
+ //#region src/domain/services/SchemaFactory.ts
1849
+ /**
1850
+ * Factory service responsible for constructing the X32 OSC Schema.
1851
+ * Encapsulates all the logic for generating channel strips, routing blocks, etc.
1852
+ */
1853
+ var SchemaFactory = class {
1854
+ /**
1855
+ * Builds the complete X32 OSC Schema.
1856
+ * @returns The constructed schema map.
1857
+ */
1858
+ createSchema() {
1859
+ const schema = {
1860
+ ...this.generateNodes(32, "ch"),
1861
+ ...this.generateNodes(16, "bus"),
1862
+ ...this.generateNodes(8, "dca"),
1863
+ ...this.generateNodes(8, "auxin"),
1864
+ ...this.generateNodes(8, "fxrtn"),
1865
+ ...this.generateNodes(6, "mtx"),
1866
+ ...Object.fromEntries(Array.from({ length: 8 }, (_, i) => [`/fx/${i + 1}/type`, this.node("i", 0)])),
1867
+ ...this.generateRange(8, "/fx", "/type", "i", 0),
1868
+ ...this.generateRange(8, "/fx", "/source/l", "i", 0),
1869
+ ...this.generateRange(8, "/fx", "/source/r", "i", 0),
1870
+ ...Object.fromEntries(Array.from({ length: 8 }, (_, slot) => Object.entries(this.generateRange(64, `/fx/${slot + 1}/par`, "", "f", 0, 2, 1))).flat()),
1871
+ ...this.generateRange(128, "/headamp", "/gain", "f", 0, 3, 0),
1872
+ ...this.generateRange(128, "/headamp", "/phantom", "i", 0, 3, 0),
1873
+ ...this.generateRange(6, "/config/mute", "", "i", 0),
1874
+ ...this.generateRange(80, "/-stat/solosw", "", "i", 0),
1875
+ "/-stat/selidx": this.node("i", 0),
1876
+ "/-stat/sendsonfader": this.node("i", 0),
1877
+ "/-stat/bussendbank": this.node("i", 0),
1878
+ "/-stat/keysolo": this.node("i", 0),
1879
+ "/-stat/screen/screen": this.node("i", 0),
1880
+ "/-stat/screen/CHAN/page": this.node("i", 0),
1881
+ "/-stat/screen/METER/page": this.node("i", 0),
1882
+ "/-stat/screen/ROUTE/page": this.node("i", 0),
1883
+ "/-stat/screen/SETUP/page": this.node("i", 0),
1884
+ "/-stat/screen/LIBRARY/page": this.node("i", 0),
1885
+ "/-stat/screen/FX/page": this.node("i", 0),
1886
+ "/-stat/screen/MON/page": this.node("i", 0),
1887
+ "/-stat/screen/USB/page": this.node("i", 0),
1888
+ "/-stat/screen/SCENE/page": this.node("i", 0),
1889
+ "/-stat/screen/ASSIGN/page": this.node("i", 0),
1890
+ "/-stat/talk/A": this.node("i", 0),
1891
+ "/-stat/talk/B": this.node("i", 0),
1892
+ "/-stat/osc/on": this.node("i", 0),
1893
+ "/-prefs/autosel": this.node("i", 1),
1894
+ "/-action/setrtasrc": this.node("i", 0),
1895
+ "/-action/playtrack": this.node("i", 0),
1896
+ "/-action/goscene": this.node("i", 0),
1897
+ "/-action/setscene": this.node("i", 0),
1898
+ "/config/routing/AES50A/1-8": this.node("i", 0),
1899
+ "/config/routing/AES50B/1-8": this.node("i", 0),
1900
+ "/config/routing/CARD/1-8": this.node("i", 0),
1901
+ "/config/routing/OUT/1-4": this.node("i", 0),
1902
+ "/-prefs/invertmutes": this.node("i", 0),
1903
+ ...this.generateChannelStrip("/main/st", 6, false),
1904
+ ...this.generateChannelStrip("/main/m", 6, false),
1905
+ ...Object.fromEntries(Array.from({ length: 16 }, (_, i) => [`/config/chlink/${i * 2 + 1}-${i * 2 + 2}`, this.node("i", 0)])),
1906
+ ...Object.fromEntries(Array.from({ length: 8 }, (_, i) => [`/config/buslink/${i * 2 + 1}-${i * 2 + 2}`, this.node("i", 0)])),
1907
+ ...Object.fromEntries(Array.from({ length: 4 }, (_, i) => [`/config/auxlink/${i * 2 + 1}-${i * 2 + 2}`, this.node("i", 0)])),
1908
+ ...Object.fromEntries(Array.from({ length: 4 }, (_, i) => [`/config/fxlink/${i * 2 + 1}-${i * 2 + 2}`, this.node("i", 0)])),
1909
+ ...this.generateRange(32, "/config/userrout/in", "", "i", 0),
1910
+ ...this.generateRange(48, "/config/userrout/out", "", "i", 0),
1911
+ "/config/solo/level": this.node("f", 0),
1912
+ "/config/solo/source": this.node("i", 0),
1913
+ "/config/solo/sourcetrim": this.node("f", 0),
1914
+ "/config/solo/exclusive": this.node("i", 0),
1915
+ "/config/solo/dim": this.node("i", 0),
1916
+ "/config/solo/dimpfl": this.node("i", 0),
1917
+ "/config/solo/dimatt": this.node("f", 0),
1918
+ "/config/solo/mono": this.node("i", 0),
1919
+ "/config/solo/chmode": this.node("i", 0),
1920
+ "/config/solo/busmode": this.node("i", 0),
1921
+ "/config/solo/dcamode": this.node("i", 0),
1922
+ "/config/solo/masterctrl": this.node("i", 0),
1923
+ "/config/solo/delay": this.node("i", 0),
1924
+ "/config/solo/delaytime": this.node("f", 0),
1925
+ "/config/solo/followsel": this.node("i", 0),
1926
+ "/config/solo/followsolo": this.node("i", 0),
1927
+ "/config/talk/enable": this.node("i", 0),
1928
+ "/config/talk/source": this.node("i", 0),
1929
+ "/config/talk/A/level": this.node("f", 0),
1930
+ "/config/talk/B/level": this.node("f", 0),
1931
+ "/config/talk/A/dim": this.node("i", 0),
1932
+ "/config/talk/B/dim": this.node("i", 0),
1933
+ "/config/talk/A/latch": this.node("i", 0),
1934
+ "/config/talk/B/latch": this.node("i", 0),
1935
+ "/config/talk/A/destmap": this.node("i", 0),
1936
+ "/config/talk/B/destmap": this.node("i", 0),
1937
+ "/config/osc/on": this.node("i", 0),
1938
+ "/config/osc/type": this.node("i", 0),
1939
+ "/config/osc/fsel": this.node("i", 0),
1940
+ "/config/osc/f1": this.node("f", .5),
1941
+ "/config/osc/f2": this.node("f", .5),
1942
+ "/config/osc/level": this.node("f", 0),
1943
+ "/config/osc/dest": this.node("i", 0),
1944
+ ...this.generateOutputs("main", 16),
1945
+ ...this.generateOutputs("aux", 6),
1946
+ ...this.generateOutputs("p16", 16),
1947
+ ...this.generateOutputs("aes", 2),
1948
+ ...this.generateOutputs("rec", 2)
1949
+ };
1950
+ Object.keys(STATIC_RESPONSES_DATA).forEach((key) => {
1951
+ if (key.startsWith("/-") || key.startsWith("/stat")) schema[key] = this.node("i", 0);
1952
+ });
1953
+ [
1954
+ "/config/routing/IN/1-8",
1955
+ "/config/routing/IN/9-16",
1956
+ "/config/routing/IN/17-24",
1957
+ "/config/routing/IN/25-32",
1958
+ "/config/routing/AUX/1-4",
1959
+ "/config/routing/OUT/1-4",
1960
+ "/config/routing/OUT/5-8",
1961
+ "/config/routing/OUT/9-12",
1962
+ "/config/routing/OUT/13-16",
1963
+ "/config/routing/P16/1-8",
1964
+ "/config/routing/P16/9-16",
1965
+ "/config/routing/CARD/1-8",
1966
+ "/config/routing/CARD/9-16",
1967
+ "/config/routing/CARD/17-24",
1968
+ "/config/routing/CARD/25-32",
1969
+ "/config/routing/AES50A/1-8",
1970
+ "/config/routing/AES50A/9-16",
1971
+ "/config/routing/AES50A/17-24",
1972
+ "/config/routing/AES50A/25-32",
1973
+ "/config/routing/AES50A/33-40",
1974
+ "/config/routing/AES50A/41-48",
1975
+ "/config/routing/AES50B/1-8",
1976
+ "/config/routing/AES50B/9-16",
1977
+ "/config/routing/AES50B/17-24",
1978
+ "/config/routing/AES50B/25-32",
1979
+ "/config/routing/AES50B/33-40",
1980
+ "/config/routing/AES50B/41-48",
1981
+ "/config/routing/PLAY/1-8",
1982
+ "/config/routing/PLAY/9-16",
1983
+ "/config/routing/PLAY/17-24",
1984
+ "/config/routing/PLAY/25-32"
1985
+ ].forEach((path) => {
1986
+ schema[path] = this.node("i", 0);
1987
+ });
1988
+ return schema;
1989
+ }
1990
+ node(type, def) {
1991
+ return new X32Node(type, def);
1992
+ }
1993
+ generateChannelStrip(base, eqBands = 4, hasPreamp = false) {
1994
+ const nodes = {};
1995
+ nodes[`${base}/config/name`] = this.node("s", base.split("/").pop()?.toUpperCase() || "");
1996
+ nodes[`${base}/config/icon`] = this.node("i", 1);
1997
+ nodes[`${base}/config/color`] = this.node("i", 1);
1998
+ nodes[`${base}/config/source`] = this.node("i", 1);
1999
+ nodes[`${base}/mix/fader`] = this.node("f", .75);
2000
+ nodes[`${base}/mix/on`] = this.node("i", 0);
2001
+ nodes[`${base}/mix/pan`] = this.node("f", .5);
2002
+ nodes[`${base}/mix/mono`] = this.node("i", 0);
2003
+ nodes[`${base}/mix/mlevel`] = this.node("f", 0);
2004
+ nodes[`${base}/mix/st`] = this.node("i", 1);
2005
+ if (hasPreamp) {
2006
+ nodes[`${base}/preamp/trim`] = this.node("f", .5);
2007
+ nodes[`${base}/preamp/hpon`] = this.node("i", 0);
2008
+ nodes[`${base}/preamp/hpf`] = this.node("f", 0);
2009
+ nodes[`${base}/preamp/phantom`] = this.node("i", 0);
2010
+ nodes[`${base}/preamp/rtnsw`] = this.node("i", 0);
2011
+ nodes[`${base}/preamp/invert`] = this.node("i", 0);
2012
+ }
2013
+ nodes[`${base}/delay/on`] = this.node("i", 0);
2014
+ nodes[`${base}/delay/time`] = this.node("f", 0);
2015
+ nodes[`${base}/insert/on`] = this.node("i", 0);
2016
+ nodes[`${base}/insert/pos`] = this.node("i", 0);
2017
+ nodes[`${base}/insert/sel`] = this.node("i", 0);
2018
+ nodes[`${base}/gate/on`] = this.node("i", 0);
2019
+ nodes[`${base}/gate/mode`] = this.node("i", 0);
2020
+ nodes[`${base}/gate/thr`] = this.node("f", 0);
2021
+ nodes[`${base}/gate/range`] = this.node("f", 0);
2022
+ nodes[`${base}/gate/attack`] = this.node("f", 0);
2023
+ nodes[`${base}/gate/hold`] = this.node("f", 0);
2024
+ nodes[`${base}/gate/release`] = this.node("f", 0);
2025
+ nodes[`${base}/gate/keysrc`] = this.node("i", 0);
2026
+ nodes[`${base}/gate/filter/on`] = this.node("i", 0);
2027
+ nodes[`${base}/gate/filter/type`] = this.node("i", 0);
2028
+ nodes[`${base}/gate/filter/f`] = this.node("f", .5);
2029
+ nodes[`${base}/dyn/on`] = this.node("i", 0);
2030
+ nodes[`${base}/dyn/mode`] = this.node("i", 0);
2031
+ nodes[`${base}/dyn/pos`] = this.node("i", 0);
2032
+ nodes[`${base}/dyn/det`] = this.node("i", 0);
2033
+ nodes[`${base}/dyn/env`] = this.node("i", 0);
2034
+ nodes[`${base}/dyn/thr`] = this.node("f", 0);
2035
+ nodes[`${base}/dyn/ratio`] = this.node("i", 0);
2036
+ nodes[`${base}/dyn/knee`] = this.node("f", 0);
2037
+ nodes[`${base}/dyn/mgain`] = this.node("f", 0);
2038
+ nodes[`${base}/dyn/attack`] = this.node("f", 0);
2039
+ nodes[`${base}/dyn/hold`] = this.node("f", 0);
2040
+ nodes[`${base}/dyn/release`] = this.node("f", 0);
2041
+ nodes[`${base}/dyn/mix`] = this.node("f", 1);
2042
+ nodes[`${base}/dyn/auto`] = this.node("i", 0);
2043
+ nodes[`${base}/dyn/keysrc`] = this.node("i", 0);
2044
+ nodes[`${base}/dyn/filter/on`] = this.node("i", 0);
2045
+ nodes[`${base}/dyn/filter/type`] = this.node("i", 0);
2046
+ nodes[`${base}/dyn/filter/f`] = this.node("f", .5);
2047
+ nodes[`${base}/eq/on`] = this.node("i", 0);
2048
+ nodes[`${base}/eq/mode`] = this.node("i", 0);
2049
+ for (let b = 1; b <= eqBands; b++) {
2050
+ nodes[`${base}/eq/${b}/type`] = this.node("i", 0);
2051
+ nodes[`${base}/eq/${b}/f`] = this.node("f", .5);
2052
+ nodes[`${base}/eq/${b}/g`] = this.node("f", .5);
2053
+ nodes[`${base}/eq/${b}/q`] = this.node("f", .5);
2054
+ }
2055
+ nodes[`${base}/grp/dca`] = this.node("i", 0);
2056
+ nodes[`${base}/grp/mute`] = this.node("i", 0);
2057
+ return nodes;
2058
+ }
2059
+ generateNodes(count, prefix) {
2060
+ const nodes = {};
2061
+ const isChannelOrAux = prefix === "ch" || prefix === "auxin";
2062
+ const eqBands = prefix === "bus" || prefix === "mtx" ? 6 : 4;
2063
+ for (let i = 1; i <= count; i++) {
2064
+ const padId = i.toString().padStart(2, "0");
2065
+ [i.toString(), padId].forEach((id) => {
2066
+ const base = `/${prefix}/${id}`;
2067
+ if (prefix === "dca") {
2068
+ nodes[`${base}/config/name`] = this.node("s", `DCA ${id}`);
2069
+ nodes[`${base}/config/color`] = this.node("i", 1);
2070
+ nodes[`${base}/fader`] = this.node("f", .75);
2071
+ nodes[`${base}/on`] = this.node("i", 0);
2072
+ } else {
2073
+ Object.assign(nodes, this.generateChannelStrip(base, eqBands, isChannelOrAux));
2074
+ if (prefix === "ch" || prefix === "auxin" || prefix === "fxrtn" || prefix === "bus") for (let b = 1; b <= 16; b++) {
2075
+ const busId = b.toString().padStart(2, "0");
2076
+ nodes[`${base}/mix/${busId}/level`] = this.node("f", 0);
2077
+ nodes[`${base}/mix/${busId}/on`] = this.node("i", 0);
2078
+ nodes[`${base}/mix/${busId}/pan`] = this.node("f", .5);
2079
+ nodes[`${base}/mix/${busId}/type`] = this.node("i", 0);
2080
+ }
2081
+ }
2082
+ });
2083
+ }
2084
+ return nodes;
2085
+ }
2086
+ generateRange(count, prefix, suffix, type, def, pad = 2, start = 1) {
2087
+ const nodes = {};
2088
+ for (let i = start; i < start + count; i++) {
2089
+ const id = i.toString().padStart(pad, "0");
2090
+ nodes[`${prefix}/${i}${suffix}`] = this.node(type, def);
2091
+ nodes[`${prefix}/${id}${suffix}`] = this.node(type, def);
2092
+ }
2093
+ return nodes;
2094
+ }
2095
+ generateOutputs(prefix, count) {
2096
+ const nodes = {};
2097
+ for (let i = 1; i <= count; i++) {
2098
+ const base = `/outputs/${prefix}/${i.toString().padStart(2, "0")}`;
2099
+ nodes[`${base}/src`] = this.node("i", 0);
2100
+ nodes[`${base}/pos`] = this.node("i", 0);
2101
+ nodes[`${base}/invert`] = this.node("i", 0);
2102
+ nodes[`${base}/delay/on`] = this.node("i", 0);
2103
+ nodes[`${base}/delay/time`] = this.node("f", 0);
2104
+ if (prefix === "p16") {
2105
+ nodes[`${base}/iQ/group`] = this.node("i", 0);
2106
+ nodes[`${base}/iQ/model`] = this.node("i", 0);
2107
+ nodes[`${base}/iQ/eq`] = this.node("i", 0);
2108
+ nodes[`${base}/iQ/speaker`] = this.node("i", 0);
2109
+ }
2110
+ }
2111
+ return nodes;
2112
+ }
2113
+ };
2114
+
2115
+ //#endregion
2116
+ //#region src/domain/services/SchemaRegistry.ts
2117
+ /**
2118
+ * Service providing access to the X32 OSC Schema.
2119
+ * Acts as the "Registry" of all available console parameters.
2120
+ */
2121
+ var SchemaRegistry = class {
2122
+ _schema;
2123
+ constructor(schemaFactory) {
2124
+ this.schemaFactory = schemaFactory;
2125
+ this._schema = this.schemaFactory.createSchema();
2126
+ }
2127
+ /**
2128
+ * Retrieves the entire schema map.
2129
+ * @returns The internal schema definition record.
2130
+ */
2131
+ getSchema() {
2132
+ return this._schema;
2133
+ }
2134
+ /**
2135
+ * Retrieves the node definition for a given path.
2136
+ * @param path - The OSC path.
2137
+ * @returns The X32Node definition or undefined if not found.
2138
+ */
2139
+ getNode(path) {
2140
+ return this._schema[path];
2141
+ }
2142
+ /**
2143
+ * Checks if a path exists in the schema.
2144
+ * @param path - The path to check.
2145
+ * @returns True if the path is registered.
2146
+ */
2147
+ has(path) {
2148
+ return path in this._schema;
2149
+ }
2150
+ /**
2151
+ * Returns all paths in the schema.
2152
+ * @returns Array of all registered OSC paths.
2153
+ */
2154
+ getAllPaths() {
2155
+ return Object.keys(this._schema);
2156
+ }
2157
+ /**
2158
+ * Maps an absolute X32 global index to its specific OSC root path.
2159
+ * Used for batch subscriptions where clients request ranges of channels.
2160
+ * @param index - The absolute integer index.
2161
+ * @returns The root path string or null if index is out of bounds.
2162
+ */
2163
+ getRootFromIndex(index) {
2164
+ if (index >= 0 && index <= 31) return `/ch/${(index + 1).toString().padStart(2, "0")}`;
2165
+ if (index >= 32 && index <= 39) return `/auxin/${(index - 31).toString().padStart(2, "0")}`;
2166
+ if (index >= 40 && index <= 47) return `/fxrtn/${(index - 39).toString().padStart(2, "0")}`;
2167
+ if (index >= 48 && index <= 63) return `/bus/${(index - 47).toString().padStart(2, "0")}`;
2168
+ if (index >= 64 && index <= 69) return `/mtx/${(index - 63).toString().padStart(2, "0")}`;
2169
+ if (index === 70) return "/main/st";
2170
+ if (index === 71) return "/main/m";
2171
+ if (index >= 72 && index <= 79) return `/dca/${(index - 71).toString().padStart(2, "0")}`;
2172
+ return null;
2173
+ }
2174
+ };
2175
+
2176
+ //#endregion
2177
+ export { ConsoleLogger as a, X32Node as c, METER_COUNTS as d, MeterData as f, UdpNetworkGateway as i, X32State as l, LogCategory as m, SchemaFactory as n, LogLevel as o, SubscriptionManager as p, OscCodec as r, InMemoryStateRepository as s, SchemaRegistry as t, SimulationService as u };