/*
 *
 *	DISCLAIMER:
 *
 *	This program is provided as a service to the programmer
 *	community to demonstrate one or more features of the Amiga
 *	personal computer.  These code samples may be freely used
 *	for commercial or noncommercial purposes.
 * 
 * 	Commodore Electronics, Ltd ("Commodore") makes no
 *	warranties, either expressed or implied, with respect
 *	to the program described herein, its quality, performance,
 *	merchantability, or fitness for any particular purpose.
 *	This program is provided "as is" and the entire risk
 *	as to its quality and performance is with the user.
 *	Should the program prove defective following its
 *	purchase, the user (and not the creator of the program,
 *	Commodore, their distributors or their retailers)
 *	assumes the entire cost of all necessary damages.  In 
 *	no event will Commodore be liable for direct, indirect,
 *	incidental or consequential damages resulting from any
 *	defect in the program even if it has been advised of the 
 *	possibility of such damages.  Some laws do not allow
 *	the exclusion or limitation of implied warranties or
 *	liabilities for incidental or consequential damages,
 *	so the above limitation or exclusion may not apply.
 *
 */

/* speech.demo.c ... as its name implies....  */

/* author:  Rob Peck, 12/1/85
 *
 * This code may be freely utilized to create programs for the Amiga. 
 */


#include "exec/types.h"
#include "exec/exec.h"

#include "exec/nodes.h"
#include "exec/lists.h"
#include "exec/memory.h"
#include "exec/interrupts.h"
#include "exec/ports.h"
#include "exec/libraries.h"
#include "exec/io.h"
#include "exec/tasks.h"
#include "exec/execbase.h"

#include "devices/narrator.h"
#include "libraries/translator.h"

struct MsgPort *readport=0;
struct MsgPort *writeport=0;

extern struct MsgPort *CreatePort();
extern struct IORequest *CreateExtIO();	

struct narrator_rb *writeNarrator=0;
struct mouth_rb *readNarrator=0;
struct Library *TranslatorBase=0;
UBYTE *sampleinput;		/* pointer to sample input string */
UBYTE outputstring[500];	/* place to put the translation */
SHORT rtnCode;			/* return code from function */
SHORT readError;
SHORT writeError;
SHORT error;
BYTE  audChanMasks[4] = { 3,5,10,12 }; /* which channels to use */

#define CANT_OPEN_TRANSLATOR -100
#define CANT_OPEN_NARRATOR -200
#define CREATE_PORT_PROBLEMS -300
#define CREATE_IO_PROBLEMS -400
#define CANT_PERFORM_WRITE -500
#define REVISION 1

extern struct Library *OpenLibrary();

main()
{
	TranslatorBase = OpenLibrary("translator.library",REVISION);
	if(TranslatorBase == NULL) exit (CANT_OPEN_TRANSLATOR);
	sampleinput = "this is a test"; /* a test string of 14 characters */
	rtnCode = Translate(sampleinput,14,outputstring,500);
	error = rtnCode + 100;
	if(rtnCode != 0) goto cleanup0;
	
	writeport = CreatePort(0,0);
	if(writeport == NULL) { error=CREATE_PORT_PROBLEMS; goto cleanup1; }
	readport = CreatePort(0,0);
	if(readport == NULL) { error=CREATE_PORT_PROBLEMS; goto cleanup2; }
	writeNarrator = (struct narrator_rb *)CreateExtIO(writeport,
					sizeof(struct narrator_rb));
	if(writeNarrator == NULL) { error=CREATE_IO_PROBLEMS; goto cleanup3; }
	readNarrator = (struct mouth_rb *)CreateExtIO(readport,
					sizeof(struct mouth_rb));

	if(readNarrator == NULL) { error=CREATE_IO_PROBLEMS; goto cleanup4; }
/* SET UP THE PARAMETERS FOR THE WRITE-MESSAGE TO THE NARRATOR DEVICE */

	/* show where to find the channel masks */
	writeNarrator->ch_masks = (audChanMasks);

	/* and tell it how many of them there are */
	writeNarrator->nm_masks = sizeof(audChanMasks);	

	/* tell it where to find the string to speak */	
	writeNarrator->message.io_Data = (APTR)outputstring;

	/* tell it how many characters the translate function returned */
	writeNarrator->message.io_Length = strlen(outputstring);

	/* if nonzero, asks that mouths be calculated during speech */
	writeNarrator->mouths = 1;

	/* tell it this is a write-command */
	writeNarrator->message.io_Command = CMD_WRITE;

/* Open the device  */

	error = OpenDevice("narrator.device", 0, writeNarrator, 0);
	if(error != 0) goto cleanup4;

/* SET UP THE PARAMETERS FOR THE READ-MESSAGE TO THE NARRATOR DEVICE */

	/* tell narrator for whose speech a mouth is to be generated */
	readNarrator->voice.message.io_Device = 
		writeNarrator->message.io_Device;
	readNarrator->voice.message.io_Unit = 
		writeNarrator->message.io_Unit;

	readNarrator->width = 0;
	readNarrator->height = 0;	/* initial mouth parameters */

	readNarrator->voice.message.io_Command = CMD_READ;
		/* initial error value */
	readNarrator->voice.message.io_Error = 0;	

/* Send an asynchronous write request to the device */

	writeError = SendIO(writeNarrator);
	if(writeError != NULL) { error=CANT_PERFORM_WRITE; goto cleanup5; }
	/* return immediately, run tasks concurrently */

/* keep sending reads until it comes back saying "no write in progress" */

	while((readError = readNarrator->voice.message.io_Error) != 
		ND_NoWrite)
	{
		DoIO(readNarrator);
		/* put task to sleep waiting for a different
		 * mouth shape or return of the message block
		 * with the error field showing no write in
		 * process
		 */
		DrawMouth(readNarrator->width,readNarrator->height);
		/* user's own unique routine, not provided here */
	}

	Delay(30);

	rtnCode = Translate("No it is not",13,outputstring,500);
	writeNarrator->sex = FEMALE;
	writeNarrator->pitch = MAXPITCH;  /* raise pitch from default value */
	writeNarrator->message.io_Data = (APTR)outputstring;
	writeNarrator->message.io_Length = strlen(outputstring);
	DoIO(writeNarrator);
	
	Delay(30);

	rtnCode = Translate("Please! I am speaking now!",26,outputstring,500);
	writeNarrator->sex = MALE;
	writeNarrator->pitch = DEFPITCH;
	writeNarrator->message.io_Data = (APTR)outputstring;
	writeNarrator->message.io_Length = strlen(outputstring);
	DoIO(writeNarrator);

	Delay(30);

	rtnCode = Translate(
		"Well, you are not very interesting, so I am going home!", 
		55,outputstring,500);
	writeNarrator->sex = FEMALE;
	writeNarrator->pitch = MAXPITCH;
	writeNarrator->message.io_Data = (APTR)outputstring;
	writeNarrator->message.io_Length = strlen(outputstring);
	DoIO(writeNarrator);

	Delay(30);

	rtnCode = Translate("Bye Bye",7,outputstring,500);
	writeNarrator->sex = MALE;
	writeNarrator->pitch = DEFPITCH;
	writeNarrator->rate = 7;	/* slow him down */
	writeNarrator->message.io_Data = (APTR)outputstring;
	writeNarrator->message.io_Length = strlen(outputstring);
	DoIO(writeNarrator);

    cleanup5:
	if(writeNarrator != 0)
		CloseDevice(writeNarrator);
				/* terminate access to the device */

	/* now return system memory to the memory allocator */ 

    cleanup4:
	if(readNarrator != 0)
		DeleteExtIO(readNarrator,sizeof(struct mouth_rb));
    cleanup3:
	if(writeNarrator != 0)
		DeleteExtIO(writeNarrator,sizeof(struct narrator_rb));
    cleanup2:
	if(readport != 0)
		DeletePort(readport);
    cleanup1:
	if(writeport != 0)
		DeletePort(writeport);
    cleanup0:
	if(TranslatorBase != 0)
   		CloseLibrary(TranslatorBase);
				/* terminate access to the library */
	
	if(error != 0) exit(error);
} /* end of test */	

DrawMouth(w,h)
SHORT w,h;
{	return(0);	/* dummy routine */	}

int strlen(string)
char *string;
{
	int i,length;
	length = -1;
	for(i=0; i<256; i++)	/* 256 characters max length at this time */
		{
		if(*string++ == '\0') { length = i+1; break; };
		}
	return(length);
}

