MIDI文件的时间单位

今天在理解一段代码时遇到了一个问题。这段代码的大致功能是读取一个MIDI文件中音符信息,包括音高和开始、结束时间。刚开始时,我是默认了这段代码的时间单位都是秒,毕竟在pretty_midi中音符的开始、结束时间都是用秒来表示的。想当然的,我觉得MIDI文件中也是以秒为单位。

为了测试一下这个结论,我把一个MIDI文件导入了FL Studio。这个MIDI是由pretty_midi输出的,其中所有的音符都从第0秒开始,第3秒结束。

MIDI导入FL Studio

FL中是以节拍为单位的,这些音符都持续了6个拍子。调整播放位置,使其与音符结尾对齐。将时间显示单位改成M:S:CS,这时问题出现了——显示时间并不是预期的3秒。

130 BPM和“不正确”的时间

注意到BPM是默认的130,便尝试将BPM调整到120,发现显示时间变成了预期的3秒。

120 BPM和“正确”的时间

觉得很是奇怪,既然MIDI中的时间单位是绝对的秒,那为什么改变FL中的BPM会影响音符的持续时间呢?既然FL中的音符时间可以由BPM决定,那难道MIDI中的时间单位不是秒而是节拍?如果MIDI中的时间单位是节拍,那pretty_midi中的start=0end=3的单位是什么?

pretty_midi官方文档

查阅了pretty_midi官方文档,发现pretty_midi里的时间单位确实是秒。但是MIDI中的时间单位呢?

Mido官方文档

Mido的文档中可以看到,MIDI文件确实是以节拍做单位的。那么我猜测在pretty_midi的代码中,应该有从秒到节拍的转换。这也就意味着需要一个默认的BPM值。

Mido官方文档

Mido的文档中可以看到,MIDI的文件默认BPM就是120,那么相信pretty_midi也是遵循了这个规则的,而且这个速度信息应当会被写入MIDI文件。

查询了pretty_midi的官方文档,果不其然。

pretty_midi官方文档

那么在FL中,FL的BPM设定所做的事情就是强行以这个速度来播放MIDI中的音符,而忽略了MIDI中自带的速度信息。这也就不难解释为什么当FL的BPM设置为120时,音符持续时间就和pretty_midi中的时间一致了。