Flow

Markov Jazz

Jazz — generative / chord-aware improvisation · Phase 36

Markov Jazz: Stopped
No pre-rendered audio yet Open it in the playground below and press Run to hear it.
Composer notes

The headline Phase 36 generative showcase. A short C-major scale teaches a Markov chain step-wise melodic motion; `(markov ...)` one-shots it, then the train/generate split `(markovTrain ...) -> MarkovModel` + `(markovGenerate ...)` reuses the model across bars. `(jam over=chords style=#jazz ...)` improvises chord-aware lines over a ii–V–I–vi progression, and `@patterns` combinators (`every`, `fast`, `sometimes`) vary the result. Every stochastic call routes through the PRNG registry, so two renders are byte-identical.

Source

// =====================================================================
// Markov Jazz — Phase 36 generative showcase
// =====================================================================
// Demonstrates the headline Phase 36 generative + improv surface:
//
//   - One-shot `(markov corpus order length seed)` for quick exploration
//   - Train/generate split `(markovTrain corpus order) -> MarkovModel`
//     + `(markovGenerate model length seed)` for reuse across many bars
//     (per D-36-06)
//   - Chord-aware Markov improvisation via `(jam over=chords style=#jazz
//     length=N seed=N)` over a ii-V-I-VI progression (per D-36-10)
//   - Phase 35 `as` chain naming threaded through Phase 36 combinators
//     (`-> (every ...) as varied`)
//
// PRNG determinism (D-v1.5-06 / D-36-09): unseeded generative calls route
// through `ExecutionContext.PrngRegistry` keyed by (SourceLocation, name)
// and reseed at every `writeWav` boundary. Two consecutive renders of
// THIS file produce byte-identical WAV output (verified by
// `scripts/test_two_run_determinism.sh examples/generative/markov_jazz.flow`).
//
// Cross-platform note: Lorenz / logistic chaos primitives carry a
// documented platform-specific FP-divergence caveat (D-36-09). This
// example uses Markov + jam ONLY — Markov state is integer-pitch-keyed
// and is byte-portable across Linux / macOS / Windows builds.
//
// Render with:
//   dotnet run --project flow-cli -- run examples/generative/markov_jazz.flow
//
// The writeWav target below is `/tmp/markov_jazz.wav` (Phase 36 test
// convention) so `scripts/test_two_run_determinism.sh` can render the
// file from any CWD. Copy the output elsewhere if you want to keep it.

use "@std"
use "@audio"
use "@patterns"
use "@generative"
use "@improv"

tempo 120 {
    timesig 4/4 {
        key Cmajor {

            // -------------------------------------------------------------
            // 1. One-shot Markov — `(markov corpus order length seed)`.
            //    A short ascending+descending C-major scale teaches the
            //    chain a step-wise melodic motion; seed=42 makes the
            //    output identical across consecutive renders.
            // -------------------------------------------------------------
            Sequence corpus = | C4q D4q E4q F4q G4q F4q E4q D4q C4q |
            Sequence oneShot = (markov corpus 2 16 42)

            // -------------------------------------------------------------
            // 2. Train once, generate many — D-36-06 split shape.
            //    `MarkovModel` is a reference-identity value type
            //    (Pitfall 6) — two `(markovTrain corpus order)` calls
            //    produce DISTINCT models; structural equality via
            //    `(markovEqual a b)`.
            // -------------------------------------------------------------
            MarkovModel m = (markovTrain corpus 2)
            Sequence riffA = (markovGenerate m 8 100)
            Sequence riffB = (markovGenerate m 8 200)

            // -------------------------------------------------------------
            // 3. Chord-aware jam over a ii-V-I-VI in C major (D-36-10).
            //    `jam` signature (positional form):
            //      (jam over=chords style=#jazz length=4 key="Cmajor"
            //           seed=1234 order=2)
            //    Style packs ship at `flow-lang/improv/styles/*.flow`;
            //    composer can override at `~/.config/flow/styles/*.flow`.
            // -------------------------------------------------------------
            Sequence chords = | Dm7 | G7 | Cmaj7 | Am7 |
            Sequence solo = (jam chords #jazz 4 "Cmajor" 1234 2)

            // -------------------------------------------------------------
            // 4. Phase 36 `@patterns` combinators (D-36-03 lambda-required,
            //    D-36-04 cycle unit = bars). Apply `fast 2.0` to every
            //    2nd bar of the `riffA` Markov output, then sprinkle a
            //    stochastic transposition on top via `sometimes` (PRNG
            //    routed through `PrngRegistry` per D-v1.5-06).
            // -------------------------------------------------------------
            Sequence varied = (every 2 (fn Sequence s => (fast s 2.0)) riffA)
            Sequence variation = (sometimes 0.4 (fn Sequence s => (transpose s +7st)) varied)

            // -------------------------------------------------------------
            // 5. Stitch all four sequences into a single piano render.
            //    Each section becomes its own bar group; the Song laid
            //    out as `[oneShot solo variation riffB]` plays them in
            //    that order.
            // -------------------------------------------------------------
            section A { Sequence v = oneShot }
            section B { Sequence v = solo }
            section C { Sequence v = variation }
            section D { Sequence v = riffB }

            Song song = [A B C D]
            Buffer mix = (renderSong song "piano")
            (writeWav "/tmp/markov_jazz.wav" mix)
        }
    }
}
examples/generative/markov_jazz.flow
Open in playground