@djodjonx/x32-simulator 0.0.3 → 0.0.5
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 +9 -0
- package/README.md +22 -0
- package/dist/server.cjs +4 -5
- package/dist/server.d.cts +1 -10
- package/dist/server.d.mts +1 -10
- package/dist/server.mjs +5 -3
- package/package.json +5 -1
- package/.commitlintrc.json +0 -3
- package/.github/workflows/publish.yml +0 -38
- package/.husky/commit-msg +0 -1
- package/.husky/pre-commit +0 -1
- package/.oxlintrc.json +0 -56
- package/INSTALL.md +0 -107
- package/docs/OSC-Communication.md +0 -184
- package/docs/X32-INTERNAL.md +0 -262
- package/docs/X32-OSC.pdf +0 -0
- package/docs/behringer-x32-x32-osc-remote-protocol-en-44463.pdf +0 -0
- package/src/application/use-cases/BroadcastUpdatesUseCase.ts +0 -120
- package/src/application/use-cases/ManageSessionsUseCase.ts +0 -9
- package/src/application/use-cases/ProcessPacketUseCase.ts +0 -26
- package/src/application/use-cases/SimulationService.ts +0 -146
- package/src/domain/entities/SubscriptionManager.ts +0 -126
- package/src/domain/entities/X32State.ts +0 -78
- package/src/domain/models/MeterConfig.ts +0 -22
- package/src/domain/models/MeterData.ts +0 -59
- package/src/domain/models/OscMessage.ts +0 -93
- package/src/domain/models/X32Address.ts +0 -72
- package/src/domain/models/X32Node.ts +0 -43
- package/src/domain/models/types.ts +0 -86
- package/src/domain/ports/ILogger.ts +0 -27
- package/src/domain/ports/INetworkGateway.ts +0 -8
- package/src/domain/ports/IStateRepository.ts +0 -16
- package/src/domain/services/MeterService.ts +0 -46
- package/src/domain/services/OscMessageHandler.ts +0 -88
- package/src/domain/services/SchemaFactory.ts +0 -308
- package/src/domain/services/SchemaRegistry.ts +0 -67
- package/src/domain/services/StaticResponseService.ts +0 -52
- package/src/domain/services/strategies/BatchStrategy.ts +0 -74
- package/src/domain/services/strategies/MeterStrategy.ts +0 -45
- package/src/domain/services/strategies/NodeDiscoveryStrategy.ts +0 -36
- package/src/domain/services/strategies/OscCommandStrategy.ts +0 -22
- package/src/domain/services/strategies/StateAccessStrategy.ts +0 -71
- package/src/domain/services/strategies/StaticResponseStrategy.ts +0 -42
- package/src/domain/services/strategies/SubscriptionStrategy.ts +0 -56
- package/src/infrastructure/mappers/OscCodec.ts +0 -54
- package/src/infrastructure/repositories/InMemoryStateRepository.ts +0 -37
- package/src/infrastructure/services/ConsoleLogger.ts +0 -177
- package/src/infrastructure/services/UdpNetworkGateway.ts +0 -100
- package/src/presentation/cli/server.ts +0 -194
- package/src/presentation/library/library.ts +0 -139
- package/tests/application/use-cases/BroadcastUpdatesUseCase.test.ts +0 -104
- package/tests/application/use-cases/ManageSessionsUseCase.test.ts +0 -12
- package/tests/application/use-cases/ProcessPacketUseCase.test.ts +0 -49
- package/tests/application/use-cases/SimulationService.test.ts +0 -77
- package/tests/domain/entities/SubscriptionManager.test.ts +0 -50
- package/tests/domain/entities/X32State.test.ts +0 -52
- package/tests/domain/models/MeterData.test.ts +0 -23
- package/tests/domain/models/OscMessage.test.ts +0 -38
- package/tests/domain/models/X32Address.test.ts +0 -30
- package/tests/domain/models/X32Node.test.ts +0 -30
- package/tests/domain/services/MeterService.test.ts +0 -27
- package/tests/domain/services/OscMessageHandler.test.ts +0 -51
- package/tests/domain/services/SchemaRegistry.test.ts +0 -47
- package/tests/domain/services/StaticResponseService.test.ts +0 -15
- package/tests/domain/services/strategies/BatchStrategy.test.ts +0 -41
- package/tests/domain/services/strategies/MeterStrategy.test.ts +0 -19
- package/tests/domain/services/strategies/NodeDiscoveryStrategy.test.ts +0 -22
- package/tests/domain/services/strategies/StateAccessStrategy.test.ts +0 -49
- package/tests/domain/services/strategies/StaticResponseStrategy.test.ts +0 -15
- package/tests/domain/services/strategies/SubscriptionStrategy.test.ts +0 -45
- package/tests/infrastructure/mappers/OscCodec.test.ts +0 -41
- package/tests/infrastructure/repositories/InMemoryStateRepository.test.ts +0 -29
- package/tests/infrastructure/services/ConsoleLogger.test.ts +0 -74
- package/tests/infrastructure/services/UdpNetworkGateway.test.ts +0 -61
- package/tests/presentation/cli/server.test.ts +0 -178
- package/tests/presentation/library/library.test.ts +0 -13
- package/tsconfig.json +0 -21
- package/tsdown.config.ts +0 -15
- package/vitest.config.ts +0 -9
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
### [0.0.5](https://github.com/djodjonx/x32-simulator/compare/v0.0.4...v0.0.5) (2026-01-10)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* **cli:** fix npx execution by adding dedicated bin entry point ([1b0de49](https://github.com/djodjonx/x32-simulator/commit/1b0de498b2706c7c8caf86488c8545742344b970))
|
|
11
|
+
|
|
12
|
+
### [0.0.4](https://github.com/djodjonx/x32-simulator/compare/v0.0.3...v0.0.4) (2026-01-08)
|
|
13
|
+
|
|
5
14
|
### [0.0.3](https://github.com/djodjonx/x32-simulator/compare/v0.0.2...v0.0.3) (2026-01-08)
|
|
6
15
|
|
|
7
16
|
|
package/README.md
CHANGED
|
@@ -160,6 +160,28 @@ The simulator covers a vast majority of the X32 OSC command set:
|
|
|
160
160
|
|
|
161
161
|
---
|
|
162
162
|
|
|
163
|
+
## 🧪 Testing Example (E2E)
|
|
164
|
+
|
|
165
|
+
The simulator is ideal for testing broadcast behavior and multi-client synchronization. When one client changes a parameter, the simulator automatically broadcasts that update to all other clients subscribed via `/xremote`.
|
|
166
|
+
|
|
167
|
+
You can find a complete, runnable example of this in [examples/dual-client-e2e.ts](./examples/dual-client-e2e.ts).
|
|
168
|
+
|
|
169
|
+
### Multi-Client Sync Test Snippet
|
|
170
|
+
|
|
171
|
+
```typescript
|
|
172
|
+
// Client A and Client B both subscribe to /xremote
|
|
173
|
+
clientA.send('/xremote');
|
|
174
|
+
clientB.send('/xremote');
|
|
175
|
+
|
|
176
|
+
// Client A changes a fader
|
|
177
|
+
clientA.send('/ch/01/mix/fader', 0.85);
|
|
178
|
+
|
|
179
|
+
// Result: BOTH Client A and Client B receive the update from the simulator
|
|
180
|
+
// This ensures your UI stays in sync across multiple devices.
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
163
185
|
## 🤝 Contributing
|
|
164
186
|
|
|
165
187
|
We welcome contributions! Please see [INSTALL.md](./INSTALL.md) for development instructions.
|
package/dist/server.cjs
CHANGED
|
@@ -6,7 +6,6 @@ let node_fs = require("node:fs");
|
|
|
6
6
|
node_fs = require_SchemaRegistry.__toESM(node_fs);
|
|
7
7
|
let node_path = require("node:path");
|
|
8
8
|
node_path = require_SchemaRegistry.__toESM(node_path);
|
|
9
|
-
let node_url = require("node:url");
|
|
10
9
|
|
|
11
10
|
//#region src/presentation/cli/server.ts
|
|
12
11
|
const loadEnv = () => {
|
|
@@ -133,9 +132,9 @@ const bootstrap = async () => {
|
|
|
133
132
|
process.exit(0);
|
|
134
133
|
});
|
|
135
134
|
};
|
|
136
|
-
if (process.argv[1] === (0, node_url.fileURLToPath)(require("url").pathToFileURL(__filename).href)) bootstrap();
|
|
137
135
|
|
|
138
136
|
//#endregion
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
137
|
+
//#region src/presentation/cli/bin.ts
|
|
138
|
+
bootstrap();
|
|
139
|
+
|
|
140
|
+
//#endregion
|
package/dist/server.d.cts
CHANGED
|
@@ -1,10 +1 @@
|
|
|
1
|
-
|
|
2
|
-
//#region src/presentation/cli/server.d.ts
|
|
3
|
-
declare const loadEnv: () => void;
|
|
4
|
-
declare const parseArgs: (argv: string[]) => {
|
|
5
|
-
PORT: number;
|
|
6
|
-
HOST: string;
|
|
7
|
-
};
|
|
8
|
-
declare const bootstrap: () => Promise<void>;
|
|
9
|
-
//#endregion
|
|
10
|
-
export { bootstrap, loadEnv, parseArgs };
|
|
1
|
+
export { };
|
package/dist/server.d.mts
CHANGED
|
@@ -1,10 +1 @@
|
|
|
1
|
-
|
|
2
|
-
//#region src/presentation/cli/server.d.ts
|
|
3
|
-
declare const loadEnv: () => void;
|
|
4
|
-
declare const parseArgs: (argv: string[]) => {
|
|
5
|
-
PORT: number;
|
|
6
|
-
HOST: string;
|
|
7
|
-
};
|
|
8
|
-
declare const bootstrap: () => Promise<void>;
|
|
9
|
-
//#endregion
|
|
10
|
-
export { bootstrap, loadEnv, parseArgs };
|
|
1
|
+
export { };
|
package/dist/server.mjs
CHANGED
|
@@ -3,7 +3,6 @@ import { a as ConsoleLogger, i as UdpNetworkGateway, n as SchemaFactory, o as Lo
|
|
|
3
3
|
import * as readline from "node:readline";
|
|
4
4
|
import * as fs from "node:fs";
|
|
5
5
|
import * as path from "node:path";
|
|
6
|
-
import { fileURLToPath } from "node:url";
|
|
7
6
|
|
|
8
7
|
//#region src/presentation/cli/server.ts
|
|
9
8
|
const loadEnv = () => {
|
|
@@ -130,7 +129,10 @@ const bootstrap = async () => {
|
|
|
130
129
|
process.exit(0);
|
|
131
130
|
});
|
|
132
131
|
};
|
|
133
|
-
if (process.argv[1] === fileURLToPath(import.meta.url)) bootstrap();
|
|
134
132
|
|
|
135
133
|
//#endregion
|
|
136
|
-
|
|
134
|
+
//#region src/presentation/cli/bin.ts
|
|
135
|
+
bootstrap();
|
|
136
|
+
|
|
137
|
+
//#endregion
|
|
138
|
+
export { };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@djodjonx/x32-simulator",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"description": "X32 Simulator",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -21,6 +21,10 @@
|
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
23
|
},
|
|
24
|
+
"files": [
|
|
25
|
+
"dist",
|
|
26
|
+
"CHANGELOG.md"
|
|
27
|
+
],
|
|
24
28
|
"scripts": {
|
|
25
29
|
"dev": "tsdown --watch",
|
|
26
30
|
"build": "tsdown",
|
package/.commitlintrc.json
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
name: Publish Package to npmjs
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
tags:
|
|
6
|
-
- 'v*'
|
|
7
|
-
|
|
8
|
-
permissions:
|
|
9
|
-
id-token: write # Required for OIDC
|
|
10
|
-
contents: write # Required to create GitHub Releases
|
|
11
|
-
|
|
12
|
-
jobs:
|
|
13
|
-
publish:
|
|
14
|
-
runs-on: ubuntu-latest
|
|
15
|
-
steps:
|
|
16
|
-
- uses: actions/checkout@v4
|
|
17
|
-
|
|
18
|
-
- uses: actions/setup-node@v4
|
|
19
|
-
with:
|
|
20
|
-
node-version: '20.x'
|
|
21
|
-
registry-url: 'https://registry.npmjs.org'
|
|
22
|
-
|
|
23
|
-
# Ensure npm is up-to-date
|
|
24
|
-
- name: Update npm
|
|
25
|
-
run: npm install -g npm@latest
|
|
26
|
-
|
|
27
|
-
- run: npm ci
|
|
28
|
-
- run: npm run build
|
|
29
|
-
- run: npm test
|
|
30
|
-
- run: npm publish --provenance --access public
|
|
31
|
-
env:
|
|
32
|
-
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
33
|
-
|
|
34
|
-
- name: Create GitHub Release
|
|
35
|
-
uses: softprops/action-gh-release@v2
|
|
36
|
-
with:
|
|
37
|
-
generate_release_notes: true
|
|
38
|
-
make_latest: true
|
package/.husky/commit-msg
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
npx --no -- commitlint --edit $1
|
package/.husky/pre-commit
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
npx lint-staged
|
package/.oxlintrc.json
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "./node_modules/oxlint/configuration_schema.json",
|
|
3
|
-
"plugins": [
|
|
4
|
-
"typescript",
|
|
5
|
-
"vitest",
|
|
6
|
-
"unicorn",
|
|
7
|
-
"oxc",
|
|
8
|
-
"import",
|
|
9
|
-
"jsdoc"
|
|
10
|
-
],
|
|
11
|
-
"categories": {
|
|
12
|
-
"correctness": "error",
|
|
13
|
-
"suspicious": "error",
|
|
14
|
-
"pedantic": "off",
|
|
15
|
-
"style": "off",
|
|
16
|
-
"perf": "warn"
|
|
17
|
-
},
|
|
18
|
-
"rules": {
|
|
19
|
-
"import/prefer-default-export": "off",
|
|
20
|
-
"import/no-named-export": "off",
|
|
21
|
-
"unicorn/filename-case": "off",
|
|
22
|
-
"eslint/no-magic-numbers": "off",
|
|
23
|
-
"eslint/max-lines-per-function": "off",
|
|
24
|
-
"eslint/max-statements": "off",
|
|
25
|
-
"eslint/max-params": "off",
|
|
26
|
-
"eslint/max-lines": "off",
|
|
27
|
-
"unicorn/no-zero-fractions": "off",
|
|
28
|
-
"eslint/sort-keys": "off",
|
|
29
|
-
"eslint/sort-imports": "off",
|
|
30
|
-
"typescript/consistent-type-imports": "off",
|
|
31
|
-
"jsdoc/require-param-type": "off",
|
|
32
|
-
"jsdoc/require-returns-type": "off",
|
|
33
|
-
"jsdoc/require-returns": "off",
|
|
34
|
-
"typescript/no-inferrable-types": "off",
|
|
35
|
-
"unicorn/prefer-top-level-await": "off",
|
|
36
|
-
"unicorn/no-null": "off",
|
|
37
|
-
"unicorn/prevent-abbreviations": "off",
|
|
38
|
-
"eslint/id-length": "off"
|
|
39
|
-
},
|
|
40
|
-
"overrides": [
|
|
41
|
-
{
|
|
42
|
-
"files": ["tests/**/*.ts"],
|
|
43
|
-
"rules": {
|
|
44
|
-
"eslint/no-magic-numbers": "off"
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
],
|
|
48
|
-
"settings": {
|
|
49
|
-
"vitest": {
|
|
50
|
-
"typecheck": true
|
|
51
|
-
}
|
|
52
|
-
},
|
|
53
|
-
"env": {
|
|
54
|
-
"builtin": true
|
|
55
|
-
}
|
|
56
|
-
}
|
package/INSTALL.md
DELETED
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
# Development Guide
|
|
2
|
-
|
|
3
|
-
This guide is for developers who want to contribute to the `x32-simulator` project or build it from source.
|
|
4
|
-
|
|
5
|
-
## 📋 Prerequisites
|
|
6
|
-
|
|
7
|
-
* **Node.js**: Version 20 or higher is required.
|
|
8
|
-
* Verify with `node -v`
|
|
9
|
-
* **npm**: Comes bundled with Node.js.
|
|
10
|
-
|
|
11
|
-
## 🛠️ Setup
|
|
12
|
-
|
|
13
|
-
1. **Clone the repository:**
|
|
14
|
-
```bash
|
|
15
|
-
git clone https://github.com/djodjonx/x32-simulator.git
|
|
16
|
-
cd x32-simulator
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
2. **Install dependencies:**
|
|
20
|
-
We use `npm ci` for reliable builds based on `package-lock.json`.
|
|
21
|
-
```bash
|
|
22
|
-
npm ci
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
## 💻 Development Workflow
|
|
26
|
-
|
|
27
|
-
### Running in Watch Mode
|
|
28
|
-
For rapid development, use the dev script. It re-bundles the project on file changes.
|
|
29
|
-
```bash
|
|
30
|
-
npm run dev
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
### Running Tests
|
|
34
|
-
We use **Vitest** for testing.
|
|
35
|
-
|
|
36
|
-
* **Run all tests:**
|
|
37
|
-
```bash
|
|
38
|
-
npm test
|
|
39
|
-
```
|
|
40
|
-
* **Run with coverage:**
|
|
41
|
-
```bash
|
|
42
|
-
npm run test:coverage
|
|
43
|
-
```
|
|
44
|
-
* **Watch mode (TDD):**
|
|
45
|
-
```bash
|
|
46
|
-
npm run test:watch
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
### Code Quality
|
|
50
|
-
Ensure your code meets the project standards before committing.
|
|
51
|
-
|
|
52
|
-
* **Linting (Oxlint):**
|
|
53
|
-
```bash
|
|
54
|
-
npm run lint
|
|
55
|
-
```
|
|
56
|
-
* **Type Checking:**
|
|
57
|
-
```bash
|
|
58
|
-
npm run type-check
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
## 🏗️ Building
|
|
62
|
-
|
|
63
|
-
To build the project for production distribution:
|
|
64
|
-
|
|
65
|
-
```bash
|
|
66
|
-
npm run build
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
This uses `tsdown` to bundle the code into the `dist/` directory:
|
|
70
|
-
* `dist/server.mjs`: The executable CLI.
|
|
71
|
-
* `dist/index.mjs` / `.cjs`: The library entry points.
|
|
72
|
-
|
|
73
|
-
## 📂 Project Structure
|
|
74
|
-
|
|
75
|
-
The project follows a **Clean Architecture** / **Hexagonal** structure:
|
|
76
|
-
|
|
77
|
-
```
|
|
78
|
-
src/
|
|
79
|
-
├── application/ # Use Cases (Business Logic orchestration)
|
|
80
|
-
├── domain/ # Core Business Logic (Entities, Models, Ports)
|
|
81
|
-
├── infrastructure/ # External adapters (UDP, Logging, Repositories)
|
|
82
|
-
└── presentation/ # Entry points
|
|
83
|
-
├── cli/ # CLI Server implementation
|
|
84
|
-
└── library/ # Library exports
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
## 🚀 Releasing
|
|
88
|
-
|
|
89
|
-
We use `standard-version` to automate versioning and changelog generation.
|
|
90
|
-
|
|
91
|
-
1. **Create a release:**
|
|
92
|
-
```bash
|
|
93
|
-
npm run release
|
|
94
|
-
```
|
|
95
|
-
This command will:
|
|
96
|
-
* Bump the version in `package.json`.
|
|
97
|
-
* Update `CHANGELOG.md`.
|
|
98
|
-
* Commit these changes.
|
|
99
|
-
* Create a git tag (e.g., `v1.1.0`).
|
|
100
|
-
|
|
101
|
-
2. **Push changes:**
|
|
102
|
-
```bash
|
|
103
|
-
git push --follow-tags
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
3. **Publish:**
|
|
107
|
-
The GitHub Action workflow will automatically detect the new tag, build the project, and publish it to NPM.
|
|
@@ -1,184 +0,0 @@
|
|
|
1
|
-
# Protocol Analysis and Implementation Strategies regarding the Behringer X32 Digital Mixing Console Ecosystem
|
|
2
|
-
|
|
3
|
-
## 1. Introduction to Networked Audio Control Systems
|
|
4
|
-
The transition from analog to digital mixing consoles has fundamentally altered the landscape of live sound reinforcement, studio recording, and broadcast audio. Among the myriad devices that have driven this paradigm shift, the **Behringer X32** and **Midas M32** families of digital consoles stand as preeminent examples of commercial success and technical ubiquity.
|
|
5
|
-
|
|
6
|
-
A central feature of these ecosystems is their capability for remote control and telemetry via standard network protocols. Unlike their analog predecessors, which relied on voltage-controlled amplifiers and physical patching, modern digital consoles operate as sophisticated computers that process audio signals via **Digital Signal Processing (DSP)** algorithms. This architecture allows the control surface—the physical faders, knobs, and buttons—to be decoupled from the audio processing engine. Consequently, the manipulation of audio parameters can be achieved not only through the physical interface but also via external software applications and automated scripts communicating over a Local Area Network (LAN).
|
|
7
|
-
|
|
8
|
-
The mechanism governing this external communication is the **Open Sound Control (OSC)** protocol. Optimized for modern networking technology, OSC provides a flexible, URL-style symbolic naming scheme (e.g., `/ch/01/mix/fader`) that is significantly more human-readable and granular than the legacy MIDI standard.
|
|
9
|
-
|
|
10
|
-
For the X32 ecosystem, this protocol facilitates the operation of:
|
|
11
|
-
* The official **X32-Edit** software (PC/Mac/Linux)
|
|
12
|
-
* The **X32-Mix** app (iPad)
|
|
13
|
-
* The **Mixing Station** app (Android)
|
|
14
|
-
* A host of third-party integration tools
|
|
15
|
-
|
|
16
|
-
---
|
|
17
|
-
|
|
18
|
-
## 2. The Documentation Landscape
|
|
19
|
-
A critical challenge for developers and integrators working with the X32 platform is the scarcity and incompleteness of official documentation provided by the manufacturer, Music Tribe. While Behringer released a preliminary OSC document in late 2012 (Version 1.01), it has not been officially updated to reflect substantial feature additions (Firmware 2.x, 3.x, and 4.x), such as new effects engines, extended routing options, and the "User" layer.
|
|
20
|
-
|
|
21
|
-
### 2.1 The "Unofficial" Standard
|
|
22
|
-
To bridge this information gap, the user community—spearheaded by researcher and developer Patrick-Gilles Maillot—undertook a massive effort to reverse-engineer the complete protocol. The resulting document, **"Unofficial X32/M32 OSC Remote Protocol,"** is widely regarded as the definitive technical reference.
|
|
23
|
-
|
|
24
|
-
> **Note:** This documentation distinguishes itself by detailing data types, value ranges, and context-dependent behaviors of the network stack, such as the critical distinction between the `/subscribe` command and the `/xremote` command.
|
|
25
|
-
|
|
26
|
-
The documentation is maintained in a live repository, covering nuanced differences between hardware models (X32 Rack, Core, Compact) which share a common firmware core but report different hardware identifiers.
|
|
27
|
-
|
|
28
|
-
---
|
|
29
|
-
|
|
30
|
-
## 3. Network Transport and Architecture
|
|
31
|
-
The foundation of the X32’s remote control capability is the **User Datagram Protocol (UDP)**.
|
|
32
|
-
|
|
33
|
-
### 3.1 UDP vs. TCP in Audio Control
|
|
34
|
-
TCP is connection-oriented, guaranteeing packet delivery via handshakes and acknowledgments (ACKs). In live mixing, however, **latency is the enemy**. If a packet containing a fader move is dropped, pausing the stream for retransmission is undesirable. The X32 network stack is therefore **stateless** and "fire-and-forget." It listens for incoming UDP datagrams, processes valid OSC messages, and sends replies to the source address without maintaining a persistent socket connection.
|
|
35
|
-
|
|
36
|
-
### 3.2 Port Assignments and Addressing
|
|
37
|
-
* **Target Port:** UDP Port **10023** (Hard-coded).
|
|
38
|
-
* **Source Port:** Ephemeral (chosen by the client OS).
|
|
39
|
-
|
|
40
|
-
**Critical Implementation Detail:** The X32 sends replies back to the *source IP* and *source port* of the incoming packet. Developers must bind to a specific local UDP socket for both sending and receiving. If the OS assigns a new port for the next message, the reply from the X32 will be sent to the original port and potentially discarded.
|
|
41
|
-
|
|
42
|
-
### 3.3 Endianness and Data Representation
|
|
43
|
-
The OSC specification 1.0 mandates Big-Endian (network byte order).
|
|
44
|
-
* **Integers:** 32-bit signed ($i$)
|
|
45
|
-
* **Floats:** 32-bit IEEE 754 ($f$)
|
|
46
|
-
* **Strings:** Null-terminated ASCII ($s$)
|
|
47
|
-
* **Blobs:** Int32 size count + binary data ($b$)
|
|
48
|
-
|
|
49
|
-
**The Deviation:** While OSC headers are Big-Endian, the internal content of binary blobs returned by the `/meters` command is encoded in **Little-Endian** format, reflecting the internal architecture of the DSP (likely Analog Devices SHARC).
|
|
50
|
-
|
|
51
|
-
---
|
|
52
|
-
|
|
53
|
-
## 4. Device Discovery and Enumeration
|
|
54
|
-
Applications utilize the `/xinfo` mechanism to locate the console, as IP addresses may be dynamic (DHCP).
|
|
55
|
-
|
|
56
|
-
### 4.1 The `/xinfo` Handshake
|
|
57
|
-
1. **Query:** Client sends `/xinfo` (Broadcast or Unicast) on port 10023.
|
|
58
|
-
2. **Response:** X32 replies with ` /xinfo ,ssss`.
|
|
59
|
-
|
|
60
|
-
**Response Arguments:**
|
|
61
|
-
1. **IP Address:** The console's self-reported IP (e.g., `192.168.1.50`).
|
|
62
|
-
2. **Console Name:** User-defined network name (e.g., `X32-FOH`).
|
|
63
|
-
3. **Model Identifier:** Hardware ID used to customize UI (e.g., `X32`, `X32RACK`, `X32CORE`).
|
|
64
|
-
4. **Firmware Version:** Critical for version control and compatibility checks (e.g., `4.06`).
|
|
65
|
-
|
|
66
|
-
### 4.2 Application Implementation
|
|
67
|
-
A typical implementation creates a UDP socket with `SO_BROADCAST` permissions, sends the `/xinfo` packet, and employs a short timeout (e.g., 2 seconds) to listen for the "business card" response.
|
|
68
|
-
|
|
69
|
-
---
|
|
70
|
-
|
|
71
|
-
## 5. Session Persistence and State Synchronization
|
|
72
|
-
Since UDP is stateless, the X32 does not inherently know if a client is "connected." To support real-time animation of faders, the protocol implements a subscription-based heartbeat.
|
|
73
|
-
|
|
74
|
-
### 5.1 The `/xremote` Command
|
|
75
|
-
* **Function:** Acts as a subscription request.
|
|
76
|
-
* **Behavior:** The X32 adds the sender to an internal list of "active remote clients" and mirrors **every** parameter change on the console to that client.
|
|
77
|
-
* **Timeout:** A watchdog timer (approx. 10 seconds) purges clients if no further command is received.
|
|
78
|
-
* **Keep-Alive:** Clients must resend `/xremote` in a background loop (every 7–9 seconds) to reset the watchdog.
|
|
79
|
-
|
|
80
|
-
### 5.2 `/xremote` vs. `/subscribe`
|
|
81
|
-
* **`/xremote`**: The "firehose" command. Requests *all* console changes. Efficient for full desktop editors.
|
|
82
|
-
* **`/subscribe`**: Requests updates for specific addresses or ranges. Efficient for mobile apps focusing on specific features.
|
|
83
|
-
|
|
84
|
-
For intercepting active channel info, `/xremote` is superior as it guarantees any selection change is broadcast without a priori knowledge.
|
|
85
|
-
|
|
86
|
-
---
|
|
87
|
-
|
|
88
|
-
## 6. Intercepting Active Channel Information
|
|
89
|
-
"Active Channel" refers to the channel currently selected by the **SEL** button on the hardware surface.
|
|
90
|
-
|
|
91
|
-
### 6.1 The `/-stat/selidx` Command
|
|
92
|
-
The X32 broadcasts the selection state via:
|
|
93
|
-
* **OSC Path:** `/-stat/selidx`
|
|
94
|
-
* **Data Type:** 32-bit Integer (`,i`)
|
|
95
|
-
* **Value Range:** 0 to 71
|
|
96
|
-
|
|
97
|
-
### 6.2 Decoding the Selection Index
|
|
98
|
-
The integer corresponds to a fixed map of channel strips:
|
|
99
|
-
|
|
100
|
-
| Index Range (Int) | Channel Type | Specific Channels | OSC Address Path |
|
|
101
|
-
| :--- | :--- | :--- | :--- |
|
|
102
|
-
| **0 – 31** | Input Channels | Channels 1 – 32 | `/ch/01` ... `/ch/32` |
|
|
103
|
-
| **32 – 39** | Aux Inputs | Aux 1 – 6, USB L/R | `/auxin/01` ... |
|
|
104
|
-
| **40 – 47** | FX Returns | FX 1L, 1R ... 4R | `/fxrtn/01` ... |
|
|
105
|
-
| **48 – 63** | Mix Buses | Bus 1 – 16 | `/bus/01` ... |
|
|
106
|
-
| **64 – 69** | Matrix Outputs | Matrix 1 – 6 | `/mtx/01` ... |
|
|
107
|
-
| **70** | Main LR | Stereo Master Bus | `/main/st` |
|
|
108
|
-
| **71** | Mono/Center | Mono Bus | `/main/m` |
|
|
109
|
-
|
|
110
|
-
> **Important:** DCAs are absent from this range as they are control groups, not processing paths with full channel strips.
|
|
111
|
-
|
|
112
|
-
### 6.3 Implementation of Interception
|
|
113
|
-
To intercept this data, a custom script acts as a parallel client:
|
|
114
|
-
1. **Subscription:** Send `/xremote` to register for updates.
|
|
115
|
-
2. **Listening:** Listen on the bound UDP port.
|
|
116
|
-
3. **Parsing:** When `/-stat/selidx` is received, parse the integer.
|
|
117
|
-
4. **Logic:** Map the integer (e.g., `0`) to the channel (`Channel 1`).
|
|
118
|
-
|
|
119
|
-
### 6.4 The `/-prefs/autosel` Variable
|
|
120
|
-
* **autosel ON:** Touching a fader triggers `/-stat/selidx`.
|
|
121
|
-
* **autosel OFF:** Only pressing the "Select" button triggers the message.
|
|
122
|
-
|
|
123
|
-
---
|
|
124
|
-
|
|
125
|
-
## 7. Information About Channels: Command Hierarchy
|
|
126
|
-
The root address for inputs is `/ch/` using a two-digit string index (`01`–`32`).
|
|
127
|
-
|
|
128
|
-
### 7.1 Functional Blocks
|
|
129
|
-
|
|
130
|
-
**Configuration (`/config`)**
|
|
131
|
-
* `/ch/{n}/config/name`: String (User name)
|
|
132
|
-
* `/ch/{n}/config/icon`: Integer (Icon index)
|
|
133
|
-
* `/ch/{n}/config/color`: Integer (Color index)
|
|
134
|
-
|
|
135
|
-
**Preamp (`/preamp`)**
|
|
136
|
-
* `/ch/{n}/preamp/gain`: Float (0.0–1.0 mapping to -12dB to +60dB)
|
|
137
|
-
* `/ch/{n}/preamp/rtnsw`: Integer (48V Phantom Power, 0/1)
|
|
138
|
-
|
|
139
|
-
**Gate & Dynamics (`/gate`, `/dyn`)**
|
|
140
|
-
* `/ch/{n}/gate/on`: Integer (Active/Bypass)
|
|
141
|
-
* `/ch/{n}/dyn/ratio`: Enum (Compression ratio)
|
|
142
|
-
|
|
143
|
-
**Equalizer (`/eq`)**
|
|
144
|
-
* `/ch/{n}/eq/{b}/f`: Float (Frequency, log mapping 20Hz–20kHz)
|
|
145
|
-
* `/ch/{n}/eq/{b}/g`: Float (Gain, -15dB to +15dB)
|
|
146
|
-
|
|
147
|
-
**Mix & Fader (`/mix`)**
|
|
148
|
-
* `/ch/{n}/mix/fader`: Float (Level, 0.75 ≈ 0dB)
|
|
149
|
-
* `/ch/{n}/mix/on`: Integer (**Note:** 1 = Unmuted/On, 0 = Muted/Off)
|
|
150
|
-
* `/ch/{n}/mix/pan`: Float (0.0 = Left, 1.0 = Right)
|
|
151
|
-
|
|
152
|
-
### 7.2 "Sends on Fader" Telemetry
|
|
153
|
-
Scripts can monitor `/-stat/sendsonfader` (0/1) to detect this mode. If active, fader moves control bus sends rather than the main mix.
|
|
154
|
-
|
|
155
|
-
---
|
|
156
|
-
|
|
157
|
-
## 8. Metering and Bulk Data Transfer
|
|
158
|
-
To avoid network flooding, metering is handled via OSC Blobs.
|
|
159
|
-
|
|
160
|
-
### 8.1 The `/meters` Command
|
|
161
|
-
Request: `/meters ,s "/meters/1"` (where `/meters/1` covers input channels).
|
|
162
|
-
|
|
163
|
-
### 8.2 Blob Structure and Endianness
|
|
164
|
-
The response uses ` /meters ,b <binary_data>`.
|
|
165
|
-
1. **Size (Int32):** Big-Endian
|
|
166
|
-
2. **Count (Int32):** **Little-Endian**
|
|
167
|
-
3. **Data (Float32 Array):** **Little-Endian**
|
|
168
|
-
|
|
169
|
-
**Critical:** Developers must switch byte-parsing logic after extracting the blob header to avoid nonsensical numeric values.
|
|
170
|
-
|
|
171
|
-
---
|
|
172
|
-
|
|
173
|
-
## 9. Application Analysis: X32-Edit
|
|
174
|
-
The official software follows this blueprint:
|
|
175
|
-
1. **Startup:** Broadcast `/xinfo`.
|
|
176
|
-
2. **Connect:** Establish unicast UDP session to port 10023.
|
|
177
|
-
3. **Sync:** Send `/xremote` and dump console state (via `/status` or node requests).
|
|
178
|
-
4. **Operation:** Loop `/xremote` every ~9s; process `/ch/...` and `/meters` updates.
|
|
179
|
-
5. **Termination:** Stop heartbeat; session times out.
|
|
180
|
-
|
|
181
|
-
---
|
|
182
|
-
|
|
183
|
-
## 10. Conclusion
|
|
184
|
-
The Behringer X32 OSC protocol is a robust system for remote audio control. By utilizing **UDP port 10023**, initiating discovery via **/xinfo**, and maintaining session persistence via **/xremote**, developers can effectively communicate with the console. Furthermore, intercepting "Active Channel" information is achievable by monitoring the **`/-stat/selidx`** command within an active subscription, enabling the creation of sophisticated custom controllers and automated workflows.
|