@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.
- package/CHANGELOG.md +10 -0
- package/README.md +28 -0
- package/dist/{UdpNetworkGateway-BrroQ6-Q.mjs → SchemaRegistry-BRVgnyaA.mjs} +990 -2
- package/dist/{UdpNetworkGateway-Ccdd7Us5.cjs → SchemaRegistry-CfDtw84j.cjs} +1033 -3
- package/dist/index.cjs +160 -6
- package/dist/index.d.cts +61 -11
- package/dist/index.d.mts +61 -11
- package/dist/index.mjs +146 -2
- package/dist/server.cjs +8 -927
- package/dist/server.mjs +1 -920
- package/package.json +1 -1
- package/src/application/use-cases/SimulationService.ts +24 -0
- package/src/domain/entities/X32State.ts +1 -1
- package/src/domain/models/X32Address.ts +2 -8
- package/src/domain/models/types.ts +0 -10
- package/src/infrastructure/repositories/InMemoryStateRepository.ts +16 -0
- package/src/infrastructure/services/UdpNetworkGateway.ts +29 -0
- package/src/presentation/library/library.ts +131 -1
package/dist/server.cjs
CHANGED
|
@@ -1,932 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
const
|
|
2
|
+
const require_SchemaRegistry = require('./SchemaRegistry-CfDtw84j.cjs');
|
|
3
3
|
let node_readline = require("node:readline");
|
|
4
|
-
node_readline =
|
|
4
|
+
node_readline = require_SchemaRegistry.__toESM(node_readline);
|
|
5
5
|
let node_fs = require("node:fs");
|
|
6
|
-
node_fs =
|
|
6
|
+
node_fs = require_SchemaRegistry.__toESM(node_fs);
|
|
7
7
|
let node_path = require("node:path");
|
|
8
|
-
node_path =
|
|
8
|
+
node_path = require_SchemaRegistry.__toESM(node_path);
|
|
9
9
|
let node_url = require("node:url");
|
|
10
|
-
let node_buffer = require("node:buffer");
|
|
11
10
|
|
|
12
|
-
//#region src/domain/services/SchemaRegistry.ts
|
|
13
|
-
/**
|
|
14
|
-
* Service providing access to the X32 OSC Schema.
|
|
15
|
-
* Acts as the "Registry" of all available console parameters.
|
|
16
|
-
*/
|
|
17
|
-
var SchemaRegistry = class {
|
|
18
|
-
_schema;
|
|
19
|
-
constructor(schemaFactory) {
|
|
20
|
-
this.schemaFactory = schemaFactory;
|
|
21
|
-
this._schema = this.schemaFactory.createSchema();
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Retrieves the entire schema map.
|
|
25
|
-
* @returns The internal schema definition record.
|
|
26
|
-
*/
|
|
27
|
-
getSchema() {
|
|
28
|
-
return this._schema;
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* Retrieves the node definition for a given path.
|
|
32
|
-
* @param path - The OSC path.
|
|
33
|
-
* @returns The X32Node definition or undefined if not found.
|
|
34
|
-
*/
|
|
35
|
-
getNode(path) {
|
|
36
|
-
return this._schema[path];
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Checks if a path exists in the schema.
|
|
40
|
-
* @param path - The path to check.
|
|
41
|
-
* @returns True if the path is registered.
|
|
42
|
-
*/
|
|
43
|
-
has(path) {
|
|
44
|
-
return path in this._schema;
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Returns all paths in the schema.
|
|
48
|
-
* @returns Array of all registered OSC paths.
|
|
49
|
-
*/
|
|
50
|
-
getAllPaths() {
|
|
51
|
-
return Object.keys(this._schema);
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* Maps an absolute X32 global index to its specific OSC root path.
|
|
55
|
-
* Used for batch subscriptions where clients request ranges of channels.
|
|
56
|
-
* @param index - The absolute integer index.
|
|
57
|
-
* @returns The root path string or null if index is out of bounds.
|
|
58
|
-
*/
|
|
59
|
-
getRootFromIndex(index) {
|
|
60
|
-
if (index >= 0 && index <= 31) return `/ch/${(index + 1).toString().padStart(2, "0")}`;
|
|
61
|
-
if (index >= 32 && index <= 39) return `/auxin/${(index - 31).toString().padStart(2, "0")}`;
|
|
62
|
-
if (index >= 40 && index <= 47) return `/fxrtn/${(index - 39).toString().padStart(2, "0")}`;
|
|
63
|
-
if (index >= 48 && index <= 63) return `/bus/${(index - 47).toString().padStart(2, "0")}`;
|
|
64
|
-
if (index >= 64 && index <= 69) return `/mtx/${(index - 63).toString().padStart(2, "0")}`;
|
|
65
|
-
if (index === 70) return "/main/st";
|
|
66
|
-
if (index === 71) return "/main/m";
|
|
67
|
-
if (index >= 72 && index <= 79) return `/dca/${(index - 71).toString().padStart(2, "0")}`;
|
|
68
|
-
return null;
|
|
69
|
-
}
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
//#endregion
|
|
73
|
-
//#region src/domain/models/X32Node.ts
|
|
74
|
-
/**
|
|
75
|
-
* Metadata for a single state node in the X32 schema.
|
|
76
|
-
* Represents a "Knob" or "Variable" on the console.
|
|
77
|
-
*/
|
|
78
|
-
var X32Node = class X32Node {
|
|
79
|
-
/** Value type (f=float, i=int, s=string). */
|
|
80
|
-
type;
|
|
81
|
-
/** Default value for reset. */
|
|
82
|
-
default;
|
|
83
|
-
/**
|
|
84
|
-
* Creates a new X32Node.
|
|
85
|
-
* @param type - The OSC data type ('f', 'i', 's').
|
|
86
|
-
* @param defaultValue - The default value.
|
|
87
|
-
*/
|
|
88
|
-
constructor(type, defaultValue) {
|
|
89
|
-
this.type = type;
|
|
90
|
-
this.default = defaultValue;
|
|
91
|
-
}
|
|
92
|
-
/**
|
|
93
|
-
* Validates if a value is compatible with this node's type.
|
|
94
|
-
* @param value - The value to check.
|
|
95
|
-
* @returns True if valid.
|
|
96
|
-
*/
|
|
97
|
-
validate(value) {
|
|
98
|
-
if (this.type === "f") return typeof value === "number";
|
|
99
|
-
if (this.type === "i") return typeof value === "number";
|
|
100
|
-
if (this.type === "s") return typeof value === "string";
|
|
101
|
-
return false;
|
|
102
|
-
}
|
|
103
|
-
/**
|
|
104
|
-
* Factory method to create from a plain object (for compatibility/migration).
|
|
105
|
-
* @param obj - Plain object.
|
|
106
|
-
* @param obj.type - OSC data type.
|
|
107
|
-
* @param obj.default - Default value.
|
|
108
|
-
* @returns A new X32Node instance.
|
|
109
|
-
*/
|
|
110
|
-
static from(obj) {
|
|
111
|
-
return new X32Node(obj.type, obj.default);
|
|
112
|
-
}
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
//#endregion
|
|
116
|
-
//#region src/domain/services/SchemaFactory.ts
|
|
117
|
-
/**
|
|
118
|
-
* Factory service responsible for constructing the X32 OSC Schema.
|
|
119
|
-
* Encapsulates all the logic for generating channel strips, routing blocks, etc.
|
|
120
|
-
*/
|
|
121
|
-
var SchemaFactory = class {
|
|
122
|
-
/**
|
|
123
|
-
* Builds the complete X32 OSC Schema.
|
|
124
|
-
* @returns The constructed schema map.
|
|
125
|
-
*/
|
|
126
|
-
createSchema() {
|
|
127
|
-
const schema = {
|
|
128
|
-
...this.generateNodes(32, "ch"),
|
|
129
|
-
...this.generateNodes(16, "bus"),
|
|
130
|
-
...this.generateNodes(8, "dca"),
|
|
131
|
-
...this.generateNodes(8, "auxin"),
|
|
132
|
-
...this.generateNodes(8, "fxrtn"),
|
|
133
|
-
...this.generateNodes(6, "mtx"),
|
|
134
|
-
...Object.fromEntries(Array.from({ length: 8 }, (_, i) => [`/fx/${i + 1}/type`, this.node("i", 0)])),
|
|
135
|
-
...this.generateRange(8, "/fx", "/type", "i", 0),
|
|
136
|
-
...this.generateRange(8, "/fx", "/source/l", "i", 0),
|
|
137
|
-
...this.generateRange(8, "/fx", "/source/r", "i", 0),
|
|
138
|
-
...Object.fromEntries(Array.from({ length: 8 }, (_, slot) => Object.entries(this.generateRange(64, `/fx/${slot + 1}/par`, "", "f", 0, 2, 1))).flat()),
|
|
139
|
-
...this.generateRange(128, "/headamp", "/gain", "f", 0, 3, 0),
|
|
140
|
-
...this.generateRange(128, "/headamp", "/phantom", "i", 0, 3, 0),
|
|
141
|
-
...this.generateRange(6, "/config/mute", "", "i", 0),
|
|
142
|
-
...this.generateRange(80, "/-stat/solosw", "", "i", 0),
|
|
143
|
-
"/-stat/selidx": this.node("i", 0),
|
|
144
|
-
"/-stat/sendsonfader": this.node("i", 0),
|
|
145
|
-
"/-stat/bussendbank": this.node("i", 0),
|
|
146
|
-
"/-stat/keysolo": this.node("i", 0),
|
|
147
|
-
"/-stat/screen/screen": this.node("i", 0),
|
|
148
|
-
"/-stat/screen/CHAN/page": this.node("i", 0),
|
|
149
|
-
"/-stat/screen/METER/page": this.node("i", 0),
|
|
150
|
-
"/-stat/screen/ROUTE/page": this.node("i", 0),
|
|
151
|
-
"/-stat/screen/SETUP/page": this.node("i", 0),
|
|
152
|
-
"/-stat/screen/LIBRARY/page": this.node("i", 0),
|
|
153
|
-
"/-stat/screen/FX/page": this.node("i", 0),
|
|
154
|
-
"/-stat/screen/MON/page": this.node("i", 0),
|
|
155
|
-
"/-stat/screen/USB/page": this.node("i", 0),
|
|
156
|
-
"/-stat/screen/SCENE/page": this.node("i", 0),
|
|
157
|
-
"/-stat/screen/ASSIGN/page": this.node("i", 0),
|
|
158
|
-
"/-stat/talk/A": this.node("i", 0),
|
|
159
|
-
"/-stat/talk/B": this.node("i", 0),
|
|
160
|
-
"/-stat/osc/on": this.node("i", 0),
|
|
161
|
-
"/-prefs/autosel": this.node("i", 1),
|
|
162
|
-
"/-action/setrtasrc": this.node("i", 0),
|
|
163
|
-
"/-action/playtrack": this.node("i", 0),
|
|
164
|
-
"/-action/goscene": this.node("i", 0),
|
|
165
|
-
"/-action/setscene": this.node("i", 0),
|
|
166
|
-
"/config/routing/AES50A/1-8": this.node("i", 0),
|
|
167
|
-
"/config/routing/AES50B/1-8": this.node("i", 0),
|
|
168
|
-
"/config/routing/CARD/1-8": this.node("i", 0),
|
|
169
|
-
"/config/routing/OUT/1-4": this.node("i", 0),
|
|
170
|
-
"/-prefs/invertmutes": this.node("i", 0),
|
|
171
|
-
...this.generateChannelStrip("/main/st", 6, false),
|
|
172
|
-
...this.generateChannelStrip("/main/m", 6, false),
|
|
173
|
-
...Object.fromEntries(Array.from({ length: 16 }, (_, i) => [`/config/chlink/${i * 2 + 1}-${i * 2 + 2}`, this.node("i", 0)])),
|
|
174
|
-
...Object.fromEntries(Array.from({ length: 8 }, (_, i) => [`/config/buslink/${i * 2 + 1}-${i * 2 + 2}`, this.node("i", 0)])),
|
|
175
|
-
...Object.fromEntries(Array.from({ length: 4 }, (_, i) => [`/config/auxlink/${i * 2 + 1}-${i * 2 + 2}`, this.node("i", 0)])),
|
|
176
|
-
...Object.fromEntries(Array.from({ length: 4 }, (_, i) => [`/config/fxlink/${i * 2 + 1}-${i * 2 + 2}`, this.node("i", 0)])),
|
|
177
|
-
...this.generateRange(32, "/config/userrout/in", "", "i", 0),
|
|
178
|
-
...this.generateRange(48, "/config/userrout/out", "", "i", 0),
|
|
179
|
-
"/config/solo/level": this.node("f", 0),
|
|
180
|
-
"/config/solo/source": this.node("i", 0),
|
|
181
|
-
"/config/solo/sourcetrim": this.node("f", 0),
|
|
182
|
-
"/config/solo/exclusive": this.node("i", 0),
|
|
183
|
-
"/config/solo/dim": this.node("i", 0),
|
|
184
|
-
"/config/solo/dimpfl": this.node("i", 0),
|
|
185
|
-
"/config/solo/dimatt": this.node("f", 0),
|
|
186
|
-
"/config/solo/mono": this.node("i", 0),
|
|
187
|
-
"/config/solo/chmode": this.node("i", 0),
|
|
188
|
-
"/config/solo/busmode": this.node("i", 0),
|
|
189
|
-
"/config/solo/dcamode": this.node("i", 0),
|
|
190
|
-
"/config/solo/masterctrl": this.node("i", 0),
|
|
191
|
-
"/config/solo/delay": this.node("i", 0),
|
|
192
|
-
"/config/solo/delaytime": this.node("f", 0),
|
|
193
|
-
"/config/solo/followsel": this.node("i", 0),
|
|
194
|
-
"/config/solo/followsolo": this.node("i", 0),
|
|
195
|
-
"/config/talk/enable": this.node("i", 0),
|
|
196
|
-
"/config/talk/source": this.node("i", 0),
|
|
197
|
-
"/config/talk/A/level": this.node("f", 0),
|
|
198
|
-
"/config/talk/B/level": this.node("f", 0),
|
|
199
|
-
"/config/talk/A/dim": this.node("i", 0),
|
|
200
|
-
"/config/talk/B/dim": this.node("i", 0),
|
|
201
|
-
"/config/talk/A/latch": this.node("i", 0),
|
|
202
|
-
"/config/talk/B/latch": this.node("i", 0),
|
|
203
|
-
"/config/talk/A/destmap": this.node("i", 0),
|
|
204
|
-
"/config/talk/B/destmap": this.node("i", 0),
|
|
205
|
-
"/config/osc/on": this.node("i", 0),
|
|
206
|
-
"/config/osc/type": this.node("i", 0),
|
|
207
|
-
"/config/osc/fsel": this.node("i", 0),
|
|
208
|
-
"/config/osc/f1": this.node("f", .5),
|
|
209
|
-
"/config/osc/f2": this.node("f", .5),
|
|
210
|
-
"/config/osc/level": this.node("f", 0),
|
|
211
|
-
"/config/osc/dest": this.node("i", 0),
|
|
212
|
-
...this.generateOutputs("main", 16),
|
|
213
|
-
...this.generateOutputs("aux", 6),
|
|
214
|
-
...this.generateOutputs("p16", 16),
|
|
215
|
-
...this.generateOutputs("aes", 2),
|
|
216
|
-
...this.generateOutputs("rec", 2)
|
|
217
|
-
};
|
|
218
|
-
Object.keys(require_UdpNetworkGateway.STATIC_RESPONSES_DATA).forEach((key) => {
|
|
219
|
-
if (key.startsWith("/-") || key.startsWith("/stat")) schema[key] = this.node("i", 0);
|
|
220
|
-
});
|
|
221
|
-
[
|
|
222
|
-
"/config/routing/IN/1-8",
|
|
223
|
-
"/config/routing/IN/9-16",
|
|
224
|
-
"/config/routing/IN/17-24",
|
|
225
|
-
"/config/routing/IN/25-32",
|
|
226
|
-
"/config/routing/AUX/1-4",
|
|
227
|
-
"/config/routing/OUT/1-4",
|
|
228
|
-
"/config/routing/OUT/5-8",
|
|
229
|
-
"/config/routing/OUT/9-12",
|
|
230
|
-
"/config/routing/OUT/13-16",
|
|
231
|
-
"/config/routing/P16/1-8",
|
|
232
|
-
"/config/routing/P16/9-16",
|
|
233
|
-
"/config/routing/CARD/1-8",
|
|
234
|
-
"/config/routing/CARD/9-16",
|
|
235
|
-
"/config/routing/CARD/17-24",
|
|
236
|
-
"/config/routing/CARD/25-32",
|
|
237
|
-
"/config/routing/AES50A/1-8",
|
|
238
|
-
"/config/routing/AES50A/9-16",
|
|
239
|
-
"/config/routing/AES50A/17-24",
|
|
240
|
-
"/config/routing/AES50A/25-32",
|
|
241
|
-
"/config/routing/AES50A/33-40",
|
|
242
|
-
"/config/routing/AES50A/41-48",
|
|
243
|
-
"/config/routing/AES50B/1-8",
|
|
244
|
-
"/config/routing/AES50B/9-16",
|
|
245
|
-
"/config/routing/AES50B/17-24",
|
|
246
|
-
"/config/routing/AES50B/25-32",
|
|
247
|
-
"/config/routing/AES50B/33-40",
|
|
248
|
-
"/config/routing/AES50B/41-48",
|
|
249
|
-
"/config/routing/PLAY/1-8",
|
|
250
|
-
"/config/routing/PLAY/9-16",
|
|
251
|
-
"/config/routing/PLAY/17-24",
|
|
252
|
-
"/config/routing/PLAY/25-32"
|
|
253
|
-
].forEach((path) => {
|
|
254
|
-
schema[path] = this.node("i", 0);
|
|
255
|
-
});
|
|
256
|
-
return schema;
|
|
257
|
-
}
|
|
258
|
-
node(type, def) {
|
|
259
|
-
return new X32Node(type, def);
|
|
260
|
-
}
|
|
261
|
-
generateChannelStrip(base, eqBands = 4, hasPreamp = false) {
|
|
262
|
-
const nodes = {};
|
|
263
|
-
nodes[`${base}/config/name`] = this.node("s", base.split("/").pop()?.toUpperCase() || "");
|
|
264
|
-
nodes[`${base}/config/icon`] = this.node("i", 1);
|
|
265
|
-
nodes[`${base}/config/color`] = this.node("i", 1);
|
|
266
|
-
nodes[`${base}/config/source`] = this.node("i", 1);
|
|
267
|
-
nodes[`${base}/mix/fader`] = this.node("f", .75);
|
|
268
|
-
nodes[`${base}/mix/on`] = this.node("i", 0);
|
|
269
|
-
nodes[`${base}/mix/pan`] = this.node("f", .5);
|
|
270
|
-
nodes[`${base}/mix/mono`] = this.node("i", 0);
|
|
271
|
-
nodes[`${base}/mix/mlevel`] = this.node("f", 0);
|
|
272
|
-
nodes[`${base}/mix/st`] = this.node("i", 1);
|
|
273
|
-
if (hasPreamp) {
|
|
274
|
-
nodes[`${base}/preamp/trim`] = this.node("f", .5);
|
|
275
|
-
nodes[`${base}/preamp/hpon`] = this.node("i", 0);
|
|
276
|
-
nodes[`${base}/preamp/hpf`] = this.node("f", 0);
|
|
277
|
-
nodes[`${base}/preamp/phantom`] = this.node("i", 0);
|
|
278
|
-
nodes[`${base}/preamp/rtnsw`] = this.node("i", 0);
|
|
279
|
-
nodes[`${base}/preamp/invert`] = this.node("i", 0);
|
|
280
|
-
}
|
|
281
|
-
nodes[`${base}/delay/on`] = this.node("i", 0);
|
|
282
|
-
nodes[`${base}/delay/time`] = this.node("f", 0);
|
|
283
|
-
nodes[`${base}/insert/on`] = this.node("i", 0);
|
|
284
|
-
nodes[`${base}/insert/pos`] = this.node("i", 0);
|
|
285
|
-
nodes[`${base}/insert/sel`] = this.node("i", 0);
|
|
286
|
-
nodes[`${base}/gate/on`] = this.node("i", 0);
|
|
287
|
-
nodes[`${base}/gate/mode`] = this.node("i", 0);
|
|
288
|
-
nodes[`${base}/gate/thr`] = this.node("f", 0);
|
|
289
|
-
nodes[`${base}/gate/range`] = this.node("f", 0);
|
|
290
|
-
nodes[`${base}/gate/attack`] = this.node("f", 0);
|
|
291
|
-
nodes[`${base}/gate/hold`] = this.node("f", 0);
|
|
292
|
-
nodes[`${base}/gate/release`] = this.node("f", 0);
|
|
293
|
-
nodes[`${base}/gate/keysrc`] = this.node("i", 0);
|
|
294
|
-
nodes[`${base}/gate/filter/on`] = this.node("i", 0);
|
|
295
|
-
nodes[`${base}/gate/filter/type`] = this.node("i", 0);
|
|
296
|
-
nodes[`${base}/gate/filter/f`] = this.node("f", .5);
|
|
297
|
-
nodes[`${base}/dyn/on`] = this.node("i", 0);
|
|
298
|
-
nodes[`${base}/dyn/mode`] = this.node("i", 0);
|
|
299
|
-
nodes[`${base}/dyn/pos`] = this.node("i", 0);
|
|
300
|
-
nodes[`${base}/dyn/det`] = this.node("i", 0);
|
|
301
|
-
nodes[`${base}/dyn/env`] = this.node("i", 0);
|
|
302
|
-
nodes[`${base}/dyn/thr`] = this.node("f", 0);
|
|
303
|
-
nodes[`${base}/dyn/ratio`] = this.node("i", 0);
|
|
304
|
-
nodes[`${base}/dyn/knee`] = this.node("f", 0);
|
|
305
|
-
nodes[`${base}/dyn/mgain`] = this.node("f", 0);
|
|
306
|
-
nodes[`${base}/dyn/attack`] = this.node("f", 0);
|
|
307
|
-
nodes[`${base}/dyn/hold`] = this.node("f", 0);
|
|
308
|
-
nodes[`${base}/dyn/release`] = this.node("f", 0);
|
|
309
|
-
nodes[`${base}/dyn/mix`] = this.node("f", 1);
|
|
310
|
-
nodes[`${base}/dyn/auto`] = this.node("i", 0);
|
|
311
|
-
nodes[`${base}/dyn/keysrc`] = this.node("i", 0);
|
|
312
|
-
nodes[`${base}/dyn/filter/on`] = this.node("i", 0);
|
|
313
|
-
nodes[`${base}/dyn/filter/type`] = this.node("i", 0);
|
|
314
|
-
nodes[`${base}/dyn/filter/f`] = this.node("f", .5);
|
|
315
|
-
nodes[`${base}/eq/on`] = this.node("i", 0);
|
|
316
|
-
nodes[`${base}/eq/mode`] = this.node("i", 0);
|
|
317
|
-
for (let b = 1; b <= eqBands; b++) {
|
|
318
|
-
nodes[`${base}/eq/${b}/type`] = this.node("i", 0);
|
|
319
|
-
nodes[`${base}/eq/${b}/f`] = this.node("f", .5);
|
|
320
|
-
nodes[`${base}/eq/${b}/g`] = this.node("f", .5);
|
|
321
|
-
nodes[`${base}/eq/${b}/q`] = this.node("f", .5);
|
|
322
|
-
}
|
|
323
|
-
nodes[`${base}/grp/dca`] = this.node("i", 0);
|
|
324
|
-
nodes[`${base}/grp/mute`] = this.node("i", 0);
|
|
325
|
-
return nodes;
|
|
326
|
-
}
|
|
327
|
-
generateNodes(count, prefix) {
|
|
328
|
-
const nodes = {};
|
|
329
|
-
const isChannelOrAux = prefix === "ch" || prefix === "auxin";
|
|
330
|
-
const eqBands = prefix === "bus" || prefix === "mtx" ? 6 : 4;
|
|
331
|
-
for (let i = 1; i <= count; i++) {
|
|
332
|
-
const padId = i.toString().padStart(2, "0");
|
|
333
|
-
[i.toString(), padId].forEach((id) => {
|
|
334
|
-
const base = `/${prefix}/${id}`;
|
|
335
|
-
if (prefix === "dca") {
|
|
336
|
-
nodes[`${base}/config/name`] = this.node("s", `DCA ${id}`);
|
|
337
|
-
nodes[`${base}/config/color`] = this.node("i", 1);
|
|
338
|
-
nodes[`${base}/fader`] = this.node("f", .75);
|
|
339
|
-
nodes[`${base}/on`] = this.node("i", 0);
|
|
340
|
-
} else {
|
|
341
|
-
Object.assign(nodes, this.generateChannelStrip(base, eqBands, isChannelOrAux));
|
|
342
|
-
if (prefix === "ch" || prefix === "auxin" || prefix === "fxrtn" || prefix === "bus") for (let b = 1; b <= 16; b++) {
|
|
343
|
-
const busId = b.toString().padStart(2, "0");
|
|
344
|
-
nodes[`${base}/mix/${busId}/level`] = this.node("f", 0);
|
|
345
|
-
nodes[`${base}/mix/${busId}/on`] = this.node("i", 0);
|
|
346
|
-
nodes[`${base}/mix/${busId}/pan`] = this.node("f", .5);
|
|
347
|
-
nodes[`${base}/mix/${busId}/type`] = this.node("i", 0);
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
});
|
|
351
|
-
}
|
|
352
|
-
return nodes;
|
|
353
|
-
}
|
|
354
|
-
generateRange(count, prefix, suffix, type, def, pad = 2, start = 1) {
|
|
355
|
-
const nodes = {};
|
|
356
|
-
for (let i = start; i < start + count; i++) {
|
|
357
|
-
const id = i.toString().padStart(pad, "0");
|
|
358
|
-
nodes[`${prefix}/${i}${suffix}`] = this.node(type, def);
|
|
359
|
-
nodes[`${prefix}/${id}${suffix}`] = this.node(type, def);
|
|
360
|
-
}
|
|
361
|
-
return nodes;
|
|
362
|
-
}
|
|
363
|
-
generateOutputs(prefix, count) {
|
|
364
|
-
const nodes = {};
|
|
365
|
-
for (let i = 1; i <= count; i++) {
|
|
366
|
-
const base = `/outputs/${prefix}/${i.toString().padStart(2, "0")}`;
|
|
367
|
-
nodes[`${base}/src`] = this.node("i", 0);
|
|
368
|
-
nodes[`${base}/pos`] = this.node("i", 0);
|
|
369
|
-
nodes[`${base}/invert`] = this.node("i", 0);
|
|
370
|
-
nodes[`${base}/delay/on`] = this.node("i", 0);
|
|
371
|
-
nodes[`${base}/delay/time`] = this.node("f", 0);
|
|
372
|
-
if (prefix === "p16") {
|
|
373
|
-
nodes[`${base}/iQ/group`] = this.node("i", 0);
|
|
374
|
-
nodes[`${base}/iQ/model`] = this.node("i", 0);
|
|
375
|
-
nodes[`${base}/iQ/eq`] = this.node("i", 0);
|
|
376
|
-
nodes[`${base}/iQ/speaker`] = this.node("i", 0);
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
return nodes;
|
|
380
|
-
}
|
|
381
|
-
};
|
|
382
|
-
|
|
383
|
-
//#endregion
|
|
384
|
-
//#region node_modules/node-osc/lib/Message.mjs
|
|
385
|
-
const typeTags = {
|
|
386
|
-
s: "string",
|
|
387
|
-
f: "float",
|
|
388
|
-
i: "integer",
|
|
389
|
-
b: "blob",
|
|
390
|
-
m: "midi"
|
|
391
|
-
};
|
|
392
|
-
/**
|
|
393
|
-
* Represents a typed argument for an OSC message.
|
|
394
|
-
*
|
|
395
|
-
* @class
|
|
396
|
-
* @private
|
|
397
|
-
*/
|
|
398
|
-
var Argument = class {
|
|
399
|
-
/**
|
|
400
|
-
* @param {string} type - The type of the argument (string, float, integer, blob, boolean).
|
|
401
|
-
* @param {*} value - The value of the argument.
|
|
402
|
-
*/
|
|
403
|
-
constructor(type, value) {
|
|
404
|
-
this.type = type;
|
|
405
|
-
this.value = value;
|
|
406
|
-
}
|
|
407
|
-
};
|
|
408
|
-
/**
|
|
409
|
-
* Represents an OSC message with an address and arguments.
|
|
410
|
-
*
|
|
411
|
-
* OSC messages consist of an address pattern (string starting with '/')
|
|
412
|
-
* and zero or more arguments of various types.
|
|
413
|
-
*
|
|
414
|
-
* @class
|
|
415
|
-
*
|
|
416
|
-
* @example
|
|
417
|
-
* // Create a message with constructor arguments
|
|
418
|
-
* const msg = new Message('/test', 1, 2, 'hello');
|
|
419
|
-
*
|
|
420
|
-
* @example
|
|
421
|
-
* // Create a message and append arguments
|
|
422
|
-
* const msg = new Message('/test');
|
|
423
|
-
* msg.append(1);
|
|
424
|
-
* msg.append('hello');
|
|
425
|
-
* msg.append(3.14);
|
|
426
|
-
*/
|
|
427
|
-
var Message = class {
|
|
428
|
-
/**
|
|
429
|
-
* Create an OSC Message.
|
|
430
|
-
*
|
|
431
|
-
* @param {string} address - The OSC address pattern (e.g., '/oscillator/frequency').
|
|
432
|
-
* @param {...*} args - Optional arguments to include in the message.
|
|
433
|
-
*
|
|
434
|
-
* @example
|
|
435
|
-
* const msg = new Message('/test');
|
|
436
|
-
*
|
|
437
|
-
* @example
|
|
438
|
-
* const msg = new Message('/test', 1, 2, 3);
|
|
439
|
-
*
|
|
440
|
-
* @example
|
|
441
|
-
* const msg = new Message('/synth', 'note', 60, 0.5);
|
|
442
|
-
*/
|
|
443
|
-
constructor(address, ...args) {
|
|
444
|
-
this.oscType = "message";
|
|
445
|
-
this.address = address;
|
|
446
|
-
this.args = args;
|
|
447
|
-
}
|
|
448
|
-
/**
|
|
449
|
-
* Append an argument to the message.
|
|
450
|
-
*
|
|
451
|
-
* Automatically detects the type based on the JavaScript type:
|
|
452
|
-
* - Integers are encoded as OSC integers
|
|
453
|
-
* - Floats are encoded as OSC floats
|
|
454
|
-
* - Strings are encoded as OSC strings
|
|
455
|
-
* - Booleans are encoded as OSC booleans
|
|
456
|
-
* - Buffers are encoded as OSC blobs
|
|
457
|
-
* - Arrays are recursively appended
|
|
458
|
-
* - Objects with a 'type' property are used as-is
|
|
459
|
-
*
|
|
460
|
-
* @param {*} arg - The argument to append. Can be:
|
|
461
|
-
* - A primitive value (number, string, boolean)
|
|
462
|
-
* - A Buffer (encoded as blob)
|
|
463
|
-
* - An array of values (will be recursively appended)
|
|
464
|
-
* - An object with 'type' and 'value' properties for explicit type control
|
|
465
|
-
*
|
|
466
|
-
* @throws {Error} If the argument type cannot be encoded.
|
|
467
|
-
*
|
|
468
|
-
* @example
|
|
469
|
-
* const msg = new Message('/test');
|
|
470
|
-
* msg.append(42); // Integer
|
|
471
|
-
* msg.append(3.14); // Float
|
|
472
|
-
* msg.append('hello'); // String
|
|
473
|
-
* msg.append(true); // Boolean
|
|
474
|
-
*
|
|
475
|
-
* @example
|
|
476
|
-
* // Append multiple values at once
|
|
477
|
-
* msg.append([1, 2, 3]);
|
|
478
|
-
*
|
|
479
|
-
* @example
|
|
480
|
-
* // Explicitly specify type
|
|
481
|
-
* msg.append({ type: 'float', value: 42 });
|
|
482
|
-
* msg.append({ type: 'blob', value: Buffer.from('data') });
|
|
483
|
-
*
|
|
484
|
-
* @example
|
|
485
|
-
* // MIDI messages (4 bytes: port, status, data1, data2)
|
|
486
|
-
* msg.append({ type: 'midi', value: { port: 0, status: 144, data1: 60, data2: 127 } });
|
|
487
|
-
* msg.append({ type: 'm', value: Buffer.from([0, 144, 60, 127]) });
|
|
488
|
-
*/
|
|
489
|
-
append(arg) {
|
|
490
|
-
let argOut;
|
|
491
|
-
switch (typeof arg) {
|
|
492
|
-
case "object":
|
|
493
|
-
if (Buffer.isBuffer(arg)) this.args.push(arg);
|
|
494
|
-
else if (arg instanceof Array) arg.forEach((a) => this.append(a));
|
|
495
|
-
else if (arg.type) {
|
|
496
|
-
if (typeTags[arg.type]) arg.type = typeTags[arg.type];
|
|
497
|
-
this.args.push(arg);
|
|
498
|
-
} else throw new Error(`don't know how to encode object ${arg}`);
|
|
499
|
-
break;
|
|
500
|
-
case "number":
|
|
501
|
-
if (Math.floor(arg) === arg) argOut = new Argument("integer", arg);
|
|
502
|
-
else argOut = new Argument("float", arg);
|
|
503
|
-
break;
|
|
504
|
-
case "string":
|
|
505
|
-
argOut = new Argument("string", arg);
|
|
506
|
-
break;
|
|
507
|
-
case "boolean":
|
|
508
|
-
argOut = new Argument("boolean", arg);
|
|
509
|
-
break;
|
|
510
|
-
default: throw new Error(`don't know how to encode ${arg}`);
|
|
511
|
-
}
|
|
512
|
-
if (argOut) this.args.push(argOut);
|
|
513
|
-
}
|
|
514
|
-
};
|
|
515
|
-
var Message_default = Message;
|
|
516
|
-
|
|
517
|
-
//#endregion
|
|
518
|
-
//#region node_modules/node-osc/lib/osc.mjs
|
|
519
|
-
function padString(str) {
|
|
520
|
-
const nullTerminated = str + "\0";
|
|
521
|
-
const padding = (4 - node_buffer.Buffer.byteLength(nullTerminated) % 4) % 4;
|
|
522
|
-
return nullTerminated + "\0".repeat(padding);
|
|
523
|
-
}
|
|
524
|
-
function readString(buffer, offset) {
|
|
525
|
-
let end = offset;
|
|
526
|
-
while (end < buffer.length && buffer[end] !== 0) end++;
|
|
527
|
-
if (end >= buffer.length) throw new Error("Malformed Packet: Missing null terminator for string");
|
|
528
|
-
return {
|
|
529
|
-
value: buffer.subarray(offset, end).toString("utf8"),
|
|
530
|
-
offset: offset + Math.ceil((end - offset + 1) / 4) * 4
|
|
531
|
-
};
|
|
532
|
-
}
|
|
533
|
-
function writeInt32(value) {
|
|
534
|
-
const buffer = node_buffer.Buffer.alloc(4);
|
|
535
|
-
buffer.writeInt32BE(value, 0);
|
|
536
|
-
return buffer;
|
|
537
|
-
}
|
|
538
|
-
function readInt32(buffer, offset) {
|
|
539
|
-
if (offset + 4 > buffer.length) throw new Error("Malformed Packet: Not enough bytes for int32");
|
|
540
|
-
return {
|
|
541
|
-
value: buffer.readInt32BE(offset),
|
|
542
|
-
offset: offset + 4
|
|
543
|
-
};
|
|
544
|
-
}
|
|
545
|
-
function writeFloat32(value) {
|
|
546
|
-
const buffer = node_buffer.Buffer.alloc(4);
|
|
547
|
-
buffer.writeFloatBE(value, 0);
|
|
548
|
-
return buffer;
|
|
549
|
-
}
|
|
550
|
-
function readFloat32(buffer, offset) {
|
|
551
|
-
if (offset + 4 > buffer.length) throw new Error("Malformed Packet: Not enough bytes for float32");
|
|
552
|
-
return {
|
|
553
|
-
value: buffer.readFloatBE(offset),
|
|
554
|
-
offset: offset + 4
|
|
555
|
-
};
|
|
556
|
-
}
|
|
557
|
-
function writeBlob(value) {
|
|
558
|
-
const length = value.length;
|
|
559
|
-
const lengthBuffer = writeInt32(length);
|
|
560
|
-
const padding = 4 - length % 4;
|
|
561
|
-
const paddingBuffer = node_buffer.Buffer.alloc(padding === 4 ? 0 : padding);
|
|
562
|
-
return node_buffer.Buffer.concat([
|
|
563
|
-
lengthBuffer,
|
|
564
|
-
value,
|
|
565
|
-
paddingBuffer
|
|
566
|
-
]);
|
|
567
|
-
}
|
|
568
|
-
function readBlob(buffer, offset) {
|
|
569
|
-
const lengthResult = readInt32(buffer, offset);
|
|
570
|
-
const length = lengthResult.value;
|
|
571
|
-
if (length < 0) throw new Error("Malformed Packet: Invalid blob length");
|
|
572
|
-
if (lengthResult.offset + length > buffer.length) throw new Error("Malformed Packet: Not enough bytes for blob");
|
|
573
|
-
const data = buffer.subarray(lengthResult.offset, lengthResult.offset + length);
|
|
574
|
-
const padding = 4 - length % 4;
|
|
575
|
-
const nextOffset = lengthResult.offset + length + (padding === 4 ? 0 : padding);
|
|
576
|
-
if (nextOffset > buffer.length) throw new Error("Malformed Packet: Not enough bytes for blob padding");
|
|
577
|
-
return {
|
|
578
|
-
value: data,
|
|
579
|
-
offset: nextOffset
|
|
580
|
-
};
|
|
581
|
-
}
|
|
582
|
-
function writeTimeTag(value) {
|
|
583
|
-
const buffer = node_buffer.Buffer.alloc(8);
|
|
584
|
-
if (value === 0 || value === null || value === void 0) {
|
|
585
|
-
buffer.writeUInt32BE(0, 0);
|
|
586
|
-
buffer.writeUInt32BE(1, 4);
|
|
587
|
-
} else if (typeof value === "number") {
|
|
588
|
-
const seconds = Math.floor(value);
|
|
589
|
-
const fraction = Math.floor((value - seconds) * 4294967296);
|
|
590
|
-
buffer.writeUInt32BE(seconds + 2208988800, 0);
|
|
591
|
-
buffer.writeUInt32BE(fraction, 4);
|
|
592
|
-
} else {
|
|
593
|
-
buffer.writeUInt32BE(0, 0);
|
|
594
|
-
buffer.writeUInt32BE(1, 4);
|
|
595
|
-
}
|
|
596
|
-
return buffer;
|
|
597
|
-
}
|
|
598
|
-
function readTimeTag(buffer, offset) {
|
|
599
|
-
if (offset + 8 > buffer.length) throw new Error("Malformed Packet: Not enough bytes for timetag");
|
|
600
|
-
const seconds = buffer.readUInt32BE(offset);
|
|
601
|
-
const fraction = buffer.readUInt32BE(offset + 4);
|
|
602
|
-
let value;
|
|
603
|
-
if (seconds === 0 && fraction === 1) value = 0;
|
|
604
|
-
else value = seconds - 2208988800 + fraction / 4294967296;
|
|
605
|
-
return {
|
|
606
|
-
value,
|
|
607
|
-
offset: offset + 8
|
|
608
|
-
};
|
|
609
|
-
}
|
|
610
|
-
function writeMidi(value) {
|
|
611
|
-
const buffer = node_buffer.Buffer.alloc(4);
|
|
612
|
-
if (node_buffer.Buffer.isBuffer(value)) {
|
|
613
|
-
if (value.length !== 4) throw new Error("MIDI message must be exactly 4 bytes");
|
|
614
|
-
value.copy(buffer);
|
|
615
|
-
} else if (typeof value === "object" && value !== null) {
|
|
616
|
-
buffer.writeUInt8(value.port || 0, 0);
|
|
617
|
-
buffer.writeUInt8(value.status || 0, 1);
|
|
618
|
-
buffer.writeUInt8(value.data1 || 0, 2);
|
|
619
|
-
buffer.writeUInt8(value.data2 || 0, 3);
|
|
620
|
-
} else throw new Error("MIDI value must be a 4-byte Buffer or object with port, status, data1, data2 properties");
|
|
621
|
-
return buffer;
|
|
622
|
-
}
|
|
623
|
-
function readMidi(buffer, offset) {
|
|
624
|
-
if (offset + 4 > buffer.length) throw new Error("Not enough bytes for MIDI message");
|
|
625
|
-
return {
|
|
626
|
-
value: buffer.subarray(offset, offset + 4),
|
|
627
|
-
offset: offset + 4
|
|
628
|
-
};
|
|
629
|
-
}
|
|
630
|
-
function encodeArgument(arg) {
|
|
631
|
-
if (typeof arg === "object" && arg.type && arg.value !== void 0) switch (arg.type) {
|
|
632
|
-
case "i":
|
|
633
|
-
case "integer": return {
|
|
634
|
-
tag: "i",
|
|
635
|
-
data: writeInt32(arg.value)
|
|
636
|
-
};
|
|
637
|
-
case "f":
|
|
638
|
-
case "float": return {
|
|
639
|
-
tag: "f",
|
|
640
|
-
data: writeFloat32(arg.value)
|
|
641
|
-
};
|
|
642
|
-
case "s":
|
|
643
|
-
case "string": return {
|
|
644
|
-
tag: "s",
|
|
645
|
-
data: node_buffer.Buffer.from(padString(arg.value))
|
|
646
|
-
};
|
|
647
|
-
case "b":
|
|
648
|
-
case "blob": return {
|
|
649
|
-
tag: "b",
|
|
650
|
-
data: writeBlob(arg.value)
|
|
651
|
-
};
|
|
652
|
-
case "d":
|
|
653
|
-
case "double": return {
|
|
654
|
-
tag: "f",
|
|
655
|
-
data: writeFloat32(arg.value)
|
|
656
|
-
};
|
|
657
|
-
case "T": return {
|
|
658
|
-
tag: "T",
|
|
659
|
-
data: node_buffer.Buffer.alloc(0)
|
|
660
|
-
};
|
|
661
|
-
case "F": return {
|
|
662
|
-
tag: "F",
|
|
663
|
-
data: node_buffer.Buffer.alloc(0)
|
|
664
|
-
};
|
|
665
|
-
case "boolean": return arg.value ? {
|
|
666
|
-
tag: "T",
|
|
667
|
-
data: node_buffer.Buffer.alloc(0)
|
|
668
|
-
} : {
|
|
669
|
-
tag: "F",
|
|
670
|
-
data: node_buffer.Buffer.alloc(0)
|
|
671
|
-
};
|
|
672
|
-
case "m":
|
|
673
|
-
case "midi": return {
|
|
674
|
-
tag: "m",
|
|
675
|
-
data: writeMidi(arg.value)
|
|
676
|
-
};
|
|
677
|
-
default: throw new Error(`Unknown argument type: ${arg.type}`);
|
|
678
|
-
}
|
|
679
|
-
switch (typeof arg) {
|
|
680
|
-
case "number": if (Number.isInteger(arg)) return {
|
|
681
|
-
tag: "i",
|
|
682
|
-
data: writeInt32(arg)
|
|
683
|
-
};
|
|
684
|
-
else return {
|
|
685
|
-
tag: "f",
|
|
686
|
-
data: writeFloat32(arg)
|
|
687
|
-
};
|
|
688
|
-
case "string": return {
|
|
689
|
-
tag: "s",
|
|
690
|
-
data: node_buffer.Buffer.from(padString(arg))
|
|
691
|
-
};
|
|
692
|
-
case "boolean": return arg ? {
|
|
693
|
-
tag: "T",
|
|
694
|
-
data: node_buffer.Buffer.alloc(0)
|
|
695
|
-
} : {
|
|
696
|
-
tag: "F",
|
|
697
|
-
data: node_buffer.Buffer.alloc(0)
|
|
698
|
-
};
|
|
699
|
-
default:
|
|
700
|
-
if (node_buffer.Buffer.isBuffer(arg)) return {
|
|
701
|
-
tag: "b",
|
|
702
|
-
data: writeBlob(arg)
|
|
703
|
-
};
|
|
704
|
-
throw new Error(`Don't know how to encode argument: ${arg}`);
|
|
705
|
-
}
|
|
706
|
-
}
|
|
707
|
-
function decodeArgument(tag, buffer, offset) {
|
|
708
|
-
switch (tag) {
|
|
709
|
-
case "i": return readInt32(buffer, offset);
|
|
710
|
-
case "f": return readFloat32(buffer, offset);
|
|
711
|
-
case "s": return readString(buffer, offset);
|
|
712
|
-
case "b": return readBlob(buffer, offset);
|
|
713
|
-
case "T": return {
|
|
714
|
-
value: true,
|
|
715
|
-
offset
|
|
716
|
-
};
|
|
717
|
-
case "F": return {
|
|
718
|
-
value: false,
|
|
719
|
-
offset
|
|
720
|
-
};
|
|
721
|
-
case "N": return {
|
|
722
|
-
value: null,
|
|
723
|
-
offset
|
|
724
|
-
};
|
|
725
|
-
case "m": return readMidi(buffer, offset);
|
|
726
|
-
default: throw new Error(`I don't understand the argument code ${tag}`);
|
|
727
|
-
}
|
|
728
|
-
}
|
|
729
|
-
/**
|
|
730
|
-
* Encode an OSC message or bundle to a Buffer.
|
|
731
|
-
*
|
|
732
|
-
* This low-level function converts OSC messages and bundles into binary format
|
|
733
|
-
* for transmission or storage. Useful for sending OSC over custom transports
|
|
734
|
-
* (WebSocket, TCP, HTTP), storing to files, or implementing custom OSC routers.
|
|
735
|
-
*
|
|
736
|
-
* @param {Object} message - OSC message or bundle object with oscType property
|
|
737
|
-
* @returns {Buffer} The encoded OSC data ready for transmission
|
|
738
|
-
*
|
|
739
|
-
* @example
|
|
740
|
-
* // Encode a message
|
|
741
|
-
* import { Message, encode } from 'node-osc';
|
|
742
|
-
*
|
|
743
|
-
* const message = new Message('/oscillator/frequency', 440);
|
|
744
|
-
* const buffer = encode(message);
|
|
745
|
-
* console.log('Encoded bytes:', buffer.length);
|
|
746
|
-
*
|
|
747
|
-
* @example
|
|
748
|
-
* // Encode a bundle
|
|
749
|
-
* import { Bundle, encode } from 'node-osc';
|
|
750
|
-
*
|
|
751
|
-
* const bundle = new Bundle(['/one', 1], ['/two', 2]);
|
|
752
|
-
* const buffer = encode(bundle);
|
|
753
|
-
*
|
|
754
|
-
* @example
|
|
755
|
-
* // Send over WebSocket
|
|
756
|
-
* const buffer = encode(message);
|
|
757
|
-
* websocket.send(buffer);
|
|
758
|
-
*/
|
|
759
|
-
function encode(message) {
|
|
760
|
-
if (message.oscType === "bundle") return encodeBundleToBuffer(message);
|
|
761
|
-
else return encodeMessageToBuffer(message);
|
|
762
|
-
}
|
|
763
|
-
function encodeMessageToBuffer(message) {
|
|
764
|
-
const address = padString(message.address);
|
|
765
|
-
const addressBuffer = node_buffer.Buffer.from(address);
|
|
766
|
-
const encodedArgs = message.args.map(encodeArgument);
|
|
767
|
-
const typeTags$1 = "," + encodedArgs.map((arg) => arg.tag).join("");
|
|
768
|
-
const typeTagsBuffer = node_buffer.Buffer.from(padString(typeTags$1));
|
|
769
|
-
const argumentBuffers = encodedArgs.map((arg) => arg.data);
|
|
770
|
-
return node_buffer.Buffer.concat([
|
|
771
|
-
addressBuffer,
|
|
772
|
-
typeTagsBuffer,
|
|
773
|
-
...argumentBuffers
|
|
774
|
-
]);
|
|
775
|
-
}
|
|
776
|
-
function encodeBundleToBuffer(bundle) {
|
|
777
|
-
const bundleString = padString("#bundle");
|
|
778
|
-
const bundleStringBuffer = node_buffer.Buffer.from(bundleString);
|
|
779
|
-
const timetagBuffer = writeTimeTag(bundle.timetag);
|
|
780
|
-
const elementBuffers = bundle.elements.map((element) => {
|
|
781
|
-
let elementBuffer;
|
|
782
|
-
if (element.oscType === "bundle") elementBuffer = encodeBundleToBuffer(element);
|
|
783
|
-
else elementBuffer = encodeMessageToBuffer(element);
|
|
784
|
-
const sizeBuffer = writeInt32(elementBuffer.length);
|
|
785
|
-
return node_buffer.Buffer.concat([sizeBuffer, elementBuffer]);
|
|
786
|
-
});
|
|
787
|
-
return node_buffer.Buffer.concat([
|
|
788
|
-
bundleStringBuffer,
|
|
789
|
-
timetagBuffer,
|
|
790
|
-
...elementBuffers
|
|
791
|
-
]);
|
|
792
|
-
}
|
|
793
|
-
/**
|
|
794
|
-
* Decode a Buffer containing OSC data into a message or bundle object.
|
|
795
|
-
*
|
|
796
|
-
* This low-level function parses binary OSC data back into JavaScript objects.
|
|
797
|
-
* Useful for receiving OSC over custom transports, reading from files,
|
|
798
|
-
* or implementing custom OSC routers.
|
|
799
|
-
*
|
|
800
|
-
* @param {Buffer} buffer - The Buffer containing OSC data
|
|
801
|
-
* @returns {Object} The decoded OSC message or bundle. Messages have
|
|
802
|
-
* {oscType: 'message', address: string, args: Array}, bundles have
|
|
803
|
-
* {oscType: 'bundle', timetag: number, elements: Array}
|
|
804
|
-
* @throws {Error} If the buffer contains malformed OSC data
|
|
805
|
-
*
|
|
806
|
-
* @example
|
|
807
|
-
* // Decode received data
|
|
808
|
-
* import { decode } from 'node-osc';
|
|
809
|
-
*
|
|
810
|
-
* const decoded = decode(buffer);
|
|
811
|
-
* if (decoded.oscType === 'message') {
|
|
812
|
-
* console.log('Address:', decoded.address);
|
|
813
|
-
* console.log('Arguments:', decoded.args);
|
|
814
|
-
* }
|
|
815
|
-
*
|
|
816
|
-
* @example
|
|
817
|
-
* // Round-trip encode/decode
|
|
818
|
-
* import { Message, encode, decode } from 'node-osc';
|
|
819
|
-
*
|
|
820
|
-
* const original = new Message('/test', 42, 'hello');
|
|
821
|
-
* const buffer = encode(original);
|
|
822
|
-
* const decoded = decode(buffer);
|
|
823
|
-
* console.log(decoded.address); // '/test'
|
|
824
|
-
*/
|
|
825
|
-
function decode(buffer) {
|
|
826
|
-
if (buffer.length >= 8 && buffer.subarray(0, 8).toString() === "#bundle\0") return decodeBundleFromBuffer(buffer);
|
|
827
|
-
else return decodeMessageFromBuffer(buffer);
|
|
828
|
-
}
|
|
829
|
-
function decodeMessageFromBuffer(buffer) {
|
|
830
|
-
let offset = 0;
|
|
831
|
-
const addressResult = readString(buffer, offset);
|
|
832
|
-
const address = addressResult.value;
|
|
833
|
-
offset = addressResult.offset;
|
|
834
|
-
const typeTagsResult = readString(buffer, offset);
|
|
835
|
-
const typeTags$1 = typeTagsResult.value;
|
|
836
|
-
offset = typeTagsResult.offset;
|
|
837
|
-
if (!typeTags$1.startsWith(",")) throw new Error("Malformed Packet");
|
|
838
|
-
const tags = typeTags$1.slice(1);
|
|
839
|
-
const args = [];
|
|
840
|
-
for (const tag of tags) {
|
|
841
|
-
const argResult = decodeArgument(tag, buffer, offset);
|
|
842
|
-
args.push({ value: argResult.value });
|
|
843
|
-
offset = argResult.offset;
|
|
844
|
-
}
|
|
845
|
-
return {
|
|
846
|
-
oscType: "message",
|
|
847
|
-
address,
|
|
848
|
-
args
|
|
849
|
-
};
|
|
850
|
-
}
|
|
851
|
-
function decodeBundleFromBuffer(buffer) {
|
|
852
|
-
let offset = 8;
|
|
853
|
-
const timetagResult = readTimeTag(buffer, offset);
|
|
854
|
-
const timetag = timetagResult.value;
|
|
855
|
-
offset = timetagResult.offset;
|
|
856
|
-
const elements = [];
|
|
857
|
-
while (offset < buffer.length) {
|
|
858
|
-
const sizeResult = readInt32(buffer, offset);
|
|
859
|
-
const size = sizeResult.value;
|
|
860
|
-
offset = sizeResult.offset;
|
|
861
|
-
if (size <= 0 || offset + size > buffer.length) throw new Error("Malformed Packet");
|
|
862
|
-
const element = decode(buffer.subarray(offset, offset + size));
|
|
863
|
-
elements.push(element);
|
|
864
|
-
offset += size;
|
|
865
|
-
}
|
|
866
|
-
return {
|
|
867
|
-
oscType: "bundle",
|
|
868
|
-
timetag,
|
|
869
|
-
elements
|
|
870
|
-
};
|
|
871
|
-
}
|
|
872
|
-
|
|
873
|
-
//#endregion
|
|
874
|
-
//#region src/infrastructure/mappers/OscCodec.ts
|
|
875
|
-
/**
|
|
876
|
-
* Handles encoding and decoding of X32 OSC messages.
|
|
877
|
-
*/
|
|
878
|
-
var OscCodec = class {
|
|
879
|
-
constructor(schemaRegistry) {
|
|
880
|
-
this.schemaRegistry = schemaRegistry;
|
|
881
|
-
}
|
|
882
|
-
/**
|
|
883
|
-
* Decodes a binary OSC message into a packet object.
|
|
884
|
-
* @param msg - Raw UDP buffer.
|
|
885
|
-
* @returns Decoded OscPacket.
|
|
886
|
-
*/
|
|
887
|
-
decode(msg) {
|
|
888
|
-
return decode(msg);
|
|
889
|
-
}
|
|
890
|
-
/**
|
|
891
|
-
* Encodes an address and arguments into a binary OSC message.
|
|
892
|
-
* @param address - OSC address pattern.
|
|
893
|
-
* @param args - Array of arguments.
|
|
894
|
-
* @returns Binary buffer.
|
|
895
|
-
*/
|
|
896
|
-
encode(address, args) {
|
|
897
|
-
return encode(this.createMessage(address, args));
|
|
898
|
-
}
|
|
899
|
-
/**
|
|
900
|
-
* Creates a typed node-osc Message based on X32 schema.
|
|
901
|
-
* @param address - Target address.
|
|
902
|
-
* @param args - Untyped arguments.
|
|
903
|
-
* @returns Typed Message.
|
|
904
|
-
*/
|
|
905
|
-
createMessage(address, args) {
|
|
906
|
-
return new Message_default(address, ...args.map((arg) => {
|
|
907
|
-
if (typeof arg === "object" && arg !== null && "type" in arg && "value" in arg) return arg;
|
|
908
|
-
if (Buffer.isBuffer(arg)) return arg;
|
|
909
|
-
const node = this.schemaRegistry.getNode(address);
|
|
910
|
-
if (node) {
|
|
911
|
-
if (node.type === "f" && typeof arg === "number") return {
|
|
912
|
-
type: "f",
|
|
913
|
-
value: arg
|
|
914
|
-
};
|
|
915
|
-
if (node.type === "i" && typeof arg === "number") return {
|
|
916
|
-
type: "i",
|
|
917
|
-
value: Math.round(arg)
|
|
918
|
-
};
|
|
919
|
-
if (node.type === "s" && typeof arg === "string") return {
|
|
920
|
-
type: "s",
|
|
921
|
-
value: arg
|
|
922
|
-
};
|
|
923
|
-
}
|
|
924
|
-
return arg;
|
|
925
|
-
}));
|
|
926
|
-
}
|
|
927
|
-
};
|
|
928
|
-
|
|
929
|
-
//#endregion
|
|
930
11
|
//#region src/presentation/cli/server.ts
|
|
931
12
|
const loadEnv = () => {
|
|
932
13
|
try {
|
|
@@ -983,10 +64,10 @@ const parseArgs = (argv) => {
|
|
|
983
64
|
const bootstrap = async () => {
|
|
984
65
|
loadEnv();
|
|
985
66
|
const { PORT, HOST } = parseArgs(process.argv);
|
|
986
|
-
const logger =
|
|
987
|
-
logger.setLevel(
|
|
988
|
-
const schemaRegistry = new SchemaRegistry(new SchemaFactory());
|
|
989
|
-
const service = new
|
|
67
|
+
const logger = require_SchemaRegistry.ConsoleLogger.getInstance();
|
|
68
|
+
logger.setLevel(require_SchemaRegistry.LogLevel.DEBUG);
|
|
69
|
+
const schemaRegistry = new require_SchemaRegistry.SchemaRegistry(new require_SchemaRegistry.SchemaFactory());
|
|
70
|
+
const service = new require_SchemaRegistry.SimulationService(new require_SchemaRegistry.UdpNetworkGateway(logger, new require_SchemaRegistry.OscCodec(schemaRegistry)), logger, new require_SchemaRegistry.InMemoryStateRepository(logger, schemaRegistry), schemaRegistry, PORT, HOST);
|
|
990
71
|
try {
|
|
991
72
|
await service.start();
|
|
992
73
|
console.log(`
|