/* 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 #define FBSZ 4096 char inbuf[FBSZ]; /* 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 */ short int division; /* time div of a quarter note (or if <0, frm/sec,res */ } hdr, ohdr; #define NTRK 256 /* 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) */ 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 */ int trksleft; /* count of tracks remaining */ dometa(c, deltime) unsigned char c; long deltime; { unsigned char d; unsigned long reclen; d = mgetc(); reclen = getvar(); if (c == 0xff && d == 0x2f) { /* end of track */ doneflg[trk] = 1; trksleft--; 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; 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); }