创建 MIDI 文件和编码事件时间:为什么应该均匀间隔 time-wise 的音符实际上变慢了?
Creating a MIDI file and encoding event times: why do notes that should be spaced uniformly time-wise actually slow down?
我正在尝试编写一个用于创建 MIDI 文件的简单界面。作为测试,我尝试创建一个播放大音阶的文件,所有音符的长度相同。我得到的文件如下(为了便于阅读而缩进)
4d 54 68 64 00 00 00 06 00 01 00 02 00 08
4d 54 72 6b 00 00 00 0b
00 ff 51 03 00 27 0f
00 ff 2f 00
4d 54 72 6b 00 00 00 54
00 c0 00
00 90 40 7f
7d 80 40 7f
7d 90 42 7f
81 7a 80 42 7f
81 7a 90 44 7f
82 77 80 44 7f
82 77 90 45 7f
83 74 80 45 7f
83 74 90 47 7f
84 71 80 47 7f
84 71 90 49 7f
85 6e 80 49 7f
85 6e 90 4b 7f
86 6b 80 4b 7f
86 6b 90 4c 7f
87 68 80 4c 7f
00 ff 2f 00
说明:第 1 行是文件 header。第 2 行是轨道 header。 (在我的界面中,我为打击乐保留了一条轨道,同时也为设置速度设置了速度。因为我在这个例子中没有打击乐,所以它不包含音符。)第 3 行设置速度,第 4 行结束轨道。第 5 行是另一首曲目 header。此曲目包含旋律。第 6 行设置通道 0 的仪器。接下来是通道 0 的 8 个交替 note-on 和 8 个 note-off 事件,然后是轨道结束。开始和结束笔记的时间是:
00, 7d, 81 7a, 82 77, 83 74, 84 71, 85 6e, 86 6b, 87 68
据我了解,它们应该均匀间隔,因为对于事件时间,MIDI 使用 7-bit-byte 格式,其中数字的长度是灵活的,除最后一个字节外的所有字节都有其 msnzb放。所以 00 应该转换为 0,7d 应该转换为 125,81 7a 应该转换为 250,等等。但是出于某种原因,当您播放文件时,它听起来并不统一 time-wise,而是变慢了。为什么会这样?我是否误解了编码事件计时的正确方法,如果是,那么正确的方法是什么?还是我的文件有其他问题导致了这个问题?
MIDI 文件中的时间戳是增量时间——您不对事件发生的时间进行编码,而是对轨道上连续事件之间的时间差进行编码。如果事件在时间上均匀分布,则它们的增量时间应该相同。
来自标准:
The syntax of an MTrk event is very simple:
<MTrk event> = <delta-time><event>
<delta-time>
is stored as a variable-length quantity. It represents the amount of time before the following event. If the first event in a track occurs at the very beginning of a track, or if two events occur simultaneously, a delta-time of zero is used. Delta-times are always present. (Not storing delta-times of 0 requires at least two bytes for any other value, and most delta-times aren't zero.) Delta-time is in some fraction of a beat (or a second, for recording a track with SMPTE times), as specified in the header chunk.
参见例如http://www.music.mcgill.ca/~ich/classes/mumt306/StandardMIDIfileformat.html
我正在尝试编写一个用于创建 MIDI 文件的简单界面。作为测试,我尝试创建一个播放大音阶的文件,所有音符的长度相同。我得到的文件如下(为了便于阅读而缩进)
4d 54 68 64 00 00 00 06 00 01 00 02 00 08
4d 54 72 6b 00 00 00 0b
00 ff 51 03 00 27 0f
00 ff 2f 00
4d 54 72 6b 00 00 00 54
00 c0 00
00 90 40 7f
7d 80 40 7f
7d 90 42 7f
81 7a 80 42 7f
81 7a 90 44 7f
82 77 80 44 7f
82 77 90 45 7f
83 74 80 45 7f
83 74 90 47 7f
84 71 80 47 7f
84 71 90 49 7f
85 6e 80 49 7f
85 6e 90 4b 7f
86 6b 80 4b 7f
86 6b 90 4c 7f
87 68 80 4c 7f
00 ff 2f 00
说明:第 1 行是文件 header。第 2 行是轨道 header。 (在我的界面中,我为打击乐保留了一条轨道,同时也为设置速度设置了速度。因为我在这个例子中没有打击乐,所以它不包含音符。)第 3 行设置速度,第 4 行结束轨道。第 5 行是另一首曲目 header。此曲目包含旋律。第 6 行设置通道 0 的仪器。接下来是通道 0 的 8 个交替 note-on 和 8 个 note-off 事件,然后是轨道结束。开始和结束笔记的时间是:
00, 7d, 81 7a, 82 77, 83 74, 84 71, 85 6e, 86 6b, 87 68
据我了解,它们应该均匀间隔,因为对于事件时间,MIDI 使用 7-bit-byte 格式,其中数字的长度是灵活的,除最后一个字节外的所有字节都有其 msnzb放。所以 00 应该转换为 0,7d 应该转换为 125,81 7a 应该转换为 250,等等。但是出于某种原因,当您播放文件时,它听起来并不统一 time-wise,而是变慢了。为什么会这样?我是否误解了编码事件计时的正确方法,如果是,那么正确的方法是什么?还是我的文件有其他问题导致了这个问题?
MIDI 文件中的时间戳是增量时间——您不对事件发生的时间进行编码,而是对轨道上连续事件之间的时间差进行编码。如果事件在时间上均匀分布,则它们的增量时间应该相同。
来自标准:
The syntax of an MTrk event is very simple:
<MTrk event> = <delta-time><event>
<delta-time>
is stored as a variable-length quantity. It represents the amount of time before the following event. If the first event in a track occurs at the very beginning of a track, or if two events occur simultaneously, a delta-time of zero is used. Delta-times are always present. (Not storing delta-times of 0 requires at least two bytes for any other value, and most delta-times aren't zero.) Delta-time is in some fraction of a beat (or a second, for recording a track with SMPTE times), as specified in the header chunk.
参见例如http://www.music.mcgill.ca/~ich/classes/mumt306/StandardMIDIfileformat.html