1#!/usr/local/bin/perl
2
3# festival_client.pl - a perl socket client for festival
4#
5# Copyright (C) 1997
6# Kevin A. Lenzo (lenzo@cs.cmu.edu) 7/97
7# All rights reserved.
8#
9# The authors hereby grant permission to use, copy, modify, distribute,
10# and license this software and its documentation for any purpose, provided
11# that existing copyright notices are retained in all copies and that this
12# notice is included verbatim in any distributions. No written agreement,
13# license, or royalty fee is required for any of the authorized uses.
14# Modifications to this software may be copyrighted by their authors
15# and need not follow the licensing terms described here, provided that
16# the new terms are clearly indicated on the first page of each file where
17# they apply.
18#
19# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
20# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
21# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
22# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
23# POSSIBILITY OF SUCH DAMAGE.
24#
25# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
26# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
27# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE
28# IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
29# NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
30# MODIFICATIONS.
31#
32#########################################################################
33#
34# A good deal of this was taken from the example in the
35# perlipc man page.  The rest is simply the Festival-specific
36# stuff.
37
38use IO::Socket;
39
40package Festival;
41
42my ($audio_command, $audio_file, $file_stuff_key);
43my ($host, $port, $kidpid, $handle, $line);
44
45$wave_type = "nist";                 # the type of the audio files
46$audio_command  = "na_play";         # your local audio play command
47
48# uncomment the next line if your audio command requires a file
49# $audio_file = "/tmp/client_tmp$$.nist"; # temp file for waveforms
50
51$file_stuff_key = "ft_StUfF_key";    # defined in speech tools
52
53$host = shift || 'localhost';
54$port = shift || 1314;
55if ($host eq "-h") {
56print STDOUT "
57  Usage:
58
59     $0 [<server> [<port>]]
60
61         OR
62
63     $0 -h
64
65  perl client for the Festival text-to-speech server
66
67  Lines that do not begin with a ( are treated as text
68  to be spoken.  Those that do begin with a ( are assumed
69  to Scheme commands to festival and are sent without
70  alteration.  Use `quit' or `exit' to quit.
71
72  Note that a server must be started before the client
73  will work.
74
75  Use the `-h' (help) option for this message.
76
77";
78
79    exit(1);
80}
81
82# create a tcp connection to the specified host and port
83
84$handle = IO::Socket::INET->new(Proto     => "tcp",
85				PeerAddr  => $host,
86				PeerPort  => $port)
87    or die "
88  Can't connect to port $port on $host: $!
89  (Are you sure the server is running and accepting connections?)
90
91";
92
93$handle->autoflush(1);     # so output gets there right away
94print STDERR "[Connected to $host:$port]\n";
95
96# tell the server to send us back a 'file' of the right type
97print $handle "(Parameter.set 'Wavefiletype '$wave_type)\n";
98
99# split the program into two processes, identical twins
100die "can't fork: $!" unless defined($kidpid = fork());
101
102# the if{} block runs only in the parent process
103if ($kidpid) {
104    # the parent handles the input so it can exit on quit
105
106    while (defined ($line = <STDIN>)) {
107	last if ($line =~ /^(quit|exit)$/);
108
109	if ($line =~ /^\(/) {
110	    # just send it wholesale if it's a ( )
111	    print $handle $line;
112	} else {
113	    # otherwise assume it's text to be spoken
114	    chomp $line;
115	    print $handle "(tts_textall \"$line\" 'file)\n";
116	}
117    }
118    kill("TERM", $kidpid);# send SIGTERM to child
119}
120# the else{} block runs only in the child process
121else {
122    # the child is forked off to get the results from the server
123    undef $line;
124    while (($line = $remains) || defined ($line = <$handle>)) {
125	undef $remains;
126	if ($line eq "WV\n") { # we have a waveform coming
127	    undef $result;
128	    if ($audio_file) {
129		open(AUDIO, ">$audio_file");
130	    } else {
131		open(AUDIO, "| $audio_command");
132	    }
133	    while ($line = <$handle>) {
134		if ($line =~ s/$file_stuff_key(.*)$//s) {
135		    $remains = $1;
136		    print AUDIO $line;
137		    last;
138		}
139		print AUDIO $line;
140	    }
141	    close AUDIO;
142
143	    if ($audio_file) {
144		# call the command if we weren't piping
145		system("$audio_command $audio_file");
146
147		# remove the evidence
148		unlink($audio_file);
149            }
150	} elsif ($line eq "LP\n") {
151	    while ($line = <$handle>) {
152		if ($line =~ s/$file_stuff_key(.*)$//s) {
153		    $remains = $1;
154		    print STDOUT $line;
155		    last;
156		}
157		print STDOUT $line;
158	    }
159	} else {
160	    # if we don't recognize it, echo it
161	    print STDOUT $line;
162	}
163    }
164}
165