朋友的公司准备做的一个内容,我负责其中一个模块,该模块需要解析MIDI文件,然后生成另外一种格式。虽然也有开源的包可以用,不过那个包bug微多,而且已经停止维护很久了。(开发那个包的好像是个搞乐队,估计专心玩音乐去了吧)
花了1天多才写完,上点翻译内容,表示斯坦福大学的内容真心好理解啊
原文地址:http://www.ccarh.org/courses/253/handout/smf/
标准MIDI文件(Standard MIDI File 简称SMF)是由MIDI块(chunks)构成的。第一个MIDI块是Header块,接下来是一个或多个Track块。Header块包含整个MIDI文件的全局数据。每一个Track块都定义了一个逻辑音轨(track)。
SMF = <header_chunk> + <track_chunk> [+ <track_chunk> ...]
一个块由三部分构成,与微软的RIFF文件类似(不同之处在于SMF是使用大端法存储(Big-endian),而RIFF是使用小端法(little-endian)),这三部分定义如下:
1、 前四个字节是块ID。Header块是:”MThd”,Track块是:”MTrk”
2、 下面四字节是无符号值,用来定义块中数据部分的长度
3、 最后则是块数据
Header块包括块ID,长度,MIDI文件的格式信息,MIDI音轨(指逻辑音轨,即Track块个数)数量和MIDI最小时间单位长度信息。
header_chunk = "MThd" + <header_length> + <format> + <n> + <division>
“MThd” 4字节
标志Header块的字符,16进制表示为:0x4D546864。这4个字符出现在MIDI文件的开头,标志这是一个MIDI文件。
<header_length> 4字节
指示Header块中数据部分的长度(永远为6字节长,因为数据部分的三个字段均为2字节)。
<format> 2字节
0 = 单一音轨文件格式
1 = 多音轨文件格式
2 = 多歌曲文件格式(一组单一音轨的文件)
<n> 2字节
Header块后的Track块的数量。
<division> 2字节
间隔时间所对应的单位时间数(tick数)。如果这个值为正,那么它标志着每一拍所对应的单位时间数。比如说,+96表示每拍对应96 ticks。如果这个值为负,间隔时间则对应SMPTE单位。
Track块包括块ID,长度和事件信息(event data)。
track_chunk = "MTrk" + <length> + <track_event> [+ <track_event> ...]
“MTrk” 4字节
标志Track块开始
<length> 4字节
标志数据部分的长度
<track_event>
序列化的音轨事件
一个音轨事件由与上一事件的间隔时间和三种事件之一构成
track_event = <v_time> + <midi_event> | <meta_event> | <sysex_event>
<v_time>
一个变长值,用来表示与前一事件的间隔时间
<midi_event>
MIDI的通道事件,比如说音符开始(note-on)与音符结束(note-off)。其播放方法在MIDI装置中都相同。
<meta_event>
元事件
<sysex_event>
系统独有事件
元事件不是MIDI数据(即不是用来控制MIDI播放的),包括前缀,类型标识,长度和数据部分
meta_event = 0xFF + <meta_type> + <v_length> + <event_data_bytes>
<meta_type> 1 字节
Type |
Event |
Type |
Event |
0x00 |
Sequence number |
0x20 |
MIDI channel prefix assignment |
0x01 |
Text event |
0x2F |
End of track |
0x02 |
Copyright notice |
0x51 |
Tempo setting |
0x03 |
Sequence or track name |
0x54 |
SMPTE offset |
0x04 |
Instrument name |
0x58 |
Time signature |
0x05 |
Lyric text |
0x59 |
Key signature |
0x06 |
Marker text |
0x7F |
Sequencer specific event |
0x07 |
Cue point |
<v_length>
变长值,表示数据部分长度
<event_data_bytes>
具体数据信息
系统高级事件(System Exclusive Event)
系统高级事件包括两种:
sysex_event = 0xF0 + <data_bytes> 0xF7 or sysex_event = 0xF7 + <data_bytes> 0xF7
第一种中MIDI数据流应包含0xF0,第二种则可以省略。
在SMF中,有一些值被表达为可变长的。这种可变长值是一种被压缩的格式:
一个可变长值使用每一个字节的低7位存储数据或者数据的一部分,最高位表示是否继续。只有可变长值的最后一字节的最高位为,其他均为1。
例如:
Variable Length Value Real Value
0x7F 127 (0x7F)
0x81 0x7F 255 (0xFF)
0x82 0x80 0x00 32768 (0x8000)