Created
April 5, 2013 12:54
-
-
Save farteryhr/5319066 to your computer and use it in GitHub Desktop.
MIDI以及mid文件的字节格式……查了一圈资料各种机翻……要么就是各种文艺一点没有程序猿风范【滚】所以写个笔记,你一定看不懂的【大雾】
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
定义 范围(左端点,右端点) | |
左闭右开区间你懂的 | |
定义 字节 | |
……8位二进制数码…… | |
定义 大端整数 | |
就是由几字节组成的整数,但是首个字节代表的是最大的8位。 | |
定义 变长MIDI整数 | |
MIDI的变长整数记录法,用低7位记录数字,最高位为1表示再读一字节拼起来。 | |
也就是,0-128直接单字节一坨,大于128切成每坨7位,也是按大坨在前,然后除了最后一坨之外,每一字节最高位改成1。 | |
定义 MIDI整数 | |
据说长度一般是一定的,对于一字节值域为0-128,对于2字节定义不太明确貌似是14位怎么的…… | |
定义 音高(1字节MIDI整数) | |
MIDI标准音高表示法,十进制60表示C4,偏移1等于偏移1半音。 | |
定义 力度(1字节MIDI整数) | |
开启音符时,作为击发力度(音量)。但是语义上是速度…… | |
语音合成上速度跟力度差远了……姑且当作砸钢琴的速度吧…… | |
因为只表示这一发的力度,区别于其他持续发声的乐器(吹的拉的)的音量可以在中途变化。 | |
关闭音符时,作为释放速度,127最快。不过我目前所见midi似乎都是瞬间释放。 | |
定义子过程 取得通道音高力度(指令和通道) | |
取<指令和通道>低4位 → 通道号 | |
读1字节MIDI整数 → 音高 | |
读1字节MIDI整数 → 力度 | |
定义子过程 取得事件 | |
读 变长MIDI整数 → 本事件前延迟Tick数 | |
读1字节整数 | |
取高4位 | |
如果高4位是0x8 //关闭/释放音符 | |
取得通道音高力度(当前字节) | |
如果高4位是0xh //打开/按下音符 | |
取得通道音高力度(当前字节) | |
如果高4位是0xa //轮指 神之名词。。据说意思就是让已经按下的音符不释放直接再来一发…… | |
取得通道音高力度(当前字节) | |
如果高4位是0xb //改变控制器 | |
取低4位 → 通道号 | |
读1字节MIDI整数 → 控制器号 //要改变的控制器,控制器很多…… 貌似有些控制器期的意义跟这里有重复…… | |
//参见http://wenku.baidu.com/view/2a4e0e64783e0912a2162a62.html 或者搜索MIDI控制器列表 | |
读1字节MIDI整数 → 新值 | |
如果高4位是0xc //改变乐器。控制器里面貌似也有类似定义的东西…… | |
取低4位 → 通道号 | |
读1字节MIDI整数 → 新的乐器号 | |
如果高4位是0xd //后触/演奏压力/音量 ……准确定义至今不明 | |
//控制器里面有情绪控制(估计是给唱的)、呼吸控制(估计是给吹的拉的)、音量控制(纯粹的音量) | |
取低4位 → 通道号 | |
读1字节MIDI整数 → 新的音量值 | |
如果高4位是0xe //音高微调/滑音,用2字节表示 | |
//据说就是按照MIDI整数规则组合起来,一共14位,合起来是0x0-0x4000。首个字节需不需要高位填1貌似没说。 | |
//然后采用偏移法而不是二补码,0x2000表示音高不变。但是变化量Pitch Bend Sensitivity具体不清楚。 | |
取2字节 → 新音高 | |
如果高4位是0xf //系统的特殊信息,低4位不再是通道号了 | |
如果低4位是0x0 //系统码,可以包任意数据,交给目标设备解释…… | |
取变长MIDI整数 → 消息长度 | |
取<消息长度>字节 → 消息 | |
//消息最后一字节一定是0xf7,似乎是当成字符串的null-terminator。 | |
//实际上消息中间也可以有0xf7出现,因为规定了读取长度。是潜规则么… | |
如果低4位是0xf //0xff,Meta-events,传说中的更加特殊事件…… | |
读1字节MIDI整数 → 消息类型 | |
读变长MIDI整数 → 消息长度 | |
读<消息长度>字节 → 消息 | |
取消息类型 | |
如果高4位是0 | |
取低4位 | |
如果是0x0 //只应发生在音轨头部(0时刻) | |
消息内容(大端整数) → 轨道序号 //据说内容长度只应是2字节。注意起这里貌似都[不]是MIDI整数了。 | |
//低4位是0x1开始的都是文本信息,只是作用不同。 | |
如果是0x1 | |
消息内容 → 通用文本事件 | |
如果是0x2 //只应在音轨头部 | |
消息内容 → 版权信息 | |
如果是0x3 //只应在头部,在多轨中的全局音轨表示歌曲标题,其他音轨中表示音轨标题。 | |
消息内容 → 歌曲标题/音轨标题 | |
如果是0x4 | |
消息内容 → 乐器相关信息 | |
如果是0x5 | |
消息内容 → 歌词 | |
如果是0x6 | |
消息内容 → 标记 //已经搞不懂要这么多种消息拿来干啥了…… | |
如果是0x7 | |
消息内容 → 注释点 //描述舞台动作用的事件……你赢了…… | |
如果是0x2f //音轨结束事件,一定会在每个音轨最后出现一个。包括在音轨长度中了,类似于系统消息的谜之0xf7。 | |
//<消息长度>一定是0x00 | |
退出子过程 | |
如果是0x51 //改变节奏速度 | |
//据说<消息长度>一定是3 | |
消息(<消息长度>字节大端整数) → 四分音符时长 //微秒数! | |
如果是0x54 //至在百度百科的那篇机翻文里面有提到,意义不明,看样子很少有使用。 | |
//据说<消息长度>一定是5,只应出现在音轨0时刻。 | |
//摘录百度百科 | |
/* | |
SMPTE 时间同步 | |
FF 54 05 hr mn se fr ff | |
这一事件,如果存在的话,将指定某一个特定事件开始的SMPTE时间。 | |
它应出现在音轨的开头,在任何非零时间后发生的事件或可传送的MIDI信息之前。 | |
*/ | |
如果是0x58 //改变拍号。应该只能出现在整小节处吧。 | |
//据说<消息长度>一定是4,不知道这里每个数都是MIDI整数还是单字节整数。 | |
取消息第0字节 → 拍号分子 | |
取消息第1字节 → 拍号分母的2的幂次 //0x02→(?/4拍) 0x03→(?/8拍) 以此类推 | |
取消息第2字节 → 四分音符对应Tick数 //这里我查的几个例子给出来的都比较模糊,待考。 | |
取消息第3字节 → 四分音符对应32分音符数 //同待考,略囧,不该永远是8么……例子上各种写十六进制0x24就是32……跪烂 | |
如果是0x59 //改变调号/谱号 | |
//据说<消息长度>一定是2 | |
取消息第0字节 → 升降号数目 //正为升,负为降 又开始用二补码了么…… | |
取消息第1字节 → 大/小调 //0→大调 1→小调 | |
如果是0x7f //真·特殊要求…… | |
消息 → 传说中的真·特殊要求内容 | |
定义 文件结构 | |
循环直至读完 | |
读4字节 → 块头 | |
如果是"MThd" //文件头 | |
读4字节大端整数 → 文件头大小 | |
读<文件头大小>字节 | |
取2字节大端整数 → MIDI类型 | |
//0:一条轨 1:多条轨,同时播放 2:多条轨非同时播放(据说可能是接着播放也可能有各种位置),貌似没人用 | |
取2字节大端整数 → 轨道数 | |
取2字节大端整数 → 每拍Tick数 //相当于分辨率,就是最小时间单位。拍被默认为四分音符。 | |
如果是"MTrk" //轨道 | |
读4字节大端整数 → 该轨道大小 | |
读<该轨道大小>字节 | |
取得事件,直到取得的事件是“音轨结束” //此时应该刚好取完 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
赞一个!