/**********************************************************/
/* MIDEXT                                                 */
/* Extracts Text/SysEx/SP Generic bank from a MIDI file   */
/* 951110 Now reads SysEx and text messages > 64K         */
/* 951112 Speeded up extraction drastically by reading    */
/*        the whole file into memory before processing    */
/**********************************************************/


#include <stdio.h>
#include <dos.h>
#include <fcntl.h>
#include <dir.h>
#include <string.h>
#include <alloc.h>
#include <string.h>
#include <ctype.h>
#include "midifile.h"

#include <c30hdr.h>

unsigned int midf, destf;
char    destfname[80];
int     data_exists = 0;
unsigned char inbyte;

unsigned long   firstnote_dtime = 0xffffffff;
int                             sysex_after_firstnote = 0;

unsigned long   sysex_len = 0L;

int extmode = 0;
int oldtype = 0xffff;

#define         TEXT    0
#define SYSEX 1
#define  BANK  2


main(int argc,char **argv)
{
       struct ffblk ffblk;
       char fname[80], extension[5];
       int namelen;
       int done, found;

       if(argc > 2)
       {
               initfuncs();

               switch(argv[2][0]){
                       case 't' : extmode = TEXT; break;
                       case 's' : extmode = SYSEX; break;
                       case 'b' : extmode = BANK; break;
               }
               switch(extmode) {
                       case TEXT:  strcpy(extension, ".TXT"); break;
                       case SYSEX: strcpy(extension, ".SYX"); break;
                       case BANK:  strcpy(extension, ".C30"); break;
               }

               strcpy(fname, argv[1]);

               if(strncmp(fname, "*.", 2) != 0)
               {
                       if(! strchr(fname, '.'))
                               strcat(fname, ".MID");

                       namelen = strchr(fname, '.') - fname;
                       strncpy(destfname, fname, namelen);
                       destfname[namelen] = 0;
                       strcat(destfname, extension);
                       extract(fname);
                       printf("OK.\n");
               }
               else
               {
                       done = findfirst(fname, &ffblk, 0);
                       found = 0;
                       while(! done)
                       {
                               namelen = strchr(ffblk.ff_name,'.') - ffblk.ff_name;
                               strncpy(destfname, ffblk.ff_name, namelen);
                               destfname[namelen] = 0;
                               strcat(destfname, extension);
                               extract(ffblk.ff_name);
                               done = findnext(&ffblk);
                               found++;
                       }
                       if(found)
                               printf("OK.\n");
                       else
                               printf("No matching files found\n");
               }
       }
       else
       {
               printf("MIDEXT v2.0  Extracts text or SysEx from a standard MIDI file\n\n");
               printf("usage: midext <midifile[.mid]> <t|s|b>\n");
               printf("\n");
               printf(" t   extract text\n");
               printf(" s   extract SysEx to raw MIDIEX file\n");
               printf(" b   extract SysEx to SP Gold Generic instrument bank file\n");
               printf("\n");
               printf("wildcards allowed\n");
       }
}


extract(char *fname)
{
       data_exists = 0;
       sysex_after_firstnote = 0;
       sysex_len = 0L;
       oldtype = 0xffff;

       if((midf = _open(fname, O_BINARY | O_RDONLY)) != -1)
       {
               destf = _creat(destfname, 0);

               if(extmode == BANK)
               {
                       _write(destf, c30hdr, sizeof(c30hdr));  /* Write bank file header   */
                       _write(destf, &sysex_len, 4);           /* Dummy write   */
               }

               mfread();
               _close(midf);

               if(data_exists)
               {
                       if(extmode == BANK)
                       {
                               lseek(destf, (unsigned long)sizeof(c30hdr), SEEK_SET);
                               _write(destf, &sysex_len, 4);    /* Write REAL SysEx length */
                       }
                       _close(destf);

                       if((sysex_after_firstnote) && (extmode != TEXT))
                               printf("Warning: SysEx data after first note played in file %s\n", strupr(fname));
               }
               else
               {
                       printf("No data in %s\n", fname);
                       _close(destf);
                       remove(destfname);
               }
       }
       else
       {
               printf("MID file not found!\n");
               exit(1);
       }
}


error(unsigned char *s)
{
       fprintf(stderr,"Error: %s\n",s);
       exit(1);
}

mext_noteon(chan,pitch,vol)
{
       if(firstnote_dtime == 0xffffffff)
               firstnote_dtime = mf_currtime;
}


mext_sysex(unsigned long leng, unsigned char far *mess)
{
       static unsigned char sysex = 0xf0;

       if(extmode == TEXT) return;

       if(! data_exists)
               data_exists = 1;

       if(mf_currtime > firstnote_dtime)
               sysex_after_firstnote = 1;

       _write(destf, &sysex, 1);
       bufwrite(mess, leng);
       sysex_len += (++leng);
}


mext_metatext(int type, unsigned long leng, unsigned char far *mess)
{
       static char *ttype[] = {
               NULL,
               "Text Event",           /* type=0x01 */
               "Copyright Notice",     /* type=0x02 */
               "Sequence/Track Name",
               "Instrument Name",      /* ...       */
               "Lyric",
               "Marker",
               "Cue Point",            /* type=0x07 */
               "Unrecognized"
       };
       int unrecognized = (sizeof(ttype)/sizeof(char *)) - 1;
       unsigned long n, c;
       unsigned char far *p = mess;
       char msgbuf[81];
       int i;

       if(extmode != TEXT) return;

       if(! data_exists)
               data_exists = 1;

       if ( type < 1 || type > unrecognized )
               type = unrecognized;

       if(oldtype != type)
       {
               oldtype = type;
               sprintf(msgbuf,"\r\n   Type: %s\r\n\r\n", ttype[type]);
               _write(destf, msgbuf, strlen(msgbuf));
       }

       for ( n = 0L; n < leng; n++ ) {
               c = *p++;
               sprintf(msgbuf, (isprint(c)||isspace(c)) ? "%c" : "\\0x%02x" , c);
               _write(destf, msgbuf, strlen(msgbuf));
       }

       sprintf(msgbuf, "\r\n");
       _write(destf, msgbuf, strlen(msgbuf));
}


bufwrite(unsigned char far *buf, unsigned long len)
{
       union REGS regs;
       struct SREGS segregs;
       unsigned int bytes_to_write;

       if(FP_OFF(buf) > 0x8000) {
               FP_SEG(buf) += 0x0800;
               FP_OFF(buf) -= 0x8000;
       }
       segregs.ds = FP_SEG(buf);

       while(1)
       {
               regs.h.ah = 0x40 ;
               regs.x.bx = destf;
               regs.x.dx = FP_OFF(buf);
               if(len >= 0x8000L)
                       bytes_to_write = 0x8000;
               else
                       bytes_to_write = (unsigned int)len;
               regs.x.cx = bytes_to_write;
               intdosx(&regs, &regs, &segregs);
               if(bytes_to_write < 0x8000) break;
               len -= 0x8000L;
               if(len == 0L) break;
               segregs.ds += 0x0800;
       }
}

initfuncs()
{
       mf_error = error;
       mf_noteon =  mext_noteon;
       mf_sysex =  mext_sysex;
       mf_text =  mext_metatext;
}