我想寫一個工具,把mid格局的音樂在sega genesis上播放,mid文件的格局如下:
1.概述:
一個MIDI文件基礎上由兩個部分組成,頭塊和軌道塊。第二節講述頭塊,第三節講述軌
道塊。一個MIDI文件有一個頭塊用來描寫文件的格局、許多的軌道塊等內容。一個軌道可以
想象為像一個大型多音軌錄音機那樣,你可認為某種聲音、某種樂譜、某種樂器或者你需要
的任何東西分配一個軌道。
2.頭塊:
頭塊呈現在文件的開頭,有三種方法來描寫文件。頭塊看起來一直是這樣的:
4D 54 68 64 00 00 00 06 ff ff nn nn dd dd
前4個字節等同於ASCII碼MThd,接著MThd之後的4個字節是頭的大小。它將一直是00
00 00 00 06,由於現行的頭信息將一直是6字節。
ff ff是文件的格局,有3種格局:
0-單軌
1-多規,同步
2-多規,異步
單軌,很顯然就只有一個軌道。同步多軌意味著所有軌道都是垂直同步的,或者其他的
措辭為他們都在同一時間開端,並且可以表現一首歌的不同部分。異步多軌沒有必要同時開
始,而且可以完整的不同步。
nn nn 是MIDI文件中的軌道數。
dd dd 是每個4分音符delta-time節奏數(這之後將做具體先容)。
3.軌道塊:
頭塊之後剩下的文件部分是軌道塊。每一個軌道包含一個頭,並且可以包含你所希看的
許多MIDI命令。軌道頭與文件頭及其類似:
4D 54 72 6B xx xx xx xx
與頭一致,前4個字節是ASCII嗎,這個是MTrk,緊跟MTrk的4個字節給出了以字節為單
位的軌道的長度(不包含軌道頭)。
在頭之下是MIDI事件,這些事件同現行的可以被帶有累加的MIDI合成器端口接收和發送
的數據是雷同的。一個MIDI 事件先於一個delta-time。一個delta-time是一個MIDI事件被
履行後的節奏數,每個四分之一音符的節奏數先前已經定義在了文件的頭塊中。這個delta-
time是一個可變長度的編碼值。這種格局固然混亂,可是答應根據需要利用多位表現較大的
數值,這不會由於需求小的數值情況下以添零的方法浪費掉一些字節!數值被轉換為7位的
字節,並且除了最後一個字節以最高有效位是0外,各個字節最有意義的一位是1,。這就允
許一個數值被一次一個字節地讀取,你假如發明最高有效位是0,則這就是這個數值的最後
一位(意義比擬小)。按照MIDI闡明,全部delta-time的長度最多超過4字節。
delta-time 之後就是MIDI事件,每個MIDI事件(除了正在運行的事件外)帶有一個最
高有效位總是1的命令字節(值將>128)。大部分命令的列表在附錄A中。每個命令都有不同
Bx 1011***x cc vv 調換把持
cc=把持號
vv=新值
Cx 1100***x pp 轉變程序(片段)
pp=新的程序號
Dx 1101***x cc 在通道後接觸
cc=管道號
Ex 1110***x bb tt 轉變互相咬和的齒輪 (2000H 表明缺省或沒有轉變)
(什麼意思搞不懂:)
bb=值的低7位(least sig)
tt=值的高7位 (most sig)
下表是沒有通道的 meta-events列表 ,他們的格局是:
FF xx nn dd
所有的 meta-events 是以 FF 開頭的命令 (xx),長度,或者含在數據的字節數(nn),
現行的數據(dd)
十六進制 二進制 數據 描寫
00 00000000 nn ssss 設定軌道的序號
nn=02 (兩字節長度的序號)
ssss=序號
01 00000001 nn tt .. 你需要的所有文本事件
nn=以字節為單位的文本長度
tt=文本字符
3=8分拍, 等等.
cc=節拍器的節奏
bb=對四分之一音符標注的第32號數字
59 01011001 02 sf mi 聲調符號
sf=升調/降調(-7=7 降調, 0=基准C調,7=7 升調)
mi=大調/小調(0=大調, 1=小調)
7F 01111111 xx dd .. 音序器的具體信息
xx=被發送的字節數
dd=數據
下表列出了把持全部系統的系統消息。這裡沒有MIDI通道數 (這些一般僅利用於MIDI鍵
盤等.)
十六進制 二進制 數據 描寫
F8 11111000 同步所必需的計時器
FA 11111010 開端當前的隊列
FB 11111011 從結束的處所持續一個隊列
FC 11111100 結束一個隊列
下表列出的是與音符相對應的命令標記。
八度音階|| 音符號
# || || C | C# | D | D# | E | F | F# | G | G# | A | A# | B
-----------------------------------------------------------------------------
0 || 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11
1 || 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23
2 || 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35
3 || 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47
4 || 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59
5 || 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71
6 || 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83
7 || 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95
8 || 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107
9 || 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119
10 || 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 |
參考材料:
"MIDI Systems and Control" Francis Rumsey 1990 Focal Press
"MIDI and Sound Book for the Atari ST" Bernd Enders and Wolfgang Klem 1989 M&T
Publishing, Inc.
MIDI file specs and general MIDI specs were also obtained by sending e-mail to
[email protected] with the phrase GET MIDISPEC PACKAGE in the message.
------------------------------ DEC.CPP ------------------------------------
/* file dec.cpp
by Dustin Caldwell ([email protected])
*/
#include <DOS.h>
#include <stdio.h>
#include <stdlib.h>
void helpdoc();
main()
{
FILE *fp;
unsigned char ch, c;
if((fp=fopen(_argv[1], "rb"))==NULL) /* open file to read */
{
printf("cannot open file %s\n",_argv[1]);
helpdoc();
exit(-1);
}
c=0;
ch=fgetc(fp);
while(!feof(fp)) /* loop for whole file */
{
printf("%u\t", ch); /* print every byte's decimal
equiv. */
c++;
if(c>8) /* print 8 numbers to a
line */
{
c=0;
printf("\n");
}
ch=fgetc(fp);
}
fclose(fp); /* close up */
}
void helpdoc() /* print help message */
{
printf("\n Binary File Decoder\n\n");
printf("\n Syntax: dec binary_file_name\n\n");
printf("by Dustin Caldwell ([email protected])\n\n");
printf("This is a filter program that reads a binary file\n");
printf("and prints the decimal equivalent of each byte\n");
printf("tab-separated. This is mostly useful when piped \n");
printf("into another file to be edited manually. eg:\n\n");
printf("c:\>dec sonata3.mid > son3.txt\n\n");
printf("This will create a file called son3.txt which can\n");
printf("be edited with any ascii editor. \n\n");
printf("(rec.exe may also be useful, as it reencodes the \n");
printf("ascii text file).\n\n");
printf("Have Fun!!\n");
}
---------------------------- REC.CPP ----------------------------------
/* File rec.cpp
by Dustin Caldwell ([email protected])
*/
#include <DOS.h>
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
void helpdoc();
main()
{
FILE *rfp, *wfp;
unsigned char ch, c;
char s[20];
if((rfp=fopen(_argv[1], "r"))==NULL) /* open the
read file */
{
printf("cannot open file %s \n",_argv[1]);
helpdoc();
exit(-1);
}
if((wfp=fopen(_argv[2], "wb"))==NULL) /* open the
write file */
{
printf("cannot open file %s \n",_argv[1]);
helpdoc();
exit(-1);
}
c=0;
ch=fgetc(rfp);
while(!feof(rfp)) /* loop for whole file */
{
if(isalnum(ch)) /* only 'see' valid ascii chars
*/
{
c=0;
while(isdigit(ch)) /* only use decimal digits (0-
9) */
{
s[c]=ch; /* build a string containing
the number */
c++;
ch=fgetc(rfp);
}
s[c]=NULL; /* must have NULL
terminator */
fputc(atoi(s), wfp);/* write the binary equivalent to file */
}
ch=fgetc(rfp); /* loop until next number
starts */
}
fclose(rfp); /* close up */
fclose(wfp);
}
void helpdoc() /* print help message */
{
printf("\n Text File Encoder\n\n");
printf("\n Syntax: rec text_file_name binary_file_name\n\n");
printf("by Dustin Caldwell ([email protected])\n\n");
printf("This is a program that reads an ascii tab-\n");
printf("delimited file and builds a binary file where\n");
printf("each byte of the binary file is one of the decimal\n");
printf("digits in the text file.\n");
printf(" eg:\n\n");
printf("c:\>rec son3.txt son3.mid\n\n");
printf("(This will create a file called son3.mid which is\n");
printf("a valid binary file)\n\n");
printf("(dec.exe may also be useful, as it decodes binary files)\n\n");
printf("Have Fun!!\n");
}