MIDI檔案結構簡介

 

讀者需要有基礎性的電腦和MIDI音樂相關知識:

  • · 基本的電腦相關知識,如十六進位數的標記法,十六進位與十進位、二進位之間的轉換方法等;
  • · 基本的樂理知識,如音高、時長、節拍、曲調等;
  • · MIDI協議基礎,如各種MIDI事件的類型和含義,事件狀態字、資料長度等的知識;
  • · MIDI檔的編輯製作經驗,如音序器(硬體或軟體)基於音軌的操作思想和使用方式等。

參考資料的話,推薦讀者去找一下《MIDI原理與開發應用》這本書,國防工業出版社出版,陳學煌、劉永志、潘曉利、馬俊編著,紅色封皮。同時讀者還可以去網上搜索相關的資料,有幾個帖子寫得也不錯。
 

1. MIDI檔結構簡介

 

MIDI檔是二進位檔案,其內部主要記錄了樂曲播放時,音序器應發送給音源的MIDI指令和每條指令發送的時間點。音序器讀取這些時間資訊和MIDI令,通過在相應的時間發送相應的指令,以實現樂曲中音符的順序播放和節拍資訊。除了音序器需要發送的MIDI事件之外,MIDI檔內部也記錄了一些輔助資訊,如版權資訊、音軌名、速度資訊、拍號、調號等等,這些資訊被稱為Meta-event,只用於記錄一些曲子的資訊,通常並不發送給MIDI系統中的 其他設備。

 

MIDI檔的資料結構被稱為“chunk”。每個chunk由最初4位元組的“chunk類型,緊接著4位元組的“Chunk大小,和最後長度可變的 “Chunk Data”構成。“Chunk data”的資料長度由“Chunk大小來規定,即“Chunk大小只描述了chunk中資料段的長度,而不是整個chunk的長度。

 

構成MIDI檔的Chunk主要有兩種類型:一種是Header ChunkMThd),另一種是Track ChunkMTrk)。

 

Header Chunk位於整個MIDI檔的起始處,是必須存在的,其起始標記就是ASCII碼形式的“MThd”字串。Track Chunk的起始標記,依然是ASCII碼形式的“MTrk”字串,並且Track Chunk整塊分佈於MIDI檔之中的任何位置,數量也不定,從1塊到若干塊皆可。實際上一個MIDI檔就是由一個Header Chunk和若干Track Chunk組成。讀者若使用一個十六進位編輯軟體(如UltraEdit)打開並查看一個MID檔時,便能找到這兩部分。

 

MIDI文件可能容納的chunks只有Header ChunkTrack Chunk,其它的非法資料結構將被忽略。在MIDIChunk檔結構中,自長度區以後的資料格式,是嚴格規定好的。

 

這裡要探討不同數量的MTrk chunk所構成的MIDI檔的類型。MIDI檔的類型通常分為三種,分別是MIDI 0格式檔、MIDI 1格式檔、MIDI 格式2檔。它們的相同點是:無論哪一種格式的MIDI檔,都要具備一個MThd chunk,和至少一條MTrk chunk。不同點是:它們各自的MTrk chunk數量不同,並且各個 chunk之間的播放方式略有區別。很多入門級電子琴和具備播放簡單和絃鈴聲的手機,只能播放MIDI 0格式檔;平時用音序器軟體編輯MIDI時,又最好保存為MIDI 1格式檔。這種現象是有原因的。

 

MIDI 0格式檔只有一個MTrk chunk。在這個 chunk中,包含了整個MIDI檔中的MIDI事件,包括meta-event、演奏資訊、效果器資訊等等。所以播放機只需要順序讀取並解析檔,並發送實際的MIDI事件即可。播放MIDI 0格式檔,對於入門級電子琴或者手機這種性能較弱、資源緊張的嵌入式系統來說,相對容易一些。音序器不需要考慮在不同MTrk之間來回跳躍取數,只需要像流媒體檔那樣順序讀取並解析就行了。

 

MIDI 1格式檔具有若干條MTrk chunk,並且chunk之間具有統一的時間資訊,也就是說,各個chunk之間的播放是同步進行的。MIDI 1格式檔的第一條MTrk chunk是專用的,稱為“Tempo Map”。它包括整個MIDI檔中所有的 meta-event。從第二條MTrk chunk開始,每一條MTrk chunk都記錄著各自的演奏和效果器等資訊。音序器在播放時,將使用統一的時間等資訊,同步播放各個chunk。這就像cakewalk軟體播放 MIDI檔一樣,在一個時間軸的滾動下(音軌區的那條標誌播放位置的分隔號),各個音軌同時播放。實際上cakewalk軟體也僅支援MIDI 0MIDI 1檔。

 

MIDI 2格式檔也具有若干條MTrk chunk,但每個chunk具有獨立的時間資訊,也就是說各個chunk的播放並不是同步的,而是每個chunk都遵循自己的時間資訊,chunk之間 沒有統一的時間聯繫,各自播放。這種檔目前筆者也未曾見過,所以筆者在此不再過多解釋此格式的檔。

 

綜上所述,在解讀MIDI檔時,首先要找到各個塊,也就是一個MThd chunk和若干MTrk chunkASCII字串。這樣使用者或軟體才能根據MThdMTrk中所記錄的資訊,確定此MIDI檔的基本參數,並進行下一步更詳細的解析。關MThdMTrk中詳細的解析規則,筆者將在下文中具體解釋。

 

以常用的音序器軟體cakewalk為例,在cakewalk軟體打開一個MIDI檔後,軟體將讀取MThd chunk內部的相關資訊,從而確定此檔的類型、chunk數目、全域時鐘設置等參數。然後軟體將讀取各個MTrk chunk,並將每個chunk內部包含的MIDI事件列在編輯區內對應的音軌部位。於是,在使用cakewalk打開一個MIDI檔後,用戶就可以在編輯區內部看到若干條黃色的音軌,每個音軌內部含有該音軌所包含的MIDI事件,用戶可以對不同音軌內的不同事件,甚至整條音軌,進行參數設置。

 


2.MThd chunk結構

 

MThd chunk中保存了此MIDI的一些基本資訊,如檔案格式(MIDI 012格式)、此MIDI檔的音軌數(從1到多條)、時間類型(使用MIDI TickFrame來計時)。當然,作為既定的標準,MThd Chunk一定是類似這樣的資料結構(十六進位):

 

  • 4D 54 68 64    \\ MThdASCII碼,為Header Chunk的標誌
  • 00 00 00 06     \\②MThd中資料部分的長度,以目前標準均為6位元組
  • hh hh               \\③MIDI檔案類型
  • ii ii                    \\④MIDI檔的音軌數目
  • jj jj                    \\此MIDI文件的時間類型

 

Header Chunk之中的資料結構定義是嚴格遵循這個標準的。目前的標準中並未規定Header Chunk有其他的資料定義(但以後也許會擴充)。所以說,在Header Chunk中,前八個位元組(即①②的資料結構)是固定樣式的,資料段的大小也是固定為6位元組的。

下面對資料段中的具體資料結構作一個介紹:

資料標誌著該MIDI檔的格式。MIDI檔案格式有三種,012格式,所以可以分別用000000010002來表示。每種格式的具體含義請見上文。

 

資料標誌著該MIDI檔中所包含的音軌數目,也可以認為Track Chunk的數目。對於MIDI 0格式檔,此值僅為1,即只有一個Track ChunkMIDI 1格式檔則可以有多個Track Chunk,而且Track Chunk數目為實際的音軌數目加一(因為第一個Track ChunkTempo Map,不記錄實際的演奏資訊)。MIDI 2格式檔因為筆者未曾遇見,所以不敢妄為解釋。

 

資料標誌著該MIDI檔的時間類型。MIDI的時間類型通常有兩種,一種是基於TPQNTicks Per Quarter-Note,每四分音符所具有的Midi Tick數)的時間度量法,另一種是基於SMPTE時間碼的時間度量法。在這裡,MIDI檔使用這個十六位數的最高位元,標誌這兩種時間類型。也就是說, 這個時間類型如果大於0x8000,則為SMPTE時間碼度量法;如果小於0x8000,則為TPQN時間度量法。而此數的後十五位元,則記錄著具體的 Midi Tick數量。SMPTE本來是用於視頻中的協定,所以它的計量單位為,就是“frame”。視頻中有幀率的概念,單位為/秒(fps。不同的視頻標 准中有不同的幀率,比如25fps30fps等等。如果MIDI系統中使用這種時間度量法,那麼它所定義的就是,在每一幀中,所具有的Midi Tick數目。這種度量法在單純的MIDI系統中比較少見,筆者概念也顯模糊,故不細談。

 

對於大多數只有音訊的MIDI系統中,MIDI檔多採用TPQN時間度量法TPQN“Ticks Per Quarter-Note(每四分音符中所包含的Midi Tick數量)的縮寫,它的意思可以從字面來理解。這個數值可以是十進位的60-480之間,數值越大,MIDI系統的時間解析度就越大,也就是說可以 演奏時值越小的音符。通常這個數都採用120240480,因為這些數都能被234甚至68整除,方便於八分音符、十六分音符、三連音甚至更短 音符的演奏,換算成十六進位,就是0x780xF00x1E0。當然注意,這些十六進位數的最高位都是0

 


3.MTrk chunk結構

 

Track Chunk內部則包含了一個MIDI檔中記錄的實際的MIDI資訊和一些輔助資訊(如meta-event)。Track Chunk依然具有和Header Chunk類似的結構,就是“Chunk標誌”+“資料段大小”+“資料。所以它的結構如下所示(十六進位):

 

  • 4D 54 72 6B         // ①MTrkASCII碼,為Track Chunk的標誌
  • pp pp pp pp          // ②MTrk中資料部分的長度
  • xx yy                    // ③Delta-timeMIDI事件
  • xx yy                    // ③Delta-timeMIDI事件
  • ……                    // (省略)③Delta-timeMIDI事件
  • 00 FF 2F00         // ④meta-event事件,此Track事件結束

 

資料依然是Chunk標誌,只不過該標誌被換成了ASCII碼的MTrk,代表接下來的資料為Track Chunk的資料。

 

資料依然是此Chunk中所包含資料的大小。當然這個數就不是如同Header Chunk中那樣的常數了,而是要精確描述接下來Track Chunk資料段的大小了。

 

接下來就是Track Chunk中所包含的真正資料了,就是由許多類似那樣的資料堆積起來的大段資料。xx代表了Delta-timeyy代表了真正的MIDI事件。這些 MIDI事件才是音序器在播放MIDI檔時需要即時處理和發送的資料。這種結構筆者將在下文中詳細介紹。

 

資料從嚴格意義上講,也屬於的類型。最初的00代表delta-time,隨後的FF2F 00為一段meta-event,代表了本Track結束。



4.Delta-TimeMIDI事件結構

 

delta-time,實際上就是“Δt”。任何學習過數學和物理學的人,都能明白“Δt”的含義:它代表著時間差。MIDI系統中的delta-time,表徵著下一個事件距離上一個事件有多長時間,即兩個事件之間的時間差。這個時間不是我們日常生活中的時分秒,而是 MIDI Tick。音序器通過對自身產生的MIDI Tick進行計數,判斷是否該處理下一個MIDI事件。如果Tick數到達delta-time,就處理下一個事件,然後繼續判斷下一個delta- time是否到達,周而復始。

 

為了能夠表示足夠長的時間,Delta-time使用可變長度數的格式,最長可以表示0x0fffffffMIDI事件則包括實際需要發送出去的MIDI事件,和meta-event事件。對於實際需要發送的資料,音序器就直接將資料發送出去;如果是meta-event事件,音序器則修改自身的相關參數。

 

這裡要注意MIDI檔的狀態字省略特點。為了減少MIDI文件的體積,人們規定:如果同一Track Chunk中的下一條MIDI事件,和上一條事件,屬於同一類型同一通道的事件(即狀態字相同)時,下一條事件的狀態字可以省略,而只需記錄資料。音序器 碰到這種情況時,應自動填充上一事件的狀態字。

 

舉個例子,MIDI檔中的事件,大多數都是“Note-On”“Note-Off”事件,其中“Note-Off”事件也可以用“Note-On”+ “力度為0”來表示。所以在MIDI檔中,這種縮略形式會用到很多。比如連續演奏幾個音符時,MIDI檔就會使用這種縮略法來減少檔體積。比圖在 MIDI檔中,常常會看到這種序列(十六進位):

 

  • 00 93 3C6B  // 音符0x3CNote-On,力度為0x6B
  • 70 3C00      // 實際發送的指令為隔0x70 Ticks之後,發送93 3C 00

 

因為力度為0,也就相當於讓某個音符停止發音。83 3C 6B93 3C 00的效果是一樣的。所以通過這種寫法,MIDI檔可以省略掉一個位元組的空間。

 

總結起來,MIDI檔可以用以下的兩張圖來描述。通過這兩張圖,相信讀者會對MIDI檔的資料結構建立一個直觀的認識。本文的目的就在此。有關 MIDI文件更細節的說明,請參考相關的MIDI文檔和手冊。相信在對MIDI檔有了一個基本認識之後,您再翻閱其他技術文檔和手冊時,就可以更加深刻 地理解其含義了。

MIDI1结构.jpg

MIDI0结构.jpg

文章轉載自:http://www.cndzq.com/bbs/thread-114440-1-1.html

 

 

文章標籤
創作者介紹

宇若彎彎

周宇若 發表在 痞客邦 PIXNET 留言(0) 人氣()