#include #include /* ** SCAT -- Scat (on a Dectalk) a MIDI melody ** psl 1/86 */ #define Dcons 6 /* 6th csyl[] must be d for Sflg */ #define Bcons 0 /* 0th csyl[] must be b for Sflg */ #define Fcons 24 /* 24th csyl[] must be f for Yflg */ #define Lcons 29 /* 29th csyl[] must be l for Yflg */ char *csyl[] = { "b", "b", "b", "b", "b", "b", "d", "d", "d", "d", "d", "d", "m", "m", "m", "n", "n", "n", "k", "k", "p", "p", "t", "t", "f", "f", "sh", "v", "w", "l", "r", }; #define Oovow 0 /* 0th vsyl[] must be uw for Sflg */ #define Eevow 1 /* 1st vsyl[] must be iy for Sflg */ #define Aavow 2 /* 2nd vsyl[] must be aa for Yflg */ #define Ahvow 3 /* 3nd vsyl[] must be ah for Yflg */ char *vsyl[] = { "uw", "iy", "aa", "ah", "aw", "ax", "ih", "yu", "eh", "rr", "ay", "ae", "uh", "ow", "em", "ix", "el", }; #define LASTREST 1 #define NCSYL (sizeof csyl / sizeof csyl[0]) #define NVSYL (sizeof vsyl / sizeof vsyl[0]) #define MC2MS(x) (5 * (x)) /* MIDI clocks to milliseconds */ #define MAXCHAN 16 #define MAXKEY 128 #define UNITY 1024 int Kflg = 2000; /* insert ^Ks once we're this far ahead */ int Pflg = 0; /* Patter heuristic */ int Sflg = 0; /* Sinatra heuristic */ int Yflg = 0; /* Yule heuristic */ char *gibber(); main(argc, argv) char *argv[]; { long now; if (argc > 1) { } while (--argc > 0) { if (argv[argc][0] == '-') { switch (argv[argc][1]) { case 'k': Kflg = atoi(&argv[argc][2]); break; case 'p': Pflg++; break; case 's': Sflg++; break; case 'y': Yflg = LASTREST; break; default: goto syntax; } } else { syntax: fprintf(stderr, "Usage: %s [OPTIONS] DTfile\n", argv[0]); fprintf(stderr, "OPTIONS are:\n"); fprintf(stderr, "-k#\t\tSet flush threshold to #\n"); fprintf(stderr, "-patter\t\tEncourage repetition\n"); fprintf(stderr, "-sinatra\tAlternate between [duw] & [biy]\n"); fprintf(stderr, "-yule\t\tUse [faa] followed by [lah]s\n"); exit(2); } } time(&now); srand((int) now); printf("["); scat(stdin, stdout); printf("].\n"); } scat(ifp, ofp) FILE *ifp, *ofp; { register int i, k, v, curmode, dur; int scatkey, scatstart, note, num, ahead; long now; curmode = scatkey = num = ahead = 0; now = 0; scatstart = 9999; 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 */ do { k = getc(ifp); } while (k != 0xF7); } else if (k == 0xF2) { /* song position */ getc(ifp); getc(ifp); } else if (k == 0xF3) { /* song select */ getc(ifp); } curmode = 0; } else /* sys real time */ ; continue; } curmode = k; if ((k = getc(ifp)) == EOF) { fprintf(stderr, "EOF after %x (mode)\n", curmode); exit(1); } } i = curmode & 0xF0; if (i == 0xA0 /* poly pressure */ || i == 0xB0 /* mod wheel */ || i == 0xE0) { /* pitch bend */ getc(ifp); continue; } else if (i == 0xC0 /* prog change */ || i == 0xD0) { /* chan pressure */ 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 || k == scatkey) && scatstart <= now) { dur = MC2MS(now - scatstart); ahead += dur; if (scatkey) { fputs(gibber(scatkey, dur), stdout); if (Yflg) Yflg = LASTREST + 1; /* not a rest */ } else { if (Kflg && ahead > Kflg / 2 && dur > 200) { ahead = Kflg; /* force ^K out now */ dur -= 200; } if (dur > 1) { fprintf(ofp, "_<%d,%d>", dur, key2note(k)); num = 4; /* force new line */ if (Yflg) Yflg = LASTREST; /* a rest */ } } if (++num >= 4) { if (Kflg && ahead >= Kflg) { ahead = 0; fputs("\013\n[", stdout); } else fputs("\n", stdout); num = 0; } scatkey = 0; } if (v != 0) /* key-on */ scatkey = k; scatstart = now; } } } char * gibber(key, dur) { register int i, j, c, v; static char buf[64]; static int num, oc[4], ov[4]; c = rand() % NCSYL; v = rand() % NVSYL; if (Pflg) { if (num < 2 || (rand() % 5) >= Pflg) /* use new consonant */ for (j = oc[(num-1) & 3]; c == j; c = rand() % NCSYL); else if (num < 4 || rand() & 010) /* use consonant from t - 2 */ c = oc[(num-2) & 3]; else /* use consonant from t - 4 */ c = oc[(num-4) & 3]; oc[num & 3] = c; if (num < 2 || (rand() % 5) >= Pflg) /* use new vowel */ for (j = ov[(num-1) & 3]; v == j; v = rand() % NVSYL); else if (num < 4 || rand() & 010) /* use vowel from t - 2 */ v = ov[(num-2) & 3]; else /* use vowel from t - 4 */ v = ov[(num-4) & 3]; ov[num & 3] = v; num++; } if (Sflg) { i = (Sflg++) & 1; c = i? Dcons : Bcons; v = i? Oovow : Eevow; } if (Yflg) { c = (Yflg == LASTREST)? Fcons : Lcons; v = (Yflg == LASTREST)? Aavow : Ahvow; } i = dur < 50? dur / 5 : 20; j = dur - i; sprintf(buf, "%s<%d,%d>%s<%d>", csyl[c], i, key2note(key), vsyl[v], j); return(buf); } key2note(key) { register int note; note = key - 35; while (note <= 0) note += 12; return(note); }