#include "quiz.h" #include "devices/narrator.h" #include "libraries/translator.h" #include "trans.h" #define MY_PITCH (2*DEFPITCH) extern struct MsgPort * CreatePort(); extern struct IORequest * CreateExtIO(); extern LONG Translate (); extern LONG OpenDevice (); extern struct Library * OpenLibrary(); struct Library * TranslatorBase; static struct MsgPort * writeport; static struct narrator_rb * writeNarrator; static UBYTE audChanMasks[4] = { 3,5,10,12 }; /* which channels to use */ static char outputstring[ 200 ]; init_speech () { TranslatorBase = OpenLibrary ( "translator.library" , (LONG)2 ); if ( TranslatorBase == NULL ) return ( FALSE ); writeport = CreatePort ( (LONG)0 , (LONG)0 ); if ( writeport == NULL ) { CloseLibrary ( TranslatorBase ); return ( FALSE ); } writeNarrator = (struct narrator_rb *) CreateExtIO ( writeport , (LONG) sizeof ( struct narrator_rb ) ); if ( writeNarrator == NULL ) { DeletePort ( writeport ); CloseLibrary ( TranslatorBase ); return ( FALSE ); } /* SET UP THE PARAMETERS FOR THE WRITE-MESSAGE TO THE NARRATOR DEVICE */ writeNarrator->ch_masks = (audChanMasks); writeNarrator->nm_masks = sizeof ( audChanMasks ); writeNarrator->sex = MALE; writeNarrator->mode = NATURALF0; writeNarrator->pitch = MY_PITCH; /* raise pitch from default value */ writeNarrator->rate = DEFRATE; writeNarrator->mouths = FALSE; writeNarrator->message.io_Command = CMD_WRITE; if ( OpenDevice ( "narrator.device" , (LONG)0 , writeNarrator , (LONG)0 ) != 0 ) { DeleteExtIO ( writeNarrator , (LONG) sizeof ( struct narrator_rb ) ); DeletePort ( writeport ); CloseLibrary ( TranslatorBase ); return ( FALSE ); } return ( TRUE ); } close_speech () { /* terminate access to the device */ if ( writeNarrator != 0 ) CloseDevice ( writeNarrator ); /* now return system memory to the memory allocator */ if ( writeNarrator != 0 ) DeleteExtIO ( writeNarrator , (LONG) sizeof ( struct narrator_rb ) ); if ( writeport != 0 ) DeletePort ( writeport ); /* terminate access to the library */ if ( TranslatorBase != NULL ) CloseLibrary ( TranslatorBase ); } speak_english ( str ) char *str; { Translate ( str , (LONG) strlen ( str ) , outputstring , (LONG) sizeof ( outputstring ) ); writeNarrator->message.io_Data = (APTR) outputstring; writeNarrator->message.io_Length = strlen ( outputstring ); DoIO ( writeNarrator ); } speak ( phonemes ) char *phonemes; { struct syllable syl; while ( trans_syllable ( &phonemes , &syl ) ) say_syllable ( &syl ); } static say_syllable ( syl ) struct syllable *syl; { char *addstr; addstr = "."; /* need a punctuation mark at the end */ switch ( syl->tone ) { case HIGH_TONE : writeNarrator->mode = ROBOTICF0; writeNarrator->pitch = MY_PITCH + 30; break; case LOW_TONE : writeNarrator->mode = ROBOTICF0; writeNarrator->pitch = MY_PITCH - 30; break; default : case MIDDLE_TONE : writeNarrator->mode = ROBOTICF0; writeNarrator->pitch = MY_PITCH; break; case RISING_TONE : writeNarrator->mode = NATURALF0; writeNarrator->pitch = MY_PITCH; addstr = "?"; break; case FALLING_TONE : writeNarrator->mode = NATURALF0; writeNarrator->pitch = MY_PITCH + 30; break; } strcpy ( outputstring , syl->phonemes ); strcat ( outputstring , addstr ); writeNarrator->message.io_Data = (APTR) outputstring; writeNarrator->message.io_Length = strlen ( outputstring ); writeNarrator->rate = DEFRATE / syl->duration; DoIO ( writeNarrator ); } static struct { char user_phoneme[8]; char amiga_phoneme[8]; int duration; } phoneme_table[] = { { "AA" , "AE" , 2 } , { "AH" , "AH" , 2 } , { "AI" , "AY" , 2 } , { "AOU", "AW" , 2 } , { "AO" , "AW" , 2 } , { "AW" , "OH" , 2 } , { "A" , "AH" , 1 } , { "BP" , "B/H", 1 } , { "B" , "B" , 1 } , { "CH" , "CH" , 1 } , { "DT" , "DX" , 1 } , { "D" , "D" , 1 } , { "EE" , "IY" , 2 } , { "EH" , "EH" , 2 } , { "ER" , "ER" , 2 } , { "EUA", "ERAH" , 2 } , { "EU" , "EHER" , 1 } , /* also EU bar duration 2 */ { "F" , "F" , 1 } , { "G" , "G" , 1 } , { "H" , "/H" , 1 } , { "IA" , "IHAH",1 } , { "IH" , "IY" , 1 } , { "IW" , "IHW", 1 } , { "I" , "IH" , 1 } , { "J" , "J" , 1 } , { "KH" , "K" , 1 } , { "K" , "K" , 1 } , { "L" , "L" , 1 } , { "M" , "M" , 1 } , { "NG" , "NX" , 1 } , { "N" , "N" , 1 } , { "OA" , "AW" , 2 } , { "OH" , "AA" , 2 } , { "OO-AY" , "UHEY" , 1 } , { "OO-A" , "UHA" , 1 } , { "OO-Y" , "OY" , 2 } , { "OOAY" , "UHEY" , 1 } , { "OOA" , "UHA" , 1 } , { "OOY" , "OY" , 2 } , { "OO" , "UH" , 1 } , { "OR" , "OH" , 1 } , { "OY" , "OY" , 1 } , { "P" , "P" , 1 } , { "R" , "R" , 1 } , { "S" , "S" , 1 } , { "T" , "T" , 1 } , { "UA" , "ERAH",1 } , { "UH" , "AH" , 2 } , { "UM" , "AHM", 1 } , { "U" , "AH" , 1 } , { "W" , "W" , 1 } , { "Y" , "Y" , 1 } , /* y bar for long y */ { "" , "" , 0 } }; static trans_syllable ( ip , syl ) char **ip; struct syllable *syl; { int i; syl->tone = MIDDLE_TONE; syl->phonemes[0] = '\0'; syl->duration = 0; while ( **ip == ' ' ) (*ip)++; if ( **ip == '-' ) (*ip)++; if ( **ip == '(' ) { (*ip)++; switch ( mklower ( *(*ip)++ ) ) { case 'h' : syl->tone = HIGH_TONE; break; case 'm' : case 'c' : case 'n' : syl->tone = MIDDLE_TONE; break; case 'l' : syl->tone = LOW_TONE; break; case 'r' : syl->tone = RISING_TONE; break; case 'f' : case 'd' : syl->tone = FALLING_TONE; break; } if ( **ip == ')' ) (*ip)++; } while ( **ip != '(' && **ip != ' ' && **ip != '\0' ) { if ( **ip == '-' ) (*ip)++; for ( i = 0; phoneme_table[i].user_phoneme[0] != '\0'; i++ ) { if ( substr ( ip , phoneme_table[i].user_phoneme ) ) { strcat ( syl->phonemes , phoneme_table[i].amiga_phoneme ); if ( syl->duration < phoneme_table[i].duration ) syl->duration = phoneme_table[i].duration; break; } } if ( phoneme_table[i].user_phoneme[0] == '\0' ) { /* not found */ return ( FALSE ); /* best that can be done */ } if ( **ip == '!' ) { (*ip)++; syl->duration = ( syl->duration + 1 ) / 2; } } return ( syl->phonemes[0] != '\0' ); } static substr ( buf , sub ) char **buf , *sub; { char *p; p = *buf; while ( *sub != '\0' ) { if ( *p++ != *sub++ ) return ( FALSE ); } *buf = p; return ( TRUE ); }