home *** CD-ROM | disk | FTP | other *** search
- /* Note: I'm sure that some of these may be improved
- and would appreciate any feedback */
- /* A set of routines to allow a user to program in BDS C words and
- phrases using a VOTRAX SC-01 chip synthesizer. The main functions is
- "talk" which takes a character string argument that looks like phonemes.
- The subroutine "pronounce" does the port I/O and will need to be
- be individually modified, most likely. Read the comments above it */
-
- /* written by Mark Zachmann Sept. 5 1981 Version 0.2 */
-
- /* main talking functions... what a slow way to do things */
-
- /* it reads a character string corresponding to the phoneme descriptions
- in the VOTRAX phoneme chart (page 3 of SC-01 data sheet)
- and decodes them into numbers (type char, though), then says them.
- Note that because it takes a while to talk I say each phoneme
- seperately, and thus, while saying one phoneme, the next
- can be decoded from the character string input */
-
- talk(line)
- char *line;
- { while(0!=*line)
- { pronounce(phoneme(line)); /* transmit to chip */
- while(','!=*line++); /* increment counter to start
- of next phoneme */
- }
- }
-
- /* Subroutine to take a character string and return a number (type char)
- corresponding to the first phoneme found in the string. Returns
- 0xFF if no match (although partial matches will have undefined
- results, e.g. O5 may be the same as O1) */
-
- phoneme(line)
- char *line;
- { switch(*line++) {
- case 'A': switch(*line)
- { case '1': return(5); /* A1 */
- case '2': return(6); /* A2 */
- case 'Y': return(0x21); /* AY */
- case 'E': { if (','==*++line) return(0x2e); /* AE */
- return(0x2f); /* AE1 */
- }
- case 'H': { if (','==*++line) return(0x24); /* AH */
- if('1'==*line) return(0x15); /* AH1 */
- return(8); /* AH2 */
- }
- case 'W': { if(','==*++line) return(0x3d); /* AW */
- if('1'==*line) return(0x13); /* AW1 */
- return(0x30); /* AW2 */
- }
- }
- case 'B': return(0xe); /* B */
- case 'C': return(0x10); /* CH */
- case 'D': { if(','==*line) return(0x1e); /* D */
- return(0x4); /* DT */
- }
- case 'E': switch(*line)
- { case ',': return(0x2c); /* E */
- case 'R': return(0x3a); /* ER */
- case '1': return(0x3c); /* E1 */
- case 'H': switch(*++line) {
- case ',': return(0x3b); /* EH */
- case '1': return(2); /* EH1 */
- case '2': return(1); /* EH2 */
- default: return(0); /* EH3 */
- }
- }
- case 'F': return(0x1d); /* F */
- case 'G': return(0x1c); /* G */
- case 'H': return(0x1b); /* H */
- case 'I': switch(*line)
- { case ',': return(0x27); /* I */
- case 'U': return(0x36); /* IU */
- case '1': return(0x0b); /* I1 */
- case '2': return(0x0a); /* I2 */
- default: return(9); /* I3 */
- }
- case 'J': return(0x1a); /* J */
- case 'K': return(0x19); /* K */
- case 'L': return(0x18); /* L */
- case 'M': return(0x0c); /* M */
- case 'N': if(','==*line) return(0x0d); /* N */
- return(0x14); /* NG */
- case 'O': switch(*line)
- { case ',': return(0x26); /* O */
- case '1': return(0x35); /* O1 */
- case '2': return(0x34); /* O2 */
- case 'O': { if(','==*++line) return(0x17); /* OO */
- return(0x16); /* OO1 */
- }
- }
- case 'P': { if(','==*line) return(0x25); /* P */
- if('0'==*++line) return(3); /* PA0 */
- return(0x3e); /* PA1 */
- }
- case 'R': return(0x2b); /* R */
- case 'S': { if(','==*line) return(0x1f); /* S */
- if('H'==*line) return(0x11); /* SH */
- return(0x3f); /* STOP */
- }
- case 'T': { if(','==*line) return(0x2a); /* T */
- if(','==*++line) return(0x39); /* TH */
- return(0x38); /* THV */
- }
- case 'U': switch(*line)
- { case ',': return(0x28); /* U */
- case '1': return(0x37); /* U1 */
- default: switch(*++line)
- { case ',': return(0x33); /* UH */
- case '1': return(0x32); /* UH1 */
- case '2': return(0x31); /* UH2 */
- default: return(0x23); /* UH3 */
- }
- }
- case 'V': return(0x0f); /* V */
- case 'W': return(0x2d); /* W */
- case 'Y': { if(','==*line) return(0x29); /* Y */
- return(0x22); /* Y1 */
- }
- case 'Z': { if(','==*line) return(0x12); /* Z */
- return(7); /* ZH */
- }
- default : return(0xff); /* error !! */
- }
- }
-
- /* this is the pronunciation subroutine. It sends a single phoneme
- to the Votrax synthesis chip. I have implemented mine by way of
- the iobyte. When the list device is set to UC3: my BIOS sends
- output to the synthesizer. Thus all handshaking is external
- to this program. !! You will need to modify either this or your BIOS.
- I suggest the BIOS as then BASIC and etc. stupid compilers can easily
- interface to the chip */
-
- pronounce(c)
- char(c);
- { char iobyt;
- iobyt=bdos(7); /* read iobyte */
- bdos(8,0xc0); /* set list to UC3: */
- bios(5,(c|0x80)); /* send character, I set my pitch to 80h always */
- bdos(8,iobyt); /* reset IOBYTE to whatever it was */
- }
-
-
-
- /* program to say a number argument
- assumes unsigned input, and calls itself recusively. Not terribly
- fast */
-
- saynum(numb)
- unsigned numb;
- { char c,d,some;
- unsigned j;
-
- some=0; /* nothing said yet */
-
- /* first process the 1000's */
- if(0!=(j=numb/1000))
- { saynum(j); /* Recur to do thousands */
- talk("TH,AH1,W,Z,I1,N,D,PA1,"); /* thousand */
- numb%=1000; /* continue with left over */
- some=1 ; /* flag it as having said something */
- }
-
- /* now the 100's */
- if(0!=(j=numb/100))
- { saynum(j); /* recurring */
- talk("H,H,UH,N,D,R,I3,D,PA1,"); /* hundred */
- numb%=100; /* continue again */
- some=1 ; /* flag it */
- }
-
- /* now separate the 10's off (if > 20) */
- if((numb>=20)&&0!=(j=numb%10)) /* recur again if not simple */
- { saynum(numb-j); /* first do the tens case */
- numb=j; /* now the remainder */
- some=1;
- }
-
- /* main non-recursive portion */
- c=numb; /* turn into a char for speed */
- d=(c>=20)? c/10 : c%10 ; /* the kernel is here */
- switch(d)
- { case 1 : { if(c==1) talk("W,UH1,I3,N,"); /* 1 */
- else talk("E1,L,EH1,V,I1,N,"); /* 11 */
- break;
- }
- case 2 : { if(c==20) talk("T,PA0,W,EH2,N,"); /* 20 */
- else if(c==12) talk("T,PA0,W,EH2,UH2,L,V,"); /* 12 */
- else talk("T,PA0,U,W,"); /* 2 */
- break;
- }
- case 3 : { if(c==3) talk("TH,R,E1,Y,"); /* 3 */
- else talk("TH,UH2,ER,"); /* 13,31 */
- break ;
- }
- case 4 : { if(c==4) talk("F,O,ER,"); /* 4 */
- else talk("F,O1,R,"); /* 14,41 */
- break;
- }
- case 5 : { if(c==5) talk("F,AH1,Y1,V,"); /* 5 */
- else talk("F,I1,F,"); /* 15,51 */
- break;
- }
- case 6 : talk("S,I,K,S,"); break; /* 6's */
- case 7 : talk("S,EH,V,I3,N,"); break; /* 7's */
- case 8 : talk("A1,Y,T,"); break ; /* 8's */
- case 9 : talk("N,AH2,Y,N,"); break ; /* 9's */
- case 0 : { if(c==10) talk("T,EH,N,"); /* 10 */
- else if(!some) talk("Z,E1,R,O1,W,"); /* 0 */
- break ;
- }
- }
- if(c>=20) talk("STOP,T,E1,PA0,"); /* ty */
- else if(c>12) talk("STOP,T,E1,E1,N,PA0,"); /* teen */
- else talk("PA1,"); /* done */
- }
-
- /* */
- /* says the day of the week, 0 is sunday 6 is saturday */
-
- sayday(dayow)
- char dayow;
- { switch(dayow) {
- case 0: talk("S,UH,N,N,"); break;
- case 1: talk("M,UH,N,"); break;
- case 2: talk("T,PA0,U,EH3,Z,STOP,"); break;
- case 3: talk("W,EH,N,Z,"); break;
- case 4: talk("TH,U1,ER,Z,"); break;
- case 5: talk("F,R,AH1,Y,"); break;
- case 6: talk("S,AE1,EH3,T,ER,"); break;
- default: talk("H,W,UH,T,"); break; /* what? */
- }
- talk("D,A1,AY,Y1,STOP,STOP,"); /* day */
- }
-
- /* */
- /* says the month desired */
- saymonth(month) /* month 0-January...11-December */
- char(month);
- { switch(month) {
- case 0: talk("D,J,I3,AE1,UH2,N,Y,IU,U1,W,AE1,EH3,R,Y,"); break;
- case 1: talk("F,EH1,B,Y,IU,U1,W,AE1,EH3,R,Y,"); break;
- case 2: talk("M,AH2,ER,T,CH,"); break;
- case 3: talk("A1,AY,P,R,OO1,L,"); break;
- case 4: talk("M,A,Y,"); break;
- case 5: talk("D,J,U1,U,N,"); break;
- case 6: talk("D,J,U1,UH3,L,AR1,E1,"); break;
- case 7: talk("AW,G,UH3,S,T,"); break;
- case 8: talk("S,EH1,P,STOP,T,EH1,EH2,M,B,R,"); break;
- case 9: talk("AH1,K,STOP,T,O,W,B,R,"); break;
- case 10: talk("N,O1,W,PA0,V,EH,M,B,R,"); break;
- case 11: talk("D,I2,Y,S,EH,M,B,R,"); break;
- default: talk("H,W,UH,T,"); break;
- }
- }
-