Skip to content

Raise TypeError on malformed MIDI messages instead of silently dropping them - #507

Open
IshaanPotle wants to merge 1 commit into
spotify:masterfrom
IshaanPotle:raise-on-malformed-midi-messages
Open

Raise TypeError on malformed MIDI messages instead of silently dropping them#507
IshaanPotle wants to merge 1 commit into
spotify:masterfrom
IshaanPotle:raise-on-malformed-midi-messages

Conversation

@IshaanPotle

Copy link
Copy Markdown

Fixes #489.

The problem

normalize_midi_messages() iterates with if / elif and no else, so any message it can't interpret is skipped:

for message in _input:
    if hasattr(message, "bytes") and hasattr(message, "time"):
        ...
    elif (isinstance(message, tuple) or isinstance(message, list)) and len(message) == 2:
        ...
    # anything else falls through silently

The caller gets a shorter list back with no indication events were lost. In practice this surfaces much later as missing notes in the rendered audio, with no traceback to debug from.

Reproduced on master before the fix — every one of these silently loses a message:

1-tuple (missing timestamp)      in=3 out=2  -> 1 silently dropped
3-tuple (extra field)            in=2 out=1  -> 1 silently dropped
bare bytes (no timestamp)        in=2 out=1  -> 1 silently dropped
None element                     in=2 out=1  -> 1 silently dropped
bare int                         in=2 out=1  -> 1 silently dropped

The change

An else branch that raises TypeError naming the offending index and value:

TypeError: Unable to interpret MIDI message at index 1: (b'\x90<@',). MIDI messages
must either be objects with `bytes` and `time` attributes (like mido.Message) or
(message, timestamp) tuples, where timestamp is the number of seconds from the start
of the returned audio buffer.

Plus tests for the five shapes that were previously dropped, and one asserting valid input is unaffected.

Note on compatibility

This turns previously-silent behavior into an exception, so it's technically a behavior change — code passing malformed messages today gets an error instead of quietly wrong audio. That seemed like the intent of the issue, but happy to switch it to a warnings.warn() instead if you'd rather keep it non-breaking for a release cycle.

Test log

$ pytest tests/test_midi_utils.py -q      # on master, with the new tests, WITHOUT the fix
FAILED tests/test_midi_utils.py::test_malformed_messages_raise[one_tuple_missing_timestamp]
FAILED tests/test_midi_utils.py::test_malformed_messages_raise[three_tuple_extra_element]
FAILED tests/test_midi_utils.py::test_malformed_messages_raise[bare_bytes_without_timestamp]
FAILED tests/test_midi_utils.py::test_malformed_messages_raise[none]
FAILED tests/test_midi_utils.py::test_malformed_messages_raise[bare_int]
5 failed, 2 passed in 0.11s

$ pytest tests/test_midi_utils.py -q      # with the fix
.......                                                                  [100%]
7 passed in 0.05s

$ ruff format --check pedalboard/midi_utils.py tests/test_midi_utils.py
2 files already formatted

$ flake8 pedalboard/midi_utils.py tests/test_midi_utils.py
(clean)

ruff check reports the same 12 pre-existing findings before and after this change; I left those alone to keep the diff focused.


Disclosure: I used an AI assistant while working on this. I reviewed the change, verified the failing/passing behavior locally, and can speak to any line of it.

normalize_midi_messages() iterates with if/elif and no else branch, so any
message it cannot interpret is skipped. The caller gets a shorter list back
with no indication that events were lost, which surfaces later as missing
notes in the rendered audio with no traceback to debug from.

Add an else branch that raises TypeError naming the offending index and
value, and tests covering the shapes that were previously dropped:
1-tuples, 3-tuples, bare bytes, None and bare ints.

Fixes spotify#489.
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.

normalize_midi_messages() silently drops malformed messages instead of raising an error

1 participant