針對 MIDI 音樂的 API ,其實在 Win 8.1 的時候就出現。在UWP中采用了新的驅動模式,MIDI 消息傳遞更加高效。
首先得說明的是,UWP 的 MIDI 相關 API 不是針對 MIDI 文件的,而是針對 MIDI 設備的,所以它不具備保存 MIDI 文件的功能。當然,如果你想把 MIDI 消息存為音頻文件,完全可以自己一個字節一個字節地寫入。MIDI 文件分為兩個數據塊——頭部和音軌。頭部主要描述音軌類型(單軌或多軌),包含軌道數量,以及計時方式。
MIDI 有兩種方式來描述音符時值:
1、Timing Clock:單個四分音符(常規是每四分音符為一拍)的“脈沖時鍾數”(PPQ),時間單位Tick,一般為24的倍數。
2、幀率。這個跟視頻有點像,比如24幀,30幀等。
計時方式用兩個字節表示(16位),如果最高位為0,表示用Tick方式來描述,剩下的15位表示Tick值;如果最高位為1,則表示幀率。
比如,如果用Tick方式表示(常用),第16位必須為0,即 0111 1111 1111 1111。
MIDI 文件除頭部外,剩下部分都是音軌數據。每個音軌由一系列事件組成。事件就是MIDI指令。MIDI 文件之所以體積小,是因為它不存儲音頻數據,只存儲指令。比如 Note on 開始播放某個音符,Note off 停止播放某個音符。每個事件都由兩段組成:
<delta time><event data>
Delta time 指事件的時間偏移量,它是相對於前一個事件而言的,當然,如果是軌道中的第一個事件(或者是元數據事件),delta time 可以是0。常用的是tick計時方式,比如,文件頭中指定每個四分音符的時值為96,那么,假調事件A播放中音1(C),事件B停止播放中音1,如果這個中音1是四分音符,即時值為1拍,兩個事件可這樣排列:
<0><note on 60><96><note off 60>
60中音1的編碼,這個老周后面會說,也就是B事件要在A事件后面,相隔時間為96,1拍。如果是八分音符呢,就是48(半拍)。
<0><note on 60><48><note off 60>
好了,關於 MIDI 文件的信息就說到這里,有興趣的話,你可以到 midi.org 官方網站去查看相關的規范。老周寫了一個讀寫 MIDI 文件的通用類,功能還未完尚,僅供參考。下載鏈接在這里。
=====================================================
下面咱們說正題。
UWP 中的 MIDI API 是用於與 MIDI 設備通信的。其實總的來說也就兩種設備:輸入/輸出。輸入設備一般來說也就是 MIDI 鍵盤了。這個我們一般人用不上,買一個的話也不便宜,起碼要幾百大洋。輸出設備可以是專門的MIDI聲卡,當然,我們一般的聲卡也可以。普通聲卡支持MIDI 的通用標准,缺點是音色不太真實。專業聲卡再配上軟音源就可以模擬出更多樂器的音色,而且質量也高。軟音源也不便宜,買一套大概也要一千大洋。
本篇咱們先不說 API 怎么用,很簡單,因為微軟都封裝好了的,直接發送 MIDI 消息就行了,或者從外接的 MIDI 鍵盤中接收 MIDI 消息。但是,前提是你得有一點樂理知識。要求不高,能看懂簡譜的話,就可以了。
簡譜頭部
在簡譜上,標題、副標題這些就不多說了,都能看明白的。在簡譜頭部,我們主要了解三個標記:
1、調號。比如我們看到許多簡譜上會標注 1 = C,意思是中音1的發音是鋼琴鍵盤上的【中央C】鍵(白鍵)。調號不理解也無所謂,其實不影響MIDI編程,我們就不需要弄得太復雜了,尤其是大調小調的區分,除非你對音樂有興趣,可以研究研究。反正就是調越高聲音越尖銳,調越低聲音越柔和。所以小調一般很適合民歌。
2、拍號:常用的是 4/4,分子為4,表示每四拍為一小節;分母為4,表示一個四分音符為一拍。這是最常見的。比如這樣:
前面部分是調號,緊跟着是拍號。
如果是,2/4,表明每兩拍為一小節,四分音符為一拍。
3、節奏(節拍):表示每分鍾多少拍(BPM)。常見的節奏為120。
表示一分鍾 120 拍,所以,每拍的時長為 0.5 秒。
如果是60,表明一分鍾60拍,即一秒一拍。
實際上,決定曲子速度的不是拍號,而是節奏。120 的曲子速度自然要比 60 的快。拍號只是確定每個音符的相對時值,標准是四分音符為1拍,那么八分音符就是半拍,十六分音符就是1/4拍,三十二分音符就是1/8拍了。總之都是二次方的,而且分的越小時值越短。
前面提到MIDI文件有 Tick 和幀率兩種計時方式,其實計時方式也不會影響曲子的速度(時長),就好比2分鍾長的視頻,你把幀率從 30 幀改為 15 幀,但視頻長度依然是 2 分鍾,只是變得不太流暢而已。MIDI 中也一樣,速度是由節拍映射(Tempo map)決定的。不同的是,我們簡譜中用的是 BPM(每分鍾多少拍),而MIDI中用的是微秒,比如,BPM=120,即0.5秒一拍,換算為微秒就是 500000了。
小節
上面咱們提到過,4/4表示每四分音符為一拍,每小節一拍。那小節是啥?在簡譜上,用小節線(豎線)來划分小節。請看下面例子。
上面例子中有兩個小節,按照拍號的規定,每小節必須是四拍,第一個3是兩拍,第二個3是兩拍,加起來正好是四拍。所以后面緊跟一條豎線,這根線就是小節線。第二個小節中,中音5是一拍,中音2是一拍,緊接着的中音3、1下面都有一橫線,是八分音符,各半拍,加起來正好一拍;最后的低音6是一拍,合起來也是四拍。
再看一個例子。
注意看拍號,2/4表示每四分音符為一拍,但每小節是兩拍。比如第一小節,中音1、中音2都是四分音符,各一拍,共兩拍,所以構成一個小節。
音符
我們剛剛在簡譜上看到的1234567,就是音符,當然這是簡譜上的表示法,這種表示法,容易識別。在五線譜中,音符是用“蝌蚪文”來表示的,不容易分別,也不好懂。
順便說說唱名和音名。這兩個東西,很多時候都會搞混。所謂唱名,就是你用嘴巴唱出來的時候發的聲,就是
dol re mi fa sol la xi
對應的音符就是 1 2 3 4 5 6 7。這個應該不難,小學生都懂。
音名就是鋼琴鍵盤上那些字母,與唱名對應的是 C D E F G A B。
中國很多樂器(尤其是吹管類)的基本音域都在 1 2 3 5 6 這幾個音上,那是因為我們古代的定音方式為“宮,商,角,徽,羽”,有的說是“宮,商,角,徴,羽”,對應的大約是1 2 3 5 6,古人是用“三分損益”法計算音階的。因此,許多民樂都沒有 4 這個音(3和4的音程是半音),比如,巴烏就是個典型。 笛子和洞簫雖然有 4 這個音(放開全部音孔,八孔簫要按住半音孔),但發聲相對較弱。其實,像巴烏(葫蘆絲)這些樂器也可以通過接中音5以下的音孔來調節出 4 的音,但也是比較弱的。
十二平均律
音階划分方式很多,比如中國古代有“五度相生”法,五度指純五度,這個很復雜,老周也說不清楚,不過,我可以總結出一句不太靠譜的話——純五度的總音程為 3.5 個全音(三個全音,一個半音)。
其他的計算方式不多講,因為 MIDI 的音階用的是十二平均律,這是世界普及的,琴鍵上用的也是十二平均律。其實,十二平均律是中國人發明的,在明朝的時候就出現了,只是當時樂器生產工藝限制,沒有人願意接受這種方式,結果讓西方人搶了頭功。
十二平均律是以每【半音】來划分的,因此,它可以包含12個音:
1、1#、2、2#、3、4、4#、5、5#、6、6#、7
對應的音名為
C、C#、D、D#、E、F、F#、G、G#、A、A#、B
其中,3和4之間的音程是半音,前一八度的7與后一八度的1之間的音程是半音,其余為全音,比如1和2之間是全音,所以,在1和2之半加一個 1#,表示在1的基礎上升半音,因此,1# 和 2b 是同一個位置,1升半音就是 1#,2 降半音是 2b。
文字是說不清楚的,看看這個圖你就懂了。
不管白鍵還是黑鍵,兩個鍵之間的音程都是半音,你會看到,3 和 4 之間沒有黑鍵,因為 3 和 4 之間的音程就是半音。故 12345 就是所謂的純五度,因為它們的總音程就是 3.5 個全音。
再看一張更大的圖。
這樣你就看到規律了,一個八度的鍵排序是這樣的:
黑 黑 黑 黑 黑 ……
-------------------------------------------------------------------------------------------------------------------
白 白 白 白 白 白 白 ……
故而,3和4之間是兩個白鍵,7和1之間是兩個白鍵,因為它們的音程都是半音。
將其替換為十二個音符,就是:
1# 2# 4# 5# 6# ……
-------------------------------------------------------------------------------
1 2 3 4 5 6 7 ……
介紹完音符,咱們還要了解音符的時值,所謂時值,就是音符的相對時間長度。
按照時值不同,可以分為以下幾種:
1、全音符。標准情況下是四拍,表示方法為 X - - -。
2、二分音符。標准情況下是二拍,表示方法 X -。
3、四分音符。一拍,表示方法 X。
4、八分音符。半拍,表示方法 。
5、十六分音符。四分之一拍,表示方式 。
6、三十二分音符。八分之一拍,表示方式 。
……
后面就不再分了,時值太短了,你也唱不出來。
當然,也有比較特殊的,比如,三拍時值的音符,也可以表示為 X - -。
好了,只要有了上面這些基本知識,就可以開始 MIDI 編程了。下一篇老周就說說如何向聲卡發送 MIDI 消息。本篇就扯到這兒了。