Skip to content

Sounds

Vector does not have sound files in any normal sense. He has a small games-industry audio engine with 474 named events baked in, and his animations do not play sounds — they ask for an event by number, and the audio engine decides which of the recordings behind that name you actually hear.

That last part is the useful bit, and it was mostly unused.

Everything below was read from the firmware tree and the soundbanks the robot ships with. Nothing was played on a robot to produce it.

Seven soundbanks sit on the robot and are loaded at boot by the animation process — not the engine, and nothing to do with the server.

BankSizeWhat is in it
Victor_SFX5.5 MBEverything cute: grunts, chirps, purrs, motor sounds
Victor_Global_Data269 kBShared containers, state and switch definitions
Victor_Dev94 kBInternal test tones
Victor_Alexa61 kBAssistant earcons
Victor_VO1.2 kBThe hook for text-to-speech
Init6 kBBus and state setup
Victor_UI32 bytesEmpty; those were the phone app’s sounds

Alongside them sit 927 loose numbered files — the actual recordings, in the audio engine’s Vorbis flavour, 32 kHz mono. The bank itself mostly holds a 1,864-byte prefetch head of each one and streams the rest off flash, which is why pulling a sound straight out of a bank gives you a fragment rather than the noise you wanted.

455 binary files hold 1,185 animation clips, and 954 of them — 80% — make a noise. They do it with an audio keyframe:

{ "Name": "RobotAudioKeyFrame",
"triggerTime_ms": 300,
"eventGroups": [{
"eventIds": [2483759946],
"audioName": ["Play__Robot_Vic_Sfx__Emote_Happy_Short"],
"volumes": [1.0],
"probabilities": [1.0]
}] }

Three things are worth knowing about that structure, and all three are easy to get wrong silently:

  • Only eventIds matters. The name is not read by anything; it is there so the file is legible. Get the number wrong and the frame is dropped without a word. Get the name wrong and nobody notices at all.
  • eventIds, volumes and probabilities must be the same length, or the whole group is thrown away with an error in the log.
  • The probabilities in one group must add up to 1.0 or less, or the clip fails to load outright.

A few sounds are fired directly by the engine rather than through a clip: the wake-word chirp, the thinking loop, the purr while you pet him. There are only about seventy of those; the animation clips do the overwhelming majority of the work.

One event name is not one sound. Ask for the short happy emote and the audio engine picks one of five different recorded takes. Across all 474 events there are 2,027 separate recordings. That is why he never sounds quite the same twice, and it costs nothing.

On top of that, one keyframe can list several events and let the robot pick one, weighted:

"eventIds": [2091194049, 146478435],
"probabilities": [0.45, 0.45]

The robot rolls a number between zero and one and walks the list adding up the weights; the first event whose slice contains the number wins. If the weights do not reach 1.0, the remainder is the chance he stays quiet — a 0.45/0.45 split is a 10% chance of silence, which is exactly what stops a repeated idle animation feeling mechanical.

Of 4,254 event groups across every stock clip, only 227 list more than one event. The mechanism was built and barely used.

There is a third lever. Some events make no noise at all; they set a state or turn a parameter that changes what later sounds do. The petting levels are pure state changes, and one event turns the purr-depth knob. Fire one of those first and the purr that follows is deeper and further in.

A catalogue of all 474 events is generated from the soundbanks, the decoded animation clips and a grep of the engine. Its columns are: the event name, a bucket, how many stock clips fire it, how many keyframes in total, how many places the engine fires it directly, how many separate recordings are behind it, its duration, its numeric id, and which bank it lives in.

GroupEventsNever fired by anything
Movement (head, lift, treads)14530
Show (weather, holiday, games)8019
Alert (wake word, timer, volume, wifi, power)527
Development test tones4436
Assistant3232
Chirp (the eye noises)326
Grunt (the vocal noises)313
Purr and petting160
Greeting121
Scene86
Attention72
Cube50
Sleep40

147 events are never fired by any stock animation or by the engine. Ignoring the test tones and the assistant earcons, that still leaves a decent pile. And the distribution is more lopsided than the table suggests: 101 events are used by exactly one clip, while a single curious-eyes chirp is fired by 380 of them.

The best of the unused:

  • The procedural blink, squint and shift chirps — twenty recorded takes between them, and not one stock clip asks for any of it. The names suggest they were made for code-driven faces rather than canned animation, which is exactly what a styleable eye is.
  • A real looping purr, used by nothing. It wants its stop event afterwards or it runs forever.
  • The quieter, to-himself versions of the normal grunts — five takes each, barely used.
  • Four escalating head-petting levels and four lift-high ones, one stock clip each. Played in sequence they are a proper “he settles into it”.
  • Sleepy muttering, one clip each.

Two bugs this turned up in Ember’s own clips, both since fixed: one clip was asking for an event with no recording behind it and playing nothing, and three were starting a loop and never stopping it.

Thirteen new clips, built on under-used events and nearly all using the weighted random pick so they do not repeat themselves: the four petting levels in sequence; the looping purr with its level raised twice and then stopped; lift tickling at a random level; a good-morning greeting; goodbye weighted against sad-goodbye; a fist bump; the face-scan loop and its stop; the three unused procedural chirps; the quiet grunts; a look-at-device, gaze-scan and touch reaction; sleepy muttering; a cube search ping; and the concentrate loop, properly stopped.

They are staged only. They reach the robot the same way every other Ember clip does, through the install-animations route, and none of them has been installed.

The generator cross-checks every event it uses against the finished catalogue, so a wrong id or a silent event fails the build rather than the robot.

Separate from all of the above, Ember can stream ordinary audio to the robot’s speaker. Those are the sound sets described in Modes and sound sets: plain 16 kHz mono WAV files, played through the SDK’s external audio playback, with no behaviour control taken so a reaction noise does not interrupt what he is doing.