MIDI文件深入剖析

midi文件组成

本文分析midi文件的组成和工作原理。

midi文件中没有任何音频数据,它仅仅是记录了该使用什么乐器演奏,演奏乐器的节拍,演奏力度等等。而真正发出音频信号数据到扬声器的是音源文件。音源文件是预先录制好的一种乐器的声音,一种乐器用一个固定的编号来表示,称之为键值,演奏的轻重程度称为力度,一种乐器演奏的时长称为tick。

废话不多,下面开始分析midi文件组成。

头块信息

数据格式:

<标志符串>(4字节) + <头块数据区长度>(4字节) + <头块数据区>(6字节)

  • 标志符串"MThd" ,MThd是头块类型,用十六进制表示就是4d 54 68 64。

  • 头块数据区长度,指的是后面接着的头块数据区长度,因为长度是6字节,所以固定显示为00 00 00 06。

  • 头块数据区,共有6字节,分别为ff ff nn nn dd dd。

    ff ff 指定midi文件格式,一般有3种:

    1. 00 00 表示只含一个音轨
    2. 00 01 表示含有多个同步音轨
    3. 00 10 表示含有多个独立音轨

    nn nn 指定轨道数,一般都会大于1,因为除了演播主音轨外,还会有全局音轨。

    dd dd 指定基本时间格式。
    dd dd 的最高位为标记位。
    0为采用ticks计时,后面的数据为一个4分音符的ticks;
    1为SMPTE格式计时,后面的数值则是定义每秒中SMTPE帧的数量及每个SMTPE帧的tick。
    用我们举例的midi来看看,dd dd 的数据为01 E0,表示采用ticks计时,1E0转十进制为480,也就是每个4分音符,包含480ticks。后面事件时间都是以ticks为单位。

音轨块

音轨块的数据格式:

<标志符串>(4字节) + <音轨块数据区长度>(4字节) + <音轨块数据区>(多个MIDI事件构成)

在头块之后,剩余的部分是一个或者多个音轨块。每个音轨块的结构如上面所示,包含3部分。
第一部分是音轨块的标志符,用ASCII码字符串表示为"MTrk",用十六进制表示就是4d 54 72 6b。
第二部分是音轨块数据区,长度也为固定4字节,指定后面的数据区长度。
第三部分是音轨块的数据区,它是由多个midi事件构成,如下面所示:

  • MIDI事件的构成格式:

< delta time > + < MIDI 消息 >

事件大体上可以分为音符、控制器和系统信息这几个种类。对于这些事件,都有统一的表达结构:种类+参
数。
“delta time”单位是tick,用动态字节表示。
MIDI消息是由一个状态字节加多个数据字节构成,状态字节最高位一直是1,所以它的范围是128255之间。数据字节最高位一直是0,所以它的范围是0127之间。
消息可分为通道消息和系统消息。
下面是MIDI通道消息的构成:
通道消息是对单一的MIDI Channle起作用,Channle的表示使用状态字节的低4位(用X表示)表示,即0~F。

状态字节 状态功能 数据字节
8X 松开音符 1字节音符号,2字节力度
9X 按下音符 1字节音符号,2字节力度
AX 触后音符 1字节音符号,2字节力度
BX 控制器变化 1字节控制器号,2字节参数
CX 改变乐器 1字节:弯音轮变换值的低字节 / 2字节:弯音轮变换值的高字节
EX 滑音(弯音轮) 1字节音符号,2字节力度
F0 系统码 系统码字节数:动态字节系统码:不含开头的 F0,但包括结尾的 F7
  • 还有一种特殊的状态字节FF,表示非MIDI事件(Non- MIDI events),也叫meta-event(元事件)。
种类字节 功能 数据字节长度 意义
00 设置轨道音序 02 音序号
01 文字事件 文本信息
02 版权 版权信息
03 歌曲名称 全局音轨名称
04 指定乐器 乐器名称
05 歌词 歌词
06 标记
07 注释 动作或事件
2F 音轨结束标记 00 必须有结束标记

实例分析

以下是一个midi文件实例分析:



MIDI文件深入剖析_第1张图片

midi播放原理

要想播放midi文件,首先在当前机器上要有音源文件。
PC机系统自带了一套音源文件,所以在PC机上用任何播放器都可以播放midi文件。
如果在嵌入式系统上播放midi文件,难度就大了点。嵌入式系统上播放midi,就好比是要制作一台电子琴,首先要把音源烧录到flash中,在没有文件系统的情况下,需要简析midi文件,再把midi文件以数组或其它形式的方法保存下来,供代码使用。

一个midi文件在单片机上的简析

一个单片机上使用的midi文件

 0x4D , 0x54 , 0x68 , 0x64 ,  // "MThd"
 0x00 , 0x00 , 0x00 , 0x06 ,  // 头块长度:不包括前4字节和本4字节
 0x00 , 0x01 ,                // 格式;1-多轨,同步
 0x00 , 0x03 ,                // 轨道数 = 3
 0x01 , 0xE0 ,                // 基本时间格式 0x01E0 = 480;
 
 0x4D , 0x54 , 0x72 , 0x6B ,  // "MTrk"
 0x00 , 0x00 , 0x00 , 0x15 ,  // 21 该规长度:不包括前4字节和本4字节
 0x00 ,                       // 时间差
 0xFF , 0x58 , 0x04 , 0x04 , 0x02 , 0x18 , 0x08 , // 其他功能、节拍、长度4、分子4、分母4、节拍器时钟24、一个四分音符包含的32分音符的个数8
 0x00 ,                       // 时间差
 0xFF , 0x51 , 0x03 , 0x0C , 0x35 , 0x00 , // 其他功能、速度、长度3:1个四分音符的微秒数800,000
 0x84 , 0xE7 , 0x00 ,         // 时间差:128^2*4+128*103+0 = 78720
 0xFF , 0x2F , 0x00 ,         // 音轨结束标志。

//======================================================================
 0x4D , 0x54 , 0x72 , 0x6B , // "MTrk"
 0x00 , 0x00 , 0x09 , 0xC9 , // 2505 该规长度:
 0x00 ,                      // 时间差
 0xFF , 0x03 , 0x07 ,        // 歌曲标题,音轨名称,长度7
 0x54 , 0x72 , 0x61 , 0x63 , 0x6B , 0x20 , 0x31 , // "Track 1"
 0x00 ,                      // 时间差
 0xFF , 0x04 , 0x1F ,        // 乐器名称,长度31,--"Microsoft GS Wavetable SW Synth"
 0x4D , 0x69 , 0x63 , 0x72 , 0x6F , 0x73 , 0x6F , 0x66 , 0x74 , 0x20 , 0x47 , 0x53 , 0x20 , 0x57, 0x61 , 0x76 , 
 0x65 , 0x74 , 0x61 , 0x62 , 0x6C , 0x65 , 0x20 , 0x53 , 0x57 , 0x20 , 0x53 , 0x79 , 0x6E , 0x74, 0x68 , 
 
 0x00 ,                     // 时间差
 0xB0 , 0x0A , 0x40 ,       // 调换控制,控制号10(声像控制器),(CAKEWALK默认值是64)新值64
 
 0x89 , 0x30 ,              // 时间差=128*9+48=1200us
 0x90 , 0x40 , 0x50 ,       // 音符打开,音符号64,速度80  (E5 : MI)
 
 0x81 , 0x58 ,              // 时间差=128*1+88=216us
 0x80 , 0x40 , 0x40 ,       // 音符关闭,音符号64,速度64  (E5 : MI)
 
 0x18 ,                     // 时间差=24us
 0x90 , 0x45 , 0x50 ,       // 音符打开,音符号69,速度80  (A5 : La)
 
 0x81 , 0x58 ,              // 时间差=128*1+88=216us
 0x80 , 0x45 , 0x40 ,       // 音符关闭,音符号69,速度64  (A5 : La)
 
 0x18 , 
 0x90 , 0x47 , 0x50 ,       // 音符打开,音符号71,速度80  (B5 : Si)
 
 0x81 , 0x58 ,              // 时间差=128*1+88=216us
 0x80 , 0x47 , 0x40 ,       // 音符关闭,音符号71,速度64  (B5 : Si)
 
 0x18 , 
 0xB0 , 0x40 , 0x7F ,       // 调换控制,控制号64(延音控制器),新值117
 
 0x00 ,                     // 时间差
 0x90 , 0x48 , 0x64 ,       // 音符打开,音符号72,速度100 (C6 : Do)
 
 0x00 ,                     // 时间差
 0x90 , 0x45 , 0x50 ,       // 音符打开,音符号69,速度80 (A5 : La)
 
 0x83 , 0x60 ,              // 时间差=128*3+96=480us
 0x80 , 0x48 , 0x40 ,       // 音符关闭,音符号72,速度64 (C6 : Do)
 
 0x00 ,                     // 时间差
 0x80 , 0x45 , 0x40 ,       // 音符关闭,音符号69,速度64  (A5 : La)
 
 0x00 ,                     // 时间差
 0x90 , 0x4A , 0x64 ,       // 音符打开,音符号74,速度100  (D6 : RE)
 
 0x81 , 0x70 ,              // 时间差=128*1+102=230us
 0x80 , 0x4A , 0x40 ,       // 音符关闭,音符号74,速度64  (D6 : RE)
 
 0x00 ,                     // 时间差
 0x90 , 0x4C , 0x64 ,       // 音符打开,音符号76,速度100  (E6 : MI)
 
 0x81 , 0x70 ,              // 时间差=128*1+102=230us
 0x80 , 0x4C , 0x40 ,       // 音符关闭,音符号76,速度100  (E6 : MI)
 
 0x00 ,  
 0xB0 , 0x40 , 0x7F ,       // 调换控制,控制号64(延音控制器),新值117
 
 0x00 , 
 0x90 , 0x4A , 0x64 ,       // 音符打开,音符号74,速度100  (D6 : RE)

你可能感兴趣的:(MIDI文件深入剖析)