Skip to content

cast() & ctx

cast(machine, scale, seq, ctx?, opts?)

Combines a machine, a pitch source, and a sequence into a Pattern that the engine can schedule.

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

Arguments

ArgumentTypeDescription
machineMachineInstrument returned by vasynth(), modal(), etc.
scaleScalePattern | ChordPattern | 'drums'Pitch source. Pass 'drums' for percussion.
seqSeqSequence from seq()
ctxIncantoContext (optional)Cycle context from the song generator
opts.idstring (optional)Explicit phrase ID — overrides the auto-derived identity (machine + scale + DSL)

Drums mode

Pass 'drums' as the scale argument to use percussion mode. The sequence degrees are interpreted as hit (x) / rest (.) instead of pitch indices.

Example

function* song(ctx) {
const key = scales(4, 'C4:minor')
const synth = vasynth({ wave: 'sawtooth', gain: 0.5 })
const kk = kick({ freq: 58, gain: 0.7 })
yield cast(synth, key, seq(4, '0,2,4,~'), ctx)
yield cast(kk, 'drums', seq(4, 'x.x...x.'), ctx)
}

ctx and ctx.cycle

ctx is the context object passed into the song generator each cycle.

  • ctx.cycle — current cycle number, starting at 0
  • ctx.beatsPerCycle — current cycle length in beats
  • ctx.rand() — returns a pseudo-random number in [0, 1), seeded per cycle. Produces the same sequence for a given seed — see Meta Events.

Pass ctx to cast() so that the scheduler can track phrase phase correctly. Modifiers (every2, robin, rev, etc.) advance based on the number of times the seq has been repeated within the polymeter — not the global cycle number.

Use ctx.cycle directly to switch phrases over time:

if (ctx.cycle % 8 < 4) {
yield cast(synth, key, seq(4, '0,2,4,~'), ctx)
} else {
yield cast(synth, key, seq(4, '7,5,4,2'), ctx)
}

opts.id — explicit phrase identity

By default, the scheduler identifies each phrase by its machine name, scale, and DSL string. The repetition counter for modifiers (rev, robin, etc.) starts from zero when the phrase first appears, and resets if the phrase is not yielded for one cycle.

Use opts.id to give two phrases with the same DSL an independent counter, or when the DSL string is generated dynamically:

// two phrases with identical DSL tracked independently
yield cast(synth, key, seq(3, '(rev:0,2,4,5,3)'), ctx, { id: 'melody-a' })
yield cast(synth, key, seq(3, '(rev:0,2,4,5,3)'), ctx, { id: 'melody-b' })