android 解析midi文件,MIDI文件格式解析

本文详细介绍了MIDI文件的组成,包括HeaderChunk(MThd)和TrackChunk(MTrk)。HeaderChunk包含文件头信息,如MIDI格式和时间度量法(TPQN)。TrackChunk则包含实际的MIDI事件和元信息,通过Delta-time表示事件时间差。文章还解析了一个具体的MIDI文件示例,展示了如何解读不同MIDI事件及其对应的音符和力度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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。

59d74800b43b

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 表示按下第一轨的音符。

59d74800b43b

MIDI事件

59d74800b43b

音符编号

在例中,接下来的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个音块:

59d74800b43b

钢琴卷帘

总结

59d74800b43b

MIDI 0 文件

59d74800b43b

MIDI 1 文件

参考链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值