kiki | | repl learn ref idioms birds oracle fish hymns sing

1. the song format

Sing runs a short kiki program called a song. A song assigns patterns to names, then returns a matrix where each row becomes a track.

The variable t is always available. It is the 16-step timeline 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15. You use it to build patterns.

The simplest song writes out 16 values by hand. Non-zero means sound, zero means silence:

The grid below the editor shows your pattern. Lit cells fire, dark cells rest. Press play to hear it. Press play again to stop.

The last line must return a matrix: [row1; row2; row3]. Each row is a track. The semicolons separate them.


2. rhythm with modulo

Writing 16 numbers by hand works, but math can be more expressive. The :! operator is modulo. t :! 4 gives the remainder when each step is divided by 4: 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3.

(t :! 4) := 0 asks "where does that cycle equal zero?" The answer is steps 0, 4, 8, 12, or every 4 steps. This is how most patterns in sing are written built up.

Try changing 4 to 8 (kicks on every other step) or 3. Press play after each change to hear it.

To hit a single specific step, skip the modulo and use t := N directly. This fires only on step 14.


3. stacking tracks

A snare at steps 4 and 12 (t :! 8) := 4 gives a cycle of 8, equal to 4 at those two positions.

Add a hi-hat on every other step with (t :! 2) := 0. Stack all three rows into a matrix:

Try changing the hat to (t :! 4) := 0 (hats every 4 steps) or t := 0 (one hit per loop).


4. voice names

The track name picks the synthesizer. Sing reads the name and maps it to a voice.

A name containing kick plays a kick drum. snare plays a snare. hat plays a hi-hat. bass or sub plays a bass synth. bell or pluck plays a bell. pad plays a soft pad. Anything else plays a plain sine synth.

The match is flexible though, so big_kick, kick2, and my_wicked_kick_track all trigger the kick voice. Try renaming a track and listening to the difference.


5. pitch

For pitched voices (bass, bell, pad, synth), the cell value sets pitch. Zero is always silence. Higher values produce higher notes.

For the bass voice, values in the range 18 to 30 give a recognizable low tone. Adding 12 moves an octave higher; adding 1 moves a half step.

(t :! 4) cycles through 0 1 2 3. Multiply by 5 first, then add 18, to map that to four pitches (18, 23, 28, 33) repeating every 4 steps. The outer parentheses matter because kiki evaluates right to left, so without them 5 :+ 18 is computed first, giving a different result.

Try changing the multiplier (the 5) or the starting value (the 18) to change the gap between notes or shift the whole thing up or down. A multiplier of 7 gives wider gaps.

Bell works the same way. Here the bell fires every third step, with the pitch rising as the step number rises.

(t :! 3) := 0 is a 0/1 mask that fires every third step. Multiplying by (t :+ 24) gives each hit a pitch based on which step it lands on.


6. combining patterns

Add two patterns with :+. This lets you combine two patterns into one. A kick every 4 steps plus a kick on the last step.

The same technique adds an extra hit at step 15 to a hat that otherwise only fires on even steps (0, 2, 4, ...)

For pitched voices, :+ also adds to the pitch value. To combine a pitch pattern with a rhythm so notes only fire where both are non-zero, use :* instead. The bell example in section 5 did this: ((t :! 3) := 0) is the on/off mask, multiplied by the pitch expression to silence the off steps.


7. tempo

Put bpm: 140 anywhere in your song to override the slider. This takes effect when you press play or eval.

You can also give bpm an array of values. Sing cycles through them one per step. Alternating between two values makes some steps slightly longer and others shorter -- a shuffle effect:

Small differences (a few BPM) produce a gentle sorta shuffle. Large differences produce a more dramatic stagger. Try 100 140 to hear the extreme version.


8. putting it together

Here we've got a five-track beat with kick, snare, hi-hat, bass, and bell.

Named lambdas are variables so you can define them in a song like anything else. Here fib is a recursive Fibonacci function. fib' t applies it to every step using the map adverb. The values grow really large pretty fast, so :! 12 folds them into one octave. The bell gets a pitch sequence that wanders with fib-character instead of rising linearly.

The workflow in sing is to press play, then keep editing the score and press Cmd+Return (or the eval button) to update the pattern without stopping.

Good things to try from here: change the bass multiplier (4) to change the gaps between notes; swap the bell offset (3 in (t :! 4) := 3) to shift its hit to a different position within each group; add a pad track with a slow-moving pitch expression.

The reference has the full operator list, and idioms shows common patterns for building sequences.