Learn Creative Coding (#129) - Live Coding Music
Learn Creative Coding (#129) - Live Coding Music

Last time we built a whole two-minute piece that composed itself - press go, sit back, watch it unfold. And I ended by admitting the itch it left me with: once you've got a system that plays itself, you start wanting to reach into it while it's running. Nudge the energy up right as the beat lands. Swap the scale mid-phrase. Break it on purpose and fix it live. That itch has a name, and it's a whole scene of its own: live coding. Allez, today we stop pressing play and start performing :-).
Here's the picture, because it's honestly one of the coolest things people do with code. Imagine a dark room, music thumping, and up on a big screen behind the performer is... a text editor. Not a fancy visual, not album art - actual code, being typed and re-typed live, and every edit changes the music you're dancing to. That's an algorave (algorithm + rave, yes really), and the golden rule of the scene is literally "show us your screens" - no hiding behind a laptop lid, the code is the show. The creative act is visible. You're not performing a finished thing, you're building it in front of everyone, mistakes and all.
The tools people use for this are things like TidalCycles, Sonic Pi, FoxDot, and more recently Strudel (which runs right in your browser). They're gorgeous and you should absolutely go play with them. But I don't want to just point you at someone else's toolbox and wave - I want you to understand what's underneath it, because it's all built on exactly the stuff we've spent this whole audio arc learning. So today we're going to build our own tiny live-coding music environment, in the browser, with Tone.js. By the end you'll be typing patterns and hearing them change without ever stopping the sound. And once you see how little code that takes, the fancy tools stop looking like magic and start looking like ideas you now own.
The one idea that makes it all work
Let me start with where we already are, because live coding is one small twist away from the sequencer we built back in episode 121. Here's a plain little loop reading a pattern - a note per step, a null for a rest. Nothing new.
// our starting point: a loop reading a pattern. this is just episode 121 again.
const synth = new Tone.PolySynth(Tone.Synth).toDestination();
let pattern = ["C4", null, "E4", "G4"]; // a step sequence, null = a rest
let step = 0;
const loop = new Tone.Loop((time) => {
const note = pattern[step % pattern.length];
if (note) synth.triggerAttackRelease(note, "8n", time);
step++;
}, "8n").start(0);
Tone.Transport.start();
Now watch closely, because this next bit is the entire secret of live coding and it's almost too simple. See how the loop reads pattern, a variable, and not a fixed list baked into the loop? That means I can change the variable while the loop is running, and the very next step it'll read the new value. The music changes without me stopping anything.
// the whole trick: the loop reads a VARIABLE. change it while it runs, the music follows.
pattern = ["C4", "E4", "G4", "B4"]; // paste this in the console mid-song -> melody shifts live
That's it. That's the seed of the whole thing. Everything else we build today is just making that - changing the running state without stopping it - feel good, sound clean, and be typeable fast under pressure. But if you get nothing else from this episode, get this: live coding is just mutating the state a running loop reads. You already knew how to do it. See where this is going?
Making the swap sound clean
Try that variable-swap trick for real, though, and you'll hit the first snag immediately. If you change pattern halfway through a bar, the music lurches - it jumps to the new sequence mid-phrase, at some random spot, and it sounds sloppy. What we actually want is for edits to land on a musical boundary, the top of the next bar, so the change feels intentional instead of like a stumble. That's called quantizing the change, and it's what separates a live-coding tool that sounds pro from one that sounds like a car crash.
The fix is a little "I want this, but not yet" buffer. When you make an edit, we don't apply it right away - we stash it, and the loop applies it only when it hits the top of a bar.
// don't apply an edit mid-bar (it lurches). queue it and swap on the next bar boundary.
let nextPattern = null;
function setPattern(p) { nextPattern = p; } // "here's what I want - land it on the beat"
const loop = new Tone.Loop((time) => {
if (step % 8 === 0 && nextPattern) { // top of the bar (8 sixteenths in)
pattern = nextPattern; // clean swap, dead on the downbeat
nextPattern = null;
}
const note = pattern[step % pattern.length];
if (note) synth.triggerAttackRelease(note, "16n", time);
step++;
}, "16n").start(0);
Feel the difference that makes? Now no matter when you fire an edit - rushing, panicking, half a bar late - it patiently waits and drops in right on the downbeat. This is the same "trust the clock, snap to the grid" discipline we leaned on scheduling rhythms in episode 121, just pointed at a new problem. The performer gets to be sloppy about timing so the music doesn't have to be. That trade is basically the whole ergonomics of live coding in one idea.
Typing music, not JavaScript
Right, next problem. Nobody wants to be typing ["C4", null, "E4", "G4"] under stage lights - too many brackets, too many quotes, too slow. Live coders use terse little mini-notations: you type something like c4 ~ e4 g4 where a space separates steps and ~ is a rest, and the tool turns that string into a pattern. Let me write us a tiny parser that does exactly that. It's maybe the highest fun-per-line code in the whole episode.
// live coders type terse strings, not JS arrays. a tiny "mini-notation" parser:
// "c4 ~ e4 g4" -> ["C4", null, "E4", "G4"] (~ means rest)
function parse(str) {
return str.trim().split(/\s+/).map((tok) => {
if (tok === "~") return null; // a rest
return tok[0].toUpperCase() + tok.slice(1); // c4 -> C4, so you can type lowercase fast
});
}
setPattern(parse("c4 ~ e4 g4 c5 ~ e4 ~"));
Look at how much nicer that is to type. c4 ~ e4 g4 c5 ~ e4 ~ - eight steps, and your fingers barely move. This is why every live-coding language grows its own little pattern language: the whole point is to describe a lot of music with very few keystrokes, because you're editing it while it plays and every second counts. Real mini-notations go way further (nested groups, repeats, random choices), and I'd genuinly encourage you to peek at how Strudel does it once you're comfy - but even this five-line version already changes how the whole thing feels to use.
The REPL: type, evaluate, hear it
So far I keep saying "paste this in the console". Let's make that a real thing - a little editor on the page where you type code, hit a key, and it runs right now against the live, playing system. That's a REPL (read-eval-print loop), and it's the beating heart of every live-coding environment. Ours is going to be embarrassingly short.
// the REPL: type code in a <textarea>, hit ctrl+enter, we run it against the live system.
const editor = document.querySelector("#code");
editor.addEventListener("keydown", (e) => {
if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) {
e.preventDefault();
try {
eval(editor.value); // run whatever the performer just typed, against the running loops
flashOk(); // it worked
} catch (err) {
flashError(err); // it threw - but crucially, the SOUND kept going
}
}
});
Quick honest word on eval, because I can hear some of you wincing. Yes, eval is dangerous - it runs arbitrary code, and you must never point it at input from strangers on the internet. But here? It's your machine, your performance, your fingers typing. This is one of the rare, legitimate homes for eval: a REPL you control end to end. Context is everything with that keyword. Makes sense, right?
The golden rule: a typo must never kill the music
Now look again at that try/catch and let me make a big deal of it, because it's the single most important line in the whole episode. When you're performing live, you will make typos. You'll reference a track that doesn't exist yet, forget a bracket, fat-finger a note name. And here is the iron law of live coding: a mistake must never stop the music. The audience is dancing. If a typo threw an error and silenced everything, the show is over. So we wrap the eval in a try/catch, and a broken line simply... doesn't apply. The loops keep spinning on the last version that worked. You fix your typo, hit ctrl+enter again, and it slots in like nothing happened.
// the golden rule of live coding: a typo must NEVER stop the music.
// a broken line just doesn't apply - the running loops play on, untouched.
function flashError(err) {
console.warn("skipped:", err.message); // YOU see the mistake...
editor.style.outline = "2px solid red"; // ...the audience just hears the last good version
setTimeout(() => (editor.style.outline = ""), 150);
}
function flashOk() {
editor.style.background = "#0f2"; // a green blink so the room can follow your edits
setTimeout(() => (editor.style.background = ""), 120);
}
I love this bit because it flips how you think about errors. In normal coding an exception is a stop-the-world emergency. In live coding it's a shrug - "that one didn't take, try again" - and the whole system is designed to keep breathing through your mistakes. Building for that resilience, on purpose, is what makes the difference between a toy and something you'd actually dare to plug into a PA in front of people.
Many voices at once
A real set isn't one melody - it's a bassline and a lead and drums, all going at once, each one edited independently while the others keep playing. So we need more than a single pattern. Let's keep a little table of named tracks, each with its own instrument, its own current pattern, and its own "next" buffer for clean swaps.
// a real set has several voices going at once. keep them in a table, by name.
const tracks = {};
function track(name, instrument) {
if (!tracks[name] && instrument) {
tracks[name] = { inst: instrument, pattern: [], next: null };
}
return tracks[name];
}
track("bass", new Tone.MonoSynth().toDestination());
track("lead", new Tone.PolySynth(Tone.Synth).toDestination());
Then one single clock drives all of them - the same "one transport, many readers" shape we used building the composition in episode 128, where a shared thing in the middle fed several engines. Each track reads its own pattern, and each track's edits quantize to the bar on their own.
// ONE clock, every track reads its own pattern. each track's edits land on the bar.
const master = new Tone.Loop((time) => {
const atBar = step % 16 === 0; // top of a 16-step bar
for (const name in tracks) {
const t = tracks[name];
if (atBar && t.next) { t.pattern = t.next; t.next = null; } // clean swap, per track
const len = t.pattern.length || 1;
const note = t.pattern[step % len];
if (note) t.inst.triggerAttackRelease(note, "16n", time);
}
step++;
}, "16n").start(0);
And now the payoff - the actual line you'd type during a set. One tiny function that reparses a string into a track's next pattern, and suddenly performing is just typing one terse line per voice and hitting ctrl+enter.
// this is what you actually TYPE mid-set. one terse line per voice.
function play(name, str) { track(name).next = parse(str); }
play("bass", "c2 ~ c2 g1 c2 ~ ds2 ~");
play("lead", "c4 e4 g4 e4 c5 g4 e4 g4");
// edit either line, ctrl+enter, and it re-lands on the next bar. no silence, no click, no stop.
Sit with that for a second, because that's a working live-coding instrument. You can layer a bass, drop a lead on top, rewrite the lead while the bass holds it down, mute a track by playing an empty pattern into it. All of it live, all of it clean on the beat, all of it resilient to your typos. That's genuinly the core of what the big tools do - everything else is polish and better pattern languages on top of this exact skeleton.
A groove trick: euclidean rhythms
Let me give you one properly delightful toy to play with live, because it's a live-coding staple and it'll make your drums instantly good. It's called a euclidean rhythm: the idea is to spread k hits as evenly as possible across n steps. It turns out that "as evenly as possible" produces, almost spookily, a huge chunk of the drum patterns used in music all over the world. The algorithm is Bjorklund's, and it's short.
// euclidean rhythm: spread K hits as evenly as possible over N steps. Bjorklund's algorithm.
// this same trick lives inside Tidal, Sonic Pi, Strudel - it's a live-coder's favourite.
function euclid(k, n) {
const out = [];
let bucket = 0;
for (let i = 0; i < n; i++) {
bucket += k;
if (bucket >= n) { bucket -= n; out.push(1); } // a hit
else out.push(0); // a rest
}
return out; // euclid(3, 8) -> [1,0,0,1,0,0,1,0], the classic "tresillo" you've heard a million times
}
Wire that straight into a drum voice and you've got a groove generator you can tweak by changing two numbers - which is exactly the kind of tiny, high-impact edit live coding is built around.
// feed a euclidean pattern into a drum voice. change the two numbers live -> whole new groove.
const kickInst = new Tone.MembraneSynth().toDestination();
function drum(name, k, n, note) {
track(name, kickInst).next = euclid(k, n).map((hit) => (hit ? (note || "C1") : null));
}
drum("kick", 5, 16); // five kicks spread over sixteen steps - a driving four-ish feel
// now try drum("kick", 3, 8) or (7, 16) or (4, 7). each one is a different world, one keystroke apart.
That (4, 7) one is my favourite party trick - an odd number of steps gives you a limping, off-kilter groove that no drum machine preset would ever hand you, and you found it by typing two digits. This is the joy of the whole practice: the distance between an idea in your head and hearing it is about three seconds and one line. You stop planning and start conversing with the sound.
Performing it, and where the screen comes in
One last thread, and it loops us right back to where this arc has been all along - the visual. Remember, at an algorave the screen is the show. Your code, projected big, is the visuals. That's a lovely constraint: it means how your code reads is part of the art. People format their live-coding sets to be beautiful to watch, comment them like liner notes, name their tracks poetically. The little green blink we added when a line evaluates? That's not just for you - it's so the room can see the exact moment your edit lands and the music turns. The audience gets to connect cause and effect, your keystroke to their ears. That feedback loop between performer, code, and crowd is the entire vibe.
And if you want to close the circle with everything we built in the audio arc, you can run the master output through an analyser (episode 127) and throw a real visualizer behind your projected code, or capture the whole set to a file with MediaRecorder (episode 20) to keep the good runs. But honestly? For a first go, resist. Put the code on screen, make the patterns readable, and let the code itself be the visual. There's something pure about it - the thing making the sound and the thing you're looking at are literally the same text. That's about as honest as generative art gets.
Your exercise: play a two-minute set
Here's the brief, and it's a different kind of challenge than usual - there's no "finished" artifact to make, because the performance is the point. Wire up the whole thing: the master loop reading per-track patterns, the parse mini-notation, the play and drum helpers, the ctrl+enter REPL with its try/catch safety net. Get a <textarea> on the page. Then start with silence, and build a set live over two minutes.
Drop a kick in first with drum("kick", 4, 16). Let it ride a few bars. Add a bassline. Let that settle, then bring in a lead. Now start editing - rewrite the lead, thin the drums to euclid(3, 8), push the bass up an octave. Mute something by playing an empty string into it, let the space breathe, bring it back. The whole skill is pacing: adding and removing and changing so the two minutes has an arc - same "does it go somewhere?" question we asked of the composition in episode 128, except now you're the director, deciding in real time. Record your screen if you can, so you can watch your own hands back and see where you rushed and where you nailed it.
And make yourself type an edit wrong at least once on purpose, just to feel the try/catch catch you - watch the red blink, watch the music not even flinch, fix it, watch it land. That moment, when you trust that your mistakes won't break the show, is the exact moment live coding stops being scary and starts being play.
Something's been nagging me about the word "music"
We've spent this whole long audio stretch making music - notes, scales, chords, beats, things that fit the grid and want to be pleasant. But typing euclid(4, 7) and hearing that lopsided, almost-wrong groove got me thinking about all the sound that isn't music. The hum of a fridge. A field recording of rain. A raw, ugly buzz that's somehow more interesting than any tidy chord. What happens if we stop trying to be musical altogether and just... make sound, as an art form in its own right - texture, noise, the accidental, the environmental? That's a genuinly different question, and it's pulling at me hard. Get your live set going first - genuinly perform it, mess it up, trust the safety net - and then come back, because next time we wander off the edge of "music" entirely and into sound as pure material :-).
't Komt erop neer...
- Live coding is performing music by writing and rewriting code while it plays - the algorave scene, "show us your screens", the code projected as the show. The creative act is made visible
- The entire secret is one idea: a loop reads a variable, and you mutate that variable while it runs. You already knew how - everything else today is making that feel good and sound clean
- Quantize your edits: stash the change in a "next" buffer and only swap it in on the top of the next bar (episode 121's grid discipline), so edits land intentionally instead of lurching mid-phrase
- A tiny mini-notation parser (
"c4 ~ e4 g4"-> a pattern) lets you describe a lot of music with very few keystrokes - vital when you're editing under pressure - The REPL (a
<textarea>+ ctrl+enter +eval) runs your typed code against the live system.evalis dangerous in general but legitimate here: it's your own machine, your own fingers - The golden rule: a typo must NEVER stop the music. Wrap the eval in
try/catchso a broken line just doesn't apply, and the loops keep breathing on the last good version - Many voices live in a table of named tracks, all driven by one clock (episode 128's shared-clock shape), each quantizing its own edits.
play(name, str)is what you actually type - Euclidean rhythms (
euclid(k, n), Bjorklund's algorithm) spread k hits evenly over n steps and hand you great grooves from two numbers - change the numbers live for instant new feels
So that's the leap the composition episode was quietly setting up. We went from a piece that plays itself to an instrument that you play - live, in the moment, mistakes and all - and the whole thing turned out to be one idea we'd had in our pocket since the very first sequencer: change the state the loop is reading. Wrap that in a clean swap, a terse notation, a fearless REPL, and a promise that errors won't kill the sound, and you've built the beating heart of a real live-coding environment in about a hundred lines. Go make a room dance with a text editor :-).
Sallukes! Thanks for reading.
X