craffel / pretty-midi

Utility functions for handling MIDI data in a nice/intuitive way.
MIT License
859 stars 151 forks source link

Compound meters errors? #152

Closed apmcleod closed 5 years ago

apmcleod commented 5 years ago

get_downbeats() seems to return incorrect values for me when used with compound meters (6/x, 9/x, 12/x).

I think the error comes from pretty_midi.py, line 716 (and also similarly line 720 for final_ts): beats[start_beat_idx:end_beat_idx:start_ts.numerator]

This line skips beats based on the numerator value. However, if the meter is compound, the skip should be start_ts.numerator // 3 I think.

This also led to me uncovering a 2nd bug in utilities.py, the qpm_to_bpm method:

Currently, compound meters are only handled correctly if they have an 8 in the denominator.

6/4, for example, would return a bpm equal to the quarter note, while the compound meter should have the bpm be equal to 3 quarter notes.

In the returns within the elif denominator in [8, 16, 32]: block, all returns are treated as if the denominator is 8. Thus, I think every return inside this block should be changed multiplied by an additional factor based on the denominator.

I think a fix would involve removing the special cases for 1, 2, and 4, and just adding them in as [1, 2, 4, 8, 16, 32]. This (with the additional factor) would then become: (note that I am unsure how the else block where I've put !!!!!!!!!! should be handled)

if denominator in [1, 2, 4, 8, 16, 32]:
    # simple triple
    if numerator == 3:
        return quarter_note_tempo * denominator / 4
    # compound meter 6/8*n, 9/8*n, 12/8*n...
    elif numerator % 3 == 0:
        return quarter_note_tempo / 3.0 * denominator / 4
    # strongly assume one denominator equals the beat
    else: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        return quarter_note_tempo * denominator / 4
else:
    return quarter_note_tempo
apmcleod commented 5 years ago

Here's an example piece, Bach BWV 864, fugue, from WTC book I, number 19. It is in 9/8.

bach-0864-fugue.mid.zip

apmcleod commented 5 years ago

Fixed by #153