home *** CD-ROM | disk | FTP | other *** search
/ Computer Music Interactif…cial Edition 1999 Winter / cd 3.iso / mac / Mac / Shares / Midishare™1.68 / Development Tools / Libraries / MidiFiles / MidiFile.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-09  |  41.4 KB  |  1,435 lines  |  [TEXT/MPS ]

  1. /*
  2.  *
  3.  *    MIDIFILE.C
  4.  *
  5.  *    functions to read and write MIDI files
  6.  *
  7.  *    c GRAME 91-96 D. Fober
  8.  *  Please, report comments and bugs to msh@rd.grame.fr
  9.  *
  10.  * modifications history:
  11.  * v113 [April 18, 96]     DF  procedural access to MidiFile_errno and errno
  12.  *                        functions MidiFileGetMFErrno and MidiFileGetErrno.
  13.  *                        error code commented in the read_undef function
  14.  * v114 [April 30, 96]     DF  ignore META events instead reading undef
  15.  * v115 [May 8, 96]     DF  tracks marked opened at creation time 
  16.  *                        (due to corrections for Code Warrior)
  17.  *
  18.  */
  19.  
  20. #include <StdLib.h>
  21. #include <String.h>
  22.  
  23. #include "MidiFile.h"
  24.  
  25. #ifdef __Macintosh__
  26. #include <Errno.h>
  27. #endif
  28.  
  29.  
  30. /*--------------------------------------------------------------------------*/
  31. /* constants                                                                */
  32. #define MDF_MThd    "MThd"                    /* file header                    */
  33. #define MDF_MTrk    "MTrk"                    /* track header                    */
  34. #define SRC_VERSION    115                        /* source code version             */
  35. #define MDF_VERSION 100                        /* MIDI File format version     */
  36. #define offset_ntrks    10                    /* tracks count offset    related */
  37.                                             /* to the beginning of the file */
  38. #define offset_trkLen    4                    /* track length offset related    */
  39.                                             /* to the header header            */
  40.  
  41. /*--------------------------------------------------------------------------*/
  42. /* functions declaration                                                    */
  43. static MidiEvPtr mdf_ignoreEv( MIDIFilePtr fd, long len);
  44. static MidiEvPtr read_undef( MIDIFilePtr fd, short status);
  45. static MidiEvPtr read_sysex( MIDIFilePtr fd, short status);
  46. static MidiEvPtr read_2DataEv( MIDIFilePtr fd, short status);
  47. static MidiEvPtr read_1DataEv( MIDIFilePtr fd, short status);
  48. static MidiEvPtr read_0DataEv( MIDIFilePtr fd, short status);
  49. static MidiEvPtr read_text( MIDIFilePtr fd, long len, short type);
  50. static MidiEvPtr read_endTrack( MIDIFilePtr fd, long len, short);
  51. static MidiEvPtr read_tempo( MIDIFilePtr fd, long len, short);
  52. static MidiEvPtr read_keySign( MIDIFilePtr fd, long len, short);
  53. static MidiEvPtr read_timeSign( MIDIFilePtr fd, long len, short);
  54. static MidiEvPtr read_seqNum( MIDIFilePtr fd, long len, short);
  55. static MidiEvPtr read_chanPref( MIDIFilePtr fd, long len, short);
  56. static MidiEvPtr read_smpte( MIDIFilePtr fd, long len, short);
  57. static Boolean write_note( MIDIFilePtr fd, MidiEvPtr ev, short status);
  58. static Boolean write_2DataEv( MIDIFilePtr fd, MidiEvPtr ev, short status);
  59. static Boolean write_1DataEv( MIDIFilePtr fd, MidiEvPtr ev, short status);
  60. static Boolean write_0DataEv( MIDIFilePtr fd, MidiEvPtr ev, short status);
  61. static Boolean dont_write( MIDIFilePtr , MidiEvPtr , short);
  62. static Boolean write_sysex( MIDIFilePtr fd, MidiEvPtr ev, short);
  63. static Boolean write_Ctrl14b( MIDIFilePtr fd, MidiEvPtr ev, short);
  64. static Boolean write_RegP( MIDIFilePtr fd, MidiEvPtr ev, short);
  65. static Boolean write_NRegP( MIDIFilePtr fd, MidiEvPtr ev, short);
  66.  
  67. static Boolean write_SeqNum( MIDIFilePtr fd, MidiEvPtr ev, short);
  68. static Boolean write_texte( MIDIFilePtr fd, MidiEvPtr ev, short status);
  69. static Boolean write_chanPref( MIDIFilePtr fd, MidiEvPtr ev, short);
  70. static Boolean write_endTrack( MIDIFilePtr fd, MidiEvPtr, short);
  71. static Boolean write_tempo( MIDIFilePtr fd, MidiEvPtr ev, short);
  72. static Boolean write_smpte( MIDIFilePtr fd, MidiEvPtr ev, short);
  73. static Boolean write_timeSign( MIDIFilePtr fd, MidiEvPtr, short);
  74. static Boolean write_keySign( MIDIFilePtr fd, MidiEvPtr, short);
  75.  
  76.  
  77. /*--------------------------------------------------------------------------*/
  78. /* global variables                                                         */
  79.  
  80. int MidiFile_errno;                            /* for errors management        */
  81.  
  82.  
  83. typedef MidiEvPtr (* NEAR ReadFunc)    ( MIDIFilePtr fd, short status);
  84. typedef MidiEvPtr (* NEAR ReadMetaFunc)( MIDIFilePtr fd, long len, short type);
  85. typedef Boolean   (* NEAR WriteFunc)   ( MIDIFilePtr fd, MidiEvPtr ev, short status);
  86.  
  87.  
  88. /*------------------- type/status byte correspondence ---------------------*/
  89. static unsigned char codeTbl[]=
  90.     { 0x90, 0x90, 0x80, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0,
  91.       0xf2, 0xf3, 0xf8, 0xfa, 0xfb, 0xfc, 0xf6, 0xfe,
  92.       0xff, 0xf0, 0xf7
  93.     };
  94.     
  95. /*------------------- status byte/type correspondence ---------------------*/
  96. static char typeTbl[]=
  97.     { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
  98.       1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  99.       3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
  100.       4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
  101.       5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
  102.       6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
  103.       7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
  104.       17,130,8,9,0,0,14,18,10,0,11,12,13,0,15,16
  105.      };
  106.  
  107. /*------------------- type/meta event correspondence -----------------------*/
  108. /* this table is also in charge of the following event types :                */
  109. /* QFrame, Ctrl14Bits, NonRegParam and RegParam                                */
  110.  
  111. static char metaCodeTbl[]=
  112.     { 
  113.         0xf1, 0xb0, 0xb0, 0xb0,
  114.         0, 1, 2, 3, 4, 5, 6, 7,
  115.         0x20, 0x2f, 0x51, 0x54,
  116.         0x58, 0x59, 0x7f
  117.     };
  118.  
  119. /*------------------- meta event/type correspondence -----------------------*/
  120. static char metaTypeTbl[]=
  121.     { 1,2,3,4,5,6,7,8,                /*  0-7            */
  122.       0,0,0,0,0,0,0,0,                /*  8-15 undefs    */
  123.       0,0,0,0,0,0,0,0,                /* 16-23 undefs    */
  124.       0,0,0,0,0,0,0,0,                /* 24-31        */
  125.       9,0,0,0,0,0,0,0,                /* 32-39 undefs    */
  126.       0,0,0,0,0,0,0,10,                /* 40-47        */
  127.       0,0,0,0,0,0,0,0,                /* 48-55 undefs    */
  128.       0,0,0,0,0,0,0,0,                /* 56-63 undefs    */
  129.       0,0,0,0,0,0,0,0,                /* 64-71 undefs    */
  130.       0,0,0,0,0,0,0,0,                /* 72-79 undefs    */
  131.       0,11,0,0,12,0,0,0,            /* 80-87        */
  132.       13,14,0,0,0,0,0,0,            /* 88-95        */
  133.       0,0,0,0,0,0,0,0,                /* 96-103  undefs     */
  134.       0,0,0,0,0,0,0,0,                /* 104-111 undefs    */
  135.       0,0,0,0,0,0,0,0,                /* 112-119 undefs    */
  136.       0,0,0,0,0,0,0,15                /* 120-126 undefs    */
  137.      };
  138.  
  139.  
  140. /*------------------- functions to read the events ------------------------*/
  141. static ReadFunc ReadEvTbl[]=
  142.     {
  143.             read_2DataEv,        /* $80 : 1 typeKeyOff        */
  144.             read_2DataEv,        /* $90 : 2 typeKeyOn        */
  145.             read_2DataEv,        /* $a0 : 3 typeKeyPress        */
  146.             read_2DataEv,        /* $b0 : 4 typeCtrlChange    */
  147.             read_1DataEv,        /* $c0 : 5 typeProgChange    */
  148.             read_1DataEv,        /* $d0 : 6 typeChanPress    */
  149.             read_2DataEv,        /* $e0 : 7 typePitchWheel    */
  150.  
  151.             read_sysex,            /* $f0 :  17 typeSysEx            */
  152.             read_1DataEv,        /* $f1 : 130 typeQuarterFrame    */    
  153.             read_2DataEv,        /* $f2 :   8 typeSongPos        */
  154.             read_1DataEv,        /* $f3 :   9 typeSongSel        */
  155.             read_undef,            /* $f4                            */
  156.             read_undef,            /* $f5                            */
  157.             read_0DataEv,        /* $f6 :  14 typeTune            */
  158.             read_sysex,            /* $f7 :  18 typeStream            */
  159.             read_0DataEv,        /* $f8 :  10 typeClock            */
  160.             read_undef,            /* $f9                            */
  161.             read_0DataEv,        /* $fa :  11 typeStart            */
  162.             read_0DataEv,        /* $fb :  12 typeContinue        */
  163.             read_0DataEv,        /* $fc :  13 typeStop            */
  164.             read_undef,            /* $fd                            */
  165.             read_0DataEv,        /* $fe :  15 typeActiveSens        */
  166.             read_undef,            /* $ff :  16 typeReset            */
  167.     };
  168.     
  169. static ReadMetaFunc ReadExtTbl[]=
  170.     {
  171.             (ReadMetaFunc)mdf_ignoreEv,    /* undef type   */
  172.             read_seqNum,        /* 134 typeSeqNum        */
  173.             read_text,            /* 135 typeText            */
  174.             read_text,            /* 136 typeCopyright    */
  175.             read_text,            /* 137 typeSeqName        */
  176.             read_text,            /* 138 typeInstrName    */
  177.             read_text,            /* 139 typeLyric        */
  178.             read_text,            /* 140 typeMarker        */
  179.             read_text,            /* 141 typeCuePoint        */
  180.             read_chanPref,        /* 142 typeChanPrefix    */
  181.             read_endTrack,        /* 143 typeEndTrack        */
  182.             read_tempo,            /* 144 typeTempo        */
  183.             read_smpte,            /* 145 typeSMPTEOffset    */
  184.             read_timeSign,        /* 146 typeTimeSign        */
  185.             read_keySign,        /* 147 typeKeySign        */
  186.             read_text            /* 148 typeSpecific        */
  187.     };
  188.  
  189. static WriteFunc WriteEvTbl[]=
  190.     {
  191.             write_note,            /* 0 typeNote            */
  192.             write_2DataEv,        /* 1 typeKeyOn            */
  193.             write_2DataEv,        /* 2 typeKeyOff            */
  194.             write_2DataEv,        /* 3 typeKeyPress        */
  195.             write_2DataEv,        /* 4 typeCtrlChange        */
  196.             write_1DataEv,        /* 5 typeProgChange        */
  197.             write_1DataEv,        /* 6 typeChanPress        */
  198.             write_2DataEv,        /* 7 typePitchWheel        */
  199.             write_2DataEv,        /* 8 typeSongPos        */
  200.             write_1DataEv,        /* 9 typeSongSel        */
  201.             write_0DataEv,        /* 10 typeClock            */
  202.             write_0DataEv,        /* 11 typeStart            */
  203.             write_0DataEv,        /* 12 typeContinue        */
  204.             write_0DataEv,        /* 13 typeStop            */
  205.             write_0DataEv,        /* 14 typeTune            */
  206.             write_0DataEv,        /* 15 typeActiveSens    */
  207.             dont_write,            /* 16 typeReset            */
  208.             write_sysex,        /* 17 typeSysEx            */
  209.             write_sysex,        /* 18 typeStream        */
  210.     };
  211.  
  212.  
  213. static WriteFunc WriteExtTbl[]=
  214.     {
  215.             write_1DataEv,        /* 130 typeQuarterFrame    */    
  216.             write_Ctrl14b,        /* 131 typeCtrl14b        */
  217.             write_NRegP,        /* 132 typeNonRegParam    */
  218.             write_RegP,            /* 133 typeRegParam        */
  219.  
  220.             write_SeqNum,        /* 134 typeSeqNum        */
  221.             write_texte,        /* 135 typeText            */
  222.             write_texte,        /* 136 typeCopyright    */
  223.             write_texte,        /* 137 typeSeqName        */
  224.             write_texte,        /* 138 typeInstrName    */
  225.             write_texte,        /* 139 typeLyric        */
  226.             write_texte,        /* 140 typeMarker        */
  227.             write_texte,        /* 141 typeCuePoint        */
  228.  
  229.             write_chanPref,        /* 142 typeChanPrefix    */
  230.             write_endTrack,        /* 143 typeEndTrack        */
  231.             write_tempo,        /* 144 typeTempo        */
  232.             write_smpte,        /* 145 typeSMPTEOffset    */
  233.             write_timeSign,        /* 146 typeTimeSign        */
  234.             write_keySign,        /* 147 typeKeySign        */
  235.             write_texte            /* 148 typeSpecific        */
  236.     };
  237.  
  238.  
  239. /*--------------------------------------------------------------------------*/
  240. /* numbers representation dependant    functions                                        */
  241. #ifdef __Macintosh__
  242. static long  LongVal (long val)  { return val;}
  243. static short ShortVal(short val) { return val;}
  244. #endif
  245.  
  246. #ifdef __Windows__
  247. static short ShortVal(short val)
  248. {
  249.     short converted= 0;
  250.  
  251.     converted= (val & 0xff) << 8;
  252.     converted|= (val & 0xff00) >> 8;
  253.     return converted;
  254. }
  255.  
  256. static long  LongVal (long val)
  257. {
  258.     long converted= 0;
  259.  
  260.     converted=  (long)ShortVal((short)(val & 0xffff)) << 16;
  261.     converted|= ShortVal((short)((val & 0xffff0000)>>16));
  262.     return converted;
  263. }
  264. #endif
  265.  
  266.  
  267. /*--------------------------------------------------------------------------*/
  268. /* Reading and writing variable length coded datas                            */
  269. /*--------------------------------------------------------------------------*/
  270.  
  271. /*--------------------------------------------------------------------------*/
  272. static unsigned long ReadVarLen( MIDIFilePtr fd)
  273. {
  274.     FILE *fp;
  275.     unsigned long val;
  276.     short c;
  277.  
  278.     fp= fd->fd;
  279.     if ((val = (unsigned long) getc(fp)) & 0x80)
  280.     {
  281.         val &= 0x7F;
  282.         do {
  283.             val=  (val<< 7) + ((c= getc(fp)) & 0x7F);
  284.             fd->_cnt--;
  285.         } while (c & 0x80 && !feof( fp));
  286.     }
  287.     fd->_cnt--;
  288.     return val;
  289. }
  290.  
  291. /*--------------------------------------------------------------------------*/
  292. static Boolean WriteVarLen( unsigned long val, FILE *fd)
  293. {
  294.     unsigned long buf;
  295.  
  296.     buf= val & 0x7F;
  297.     while( val >>= 7)
  298.     {
  299.         buf <<= 8;
  300.         buf |= 0x80;
  301.         buf += (val & 0x7F);
  302.     }
  303.     while( true)
  304.     {
  305.         putc( (int)buf, fd);
  306.         if( buf & 0x80) buf >>= 8;
  307.         else             break;
  308.     }
  309.     return !ferror( fd);
  310. }
  311.  
  312.  
  313.  
  314. /*--------------------------------------------------------------------------*/
  315. /* Reading and writing the MIDI file header                                    */
  316. /*--------------------------------------------------------------------------*/
  317.  
  318. /*--------------------------------------------------------------------------*/
  319. static Boolean ReadMdfHeader( MIDIFilePtr fd)
  320. {
  321.     MDF_Header h;
  322.     Boolean ret= true;                            /* return code         */
  323.  
  324.     if( fread( &h, sizeof( MDF_Header),1, fd->fd)== 1) {    /* read the header  */
  325.         if( strncmp( h.id, MDF_MThd, 4) || LongVal(h.len)!= 6) {
  326.             MidiFile_errno= MidiFileErrFrmt;/* bad file format        */
  327.             ret= false;
  328.         }
  329.         else {
  330.             fd->format= ShortVal(h.format);            /* file format             */
  331.             fd->ntrks= ShortVal(h.ntrks);                /* tracks count         */
  332.             fd->time= ShortVal(h.time);                /* time representation    */
  333.         }
  334.     }
  335.     else ret= false;
  336.     return ret;
  337. }
  338.  
  339. /*--------------------------------------------------------------------------*/
  340. static Boolean Create_mdfHeader( MIDIFilePtr fd,  short format, short time)
  341. {
  342.     MDF_Header h;
  343.     Boolean ret;                        /* return code         */
  344.  
  345.     strcpy( h.id, MDF_MThd);                /* copy the header        */
  346.     h.len= LongVal(6);                                /* datas length            */
  347.     h.ntrks= 0;                                /* tracks count = 0        */
  348.     h.format= ShortVal(format);                        /* file format            */
  349.     h.time= ShortVal(time);                            /* time representation    */
  350.     ret= (fwrite( &h, sizeof( MDF_Header), 1, fd->fd)== 1);
  351.     return ret;
  352. }
  353.  
  354.  
  355.  
  356. /*--------------------------------------------------------------------------*/
  357. /* Reading and writing a track header                                        */
  358. /*--------------------------------------------------------------------------*/
  359.  
  360. /*--------------------------------------------------------------------------*/
  361. static Boolean ReadTrkHeader( FILE *fd,  MDF_Trk *h)
  362. {
  363.     Boolean ret= true;                                /* return code         */
  364.     
  365.     if( fread( h, sizeof( MDF_Trk), 1, fd)== 1)      /* reading header    */
  366.     {
  367.         if( strncmp( h->id, MDF_MTrk, 4))
  368.         {
  369.          h->len= LongVal (h->len);
  370.             MidiFile_errno= MidiFileErrFrmt;        /* bad file            */
  371.             ret= false;
  372.         }
  373.     }
  374.     else ret= false;
  375.     return ret;
  376. }
  377.  
  378. /*--------------------------------------------------------------------------*/
  379. static Boolean Create_trkHeader( FILE *fd,  long len)
  380. {
  381.     Boolean ret= true;                                /* return code         */
  382.     MDF_Trk h;                                        /* track header        */
  383.  
  384.     strcpy( h.id, MDF_MTrk);                        /* copy the header    */
  385.     h.len= LongVal(len);                                        /* datas length        */
  386.     ret= (fwrite( &h, sizeof( MDF_Trk), 1, fd)== 1);
  387.     return ret;
  388. }
  389.  
  390.  
  391. /*--------------------------------------------------------------------------*/
  392. /* Functions to locate within the file                                        */
  393. /*--------------------------------------------------------------------------*/
  394.  
  395. /*--------------------------------------------------------------------------*/
  396. Boolean MFAPI MidiFileChooseTrack( MIDIFilePtr fd, short trackIndex)
  397. {
  398.     MDF_Trk h;
  399.  
  400.     MidiFile_errno= MidiFileNoErr;
  401.     if( trackIndex >= fd->ntrks)
  402.     {
  403.         MidiFile_errno= MidiFileErrNoTrack;
  404.         return false;
  405.     }
  406.     if( fseek( fd->fd, sizeof( MDF_Header), SEEK_SET))    /* pos = piste 0    */
  407.         return false;
  408.     while( trackIndex--)
  409.         if( !ReadTrkHeader( fd->fd, &h) || fseek( fd->fd, LongVal (h.len), SEEK_CUR))
  410.             return false;
  411.     return true;
  412. }
  413.  
  414.  
  415. /*--------------------------------------------------------------------------*/
  416. /*                                                                            */
  417. /*                            Functions to write events                        */
  418. /*                                                                            */
  419. /*--------------------------------------------------------------------------*/
  420.  
  421. /*--------------------------------------------------------------------------*/
  422. /*     Writing meta-events                                                        */
  423. /*--------------------------------------------------------------------------*/
  424.  
  425. /*--------------------------------------------------------------------------*/
  426. static Boolean write_keySign( MIDIFilePtr f, MidiEvPtr ev, short unused1)
  427. {
  428.     FILE *fd;
  429.     
  430.     fd= f->fd;
  431.     putc( META, fd);                        /* meta evt    header    */
  432.     putc( MDF_Ton, fd);                        /* meta evt    type    */
  433.     putc( MDF_TonLen, fd);                    /* length            */
  434.     putc( KSTon(ev), fd);                    /* signature        */
  435.     putc( KSMode(ev), fd);                    /* mode: maj/min    */
  436.     return !ferror( fd);    
  437. }
  438.  
  439. /*--------------------------------------------------------------------------*/
  440. static Boolean write_timeSign( MIDIFilePtr f, MidiEvPtr ev, short unused1)
  441. {
  442.     FILE *fd;
  443.     
  444.     fd= f->fd;
  445.     putc( META, fd);                        /* meta evt    header    */
  446.     putc( MDF_Meas, fd);                    /* meta evt    type    */
  447.     putc( MDF_MeasLen, fd);                    /* length            */
  448.     putc( TSNum(ev), fd);                    /* numerator        */
  449.     putc( TSDenom(ev), fd);                    /* denominator        */
  450.     putc( TSClocks(ev), fd);                /* # of MIDI clocks */
  451.     putc( TS32nd(ev), fd);                    /* # of 32nd - note */
  452.     return !ferror( fd);    
  453. }
  454.  
  455. /*--------------------------------------------------------------------------*/
  456. static Boolean write_smpte( MIDIFilePtr f, MidiEvPtr ev, short unused1)
  457. {
  458.     int l;
  459.     FILE *fd;
  460.     
  461.     fd= f->fd;
  462.     putc( META, fd);                        /* meta evt    header    */
  463.     putc( MDF_Offset, fd);                    /* meta evt    type    */
  464.     putc( MDF_OffsetLen, fd);                /* length            */
  465.     l= (int)MidiGetField( ev, 0L);            /* time offset (sec)*/
  466.     putc( l/3600, fd);                        /* hours            */
  467.     l%= 3600;
  468.     putc( l/60, fd);                        /* minutes            */
  469.     putc( l%60, fd);                        /* seconds            */
  470.     l= (int)MidiGetField( ev, 1L);            /* frame and frac    */
  471.     putc( l/100, fd);                        /* frame            */
  472.     putc( l%100, fd);                        /* fractionnal frame*/
  473.     return !ferror( fd);    
  474. }
  475.  
  476. /*--------------------------------------------------------------------------*/
  477. static Boolean write_tempo( MIDIFilePtr f, MidiEvPtr ev, short unused1)
  478. {
  479.     unsigned long l;
  480.     unsigned short s;
  481.     FILE *fd;
  482.     
  483.     fd= f->fd;
  484.      putc( META, fd);                        /* meta evt    header    */
  485.       putc( MDF_Tempo, fd);                    /* meta evt    type    */
  486.        putc( MDF_TempoLen, fd);                /* length            */
  487.         l= Tempo( ev);
  488.         s= (short)l;
  489.         putc( (int)(l >> 16), fd);
  490.        putc( s >> 8, fd);
  491.        putc( s & 0xF, fd);
  492.     return !ferror( fd);    
  493. }
  494.  
  495. /*--------------------------------------------------------------------------*/
  496. static Boolean write_endTrack( MIDIFilePtr f, MidiEvPtr  unused1, short unused2)
  497. {
  498.     FILE *fd;
  499.     
  500.     fd= f->fd;
  501.     putc( META, fd);                        /* meta evt    header    */
  502.     putc( MDF_EndTrk, fd);                    /* meta evt    type    */
  503.     putc( MDF_EndTrkLen, fd);                /* length            */
  504.     return !ferror( fd);    
  505. }
  506.  
  507. /*--------------------------------------------------------------------------*/
  508. static Boolean write_chanPref( MIDIFilePtr f, MidiEvPtr ev, short unused1)
  509. {
  510.     FILE *fd;
  511.     
  512.     fd= f->fd;
  513.     putc( META, fd);                        /* meta evt    header    */
  514.     putc( MDF_ChanPref, fd);                /* meta evt    type    */
  515.     putc( MDF_ChanPrefLen, fd);                /* length            */
  516.     putc( ChanPrefix(ev), fd);
  517.     return !ferror( fd);    
  518. }
  519.  
  520. /*--------------------------------------------------------------------------*/
  521. static Boolean write_texte( MIDIFilePtr f, MidiEvPtr ev, short status)
  522. {
  523.     unsigned long len, i;
  524.     FILE *fd;
  525.     
  526.     fd= f->fd;
  527.     putc( META, fd);                        /* meta evt    header    */
  528.     putc( status, fd);                        /* meta evt type    */
  529.     len= MidiCountFields( ev);
  530.     WriteVarLen( len, fd);
  531.     for( i=0; i<len; i++)
  532.         putc( (int)MidiGetField( ev, i), fd);
  533.     return !ferror( fd);    
  534. }
  535.  
  536. /*--------------------------------------------------------------------------*/
  537. static Boolean write_SeqNum( MIDIFilePtr f, MidiEvPtr ev, short unused1)
  538. {
  539.     unsigned short s;
  540.     FILE *fd;
  541.     
  542.     fd= f->fd;
  543.     putc( META, fd);                        /* meta evt    header    */
  544.     putc( MDF_NumSeq, fd);                    /* meta evt    type    */
  545.     putc( MDF_NumSeqLen, fd);                /* length            */
  546.     s= SeqNum(ev);
  547.     putc( s >> 8, fd);
  548.     putc( s & 0xF, fd);
  549.     return !ferror( fd);    
  550. }
  551.  
  552.  
  553. /*--------------------------------------------------------------------------*/
  554. /*     Writing MIDI events                                                        */
  555. /*--------------------------------------------------------------------------*/
  556.  
  557. /*--------------------------------------------------------------------------*/
  558. static Boolean write_param( FILE *fd, short num, short val, short type)
  559. {
  560.     putc( type, fd);                        /* NRP number msb            */
  561.     putc( num >> 7, fd);                    /* msb value                */
  562.     WriteVarLen( 0, fd);                    /* next ev, running status     */
  563.     putc( type-1, fd);                        /* NRP number lsb            */
  564.     putc( num & 0x7F, fd);                    /* lsb value                */
  565.     WriteVarLen( 0, fd);                    /* next ev, running status     */
  566.     putc( 6, fd);                            /* data entry msb             */
  567.     putc( val >> 7, fd);                    /* msb                        */
  568.     WriteVarLen( 0, fd);                    /* next ev, running status     */
  569.     putc( 38, fd);                            /* data entry lsb            */
  570.     putc( val & 0x7F, fd);                    /* lsb                        */
  571.     return !ferror( fd);    
  572. }
  573.  
  574. /*--------------------------------------------------------------------------*/
  575. static Boolean write_NRegP( MIDIFilePtr fd, MidiEvPtr ev, short unused1)
  576. {
  577.     short num, val;
  578.  
  579.     num= (short)MidiGetField( ev, 0);                    /* control number    */
  580.     val= (short)MidiGetField( ev, 1);                    /* 14 bits value    */
  581.     putc( ControlChg + Canal( ev), fd->fd);        /* status byte        */
  582.     return write_param( fd->fd, num, val, 99);
  583. }
  584.  
  585. /*--------------------------------------------------------------------------*/
  586. static Boolean write_RegP( MIDIFilePtr fd, MidiEvPtr ev, short unused1)
  587. {
  588.     short num, val;
  589.  
  590.     num= (short)MidiGetField( ev, 0);                    /* control number    */
  591.     val= (short)MidiGetField( ev, 1);                    /* 14 bits value    */
  592.     putc( ControlChg + Canal( ev), fd->fd);        /* status byte        */
  593.     return write_param( fd->fd, num, val, 101);
  594. }
  595.  
  596. /*--------------------------------------------------------------------------*/
  597. static Boolean write_Ctrl14b( MIDIFilePtr f, MidiEvPtr ev, short unused1)
  598. {
  599.     short num, val;
  600.     FILE *fd;
  601.     
  602.     fd= f->fd;
  603.     num= (short)MidiGetField( ev, 0);                    /* control number    */
  604.     val= (short)MidiGetField( ev, 1);                    /* 14 bits value    */
  605.     putc( ControlChg + Canal( ev), fd);            /* status byte        */
  606.     putc( num, fd);                                /* control number    */
  607.     putc( val >> 7, fd);                        /* msb                */
  608.     WriteVarLen( 0, fd);                    /* next ev, running status     */
  609.     putc( num+32, fd);                            /* associated control     */
  610.     putc( val & 0x7F, fd);                        /* lsb                */
  611.     return !ferror( fd);    
  612. }
  613.  
  614. /*--------------------------------------------------------------------------*/
  615. static Boolean write_sysex( MIDIFilePtr f, MidiEvPtr ev, short unused1)
  616. {
  617.     unsigned long count;
  618.     FILE *fd;
  619.     MidiSEXPtr e;
  620.     
  621.     fd= f->fd;
  622.     count= MidiCountFields( ev);
  623.     if( EvType( ev)== typeSysEx)            /* sysex message        */
  624.         putc( 0xF0, fd);                    /* sysex header            */
  625.     else                                    /* stream message        */
  626.         putc( 0xF7, fd);                    /* header sysex    next     */
  627.     WriteVarLen( count, fd);                /* message length        */
  628.     e= Link( LinkSE(ev));
  629.     while( count) {
  630.         fwrite( e->data, (count >= 12) ? 12 : (int)count, 1, fd);
  631.         e= Link(e);
  632.         count-= (count >= 12) ? 12 : count;
  633.     }
  634.     return !ferror( fd);    
  635. }
  636.  
  637. /*--------------------------------------------------------------------------*/
  638. static Boolean dont_write( MIDIFilePtr unused1, MidiEvPtr unused2, short unused3)
  639. {
  640.     return true;
  641. }
  642.  
  643. /*--------------------------------------------------------------------------*/
  644. static Boolean write_0DataEv( MIDIFilePtr fd, MidiEvPtr unused1, short status)
  645. {
  646.     putc( status, fd->fd);
  647.     return !ferror( fd->fd);    
  648. }
  649.  
  650. /*--------------------------------------------------------------------------*/
  651. static Boolean write_1DataEv( MIDIFilePtr f, MidiEvPtr ev, short status)
  652. {
  653.     FILE *fd;
  654.     
  655.     fd= f->fd;
  656.     putc( status, fd);
  657.     putc( Data( ev)[0], fd);
  658.     return !ferror( fd);    
  659. }
  660.  
  661. /*--------------------------------------------------------------------------*/
  662. static Boolean write_2DataEv( MIDIFilePtr f, MidiEvPtr ev, short status)
  663. {
  664.     FILE *fd;
  665.     
  666.     fd= f->fd;
  667.     putc( status, fd);
  668.     putc( Data( ev)[0], fd);
  669.     putc( Data( ev)[1], fd);
  670.     return !ferror( fd);    
  671. }
  672.  
  673. /*--------------------------------------------------------------------------*/
  674. static Boolean write_note( MIDIFilePtr f, MidiEvPtr ev, short status)
  675. {
  676.     MidiEvPtr c;
  677.     FILE *fd;
  678.     
  679.     fd= f->fd;
  680.     if( c = MidiCopyEv( ev))
  681.     {
  682.         EvType(c)= typeKeyOff;
  683.         Vel(c) = 0;
  684.         Date(c) = Date( ev) + Dur( ev);
  685.         Dur(c) = 0;
  686.         MidiAddSeq( f->keyOff, c);
  687.         putc( status, fd);
  688.         putc( Data( ev)[0], fd);
  689.         putc( Data( ev)[1], fd);
  690.     }
  691.     else
  692.     {
  693.         MidiFile_errno= MidiFileErrEvs;
  694.         return false;
  695.     }
  696.     return !ferror( fd);    
  697. }
  698.  
  699. /*--------------------------------------------------------------------------*/
  700. static Boolean WriteEv( MIDIFilePtr fd, MidiEvPtr ev)
  701. {
  702.     short type;
  703.     Boolean ret= true;
  704.     
  705.     type= EvType( ev);
  706.     if( type < typePrivate)
  707.         ret= (* WriteEvTbl[type])( fd, ev, (type < typeSongPos ? codeTbl[type]+Canal(ev) : codeTbl[type]));
  708.     else if( type >= typeQuarterFrame && type < typeReserved)
  709.     {
  710.         type-= typeQuarterFrame;
  711.         ret= (* WriteExtTbl[type])( fd, ev, metaCodeTbl[type]);
  712.     }
  713.     return ret;
  714. }
  715.  
  716. /*--------------------------------------------------------------------------*/
  717. static Boolean FlushKeyOff( MIDIFilePtr fd)
  718. {
  719.     MidiSeqPtr seq;
  720.     MidiEvPtr ev;
  721.     Boolean ret= true;
  722.     long date;
  723.     
  724.     seq= fd->keyOff;                        /* keyOff sequence ptr    */
  725.     ev= seq->first;                            /* first event            */
  726.     date= fd->curDate;                        /* current date            */
  727.     while( ev && ret)
  728.     {
  729.         seq->first= Link(ev);                /* first = next            */
  730.         ret= (WriteVarLen( Date( ev)- date, fd->fd) 
  731.               && WriteEv( fd, ev));            /* write the event        */
  732.         date= Date( ev);                    /* uodate the date        */
  733.         MidiFreeEv( ev);                    /* free the event        */
  734.         ev= seq->first;                        /* next event            */
  735.     }
  736.     if( ret) seq->last= nil;                /* update the sequence    */
  737.     fd->curDate= date;                        /* update current date    */
  738.     return ret;
  739. }
  740.  
  741. /*--------------------------------------------------------------------------*/
  742. Boolean MFAPI MidiFileNewTrack( MIDIFilePtr fd)
  743. {
  744.     MidiFile_errno= MidiFileNoErr;
  745.     if( isTrackOpen( fd) && !MidiFileCloseTrack( fd)) /* eventualy close the track */
  746.         return false;
  747.     if( fseek( fd->fd, 0, SEEK_END))         /* locate to the end of the file    */
  748.         return false;
  749.     if( !Create_trkHeader( fd->fd, 0))          /* write the track header     */
  750.         return false;
  751.     if( fgetpos(fd->fd,&fd->trkHeadOffset))    /* get the track location     */
  752.         return false;
  753.     fd->curDate= 0;                            /* current date = 0            */
  754.     fd->opened= true;                        /* track marked opened        */
  755.     return true;
  756. }
  757.  
  758. /*--------------------------------------------------------------------------*/
  759. Boolean MFAPI MidiFileOpenTrack( MIDIFilePtr fd)
  760. {
  761.     MDF_Trk h;
  762.  
  763.     MidiFile_errno= MidiFileNoErr;
  764.     if( fd->mode)
  765.     {
  766.         MidiFile_errno= MidiFileErrNoTrack;
  767.         return false;
  768.     }
  769.     if( isTrackOpen( fd))                    /* track still opened        */
  770.         return true;
  771.     if( ReadTrkHeader( fd->fd, &h))            /* read the track header    */
  772.     {
  773.         fd->_cnt= LongVal(h.len);             /* track length=0 => end    */
  774.         fd->curDate= 0;                        /* current date = 0            */
  775.         fd->opened= true;                    /* track marked opened        */
  776.     }
  777.     else return false;
  778.     return true;
  779. }
  780.  
  781. /*--------------------------------------------------------------------------*/
  782. Boolean MFAPI MidiFileCloseTrack( MIDIFilePtr fd)
  783. {
  784.     fpos_t offset1, offset2;                /* beg and end track offsets */
  785.     long trkLen;                            /* track length                 */
  786.     short ntrks;                            /* tracks count                 */
  787.     Boolean ret;
  788.  
  789.     MidiFile_errno= MidiFileNoErr;
  790.     offset1= fd->trkHeadOffset;
  791.     if( fd->mode )                                /* writing mode                    */
  792.     {
  793.         if( isTrackOpen(fd))                    /* track opened                    */
  794.         {
  795.             offset1= fd->trkHeadOffset;
  796.             ret= FlushKeyOff( fd);                /* write the remaining keyOff    */
  797.             if( fgetpos( fd->fd, &offset2))         /* get the end track location     */
  798.                 return false;
  799. //            trkLen= LongVal(offset2- offset1);    /* get the track length            */
  800. #if __MWERKS__
  801.             trkLen= offset2._Off - offset1._Off;    /* get the track length            */
  802.             offset1._Off -= offset_trkLen;
  803. #else
  804.             trkLen= LongVal(offset2- offset1);    /* get the track length            */
  805.             offset1-= offset_trkLen;
  806. #endif
  807.             if( fsetpos( fd->fd, &offset1))         /* to track length position     */
  808.                 return false;
  809.                                                 /* update the track length         */
  810.             if( fwrite( &trkLen, sizeof( trkLen), 1, fd->fd)!= 1)
  811.                 return false;
  812.                                                 /* to track count position        */
  813.             if( fseek( fd->fd, offset_ntrks, SEEK_SET))
  814.                 return false;
  815.             fd->ntrks++;                        /* track count                     */
  816.                                                 /* update the tracks count         */
  817.             ntrks= ShortVal(fd->ntrks);
  818.             if( fwrite( &ntrks, sizeof(ntrks), 1, fd->fd)!= 1)
  819.                 return false;    
  820.         }
  821.     }
  822.     else if( isTrackOpen( fd))                    /* reading mode                    */
  823.                                 /* locate to the beginning of the next track    */
  824.         ret= ( fseek( fd->fd, fd->_cnt, SEEK_CUR)== 0);
  825.     fd->opened= false;                            /* track is marked closed        */
  826.     return ret;
  827. }
  828.  
  829. /*--------------------------------------------------------------------------*/
  830. Boolean MFAPI MidiFileWriteEv( MIDIFilePtr fd, MidiEvPtr ev)
  831. {
  832.     MidiSeqPtr seq;
  833.     MidiEvPtr off;
  834.     long date;
  835.     
  836.     if( fd->opened)
  837.         MidiFile_errno= MidiFileNoErr;
  838.     else
  839.     {
  840.         MidiFile_errno= MidiFileErrTrackClose;
  841.         return false;
  842.     }
  843.     date= fd->curDate;                                    /* current date        */
  844.     seq= fd->keyOff;                                    /* keyOff sequence     */
  845.     off= seq->first;                                    /* next keyOff         */
  846.     while( off && (Date(ev) >= Date(off)))    /* key off before current evt    */
  847.     {
  848.         if( !WriteVarLen( Date(off)- date, fd->fd) ||    /* write the offset    */
  849.             !WriteEv( fd, off))                            /* and the key off    */
  850.             return false;
  851.         date= Date( off);                            /* update current date    */
  852.         seq->first= Link(off);                        /* update the sequence    */
  853.         MidiFreeEv( off);                            /* free the key off        */
  854.         if( !(off= seq->first))                        /* key off = next        */
  855.             seq->last= nil;
  856.     }
  857.     if( !WriteVarLen( Date( ev)- date, fd->fd) ||        /* write the offset    */
  858.         !WriteEv( fd, ev))                                /* and the event    */
  859.         return false;
  860.     fd->curDate= Date( ev);                            /* update current date    */
  861.     return true;
  862. }
  863.  
  864. /*--------------------------------------------------------------------------*/
  865. Boolean MFAPI MidiFileWriteTrack( MIDIFilePtr fd, MidiSeqPtr seq)
  866. {
  867.     MidiEvPtr ev;
  868.     Boolean ret= true;
  869.     
  870.     MidiFile_errno= MidiFileNoErr;
  871.     if( !MidiFileNewTrack( fd))                      /* write the track header     */
  872.         return false;
  873.  
  874.     ev= seq->first;
  875.     while( ev && ret)
  876.     {
  877.         ret= MidiFileWriteEv( fd, ev);                /* write the event        */
  878.         ev= Link( ev);                                /* next event            */
  879.     }
  880.  
  881.     if( !MidiFileCloseTrack( fd))                /* update the track header    */
  882.         ret= false;                                /* and the file header        */
  883.     return ret;
  884. }
  885.  
  886.  
  887. /*--------------------------------------------------------------------------*/
  888. /* Reading a track                                                            */
  889. /*--------------------------------------------------------------------------*/
  890.  
  891. /*--------------------------------------------------------------------------*/
  892. static Boolean mdf_GetDate( MIDIFilePtr fd)
  893. {
  894.     long offset;
  895.     
  896.     offset= ReadVarLen( fd);             /* get the offset to next event    */
  897.     if( feof( fd->fd))                        /* error control    */
  898.     {
  899.         MidiFile_errno= MidiFileErrFrmt;
  900.         return false;
  901.     }
  902.     if( ferror( fd->fd))                    /* error control    */
  903.         return false;
  904.     fd->curDate+= offset;            /* add the offset to the current date    */
  905.     return true;
  906. }
  907.  
  908. /*--------------------------------------------------------------------------*/
  909. static MidiEvPtr mdf_ignoreEv( MIDIFilePtr fd, long len)
  910. {
  911.     fd->_cnt-= len;
  912.     while( len--)
  913.         getc( fd->fd);
  914.     return 0;
  915. }
  916.  
  917.  
  918. /*--------------------------------------------------------------------------*/
  919. /* functions to read a meta event                                            */
  920. /*--------------------------------------------------------------------------*/
  921.  
  922. /*--------------------------------------------------------------------------*/
  923. static MidiEvPtr read_text( MIDIFilePtr fd, long len, short type)
  924. {
  925.     MidiEvPtr ev=nil;
  926.  
  927.     if( ev= MidiNewEv( type + 133))
  928.     {
  929.         fd->_cnt-= len;
  930.         while( len--)
  931.             MidiAddField( ev, (long)getc( fd->fd));
  932.     }
  933.     else MidiFile_errno= MidiFileErrEvs;
  934.     return ev;
  935. }
  936.  
  937. /*--------------------------------------------------------------------------*/
  938. static MidiEvPtr read_endTrack( MIDIFilePtr fd, long len, short unused1)
  939. {
  940.     MidiEvPtr ev=nil;
  941.     
  942.     if( len!= MDF_EndTrkLen)            /* message length */
  943.         mdf_ignoreEv( fd, len);
  944.     else if( !(ev= MidiNewEv( typeEndTrack)))
  945.         MidiFile_errno= MidiFileErrEvs;
  946.     return ev;
  947. }
  948.  
  949. /*--------------------------------------------------------------------------*/
  950. static MidiEvPtr read_tempo( MIDIFilePtr fd, long len, short unused1)
  951. {
  952.     MidiEvPtr ev=nil;
  953.     long tempo;
  954.     
  955.     if (len != MDF_TempoLen)             /* message length */
  956.         mdf_ignoreEv( fd, len);
  957.     else if( ev= MidiNewEv( typeTempo))
  958.     {
  959.         tempo= (long)getc(fd->fd);
  960.         tempo <<= 8;
  961.         tempo|= getc(fd->fd);
  962.         tempo <<= 8;
  963.         tempo|= getc(fd->fd);
  964.         Tempo(ev)= tempo;
  965.         fd->_cnt-= len;
  966.     }
  967.     else MidiFile_errno= MidiFileErrEvs;
  968.     return ev;
  969. }
  970.  
  971. /*--------------------------------------------------------------------------*/
  972. static MidiEvPtr read_keySign( MIDIFilePtr fd, long len, short unused1)
  973. {
  974.     MidiEvPtr ev=nil;
  975.  
  976.     if (len != MDF_TonLen)                 /* message length */
  977.         mdf_ignoreEv( fd, len);
  978.     else if( ev= MidiNewEv( typeKeySign))
  979.     {
  980.         KSTon( ev)= getc(fd->fd);
  981.         KSMode( ev)= getc(fd->fd);
  982.         fd->_cnt-= len;
  983.     }
  984.     else MidiFile_errno= MidiFileErrEvs;
  985.     return ev;
  986. }
  987.  
  988. /*--------------------------------------------------------------------------*/
  989. static MidiEvPtr read_timeSign( MIDIFilePtr fd, long len, short unused1)
  990. {
  991.     MidiEvPtr ev=nil;
  992.  
  993.     if (len != MDF_MeasLen)             /* message length */
  994.         mdf_ignoreEv( fd, len);
  995.     else if( ev= MidiNewEv( typeTimeSign))
  996.     {
  997.         TSNum( ev)= getc(fd->fd);
  998.         TSDenom( ev)= getc(fd->fd);
  999.         TSClocks( ev)= getc(fd->fd);
  1000.         TS32nd( ev)= getc(fd->fd);
  1001.         fd->_cnt-= len;
  1002.     }
  1003.     else MidiFile_errno= MidiFileErrEvs;
  1004.     return ev;
  1005. }
  1006.  
  1007. /*--------------------------------------------------------------------------*/
  1008. static MidiEvPtr read_seqNum( MIDIFilePtr fd, long len, short unused1)
  1009. {
  1010.     MidiEvPtr ev=nil;
  1011.     short num;
  1012.  
  1013.     if (len != MDF_NumSeqLen)             /* message length */
  1014.         mdf_ignoreEv( fd, len);
  1015.     else if( ev= MidiNewEv( typeSeqNum))
  1016.     {
  1017.         num= getc(fd->fd);
  1018.         num <<= 8;
  1019.         num|= getc(fd->fd);
  1020.         SeqNum(ev)= num;
  1021.         fd->_cnt-= len;
  1022.     }
  1023.     else MidiFile_errno= MidiFileErrEvs;
  1024.     return ev;
  1025. }
  1026.  
  1027. /*--------------------------------------------------------------------------*/
  1028. static MidiEvPtr read_chanPref( MIDIFilePtr fd, long len, short unused1)
  1029. {
  1030.     MidiEvPtr ev=nil;
  1031.  
  1032.     if (len != MDF_ChanPrefLen)         /* message length */
  1033.         mdf_ignoreEv( fd, len);
  1034.     else if( ev= MidiNewEv( typeChanPrefix))
  1035.     {
  1036.         ChanPrefix(ev)= getc(fd->fd);
  1037.         fd->_cnt-= len;
  1038.     }
  1039.     else MidiFile_errno= MidiFileErrEvs;
  1040.     return ev;
  1041. }
  1042.  
  1043. /*--------------------------------------------------------------------------*/
  1044. static MidiEvPtr read_smpte( MIDIFilePtr fd, long len, short unused1)
  1045. {
  1046.     MidiEvPtr ev=nil;
  1047.     long tmp;
  1048.  
  1049.     if (len != MDF_OffsetLen)             /* message length */
  1050.         mdf_ignoreEv( fd, len);
  1051.     else if( ev= MidiNewEv( typeSMPTEOffset))
  1052.     {
  1053.         tmp= getc(fd->fd)* 3600;        /* hours -> sec.        */
  1054.         tmp+= getc(fd->fd)* 60;            /* min.  -> sec.        */
  1055.         tmp+= getc(fd->fd);                /* sec.                    */
  1056.         MidiSetField( ev, 0L,tmp);
  1057.         tmp= getc(fd->fd)* 100;            /* frame count *100     */
  1058.         tmp+= getc(fd->fd);                /* fractionnal frame    */
  1059.         MidiSetField( ev, 1L, tmp);
  1060.         fd->_cnt-= len;
  1061.     }
  1062.     else MidiFile_errno= MidiFileErrEvs;
  1063.     return ev;
  1064. }
  1065.  
  1066. /*--------------------------------------------------------------------------*/
  1067. static MidiEvPtr mdf_read_meta( MIDIFilePtr fd)
  1068. {
  1069.     short type;
  1070.     unsigned long len;
  1071.  
  1072.     type= getc(fd->fd);                        /* read the message    type    */
  1073.     fd->_cnt--;                                /* update remain            */
  1074.     len= ReadVarLen(fd);                    /* read the message    length     */
  1075.  
  1076.     if( type & 0x80) type=0;                /* type > 127 => unknown    */
  1077.     else type= metaTypeTbl[type];
  1078.     return (*ReadExtTbl[type])( fd, len, type);
  1079. }
  1080.  
  1081.  
  1082. /*--------------------------------------------------------------------------*/
  1083. static MidiEvPtr read_undef( MIDIFilePtr fd,  short len)
  1084. {
  1085.     //MidiFile_errno= MidiFileErrUnknow;
  1086.     
  1087.     return nil;
  1088. }
  1089.  
  1090.  
  1091. /*--------------------------------------------------------------------------*/
  1092. /* functions to read a MIDI event                                            */
  1093. /*--------------------------------------------------------------------------*/
  1094.  
  1095. /*--------------------------------------------------------------------------*/
  1096. static MidiEvPtr read_sysex( MIDIFilePtr fd, short status)
  1097. {
  1098.     MidiEvPtr ev;
  1099.     unsigned long len;
  1100.     short c;
  1101.  
  1102.     if( ev= MidiNewEv( status== 0xF0 ? typeSysEx : typeStream))
  1103.     {
  1104.         len= ReadVarLen( fd);                /* message length    */
  1105.         while( len--)
  1106.         {
  1107.             c= getc( fd->fd);                /* read the datas    */
  1108.             fd->_cnt--;
  1109.             MidiAddField( ev, c);            /* and store them to the event */
  1110.         }
  1111.     }
  1112.     else MidiFile_errno= MidiFileErrEvs;
  1113.     return ev;
  1114. }
  1115.  
  1116. /*--------------------------------------------------------------------------*/
  1117. static MidiEvPtr read_2DataEv( MIDIFilePtr fd, short status)
  1118. {
  1119.     MidiEvPtr ev;
  1120.  
  1121.     if( ev= MidiNewEv( typeTbl[status & 0x7F]))    /* event allocation    */
  1122.     {
  1123.         Data( ev)[0]= getc( fd->fd);            /* store the first data */
  1124.         Data( ev)[1]= getc( fd->fd);            /* and the 2nd data        */
  1125.         fd->_cnt-= 2;
  1126.     }
  1127.     else MidiFile_errno= MidiFileErrEvs;
  1128.     return ev;
  1129. }
  1130.  
  1131. /*--------------------------------------------------------------------------*/
  1132. static MidiEvPtr read_1DataEv( MIDIFilePtr fd, short status)
  1133. {
  1134.     MidiEvPtr ev;
  1135.     
  1136.     if( ev= MidiNewEv( typeTbl[status & 0x7F]))    /* event allocation    */
  1137.     {
  1138.         Data( ev)[0]= getc( fd->fd);            /* store the data    */
  1139.         fd->_cnt--;
  1140.     }
  1141.     else MidiFile_errno= MidiFileErrEvs;
  1142.     return ev;
  1143. }
  1144.  
  1145. /*--------------------------------------------------------------------------*/
  1146. static MidiEvPtr read_0DataEv( MIDIFilePtr unused1, short status)
  1147. {
  1148.     MidiEvPtr ev;
  1149.     
  1150.     if( !(ev= MidiNewEv( typeTbl[status & 0x7F])))/* event allocation    */
  1151.         MidiFile_errno= MidiFileErrEvs;
  1152.     return ev;
  1153. }
  1154.  
  1155. /*--------------------------------------------------------------------------*/
  1156. static MidiEvPtr ReadEv( MIDIFilePtr fd)
  1157. {
  1158.     MidiEvPtr ev= nil;
  1159.     short c;
  1160.     static short status= 0;
  1161.     
  1162.     c= getc( fd->fd);
  1163.     fd->_cnt--;                                        /* update remain    */
  1164.     
  1165.     if( c== META)                                    /* meta evt            */
  1166.     {
  1167.         ev= mdf_read_meta( fd);
  1168.         c= status= 0;
  1169.     }
  1170.     else if( c & 0x80)                                /* status byte        */
  1171.         status= c;
  1172.     else if( status)                                /* running status    */
  1173.     {
  1174.         ungetc (c, fd->fd);                            /* unget the char    */
  1175.         fd->_cnt++;
  1176.         c= status;
  1177.     }
  1178.     else 
  1179.     {
  1180.         MidiFile_errno= MidiFileErrFrmt;
  1181.         c= 0;
  1182.     }
  1183.     if( c)
  1184.     {
  1185.         if( ev= (* ReadEvTbl[(c<SysEx) ? (c & 0x7F)/16 : c- SysEx+7])( fd, c))
  1186.             if( c < SysEx)
  1187.                 Canal(ev)= c%16;
  1188.     }
  1189.     if( (ferror( fd->fd) || feof( fd->fd)) && ev)
  1190.     {
  1191.         MidiFreeEv( ev);
  1192.         ev= 0;
  1193.         if( feof( fd->fd))
  1194.             MidiFile_errno= MidiFileErrFrmt;
  1195.     }
  1196.     return ev;
  1197. }
  1198.  
  1199. /*--------------------------------------------------------------------------*/
  1200. MidiEvPtr MFAPI MidiFileReadEv( MIDIFilePtr fd)
  1201. {
  1202.     MidiEvPtr ev= nil;
  1203.  
  1204.     MidiFile_errno= MidiFileNoErr;
  1205.     if( isTrackOpen( fd))                    /* if the track is opened        */
  1206.     {
  1207.         if( fd->_cnt > 0)                    /* if there are events to read    */
  1208.         {
  1209.             if( mdf_GetDate( fd))            /* read the next event date        */
  1210.                 if( ev= ReadEv( fd))        /* read the event                */
  1211.                     Date( ev)= fd->curDate;    /* store its date                */
  1212.         }
  1213.         else fd->opened= false;                /* otherwise: close the track    */
  1214.     }
  1215.     else MidiFile_errno= MidiFileErrTrackClose;
  1216.     return ev;
  1217. }
  1218.  
  1219. /*--------------------------------------------------------------------------*/
  1220. MidiSeqPtr MFAPI MidiFileReadTrack( MIDIFilePtr fd)
  1221. {
  1222.     MidiSeqPtr seq= nil;
  1223.     MidiEvPtr ev;
  1224.     
  1225.     MidiFile_errno= MidiFileNoErr;
  1226.     if( MidiFileOpenTrack( fd)) {                    /* open the track            */
  1227.         if( seq= MidiNewSeq()) {                    /* allocate a sequence         */
  1228.             while( isTrackOpen( fd)) {            /* while there are events    */
  1229.                 if( ev= MidiFileReadEv( fd)) {    /* read these events        */
  1230.                     if( !seq->first)            /* store them to the seq     */
  1231.                         seq->first= seq->last= ev;
  1232.                     else {
  1233.                         Link(seq->last)= ev;
  1234.                         seq->last= ev;
  1235.                     }
  1236.                 }
  1237.                 else if( isMidiFileError( fd)) {    /* if it's an error            */
  1238.                     MidiFreeSeq( seq);            /* free the sequence        */
  1239.                     seq= nil;                    /* to return error            */
  1240.                     break;
  1241.                 }                        /* otherwise it's an ignored event */
  1242.             }
  1243.         }
  1244.         else MidiFile_errno= MidiFileErrEvs;
  1245.     }
  1246.     return seq;
  1247. }
  1248.  
  1249.  
  1250.  
  1251. /*--------------------------------------------------------------------------*/
  1252. /* Opening and closing a MIDI file                                            */
  1253. /*--------------------------------------------------------------------------*/
  1254.  
  1255. /*--------------------------------------------------------------------------*/
  1256. static const char *mdf_getStdMode( short mode)
  1257. {
  1258.     switch( mode)
  1259.     {
  1260.         case MidiFileRead:
  1261.             return "rb";
  1262.         case MidiFileAppend:
  1263.             return "rb+";
  1264.         default:
  1265.             MidiFile_errno= MidiFileErrMode;
  1266.             return nil;
  1267.     }
  1268. }
  1269.  
  1270. /*--------------------------------------------------------------------------*/
  1271. static void ErrOpen( MIDIFilePtr fd)
  1272. {
  1273.     if( fd)
  1274.     {
  1275.         if( fd->fd) fclose( fd->fd);        /* file opened: we close it         */
  1276.         if( fd->mode && fd->keyOff) 
  1277.             MidiFreeSeq( fd->keyOff);        /* allocated sequence: we free it     */
  1278.         free( fd);
  1279.     }
  1280. }
  1281.  
  1282. /*--------------------------------------------------------------------------*/
  1283. static Boolean stdInit( MIDIFilePtr fd)
  1284. {
  1285.     fd->opened= false;
  1286.     fd->curDate= 0;
  1287.     if( fd->mode)
  1288.     {
  1289.         if( !(fd->keyOff= MidiNewSeq()))
  1290.             return false;
  1291.     }
  1292.     else fd->keyOff= nil;
  1293.     return true;
  1294. }
  1295.  
  1296. /*--------------------------------------------------------------------------*/
  1297. MIDIFilePtr MFAPI MidiFileOpen( const char *filename, short mode)
  1298. {
  1299.     MIDIFilePtr fd;            /* my MIDI file descriptor    */
  1300.     Boolean ok= true;                /* to check for errors        */
  1301.     const char *stdMode;            /* standard opening mode    */
  1302.     
  1303.     MidiFile_errno= MidiFileNoErr;
  1304.     if( fd= (MIDIFilePtr)malloc( sizeof( midiFILE)))
  1305.     {
  1306.         fd->fd= nil;
  1307.         stdInit( fd);                                /* standard initialization    */
  1308.         if( (stdMode= mdf_getStdMode( mode)) &&        /* opening mode control        */
  1309.             (fd->fd= fopen( filename, stdMode)))    /* file opening                */
  1310.         {            
  1311.             if( ok= ReadMdfHeader( fd))                /* read the file header        */
  1312.             {
  1313.                 if( fd->format== midifile0 && mode== MidiFileAppend)
  1314.                 {                                    /* error :                    */
  1315.                     MidiFile_errno= MidiFileErrAdd0;/* try to add to a 0 format    */
  1316.                     ok= false;                        /* file                        */
  1317.                 }
  1318.                 fd->mode= (mode== MidiFileAppend ? true : false);
  1319.                 ok= stdInit( fd);
  1320.             }
  1321.         }
  1322.         else ok= false;
  1323.     }
  1324.     if( !ok)                                        /* we've got an error        */
  1325.     {
  1326.         ErrOpen( fd);
  1327.         fd= nil;
  1328.     }
  1329.     return fd;
  1330. }
  1331.  
  1332.  
  1333. /*--------------------------------------------------------------------------*/
  1334. MIDIFilePtr MFAPI MidiFileCreate( const char *name, short format, short timeDef, short ticks)
  1335. {
  1336.     MIDIFilePtr fd;            /* my MIDI file descriptor    */
  1337.     Boolean ok= true;                /* to check for errors        */
  1338.     short time;                        /* time representation         */
  1339.     
  1340.     MidiFile_errno= MidiFileNoErr;
  1341.     if( fd= (MIDIFilePtr )malloc( sizeof( midiFILE)))
  1342.     {
  1343.         if( fd->fd= fopen( name, "wb+"))        /* open the file    */
  1344.         {
  1345.             fd->mode= true;                        /* writing mode        */
  1346.             fd->ntrks= 0;                        /* tracks count = 0    */
  1347.             fd->format= format;                    /* file format         */
  1348.             if( timeDef)                        /* smpte time        */
  1349.             {
  1350.                 time= (timeDef | 0x80) << 8;
  1351.                 time|= (char) ticks;
  1352.             }
  1353.             else time= ticks & 0x7FFF;
  1354.             if( ok= stdInit( fd))                /* standard initialization    */
  1355.                 ok= Create_mdfHeader( fd, format, fd->time= time);
  1356.         }
  1357.         else ok= false;
  1358.     }
  1359.     if( !ok)                                    /* we've got an error        */
  1360.     {
  1361.         ErrOpen( fd);
  1362.         fd= nil;
  1363.     }
  1364.     return fd;
  1365. }
  1366.  
  1367. /*--------------------------------------------------------------------------*/
  1368. Boolean MFAPI MidiFileClose( MIDIFilePtr fd)
  1369. {
  1370.     int ret1= true, ret2;                /* return code        */
  1371.     
  1372.     MidiFile_errno= MidiFileNoErr;
  1373.     if( fd->mode)                                /* writing mode        */
  1374.     {
  1375.         if( isTrackOpen(fd))                        /* track still opened    */
  1376.             ret1= MidiFileCloseTrack( fd);        /* we close it            */
  1377.         if( fd->keyOff)
  1378.             MidiFreeSeq( fd->keyOff);            /* free the sequence    */
  1379.     }
  1380.     ret2= fclose( fd->fd);                        /* close the file        */
  1381.     free( fd);                                    /* free the memory         */
  1382.     return ret1 && ret2== 0;
  1383. }
  1384.  
  1385. /*--------------------------------------------------------------------------*/
  1386. const MDF_versions * MFAPI MidiFileGetVersion(void)
  1387. {
  1388.     static MDF_versions versions;
  1389.     
  1390.     versions.src= SRC_VERSION;
  1391.     versions.MidiFile= MDF_VERSION;
  1392.     return (const MDF_versions *)&versions;
  1393. }
  1394.  
  1395. /*--------------------------------------------------------------------------*/
  1396. int MFAPI MidiFileGetMFErrno (void)
  1397. {
  1398.     return  MidiFile_errno;
  1399. }
  1400.  
  1401. /*--------------------------------------------------------------------------*/
  1402. int MFAPI MidiFileGetErrno (void)
  1403. {
  1404.     return errno;
  1405. }
  1406.  
  1407. /*--------------------------------------------------------------------------*/
  1408. /* this main is required on the Macintosh to build the Common Lisp library     */
  1409.  
  1410. #ifdef CL_LIB
  1411.  
  1412. void main()
  1413. {
  1414.     MidiFileGetVersion();
  1415.     MidiFileOpen( (const char FAR *)0, 0);
  1416.     MidiFileCreate( (const char FAR *)0, 0, 0, 0);
  1417.     MidiFileClose( nil);
  1418.  
  1419.     MidiFileOpenTrack( 0);
  1420.     MidiFileNewTrack( 0);
  1421.     MidiFileCloseTrack( 0);
  1422.     MidiFileChooseTrack( 0, 0);
  1423.  
  1424.     MidiFileReadEv( 0);
  1425.     MidiFileReadTrack( 0);
  1426.  
  1427.     MidiFileWriteEv( 0, 0);
  1428.     MidiFileWriteTrack( 0, 0);
  1429.  
  1430.     MidiFileGetMFErrno();
  1431.     MidiFileGetErrno();
  1432. }
  1433.  
  1434. #endif
  1435.