Midi文件详解
本文主要介绍 MIDI 文件格式存储格式, 一个 MIDI 文件由一个 MThd 和多个 MTrk 构成。
博主博客
文件头MThd

| 偏移地址 | 数据值 | 内容 |
|---|---|---|
| 00H~03H | 4D 54 68 64 | MThd 的 ascii |
| 04H~07H | 00 00 00 06 | MThd长度,固定是6,即后面6位都是文件头 |
| 08H~09H | 00 01 | 格式类型 0 - 单轨 1 - 多轨(同步) 2 - 多轨(异步) |
| 0AH~0BH | 00 12 | MTrk块数量 |
| 0CH~0DH | 00 60 | 最高位为标记位,0为采用ticks计时,后面的数据为一个4分音符的ticks,即TPQN,Ticks Per Quarter-Note;1为SMPTE格式计时,后面的数值则是定义每秒中SMTPE帧的数量及每个SMTPE帧的tick。比如01 E0,表示采用ticks计时,1E0转十进制为480,也就是每个4分音符,包含480 ticks。后面事件时间都是以ticks为单位 |
MTrk
第一个 MTrk 解析

| 数据长度(单位:字节) | 数据值 | 内容 |
|---|---|---|
| 4 | 4D 54 72 6B | MTrk 的 ascii |
| 4 | 00 00 00 4C | 这个 MTrk 的长度,即后面4C个字节都是这个 MTrk 的 |
| 1 | 00 | 事件时间,这个时间长度可变的,在这里1个字节,也可以多个字节,详情查看附录 |
| 2 | FF 58 | 时间签名,详情查看附录 |
| 1 | 04 | 即后面4个字节放时间签名信息 |
| 4 | 04 02 18 08 | 拍号 4/4 ,详情查看附录 |
| 4 | 00 B0 07 FF | 0 tick,控制器消息,信道为 0,控制器编号 7,控制器值 255,详情查看附录 |
| 4 | 00 B1 07 FF | 0 tick,控制器消息,信道为 1,控制器编号 7, 控制器值 255,详情查看附录 |
| 56 | … | … |
| 4 | 00 FF 2F 00 | 0 tick,MTrk 结束标记 |
第二个 MTrk 解析

| 数据长度(单位:字节) | 数据值 | 内容 |
|---|---|---|
| 4 | 4D 54 72 6B | MTrk 的 ascii |
| 4 | 00 00 00 13 | 这个 MTrk 的长度,即后面 19 个字节都是这个 MTrk 的 |
| 1 | 00 | 事件时间,0 tick,这个时间长度可变的,在这里1个字节,也可以多个字节,详情查看附录 |
| 6 | FF 51 03 05 F1 EA | FF 51 03 为 MPQN 标识, 值为 389610,详情查看附录 |
| 2 | 83 00 | 事件时间,384 tick |
| 6 | FF 51 03 05 F1 EA | FF 51 03 为 MPQN 标识, 值为 389610,详情查看附录 |
| 4 | 00 FF 2F 00 | 0 tick,MTrk 结束标记 |
第三个 MTrk 解析

| 数据长度(单位:字节) | 数据值 | 内容 |
|---|---|---|
| 4 | 4D 54 72 6B | MTrk 的 ascii |
| 4 | 00 00 01 6A | 这个 MTrk 的长度,即后面 362 个字节都是这个 MTrk 的 |
| 1 | 00 | 事件时间,这个时间长度可变的,在这里1个字节,也可以多个字节,详情查看附录 |
| 2+1+10 | FF 03 0A 43 68 61 6E 6E 65 6C 20 23 31 | 序号/曲目名称,长度为 10 个字节,曲目名称为 Channel #1,详情查看附录 |
| 4 | 00 B0 0A 40 | 0 tick,控制器消息,信道为 0,控制器编号 0A(十进制 10) 代表全景控制器,控制器值 40(十进制 64)代表中,详情查看附录 |
| 4 | 00 E0 00 40 | 0 tick,音调轮,信道为 0, 值为 2000H(十进制 8192), 高位 40 (取低 7 位), 低位 00 (取低 7 位),详情查看附录 |
| 13 | 00 B0 65 00 00 64 00 00 06 0C 00 0A 40 | 0 tick,控制器消息,信道为 0,控制器编号 65(十进制 101)代表注册参数,控制器值 0,详情查看附录 |
| 4 | 00 E0 00 40 | 0 tick,音调轮,信道为 0, 值为 2000H(十进制 8192), 高位 40 (取低 7 位), 低位 00 (取低 7 位),详情查看附录 |
| 3 | 00 C0 30 | 0 tick,乐器使用 30(弦乐合奏 1),信道为 0 |
| 13 | 00 B0 65 00 00 64 00 00 06 0C 00 0A 40 | |
| 4 | 00 E0 00 40 | 0 tick,音调轮,信道为 0, 值为 2000H(十进制 8192), 高位 40 (取低 7 位), 低位 00 (取低 7 位),详情查看附录 |
| 9 | 00 C0 30 00 10 00 10 00 30 | 0 tick,乐器使用 30(弦乐合奏 1),信道为 0 |
| 13 | 00 B0 65 00 00 64 00 00 06 0C 00 0A 40 | 0 tick,控制器消息,信道为 0, 控制器编号 65(十进制 101)代表注册参数,控制器值 0, 0 tick,控制器编号 64(十进制 100)代表注册参数,控制器值 0, 0 tick,控制器编号 06(十进制 6)代表数据输入,控制器值 0C(十进制 12), 0 tick,控制器编号 0A(十进制 10)代表全景控制器,控制器值 40(十进制 64)代表中, 详情查看附录 |
| 4 | 00 E0 00 40 | 0 tick,音调轮,信道为 0, 值为 2000H(十进制 8192), 高位 40 (取低 7 位), 低位 00 (取低 7 位),详情查看附录 |
| 10 | 00 C0 30 00 10 00 30 83 00 17 | 0 tick,乐器使用 30(弦乐合奏 1),信道为 0,(83 00)384 tick,乐器编号(17)23 |
| 4 | 00 90 3C 64 | 0 tick,按下 C4 键(库乐队看到的是C3, 因为库乐队从C-2开始计算),力度100,详情查看附录 |
| 4 | 0C 80 3C 00 | 12 tick,释放 C4 键, 力度 0 |
| 4 | 00 90 3E 64 | 0 tick,按下 D4 键,力度 100 |
| 4 | 0C 80 3E 00 | 12 tick,释放 D4 键,力度 0 |
| … | … | … |
| 00 90 3C 64 00 39 64 00 40 64 | ||
| 60 80 40 00 00 39 00 00 3C 00 83 C7 | ||
| 5C B0 65 00 | ||
| 00 64 00 00 06 0C 00 0A 40 | ||
| 00 E0 00 40 | ||
| 00 C0 17 | ||
| 01 B0 65 00 | ||
| 00 64 00 00 06 0C 00 0A 40 | ||
| 00 E0 00 40 | ||
| 00 C0 17 | ||
| 00 B0 65 00 | ||
| 00 64 00 00 06 0C 00 0A 40 | ||
| 00 0E 00 40 | ||
| 00 C0 17 | ||
| 4 | 00 FF 2F 00 | 0 tick,MTrk 结束标记 |
Android MIDI 解析库
附录
MIDI音符代码表
事件的时间(单位:tick)(可变长度)
这个时间是经过压缩的(一个字节7位保存数据),所以必须使用特定的计算方式。
1.一个字节
二进制范围:0000 0000~0111 1111
第一位必须是 0,直接专程十进制就是对应 tick,比如 01111111 就是 127 tick。
2.两个字节
二进制范围:1000 0000 0000 0000~1111 1111 0111 1111
第一个字节第一位必须是 1,第二个字节第一位必须是 0。
获取对应 tick, 比如 1100 0000 0100 0000,
先把第一个字节第一位去掉, 第二个字节第一位去掉, 变成
100 0000 100 0000
再整理一下就是
10 0000 0100 0000
转成十进制就是
8256 tick。
3.三个字节
二进制范围:1000 0000 1000 0000 0000 0000~1111 1111 1111 1111 0111 1111
前面的字节第一位必须是 1, 最后一个字节第一位必须是 0。
获取对应 tick, 比如 1100 0000 1100 0000 0100 0000,
先把所有字节的第一位去掉,变成
100 0000 100 0000 100 0000
再整理一下就是
1 0000 0010 0000 0100 0000
转成十进制就是
1056832 tick。
FF 命令
| 数据长度(单位:字节) | 数据值 | 内容 |
|---|---|---|
| 3+nn | FF 00 nn ss ss | 设置轨道的序列号,nn 02(2字节序列号长度) 为序列号长度, ssss 序列号 |
| 3+nn | FF 01 nn tt … | 文本事件,nn 文本字节长度,tt 文本字符 |
| 3+nn | FF 02 nn tt … | 版权信息,nn 文本字节长度,tt 文本字符 |
| 3+nn | FF 03 nn tt … | 序号/曲目名称,nn 文本字节长度,tt 文本字符 |
| 3+nn | FF 04 nn tt … | 轨道乐器名称,nn 文本字节长度,tt 文本字符 |
| 3+nn | FF 05 nn tt … | 歌词,nn 文本字节长度,tt 文本字符 |
| 3+nn | FF 06 nn tt … | 标记,nn 文本字节长度,tt 文本字符 |
| 3+nn | FF 07 nn tt … | 提示点,nn 文本字节长度,tt 文本字符 |
| 4 | FF 20 01 cc | MIDI 通道 |
| 4 | FF 21 01 pp | MIDI 端口 |
| 3 | FF 2F 00 | MTrk结束标志,必须在MTrk块末尾出现, 且每个 MTrk 块仅有一个 |
| 6 | FF 51 03 tt tt tt | 每个四分音符的速度(单位:微秒), 即 Microseconds Per MIDI Quarter-Note(MPQN) |
| 8 | FF 54 05 hh mm ss ff cc | SMPTE 偏移, 指定 MTrk 的SMPTE开始时间(小时,分钟,秒,帧,子帧) |
| 6 | FF 58 nn dd cc bb | 时间签名, nn 为分子, dd 为分母 02 四分音符 03 八分音符 依此类推 cc 节拍器点击的节拍数,bb 四分音符的 32 分音符数 |
| 5 | FF 59 02 sf mi | 密钥签名,sf 升号/降号 -7 7个降号 0 C 键 7 7个升号 mi 主键/副键 0 主键 1 副键 |
| 3+xx | FF 7F xx dd … | 定序器特定元事件,xx 要发送的字节数,dd 数据 |
MIDI 事件命令
| 数据长度(单位:字节) | 数据值 | 内容 |
|---|---|---|
| 3 | 8x nn vv | Note off(键被释放) x 是信道编号 nn 音高(可根据MIDI音符代码表查询对应音高) vv 力度(范围1~127) |
| 3 | 9x nn vv | Note on(键被按下), x 是信道编号 nn 音高(可根据MIDI音符代码表查询对应音高) vv 力度(范围1~127) |
| 3 | Ax nn vv | 键触控后, x 是信道编号 nn 音高(可根据MIDI音符代码表查询对应音高) vv 力度(范围1~127) |
| 3 | Bx cc vv | 控制器消息(Control Change), x 是信道编号 cc 控制器编号 vv 控制器的值 |
| 2 | Cx pp | 乐器(Program change), x 是信道编号 乐器编号 |
| 2 | Dx cc | channel 触控后, x 是信道编号 cc 新的 channel 编号 |
| 3 | Ex bb tt | 音调轮(Pitch wheel change)(2000H正常或无变化), x 是信道编号 bb 低位 7 位值 高位 7 位值 |
| 1 | F8 | 需要同步时使用的定时时钟。 |
| 1 | FA | 启动当前序列 |
| 1 | FB | 继续停止的序列 |
| 1 | FC | 停止序列 |
力度对应表

音调轮(Pitch wheel change)
以下是 MIDI 音调轮消息的示例。
0xE3 0x54 0x39
状态字节 0xE3 表明这是通道 3 的音调轮消息。0x39 和 0x54(57 和 84 十进制值)的二进制表示为 00111001 和 01010100。删除每个字节的最高位后,这两个字节构成14 位值 01110011010100,即 0x1CD4(十进制为 7380)。新间距的值为 0x1CD4。该间距比 0x2000 的中心低 0x032C(十进制为 812)。将其转换为特定音调取决于设备。例如,如果 0x2000(十进制 8192)表示音高没有变化,而 0x0000(十进制 0)低两个半音,并且如果音高按指数计算,则 -0x032C(十进制 -812)将表示音高略微下降不到 20 美分。
BPM
BPM(Beat Per Minute) 即每分钟节拍数的单位。
可以根据 FF 命令(FF 51 03 tt tt tt)获得 tt tt tt 进行计算。
BPM=60,000,000 / (tt tt tt),其中 60,000,000为60秒
比如 tt tt tt 为 07 A1 20, 则 BPM=120
tick 转绝对时间
MPQN 可以根据 FF 命令(FF 51 03 tt tt tt)获得 tt tt tt 进行计算。
比如 MPQN tt tt tt 为 07 A1 20, TPQN 为 01 E0, 如果不知道 TPQN 是什么按键盘Ctrl+F搜索TPQN上文有说。
MPQN/TPQN=1041.67 us=1.042 ms
则 1000 tick = 1000 * 1.042 ms = 1.042 s
公式
MSPM–microseconds per minute = 60 000 000
BPM–beats per minute
MPQN–microseconds per quaternote
BPM = MSPM / MPQN
MPQN = MSPM / BPM
因此,如果我们有 120 BPM (标准,默认速度) ,那么一个四分音符的周期是:
MPQN=60 000 000/120 BPM = 500 000 ms
下一步是计算一个时钟节拍频率,当我们有一个四分音符周期时:
1 tick=MPQN/1000000/PPQN=500 000/1000000/96 PPQN = ~0.005208333333 Hz…
我们用 ~0.005208333333 Hz 计算四分之一音符的时间, 例如分辨率为 96PPQN 那么 96 tick 一个完整的四分音符持续时间为
96 * 1 tick = 96 * 0.005208333333 Hz = 500 000 ms = 0.5s
BPM–每分钟的节拍数 60 000 000/MPQN
PPQN–Pulses per quater note(每四分音符的脉冲数),在 MIDI 文件中找到分辨率
MPQN–每四分音符微秒或四分音符持续时间,范围为 0-8355711 微秒(根据 MIDI 文件规范)
QLS–seconds per quaternote(每秒数四分音符)(MPQN/1000000)
TDPS–seconds per tick(每秒 tick 数)(QLS/PPQN)
参考资料:
1.MIDI音符代码表
2.(.mid) Standard MIDI File Format
3.音乐研发必备:理解 MIDI 协议与标准 MIDI 文件格式
4.midi文件说明
5.MIDI Pitch Wheel message
6.MIDI Tutorial
7.Delta times in MIDI files
评论