#!/usr/bin/env python3 """MIDI Demo Page — Groove in Em × Muse VCS. Outputs: artifacts/midi-demo.html Demonstrates Muse's 21-dimensional MIDI version control using an original funky-soul groove composition built across a 5-act VCS narrative: Instruments: - Drums (kick/snare/hi-hat/ghost snares/crash) - Bass guitar (E minor pentatonic walking line) - Electric Piano (Em7→Am7→Bm7→Cmaj7 chord voicings) - Lead Synth (E pentatonic melody with pitch bends) - Brass/Ensemble (stabs and pads — conflict & resolution) VCS Narrative: Act 1 — Foundation (3 commits on main) Act 2 — Divergence (feat/groove + feat/harmony branches) Act 3 — Clean Merge (feat/groove + feat/harmony → main) Act 4 — Conflict (conflict/brass-a vs conflict/ensemble) Act 5 — Resolution (resolved mix, v1.0 tag, 21 dimensions) """ import json import logging import math import pathlib logger = logging.getLogger(__name__) # ───────────────────────────────────────────────────────────────────────────── # MUSICAL CONSTANTS (96 BPM, E minor) # ───────────────────────────────────────────────────────────────────────────── BPM: int = 96 BEAT: float = 60.0 / BPM # 0.625 s / beat BAR: float = 4 * BEAT # 2.5 s / bar S16: float = BEAT / 4 # 16th note = 0.15625 s E8: float = BEAT / 2 # 8th note = 0.3125 s Q4: float = BEAT # quarter = 0.625 s H2: float = 2 * BEAT # half = 1.25 s W1: float = 4 * BEAT # whole = 2.5 s BARS: int = 8 # every commit plays 8 bars ≈ 20 s # GM Drum pitches KICK = 36; SNARE = 38; HAT_C = 42; HAT_O = 46; CRASH = 49; RIDE = 51 # E-minor chord voicings (mid register) _EM7 = [52, 55, 59, 62] # E3 G3 B3 D4 _AM9 = [57, 60, 64, 67] # A3 C4 E4 G4 _BM7 = [59, 62, 66, 69] # B3 D4 F#4 A4 _CMAJ = [60, 64, 67, 71] # C4 E4 G4 B4 CHORDS: list[list[int]] = [_EM7, _AM9, _BM7, _CMAJ] # E pentatonic (lead) PENTA: list[int] = [64, 67, 69, 71, 74, 76] # E4 G4 A4 B4 D5 E5 def _n(pitch: int, vel: int, t: float, dur: float, instr: str) -> list[object]: """Pack a single MIDI note: [pitch, vel, start_sec, dur_sec, instr].""" return [pitch, vel, round(t, 5), round(dur, 5), instr] def _bs(bar: int) -> float: """Bar start time in seconds (0-indexed).""" return bar * BAR # ───────────────────────────────────────────────────────────────────────────── # DRUMS # ───────────────────────────────────────────────────────────────────────────── def gen_drums_basic(bars: range) -> list[list[object]]: """Kick + snare only — the skeleton groove.""" notes: list[list[object]] = [] for b in bars: t = _bs(b) if b == bars.start: notes.append(_n(CRASH, 100, t, 1.0, "crash")) # Kick beats 1 & 3 notes.append(_n(KICK, 110, t, 0.08, "kick")) notes.append(_n(KICK, 100, t + 2 * Q4, 0.08, "kick")) # Snare beats 2 & 4 notes.append(_n(SNARE, 95, t + Q4, 0.10, "snare")) notes.append(_n(SNARE, 90, t + 3 * Q4, 0.10, "snare")) return notes def gen_drums_full(bars: range) -> list[list[object]]: """Full funk pattern: kick/snare + hi-hat 16ths + ghost snares.""" notes = gen_drums_basic(bars) for b in bars: t = _bs(b) # Closed hi-hat every 16th (open on 14th 16th) for i in range(16): if i == 14: notes.append(_n(HAT_O, 72, t + i * S16, 0.20, "hat_o")) else: vel = 75 if i % 4 == 0 else (60 if i % 2 == 0 else 45) notes.append(_n(HAT_C, vel, t + i * S16, 0.06, "hat_c")) # Ghost snares (very soft, add texture) for ghost_16th in [2, 6, 10, 14]: notes.append(_n(SNARE, 22, t + ghost_16th * S16, 0.04, "ghost")) # Syncopated kick pickup on odd bars if b % 2 == 1: notes.append(_n(KICK, 78, t + 3 * Q4 + S16, 0.07, "kick")) return notes # ───────────────────────────────────────────────────────────────────────────── # BASS GUITAR (E minor pentatonic walking line) # ───────────────────────────────────────────────────────────────────────────── # E2=40 G2=43 A2=45 B2=47 C3=48 D3=50 E3=52 _BASS_CELLS: list[list[tuple[float, int, float, int]]] = [ # (beat_offset, pitch, dur_beats, vel) — bar 0 mod 4 (Em root) [(0.0, 40, 1.00, 95), (1.00, 43, 0.50, 85), (1.50, 45, 0.25, 80), (1.75, 47, 2.25, 90)], # bar 1 mod 4 (Am flavor) [(0.0, 40, 1.25, 95), (1.25, 43, 0.50, 85), (1.75, 45, 0.75, 85), (2.50, 47, 0.50, 80), (3.00, 50, 1.00, 80)], # bar 2 mod 4 (Am → Bm) [(0.0, 45, 1.00, 90), (1.00, 48, 0.50, 80), (1.50, 47, 1.75, 85), (3.25, 45, 0.75, 75)], # bar 3 mod 4 (Bm → Em) [(0.0, 47, 1.00, 90), (1.00, 50, 0.50, 85), (1.50, 45, 1.00, 80), (2.50, 40, 1.50, 95)], ] def gen_bass(bars: range) -> list[list[object]]: """E minor pentatonic walking bass line — 4-bar repeating cell.""" notes: list[list[object]] = [] for b in bars: t = _bs(b) for beat_off, pitch, dur_beats, vel in _BASS_CELLS[b % 4]: notes.append(_n(pitch, vel, t + beat_off * Q4, dur_beats * Q4, "bass")) return notes # ───────────────────────────────────────────────────────────────────────────── # ELECTRIC PIANO (Em7 → Am9 → Bm7 → Cmaj7 comping) # ───────────────────────────────────────────────────────────────────────────── # Syncopated comping hits within each bar _COMP_HITS: list[tuple[float, float, int]] = [ # (beat_offset, dur_beats, base_vel) (0.00, 0.35, 85), # beat 1 stab (1.50, 0.50, 70), # beat 2+ upbeat (2.00, 0.35, 80), # beat 3 stab (3.50, 1.00, 72), # beat 4+ sustain into next bar ] def gen_epiano(bars: range) -> list[list[object]]: """Funky electric piano comping — syncopated voicings.""" notes: list[list[object]] = [] for b in bars: t = _bs(b) chord = CHORDS[b % 4] for beat_off, dur_beats, base_vel in _COMP_HITS: for i, pitch in enumerate(chord): vel = min(127, base_vel + (3 - i) * 3) # root loudest notes.append(_n(pitch, vel, t + beat_off * Q4, dur_beats * Q4, "epiano")) return notes # ───────────────────────────────────────────────────────────────────────────── # LEAD SYNTH (E pentatonic melody, 4-bar cell) # ───────────────────────────────────────────────────────────────────────────── # (abs_beat_within_4_bars, pitch_idx, dur_beats, vel) _LEAD_CELL: list[tuple[float, int, float, int]] = [ # bar 0 — call phrase (ascending) (0.00, 2, 0.50, 85), (0.50, 3, 0.25, 80), (0.75, 4, 0.25, 82), (1.00, 4, 0.50, 88), (1.50, 3, 0.50, 78), (2.00, 3, 0.40, 80), (2.50, 2, 0.50, 75), (3.00, 1, 1.00, 82), # bar 1 — response (peak) (4.00, 0, 0.50, 75), (4.50, 1, 0.50, 78), (5.00, 2, 1.00, 88), (6.00, 3, 0.50, 82), (6.50, 4, 0.25, 80), (6.75, 5, 0.25, 85), (7.00, 5, 1.00, 92), # bar 2 — descent (8.00, 4, 0.50, 85), (8.50, 3, 0.50, 80), (9.00, 2, 0.50, 78), (9.50, 1, 0.50, 75), (10.00, 0, 1.00, 80), (11.00, 1, 1.00, 82), # bar 3 — resolution (12.00, 2, 0.50, 80), (12.50, 3, 0.50, 82), (13.00, 4, 1.00, 88), (14.00, 3, 0.50, 80), (14.50, 2, 0.50, 78), (15.00, 0, 1.50, 92), ] def gen_lead(bars: range) -> list[list[object]]: """E pentatonic melody — 4-bar repeating call-and-response phrase.""" notes: list[list[object]] = [] first = bars.start for b in bars: t = _bs(b) cell_bar = (b - first) % 4 for abs_beat, pidx, dur_beats, vel in _LEAD_CELL: if int(abs_beat) // 4 == cell_bar: local_beat = abs_beat - cell_bar * 4 notes.append(_n(PENTA[pidx], vel, t + local_beat * Q4, dur_beats * Q4, "lead")) return notes # ───────────────────────────────────────────────────────────────────────────── # BRASS / ENSEMBLE # ───────────────────────────────────────────────────────────────────────────── def gen_brass_a(bars: range) -> list[list[object]]: """Brass A: punchy staccato off-beat stabs. G major triad.""" STAB = [55, 59, 62] # G3 B3 D4 (Em → G power) notes: list[list[object]] = [] for b in bars: t = _bs(b) for beat_off in [0.5, 1.5, 2.5, 3.5]: for pitch in STAB: notes.append(_n(pitch, 95, t + beat_off * Q4, E8 * 0.55, "brass")) return notes def gen_brass_b(bars: range) -> list[list[object]]: """Brass B / Ensemble: legato swell pads. Em9 voicing.""" PAD = [52, 55, 59, 64, 67] # E3 G3 B3 E4 G4 notes: list[list[object]] = [] for b in bars: t = _bs(b) for pitch in PAD: notes.append(_n(pitch, 70, t, H2 * 1.8, "brassb")) notes.append(_n(pitch + 12, 55, t + H2, H2, "brassb")) # octave upper bloom return notes # ───────────────────────────────────────────────────────────────────────────── # COMMIT DATA (13 commits, 4 branches, 5 acts) # ───────────────────────────────────────────────────────────────────────────── def _all_notes(instrs: list[str], bars: range) -> list[list[object]]: """Gather notes for the given instruments over the bar range.""" generators: dict[str, list[list[object]]] = {} if any(i in instrs for i in ["kick", "snare", "hat_c", "hat_o", "ghost", "crash"]): full = set(instrs) & {"hat_c", "hat_o", "ghost"} if full: generators.update({k: [] for k in ["kick","snare","hat_c","hat_o","ghost","crash"]}) for nt in gen_drums_full(bars): if nt[4] in instrs: generators[str(nt[4])].append(nt) else: for nt in gen_drums_basic(bars): if nt[4] in instrs: generators.setdefault(str(nt[4]), []).append(nt) if "bass" in instrs: generators["bass"] = gen_bass(bars) if "epiano" in instrs: generators["epiano"] = gen_epiano(bars) if "lead" in instrs: generators["lead"] = gen_lead(bars) if "brass" in instrs: generators["brass"] = gen_brass_a(bars) if "brassb" in instrs: generators["brassb"] = gen_brass_b(bars) all_notes: list[list[object]] = [] for lst in generators.values(): all_notes.extend(lst) return all_notes _R = range(0, BARS) # all 8 bars _DK = ["kick", "snare"] _DF = ["kick", "snare", "hat_c", "hat_o", "ghost", "crash"] def _build_commits() -> list[dict[str, object]]: """Return the full ordered commit list with note payloads.""" def mk( sha: str, branch: str, label: str, cmd: str, output: str, act: int, instrs: list[str], dim_act: dict[str, int], parents: list[str] | None = None, conflict: bool = False, resolved: bool = False, ) -> dict[str, object]: notes = _all_notes(instrs, _R) return { "sha": sha, "branch": branch, "label": label, "cmd": cmd, "output": output, "act": act, "notes": notes, "dimAct": dim_act, "parents": parents or [], "conflict": conflict, "resolved": resolved, } # Dimension shorthand _META = {"time_signatures": 2, "key_signatures": 2, "tempo_map": 2, "markers": 2, "track_structure": 1} _VOL = {"cc_volume": 2, "cc_pan": 1} _BASS_D = {"cc_portamento": 2, "cc_reverb": 1, "cc_expression": 1, "cc_other": 1} _PIANO = {"cc_sustain": 2, "cc_chorus": 1, "cc_soft_pedal": 1, "cc_sostenuto": 1} _LEAD_D = {"pitch_bend": 3, "cc_modulation": 2, "channel_pressure": 2, "poly_pressure": 1} _BRASS_D = {"cc_expression": 3} _ENS_D = {"cc_reverb": 3, "cc_chorus": 2} # CONFLICT source c: list[dict[str, object]] = [] c.append(mk("a0f4d2e1", "main", "muse init\\n--domain midi", "muse init --domain midi", "✓ Initialized Muse repository\n domain: midi | .muse/ created", 0, [], {**_META}, )) c.append(mk("1b3c8f02", "main", "Foundation\\n4/4 · 96 BPM · Em", "muse commit -m 'Foundation: 4/4, 96 BPM, Em key'", "✓ [main 1b3c8f02] Foundation: 4/4, 96 BPM, Em key\n" " 1 file changed — .museattributes, time_sig, key_sig, markers", 1, [], {**_META, "program_change": 1}, ["a0f4d2e1"], )) c.append(mk("2d9e1a47", "main", "Foundation\\nkick + snare groove", "muse commit -m 'Foundation: kick+snare groove pattern'", "✓ [main 2d9e1a47] Foundation: kick+snare groove pattern\n" " notes dim active | cc_volume", 1, _DK, {**_META, "notes": 2, **_VOL}, ["1b3c8f02"], )) # ── Act 2: Divergence ───────────────────────────────────────────────────── c.append(mk("3f0b5c8d", "feat/groove", "Groove\\nfull drum kit + bass", "muse commit -m 'Groove: hi-hat 16ths, ghost snares, bass root motion'", "✓ [feat/groove 3f0b5c8d] Groove: hi-hat 16ths, ghost snares, bass root motion\n" " notes, program_change, cc_portamento, cc_pan", 2, [*_DF, "bass"], {**_META, "notes": 3, **_VOL, "program_change": 2, **_BASS_D}, ["2d9e1a47"], )) c.append(mk("4a2c7e91", "feat/groove", "Groove\\nbass expression + reverb", "muse commit -m 'Groove: bass portamento slides, CC reverb tail'", "✓ [feat/groove 4a2c7e91] Groove: bass portamento slides, CC reverb tail\n" " cc_portamento, cc_reverb, cc_expression active", 2, [*_DF, "bass"], {**_META, "notes": 3, **_VOL, "program_change": 2, **_BASS_D}, ["3f0b5c8d"], )) c.append(mk("5e8d3b14", "feat/harmony", "Harmony\\nEm7→Am9→Bm7→Cmaj7", "muse commit -m 'Harmony: Em7 chord voicings, CC sustain + chorus'", "✓ [feat/harmony 5e8d3b14] Harmony: Em7 chord voicings, CC sustain + chorus\n" " notes, cc_sustain, cc_chorus, cc_soft_pedal", 2, [*_DF, "epiano"], {**_META, "notes": 3, **_VOL, "program_change": 2, **_PIANO}, ["2d9e1a47"], )) c.append(mk("6c1f9a52", "feat/harmony", "Melody\\nE pentatonic + pitch bends", "muse commit -m 'Melody: E pentatonic lead, pitch_bend, channel_pressure'", "✓ [feat/harmony 6c1f9a52] Melody: E pentatonic lead, pitch_bend, channel_pressure\n" " pitch_bend, cc_modulation, channel_pressure, poly_pressure", 2, [*_DF, "epiano", "lead"], {**_META, "notes": 3, **_VOL, "program_change": 2, **_PIANO, **_LEAD_D}, ["5e8d3b14"], )) # ── Act 3: Clean Merge ──────────────────────────────────────────────────── c.append(mk("7b4e2d85", "main", "MERGE\\nfeat/groove + feat/harmony", "muse merge feat/groove feat/harmony", "✓ Merged 'feat/groove' into 'main' — 0 conflicts\n" "✓ Merged 'feat/harmony' into 'main' — 0 conflicts\n" " Full rhythm + harmony stack active", 3, [*_DF, "bass", "epiano", "lead"], {**_META, "notes": 4, **_VOL, "program_change": 3, **_BASS_D, **_PIANO, **_LEAD_D}, ["4a2c7e91", "6c1f9a52"], )) # ── Act 4: Conflict ─────────────────────────────────────────────────────── c.append(mk("8d7f1c36", "conflict/brass-a", "Brass A\\nstaccato stabs", "muse commit -m 'Brass A: punchy stabs, CC expression bus'", "✓ [conflict/brass-a 8d7f1c36] Brass A: punchy stabs, CC expression bus\n" " brass track | cc_expression elevated", 4, [*_DF, "bass", "epiano", "lead", "brass"], {**_META, "notes": 4, **_VOL, "program_change": 3, **_BASS_D, **_PIANO, **_LEAD_D, **_BRASS_D}, ["7b4e2d85"], )) c.append(mk("9e0a4b27", "conflict/ensemble", "Ensemble\\nlegato pads", "muse commit -m 'Ensemble: legato pads, CC reverb swell'", "✓ [conflict/ensemble 9e0a4b27] Ensemble: legato pads, CC reverb swell\n" " brassb track | cc_reverb elevated (CONFLICT INCOMING)", 4, [*_DF, "bass", "epiano", "lead", "brassb"], {**_META, "notes": 4, **_VOL, "program_change": 3, **_BASS_D, **_PIANO, **_LEAD_D, **_ENS_D}, ["7b4e2d85"], )) c.append(mk("a1b5c8d9", "main", "MERGE\\nconflict/brass-a → main", "muse merge conflict/brass-a", "✓ Merged 'conflict/brass-a' into 'main' — 0 conflicts\n" " stab brass layer integrated", 4, [*_DF, "bass", "epiano", "lead", "brass"], {**_META, "notes": 4, **_VOL, "program_change": 3, **_BASS_D, **_PIANO, **_LEAD_D, **_BRASS_D}, ["7b4e2d85", "8d7f1c36"], )) c.append(mk("b2c6d9e0", "main", "⚠ CONFLICT\\ncc_reverb dimension", "muse merge conflict/ensemble", "⚠ CONFLICT detected in dimension: cc_reverb\n" " conflict/brass-a: cc_reverb = 45\n" " conflict/ensemble: cc_reverb = 82\n" " → muse resolve --strategy=auto cc_reverb", 4, [*_DF, "bass", "epiano", "lead", "brass", "brassb"], {**_META, "notes": 5, **_VOL, "program_change": 4, **_BASS_D, **_PIANO, **_LEAD_D, **_BRASS_D, **_ENS_D}, ["a1b5c8d9", "9e0a4b27"], conflict=True, )) # ── Act 5: Resolution ───────────────────────────────────────────────────── c.append(mk("c3d7e0f1", "main", "RESOLVED · v1.0\\n21 dimensions active", "muse resolve --strategy=auto cc_reverb && muse tag add v1.0", "✓ Resolved cc_reverb — took max(45, 82) = 82\n" "✓ All 21 MIDI dimensions active\n" "✓ Tag 'v1.0' created → [main c3d7e0f1]", 5, [*_DF, "bass", "epiano", "lead", "brass", "brassb"], {**_META, "notes": 5, **_VOL, "program_change": 4, **_BASS_D, **_PIANO, **_LEAD_D, **_BRASS_D, **_ENS_D}, ["b2c6d9e0"], resolved=True, )) return c # ───────────────────────────────────────────────────────────────────────────── # HTML TEMPLATE # ───────────────────────────────────────────────────────────────────────────── _HTML = """\
Groove in Em — 5-act VCS narrative · 5 instruments · 21 dimensions
Click to initialize audio engine.