Skip to content

Who picks the sound

The use cases mix two different kinds of sound, and the protocol handles them differently. Getting this wrong in either direction is expensive, so it has its own rule.

If a teacher, a story or a game script decides what the sound is, the engine names it. If the sound is feedback on something that happened, SuperCollider chooses it.

KindExamplesWho names itHow
ContentA child’s uploaded poem, story narration, the giraffe in the savanna story, “Hull breach detected”, a jungle ambience bedEngine/sample/load then /sample/play, or a mode message carrying a sample key
FeedbackThe chime when a Chase hold is hit, the pattern tone in Find the Match, the arpeggiator itself, a success fanfareSuperColliderA mode message saying what happened; SuperCollider maps it to sound using the mode’s soundSet

Why the split:

  • Content changes without code. A teacher uploads a new recording, a story gets a new narrator. If SuperCollider had to know those sounds, every new story would be a SuperCollider change.
  • Feedback is sound design. Whether a hit rises in pitch with progress, how a wrong answer sounds so it never feels like a buzzer at a five-year-old — that is the sound designer’s decision, and it belongs where the sound designer works.

Modes that are mostly content — Sound Wall, Memory Game, Arcade — carry sample keys in their own messages (/mode/memory/correct … "savanna/giraffe"). That keeps the message semantic, so SuperCollider still knows it is a correct answer: it pans it to the hold, ducks the ambience, and lets the growl land harder near the top of the wall.

Audio never travels over OSC — a 1400-byte UDP packet holds about 15 ms of CD audio. Files live in the asset directory both programs can read:

/sys/assets "/Users/wall/ClimbingWall/assets" the root, once
/sample/load "savanna/giraffe" "stories/savanna/giraffe.wav"
/sample/loaded "savanna/giraffe" 1 2.4 "" ← wait for this
/sample/play "savanna/giraffe" "sfx" 1.0 0.0 0
/sample/ended "savanna/giraffe" 1 ← sequence on this

Load everything a mode will name before /mode/load, and wait for every /sample/loaded. A sample played before it has loaded is silence that looks like a bug somewhere else.

The set of loaded samples is state: /sample/load is rate: state, so after a SuperCollider restart the engine re-sends every load as part of /sys/sync.

Memory Game lights each animal as the story mentions it. Only SuperCollider knows when a line of narration actually finishes — the engine can only guess from the duration, and the guess drifts. So the engine plays a line, waits for its /sample/ended, then lights the next hold and plays the next line.

Every sound belongs to exactly one bus, and each bus has a level:

BusCarries
voiceNarration, spoken instructions, arcade radio voices
musicThe Climbing Synth arpeggiator, background music
ambienceLooping soundscapes — jungle, space station
sfxFeedback SuperCollider chooses, plus story sound effects
contentTeacher-uploaded audio in Sound Wall

/audio/bus/volume sets a level; /sample/play names its bus. SuperCollider ducks music and ambience under voice automatically, so a story stays intelligible without the engine riding levels line by line.

SuperCollider pans every hold-related sound to that hold’s position, using the live /wall/config — a child on the left hears their hit from the left. In zoned modes that is what keeps four simultaneous games audibly apart. /sample/play has an explicit pan for sounds with no hold, such as narration, which stays centred.

/audio/record/start and /audio/record/stop capture the master output — what the room heard, effects included. /audio/record/saved returns a path relative to the asset root, so a recording can go straight back into /sample/load. That is what turns Climbing Synth sessions into the class library the use case asks for.