Reference

OSC and WebSocket API

Draft. This API is planned for a coming release and isn’t in the current preview build. Addresses may change before then.

Overview

Chronos Studio accepts OSC commands to run the show and pushes live status back to anyone who subscribes. Consoles, QLab, Bitfocus Companion, TouchOSC or a tablet can drive it and show its state without touching the Chronos screen.

  • Two directions: control in (transport, locate, sources, outputs, Chronos Sync, Chronos Cue) and live status out (timecode, lock, transport, sync health, cues fired).
  • Separate from Chronos Cue’s own OSC events. Cue sends whatever addresses the show designer programs at set timecodes. This API is Chronos’s own fixed address space.
  • Status is for display, not sync. OSC over a network can’t hold frame accuracy, so machines still sync over LTC, MTC or Art-Net.
  • Versioned: every address starts with /chronos/. /chronos/version replies with the API version (1.0) and the app version. Breaking changes would move to /chronos/v2/.
  • Licence-aware: addresses for modules the licence doesn’t include reply module_locked instead of acting.

Everything the app can do or show has an address. Every setting, every show-file edit and every value on screen can be read, changed and subscribed to over OSC. The only exceptions are licence keys and the OSC passcode itself, which stay in the app. Controllers can discover the full address tree with OSCQuery (see Show files, settings and devices).

Connection

Chronos listens on port 53800 for UDP, TCP, WebSocket and HTTP (changeable in Settings), and only on the network interface the operator picks.

Transport Framing Use it for
UDP One OSC packet per datagram (OSC 1.0) Consoles, Companion, TouchOSC; control and live status
TCP SLIP-framed OSC (OSC 1.1) Controllers that need every reply delivered; show-control software
WebSocket ws://<machine>:53800/chronos: binary frames = one OSC packet each; text frames = JSON {"address": "/chronos/transport/play", "args": []} Browser and web-app controllers, dashboards, scripts; same addresses, replies and subscriptions
HTTP OSCQuery on the same port Discovering the address tree (see Show files, settings and devices)
  • Replies go back to the sender’s address and source port. A controller that listens elsewhere sends /chronos/replyport <i:port> once.
  • Discovery: Chronos advertises _osc._udp and _osc._tcp over Bonjour/mDNS with the machine name, so controllers can find it without typing an IP.
  • Security (off by default):
    • Allowed addresses: a list of IPs or subnets; everything else is ignored silently.
    • Passcode: when set, a client sends /chronos/connect <s:passcode> first. The session lasts until 60 s without traffic.
    • Read-only mode: status and queries work, control replies not_allowed.
  • Loopback: 127.0.0.1 is always allowed, for software on the same machine.

Conventions

Send an address with arguments to change something; send it with no arguments to ask for its current value.

  • Addresses are lowercase, /chronos/<area>/<item>, with ids as path parts where needed (/chronos/output/ltc1/enable).
  • Types: s string, i int32, f float32. Booleans are ints 0 or 1, since many controllers can’t send OSC T/F.
  • Timecode is a string HH:MM:SS:FF, with ; before the frames for drop-frame (01:00:00;00). Status messages also carry the absolute frame count as an int.
  • Rates are strings: 23.976, 24, 25, 29.97df, 29.97, 30.
  • Ids are short and stable: outputs ltc1, mtc1, artnet1; sources ltc1, mtc1, artnet1, link, internal.
  • Replies: every message gets /chronos/reply/<original address> followed by s:ok and any values, or s:error, s:<code>, s:<message>. /chronos/replies <i:0|1> turns replies off for fire-and-forget controllers.
  • Bundles are applied together in one frame, for example a rate change and a locate.
  • Wildcards (*, ?, [ ], {a,b} from OSC 1.0) work on ids: /chronos/output/*/enable 0 mutes every output.

Control: transport and generator

These run Chronos Core, so every licence has them (Chronos Edit accepts them but sends no live output).

Address Arguments What it does
/chronos/mode s: generate | chase | convert Sets how Chronos makes its clock
/chronos/transport/play none Runs the generator from the current position
/chronos/transport/pause none Holds the current frame, outputs keep sending it
/chronos/transport/stop none Stops and returns to the start time
/chronos/transport/locate s: timecode Jumps to a time; keeps playing if it was playing
/chronos/transport/nudge i: frames (signed) Moves the clock by whole frames
/chronos/generator/start s: timecode Sets the start time that Stop returns to
/chronos/generator/rate s: rate Sets the generator frame rate
/chronos/generator/offset s: timecode, optional i: 1 for negative Global offset added before every output

With no arguments, /chronos/mode, /chronos/generator/rate and the other setters reply with their current value.

Sources, chase and outputs

Sources and outputs are named by id; /chronos/source/list and /chronos/output/list reply with the ids this machine has.

Address Arguments What it does Module
/chronos/source/select s: id Picks what Chronos chases (ltc1, mtc1, artnet1, link) Core; link needs Link
/chronos/source/list none Replies with every source id and whether it has signal Core
/chronos/chase/freewheel i: frames How long to keep running after the source drops Core
/chronos/chase/jam i: 0 | 1 Jam-sync: lock once, then run on the internal clock Core
/chronos/output/list none Replies with every output id and whether it’s on Core
/chronos/output/<id>/enable i: 0 | 1 Turns one output on or off Core
/chronos/output/<id>/offset s: timecode, optional i: 1 for negative Offset for that output only Core
/chronos/output/<id>/rate s: rate Output frame rate when converting Core
/chronos/link/follow s: master | deck1 … deck6 Which CDJ or mixer channel Chronos Link follows Link

Tracks and markers

Chronos can say what is playing: the track on each DJ deck (Chronos Link) and the named sections of the show timeline (markers such as songs or scenes, saved in the show file). Query them here, or subscribe to the track topic under Live status.

Address Arguments What it replies Module
/chronos/track/now none What Chronos is following: s: source (deck2, marker), s: title, s: artist, f: BPM, s: position, s: remaining Core (markers); Link (decks)
/chronos/track/next none The next marker, or the track loaded on the other deck: s: title, s: starts at Core; Link
/chronos/link/decks none Every deck: s: deck, s: title, s: artist, f: BPM, s: key, i: on air Link
/chronos/marker/list none Every marker: s: number, s: name, s: start timecode, s: end timecode Core
/chronos/marker/<n>/locate none Jumps the generator to that marker’s start Core
/chronos/marker/add s: name, optional s: timecode (default: now) Adds a marker to the show file, e.g. while rehearsing Core

Titles and artists come from the DJ gear’s own metadata; Chronos only reports them.

Show files, settings and devices

Everything on the app’s settings screens is one settings tree, so a controller can read or change any of it with two addresses, without the API growing a new address for each option.

Address Arguments What it does
/chronos/settings/get s: path (e.g. output/ltc1/level, or / for all) Replies with the value (or every path and value under it)
/chronos/settings/set s: path, then the value Changes a setting; replies with the value actually applied
/chronos/settings/reset s: path Back to the default
/chronos/show/new optional s: name New empty show
/chronos/show/open s: name (from the show list) Opens a saved show
/chronos/show/list none Replies with saved show names and when each was saved
/chronos/show/save / saveas none / s: name Saves the show
/chronos/show/revert none Drops unsaved changes
/chronos/undo / redo none Same as the app’s Undo and Redo, for any change made by hand or over OSC
/chronos/device/audio none Replies with audio inputs and outputs (for LTC)
/chronos/device/midi none Replies with MIDI ports (for MTC and MSC)
/chronos/device/network none Replies with network interfaces and addresses (for Art-Net and OSC)
/chronos/view/page s: main | outputs | cue | sync | settings Switches what the app shows
/chronos/view/fullscreen i: 0 | 1 Full-screen clock display
/chronos/view/lock i: 0 | 1 Locks the app’s own controls, so only OSC can change the show
/chronos/app/identify none Flashes the clock on screen, to find which machine is which

Discovery: Chronos also answers OSCQuery over HTTP on the same port. It returns every address with its argument types, ranges, current value and a description, so tools like Companion or TouchOSC can build a control page on their own. /chronos/describe <s:path> returns the same over plain OSC.

Chronos Sync

The manual switch to a warm spare works on every edition; automatic failover needs Studio, the Event Pass or the Preview. Send these to either machine; Chronos forwards them to its partner.

Address Arguments What it does Needs
/chronos/sync/role none Replies primary or backup, and the partner’s name backup
/chronos/sync/take none Manual switch: the backup takes over outputs now backup
/chronos/sync/giveback none Hands outputs back to the primary backup
/chronos/sync/failover/arm i: 0 | 1 Arms or disarms automatic failover failover
/chronos/sync/health none Replies partner reachable, clock difference in frames, last heartbeat age in ms backup

A manual take or giveback happens on a frame boundary so the timecode doesn’t jump.

Chronos Cue (Studio only)

These control the timecode-triggered event list; on Stage they reply module_locked. Events are numbered as in the app (12, 12.5) and belong to the active list.

Address Arguments What it does
/chronos/cue/lists none Replies with the event list names
/chronos/cue/list/select s: name Makes a list active
/chronos/cue/arm i: 0 | 1 Arms or disarms the whole list (disarmed = nothing fires)
/chronos/cue/<n>/enable i: 0 | 1 Skips or restores one event
/chronos/cue/<n>/fire none Fires one event now, ignoring its timecode
/chronos/cue/<n>/time s: timecode Moves an event’s trigger time
/chronos/cue/next none Replies with the next event’s number, name and trigger time
/chronos/cue/panic none Disarms the list and sends each output’s “all off” (MIDI all notes off, Art-Net blackout if set)

The OSC, MIDI, MSC and Art-Net DMX messages that events send are part of the show file, not this API.

Editing events over OSC (Studio), so a console or script can build and change the list:

Address Arguments What it does
/chronos/cue/list/new s: name Creates an empty list
/chronos/cue/list/rename s: old name, s: new name Renames a list
/chronos/cue/list/delete s: name Deletes a list (not the active one)
/chronos/cue/new s: number, s: name, s: timecode Adds an event to the active list
/chronos/cue/<n>/name s: name Renames an event
/chronos/cue/<n>/renumber s: new number Renumbers an event
/chronos/cue/<n>/action/add s: osc | midi | msc | artnet, then that type’s fields (below) Adds a message the event sends
/chronos/cue/<n>/action/<k>/set same fields as add Changes one of the event’s messages
/chronos/cue/<n>/action/<k>/delete none Removes one message
/chronos/cue/<n>/actions none Replies with every message the event sends
/chronos/cue/<n>/duplicate s: new number, optional s: timecode Copies an event
/chronos/cue/<n>/delete none Deletes an event

Message fields: osc = s: host, i: port, s: address, then its arguments; midi = s: port, s: note / cc / program, i: channel, i: number, i: value; msc = s: port, i: device id, s: command, s: cue number; artnet = i: universe, i: channel, i: value, optional i: fade ms.

Live status

A controller subscribes to the topics it wants, and Chronos pushes each change to it until the subscription lapses. Status goes to the address and port the subscription came from (or its /chronos/replyport).

  • Subscribe: /chronos/subscribe <s:topic> [<s:topic> …], or all. Chronos replies with the current value of each topic straight away.
  • Stay subscribed: a subscription ends after 10 s without any message from that controller; /chronos/ping (reply /chronos/pong) or re-subscribing keeps it alive. TCP subscriptions last until the connection closes.
  • Unsubscribe: /chronos/unsubscribe <s:topic>, or all.
  • Limit: 16 subscribed controllers per machine.
Topic Pushed as Arguments When
timecode /chronos/status/timecode s: timecode, i: frame count, s: rate Every frame by default; /chronos/subscribe timecode <i:per second> for fewer (e.g. 10 for a display)
transport /chronos/status/transport s: playing | paused | stopped | chasing, s: mode On change
lock /chronos/status/lock s: locked | freewheel | lost, s: source id, i: freewheel frames left On change, plus every second while freewheeling
sources /chronos/status/source s: id, i: signal present, s: rate detected, f: level dBFS (LTC), f: jitter ms Once a second per source
outputs /chronos/status/output s: id, i: enabled, i: sending, s: timecode sent On change; timecode sent with the timecode topic rate
sync /chronos/status/sync s: role, s: primary | backup has outputs, i: partner reachable, i: clock difference in frames, i: failover armed On change, and every second
cue /chronos/status/cue s: number, s: name, s: timecode fired, s: next number, s: next timecode Each event fired; the list’s armed state on change (Studio)
track /chronos/status/track s: source, s: title, s: artist, f: BPM, s: next title When the followed track or marker changes; /chronos/status/track/position (s: position, s: remaining) once a second
decks /chronos/status/deck s: deck, s: title, s: artist, f: BPM, i: on air When any deck loads a track or goes on or off air (Link)
settings /chronos/status/setting s: path, then the new value Any setting changed, in the app or over OSC
show /chronos/status/show s: name, i: unsaved changes, s: last saved On open, save and first unsaved change
devices /chronos/status/device s: audio | midi | network, s: name, i: connected When a device is plugged in or removed
diagnostics /chronos/status/diagnostics f: CPU %, f: audio buffer ms, i: dropped frames, i: GC pauses Every 5 seconds
log /chronos/status/log s: info | warning | error, s: message Each warning or error (info only if asked: /chronos/subscribe log info)
licence /chronos/status/licence s: edition, s: valid until, i: offline days left, i: devices used, i: devices max On change and at subscribe
clients /chronos/status/client s: address, s: name, i: connected When an OSC controller connects or its subscription lapses
heartbeat /chronos/status/heartbeat i: uptime seconds, s: machine name Every second, always sent to subscribers

Timecode pushes are best-effort UDP: good for displays and triggers, but a late packet is dropped rather than queued.

Licensing gates and errors

The OSC API follows the same licence as the app: nothing extra to buy, and module addresses lock with their module.

Licence What works over OSC
Chronos Edit (no licence) Queries, status and programming; transport runs but outputs stay off
Chronos Stage Core, Link and manual backup
Chronos Studio, Event Pass, Preview Everything, including Chronos Cue and automatic failover
Error code Meaning
bad_address No such address or id
bad_args Wrong number or type of arguments
out_of_range Value not allowed (e.g. an unknown rate or a time past 23:59:59)
module_locked The licence doesn’t include that module
not_allowed Read-only mode, or no /chronos/connect when a passcode is set
busy Chronos can’t do it right now (e.g. a Sync take while the partner is unreachable)