MIDI文件结构解读

来源 :MIDI音乐制作 | 被引量 : 0次 | 上传用户:sosmax68
下载到本地 , 更方便阅读
声明 : 本文档内容版权归属内容提供方 , 如果您对本文有版权争议 , 可与客服联系进行内容授权或下架
论文部分内容阅读
  作为一位合格的MIDI制作者应该详细了解MIDI规范,MIDI信息结构和文件结构,这对于深入研究各种MIDI相关设备和软件的操作有着比较重要的意义,同时对于合理利用硬件设备,充分发挥资源潜力有着非常显著的作用。掌握MIDI底层的一些信息往往要涉及到计算机通讯和数据结构等方面比较复杂的知识,对于一位音乐家而言,不能要求他去专研一些过于数学化的道理,那无疑会对音乐家敏锐的感性思维造成束缚。但有的时候我们又不得不翻阅大量的资料和说明来帮助机器实现一个简单的MIDI动作;有时我们又面临自己善变的美感,不得不对我们的作品作批量而有规则的修改。很多时候,我们的工作虽然不会直接针对MIDI数据的底层来展开,但我们的音序器有时的确显得力不从心。
  让一位程序员来了解音乐确要容易得多,据观察几乎每一位程序员都是音乐痴迷的爱好者,而事实上程序员往往为了工作的需要必须去了解各行各业的规范,协议或者理论,有可能的话也会包括和声学和曲式学。当然,我们也同样无法要求一名程序员来创作音乐。
  于是我们何不在自己闲暇的时间,来了解一下每天围绕在我们身边的那些有趣的电信号呢。现在就让我们开始一起来看看这些激越着我们灵感和激情的、可爱的信息是怎样被我们的设备来组织和指挥的。
  
  基础篇-数字、数制
  
  要揭开MIDI文件里的秘密,首先要了解数字化音乐设备是如何来组织庞大的数据信息的,而这些设备组织数据的方法与我们在个人电脑中使用的数据管理方法基本相同。如果您发现这些基础的理论您已经了解并掌握了,您完全可以跳过此篇直接阅读后面的文字。
  我们知道,任何数据如果需要用计算机或者扩展型专用设备来处理和存储,必须使用二进制的数字,这就好像我4岁的孩子老问我动画片里的角色是好的还是坏的一样,最简单的处理问题的逻辑不过就这两种-好的、坏的,用逻辑学术语描述就是真、假,用数字来表示就是1或者0。计算设备基本上可以看成一大群2-4岁的孩子在一起做游戏,他们判断外界信息的标准只可能有两种,如果把计算机的CPU中的任何一个最小的处理单元拿出来看的话,它基本上和我书房里的电灯开关是一样的,往上拨是开,灯会亮;往下拨是关,灯会灭。这些开关足够多而且足够小的话,把他们按一定方式组织起来,那就是一块CPU了。当然,如果要尝试使用第三种状态,这对于一个孩子来说是很难理解的,对于设备的数字逻辑设计而言也没有必要,因为任何第三种状态都可以通过合理组织,用2种状态来描述。现在我们记住,使用1和0这两个数字来控制电路的通和断,事情就是这么简单,我们的灵感就变成了声音了。
  上面一段话看起来是那么站不住脚,因为我们在做MIDI音乐的时候经常要输入各种数据,比如设定一通道的Volume为99,设定一个音符的力度为112,看起来与仅用1和0这两个数字表示相去胜远。的确如此,如果只给我两个数,一个是1一个是0当然无法表示112或者99,但对于音乐家而言,组合和搭配总是那么妙不可言的,很多时候我们会用一个脚鼓的声音加上一个很低的震音琴的声音组合成一种神秘古老的打击乐音色,现在就发挥一下您的这种想象力吧,把很多个1和0串起来看看会发生什么。
  马上来做,首先从0开始,0增加一个量,就变成了1;接着给1再增加一个量,1会变成几呢?没错,变成了2;二进制意味着所有的可以使用数字只有0和1,没有2,一旦数量增加到2则必须像9+1一样进位;于是1+1=10,的确,如果您顺利的理解了这个算式您的一只脚已经从音乐领域迈入了数字领域了;接下去的事情变得越来越有规律了,10+1=11,11+1=100,100+1=101,101+1=110,110+1=111,111+1=1000缮现在您可能发现平时我们的2这个数量在二进制数中表示成了10, 而3这个数量在二进制数中表示成了11,4这个数量在二进制数中表示成了100,5表示成了101,6表示成了110缮于是如果您打开计算机的硬盘看看的话,那黑色的盘面上写满了10010111010001001缮.这样的数字序列,当然这只是个玩笑,但那上面的确是用某种物理方式记录了这样的一串数。
  我简直就是在浪费作曲家宝贵的时间,难道要让一位伟大的音乐家来解读这些数码不成?事实上就算让一位数学家来解读这样的数也几乎是毫无意义的,因为把信息设计成这种形式就是要使电子设备知道什么时候关、什么时候开;既然如此何不让计算机自己去解读呢。
  我们必须对这些冗长而莫名其妙的数码进行人性化的分组,然后必须把它描述成人容易理解的方式,然后我们才能研究里面的规律,不然这个月我的收入帐目可能一辈子都读不懂了,还怎么能算计一下省点钱到小金库里去呢。计算机里存的所有文件既然从根本上来看都是如上面那样的二进制数串,那么我们就可以对所有的数据进行统一的规划,这使得任何使用同样规划方法的计算机之间能够共享数据。一般我们把这些数字每一位叫做bit,注意不要与音乐里的bit混淆,但他们也有着共同点,那就是用来表述事物的最小单位,音乐里一个bit就是一拍,计算机数里的一个bit就是数串里的一位,我们来看一个8 bit的数据,它是这样的:10001101,一共有8位数,如果我们一个月能收入8位数那该多好。
  为了不与bit搞混淆,我另起一段来说byte,读这个单词我常读作拜特,就是害怕与bit弄混,总的来说byte肯定不是1位数,byte是很多位bit的数,但byte也是一个数量单位,我们常称作字节,它是一个设备数据吞吐量的最小有效单位。你会经常在电梯里听到几个年轻人在讨论新买的硬盘有100G的容量,或者听到老太太们谈论今天早上白菜价格比昨天贵了1角钱。其中那个100G指的就是字节数。一般我们可以假设每个byte由8位组成,也就是说1 byte=8 bit。
  MIDI文件里的数据也是以字节为基本单位来组织的,现在请你找找你的作品的MIDI文件,在windowsXP系统里,你可以尝试用右建点击一个文件,在弹出的菜单里看看文件属性,你会发现这个文件的SIZE是101Kb或着95Kb之类,Kb表示千字节,101Kb就意味着它里面包含了101,000左右个byte。规定好了8个数为一个字节后,前面那个莫名其妙的数码就变得好组织多了,我们可以每隔8位表示一个信息,比如第一个8位用来表示一个音符的力度值,第二8位用来表示该音符的时值,接下去第三个8位用来表示一个弯音轮信息缮
  我的写作指导告诉我,我已经创造了足以令一位失眠症患者立即熟睡的良药。如果继续通篇文字的话,恐怕读他的人全都要进入梦乡了。好吧,我们来看一些图:
  这是一个由3个音符组成的midi文件,只占用了一个Track 一个Channel
  包含的midi信息如下:
  在磁盘里,这个midi文件所包含的数据是这样的:
  我们可以看到几个基本的内涵,第一,在磁盘里,所有的信息均是以一些数字来存储的,第二,这些数字根本来看都是二进制的数。上面这张图里显示的就是该midi文件里的全部数字,但并非由0或1组成的二进制数,而是以另外一种表示方法来显示的,为了让人看起来清晰整洁,我们常常把二进制数写成16进制的形式,如果硬要把上面这一段数字用最底层的机器代码写出来的话应该是:
  01001101 01010100 01101000 01100100 00000000 00000000 00000000 00000110 00000000 00000001 00000010........太恐怖了,难以想象如果让所有的音乐家都整天面对这些东西,世界将会变成怎样。幸运的是我们的科学家,那些数学家、和计算机专家们早已为我们设计了非常丰富的软件和硬件工具,让我们随时可以使用和驾驭这些我们原本看起来就头疼的东西。所以当我们呼吸着咖啡的清香,享受着里各种LED指示灯美丽的光彩时,千万别忘了感谢那些科学家呀。
  出于对伟大人物的敬仰和崇拜,我们在获得制作报酬之余抽空来了解一下这些数字如何被那些伟大的专家们训练得如此听话也是很有必要的。
  当然,无论是音乐家还是数学家,面对纯粹的二进制数来工作都是非常苦恼的,我们必须使用16进制这种更适合人的思维方式的表示方法来对数据进行分析和研究。从理论的角度来看,16进制是以16为权的数制,也就是说使用16个符号来表示基本的数据单位,每逢16进一位,这16个符号分别是:0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F。每一个字节由两位16进制数字来表示,每一位16进制的数字表示半个字节也就4个bit。比如说我们要表示一个中央C的音高,他的音高值在MIDI规范中被定义为60,转换成二进制数就是00111100,把这8位二进制数分成两半00111100,前面4位变成十六进制数就是3,后面四位变成十六进制数就是C,因而把中央C的音高值保存到磁盘里后就会变成00111100,当我们把这个二进制的数转换成十六进制数时就是3C,于是当我们把这个带有中央C的文件用一些字节编辑器打开看时就能看到3C这个数。事实上,在很多MIDI设备的说明手册里,当对数据信息的含义进行解释时用到的数字大多都是十六进制表示的。也许你还记得,当你从手册上抄写一段GM初始化的系统信息代码时,那一串数字也都是两位两位的排列,类似于:F0 7E 7F 09 01 F7 的十六进制的形式,翻译成二进制数是 11110000 01111110 01111111 00001001 00000001 11110111。于是当你的合成器接收到从midi文件传来的这一串数时,它的某些逻辑部件就受到开-关的电脉冲,并转变成其他的动作,包括把十通道设置为打击乐,把音色编排解释为GM规定的编号等等。
  为了更清晰的理解前面这所有的文字,我们再来画一副图:
  二进制与十六进制数对照表,每4位二进制数转换为1位十六进制数
  
  概要篇-文件结构概述
  
  正如我们写一篇文章,首先要规划好这篇文章的篇章段落,组织一大堆数据也是如此,聪明的MIDI规范设计者们也给midi文件的构造作了很详细的规划,分章分节,错落有致。
  首先我们来回忆一下两个概念,字节(Byte),位(bit),在midi文件里,每个字节被定义为8位的二进制数,为了表述方便,让我们把这八位数字编个号,从右向左依次为第0位,第1位,第2位,第3位,第4位,第5位,第6位,第7位,第0位叫做lsb(the Least Significant Bit最低位),第7位叫做msb(the Most Significant Bit最高位)。注意不要与midi event里常提到的LSB和MSB搞混,那是LSB(the Least Significant Byte低位字节)和MSB(the Most Significant Byte高位字节)。后面我们会详细讲述高位字节和低位字节的用法。同时为了区分十进制数和十六进制数的表示,在下面的文字里会在十六进制数的后面加一个小写的h,比如十六进制数23会写成23h,十进制的二十三则会写成23。
  MIDI文件是用来存储midi信息的一种文件格式,这里所说的midi信息就是我们在音序器里所看到和熟知的部份events,所有的信息都是基于event的,对设备的控制信号或基于event的其他辅助信息,这些信息都以时间为线索来进行编码,出于经济存储的目的,有些midi事件会采取其他等效方式存储于文件中,例如系统信息中的实时事件以及RPN和NRPN事件等。有别于其他的声音文件(如wave; MP3等),midi文件中并不存储任何波形编解码数据,他仅仅记录一串对设备的控制信号。从音乐家的角度来理解,midi文件存储的其实可以看作一本总谱,里面有拍号,速度记号,音符,时值信息,力度值等等信息,每一个信息单位叫做一个midi-event(以下中文称之为midi事件)。
  所有的midi文件里存储的event大体分为两类,一类叫做通道事件,一类叫做非通道事件。通道信息是指那些基于通道的event,我们都知道,很多时候我们通过设定通道来区分每种乐器或声部,通常我们在音序器里设定好一个音轨的通道后,就可以在这一轨里录制和编辑midi事件,所有录制在这一轨里的事件都会被音序器自动定义在你所设定的通道里发送或接收。而实际上每一个音符或者其他的event在midi文件里都被自动打上了通道标记,这就使得在播放多个通道的音乐时,不至于把各通道里的事件弄混了。几乎所有的与音乐直接有关的信息都是带有通道标记的信息,比如音高信息、时值信息、力度信息、表情信息、弯音轮/调制轮信息、呼吸控制器信息、音量控制器信息、声场控制器信息等等,所有这些信息都属于通道事件。非通道事件则不带有通道标记,这种事件往往对整首音乐进行总体设定或控制,比如一串GM初始化信息,一个效果器类型控制等。
  所有这些信息在保存为一个midi文件的时候,逻辑上都被划分为若干的文件块(Chunk),MIDI文件标准规定,一个midi文件必须包括最少2个块,它们是文件头块和音轨块,其中音轨块可以有很多个并列,但至少得有一个。如下图所示:
  至少要包含文件头和一个音轨才能成文合法的midi文件
  顺便复习一下音轨(Track)和通道(Channel)的区别,音轨是基于对信息组织的一种方式,类似于我们组织一首合奏曲,我们常用声部来区分不同位置的音。通道则是演奏实现的一种方式,不同的声部可能由同一乐器担任或者由不同乐器担任,无论如何,通道都是在演奏的时候才起作用,他指示设备使用哪种音色来演奏。
  
  文件头块(head chunk)包含midi文件类型识别信息,块长度信息,midi格式信息和时钟计数器单位信息,这些信息相当于对整个文件的一个简要概述,让读取它的软件或设备一开始就知道此文件到底有多大,有多少信息需要处理,怎么来进行时间计量。
  音轨块(track chunk)类似于我们在音序器或音序软件里看到的track,midi文件内部也是按照与音序器里同样的track来组织的,但我们知道,midi 0格式的文件所有的数据都是存放于一个track里面的,所以midi 0格式的文件只有一个音轨块。
  在每个音轨块的开头都会有一小段对本音轨的描述信息,叫块头,在块头的后面就是一个一个的midi事件,每个事件都由若干的字节组成。
  变长信息与定长信息(Variable Length Quantity & Fixed Length Quantity) 有一点我们必须知道,在数字信息世界里,信息单位的长度是一个非常重要的量,因为在文件里是没有什么格子或标点符号的,所有的数据看起来都很类似并连成一串,很难区分哪些数字表示哪种信息,计算机往往按照事先约定的长度来对信息分节。比如在读取纯文本文件时,约定是每8位读出一个字符,这样计算机每读8位数就把它解释成一个字母或符号显示出来。看下面这个例子:
  襪,i,d,i?四个字母的二进制代码
  这是一个纯文本文件的二进制代码和十六进制代码,我们看到每隔8位自动读出一个字符,读完这32位后就读出了“m,i,d,i”这四个字符。
  像上面这种每个信息的单位长度固定不变的就属于定长信息,可以看出这种信息比较占空间,浪费率比较大。而midi文件里数量变化最大的信息莫过于时间信息了,如果以微秒来计算,几秒钟的时间就会从0增量到几十万的数量级,使用变长信息来表示时间可以大大节约空间使用效率,也就是说表示每个时钟值的数不是固定长度的,而是由具体情况来具体改变,需要多少位就用多少位,不过这同样也会使得midi文件信息的读取算法更为复杂,幸运的是我们的CPU处理这点事情还是很轻松的。
  Midi event / SysEx event / Meta event ?三种类型的midi事件,在midi文件里,所有的事件按其功能不同被划分为三类:
  1. Midi event - midi事件,如音符开,力度,时值,控制器等与音乐直接相关的信息
  2. SysEx event ?系统控制事件,如GM初始化以及其他设备自定义的控制信息等
  3. Meta event ?附加事件,如歌词,标记,音轨名,调号,拍号,速度值等
  
  实例篇- 具体了解内部结构
  
  现在就让我们来具体分析一个实际的midi文件从而透彻的了解每个数字的含义。到目前为止,虽然有些概念对我们这些曾经把数学课时间耗在了琴房里的人来说的确有些让人发晕,不过没关系,通过下面的例子,我们就会逐渐理解他们。
  为了研究的方便,我们来设计一个尽可能小的麻雀型样例,如果您企图在自己的电脑上来试验的话,除了生成midi文件的工具外您可能还需要一个能读取文件二进制代码的工具软件和一个科学计算器用来转化数制。推荐Ultra Edit+Windwos自带的计算器,那样的话本文就不需要另外花文字来介绍这些软件的用法了,他们都是很直观很容易上手的软件。
  我们将使用Cake Walk 9来设计这个样例,因为Cake Walk 9是目前仅剩下的最容易与MIDI底层打交道同时又兼顾了较好操作界面的音序器了,首先我们用MIDI 1格式来存储,时基(Time-base)设为120,速度100,4/4拍,一个降号的调,在第一小节开始处插入一个Marker 内容并写上marker1,文件信息如下图所示:
  每一轨的参数如下面表格的描述:
  在Cake Walk 9中设置如下图:
  在第一轨里输入F0 7E 7F 09 01 F7 系统信息,这是一串GM模式初始化信息。如下图:
  第二轨里包含的事件如下图所示:
  第三轨如下:
  第四轨如下:
  现在我们就用二进制编辑器打开刚才生成的midi文件。
  
  文件头块
  文件头块从最开始的第一个数一直往后,如下图我用红线筐起来的部份
  它是由这么3个部份组成的(紫色圆点分开了3个部份)
  ◆ 块标记 - 从头向后数4个字节(每字节占用2个十六进制数),这4个字节的数值表示4个文本字符,它们是:M、T、h、d,MThd是所有midi文件头的识别符号,我们可以用来区分midi与其它的文件类型。
  ◆ 块长度 ?也是占用4个字节,接着刚才的标记再往后数4个字节,这4个数表示接下去文件头块里还有多少字节的数据,也就是说计算机读取了这4个字节的信息后,就会知道下面还要读多少字节才到音轨块。我们看到图里显示的是00 00 00 06,转换成十进制数就是6,再往下读6个字节文件头就结束了。
  ◆ 信息数据 ?那么接着读6个字节吧,这6个字节分别是 00 01h, 00 05h, 00 78h三段,分别是
  1、 文件格式 ?MIDI 0 / MIDI 1,可以看到这两个字节0001h的值是1,我们刚才的确是以midi 1格式存储的。
  2、 音轨块的个数 ?0005h表示在文件头后面将会有5个音轨块。可我们明明只创建了4个track呀,怎么会多出一个呢?在midi 1格式的文件里,总会把标题,版权,拍号,调号等信息作为一个单独的Track来存放,所以在Cake Walk 9里面看到的那些Track是不包括这些文本信息的。在后面的track块描述里我们将会看到。
  3、 时钟编码方案 ?在最后的2个字节0078h表示的是此文件将使用的时钟计量方案。Midi使用2种时间码方案,一种叫metrical timing,它是基于tick的一种累计方式,正如我们常使用的一个四分音符占用120个tick或45个tick这样的方案;另一种叫作timecode,它是来源于传统录音工业标准,基于帧(Frame)的计时方法,由小时:分钟:秒:千分秒组成。这2个字节我们变成二进制是00000000 01111000,最高位(bit)为0时表示使用metrical timing,为1时表示使用timecode,当使用metrical timing时,后面的15位的值表示每个四分音符占用的tick数,刚才我们设计这个样本的时候使用的时基是120,000000001111000转成十进制就是120,很显然这个文件正如我们设计的那样是使用120时基的metrical timing时钟编码。使用传统的timecode编码时,后面的15个二进制位将分别表示每秒的帧数和子帧数,由于我们很少使用MIDI作为最终产品来为其他产品配音,所以也很少使用基于timecode的时钟码来存储midi文件,这里就不详细介绍了。
  
  TRACK 0 块
  前面提到过,MIDI 1格式的文件会把诸如标题,版权,拍号,调号等信息作为一个特殊的音轨存储到第一个track里面,而在Cake Walk 9里面这个音轨是隐藏的,如果我们把这个文件导入到其他音序软件中比如Cubase等,就会清楚地看到Track 0被单独列为一个音轨了。
  在开始讨论每个event之前我们还必须进一步了解各种event事件的编排方式以及时钟值的表示方法,正如前面所说,在midi文件里所有的event事件都分为三种,Midi event;SysEx event;Meta event,Track 0所包含的那些标题,拍号等都属于Meta event,也就是附加信息,这一类事件都以<时钟值+FFh+类型+数据>的格式来表示。这样,每一个事件都以时钟值打头,而时钟值的表示方法又是整个midi文件结构中最复杂的一种编码方法,我们有必要在这一段里对时钟值编码作一个详细的介绍。
  时钟值信息属于一种变长信息,前面已经介绍了什么是变长信息。我们来设想一下,如果把第一个事件的时间点作为0,以每个四分音符占用120个时间单位(tick)的方式来编排随后的每个事件的时间,那么几十分钟的曲子下来,最后的时钟值将会相当的大,用二进制数表示很大的数量时将会占用很多的数位,同时我们还会注意到,在同一时间点上同时演奏的event在一首像样的音乐里也是经常出现的,这样一来,一个midi文件将会花掉大半的存储空间来存储时间数据,在设备进行播放的时候也会花掉很多处理时间来进行时钟的操作,这些在早期的midi系统里实在是难以接受的铺张浪费,要知道midi的规范是制定在设备很原始的时代的。当然,既便是现在也不容随意浪费存储资源。
  MIDI文件规范使用相对时间来存储时钟值,也就是说每个事件的时间都是以上一个事件的时间为参照的差值,我们很清楚任何乐曲都不会有长达几分钟的休止或延长几分钟的长音,所以两个连续的事件之间的时间差总是不太大的。在这个基础上,还对时钟值表示方法进行灵活处理,当时间差很小时,仅使用一个字节来表示,当一个字节的8位二进制数表示不了一个较大的时间差时,就把这个数扩充到两个字节,使用16位二进制数来表示,如果还不够大,就再扩充,最多可以扩充到4个字节来表示一个时间差值,midi可允许的两个连续事件之间的时间差值最大可达到四十亿个tick,也就是说如果以120个tick为一个四分音符,midi的最大时间差可以允许到三千多万个四分音符。我没见过一首曲子中间停这么久的情况,您见过吗?
  我们通过几个例子来显示时钟值的变化,假设最开头的事件就是F和A两个音符,他们的tick数为0
  可以看到F和A的tick数都是0,这两个音符事件在midi文件里是一前一后来记录的,F-A,但由于两个音符是同时发生的,所以A音符时钟值为0,表示他与F事件的时间差为0;而这两个音符的时值都是240,是二分音符。休止了20个小节之后,接下去的事件是音符E,这个事件的时钟值是多少呢?经过计算可以很容易得到10080 tick,E事件的时钟值与前面A事件的时间差为10080,所以,E的时钟值就是10080,转成二进制数10080= 00100111 01100000,显然需要占用超过8位的存储空间了,必须使用2个字节。Midi文件规范对这种变化情况作了规定:每个字节的八位二进制数中,最高位仅用作标记位,当最高位为1时表示该字节之后还跟着一个字节一起表示时钟值,当最高位为0时表示该时钟值仅占用本字节;除去最高位,剩下的7个二进制位用来表示时钟值。为了清楚表示,我们来看下面图示:
  我们要把10080= 00100111 01100000这个数填入下面的表格里,怎么来填呢?首先我们把标记位写好,因为占用了2个字节,所以第一字节的最高位要填1,表示下一个字节还是时间码;到第二字节为止,已经可以完全表示整个数了,所以第二字节的最高位就填0。
  现在我们已经作好标记了,接下来我们把10080= 00100111 01100000分成2组,每组7个数字分别填入两个字节里,开头的0可以略去,这样就成了1001110; 1100000,于是就得到如下的填法
  现在我们就得到最终E这个音符事件的时钟值,它由2个字节组成,一共占用16位2进制位,它是11001110;01100000 。把它变成16进制数就是CE 60h。
  我们回到Track 0的描述来
  红线匡住的是第一个track的数据
  这里面包含着10个Meta事件,每个Meta事件都是由这种格式组成的:
  时钟值 + FFh + 类型 + 数据
  其中FF是Meta事件的标志,类型表示是哪一种Meta,很多Meta类型后面会紧跟着长度
  上图中用紫色圆点把每个事件分开来:
  ◆ 事件0块头 ?4D 54 72 6B 00 00 00 60h,4D 54 72 6Bh是四个字母的代码,为M,T,r,k,Mtrk是音轨块的标记,碰到这四个字符,一个音轨就开始了;标记的后面接着是00 00 00 60h,这四个字节,表示接下去在这个块里还有96 (60h=96) 个字节的数据,不信您可以数一下。
  ◆ 事件1曲名 ?FFh是Meta事件的标志;在FFh的前面有个00h,这就是此事件的时钟值,由于他是全曲的第一个事件,所以其时钟值为0;在FFh之后是03h,表示这是个标题类型的Meta事件 (Meta的所有类型将在稍后罗列);03h后面的05h表示接下去有5个字节数据用来表示这一个Meta事件;分别是74h= t、69h= i、74h= t、6Ch= l、65h = e
  ◆ 事件2曲名 - 为了简单表述,下面对同样的情况就不一一细说了,在这一个事件里,每个字节分别表示:00 h (时钟值);FF h (Meta事件标记);03 h (Meta类型标记,又是一个标题类型的Meta);08 h (接下去有8个字节的文本);73 75 62 74 69 74 6C 65 h (分别为s, u, b, t, i, t, l, e)
  ◆ 事件3版权事件 ?00 h(时钟值);FF h(标记);02 h(表示这个是一个版权信息类型的Meta事件);09 h(后面将用9个字节来描述版权信息);63 6F 70 79 72 69 67 68 74 h(copyright九个字符)
  ◆ 事件4文本事件1 ?00 h(时钟值);FF h(标记);01 h(文本Meta事件的标志);06 h(后跟6字节文本);61 75 74 68 6F 72 h(分别为author六个字母)
  ◆ 事件5文本事件2 ?00 h(时钟值);FF h (标记);01 h(文本Meta事件的标志);0C(后跟12个字节文本);分别为instructions
  ◆ 事件6拍号事件 ?00 h(时钟值);FF h(标记);58 h(表示这个Meta事件是拍号信息);04 h(后跟4个字节数据来表示拍号);04 h(每小节4拍);02 h(单位拍时值,0=全音符/1=二分音符/2=四分音符/3=八分音符/4=十六分音符,此处为2,表示以四分音符为一拍,前一字节与这一字节合起来表示拍号4/4);18 h(单位拍占用的MIDI Clock数,24);08 h(表示一个MIDI Clock里定义的三十二分音符的个数,一般固定为8,有些音序器支持非八等份的三十二分音符不规则划分法)。特别在midi 1格式里拍号变化只能在track 0里记录。
  ◆ 事件7调号事件 -00 h(时钟值);FF h(标记);59 h(表示这个Meta事件是调号信息);02 h(后跟2个字节数据来表示调号);FF h(千万别与Meta标志FF h搞混了,这里的FF h是一个数值,表示-1这个十进制值,也就是一个降号,-2表示两个降号,1表示一个升号,0表示无升降号,依此类推);00 h(表示大调,01 h表示小调,某些音序器可以表示大小调式,除此以外这个数值毫无意义)
  ◆ 事件8速度值事件 -00 h(时钟值);FF h(标记);51 h(表示这个Meta事件是速度值信息);03 h(后跟3个字节数据来表示速度);09 27 C0 h(这三个数字等于十进制的600000,它的意思是每个四分音符占用六十万微秒,相当于600毫秒,也就是0.6秒,1微秒=1/1百万秒,之所以这样来编码速度单位,是为了机器处理音乐这种时间至上的艺术时能尽可能的精确,否则失之毫厘谬以千里)。
  ◆ 事件9记号Marker事件 - 00 h(时钟值);FF h(标记);06 h(表示这个Meta事件是Marker信息);07 h(后跟7个字节数据来表示记号Marker);分别是7个文本字符:marker1
  ◆ 事件10块结束 ?每一个音轨块都会以FF 2F 00 h这三个字节来结束,我们看到此轨结束符的时钟值为0,而且所有的Meta事件的时钟值都是0,可以得知在这一轨里记录的事件都是放在此曲最开头的地方并作为同时发生事件对待。
  到此为止第一轨的内容就介绍完了,我们把所有Meta的类型罗列在下面这个表里
  Meta事件列表
  
  Meta事件除了在第一轨里会用到外,在其他音轨里也会用到。
  
  TRACK 1 块
  在开始了解音轨1之前我们有必要对系统信息再作一下回忆。我记得好多年以前在midifan网站上登过一篇报导midi文件病毒的文章,当时很多朋友很惊讶,感叹病毒无处不在,很显然,对于一个非常了解硬件结构的人来说,写段指令来捣捣乱远非什么难事。我们通过计算机或者音序器对midi设备进行控制的过程也就是向设备发送指令的过程,其中绝大多数指令均是以MIDI规范定义的方式来发送的,但很多厂商对自己设备的底层控制以及一些非MIDI功能的实现都是通过自己定义的指令来完成的,于是midi规范必须要开放一个用于传达这种特殊指令的接口,以便于不同的厂商自定对自己产品的底层控制指令,这个接口就是系统信息。
  系统信息使用F0打头的字节并以F7为结尾字节,中间搭载着各种设备的专用信息,不是这种厂商的产品将无法识别和执行这些信息,从而会忽略执行这些指令。这些信息能够实现对专用设备的一些强大的控制,比如初始化内存数据,设定效果器参数,强制使用某种播放模式,改写设备指令集,甚至关机开机等等,同时很多设备开放的专用指令几乎可以完全替代所有的MIDI标准指令,从而实现只有系统信息没有一个MIDI音符的音乐文件,当然这种控制指令也只能是针对特定设备来进行编写。每种设备的定义都不相同,具体请大家参照设备说明书。十分有趣的是有些软音源、寄生式音源竟然也不同程度制作了虚拟的系统信息供使用。
  在制作我们的样例时,我们在Cake Walk 9的第一轨里插入了一段GM初始化信息,这一段信息是一种默许的标准化信息,也就是说很多支持GM的设备都能明白这段指令应该怎么做,不管它来自哪个厂商。因而不用考虑是否兼容的问题了。下面我们来看Track 1里的数据。
  还是接着上一个Track,这一个音轨只有短短的几个事件,从紫色圆点可以看到,该音轨被分为5个事件,第一个事件看起来您应该觉得眼熟,他和Track 0的第一个事件很像。没错,他也是这个Track的块头,所不同的是块头的后四个字节值为21h,表示接下去有33个字节数据,不信您就再数数。同样,他也是以FF 2F 00h作为音轨结束标志的。下面我们具体分析:
  ◆ 块头 ?4D 54 72 6B ; 00 00 00 21 h, 前四个字节是文本MTrk,后四个字节是本块长度,后随33字节。
  ◆ 端口号Meta事件 ?00 h(时钟值,距离上一个事件时间差为0);FF h(Meta事件);21 h(端口号类型的Meta);01 h(后跟1个字节表示端口号数);00 h(端口号为1,默认第一端口为00)
  ◆ 音轨名事件 ?00 h(时钟值);FF h(Meta标志);03 h(音轨名Meta);0C h(后面有12个字节的数据);53 79 73 74 65 6D 20 72 65 73 65 74 h(System reset包括空格在内12个字母)
  ◆ 系统信息事件 ?00 h(时钟值);F0 h(系统信息开头标志);05 7E 7F 09 01 h(我们在Cake Walk 9里插入的那一段GM初始化信息的值);F7 h(系统信息结束标志)
  ◆ 块结束 ?00 h(时钟值);FF 2F 00 h(此音轨结束)
  可以看到在第四个事件中,除了时钟值以外,其余部份都与我们在Cake Walk 9中插入的一模一样,在midi文件里系统信息是保持原样不变的,就像是通过F0 ?F7这条船搭载了一堆货物一样,最终必须完好无损的交给设备。
  到目前为止,我们还没有看到一个让设备发音的事件出现,以上的所有事件都属于非通道信息,在后面我们将看到的事件中将会出现带有通道标记的通道信息。
  
  TRACK 2 块
  开始研究音符等MIDI事件前有一个很重要的概念需要我们提前掌握,在MIDI文件里面,对于同类事件连续出现的情况及进行了一中叫做Running Status (运动着的状态)的处理技术,这是一种数据压缩的方法。例如有2个连续的音符事件,在对这两个事件编码时,第一个事件由时钟值+标志符+参数组成,而第二个事件则直接由时钟值+参数组成,省略的相同的事件的标志符,这样一来可以节约很多相同标志符所占用的空间。特别在很多连续的音符事件时,对于每个音符的开事件和关事件不再分成2种标志符来表示,而是都使用开事件标志符,使用力度值为0表示音符的结束,也就是关事件,这样一长串连续的音符开关事件就可以很简单的由一串时钟值+音符号+力度值(为0时表示音符关)的序列来表示。
  下面我们就来分析这一个音轨的具体事件:
  为了节约篇幅,接下去对每个事件仅作简单说明,然后再对每类事件统一介绍。其中,海绿色为时钟值,紫红色为事件标志字节,括弧里的标志字节是Running status 处理时省略了的。
  通过阅读上面这一些说明,您大概也摸到一些门道了,每个事件前面都是时钟值,倒数第三个事件由于距离前一事件时间较长,因而使用了变长信息来表示较大的数值。在时钟值的后面紧跟着事件标志,Meta的标志前面已经讲过了,这里新出现的主要是音符和控制器等MIDI事件,所有的MIDI事件都必须绑定一个通道号码,所以,MIDI事件标志的字节分成两部份,前半个字节表示事件类型,后半个字节表示通道号,在这一音轨里所有MIDI事件都使用1通道,MIDI文件把他编为0h,例如例中的90h,9h表示音符开事件,0h表示通道号。各种类型的事件后面跟着的参数信息都是固定的,所以不再需要一个说明长度的字节。我们来罗列一下所有的MIDI事件以及它们后面的参数表示法。
  细心的读者一定注意到一些问题,在这一轨里我们没有做过控制器0号和32号,哪里来的这两个控制器呢?样例里使用了RPN来修改弯音的变化量,但怎么没看到了呢?我们在制作样例时,这一音轨我们设定的是使用第一号音色钢琴,音色库号设为1,MIDI文件通过两个控制器来实现双字节对大数字库号的记录,控制器0和控制器32,我们知道,0号和32号控制器是用来对音色库编号进行设定的,0号设定库号二进制值的高8位,32号设定库号二进制值的低8位,因为每个控制器信息都只使用1个字节来表示控制器的值,范围只有0-127,因而对于很多音色库而言,都是使用双字节来对库编号,两个字节的二进制值合并表示一个较大的数从而实现库号的编码。我们的样例并没有选择音色库,但MIDI文件必须指定两个控制器的值,这是规范,在这个例子中,0号控制置0,32号控制器置1,合起来的二进制数是00000000 00000001,其值为十进制数的1,也就是说,在没有设定库号的情况下,MIDI文件会默认为音色库为1号,这对于GM设备而言几乎是没有任何作用的。
  样例中使用的RPN是健在MIDI文件中被转换成了控制器,MIDI文件规范中并没有定义RPN或者NRPN事件,所有此类事件均由控制器来实现。这一点相信有一定基础的读者也能明白,这里使用四个控制器101,100,6,38分别进行高位字节读数开,低位字节读数开,高位字节置值,低位字节置值四个操作,从而存储了RPN信息。对于NRPN事件将通过99、98、6、38四个控制器来实现,但需要根据具体设备确定数据值,详细请参阅具体设备的用户手册。
  
  TRACK 2 块
  这一轨由19个事件组成,所有的事件类型在上面几个轨中都有介绍,其中FF 05h是Meta的歌词事件,93h是音符开事件,通道号4。值得注意的是这一音轨的音色库号我们在Cake Walk 9中设定的值为1024,显然一个字节没法表示这么大的数,上一轨里我们曾提到使用控制器0号和32号来表示库号的高八位和低八位二进制数的方法,现在我们来看一下这个大数怎么被分为2个字节。1024=00000100 00000000(二进制),每个字节最高位为标志位,低七位表示具体值,低位字节的低七位为0(LSB),高位字节的低七位加上低位字节去掉标志位后的进位为1000(MSB),MSB=00001000,转成十进制数为8,LSB=00000000十进制值为0,要表示1024号音色库只需要让控制器0号等于8,控制器32号等于0既可。于是我们看到在这一轨的第四个事件里B3 00 08h把控制器0号设为8,第五个事件里20 00h,把32号控制置0。现在我们把这19个事件作为一个练习在纸上来罗列一下,并尝试自己把每个字节的含义解释一遍以便熟悉内部的结构,需要注意的是歌词事件里的值是每个字节表示一个文本字符,如果不知道具体数据代表哪个字符没关系,可以通过ASCII代码来查询,ASCII代码表可以透过互联网来搜索,他不属于这篇文章要涉及的范畴。
  
  TRACK 3 块
  这是打击乐音轨,打击乐音轨中的各种打击乐器和其他音轨一样按照不同的音符来标记,所以在这一音轨里大家看到还是一个个音符数据。这一轨的音色库号设定为8096,MSB=63,LSB=32,所以控制器0和32分别表示成3Fh和20h。最后该音轨还是以FF 2F 00h结束,MIDI文件没有特别的文件结束符,而是通过文件头块里对后随字节数的描述自动决定文件的结束。
  
  结 束 语:这一篇文章站在MIDI音乐制作者的角度对MIDI文件进行深入解读,因而没有对音乐的知识作过多地讲述,尽管如此,它仍然可以作为程序员进行MIDI文件操作编程的一个参考。个人认为,无论作为一位音乐制作人还是作为一位娱乐产品开发的程序员,都应该是一只脚站在音乐的领域,一只脚站在数字领域的。从目前的MIDI制作行业角度来看,我们的工作应该不仅仅局限于对音乐领域的感悟,更应该主动涉猎数字领域。特别是处在边缘行业的MIDI制作者们,我们的工作经常要成为艺术创造和设备控制的纽带,只有具有敏锐的音乐思维同时能对设备娴熟控制的人才能充分发挥工具的所有潜质来为我们的艺术作品服务。
  出于职业的需要,我经常穿梭于MIDI作曲者和程序员之间,听到的大多是来自音乐人对程序的抱怨,以及程序员对音乐的苛求,两个领域在事实上已经通过MIDI等一系列数字娱乐技术紧密结合在一起,然而我们的工作者们却还没有做好相互沟通的准备。希望此文能为同时爱好或从事这两个领域工作的人们提供一点线索,进而更好的协调与合作。
  注:本文中所涉及到的图表、注解、公式等内容请以PDF格式阅读原文
其他文献
导言  学习电脑音乐的朋友在对待怎样做好混音这一步工作的时候,感到无从下手的不在少数。因此为了解决这个问题,我们今天就拿一个例子《好想》来做一下实例演示。看看怎样混音才能得到比较好的效果。    第一节 混音前的准备工作    本篇文章主要是阐明混音的方法,而不是具体某个软件的使用;尽管实例讲解需要带入到某个具体软件里才好讲解,但是我们不能被软件所束缚,希望看这篇文章的朋友也能举一反三,应用在您自
期刊
个人简介:  李素文男27岁 山西省高平市河西镇人  2000——2002年毕业于太原师范学院音乐教育专业  2002——2005年进修于山西师范大学音乐学本科  2002——至今,自学从事电脑音乐制作的研究,并创立音频新闻网,主要进行音色产品的介绍与评测工作。    一.软件简介:    Waves AudioTrack是一个由均衡器、压缩机和噪声门组合而成的插件效果器。它可以为多轨的音频文件提
期刊
“眼花缭乱”“模糊”“混浊不清”真得可以用来形容我现在的感觉。老实说,我真的很惭愧于评论二字。试问在一个很不清晰的状态之下又怎么能用评论二字来代表我现在的心绪呢?不过值得庆幸的是,清晨的思维状态是最佳状态,虽然昨晚的睡眠不是很强。好,于是乎,提笔写下了这篇文章,也算是对将来我个人的发展埋下了一个引子和另一段警示。    是历史的必然性,因为它已经成为历史    如果我不是用假设、或者、可能、恐怕这
期刊
        
期刊
调式,曲调运动围绕中心音而展开,中心音与曲调中各音形成一个体系,称为调式。我国歌曲创作中五声调式和大小调式是常用调式。除此之外,还包括一些具有色彩性的地方,地域调式。  调式中主、属、下属音,形成调式的框架,在音乐的运动中,属、下属音支持主音而明确调性,肯定调性。而其它非功能性音级,是调式的色彩音级。它们点缀调式,并支持主音。运用好这些色彩音级,使音乐旋律更加流畅,增强调式的风格性。  调式中的各
期刊
[摘要]整合资源县的旅游产业资源,以旅游业推进社会主义新农村建设,使之成为农村经济新的增长最和着力点,是当前资源县旅游业亟需解决的重点课题。  [关键词]资源旅游;丹霞风光;原始文化    大力发展旅游业,做大做强旅游业,是资源县落实科学发展观,实现经济和社会以及人与自然全面、协调、可持续发展的重大举措。近年来,资源县紧紧围绕“生态立县、旅游兴县”的奋斗目标,致力发展旅游产业,使全县旅游业发展取得
期刊
在藏区有很多的民间弹唱歌手,基本上都是原创,少数则翻唱知名弹唱手的歌以及改编一些民间歌谣,歌曲多数是自身情感的流露,创作的灵感源于生活。在藏区各大州县及乡镇都会有不同规模的弹唱大赛,通过各级选拔,每年会推出一些新人。不论男女老少,还是僧俗群众,学生干部,无论什么职业各类群体,都有为数可观的弹唱歌手。你要是到藏区旅游,在大街小巷的音像店便能看到无数张弹唱专辑(VCD唱片),有些画面可能比较粗糙,但是
期刊
要将DSP数字技术与监听音箱相结合,在产品设计和产品完成阶段要有一系列重大的技术突破,才能让用户最终受益。GENELEC技术编辑Christophe Anet和董事长Ilpo Martikainen在下面的文章中阐述了真力为何研究数字技术并将其应用到监听产品中。    追溯到70年代,具有现代科技理念的工程师们就已经就最初的北欧广播N12阐述了控制室的监听条件。其中最主要的一项成就就是定义了控制室
期刊
Liquid Mix 是一个革命性的产品,它是通过火线连接电脑的混音效果处理器,能同时在数字音频工作站中处理多达32轨的压缩和均衡效果插件,由于支持RTAS、Audio Unit、VST等多种格式,它可以在Pro Tools HD/LE、Logic、Cubase/Nuendo、Samplitude、Sonar等主流工作站软件里工作。  (图一,Liquid Mix 外观,右侧为 Focusrite
期刊
一、录制原声      1.打开Cool edit进入多音轨界面右击音轨1空白处,插入你所要录制歌曲的音频、midi、视频伴奏文件。音频文件中包括wav、mp3、wma等等各种个样的文件格式(如图)。    在需要插入视频文件的时候,你需要做的就是先把视频文件的原唱去掉,步骤是这样的:  (1) 导入所需要的文件(如图)      (2)在切换到波形编辑窗口中,确定好哪一轨是伴奏,哪一轨是原声,将
期刊