Skip to content

synthio: follow the MIDI file's tempo map in MidiTrack - #38

Open
tyeth wants to merge 1 commit into
synthio-miditrack-long-delaysfrom
synthio-miditrack-set-tempo
Open

tyeth wants to merge 1 commit into
synthio-miditrack-long-delaysfrom
synthio-miditrack-set-tempo

Conversation

@tyeth

@tyeth tyeth commented Oct 23, 2026 •

Copy link
Copy Markdown
Owner

This one is a feature rather than a bug fix, so it is last in the stack and can be dropped independently.

MidiTrack played at one fixed rate for the whole track, so a file that changes tempo, or that simply does not use the 120 BPM default, played at the wrong speed throughout. The Set Tempo meta event was skipped.

This acts on Set Tempo. Its value is in microseconds per quarter note, which can only be converted to the ticks per second MidiTrack works in if the ticks per quarter note is known, so that becomes a new optional ticks_per_beat argument. from_file() reads it from the file header. It stays 0 for SMPTE timing, where the rate is already absolute and Set Tempo does not apply, and for callers passing raw track bytes without it — so existing code is unaffected.

The tempo is rewound along with the track when the sample restarts, so a looping track does not inherit the rate its last loop ended on.

Verification. Cross-checked against adafruit_midi_parser on a file with a mid-track tempo change: the new decoder reproduces its timings exactly (0.50s then 0.25s). Builds clean on arm and xtensa. No hardware.

Size. About +144 bytes of flash on nrf52840, plus six bytes per MidiTrack object.

Stacked on #37.

🤖 Generated with Claude Code

MidiTrack played at one fixed rate for the whole track, so a file that
changes tempo, or that simply does not use the 120 BPM default, played at
the wrong speed throughout. The Set Tempo meta event was skipped.

Act on Set Tempo. Its value is in microseconds per quarter note, which can
only be converted to the ticks per second MidiTrack works in if the ticks
per quarter note is known, so take that as a new optional ticks_per_beat
argument. from_file() reads it from the file header; it is left at 0 for
SMPTE timing, where the rate is already absolute and Set Tempo does not
apply, and for callers that pass raw track bytes without it.

The tempo is rewound along with the track when the sample restarts, so a
looping track does not inherit the rate its last loop ended on.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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