악보 따라 듣기 (score-sync-guide)
MusicXML 총보 + 오디오 녹음으로 한 편의 영상을 만듭니다: 왼쪽에는 단선 가로 스크롤 악보(재생선 고정, 현재 소리나는 음표 빨간색, 연주 중인 파트만 표시)가 있고, 오른쪽에는 감상 해설 카드와 해당 악장의 형식 구조가 표시됩니다. 전체 워크플로우는 네이티브 Windows에서 실행되며, WSL, Node.js 또는 Playwright가 필요하지 않습니다.
이 워크플로우는 Mahler 6번 교향곡(4악장, 83분)의 실제 제작 경험에서 비롯되었습니다. 음표 수준 정렬 알고리즘은 tofucurd/score-sync-video(MIT)에서 이식되었으며, 플레이어의 여러 디자인(고정 커서, 안정적인 성부 집합, 2단계 형식 구조, 블록 단위 재렌더링 가능)도 이 프로젝트에서 차용했습니다. 이 스킬은 해당 프로젝트의 Windows 현지화 및 확장(해설 카드, 녹음 정렬 워크플로우, 교차 검증 도구)입니다.
먼저 읽어야 할 규칙
- 원본 파일을 수정하지 않습니다. 악보와 녹음은 프로젝트 루트 디렉토리에 읽기 전용으로 보관합니다. 악보 수정은 모두
scores_fixed/corrections.json에 기록하고,tools/fix_mxl.py로 복사본을 생성하며, 그 근거(원본 악보 페이지, 스크린샷)를 남깁니다. - 음표 수정 전 사용자에게 문의합니다. 커뮤니티 MusicXML과 인쇄된 총보는 종종 다른 버전일 수 있으며, '불일치'가 반드시 오류는 아닙니다. 명백한 가져오기 오류만 수정합니다.
- 상업용 녹음은 어떤 제3자 서비스에도 업로드하지 않으며, 저장소에도 포함하지 않습니다.
- 새로운 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는 지문을 사용하여 만료된 세부 정렬을 차단합니다). - 완성된 영상은 프레임별로 확인하고, 프레임을 추출하여 육안 검사했습니다.