Skip to content

writeMidiFile: emit PART VOCALS / HARM1 / HARM2 / HARM3 tracks - #76

Open
elicwhite wants to merge 1 commit into
midi-writer-guitarfrom
midi-writer-vocals
Open

writeMidiFile: emit PART VOCALS / HARM1 / HARM2 / HARM3 tracks#76
elicwhite wants to merge 1 commit into
midi-writer-guitarfrom
midi-writer-vocals

Conversation

@elicwhite

Copy link
Copy Markdown
Owner

Adds vocal-track emission to writeMidiFile. One MIDI track per vocal
part (vocals → PART VOCALS, harmony{1,2,3} → HARM{1,2,3}; HARM* not
PART HARM*, matching the convention used in the wild).

Phrase-marker emission is careful about YARG's CopyDownPhrases, which
at parse time copies HARM1's notePhrases onto HARM2/HARM3:

  • PART VOCALS: notePhrases → 105 (player:2 → 106)
  • HARM1: notePhrases → 105, staticLyricPhrases → 106
  • HARM2: only staticLyricPhrases → 106 (note 105 comes from HARM1
    via CopyDown on re-parse — would double-count otherwise)
  • HARM3: no phrase markers at all

Lyrics and notes are union'd across both phrase sets (note 105 and 106
can have different boundaries; emitting the union keeps all lyrics
that belong on the track). Zero-length vocal notes are preserved via
per-event seq tags so finalizeMidiTrack keeps noteOn immediately
before its matching noteOff.

Star power (MIDI 116) is suppressed on HARM2/HARM3 — CopyDown recreates
it from HARM1 on re-parse. Range shifts (MIDI 0) and lyric shifts (MIDI

  1. are per-part for lossless round-trip, with fallback to the
    track-level arrays for the part that owns them (PART VOCALS, or HARM1
    when PART VOCALS is absent). Raw vocal-track text events (stance
    markers, facial anim triggers) are re-emitted verbatim so that
    stance-only tracks survive round-trip — YARG marks a VocalsPart
    non-empty iff it has phrases or text events.

Tests: 18 new cases covering track naming (PART VOCALS, HARM1/2/3 with
no PART HARM* prefix), phrase-marker routing per part, pitched/
percussion/out-of-range note emission, lyric union across phrase sets,
star power suppression on HARM2/3, range+lyric shifts, text events,
and round-trip through parseChartAndIni for both PART VOCALS and the
full harmony stack with CopyDown semantics preserved.

71 midi-writer tests, 415 total scan-chart tests passing.

@elicwhite
elicwhite force-pushed the midi-writer-guitar branch from 3d5ebf4 to 6bfcf43 Compare April 20, 2026 05:09
@elicwhite
elicwhite force-pushed the midi-writer-vocals branch from 17b2b16 to ba58fa3 Compare April 20, 2026 05:09
@elicwhite
elicwhite force-pushed the midi-writer-guitar branch from 6bfcf43 to fa58c6e Compare April 20, 2026 05:10
@elicwhite
elicwhite force-pushed the midi-writer-vocals branch from ba58fa3 to cc46d30 Compare April 20, 2026 05:10
@elicwhite
elicwhite force-pushed the midi-writer-guitar branch from fa58c6e to 409ccf5 Compare April 20, 2026 05:19
@elicwhite
elicwhite force-pushed the midi-writer-vocals branch from cc46d30 to 631a9d0 Compare April 20, 2026 05:19
@elicwhite
elicwhite marked this pull request as ready for review April 20, 2026 16:09
@elicwhite
elicwhite force-pushed the midi-writer-vocals branch from 631a9d0 to a5b46ec Compare April 21, 2026 04:29
@elicwhite
elicwhite force-pushed the midi-writer-guitar branch 2 times, most recently from 4069bbd to e846368 Compare April 21, 2026 04:47
@elicwhite
elicwhite force-pushed the midi-writer-vocals branch from a5b46ec to e69e3e0 Compare April 21, 2026 04:48
@elicwhite
elicwhite force-pushed the midi-writer-vocals branch 2 times, most recently from b5242da to 7a8a4ff Compare April 21, 2026 16:35
@elicwhite
elicwhite force-pushed the midi-writer-guitar branch 2 times, most recently from 7627809 to 0dc86ae Compare April 21, 2026 16:38
@elicwhite
elicwhite force-pushed the midi-writer-vocals branch 2 times, most recently from 09e9e4e to 4de2741 Compare April 21, 2026 16:51
@elicwhite
elicwhite force-pushed the midi-writer-guitar branch from 0dc86ae to 21b132d Compare April 21, 2026 16:51
@elicwhite
elicwhite force-pushed the midi-writer-guitar branch from 21b132d to f4cca25 Compare April 21, 2026 23:18
@elicwhite
elicwhite force-pushed the midi-writer-vocals branch from 4de2741 to 771cfa8 Compare April 21, 2026 23:18
Adds vocal-track emission to writeMidiFile. One MIDI track per vocal
part (vocals → PART VOCALS, harmony{1,2,3} → HARM{1,2,3}; HARM* not
PART HARM*, matching the convention used in the wild).

Phrase-marker emission is careful about YARG's CopyDownPhrases, which
at parse time copies HARM1's notePhrases onto HARM2/HARM3:

  - PART VOCALS: notePhrases → 105 (player:2 → 106)
  - HARM1: notePhrases → 105, staticLyricPhrases → 106
  - HARM2: only staticLyricPhrases → 106 (note 105 comes from HARM1
    via CopyDown on re-parse — would double-count otherwise)
  - HARM3: no phrase markers at all

Lyrics and notes are union'd across both phrase sets (note 105 and 106
can have different boundaries; emitting the union keeps all lyrics
that belong on the track). Zero-length vocal notes are preserved via
per-event `seq` tags so finalizeMidiTrack keeps noteOn immediately
before its matching noteOff.

Star power (MIDI 116) is suppressed on HARM2/HARM3 — CopyDown recreates
it from HARM1 on re-parse. Range shifts (MIDI 0) and lyric shifts (MIDI
1) are per-part for lossless round-trip, with fallback to the
track-level arrays for the part that owns them (PART VOCALS, or HARM1
when PART VOCALS is absent). Raw vocal-track text events (stance
markers, facial anim triggers) are re-emitted verbatim so that
stance-only tracks survive round-trip — YARG marks a VocalsPart
non-empty iff it has phrases or text events.

Tests: 18 new cases covering track naming (PART VOCALS, HARM1/2/3 with
no PART HARM* prefix), phrase-marker routing per part, pitched/
percussion/out-of-range note emission, lyric union across phrase sets,
star power suppression on HARM2/3, range+lyric shifts, text events,
and round-trip through parseChartAndIni for both PART VOCALS and the
full harmony stack with CopyDown semantics preserved.

71 midi-writer tests, 415 total scan-chart tests passing.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant