OSC protocol
Everything the engine does, it does over OSC — drive it and watch it from a script, a controller, or whatever you feel like wiring up.
Everything the engine does, it does over OSC (UDP). Studio is just the best-known client; the contract is open to anything that can sling UDP packets — a script, a hardware controller, a phone, whatever you feel like wiring up. This page covers the shape of that contract.
The control / state contract
Messages fall into two directions:
- Control —
/omniphony/control/…, sent client → engine to change state or trigger an action. - State —
/omniphony/state/…, emitted engine → subscribed clients when something changes (and as snapshots on connect).
To receive state, a client registers first: send /omniphony/register [listen_port] to the engine’s receive port (default 9000), then keep it alive with periodic /omniphony/heartbeat [listen_port]. The engine answers with a full state bundle on registration and streams deltas after that. (Studio does exactly this — see Using Studio.)
Argument conventions
- Booleans are accepted as OSC
int(0/ non-zero),float, orbool; the engine coerces. Most toggles take a single int0/1. - Enums are lowercase strings; an unrecognised value is ignored — the engine validates and drops bad input rather than erroring.
- Realtime gain controls (
/control/realtime/*) carry a trailing monotonic sequence int so the engine can drop stale, out-of-order updates. - Larger structured payloads (layout, speakers, audio, input config) are sent as a single JSON string argument.
A few representative addresses
| Address | Args | Meaning |
|---|---|---|
/control/render_backend |
s |
Select the active backend by id. |
/control/backend/param |
[key, value] |
Set a backend parameter (schema-driven). |
/control/realtime/master_gain |
f, seq int |
Master gain. |
/control/output_mode |
s |
speaker / binaural output stage. |
/control/channel_render_mode |
s |
How non-object bed content is rendered. |
/control/save_config |
— | Persist the current config. |
The full state snapshot is published as /omniphony/state/renderer (JSON), with individual deltas for render config, metering, latency, head pose, and more.
The machine-readable single source of truth for every address is the
runtime_control::osc_contractmodule in the renderer (ALL_CONTROL/ALL_STATE). Generate against that rather than hardcoding strings, so your client never drifts from the engine. The repository’sdocs/osc-control-contract.mdis the full human-readable table.
Where backends fit
The two backend addresses in the table above (/control/render_backend, /control/backend/param) aren’t special-cased strings — the engine publishes each registered backend’s id, label, and parameter schema in the state snapshot, and every client (Studio included) generates its controls from that. So when you write your own backend, it shows up over this same contract for free, with no protocol changes.