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): SeqMelody mode
Triggered when the string contains digits or commas. Elements are separated by commas.
| Token | Meaning |
|---|---|
0, 2, -1 | Scale 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 restsseq(4, '{0,2,4},~,~,~') // root-position triad held for 4 beatsseq(3, '[0,2,4],2,0') // triplet subdivision on beat 1seq(4, '0,_,_,2,_,4,_,_') // sparse bass lineDrum mode
Triggered when the string contains only x and . (no digits or commas).
| Token | Meaning |
|---|---|
x | Hit |
. | Rest |
Suffix ~ after x extends the hit; suffix _ after x adds a rest step; ! repeats the hit.
seq(4, 'x.x...x.') // syncopated kickseq(4, '..x...x.') // backbeat snare on beats 2 & 4seq(4, 'x.x.x.x.') // straight 8th hi-hatModifiers (mode: ...)
Modifiers wrap a sub-sequence and alter playback behavior. Modifiers work in both melody and drum modes.
| Syntax | Behavior |
|---|---|
(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 repetitionseq(4, '(robin:0,2,4,2),_,(every2:3),_') // round-robin + conditionalseq(4, '(every4:0),_,_,(every4:4)') // bell on every 4th repetitionseq(4, '(every2:...x)') // open hat on every 2nd repetitionseq(4, '(last2:...x)') // open hat on the 2nd of every 2 repetitionsseq(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 cycleseq(4, 'x.x.x.x.').offset(0.25) // behind-the-beat hatsscales(beats, dslString)
Returns a ScalePattern that cycles through one or more scales.
scales(beats: number, dslString: string): ScalePatternscales(dslString: string): ScalePattern // beats = number of itemsFormat: "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-penta → minor pentatonic, harmonic-minor → harmonic minor, melodic-minor → melodic 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 lowerchords(beats, scaleOrKey, progression)
Returns a ChordPattern that cycles through a Roman-numeral chord progression.
chords(beats: number, scaleOrKey: string | ScalePattern, progression: string): ChordPatternchords(scaleOrKey: string | ScalePattern, progression: string): ChordPattern // beats = chord countchords(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.
| Symbol | Scale degree |
|---|---|
I / i | 1st (tonic) |
II / ii | 2nd |
III / iii | 3rd |
IV / iv | 4th |
V / v | 5th |
VI / vi | 6th |
VII / vii | 7th |
Quality suffixes (appended directly to the numeral):
| Suffix | Quality |
|---|---|
| (none) | Diatonic triad (3 voices) |
maj | Major triad |
min / m | Minor triad |
dim | Diminished triad |
aug | Augmented triad |
7 | Dominant 7th (4 voices) |
maj7 | Major 7th |
min7 / m7 | Minor 7th |
dim7 | Diminished 7th |
9 | 9th 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 1chords(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,): PatternPass '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 chordsyield cast(kk, 'drums', seq(4, 'x.x.'), ctx) // 4-beat drum loopPhase 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.