Logo Search packages:      
Sourcecode: festival version File versions  Download package

festival_client.cc

/*************************************************************************/
/*                                                                       */
/*                Centre for Speech Technology Research                  */
/*                     University of Edinburgh, UK                       */
/*                       Copyright (c) 1996,1997                         */
/*                        All Rights Reserved.                           */
/*                                                                       */
/*  Permission is hereby granted, free of charge, to use and distribute  */
/*  this software and its documentation without restriction, including   */
/*  without limitation the rights to use, copy, modify, merge, publish,  */
/*  distribute, sublicense, and/or sell copies of this work, and to      */
/*  permit persons to whom this work is furnished to do so, subject to   */
/*  the following conditions:                                            */
/*   1. The code must retain the above copyright notice, this list of    */
/*      conditions and the following disclaimer.                         */
/*   2. Any modifications must be clearly marked as such.                */
/*   3. Original authors' names are not deleted.                         */
/*   4. The authors' names are not used to endorse or promote products   */
/*      derived from this software without specific prior written        */
/*      permission.                                                      */
/*                                                                       */
/*  THE UNIVERSITY OF EDINBURGH AND THE CONTRIBUTORS TO THIS WORK        */
/*  DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING      */
/*  ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT   */
/*  SHALL THE UNIVERSITY OF EDINBURGH NOR THE CONTRIBUTORS BE LIABLE     */
/*  FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES    */
/*  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN   */
/*  AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,          */
/*  ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF       */
/*  THIS SOFTWARE.                                                       */
/*                                                                       */
/*************************************************************************/
/*             Author :  Alan W Black                                    */
/*             Date   :  December 1996                                   */
/*-----------------------------------------------------------------------*/
/*                                                                       */
/* Client program used to send comands/data to a festival server         */
/*                                                                       */
/*=======================================================================*/

#include <stdio.h>
#include "EST_unix.h"
#include "festival.h"

#ifdef WIN32
typedef HANDLE SERVER_FD;
#else
typedef FILE *SERVER_FD;
#endif

static void festival_client_main(int argc, char **argv);
static void copy_to_server(FILE *fdin,SERVER_FD serverfd);
static void ttw_file(SERVER_FD serverfd, const EST_String &file);
static void client_accept_waveform(SERVER_FD fd);
static void client_accept_s_expr(SERVER_FD fd);
static void new_state(int c, int &state, int &bdepth);

static EST_String output_filename = "-";
static EST_String output_type = "riff";
static EST_String tts_mode = "nil";
static EST_String prolog = "";
static int withlisp = FALSE;
static EST_String aucommand = "";
static int async_mode = FALSE;

// So that festival_error works (and I don't need the whole of libFestival.a)
void festival_tidy_up() { return; }

int main(int argc, char **argv)
{

    festival_client_main(argc,argv);

    return 0;
}

static void festival_client_main(int argc, char **argv)
{
    EST_Option al;
    EST_StrList files;
    EST_String server;
    int port;
    FILE *infd;

    parse_command_line(argc, argv, 
      EST_String("Usage:\n")+
        "festival_client <options> <file0> <file1> ...\n"+
      "Access to festival server process\n"+
      "--server <string>   hostname (or IP number) of server\n"+
      "--port <int> {1314} port number of server proces (1314)\n"+
      "--output <string>   file to save output waveform to\n"+
      "--otype <string> {riff}\n"
        "                    output type for waveform\n"+
      "--passwd <string>   server passwd in plain text (optional)\n"+
      "--prolog <string>   filename containing commands to be sent\n"+
        "                    to the server before standard commands\n"+
        "                    (useful when using --ttw)\n"+
      "--async             Asychronous mode, server may send back\n"+
        "                    multiple waveforms per text file\n"+
      "--ttw               Text to waveform: take text from first\n"+
        "                    arg or stdin get server to return\n"+
        "                    waveform(s) stored in output or operated\n"+
        "                    on by aucommand.\n"+
        "--withlisp          Output lisp replies from server.\n"+
        "--tts_mode <string> TTS mode for file (default is fundamental).\n"+
        "--aucommand <string>\n"+
        "                    command to be applied to each\n"+
        "                    waveform retruned from server.  Use $FILE\n"+
        "                    in string to refer to waveform file\n",
                  files, al);

    if (al.present("--server"))
      server = al.val("--server");
    else
      server = "localhost";

    if (al.present("--port"))
      port = al.ival("--port");
    else
      port = FESTIVAL_DEFAULT_PORT;

    if (al.present("--tts_mode"))
      tts_mode = al.val("--tts_mode");

    if (al.present("--output"))
      output_filename = al.val("--output");
    if (al.present("--otype"))
    {
      output_type = al.val("--otype");
      if (!output_type.matches(RXalphanum))
      {
          cerr << "festival_client: invalid output type \"" 
            << output_type << "\"" << endl;
          exit(-1);
      }
    }

    // Specify what to do with received waveform
    if (al.present("--aucommand"))
      aucommand = al.val("--aucommand");

    if (al.present("--withlisp"))
      withlisp = TRUE;

    if (al.present("--async"))
      async_mode = TRUE;
    else
      async_mode = FALSE;

    int fd = festival_socket_client(server,port);
#ifdef WIN32
    HANDLE serverfd = (HANDLE)fd;
#else
    FILE *serverfd = fdopen(fd,"wb");
#endif

    if (al.present("--passwd"))
#ifdef WIN32
      {
            DWORD bytes_written;
            DWORD passwdlen = (DWORD)strlen(al.val("--passwd"))+1;
            char *buffer = new char[passwdlen];
            sprintf(buffer,"%s\n",al.val("--passwd"));
            bytes_written = send((SOCKET)serverfd,buffer,passwdlen,0);
            if (SOCKET_ERROR == bytes_written || bytes_written < passwdlen)
            {
                  GetLastError();  // at least get the error
                  cerr << "festival_client:  can't send password to server\n";
            }
            delete [] buffer;
      }
#else
      fprintf(serverfd,"%s\n",(const char *)al.val("--passwd"));
#endif

    if (al.present("--prolog"))
    {
      FILE *pfd = fopen(al.val("--prolog"),"rb");
      if (pfd == NULL)
      {
          cerr << "festival_client: can't open prolog file \"" 
            << al.val("--prolog") << "\"" << endl;
          exit(-1);
      }
      copy_to_server(pfd,serverfd);
      fclose(pfd);
    }

    if (al.present("--ttw"))
      ttw_file(serverfd,files.nth(0));
    else
    {
      if ((files.length() == 0) || (files.nth(0) == "-"))
          copy_to_server(stdin,serverfd);
      else 
      {
          if ((infd=fopen(files.nth(0),"rb")) == NULL)
          {
            cerr << "festival_client: can't open \"" <<
                files.nth(0) << "\"\n";
            exit(-1);
          }
          copy_to_server(infd,serverfd);
      }
    }

    return;
}

static void ttw_file(SERVER_FD serverfd, const EST_String &file)
{
    // text to waveform file.  This includes the tts wraparounds for
    // the text in file and outputs a waveform in output_filename
    // This is done as *one* waveform.  This is designed for short
    // dialog type examples.  If you need spooling this isn't the
    // way to do it
    EST_String tmpfile = make_tmp_filename();
    FILE *fd, *tfd;
    int c;
    
    if ((fd=fopen(tmpfile,"wb")) == NULL)
    {
      cerr << "festival_client: can't open tmpfile \"" <<
          tmpfile << "\"\n";
      exit(-1);
    }
    // Here we ask for NIST because its a byte order aware headered format
    // the eventual desired format might be unheadered and if we asked the
    // the server for that we wouldn't know if it required byte swap or 
    // not.  The returned wave data from the server is actually saved
    // to a file and read in by EST_Wave::load so NIST is a safe option
    // Of course when the wave is saved by the client the requested 
    // format is respected.
    fprintf(fd,"(Parameter.set 'Wavefiletype 'nist)\n");
    if (async_mode)
    {   // In async mode we need to set up tts_hooks to send back the waves
      fprintf(fd,"(tts_return_to_client)\n");
      fprintf(fd,"(tts_text \"\n");
    }
    else   // do it in one go
      fprintf(fd,"(tts_textall \"\n");
    if (file == "-")
      tfd = stdin;
    else if ((tfd=fopen(file,"rb")) == NULL)
    {
      cerr << "festival_client: can't open text file \"" <<
          file << "\"\n";
      exit(-1);
    }

    while ((c=getc(tfd)) != EOF)
    {
      if ((c == '"') || (c == '\\'))
          putc('\\',fd);
      putc(c,fd);
    }
    if (file != "-")
      fclose(tfd);

    fprintf(fd,"\" \"%s\")\n",(const char *)tts_mode);

    fclose(fd);

    // Now send the file to the server
    if ((fd=fopen(tmpfile,"rb")) == NULL)
    {
      cerr << "festival_client: tmpfile \"" <<
          tmpfile << "\" mysteriously disappeared\n";
      exit(-1);
    }
    copy_to_server(fd,serverfd);
    fclose(fd);
    unlink(tmpfile);
}

static void copy_to_server(FILE *fdin,SERVER_FD serverfd)
{
    // Open a connection and copy everything from stdin to 
    // server
    int c,n;
    int state=0;
    int bdepth=0;
    char ack[4];

    while((c=getc(fdin)) != EOF)
    {
#ifdef WIN32
      DWORD bytes_pending;
      n = send((SOCKET)serverfd,(const char *)&c,1,0);
      if (SOCKET_ERROR == n || 0 == n)
      {
            if (SOCKET_ERROR == n)
                  GetLastError();
            cerr << "festival_client: couldn't copy to server\n";
      }
#else
      putc(c,serverfd);
#endif
      new_state(c,state,bdepth);

      if (state == 1)
      {
          state = 0;
#ifndef WIN32
          fflush(serverfd);
#endif
          do {
#ifdef WIN32
            {
                  for (n=0; n < 3; )
                  {
                        int bytes_read = recv((SOCKET)serverfd,ack+n,3-n,0);
                        if (SOCKET_ERROR == bytes_read)
                        {
                              GetLastError();
                              cerr << "festival_client: error reading from server\n";
                        }
                        else n+= bytes_read;
                  }
            }
#else
            for (n=0; n < 3; )
                n += read(fileno(serverfd),ack+n,3-n);
#endif
            ack[3] = '\0';
            if (streq(ack,"WV\n"))    // I've been sent a waveform
                client_accept_waveform(serverfd);
            else if (streq(ack,"LP\n"))    // I've been sent an s-expr
            {
                client_accept_s_expr(serverfd);
            }
            else if (streq(ack,"ER\n"))
            {
                cerr << "festival server error: reset to top level\n";
                break;
            }
          } while (!streq(ack,"OK\n"));
      }
    }
}

static void new_state(int c, int &state, int &bdepth)
{
    // FSM (plus depth) to detect end of s-expr

    if (state == 0)
    {
      if ((c == ' ') || (c == '\t') || (c == '\n') || (c == '\r'))
          state = 0;
      else if (c == '\\')   // escaped character
          state = 2;
      else if (c == ';')
          state = 3;  // comment
      else if (c == '"')
          state = 4;  // quoted string
      else if (c == '(')
      {
          bdepth++;
          state = 5;
      }
      else
          state = 5;  // in s-expr
    }
    else if (state == 2)
      state = 5;      // escaped character
    else if (state == 3)
    {
      if (c == '\n')
          state = 5;
      else
          state = 3;
    }
    else if (state == 4)
    {
      if (c == '\\')
          state = 6;
      else if (c == '"')
          state = 5;
      else
          state = 4;
    }
    else if (state == 6)
      state = 4;
    else if (state == 5)
    {
      if ((c == ' ') || (c == '\t') || (c == '\n') || (c == '\r'))
      {
          if (bdepth == 0)
            state = 1;
          else
            state = 5;
      }
      else if (c == '\\')   // escaped character
          state = 2;
      else if (c == ';')
          state = 3;  // comment
      else if (c == '"')
          state = 4;  // quoted string
      else if (c == '(')
      {
          bdepth++;
          state = 5;
      }
      else if (c == ')')
      {
          bdepth--;
          state = 5;
      }
      else
          state = 5;  // in s-expr
    }
    else  // shouldn't get here
      state = 5;
}

static void client_accept_waveform(SERVER_FD fd)
{
    // Read a waveform from fd.  The waveform will be passed
    // using 
    EST_String tmpfile = make_tmp_filename();
    EST_Wave sig;

    // Have to copy this to a temporary file, then load it.
#ifdef WIN32
    socket_receive_file((SOCKET)fd,tmpfile);
#else
    socket_receive_file(fileno(fd),tmpfile);
#endif
    sig.load(tmpfile);
    if (aucommand != "")
    {
      // apply the command to this file 
      EST_String tmpfile2 = make_tmp_filename();
      sig.save(tmpfile2,output_type);
      char *command = walloc(char,1024+tmpfile2.length()+aucommand.length());
      sprintf(command,"FILE=\"%s\"; %s",(const char *)tmpfile2,
            (const char *)aucommand);
      system(command);
      unlink(tmpfile2);
    }
    else if (output_filename == "")
      cerr << "festival_client: ignoring received waveform, no output file"
          << endl;
    else
      sig.save(output_filename,output_type);
    unlink(tmpfile);
}

static void client_accept_s_expr(SERVER_FD fd)
{
    // Read an s-expression.  Inefficeintly into a file
    EST_String tmpfile = make_tmp_filename();
    FILE *tf;
    int c;
    
    // Have to copy this to a temporary file, then load it.
#ifdef WIN32
    socket_receive_file((SOCKET)fd,tmpfile);
#else
    socket_receive_file(fileno(fd),tmpfile);
#endif
    
    if (withlisp)
    {
      if (( tf = fopen(tmpfile,"rb")) == NULL)
      {
          cerr << "festival_client: lost an s_expr tmp file" << endl;
      }
      else
      {
          while ((c=getc(tf)) != EOF)
            putc(c,stdout);
          fclose(tf);
      }
    }
    
    unlink(tmpfile);
}


Generated by  Doxygen 1.6.0   Back to index