/* Converts MID format 0 files to CMF */


#include <stdio.h>
#include <dos.h>
#include <alloc.h>

long read32bit();
long to32bit();
int read16bit();
int to16bit();

long Mf_toberead = 0L;
long musdatalen = 0L;

int format,ntrks,division;


unsigned char CMFHeader[40] =
       {'C','T','M','F',0x01,0x01,0x28,0x00,
       0x28,0x08,0x30,0,0x60,0,0,0,0,0,0,0,
       1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,128,0,120,0};

unsigned char InstrBuf[128][16];

unsigned char *MusicBuf;

FILE* midfile;


main(int argc, char **argv)
{
FILE* cmffile;
FILE* instrfile;
int ch;
int tempo,ticks_psec,ticks_pqn;


       if(argc > 1)
       {
               readmidfile(argv);

               if(argc>4)
               {
                       tempo = atoi(argv[4]);
                       ticks_psec =(int)( (float)division * ((float)tempo/(float)60) );
                       ticks_pqn = (int)( (float)ticks_psec * ((float)60/(float)tempo) );
                       CMFHeader[10] = ticks_pqn & 0xFF;
                       CMFHeader[11] = (ticks_pqn >> 8) & 0xFF;
                       CMFHeader[12] = ticks_psec & 0xff;
                       CMFHeader[13] = (ticks_psec >> 8) & 0xFF;
                       CMFHeader[38] = tempo & 0xff;
                       CMFHeader[39] = (tempo >> 8) & 0xff;
               }

               cmffile = fopen(argv[1],"wb");
               fwrite(CMFHeader,1,40,cmffile);

               if(instrfile=fopen(argv[3],"rb"))
               {
                       fread(&InstrBuf[0],1,2048,instrfile);
                       fclose(instrfile);
               } else
               {
                       printf("Instrument file %s not found!\n",argv[3]);
                       free(MusicBuf);
                       exit(1);
               }

               fwrite(&InstrBuf[0],1,2048,cmffile);
               fwrite(MusicBuf,1,(unsigned)musdatalen,cmffile);

               fclose(cmffile);
               free(MusicBuf);
       }
       else
       {
               printf("MAKECMF converts a .MID format 0 file to CMF\n");
               printf("usage: makecmf <cmffile> <midfile> <instrfile> [<tempo>]\n");
       }
}


readmidfile(char **argv)
{
int i;

       if(midfile=fopen(argv[2],"rb"))
       {

               if ( (i=readmt("MThd")) == EOF )
               {

                       printf("This is not a valid MID file!\n");
                       fclose(midfile);
                       exit(1);
               }

               Mf_toberead = read32bit();
               format = read16bit();
               if(format == 1)
               {
                       printf("Not a format 0 MID file!\n");
                       fclose(midfile);
                       exit(1);
               }
               ntrks = read16bit();
               division = read16bit();

               while ( Mf_toberead > 0 )
               (void) egetc();

               readmt("MTrk");

               Mf_toberead = read32bit();
               musdatalen = Mf_toberead;


               if( MusicBuf = malloc(musdatalen))
               {
                       fread(MusicBuf,1,(unsigned)musdatalen,midfile);
                       fclose(midfile);
               }
               else
               {
                       printf("Not enough memory!\n");
                       fclose(midfile);
                       exit(1);
               }
       }
       else
       {
               printf("Couldn't find MID file %s!\n",argv[2]);
               exit(1);
       }
}


readmt(char *s)         /* read through the "MThd" or "MTrk" header string */
{
       int n = 0;
       char *p = s;
       int c;

       while ( (n++<4) && ((c=getc(midfile)) != EOF) ) {
               if ( c != *p++ ) {
                       char buff[32];
                       (void) strcpy(buff,"expecting ");
                       (void) strcat(buff,s);
                       return(EOF);
               }
       }
       return(c);

}


egetc()                 /* read a single character and abort on EOF */
{
       int c = getc(midfile);

       if ( c == EOF )
       {
               printf("premature EOF");
               fclose(midfile);
               exit(1);
       }

       Mf_toberead--;
       return(c);
}


long to32bit(c1,c2,c3,c4)
{
       long value = 0L;

       value = (c1 & 0xff);
       value = (value<<8) + (c2 & 0xff);
       value = (value<<8) + (c3 & 0xff);
       value = (value<<8) + (c4 & 0xff);
       return (value);
}


to16bit(int c1,int c2)
{
       return ((c1 & 0xff ) << 8) + (c2 & 0xff);
}

long read32bit()
{
       int c1, c2, c3, c4;

       c1 = egetc();
       c2 = egetc();
       c3 = egetc();
       c4 = egetc();
       return to32bit(c1,c2,c3,c4);
}


read16bit()
{
       int c1, c2;
       c1 = egetc();
       c2 = egetc();
       return to16bit(c1,c2);
}