#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 );
}
