Files
dsp-thomann/dsp408-protocol.md
T
LucasDLTG bd5eaa3446
CI / Rust CI (push) Successful in 3m40s
feat: add documentations
2026-07-21 11:58:59 +02:00

1893 lines
60 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# DSP 408 Protocol Documentation
# TODO
- Existing but not implemented commands: 0x19, 0x25, 0x28, 0x2E, 0x50, 0x51, 0x52, 0x53
- Commands 0x2E, 0x50, 0x51, 0x52, 0x53 seem to be used for firmware update: DO NOT SEND THEM WITHOUT KNOWLEDGE - RISK OF DEVICE BRICK (I brick my device)
- Commands: 0x19, 0x24, 0x28 are triggered by upload preset
- Identify: 0x2C parameters
- Implement: if 2 DSP with same ip, they need to share same socket since dsp dont accept multiples connections
- In unlock check if first byte is device id
- Dsp and python code allow to send commands even if dsp is locked
- Convert back data as in 0x38 to display real value
# Tables of Content
## Encoding Index
| Encoding | Used by | Description |
|---|---|---|
| [Preset Name](#21-preset-name) | Preset save/load | 14-byte fixed string |
| [Channel Name](#22-channel-name) | Channel labeling | 8-byte fixed string |
| [Password](#23-password) | Login/lock | 4-byte fixed string |
| [Preset Index](#31-preset-index) | Preset select | 1-byte index (21 presets) |
| [Channel Index](#32-channel-index) | Gain, Mute, Delay, PEQ, GEQ | 1-byte index (12 channels) |
| [PEQ Band Index](#33-peq-band-index) | PEQ | 1-byte index (9 bands) |
| [Frequency Band Index](#34-frequency-band-index) | GEQ | 1-byte index (31 bands) |
| [Delay Unit](#35-delay-unit) | Channel Delay | 1-byte unit selector |
| [Compressor Ratio](#36-compressor-ratio) | Compressor | 1-byte index (16 ratios) |
| [Input Source Type](#37-input-source-type) | Input select | 1-byte index (4 sources) |
| [PEQ Filter Type](#38-peq-filter-type) | PEQ | 1-byte index (9 filter types) |
| [Crossover Slope](#39-crossover-slope) | Crossover | 1-byte index (21 slopes) |
| [Matrix Input Mask](#41-matrix-input-mask) | Input routing | 1-byte bitmask |
| [Channel Gain](#51-channel-gain) | Gain | 16-bit dB value (-60 to +12 dB) |
| [GEQ / PEQ Gain](#52-geq--peq-gain) | GEQ, PEQ | 8-bit ±12 dB value |
| [PEQ Q Factor](#53-peq-q-factor) | PEQ | 8-bit logarithmic Q value |
| [Hold](#61-hold-gate) | Gate | 16-bit ms value |
| [Attack](#62-attack-compressor) | Compressor | 16-bit ms value |
| [Release](#63-release-compressor) | Compressor | 16-bit ms value |
| [Knee](#64-knee-compressor) | Compressor | 8-bit dB value |
| [Sidechain Frequency](#65-sidechain-frequency-compressor) | Compressor | 16-bit logarithmic Hz value |
| [Gate Threshold](#66-gate-threshold) | Gate | 16-bit dB value |
| [Compressor Threshold](#67-compressor-threshold) | Compressor | 8-bit dB value |
| [Channel Delay](#71-channel-delay) | Delay | 8-bit linear value |
| [Meter Level](#81-meter-level) | Metering | Float16 level + peak byte |
---
## Commands Index
| Command | Category | Description |
|---|---|---|
| `0x01` — [Acknowledgement](#0x01--acknowledgement) | Connection & Session | Signals the device finished loading/processing and is ready |
| `0x02` — [Not Implemented](#0x02--not-implemented) | Connection & Session | Signals that the command just sent is invalid/unimplemented |
| `0x10` — [Start](#0x10--start) | Connection & Session | Initiates a session with the device |
| `0x11` — [Disconnect](#0x11--disconnect) | Connection & Session | Terminates the session |
| `0x12` — [Acknowledgement (Client → Device)](#0x12--acknowledgement-client--device) | Connection & Session | Client-side confirmation after loading parameters |
| `0x13` — [Device Name](#0x13--device-name) | Device Info | Reads the device's display name |
| `0x14` — [Current Preset Index](#0x14--current-preset-index) | Preset Management | Reads the currently active preset |
| `0x15` — [Set Delay Unit](#0x15--set-delay-unit) | Channel Processing | Changes the display unit used for delay values |
| `0x20` — [Recall Preset](#0x20--recall-preset) | Preset Management | Recalls (loads) a stored preset |
| `0x21` — [Store Preset](#0x21--store-preset) | Preset Management | Saves the current live settings into a preset slot |
| `0x22` — [Get Preset Modification Status](#0x22--get-preset-modification-status) | Preset Management | Reports which presets have unsaved/modified state |
| `0x23` — [Factory Reset](#0x23--factory-reset) | Preset Management | Restores factory defaults |
| `0x27 / 0x24` — [Config Chunk (Request / Response)](#0x27--0x24--config-chunk-request--response) | Preset Management | Streams the full device configuration in indexed chunks |
| `0x26` — [Store Preset Name](#0x26--store-preset-name) | Preset Management | Sets the working preset name prior to saving |
| `0x29` — [Get Preset Name](#0x29--get-preset-name) | Preset Management | Reads the name of a given preset |
| `0x2A` — [Copy Channel](#0x2a--copy-channel) | Channel Configuration | Copies one channel's settings onto another |
| `0x2C` — [Device Flags](#0x2c--device-flags) | Device Info | Reads device status flags, including lock state |
| `0x2D` — [Unlock Device](#0x2d--unlock-device) | Security | Authenticates with a password to unlock the device |
| `0x2F` — [Lock Device](#0x2f--lock-device) | Security | Locks the device behind a password |
| `0x30` — [Set Compressor](#0x30--set-compressor) | Dynamics | Sets compressor parameters for a channel |
| `0x31` — [Set Low-Pass Filter](#0x31--set-low-pass-filter) | Filters & EQ | Sets the low-pass filter for a channel |
| `0x32` — [Set High-Pass Filter](#0x32--set-high-pass-filter) | Filters & EQ | Sets the high-pass filter for a channel |
| `0x33` — [Set PEQ Band](#0x33--set-peq-band) | Filters & EQ | Sets one parametric EQ band (input channels only) |
| `0x34` — [Set Gain](#0x34--set-gain) | Channel Processing | Sets a channel's gain |
| `0x35` — [Set Mute](#0x35--set-mute) | Channel Processing | Mutes or unmutes a channel |
| `0x36` — [Invert Gain](#0x36--invert-gain) | Channel Processing | Inverts polarity on a channel |
| `0x38` — [Set Delay](#0x38--set-delay) | Channel Processing | Sets a channel's delay value |
| `0x39` — [Set Input Source](#0x39--set-input-source) | Input & Routing | Selects the analog/test signal source |
| `0x3A` — [Matrix Routing](#0x3a--matrix-routing) | Input & Routing | Sets which inputs feed a given output channel |
| `0x3B` — [Link Channel](#0x3b--link-channel) | Channel Configuration | Groups channels so they move together |
| `0x3C` — [Bypass EQ](#0x3c--bypass-eq) | Channel Processing | Enables or bypasses all EQ processing on a channel |
| `0x3D` — [Set Channel Name](#0x3d--set-channel-name) | Channel Configuration | Sets the display name of an output channel |
| `0x3E` — [Set Gate Parameters](#0x3e--set-gate-parameters) | Dynamics | Sets noise-gate parameters for a channel |
| `0x3F` — [Set Output Limiter](#0x3f--set-output-limiter) | Dynamics | Sets output-limiter parameters (output channels only) |
| `0x40` — [Get Level Meters](#0x40--get-level-meters) | Metering | Reads current level-meter and clip-indicator values for all channels |
| `0x41` — [Set Matrix Gain](#0x41--set-matrix-gain) | Input & Routing | Sets the send gain from one input to one output |
| `0x48` — [Set GEQ Band](#0x48--set-geq-band) | Filters & EQ | Sets one band of a 31-band graphic EQ (input channels only) |
| `0x49` — [Set GEQ Bypass](#0x49--set-geq-bypass) | Filters & EQ | Enables or bypasses the graphic EQ on an input channel (input channels only) |
---
# Encoding / Decoding Specification
## 1. Overview & Conventions
- All multi-byte numeric fields are **little-endian**: the low-order byte (`LO`) is transmitted/stored first, the high-order byte (`HI`) second.
```text
LO = raw & 0xFF
HI = (raw >> 8) & 0xFF
```
```text
raw = LO | (HI << 8)
```
- Quantized parameters (e.g. gain, threshold) are rounded to the nearest valid step **before** encoding. The decoding formula always reverses the encoding formula exactly.
- All lookup-table fields (enums, indices) are 1 byte unless otherwise noted.
---
## 2. Fixed-Length Strings
All string fields share one encoding model: write the text as ASCII bytes, then pad up to the fixed length with a pad byte. Decoding reverses this: read the fixed length, then strip trailing pad bytes.
### 2.1 Preset Name
| Field | Value |
|---|---|
| **Purpose** | Human-readable preset name |
| **Size** | 14 bytes |
| **Pad byte** | `0x20` (space) |
**Encoding (value → raw):**
```text
bytes = ASCII(name)[0:14]
bytes = bytes + 0x20 × (14 - len(bytes))
```
**Decoding (raw → value):**
```text
name = ASCII(bytes).rstrip(0x20)
```
### 2.2 Channel Name
| Field | Value |
|---|---|
| **Purpose** | Human-readable channel name |
| **Size** | 8 bytes |
| **Pad byte** | `0x00` |
**Encoding (value → raw):**
```text
bytes = ASCII(name)[0:8]
bytes = bytes + 0x00 × (8 - len(bytes))
```
**Decoding (raw → value):**
```text
name = ASCII(bytes).rstrip(0x00)
```
### 2.3 Password
| Field | Value |
|---|---|
| **Purpose** | Password value |
| **Size** | 4 bytes |
| **Pad byte** | `0x00` |
**Encoding (value → raw):**
```text
bytes = ASCII(password)[0:4]
bytes = bytes + 0x00 × (4 - len(bytes))
```
**Decoding (raw → value):**
```text
password = ASCII(bytes).rstrip(0x00)
```
---
## 3. Enumerated & Index Values
All fields in this section are 1 byte and work as a direct lookup table.
**Encoding (value → raw):** find the desired option in the table and use its byte value.
**Decoding (raw → value):** look up the byte value in the table to get the option.
### 3.1 Preset Index
**Range:** `0x00`–`0x14` (21 presets)
| Index | Preset |
|---|---|
| `0x00` | Preset 0 |
| `0x01` | Preset 1 |
| … | … |
| `0x14` | Preset 20 |
### 3.2 Channel Index
**Range:** `0x00`–`0x0B` (12 channels)
| Index | Channel | Index | Channel |
|---|---|---|---|
| `0x00` | IN_A | `0x06` | OUT_3 |
| `0x01` | IN_B | `0x07` | OUT_4 |
| `0x02` | IN_C | `0x08` | OUT_5 |
| `0x03` | IN_D | `0x09` | OUT_6 |
| `0x04` | OUT_1 | `0x0A` | OUT_7 |
| `0x05` | OUT_2 | `0x0B` | OUT_8 |
### 3.3 PEQ Band Index
**Range:** `0x00`–`0x08` (9 bands)
**Band limit by channel type:**
| Channel Type | Maximum Band |
|---|---|
| Input | B7 (`0x07`) |
| Output | B8 (`0x08`) |
| Index | Band | Index | Band |
|---|---|---|---|
| `0x00` | B0 | `0x05` | B5 |
| `0x01` | B1 | `0x06` | B6 |
| `0x02` | B2 | `0x07` | B7 |
| `0x03` | B3 | `0x08` | B8 |
| `0x04` | B4 | | |
### 3.4 Frequency Band Index
**Range:** `0x00`–`0x1E` (31 bands, ISO 1/3-octave centers)
| Index | Frequency | Index | Frequency | Index | Frequency | Index | Frequency |
|---|---|---|---|---|---|---|---|
| `0x00` | 20 Hz | `0x08` | 125 Hz | `0x10` | 800 Hz | `0x18` | 5 kHz |
| `0x01` | 25 Hz | `0x09` | 160 Hz | `0x11` | 1 kHz | `0x19` | 6.3 kHz |
| `0x02` | 31.5 Hz | `0x0A` | 200 Hz | `0x12` | 1.25 kHz | `0x1A` | 8 kHz |
| `0x03` | 40 Hz | `0x0B` | 250 Hz | `0x13` | 1.6 kHz | `0x1B` | 10 kHz |
| `0x04` | 50 Hz | `0x0C` | 315 Hz | `0x14` | 2 kHz | `0x1C` | 12.5 kHz |
| `0x05` | 63 Hz | `0x0D` | 400 Hz | `0x15` | 2.5 kHz | `0x1D` | 16 kHz |
| `0x06` | 80 Hz | `0x0E` | 500 Hz | `0x16` | 3.15 kHz | `0x1E` | 20 kHz |
| `0x07` | 100 Hz | `0x0F` | 630 Hz | `0x17` | 4 kHz | | |
### 3.6 Compressor Ratio
**Range:** `0x0000`–`0x0F00` (16 values)
| Value | Ratio | Value | Ratio |
|---|---|---|---|
| `0x0000` | 1:1 | `0x0800` | 3.5:1 |
| `0x0100` | 1.1:1 | `0x0900` | 4:1 |
| `0x0200` | 1.3:1 | `0x0A00` | 5:1 |
| `0x0300` | 1.5:1 | `0x0B00` | 6:1 |
| `0x0400` | 1.7:1 | `0x000C` | 8:1 |
| `0x0500` | 2:1 | `0x0D00` | 10:1 |
| `0x0600` | 2.5:1 | `0x0E00` | 20:1 |
| `0x0700` | 3:1 | `0x0F00` | LIMIT |
### 3.7 Input Source Type
**Range:** `0x00`–`0x03` (4 types)
| Value | Input Source |
|---|---|
| `0x00` | Analog |
| `0x01` | Pink Noise |
| `0x02` | White Noise |
| `0x03` | Sine Wave |
### 3.8 PEQ Filter Type
**Range:** `0x00`–`0x08` (9 types)
| Value | Filter | Value | Filter |
|---|---|---|---|
| `0x00` | Peak | `0x05` | HP 6dB |
| `0x01` | Low Shelf | `0x06` | HP 12dB |
| `0x02` | High Shelf | `0x07` | All Pass 1 |
| `0x03` | LP 6dB | `0x08` | All Pass 2 |
| `0x04` | LP 12dB | | |
### 3.9 Crossover Slope
**Range:** `0x00`–`0x14` (21 values)
| Value | Slope | Value | Slope |
|---|---|---|---|
| `0x00` | Bypass | `0x0B` | BW 30 |
| `0x01` | BW 6 | `0x0C` | BL 30 |
| `0x02` | BL 6 | `0x0D` | BW 36 |
| `0x03` | BW 12 | `0x0E` | BL 36 |
| `0x04` | BL 12 | `0x0F` | LR 36 |
| `0x05` | LR 12 | `0x10` | BW 42 |
| `0x06` | BW 18 | `0x11` | BL 42 |
| `0x07` | BL 18 | `0x12` | BW 48 |
| `0x08` | BW 24 | `0x13` | BL 48 |
| `0x09` | BL 24 | `0x14` | LR 48 |
| `0x0A` | LR 24 | | |
---
## 4. Bit Mask Values
### 4.1 Matrix Input Mask
| Field | Value |
|---|---|
| **Purpose** | Which inputs are active/routed |
| **Size** | 1 byte |
| **Range** | `0x00`–`0x0F` |
| Input | Bit mask |
|---|---|
| IN_A | `0x01` |
| IN_B | `0x02` |
| IN_C | `0x04` |
| IN_D | `0x08` |
**Encoding (value → raw):** OR together the bit mask of every active input.
```text
raw = (IN_A ? 0x01 : 0) | (IN_B ? 0x02 : 0) | (IN_C ? 0x04 : 0) | (IN_D ? 0x08 : 0)
```
**Decoding (raw → value):** AND the raw byte with each bit mask to test whether that input is active.
```text
IN_A_active = (raw & 0x01) != 0
IN_B_active = (raw & 0x02) != 0
IN_C_active = (raw & 0x04) != 0
IN_D_active = (raw & 0x08) != 0
```
---
## 5. Gain & Equalizer Parameters
### 5.1 Channel Gain
| Field | Value |
|---|---|
| **Purpose** | Per-channel input/output gain |
| **Size** | 2 bytes, little-endian |
| **Range** | -60 dB to +12 dB |
**Quantization:**
| dB Range | Resolution |
|---|---|
| `[-60, -20)` | 0.5 dB |
| `[-20, +12]` | 0.1 dB |
**Encoding (value → raw):**
```text
if -60 <= dB < -20:
raw = round((dB + 60) / 0.5)
if -20 <= dB <= 12:
raw = round(80 + (dB + 20) / 0.1)
LO = raw & 0xFF
HI = (raw >> 8) & 0xFF
```
**Decoding (raw → value):**
```text
raw = LO | (HI << 8)
if 0 <= raw <= 79:
dB = raw × 0.5 - 60
if 80 <= raw <= 320:
dB = (raw - 80) × 0.1 - 20
```
### 5.2 GEQ / PEQ Gain
| Field | Value |
|---|---|
| **Purpose** | Graphic/parametric EQ band gain |
| **Size** | 2 bytes |
| **Range** | -12 dB to +12 dB |
| **Resolution** | 0.1 dB |
**Encoding (value → raw):**
```text
raw = round(dB × 10 + 120)
LO = raw & 0xFF
HI = (raw >> 8) & 0xFF
```
**Decoding (raw → value):**
```text
dB = (raw - 120) / 10
```
| Raw | Gain |
|---|---|
| `0x00` | -12 dB |
| `0x78` | 0 dB |
| `0xF0` | +12 dB |
### 5.3 PEQ Q Factor
| Field | Value |
|---|---|
| **Purpose** | Parametric EQ bandwidth (Q) |
| **Size** | 1 byte, logarithmic index |
| **Range** | 0.40 to 128.00 |
| **Raw range** | `0x00`–`0x64` (0–100) |
**Encoding (value → raw):**
```text
raw = round(log(Q / 0.40) / log(128 / 0.40) × 100)
```
**Decoding (raw → value):**
```text
Q = 0.40 × (128 / 0.40) ^ (raw / 100)
```
---
## 6. Dynamics Processing Parameters
### 6.1 Hold (Gate)
| Field | Value |
|---|---|
| **Purpose** | Gate hold time |
| **Size** | 2 bytes, little-endian |
| **Range** | 10 ms to 999 ms |
**Encoding (value → raw):**
```text
raw = hold_ms - 1
LO = raw & 0xFF
HI = (raw >> 8) & 0xFF
```
**Decoding (raw → value):**
```text
raw = LO | (HI << 8)
hold_ms = raw + 1
```
### 6.2 Attack (Compressor)
| Field | Value |
|---|---|
| **Purpose** | Compressor attack time |
| **Size** | 2 bytes, little-endian |
| **Range** | 1 ms to 999 ms |
**Encoding (value → raw):**
```text
raw = attack_ms - 1
LO = raw & 0xFF
HI = (raw >> 8) & 0xFF
```
**Decoding (raw → value):**
```text
raw = LO | (HI << 8)
attack_ms = raw + 1
```
### 6.3 Release
| Field | Value |
|---|---|
| **Purpose** | Release time |
| **Size** | 2 bytes, little-endian |
| **Range** | 10 ms to 3000 ms |
**Encoding (value → raw):**
```text
raw = release_ms - 1
LO = raw & 0xFF
HI = (raw >> 8) & 0xFF
```
**Decoding (raw → value):**
```text
raw = LO | (HI << 8)
release_ms = raw + 1
```
### 6.4 Knee (Compressor)
| Field | Value |
|---|---|
| **Purpose** | Compressor knee width |
| **Size** | 2 bytes |
| **Range** | 0 dB to 12 dB |
| **Resolution** | 1 dB |
**Encoding (value → raw):**
```text
raw = round(knee_db)
LO = raw & 0xFF
HI = (raw >> 8) & 0xFF
```
**Decoding (raw → value):**
```text
knee_db = LO | (HI << 8)
```
### 6.5 Sidechain Frequency (Compressor)
| Field | Value |
|---|---|
| **Purpose** | Compressor sidechain filter frequency |
| **Size** | 2 bytes, little-endian |
| **Range** | 19.70 Hz to 20160 Hz |
| **Raw range** | `0x0000`–`0x012C` |
**Encoding (value → raw):**
```text
raw = round(log(Hz / 19.70) / log(20160 / 19.70) × 300)
LO = raw & 0xFF
HI = (raw >> 8) & 0xFF
```
**Decoding (raw → value):**
```text
raw = LO | (HI << 8)
Hz = 19.70 × (20160 / 19.70) ^ (raw / 300)
```
### 6.6 Gate Threshold Encoding
Gate threshold uses a **16-bit little-endian** value.
| Field | Value |
|---|---|
| **Purpose** | Gate open/close threshold |
| **Size** | 2 bytes, little-endian |
| **Range** | `-90.0 dB` to `0.0 dB` |
| **Raw range** | `0x0000`–`0x00B4` (0–180) |
| **Resolution** | `0.5 dB` |
**Encoding (dB → raw):**
```text
raw = round((dB - (-90.0)) × 2)
LO = raw & 0xFF
HI = (raw >> 8) & 0xFF
```
**Decoding (raw → dB):**
```text
raw = LO | (HI << 8)
dB = -90.0 + (raw / 2)
```
### 6.7 Compressor Threshold
| Field | Value |
|---|---|
| **Purpose** | Compressor threshold |
| **Size** | 2 bytes |
| **Range** | -110 dB to 0 dB |
| **Resolution** | 0.5 dB |
**Encoding (value → raw):**
```text
raw = round((dB - (-110)) × 2)
LO = raw & 0xFF
HI = (raw >> 8) & 0xFF
```
**Decoding (raw → value):**
```text
raw = LO | (HI << 8)
dB = (raw / 2) - 110
```
---
## 7. Delay
### 7.1 Channel Delay
| Field | Value |
|---|---|
| **Purpose** | Per-channel delay |
| **Size** | 1 byte |
| **Raw range** | `0x00`–`0xFF` (0–255) |
**Range by selected unit** (see [Delay Unit](#35-delay-unit)):
| Unit | `delay_min` | `delay_max` |
|---|---|---|
| Millisecond | 0.000 ms | 680.000 ms |
| Meter | 0.000 m | 233.580 m |
| Feet | 0.000 ft | 766.329 ft |
**Encoding (value → raw):**
```text
raw = round((delay - delay_min) / (delay_max - delay_min) × 255)
```
**Decoding (raw → value):**
```text
delay = delay_min + (raw / 255) × (delay_max - delay_min)
```
### 7.2 Delay Unit
**Range:** `0x00`–`0x02` (3 units)
| Value | Unit |
|---|---|
| `0x00` | Millisecond |
| `0x01` | Meter |
| `0x02` | Feet |
---
## 8. Metering
### 8.1 Meter Level
| Field | Value |
|---|---|
| **Purpose** | Per-channel level + peak metering |
| **Size** | 3 bytes per channel |
| **Total** | 12 channels × 3 bytes = 36 bytes |
| Byte offset | Field | Format |
|---|---|---|
| 0–1 | Level | IEEE754 float16, little-endian |
| 2 | Peak | 1-byte peak value (format not specified in source) |
**Encoding (value → raw):**
```text
level_bytes = float16_encode(level) // 2 bytes, little-endian
peak_byte = peak_encode(peak) // format undefined — see note below
raw = level_bytes + peak_byte
```
**Decoding (raw → value):**
```text
level = float16_decode(raw[0:2]) // little-endian
peak = peak_decode(raw[2]) // format undefined — see note below
```
---
# Command Specification
## 1. Frame Structure
Every command — query or response — shares one frame layout. Colors match the highlighted examples throughout this document:
| Field | Size | Color | Description |
|---|---|---|---|
| `STX` | 2 bytes | <span style="color:#4ea1ff">■</span> | Fixed start marker: `10 02` |
| `DIR` | 2 bytes | <span style="color:#a56eff">■</span> | Direction (see below) |
| `LEN` | 1 byte | <span style="color:#ffb347">■</span> | Byte count of `CMD + DATA` |
| `CMD` | 1 byte | <span style="color:#ff6b6b">■</span> | Command code |
| `DATA` | `LEN - 1` bytes | <span style="color:#5cd65c">■</span> | Command payload (may be 0 bytes) |
| `ETX` | 2 bytes | <span style="color:#4ea1ff">■</span> | Fixed end marker: `10 03` |
| `CS` | 1 byte | <span style="color:#ffd700">■</span> | Checksum (see below) |
Example skeleton:
<span style="color:#4ea1ff">10 02</span> <span style="color:#a56eff">DIR DIR</span> <span style="color:#ffb347">LEN</span> <span style="color:#ff6b6b">CMD</span> <span style="color:#5cd65c">DATA...</span> <span style="color:#4ea1ff">10 03</span> <span style="color:#ffd700">CS</span>
### Direction (`DIR`)
| Value | Direction |
|---|---|
| `00 XX` | Host → Device (Query) |
| `XX 00` | Device → Host (Response) |
XX represents the device Id
### Length (`LEN`)
```text
LEN = size(CMD) + size(DATA) = 1 + size(DATA)
```
### Checksum (`CS`)
The checksum is the **XOR of every byte in the frame from `DIR` through `DATA`, inclusive, with an initial seed of `0x01`**.
**Encoding (value → raw):**
```text
CS = DIR[0] ^ DIR[1] ^ LEN ^ CMD ^ DATA[0] ^ ... ^ DATA[N-1] ^ 0x01
```
**Decoding / verification (raw → check):**
```text
computed_CS = DIR[0] ^ DIR[1] ^ LEN ^ CMD ^ DATA[0] ^ ... ^ DATA[N-1] ^ 0x01
valid = (computed_CS == received_CS)
```
---
## 2. Command Template
Every command in this document uses the same shape:
**`0xXX` — Name**
**Direction:** Host→Device / Device→Host / Both
**Category:** ...
**Purpose:** one-line description
**Sequencing:** what must precede/follow this command, if anything
**Payload Fields** — table of `Offset | Field | Size | Encoding Reference | Value/Range`
**Example** — annotated, color-coded hex frame
---
## 3. Connection & Session
### `0x01` — Acknowledgement
**Direction:** Device → Host
**Category:** Connection & Session
**Purpose:** Signals the device finished loading/processing and is ready.
**Sequencing:** Sent after any state-changing command.
**Payload Fields**
| Offset | Field | Size | Encoding |
|---|---|---|---|
| — | (none) | 0 bytes | Command has no payload |
**Example**
<span style="color:#4ea1ff">10 02</span>
<span style="color:#a56eff">01 00</span>
<span style="color:#ffb347">01</span>
<span style="color:#ff6b6b">01</span>
<span style="color:#4ea1ff">10 03</span>
<span style="color:#ffd700">00</span>
---
### `0x02` — Not Implemented
**Direction:** Device → Host
**Category:** Connection & Session
**Purpose:** Signals that the command just sent is invalid/unimplemented.
**Sequencing:** Sent in place of `0x01` when a command fails to parse or is unsupported.
**Payload Fields**
| Offset | Field | Size | Encoding |
|---|---|---|---|
| — | (none) | 0 bytes | Command has no payload |
**Example**
<span style="color:#4ea1ff">10 02</span>
<span style="color:#a56eff">01 00</span>
<span style="color:#ffb347">01</span>
<span style="color:#ff6b6b">02</span>
<span style="color:#4ea1ff">10 03</span>
<span style="color:#ffd700">00</span>
---
### `0x10` — Start
**Direction:** Host → Device (Query), Device → Host (Response)
**Category:** Connection & Session
**Purpose:** Initiates a session with the device.
**Sequencing:** First command sent on connect.
**Payload Fields (Response only)**
| Offset | Field | Size | Encoding |
|---|---|---|---|
| `Byte 1` | Status | 1 byte | `0x13` = OK |
**Example — Query**
<span style="color:#4ea1ff">10 02</span>
<span style="color:#a56eff">00 01</span>
<span style="color:#ffb347">01</span>
<span style="color:#ff6b6b">10</span>
<span style="color:#4ea1ff">10 03</span>
<span style="color:#ffd700">11</span>
**Example — Response**
<span style="color:#4ea1ff">10 02</span>
<span style="color:#a56eff">01 00</span>
<span style="color:#ffb347">02</span>
<span style="color:#ff6b6b">10</span>
<span style="color:#5cd65c">13</span>
<span style="color:#4ea1ff">10 03</span>
<span style="color:#ffd700">01</span>
---
### `0x11` — Disconnect
**Direction:** Host → Device
**Category:** Connection & Session
**Purpose:** Terminates the session.
**Payload Fields**
| Offset | Field | Size | Encoding |
|---|---|---|---|
| — | (none) | 0 bytes | Command has no payload |
**Example**
<span style="color:#4ea1ff">10 02</span>
<span style="color:#a56eff">00 01</span>
<span style="color:#ffb347">01</span>
<span style="color:#ff6b6b">11</span>
<span style="color:#4ea1ff">10 03</span>
<span style="color:#ffd700">10</span>
---
### `0x12` — Acknowledgement (Client → Device)
**Direction:** Host → Device
**Category:** Connection & Session
**Purpose:** Client-side confirmation after loading parameters (mirrors `0x01` but in the opposite direction).
**Sequencing:** Followed by `0x01`.
**Payload Fields**
| Offset | Field | Size | Encoding |
|---|---|---|---|
| — | (none) | 0 bytes | Command has no payload |
**Example**
<span style="color:#4ea1ff">10 02</span>
<span style="color:#a56eff">00 01</span>
<span style="color:#ffb347">01</span>
<span style="color:#ff6b6b">12</span>
<span style="color:#4ea1ff">10 03</span>
<span style="color:#ffd700">13</span>
---
## 4. Device Info
### `0x13` — Device Name
**Direction:** Host → Device (Query), Device → Host (Response)
**Category:** Device Info
**Purpose:** Reads the device's display name.
**Payload Fields (Response only)**
| Offset | Field | Size | Encoding |
|---|---|---|---|
| `Byte 1` – `Byte N-1` | Device name | 13 bytes | [Enc §2.2 Channel Name](#22-channel-name)|
**Example — Query**
<span style="color:#4ea1ff">10 02</span>
<span style="color:#a56eff">00 01</span>
<span style="color:#ffb347">01</span>
<span style="color:#ff6b6b">13</span>
<span style="color:#4ea1ff">10 03</span>
<span style="color:#ffd700">12</span>
**Example — Response**
<span style="color:#4ea1ff">10 02</span>
<span style="color:#a56eff">01 00</span>
<span style="color:#ffb347">0E</span>
<span style="color:#ff6b6b">13</span>
<span style="color:#5cd65c">44 53 50 34 30 38 20 56 30 31 30 34 50</span>
<span style="color:#4ea1ff">10 03</span>
<span style="color:#ffd700">45</span>
---
### `0x2C` — Device Flags
**Direction:** Host → Device (Query), Device → Host (Response)
**Category:** Device Info
**Purpose:** Reads device status flags, including lock state. Not fully reverse-engineered.
**Payload Fields (Response only)**
| Offset | Field | Size | Encoding |
|---|---|---|---|
| `Byte 1` | Unknown | 1 byte | `00` observed |
| `Byte 2-3` | Unknown | 2 bytes | `27 0F` observed |
| `Byte 4-5` | Unknown | 2 bytes | `00 00` observed |
| `Byte 6` | Lock state | 1 byte | `01` = Locked, `00` = Unlocked |
**Example — Query**
<span style="color:#4ea1ff">10 02</span>
<span style="color:#a56eff">00 01</span>
<span style="color:#ffb347">01</span>
<span style="color:#ff6b6b">2C</span>
<span style="color:#4ea1ff">10 03</span>
<span style="color:#ffd700">2D</span>
**Example — Response**
<span style="color:#4ea1ff">10 02</span>
<span style="color:#a56eff">01 00</span>
<span style="color:#ffb347">07</span>
<span style="color:#ff6b6b">2C</span>
<span style="color:#5cd65c">00 27 0F 00 00 00</span>
<span style="color:#4ea1ff">10 03</span>
<span style="color:#ffd700">03</span>
---
## 5. Preset Management
### `0x14` — Current Preset Index
**Direction:** Host → Device (Query), Device → Host (Response)
**Category:** Preset Management
**Purpose:** Reads the currently active preset.
**Payload Fields (Response only)**
| Offset | Field | Size | Encoding |
|---|---|---|---|
| `Byte 1` | Preset index | 1 byte | [Enc §3.1 Preset Index](#31-preset-index)|
**Example — Query**
<span style="color:#4ea1ff">10 02</span>
<span style="color:#a56eff">00 01</span>
<span style="color:#ffb347">01</span>
<span style="color:#ff6b6b">14</span>
<span style="color:#4ea1ff">10 03</span>
<span style="color:#ffd700">15</span>
**Example — Response**
<span style="color:#4ea1ff">10 02</span>
<span style="color:#a56eff">01 00</span>
<span style="color:#ffb347">02</span>
<span style="color:#ff6b6b">14</span>
<span style="color:#5cd65c">06</span>
<span style="color:#4ea1ff">10 03</span>
<span style="color:#ffd700">10</span>
---
### `0x20` — Recall Preset
**Direction:** Host → Device
**Category:** Preset Management
**Purpose:** Recalls (loads) a stored preset.
**Sequencing:** Followed by `0x01` (Acknowledgement) once loading finishes.
**Payload Fields**
| Offset | Field | Size | Encoding |
|---|---|---|---|
| `Byte 1` | Preset index | 1 byte | [Enc §3.1 Preset Index](#31-preset-index) |
**Example**
<span style="color:#4ea1ff">10 02</span>
<span style="color:#a56eff">00 01</span>
<span style="color:#ffb347">02</span>
<span style="color:#ff6b6b">20</span>
<span style="color:#5cd65c">10</span>
<span style="color:#4ea1ff">10 03</span>
<span style="color:#ffd700">32</span>
---
### `0x21` — Store Preset
**Direction:** Host → Device
**Category:** Preset Management
**Purpose:** Saves the current live settings into a preset slot.
**Sequencing:** Call `0x26` (Store Preset Name) first to set the name being saved. Must be followed by `0x12`.
**Payload Fields**
| Offset | Field | Size | Encoding |
|---|---|---|---|
| `Byte 1` | Preset slot | 1 byte | [Enc §3.1 Preset Index](#31-preset-index), no 0x00|
**Example**
<span style="color:#4ea1ff">10 02</span>
<span style="color:#a56eff">00 01</span>
<span style="color:#ffb347">02</span>
<span style="color:#ff6b6b">21</span>
<span style="color:#5cd65c">01</span>
<span style="color:#4ea1ff">10 03</span>
<span style="color:#ffd700">CS</span>
---
### `0x22` — Get Preset Modification Status
**Direction:** Host → Device (Query), Device → Host (Response)
**Category:** Preset Management
**Purpose:** Reports which presets have unsaved/modified state.
**Payload Fields (Response only)**
| Offset | Field | Size | Encoding |
|---|---|---|---|
| `Byte 1`–`Byte 20` | Per-preset modified flag | 1 byte each | `0xFF` = modified, `0x00` = unmodified |
**Example — Query**
<span style="color:#4ea1ff">10 02</span>
<span style="color:#a56eff">00 01</span>
<span style="color:#ffb347">01</span>
<span style="color:#ff6b6b">22</span>
<span style="color:#4ea1ff">10 03</span>
<span style="color:#ffd700">23</span>
**Example — Response**
<span style="color:#4ea1ff">10 02</span>
<span style="color:#a56eff">01 00</span>
<span style="color:#ffb347">15</span>
<span style="color:#ff6b6b">22</span>
<span style="color:#5cd65c">FF 00 FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00</span>
<span style="color:#4ea1ff">10 03</span>
<span style="color:#ffd700">37</span>
---
### `0x23` — Factory Reset
**Direction:** Host → Device
**Category:** Preset Management
**Purpose:** Restores factory defaults.
**Sequencing:** Device acknowledges with `0x01`.
**Payload Fields**
| Offset | Field | Size | Encoding |
|---|---|---|---|
| — | (none) | 0 bytes | Command has no payload |
**Example**
<span style="color:#4ea1ff">10 02</span>
<span style="color:#a56eff">00 01</span>
<span style="color:#ffb347">01</span>
<span style="color:#ff6b6b">23</span>
<span style="color:#4ea1ff">10 03</span>
<span style="color:#ffd700">CS</span>
---
### `0x27` / `0x24` — Config Chunk (Request / Response)
**Direction:** `0x27` Host→Device (Request), `0x24` Device→Host (Response)
**Category:** Preset Management
**Purpose:** Streams the full device configuration in indexed chunks.
**Sequencing:** Request `0x27` is followed by response `0x24`. Must be followed by `0x12`, after full batch request.
**Payload Fields — Request (`0x27`)**
| Offset | Field | Size | Encoding |
|---|---|---|---|
| `Byte 1` | Chunk index | 1 byte | `0x00`–`0x1C` |
**Payload Fields — Response (`0x24`)**
| Offset | Field | Size | Encoding |
|---|---|---|---|
| `Byte 1` | Sub-index | 1 bytes | `0x00`–`0x1C` |
| `Byte 2`–`Byte 51` | Configuration data | 50 bytes | binary/ASCII mixed |
**Example — Request**
<span style="color:#4ea1ff">10 02</span>
<span style="color:#a56eff">00 01</span>
<span style="color:#ffb347">03</span>
<span style="color:#ff6b6b">27</span>
<span style="color:#5cd65c">INDEX</span>
<span style="color:#4ea1ff">10 03</span>
<span style="color:#ffd700">CS</span>
**Example — Response**
<span style="color:#4ea1ff">10 02</span>
<span style="color:#a56eff">01 00</span>
<span style="color:#ffb347">34</span>
<span style="color:#ff6b6b">24</span>
<span style="color:#5cd65c">00 FF 00 44 65 66 61 75 6C 74 20 50 72 65 73 65 74 49 6E 41 00 00 00 00 00 00 00 63 00 63 00 00 00 78 00 78 00 78 00 78 00 78 00 78 00 78 00 78 00</span>
<span style="color:#4ea1ff">10 03</span>
<span style="color:#ffd700">BF</span>
---
### Config Data — Reassembled Payload Layout
The 50-byte pages from chunks `0x00`–`0x1C` are concatenated in index order into a single buffer before parsing. Below is that buffer's field layout, byte-for-byte, in the order fields are consumed.
**Legend (protocol constants used below)**
| Symbol | Meaning |
|---|---|
| `PNL` | `PRESET_NAME_LENGTH` |
| `CNL` | `CHANNEL_NAME_LENGTH` |
| `N_IN` | number of input channels (`len(INPUT_ORDER)`) |
| `N_OUT` | number of output channels (`len(OUTPUT_ORDER)`) |
| `N_FREQ` | number of GEQ bands (`len(list(FrequencyValue))`) |
| `N_PEQ_IN` | number of input PEQ bands (`len(PEQ_INPUT_BANDS)`) |
| `N_PEQ_OUT` | number of output PEQ bands (`len(PEQ_OUTPUT_BANDS)`) |
**Header**
| Offset | Field | Size | Encoding |
|---|---|---|---|
| `0x00` | Flags (unused) | 2 bytes | reserved |
| `0x02` | Preset name | `PNL` bytes | ASCII, raw → `raw_to_preset_name` |
**Per Input Channel — repeats `N_IN` times**
| Offset (within block) | Field | Size | Encoding |
|---|---|---|---|
| `+0x00` | Channel name | `CNL` bytes | ASCII, raw → `raw_to_channel_name` |
| `+CNL` | Gate: attack | 2 bytes | `u16` → `raw_to_attack_ms` |
| `+CNL+2` | Gate: release | 2 bytes | `u16` → `raw_to_release_ms` |
| `+CNL+4` | Gate: hold | 2 bytes | `u16` → `raw_to_hold_ms` |
| `+CNL+6` | Gate: threshold | 2 bytes | `u16` → `raw_to_threshold_db` |
| `+CNL+8` | GEQ gains | `2 × N_FREQ` bytes | `N_FREQ` × `u16` → `raw_to_eq_gain` |
| `+CNL+8+2·N_FREQ` | PEQ chain | `6 × N_PEQ_IN` bytes | `N_PEQ_IN` bands, each: `u16` gain, `u16` freq, `u8` Q, `u8` filter type |
| … | Crossover: HP freq | 2 bytes | `u16` → `raw_to_frequency_hz` |
| … | Crossover: LP freq | 2 bytes | `u16` → `raw_to_frequency_hz` |
| … | Crossover: HP slope | 1 byte | `u8` → `raw_to_crossover_filter` |
| … | Crossover: LP slope | 1 byte | `u8` → `raw_to_crossover_filter` |
| … | Channel gain | 2 bytes | `u16` → `raw_to_channel_gain` |
| … | Phase inverted | 1 byte | `u8` bool |
| … | Reserved | 2 bytes | skipped |
| … | Delay (raw) | 1 byte | `u8`, resolved via `raw_to_delay(value, delay_unit)` once the header-level delay unit is parsed |
| … | Linked channels | 2 bytes | `u16` bitmap → `raw_to_link_channels` |
Per-channel block size: `CNL + 2·N_FREQ + 6·N_PEQ_IN + 22` bytes.
**Per Output Channel — repeats `N_OUT` times** (immediately follows the last input channel block)
| Offset (within block) | Field | Size | Encoding |
|---|---|---|---|
| `+0x00` | Channel name | `CNL` bytes | ASCII, raw → `raw_to_channel_name` |
| … | Matrix: connected | 2 bytes | `u16` bitmap → `raw_to_matrix` |
| … | Matrix: gains | 8 bytes | 4 × `u16` → `raw_to_matrix_gain` |
| … | Crossover (HP/LP freq + slope) | 6 bytes | same layout as input crossover |
| … | PEQ chain | `6 × N_PEQ_OUT` bytes | `N_PEQ_OUT` bands, same per-band layout as input |
| … | Compressor: ratio | 2 bytes | `u16` → `raw_to_ratio` |
| … | Compressor: attack | 2 bytes | `u16` → `raw_to_attack_ms` |
| … | Compressor: release | 2 bytes | `u16` → `raw_to_release_ms` |
| … | Compressor: knee | 2 bytes | `u16` → `raw_to_knee_db` |
| … | Compressor: threshold | 2 bytes | `u16` → `raw_to_threshold_db` |
| … | Limiter: attack | 2 bytes | `u16` → `raw_to_attack_ms` |
| … | Limiter: release | 2 bytes | `u16` → `raw_to_release_ms` |
| … | Reserved | 2 bytes | skipped |
| … | Limiter: threshold | 2 bytes | `u16` → `raw_to_threshold_db` |
| … | Channel gain | 2 bytes | `u16` → `raw_to_channel_gain` |
| … | Phase inverted | 1 byte | `u8` bool |
| … | Reserved | 2 bytes | skipped |
| … | Delay (raw) | 1 byte | `u8`, resolved via `raw_to_delay(value, delay_unit)` |
| … | Linked channels | 2 bytes | `u16` bitmap → `raw_to_link_channels` |
Per-channel block size: `CNL + 6·N_PEQ_OUT + 42` bytes.
**Global Flags** (immediately follows the last output channel block)
| Offset (within section) | Field | Size | Encoding |
|---|---|---|---|
| `+0x00` | Input mute bitmap | 2 bytes | `u16`, bit *i* = `INPUT_ORDER[i]` muted |
| `+0x02` | Output mute bitmap | 2 bytes | `u16`, bit *i* = `OUTPUT_ORDER[i]` muted |
| `+0x04` | Input PEQ band mute | `2 × N_IN` bytes | one `u16` per input channel, bit *j* = `PEQ_INPUT_BANDS[j]` bypassed |
| `+0x04+2·N_IN` | Output PEQ band mute | `2 × N_OUT` bytes | one `u16` per output channel, bit *j* = `PEQ_OUTPUT_BANDS[j]` bypassed |
**Input Source & Delay Unit** (immediately follows Global Flags)
| Offset (within section) | Field | Size | Encoding |
|---|---|---|---|
| `+0x00` | Input source type | 2 bytes | `u16` → `raw_to_input_source` |
| `+0x02` | Input source frequency | 2 bytes | `u16` → `raw_to_frequency_value` |
| `+0x04` | Delay unit | 2 bytes | `u16` → `raw_to_delay_unit` (applies to all previously-read raw delay bytes) |
**Trailing Bypass Flags** (immediately follows Input Source & Delay Unit)
| Offset (within section) | Field | Size | Encoding |
|---|---|---|---|
| `+0x00` | Input PEQ chain bypass bitmap | 2 bytes | `u16`, bit *i* = `INPUT_ORDER[i]`'s PEQ chain bypassed |
| `+0x02` | Output PEQ chain bypass bitmap | 2 bytes | `u16`, bit *i* = `OUTPUT_ORDER[i]`'s PEQ chain bypassed |
| `+0x04` | Input GEQ bypass bitmap | 2 bytes | `u16`, bit *i* = `INPUT_ORDER[i]`'s GEQ bypassed |
**Total reassembled payload size:**
`2 + PNL + N_IN·(CNL + 2·N_FREQ + 6·N_PEQ_IN + 22) + N_OUT·(CNL + 6·N_PEQ_OUT + 42) + 4 + 2·N_IN + 2·N_OUT + 4 + 2 + 6` bytes.
---
### `0x26` — Store Preset Name
**Direction:** Host → Device
**Category:** Preset Management
**Purpose:** Sets the working preset name prior to saving.
**Sequencing:** Call before `0x21` (Store Preset).
**Payload Fields**
| Offset | Field | Size | Encoding |
|---|---|---|---|
| `Byte 1`–`Byte 14` | Preset name | 14 bytes | [Enc §2.1 Preset Name](#21-preset-name) |
**Example**
<span style="color:#4ea1ff">10 02</span>
<span style="color:#a56eff">00 01</span>
<span style="color:#ffb347">0F</span>
<span style="color:#ff6b6b">26</span>
<span style="color:#5cd65c">50 72 65 73 65 74 20 4E 61 6D 65 20 20 20</span>
<span style="color:#4ea1ff">10 03</span>
<span style="color:#ffd700">CS</span>
---
### `0x29` — Get Preset Name
**Direction:** Host → Device (Query), Device → Host (Response)
**Category:** Preset Management
**Purpose:** Reads the name of a given preset.
**Payload Fields — Query**
| Offset | Field | Size | Encoding |
|---|---|---|---|
| `Byte 1` | Preset index | 1 byte | [Enc §3.1 Preset Index](#31-preset-index) |
**Payload Fields — Response**
| Offset | Field | Size | Encoding |
|---|---|---|---|
| `Byte 1`–`Byte N` | Preset name | 14 bytes | [Enc §2.1 Preset Name](#21-preset-name) |
**Example — Query**
<span style="color:#4ea1ff">10 02</span>
<span style="color:#a56eff">00 01</span>
<span style="color:#ffb347">02</span>
<span style="color:#ff6b6b">29</span>
<span style="color:#5cd65c">00</span>
<span style="color:#4ea1ff">10 03</span>
<span style="color:#ffd700">2B</span>
**Example — Response**
<span style="color:#4ea1ff">10 02</span>
<span style="color:#a56eff">01 00</span>
<span style="color:#ffb347">10</span>
<span style="color:#ff6b6b">29</span>
<span style="color:#5cd65c">4D 61 69 6E 20 70 72 65 73 65 74 20 20 20</span>
<span style="color:#4ea1ff">10 03</span>
<span style="color:#ffd700">17</span>
---
## 6. Security
### `0x2D` — Unlock Device
**Direction:** Host → Device (Query), Device → Host (Response)
**Category:** Security
**Purpose:** Authenticates with a password to unlock the device.
**Payload Fields — Query**
| Offset | Field | Size | Encoding |
|---|---|---|---|
| `Byte 1` | Unknown | 1 byte | `00` observed |
| `Byte 2`–`Byte N` | Password | 4 bytes | [Enc §2.3 Password](#23-password) |
**Payload Fields — Response**
| Offset | Field | Size | Encoding |
|---|---|---|---|
| `Byte 1` | Status category | 1 byte | `00` observed |
| `Byte 2` | Authentication result | 1 byte | `00` = Failed, `01` = Success |
**Example — Query (password `1234`)**
<span style="color:#4ea1ff">10 02</span>
<span style="color:#a56eff">00 01</span>
<span style="color:#ffb347">06</span>
<span style="color:#ff6b6b">2D</span>
<span style="color:#5cd65c">00 31 32 33 34</span>
<span style="color:#4ea1ff">10 03</span>
<span style="color:#ffd700">2F</span>
**Example — Response**
<span style="color:#4ea1ff">10 02</span>
<span style="color:#a56eff">01 00</span>
<span style="color:#ffb347">03</span>
<span style="color:#ff6b6b">2D</span>
<span style="color:#5cd65c">00 01</span>
<span style="color:#4ea1ff">10 03</span>
<span style="color:#ffd700">2F</span>
---
### `0x2F` — Lock Device
**Direction:** Host → Device
**Category:** Security
**Purpose:** Locks the device behind a password.
**Sequencing:** Followed by `0x01`.
**Payload Fields**
| Offset | Field | Size | Encoding |
|---|---|---|---|
| `Byte 1`–`Byte N` | Password | 4 bytes | [Enc §2.3 Password](#23-password) |
**Example (password `1234`)**
<span style="color:#4ea1ff">10 02</span>
<span style="color:#a56eff">00 01</span>
<span style="color:#ffb347">05</span>
<span style="color:#ff6b6b">2F</span>
<span style="color:#5cd65c">31 32 33 34</span>
<span style="color:#4ea1ff">10 03</span>
<span style="color:#ffd700">2E</span>
---
## 7. Channel Configuration
### `0x2A` — Copy Channel
**Direction:** Host → Device
**Category:** Channel Configuration
**Purpose:** Copies one channel's settings onto another.
**Sequencing:** Followed by `0x01`.
**Payload Fields**
| Offset | Field | Size | Encoding |
|---|---|---|---|
| `Byte 1` | Source channel | 1 byte | [Enc §3.2 Channel Index](#32-channel-index) |
| `Byte 2` | Destination channel | 1 byte | [Enc §3.2 Channel Index](#32-channel-index) |
**Example**
<span style="color:#4ea1ff">10 02</span>
<span style="color:#a56eff">00 01</span>
<span style="color:#ffb347">03</span>
<span style="color:#ff6b6b">2A</span>
<span style="color:#5cd65c">00 01</span>
<span style="color:#4ea1ff">10 03</span>
<span style="color:#ffd700">28</span>
---
### `0x3B` — Link Channel
**Direction:** Host → Device
**Category:** Channel Configuration
**Purpose:** Groups channels so they move together.
**Sequencing:** Followed by `0x01`. Use `0x2A` (Copy Channel) before linking channels with `0x3B`.
**Payload Fields**
| Offset | Field | Size | Encoding |
|---|---|---|---|
| `Byte 1` | Channel index | 1 byte | [Enc §3.2 Channel Index](#32-channel-index) |
| `Byte 2` | Link mask | 1 byte | Bitmask — same OR pattern as [Enc §4.1 Matrix Input Mask](#41-matrix-input-mask), generalized to the channel's own bit position |
**Link mask rule:** bit `N` set → channel `N` is linked to this channel.
| Value | Meaning |
|---|---|
| `0x00` | No linked channels |
| `0x01`–`0x0F` | Valid range for input channels (bits 0–3 only) |
| `0x01`–`0xFF` | Valid range for output channels (bits 0–7) |
**Example**
<span style="color:#4ea1ff">10 02</span>
<span style="color:#a56eff">00 01</span>
<span style="color:#ffb347">03</span>
<span style="color:#ff6b6b">3B</span>
<span style="color:#5cd65c">03 08</span>
<span style="color:#4ea1ff">10 03</span>
<span style="color:#ffd700">33</span>
(Channel `0x03`, link mask `0x08` → linked to channel 3)
---
### `0x3D` — Set Channel Name
**Direction:** Host → Device
**Category:** Channel Configuration
**Purpose:** Sets the display name of an output channel.
**Sequencing:** Followed by `0x01`.
**Payload Fields**
| Offset | Field | Size | Encoding |
|---|---|---|---|
| `Byte 1` | Output channel index | 1 byte | [Enc §3.2 Channel Index](#32-channel-index) |
| `Byte 2`–`Byte 9` | Channel name | 8 bytes | [Enc §2.2 Channel Name](#22-channel-name) |
**Example**
<span style="color:#4ea1ff">10 02</span>
<span style="color:#a56eff">00 01</span>
<span style="color:#ffb347">0A</span>
<span style="color:#ff6b6b">3D</span>
<span style="color:#5cd65c">CH NAME[8]</span>
<span style="color:#4ea1ff">10 03</span>
<span style="color:#ffd700">CS</span>
---
## 8. Channel Processing
### `0x15` — Set Delay Unit
**Direction:** Host → Device
**Category:** Channel Processing
**Purpose:** Changes the display unit used for delay values.
**Sequencing:** Device acknowledges with `0x01`.
**Payload Fields**
| Offset | Field | Size | Encoding |
|---|---|---|---|
| `Byte 1` | Delay unit | 1 byte | [Enc §3.5 Delay Unit](#72-delay-unit) |
**Example**
<span style="color:#4ea1ff">10 02</span>
<span style="color:#a56eff">00 01</span>
<span style="color:#ffb347">02</span>
<span style="color:#ff6b6b">15</span>
<span style="color:#5cd65c">01</span>
<span style="color:#4ea1ff">10 03</span>
<span style="color:#ffd700">CS</span>
---
### `0x34` — Set Gain
**Direction:** Host → Device
**Category:** Channel Processing
**Purpose:** Sets a channel's gain.
**Sequencing:** Device acknowledges with `0x01`.
**Payload Fields**
| Offset | Field | Size | Encoding |
|---|---|---|---|
| `Byte 1` | Channel index | 1 byte | [Enc §3.2 Channel Index](#32-channel-index) |
| `Byte 2-3` | Gain | 2 bytes, little-endian | [Enc §5.1 Channel Gain](#51-channel-gain) |
**Example**
<span style="color:#4ea1ff">10 02</span>
<span style="color:#a56eff">00 01</span>
<span style="color:#ffb347">04</span>
<span style="color:#ff6b6b">34</span>
<span style="color:#5cd65c">CH LO HI</span>
<span style="color:#4ea1ff">10 03</span>
<span style="color:#ffd700">CS</span>
---
### `0x35` — Set Mute
**Direction:** Host → Device
**Category:** Channel Processing
**Purpose:** Mutes or unmutes a channel.
**Sequencing:** Device acknowledges with `0x01`.
**Payload Fields**
| Offset | Field | Size | Encoding |
|---|---|---|---|
| `Byte 1` | Channel index | 1 byte | [Enc §3.2 Channel Index](#32-channel-index) |
| `Byte 2` | Mute state | 1 byte | `0x00` = Unmuted, `0x01` = Muted |
**Example**
<span style="color:#4ea1ff">10 02</span>
<span style="color:#a56eff">00 01</span>
<span style="color:#ffb347">03</span>
<span style="color:#ff6b6b">35</span>
<span style="color:#5cd65c">CH MUTE</span>
<span style="color:#4ea1ff">10 03</span>
<span style="color:#ffd700">CS</span>
---
### `0x36` — Invert Gain
**Direction:** Host → Device
**Category:** Channel Processing
**Purpose:** Inverts polarity on a channel.
**Sequencing:** Device acknowledges with `0x01`.
**Payload Fields**
| Offset | Field | Size | Encoding |
|---|---|---|---|
| `Byte 1` | Channel index | 1 byte | [Enc §3.2 Channel Index](#32-channel-index) |
| `Byte 2` | Invert state | 1 byte | `0x00` = Normal, `0x01` = Inverted |
**Example**
<span style="color:#4ea1ff">10 02</span>
<span style="color:#a56eff">00 01</span>
<span style="color:#ffb347">03</span>
<span style="color:#ff6b6b">36</span>
<span style="color:#5cd65c">CH INVERT</span>
<span style="color:#4ea1ff">10 03</span>
<span style="color:#ffd700">CS</span>
---
### `0x38` — Set Delay
**Direction:** Host → Device
**Category:** Channel Processing
**Purpose:** Sets a channel's delay value.
**Sequencing:** Device acknowledges with `0x01`.
**Payload Fields**
| Offset | Field | Size | Encoding |
|---|---|---|---|
| `Byte 1` | Channel index | 1 byte | [Enc §3.2 Channel Index](#32-channel-index) |
| `Byte 2` | Reserved | 1 byte | Always `0x00` |
| `Byte 3` | Delay | 1 byte | [Enc §7.1 Channel Delay](#71-channel-delay) |
**Example**
<span style="color:#4ea1ff">10 02</span>
<span style="color:#a56eff">00 01</span>
<span style="color:#ffb347">04</span>
<span style="color:#ff6b6b">38</span>
<span style="color:#5cd65c">CH 00 DELAY</span>
<span style="color:#4ea1ff">10 03</span>
<span style="color:#ffd700">CS</span>
---
### `0x3C` — Bypass EQ
**Direction:** Host → Device
**Category:** Channel Processing
**Purpose:** Enables or bypasses all EQ processing on a channel.
**Sequencing:** Device acknowledges with `0x01`.
**Payload Fields**
| Offset | Field | Size | Encoding |
|---|---|---|---|
| `Byte 1` | Channel index | 1 byte | [Enc §3.2 Channel Index](#32-channel-index) |
| `Byte 2` | EQ bypass state | 1 byte | `0x00` = Active, `0x01` = Bypassed |
**Example**
<span style="color:#4ea1ff">10 02</span>
<span style="color:#a56eff">00 01</span>
<span style="color:#ffb347">03</span>
<span style="color:#ff6b6b">3C</span>
<span style="color:#5cd65c">CH BYPASS</span>
<span style="color:#4ea1ff">10 03</span>
<span style="color:#ffd700">CS</span>
---
## 9. Dynamics
### `0x30` — Set Compressor
**Direction:** Host → Device
**Category:** Dynamics
**Purpose:** Sets compressor parameters for a channel.
**Sequencing:** Device acknowledges with `0x01`.
**Payload Fields**
| Offset | Field | Size | Encoding |
|---|---|---|---|
| `Byte 1` | Channel index | 1 byte | [Enc §3.2 Channel Index](#32-channel-index) |
| `Byte 2-3` | Ratio | 2 bytes, little-endian | [Enc §3.6 Compressor Ratio](#36-compressor-ratio) |
| `Byte 4-5` | Attack | 2 bytes, little-endian | [Enc §6.2 Attack](#62-attack-compressor) |
| `Byte 6-7` | Release | 2 bytes, little-endian | [Enc §6.3 Release](#63-release-compressor) |
| `Byte 8-9` | Knee | 2 bytes, little-endian | [Enc §6.4 Knee](#64-knee-compressor) |
| `Byte 10-11` | Threshold | 2 bytes, little-endian | [Enc §6.7 Compressor Threshold](#67-compressor-threshold) |
**Example**
<span style="color:#4ea1ff">10 02</span>
<span style="color:#a56eff">00 01</span>
<span style="color:#ffb347">0C</span>
<span style="color:#ff6b6b">30</span>
<span style="color:#5cd65c">CH RA 00 AT_LO AT_HI RE_LO RE_HI KN 00 TH 00</span>
<span style="color:#4ea1ff">10 03</span>
<span style="color:#ffd700">CS</span>
---
### `0x3E` — Set Gate Parameters
**Direction:** Host → Device
**Category:** Dynamics
**Purpose:** Sets noise-gate parameters for a channel.
**Sequencing:** Device acknowledges with `0x01`.
**Payload Fields**
| Offset | Field | Size | Encoding |
|---|---|---|---|
| `Byte 1` | Channel index | 1 byte | [Enc §3.2 Channel Index](#32-channel-index) |
| `Byte 2-3` | Attack | 2 bytes, little-endian | [Enc §6.2 Attack](#62-attack-compressor) |
| `Byte 4-5` | Release | 2 bytes, little-endian | [Enc §6.3 Release](#63-release-compressor) |
| `Byte 6-7` | Hold | 2 bytes, little-endian | [Enc §6.1 Hold](#61-hold-gate) |
| `Byte 8-9` | Threshold | 2 bytes, little-endian | [Enc §6.6 Gate Threshold](#66-gate-threshold) |
**Example**
<span style="color:#4ea1ff">10 02</span>
<span style="color:#a56eff">00 01</span>
<span style="color:#ffb347">0A</span>
<span style="color:#ff6b6b">3E</span>
<span style="color:#5cd65c">CH AT 00 RE_LO RE_HI HO_LO HO_HI GA 00</span>
<span style="color:#4ea1ff">10 03</span>
<span style="color:#ffd700">82</span>
---
### `0x3F` — Set Output Limiter
**Direction:** Host → Device
**Category:** Dynamics
**Purpose:** Sets output-limiter parameters. Output channels only.
**Sequencing:** Device acknowledges with `0x01`.
**Payload Fields**
| Offset | Field | Size | Encoding |
|---|---|---|---|
| `Byte 1` | Output channel index | 1 byte | [Enc §3.2 Channel Index](#32-channel-index) |
| `Byte 2-3` | Attack | 2 bytes, little-endian | [Enc §6.2 Attack](#62-attack-compressor) |
| `Byte 4-5` | Release | 2 bytes, little-endian | [Enc §6.3 Release](#63-release-compressor) |
| `Byte 6-7` | Reserved | 2 bytes | Always `0000` |
| `Byte 8-9` | Threshold | 2 bytes, little-endian | [Enc §6.7 Compressor Threshold](#67-compressor-threshold) |
**Example**
<span style="color:#4ea1ff">10 02</span>
<span style="color:#a56eff">00 01</span>
<span style="color:#ffb347">0A</span>
<span style="color:#ff6b6b">3F</span>
<span style="color:#5cd65c">CH AT_LO AT_HI RE_LO RE_HI 00 00 TH 00</span>
<span style="color:#4ea1ff">10 03</span>
<span style="color:#ffd700">CS</span>
---
## 10. Filters & EQ
### `0x31` — Set Low-Pass Filter
**Direction:** Host → Device
**Category:** Filters & EQ
**Purpose:** Sets the low-pass filter for a channel.
**Sequencing:** Device acknowledges with `0x01`.
**Payload Fields**
| Offset | Field | Size | Encoding |
|---|---|---|---|
| `Byte 1` | Channel index | 1 byte | [Enc §3.2 Channel Index](#32-channel-index) |
| `Byte 2-3` | Cutoff frequency | 2 bytes, little-endian | [Enc §6.5 Sidechain Frequency](#65-sidechain-frequency-compressor) |
| `Byte 4` | Filter type | 1 byte | [Enc §3.9 Crossover Slope](#39-crossover-slope) |
**Example**
<span style="color:#4ea1ff">10 02</span>
<span style="color:#a56eff">00 01</span>
<span style="color:#ffb347">04</span>
<span style="color:#ff6b6b">31</span>
<span style="color:#5cd65c">CH FREQ_LO FREQ_HI TYPE</span>
<span style="color:#4ea1ff">10 03</span>
<span style="color:#ffd700">CS</span>
---
### `0x32` — Set High-Pass Filter
**Direction:** Host → Device
**Category:** Filters & EQ
**Purpose:** Sets the high-pass filter for a channel.
**Sequencing:** Device acknowledges with `0x01`.
**Payload Fields**
| Offset | Field | Size | Encoding |
|---|---|---|---|
| `Byte 1` | Channel index | 1 byte | [Enc §3.2 Channel Index](#32-channel-index) |
| `Byte 2-3` | Cutoff frequency | 2 bytes, little-endian | [Enc §6.5 Sidechain Frequency](#65-sidechain-frequency-compressor) |
| `Byte 4` | Filter type | 1 byte | [Enc §3.9 Crossover Slope](#39-crossover-slope) |
**Example**
<span style="color:#4ea1ff">10 02</span>
<span style="color:#a56eff">00 01</span>
<span style="color:#ffb347">04</span>
<span style="color:#ff6b6b">32</span>
<span style="color:#5cd65c">CH FREQ_LO FREQ_HI TYPE</span>
<span style="color:#4ea1ff">10 03</span>
<span style="color:#ffd700">CS</span>
---
### `0x33` — Set PEQ Band
**Direction:** Host → Device
**Category:** Filters & EQ
**Purpose:** Sets one parametric EQ band. Input channels only.
**Sequencing:** Device acknowledges with `0x01`.
**Payload Fields**
| Offset | Field | Size | Encoding |
|---|---|---|---|
| `Byte 1` | Channel index | 1 byte | [Enc §3.2 Channel Index](#32-channel-index) |
| `Byte 2` | PEQ band index | 1 byte | [Enc §3.3 PEQ Band Index](#33-peq-band-index) |
| `Byte 3-4` | Gain | 2 bytes, little-endian | [Enc §5.2 GEQ/PEQ Gain](#52-geq--peq-gain) |
| `Byte 5-6` | Frequency | 2 bytes, little-endian | [Enc §6.5 Sidechain Frequency](#65-sidechain-frequency-compressor)
| `Byte 7` | Q factor | 1 byte | [Enc §5.3 PEQ Q Factor](#53-peq-q-factor) | `0x00`–`0x64` |
| `Byte 8` | Filter type | 1 byte | [Enc §3.8 PEQ Filter Type](#38-peq-filter-type) | `0x00`–`0x08` |
| `Byte 9` | Bypass | 1 byte | `0x00` = Enabled, `0x01` = Bypassed |
**Example**
<span style="color:#4ea1ff">10 02</span>
<span style="color:#a56eff">00 01</span>
<span style="color:#ffb347">0A</span>
<span style="color:#ff6b6b">33</span>
<span style="color:#5cd65c">CH BAND GAIN 00 FREQ_LO FREQ_HI Q TYPE BYPASS</span>
<span style="color:#4ea1ff">10 03</span>
<span style="color:#ffd700">CS</span>
---
### `0x48` — Set GEQ Band
**Direction:** Host → Device
**Category:** Filters & EQ
**Purpose:** Sets one band of a 31-band graphic EQ. Input channels only.
**Sequencing:** Device acknowledges with `0x01`.
**Payload Fields**
| Offset | Field | Size | Encoding |
|---|---|---|---|
| `Byte 1` | Channel index | 1 byte | [Enc §3.2 Channel Index](#32-channel-index) |
| `Byte 2` | GEQ band index | 1 byte | [Enc §3.4 Frequency Band Index](#34-frequency-band-index) |
| `Byte 3-4` | Gain | 2 bytes, little-endian | [Enc §5.2 GEQ/PEQ Gain](#52-geq--peq-gain) |
**Example**
<span style="color:#4ea1ff">10 02</span>
<span style="color:#a56eff">00 01</span>
<span style="color:#ffb347">05</span>
<span style="color:#ff6b6b">48</span>
<span style="color:#5cd65c">CH BAND DB 00</span>
<span style="color:#4ea1ff">10 03</span>
<span style="color:#ffd700">CS</span>
---
### `0x49` — Set GEQ Bypass
**Direction:** Host → Device
**Category:** Filters & EQ
**Purpose:** Enables or bypasses the graphic EQ on an input channel.
**Sequencing:** Device acknowledges with `0x01`.
**Payload Fields**
| Offset | Field | Size | Encoding |
|---|---|---|---|
| `Byte 1` | Channel index | 1 byte | [Enc §3.2 Channel Index](#32-channel-index) |
| `Byte 2` | Bypass | 1 byte | `0x00` = GEQ enabled, `0x01` = GEQ bypassed |
**Example**
<span style="color:#4ea1ff">10 02</span>
<span style="color:#a56eff">00 01</span>
<span style="color:#ffb347">02</span>
<span style="color:#ff6b6b">49</span>
<span style="color:#5cd65c">CH BP</span>
<span style="color:#4ea1ff">10 03</span>
<span style="color:#ffd700">CS</span>
---
## 11. Input & Routing
### `0x39` — Set Input Source
**Direction:** Host → Device
**Category:** Input & Routing
**Purpose:** Selects the analog/test signal source.
**Sequencing:** Device acknowledges with `0x01`.
**Payload Fields**
| Offset | Field | Size | Encoding |
|---|---|---|---|
| `Byte 1` | Source type | 1 byte | [Enc §3.7 Input Source Type](#37-input-source-type) |
| `Byte 2` | Sine wave frequency (only meaningful when `Byte 1 = 0x03`) | 1 byte | [Enc §3.4 Frequency Band Index](#34-frequency-band-index) |
**Examples**
Analog:
<span style="color:#4ea1ff">10 02</span> <span style="color:#a56eff">00 01</span> <span style="color:#ffb347">03</span> <span style="color:#ff6b6b">39</span> <span style="color:#5cd65c">00 00</span> <span style="color:#4ea1ff">10 03</span> <span style="color:#ffd700">3A</span>
Pink Noise:
<span style="color:#4ea1ff">10 02</span> <span style="color:#a56eff">00 01</span> <span style="color:#ffb347">03</span> <span style="color:#ff6b6b">39</span> <span style="color:#5cd65c">01 00</span> <span style="color:#4ea1ff">10 03</span> <span style="color:#ffd700">3B</span>
White Noise:
<span style="color:#4ea1ff">10 02</span> <span style="color:#a56eff">00 01</span> <span style="color:#ffb347">03</span> <span style="color:#ff6b6b">39</span> <span style="color:#5cd65c">02 00</span> <span style="color:#4ea1ff">10 03</span> <span style="color:#ffd700">38</span>
Sine Wave:
<span style="color:#4ea1ff">10 02</span> <span style="color:#a56eff">00 01</span> <span style="color:#ffb347">03</span> <span style="color:#ff6b6b">39</span> <span style="color:#5cd65c">03 XX</span> <span style="color:#4ea1ff">10 03</span> <span style="color:#ffd700">YY</span>
---
### `0x3A` — Matrix Routing
**Direction:** Host → Device
**Category:** Input & Routing
**Purpose:** Sets which inputs feed a given output channel.
**Sequencing:** Device acknowledges with `0x01`.
**Payload Fields**
| Offset | Field | Size | Encoding |
|---|---|---|---|
| `Byte 1` | Output channel | 1 byte | [Enc §3.2 Channel Index](#32-channel-index) |
| `Byte 2` | Input routing mask | 1 byte | [Enc §4.1 Matrix Input Mask](#41-matrix-input-mask) |
**Example**
<span style="color:#4ea1ff">10 02</span>
<span style="color:#a56eff">00 01</span>
<span style="color:#ffb347">03</span>
<span style="color:#ff6b6b">3A</span>
<span style="color:#5cd65c">OUT INPUT_MASK</span>
<span style="color:#4ea1ff">10 03</span>
<span style="color:#ffd700">CS</span>
---
### `0x41` — Set Matrix Gain
**Direction:** Host → Device
**Category:** Input & Routing
**Purpose:** Sets the send gain from one input to one output.
**Sequencing:** Device acknowledges with `0x01`.
**Payload Fields**
| Offset | Field | Size | Encoding |
|---|---|---|---|
| `Byte 1` | Output channel index | 1 byte | [Enc §3.2 Channel Index](#32-channel-index) |
| `Byte 2` | Input channel index | 1 byte | [Enc §3.2 Channel Index](#32-channel-index) |
| `Byte 3-4` | Gain | 2 bytes, little-endian | [Enc §5.1 Channel Gain](#51-channel-gain) |
**Example**
<span style="color:#4ea1ff">10 02</span>
<span style="color:#a56eff">00 01</span>
<span style="color:#ffb347">05</span>
<span style="color:#ff6b6b">41</span>
<span style="color:#5cd65c">CH_OUT CH_IN GAIN_LO GAIN_HI</span>
<span style="color:#4ea1ff">10 03</span>
<span style="color:#ffd700">CS</span>
---
## 12. Metering
### `0x40` — Get Level Meters
**Direction:** Host → Device (Query), Device → Host (Response)
**Category:** Metering
**Purpose:** Reads current level-meter and clip-indicator values for all channels.
**Payload Fields (Response only)**
| Offset | Field | Size | Encoding |
|---|---|---|---|
| `Byte 1-36` | 12 meter channels | 3 bytes × 12 | [Enc §8.1 Meter Level](#81-meter-level) |
| `Byte 37` | Input clip indicator | 1 byte bitmask | Same OR bitmask pattern as [Enc §4.1](#41-matrix-input-mask) |
| `Byte 38` | Output clip indicator | 1 byte bitmask | Same OR bitmask pattern as [Enc §4.1](#41-matrix-input-mask) |
**Example — Query**
<span style="color:#4ea1ff">10 02</span>
<span style="color:#a56eff">00 01</span>
<span style="color:#ffb347">01</span>
<span style="color:#ff6b6b">40</span>
<span style="color:#4ea1ff">10 03</span>
<span style="color:#ffd700">41</span>
**Example — Response**
<span style="color:#4ea1ff">10 02</span>
<span style="color:#a56eff">01 00</span>
<span style="color:#ffb347">27</span>
<span style="color:#ff6b6b">40</span>
<span style="color:#5cd65c">A2 36 A5 A0 36 A0 ... 39 00 00</span>
<span style="color:#4ea1ff">10 03</span>
<span style="color:#ffd700">75</span>
---