/*************************************************************************
 * S P E E C H - a sample program which receive text input from a window *
 *               and speaks the text using the Amiga's built in voice    *
 *               synthesizer                                             *
 *                                       -- By Tom Krotchko              *
 *************************************************************************/
#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 "libraries/translator.h"
#include "devices/audio.h"
#include "devices/narrator.h"
#include "intuition/intuition.h"
#include "graphics/gfxbase.h"
#include "string.h"

#define TEXT_INPUT 100
#define PHON_INPUT 200

struct IntuitionBase *IntuitionBase;
struct IntuiMessage *message;
struct GfxBase *GfxBase;

/* This is the beginning of the structures created with PowerWindows */
UBYTE UNDOBUFFER1[25];
UBYTE UNDOBUFFER2[43];

UBYTE Gadget2SIBuff[43];
struct StringInfo Gadget2SInfo = {
   Gadget2SIBuff,   /* buffer where text will be edited */
   UNDOBUFFER2,   /* optional undo buffer */
   0,   /* character position in buffer */
   43,   /* maximum number of characters to allow */
   0,   /* first displayed character buffer position */
   0,0,0,0,0,   /* Intuition initialized and maintained variables */
   0,   /* Rastport of gadget */
   0,   /* initial value for integer gadgets */
   NULL   /* alternate keymap (fill in if you set the flag) */
};

SHORT BorderVectors1[] = {
   0,0,
   350,0,
   350,10,
   0,10,
   0,0
};
struct Border Border1 = {
   -2,-1,   /* XY origin relative to container TopLeft */
   3,0,JAM1,   /* front pen, back pen and drawmode */
   5,   /* number of XY vectors */
   BorderVectors1,   /* pointer to XY vectors */
   NULL   /* next border in list */
};

struct Gadget Gadget2 = {
   NULL,   /* next gadget */
   22,69,   /* origin XY of hit box relative to window TopLeft */
   347,10,   /* hit box width and height */
   NULL,   /* gadget flags */
   RELVERIFY+STRINGCENTER+GADGIMMEDIATE,   /* activation flags */
   STRGADGET,   /* gadget type flags */
   (APTR)&Border1,   /* gadget border or image to be rendered */
   NULL,   /* alternate imagery for selection */
   NULL,   /* first IntuiText structure */
   NULL,   /* gadget mutual-exclude long word */
   (APTR)&Gadget2SInfo,   /* SpecialInfo structure */
   200,   /* user-definable data */
   NULL   /* pointer to user-definable data */
};

UBYTE Gadget1SIBuff[]={"Welcome To Jumpdisk       "};
struct StringInfo Gadget1SInfo = {
   Gadget1SIBuff,   /* buffer where text will be edited */
   UNDOBUFFER1,   /* optional undo buffer */
   0,   /* character position in buffer */
   25,   /* maximum number of characters to allow */
   0,   /* first displayed character buffer position */
   0,0,0,0,0,   /* Intuition initialized and maintained variables */
   0,   /* Rastport of gadget */
   0,   /* initial value for integer gadgets */
   NULL   /* alternate keymap (fill in if you set the flag) */
};

SHORT BorderVectors2[] = {
   0,0,
   161,0,
   161,10,
   0,10,
   0,0
};
struct Border Border2 = {
   -2,-1,   /* XY origin relative to container TopLeft */
   3,0,JAM1,   /* front pen,copy back pen and drawmode */
   5,   /* number of XY vectors */
   BorderVectors2,   /* pointer to XY vectors */
   NULL   /* next border in list */
};

struct Gadget Gadget1 = {
   &Gadget2,   /* next gadget */
   111,28,   /* origin XY of hit box relative to window TopLeft */
   158,9,   /* hit box width and height */
   NULL,   /* gadget flags */
   RELVERIFY+STRINGCENTER+GADGIMMEDIATE,   /* activation flags */
   STRGADGET,   /* gadget type flags */
   (APTR)&Border2,   /* gadget border or image to be rendered */
   NULL,   /* alternate imagery for selection */
   NULL,/* first IntuiText structure */
   NULL,   /* gadget mutual-exclude long word */
   (APTR)&Gadget1SInfo,   /* SpecialInfo structure */
   100,   /* user-definable data */
   NULL   /* pointer to user-definable data */
};

#define GadgetList1 Gadget1

struct IntuiText IText2 = {
   3,0,JAM2,   /* front and back text pens, drawmode and fill byte */
   18,56,   /* XY origin relative to container TopLeft */
   NULL,   /* font pointer or NULL for default */
   "Enter Phonemes To Be Spoken and Press Return:",   /* pointer to text */
   NULL   /* next IntuiText structure */
};

struct IntuiText IText1 = {
   3,0,JAM2,   /* front and back text pens, drawmode and fill byte */
   32,15,   /* XY origin relative to container TopLeft */
   NULL,   /* font pointer or NULL for default */
   "Enter Text To Be Spoken and Press Return:",   /* pointer to text */
   &IText2   /* next IntuiText structure */
};

#define IntuiTextList1 IText1

struct NewWindow NewWindowStructure1 = {
   121,40,   /* window XY origin relative to TopLeft of screen */
   392,104,   /* window width and height */
   0,1,   /* detail and block pens */
   GADGETDOWN+GADGETUP+CLOSEWINDOW,   /* IDCMP flags */
   WINDOWDRAG+WINDOWDEPTH+WINDOWCLOSE,   /* other window flags */
   &Gadget1,    /* first gadget in gadget list */
   NULL,   /* custom CHECKMARK imagery */
   "Speech Window",   /* window title */
   NULL,   /* custom screen pointer */
   NULL,   /* custom bitmap */
   5,5,   /* minimum width and height */
   640,200,   /* maximum width and height */
   WBENCHSCREEN   /* destination screen type */
};


/* end of PowerWindows source generation */
struct Window *Window;
/******************* VARIABLES AND STRUCTURES FOR SPEAKING ***************/
  struct Library *TranslatorBase=NULL;
  struct MsgPort *WPort;
  extern struct IORequest *CreateExtIO();
  extern struct Library *OpenLibrary();
  struct narrator_rb *wmes;
  struct mouth_rb *rmes;
  BYTE audChanMasks[]={3,5,10,12};
/* * * * * * * * BEGINNING OF MAIN * * * * * * * * * * * * * * * * * * * */
void main() {
   ULONG Signals, MIClass;
   USHORT MIGadID;
   struct Gadget *MIGad;
   int successful;
   LONG gad_pos, real_pos;


   /* Open the translator and narrator */
   successful=OpenSpeech();
   if(successful==0)
      exit(FALSE);

   /* Say the welcome */
   SpeakLine();
   say_phoneme();

   /* Open a window to let the user interact */
   successful=OpenWin();
   if(successful==0)
      exit(FALSE);

   for (;;) {
    Signals=Wait(1<<Window->UserPort->mp_SigBit);
  
     while(message=(struct IntuiMessage *)GetMsg(Window->UserPort)) {
         MIClass=message->Class;
         MIGad  =(struct Gadget *)message->IAddress;
         MIGadID=MIGad->GadgetID;
         ReplyMsg(message);

         switch (MIClass) {
           case CLOSEWINDOW:
             ShutDown();
             exit(TRUE);
             break;
           case GADGETUP:
           /* If the Relverify flag is set, string gadgets will return */
           /* a GADGETUP message when the RETURN key is pressed.       */
            switch (MIGadID) {
               case TEXT_INPUT:
                 SpeakLine(); /* SpeakLine() does the translation */

                 /* Remove the gadgets and update with new text info */
                 gad_pos = RemoveGList(Window,&Gadget1,1L);
                 real_pos = AddGList(Window,&Gadget1,
                                       gad_pos,1L,(LONG)NULL);
                 RefreshGList(&Gadget2,Window,(LONG)NULL,1L);

                 gad_pos = RemoveGList(Window,&Gadget2,1L);
                 real_pos = AddGList(Window,&Gadget2,
                                       gad_pos,1L,(LONG)NULL);
                 RefreshGList(&Gadget2,Window,(LONG)NULL,1L);

                 /* Finally, speak the translated phonemes */
                 say_phoneme();
                 break;
               case PHON_INPUT:

                 /* This area allows direct entry of phonemes. The only */
                 /* problem with this is that user may enter incorrect  */
                 /* phoenemes resulting in no sound.                    */
                 say_phoneme();

                 break;
               default:
                 break;
              }           
             break;
           case GADGETDOWN:
             break;
           default:
             printf("Serious IDCMP problem.\n");
             break;
         } /* switch */
     } /* while  */
   }   /*  for  */
} 
/******** E N D   O F   M A I N () *******/
int OpenWin()
{
  IntuitionBase=(struct IntuitionBase *) 
    OpenLibrary("intuition.library",0);

  if(IntuitionBase==NULL) {
    DisplayBeep(NULL);
    return(0);
  } 

  GfxBase=(struct GfxBase *) 
    OpenLibrary("graphics.library",0);

  if(GfxBase==NULL) {
    DisplayBeep(NULL);
    return(0);
  } 

  if((Window=(struct Window *) OpenWindow(&NewWindowStructure1))==NULL)
    return(0);

  PrintIText(Window->RPort,&IText1,0,0);

  return(1); /* Successful */
}

int OpenSpeech()
{
  /* First set up our message port */
  if((WPort=(struct MsgPort *)CreatePort(0,0))==NULL)
    return(0);

  /* Do the CreateExtIO to allocate memory for I/O */
  if((wmes=(struct narrator_rb *) 
      CreateExtIO(WPort,sizeof(struct narrator_rb)))==NULL)
    return(0);

  wmes->message.io_Command=CMD_WRITE;
 
  /* Open the narrator device */
  if(OpenDevice("narrator.device",0,wmes,0)!=0)
    return(0);

  /* Open the translator library */
  TranslatorBase=(struct Library *) OpenLibrary("translator.library",1);
  if(TranslatorBase==NULL)
     return(0);
  return(1);
}

ShutDown()
{
  CloseWindow(Window); 
  CloseLibrary(TranslatorBase);
  CloseDevice(wmes);
}

SpeakLine()
{
  if((Translate(Gadget1SIBuff,25,Gadget2SIBuff,43))!=0) {
    DisplayBeep(NULL);
  }
}

say_phoneme()
{
  wmes->message.io_Data=(APTR)Gadget2SIBuff;
  wmes->message.io_Length=strlen(Gadget2SIBuff);
  wmes->ch_masks=audChanMasks;
  wmes->nm_masks=sizeof(audChanMasks);

  /* These are the various speaking parameters. Feel free to experiment */
  wmes->mouths=0;
  wmes->volume=40;
  wmes->rate=160;
  wmes->sex=MALE;
  wmes->pitch=DEFPITCH;

  /* DoIO actually does the speech. Notice that this function will not */
  /* return until after the speech is finished.                        */
  DoIO(wmes);
}
