이 글은 ScorePlayer 시리즈의 2번째 기록입니다. (총 6개)

오늘 한 일

  • 새 프로젝트 폴더에 작업 규칙(CLAUDE.md)을 만들고, 저장소를 열어 리모트에 연결했다.
    • 이유: 코드보다 규칙이 먼저 필요했다. 이 프로젝트는 렌더 구조를 잘못 잡으면 최종 목표(투명 영상 추출)로 못 넘어가는데, 그 제약이 기획 문서에만 있고 구현 지침으로는 없었다.
  • 기획 문서(README)에서 사실과 다른 부분을 정정했다.
  • 입력 포맷을 MusicXML 하나로 좁히고 MIDI는 뒤로 미뤘다.
  • 가사를 기능으로 넣고, 악보에 가사가 없을 때 사용자가 직접 넣는 방식을 붙여넣기 + 보정으로 정했다.
  • 피아노 대보표 두 단, 재생 소리, 볼이 음표를 짚을지 가사 음절을 짚을지 고르는 설정을 기획에 반영했다.
  • 위 결정들에서 아키텍처 규칙 세 개가 새로 나와 문서에 못박았다.
    • 단(오선)은 처음부터 배열로 둔다
    • 재생 중 시각은 오디오가 정하고, 추출 중 시각은 프레임 번호가 정한다
    • 곡 전체를 매 프레임 훑지 않고 재생선 주변 구간만 그린다

막힌 부분

MusicXML이 “MIDI + 가사”인 줄 알았는데 아니었다

처음에는 두 포맷을 다 받기로 하고 규칙을 짰다. 그런데 둘이 담는 정보가 겹치지 않는다.

악보를 그리는 데 필요한 것MusicXMLMIDI
음높이 표기(C♯인지 D♭인지)있음없음
음가(점8분음표인지)있음틱 길이뿐
마디·박자표·조표있음없거나 못 믿음
어느 단(왼손·오른손)음표마다 있음없음
가사있음보통 없음
실연 타이밍·세기·페달없음있음

MIDI로 악보를 그리려면 위의 다섯 줄을 전부 추론해야 한다. 음가 되돌리기, 마디 나누기, 이명동음 결정, 손 나누기 — 악보 프로그램이 MIDI를 열 때 하는 일이고 결과가 늘 손봐야 하는 상태로 나온다. 볼 타이밍도 갈린다. 노래방 볼은 정박에 튀어야 보기 좋은데 사람이 친 MIDI를 그대로 쓰면 미세하게 흔들린다.

  • 해결: MusicXML을 1급 입력으로 두고 MIDI는 백로그로 내렸다. 악보 프로그램으로 작업하는 환경이라 MusicXML을 바로 내보낼 수 있다는 게 전제이고, 그 전제가 깨지면 MIDI 어댑터를 앞당긴다고 적어 뒀다.
  • 덤: 이 결정 하나로 Phase 1에서 손 나누기 추측과 음가 추론이 통째로 사라졌다. 제일 위험한 단계가 빠진 셈이다.

입력이 늘면 그리는 코드가 포맷을 알게 된다

입력을 둘로 늘리기로 했을 때, 렌더에서 “MIDI면 이렇게, MusicXML이면 저렇게”로 갈라지기 시작하면 그 분기가 그리는 코드 전체로 번진다. 가사는 파일에서 올 수도 있고 사용자가 넣을 수도 있어서 출처가 셋이라 더 그렇다.

  • 해결: 포맷마다 어댑터를 두고 공통 악보 모델을 만들어 넘기는 것을 규칙으로 못박았다. 시간 환산(MIDI는 틱, MusicXML은 분할 단위)도 어댑터에서 끝내서, 렌더는 초 단위 시각만 본다.
  • 지금은 입력이 하나뿐이지만 경계는 처음부터 둔다. 나중에 끼워 넣으려면 렌더를 뜯게 된다.

다음에 할 일

  • 네이티브 스택 확정 — 문서로 고르지 말고 4K 알파를 실제로 뽑아 보는 작은 실험부터
  • 대보표 두 단 오선을 그리고 스크롤 붙이기
  • MusicXML 파싱을 어댑터 경유로 붙이기
  • 재생 소리 붙이기(볼보다 먼저 — 볼 타이밍은 귀로 판단한다)
  • 가사 직접 입력의 보정 화면 설계

Series: ScorePlayer


Suggested Posts