ucmix — StudioLive mixer control
ucmix reads and writes any parameter on a PreSonus StudioLive Series III mixer
over the mixer's own network protocol (UCNET). No PreSonus software is required
or involved — it talks straight to the mixer's control port.
First checks
command -v ucmix
ucmix --version
ucmix profile ls # is a mixer saved?
If ucmix is missing, install it:
brew install steveclarke/tap/ucmix
If no mixer is configured, find and save one (mixers announce themselves on the LAN):
ucmix discover # list mixers on the network
ucmix setup # interactive: pick one, name it, save it as the current profile
# or, if you already know the address:
ucmix profile add foh --host 192.168.1.50 --use
Every command then uses the current profile. Override per-command with -p <name>
or --host <ip>.
The model — two verbs over one namespace
The mixer is one flat namespace of ~20,000 parameters, each a path → value:
line/ch1/username = "Drums" # channel 1 name
line/ch1/48v = true # phantom power
line/ch1/volume = -6 # fader, dB
aux/ch1/limit/threshold = -6 # monitor-mix limiter, dB
fx/ch1/plugin/reflection = 0.79 # a reverb knob (raw)
Everything the mixer can do is one of those paths. Two verbs cover all of it:
ucmix get <path>— read one valueucmix set <path> <value>— write one value; alsoset p1=v1 p2=v2 …orset -f <file>(apath valueper line) to write many over one connection
Read reference/paths.md for the path grammar (groups, channel indexing, and the
value form for each parameter family). To see the exact live paths on a specific
board, run ucmix dump (all) or ucmix dump <prefix> (filtered).
Humanized vs raw values
Common controls accept human values and the tool converts to the wire form:
| Path family | You write | Not the raw wire value |
|---|---|---|
.../48v, .../mute, .../*on*, .../link |
on / off |
(bool) |
.../volume, .../aux{n}, .../FXA..FXH, .../limit/threshold |
dB, e.g. -6dB |
|
.../limit/release |
ms, e.g. 400 |
|
.../username |
a string, e.g. "Vox Steve" |
|
.../color |
hex, e.g. 4ed2ff |
reads back as 8 lowercase RGBA digits (4ed2ffff) |
.../iconid |
an icon id, e.g. vocals/leadvocals |
|
.../adc_src (input patch) |
the input number, e.g. 5 |
Every other path has no humanizing layer — you pass the raw wire value the
mixer expects, usually a float in 0..1 (e.g. fx/ch1/plugin/lpf 0.869), an
integer index, or an enum number. get <path> returns the raw value; get <path> --raw forces raw even on humanized paths. When reproducing a captured setting,
read its raw value and write that same raw value back.
Commands
Run ucmix <command> --help for flags; the CLI evolves, so verify against --help
rather than trusting this list to be complete.
get <path>/set <path> <value>— read / write one parameterset p1=v1 p2=v2 …/set -f <file>— write many parameters over one connectionchannel <n> <verb> <value>/mix <name|n> <verb> <value>/send <ch> <mix> <dB>— human shortcuts oversetfor the common channel-strip, monitor-mix, and send actions (a thin veneer; the rawsetpath model still covers everything). Built for humans at a keyboard — an agent should keep using rawget/setbelow.dump [prefix]— read every path (or those under a prefix);--as-configemits YAMLverify <config.yml>/apply <config.yml>— board as code: diff / write a whole configstore <project> <name>— store the current state as a new scene (--replaceto overwrite one);recall <project> <scene>— load a stored scene;rename <project> <scene> <new-name>— retitle one;delete <project> <scene>— remove one (destructive; needs--yesor a prompt). Project and scene arguments accept either the display title ("135 Main Live","Opening") or the board's slot name ("03.135 Main Live.proj","04.Opening.scn")reset— factory reset (destructive; needs--yes)ls projects— list projects on the board;ls scenes <project>— list a project's scenes.<project>is a name fromls projects(e.g.01.Sevenview Live.proj). Both take--json.project ls— list projects with their titles, marking the one the board has loadedfilters ls [scene|advanced|project]/filters set <group> <tile> <on|off>— the scope filters that decide what a store, recall or reset touchesdiscover/setup/profile/config— find/save/manage mixer connections
Agent rules
- Use
--jsonfor any command whose output you will parse;--no-colorfor plain text. - Verify writes with a fresh
get.setreports that it sent the value, not that the board is now in that state. Read it back to confirm. - Prefer humanized values (
-6dB,on, an input number) where a path family supports them; fall back to raw0..1wire values for everything else. - To copy a setting from one board/state to another,
get <path> --rawthenset <path> <that raw value>— raw round-trips exactly. - Write many parameters in one call —
set p1=v1 p2=v2 …orset -f <file>— rather than loopingset. A batch reuses one connection and commits once; separatesetprocesses reconnect per write and can drop writes under rapid reconnect. resetandapply --resetare destructive — only with--yesand a clear target.- Never assume a path exists; confirm with
dump <prefix>orgeton a real board.
Scenes — store, recall, rename
store allocates the next free scene slot itself, the same way UC Surface does, and
refuses to overwrite an existing scene of that name unless given --replace. A project
holds 20 scene slots; ErrNoFreeSlot means they are all taken (delete one in UC Surface).
store and recall wait for the board to confirm the operation and fail if it never
does — a store that reports success really is on disk. This matters because the
underlying request is fire-and-forget: earlier versions printed success as soon as the bytes
were sent, and a scene the board dropped looked saved. If store errors, treat the scene as
NOT stored.
Because they wait on the board, both take a few seconds. That is the board committing to flash, not a hang.
ucmix store "135 Main Live" "Opening" # new scene, next free slot
ucmix store "135 Main Live" "Opening" --replace # overwrite it deliberately
ucmix rename "135 Main Live" "Opening" "Opening Set" # retitle, keeps its slot
ucmix recall "135 Main Live" "Opening Set"
ucmix delete "135 Main Live" "Opening Set" --yes # destructive, frees the slot
delete frees the scene's slot, which the next store reuses. Like store and recall
it waits for the board to confirm. It prompts before acting; --yes skips the prompt and
is required when there is no terminal.
The project layer and scope filters
A project is the setup a scene sits on: input source and patching, AVB/SD/USB routing,
flex mode, GEQ, solo. Scenes live inside a project. project ls lists the projects and marks
the loaded one. Storing or recalling a project as a unit is not implemented — the request
UC Surface sends for it has not been captured (issue #6), and project store / project recall fail with that explanation rather than guessing at the format.
The scope filters are the blue tiles that decide what a store, recall or reset actually
touches. Each tile is an ordinary parameter, so it reads through get/dump and writes
through set; filters is the named surface over them.
ucmix filters ls # every tile in every group, with its state
ucmix filters ls scene --json # one group, machine-readable
ucmix filters set scene 48v on # include phantom power in a store/recall
ucmix filters set project inputpatching off
Groups: scene (Scene Filter, global/fltr*), advanced (Advanced Scene Filter,
advancedscenefilters/*), project (Project Filter, projectfilters/*). Tile names are the
board's own key names, so a tile names the parameter it writes; - and _ are
interchangeable. filters set reads the tile back on a fresh connection and reports what the
board holds, the same as set and the noun verbs.
A board ships with the scene filter's 48v tile excluded, which is why recalling a scene
leaves phantom power as it is. Changing a filter changes what every later store and recall
carries — it is a global setting, not a per-command flag.
Known limitations
ls projects/ls sceneslist the board's presets over the FR/FD file-request protocol (the same one UC Surface uses). A board that never answers fails with a clear timeout and hint instead of hanging. Empty slots and the project config file are dropped from the output; only occupied projects/scenes are shown.applywrites over one connection with a library commit barrier and verifies on a fresh connection (a freshget).set -f <file>is the same batch write path without the verify.renameis confirmed by re-listing the project, not by a board acknowledgment (the board sends none for a rename).store,recall, anddeleteall wait on a real one.resetis still unconfirmed fire-and-forget — it reports that the request was sent, not that the board acted on it.- Scope-filter reads are hardware-confirmed on a 32R (firmware 3.4.0), and the write path was confirmed by flipping one tile and reading it back. A project store/recall has no captured request and is not implemented.
- The high-pass filter is calibrated: Hz over the board's 24 Hz – 1 kHz sweep,
logarithmic,
0= off. The limiter release curve and reverb-type enums are not — their humanized conversions are approximate. Use raw values when exactness matters. - Some UCNET parameters have no control in UC Surface (e.g. an FX return's Main/LR
assign,
fxreturn/chN/lr). Writing one leaves the board in a state the operator cannot see or undo from the console. Prefer a change that maps to a visible UC Surface control (e.g. pull the FX return fader down for a dry main, not an LR unassign), and when a write has no UI equivalent, say so.