Skip to content

Climbing Synth

The wall becomes an instrument. Holds in the Keyboard Area are notes of a scale; the notes being held fill the slots of a looping arpeggiator in the order they were pressed, and empty slots stay silent. Holds in the Effects Area shape the sound in real time — reverb, delay, filtering and so on — so some children compose while others play the mixing desk.

If the notes stay the same for three seconds the pattern freezes and keeps playing after everyone lets go. The Reset Hold clears it.

This is the one mode where SuperCollider owns the clock. The arpeggiator runs at audio precision inside SuperCollider; it reports every step back with /mode/synth/step so the lights pulse in time. The engine owns everything else: which keys are held, the freeze timer, the reset hold, and how each effect hold behaves.

Mode id: synth · Status: draft · Since: 0.2.0 · Spec: Prototype Use Cases, pp. 6–7

Load this mode with /mode/load and type tags sssffis:

NetAddr("127.0.0.1", 57120).sendMsg('/mode/load', "synth", "pentatonic", "", 60.0, 110.0, 4, "marimba");

Sent in this exact order, immediately after the mode id.

#NameTypeRange / defaultDescription
1scalespentatonic, major, minor, dorian, custom
default pentatonic
Pitch set. Every combination of notes in any of these sounds consonant, which is the point — no child can play a wrong note.
2customScalesSemitone offsets from the root, space-separated, used only when scale is custom — e.g. “0 2 4 7 9”. Empty otherwise.
3rootNotef36.0 – 72.0
midinote
default 60.0
The note key 0 plays. Higher keys climb the scale, wrapping into higher octaves.
4tempof60.0 – 180.0
bpm
default 110.0
Arpeggiator tempo. One step per sixteenth note.
5stepsi2 – 8
default 4
Arpeggiator slots — the most notes that can sound in the pattern.
6instrumentssynth, piano, marimba, strings
default marimba
The instrument voice.

Changed while the mode runs, with /mode/param name value. Always a float, always clamped, never an error if the name is unknown.

NameRange / defaultDescription
tempo60.0 – 180.0
bpm
default 110.0
Change tempo without reloading.
effectDepth0.0 – 1.0
default 0.7
Overall effect intensity. Scales every effect amount, so a teacher can make the Effects Area gentler without touching its holds.
NetAddr("127.0.0.1", 57120).sendMsg('/mode/param', "tempo", 110.0);

Settings from the use case that never cross the wire. The engine applies them; SuperCollider does not need them, so they are not in the protocol.

Setting
Keyboard and Effects Area layoutWhich holds are keys and which are effects. The engine sends key and effect indices, never hold positions, so the layout can change freely.
Freeze timeoutThree seconds by default. The engine runs the timer and sends /mode/synth/freeze; SuperCollider does not need to know the duration.
Effect behaviourWhether an effect hold is temporary (while held), cumulative (each touch adds) or persistent (toggles). The engine applies the behaviour and sends the resulting level — see /mode/synth/effect.
Visual animations and feedbackIncluding the per-step pulse, driven by /mode/synth/step.

/mode/synth/notes

engine → sc state since 0.2.0

The notes currently in the arpeggiator, in slot order.

i* keys
i*
keys i int32 0 – 47repeats 0 – steps times
Key indices in the order they were pressed, 0 = rootNote. Zero to `steps` values; slots beyond the list are silent rests. An empty message means no notes.
packet /mode/synth/notes 0 2 4
SuperCollider NetAddr("127.0.0.1", 57120).sendMsg('/mode/synth/notes', 0, 2, 4);
engine (C#) osc.Send(Osc.ModeSynthNotes, 0, 2, 4);

The WHOLE pattern, every time it changes — never "add note" or "remove note". A dropped note-on would otherwise leave a key stuck in the pattern until reset; a dropped full list is corrected by the next one.

Key indices, not pitches: SuperCollider maps them through the scale. Changing the scale therefore never requires the engine to recompute anything.

/mode/synth/freeze

engine → sc state since 0.2.0

Whether the pattern is frozen.

i frozen
i
frozen i int32 0 | 1
1 — keep looping the current pattern even when every hold is released. 0 — follow /mode/synth/notes live.
packet /mode/synth/freeze 1
SuperCollider NetAddr("127.0.0.1", 57120).sendMsg('/mode/synth/freeze', 1);
engine (C#) osc.Send(Osc.ModeSynthFreeze, 1);

While frozen the engine keeps sending /mode/synth/notes unchanged, so a restarted SuperCollider picks the frozen pattern straight back up.

/mode/synth/reset

engine → sc event since 0.2.0

The Reset Hold was pressed. Clear the pattern.

/mode/synth/reset takes no arguments.

packet /mode/synth/reset
SuperCollider NetAddr("127.0.0.1", 57120).sendMsg('/mode/synth/reset');
engine (C#) osc.Send(Osc.ModeSynthReset);

Plays the reset gesture and returns every effect to zero. The engine follows it with an empty /mode/synth/notes and /mode/synth/freeze 0, so the state is correct even if this message is lost.

/mode/synth/effect

engine → sc state since 0.2.0

The current level of one effect.

s effect
f amount
sf
effect s string "reverb" | "delay" | "filter" | "modulation" | "pitch" | "stutter"
Which effect. filter is a low-pass sweep; pitch transposes the pattern by up to an octave; stutter is the rhythmic variation.
amount f float32 0.0 – 1.0normalizeddefault 0.0
Absolute level, 0.0 off. Scaled by the effectDepth runtime param.
packet /mode/synth/effect delay 0.6
SuperCollider NetAddr("127.0.0.1", 57120).sendMsg('/mode/synth/effect', "delay", 0.6);
engine (C#) osc.Send(Osc.ModeSynthEffect, "delay", 0.6f);

An absolute level, never a touch. The engine turns effect-hold touches into levels according to each hold's behaviour, and sends the result. A dropped message is corrected by the next change or by /sys/sync.

Effects only sound while the pattern has at least one note, per the use case; SuperCollider keeps the levels while silent.

/mode/synth/step

sc → engine event since 0.2.0

The arpeggiator just played a step.

i stepIndex
i key
ii
stepIndex i int32 0 – 7
Which slot, 0..steps-1.
key i int32 -1 – 47
The key index that sounded, or -1 for a silent slot.
packet /mode/synth/step 2 4
SuperCollider ~osc[\modeSynthStep].value(2, 4);
engine (C#) // handler for Osc.ModeSynthStep

Sent on every step, even silent ones, so the engine can pulse the lit key holds in time with the sound. At 180 bpm this is 12 messages a second. The engine should not use it to drive anything audible.