home *** CD-ROM | disk | FTP | other *** search
/ C++ Games Programming / CPPGAMES.ISO / mt / mt_to_mf.c < prev    next >
C/C++ Source or Header  |  1989-01-14  |  10KB  |  321 lines

  1. /* mt_to_mf.c  converts MT song files to Standard MIDI Files 1.0 format */
  2. /* `MIDI Sequencing In C', Jim Conger, M&T Books, 1989 */
  3.  
  4. /* #define TURBOC  1   Define if using Turbo C, leave out for Microsoft C */
  5.  
  6. #include <stdio.h>
  7. #include <string.h>
  8.  
  9. #ifdef TURBOC
  10.     #include <alloc.h>
  11. #else
  12.     #include <malloc.h>
  13. #endif
  14.  
  15. #define NTRACK              8
  16. #define TITLE_WIDE          51
  17. #define TRACK_NAME_WIDE     9
  18. #define NBYTES              30000   /* default track data buffer */
  19. #define TIME_OUT            0xF8
  20. #define ALL_END             0xFC
  21.  
  22. #define META                0xFF    /* meta event codes */
  23. #define TEXTEVENT           01
  24. #define SEQNAME             03
  25. #define INSNAME             04
  26. #define CHANPREF            0x20
  27. #define ENDTRACK            0x2F
  28. #define SETTEMPO            0x51
  29. #define TIMESIG             0X58
  30.  
  31. /* function prototypes */
  32.  
  33. void write_buf(char *sp, char *ep, FILE *outfile);  /* function prototypes */
  34. char *copy_var_len(long n, char *cp);
  35. void put_to_file(void *addr, int size, FILE *stream);
  36. void put_len(long n, FILE *stream);
  37. void write_mthd(int ntrack, FILE *outfile);
  38. void get_from_file(void *addr, int size, FILE *stream);
  39. FILE *open_file(char *filename, char *status);
  40.  
  41.  
  42. void
  43. main(argc, argv)
  44. int argc;
  45. char *argv[];
  46. {
  47.     char title[TITLE_WIDE], trackname[NTRACK][TRACK_NAME_WIDE];
  48.     unsigned char *buf, *cp, *cp1, b[4], runstatus;
  49.     int metrate, meter, ntrack, trk, midichan[NTRACK], i, n, at_end;
  50.     long eventcount[NTRACK], event, ticks, msec_qnote;
  51.     FILE *infile, *outfile;
  52.     
  53.     if (argc < 3){
  54.         fputs("\nUsage:  mt_to_mf  infile  outfile", stdout);
  55.         fputs("\nWhere infile is the MT .SNG file name;", stdout);
  56.         fputs("\n outfile is the Standard MIDI file name for output.", stdout);
  57.         exit(0);
  58.     }
  59.  
  60.     infile = open_file(argv[1], "rb");      /* open the files specified on */
  61.     outfile = open_file(argv[2], "wb");     /* the command line. */
  62.  
  63.     /* All of the data is first written to a memory buffer called buf. */
  64.     /* When conversion is complete, the buffer is written to disk. */
  65.     /* This allows the length of the buffer to be know prior to writing. */
  66.     
  67.     buf = (char *)malloc(NBYTES);
  68.     if (buf == NULL){
  69.         fputs("\nCould not allocate memory for track data.", stdout);
  70.         exit(0);
  71.     }
  72.     
  73.     get_from_file(title, TITLE_WIDE, infile);   /* read infile header data */
  74.     get_from_file(&metrate, sizeof(int), infile);
  75.     get_from_file(&meter, sizeof(int), infile);
  76.     get_from_file(&n, sizeof(int), infile);     /* ignore pitchbend flag */
  77.     get_from_file(&n, sizeof(int), infile);     /* ignore exclusive flag */
  78.     
  79.     for (i = 0; i < NTRACK; i++){
  80.         get_from_file(trackname[i], TRACK_NAME_WIDE, infile);
  81.         get_from_file(&midichan[i], sizeof(int), infile);
  82.         get_from_file(&eventcount[i], sizeof(long), infile);
  83.         get_from_file(&n, sizeof(int), infile); /* ignore play status */
  84.         get_from_file(&n, sizeof(int), infile); /* ignore midi volume */
  85.     }
  86.  
  87.     fputs("\nConverting to MIDI Files Format...\n", stdout);
  88.     
  89.     ntrack = 0;
  90.     for (i = 0; i < NTRACK; i++){   /* find number of tracks with data */
  91.         if (eventcount[i] > 1)
  92.             ntrack++;
  93.     }
  94.     write_mthd(ntrack + 1, outfile);    /* put header chunck to outfile */
  95.     
  96.     cp = buf;           /* cp points to start of allocated memory area */
  97.     
  98.     *cp++ = 0;          /* time sig., tempo and title track added first */  
  99.     *cp++ = META;       /* note that data is written to buffer. */
  100.     *cp++ = TIMESIG;
  101.     *cp++ = 4;
  102.     *cp++ = (char)meter;
  103.     *cp++ = 2;          /* MT always uses quarter note for beat, etc. */
  104.     *cp++ = 24;
  105.     *cp++ = 8;
  106.     
  107.     *cp++ = 0;
  108.     *cp++ = META;       /* tempo, most significant bytes first */
  109.     *cp++ = SETTEMPO;
  110.     msec_qnote = 60000000/metrate;      /* a long data type (4 bytes) */
  111.     cp1 = (char *)&msec_qnote;          /* cp1 points to long's memory area */
  112.     *cp++ = 3;                          /* 3 is fixed value for this META */
  113.     *cp++ = *(cp1 + 2);                 /* write value in correct order */
  114.     *cp++ = *(cp1 + 1);                 /* opposite to the 80x86 convention */
  115.     *cp++ = *cp1;
  116.  
  117.     *cp++ = 0;                          /* song name as meta text event */
  118.     *cp++ = META;
  119.     *cp++ = TEXTEVENT;
  120.     *cp++ = TITLE_WIDE;
  121.     strcpy(cp, title);                  /* title copied in one shot */
  122.     cp += TITLE_WIDE;                   /* update pointer */
  123.     
  124.     *cp++ = 0;                          /* end of title meta event */
  125.     *cp++ = META;
  126.     *cp++ = ENDTRACK;
  127.     *cp++ = 0;
  128.  
  129.     put_to_file("MTrk", 4, outfile);    /* write first track chunk */
  130.     put_len((long)(cp - buf), outfile); /* write computed buffer length */
  131.     write_buf(buf, cp, outfile);        /* write whole buffer at once */
  132.     
  133.     for (trk = 0; trk < NTRACK; trk++){
  134.         if (eventcount[trk] > 1){
  135.             cp = buf;           /* cp points back to start of memory buffer */
  136.             *cp++ = 0;          /* track name as meta instrument name event */
  137.             *cp++ = META;
  138.             *cp++ = INSNAME;
  139.             *cp++ = TRACK_NAME_WIDE;
  140.             strcpy(cp, trackname[trk]);
  141.             cp += TRACK_NAME_WIDE;
  142.             
  143.             *cp++ = 0;          /* track channel as MIDI channel prefix */
  144.             *cp++ = META;
  145.             *cp++ = CHANPREF;
  146.             *cp++ = 1;
  147.             *cp++ = midichan[trk];
  148.             
  149.             at_end = ticks = event = 0;
  150.             runstatus = 0;
  151.             while (event++ < eventcount[trk] && !at_end){
  152.                 fgetc(infile);
  153.                 for (i = 0; i < 4; i++){
  154.                     b[i] = (char) fgetc(infile);
  155.                 }
  156.                 if (b[1] == ALL_END)
  157.                     at_end = 1;
  158.                 else if (b[0] == TIME_OUT)
  159.                     ticks += 240;
  160.                 else{               /* convert event data to files format */
  161.                     ticks += b[0];
  162.                     if (b[1] >= 0x80 && b[1] <= 0xEF){  /* if MIDI channel */
  163.                         cp = copy_var_len(ticks, cp);   /* voice message */
  164.                         if (b[1] == runstatus)      /* check running status */
  165.                             ;
  166.                         else
  167.                             *cp++ = b[1];
  168.                         *cp++ = b[2];
  169.                         if (b[1] < 0xC0 || b[1] >= 0xE0)
  170.                             *cp++ = b[3];           /* if four byte message */
  171.                         ticks = 0;
  172.                         runstatus = b[1];
  173.                     }
  174.                 }
  175.                 if (cp - buf + 3 >= NBYTES){
  176.                     fputs("\nTrack shortened, out of buffer space.", stdout);
  177.                     break;
  178.                 }
  179.             }
  180.             *cp++ = 0;
  181.             *cp++ = META;
  182.             *cp++ = ENDTRACK;
  183.             *cp++ = 0;
  184.             
  185.             put_to_file("MTrk", 4, outfile);    /* write track chunk */
  186.             put_len((long)(cp - buf), outfile); /* write data length */
  187.             write_buf(buf, cp, outfile);        /* write all data at once */
  188.         }
  189.     } /* for (trk... */ 
  190.     fclose(infile);                         /* close files and exit to dos */
  191.     fclose(outfile);
  192.     fputs("\nData conversion completed.", stdout);
  193.     exit(0);
  194. }
  195.  
  196.  
  197. void
  198. write_buf(sp, ep, outfile)
  199. char *sp, *ep;
  200. FILE *outfile;
  201. {
  202.     while (sp != ep)
  203.         fputc(*sp++, outfile);
  204. }
  205.  
  206.  
  207. char 
  208. *copy_var_len(n, cp)
  209. long n;
  210. char *cp;
  211. {
  212.     register long buffer;
  213.     
  214.     buffer = n & 0x7F;
  215.     while ((n >>= 7) > 0){
  216.         buffer <<= 8;
  217.         buffer |= 0x80;
  218.         buffer += (n & 0x7F);
  219.     }
  220.     
  221.     while (buffer & 0x80){
  222.         *cp++ = (char) buffer;
  223.         buffer >>= 8;
  224.     }   
  225.     *cp++ = (char) buffer;
  226.     return(cp);
  227. }
  228.  
  229.  
  230.  
  231. void
  232. put_len(n, stream)      /* chunk lengths are always 4 bytes long */
  233. long n;
  234. FILE *stream;
  235. {
  236.     char *cp;
  237.     
  238.     cp = (char *)&n;
  239.     fputc(*(cp + 3), stream);
  240.     fputc(*(cp + 2), stream);
  241.     fputc(*(cp + 1), stream);
  242.     fputc(*cp, stream);
  243. }
  244.             
  245.     
  246.  
  247. void
  248. write_mthd(ntrack, outfile)     /* write header chunk to output file */
  249. int ntrack;
  250. FILE *outfile;
  251. {
  252.     int i, n;
  253.     
  254.     put_to_file("MThd", 4, outfile);        /* MThd  =  chunk type */
  255.     n = 0;
  256.     for (i = 0; i < 3; i++)
  257.         put_to_file(&n, 1, outfile);
  258.     n = 6;
  259.     put_to_file(&n, 1, outfile);            /* 00 00 00 06 = lenght*/
  260.     n = 0;
  261.     put_to_file(&n, 1, outfile);
  262.     n = 1;
  263.     put_to_file(&n, 1, outfile);            /* 00 01 = format */
  264.     n = 0;
  265.     put_to_file(&n, 1, outfile);
  266.     put_to_file(&ntrack, 1, outfile);       /* 00 0n = number of tracks */
  267.     put_to_file(&n, 1, outfile);
  268.     n = 120;
  269.     put_to_file(&n, 1, outfile);            /* 00 78 = 120 ticks/Q note */
  270. }
  271.  
  272.  
  273.  
  274. void
  275. get_from_file(addr, size, stream)   /* get data from stream, put into near */
  276. void *addr;                         /* memory */
  277. int size;
  278. FILE *stream;
  279. {
  280.     int i;
  281.     char *addr2;
  282.     
  283.     addr2 = (char *)addr;
  284.     for(i = 0; i < size; i++){
  285.         *addr2++ = fgetc(stream);
  286.     }
  287. }
  288.  
  289.  
  290. void
  291. put_to_file(addr, size, stream)     /* put near data to stream */
  292. void *addr;
  293. int size;
  294. FILE *stream;
  295. {
  296.     int i;
  297.     char *addr2;
  298.     
  299.     addr2 = (char *)addr;
  300.     for(i = 0; i < size; i++){
  301.         fputc(*addr2++, stream);
  302.     }
  303. }
  304.  
  305.  
  306. FILE
  307. *open_file(filename, status)
  308. char *filename, *status;
  309. {
  310.     FILE *file;
  311.     
  312.     file = fopen(filename, status);
  313.     if (file == NULL){
  314.         fputs("\nCould not open file ", stdout);
  315.         fputs(filename, stdout);
  316.         fputc('\n', stdout);
  317.         exit(0);
  318.     }
  319.     return(file);
  320. }
  321.