#include #include /* ** SCAT -- Scat (on a Dectalk) a MIDI melody ** psl 1/86 */ char *syl[] = { "doo", "bee", }; #define NSYL (sizeof syl / sizeof syl[0]) /* ** NOTEDUR -- Adjust note durations ** Two pass, first copy all but key-offs and calc key-off times. ** On second pass insert key-offs. ** newdur = max(fact * olddur + konst, mindur) ** psl 1/86 */ #include #include #define MAXCHAN 16 #define MAXKEY 128 #define UNITY 1024 #define MAXQ 4096 struct qstr { /* key-off events */ long when; char mode; char key; } queue[MAXQ]; struct qstr *qip = queue; struct qstr *qop = queue; char tempfile[64]; int konst = 0; /* constant note duration, MIDI clocks */ int fact = UNITY; /* proportion of old duration */ int mindur = 10; /* minimum note duration, MIDI clocks */ int join = 0; /* if set, join overlapped notes */ main(argc, argv) char *argv[]; { FILE *tfp; int comp(); extern double atof(); if (argc < 2) { syntax: fprintf(stderr, "Usage: %s [options] new\n", argv[0]); fprintf(stderr, "-f#.# sets the new/old duration ratio.\n"); fprintf(stderr, "-k# sets a duration constant in MIDI clocks.\n"); fprintf(stderr, "-m# sets the minimum duration in MIDI clocks.\n"); fprintf(stderr, " new_dur = max(f * old_dur + k, m)\n"); fprintf(stderr, "-legato is a synonym for: -f1.5.\n"); fprintf(stderr, "-staccato is a synonym for: -f0.25 -k10.\n"); fprintf(stderr, "-articulated is a synonym for: -f0.98.\n"); fprintf(stderr, "-join causes overlapped notes to become one.\n"); fprintf(stderr, "defaults are: -f1.0 -k0 -m10\n"); exit(2); } while (--argc > 0) { if (argv[argc][0] == '-') { switch (argv[argc][1]) { case 'a': fact = UNITY * 0.98; break; case 'f': fact = UNITY * atof(&argv[argc][2]); break; case 'j': join = 1; break; case 'k': konst = atoi(&argv[argc][2]); break; case 'l': fact = UNITY * 1.5; break; case 'm': mindur = atoi(&argv[argc][2]); break; case 's': fact = UNITY * 0.25; konst = 10; break; default: goto syntax; } } } if (mindur < 0) goto syntax; sprintf(tempfile, "/tmp/notedur%d", getpid()); if ((tfp = fopen(tempfile, "w")) == (FILE *) NULL) { perror(tempfile); exit(1); } copyfile(stdin, tfp); fclose(tfp); qsort(queue, qip - qop, sizeof queue[0], comp); if ((tfp = fopen(tempfile, "r")) == (FILE *) NULL) { perror(tempfile); exit(1); } merge(tfp, stdout); unlink(tempfile); } copyfile(ifp, ofp) FILE *ifp, *ofp; { register int i, k, v, curmode, dur, chan; int key[MAXCHAN][MAXKEY]; long now, last, start[MAXCHAN][MAXKEY]; for (chan = MAXCHAN; --chan >= 0; ) for (k = MAXKEY; --k >= 0; ) key[chan][k] = 0; curmode = 0; now = last = 0; while ((i = getc(ifp)) != EOF) { if (i == 0xF8) { now += MPU_CLOCK_PERIOD; continue; } now += i; if ((k = getc(ifp)) == EOF) { fprintf(stderr, "EOF after 0x%x (now=%d)\n", i, now); exit(1); } if (k & 0x80) { if ((k & 0xF0) == 0xF0) { if (k < 0xF8) { /* sys excl or sys common */ if (k == 0xF0) { /* sys excl */ put2(ofp, now - last, k); do { k = getc(ifp); putc(k, ofp); } while (k != 0xF7); } else if (k == 0xF2) { /* song position */ k = getc(ifp); put4(ofp, now - last, 0xF2, k, getc(ifp)); } else if (k == 0xF3) { /* song select */ put3(ofp, now - last, k, getc(ifp)); } else { put2(ofp, now - last, k); } curmode = 0; } else /* sys real time */ put2(ofp, now - last, k); last = now; continue; } curmode = k; if ((k = getc(ifp)) == EOF) { fprintf(stderr, "EOF after %x (mode)\n", curmode); exit(1); } } i = curmode & 0xF0; chan = curmode % MAXCHAN; if (i == 0xA0 /* poly pressure */ || i == 0xB0 /* mod wheel */ || i == 0xE0) { /* pitch bend */ put4(ofp, now - last, curmode, k, getc(ifp)); last = now; continue; } else if (i == 0xC0 /* prog change */ || i == 0xD0) { /* chan pressure */ put3(ofp, now - last, curmode, k); last = now; continue; } else if (i == 0x90 || i == 0x80) { /* key-on/off event */ if ((v = getc(ifp)) == EOF) { fprintf(stderr, "unexpected EOF in mode %x\n", curmode); exit(1); } if (i == 0x80) /* hack to turn 0x80 into 0x90 */ v = 0; if (v != 0) { /* key-on */ if (key[chan][k] == 0 || join == 0) { put4(ofp, now - last, curmode, k, v); last = now; start[chan][k] = now; } key[chan][k]++; } else { /* key-off */ if (--key[chan][k] < 0) { /* extra key-off */ key[chan][k] = 0; continue; } if (key[chan][k] == 0 || join == 0) { dur = (fact * (now - start[chan][k])) / UNITY + konst; dur = dur < mindur? mindur : dur; qip->when = start[chan][k] + dur; qip->mode = 0x90 | chan; qip->key = k; if (++qip == &queue[MAXQ]) qip = queue; if (qip == qop) { fprintf(stderr, "Key-off queue overflow!\n"); exit(1); } } } } } } comp(q1, q2) struct qstr *q1, *q2; { return((int) (q1->when - q2->when)); } merge(ifp, ofp) FILE *ifp, *ofp; { register int i, k, v, curmode, stat; long now, last; curmode = 0; now = last = 0; while ((i = getc(ifp)) != EOF) { if (i == RT_TCIP) { now += MPU_CLOCK_PERIOD; continue; } now += i; while (qop != qip && qop->when <= now) { put4(ofp, qop->when - last, qop->mode, qop->key, 0); last = qop->when; if (++qop == &queue[MAXQ]) qop = queue; } curmode = getc(ifp); stat = curmode & 0xF0; if (curmode > 0xF3 || curmode == 0xF1) { put2(ofp, now - last, curmode); last = now; continue; } if (curmode == 0xF0) { /* sys excl */ put2(ofp, now - last, curmode); last = now; do { k = getc(ifp); putc(k, ofp); } while (k != 0xF7); continue; } k = getc(ifp); if (stat == 0xC0 || stat == 0xD0 || curmode == 0xF3) { put3(ofp, now - last, curmode, k); last = now; continue; } v = getc(ifp); put4(ofp, now - last, curmode, k, v); last = now; } while (qop != qip) { put4(ofp, qop->when - last, curmode = qop->mode, qop->key, 0); last = qop->when; if (++qop == &queue[MAXQ]) qop = queue; } if (curmode != 0xF9) /* a final command */ put2(ofp, now > last? now - last : 0, 0xF9); } put2(ofp, dt, mode) FILE *ofp; long dt; { if (ofp == (FILE *) 0) return; if (dt < 0) dt = 0; putdt(ofp, dt); putc(mode, ofp); } put3(ofp, dt, mode, n) FILE *ofp; long dt; { if (ofp == (FILE *) 0) return; if (dt < 0) dt = 0; putdt(ofp, dt); putc(mode, ofp); putc(n, ofp); } put4(ofp, dt, mode, k, v) FILE *ofp; long dt; { if (ofp == (FILE *) 0) return; if (dt < 0) dt = 0; putdt(ofp, dt); putc(mode, ofp); putc(k, ofp); putc(v, ofp); } putdt(ofp, dt) FILE *ofp; long dt; { while (dt >= MPU_CLOCK_PERIOD) { putc(RT_TCIP, ofp); dt -= MPU_CLOCK_PERIOD; } putc((char) dt, ofp); }