Communitygithub.com

Score Sync Guide (Score-Following Video)

Create a long-form video from a MusicXML orchestral score and an audio recording, featuring synchronized scrolling score playback and guided analysis cards. Ideal for score-following, guided-listening videos, or aligning a score to a recording bar-by-bar.

What is Score Sync Guide (Score-Following Video)?

This skill enables the creation of a score-following video from a MusicXML score and an audio recording on native Windows (no WSL, Node, or Playwright required). The left side shows a horizontal scrolling single-line score with a fixed playhead, red highlighting for sounding notes, and visible parts only. The right side displays guided analysis cards and movement structure. The process includes bar-by-bar alignment via DTW, note-by-note refinement using an onset alignment algorithm ported from tofucurd/score-sync-video (MIT), and tools for cross-checking analysis cards against the score. It supports batch rendering for long works (e.g., 83-minute Mahler 6) with headless Edge and ffmpeg, and includes a template project structure, automated quality checks, and detailed Windows-specific notes to avoid common encoding/process pitfalls. Users run Python scripts (verovio, music21, librosa, numba) directly without package managers or sandboxing.

Works with~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Qiushuii/score-sync-guide/tree/HEAD/skills/score-sync-guide

Ask in your favorite AI

Open a new chat with this agent skill pre-loaded.

Documentation

Score-Following Guide (score-sync-guide)

Turn a MusicXML score + an audio recording into a video: on the left, a single-line horizontally scrolling score with a fixed playhead, red highlighting for sounding notes, and only the currently active parts shown; on the right, guided analysis cards and the movement's formal structure. The entire workflow runs on native Windows, no WSL, Node, or Playwright required.

This approach comes from the actual production of a Mahler Symphony No. 6 (four movements, 83 minutes). The onset alignment algorithm is ported from tofucurd/score-sync-video (MIT), and several player design ideas (fixed cursor, stable part sets, two-level form structure, render-by-block resumability) also draw from it. This skill is its Windows localization and extension (analysis cards, recording alignment workflow, cross-checking tools).

Read These Rules First

  1. Original files stay untouched. The score and recording go in the project root, read-only. All score corrections go into scores_fixed/corrections.json, generated by tools/fix_mxl.py to produce a copy, with justification (original score page, screenshot).
  2. Ask the user before changing notes. Community MusicXML and printed scores are often different versions; "inconsistency" is not necessarily an error. Only fix obvious import errors.
  3. Do not upload commercial recordings to any third-party service, and do not include them in the repository.
  4. New Python packages are installed by the user: Just list the package name and command; do not run pip install yourself.
  5. Every factual claim in an analysis card must have a basis: score data (specify measure number) or verifiable literature (references.json + superscript). If unverifiable, don't write it or mark it as "unverified." Automatic harmony analysis is unreliable for large orchestral scores; use only as a hint.
  6. If the user cannot read music, verification relies on listening: listening against the score (via collected disputed excerpts) is more reliable than listening for a "click" sound.
  7. Run fine onset alignment first, then ask the user to listen, then add pins. Doing it the other way (asking the user to report timestamps one by one) wastes effort on within-bar offsets that fine alignment can usually resolve automatically.
  8. The user's personal opinions are only embellishments; do not fabricate or exaggerate views on their behalf.

Workflow Overview

StepWhat to doMain filesDetails
0Create project: copy template/ to project root, write manifest.jsontemplate/, examples/mahler6/manifest.jsonworkflow
1Score health check: parts, repeats, tempo, rehearsal marks, placeholder charactersanalyze.py, check_all.pyworkflow
2Corrected copy, Chinese part names and mergestools/fix_mxl.py, tools/build_labels.py, labels.jsonworkflow
3Bar-by-bar DTW → immediately run fine onset alignmentalign/align.py, align/ssv_align.pyalignment
4Listen-check: disputed excerpts; only for places still wrong after fine alignment, add pins and local re-alignment, then re-run fine alignmentdemo/make_disputes.py, align/manual_regions.json, align/refine_local.pyalignment
5Form, motives, analysis cardsform/, motifs.json, cards/cards
6Cross-check cards against score, review dwell timestools/cards_xcheck.py, tools/cards_review.pycards
7Layout, player page, test clipdemo/build_score.py, demo/player.html, demo/render_frames.pyrendering
8Full video rendering and assemblydemo/render_film.pyrendering

Gotchas on Windows (encoding, processes, ports, batch newlines, ffmpeg sample rate, etc.) are collected in windows-notes — skim it before starting.

Shortest Path (One Movement)

# System Python (with verovio, music21, librosa, numba installed)
$py = "python"
& $py -X utf8 analyze.py                                   # Health check: out/<score>_structure.json, report.txt
& $py -X utf8 align/align.py --movement 1                  # ① Bar-by-bar DTW → align/m1_measures.json (opening anchor in align/anchors.json)
& $py -X utf8 align/ssv_align.py 1                         # ② Immediately run fine onset alignment → align/m1_ssv_chain.json
& $py -X utf8 align/make_checklist.py                      # Listen-check checklist
& $py -X utf8 demo/make_disputes.py                        # ③ Disputed excerpts: listen against score
# ④ Only for still-wrong places, add pins/beats to align/manual_regions.json, if needed:
& $py -X utf8 align/refine_local.py --movement 1
& $py -X utf8 align/ssv_align.py 1                         # ⑤ Re-run fine alignment if pins or measure table changed
& $py -X utf8 demo/build_score.py --movement 1 --range 1-40 --out demo/build   # Layout (positions start at 1)
& $py -X utf8 demo/render_frames.py --data build/data.js --out demo/test.mp4  # Test clip

Full film:

& $py -X utf8 demo/render_film.py plan --res 1920x1080 --fps 60 --name sample --single 4
& $py -X utf8 demo/render_film.py worker 1 --only 4        # Multiple workers can run simultaneously (number determines debug port)
& $py -X utf8 demo/render_film.py worker 2
& $py -X utf8 demo/render_film.py status
& $py -X utf8 demo/render_film.py assemble

For long renders, start the process detached from the current terminal (see the WMI section in windows-notes), otherwise closing the terminal or session will break the render.

Pre-Delivery Self-Check

  • Timeline is strictly increasing, no missing measures; measures after unfolding repeats match play_order.
  • Part names are all in Chinese, no "Unclassified."
  • Suspicious items from cards_xcheck.py have been judged individually; all items in cards_review.py pass; after modifying cards, re-run build_refs.py.
  • After changing measure tables or pins, re-run ssv_align.py (build_score.py uses fingerprints to catch outdated fine alignments).
  • Check frame counts segment by segment in the final film; spot-check rendered frames visually.

Related Skills