/* history * lfa: added support for time signature */ #include #include #define MAXDELTA 31 #define NUMNOTES 45 // opcodes when TNE = 31 and channles = 0 #define CONTINUE 1 #define STOP 0 #define SETTEMPO 3 typedef struct event{ int time; int chan; int tone; int on ; struct event* next; struct event* prev; } etype; // tslice is the length int qn_units; int meas; float start; char note[10]; char vel[10]; float dur; float tempo = 200; // in quarter notes per timeslices float tslice = 10; // in milliseconds float resolution; int chan[4] ={0,0,0,0};// tone currently played by channel char *name; /*int cntdwn[NUMNOTES] = {14, 15, 16, 17, 18, 19, 20, 21, 23, 24, 26, 27, 29, 30, 32, 34, 36, 38, 40, 43, 45, 48, 51, 54, 57, 61, 64, 68, 72, 76, 81, 86, 91, 96, 102, 108, 115, 121, 129, 136, 144, 153, 162, 172, 182}; */ int offsets[256]; etype* addEvent(etype *, etype *); etype* getNextPlayed(etype *); void dumpEvents(etype *); void printEvent(etype *); void assignChan(etype *); void cleanUp(etype *); void dumpHeader(int); void dumpPacket(unsigned, unsigned *); int note2index(); FILE *fd, *of; int octave_shift; int beat; main (int argc, char *argv[]) { char line[100]; int ix,begin, end; etype *ev; // tmp variable etype *first; // always points to the earliest event; etype *last; // always points to the latest event; char track[10]; int intrack; if (argc != 8) { printf( "usage: \n", argc); exit(0); } octave_shift = atoi(argv[5]); printf ("Octave shift is %d\n", octave_shift); of = fopen(argv[6],"w"); if (!of) { printf("failed to open %s\n", argv[6]); exit(); } fd = fopen(argv[1],"r"); if (!fd) { printf("failed to open %s\n", argv[1]); exit(); } name = argv[7]; sprintf(track, "Track %d", atoi(argv[2])); printf("seeking track %s\n", track); intrack = 0; tempo = (float)atoi(argv[3]); tslice = (float)atoi(argv[4]); printf("%f %f\n", tempo, tslice); dumpHeader(tslice); /* create three zero time events to turn everything off */ // channel 0 init event first = (etype*)malloc(sizeof(etype)); first->chan = 1; first->tone = 0; first->time = 0; first->on = 0; first->next = (etype*)malloc(sizeof(etype)); first->prev = NULL; // channel 1 init event ev = first->next; ev->prev = first; ev->chan = 2; ev->tone = 0; ev->time = 0; ev->on = 0; ev->next = (etype*)malloc(sizeof(etype)); ev->next->prev = ev; // channel 2 init event ev = ev->next; ev->chan = 3; ev->tone = 0; ev->time = 0; ev->on = 0; ev->next = NULL; last = ev; offsets['A'] = 0; offsets['B'] = 2; offsets['C'] = 3; offsets['D'] = 5; offsets['E'] = 7; offsets['F'] = 8; offsets['G'] = 10; /* first read the units/quarternote */ fscanf(fd, "%d", &qn_units); printf("units = %d\n", qn_units); printf("resolution is %f\n", resolution = (((float)qn_units) * ((tempo / 60) * (tslice/1000)))); while (fgets(line, 100, fd)) { if (*line == 'T') { line[7] = NULL; if (strcmp(line, track) ==0) intrack = 1; else intrack = 0; } if (intrack && *line == 'M' && line[10] != '=') { if (parseLine(line)) { //printf("%s",line); begin = getStart(); end = getEnd(begin); ix = note2index(); if (begin != -1) { ev = (etype*)malloc(sizeof(etype)); ev->next = NULL; ev->prev = NULL; ev->on = 1; ev->tone = ix; ev->time = begin/resolution; last = addEvent(last,ev); } if (end != -1) { ev = (etype*)malloc(sizeof(etype)); ev->next = NULL; ev->prev = NULL; ev->tone = ix; ev->on = 0; ev->time = end/resolution; last = addEvent(last,ev); } } } else if (intrack && *line == 'M' && line[10] == '=') { line[20] = NULL; beat = atoi(&line[19]); } } assignChan(first); cleanUp(first); dumpEvents(first); fprintf(of,"ff000000f80%x", STOP); //turns off all channels and sends stop command fclose(of); fclose(fd); } int parseLine(char* line) { meas = -1; start = -1; *note = NULL; *vel = NULL; dur = -1; while (*line == 'M' || *line == '0') line++; if (sscanf(line, "%d %f %s %s %f", &meas, &start, note, vel, &dur) == 5 || sscanf(line, "%d %f %s %s TIE",&meas, &start, note, vel) == 4 || sscanf(line, "%d TIE %s %s %f", &meas, note, vel, &dur) == 4) { //printf("meas = %d start = %f note = %s vel = %s dur = %f\n", meas, start, note, vel, dur); return (1); } else return (0); } int getStart() { if (start != -1) return ( (meas*beat*qn_units) + (floor(start)-1)*qn_units + (1000*(start - floor(start)))); else return (-1); } int getEnd(int begin) { if (dur != -1) { if (begin == -1) // this is a TIE return ( (meas*beat*qn_units) + (floor(dur)-1)*qn_units + (dur - floor(dur))); else return ( begin + (floor(dur)*qn_units + (1000*(dur - floor(dur))))); } else return (-1); } etype* addEvent( etype* l, etype* e ) { // add events to the list sorted by time while (l->time > e->time) { l = l->prev; // go back in time } // insert the event e->next = l->next; e->prev = l; l->next = e; if (e->next) e->next->prev = e; // re-establish last while (l->next) l = l->next; return(l); } int getChan(int tone) { if (chan[1] == tone) return 1; if (chan[2] == tone) return 2; if (chan[3] == tone) return 3; return(0); } void dumpPacket(unsigned b1, unsigned * t){ if (b1 <= 15) fprintf(of, "0"); fprintf(of,"%x",b1); if (b1 & 0x01) {if (t[1]<=15) fprintf(of,"0"); fprintf(of,"%x", t[1]);} if (b1 & 0x02) {if (t[2]<=15) fprintf(of,"0"); fprintf(of,"%x", t[2]);} if (b1 & 0x04) {if (t[3]<=15) fprintf(of,"0"); fprintf(of,"%x", t[3]);} if (!(b1 & 0x07)) {if (t[0]<=15) fprintf(of,"0"); fprintf(of,"%x", t[0]);} // this case tone 0 is the opcode // for the listing printf("%2x",b1); if (b1 & 0x01) printf("%2x", t[1]); if (b1 & 0x02) printf("%2x", t[2]); if (b1 & 0x04) printf("%2x", t[3]); if (!(b1 & 0x07)) printf("%2x", t[0]); // this case tone 0 is the opcode printf("\n"); } void assignChan(etype* f) { while (f) { if (f->chan) chan[f->chan] = f->tone; //init each to off //first 3 are off events //for each channel else if (f->on) { f->chan = getChan(0); //find unused channel if (f->chan) chan[f->chan] = f->tone; //set to this tone } else { f->chan = getChan(f->tone); // find channel for this tone if (f->chan) chan[f->chan] = 0; //clear the channel else printf("warning: off event w/ no on event\n"); } f = f->next; } } void dumpEvents(etype* f) { unsigned TNE; int time = 0; unsigned byte1 = 0; unsigned tones[4] = {0,0,0}; etype *tmp; while (f) { if (f->chan) { printEvent(f); if (tmp = getNextPlayed(f)) TNE = tmp->time - f->time; else TNE = 0; if (TNE == 0) { byte1 |= 1 << (f->chan-1); tones[f->chan] = f->on * f->tone; } else { if (TNE > MAXDELTA) { byte1 = (MAXDELTA << 3) | (byte1 & 0x07) | (1<<((f->chan)-1)); TNE -= MAXDELTA; } else { byte1 = (TNE << 3) | (byte1 & 0x07) | (1<<((f->chan)-1)); TNE = 0; } tones[f->chan] = f->on * f->tone; dumpPacket(byte1, tones); byte1 = 0; } while (TNE) { printf("repeat %d\n", TNE); byte1 = ((MAXDELTAMAXDELTA) TNE -= MAXDELTA; else TNE = 0; } } else printf("skipping t = %d, tone = %d, chan = %d event=%d\n", (f->time - time), f->tone, f->chan, f->on); f = f->next; } } void cleanUp(etype *f) { etype *tmp; f = f->next; // don't start at the beginning while (f->next) { if (!f->chan) { tmp = f; f->next->prev = f->prev; f->prev->next = f->next; printf("unplayed..."); printEvent(tmp); free(tmp); } else if (f->time == f->next->time) { //same time if (f->chan == f->next->chan) { //same channel if (f->on) { // delete next event tmp = f->next; f->next = tmp->next; f->next->prev = f; printf("cancelling..."); printEvent(tmp); free(tmp); } else { // f is off, assume next is on tmp = f; f->next->prev = f->prev; f->prev->next = f->next; f = f->next; printf("cancelling..."); printEvent(tmp); free(tmp); } } } f = f->next; // go to next event } } void printEvent(etype* f) { printf("absolute time = %d, tone = %d, chan = %d event= %d\n", f->time, f->tone, f->chan, f->on); } etype *getNextPlayed(etype *f) { while (f->next) { if (f->next->chan) return (f->next); f = f->next; } return(NULL); } int note2index() { char *n; int base; n = note; base = offsets[*n]; // lowest instance of this note if (*++n == '#') { base++; n++; } base = base + (12*(atoi(n)-1)) + (octave_shift*12); if (base < 0) {base = 0; printf("warning: out of low range\n");} if (base > NUMNOTES-1) { base = NUMNOTES-1; printf("warning: out of hi range\n"); } return(base); } void dumpHeader(int t) { int len; len = strlen(name); if (len <= 15) fprintf(of,"0%x", len); else fprintf(of,"%x",len); fprintf(of,"%s",name); if (t <= 15) fprintf(of,"0%x", t); else fprintf(of,"%x", t); }