Small Sounds
Announcing Small Sounds: A Declarative Sound Language
Why Small Sounds?
I wanted some sound effects generated client side, in the browser. I did not want to specify each note. Write up courtesy of Claude.
Try it Here
The Langauge
Small Sounds has a sound language, STA (Sound/Texture/Animation), a single-line declarative DSL for procedural audio synthesis. Its power comes from two key abstractions:
Core Syntax
PLAY <Source> [PARAM values...] [PARAM values...]...
Sources:
Sine
,
Saw
,
Square
,
Triangle
,
Pink
,
Brown
,
White
,
Clap
Parameters:
DUR
,
FREQ
,
VOL
,
GAP
,
COUNT
,
LOOP
,
JITTER
,
CUTOFF
,
Q
The STACurve: Compactness Through Interpolation
The magic is that every parameter accepts a curve , not just a value:
| Input | Meaning |
|---|---|
FREQ 440
|
Constant 440Hz |
FREQ 220 880
|
Sweep from 220→880Hz over duration |
FREQ 400 800 400
|
Rise then fall (siren) |
VOL 0 1 0
|
Fade in, then out (envelope) |
This eliminates MIDI's need for separate note-on/off events, pitch-bend messages, and CC automation. A single token like
FREQ 100 50
is
the automation curve.
Dual Interpretation: Sequences vs. Envelopes
The same curve serves two purposes depending on context:
-
Within a voice:
getAt(t)interpolates over normalized time (0→1) -
Across a sequence:
getDistributed(count)samples discrete values for each event
So
VOL 0.2 1.0
means:
- For a single voice: fade from 20%→100%
-
For
COUNT 5: five events with volumes [0.2, 0.4, 0.6, 0.8, 1.0]
Expressiveness Examples
| MIDI Equivalent | STA |
|---|---|
| Note + pitch bend + volume CC |
PLAY Sine DUR 1 FREQ 200 400 VOL 0 1 0
|
| 4 notes with arpeggio timing |
PLAY Sine COUNT 4 GAP 0.05 FREQ 400 800
|
| Randomized texture |
PLAY Pink COUNT 20 LOOP 10 JITTER 0.1
|
The language compresses what would be dozens of MIDI events into a single declarative statement, while
COUNT
,
LOOP
, and
JITTER
provide controlled randomness for organic textures—something MIDI can't express at all.
Current Status
It works, does what I wanted. The gallop sound needs more work for sure. It's stronger on the futuristic bleeps and boops, which is what I mainly wanted it for. The waves, wind, heartbeat were bonus.
Made with Claude
This took quite a bit of trial and error to get right. The various engines had a lot of trouble grasping the concept of a curve that controlled any variable and that could be sampled from to get a sequence of notes. If prompting for this again, I'd lead with that concept.
On the other hand the engines had no trouble at all making the UI and even volunteered to provide the nice graph. I did not have to learn about WebAudio or find the boilerplate code to make it work.