Standard MIDI File Format
Dustin Caldwell
Das Standard-MIDI-Format ist sehr widerspänstig. Betrachtet als ein Ganzes ist es ziemlich überwältigend. Egal, wie man es sieht, eine Musiksequenz so genau zu beschreiben, dass man es 1:1 wiedergeben kann ist keine einfache Sache. Trotz dieser Schwierigkeit ist der Aufbau des MIDI-Formates recht gut nachvollziehbar, wenn es einmal verstanden worden ist.
An diesem Punkt muss ich sagen, dass ich keinesfalls ein Profi in Sachen MIDI oder MIDI-Dateien bin. Ich habe eine Gravis UltraSound Karte für meinen PC und nachdem ich ein paar Mididateien (.MID) gehört hatte, dachte ich "Ich würde gerne meine eigenen Mididateien machen". Mehrere nervenzerreißende Stunden später bemerkte ich, dass das wirklich ein hartes Stück Arbeit ist. Aber ich konnte einfach nicht zulassen, dass mich so ein "dummes" Dateiformat stoppt :)! Falls ihr irgendwelche Fehler in diesem Dokument findet, lasst es mich wissen und ich werde diesen Fehler beheben. Dieses Dokument beschreibt desweiteren nicht JEDES vorhandene Midi-Format und auch nicht jedes Midi-Kommando. Es ist nur ein Basisdokument aus dem ein recht guter Midi-Player und Editor herauskommen soll :)!
1. Übersicht
Eine Midi-Datei (.MID) besteht aus 2 Teilen, Header-Chunks und Track-Chunks. Eine Midi-Datei enthält EINEN Header-Chunk, der das Dateiformat angibt usw. und eine bestimmte Anzahl an Track-Chunks.
2. Header Chunk
Der Header-Chunk befindet sich am Dateianfang und beschreibt die Datei in 3 Formen. Der Header-Chunk sieht immer so aus:
4D 54 68 64 00 00 00 06 ff ff nn nn dd dd
Das ASCII-Äquivalent der ersten 4 Bytes ist "MThd". Nach dem "MThd" folgt die 4-Byte-Größe des Headers. Dieser Wert beträgt immer 00 00 00 06, da der .Mid-Header immer eine größe von 6 Bytes hat.
ff: ff gibt das Dateiformat an. Es gibt 3 Formate:
0 - eine Spur
1 - mehrere Spuren, synchron
2 - mehrere Spuren, nicht synchron
"Eine Spur" ist eigentlich selbsterklärend - es kommt halt nur eine Spur im .MID vor. "Mehrere Spuren, synchron" heißt, dass alle Spuren synchron gespielt werden, in anderen Worten, sie starten alle gleichzeitig. Nicht-synchrone Spuren müssen nicht unbedingt gleichzeitig starten und können absolut asynchron sein.
nn: nn gibt die Anzahl der Tracks in einer MIDI-Datei an.
dd: dd gibt die Anzahl der Delta-time Ticks pro Viertelnote an (mehr dazu später)
3. Der Track-Chunk:
Der Rest einer MID-Datei nach dem Header-Chunk besteht aus Track-Chunks. Jeder Track hat einen Header und kann so viele MIDI-Kommandos enthalten wie nötig.
Der Kopf eines Tracks ähnelt sehr dem Datei-Header:
4D 54 72 6B xx xx xx xx
Wie der Header besitzen die ersten 4 Byte ein ASCII-Äquivalent. Dieses mal ist es "MTrk". Die 4 Bytes nach "MTrk" beschreibt die Länge des Tracks (ohne den Track-Kopf) in Bytes.
Danach kommen Midi-Ereignisse. Diese Ereignisse sind identisch zu den Daten, die von MIDI-Ports auf einem Synthesizer geliefert werden, jedoch mit einem Unterschied. Vor dem Midi-Ereignis steht eine Delta-Zeit. Eine Delta-Zeit gibt die Anzahl an Ticks an, nach denen ein Midi-Ereignis ausgeführt werden soll. Die Anzahl der Ticks pro Viertelnote wurde vorher im Datei-Header-Chunk festgelegt. Diese Delta-Zeit ist ein Variablen-Längen-Verschlüsselter-Wert :). Dieses Format kann zwar verwirren, hat aber den Vorteil, dass keine kleinen Zahlen benötigt werden, die sinnlos Bytes verschwenden. Die Zahl wird konvertiert in ein 7-bit-Byte, wobei das höerwertiges Bit jedes Bytes "1" beträgt, bis auf das letzte Byte der Nummer, das ein MSB (Most Significant Bit = Höherwertiges Bit [ganz links]) von 0 hat. Dieses erlaubt, dass mit einem mal 1 Byte gelesen werden kann. Wenn ein MBS von 0 erscheint, muss dies das letzte Byte der Nummer gewesen sein. Die Delta-Zeit sollte mindestens 4 Bytes lang sein. Darauf folgt ein Midi-Ereignis. Jedes MIDI-Ereignis besitzt ein Kommandobyte, dass ein MSB von 1 besitzt ( der Wert ist dann >=128). Eine Liste für vieler dieser Kommandos befindet sich in Anhang A. Jedes Kommando hat verschiedene Parameter und Längen, aber die Daten, die dann folgen haben immer ein MSB von 0 (<128). Die Ausnahme hierzu ist ein Meta-Ereignis, die Daten mit einem MSB von 1 haben. Wie auch immer, Meta-Ereignisse benötigen einen Längenparameter, die Verwirrung vermeiden sollen.
Eine Feinheit, die für Verwirrung sorgen kann, ist der sog. "running mode". Das passiert, wenn das aktuelle Midi-Kommando weggelassen wird. Das heißt, dass das MIDI-Ereignis aus einer Delta-Zeit und ein einem Parameter, der zu dem Kommando leiten würde, währe dieses einbezogen, besteht :).
4. Ende
Falls diese Erklärung nur für nochmehr Verwirrung über dieses Thema gesorgt haben sollte, enthalten die Anhänge Beispiele, die dem besseren Verständnis dienen sollten.
Anhang A: Midi-Ereignis Kommandos
jedes MIDI-Kommando hat 2 Teile. Der linken Nibble (Ein Nibble = 4 Bit) enthält das Kommando und rechte Nibble enthält den Kanal auf welchem das Kommando ausgeführt werden soll. Es gibt 16 Midi-Kanäle und 8 Midi-Kommandos (das Kommandonybble muss einen MSB von 1 haben). In der folgenden Tabelle gibt "x" den Kanal an.
Hex | Binär | Daten | Beschreibung |
8x | 1000xxxx | nn vv | Note aus nn=Noten-Nummer vv=Geschwindigkeit |
9x | 1001xxxx | nn vv | Note an nn=Noten-Nummer vv=Geschwindigkeit |
Ax | 1010xxxx | nn vv | Noten-Abklingen nn=Note vv=Geschwindikkeit |
Bx | 1011xxxx | cc vv | Kontrolländerung cc=Kontrollnummer vv=Neuer Wert |
Cx | 1101xxxx | cc | Kanalausklang cc=Kanalnummer |
Ex | 1110xxxx | bb tt | Tonhöhenänderung bb=Boden tt=Höchster Wert |
Die folgende Tabelle zeigt Meta-Ereignisse, die keine Midi-Kanal.Nummer haben. Sie haben folgendes Format:
FF xx nn dd
Alle Meta-Ereignisse starten mit FF (#255), gefolgt vom Kommando (xx)m der Länge oder der Anzahl an Bytes, die die Daten enthalten (nn) und den eigentlichen Daten (dd).
Hex | Binär | Daten | Beschreibung |
00 | 00000000 | nn ssss | Setzt die Sequenz der Spur. nn=02 (Länge der 2-Byte Sequenznummer) ssss=Sequenznummer |
01 | 00000001 | nn tt .. | Text. nn=Länge in Bytes des Textes tt=eigentlicher Text |
02 | 00000010 | nn tt .. | Das gleiche wie "Text", aber benutzt als Copyright-info. nn tt=genauso wie im Textereignis |
03 | 00000011 | nn tt .. | Sequenz oder Spurenname. nn tt=genauso wie im Textereignis |
04 | 00000100 | nn tt .. | Spuren-Instrumenten -Name nn tt=genauso wie im Textereignis |
05 | 00000101 | nn tt .. | Lyrik nn tt=genauso wie im Textereignis |
06 | 00000110 | nn tt .. | Marker nn tt=genauso wie im Textereignis |
07 | 00000111 | nn tt .. | Hinweis nn tt=genauso wie im Textereignis |
2F | 00101111 | 00 | Dieses Ereignis muss am Ende jeder Spur kommen. |
51 | 01010001 | 03 tttttt | Neues Tempo tttttt=mikrosekunden/Viertelnote |
58 | 01011000 | 04 nn dd ccbb | Zeit Signatur ("Notenschlüssel") nn=Zähler der Zeitsignatur. dd=Nenner der Zeitsignatur. 2=viertel 3=achtel, usw. cc=Anzahl Ticks in einem Metronomschlag bb=anzahl 32tel-Noten zu einer Viertelnode |
59 | 01011001 | 02 sf mi | Feinabstimmung sf=(>128)Ton erhöhen/(<128) Ton niedersetzen 7=7 sharps) mi=hoch/tief (0=hoch, 1=tief) |
7F | 01111111 | xx dd .. | Sequenzinformationen xx=Anzahl an zu sendenden Bytes dd=Daten |
Die folgende Liste zeigt Systemnachichten, die seiner Kontrolle dienen. Sie haben keine MIDI-Kanal-Nummer. (Normalerweise kommen sie nur vor, um ein KeyBoard zu kontrollieren usw.)
Hex | Binär | Daten | Beschreibung |
F8 | 11111000 | Pause, falls eine Synchronisation notwendig ist | |
FA | 11111010 | Starte Sequenz | |
FB | 11111011 | Spiele gestoppte Sequenz weiter | |
FC | 11111100 | Sequenz anhalten |
Die folgende Tabelle zeigt, welche Nummern für welche Noten stehen
Oktave|| Notennummer # || || 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 |
QUELLEN
"MIDI Systems and Control" Francis Rumsey 1990 Focal Press
"MIDI and Sound Book for the Atari ST" Bernd Enders and Wolfgang Klemme
1989 M&T Publishing, Inc.
MIDI file specs and general MIDI specs were also obtained by sending e-mail
to LISTSERV@AUVM.AMERICAN.EDU with the phrase GET MIDISPEC PACKAGE
in the message.
--------------------- ORIGINAL-TEXT ------------------------- Standard MIDI File Format Dustin Caldwell The standard MIDI file format is a very strange beast. When viewed as a whole, it can be quite overwhelming. Of course, no matter how you look at it, describing a piece of music in enough detail to be able to reproduce it accurately is no small task. So, while complicated, the structure of the midi file format is fairly intuitive when understood. I must insert a disclaimer here that I am by no means an expert with midi nor midi files. I recently obtained a Gravis UltraSound board for my PC, and upon hearing a few midi files (.MID) thought, "Gee, I'd like to be able to make my own .MID files." Well, many aggravating hours later, I discovered that this was no trivial task. But, I couldn't let a stupid file format stop me. (besides, I once told my wife that computers aren't really that hard to use, and I'd hate to be a hypocrite) So if any errors are found in this information, please let me know and I will fix it. Also, this document's scope does not extend to EVERY type of midi command and EVERY possible file configuration. It is a basic guide that should enable the reader (with a moderate investment in time) to generate a quality midi file. 1. Overview A midi (.MID) file contains basically 2 things, Header chunks and Track chunks. Section 2 explains the header chunks, and Section 3 explains the track chunks. A midi file contains ONE header chunk describing the file format, etc., and any number of track chunks. A track may be thought of in the same way as a track on a multi-track tape deck. You may assign one track to each voice, each staff, each instrument or whatever you want. 2. Header Chunk The header chunk appears at the beginning of the file, and describes the file in three ways. The header chunk always looks like: 4D 54 68 64 00 00 00 06 ff ff nn nn dd dd The ascii equivalent of the first 4 bytes is MThd. After MThd comes the 4-byte size of the header. This will always be 00 00 00 06, because the actual header information will always be 6 bytes. ff ff is the file format. There are 3 formats: 0 - single-track 1 - multiple tracks, synchronous 2 - multiple tracks, asynchronous Single track is fairly self-explanatory - one track only. Synchronous multiple tracks means that the tracks will all be vertically synchronous, or in other words, they all start at the same time, and so can represent different parts in one song. Asynchronous multiple tracks do not necessarily start at the same time, and can be completely asynchronous. nn nn is the number of tracks in the midi file. dd dd is the number of delta-time ticks per quarter note. (More about this later) 3. Track Chunks The remainder of the file after the header chunk consists of track chunks. Each track has one header and may contain as many midi commands as you like. The header for a track is very similar to the one for the file: 4D 54 72 6B xx xx xx xx As with the header, the first 4 bytes has an ascii equivalent. This one is MTrk. The 4 bytes after MTrk give the length of the track (not including the track header) in bytes. Following the header are midi events. These events are identical to the actual data sent and received by MIDI ports on a synth with one addition. A midi event is preceded by a delta-time. A delta time is the number of ticks after which the midi event is to be executed. The number of ticks per quarter note was defined previously in the file header chunk. This delta-time is a variable-length encoded value. This format, while confusing, allows large numbers to use as many bytes as they need, without requiring small numbers to waste bytes by filling with zeros. The number is converted into 7-bit bytes, and the most-significant bit of each byte is 1 except for the last byte of the number, which has a msb of 0. This allows the number to be read one byte at a time, and when you see a msb of 0, you know that it was the last (least significant) byte of the number. According to the MIDI spec, the entire delta- time should be at most 4 bytes long. Following the delta-time is a midi event. Each midi event (except a running midi event) has a command byte which will always have a msb of 1 (the value will be >= 128). A list of most of these commands is in appendix A. Each command has different parameters and lengths, but the data that follows the command will have a msb of 0 (less than 128). The exception to this is a meta- event, which may contain data with a msb of 1. However, meta-events require a length parameter which alleviates confusion. One subtlety which can cause confusion is running mode. This is where the actual midi command is omitted, and the last midi command issued is assumed. This means that the midi event will consist of a delta-time and the parameters that would go to the command if it were included. 4. Conclusion If this explanation has only served to confuse the issue more, the appendices contain examples which may help clarify the issue. Also, 2 utilities and a graphic file should have been included with this document: DEC.EXE - This utility converts a binary file (like .MID) to a tab-delimited text file containing the decimal equivalents of each byte. REC.EXE - This utility converts a tab-delimited text file of decimal values into a binary file in which each byte corresponds to one of the decimal values. MIDINOTE.PS - This is the postscript form of a page showing note numbers with a keyboard and with the standard grand staff. Appendix A 1. MIDI Event Commands Each command byte has 2 parts. The left nybble (4 bits) contains the actual command, and the right nybble contains the midi channel number on which the command will be executed. There are 16 midi channels, and 8 midi commands (the command nybble must have a msb of 1). In the following table, x indicates the midi channel number. Note that all data bytes will be <128 (msb set to 0). Hex Binary Data Description 8x 1000xxxx nn vv Note off (key is released) nn=note number vv=velocity 9x 1001xxxx nn vv Note on (key is pressed) nn=note number vv=velocity Ax 1010xxxx nn vv Key after-touch nn=note number vv=velocity Bx 1011xxxx cc vv Control Change cc=controller number vv=new value Cx 1100xxxx pp Program (patch) change pp=new program number Dx 1101xxxx cc Channel after-touch cc=channel number Ex 1110xxxx bb tt Pitch wheel change (2000H is normal or no change) bb=bottom (least sig) 7 bits of value tt=top (most sig) 7 bits of value The following table lists meta-events which have no midi channel number. They are of the format: FF xx nn dd All meta-events start with FF followed by the command (xx), the length, or number of bytes that will contain data (nn), and the actual data (dd). Hex Binary Data Description 00 00000000 nn ssss Sets the track's sequence number. nn=02 (length of 2-byte sequence number) ssss=sequence number 01 00000001 nn tt .. Text event- any text you want. nn=length in bytes of text tt=text characters 02 00000010 nn tt .. Same as text event, but used for copyright info. nn tt=same as text event 03 00000011 nn tt .. Sequence or Track name nn tt=same as text event 04 00000100 nn tt .. Track instrument name nn tt=same as text event 05 00000101 nn tt .. Lyric nn tt=same as text event 06 00000110 nn tt .. Marker nn tt=same as text event 07 00000111 nn tt .. Cue point nn tt=same as text event 2F 00101111 00 This event must come at the end of each track 51 01010001 03 tttttt Set tempo tttttt=microseconds/quarter note 58 01011000 04 nn dd ccbb Time Signature nn=numerator of time sig. dd=denominator of time sig. 2=quarter 3=eighth, etc. cc=number of ticks in metronome click bb=number of 32nd notes to the quarter note 59 01011001 02 sf mi Key signature sf=sharps/flats (-7=7 flats, 0=key of C, 7=7 sharps) mi=major/minor (0=major, 1=minor) 7F 01111111 xx dd .. Sequencer specific information xx=number of bytes to be sent dd=data The following table lists system messages which control the entire system. These have no midi channel number. (these will generally only apply to controlling a midi keyboard, etc.) Hex Binary Data Description F8 11111000 Timing clock used when synchronization is required. FA 11111010 Start current sequence FB 11111011 Continue a stopped sequence where left off FC 11111100 Stop a sequence The following table lists the numbers corresponding to notes for use in note on and note off commands. Octave|| Note Numbers # || || 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 | BIBLIOGRAPHY "MIDI Systems and Control" Francis Rumsey 1990 Focal Press "MIDI and Sound Book for the Atari ST" Bernd Enders and Wolfgang Klemme 1989 M&T Publishing, Inc. MIDI file specs and general MIDI specs were also obtained by sending e-mail to LISTSERV@AUVM.AMERICAN.EDU with the phrase GET MIDISPEC PACKAGE in the message. ------------------------------- DEC.CPP ------------------------------------ /* file dec.cpp by Dustin Caldwell (dustin@gse.utah.edu) */ #include#include #include 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 (dustin@gse.utah.edu)\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 (dustin@gse.utah.edu) */ #include #include #include #include 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 (dustin@gse.utah.edu)\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"); }