Generate a Progression with a Markov Chain
markov(states, matrix, start) moves between numbered
states. Row i of the matrix holds the chances of going from state i to each state, and each row
sums to 1. The chain takes the same path on every playback.
Write the chain and map its states
Section titled “Write the chain and map its states”The chain outputs state indices, so map them to notes or chords. A small script pattern does that:
use "std/instruments" { SamplerMelodic, Kit };use "std/generative" { markov };
class Mapped { let chain; let notes;
fn new(chain, notes) { this.chain = chain; this.notes = notes; }
fn query(cycle) { return this.notes[this.chain.query(cycle)]; }}
let three_state = markov( 3, #[ #[0.5, 0.5, 0.0], #[0.0, 0.5, 0.5], #[0.5, 0.0, 0.5] ], 0);
let lead = AudioTrack("lead");lead.set_instrument(SamplerMelodic(Kit("keys")));lead << Mapped(three_state, #[C4, E4, G4]);
PLAY;Forbid a move
Section titled “Forbid a move”Set its weight to zero. In the chain above, state 0 never jumps straight to state 2, and state 2 never reaches state 1. Zeros encode the rules of your harmony — for example, to stop a V chord from going directly to a ii.
Don’t make a whole row zero unless you want the chain to stay stuck in that state.
End on a cadence
Section titled “End on a cadence”Give the home state a row that points only to itself. Once the chain reaches it, it stays:
use "std/generative" { markov };
let resolving = markov( 3, #[ #[0.0, 0.7, 0.3], // start: mostly move toward state 1 #[0.0, 0.3, 0.7], // middle: mostly move toward state 2 #[0.0, 0.0, 1.0] // end: stay ], 0);
print(resolving.query(10)); // settled on state 2Related
Section titled “Related”- Generative —
markovand its methods - Write a Pattern as a Class — patterns with state of their own