From 3d0ba770a7a9f86768d6f1a53aa74cb21d046d79 Mon Sep 17 00:00:00 2001 From: tyeth Date: Fri, 23 Oct 2026 01:33:50 +0100 Subject: [PATCH] synthio: support running status in MidiTrack A MIDI file may omit the status byte when it repeats the previous one, so a run of notes on the same channel is encoded as data bytes alone. The decoder read each of those as a status byte, took the invalid-event branch and ended the track. Remember the last channel status byte and imply it when the next event begins with a data byte. System messages cancel it, as the specification requires. Co-Authored-By: Claude Opus 5 --- shared-module/synthio/MidiTrack.c | 16 +++++++++++++++- shared-module/synthio/MidiTrack.h | 2 ++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/shared-module/synthio/MidiTrack.c b/shared-module/synthio/MidiTrack.c index 4988857c080..96d9ac6168a 100644 --- a/shared-module/synthio/MidiTrack.c +++ b/shared-module/synthio/MidiTrack.c @@ -100,7 +100,20 @@ static void decode_until_pause(synthio_miditrack_obj_t *self) { if (self->pos >= len) { break; } - uint8_t status = buffer[self->pos++]; + uint8_t status = buffer[self->pos]; + if (status & 0x80) { + self->pos++; + // a channel message arms running status; a system one cancels it + self->running_status = (status < 0xF0) ? status : 0; + } else { + // running status: the status byte is omitted and the previous + // channel message is implied + status = self->running_status; + if (status == 0) { + record_midi_stream_error(self); + break; + } + } switch (status >> 4) { case 8: { // Note Off mp_obj_t note = parse_note(self); @@ -136,6 +149,7 @@ static void decode_until_pause(synthio_miditrack_obj_t *self) { static void start_parse(synthio_miditrack_obj_t *self) { self->pos = 0; self->error_location = -1; + self->running_status = 0; self->synth.span.dur = decode_duration(self); if (self->synth.span.dur == 0) { // the usual case: the file starts with some MIDI event, not a delay diff --git a/shared-module/synthio/MidiTrack.h b/shared-module/synthio/MidiTrack.h index 1e4d5cba2da..918ff147e3c 100644 --- a/shared-module/synthio/MidiTrack.h +++ b/shared-module/synthio/MidiTrack.h @@ -17,6 +17,8 @@ typedef struct { size_t pos; mp_int_t error_location; uint32_t tempo; + // last channel status byte, for events that omit it (running status) + uint8_t running_status; } synthio_miditrack_obj_t;