# 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 | ■ | Fixed start marker: `10 02` | | `DIR` | 2 bytes | ■ | Direction (see below) | | `LEN` | 1 byte | ■ | Byte count of `CMD + DATA` | | `CMD` | 1 byte | ■ | Command code | | `DATA` | `LEN - 1` bytes | ■ | Command payload (may be 0 bytes) | | `ETX` | 2 bytes | ■ | Fixed end marker: `10 03` | | `CS` | 1 byte | ■ | Checksum (see below) | Example skeleton: 10 02 DIR DIR LEN CMD DATA... 10 03 CS ### 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** 10 02 01 00 01 01 10 03 00 --- ### `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** 10 02 01 00 01 02 10 03 00 --- ### `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** 10 02 00 01 01 10 10 03 11 **Example — Response** 10 02 01 00 02 10 13 10 03 01 --- ### `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** 10 02 00 01 01 11 10 03 10 --- ### `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** 10 02 00 01 01 12 10 03 13 --- ## 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** 10 02 00 01 01 13 10 03 12 **Example — Response** 10 02 01 00 0E 13 44 53 50 34 30 38 20 56 30 31 30 34 50 10 03 45 --- ### `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** 10 02 00 01 01 2C 10 03 2D **Example — Response** 10 02 01 00 07 2C 00 27 0F 00 00 00 10 03 03 --- ## 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** 10 02 00 01 01 14 10 03 15 **Example — Response** 10 02 01 00 02 14 06 10 03 10 --- ### `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** 10 02 00 01 02 20 10 10 03 32 --- ### `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** 10 02 00 01 02 21 01 10 03 CS --- ### `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** 10 02 00 01 01 22 10 03 23 **Example — Response** 10 02 01 00 15 22 FF 00 FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 03 37 --- ### `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** 10 02 00 01 01 23 10 03 CS --- ### `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** 10 02 00 01 03 27 INDEX 10 03 CS **Example — Response** 10 02 01 00 34 24 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 10 03 BF --- ### 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** 10 02 00 01 0F 26 50 72 65 73 65 74 20 4E 61 6D 65 20 20 20 10 03 CS --- ### `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** 10 02 00 01 02 29 00 10 03 2B **Example — Response** 10 02 01 00 10 29 4D 61 69 6E 20 70 72 65 73 65 74 20 20 20 10 03 17 --- ## 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`)** 10 02 00 01 06 2D 00 31 32 33 34 10 03 2F **Example — Response** 10 02 01 00 03 2D 00 01 10 03 2F --- ### `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`)** 10 02 00 01 05 2F 31 32 33 34 10 03 2E --- ## 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** 10 02 00 01 03 2A 00 01 10 03 28 --- ### `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** 10 02 00 01 03 3B 03 08 10 03 33 (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** 10 02 00 01 0A 3D CH NAME[8] 10 03 CS --- ## 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** 10 02 00 01 02 15 01 10 03 CS --- ### `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** 10 02 00 01 04 34 CH LO HI 10 03 CS --- ### `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** 10 02 00 01 03 35 CH MUTE 10 03 CS --- ### `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** 10 02 00 01 03 36 CH INVERT 10 03 CS --- ### `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** 10 02 00 01 04 38 CH 00 DELAY 10 03 CS --- ### `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** 10 02 00 01 03 3C CH BYPASS 10 03 CS --- ## 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** 10 02 00 01 0C 30 CH RA 00 AT_LO AT_HI RE_LO RE_HI KN 00 TH 00 10 03 CS --- ### `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** 10 02 00 01 0A 3E CH AT 00 RE_LO RE_HI HO_LO HO_HI GA 00 10 03 82 --- ### `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** 10 02 00 01 0A 3F CH AT_LO AT_HI RE_LO RE_HI 00 00 TH 00 10 03 CS --- ## 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** 10 02 00 01 04 31 CH FREQ_LO FREQ_HI TYPE 10 03 CS --- ### `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** 10 02 00 01 04 32 CH FREQ_LO FREQ_HI TYPE 10 03 CS --- ### `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** 10 02 00 01 0A 33 CH BAND GAIN 00 FREQ_LO FREQ_HI Q TYPE BYPASS 10 03 CS --- ### `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** 10 02 00 01 05 48 CH BAND DB 00 10 03 CS --- ### `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** 10 02 00 01 02 49 CH BP 10 03 CS --- ## 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: 10 02 00 01 03 39 00 00 10 03 3A Pink Noise: 10 02 00 01 03 39 01 00 10 03 3B White Noise: 10 02 00 01 03 39 02 00 10 03 38 Sine Wave: 10 02 00 01 03 39 03 XX 10 03 YY --- ### `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** 10 02 00 01 03 3A OUT INPUT_MASK 10 03 CS --- ### `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** 10 02 00 01 05 41 CH_OUT CH_IN GAIN_LO GAIN_HI 10 03 CS --- ## 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** 10 02 00 01 01 40 10 03 41 **Example — Response** 10 02 01 00 27 40 A2 36 A5 A0 36 A0 ... 39 00 00 10 03 75 ---