來源:http://blog.163.com/waft_xu/blog/static/4381529420081241836248/
MIDI文件屬於二進制文件,這種文件一般都有如下基本結構: 文件頭+數據描述
文件頭一般包括文件的類型,因爲Midi文件僅以.mid爲擴展名的就有0類和1類兩種,而大家熟悉的位圖文件的格式就更多了,所以纔會出現文件頭這種東西。
而數據描述部份是主體,我們現在來一起分析它的結構:
在每個Midi文件的開頭都有如下內容,它們的十六進制代碼爲:“4d 54 68 64 00 00 00 06 ff ff nn nn dd dd”。
前四個是ASCII字符“MThd”是用來鑑別是否Midi文件,而隨後的四個字節是指明文件頭描述部分的字節數,它總是6,所以一定是“00 00 00 06”,以下是剩餘部分的含義:
ff ff |
指定Midi的格式 |
00 00 |
單音軌 |
00 01 |
多音軌,且同步。這是最常見的 |
||
00 02 |
多音軌,但不同步 |
||
nn nn |
指定軌道數 |
實際音軌數加上一個全局的音軌 |
|
dd dd |
指定基本時間 |
一般爲120(00 78),即一個四分音符的tick數,tick是MIDI中的最小時間單位 |
以上就是MIDI文件頭了,後面的所有內容都是真正做事的,我們先來看看它的構成。
MIDI的數據是由若干個格式相同的子數據構成的,這些子數據在多音軌的格式中記錄了一個軌道的所有信息。多加一個音軌,就簡單地把數據追加在前一音軌的後面就可以了,不過不要忘記更改文件頭中的nn nn(軌道數)。
先看全局音軌。全局音軌包括歌曲的附加信息(比如標題和版權)、歌曲速度和系統碼(Sysx)等內容。
不管是全局音軌還是含有音符的音軌,都以“4D 54 72 6B”開頭,它其實是ASCII字符“MTrk”,其後跟着一個4個字節的整數,它標誌了該軌道的字節數,這不包括前面的4個字節和本身的4個字節。這一點,我們可以在後面的例子中去理解。
接着就是記錄數據的地方了,每一個數據有着相同的結構:時間差+事件。
所謂時間差,指的是前一個事件到該事件的時間數,它的單位是tick(MIDI的最小時間單位)。它的構成比較特殊,這裏要用二進制來說明。
一個字節有8位,如果僅使用7位,它可以表示0~127這128個數,而剩下的一位,則用來作爲標誌。如果要表示的數在以上範圍,則這個標誌爲0,這時,一個7位的字節可以表示0~127tick。如果要表示的數超出了這個範圍(比如240),則把標誌設置成1,然後記錄下高7位,剩下的留給下一個字節,在該例中240可以分解成128*1+112,這裏的1就是第一個字節要記錄的,加上標誌位,應該爲10000001,即十六進制的81;而112是下一個字節記錄的,它的十六進制爲70:所以要表示240這個時間,要寫成81 70。同理,如果要表示65535tick,則可以先計算出65535=1282*3+1281*127+1280*127,然後得出結果:83 FF 7F。由此,我們反過來也可以知道如何確定時間差:只要標誌位爲0,則表示結束讀取時間差。比如82 C0 03表示1282*2+1281*64+1280*3=40963,如果基本時間爲120,則有341:043個四分音符。
以這種方式記錄整數的字節稱爲動態字節,它根據記錄的整數改變自身的長度,這在後面還要用到,所以必須熟練計算。
看完了這麼麻煩的東西,我們再來看個更麻煩的東西:事件。在這些標準的解釋後面,我們會通過一些例子來進一步掌握這些內容。
事件大體上可以分爲音符、控制器和系統信息這幾個種類。對於這些事件,都有統一的表達結構:種類+參數。
對於一個音符,由於它的有效範圍是0~127,所以直接用00~7F作爲“種類”,可以認爲是個音符,比如3C表示中央C。而一個音符的最重要的參數是力度(也叫速度:velocity)。比如,3C 64 表示一個力度爲十進制100的中央C音符。
因爲一個字節有8位,所以剩餘的一位如果置1,再聯合其他的7位,則可以表示各種信息。我們暫且無視一個音軌到底是全局的還是用於記錄音符的。它們歸根結底都是用來記錄各種事件的,只不過有些應出現在全局音軌比較合乎邏輯而已。既然這樣,我們就可以從下面的表來看事件:
下表中,x表示音軌0~F,比如81表示鬆開第二軌的音符。
種類 |
參數(十六進制) |
|
字節 |
含義 |
|
8x |
鬆開音符 |
音符(00~7F):鬆開的音符 |
力度:00~7F |
||
9x |
按下音符 |
音符(00~7F):按下的音符 |
力度:00~7F |
||
Ax |
觸後音符 (Key After Touch) |
音符:00~7F |
力度:00~7F |
||
Bx |
控制器 |
控制器號碼:00~7F |
控制器參數:00~7F |
||
Cx |
改變樂器 |
樂器號碼:00~7F |
Dx |
觸後通道 |
值:00~7F |
Ex |
滑音 |
音高(Pitch)低位:Pitch mod 128 |
音高高位:Pitch div 128 |
||
F0 |
系統碼 |
系統碼字節數:動態字節 |
系統碼:不含開頭的F0,但包括結尾的F7 |
||
FF |
其他格式 |
程式種類:00~FF |
數據佔用的字節數:動態字節 |
||
數據:個數由上一參數確定 |
||
00~7F |
上次激活格式的參數(8x、9x、Ax、Bx、Cx、Dx、Ex) |
下表詳細地列出了FF的詳細情況,對於字節數由數據決定的情況,表中以“--”表示。
種類 |
字節數 |
數據 |
|
字節 |
含義 |
||
00 |
設置軌道音序 |
02 |
音序號 00 00~ FF FF |
01 |
歌曲備註 |
-- |
文本信息 |
音軌文本 |
文本信息 |
||
02 |
歌曲版權 |
-- |
版權信息 |
03 |
歌曲標題 |
-- |
歌曲標題:用於全局音軌,第一次使用表示主標題,第二次表示副標題 |
音軌名稱 |
-- |
音軌名 |
|
04 |
樂器名稱 |
-- |
音軌文本(同01/2) |
05 |
歌詞 |
-- |
歌詞 |
06 |
標記 |
-- |
用文本標記(Marker) |
07 |
開始點 |
-- |
用文本記錄開始點(同01/2) |
2F |
音軌結束標誌 |
00 |
無 |
51 |
速度 |
03 |
3字節整數,1個四分音符的微秒數 |
58 |
節拍 |
04 |
分子 |
分母:00(1),01(2),02(4),03(8)等 |
|||
節拍器時鐘 |
|||
一個四分音符包含的三十二分音符的個數 |
|||
59 |
調號 |
02 |
升降號數:-7~-1(降號),0(C),1~7(升號) |
大小調:0(大調),1(小調) |
|||
7F |
音序特定信息 |
-- |
音序特定信息 |
這些就是MIDI結構的全部內容