MIDI文件格式解析

MIDI文件由两部分构成:Header Chunk(MThd)+ Track Chunk(MTrk)

“Chunk”是一种数据结构,每个chunk由最初4字节的“Chunk类型”,紧接着4字节的“Chunk大小”,和最后长度可变的“Chunk数据”构成。注意,“Chunk大小”描述的是“Chunk 数据”的长度,而不是整个Chunk的长度。

用编辑器打开JSB Chorales数据集中的一个midi文件,截取前8行显示如下:

4d54 6864 0000 0006 0000 0001 0064 4d54
726b 0000 03a9 00c0 0000 903c 5a00 903f
5a00 9043 5a00 9048 5a78 803f 0000 904b
5a78 803c 0000 8043 0000 8048 0000 9037
5a00 9046 5a78 8037 0000 8046 0000 9038
5a00 9048 5a00 904d 5a78 8038 0000 8048
0000 804b 0000 903a 5a00 9046 5a00 904a
5a78 803a 0000 804a 0000 804d 0000 903f

这是midi文件的十六进制代码。
每一个十六进制代码能表示4bit,
1 byte(字节)=8bit,1 word(字)=2 byte,
因此4d这样的两个十六进制代码就是1 byte
4d54这样的四个十六进制代码就是1 word

MThd

在每个 Midi 文件的开头都有如下内容,它们的十六进制代码为
4d54 6864 0000 0006 ffff nnnn dddd
对应例中的
4d54 6864 0000 0006 0000 0001 0064
其中,
4d54 6864是ACSII表示的“MThd”字符串,表示构成MIDI文件的Chunk类型是文件头(Header Chunk)。
0000 0006是MThd中数据部分的长度,以目前标准均为6字节,也就是接下来的ffff nnnn dddd

MThd中的数据部分

补充:nnnn值表示文件中有多少个MTrk块。对于MIDI 0格式文件,nnnn值仅为0001,即只有一个Track Chunk;MIDI 1格式文件则可以有多个Track Chunk,而且Track Chunk数目为实际的音轨数目加一;MIDI 2格式文件不常见,不了解。

补充2: dddd值多采用TPQN时间度量法。TPQN是“Ticks Per Quarter-Note(每四分音符中所包含的Midi Tick数量)”的缩写,可以是十进制的60-480之间,数值越大,MIDI系统的时间分辨率就越大,也就是说可以演奏时值越小的音符。通常这个数都采用120、240、480,因为这些数都能被2、3、4甚至6、8整除,方便于八分音符、十六分音符、三连音甚至更短音符的演奏,换算成十六进制,就是0x78、0xF0、0x1E0。当然注意,这些十六进制数的最高位都是0。dddd值如果大于0x8000,则为SMPTE时间码度量法,这里不详细介绍了。

MTrk

MTrk(Track Chunk)内部则包含了实际的MIDI信息和一些辅助信息,如meta-event。还是以上面的midi文件为例:
4d54 726b 是MTrk的开头,也就是“MTrk”的ASCII编码。
0000 03a9 是MTrk数据部分的大小(非固定),这里转化为十进制是937。接下来就是937字节的数据。
xxyy xxyyyy ... ... xx代表了Delta-time,yy代表了真正的MIDI事件。这些MIDI事件才是音序器在播放MIDI文件时需要实时处理和发送的数据。
00ff 2f00 是meta-event事件,表示此Track结束。

  • Delta-time:时间差,表征着当前事件距离上一个事件有多长时间,单位为tick。音序器通过对MIDI Tick进行计数,判断是否该处理下一个MIDI事件。Delta-time使用可变长度数的格式,最短1个字节,最长4个字节(最长可以表示0x0fffffff)。具体来说,一个字节有 8 bit,将其最高位bit作为标志位,剩下7 bit就可以表示 0~127。如果Delta-time值超过127,就将标志位设置为1,并且下一个字节用来继续表示Delta-time。只要标志位为 0,则表示结束读取Delta-time。
  • MIDI事件:MIDI事件包括1.实际需要发送的数据(音序器直接将数据发送出去);2.meta-event事件(音序器修改自身的相关参数)。

MIDI事件

下表中,x 表示音轨 0~F,比如 90 表示按下第一轨的音符。
MIDI事件
音符编号

在例中,接下来的MIDI编码为:
---- ---- ---- 00c0 0000 903c 5a00 903f
5a00 9043 5a00 9048 5a-- ---- ---- ----

解析如下:
00 c0 00 :时间差00,改变第一轨乐器,乐器号码为00
00 90 3c 5a :时间差00,按下第一轨音符,音符号码为3c(60,C4,中央C),力度为5a(90)
00 90 3f 5a :时间差00,按下第一轨音符,音符号码为3f(63,#D4),力度为5a(90)
00 90 43 5a:时间差00,按下第一轨音符,音符号码为43(67,G4),力度为5a(90)
00 90 48 5a:时间差00,按下第一轨音符,音符号码为48(72,C5),力度为5a(90)
78 80 3f 00:时间差78(120tick),松开第一轨音符,音符号码为3f(63,#D4),力度为5a(90)
00 90 4b 5a:时间差00,按下第一轨音符,音符号码为4b(75,#D5),力度为5a(90)
78 80 3c 00:时间差78(120tick),松开第一轨音符,音符号码为3c(60,C4),力度为00
00 80 43 00:时间差00,松开第一轨音符,音符号码为43(67,G4),力度为00
00 80 48 00:时间差00,松开第一轨音符,音符号码为48(72,C5),力度为00
00 90 37 5a:时间差00,按下第一轨音符,音符号码为37(55,G3),力度为5a(90)
00 90 46 5a:时间差00,按下第一轨音符,音符号码为46(70,#A4),力度为5a(90)

上述指令表示的就是下图中的前7个音块:
钢琴卷帘

总结

MIDI 0 文件

MIDI 1 文件

参考链接

https://www.cnblogs.com/us-wjz/articles/11618899.html
https://blog.csdn.net/tiankong_/article/details/78754545
https://www.bilibili.com/read/cv1753143/

你可能感兴趣的:(MIDI文件格式解析)