#include #include /* ** SING -- Sing (on a Dectalk) a MIDI melody ** psl 1/86 */ #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 #define X 0 /* garbage, deleted from input */ #define M 1 /* misc, passed untouched */ #define S 2 /* stress, optionally passed untouched */ #define F 3 /* syntactic structure, optionally passed untouched */ #define V 4 /* vowel, note duration goes here */ #define C 5 /* consonant, small duration here */ char type[] = { 0,0,0,0,0,0,0,0, /* NUL - BEL */ 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, F,F,S,F,M,M,M,S, /* - ' */ M,F,F,M,F,F,F,M, /* ( - / */ M,M,M,M,M,M,M,M, /* 0 - 7 */ M,M,M,M,M,M,M,F, /* 8 - ? */ V,V,M,C,C,V,M,C, /* @ - G */ M,V,C,M,V,V,V,V, /* H - O */ M,M,V,C,C,V,M,V, /* P - W */ M,V,C,0,M,0,V,V, /* X - _ */ S,V,C,V,C,V,C,C, /* ` - g */ C,V,M,C,C,C,C,V, /* h - o */ C,M,C,C,C,V,C,C, /* p - w */ V,C,C,M,V,M,M,X, /* x - DEL */ }; int Sflg = 0; /* allow stress marks through if != 0 */ int Fflg = 0; /* allow structure marks through if != 0 */ main(argc, argv) char *argv[]; { char *phonfile; int i; long now; FILE *lfp; for (i = 1; i < argc; i++) { if (argv[i][0] == '-') { switch (argv[i][1]) { case 's': /* don't strip stress */ Sflg = 1; break; case 'f': /* don't strip syntactic struct. */ Fflg = 1; break; default: goto syntax; } } else { phonfile = argv[i]; if ((lfp = fopen(phonfile, "r"))) { sing(stdin, lfp, stdout); fclose(lfp); } else perror(phonfile); } } if (!phonfile) { syntax: fprintf(stderr, "Usage: %s [-f] [-s] PHON [...] DT\n", argv[0]); fprintf(stderr, "where:\n"); fprintf(stderr, " -f disables stripping of syntactic structure marks,\n"); fprintf(stderr, " -s disables stripping of stress marks,\n"); fprintf(stderr, " MIDI is a file of midi data,\n"); fprintf(stderr, " PHON is a file of 1-char phonemes, and\n"); fprintf(stderr, " DT is a file of Dectalk commands.\n"); exit(2); } } sing(ifp, lfp, ofp) FILE *ifp, *lfp, *ofp; { register int i, k, v, curmode, dur, pc; int key, start, note, pt; long now; fprintf(ofp, "["); curmode = key = 0; now = 0; start = 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 == key) && start <= now) { dur = MC2MS(now - start); if (key) { while ((pc = getc(lfp)) != EOF && (pt = type[pc]) != V) { if (pt == M || (pt == S && Sflg) || (pt == F && Fflg)) fprintf(ofp, "%c", pc); else if (pt == C) { i = dur < 50? dur / 5 : 20; dur -= i; fprintf(ofp, "%c<%d>", pc, i); } } if (pc != EOF) /* got our vowel */ fprintf(ofp, "%c<%d,%d>", pc, dur, key2note(key)); while ((pc = getc(lfp)) != EOF && type[pc] == M) fprintf(ofp, "%c", pc); if (pc != EOF) /* got some non-M phoneme */ ungetc(pc, lfp); fprintf(ofp, "\n"); } else if (dur > 1) fprintf(ofp, "_<%d,%d>", dur, key2note(k)); key = 0; } if (v != 0) /* key-on */ key = k; start = now; } } fprintf(ofp, "].\n"); } key2note(key) { register int note; note = key - 35; while (note <= 0) note += 12; return(note); }