/* program to speak multiple lines of text
        lines read from standard in
           each line may be up to 1000 characters in length
           including terminating null
        speech comes from espeak program
        program halts when line "eSpeakABBCCCDDDEEEEFFFFdone" read
*/

/* compile with the command:
   gcc -lespeak -o textlines-to-speech textlines-to-speech.c

 */

#include <stdio.h>
#include <string.h>
#include <espeak/speak_lib.h>
#include <semaphore.h>       /* semaphores for text-to-speech synchronization */
#include <fcntl.h>           /* for semaphore constants */
#include <errno.h>

/* libraries for the random number generator */
#include <stdlib.h>
#include <time.h>

int main ()
{
  int MAX = 1000;   // maximum characters in a line
  char line[MAX];

  /* sentinel strings for processing commands */
  char * terminating_string = "eSpeakABBCCCDDDEEEEFFFFdone";
  char * set_voice_female = "eSpeakABBCCCDDDEEEEFFFFfemale";
  char * set_voice_male = "eSpeakABBCCCDDDEEEEFFFFmale";

  
  /* initalize eSpeak package */
  espeak_Initialize(AUDIO_OUTPUT_PLAYBACK, 0, NULL, 0);
  espeak_SetVoiceByName("en-us");
  espeak_SetParameter(espeakRATE, 140, 0);

  /* set voice randomly to female or male */
  srand (time ((time_t *) 0) ); // initialize random generator

  int i, rand_num;
  for (i = 0; i < 10; i++)
    rand_num = rand() % 10;
  /* printf ("rand_num = %d\n", rand_num);*/
  if (rand_num < 5)
    {
      espeak_VOICE his_voice = {NULL, NULL, NULL, 1, 55, 0, 0, 0};
      espeak_SetVoiceByProperties(&his_voice);
          // speak line
      espeak_Synth("initialization male", strlen("initialization male"), 0, POS_CHARACTER, 0, 0,
                       NULL, NULL);
      // wait for speaking to finish
      espeak_Synchronize();  
     printf ("initialization male\n");
    }   
  else
    {
      espeak_VOICE her_voice = {NULL, NULL, NULL, 2, 32, 0, 0, 0};
      espeak_Synth("initialization female", strlen("initialization female"), 0, POS_CHARACTER, 0, 0,
                   NULL, NULL);
      // wait for speaking to finish
      espeak_Synchronize();  
      espeak_SetVoiceByProperties(&her_voice);
      espeak_Cancel();
      printf ("initialization female\n");
    }

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

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

   printf ("semaphores in textlines-to-speech initialized\n");
   /* signal eSpeakPackage that setup done */
   if (sem_post (sem_done) == 0)
     printf ("sem_post incremented\n");
   else
     printf ("sem_post increment failed\n");
   
  int sem_value;
  sem_getvalue (sem_done, &sem_value);
  printf ("value of sentinel:  %d\n", sem_value);

    printf ("on to first read in textlines-to-speech\n");

  // retrieve first line
  for (i = 0; i < MAX; i++)  // first, null entire line array
    line[i] = 0;

  sem_getvalue (sem_done, &sem_value);
  printf ("value of sentinel:  %d\n", sem_value);

  fgets (line, MAX, stdin);
     printf ("after first read in textlines-to-speech\n");
 // remove newline character, if present
  if (line[strlen(line)-1] == '\n')
    line[strlen(line)-1] = 0;
  printf ("Line before main loop:  '%s'\n", line);

  while (strcmp (line, terminating_string) != 0)
    { 
  sem_getvalue (sem_done, &sem_value);
  printf ("value of sentinel:  %d\n", sem_value);
      printf ("Line:  '%s'\n", line);
      // check voice parameter commands 
      if (strcmp(line, set_voice_female) == 0)
        {
          espeak_VOICE her_voice = {NULL, NULL, NULL, 2, 0, 0, 0, 0};
          espeak_SetVoiceByProperties(&her_voice);
          printf ("change female\n");
        }
      else if (strcmp(line, set_voice_male) == 0)
        {
          espeak_VOICE his_voice = {NULL, NULL, NULL, 1, 0, 0, 0, 0};
          espeak_SetVoiceByProperties(&his_voice);
          printf ("change male\n");
        }
      else
        {
          if (strlen(line) > 0)
            {
              // speak line
              espeak_Synth(line, strlen(line), 0, POS_CHARACTER, 0, 0, NULL, NULL);
              // wait for speaking to finish
              espeak_Synchronize();  
            }
        }
       sem_post (sem_done);

       /* get next [non-empty] line */
       /* initial whitespace is trimmed */
       char ch = fgetc(stdin);;
       while (isspace(ch))
         {
           if (ch == '\n')
             /* if at end of line, signal for next line */
             sem_post (sem_done);
           ch = fgetc(stdin);
         }
       line[0] = ch;

       /* read line until '\n' */
       i = 1;
       while ((i < MAX-1) && ((line[i] = fgetc(stdin)) != '\n'))
         i++;
       /* null character throughout rest of input line */
       for (; i < MAX; i++)
         line[i] = 0;

       /*  // get next line
      for (i = 0; i < MAX; i++)  // first, null entire line array
        line[i] = 0;
      fgets (line, MAX, stdin);
      // remove newline character, if present
      if (line[strlen(line)-1] == '\n')
      line[strlen(line)-1] = 0;     */


      printf ("string length:  %dn", strlen(line)); 
    }

  sem_getvalue (sem_done, &sem_value);
  printf ("value of sentinel:  %d\n", sem_value);

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

  char full_sem_done_name [50];
  strcpy ( full_sem_done_name, "/run/shm/sem.espeak-sem-done-curry");
 if (remove (full_sem_done_name))
   printf ("error in removing semaphore %s; code %s\n", full_sem_done_name, strerror(errno));

  return 0;
}
