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() — seeded pseudo-random number, reproducible per seed. Also takes a range and has an integer variant — see Random numbers.
    • ctx.rand() → [0, 1), ctx.rand(max) → [0, max), ctx.rand(min, max) → [min, max)
    • ctx.rand.int(min, max) → integer in [min, max] (both ends inclusive)

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' })

Bounce uses the same pattern repetition, offsets, articulations, bus routing and machine automation as live playback. Negative offsets in the first cycle are included as a pickup at the beginning of the exported audio. Nested arrays of patterns and control events may be yielded together.

When a sequence repeats more often than a dynamic scale, each repetition resolves its notes at the song’s current absolute beat. For example, cast(machine, scales(4, 'C4:major,D4:major'), seq(1, '0'), ctx) plays C4, C4, D4, D4 in a four-beat cycle. This also applies to scales31.

Current key and chord

Nimbus shows the key and chord in the Header when a pitched note starts, including inversions such as Dm7/F. Scale-only patterns show their key. Simultaneous harmonies are listed together; 31EDO harmony is marked explicitly, with ^ / v representing one-step shifts. Unnamed chord stacks are shown as pitch names.

The display follows scheduled note durations and clears during rests, on Stop, and when Apply or an A/B swap is accepted. The new harmony appears when the new notes start, not when the lookahead scheduler evaluates the code. Instrument release tails and reverb do not extend the display. Percussion and unpitched sample slices do not supply a key.

Library consumers can receive the same resolved information:

const engine = new Incanto({
onHarmony(harmonies) {
// Harmony[]: { key: string, chord?: string, edo: 12 | 31 }[]
// Empty when no scheduled pitched notes remain, or on stop/swap.
renderHarmony(harmonies)
},
})

useIncanto() exposes this array as harmonies. NoteEvent.harmony holds resolved chord metadata; scale patterns supply Pattern.resolveHarmony(absoluteBeat). These describe the DSL pitch source, rather than estimating harmony from audio.