Pattern Basics
Patterns are the heart of music-making in Resonon. They describe sequences of notes, rests, and samples that repeat over time — think of a pattern as one looping bar in a DAW, written as text.
Let’s start with a complete example you can run, then take it apart:
use "std/instruments" { Sampler, Kit };
let drums = AudioTrack("drums");drums.load_instrument(Sampler(Kit("CR-78")));
drums << [bd sd bd sd];
PLAY;The first three lines set up an audio track with a drum sampler — that part you know from Hello, Sound. The interesting line is this one:
drums << [bd sd bd sd];[bd sd bd sd] is a pattern: four drum hits in square brackets. The << operator sends it to the track, and PLAY starts the transport. The pattern loops forever until you PAUSE or replace it.
Cycles
Section titled “Cycles”Patterns fit into cycles. A cycle is the fundamental unit of time in Resonon — every pattern repeats once per cycle, like a bar looping in a DAW. Cycle duration is set by the tempo:
setbpm(120); // 120 BPM, default 4 beats per cyclesetbpm(140, 8); // 140 BPM, 8 beats per cycleThe relationship between BPM, beats per cycle, and cycle duration:
cycle_duration = beats_per_cycle * 60 / bpm| BPM | Beats/Cycle | Cycle Duration |
|---|---|---|
| 120 | 4 | 2.0 s |
| 120 | 8 | 4.0 s |
| 140 | 4 | ~1.71 s |
Use the second argument to setbpm when your patterns span more (or fewer) than 4 beats.
Time Division
Section titled “Time Division”Elements within a pattern divide the cycle evenly:
let whole = [C4]; // One note fills the whole cyclelet halves = [C4 D4]; // Each note gets 1/2 of the cyclelet quarters = [C4 D4 E4 F4]; // Each note gets 1/4 of the cycleThe more elements you put in a pattern, the faster they play — four elements play as quarter notes, eight as eighth notes, and so on. There is no fixed grid: a three-element pattern divides the cycle into exact thirds.
Use _ (underscore) for silent steps. A rest occupies time just like a note:
let offbeat = [C4 _ E4 _]; // Play, rest, play, restlet sparse = [bd _ _ sd]; // Kick on 1, snare on 4Notes and Numbers
Section titled “Notes and Numbers”Note names combine a letter, optional accidental, and octave: C4, f#3, Bb2. Plain numbers are interpreted as MIDI note values (0–127), and you can mix both freely:
let named = [C4 D4 E4 F4];let numeric = [60 62 64 65]; // Same melody as abovelet mixed = [C4 62 E4 67];Numbers are handy for drum programming with General MIDI note maps:
// GM drum map: 36=kick, 38=snare, 42=closed hhlet gm_beat = [36 42 38 42];Pattern Types
Section titled “Pattern Types”The bracket syntax determines what kind of pattern you get:
| Syntax | Type | Behavior |
|---|---|---|
[C4 D4 E4] | Sequence | Elements divide the cycle evenly |
[C4, E4, G4] | Stack | All elements play simultaneously |
<C4 D4 E4> | Alternating | One element per cycle, rotating |
Sequence is the workhorse — elements play one after another. Stack layers everything at once, giving you chords or parallel rhythms. Alternating picks one element per cycle and rotates through them, so the pattern evolves over time.
Sample patterns like [bd sd hh] are ordinary sequences; the identifiers resolve as sample names when the pattern reaches an audio track with a sampler loaded.
All three types are explored in depth in Mini-Notation in Depth.
Pattern Constructors
Section titled “Pattern Constructors”You can also build patterns with constructor functions, which is useful when the contents come from variables or arrays:
let s = Sequence(C4, E4, G4); // Same as [C4 E4 G4]let st = Stack(C4, E4, G4); // Same as [C4, E4, G4]let alt = Alternating(C4, E4, G4); // Same as <C4 E4 G4>
// All three also accept an arraylet notes = #[C4, D4, E4, F4, G4];let melody = Sequence(notes);How Patterns Work
Section titled “How Patterns Work”Patterns are lazy — they compute events on demand, not upfront. Think of a pattern as a recipe, not a recording:
- On-demand: the scheduler queries one cycle at a time, computing only what it needs right now
- Stateless: each query is independent — any cycle can be asked for in any order
- Infinite by default: patterns repeat forever without storing infinite data
This has a practical consequence: transformations like .fast(2) or .reverse() adjust how the pattern is queried, not the data itself. Chaining many transformations costs nothing until the scheduler actually asks for events.
Next Steps
Section titled “Next Steps”Now that you know how patterns divide time, dive into the notation that makes them expressive.
- Mini-Notation in Depth — nesting, parallel voices, alternation, and modifiers
- Polymetric & Euclidean — algorithmic rhythm generation
- Mini-Notation Grammar — the complete syntax reference