home *** CD-ROM | disk | FTP | other *** search
- /* mt_to_mf.c converts MT song files to Standard MIDI Files 1.0 format */
- /* `MIDI Sequencing In C', Jim Conger, M&T Books, 1989 */
-
- /* #define TURBOC 1 Define if using Turbo C, leave out for Microsoft C */
-
- #include <stdio.h>
- #include <string.h>
-
- #ifdef TURBOC
- #include <alloc.h>
- #else
- #include <malloc.h>
- #endif
-
- #define NTRACK 8
- #define TITLE_WIDE 51
- #define TRACK_NAME_WIDE 9
- #define NBYTES 30000 /* default track data buffer */
- #define TIME_OUT 0xF8
- #define ALL_END 0xFC
-
- #define META 0xFF /* meta event codes */
- #define TEXTEVENT 01
- #define SEQNAME 03
- #define INSNAME 04
- #define CHANPREF 0x20
- #define ENDTRACK 0x2F
- #define SETTEMPO 0x51
- #define TIMESIG 0X58
-
- /* function prototypes */
-
- void write_buf(char *sp, char *ep, FILE *outfile); /* function prototypes */
- char *copy_var_len(long n, char *cp);
- void put_to_file(void *addr, int size, FILE *stream);
- void put_len(long n, FILE *stream);
- void write_mthd(int ntrack, FILE *outfile);
- void get_from_file(void *addr, int size, FILE *stream);
- FILE *open_file(char *filename, char *status);
-
-
- void
- main(argc, argv)
- int argc;
- char *argv[];
- {
- char title[TITLE_WIDE], trackname[NTRACK][TRACK_NAME_WIDE];
- unsigned char *buf, *cp, *cp1, b[4], runstatus;
- int metrate, meter, ntrack, trk, midichan[NTRACK], i, n, at_end;
- long eventcount[NTRACK], event, ticks, msec_qnote;
- FILE *infile, *outfile;
-
- if (argc < 3){
- fputs("\nUsage: mt_to_mf infile outfile", stdout);
- fputs("\nWhere infile is the MT .SNG file name;", stdout);
- fputs("\n outfile is the Standard MIDI file name for output.", stdout);
- exit(0);
- }
-
- infile = open_file(argv[1], "rb"); /* open the files specified on */
- outfile = open_file(argv[2], "wb"); /* the command line. */
-
- /* All of the data is first written to a memory buffer called buf. */
- /* When conversion is complete, the buffer is written to disk. */
- /* This allows the length of the buffer to be know prior to writing. */
-
- buf = (char *)malloc(NBYTES);
- if (buf == NULL){
- fputs("\nCould not allocate memory for track data.", stdout);
- exit(0);
- }
-
- get_from_file(title, TITLE_WIDE, infile); /* read infile header data */
- get_from_file(&metrate, sizeof(int), infile);
- get_from_file(&meter, sizeof(int), infile);
- get_from_file(&n, sizeof(int), infile); /* ignore pitchbend flag */
- get_from_file(&n, sizeof(int), infile); /* ignore exclusive flag */
-
- for (i = 0; i < NTRACK; i++){
- get_from_file(trackname[i], TRACK_NAME_WIDE, infile);
- get_from_file(&midichan[i], sizeof(int), infile);
- get_from_file(&eventcount[i], sizeof(long), infile);
- get_from_file(&n, sizeof(int), infile); /* ignore play status */
- get_from_file(&n, sizeof(int), infile); /* ignore midi volume */
- }
-
- fputs("\nConverting to MIDI Files Format...\n", stdout);
-
- ntrack = 0;
- for (i = 0; i < NTRACK; i++){ /* find number of tracks with data */
- if (eventcount[i] > 1)
- ntrack++;
- }
- write_mthd(ntrack + 1, outfile); /* put header chunck to outfile */
-
- cp = buf; /* cp points to start of allocated memory area */
-
- *cp++ = 0; /* time sig., tempo and title track added first */
- *cp++ = META; /* note that data is written to buffer. */
- *cp++ = TIMESIG;
- *cp++ = 4;
- *cp++ = (char)meter;
- *cp++ = 2; /* MT always uses quarter note for beat, etc. */
- *cp++ = 24;
- *cp++ = 8;
-
- *cp++ = 0;
- *cp++ = META; /* tempo, most significant bytes first */
- *cp++ = SETTEMPO;
- msec_qnote = 60000000/metrate; /* a long data type (4 bytes) */
- cp1 = (char *)&msec_qnote; /* cp1 points to long's memory area */
- *cp++ = 3; /* 3 is fixed value for this META */
- *cp++ = *(cp1 + 2); /* write value in correct order */
- *cp++ = *(cp1 + 1); /* opposite to the 80x86 convention */
- *cp++ = *cp1;
-
- *cp++ = 0; /* song name as meta text event */
- *cp++ = META;
- *cp++ = TEXTEVENT;
- *cp++ = TITLE_WIDE;
- strcpy(cp, title); /* title copied in one shot */
- cp += TITLE_WIDE; /* update pointer */
-
- *cp++ = 0; /* end of title meta event */
- *cp++ = META;
- *cp++ = ENDTRACK;
- *cp++ = 0;
-
- put_to_file("MTrk", 4, outfile); /* write first track chunk */
- put_len((long)(cp - buf), outfile); /* write computed buffer length */
- write_buf(buf, cp, outfile); /* write whole buffer at once */
-
- for (trk = 0; trk < NTRACK; trk++){
- if (eventcount[trk] > 1){
- cp = buf; /* cp points back to start of memory buffer */
- *cp++ = 0; /* track name as meta instrument name event */
- *cp++ = META;
- *cp++ = INSNAME;
- *cp++ = TRACK_NAME_WIDE;
- strcpy(cp, trackname[trk]);
- cp += TRACK_NAME_WIDE;
-
- *cp++ = 0; /* track channel as MIDI channel prefix */
- *cp++ = META;
- *cp++ = CHANPREF;
- *cp++ = 1;
- *cp++ = midichan[trk];
-
- at_end = ticks = event = 0;
- runstatus = 0;
- while (event++ < eventcount[trk] && !at_end){
- fgetc(infile);
- for (i = 0; i < 4; i++){
- b[i] = (char) fgetc(infile);
- }
- if (b[1] == ALL_END)
- at_end = 1;
- else if (b[0] == TIME_OUT)
- ticks += 240;
- else{ /* convert event data to files format */
- ticks += b[0];
- if (b[1] >= 0x80 && b[1] <= 0xEF){ /* if MIDI channel */
- cp = copy_var_len(ticks, cp); /* voice message */
- if (b[1] == runstatus) /* check running status */
- ;
- else
- *cp++ = b[1];
- *cp++ = b[2];
- if (b[1] < 0xC0 || b[1] >= 0xE0)
- *cp++ = b[3]; /* if four byte message */
- ticks = 0;
- runstatus = b[1];
- }
- }
- if (cp - buf + 3 >= NBYTES){
- fputs("\nTrack shortened, out of buffer space.", stdout);
- break;
- }
- }
- *cp++ = 0;
- *cp++ = META;
- *cp++ = ENDTRACK;
- *cp++ = 0;
-
- put_to_file("MTrk", 4, outfile); /* write track chunk */
- put_len((long)(cp - buf), outfile); /* write data length */
- write_buf(buf, cp, outfile); /* write all data at once */
- }
- } /* for (trk... */
- fclose(infile); /* close files and exit to dos */
- fclose(outfile);
- fputs("\nData conversion completed.", stdout);
- exit(0);
- }
-
-
- void
- write_buf(sp, ep, outfile)
- char *sp, *ep;
- FILE *outfile;
- {
- while (sp != ep)
- fputc(*sp++, outfile);
- }
-
-
- char
- *copy_var_len(n, cp)
- long n;
- char *cp;
- {
- register long buffer;
-
- buffer = n & 0x7F;
- while ((n >>= 7) > 0){
- buffer <<= 8;
- buffer |= 0x80;
- buffer += (n & 0x7F);
- }
-
- while (buffer & 0x80){
- *cp++ = (char) buffer;
- buffer >>= 8;
- }
- *cp++ = (char) buffer;
- return(cp);
- }
-
-
-
- void
- put_len(n, stream) /* chunk lengths are always 4 bytes long */
- long n;
- FILE *stream;
- {
- char *cp;
-
- cp = (char *)&n;
- fputc(*(cp + 3), stream);
- fputc(*(cp + 2), stream);
- fputc(*(cp + 1), stream);
- fputc(*cp, stream);
- }
-
-
-
- void
- write_mthd(ntrack, outfile) /* write header chunk to output file */
- int ntrack;
- FILE *outfile;
- {
- int i, n;
-
- put_to_file("MThd", 4, outfile); /* MThd = chunk type */
- n = 0;
- for (i = 0; i < 3; i++)
- put_to_file(&n, 1, outfile);
- n = 6;
- put_to_file(&n, 1, outfile); /* 00 00 00 06 = lenght*/
- n = 0;
- put_to_file(&n, 1, outfile);
- n = 1;
- put_to_file(&n, 1, outfile); /* 00 01 = format */
- n = 0;
- put_to_file(&n, 1, outfile);
- put_to_file(&ntrack, 1, outfile); /* 00 0n = number of tracks */
- put_to_file(&n, 1, outfile);
- n = 120;
- put_to_file(&n, 1, outfile); /* 00 78 = 120 ticks/Q note */
- }
-
-
-
- void
- get_from_file(addr, size, stream) /* get data from stream, put into near */
- void *addr; /* memory */
- int size;
- FILE *stream;
- {
- int i;
- char *addr2;
-
- addr2 = (char *)addr;
- for(i = 0; i < size; i++){
- *addr2++ = fgetc(stream);
- }
- }
-
-
- void
- put_to_file(addr, size, stream) /* put near data to stream */
- void *addr;
- int size;
- FILE *stream;
- {
- int i;
- char *addr2;
-
- addr2 = (char *)addr;
- for(i = 0; i < size; i++){
- fputc(*addr2++, stream);
- }
- }
-
-
- FILE
- *open_file(filename, status)
- char *filename, *status;
- {
- FILE *file;
-
- file = fopen(filename, status);
- if (file == NULL){
- fputs("\nCould not open file ", stdout);
- fputs(filename, stdout);
- fputc('\n', stdout);
- exit(0);
- }
- return(file);
- }
-