-
Notifications
You must be signed in to change notification settings - Fork 0
Generative
Flow has several primitives for algorithmic and probabilistic music: Euclidean rhythms, weighted random choice, seeded randomness, sequence mutation (vary), and polyrhythm construction.
Distribute k hits evenly across n steps using the Bjorklund algorithm:
use "@std"
Sequence e38 = (euclidean 3 8 C4)
(print (str e38)) Note: X..X..X. style pattern
Sequence e58 = (euclidean 5 8 E4)
(print (str e58))
Signature: (euclidean Int hits, Int steps, Note pitch) -> Sequence
Common Euclidean patterns map to global rhythmic traditions:
hits / steps
|
Feel |
|---|---|
| 3/8 | Cuban tresillo |
| 5/8 | West African bell pattern |
| 3/4 | Simple triplet |
| 7/16 | Afro-Cuban bembé |
Pick a note at random from a set. This is syntax, not a function — it works only inside | ... | note streams.
(? ...) picks one of the listed notes with equal probability on each evaluation:
use "@std"
timesig 4/4 {
Sequence random = | (? C4 E4 G4) (? C4 E4 G4) (? C4 E4 G4) (? C4 E4 G4) |
}
Append :weight to bias the selection:
timesig 4/4 {
Sequence weighted = | (? C4:50 E4:30 G4:20) (? C4:50 E4:30 G4:20) _ _ |
}
Weights are relative, not percentages. :50 :30 :20 is equivalent to :5 :3 :2.
Rests (_) can be options too:
timesig 4/4 {
Sequence sparse = | (? C4 _) (? E4 _) (? G4 _) (? C4 _) |
}
(?? ...) is a second, separately seeded RNG. It produces reproducible output once a seed is set.
use "@std"
(??set 42)
timesig 4/4 {
Sequence seeded = | (?? C4 E4 G4) (?? D4 F4 A4) (?? E4 G4 B4) (?? C4 E4 G4) |
}
| Function | Effect |
|---|---|
(??set N) |
Set the seeded RNG state to N
|
(??reset) |
Reset the seeded RNG to its initial state |
(??) |
Get a random Float from the seeded stream |
(?) |
Get a random Float from the unseeded stream |
vary applies random mutations to a sequence. You can choose what to mutate and whether to constrain output to a key.
use "@std"
Sequence s = | C4 D4 E4 F4 G4 |
Note: basic mutation (random type, 30% chance per note)
Sequence v1 = s -> vary(0.3)
Note: specific mutation type
Sequence v2 = (vary s 0.5 "pitch")
Sequence v3 = (vary s 0.5 "rhythm")
Sequence v4 = (vary s 0.5 "rest")
Sequence v5 = (vary s 0.5 "velocity")
Note: seeded (reproducible)
Sequence v6 = (vary s 0.5 42)
Note: seeded + type
Sequence v7 = (vary s 0.5 "pitch" 42)
Note: diatonic — constrain pitch mutations to a scale
Sequence v8 = (vary s 0.5 "pitch" "Cmajor")
Sequence v9 = (vary s 0.5 "pitch" "Cmajor" 42)
Overloads
| Signature | Description |
|---|---|
(Sequence, Double) -> Sequence |
Random mutation type |
(Sequence, Double, String) -> Sequence |
Specific type |
(Sequence, Double, Int) -> Sequence |
Seeded random type |
(Sequence, Double, String, Int) -> Sequence |
Seeded, specific type |
(Sequence, Double, String, String) -> Sequence |
Diatonic (type, key) |
(Sequence, Double, String, String, Int) -> Sequence |
Diatonic, seeded |
Mutation types
| Type | Effect |
|---|---|
"pitch" |
Shift pitch up/down, optionally snapping to key |
"rhythm" |
Randomize note durations |
"rest" |
Replace note with rest |
"velocity" |
Randomize velocity |
Overlay two sequences with different time signatures. polyrhythm figures out the cycle length (LCM of time signatures) and returns a mixed buffer:
use "@std"
use "@audio"
tempo 120 {
timesig 3/4 {
Sequence waltz = | A3 E4 E4 |
timesig 4/4 {
Sequence quarters = | C4 C4 C4 C4 |
Buffer poly = (polyrhythm waltz quarters)
(exportWav poly "polyrhythm.wav")
}
}
}
Signatures
| Signature | Description |
|---|---|
(polyrhythm Sequence, Sequence) -> Buffer |
Auto-align via LCM of time signatures |
(polyrhythm Sequence, Sequence, Int) -> Buffer |
Explicit beat count override |
Generative primitives compose cleanly:
use "@std"
use "@audio"
tempo 120 {
timesig 4/4 {
key Cmajor {
Note: a Euclidean hi-hat
Sequence hat = (euclidean 5 8 C5)
Note: a seeded melodic line
(??set 7)
Sequence lead = | (?? C4 E4 G4 B4) (?? D4 F4 A4) (?? E4 G4 B4) (?? F4 A4 C5) |
Note: diatonic mutation on the lead
Sequence varied = (vary lead 0.3 "pitch" "Cmajor" 7)
section groove {
Sequence a = hat
Sequence b = varied
}
Song song = [groove*4]
Buffer buf = (renderSong song "piano")
(exportWav buf "generative.wav")
}
}
}
- Note Streams - Full note-stream syntax
- Pattern Transforms - Deterministic transforms
- Chords and Harmony - Scales for diatonic variation
- Loops - Generating longer pieces imperatively