Skip to content

synthio: stop MidiTrack treating every 0xF. byte as End of Track - #34

Open
tyeth wants to merge 1 commit into
base/upstream-main-cfe5624efrom
synthio-miditrack-meta-events
Open

tyeth wants to merge 1 commit into
base/upstream-main-cfe5624efrom
synthio-miditrack-meta-events

Conversation

@tyeth

@tyeth tyeth commented Oct 23, 2026

Copy link
Copy Markdown
Owner

MidiTrack read any byte with a high nibble of 15 as an "End of Track" event and stopped there. A MIDI track conventionally opens with a Set Tempo meta event, which begins 0xFF, so for most real files the track ended before a single note played and the sample was silent.

Meta and System Exclusive events both carry an explicit length, so this skips exactly that many bytes instead of guessing, and ends the track only on an actual End of Track meta event. Also reports error_location as the offset where the error was found rather than the end of the track it was abandoned at.

Effect. Decoding the first 30 seconds of a stock Bach Toccata (mfiles.co.uk, format 1, 256 ticks/beat):

track before after
2 2 note events 479
3 0 423

Verification. No hardware. I mirrored the decoder before and after in Python and cross-checked against adafruit_midi_parser as an independent oracle on hand-built files; the new decoder matches it exactly where the old returned nothing. Builds clean for circuitplayground_bluefruit (arm) and adafruit_funhouse (xtensa).

Size. About +272 bytes of flash on nrf52840.

First of five stacked micro-PRs fixing MidiTrack's MIDI parsing; the rest build on this branch.

🤖 Generated with Claude Code

The decoder read any byte with a high nibble of 15 as an "End of Track"
event and stopped there. A MIDI track conventionally opens with a Set
Tempo meta event, which begins 0xFF, so for most real files the track
ended before a single note was played and the sample was silent.

Meta and System Exclusive events both carry an explicit length, so skip
exactly that many bytes instead of guessing, and end the track only on an
actual End of Track meta event. Decoding the first 30 seconds of a stock
Bach Toccata now yields 479 and 423 note events on its two note tracks,
where it previously yielded 2 and none.

Also report error_location as the offset where the error was found rather
than the end of the track it was abandoned at.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@tyeth

tyeth commented Oct 23, 2026

Copy link
Copy Markdown
Owner Author

Status note covering this stack (#34–#38).

Verified on an Adafruit FunHouse that synthio playback works end to end through audiopwmio with these changes applied — from_file() parsed the header (1000 ticks/sec), played to completion, and error_location was None, i.e. a clean decode. So these changes are confirmed not to regress playback on real hardware.

The parser fixes themselves are verified on the host rather than on the device: each is cross-checked against adafruit_midi_parser as an independent oracle, and the before/after decoders are mirrored in Python. The file used in the hardware run had been pre-processed to suit the old decoder (meta events stripped), so it did not exercise them. A file that does — Set Tempo events, running status, velocity-0 note-offs and a real End of Track — decodes to 114 note events over 30.3s on the new decoder and to nothing at all on the old one.

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