Meta Events
Meta events are plain objects you yield from the song generator alongside patterns.
The engine intercepts them at the cycle boundary and applies their effect.
function* song(ctx) { yield { type: 'tempo', bpm: 140 } yield { type: 'seed', seed: 42, once: true } yield cast(synth, key, seq(4, '0,2,4,~'), ctx)}Common fields
| Field | Type | Description |
|---|---|---|
type | string | Identifies the event kind (required) |
once | boolean | When true, the event applies only on the first cycle after play() or swap(). Subsequent cycles ignore it. |
beat | number | Offset in beats within the cycle at which the event fires (FX events only, default 0). |
tempo — Change BPM
yield { type: 'tempo', bpm: 160 }yield { type: 'tempo', bpm: 90, once: true } // set once at startTakes effect at the next cycle boundary, so all notes in the current cycle still use the previous BPM.
| Field | Type | Description |
|---|---|---|
bpm | number | New beats-per-minute value (must be positive) |
bpc — Change beats per cycle
yield { type: 'bpc', bpc: 8 }Changes how many beats make up one cycle.
| Field | Type | Description |
|---|---|---|
bpc | number | New cycle length in beats (positive integer) |
seed — Set random seed
yield { type: 'seed', seed: 42, once: true }Sets the random seed used to generate ctx.rand() values. With the same seed, the same
sequence of ctx.rand() calls produces the same values — play → stop → play always
sounds identical.
The seed takes effect starting from the next cycle. Use once: true so the seed is
re-established after each swap() without overriding changes made later in the song.
| Field | Type | Description |
|---|---|---|
seed | number | Integer seed value. Any finite number is accepted. |
Reproducibility guarantee
When you call play() or swap():
- The seed resets to the value passed to
new Incanto({ seed })(default0). - On the first cycle,
ctx.rand()is derived from that initial seed. - When a
seedevent is processed, subsequent cycles use the new seed with a per-generator cycle counter that restarts from0on eachplay()/swap().
This means two songs with the same seed event and the same generator always produce
the same ctx.rand() sequence from cycle 1 onwards.
Example — reproducible variation
function* song(ctx) { yield { type: 'seed', seed: 1337, once: true }
const key = scales(4, 'A3:minor') const synth = vasynth({ wave: 'sawtooth', gain: 0.5 })
while (true) { // ctx.rand() returns a deterministic value in [0, 1) const octave = ctx.rand() > 0.5 ? 1 : 0 yield cast(synth, key, seq(4, `${octave},2,4,~`), ctx) }}fx_reverb — Master reverb mix
yield { type: 'fx_reverb', mix: 0.3 }yield { type: 'fx_reverb', mix: 0.6, beat: 2 } // fade in at beat 2| Field | Type | Description |
|---|---|---|
mix | number | Wet/dry ratio: 0 = dry, 1 = full wet |
beat | number | Cycle beat offset for the change (default 0) |
fx_delay — Ping-pong delay
yield { type: 'fx_delay', time: 0.375, feedback: 0.4 }| Field | Type | Description |
|---|---|---|
time | number | Delay time in seconds |
feedback | number | Feedback amount: 0 = no repeats, <1 = decaying repeats |
beat | number | Cycle beat offset (default 0) |
fx_gain — Master output gain
yield { type: 'fx_gain', gain: 0.8 }| Field | Type | Description |
|---|---|---|
gain | number | Output gain multiplier (1.0 = unity gain) |
beat | number | Cycle beat offset (default 0) |
swap — Switch active deck (Dual Deck mode)
When the editor is in Dual Deck mode, yielding a swap event at a specific cycle
transitions playback to the other deck at the next cycle boundary.
function* song(ctx) { // switch to deck B after 4 cycles if (ctx.cycle === 4) yield { type: 'swap', target: 'B' } yield cast(synth, key, seq(4, '0,2,4,~'), ctx)}| Field | Type | Description |
|---|---|---|
target | 'A' | 'B' | Deck to switch to. Omit to swap to the opposite deck. |
The swap takes effect at the next cycle boundary (same as Mod-Enter Apply).
If the editor is in Single Deck mode or the target deck has no code, the event is ignored.
User-defined events
Any object with a type string and no machine key is treated as a meta event and passed
to the onMeta callback you provide when constructing Incanto. This lets you synchronise
lyrics, chord labels, lighting cues, or any external state with the music.
yield { type: 'lyrics', text: 'verse 1', beat: 0 }yield { type: 'section', name: 'chorus' }The engine delivers user-defined events via setTimeout at the correct audio time so
they stay in sync with the notes.