Skip to content

Sequence DSL

seq(beats, dslString)

Creates a sequence object. The mode (melody vs drum) is auto-detected from the string content.

seq(beats: number, dslString: string): Seq

Melody mode

Triggered when the string contains digits or commas. Elements are separated by commas.

TokenMeaning
0, 2, -1Scale degree (integer, negative allowed)
~Tie — extends the preceding note by one step
_Rest
!Repeat — repeats the preceding note by one step
{0,2,4}Chord — all degrees sound simultaneously
[0,2,4]Subdivision — 3 elements compressed into 1 beat

Degrees wrap across octaves: degree 7 in a 7-note scale plays one octave up from degree 0.

seq(4, '0,2,4,~') // C E G, tie (G held for 2 steps)
seq(4, '0,~,2,_,4,_,3,_') // ascending with ties and rests
seq(4, '{0,2,4},~,~,~') // root-position triad held for 4 beats
seq(3, '[0,2,4],2,0') // triplet subdivision on beat 1
seq(4, '0,_,_,2,_,4,_,_') // sparse bass line

Drum mode

Triggered when the string contains only x and . (no digits or commas).

TokenMeaning
xHit
.Rest

Suffix ~ after x extends the hit; suffix _ after x adds a rest step; ! repeats the hit.

seq(4, 'x.x...x.') // syncopated kick
seq(4, '..x...x.') // backbeat snare on beats 2 & 4
seq(4, 'x.x.x.x.') // straight 8th hi-hat

Modifiers (mode: ...)

Modifiers wrap a sub-sequence and alter playback behavior. Modifiers work in both melody and drum modes.

SyntaxBehavior
(rev: a,b,c)Reverses child order on alternating repetitions (even rep=forward, odd rep=reversed)
(robin: a,b,c)Round-robin: advances one child per repetition
(rand: a,b,c)Picks one child at random per repetition
(shuffle: a,b,c)Shuffles child order randomly per repetition
(everyN: a,b,c)Plays children only on every N-th repetition; silent otherwise. Write the number directly in the keyword: every2, every4, etc.
(lastN: a,b,c)Plays children only on the last repetition of every N; silent otherwise. Write the number directly in the keyword: last2, last4, etc.
(w: N*a, M*b)Weighted random: N*item sets relative weight for that item

Modifiers count repetitions of the seq within the polymeter, not song cycles. A seq(1, ...) with bpc=4 repeats 4 times per song cycle, so (robin:0,1) produces 0,1,0,1 within a single cycle.

seq(3, '(rev:0,2,4,5,3)') // reverses on every other repetition
seq(4, '(robin:0,2,4,2),_,(every2:3),_') // round-robin + conditional
seq(4, '(every4:0),_,_,(every4:4)') // bell on every 4th repetition
seq(4, '(every2:...x)') // open hat on every 2nd repetition
seq(4, '(last2:...x)') // open hat on the 2nd of every 2 repetitions
seq(4, '(w:3*0,1*4,1*7)') // degree 0 three times as likely

.offset(beats)

Returns a new Seq shifted in time by beats (range −1 to +1, silently clamped). Negative values start the phrase before the cycle boundary (anacrusis / pickup), positive values delay it for a laid-back or syncopated feel. Note content, polymeter phase and modifier counting are unchanged — only the playback time origin moves.

seq(4, '0,2,4,6').offset(-0.5) // half-beat pickup into each cycle
seq(4, 'x.x.x.x.').offset(0.25) // behind-the-beat hats

scales(beats, dslString)

Returns a ScalePattern that cycles through one or more scales.

scales(beats: number, dslString: string): ScalePattern
scales(dslString: string): ScalePattern // beats = number of items

Format: "ROOT[OCTAVE]:SCALE_NAME" (comma-separated for multiple scales).

scales(4, 'D4:minor')
scales(8, 'C4:major, G4:mixolydian')

Scale names are resolved via the tonal library. Commonly used names:

major minor dorian phrygian lydian mixolydian locrian minor pentatonic major pentatonic harmonic minor melodic minor chromatic whole tone diminished

Aliases: minor-pentaminor pentatonic, harmonic-minorharmonic minor, melodic-minormelodic minor.

Root notes: C C# Db D D# Eb E F F# Gb G G# Ab A A# Bb B

Octave defaults to 4 when omitted (D:minor = D4:minor).

.transpose(semitones)

Returns a new ScalePattern shifted by the given number of semitones. Negative values move down.

const key = scales(4, 'D4:minor')
const bKey = key.transpose(-12) // one octave lower

chords(beats, scaleOrKey, progression)

Returns a ChordPattern that cycles through a Roman-numeral chord progression.

chords(beats: number, scaleOrKey: string | ScalePattern, progression: string): ChordPattern
chords(scaleOrKey: string | ScalePattern, progression: string): ChordPattern // beats = chord count
chords(8, key, 'I,VII,VI,III')
chords(4, 'C4:major', 'I,IV,V,I')

Roman numerals

Uppercase = diatonic triad built on that scale degree; lowercase is also accepted.

SymbolScale degree
I / i1st (tonic)
II / ii2nd
III / iii3rd
IV / iv4th
V / v5th
VI / vi6th
VII / vii7th

Quality suffixes (appended directly to the numeral):

SuffixQuality
(none)Diatonic triad (3 voices)
majMajor triad
min / mMinor triad
dimDiminished triad
augAugmented triad
7Dominant 7th (4 voices)
maj7Major 7th
min7 / m7Minor 7th
dim7Diminished 7th
99th chord (5 voices)

~ or _ after a symbol holds the preceding chord for an extra step.

chords(4, key, 'I~~,V') // I held for 3 beats, V for 1
chords(4, key, 'Imaj7,IVmaj7,V7,I')

cast(machine, scaleOrChords, seq, ctx)

Combines a machine, a pitch source, and a sequence into a playable Pattern.

cast(
machine: Machine,
scaleOrKit: string | ScalePattern | ChordPattern,
seq: Seq,
ctx?: IncantoContext,
): Pattern

Pass 'drums' (or any non-scale string) as scaleOrKit for percussion — pitch is ignored.

yield cast(vib, prog, seq(4, '0,2,4,3'), ctx)
yield cast(bass, bKey, seq(4, '0,_,4,_'), ctx)
yield cast(kk, 'drums', seq(4, 'x.x.'), ctx)

ctx carries ctx.cycle (current cycle number, 0-indexed) and ctx.beatsPerCycle.


Polymeter

Each seq has its own beats length. When seq.beats differs from the chord or cycle length, the sequence repeats at its own period — natural polymeter with no extra configuration.

yield cast(vib, prog, seq(3, '0,2,4'), ctx) // 3-beat pattern against 8-beat chords
yield cast(kk, 'drums', seq(4, 'x.x.'), ctx) // 4-beat drum loop

Phase tracking

The scheduler tracks each phrase’s repetition count independently of the global cycle number. Modifier operators (rev, robin, rand, shuffle, everyN) advance based on how many times the seq has been repeated since the phrase first appeared, not based on ctx.cycle.

A phrase is identified by its machine name + scale + DSL string (or by opts.id if provided to cast()). If a phrase is not yielded for one cycle, its repetition count resets the next time it appears.