midi格式与解析

MIDI文件以时间为单位,分为多个轨道,记录音频形式。
其大致可表示为

头块=MThd+长度+格式+轨道块数+时间
轨道块=MTrk+长度+ 事件{ }^{+}
事件=增量时间+(元事件|MIDI事件|系统事件)
元事件=0xFF+元事件类型+长度+数据
系统事件=(0xF0+长度+数据) + (0xF7+长度+数据){ }^{*},其中可带多个,但第一个必须是0xF0开头,接下来的必须以0xF7开头,最后的数据部分必须以0xF7结尾,标识结束。

VLQ

Variable Length Quantity,一种编码格式,Base 128 Varints。
首先要明确的是MIDI为大端格式,即高字节低地址。
而VLQ格式以字节为单位,其每个字节的最高位是标志位,”1″代表后续仍有数据,”0″表示结束。
所以,其每个字节只有7个有效位,当解码时需重新组装。
如”10000001 00000000″组装后表示”10000000″,即0x80.

from struct import unpack
def read_v(file):
    ans = 0
    buffer = unpack('B', file.read(1))[0]
    while buffer > 127:
        ans = ans*128+(buffer-128)
        buffer = unpack('B', file.read(1))[0]
    ans = ans*128+buffer
    return ans

头块

前4个字节固定是”MThd”,值为”4D 54 68 64″。
长度占4个字节,现今通行的长度都是6,值为”00 00 00 06″.
格式占2个字节,有3个取值——0、1、2。其中,0 =单音轨文件格式,1 =多个音轨文件格式,2 =多个乐曲文件格式(即,一系列类型0文件)。也有称1为同步多音轨,2为异步多音轨。
轨道块数占2个字节。
时间占2个字节。若第一个字节为正,则该时间表示PPQN,即每个四分音符的嘀嗒值。若第一个字节为负,则时间表示SMPTE,其第一个字节绝对值表示每秒帧数,有四个标准——24、25、29、30,其第二个字节表示每一帧中的子帧数。
明确一些时间:
BPM——每分钟内的四分音符数。
Tempo——速度元事件中指定速度。
MIDI时钟——MIDI时钟字节是通过MIDI发送的,以便同步2个设备的播放,每个四分音符中有24个MIDI时钟。
BPM=60,000,000 / Tempo
每个PPQN的毫秒时间 = Tempo / PPQN
每个MIDI时钟的毫秒时间 = Tempo / 24
每个MIDI时钟对应的PPQN = PPQN / 24
每个四分音符的子帧时间 = Tempo / (帧率 * 子帧率)
每个PPQN的子帧时间 = 每个四分音符的子帧时间/嘀嗒时基
每个PPQN的毫秒时间 = 每个PPQN的子帧时间 * 帧率 * 子帧率

轨道块

事件

增量时间为事件与上一个事件之间的持续时间(以时钟为单位),以VLQ编码。

 

元事件

元事件类型占1个字节。

  • 0x 00,表示序列号,此可选事件必须发生在MTrk的开头(即,在任何非零增量时间之前和在任何Midi事件之前),以指定序列号。一般其后跟着”02 SS SS”,SS SS是与MIDI Cue消息相对应的数字。在格式2的MIDI文件中,此数字标识每个“模式”(即MTrk),以便“歌曲”序列可以使用MIDI Cue消息引用模式。如果ss ss省略数字(即,长度字节= 0而不是2),然后使用文件中MTrk的位置(即,第一个MTrk块是第一个模式)。在仅包含一个“模式”的格式0或1中(即使格式1包含多个MTrk),此事件也仅放置在第一个MTrk中。因此,一组具有不同序号的格式1文件可以包含一个“歌曲集合”。在格式2中,每个MTrk块中只能有一个这些事件。在格式0或1中只能有一个这些事件,它必须在第一个MTrk中。
  • 0x 01,表示任何目的的任何数量的文本。最好将此事件放在MTrk的开头,一般用作注释。长度使用VLQ编码。
  • 0x 02,版权信息(即文本)。最好将此事件放在MTrk的开头。长度使用VLQ编码。
  • 0x 03,序列或音轨的名称(即文本)。最好将此事件放在MTrk的开头。长度使用VLQ编码。
  • 0x 04,轨道演奏的乐器的名称(即文本)。最好将此事件中的一个(或多个)放在MTrk的开头,以便向用户标识正在播放曲目的乐器。通常,通过MTrk中的MIDI程序更改事件,特别是在用于常规MIDI声音模块的 MIDI文件中,在音频设备上设置乐器(例如,补丁,音调,库等)。因此,存在此事件仅仅是为了向用户提供轨道仪器的视觉反馈。长度使用VLQ编码。
  • 0x 05,在给定节拍上出现的歌曲歌词(即文本)。单个歌词 元事件应该只包含一个音节。长度使用VLQ编码。
  • 0x 06,在给定节拍上出现的标记(即文本)。标记事件可用于表示循环开始和循环结束(即,序列循环回到上一个事件)。长度使用VLQ编码。
  • 0x 07,在给定节拍上出现的提示点(即文本)。提示点可用于表示WAVE(即采样的声音)文件开始播放的位置,文本将是WAVE的文件名。长度使用VLQ编码。
  • 0x 20,MIDI通道,其后一般跟着”01 cc”。此可选事件通常发生在MTrk的开头(即,在任何非零增量时间之前以及在除序列号以外的任何元事件之前),指定任何后续元事件或System Exclusive事件与哪个MIDI通道相关联。数据字节cc是MIDI通道,其中0是第一个通道。
  • 0x 21,MIDI端口,其后一般跟着”01 pp”。此可选事件通常发生在MTrk的开头(即,在任何非零增量时间之前和任何Midi事件之前),指定MTrk中的MIDI事件从哪个MIDI端口(即总线)中移出。数据字节pp是端口号,其中0是系统中的第一个MIDI总线。MIDI规范每个MIDI输入/输出(即端口,总线,插孔或您用来描述单个MIDI输入/输出的硬件的任何术语)限制为16个MIDI通道。给定事件的MIDI通道号被编码为事件的状态字节的最低4位。因此,通道号始终为0到15。
  • 0x 2F,此事件不是可选的。它必须是每个MTrk中的最后一个事件。它用作MTrk结束的确定标记。每个MTrk仅1个。其长度字段为”00″.
  • 0x 51,表示速度,其后跟着”03 tt tt tt”。tt tt tt的3个数据字节是每四分音符微秒的速度。换句话说,微秒速度值告诉您音序器的每个“四分音符”应保持多长时间。若没有该事件,假定BPM=120.
  • 0x 54,表示SMPTE偏移,其后跟着”05 hr mn se fr ff”,指定MTrk的SMPTE开始时间(小时,分钟,秒,帧,子帧)。它应该在MTrk的开始。不应使用MIDI时间代码的SMPTE格式对小时进行编码 。在格式1文件中,SMPTE 偏移必须与速度映射(即第一个MTrk)一起存储,并且在任何其他MTrk中都没有意义。所述ff字段包含分数帧。
  • 0x 58,表示拍号。其后跟着”04 nn dd cc bb”。nn和dd表示在乐谱上标注的签名的“分子”和“分母”。dd表示2的幂,2表示四分音符,3表示八分音符。cc表示MIDI时钟的节拍器的数目,dd表示在MIDI四分音符32谱写的音符(24个MIDI时钟)的数量。若没有该事件,假定为”4/4″.
  • 0x 59,调号。其后跟着”02 sf mi”,sf取值-7到7,0表示C调。mi取值0或1,0表示大调,1表示小调。
  • 0x 7F,定序器特定元事件。长度使用VLQ编码。

MIDI事件

MIDI事件使用第一个字节前四位作为标志位,其除F为作用于全局外,其余皆在后四位指示通道号。

对第一个字节:

  • 0x80-0x8F,Note Off,关闭音符,其后第一个字节为音符,第二个字节为速度(力度)。
  • 0x90-0x9F,Note On,打开音符,其后第一个字节为音符,第二个字节为速度(力度)。
  • 0xA0-0xAF,复音触后,其后第一个字节为音符,第二个字节为压力值。复音,指叠加多个音色,触后表示按住音符不动,接着向下按。
  • 0xB0-0xBF,控制器改变,其后第一个字节为控制器编号,第二个字节为值。
  • 0xC0-0xCF,音色改变,其后只有一个字节,表示编号。
  • 0xD0-0xDF,通道触后,其后只有一个字节,表示压力值。
  • 0xE0-0xEF,弯音,用于持续变化音高,其第一个字节为粗调,第二个字节为精调。
  • 0xF2.乐曲位置指针.
  • 0xF3,歌曲选择。
  • 0xF6,调音请求。收到调谐请求后,所有模拟合成器都应调谐其振荡器。
  • 0xF8。时钟,当需要同步时,发送24个MIDI时钟。
  • 0xFA.音序开始。通知MIDI设备或音序器,从当前乐曲的最开头处播放。
  • 0xFB,序列继续。通知MIDI设备或音序器,从上次停止时的位置开始播放。
  • 0xFC,音序停止。
  • 0xFE,连接确认。
  • 0xFF,重启。将系统中的所有接收器重置为开机状态。应该谨慎使用,最好在手动控制下使用。特别是,它不应在上电时发送。

中央C为C4,所有音符值:

八度 音符
C C# D D# E F F# G G# A A# B
-1 0 1 2 3 4 5 6 7 8 9 10 11
0 12 13 14 15 16 17 18 19 20 21 22 23
1 24 25 26 27 28 29 30 31 32 33 34 35
2 36 37 38 39 40 41 42 43 44 45 46 47
3 48 49 50 51 52 53 54 55 56 57 58 59
4 60 61 62 63 64 65 66 67 68 69 70 71
5 72 73 74 75 76 77 78 79 80 81 82 83
6 84 85 86 87 88 89 90 91 92 93 94 95
7 96 97 98 99 100 101 102 103 104 105 106 107
8 108 109 110 111 112 113 114 115 116 117 118 119
9 120 121 122 123 124 125 126 127

发表评论

电子邮件地址不会被公开。 必填项已用*标注