abc2midi: fix -PMAR perturbing note timing and end-of-track time (#26)

Emitting a Marker meta-event from the PART case wrote the event with
delta_time_track0 (correct, since that's the conductor-track accumulator)
but did not also reset delta_time. On track 0 in multi-track mode,
delta_time also accumulates via timestep() and is what writetrack()
returns to the MIDI library as the end-of-track delta — so each marker
left a stale delta_time that pushed the end-of-track event past the end
of the music. In single-track mode (ntracks == 1), markers were written
with delta_time_track0 too, but delta_time is the only relevant counter
in that mode, so notes following each marker were shifted later.

Fix: mirror the TEMPO handler — on ntracks == 1 use delta_time and reset
it; on ntracks != 1 keep using delta_time_track0 for the event delta but
also zero delta_time so the end-of-track is not inflated.

Reported by James Allwright with the partdemo.abc test case (now in
samples/), which exercises the parts != -1 path (header P:BACDBAC plus
body P: labels A/B/C/D). James independently fixed the same bug in his
abc2midiu fork in r32 (commit 34b7c32, "Add -PMAR option for part
markers"), where the equivalent reset is on the single delta_time
counter — his fork having retired delta_time_track0 in an earlier
refactor. Verified that mftext output of the generated MIDI is now
byte-identical to the non-PMAR output except for the added Marker
events, on both partdemo.abc (single-track) and samples/demo.abc tune 5
with P:(AB)3 (multi-track).

Add a CMake/CTest regression test (abc2midi_pmar_partdemo) that locks in
the post-fix mftext output. To support it, add_golden_test() gains an
optional NAME (to register multiple tests against the same TYPE+SAMPLE
pair) and an optional ABC2MIDI_ARGS (forwarded to the abc2midi
invocation in run_via_mid). Reverting the genmidi.c fix makes the new
test fail; reapplying it makes it pass.
This commit is contained in:
Ronan Keryell
2026-05-01 06:09:46 -07:00
committed by GitHub
parent 1d8d1f621c
commit a6fa0d6b8a
5 changed files with 209 additions and 11 deletions

View File

@@ -68,8 +68,11 @@ endfunction()
# Convert ${SAMPLE} to MIDI, then run ${bin} on the resulting MIDI file and
# capture its stdout. Any extra arguments are inserted BEFORE the MIDI path
# (needed e.g. for "midi2abc -f <file>").
#
# ABC2MIDI_ARGS (set by the caller, possibly empty) is forwarded as a CMake
# list to the abc2midi invocation, so callers can opt into flags like -PMAR.
function(run_via_mid outfile bin)
run_or_die("${ABC2MIDI}" "${SAMPLE}" -o "${midfile}" -quiet -silent)
run_or_die("${ABC2MIDI}" "${SAMPLE}" ${ABC2MIDI_ARGS} -o "${midfile}" -quiet -silent)
run_to_file("${outfile}" "${bin}" ${ARGN} "${midfile}")
endfunction()