/* ** TAB2MPU -- Convert tab to mpu format ** psl 3/88 */ #include #include #define MAXSTRINGS 16 /* that ought to hold them */ #define KVEL 0x40 /* default volume */ #define TIECHAR '(' int Cps = 30; /* MPU clocks / note, (sixteenths) */ int Acps = 24; /* articulated Cps (sixteenths, 80% duty) */ int Tuning[MAXSTRINGS]; /* How the instrument is tuned */ int Chan[MAXSTRINGS]; /* channels for each string */ int Nut[MAXSTRINGS]; /* string lengths (e.g. banjo Nut[4] = 5) */ int Nstrings = 0; int Kvel = KVEL; /* how loud we're playing (key velocity) */ int Nn[] = { 9, 11, 0, 2, 4, 5, 7, }; double Artic = 0.8; /* articulation, note duty cycle */ long Lastwhen; extern double atof(); main(argc, argv) char *argv[]; { register int i; FILE *ifp; ifp = stdin; for (i = 1; i < argc; i++) { if (argv[i][0] == '-') { switch (argv[i][1]) { default: fprintf(stderr, "Usage: %s [file or stdin]\n", argv[0]); fprintf(stderr, "See tab(5) for tab language details.\n"); exit(2); } } else if (!(ifp = fopen(argv[i], "r"))) perror(argv[i]); else { detab(ifp, stdout); fclose(ifp); } } if (ifp == stdin) detab(ifp, stdout); exit(0); } detab(ifp, ofp) FILE *ifp, *ofp; { char *cp, buf[256], a[9][64]; int nr, nf, s, fret[MAXSTRINGS], a0; long when, offtime; when = Lastwhen = offtime = 0L; for (nr = 1; fgets(buf, sizeof buf, ifp); nr++) { nf = sscanf(buf, "%s%s%s%s%s%s%s%s%s", a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]); if (nf <= 0) continue; if (a[0][0] == '#') { if (strcmp(a[0], "#ARTIC") == 0) { Artic = atof(a[1]); if (Artic <= 0. || Artic > 1.) { fprintf(stderr, "Error in: %s", buf); fprintf(stderr, "Articulation range is 0.1 to 1.0\n"); Artic = 0.8; } Acps = Cps * Artic + 0.5; } else if (strcmp(a[0], "#CHANS") == 0) { getnums(nr, nf, a, Chan, "channel", 1, 16, -1); } else if (strcmp(a[0], "#NUT") == 0) { getnums(nr, nf, a, Nut, "nut", 0, 22, 0); } else if (strcmp(a[0], "#SPEED") == 0) { Cps = (2 * MPU_CLOCK_PERIOD) / atoi(a[1]); Acps = Cps * Artic + 0.5; } else if (strcmp(a[0], "#TUNING") == 0) { Nstrings = gettuning(nr, nf, a); for (s = Nstrings; --s >= 0; fret[s] = -1); } else if (strcmp(a[0], "#VOL") == 0 || strcmp(a[0], "#VOLUME") == 0 || strcmp(a[0], "#VEL") == 0 || strcmp(a[0], "#VELOCITY") == 0) { Kvel = atoi(a[1]); } continue; } if (Nstrings == 0) { fprintf(stderr, "Line %d: data before '#TUNING' spec\n", nr); exit(1); } a0 = (*buf > ' ')? 1 : 0; /* skip finger info */ if (nf - a0 < Nstrings) { fprintf(stderr, "Line %d: missing data\n", nr); exit(1); } for (s = Nstrings; --s >= 0; ) { cp = a[a0 + Nstrings - s - 1]; if (*cp != TIECHAR && fret[s] != -1) { pluck(ofp, offtime, s, fret[s], 0); /* key-off */ fret[s] = -1; } } for (s = Nstrings; --s >= 0; ) { cp = a[a0 + Nstrings - s - 1]; if ('0' <= *cp && *cp <= '9') pluck(ofp, when, s, fret[s] = atoi(cp), Kvel); /* key-on */ } offtime = when + Acps; when += Cps; } for (s = Nstrings; --s >= 0; ) if (fret[s] != -1) pluck(ofp, offtime, s, fret[s], 0); /* key-off */ pluck(ofp, when, -1, -1, -1); /* TCWME */ } pluck(ofp, when, s, f, v) FILE *ofp; long when; { int dt; dt = when - Lastwhen; while (dt >= MPU_CLOCK_PERIOD) { putc(RT_TCIP, ofp); dt -= MPU_CLOCK_PERIOD; } putc(dt, ofp); /* timing byte */ if (s >= 0 && f >= 0 && v >= 0) { putc(CH_KEY_ON | Chan[s], ofp); if (f == 0) putc(Tuning[s], ofp); else putc(Tuning[s] + f - Nut[s], ofp); putc(v, ofp); } else putc(RT_TCWME, ofp); Lastwhen = when; } gettuning(nr, nf, a) char a[][64]; { register char *cp; register int n, i; int t[MAXSTRINGS]; for (n = 0; n < nf - 1 && n < MAXSTRINGS; n++) { cp = a[n + 1]; i = -1; if ('0' <= *cp && *cp <= '9') i = strtol(cp, 0, 0); else if ('A' <= *cp && *cp <= 'G') i = pitch2num(nr, cp); if (i > -1) t[n] = i; else { fprintf(stderr, "Line %d: Note format error in %s", nr, cp); exit(1); } } for (i = n; --i >= 0; Tuning[i] = t[n - i - 1]); return(n); } pitch2num(nr, buf) char *buf; { register char *cp = buf; register int n, o; if (*cp == 'R' || *cp == '-') return(-1); if (*cp < 'A' || *cp > 'G') { fprintf(stderr, "Line %d: bad note format in %s\n", nr, buf); return(-1); } n = Nn[*cp++ - 'A']; while (*cp == 'b') { --n; cp++; } while (*cp == '#') { n++; cp++; } if (*cp == '-') o = -(*++cp - '0'); else o = *cp - '0'; if (o < -1 || o > 8) { fprintf(stderr, "Line %d: octave out of range in: %s\n", nr, buf); return(-1); } return(12 + 12 * o + n); } getnums(nr, nf, a, array, name, lo, hi, delta) char a[][64], *name; int array[]; { register char *cp; register int n, i; int x[MAXSTRINGS]; for (n = 0; n < nf - 1 && n < MAXSTRINGS; n++) { cp = a[n + 1]; i = strtol(cp, 0, 0); if (lo <= i && i <= hi) x[n] = i + delta; else { fprintf(stderr, "Line %d: %s spec error (range is %d:%d)\n", nr, name, lo, hi); exit(1); } } for (i = n; --i >= 0; array[i] = x[n - i - 1]); return(n); }