Skip to content

Patterns, Tracks & Effects

In the last guide you heard a beat. Now let’s see what made it tick: patterns shape time, tracks layer sound, and effects color it. We’ll keep things hands-on here — each idea gets just enough to be useful, with links to the deeper chapters when you want the full story.

Everything below builds on a single drums track, so write the first snippet into a .non file, then add each following block underneath and re-execute as you go.

Start with the same setup as before — a drums track playing a four-event pattern:

use "std/instruments" { Sampler, Kit };
let drums = AudioTrack("drums");
drums.load_instrument(Sampler(Kit("CR-78")));
drums << [bd sd bd sd];
PLAY;

A pattern lives inside square brackets [...] and repeats forever. Its total length is one cycle — think of it as one bar of music. Whatever events you put inside split that bar evenly between them. Four events here, so each gets a quarter of the bar.

The neat consequence: the number of events sets the speed. Put two notes in and they play as half-notes; put eight and they play as eighth-notes. You don’t count durations — you just write what you want and the cycle divides itself.

There’s much more to how patterns carve up time — nesting, alternation, euclidean rhythms, and more. The Pattern Basics chapter is the place to dig in.

A pattern can hold more than one voice at once. Separate them with commas and they play simultaneously:

drums << [bd _ sd _, hh hh hh hh];

The _ (underscore) is a rest — silence that still takes up its slot. So the first voice is a kick-snare backbone with gaps, and the second is a steady run of hi-hats over the top. A comma-separated pattern is called a stack: like stacking lanes in a DAW, every layer runs on the same grid at the same time.

Commas are just the start. Mini-notation can nest patterns, alternate between cycles, stretch and repeat events, and more — see Mini-Notation in Depth.

One track, one instrument. To layer a different sound, make another track. Here’s a clap on the off-beats, playing alongside the drums:

let perc = AudioTrack("perc");
perc.load_instrument(Sampler(Kit("CR-78")));
perc << [_ cp _ cp];
PLAY;

Each track is like a channel on a mixer: it has its own instrument, its own pattern, its own volume and pan, and it plays independently of the others. Build up an arrangement by stacking as many as you like. The Tracks & Master chapter covers volume, pan, and routing to the master output.

So far the sound is dry. Effects process a track’s audio after the instrument — in DAW terms, they’re insert effects sitting in the channel’s signal chain. Let’s put an echo on the drums:

use "std/effects" { Delay };
drums.load_effect(Delay(0.25, 0.5));
PLAY;

Delay(0.25, 0.5) builds a delay with a quarter-second time and half feedback; load_effect drops it onto the track. The drums now trail off into echoes. You can keep adding effects to build a chain — a filter, a reverb, and so on — and the order matters. Effects walks through the full set and how chains stack up.

Because the session keeps running, you reshape a track by re-sending it a pattern. Change the drums line and execute it again:

drums << [bd bd sd _, hh hh hh hh];

The new pattern swaps in at the next cycle boundary, so the change lands in time rather than mid-beat. This is the whole live-coding loop: keep playback going and evolve one line at a time.

You can now shape patterns, layer tracks, and add effects. From here, go deeper or learn how to save your work as a project.