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;