MIDI二进制文件格式简析

本文主要参考自Official MIDI Specifications

Chunks

每个MIDI文件由一系列chunk组成,每个chunk的前四个字节为魔数(magic number),是由四个ASCII字符所组成的类型标识。目前标准格式中已定义的chunk类型只有headertrack两种,其魔数分别为"MThd""MTrk",对于类型未被定义的chunk则应该被忽略。

每个chunk在其四字符类型之后紧跟一个32位无符号整数,意味这一chunk后续将要读入的字节个数,每个chunk已经读入的这八个字节不包含在内。

通常来说,一个MIDI文件中首先要存在一个header chunk,然后一系列track chunk紧随其后,格式大致如下:

MThd

MTrk

MTrk

...

Header Chunks

在目前的标准中,header chunk长度固定为14,其由五个部分所组成:

=

其中type固定为"MThd"formatntrksdivision均为16位,因此length固定为0x00000006

format指定了整个文件的组织结构,在当前的标准下,仅支持0x00000x00010x0002这三种可能的值。

0 the file contains a single multi-channel track

1 the file contains one or more simultaneous tracks (or MIDI outputs) of a
sequence

2 the file contains one or more sequentially independent single-track patterns

ntrks表示整个文件中track chunk的总个数,对于format为零的文件来说ntrks的值总是0x0001

最后的division表示了delta-times的含义,有metrical timetime-code-based time这两种形式,这取决于其最高位是否为零。

假如division最高位为零,那么就属于metrical time形式,这个16位无符号整数的意义为每个四分音符的ticks个数。否则属于time-code-based time形式,其低8位表示每帧的ticks个数,高8位为一个8位负数补码,有-24-25-29-30这四种可能的值,其意义与SMPTE有关,以下内容摘抄自维基百科:

Sub-second timecode time values are expressed in terms of frames. Common supported frame rates include:

24 frame/sec (film, ATSC, 2K, 4K, 6K)

25 frame/sec (PAL (Europe, Uruguay, Argentina, Australia), SECAM, DVB, ATSC)

29.97 (30 ÷ 1.001) frame/sec (NTSC American System (US, Canada, Mexico, Colombia, etc.), ATSC, PAL-M (Brazil))

30 frame/sec (ATSC)

在这里可以发现,凭借division是完全不足以描述每个时间间隔的实际长度的。在规范中对此有所说明,在默认情况下,乐曲的节奏为4/4拍,速度为每分钟120拍。这类元数据应该在MIDI文件中被指定,对于format0x0000的文件应处于其track chunk的开始,对于format0x0001的文件应包含在第一个track chunk之内,对于format0x0002的文件应包含在每个track chunk之中。

值得一提的是,未来的标准有可能会定义更多种类的formatchunk,甚至有可能为header chunk添加更多的参数从而使其length不再为0x00000006,因此对于程序的实现者来说,遵守标准是十分必要的。

Track Chunks

无论format的取值是什么,Track Chunks的结构都是一致的:

= +

length后是一串连续的MTrk event,每个MTrk event由两部分组成:

=

这里的delta-time是一种variable-length quantity,其每个字节仅有7个有效位,最高位若非零则说明后面还有下一字节,最多可占据四个字节,因此其最大值为0x0fffffff。以下为参考示例:

Number(hex) Representation(hex)
00000000 00
00000040 40
0000007F 7F
00000080 81 00
00002000 C0 00
00003FFF FF 7F
00004000 81 80 00
00100000 C0 80 00
001FFFFF FF FF 7F
00200000 81 80 80 00
08000000 C0 80 80 00
0FFFFFFF FF FF FF 7F

delta-time后紧跟的event有三种不同的类型:

= | |

MIDI event的第一个字节通常表示running status,其最高位必须非零,对于sysex eventmeta-event来说,这个字节分别为0xf00xff

MIDI event

在每个track chunk中出现的第一个MIDI event必须指定running status,而对于后续的MIDI event,假如其紧跟在一个MIDI event后面,并且与前一个MIDI event有着同样的running status,那么这一个MIDI eventrunning status可以被省略。

每个MIDI event根据其running status高4位的不同而存在一个或两个单字节参数,这些参数的最高位均为零,running status的低4位表示channel的编号,每个MIDI event只会在对应的channel上造成影响。举几个例子,以16进制表示:高4位为C意为Program Change,其跟随一个单字节参数,表示修改乐器音色;高4位为9意为Note On,高4位为8意为Note Off,这两者都跟随两个单字节参数,分别表示音高与力度。

中央C在MIDI event中的值为0x3c,每升高半音则加一,每降低半音则减一,通过这种规律可以推断出标准音为0x45

channel最多有16个,每个channel之间是独立的,也就是说不同的channel可以通过Program Change同时使用不同的音色,而又由于Note OnNote Off也是独立的,因此同一个channel中也可以同时播放不止一个音符。不过打击乐通常位于第10号channel

音色对照表见文章末尾。

sysex event

这是一种结构稍显复杂的事件信息,它可以包含一连串的sysex event,其基本结构如下:

F0

这里lengthbytes的长度,如果bytes不以0xf7结尾,那么其后就要跟随一个变长的delta-time,然后在跟随下一个sysex event,就像这样:

F7

除第一个sysex event之外,后续跟随的sysex event首字节应为0xf7,且最后一个sysex event的最后一字节应为0xf7。以下是一串合法的sysex event示例:

F0 03 43 12 00

81 48

F7 06 43 12 00 43 12 00

64

F7 04 43 12 00 F7

以上部分的0x81480x64分别表示200-tick delta-time和100-tick delta-time

meta-event

这一部分的格式是比较固定的:

FF

所有meta-event0xff起始,然后紧跟一个字节的type,再然后跟随一个变长的lengthlength的值即为bytes的长度。

Standard MIDI Files 1.0中已经预定义了一部分meta-event,其中Copyright Notice应作为第一个track的第一个eventSequence NumberSequence/Track Name若存在则必须在任何delta-times非零的event前出现,End of Track必须作为每个track的最后一个event

FF meta-event
FF 00 02 ssss Sequence Number
FF 01 len text Text Event
FF 02 len text Copyright Notice
FF 03 len text Sequence/Track Name
FF 04 len text Instrument Name
FF 05 len text Lyric
FF 06 len text Marker
FF 07 len text Cue Point
FF 20 01 cc MIDI Channel Prefix
FF 2F 00 End of Track
FF 51 03 tttttt Set Tempo
FF 54 05 hr mn se fr ff SMPTE Offset
FF 58 04 nn dd cc bb Time Signature
FF 59 02 sf mi Key Signature
FF 7F len data Sequencer-Specific Meta-Event

Set Tempo参数的意义为每个四分音符的微秒数。

Time Signature参数的意义分别为节奏的分子、以二为底取得节奏分母的对数、节拍器每响一次的MIDI clocks个数、每个四分音符所包含的三十二分音符个数(最后这个我也不理解有什么意义),比如以下示例:

Therefore, the complete event for 6/8 time, where the metronome clicks every three eighth-notes, but there are 24 clocks per quarter-note, 72 to the bar, would be (in hex):

FF 58 04 06 03 24 08

That is, 6/8 time (8 is 2 to the 3rd power, so this is 06 03), 36 MIDI clocks per dotted-quarter (24 hex!), and eight notated 32nd-notes per MIDI quarter note.

Key Signature的第一个参数表示乐曲经过了移调所添加的升降号个数,第二个参数取0x000x01意为大调或小调。

以下音色对照表引用自General MIDI System Level 1

General MIDI Sound Set Groupings(all channels except 10)

Prog # Instrument Group Prog # Instrument Group
1-8 Piano 65-72 Reed
9-16 Chromatic Percussion 73-80 Pipe
17-24 Organ 81-88 Synth Lead
25-32 Guitar 89-96 Synth Pad
33-40 Bass 97-104 Synth Effects
41-48 Strings 105-112 Ethnic
49-56 Ensemble 113-120 Percussive
57-64 Brass 121-128 Sound Effects

General MIDI Percussion Map(Channel 10)

MIDI Key Drum Sound MIDI Key Drum Sound MIDI Key Drum Sound
35 Acoustic Bass Drum 51 Ride Cymbal 1 67 High Agogo
36 Bass Drum 1 52 Chinese Cymbal 68 Low Agogo
37 Side Stick 53 Ride Bell 69 Cabasa
38 Acoustic Snare 54 Tambourine 70 Maracas
39 Hand Clap 55 Splash Cymbal 71 Short Whistle
40 Electric Snare 56 Cowbell 72 Long Whistle
41 Low Floor Tom 57 Crash Cymbal 2 73 Short Guiro
42 Closed Hi Hat 58 Vibraslap 74 Long Guiro
43 High Floor Tom 59 Ride Cymbal 2 75 Claves
44 Pedal Hi-Hat 60 Hi Bongo 76 Hi Wood Block
45 Low Tom 61 Low Bongo 77 Low Wood Block
46 Open Hi-Hat 62 Mute Hi Conga 78 Mute Cuica
47 Low-Mid Tom 63 Open Hi Conga 79 Open Cuica
48 Hi Mid Tom 64 Low Conga 80 Mute Triangle
49 Crash Cymbal 1 65 High Timbale 81 Open Triangle
50 High Tom 66 Low Timbale

你可能感兴趣的:(MIDI二进制文件格式简析)