MIDI文件由兩部分構(gòu)成:Header Chunk(MThd)+ Track Chunk(MTrk)
“Chunk”是一種數(shù)據(jù)結(jié)構(gòu),每個(gè)chunk由最初4字節(jié)的“Chunk類(lèi)型”叛拷,緊接著4字節(jié)的“Chunk大小”,和最后長(zhǎng)度可變的“Chunk數(shù)據(jù)”構(gòu)成缀踪。注意,“Chunk大小”描述的是“Chunk 數(shù)據(jù)”的長(zhǎng)度虹脯,而不是整個(gè)Chunk的長(zhǎng)度驴娃。
用編輯器打開(kāi)JSB Chorales數(shù)據(jù)集中的一個(gè)midi文件,截取前8行顯示如下:
4d54 6864 0000 0006 0000 0001 0064 4d54
726b 0000 03a9 00c0 0000 903c 5a00 903f
5a00 9043 5a00 9048 5a78 803f 0000 904b
5a78 803c 0000 8043 0000 8048 0000 9037
5a00 9046 5a78 8037 0000 8046 0000 9038
5a00 9048 5a00 904d 5a78 8038 0000 8048
0000 804b 0000 903a 5a00 9046 5a00 904a
5a78 803a 0000 804a 0000 804d 0000 903f
這是midi文件的十六進(jìn)制代碼循集。
每一個(gè)十六進(jìn)制代碼能表示4bit唇敞,
1 byte(字節(jié))=8bit,1 word(字)=2 byte暇榴,
因此4d
這樣的兩個(gè)十六進(jìn)制代碼就是1 byte
厚棵,
而4d54
這樣的四個(gè)十六進(jìn)制代碼就是1 word
。
MThd
在每個(gè) Midi 文件的開(kāi)頭都有如下內(nèi)容,它們的十六進(jìn)制代碼為
4d54 6864 0000 0006 ffff nnnn dddd
對(duì)應(yīng)例中的
4d54 6864 0000 0006 0000 0001 0064
其中蔼紧,
4d54 6864
是ACSII表示的“MThd”字符串婆硬,表示構(gòu)成MIDI文件的Chunk類(lèi)型是文件頭(Header Chunk)。
0000 0006
是MThd中數(shù)據(jù)部分的長(zhǎng)度奸例,以目前標(biāo)準(zhǔn)均為6字節(jié)彬犯,也就是接下來(lái)的ffff nnnn dddd
向楼。
補(bǔ)充:
nnnn
值表示文件中有多少個(gè)MTrk塊。對(duì)于MIDI 0格式文件谐区,nnnn
值僅為0001湖蜕,即只有一個(gè)Track Chunk;MIDI 1格式文件則可以有多個(gè)Track Chunk宋列,而且Track Chunk數(shù)目為實(shí)際的音軌數(shù)目加一昭抒;MIDI 2格式文件不常見(jiàn),不了解炼杖。
補(bǔ)充2: dddd
值多采用TPQN時(shí)間度量法灭返。TPQN是“Ticks Per Quarter-Note(每四分音符中所包含的Midi Tick數(shù)量)”的縮寫(xiě),可以是十進(jìn)制的60-480之間坤邪,數(shù)值越大熙含,MIDI系統(tǒng)的時(shí)間分辨率就越大,也就是說(shuō)可以演奏時(shí)值越小的音符艇纺。通常這個(gè)數(shù)都采用120怎静、240、480黔衡,因?yàn)檫@些數(shù)都能被2蚓聘、3、4甚至6员帮、8整除或粮,方便于八分音符、十六分音符捞高、三連音甚至更短音符的演奏,換算成十六進(jìn)制渣锦,就是0x78硝岗、0xF0、0x1E0袋毙。當(dāng)然注意型檀,這些十六進(jìn)制數(shù)的最高位都是0。dddd
值如果大于0x8000听盖,則為SMPTE時(shí)間碼度量法胀溺,這里不詳細(xì)介紹了。
MTrk
MTrk(Track Chunk)內(nèi)部則包含了實(shí)際的MIDI信息和一些輔助信息皆看,如meta-event仓坞。還是以上面的midi文件為例:
4d54 726b
是MTrk的開(kāi)頭,也就是“MTrk”的ASCII編碼腰吟。
0000 03a9
是MTrk數(shù)據(jù)部分的大形薨!(非固定)徙瓶,這里轉(zhuǎn)化為十進(jìn)制是937。接下來(lái)就是937字節(jié)的數(shù)據(jù)嫉称。
xxyy xxyyyy ... ...
xx代表了Delta-time侦镇,yy代表了真正的MIDI事件。這些MIDI事件才是音序器在播放MIDI文件時(shí)需要實(shí)時(shí)處理和發(fā)送的數(shù)據(jù)织阅。
00ff 2f00
是meta-event事件壳繁,表示此Track結(jié)束。
- Delta-time:時(shí)間差荔棉,表征著當(dāng)前事件距離上一個(gè)事件有多長(zhǎng)時(shí)間闹炉,單位為tick。音序器通過(guò)對(duì)MIDI Tick進(jìn)行計(jì)數(shù)江耀,判斷是否該處理下一個(gè)MIDI事件剩胁。Delta-time使用可變長(zhǎng)度數(shù)的格式,最短1個(gè)字節(jié)祥国,最長(zhǎng)4個(gè)字節(jié)(最長(zhǎng)可以表示0x0fffffff)昵观。具體來(lái)說(shuō),一個(gè)字節(jié)有 8 bit舌稀,將其最高位bit作為標(biāo)志位啊犬,剩下7 bit就可以表示 0~127。如果Delta-time值超過(guò)127壁查,就將標(biāo)志位設(shè)置為1觉至,并且下一個(gè)字節(jié)用來(lái)繼續(xù)表示Delta-time。只要標(biāo)志位為 0睡腿,則表示結(jié)束讀取Delta-time语御。
- MIDI事件:MIDI事件包括1.實(shí)際需要發(fā)送的數(shù)據(jù)(音序器直接將數(shù)據(jù)發(fā)送出去);2.meta-event事件(音序器修改自身的相關(guān)參數(shù))席怪。
MIDI事件
下表中,x 表示音軌 0~F,比如 90 表示按下第一軌的音符应闯。在例中,接下來(lái)的MIDI編碼為:
---- ---- ---- 00c0 0000 903c 5a00 903f
5a00 9043 5a00 9048 5a-- ---- ---- ----
解析如下:
00 c0 00
:時(shí)間差00挂捻,改變第一軌樂(lè)器碉纺,樂(lè)器號(hào)碼為00
00 90 3c 5a
:時(shí)間差00,按下第一軌音符刻撒,音符號(hào)碼為3c(60骨田,C4,中央C)声怔,力度為5a(90)
00 90 3f 5a
:時(shí)間差00态贤,按下第一軌音符,音符號(hào)碼為3f(63捧搞,#D4)抵卫,力度為5a(90)
00 90 43 5a
:時(shí)間差00狮荔,按下第一軌音符,音符號(hào)碼為43(67介粘,G4)殖氏,力度為5a(90)
00 90 48 5a
:時(shí)間差00,按下第一軌音符姻采,音符號(hào)碼為48(72雅采,C5),力度為5a(90)
78 80 3f 00
:時(shí)間差78(120tick)慨亲,松開(kāi)第一軌音符婚瓜,音符號(hào)碼為3f(63,#D4)刑棵,力度為5a(90)
00 90 4b 5a
:時(shí)間差00巴刻,按下第一軌音符,音符號(hào)碼為4b(75蛉签,#D5)胡陪,力度為5a(90)
78 80 3c 00
:時(shí)間差78(120tick),松開(kāi)第一軌音符碍舍,音符號(hào)碼為3c(60柠座,C4),力度為00
00 80 43 00
:時(shí)間差00片橡,松開(kāi)第一軌音符妈经,音符號(hào)碼為43(67,G4)捧书,力度為00
00 80 48 00
:時(shí)間差00吹泡,松開(kāi)第一軌音符,音符號(hào)碼為48(72经瓷,C5)荞胡,力度為00
00 90 37 5a
:時(shí)間差00,按下第一軌音符了嚎,音符號(hào)碼為37(55,G3)廊营,力度為5a(90)
00 90 46 5a
:時(shí)間差00歪泳,按下第一軌音符,音符號(hào)碼為46(70露筒,#A4)呐伞,力度為5a(90)
總結(jié)
參考鏈接
https://www.cnblogs.com/us-wjz/articles/11618899.html
https://blog.csdn.net/tiankong_/article/details/78754545
https://www.bilibili.com/read/cv1753143/