2018年12月25日星期二

純文字製作 MIDI 檔案?

MIDI 全名是 Musical Instrument Digital Interface (樂器數碼介面)
MIDI 實際不是聲音格式檔案,只是一連串與音效有關的指令,通過音效卡來模擬樂器的聲音
MusicXML 是一種 XML 格式,可以純文字來製作,但 MusicXML 還比 MIDI 更複雜
而且 MIDI 本身就是標準格式,因此直接使用 MIDI 來測試

MIDI 格式是由一連串 十六進制 內容組成,因此不能單純以純文字製作,但通過如 printf '\x41' 這種方式輸出內容勉強都能以純文字方式建立
MIDI 由兩部分組成
一個 MIDI Header Chunk一個或以上 MIDI Track Chunk 組成
可以用 MIDI = MIDI Header Chunk + MIDI Track Chunk [+ MIDI Track Chunk ...] 表達

MIDI Header Chunk 由五部分組成
MIDI Header Chunk = "MThd" + 資料長度 + MIDI格式 + 音軌數量 + Ticks Per Quarter Note
以下表單是概要
部分十六進制資料位元組長度說明
14D 54 68 644標頭資料 MThd
200 00 00 064資料長度為 6 ,在標準MIDI格式規格中必定為 6
300 012MIDI格式
400 012音軌數量
500 602TPQN 60 (hex) = 96 (dec)
  1. MIDI Header Chunk 開首必為 4位元組 ,轉換成字元就是 MThd
  2. 之後是 4位元組資料長度
  3. 之後是 2位元組MIDI格式 ,共有 3種
    • 0 - 單音軌
    • 1 - 同步多音軌 (通常編曲軟件匯出 MIDI 的格式)
    • 2 - 異步多音軌
  4. 之後是 2位元組音軌數量
    MIDI格式 為 0 時,音軌數量 必須是 1
    MIDI格式 為 1 或 2 時,音軌數量 必須是 1 或以上
  5. 之後是 2位元組 的 Ticks Per Quarter Note (TPQN)
    即是 每一拍是多少Ticks一拍指一個四分音符(或四分休止符)的時間長度
    一拍(四分)是 16 Ticks二拍(二分)便是 32 Ticks半拍(八分)則是 8 Ticks
    雖然一般節拍長度都是以 二指數遞增 ,但編曲時還有如 三連音五連音非二指數遞增 的時間長度
    因此設定 TPQN 時需要考慮編曲的內容需要來調整,例如 TPQN 為 480 (01E0 hex) 便是 3, 5, 32 的倍數,編曲時便可以較多變動空間
    若還需要使用如 七連音質數數值的連音 時間長度,便再計算及調整
由於 MIDI格式音軌數量TPQN 共合 6位元組 ,因此 資料長度 為 6

MIDI Track Chunk 由三部分組成
MIDI Track Chunk = "Mtrk" + 資料長度 + Event [+ Event ...]
以下表單為概要
部分十六進制資料位元組長度說明
14D 54 72 6B4音軌標頭 MTrk
200 00 00 044資料長度, 00 00 00 04 表示 資料長度 為 4
3**Event
  1. MIDI Track Chunk 開首必為 4位元組 ,轉換成字元就是 Mtrk
  2. 之後是 4位元組資料長度 ,長度計算至 Track Footer
  3. 然後是最少一組 Event

Event 由三部分組成
Event = 相距時間長度 + (MIDI Event | Meta Event | SysEx Event) + 00 (hex)
以下表單為概要
部分十六進制資料位元組長度說明
1001相距時間長度, 00 表示 與上一個 Event 的相距時間長度 為 0
2**MIDI Event | Meta Event | SysEx Event
3001結束 Event
  1. 相距時間長度 與上一個 Event 的相距時間長度
  2. 當中可以使用一種或多種 Event ,次序不限定
    • MIDI Event 為音訊內容
    • Meta Event 為音軌或音訊資料
    • SysEx Event
  3. 00 為十六進制資料,結束 Event

MIDI Event 由二部分組成
MIDI Event = Note On + Note Off
MIDI Event 就是觸發音效的 Event ,當中 Note On

Note On 由三部分組成,是音效開始
Note On = 音效開始 + 音調 + 音量
以下表單為概要
部分十六進制資料位元組長度說明
190 ~ 9F1音效開始
200 ~ 7F1音調
300 ~ 7F1音量
  1. 音效開始1位元組 為 90 ~ 9F (hex) 即是 144 ~ 159 (dec)
  2. 音調1位元組 範圍為 00 ~ 7F (hex) 即是 0 ~ 127 (dec) ,當音標為 3C (hex) 即是 60 (dec) 時,等同 Middle C
  3. 音量1位元組 範圍為 00 ~ 7F ,當音量為 0 時,等同 休止符 (Rest)

Note Off 由三部分組成,是音效結束
Note Off = 音效時間長度 + 音效停止 + 音調
以下表單為概要
部分十六進制資料位元組長度說明
1* 00 ~ 7F1 ~ 16音效時間長度
280 ~ 8F1音效停止
300 ~ 7F1音調,與之前相同
  1. 音效時間長度1至16位元組 ,當長度是 7F (hex) = 127 (dec) Ticks ,可以直接寫入
    但 Ticks 超過127 便會非常複雜
    例如以在下 TPQN 使用 60 (hex) = 96 (dec) ,當使用 二分音符(或二分休止符) 便會是 192 ,是不能直接寫入 C0
    由於 192 除以128 商數 為 1 餘數 為 64
    因為進行 1次 除以128 ,所以需要用多 1位元組 寫成 128+1 64 (dec) = 81 40 (hex)
    若果 商數 仍是 超過127 ,便需要再 除以128
    例如 32768 除以128 商數 為 256 超過127 ,需要再 除以128 商數 為 2 餘數 為 0
    因為進行 2次 除以128 ,所以需要用多 2位元組 寫成 128+2 128+0 0 (dec) = 82 80 00 (hex)
    商數超過127 ,繼續 除以128
  2. 音效停止1位元組 為 80 ~ 8F (hex) 即是 128 ~ 143 (dec)
  3. 音調1位元組 與剛才相同

當同時間寫入超過一個音調可以寫成
MIDI Event = 相距時間長度 + Note On [+ 相距時間長度 + Note on] + Note Off + 00 [+ Note Off + 00]
但這種 MIDI Event 只需要 第一個 Note Off 需要有已計算妥當的 音效時間長度
其餘的 Note Off 的 音效時間長度 為 0 即可,否則之後的 Note Off 的 音效時間長度 便會延長
例如
部分十六進制資料位元組長度說明
200 90 3C 7F4相距時間長度為 0 ,音效開始,音調為 3C (hex) ,音量為 7F (hex)
400 90 40 7F4相距時間長度為 0 ,音效開始,音調為 40 (hex) ,音量為 7F (hex)
560 80 3C 004音效時間長度 為 60 (hex) ,停止音調為 3C (hex) 的音效,結束 Event
700 80 40 004音效時間長度 為 60+0 (hex) ,停止音調為 40 (hex) 的音效,結束 Event

Meta Event 有多種設定形式
Meta Event = FF + 資料類型 + 資料長度 + 資料參數
以下表單為概要
部分十六進制資料位元組長度說明
1*1資料類型,有指點類型設值
2*1資料長度
3*1 ~ 255資料參數,若參數超越 ASCII編碼 需要使用 URL編碼 寫入
  • 00編曲號碼 ,資料長度 為 2
  • 01描述資料
  • 02版權資訊
  • 03音軌名稱
  • 04樂器名稱
  • 05當前歌詞
  • 06 未了解使用方法
  • 07 未了解使用方法
  • 08 未了解使用方法
  • 09 未了解使用方法
  • 20 未了解使用方法
  • 21 未了解使用方法
  • 2F音軌結束 ,資料長度 為 0 ,沒有參數
  • 51Tempo ,資料長度 為 3 ,三個參數為 Micro Tempo
    MIDI 實際並不是以 五線譜 的 Tempo 計算速度,而是使用 Beats Per Minute (BPM) 來計算
    60BPM = 1秒 = 1個四分音符(或四分休止符)
    微秒 除以 Beats 計算出 Micro Tempo
    例如 60BPM , 1分鐘 = 60秒 = 60000000微秒 / 60 Beats = 1000000 Micro Tempo , 1000000 (dec) = 0F4240 (hex)
    因此使用 60BPM 需要寫成 FF 51 03 0F 42 40 ,預設為 60BPM
  • 54SMPTE偏移值 未了解使用方法
  • 58拍號 ,資料長度 為 4
    1. 第一個參數為 分子 ,表示每節有多少拍
    2. 第二個參數為 分母 ,以 2n 方式為一拍,例如 2 為 四分一拍, 3 為 八分一拍,如此類推
    3. 第三個參數為 MIDI Clock ,以 四分一拍(2) 為 24 (dec) = 18 (hex) TPQN ,八分一拍(3) 為 36 (dec) = 24 (hex) TPQN ,如此類推
      資料為 0 時會自動計算,預設為 四四拍
    4. 第四個參數通常為 固定值 8 ,某些 編曲器 會不同
  • 59變調 ,資料長度 為 2
    1. 第一個參數為 調號 為 -7 ~ 7
      0 為 沒有調號 , 1 ~ 7 為 Sharp數量 , -1 ~ -7 為 Flat數量
      Sharp 是正數,沒有特殊設定,但 Flat 是負數,便需要使用 Two's Complement 來計算
      十進制資料十六進制資料大調小調
      707升C升A
      606升F升D
      505B升G
      404E升C
      303A升F
      202DB
      101GE
      000CA
      -1FFFD
      -2FE降BG
      -3FD降EC
      -4FC降AF
      -5FB降D降B
      -6FA降G降E
      -7F9降C降A
      預設為 沒有調號
    2. 第二個參數為 譜號
      0 為 高音譜號 , 1 為 低音譜號
      預設為 高音譜號
  • 7F 未了解使用方法

樂器表,數值為 00 (hex) ~ 7F (hex)
十六進制樂器種類樂器
00鋼琴平台鋼琴
01鋼琴亮音鋼琴
02鋼琴電鋼琴
03鋼琴酒吧鋼琴
04鋼琴電子鋼琴1
05鋼琴電子鋼琴2
06鋼琴大鍵琴
07鋼琴電翼琴
08高定音敲擊樂器鋼片琴
09高定音敲擊樂器鐘琴
0A高定音敲擊樂器音樂盒
0B高定音敲擊樂器顫音琴
0C高定音敲擊樂器馬林巴琴
0D高定音敲擊樂器木琴
0E高定音敲擊樂器管鐘
0F高定音敲擊樂器揚琴
10風琴音栓風琴
11風琴敲擊風琴
12風琴搖滾風琴
13風琴教堂管風琴
14風琴簧風琴
15風琴手風琴
16風琴口琴
17風琴探戈手風琴
18結他尼龍弦木結他
19結他鋼弦木結他
1A結他爵士樂電結他
1B結他原音電結他
1C結他悶音電結他
1D結他破音電結他
1E結他失真音電結他
1F結他泛音結他
20低音結他民謠低音結他
21低音結他指奏低音電結他
22低音結他撥奏低音電結他
23低音結他無格低音結他
24低音結他捶鈎低音結他1
25低音結他捶鈎低音結他2
26低音結他合成低音結他1
27低音結他合成低音結他2
28弦樂器小提琴
29弦樂器中提琴
2A弦樂器大提琴
2B弦樂器低音大提琴
2C弦樂器顫弓弦樂
2D弦樂器彈撥弦樂
2E弦樂器豎琴
2F弦樂器定音鼓
30合奏弦樂合奏1
31合奏弦樂合奏2
32合奏合成弦樂1
33合奏合成弦樂2
34合奏人聲「啊」
35合奏人聲「喔」
36合奏合成人聲
37合奏打擊交響樂
38銅管樂器小號
39銅管樂器長號
3A銅管樂器大號
3B銅管樂器悶音小號
3C銅管樂器法國號
3D銅管樂器銅管樂
3E銅管樂器合成銅管1
3F銅管樂器合成銅管2
40簧管樂器高音色士風
41簧管樂器中音色士風
42簧管樂器次中音色士風
43簧管樂器上低音色士風
44簧管樂器雙簧管
45簧管樂器英國管
46簧管樂器低音管
47簧管樂器單簧管
48吹管樂器短笛
49吹管樂器長笛
4A吹管樂器直笛
4B吹管樂器排笛
4C吹管樂器瓶笛
4D吹管樂器尺八
4E吹管樂器哨子
4F吹管樂器陶笛
50合成音主旋律方波
51合成音主旋律鋸齒波
52合成音主旋律汽笛風琴
53合成音主旋律合成吹管
54合成音主旋律合成電結他
55合成音主旋律人聲鍵盤
56合成音主旋律五度音
57合成音主旋律低音結他主結他合奏
58合成音和弦新世紀
59合成音和弦溫暖
5A合成音和弦多重合音
5B合成音和弦人聲合唱
5C合成音和弦玻璃
5D合成音和弦金屬
5E合成音和弦光華
5F合成音和弦掃掠
60合成音效下雨
61合成音效電影音效
62合成音效水晶
63合成音效氣氛
64合成音效明亮
65合成音效魅影
66合成音效回音
67合成音效科幻
68民族樂器西塔琴
69民族樂器五弦琴
6A民族樂器三味線
6B民族樂器古箏
6C民族樂器卡林巴鐵片琴
6D民族樂器蘇格蘭風笛
6E民族樂器古提琴
6F民族樂器獸笛
70打擊樂器叮噹鈴
71打擊樂器阿哥哥鈴
72打擊樂器鋼鼓
73打擊樂器木魚
74打擊樂器太鼓
75打擊樂器定音筒鼓
76打擊樂器合成鼓
77打擊樂器逆轉鈸聲
78音效結他滑弦雜音
79音效呼吸雜音
7A音效海岸
7B音效鳥鳴
7C音效電話鈴聲
7D音效直升機
7E音效拍手
7F音效槍聲

聲調表,數值為 00 (hex) ~ 7F (hex)
度數CC# / CbDD# / EbEFF# / GbGG# / AbAA# / BbB
-1000102030405060708090A0B
00C0D0E0F1011121314151617
118191A1B1C1D1E1F20212223
22425262728292A2B2C2D2E2F
3303132333435363738393A3B
43C *3D3E3F4041424344454647
548494A4B4C4D4E4F50515253
65455565758595A5B5C5D5E5F
7606162636465666768696A6B
86C6D6E6F7071727374757677
978797A7B7C7D7E7F
* 3C 為 Middle C

以下是一個利用 Bash 建立 一個擁有 Middle C 四分音符 的 MIDI檔案 示範
output='test.mid'
printf '' >"${output}"
for b in \
4D 54 68 64 \
00 00 00 06 \
00 01 \
00 01 \
00 60 \
4D 54 72 6B \
00 00 00 0C \
00 90 3C 7F 60 80 3C 00 \
00 FF 2F 00 \
; do
    printf "\\x${b}" >>"${output}"
done
便是最簡單的 MIDI 格式

沒有留言 :

發佈留言