MIDI檔案格式分析
MIDI檔案屬於二進制檔案,這種檔案一般都有如下基本結構: 文件頭+數據描述 檔案頭一般包括檔案的類型,因為Midi檔案僅以.mid為擴展名的就有0類和1類兩種,而大家熟悉的點陣圖檔案的格式就更多了,所以才會出現檔案頭這種東西。
以下是MIDI檔案塊結構
類型 | 長度 | 數據 |
4個位元組 | 4個位元組 | 4個位元組 |
類型指的是"MThd"或"MTrk",長度指的是除去類型和長度兩部分外,其他數據占的位元組數。
而數據描述部份是主體,我們現在來一起分析它的結構:
在每個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 |  指定基本時間格式類型 | 類型1:定義一個四分音符的tick數,tick是MIDI中的最小時間單位 類型2:定義每秒中SMTPE幀的數量及每個SMTPE幀的tick |
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觸後音符 | 音符: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) |
種類 位元組 含義 | 位元組數 |  數據 |
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 | 略 |
59調號 | 02 | 大小調:0(大調),1(小調) 升降號數:-7~-1(降號),0(C),1~7(升號) |
7F音序特定信息 | -- | 音序特定信息 |