Skip to content

Types & units

Every continuous or normalized value is a float (f). Integers are only for genuine identifiers, counts and flags.

This has its own page because it is the single most common integration bug in engine↔SuperCollider work, and because of how it fails.

Game engines are cheerfully permissive about numeric literals. Send 1 where the contract says float, and most OSC libraries will happily encode an i. On the SuperCollider side, msg[1] is then an Integer rather than a Float. Nothing throws. Nothing logs. Arithmetic mostly still works. But 1 / 2 is 0 in integer arithmetic where 1.0 / 2 is 0.5, and somewhere three layers down a filter cutoff lands at 0 Hz and the wall goes silent for reasons that have nothing visible to do with the message that caused it.

Three things enforce the rule so you do not have to remember it:

  • The type tag string is on every message on this site, rendered with each glyph directly above the argument it types.
  • The validator fails the build if a declared argument type and the type tag string disagree, or if an example carries a value of the wrong type.
  • The generated code coerces at the boundary. The SuperCollider senders call .asFloat; the C# examples carry the f suffix. Neither side can send the wrong thing by accident through the generated path.

The monitor catches the remaining case — an engine that constructs a packet by hand — and names the offending argument.

TagMeaningUsed for
iint32Identifiers, counts, flags, enum values
ffloat32Everything continuous: gains, positions, times, normalized values
sstringMode ids, parameter names, version strings, free text
bblobNothing yet

A trailing * on a type tag string means the last argument repeats to the end of the message. /mode/synth/notes declares i*: zero to steps key indices. Such an array is either a fixed length, or count: variable with a maxCount the monitor enforces — an empty /mode/synth/notes is legal and means “no notes”.

h, d, T, F and N are legal in the schema but unused. Prefer i and f — some engine-side OSC libraries handle the exotic tags badly or not at all.

Some integers index something whose size is only known when the installation is running. They are declared with ref instead of a range:

refLegal valuesSized by
hold0 … holdCount − 1the last /wall/config
zone0 … zoneCount − 1the running mode’s zoneCount init param
speaker0 … speakers − 1SuperCollider’s output layout

A hard-coded range: [0, 239] on a hold index would be correct on exactly one wall. The validator rejects a hold index without ref: hold, and rejects a ref with a range; the monitor checks each one against the configuration it has actually seen on the wire.

Every argument that has a meaningful range declares one, and the site shows it.

Values outside the declared range are clamped, not rejected. A receiver that drops an out-of-range message turns a small sender bug into silence, which is much harder to debug than a slightly wrong sound. Clamp, use the value, and log it once.

Normalized 0.0 – 1.0 is the default idiom for anything continuous. It moves the question of what the value means physically into SuperCollider, where the curve can be tuned without touching the protocol or the engine.

Units are declared per argument and rendered on every message:

  • normalized0.0 – 1.0. Preferred for gains, levels, progress, intensities.
  • seconds — float seconds, never milliseconds and never samples.
  • midinote — a float, so microtonal tunings and glides stay possible without a protocol change.
  • bpm — beats per minute, a float.
  • meters — physical wall dimensions.

Send gain as a normalized fader position rather than decibels. Decibels invite an argument about which reference and which curve; a fader position does not, and SuperCollider applies the curve.

timestamp arguments are engine time since session start, as monotonic float seconds. They are for ordering events and for measuring latency.

They are not for scheduling. The two clocks are not synchronised and there is no attempt to synchronise them. Anything that needs to happen at a specific moment in the future carries a duration instead — see holdTime on /mode/arcade/objective, which says “5.0 seconds” rather than naming an absolute instant that SuperCollider would have to translate.

The one mode with a musical clock, Climbing Synth, settles it by giving the clock to SuperCollider outright: the arpeggiator runs at audio precision there, and SuperCollider reports each step to the engine with /mode/synth/step so the lights follow the sound, never the other way round.