/* midiplay - plays MIDI file through PC internal speaker * * version 1.1 * * written by James Allwright 27th March 1997 * Department of Electronics and Computer Science, * University of Southampton, UK * Comments to jra@ecs.soton.ac.uk * * karaoke capability added October 1998. * * based on public domain 'midifilelib' package. * * This code may be freely distributed. */ #include #include #include "midifile.h" static FILE *F; int SECONDS; /* global that tells whether to display seconds or ticks */ int division; /* from the file header */ long tempo = 500000; /* the default tempo is 120 beats/minute */ int unitlen; int channel; int track, trackno, settrack; int karaokeon; int format; int active[256]; int transpose; int tempofactor; extern char* index(); #define MAXSYLL 20 struct note_type { long start, stop; int pitch; char text[MAXSYLL]; /* should be enough for most syllables */ struct note_type *next; }; struct note_type *head; struct note_type *tail; struct note_type *textplace; struct note_type* create(my_pitch, now) int my_pitch; long now; { extern char* malloc(); struct note_type* newitem; newitem = (struct note_type*) malloc(sizeof(struct note_type)); if (newitem == NULL) { printf("Could not allocate memory for note\n"); exit(0); }; newitem->next = NULL; newitem->start = now; newitem->pitch = my_pitch; newitem->text[0] = '\0'; /* empty string */ return(newitem); }; change(newpitch, time) int newpitch; long time; { if (time == tail->start) { tail->pitch = newpitch; } else { tail->stop = time; tail->next = create(newpitch, time); tail = tail->next; }; }; addwords(p, s) struct note_type* p; char* s; { char *linebreak; if ((strlen(s) + strlen(p->text)) < MAXSYLL) { strcpy(p->text + strlen(p->text), s); linebreak = index(p->text, '\\'); /* use only one linebreak marker for simplicity */ if (linebreak != NULL) { *linebreak = '/'; }; } else { /* assume any long strings are not part of the karaoke words */ printf("- %s\n", s); }; }; struct note_type* findtextplace(p, now) /* find place in list for karaoke syllables words to go */ /* p is old value for textplace, normally just before now */ struct note_type* p; long now; /* time */ { struct note_type* q; q = p; if ((q == NULL) || (q->start > now)) { q = head; }; while ((q != NULL) && (q->start < now)) { q = q->next; }; return(q); } dotext(place) struct note_type* place; { struct note_type* t; char *c; char *q; c = index(place->text, '/'); if (c != NULL) { /* print out whole line in advance */ c++; printf("\r\"%s", c); t = place->next; while ((t != NULL) && (index(t->text, '/') == NULL)) { printf(t->text); t = t->next; }; if (t != NULL) { q = t->text; while (*q != '/') { printf("%c", *q); q++; }; }; printf("\"\n %s", c); } else { printf(place->text); }; } filegetc() { return(getc(F)); } /* for crack */ extern int arg_index; int readnum(num) char *num; { int t; char *p; t = 0; p = num; while (((int)*p >= '0') && ((int)*p <= '9')) { t = t * 10 + (int) *p - '0'; p = p + 1; }; return t; }; int readnump(p) char **p; { int t; t = 0; while (((int)**p >= '0') && ((int)**p <= '9')) { t = t * 10 + (int) **p - '0'; *p = *p + 1; }; return t; }; int getarg(option, argc, argv) char *option; char *argv[]; int argc; { int j, place; place = -1; for (j=0; j\n"); printf(" -t \n"); printf(" -c \n"); printf(" -s \n"); printf(" -p 100 = no change\n"); printf(" -i more information\n"); exit(0); }; arg = getarg("-t", argc, argv); if ((arg != -1) && (arg < argc)) { track = readnum(argv[arg]); settrack = 1; } else { track = 0; settrack = 0; }; arg = getarg("-p", argc, argv); if ((arg != -1) && (arg < argc)) { tempofactor = readnum(argv[arg]) - 1; } else { tempofactor = 100; }; arg = getarg("-c", argc, argv); if ((arg != -1) && (arg < argc)) { channel = readnum(argv[arg]) - 1; } else { channel = -1; }; transpose = 0; arg = getarg("-s", argc, argv); if ((arg != -1) && (arg < argc)) { int t; if (*argv[arg] == '-') { transpose = - readnum(argv[arg] + 1); } else { transpose = readnum(argv[arg]); }; }; trackno = 0; initfuncs(); Mf_getc = filegetc; mfread(); fclose(F); /* finish off tune */ tail->stop = Mf_currtime; /* post-process tune */ place = head; while (place != NULL) { long dt; if (place->stop > place->start) { dt = place->stop - place->start; place->start = (long) (1000000.0 * mf_ticks2sec(dt, division, tempo) * ((float) tempofactor/100.0)); } else { place->start = (long) 0; }; if (place->pitch != -1) { place->pitch = interval[place->pitch]; }; place = place->next; }; /* play tune */ place = head; while (place != NULL) { dotext(place); note(place->pitch, place->start); place = place->next; }; clearkey(); /* free up space */ place = head; while (place != NULL) { tail = place->next; free(place); place = tail; }; }; FILE * efopen(name,mode) char *name; char *mode; { FILE *f; /* extern int errno; extern char *sys_errlist[]; extern int sys_nerr; char *errmess; */ if ( (f=fopen(name,mode)) == NULL ) { (void) fprintf(stderr,"*** ERROR *** Cannot open '%s'!\n",name); /* if ( errno <= sys_nerr ) errmess = sys_errlist[errno]; else errmess = "Unknown error!"; (void) fprintf(stderr,"************* Reason: %s\n",errmess); */ exit(1); } return(f); } error(s) char *s; { fprintf(stderr,"Error: %s\n",s); } txt_header(xformat,ntrks,ldivision) int xformat, ntrks, ldivision; { division = ldivision; format = xformat; } txt_trackstart() { trackno = trackno + 1; /* read from first non-empty track */ if ((settrack == 0) && (head == tail)) { track = trackno; }; } txt_trackend() { karaokeon = 0; } int trackfilter() { return ((track == 0) || (track == trackno)); }; int chantrackfilter(chan) int chan; { return (((channel == -1) || (channel == chan)) && ((track == 0) || (track == trackno))); }; do_on(pitch) int pitch; { active[pitch] = 1; if (pitch > tail->pitch) { change(pitch, Mf_currtime); }; }; do_off(pitch) int pitch; { int i, nextpitch; active[pitch] = 0; nextpitch = -1; i = 255; while ((i>-1) && (nextpitch == -1)) { if (active[i] == 1) { nextpitch = i; }; i = i - 1; }; change(nextpitch, Mf_currtime); }; int clip(x) int x; { int y; y = x; if (y > 255) y = 255; if (y < 0) y = 0; return(y); }; txt_noteon(chan,pitch,vol) int chan, pitch, vol; { if (chantrackfilter(chan)) { if (vol != 0) { do_on(clip(pitch+transpose)); } else { do_off(clip(pitch+transpose)); }; }; } txt_noteoff(chan,pitch,vol) int chan, pitch, vol; { if (chantrackfilter(chan)) { do_off(clip(pitch+transpose)); }; } txt_pressure(chan,pitch,press) int chan, pitch, press; { } txt_parameter(chan,control,value) int chan, control, value; { } txt_pitchbend(chan,msb,lsb) int chan, msb, lsb; { } txt_program(chan,program) int chan, program; { } txt_chanpressure(chan,press) int chan, press; { } txt_sysex(leng,mess) int leng; char *mess; { } txt_metamisc(type,leng,mess) int type, leng; char *mess; { } txt_metaspecial(type,leng,mess) int type, leng; char *mess; { } txt_metatext(type,leng,mess) int type, leng; char *mess; { char buffer[40]; int i, l; l = leng; if (l>39) { l = 39; }; for (i=0; i