主要是脑子里要时刻留意这个字节或者是下一字节的数据是不是最高位为1,也就是是不是比0x80大。
比如在读DeltaTime时,就得看当前字节最高位是否为1,是1就表明下一字节还是DeltaTime,是0就表示DeltaTime结束;DeltaTime结束后的下一字节就是具体的事件了。
在读MIDI事件时,也得看当前字节最高位是否为1。是0的话,说明包括目前这个以及后续若干字节都会是数据,而状态字被缩写了,得延续前一个状态字;是1的话,表明这是个状态字,那么除了这个之外的后面若干字节都是数据。
在读某个MIDI事件的数据时,要知道这个MIDI事件包含的数据字节是多长。有1字节的,如换音色的Program Change;有2字节的,如音符NoteOn/Off、弯音轮、控制器等;有不定长的,如Meta-Event或者SysEx系统码,不定长的事件会在事件当中写明了长度,相当于还是有确定的长度。
以上的过程是能画出代码流程图的,MIDI文件的读取也就是这么读的。
另外,能看出来,MIDI文件更像是一种把各个MIDI事件打包压缩出来的一种东西。MIDI文件的时码是一种相对的时差,不是绝对的时刻;MIDI事件的长度也都各自不同,从1个字节到几十k字节都有可能。这就很讨厌了,在读取MIDI文件并解码的时候,要在内存里创建出所有MIDI事件的完整数据结构,包括时间码,状态字,通道号,以及不定长的数据。还得把所有事件串成链表。对于MIDI 1格式的文件还得考虑各个Chunk(或者说音轨)之间在一个播放时间下的同步问题,烦得很。
所以各个音序器或者DAW软硬件(是的,还有硬件)基本都有专有的工程文件格式,不一定是MIDI。比如各个软件有Cubase的cpr,Cakewalk的cwp,FL也有它自己的工程格式;硬件有老雅马哈合成器QS300的ESEQ,雅马哈双排键电子琴EL-900M的EVT,或者老KORG合成器Trinity的SNG(好象是这个扩展名吧,时间长了,忘了)。这些软硬音序器也都有自己独门的对MIDI文件的解读和导出方式。
俺之前有帖子:
啊…如果俺说俺现在逐渐放弃Sonar,甚至逐渐放弃Cakewalk了,不知道层主会不会有一种被俺耍了,想痛扁俺一顿的想法…从Cakewalk从老版本的Cakewalk Pro Audio 9.03,到后来的Sonar 8.53,俺是一直知道Cakewalk会自作主张地对MIDI做些手脚的。这个事情在保存成它自己的早期的wrk工程文件或者是后来的cwp工程文件时,是看不出来的。但是——在工程保存成m…
这里提到了Cakewalk对MIDI文件的处理有点儿自作主张。想说的是啥呢?就是:
你在如今这些大型的,功能完整的DAW软件里,比如什么Cubase啊,Logic Pro啊,Sonar啊,FL Studio啊,等等软件中看到的音符或者其他什么什么东西的参数和状态,保存成专用的工程文件倒没什么。但导出成MIDI文件之后,MIDI文件里的内容可能会和你在编辑时有所不同了。反而有些小型的纯粹的MIDI音序器软件(比如俺用的那个“世界树”),能告诉你最真实的MIDI文件内容(但它因为太简单了,有些复杂的MIDI它也搞不定,比如俺碰到好多次对SMPTE时码的兼容性不佳)。俺那个帖子也看到了俺被Sonar坑的故事,所以这里稍微提醒一下楼主。咱搞开发的,软件也好硬件也好,要有“怀疑一切”的精神,心里得留个心眼儿,看到的未必是真的。所以在楼主后续的开发中如果还会碰到什么稀奇古怪的情况时,不要慌张,要知道一切皆有可能~
不过绝大多数情况下,用那些大型DAW软件编曲作曲写MIDI还都是真香的~就算存成MIDI文件,里边有些东西被改变了,通常也不会影响其播放或者再制作。不必过分恐慌~