/* This is the source such as it is. It compiled under several different compilers, but use at your own risk. This program released to the public domain (author: Tom Zerucha) [to satisfy legal types]. This is not my best work, but because several people asked for it, here is my midi format 1 to format 0 converter. Note that there are hooks for editing things such as patch changes. It was adapted from a player I am working on so some of the comments aren't fixed yet. */ #include #include #include #include /* for exit() */ #ifndef SEEK_SET #define SEEK_SET 0 #endif #define FBSZ 4096 unsigned char inbuf[FBSZ]; #define NTRK 256 /* standard midi header after fixing for byte differences */ struct mthd { char mthd [4]; unsigned long hdlen; unsigned short int format; /* 0 - sgl multichan trk, 1 - 1+ simul, 2 - 1+ indep */ unsigned short int ntrks; /* number of track chunks */ unsigned short int division; /* time div of a quarter note (or if <0, frm/sec,res */ } hdr; /* standard track header - left unfixed*/ struct mtrkh { char mtrk[4]; unsigned char trln[4]; } mthdmy; unsigned long trklen[NTRK]; /* real track lengths */ unsigned char *trkbuf[NTRK]; /* pointers to malloced track buffers */ unsigned int trkptr[NTRK]; /* displacement into track */ unsigned int trk; /* current track */ /* input and out files */ FILE *f, *of; int optr; /* output pointer */ /* write character out (buffered) */ /* on a PC this is faster than simply using fputc(of) */ void mputc(x) unsigned char x; { inbuf[optr++] = x; if( optr == FBSZ ) { fwrite( inbuf, 1, FBSZ, of ); optr = 0; } } /* this is fast, but unprotected from buffer overrun */ /* should verify against trklen[trk] */ #define mgetc() (trkbuf[trk][trkptr[trk]++]) /* this gets a standard midifile variable length value */ unsigned long getvar() { unsigned long reclen; unsigned char c; reclen = 0; do { c = mgetc(); reclen <<= 7; reclen |= c & 0x7f; } while( c & 0x80 ); return( reclen ); } /* this puts a standard midifile variable length value */ void putvar(val) unsigned long val; { char subs[6]; int i; i = 0; while( val > 127 ) { subs[i++] = 0x80 | ( val & 127 ); val >>= 7; } subs[i++] = 0x80 | ( val & 127 ); subs[0] &= 0x7f; while( i-- ) mputc( subs[i] ); } /*---------------------------------------------------------------------------*/ int doneflg[NTRK]; /* set when EOT is encountered */ unsigned int trksleft; /* count of tracks remaining */ void dometa(c, deltime) unsigned char c; unsigned long deltime; { unsigned char d; unsigned long reclen; d = mgetc(); reclen = getvar(); if( c == 0xff && d == 0x2f ) { /* end of track */ doneflg[trk] = 1; trksleft--; trkptr[trk]+=reclen; /* while( reclen-- ) mgetc(); */ return; } /* but don't do end of track */ putvar( deltime ); mputc( c ); mputc( d ); putvar( reclen ); while( reclen-- ) mputc( mgetc() ); } /*---------------------------------------------------------------------------*/ main(argc, argv) int argc; char *argv[]; { unsigned char c, d; unsigned char mtype; unsigned long reclen; unsigned int maxtrk; int gotevt[NTRK]; int laststs[NTRK]; unsigned long lastmstime; unsigned long currtime; unsigned long deltime; unsigned long nextevt[NTRK]; unsigned long tptr; optr = 0; /* read in file */ of = fopen( argv[2], "wb" ); if( !of ) exit( -1 ); f = fopen( argv[1], "rb" ); if( !f ) exit( -1 ); /* get header */ fread( inbuf, 1, 14, f ); strncpy( hdr.mthd, inbuf, 4 ); /* portable bigendian to header */ hdr.hdlen = inbuf[4]; hdr.hdlen <<= 8; hdr.hdlen |= inbuf[5]; hdr.hdlen <<= 8; hdr.hdlen |= inbuf[6]; hdr.hdlen <<= 8; hdr.hdlen |= inbuf[7]; hdr.format = inbuf[8]; hdr.format <<= 8; hdr.format |= inbuf[9]; hdr.ntrks = inbuf[10]; hdr.ntrks <<= 8; hdr.ntrks |= inbuf[11]; hdr.division = inbuf[12]; hdr.division <<= 8; hdr.division |= inbuf[13]; printf( "Header, len=%ld format=%d #tracks=%d clk/qtr=%d\n", hdr.hdlen, hdr.format, hdr.ntrks, hdr.division ); /* change and write new header */ inbuf[8] = 0; inbuf[9] = 0; inbuf[10] = 0; inbuf[11] = 1; fwrite( inbuf, 1, 14, of ); maxtrk = hdr.ntrks; /**/ if( maxtrk > NTRK ) { printf( "Too many tracks (%d > %d)\n", maxtrk, NTRK ); exit( -1 ); } /* read in track headers, allocate buffers, and read in track data */ trk = 0; while( trk < maxtrk && !feof( f ) ) { /* reset flags while we are at it */ gotevt[trk] = 0; doneflg[trk] = 0; trkptr[trk] = 0; nextevt[trk] = 0; fread( &mthdmy, 1, sizeof( mthdmy ), f ); trklen[trk] = mthdmy.trln[0]; trklen[trk] <<= 8; trklen[trk] |= mthdmy.trln[1] & 0xff; trklen[trk] <<= 8; trklen[trk] |= mthdmy.trln[2] & 0xff; trklen[trk] <<= 8; trklen[trk] |= mthdmy.trln[3] & 0xff; printf( "Track %d Len:%ld\n", trk, trklen[trk] ); if( !trklen[trk] ) doneflg[trk] = 1; else { trkbuf[trk] = malloc( trklen[trk] ); if( !trkbuf[trk] ) { printf( "Out of Memory\n" ); exit( -1 ); } fread( trkbuf[trk], 1, trklen[trk], f ); } trk++; } fclose( f ); tptr = ftell( of ); fwrite( &mthdmy, 1, sizeof( mthdmy ), of ); /* need to fix .trklen at offset later */ #if 0 if( trk != maxtrk ) /* sometimes they aren't all there */ maxtrk = trk; #endif trksleft = maxtrk; lastmstime = 0; currtime = 0; while( trksleft ) { /* scan tracks for ready event */ for( trk = 0; trk < maxtrk; trk++ ) { /* process track while events can be done */ while( !doneflg[trk] ) { /* get time of next event */ if( !gotevt[trk] ) nextevt[trk] += getvar(); /* check if next event is later */ if( currtime < nextevt[trk] ) { gotevt[trk] = 1; break; } else gotevt[trk] = 0; deltime = currtime - lastmstime; lastmstime = currtime; /* get status byte and dispatch by type */ c = mgetc(); if( c > 0x7f ) laststs[trk] = c; else { trkptr[trk]--; c = laststs[trk]; } switch( c >> 4 ) { case 0x0f: switch( c & 0x0f ) { case 0x00: case 0x07: case 0x0f: dometa( c, deltime ); break; default: printf( "UNKNOWN %02x \n", c ); break; } break; /* these are split out so you can play with the settings if desired */ case 0x08: /* note off */ case 0x09: /* note on */ case 0x0a: /* poly aftch */ case 0x0e: /* pitch bend */ case 0x0b: /* controller */ putvar( deltime ); mtype = c; mputc( c ); c = mgetc(); mputc( c ); d = mgetc(); mputc( d ); break; case 0x0d: /* channel aftch */ case 0x0c: /* program (patch) */ putvar( deltime ); mputc( c ); d = mgetc(); mputc( d ); break; default: break; } } } currtime++; if( !( currtime % 1000 ) ) { printf( "%6ld delta time\r", currtime ); fflush( stdout ); } } mputc( 0x00 ); mputc( 0xff ); mputc( 0x2f ); mputc( 0x00 ); fwrite( inbuf, 1, optr, of ); reclen = ftell( of ) - tptr - 8; /* backpatch track length */ fseek( of, tptr, 0 ); /* 0 - from BOF */ mthdmy.trln[3] = reclen & 0xff; reclen >>= 8; mthdmy.trln[2] = reclen & 0xff; reclen >>= 8; mthdmy.trln[1] = reclen & 0xff; reclen >>= 8; mthdmy.trln[0] = reclen & 0xff; fwrite( &mthdmy, 1, sizeof( mthdmy ), of ); fclose( of ); }