Yikai-Liao / symusic

A cross platform note level midi decoding library with lightening speed, based on minimidi.
https://yikai-liao.github.io/symusic/
MIT License
108 stars 8 forks source link

MIDI with negative beginning tick #37

Closed Natooz closed 2 months ago

Natooz commented 2 months ago

Hey, 👋

I encountered a case where a specific MIDI file from the Lakh dataset got it's first tick before 0. 10e903c3aa7a6b6c5ce5a74d5cfb8702.mid.zip

Screenshot 2024-04-20 at 17 06 00

When inspecting tracks, the 14th (idx 13) note of the 19th (idx 18) track has a time at -4465856

for ti, track in enumerate(score.tracks):
    for ni, note in enumerate(track.notes):
        if note.time < 0:
            test = 0

Didn't have to to dig further yet, I'll just leave this open

Yikai-Liao commented 2 months ago

This looks like an int overflow is occurring, I'll check further.

lzqlzzq commented 2 months ago

Seems same problem occurred in mido. 7PtCAzQKNS

Natooz commented 2 months ago

I found other MIDIs for which the resample operation shifts some of their events to negative time values midis.zip They all have in common very large end tick values.

To reproduce:

from pathlib import Path
from symusic import Score

paths = list(Path("midis").glob("**/*.mid"))
for path in paths:
    score = Score(path)
    score = score.resample(12, min_dur=1)
    start_tick = score.start()
Yikai-Liao commented 2 months ago

@Natooz This is an int overflow caused by improper multiplication order during resample.

I've adjusted the order of multiplication in the resample and these examples no longer overflow. But an inappropriate resample can still cause an overflow, so I've further added an overflow check to determine if the scaled time is still valid.

Natooz commented 2 months ago

Wonderful thank you!