#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
// #include <kernel.h> -- ARM only ...
/* The KLATT phoneme codes:
**
** IY bEEt IH bIt
** EY gAte EH gEt
** AE fAt AA fAther
** AO lAWn OW lOne
** UH fUll UW fOOl
** ER mURdER AX About
** AH bUt AY hIde
** AW hOW OY tOY
**
** p Pack b Back
** t Time d Dime
** k Coat g Goat
** f Fault v Vault
** TH eTHer DH eiTHer
** s Sue z Zoo
** SH leaSH ZH leiSure
** HH How m suM
** n suN NG suNG
** l Laugh w Wear
** y Young r Rate
** CH CHar j Jar
** WH WHere
*/
#define NONE_FOUND 1
#ifdef KLATT
#undef NONE_FOUND
#endif
#ifdef TOAL
#undef NONE_FOUND
#endif
#ifdef KLATT
#undef NONE_FOUND
#endif
#ifdef NONE_FOUND
#define KLATT
#endif
#define MAX_LENGTH 128
static FILE *In_file;
static FILE *Out_file;
static int Char, Char1, Char2, Char3;
static char *Rep_code2[128][128];
static char *Rep_code[128];
/*
** main(argc, argv)
** int argc;
** char *argv[];
**
** This is the main program. It takes up to two file names (input
** and output) and translates the input file to phoneme codes
** (see ENGLISH.C) on the output file.
*/
main(argc, argv)
int argc;
char *argv[];
{
if (argc > 3)
{
fputs("Usage: PHONEME [infile [outfile]]\n", stderr);
exit(1);
}
if (argc == 1)
{
#ifdef SUPERIOR
// _kernel_oscli("say hello. this is my text to speech demo\r");
#endif
fputs("Enter english text:\n", stderr);
}
if (argc > 1)
{
In_file = fopen(argv[1], "r");
if (In_file == 0)
{
fputs("Error: Cannot open input file.\n", stderr);
fputs("Usage: PHONEME [infile [outfile]]\n", stderr);
exit(1);
}
}
else
In_file = stdin;
if (argc > 2)
{
Out_file = fopen(argv[2], "w");
if (Out_file == 0)
{
fputs("Error: Cannot create output file.\n", stderr);
fputs("Usage: PHONEME [infile [outfile]]\n", stderr);
exit(1);
}
}
else
Out_file = stdout;
#ifndef ORIGINAL
Init_Rules();
#endif
{
int i, j;
for (i = 0; i < 128; i++) {
Rep_code[i] = "<UNDEF>";
for (j = 0; j < 128; j++) {
Rep_code2[i][j] = "<UNDEF>";
}
}
}
Rep_code['a'] = "A4";
Rep_code['b'] = "B4";
Rep_code['c'] = "C4";
Rep_code['d'] = "D4";
Rep_code['e'] = "E4";
Rep_code['f'] = "F4";
Rep_code['g'] = "G4";
Rep_code['h'] = "H4";
Rep_code['i'] = "I4";
Rep_code['j'] = "J4";
Rep_code['k'] = "K4";
Rep_code['l'] = "L4";
Rep_code['m'] = "M4";
Rep_code['n'] = "N4";
Rep_code['o'] = "O4";
Rep_code['p'] = "P4";
Rep_code['q'] = "Q4";
Rep_code['r'] = "R4";
Rep_code['s'] = "S4";
Rep_code['t'] = "T4";
Rep_code['u'] = "U4";
Rep_code['v'] = "V4";
Rep_code['w'] = "W4";
Rep_code['x'] = "X4";
Rep_code['y'] = "Y4";
Rep_code['z'] = "Z4";
Rep_code['A'] = "A4";
Rep_code['B'] = "B4";
Rep_code['C'] = "C4";
Rep_code['D'] = "D4";
Rep_code['E'] = "E4";
Rep_code['F'] = "F4";
Rep_code['G'] = "G4";
Rep_code['H'] = "H4";
Rep_code['I'] = "I4";
Rep_code['J'] = "J4";
Rep_code['K'] = "K4";
Rep_code['L'] = "L4";
Rep_code['M'] = "M4";
Rep_code['N'] = "N4";
Rep_code['O'] = "O4";
Rep_code['P'] = "P4";
Rep_code['Q'] = "Q4";
Rep_code['R'] = "R4";
Rep_code['S'] = "S4";
Rep_code['T'] = "T4";
Rep_code['U'] = "U4";
Rep_code['V'] = "V4";
Rep_code['W'] = "W4";
Rep_code['X'] = "X4";
Rep_code['Y'] = "Y4";
Rep_code['Z'] = "Z4";
#ifdef KLATT
Rep_code2['I']['Y'] = "IY";
Rep_code2['E']['Y'] = "EY";
Rep_code2['A']['E'] = "AE";
Rep_code2['A']['O'] = "AO";
Rep_code2['U']['H'] = "UH";
Rep_code2['E']['R'] = "ER";
Rep_code2['A']['H'] = "AH";
Rep_code2['A']['W'] = "AW";
Rep_code2['I']['H'] = "IH";
Rep_code2['E']['H'] = "EH";
Rep_code2['A']['A'] = "AA";
Rep_code2['O']['W'] = "OW";
Rep_code2['U']['W'] = "UW";
Rep_code2['A']['X'] = "AX";
Rep_code2['A']['Y'] = "AY";
Rep_code2['O']['Y'] = "OY";
Rep_code2['T']['H'] = "TH";
Rep_code2['S']['H'] = "SH";
Rep_code2['H']['H'] = "HH";
Rep_code2['C']['H'] = "CH";
Rep_code2['W']['H'] = "WH";
Rep_code2['D']['H'] = "DH";
Rep_code2['Z']['H'] = "ZH";
Rep_code2['N']['G'] = "NG";
#endif
#ifdef SUPERIOR /* first iteration - guessing */
Rep_code2['I']['Y'] = "EE4";
Rep_code2['E']['Y'] = "AY4";
Rep_code2['A']['E'] = "AE4";
Rep_code2['A']['O'] = "OH4";
Rep_code2['U']['H'] = "UH4"; /* full ??? */
Rep_code2['E']['R'] = "AXR4";
Rep_code2['A']['H'] = "AH4";
Rep_code2['A']['W'] = "AW4";
Rep_code2['I']['H'] = "IH4";
Rep_code2['E']['H'] = "EH4";
Rep_code2['A']['A'] = "O4"; /* zombie -> ZAAMBIH */
Rep_code2['O']['W'] = "OW4";
Rep_code2['U']['W'] = "UW4";/* fool ??? Can't see any difference! */
Rep_code2['A']['X'] = "AX4"; /* *a*bout ??? */
Rep_code2['A']['Y'] = "IY4";
Rep_code2['O']['Y'] = "OY4";
Rep_code2['T']['H'] = "TH4"; /* The??? */
Rep_code2['S']['H'] = "SH4";
Rep_code2['H']['H'] = "H4";
Rep_code2['C']['H'] = "CH4";
Rep_code2['W']['H'] = "HW4";
Rep_code2['D']['H'] = "DH4"; /* This */
Rep_code2['Z']['H'] = "ZH4"; /* I did't have this one! - added! */
Rep_code2['N']['G'] = "NX4";
#endif
#ifdef TOAL
Rep_code2['I']['Y'] = "Ê";
Rep_code2['E']['Y'] = "Â";
Rep_code2['A']['E'] = "a";
Rep_code2['A']['O'] = "o";
Rep_code2['U']['H'] = "û"; /* full ??? */
Rep_code2['E']['R'] = "ør";
Rep_code2['A']['H'] = "u";
Rep_code2['A']['W'] = "ö";
Rep_code2['I']['H'] = "i";
Rep_code2['E']['H'] = "e";
Rep_code2['A']['A'] = "ø"; /* zombie -> ZAAMBIH */
Rep_code2['O']['W'] = "ô";
Rep_code2['U']['W'] = "û"; /* fool ??? Can't see any difference! */
Rep_code2['A']['X'] = "i"; /* *a*bout ??? */
Rep_code2['A']['Y'] = "ý";
Rep_code2['O']['Y'] = "ó";
Rep_code2['T']['H'] = "Ð"; /* The */
Rep_code2['S']['H'] = "§";
Rep_code2['H']['H'] = "h";
Rep_code2['C']['H'] = "Ç";
Rep_code2['W']['H'] = "µ";
Rep_code2['D']['H'] = "Ð"; /* This */
Rep_code2['Z']['H'] = "J"; /* I did't have this one! - added! */
Rep_code2['N']['G'] = "Ñ";
#endif
xlate_file();
}
outstring(string)
char *string;
{
while (*string != '\0')
outchar(*string++);
}
outchar(chr)
int chr;
{
static int first;
static int UC_PENDING = (0!=0);
char action[256];
static char line[256] = { '\0' };
static char *linep = line;
if (UC_PENDING) {
linep += sprintf(linep, "%s", Rep_code2[first][chr]);
fprintf(Out_file, "%s", Rep_code2[first][chr]);
UC_PENDING = (0!=0);
return;
}
if (isupper(chr&127)) {
first = chr&127;
UC_PENDING = (0==0);
} else {
if (chr == '\n' || chr == ' ') {
sprintf(action, "speakw %s\r", line);
fprintf(stderr, " (%s) ", line);
#ifdef SUPERIOR
// _kernel_oscli(action);
#endif
linep = line; *linep = '\0';
} else {
linep += sprintf(linep, "%s", Rep_code[chr&127]);
}
if (chr != ' ') fputc(chr,Out_file);
}
}
int makeupper(character)
int character;
{
if (islower(character))
return toupper(character);
else
return character;
}
new_char()
{
/*
If the cache is full of newline, time to prime the look-ahead
again. If an EOF is found, fill the remainder of the queue with
EOF's.
*/
if (Char == '\n' && Char1 == '\n' && Char2 == '\n' && Char3 == '\n')
{ /* prime the pump again */
Char = getc(In_file);
if (Char == EOF)
{
Char1 = EOF;
Char2 = EOF;
Char3 = EOF;
return Char;
}
if (Char == '\n')
return Char;
Char1 = getc(In_file);
if (Char1 == EOF)
{
Char2 = EOF;
Char3 = EOF;
return Char;
}
if (Char1 == '\n')
return Char;
Char2 = getc(In_file);
if (Char2 == EOF)
{
Char3 = EOF;
return Char;
}
if (Char2 == '\n')
return Char;
Char3 = getc(In_file);
}
else
{
/*
Buffer not full of newline, shuffle the characters and
either get a new one or propagate a newline or EOF.
*/
Char = Char1;
Char1 = Char2;
Char2 = Char3;
if (Char3 != '\n' && Char3 != EOF)
Char3 = getc(In_file);
}
return Char;
}
/*
** xlate_file()
**
** This is the input file translator. It sets up the first character
** and uses it to determine what kind of text follows.
*/
xlate_file()
{
/* Prime the queue */
Char = '\n';
Char1 = '\n';
Char2 = '\n';
Char3 = '\n';
new_char(); /* Fill Char, Char1, Char2 and Char3 */
while (Char != EOF) /* All of the words in the file */
{
if (isdigit(Char))
have_number();
else
if (isalpha(Char) || Char == '\'')
have_letter();
else
if (Char == '$' && isdigit(Char1))
have_dollars();
else
have_special();
}
}
have_dollars()
{
long int value;
value = 0L;
for (new_char() ; isdigit(Char) || Char == ',' ; new_char())
{
if (Char != ',')
value = 10 * value + (Char-'0');
}
say_cardinal(value); /* Say number of whole dollars */
/* Found a character that is a non-digit and non-comma */
/* Check for no decimal or no cents digits */
if (Char != '.' || !isdigit(Char1))
{
if (value == 1L)
outstring("dAAlER ");
else
outstring("dAAlAArz ");
return;
}
/* We have '.' followed by a digit */
new_char(); /* Skip the period */
/* If it is ".dd " say as " DOLLARS AND n CENTS " */
if (isdigit(Char1) && !isdigit(Char2))
{
if (value == 1L)
outstring("dAAlER ");
else
outstring("dAAlAArz ");
if (Char == '0' && Char1 == '0')
{
new_char(); /* Skip tens digit */
new_char(); /* Skip units digit */
return;
}
outstring("AAnd ");
value = (Char-'0')*10 + Char1-'0';
say_cardinal(value);
if (value == 1L)
outstring("sEHnt ");
else
outstring("sEHnts ");
new_char(); /* Used Char (tens digit) */
new_char(); /* Used Char1 (units digit) */
return;
}
/* Otherwise say as "n POINT ddd DOLLARS " */
outstring("pOYnt ");
for ( ; isdigit(Char) ; new_char())
{
say_ascii(Char);
}
outstring("dAAlAArz ");
return;
}
have_special()
{
if (Char == '\n')
outchar('\n');
else
if (!isspace(Char))
say_ascii(Char);
new_char();
return;
}
have_number()
{
long int value;
int lastdigit;
value = Char - '0';
lastdigit = Char;
for (new_char() ; isdigit(Char) ; new_char())
{
value = 10 * value + (Char-'0');
lastdigit = Char;
}
/* Recognize ordinals based on last digit of number */
switch (lastdigit)
{
case '1': /* ST */
if (makeupper(Char) == 'S' && makeupper(Char1) == 'T' &&
!isalpha(Char2) && !isdigit(Char2))
{
say_ordinal(value);
new_char(); /* Used Char */
new_char(); /* Used Char1 */
return;
}
break;
case '2': /* ND */
if (makeupper(Char) == 'N' && makeupper(Char1) == 'D' &&
!isalpha(Char2) && !isdigit(Char2))
{
say_ordinal(value);
new_char(); /* Used Char */
new_char(); /* Used Char1 */
return;
}
break;
case '3': /* RD */
if (makeupper(Char) == 'R' && makeupper(Char1) == 'D' &&
!isalpha(Char2) && !isdigit(Char2))
{
say_ordinal(value);
new_char(); /* Used Char */
new_char(); /* Used Char1 */
return;
}
break;
case '0': /* TH */
case '4': /* TH */
case '5': /* TH */
case '6': /* TH */
case '7': /* TH */
case '8': /* TH */
case '9': /* TH */
if (makeupper(Char) == 'T' && makeupper(Char1) == 'H' &&
!isalpha(Char2) && !isdigit(Char2))
{
say_ordinal(value);
new_char(); /* Used Char */
new_char(); /* Used Char1 */
return;
}
break;
}
say_cardinal(value);
/* Recognize decimal points */
if (Char == '.' && isdigit(Char1))
{
outstring("pOYnt ");
for (new_char() ; isdigit(Char) ; new_char())
{
say_ascii(Char);
}
}
/* Spell out trailing abbreviations */
if (isalpha(Char))
{
while (isalpha(Char))
{
say_ascii(Char);
new_char();
}
}
return;
}
have_letter()
{
char buff[MAX_LENGTH];
int count;
count = 0;
buff[count++] = ' '; /* Required initial blank */
buff[count++] = makeupper(Char);
for (new_char() ; isalpha(Char) || Char == '\'' ; new_char())
{
buff[count++] = makeupper(Char);
if (count > MAX_LENGTH-2)
{
buff[count++] = ' ';
buff[count++] = '\0';
xlate_word(buff);
count = 1;
}
}
buff[count++] = ' '; /* Required terminating blank */
buff[count++] = '\0';
/* Check for AAANNN type abbreviations */
if (isdigit(Char))
{
spell_word(buff);
return;
}
else
if (strlen(buff) == 3) /* one character, two spaces */
say_ascii(buff[1]);
else
if (Char == '.') /* Possible abbreviation */
abbrev(buff);
else
{
char *s;
/*fprintf(Out_file, "<");*/
xlate_word(buff);
s = buff;
while (*s != '\0') {
if (isalpha(*s) && isupper(*s)) *s = tolower(*s);
s++;
}
if (*buff == ' ')
fprintf(Out_file, "=%s", buff+1); /* was >= */
else
fprintf(Out_file, "=%s", buff); /* was >= */
}
if (Char == '-' && isalpha(Char1))
new_char(); /* Skip hyphens */
}
/* Handle abbreviations. Text in buff was followed by '.' */
abbrev(buff)
char buff[];
{
if (strcmp(buff, " DR ") == 0)
{
xlate_word(" DOCTOR ");
new_char();
}
else
if (strcmp(buff, " MR ") == 0)
{
xlate_word(" MISTER ");
new_char();
}
else
if (strcmp(buff, " MRS ") == 0)
{
xlate_word(" MISSUS ");
new_char();
}
else
if (strcmp(buff, " PHD ") == 0)
{
spell_word(" PHD ");
new_char();
}
else
xlate_word(buff);
}