#!/usr/bin/env python3 """MIDI Demo Page generator — Bach Prelude BWV 846 × Muse VCS. Outputs: artifacts/midi-demo.html Demonstrates Muse's 21-dimensional MIDI version control using Bach's Prelude No. 1 in C Major (BWV 846). Note data sourced from the music21 corpus (MuseScore 1.3 transcription, 2013-07-09, musescore.com/score/117279). Bach died 1750 — public domain. Format: [pitch_midi, velocity, start_sec, duration_sec, measure, voice] """ import json import logging import pathlib logger = logging.getLogger(__name__) # ────────────────────────────────────────────────────────────────────────────── # Bach BWV 846 — note data extracted from music21 corpus MusicXML # Voices: 1=treble arpeggios (pitch 55-81), 5=bass long notes (36-60), # 6=inner voice (47-64). Tempo: 66 BPM, Duration: ~127s. # ────────────────────────────────────────────────────────────────────────────── _BACH_NOTES_JSON = ( "[[60,64,0.0,1.5833,1,5],[64,64,0.2083,0.5938,1,6],[67,80,0.4167,0.1979,1,1]," "[72,80,0.625,0.1979,1,1],[76,80,0.8333,0.1979,1,1],[67,80,1.0417,0.1979,1,1]," "[72,80,1.25,0.1979,1,1],[76,80,1.4583,0.1979,1,1],[60,64,1.6667,1.5833,1,5]," "[64,64,1.875,0.5938,1,6],[67,80,2.0833,0.1979,1,1],[72,80,2.2917,0.1979,1,1]," "[76,80,2.5,0.1979,1,1],[67,80,2.7083,0.1979,1,1],[72,80,2.9167,0.1979,1,1]," "[76,80,3.125,0.1979,1,1],[60,64,3.3333,1.5833,2,5],[62,64,3.5417,0.5938,2,6]," "[69,80,3.75,0.1979,2,1],[74,80,3.9583,0.1979,2,1],[77,80,4.1667,0.1979,2,1]," "[69,80,4.375,0.1979,2,1],[74,80,4.5833,0.1979,2,1],[77,80,4.7917,0.1979,2,1]," "[60,64,5.0,1.5833,2,5],[62,64,5.2083,0.5938,2,6],[69,80,5.4167,0.1979,2,1]," "[74,80,5.625,0.1979,2,1],[77,80,5.8333,0.1979,2,1],[69,80,6.0417,0.1979,2,1]," "[74,80,6.25,0.1979,2,1],[77,80,6.4583,0.1979,2,1],[59,64,6.6667,1.5833,3,5]," "[62,64,6.875,0.5938,3,6],[67,80,7.0833,0.1979,3,1],[74,80,7.2917,0.1979,3,1]," "[77,80,7.5,0.1979,3,1],[67,80,7.7083,0.1979,3,1],[74,80,7.9167,0.1979,3,1]," "[77,80,8.125,0.1979,3,1],[59,64,8.3333,1.5833,3,5],[62,64,8.5417,0.5938,3,6]," "[67,80,8.75,0.1979,3,1],[74,80,8.9583,0.1979,3,1],[77,80,9.1667,0.1979,3,1]," "[67,80,9.375,0.1979,3,1],[74,80,9.5833,0.1979,3,1],[77,80,9.7917,0.1979,3,1]," "[60,64,10.0,1.5833,4,5],[64,64,10.2083,0.5938,4,6],[67,80,10.4167,0.1979,4,1]," "[72,80,10.625,0.1979,4,1],[76,80,10.8333,0.1979,4,1],[67,80,11.0417,0.1979,4,1]," "[72,80,11.25,0.1979,4,1],[76,80,11.4583,0.1979,4,1],[60,64,11.6667,1.5833,4,5]," "[64,64,11.875,0.5938,4,6],[67,80,12.0833,0.1979,4,1],[72,80,12.2917,0.1979,4,1]," "[76,80,12.5,0.1979,4,1],[67,80,12.7083,0.1979,4,1],[72,80,12.9167,0.1979,4,1]," "[76,80,13.125,0.1979,4,1],[60,64,13.3333,1.5833,5,5],[64,64,13.5417,0.5938,5,6]," "[69,80,13.75,0.1979,5,1],[76,80,13.9583,0.1979,5,1],[81,80,14.1667,0.1979,5,1]," "[69,80,14.375,0.1979,5,1],[76,80,14.5833,0.1979,5,1],[81,80,14.7917,0.1979,5,1]," "[60,64,15.0,1.5833,5,5],[64,64,15.2083,0.5938,5,6],[69,80,15.4167,0.1979,5,1]," "[76,80,15.625,0.1979,5,1],[81,80,15.8333,0.1979,5,1],[69,80,16.0417,0.1979,5,1]," "[76,80,16.25,0.1979,5,1],[81,80,16.4583,0.1979,5,1],[60,64,16.6667,1.5833,6,5]," "[62,64,16.875,0.5938,6,6],[66,80,17.0833,0.1979,6,1],[69,80,17.2917,0.1979,6,1]," "[74,80,17.5,0.1979,6,1],[66,80,17.7083,0.1979,6,1],[69,80,17.9167,0.1979,6,1]," "[74,80,18.125,0.1979,6,1],[60,64,18.3333,1.5833,6,5],[62,64,18.5417,0.5938,6,6]," "[66,80,18.75,0.1979,6,1],[69,80,18.9583,0.1979,6,1],[74,80,19.1667,0.1979,6,1]," "[66,80,19.375,0.1979,6,1],[69,80,19.5833,0.1979,6,1],[74,80,19.7917,0.1979,6,1]," "[59,64,20.0,1.5833,7,5],[62,64,20.2083,0.5938,7,6],[67,80,20.4167,0.1979,7,1]," "[74,80,20.625,0.1979,7,1],[79,80,20.8333,0.1979,7,1],[67,80,21.0417,0.1979,7,1]," "[74,80,21.25,0.1979,7,1],[79,80,21.4583,0.1979,7,1],[59,64,21.6667,1.5833,7,5]," "[62,64,21.875,0.5938,7,6],[67,80,22.0833,0.1979,7,1],[74,80,22.2917,0.1979,7,1]," "[79,80,22.5,0.1979,7,1],[67,80,22.7083,0.1979,7,1],[74,80,22.9167,0.1979,7,1]," "[79,80,23.125,0.1979,7,1],[59,64,23.3333,1.5833,8,5],[60,64,23.5417,0.5938,8,6]," "[64,80,23.75,0.1979,8,1],[67,80,23.9583,0.1979,8,1],[72,80,24.1667,0.1979,8,1]," "[64,80,24.375,0.1979,8,1],[67,80,24.5833,0.1979,8,1],[72,80,24.7917,0.1979,8,1]," "[59,64,25.0,1.5833,8,5],[60,64,25.2083,0.5938,8,6],[64,80,25.4167,0.1979,8,1]," "[67,80,25.625,0.1979,8,1],[72,80,25.8333,0.1979,8,1],[64,80,26.0417,0.1979,8,1]," "[67,80,26.25,0.1979,8,1],[72,80,26.4583,0.1979,8,1],[57,64,26.6667,1.5833,9,5]," "[60,64,26.875,0.5938,9,6],[64,80,27.0833,0.1979,9,1],[67,80,27.2917,0.1979,9,1]," "[72,80,27.5,0.1979,9,1],[64,80,27.7083,0.1979,9,1],[67,80,27.9167,0.1979,9,1]," "[72,80,28.125,0.1979,9,1],[57,64,28.3333,1.5833,9,5],[60,64,28.5417,0.5938,9,6]," "[64,80,28.75,0.1979,9,1],[67,80,28.9583,0.1979,9,1],[72,80,29.1667,0.1979,9,1]," "[64,80,29.375,0.1979,9,1],[67,80,29.5833,0.1979,9,1],[72,80,29.7917,0.1979,9,1]," "[50,64,30.0,1.5833,10,5],[57,64,30.2083,0.5938,10,6],[62,80,30.4167,0.1979,10,1]," "[66,80,30.625,0.1979,10,1],[72,80,30.8333,0.1979,10,1],[62,80,31.0417,0.1979,10,1]," "[66,80,31.25,0.1979,10,1],[72,80,31.4583,0.1979,10,1],[50,64,31.6667,1.5833,10,5]," "[57,64,31.875,0.5938,10,6],[62,80,32.0833,0.1979,10,1],[66,80,32.2917,0.1979,10,1]," "[72,80,32.5,0.1979,10,1],[62,80,32.7083,0.1979,10,1],[66,80,32.9167,0.1979,10,1]," "[72,80,33.125,0.1979,10,1],[55,64,33.3333,1.5833,11,5],[59,64,33.5417,0.5938,11,6]," "[62,80,33.75,0.1979,11,1],[67,80,33.9583,0.1979,11,1],[71,80,34.1667,0.1979,11,1]," "[62,80,34.375,0.1979,11,1],[67,80,34.5833,0.1979,11,1],[71,80,34.7917,0.1979,11,1]," "[55,64,35.0,1.5833,11,5],[59,64,35.2083,0.5938,11,6],[62,80,35.4167,0.1979,11,1]," "[67,80,35.625,0.1979,11,1],[71,80,35.8333,0.1979,11,1],[62,80,36.0417,0.1979,11,1]," "[67,80,36.25,0.1979,11,1],[71,80,36.4583,0.1979,11,1],[55,64,36.6667,1.5833,12,5]," "[58,64,36.875,0.5938,12,6],[64,80,37.0833,0.1979,12,1],[67,80,37.2917,0.1979,12,1]," "[73,80,37.5,0.1979,12,1],[64,80,37.7083,0.1979,12,1],[67,80,37.9167,0.1979,12,1]," "[73,80,38.125,0.1979,12,1],[55,64,38.3333,1.5833,12,5],[58,64,38.5417,0.5938,12,6]," "[64,80,38.75,0.1979,12,1],[67,80,38.9583,0.1979,12,1],[73,80,39.1667,0.1979,12,1]," "[64,80,39.375,0.1979,12,1],[67,80,39.5833,0.1979,12,1],[73,80,39.7917,0.1979,12,1]," "[53,64,40.0,1.5833,13,5],[57,64,40.2083,0.5938,13,6],[62,80,40.4167,0.1979,13,1]," "[69,80,40.625,0.1979,13,1],[74,80,40.8333,0.1979,13,1],[62,80,41.0417,0.1979,13,1]," "[69,80,41.25,0.1979,13,1],[74,80,41.4583,0.1979,13,1],[53,64,41.6667,1.5833,13,5]," "[57,64,41.875,0.5938,13,6],[62,80,42.0833,0.1979,13,1],[69,80,42.2917,0.1979,13,1]," "[74,80,42.5,0.1979,13,1],[62,80,42.7083,0.1979,13,1],[69,80,42.9167,0.1979,13,1]," "[74,80,43.125,0.1979,13,1],[53,64,43.3333,1.5833,14,5],[56,64,43.5417,0.5938,14,6]," "[62,80,43.75,0.1979,14,1],[65,80,43.9583,0.1979,14,1],[71,80,44.1667,0.1979,14,1]," "[62,80,44.375,0.1979,14,1],[65,80,44.5833,0.1979,14,1],[71,80,44.7917,0.1979,14,1]," "[53,64,45.0,1.5833,14,5],[56,64,45.2083,0.5938,14,6],[62,80,45.4167,0.1979,14,1]," "[65,80,45.625,0.1979,14,1],[71,80,45.8333,0.1979,14,1],[62,80,46.0417,0.1979,14,1]," "[65,80,46.25,0.1979,14,1],[71,80,46.4583,0.1979,14,1],[52,64,46.6667,1.5833,15,5]," "[55,64,46.875,0.5938,15,6],[60,80,47.0833,0.1979,15,1],[67,80,47.2917,0.1979,15,1]," "[72,80,47.5,0.1979,15,1],[60,80,47.7083,0.1979,15,1],[67,80,47.9167,0.1979,15,1]," "[72,80,48.125,0.1979,15,1],[52,64,48.3333,1.5833,15,5],[55,64,48.5417,0.5938,15,6]," "[60,80,48.75,0.1979,15,1],[67,80,48.9583,0.1979,15,1],[72,80,49.1667,0.1979,15,1]," "[60,80,49.375,0.1979,15,1],[67,80,49.5833,0.1979,15,1],[72,80,49.7917,0.1979,15,1]," "[52,64,50.0,1.5833,16,5],[53,64,50.2083,0.5938,16,6],[57,80,50.4167,0.1979,16,1]," "[60,80,50.625,0.1979,16,1],[65,80,50.8333,0.1979,16,1],[57,80,51.0417,0.1979,16,1]," "[60,80,51.25,0.1979,16,1],[65,80,51.4583,0.1979,16,1],[52,64,51.6667,1.5833,16,5]," "[53,64,51.875,0.5938,16,6],[57,80,52.0833,0.1979,16,1],[60,80,52.2917,0.1979,16,1]," "[65,80,52.5,0.1979,16,1],[57,80,52.7083,0.1979,16,1],[60,80,52.9167,0.1979,16,1]," "[65,80,53.125,0.1979,16,1],[50,64,53.3333,1.5833,17,5],[53,64,53.5417,0.5938,17,6]," "[57,80,53.75,0.1979,17,1],[60,80,53.9583,0.1979,17,1],[65,80,54.1667,0.1979,17,1]," "[57,80,54.375,0.1979,17,1],[60,80,54.5833,0.1979,17,1],[65,80,54.7917,0.1979,17,1]," "[50,64,55.0,1.5833,17,5],[53,64,55.2083,0.5938,17,6],[57,80,55.4167,0.1979,17,1]," "[60,80,55.625,0.1979,17,1],[65,80,55.8333,0.1979,17,1],[57,80,56.0417,0.1979,17,1]," "[60,80,56.25,0.1979,17,1],[65,80,56.4583,0.1979,17,1],[43,64,56.6667,1.5833,18,5]," "[50,64,56.875,0.5938,18,6],[55,80,57.0833,0.1979,18,1],[59,80,57.2917,0.1979,18,1]," "[65,80,57.5,0.1979,18,1],[55,80,57.7083,0.1979,18,1],[59,80,57.9167,0.1979,18,1]," "[65,80,58.125,0.1979,18,1],[43,64,58.3333,1.5833,18,5],[50,64,58.5417,0.5938,18,6]," "[55,80,58.75,0.1979,18,1],[59,80,58.9583,0.1979,18,1],[65,80,59.1667,0.1979,18,1]," "[55,80,59.375,0.1979,18,1],[59,80,59.5833,0.1979,18,1],[65,80,59.7917,0.1979,18,1]," "[48,64,60.0,1.5833,19,5],[52,64,60.2083,0.5938,19,6],[55,80,60.4167,0.1979,19,1]," "[60,80,60.625,0.1979,19,1],[64,80,60.8333,0.1979,19,1],[55,80,61.0417,0.1979,19,1]," "[60,80,61.25,0.1979,19,1],[64,80,61.4583,0.1979,19,1],[48,64,61.6667,1.5833,19,5]," "[52,64,61.875,0.5938,19,6],[55,80,62.0833,0.1979,19,1],[60,80,62.2917,0.1979,19,1]," "[64,80,62.5,0.1979,19,1],[55,80,62.7083,0.1979,19,1],[60,80,62.9167,0.1979,19,1]," "[64,80,63.125,0.1979,19,1],[48,64,63.3333,1.5833,20,5],[55,64,63.5417,0.5938,20,6]," "[58,80,63.75,0.1979,20,1],[60,80,63.9583,0.1979,20,1],[64,80,64.1667,0.1979,20,1]," "[58,80,64.375,0.1979,20,1],[60,80,64.5833,0.1979,20,1],[64,80,64.7917,0.1979,20,1]," "[48,64,65.0,1.5833,20,5],[55,64,65.2083,0.5938,20,6],[58,80,65.4167,0.1979,20,1]," "[60,80,65.625,0.1979,20,1],[64,80,65.8333,0.1979,20,1],[58,80,66.0417,0.1979,20,1]," "[60,80,66.25,0.1979,20,1],[64,80,66.4583,0.1979,20,1],[41,64,66.6667,1.5833,21,5]," "[53,64,66.875,0.5938,21,6],[57,80,67.0833,0.1979,21,1],[60,80,67.2917,0.1979,21,1]," "[64,80,67.5,0.1979,21,1],[57,80,67.7083,0.1979,21,1],[60,80,67.9167,0.1979,21,1]," "[64,80,68.125,0.1979,21,1],[41,64,68.3333,1.5833,21,5],[53,64,68.5417,0.5938,21,6]," "[57,80,68.75,0.1979,21,1],[60,80,68.9583,0.1979,21,1],[64,80,69.1667,0.1979,21,1]," "[57,80,69.375,0.1979,21,1],[60,80,69.5833,0.1979,21,1],[64,80,69.7917,0.1979,21,1]," "[42,64,70.0,1.5833,22,5],[48,64,70.2083,0.5938,22,6],[57,80,70.4167,0.1979,22,1]," "[60,80,70.625,0.1979,22,1],[63,80,70.8333,0.1979,22,1],[57,80,71.0417,0.1979,22,1]," "[60,80,71.25,0.1979,22,1],[63,80,71.4583,0.1979,22,1],[42,64,71.6667,1.5833,22,5]," "[48,64,71.875,0.5938,22,6],[57,80,72.0833,0.1979,22,1],[60,80,72.2917,0.1979,22,1]," "[63,80,72.5,0.1979,22,1],[57,80,72.7083,0.1979,22,1],[60,80,72.9167,0.1979,22,1]," "[63,80,73.125,0.1979,22,1],[44,64,73.3333,1.5833,23,5],[53,64,73.5417,0.5938,23,6]," "[59,80,73.75,0.1979,23,1],[60,80,73.9583,0.1979,23,1],[62,80,74.1667,0.1979,23,1]," "[59,80,74.375,0.1979,23,1],[60,80,74.5833,0.1979,23,1],[62,80,74.7917,0.1979,23,1]," "[44,64,75.0,1.5833,23,5],[53,64,75.2083,0.5938,23,6],[59,80,75.4167,0.1979,23,1]," "[60,80,75.625,0.1979,23,1],[62,80,75.8333,0.1979,23,1],[59,80,76.0417,0.1979,23,1]," "[60,80,76.25,0.1979,23,1],[62,80,76.4583,0.1979,23,1],[43,64,76.6667,1.5833,24,5]," "[53,64,76.875,0.5938,24,6],[55,80,77.0833,0.1979,24,1],[59,80,77.2917,0.1979,24,1]," "[62,80,77.5,0.1979,24,1],[55,80,77.7083,0.1979,24,1],[59,80,77.9167,0.1979,24,1]," "[62,80,78.125,0.1979,24,1],[43,64,78.3333,1.5833,24,5],[53,64,78.5417,0.5938,24,6]," "[55,80,78.75,0.1979,24,1],[59,80,78.9583,0.1979,24,1],[62,80,79.1667,0.1979,24,1]," "[55,80,79.375,0.1979,24,1],[59,80,79.5833,0.1979,24,1],[62,80,79.7917,0.1979,24,1]," "[43,64,80.0,1.5833,25,5],[52,64,80.2083,0.5938,25,6],[55,80,80.4167,0.1979,25,1]," "[60,80,80.625,0.1979,25,1],[64,80,80.8333,0.1979,25,1],[55,80,81.0417,0.1979,25,1]," "[60,80,81.25,0.1979,25,1],[64,80,81.4583,0.1979,25,1],[43,64,81.6667,1.5833,25,5]," "[52,64,81.875,0.5938,25,6],[55,80,82.0833,0.1979,25,1],[60,80,82.2917,0.1979,25,1]," "[64,80,82.5,0.1979,25,1],[55,80,82.7083,0.1979,25,1],[60,80,82.9167,0.1979,25,1]," "[64,80,83.125,0.1979,25,1],[43,64,83.3333,1.5833,26,5],[50,64,83.5417,0.5938,26,6]," "[55,80,83.75,0.1979,26,1],[59,80,83.9583,0.1979,26,1],[65,80,84.1667,0.1979,26,1]," "[55,80,84.375,0.1979,26,1],[59,80,84.5833,0.1979,26,1],[65,80,84.7917,0.1979,26,1]," "[43,64,85.0,1.5833,26,5],[50,64,85.2083,0.5938,26,6],[55,80,85.4167,0.1979,26,1]," "[59,80,85.625,0.1979,26,1],[65,80,85.8333,0.1979,26,1],[55,80,86.0417,0.1979,26,1]," "[59,80,86.25,0.1979,26,1],[65,80,86.4583,0.1979,26,1],[43,64,86.6667,1.5833,27,5]," "[51,64,86.875,0.5938,27,6],[57,80,87.0833,0.1979,27,1],[60,80,87.2917,0.1979,27,1]," "[66,80,87.5,0.1979,27,1],[57,80,87.7083,0.1979,27,1],[60,80,87.9167,0.1979,27,1]," "[66,80,88.125,0.1979,27,1],[43,64,88.3333,1.5833,27,5],[51,64,88.5417,0.5938,27,6]," "[57,80,88.75,0.1979,27,1],[60,80,88.9583,0.1979,27,1],[66,80,89.1667,0.1979,27,1]," "[57,80,89.375,0.1979,27,1],[60,80,89.5833,0.1979,27,1],[66,80,89.7917,0.1979,27,1]," "[43,64,90.0,1.5833,28,5],[52,64,90.2083,0.5938,28,6],[55,80,90.4167,0.1979,28,1]," "[60,80,90.625,0.1979,28,1],[67,80,90.8333,0.1979,28,1],[55,80,91.0417,0.1979,28,1]," "[60,80,91.25,0.1979,28,1],[67,80,91.4583,0.1979,28,1],[43,64,91.6667,1.5833,28,5]," "[52,64,91.875,0.5938,28,6],[55,80,92.0833,0.1979,28,1],[60,80,92.2917,0.1979,28,1]," "[67,80,92.5,0.1979,28,1],[55,80,92.7083,0.1979,28,1],[60,80,92.9167,0.1979,28,1]," "[67,80,93.125,0.1979,28,1],[43,64,93.3333,1.5833,29,5],[50,64,93.5417,0.5938,29,6]," "[55,80,93.75,0.1979,29,1],[60,80,93.9583,0.1979,29,1],[65,80,94.1667,0.1979,29,1]," "[55,80,94.375,0.1979,29,1],[60,80,94.5833,0.1979,29,1],[65,80,94.7917,0.1979,29,1]," "[43,64,95.0,1.5833,29,5],[50,64,95.2083,0.5938,29,6],[55,80,95.4167,0.1979,29,1]," "[60,80,95.625,0.1979,29,1],[65,80,95.8333,0.1979,29,1],[55,80,96.0417,0.1979,29,1]," "[60,80,96.25,0.1979,29,1],[65,80,96.4583,0.1979,29,1],[43,64,96.6667,1.5833,30,5]," "[50,64,96.875,0.5938,30,6],[55,80,97.0833,0.1979,30,1],[59,80,97.2917,0.1979,30,1]," "[65,80,97.5,0.1979,30,1],[55,80,97.7083,0.1979,30,1],[59,80,97.9167,0.1979,30,1]," "[65,80,98.125,0.1979,30,1],[43,64,98.3333,1.5833,30,5],[50,64,98.5417,0.5938,30,6]," "[55,80,98.75,0.1979,30,1],[59,80,98.9583,0.1979,30,1],[65,80,99.1667,0.1979,30,1]," "[55,80,99.375,0.1979,30,1],[59,80,99.5833,0.1979,30,1],[65,80,99.7917,0.1979,30,1]," "[36,64,100.0,1.5833,31,5],[48,64,100.2083,0.5938,31,6],[55,80,100.4167,0.1979,31,1]," "[58,80,100.625,0.1979,31,1],[64,80,100.8333,0.1979,31,1],[55,80,101.0417,0.1979,31,1]," "[58,80,101.25,0.1979,31,1],[64,80,101.4583,0.1979,31,1],[36,64,101.6667,1.5833,31,5]," "[48,64,101.875,0.5938,31,6],[55,80,102.0833,0.1979,31,1],[58,80,102.2917,0.1979,31,1]," "[64,80,102.5,0.1979,31,1],[55,80,102.7083,0.1979,31,1],[58,80,102.9167,0.1979,31,1]," "[64,80,103.125,0.1979,31,1],[36,64,103.3333,1.5833,32,5],[48,64,103.5417,0.5938,32,6]," "[53,80,103.75,0.1979,32,1],[57,80,103.9583,0.1979,32,1],[60,80,104.1667,0.1979,32,1]," "[65,80,104.375,0.1979,32,1],[60,80,104.5833,0.1979,32,1],[57,80,104.7917,0.1979,32,1]," "[60,80,105.0,0.1979,32,1],[57,80,105.2083,0.1979,32,1],[53,80,105.4167,0.1979,32,1]," "[57,80,105.625,0.1979,32,1],[53,80,105.8333,0.1979,32,1],[50,80,106.0417,0.1979,32,1]," "[53,80,106.25,0.1979,32,1],[50,80,106.4583,0.1979,32,1],[36,64,116.3636,1.7273,33,5]," "[47,64,116.5909,0.6477,33,6],[67,80,116.8182,0.2159,33,1],[71,80,117.0455,0.2159,33,1]," "[74,80,117.2727,0.2159,33,1],[77,80,117.5,0.2159,33,1],[74,80,117.7273,0.2159,33,1]," "[71,80,117.9545,0.2159,33,1],[74,80,118.1818,0.2159,33,1],[71,80,118.4091,0.2159,33,1]," "[67,80,118.6364,0.2159,33,1],[71,80,118.8636,0.2159,33,1],[62,80,119.0909,0.2159,33,1]," "[65,80,119.3182,0.2159,33,1],[64,80,119.5455,0.2159,33,1],[62,80,119.7727,0.2159,33,1]," "[64,80,120.0,3.4545,34,1],[36,64,120.0,3.4545,34,5],[67,80,123.6364,3.4545,34,1]," "[72,80,123.6364,3.4545,34,1],[48,64,123.6364,3.4545,34,5]]" ) # ────────────────────────────────────────────────────────────────────────────── # 21 MIDI Dimensions # ────────────────────────────────────────────────────────────────────────────── _DIMS_21: list[dict[str, str]] = [ {"id": "notes", "label": "Notes", "group": "core", "color": "#00d4ff", "desc": "note_on/note_off — the musical content itself"}, {"id": "pitch_bend", "label": "Pitch Bend", "group": "expr", "color": "#7c6cff", "desc": "pitchwheel — semitone-accurate pitch deviation"}, {"id": "channel_pressure", "label": "Ch. Pressure", "group": "expr", "color": "#9d8cff", "desc": "aftertouch — mono channel pressure"}, {"id": "poly_pressure", "label": "Poly Aftertouch","group": "expr", "color": "#b8a8ff", "desc": "polytouch — per-note polyphonic aftertouch"}, {"id": "cc_modulation", "label": "Modulation", "group": "cc", "color": "#ff6b9d", "desc": "CC 1 — modulation wheel depth"}, {"id": "cc_volume", "label": "Volume", "group": "cc", "color": "#ff8c42", "desc": "CC 7 — channel volume level"}, {"id": "cc_pan", "label": "Pan", "group": "cc", "color": "#ffd700", "desc": "CC 10 — stereo pan position"}, {"id": "cc_expression", "label": "Expression", "group": "cc", "color": "#00ff87", "desc": "CC 11 — expression controller"}, {"id": "cc_sustain", "label": "Sustain Pedal", "group": "cc", "color": "#00d4ff", "desc": "CC 64 — damper/sustain pedal"}, {"id": "cc_portamento", "label": "Portamento", "group": "cc", "color": "#66e0ff", "desc": "CC 65 — portamento on/off"}, {"id": "cc_sostenuto", "label": "Sostenuto", "group": "cc", "color": "#99eaff", "desc": "CC 66 — sostenuto pedal"}, {"id": "cc_soft_pedal", "label": "Soft Pedal", "group": "cc", "color": "#aaeeff", "desc": "CC 67 — soft pedal (una corda)"}, {"id": "cc_reverb", "label": "Reverb Send", "group": "fx", "color": "#e879f9", "desc": "CC 91 — reverb send level"}, {"id": "cc_chorus", "label": "Chorus Send", "group": "fx", "color": "#c084fc", "desc": "CC 93 — chorus send level"}, {"id": "cc_other", "label": "Other CC", "group": "fx", "color": "#a78bfa", "desc": "All remaining CC numbers"}, {"id": "program_change", "label": "Program/Patch", "group": "meta", "color": "#fb923c", "desc": "program_change — instrument/patch select"}, {"id": "tempo_map", "label": "Tempo Map", "group": "meta", "color": "#f87171", "desc": "set_tempo meta events (non-independent)"}, {"id": "time_signatures", "label": "Time Signatures","group": "meta", "color": "#fbbf24", "desc": "time_signature meta events (non-independent)"}, {"id": "key_signatures", "label": "Key Signatures", "group": "meta", "color": "#a3e635", "desc": "key_signature meta events"}, {"id": "markers", "label": "Markers", "group": "meta", "color": "#34d399", "desc": "marker, cue, text, lyrics, copyright events"}, {"id": "track_structure", "label": "Track Structure","group": "meta", "color": "#94a3b8", "desc": "track_name, sysex, unknown meta (non-independent)"}, ] # ────────────────────────────────────────────────────────────────────────────── # Commit graph definition # dagX: column (0=lower-register, 1=main, 2=upper-register) # dagY: row (0=top) # filter: {minM, maxM, voices[]} or null for no notes # dims: dimension IDs active/modified in this commit # dimAct: activity level per dimension (0-4) # ────────────────────────────────────────────────────────────────────────────── _COMMITS: list[dict[str, object]] = [ { "id": "c0", "sha": "0000000", "branch": "main", "label": "muse init", "message": "Initial commit — muse init --domain midi", "command": "muse init --domain midi", "output": "✓ Initialized Muse repository\n Domain : midi\n Dimensions: 21\n Location : .muse/\n Tracking : muse-work/", "parents": [], "dagX": 1, "dagY": 0, "filter": None, "newVoices": [], "newMeasures": [], "dims": [], "dimAct": {}, "stats": "0 notes · 0 dimensions", "noteCount": 0, }, { "id": "c1", "sha": "a1b2c3d", "branch": "feat/lower-register", "label": "bass + inner\nbars 1–12", "message": "feat: bass and inner voices, bars 1–12", "command": 'muse commit -m "feat: bass and inner voices, bars 1–12"', "output": "✓ [feat/lower-register a1b2c3d]\n 48 notes added\n Dimensions modified: notes, tempo_map,\n time_signatures, track_structure\n Key detected: C major", "parents": ["c0"], "dagX": 0, "dagY": 1, "filter": {"minM": 1, "maxM": 12, "voices": [5, 6]}, "newVoices": [5, 6], "newMeasures": [1, 12], "dims": ["notes", "tempo_map", "time_signatures", "track_structure"], "dimAct": {"notes": 3, "tempo_map": 2, "time_signatures": 2, "track_structure": 1}, "stats": "+48 notes · 4 dimensions", "noteCount": 48, }, { "id": "c2", "sha": "b3c4d5e", "branch": "feat/lower-register", "label": "lower voices\nbars 13–24", "message": "feat: bass and inner voices extended, bars 13–24", "command": 'muse commit -m "feat: bass and inner voices extended, bars 13–24"', "output": "✓ [feat/lower-register b3c4d5e]\n 40 notes added\n Dimensions modified: notes, cc_sustain,\n cc_volume\n Chord progression: Fm → C7 → Dm", "parents": ["c1"], "dagX": 0, "dagY": 2, "filter": {"minM": 1, "maxM": 24, "voices": [5, 6]}, "newVoices": [5, 6], "newMeasures": [13, 24], "dims": ["notes", "cc_sustain", "cc_volume"], "dimAct": {"notes": 3, "cc_sustain": 2, "cc_volume": 1}, "stats": "+40 notes · 3 dimensions", "noteCount": 88, }, { "id": "c3", "sha": "c4d5e6f", "branch": "feat/lower-register", "label": "lower voices\nbars 25–34 + FX", "message": "feat: complete lower register + reverb + expression", "command": 'muse commit -m "feat: complete lower register + reverb + expression"', "output": "✓ [feat/lower-register c4d5e6f]\n 42 notes added\n Dimensions modified: notes, cc_sustain,\n cc_reverb, cc_expression, markers\n Bass descends to C2 (MIDI 36) — full range", "parents": ["c2"], "dagX": 0, "dagY": 3, "filter": {"minM": 1, "maxM": 34, "voices": [5, 6]}, "newVoices": [5, 6], "newMeasures": [25, 34], "dims": ["notes", "cc_sustain", "cc_reverb", "cc_expression", "markers"], "dimAct": {"notes": 3, "cc_sustain": 2, "cc_reverb": 2, "cc_expression": 3, "markers": 1}, "stats": "+42 notes · 5 dimensions", "noteCount": 130, }, { "id": "c4", "sha": "d5e6f7a", "branch": "feat/upper-register", "label": "treble arpeggios\nbars 1–12", "message": "feat: treble arpeggios, bars 1–12", "command": 'muse commit -m "feat: treble arpeggios, bars 1–12"', "output": "✓ [feat/upper-register d5e6f7a]\n 144 notes added\n Dimensions modified: notes, cc_volume,\n program_change\n Voice 1: soprano arpeggios reach A5 (MIDI 81)", "parents": ["c0"], "dagX": 2, "dagY": 1, "filter": {"minM": 1, "maxM": 12, "voices": [1]}, "newVoices": [1], "newMeasures": [1, 12], "dims": ["notes", "cc_volume", "program_change"], "dimAct": {"notes": 4, "cc_volume": 2, "program_change": 1}, "stats": "+144 notes · 3 dimensions", "noteCount": 144, }, { "id": "c5", "sha": "e6f7a8b", "branch": "feat/upper-register", "label": "arpeggios\nbars 13–24", "message": "feat: treble arpeggios, bars 13–24 + modulation", "command": 'muse commit -m "feat: treble arpeggios, bars 13–24 + modulation"', "output": "✓ [feat/upper-register e6f7a8b]\n 120 notes added\n Dimensions modified: notes, cc_modulation,\n cc_expression, key_signatures\n Development section — chromatic tensions", "parents": ["c4"], "dagX": 2, "dagY": 2, "filter": {"minM": 1, "maxM": 24, "voices": [1]}, "newVoices": [1], "newMeasures": [13, 24], "dims": ["notes", "cc_modulation", "cc_expression", "key_signatures"], "dimAct": {"notes": 4, "cc_modulation": 2, "cc_expression": 3, "key_signatures": 1}, "stats": "+120 notes · 4 dimensions", "noteCount": 264, }, { "id": "c6", "sha": "f7a8b9c", "branch": "feat/upper-register", "label": "coda\nbars 25–34", "message": "feat: coda arpeggios bars 25–34 + final dynamics", "command": 'muse commit -m "feat: coda arpeggios bars 25–34 + final dynamics"', "output": "✓ [feat/upper-register f7a8b9c]\n 139 notes added\n Dimensions modified: notes, cc_expression,\n cc_soft_pedal, markers\n Coda: bars 33–34 hold final C major chord", "parents": ["c5"], "dagX": 2, "dagY": 3, "filter": {"minM": 1, "maxM": 34, "voices": [1]}, "newVoices": [1], "newMeasures": [25, 34], "dims": ["notes", "cc_expression", "cc_soft_pedal", "markers"], "dimAct": {"notes": 4, "cc_expression": 3, "cc_soft_pedal": 2, "markers": 2}, "stats": "+139 notes · 4 dimensions", "noteCount": 403, }, { "id": "c7", "sha": "9a0b1c2", "branch": "main", "label": "muse merge\nPrelude complete ✓", "message": "merge: unite lower and upper registers — Prelude BWV 846 complete", "command": "muse merge feat/lower-register feat/upper-register", "output": "✓ [main 9a0b1c2] merge: Prelude BWV 846 complete\n Auto-merged: notes (no pitch conflicts —\n registers non-overlapping)\n Merged dimensions: 10 / 21\n 533 notes · 2:07 duration · Key: C major", "parents": ["c3", "c6"], "dagX": 1, "dagY": 4, "filter": {"minM": 1, "maxM": 34, "voices": [1, 5, 6]}, "newVoices": [1, 5, 6], "newMeasures": [1, 34], "dims": [ "notes", "tempo_map", "time_signatures", "track_structure", "cc_sustain", "cc_volume", "cc_expression", "cc_reverb", "cc_modulation", "cc_soft_pedal", "markers", "program_change", "key_signatures", ], "dimAct": { "notes": 4, "tempo_map": 2, "time_signatures": 2, "track_structure": 1, "cc_sustain": 2, "cc_volume": 2, "cc_expression": 3, "cc_reverb": 2, "cc_modulation": 2, "cc_soft_pedal": 2, "markers": 2, "program_change": 1, "key_signatures": 1, }, "stats": "533 notes · 13 dimensions · 2:07", "noteCount": 533, }, ] def render_midi_demo() -> str: """Generate the complete self-contained MIDI demo HTML page.""" notes_json = _BACH_NOTES_JSON commits_json = json.dumps(_COMMITS, separators=(",", ":")) dims_json = json.dumps(_DIMS_21, separators=(",", ":")) html = _HTML_TEMPLATE html = html.replace("__NOTES_JSON__", notes_json) html = html.replace("__COMMITS_JSON__", commits_json) html = html.replace("__DIMS_JSON__", dims_json) return html # ────────────────────────────────────────────────────────────────────────────── # HTML template (no Python f-strings — JS braces are literal) # ────────────────────────────────────────────────────────────────────────────── _HTML_TEMPLATE = """ Bach BWV 846 × Muse VCS — 21-Dimensional MIDI Demo
Muse VCS · MIDI Domain · 21-Dimensional Version Control

Bach · Prelude No. 1 in C Major
BWV 846 · Well-Tempered Clavier

Watch Bach's Prelude built commit-by-commit across two parallel branches — then merged automatically using Muse's 21-dimensional MIDI diff engine. 533 authentic notes. Real piano audio. Zero conflicts.

533 notes · 34 bars 21 MIDI dimensions 2 branches · 1 merge Salamander Grand Piano Bach (1685–1750) · Public domain music21 corpus
📖 CLI Reference Landing Page
Interactive Demo — click any commit to hear and see that state
Commit DAG main
Piano Roll — 4 octaves (C2 → C6)
■ Treble arpeggios ■ Bass ■ Inner voice
21 MIDI Dimensions 0 active
0:00
2:07
0000000
Select a commit to begin
Click "Load Piano"
muse — MIDI repository
$ muse status
On branch main · 0 notes · Select a commit ↑
Dimension Activity Heatmap — Commits × Dimensions darker = inactive · brighter = active
MIDI-Domain Commands — muse CLI Reference

All standard VCS commands (commit, log, branch, merge, diff, …) work on MIDI files. The commands below are MIDI-specific additions provided by MidiPlugin.

""" if __name__ == "__main__": logging.basicConfig(level=logging.INFO, format="%(message)s") out = pathlib.Path("artifacts/midi-demo.html") out.parent.mkdir(exist_ok=True) content = render_midi_demo() out.write_text(content, encoding="utf-8") kb = len(content) // 1024 logger.info("✅ artifacts/midi-demo.html written (%d KB)", kb)