Skip to content

Make a Reproducible Random Choice

The functions in std/random take a seed and return the same result for the same seed, so a piece that uses them plays the same way every time, and after every seek. How Patterns Work explains why.

choose(seed, values) picks one element; choose_weighted(seed, values, weights) takes a parallel array of weights:

use "std/random" { choose, choose_weighted };
let notes = #[C4, E4, G4, B4];
print(choose(0, notes)); // the same element on every run
let chords = #[[C4 E4 G4], [F4 A4 C5], [G4 B4 D5]];
let weights = #[3, 1, 1]; // C major three times as likely
print(choose_weighted(0, chords, weights));

rand(seed) returns a number from 0 to 1 the same way. Change the seed for a different pick.

Seed with the cycle number, inside a stream or an on_cycle callback, and the pick changes from cycle to cycle but is the same on every playback:

use "std/instruments" { SamplerMelodic, Kit };
use "std/random" { choose };
let lead = AudioTrack("lead");
lead.set_instrument(SamplerMelodic(Kit("keys")));
let notes = #[60, 64, 67, 71];
on_cycle(fn(cycle) {
lead << Sequence(#[choose(cycle, notes)]);
});
PLAY;

Assert that the same seed gives the same value:

use "std/random" { rand };
assert rand(7) == rand(7), "same seed must give the same value";
print("deterministic");

rand_true() and choose_true() are unseeded and fail this check on purpose. Use them only when you want a different result on every call.