/* * * * * * * * * * * * * * * * * * * * * * 
 *  eSpeakPackage.h  -- Header to utilize the eSpeak package within C
 *
 *  eSpeak's author:  Jonathan Duddington
 *  eSpeak source:  http://espeak.sourceforge.net/
 *
 *  author of this adaptation package:  Henry M. Walker
 *
 * * * * * * * * * * * * * * * * * * * * * * /

/* Note: each function name starts with eSpeak to make it 
   easier to understand whether it is a speech function. */

#include "eSpeakPackage.h"
#include <sys/types.h>       /* file of data types needed for many compilers */
#include <unistd.h>          /* needed for fork, getpid procedures */
#include <semaphore.h>       /* semaphores for text-to-speech synchronization */
#include <fcntl.h>           /* for semaphore constants */
#include <stdlib.h>          /* needed for exit procedures */
#include <string.h>          /* needed for constructing full path name */
#include <stdio.h>
#include <espeak/speak_lib.h>

/* string to terminate connection to textlines-to-speech program */
char * terminating_string = "eSpeakABBCCCDDDEEEEFFFFdone";

/* directory of textlines-to-speech program */
char * speech_dir = "/home/walker/public_html/bluetooth-with-c/MyroC";

FILE * fpespeak;   /* variable for accessing textlines-to-speech program */

/* semaphores for text-to-speech synchronization */
sem_t *sem_start; /* textlines-to-speech.c ready to receive line of text */
sem_t *sem_done; /* textlines-to-speech.c finished with line of text */

/* set up the local environment to utilize the eSpeak package 
 */
void eSpeakConnect ()
{  pid_t pid;                /* variable to record process id of child */
   
  /* start pulseaudio running for audio output */
   pid = fork();             /* create new process */
   if ( -1 == pid)           /* check for error in spawning child process */
     { perror ("error in fork");  
       exit (1);
     }

   if (0 == pid)             /* check if this is the new child process */
     { /* processing for child */
       printf ("starting pulseaudio\n");

       /* construct full path name of startPulseAudio program */
       char * prog_call = "startPulseAudio";
       char * full_script = malloc (strlen(speech_dir) + strlen(prog_call) + 2);
       full_script[0] = 0;
       strcpy (full_script, speech_dir);
       strcat (full_script, "/");
       strcat (full_script, prog_call);
       /* printf ("full programm call:  %s\n", full_script); */

       execlp (full_script, full_script, (char *)0);
       free (full_script);
       exit(0);
     } 
  else 
     { /* processing for parent */
       waitpid (pid);
       /* printf ("parent in eSpeakConnect\n"); */
     }

   /* set up read, continue semaphores for synchronization with
      textlines-to-speech.c
   */
   int hostnameMAX = 50;
   char hostname [hostnameMAX];
   gethostname (hostname, hostnameMAX);
   
   char sem_start_name [hostnameMAX];
   char sem_done_name [hostnameMAX];
   strcpy (sem_start_name, "/espeak-sem-start-");
   strcat (sem_start_name, hostname);
   strcpy (sem_done_name, "/espeak-sem-done-");
   strcat (sem_done_name, hostname);
   /* printf ("semaphorename: %s\n", semaphorename); */

   /* set up named semaphones with permissions 0644
      both semaphores initialized to value 0
   */
   sem_start = sem_open(sem_start_name, O_CREAT, 0644, 0); 
   if (sem_start == SEM_FAILED)
     printf ("error opening sem start\n");
   sem_done  = sem_open(sem_done_name,  O_CREAT, 0644, 0); 
   if (sem_done == SEM_FAILED)
     printf ("error opening sem done\n");
   printf ("semaphorename: %s   %s\n", sem_start_name, sem_done_name); 

   /* start program textlines-to-speech running
      to speak successive lines of text
      
      textlines-to-speech takes successive lines from standard input
      input continues until "eSpeakABBCCCDDDEEEEFFFFdone" read
   */

   /* construct full path name of textlines-to-speech program */
   char * prog_call = "textlines-to-speech 2> /dev/null";
   char * full_call = malloc (strlen(speech_dir) + strlen(prog_call) + 2);
   full_call[0] = 0; /* start with null string */
   strcpy (full_call, speech_dir);
   strcat (full_call, "/");
   strcat (full_call, prog_call);
   /* printf ("full programm call:  %s\n", full_call); */
   
     /* start executing textlines-to-speech with input through pipe
      child process will handle espeak processing
    */

   fpespeak = popen (full_call, "w");
   if (fpespeak == NULL)
     { perror ("error in starting espeak framework");
       exit (1);
     }

   free (full_call);

   sem_wait (sem_done);
   printf ("eSpeakConnect done\n");
}

/* clean up the local environment when the eSpeak package is no longer needed
 */
void eSpeakDisconnect ()
{  pid_t pid;                /* variable to record process id of child */
   

  /* stop textlines-to-speech with sentinel string*/
  /* sem_wait (sem_start);*/
  fprintf (fpespeak, "%s", "eSpeakABBCCCDDDEEEEFFFFdone");
  fputc ('\n', fpespeak);
  sem_wait (sem_done);

  /* close pipe to textlines-to-speech */
  pclose (fpespeak);

  /* clean up semaphores */
  sem_close (sem_start);
  sem_close (sem_done);

   /* terminate pulseaudio daemon */
   pid = fork();             /* create new process */
   if ( -1 == pid)           /* check for error in spawning child process */
     { perror ("error in fork");  
       exit (1);
     }

   if (0 == pid)             /* check if this is the new child process */
     { /* processing for child */
       printf ("stopping pulseaudio\n");
       char * prog_call = "stopPulseAudio";
       char * full_script = malloc (strlen(speech_dir) + strlen(prog_call) + 2);
       full_script[0] = 0;
       strcpy (full_script, speech_dir);
       strcat (full_script, "/");
       strcat (full_script, prog_call);
       /* printf ("full programm call:  %s\n", full_script); */

       execlp (full_script, full_script, (char *)0);
       free (full_script);
       exit(0);
     } 
  else 
     { /* processing for parent */
       waitpid (pid);
       /* printf ("parent in eSpeakDisconnect\n"); */
     }
}

/* create audio for the user
   @param text:  the string to be converted to audible speech
                 any string is valid, as long as it does not begin
                     eSpeakABBCCCDDDEEEEFFFF   
 */
void eSpeakTalk (const char * text)
{ 
  /* send text through pipe to textlines-to-speech program */
  printf ("starting to speak %s\n", text);
  /*sem_wait (sem_start); */
  fprintf (fpespeak, "%s", text);
  fputc ('\n', fpespeak);
  printf ("done speaking %s\n", text);
  sem_wait (sem_done);
  printf ("exiting eSpeakTalk %s\n", text);
}

/* set quality of voice to female or male 
   @param gender:  "female" sets woman's voice
                   "male" sets man's voice
   if gender is neither "female" nor "male", voice unchanged
*/
void eSpeakSetGender (const char * gender)
{
  int i;
  int len = strlen(gender)+1;

  /* capitalize input string */
  char genderCaps[len];
  for (i = 0; i < strlen(gender); i++)
    genderCaps[i] = tolower(gender[i]);
  genderCaps [len-1] = 0;
  
  if (strcmp("male", genderCaps) == 0)
    {
      /* tell textlines-to-speech to switch to male voice */
      /*sem_wait (sem_start);*/
      fprintf (fpespeak, "%s", "eSpeakABBCCCDDDEEEEFFFFmale");
      fputc ('\n', fpespeak);
      sem_wait (sem_done);
    }
  else if (strcmp("female", genderCaps) == 0)
    {
      /* tell textlines-to-speech to switch to female voice */
      /*sem_wait (sem_start);*/
      fprintf (fpespeak, "%s", "eSpeakABBCCCDDDEEEEFFFFfemale");
      fputc ('\n', fpespeak);
      sem_wait (sem_done);
    }
}

