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