2007年11月11日星期日

Standard MIDI File Format


                                                        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   <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     (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   <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     (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");  
  }  

没有评论: