Verified on a live S31 against an unused, silent input (restored after): a float fader write is accepted and echoed, but a mute written as int 0/1 or as an OSC True/False is silently ignored, while a float 1.0/0.0 works. DiGiCo's 2014 SD command list says int, which is wrong for the S31. Every switch (mute, solo, send on, group assign, EQ/dynamics/filter/ insert/delay switches, phantom, phase, pad, GEQ in) now goes out as a float. The mock console now ignores int and T/F switch writes the same way the console does, so a regression to int fails 38 checks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
195 lines
13 KiB
Markdown
195 lines
13 KiB
Markdown
# DiGiCo S-Series (S21 / S31): control and iPad relay
|
|
|
|
This connection does two things:
|
|
|
|
1. **Controls the console over OSC.** On connect it asks the console what it has (inputs, busses,
|
|
matrix outputs, control groups, graphic EQs, snapshots) and builds its dropdowns, variables and
|
|
presets from the live names. Faders, mutes, solos, pans, aux sends, group assigns, matrix sends,
|
|
control groups, graphic EQs, per-channel switches (phantom, EQ in, filters, inserts ...) and
|
|
snapshots are covered, with feedbacks, variables, rotary-encoder presets and input meters.
|
|
2. **Relays the DiGiCo iPad app.** An S-Series console talks to exactly one iPad at a time. Companion
|
|
takes that slot and the iPad apps connect to this computer instead; everything an app sends is
|
|
forwarded to the console unchanged, and everything the console sends is copied to every app, so
|
|
several iPads can be used together with Companion.
|
|
|
|
## Console setup (once, at the surface)
|
|
|
|
Main Menu, **Extensions > iPad**:
|
|
|
|
| Console field | Value |
|
|
| --- | --- |
|
|
| iPad IP address | the computer running Companion |
|
|
| Send port *(console to this computer)* | this connection's **Local receive port** (default `9000`) |
|
|
| Receive port *(this computer to the console)* | this connection's **Console receive port** (default `8000`) |
|
|
| iPad connection | enabled |
|
|
|
|
The console sends every reply and every change to that one IP address and Send port, never to the
|
|
port a query came from. That is why the connection binds a fixed local port.
|
|
|
|
## iPad app setup
|
|
|
|
In the DiGiCo S app, for every iPad:
|
|
|
|
| iPad field | Value |
|
|
| --- | --- |
|
|
| Console IP | the computer running Companion, **not** the console |
|
|
| Send port | this connection's **Relay port** (default `8000`) |
|
|
| Receive port | this connection's **iPad receive port** (default `9000`) |
|
|
|
|
An iPad that stays quiet for *Forget an iPad after* seconds (0 = never) is dropped from the fan-out list, and at most
|
|
16 are kept. `$(label:relay_clients)` shows how many are live. Changing only the idle timeout, the iPad receive port or
|
|
Debug logging does not interrupt the relay or the console link; changing the relay port reopens the relay and keeps the
|
|
list of iPads. If the relay port is already in use the connection shows the warning "iPad relay: port N in use" and tries
|
|
again every 10 seconds (a console-link port that cannot be bound shows a connection failure and is retried the same way). Other controllers share the console through the relay,
|
|
and anything they change reaches this module too, so feedbacks follow moves made on the surface or on an iPad.
|
|
|
|
## Settings
|
|
|
|
| Setting | Default | Meaning |
|
|
| --- | --- | --- |
|
|
| Console IP | | The console's address |
|
|
| Console receive port | 8000 | UDP port the module sends to |
|
|
| Local receive port | 9000 | UDP port the module listens on (the console's Send port) |
|
|
| Enable iPad relay | on | Turns the relay on |
|
|
| Relay port | 8000 | Where iPad apps send |
|
|
| iPad receive port | 9000 | Where relayed console traffic goes (0 = the app's own source port) |
|
|
| Forget an iPad after | 3600 s | Idle time before an iPad is dropped (0 = never; an iPad that only watches sends nothing). At most 16 iPads are kept; the least recently seen is dropped first |
|
|
| Debug logging | off | Logs every new address pattern once and all traffic at debug level |
|
|
|
|
## What it discovers
|
|
|
|
On every connect (and on the **Reload** action, and automatically after the console was silent for
|
|
20 seconds and comes back) the module asks for the console name, the matrix, control group and graphic EQ
|
|
counts, the buss types and modes, every name, the session name, the snapshot list, and the fader, mute,
|
|
solo and pan of everything that answered. The console does not answer the input and buss counts, so an
|
|
entity exists when its **name** answered; entities that never answer are hidden from dropdowns, variables
|
|
and presets. Dropdown entries read `1 · KICK In`, `24 · Monitors (group)`, `3 · Message · cue 4`.
|
|
When a name, a buss mode or the snapshot list changes, the definitions are rebuilt a moment later.
|
|
Sends, group assigns, matrix sends, graphic EQ gains and the per-channel switches are **not** bulk-loaded:
|
|
each is read the first time a button or action needs it.
|
|
|
|
The 25 busses are each an **aux** or a **group**, according to `/Console/Aux_Outputs/types` (1 = aux,
|
|
0 = group). Aux busses take sends (level, on, pan); group busses take input assigns. A buss's
|
|
fader, mute and solo are on the Aux_Outputs or Group_Outputs side that matches its mode.
|
|
|
|
## Actions
|
|
|
|
Level actions take dB (`-inf` at the bottom of the number field). Every level has a **set** and a
|
|
relative **adjust** version for rotary encoders; adjusting from -inf lands at -60 dB on the first step up.
|
|
Toggles read the current state first when it is not known yet.
|
|
|
|
| Group | Actions |
|
|
| --- | --- |
|
|
| Inputs | mute, solo (several inputs at once), fader set/adjust, pan set/adjust, set name |
|
|
| Aux sends | on/off, level set/adjust, pan set/adjust |
|
|
| Groups | assign input on/off |
|
|
| Busses | mute, solo (several), fader set/adjust |
|
|
| Matrix | output mute, fader set/adjust; matrix send on/off, level set/adjust |
|
|
| Control groups | mute, solo, fader set/adjust |
|
|
| Graphic EQ | in/out, band gain set/adjust (bands 1-32) |
|
|
| Channel strip | per input and per buss: phantom, phase, pad, EQ in, compressor in, gate in, high-pass in, low-pass in, delay in, insert A/B in (on/off); trim (-40 to +40 dB), analog gain (0 to 60 dB), filter frequencies (20 to 20000 Hz) (set/adjust; trim also on matrix outputs) |
|
|
| Snapshots | fire (pick from the list or type an index), next, previous |
|
|
| Console | reload, raw OSC, relay: forget all iPads |
|
|
|
|
The channel-strip values are what the console reports (trim and gain in dB, filters in Hz). In the console's
|
|
own naming `lo_filter` is the high-pass filter and `hi_filter` the low-pass filter; the actions are named for
|
|
what they do. Delay times and the send pre/post fader switch are not offered: their units and meaning were
|
|
never verified.
|
|
|
|
**Encoders and writes.** Every write updates the module's state at once, so a fast encoder turn accumulates. For
|
|
0.4 seconds after the last write to a value, a different value arriving for it is treated as a late echo of an
|
|
earlier step and ignored; then one query confirms what the console has. The snapshot *Fire* action sends the
|
|
snapshot's list position (0 = the first); verify it once on your console before using it live.
|
|
|
|
**Macros:** the console never answered a macro query, so there is no macro action. If your console supports it, the
|
|
*Send raw OSC* action can send `/Macros/Buttons/press` with an integer argument (0-255).
|
|
|
|
## Feedbacks
|
|
|
|
* Boolean (button colour): input muted / solo, aux send on, group assigned, buss muted /
|
|
solo, matrix muted, control group muted, snapshot is current, fader level above/below a threshold, send
|
|
level above/below, console link alive, relay has an iPad, every channel-strip switch above, and the meter
|
|
feedbacks below.
|
|
* Value (use with a preset's local variable to put live numbers in button text): input fader, input pan,
|
|
send level, send On/Off, buss / matrix / control group fader, current snapshot name, input meter value.
|
|
* Advanced bars: input fader, aux send level and buss fader draw a horizontal bar along the bottom of the
|
|
button (-60 to +10 dB); the input meter draws a vertical bar at the right edge (green, amber, red).
|
|
|
|
## Variables
|
|
|
|
`input_N_name|fader|mute|pan`, `buss_N_name|mode|stereo|fader|mute`, `matrix_N_name|fader|mute`,
|
|
`cg_N_name|fader|mute` (only for entities that exist), `snapshot_index|name|cue|count`, `console_name`,
|
|
`session_name`, `connected`, `relay_clients`, `relay_client_ips` and `last_change`. Use them as
|
|
`$(label:input_1_name)` with the connection's label. There are no per-send variables: use the value feedbacks.
|
|
|
|
## Presets
|
|
|
|
Presets are named with the live entity names and rebuilt when names load.
|
|
|
|
| Preset group | What the buttons do |
|
|
| --- | --- |
|
|
| Inputs: Mute | One button per input; red when muted |
|
|
| Inputs: Fader (knob) | Rotary: turn = fader -/+1 dB, press = mute; shows name and dB, with a level bar |
|
|
| Inputs: Solo | One button per input |
|
|
| Busses | Master mute, and master fader knob (turn = fader, press = mute) per named buss |
|
|
| Sends to *aux name* | One section per named aux buss: per input an **On/off** button (green when on, shows the level) and a **Level (knob)** (turn = send level, press = on/off, with a bar) |
|
|
| Group *group name* | One section per named group buss: per input an **Assign** toggle, green when assigned |
|
|
| Matrix, Control groups | Mute and fader knob per output / group |
|
|
| Snapshots | **Fire** per snapshot (green when current), next, previous, current (display) |
|
|
| Input meters | Level, gate gain reduction and compressor gain reduction buttons per input |
|
|
| Console | Reload, connection status, relay status |
|
|
|
|
Busses and control groups with no name are unused slots and get no presets. If the preset list would exceed
|
|
3000 entries or 4 MB, the per-input send level knobs are left out and a warning is logged.
|
|
|
|
## Meters
|
|
|
|
Input meters are subscribed on the console the first time a meter feedback renders (ids start at 5000 so
|
|
they never collide with an iPad's). The console then streams values 0-127 several times a second; the
|
|
module re-checks the meter feedbacks at most 10 times a second. Level is the post-fader input meter; gate and
|
|
compressor gain reduction are the two reduction meters. There is no known buss meter address, so busses
|
|
have no meters. The console keeps one subscription table: an iPad connecting clears it (`/Meters/clear`),
|
|
and the module re-subscribes half a second after it sees that pass through the relay. Two iPads watching
|
|
different banks both receive the mixed stream. The module never sends `/Meters/clear` itself.
|
|
|
|
## Troubleshooting
|
|
|
|
* **No reply from the console.** The console only answers to the iPad IP address and Send port set on the
|
|
console. Check them, and that nothing else on this computer owns the local receive port.
|
|
* **Dropdowns show generic names.** The load has not finished or the console did not answer the names;
|
|
press **Reload**. The log shows `load complete` with the counts when it is done.
|
|
* **Something changed on the console is not shown.** Press Reload after a session change; sends and
|
|
per-channel values are only read when first needed.
|
|
* **Debug logging** lists every new address pattern once (Connections log), so touching a control on the
|
|
surface shows its address; `$(label:last_change)` shows the last change reported.
|
|
|
|
## Protocol (condensed)
|
|
|
|
A query is the address plus `/?` with no argument; the reply is the same address without `/?`. All 0/1
|
|
switches are **reported and written as floats** (0.0 / 1.0), verified on an S31 on 2026-10-15: integer and
|
|
OSC `T`/`F` writes to a switch are silently ignored (no echo, no change), unlike the 2014 DiGiCo list.
|
|
Levels, sends and pans are floats too. Numbers are 1-based, snapshot indexes 0-based.
|
|
|
|
| Address | Reply | Notes |
|
|
| --- | --- | --- |
|
|
| `/Console/Name` | s | also the keepalive (every 5 s) |
|
|
| `/Console/{Matrix_Outputs,Matrix_Inputs,Control_Groups,Graphic_EQ}` | i | counts that answer |
|
|
| `/Console/{Input_Channels,Aux_Outputs,Group_Outputs}` | i | pushed once after first contact, never answered |
|
|
| `/Console/Aux_Outputs/types` | 25 x i | 1 = aux, 0 = group |
|
|
| `/Console/{Aux_Outputs,Group_Outputs,Input_Channels}/modes` | i per buss / input | 2 = stereo, 1 = mono |
|
|
| `/Console/Session/Filename` | s | |
|
|
| `/Input_Channels/N/Channel_Input/name`, `/Aux_Outputs/N/Buss_Trim/name`, `/Group_Outputs/N/Buss_Trim/name`, `/Matrix_Outputs/N/Buss_Trim/name`, `/Control_Groups/N/name`, `/Graphic_EQ/N/name` | s | matrix inputs have no name address |
|
|
| `/{Input_Channels,Aux_Outputs,Group_Outputs,Matrix_Outputs,Control_Groups}/N/{fader,mute,solo}` | f | fader in dB, -150 = -inf |
|
|
| `/Input_Channels/N/Panner/pan` | f | 0..1, 0.5 = centre |
|
|
| `/Input_Channels/N/Aux_Send/M/{send_level,send_on,send_pan}` | f | |
|
|
| `/Input_Channels/N/Group_Send/M/group` | f | |
|
|
| `/Matrix_Inputs/N/Matrix_Send/M/{send_level,send_on}` | f | |
|
|
| `/Graphic_EQ/N/{geq_in,geq_gain_1..32}` | f | |
|
|
| `/Input_Channels/N/{Channel_Input,Filters,Channel_Delay,EQ,Dynamics,Insert}/...` and the buss equivalents | f | the channel-strip switches and values above |
|
|
| `/Snapshots/Current_Snapshot`, `/Snapshots/count` | i | |
|
|
| `/Snapshots/names` | one `/Snapshots/name` `iiis` per snapshot: index, cue x 100, ?, name | |
|
|
| `/Snapshots/Fire_Snapshot_number`, `/Snapshots/Fire_Next_Snapshot`, `/Snapshots/Fire_Prev_Snapshot` | none | write-only int |
|
|
| `/Input_Channels/N/Channel_Input/post_meter`, `/Input_Channels/N/Dynamics/GR_meter` | none | send `,ii [id, kind]` (kind 1 level and gate, 4 compressor) to subscribe |
|
|
| `/Meters/values` | `ii...` | pushed pairs `[id, value]`, value 0..127 |
|
|
| `/Meters/clear` | none | clears every subscription on the console; sent by iPad apps, never by this module |
|