跟譜聽(score-sync-guide)
把 MusicXML 總譜 + 一份錄音 做成一支影片:左邊是單行橫向滾動的總譜,播放線固定不動,正在發聲的音符變紅,只顯示正在演奏的聲部;右邊是導賞解析卡和本樂章的曲式結構。全流程在原生 Windows 上跑,不需要 WSL、Node 或 Playwright。
這套做法來自一部馬勒第六交響曲(四個樂章、83 分鐘)的實際製作。其中逐起音對齊演算法移植自 tofucurd/score-sync-video(MIT),播放器的若干設計(固定游標、穩定的聲部集合、兩級曲式結構、按塊可續渲)也借鑒了它;本 skill 是它在 Windows 上的在地化與擴展(導賞卡片、錄音對齊流程、交叉核對工具)。
先讀這幾條規矩
- 原始檔案不動。 譜面、錄音放在專案根目錄,唯讀;改譜一律寫進
scores_fixed/corrections.json,由tools/fix_mxl.py生成副本,並記錄依據(原譜頁碼、截圖)。 - 改音符先問使用者。 社群 MusicXML 與印刷總譜常是不同版本,「不一致」不一定是錯。只修明顯的導入錯誤。
- 商業錄音不上傳到任何第三方服務,也不進倉庫。
- 新裝 Python 包由使用者自己裝:列出包名和命令,不要擅自
pip install。 - 解析卡裡每一條事實性斷言都要有依據:譜面資料(寫明小節號)或可核查的文獻(
references.json+ 角標)。查不到就不寫,或標「未核實」。自動和聲分析對大編制管弦樂不可靠,只作線索。 - 使用者不識譜時,驗收靠耳朵:對著譜面聽(爭議片段合集)比聽「嗒」聲更可靠。
- 先跑逐起音細對齊,再請使用者聽、再加釘點。 反過來做(先讓使用者逐個報時刻),會把大量精力花在細對齊本來就能自動解決的小節內偏移上。
- 使用者的個人看法只作點綴,不替使用者編造或誇大觀點。
流程總覽
| 步驟 | 做什麼 | 主要檔案 | 詳見 |
|---|---|---|---|
| 0 | 建專案:把 template/ 複製到專案根目錄,寫 manifest.json | template/、examples/mahler6/manifest.json | workflow |
| 1 | 體檢譜面:聲部、反覆、速度、排練記號、佔位字 | analyze.py、check_all.py | workflow |
| 2 | 校訂副本、聲部中文名與合併 | tools/fix_mxl.py、tools/build_labels.py、labels.json | workflow |
| 3 | 逐小節 DTW → 馬上做逐起音細對齊 | align/align.py、align/ssv_align.py | alignment |
| 4 | 聽檢:爭議片段合集;只在細對齊之後仍錯的地方加釘點、局部重校,再重跑細對齊 | demo/make_disputes.py、align/manual_regions.json、align/refine_local.py | alignment |
| 5 | 曲式、動機、解析卡 | form/、motifs.json、cards/ | cards |
| 6 | 交叉核對卡片與譜面、審停留時間 | tools/cards_xcheck.py、tools/cards_review.py | cards |
| 7 | 排譜、播放頁、試片 | demo/build_score.py、demo/player.html、demo/render_frames.py | rendering |
| 8 | 全片渲染與拼接 | demo/render_film.py | rendering |
Windows 上踩過的坑(編碼、行程、埠、批次處理換行、ffmpeg 取樣率等)集中在 windows-notes,動手前掃一遍。
最短路徑(一個樂章)
# 系統 Python(裝了 verovio、music21、librosa、numba)
$py = "python"
& $py -X utf8 analyze.py # 體檢:out/<譜名>_structure.json、report.txt
& $py -X utf8 align/align.py --movement 1 # ① 逐小節 DTW → align/m1_measures.json(開頭錨點寫在 align/anchors.json)
& $py -X utf8 align/ssv_align.py 1 # ② 緊接著逐起音細對齊 → align/m1_ssv_chain.json
& $py -X utf8 align/make_checklist.py # 聽檢清單
& $py -X utf8 demo/make_disputes.py # ③ 爭議片段合集:對著譜面聽
# ④ 只在仍然不對的地方往 align/manual_regions.json 加 pins/beats,必要時:
& $py -X utf8 align/refine_local.py --movement 1
& $py -X utf8 align/ssv_align.py 1 # ⑤ 改了釘點或小節表就重跑細對齊
& $py -X utf8 demo/build_score.py --movement 1 --range 1-40 --out demo/build # 排譜(位置從 1 起)
& $py -X utf8 demo/render_frames.py --data build/data.js --out demo/test.mp4 # 試片
整片:
& $py -X utf8 demo/render_film.py plan --res 1920x1080 --fps 60 --name 樣片 --single 4
& $py -X utf8 demo/render_film.py worker 1 --only 4 # 可同時起多個 worker(編號決定除錯埠)
& $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
長時間渲染要用與當前終端脫鉤的行程啟動(見 windows-notes 的 WMI 一節),否則關掉終端或工作階段就斷了。
交付前自檢
- 時間軸嚴格遞增,沒有缺小節;展開反覆後的小節數與
play_order一致。 - 聲部名全部是中文,沒有「未分類」。
cards_xcheck.py的可疑項逐條判斷過;cards_review.py全部通過;改過卡片後重跑build_refs.py。- 改了小節表或釘點後重跑
ssv_align.py(build_score.py會用指紋攔下過期的細對齊)。 - 成片逐段核對幀數;抽幀目檢。