/* 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/eSpeakPackage.h"

int MAX = 1000;   // maximum characters in an input line
int line_len;          // number of characters after initial whitespace

int output_channel = 1;

int debug = 1;  // debugging flag --- 0 for printing; 1 supress printing

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

/* read next [non-empty] line from input 
   empty lines will be skipped 
   initial whitespace is ignored
   full line array is initialized (nulls placed at end)
*/
void read_line (char * line)
{
  /* get next [non-empty] line */
  /* initial whitespace is trimmed */
  if (debug)
    fprintf (stderr, "info:  starting read_line\n");

  char ch = getchar();
  
  while (isspace(ch))
    {
      if (ch == '\n')
        {
          /* if at end of line, report 0 non-nulls on line */
          int zero = 0;
          if (debug)
            fprintf(stderr, "info:  null-line processing\n");
          write (output_channel, &zero, 4);
        }
      ch = getchar();
    }

  /* terminate line with nulls */
  line[0] = ch;
 
/* read line until '\n' */
  int i = 1;
  while ((i < MAX-1) && ((line[i] = getchar()) != '\n'))
    i++;
  /* store number of characters after initial whitespace */
  line_len = i;

  /* null character throughout rest of input line */
  for (; i < MAX; i++)
    line[i] = 0;
  if (debug)
    fprintf(stderr, "info:  read_line exiting\n");
}

int main ()
{

  if (debug)
    fprintf (stderr, "info:  starting textlines-to-speech\n");
  char line[MAX] = 0;

  /* 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;
  if (rand_num < 5)
    {
      espeak_VOICE his_voice = {NULL, NULL, NULL, 1, 55, 0, 0, 0};
      espeak_SetVoiceByProperties(&his_voice);
      espeak_SetParameter(espeakPITCH, 50, 0);
      espeak_SetParameter(espeakRANGE, 70, 0);
      if (debug)
        fprintf (stderr, "info:  initialization male\n");

          // speak line
      espeak_Synth("initialized with male voice", strlen("initialized with male voice"), 0, POS_CHARACTER, 0, 0,
                       NULL, NULL);
      // wait for speaking to finish
      espeak_Synchronize();  
    }   
  else
    {
      espeak_VOICE her_voice = {NULL, NULL, NULL, 2, 22, 0, 0, 0};
      espeak_SetVoiceByProperties(&her_voice);
      espeak_SetParameter(espeakPITCH, 80, 0);
      espeak_SetParameter(espeakRANGE, 70, 0);
      if (debug)
        fprintf (stderr, "info:  initialization female\n");
      espeak_Synth("initialized with female voice", strlen("initialized with female voice"), 0, POS_CHARACTER, 0, 0,
                   NULL, NULL);
      // wait for speaking to finish
      espeak_Synchronize();  

    }
  
  /* signal user package that set up is complete */
  int zero = 0;
  write (output_channel, &zero, 4);


/* retrieve first line */
  if (debug)
    fprintf (stderr, "info:  starting first read_line\n");
  read_line (line);

  while (strcmp (line, terminating_string) != 0)
    { 
      if (debug)
        fprintf (stderr, "info:  Line:  '%s'\n", line);
      // check voice parameter commands 

      if (strcmp(line, set_voice_female) == 0)
        {
          espeak_VOICE her_voice = {NULL, NULL, NULL, 2, 22, 0, 0, 0};
          espeak_SetVoiceByProperties(&her_voice);
          espeak_SetParameter(espeakPITCH, 80, 0);
          if (debug)
            fprintf (stderr, "info:  change female\n");
        }
      else if (strcmp(line, set_voice_male) == 0)
        {
          espeak_VOICE his_voice = (eSpeak_VOICE) {NULL, NULL, NULL, 1, 55, 0, 0, 0};
          espeak_SetVoiceByProperties(&his_voice);
          espeak_SetParameter(espeakPITCH, 50, 0);
          if (debug)
            fprintf (stderr, "info:  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();  
            }
        }

      /* record number of characters in line processed */  
      if (debug)
        fprintf (stderr, "info:  reporting %d characters read\n", line_len);
      write (output_channel, &line_len, 4);

      memset (line, 0, MAX);
      read_line (line);

      if (debug)
        fprintf (stderr, "info:  string length:  %d\n", strlen(line)); 
    }

  if (debug)
    fprintf(stderr, "info:  textlines-to-speech exiting\n");

  exit(0);
}
  

