Skip to content

Control Flow

let x = 5;
if x > 0 {
PRINT "positive";
}
if x > 10 {
PRINT "big";
} else {
PRINT "small";
}

Nested if/else chains work for multi-branch logic:

let score = 85;
if score >= 90 {
PRINT "A";
} else {
if score >= 80 {
PRINT "B";
} else {
PRINT "below B";
}
}

When both branches are present, if can be used as an expression. The last value in each branch is the result.

let mood = "happy";
let tempo = if mood == "happy" { 140 } else { 80 };

Chained if/else if/else works in expression position too:

let hour = 14;
let greeting = if hour < 12 { "morning" }
else if hour < 18 { "afternoon" }
else { "evening" };
let count = 0;
loop {
PRINT count;
count += 1;
if count >= 3 { break; }
}

Use continue to skip the rest of the current iteration:

let i = 0;
loop {
i += 1;
if i > 6 { break; }
if i % 2 == 0 { continue; } // skip even numbers
PRINT i; // 1, 3, 5
}

Labels let break and continue target a specific enclosing loop.

loop:rows {
loop:cols {
if done_with_rows {
break:rows; // exits the outer loop
}
if done_with_col {
continue:rows; // jumps to next row iteration
}
}
}
do 3 {
PRINT "Hello!";
}

The count expression is evaluated once before the loop begins and truncated to an integer. Any numeric expression works:

let reps = 4;
do reps {
PRINT "go";
}
do 2 + 2 {
PRINT "four times";
}

Use break to exit a do loop early:

do 100 {
if some_condition { break; }
}

Iterate over ranges, arrays, patterns, or dictionaries.

// Range
for i in range(5) {
PRINT i; // 0, 1, 2, 3, 4
}
// Range with start
for i in range(2, 5) {
PRINT i; // 2, 3, 4
}
// Over an array
let numbers = #[10, 20, 30];
for n in numbers {
PRINT n;
}
// Over a pattern
let melody = [C4 D4 E4];
for note in melody {
PRINT note;
}

break and continue work inside for loops as well:

for n in #[1, 3, 5, 7, 8, 9, 10] {
if n > 5 && n % 2 == 0 {
PRINT n; // 8
break;
}
}

for k in dict iterates over the keys of a dictionary. Use dict[k] to access the corresponding value:

let cc_map = #{"filter": 74, "resonance": 71, "volume": 7};
for param in cc_map {
PRINT param + " -> CC " + cc_map[param];
}
// filter -> CC 74
// resonance -> CC 71
// volume -> CC 7

For simultaneous access to keys and values, use .entries() which yields [key, value] pairs:

for entry in cc_map.entries() {
let name = entry[0];
let cc = entry[1];
PRINT name + ": " + cc;
}

See Dictionaries for more dict operations.

.iter().enumerate() yields [index, value] pairs, useful when you need both position and element:

let notes = #[C4, E4, G4, B4];
for pair in notes.iter().enumerate() {
let i = pair[0];
let note = pair[1];
PRINT "Step " + i + ": " + note;
}
// Step 0: C4
// Step 1: E4
// Step 2: G4
// Step 3: B4

See Iterators for more iterator methods.

match selects the first arm whose pattern matches the subject. For full coverage of variable binding, guards, and block bodies, see Match Expressions.

let day = match 3 {
1 => "Monday"
2 => "Tuesday"
3 => "Wednesday"
_ => "other"
};

Guards add conditions to arms:

let temp = 35;
let weather = match temp {
t if t > 30 => "hot"
t if t > 15 => "mild"
_ => "cold"
};

These commands control the global transport.

CommandDescription
PLAYStart or resume playback
PAUSESuspend playback without resetting position
STOPHalt playback, reset position, stop recording
RECORDStart playback and record on armed tracks
SEEK exprJump to a cycle position

Starts or resumes MIDI and audio playback from the current position.

PLAY;

Suspends playback without resetting the transport position. Calling PLAY afterwards resumes from where it left off.

PLAY;
// ... playback runs ...
PAUSE;
// position is preserved
PLAY; // resumes from the same point

Halts playback, resets the transport position to the beginning, and stops any active recording.

STOP;

Like PLAY, but also starts recording on any armed tracks. Useful for capturing live MIDI input or audio.

track.input("keyboard").monitor("in");
track.arm();
RECORD; // playback + recording begins

See Audio Input for track arming and input setup.

Jumps the transport to a specific cycle position. Takes any numeric expression.

SEEK 0; // jump to the beginning
let drop = 32;
SEEK drop; // jump to cycle 32
SEEK drop - 4; // jump to 4 cycles before the drop

A practical example combining transport commands:

PLAY;
// ... listen to the intro ...
PAUSE;
SEEK 16; // skip ahead to the chorus
PLAY; // resume from cycle 16
// ... done ...
STOP; // halt and reset to beginning