blob: 0549cccb00da2482ec699c2bd17e5330008d23fb [file] [log] [blame]
Jonas Häggqvist17e03e72007-08-25 22:00:13 +00001#!/usr/bin/perl -s
2# __________ __ ___.
3# Open \______ \ ____ ____ | | _\_ |__ _______ ___
4# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7# \/ \/ \/ \/ \/
8# $Id:
9#
10# Copyright (C) 2007 Jonas Häggqvist
11#
12# All files in this archive are subject to the GNU General Public License.
13# See the file COPYING in the source tree root for full license agreement.
14#
15# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16# KIND, either express or implied.
17
18use strict;
19use warnings;
20use File::Basename;
21use File::Copy;
22use Switch;
23use vars qw($V $C $t $l $e $E $s $S $i $v);
Jens Arnold080522f2007-09-01 08:38:10 +000024use IPC::Open2;
Jonas Häggqvist17e03e72007-08-25 22:00:13 +000025use IPC::Open3;
26use Digest::MD5 qw(md5_hex);
Jonas Häggqvist42951492007-11-16 19:59:09 +000027use DirHandle;
Jonas Häggqvist17e03e72007-08-25 22:00:13 +000028
29sub printusage {
30 print <<USAGE
31
32Usage: voice.pl [options] [path to dir]
33 -V
34 Create voice file. You must also specify -t and -l.
35
36 -C
37 Create .talk clips.
38
39 -t=<target>
40 Specify which target you want to build voicefile for. Must include
41 any features that target supports.
42
43 -i=<target_id>
44 Numeric target id. Needed for voice building.
45
46 -l=<language>
47 Specify which language you want to build. Without .lang extension.
48
49 -e=<encoder>
50 Which encoder to use for voice strings
51
52 -E=<encoder options>
53 Which encoder options to use when compressing voice strings. Enclose
54 in double quotes if the options include spaces.
55
56 -s=<TTS engine>
57 Which TTS engine to use.
58
59 -S=<TTS engine options>
60 Options to pass to the TTS engine. Enclose in double quotes if the
61 options include spaces.
62
63 -v
64 Be verbose
65USAGE
66;
67}
68
69# Initialize TTS engine. May return an object or value which will be passed
70# to voicestring and shutdown_tts
71sub init_tts {
72 our $verbose;
73 my ($tts_engine, $tts_engine_opts, $language) = @_;
Jens Arnold080522f2007-09-01 08:38:10 +000074 my %ret = ("name" => $tts_engine);
Jonas Häggqvist17e03e72007-08-25 22:00:13 +000075 switch($tts_engine) {
76 case "festival" {
77 print("> festival $tts_engine_opts --server\n") if $verbose;
78 my $pid = open(FESTIVAL_SERVER, "| festival $tts_engine_opts --server > /dev/null 2>&1");
Jens Arnold080522f2007-09-01 08:38:10 +000079 my $dummy = *FESTIVAL_SERVER; #suppress warning
Jonas Häggqvist17e03e72007-08-25 22:00:13 +000080 $SIG{INT} = sub { kill TERM => $pid; print("foo"); panic_cleanup(); };
81 $SIG{KILL} = sub { kill TERM => $pid; print("boo"); panic_cleanup(); };
Jens Arnold080522f2007-09-01 08:38:10 +000082 $ret{"pid"} = $pid;
Jonas Häggqvist17e03e72007-08-25 22:00:13 +000083 }
Jens Arnold5dbea462007-09-02 22:32:34 +000084 case "sapi" {
Jonas Häggqvist17e03e72007-08-25 22:00:13 +000085 my $toolsdir = dirname($0);
86 my $path = `cygpath $toolsdir -a -w`;
87 chomp($path);
Jens Arnold080522f2007-09-01 08:38:10 +000088 $path = $path . '\\';
Jens Arnold5dbea462007-09-02 22:32:34 +000089 my $cmd = $path . "sapi_voice.vbs /language:$language $tts_engine_opts";
Jens Arnold080522f2007-09-01 08:38:10 +000090 $cmd =~ s/\\/\\\\/g;
91 print("> cscript //nologo $cmd\n") if $verbose;
92 my $pid = open2(*CMD_OUT, *CMD_IN, "cscript //nologo $cmd");
93 $SIG{INT} = sub { print(CMD_IN "QUIT\r\n"); panic_cleanup(); };
94 $SIG{KILL} = sub { print(CMD_IN "QUIT\r\n"); panic_cleanup(); };
Jens Arnolddf9a1662007-09-04 22:03:05 +000095 print(CMD_IN "QUERY\tVENDOR\r\n");
96 my $vendor = readline(CMD_OUT);
97 $vendor =~ s/\r\n//;
Jens Arnold2829aef2007-09-04 22:13:52 +000098 %ret = (%ret,
Jens Arnolddf9a1662007-09-04 22:03:05 +000099 "stdin" => *CMD_IN,
100 "stdout" => *CMD_OUT,
101 "toolspath" => $path,
102 "vendor" => $vendor);
Jonas Häggqvist17e03e72007-08-25 22:00:13 +0000103 }
104 }
Jens Arnold080522f2007-09-01 08:38:10 +0000105 return \%ret;
Jonas Häggqvist17e03e72007-08-25 22:00:13 +0000106}
107
108# Shutdown TTS engine if necessary.
109sub shutdown_tts {
Jens Arnold080522f2007-09-01 08:38:10 +0000110 my ($tts_object) = @_;
111 switch($$tts_object{"name"}) {
Jonas Häggqvist17e03e72007-08-25 22:00:13 +0000112 case "festival" {
113 # Send SIGTERM to festival server
Jens Arnold080522f2007-09-01 08:38:10 +0000114 kill TERM => $$tts_object{"pid"};
Jonas Häggqvist17e03e72007-08-25 22:00:13 +0000115 }
Jens Arnold5dbea462007-09-02 22:32:34 +0000116 case "sapi" {
Jens Arnold080522f2007-09-01 08:38:10 +0000117 print({$$tts_object{"stdin"}} "QUIT\r\n");
118 close($$tts_object{"stdin"});
Jonas Häggqvist17e03e72007-08-25 22:00:13 +0000119 }
120 }
121}
122
123# Apply corrections to a voice-string to make it sound better
124sub correct_string {
125 our $verbose;
Jens Arnold080522f2007-09-01 08:38:10 +0000126 my ($string, $language, $tts_object) = @_;
Jonas Häggqvist17e03e72007-08-25 22:00:13 +0000127 my $orig = $string;
128 switch($language) {
Jens Arnolddf9a1662007-09-04 22:03:05 +0000129 # General for all engines and languages
Jens Arnold2829aef2007-09-04 22:13:52 +0000130 $string =~ s/USB/U S B/g;
131 $string =~ s/ID3/I D 3/g;
Jonas Häggqvist17e03e72007-08-25 22:00:13 +0000132
Jens Arnolddf9a1662007-09-04 22:03:05 +0000133 case "english" {
Jonas Häggqvist29f07cd2007-10-02 16:34:06 +0000134 switch($$tts_object{"name"}) {
Jonas Häggqvist2af37552007-10-02 17:32:30 +0000135 case ["sapi","festival"] {
Jonas Häggqvist29f07cd2007-10-02 16:34:06 +0000136 $string =~ s/plugin(s?)/plug-in$1/ig;
137 }
138 }
Jens Arnolddf9a1662007-09-04 22:03:05 +0000139 }
140 case "deutsch" {
141 # for all german engines (e.g. for english words)
142 $string =~ s/alkaline/alkalein/ig;
143 $string =~ s/byte(s?)/beit$1/ig;
144 $string =~ s/clip(s?)/klipp$1/ig;
145 $string =~ s/cuesheet/kjuschiet/ig;
146 $string =~ s/dither/didder/ig;
147 $string =~ s/equalizer/iquileiser/ig;
148 $string =~ s/\bflash\b/fläsh/ig;
149 $string =~ s/\bfirmware(s?)\b/firmwer$1/ig;
150 $string =~ s/\bI D 3 tag\b/I D 3 täg/ig; # can't just use "tag" here
151 $string =~ s/\bloudness\b/laudness/ig;
152 $string =~ s/\bunicode\b/unikod/ig;
153 switch($$tts_object{"name"}) {
154 case "sapi" { # just for SAPI
155 switch($$tts_object{"vendor"}) {
156 case "AT&T Labs" {
157 $string =~ s/alphabet/alfabet/ig;
158 $string =~ s/ampere/amper/ig;
159 $string =~ s/\bdezibel\b/de-zibell/ig;
160 $string =~ s/diddering/didde-ring/ig;
161 $string =~ s/energie\b/ener-gie/ig;
162 $string =~ s/\bnumerisch\b/numehrisch/ig;
163 $string =~ s/\brücklauf\b/rück-lauf/ig;
164 $string =~ s/\bsuchlauf\b/such-lauf/ig;
165 }
166 }
167 }
Jonas Häggqvist17e03e72007-08-25 22:00:13 +0000168 }
169 }
Magnus Holmgren92d99df2007-11-14 17:48:18 +0000170 case "svenska" {
171 # for all swedish engines (e.g. for english words)
172 $string =~ s/kilobyte/kilobajt/ig;
173 $string =~ s/megabyte/megabajt/ig;
174 $string =~ s/gigabyte/gigabajt/ig;
175 $string =~ s/\bloudness\b/laudness/ig;
176
177 switch($$tts_object{"name"}) {
178 case "espeak" { # just for eSpeak
179 $string =~ s/ampere/ampär/ig;
180 $string =~ s/bokmärken/bok-märken/ig;
181 $string =~ s/generella/schenerella/ig;
182 $string =~ s/dithering/diddering/ig;
183 $string =~ s/\bunicode\b/jynikod/ig;
184 $string =~ s/uttoning/utoning/ig;
185 $string =~ s/procent/pro-cent/ig;
186 $string =~ s/spellistor/spelistor/ig;
187 $string =~ s/cuesheet/qjyschiit/ig;
188 }
189 }
190 }
Jonas Häggqvist17e03e72007-08-25 22:00:13 +0000191 }
192 if ($orig ne $string) {
193 printf("%s -> %s\n", $orig, $string) if $verbose;
194 }
195 return $string;
196}
197
198# Produce a wav file of the text given
199sub voicestring {
200 our $verbose;
Jens Arnold080522f2007-09-01 08:38:10 +0000201 my ($string, $output, $tts_engine_opts, $tts_object) = @_;
Jonas Häggqvist17e03e72007-08-25 22:00:13 +0000202 my $cmd;
Jens Arnold080522f2007-09-01 08:38:10 +0000203 printf("Generate \"%s\" with %s in file %s\n", $string, $$tts_object{"name"}, $output) if $verbose;
204 switch($$tts_object{"name"}) {
Jonas Häggqvist17e03e72007-08-25 22:00:13 +0000205 case "festival" {
206 # festival_client lies to us, so we have to do awful soul-eating
207 # work with IPC::open3()
208 $cmd = "festival_client --server localhost --otype riff --ttw --output \"$output\"";
209 print("> $cmd\n") if $verbose;
210 # Open command, and filehandles for STDIN, STDOUT, STDERR
211 my $pid = open3(*CMD_IN, *CMD_OUT, *CMD_ERR, $cmd);
212 # Put the string to speak into STDIN and close it
213 print(CMD_IN $string);
214 close(CMD_IN);
215 # Read all output from festival_client (because it LIES TO US)
216 while (<CMD_ERR>) {
217 }
218 close(CMD_OUT);
219 close(CMD_ERR);
220 }
221 case "flite" {
222 $cmd = "flite $tts_engine_opts -t \"$string\" \"$output\"";
223 print("> $cmd\n") if $verbose;
224 `$cmd`;
225 }
226 case "espeak" {
227 # xxx: $tts_engine_opts isn't used
Jonas Häggqvistd35d2d92007-11-16 21:33:24 +0000228 $cmd = "espeak $tts_engine_opts -w \"$output\"";
Jonas Häggqvist17e03e72007-08-25 22:00:13 +0000229 print("> $cmd\n") if $verbose;
230 open(ESPEAK, "| $cmd");
231 print ESPEAK $string . "\n";
232 close(ESPEAK);
233 }
Jens Arnold5dbea462007-09-02 22:32:34 +0000234 case "sapi" {
235 print({$$tts_object{"stdin"}} "SPEAK\t$output\t$string\r\n");
Jonas Häggqvist17e03e72007-08-25 22:00:13 +0000236 }
Jonas Häggqvist005699f2007-09-01 20:03:20 +0000237 case "swift" {
Jonas Häggqvist42951492007-11-16 19:59:09 +0000238 $cmd = "swift $tts_engine_opts -o \"$output\" \"$string\"";
Jonas Häggqvist005699f2007-09-01 20:03:20 +0000239 print("> $cmd\n") if $verbose;
240 system($cmd);
241 }
Jonas Häggqvist17e03e72007-08-25 22:00:13 +0000242 }
243}
244
Jens Arnold080522f2007-09-01 08:38:10 +0000245# trim leading / trailing silence from the clip
246sub wavtrim {
247 our $verbose;
248 my ($file, $threshold, $tts_object) = @_;
249 printf("Trim \"%s\"\n", $file) if $verbose;
Jens Arnold5dbea462007-09-02 22:32:34 +0000250 if ($$tts_object{"name"} eq "sapi") {
Jens Arnold080522f2007-09-01 08:38:10 +0000251 my $cmd = $$tts_object{"toolspath"}."wavtrim $file $threshold";
Jens Arnold5dbea462007-09-02 22:32:34 +0000252 print({$$tts_object{"stdin"}} "EXEC\t$cmd\r\n");
Jens Arnold080522f2007-09-01 08:38:10 +0000253 }
254 else {
Jonas Häggqvist42951492007-11-16 19:59:09 +0000255 my $cmd = dirname($0) . "/wavtrim \"$file\" $threshold";
Jens Arnold080522f2007-09-01 08:38:10 +0000256 print("> $cmd\n") if $verbose;
257 `$cmd`;
258 }
259}
260
Jonas Häggqvist17e03e72007-08-25 22:00:13 +0000261# Encode a wav file into the given destination file
262sub encodewav {
263 our $verbose;
Jens Arnold080522f2007-09-01 08:38:10 +0000264 my ($input, $output, $encoder, $encoder_opts, $tts_object) = @_;
Jens Arnoldd70857b2007-08-29 06:14:45 +0000265 my $cmd = '';
Jonas Häggqvist17e03e72007-08-25 22:00:13 +0000266 printf("Encode \"%s\" with %s in file %s\n", $input, $encoder, $output) if $verbose;
Thom Johansen75432612007-11-18 17:10:50 +0000267 $cmd = "$encoder $encoder_opts \"$input\" \"$output\"";
Jens Arnold5dbea462007-09-02 22:32:34 +0000268 if ($$tts_object{"name"} eq "sapi") {
269 print({$$tts_object{"stdin"}} "EXEC\t$cmd\r\n");
Jens Arnold080522f2007-09-01 08:38:10 +0000270 }
271 else {
272 print("> $cmd\n") if $verbose;
273 `$cmd`;
274 }
Jonas Häggqvist17e03e72007-08-25 22:00:13 +0000275}
276
Jens Arnold080522f2007-09-01 08:38:10 +0000277# synchronize the clip generation / processing if it's running in another process
278sub synchronize {
279 my ($tts_object) = @_;
Jens Arnold5dbea462007-09-02 22:32:34 +0000280 if ($$tts_object{"name"} eq "sapi") {
Jens Arnold080522f2007-09-01 08:38:10 +0000281 print({$$tts_object{"stdin"}} "SYNC\t42\r\n");
282 my $wait = readline($$tts_object{"stdout"});
283 #ignore what's actually returned
284 }
Jonas Häggqvist17e03e72007-08-25 22:00:13 +0000285}
286
287# Run genlang and create voice clips for each string
288sub generateclips {
289 our $verbose;
290 my ($language, $target, $encoder, $encoder_opts, $tts_engine, $tts_engine_opts) = @_;
291 my $genlang = dirname($0) . '/genlang';
292 my $english = dirname($0) . '/../apps/lang/english.lang';
293 my $langfile = dirname($0) . '/../apps/lang/' . $language . '.lang';
294 my $id = '';
295 my $voice = '';
296 my $cmd = "$genlang -o -t=$target -e=$english $langfile 2>/dev/null";
297 my $pool_file;
298 open(VOICEFONTIDS, "> voicefontids");
299 my $i = 0;
Jens Arnoldf2ed1e42007-09-02 00:50:08 +0000300 local $| = 1; # make progress indicator work reliably
Jonas Häggqvist17e03e72007-08-25 22:00:13 +0000301
302 my $tts_object = init_tts($tts_engine, $tts_engine_opts, $language);
303 print("Generating voice clips");
304 print("\n") if $verbose;
305 for (`$cmd`) {
306 my $line = $_;
307 print(VOICEFONTIDS $line);
308 if ($line =~ /^id: (.*)$/) {
309 $id = $1;
310 }
311 elsif ($line =~ /^voice: "(.*)"$/) {
312 $voice = $1;
313 if ($id !~ /^NOT_USED_.*$/ && $voice ne "") {
314 my $wav = $id . '.wav';
315 my $mp3 = $id . '.mp3';
316
317 # Print some progress information
318 if (++$i % 10 == 0 and !$verbose) {
319 print(".");
320 }
321
322 # Apply corrections to the string
Jens Arnolddf9a1662007-09-04 22:03:05 +0000323 $voice = correct_string($voice, $language, $tts_object);
Jonas Häggqvist17e03e72007-08-25 22:00:13 +0000324
Jens Arnolddf9a1662007-09-04 22:03:05 +0000325 # If we have a pool of snippets, see if the string exists there first
Jonas Häggqvist17e03e72007-08-25 22:00:13 +0000326 if (defined($ENV{'POOL'})) {
Jens Arnolddf9a1662007-09-04 22:03:05 +0000327 $pool_file = sprintf("%s/%s-%s.mp3", $ENV{'POOL'},
328 md5_hex("$voice $tts_engine $tts_engine_opts $encoder_opts"),
329 $language);
Jonas Häggqvist17e03e72007-08-25 22:00:13 +0000330 if (-f $pool_file) {
331 printf("Re-using %s (%s) from pool\n", $id, $voice) if $verbose;
332 copy($pool_file, $mp3);
333 }
334 }
335
336 # Don't generate MP3 if it already exists (probably from the POOL)
337 if (! -f $mp3) {
338 if ($id eq "VOICE_PAUSE") {
339 print("Use distributed $wav\n") if $verbose;
340 copy(dirname($0)."/VOICE_PAUSE.wav", $wav);
341 }
342 else {
Jens Arnold080522f2007-09-01 08:38:10 +0000343 voicestring($voice, $wav, $tts_engine_opts, $tts_object);
344 wavtrim($wav, 500, $tts_object);
345 # 500 seems to be a reasonable default for now
Jonas Häggqvist17e03e72007-08-25 22:00:13 +0000346 }
347
Jens Arnold080522f2007-09-01 08:38:10 +0000348 encodewav($wav, $mp3, $encoder, $encoder_opts, $tts_object);
349 synchronize($tts_object);
Jonas Häggqvist17e03e72007-08-25 22:00:13 +0000350 if (defined($ENV{'POOL'})) {
351 copy($mp3, $pool_file);
352 }
353 unlink($wav);
354 }
355 $voice = "";
356 $id = "";
357 }
358 }
359 }
360 print("\n");
361 close(VOICEFONTIDS);
Jens Arnold080522f2007-09-01 08:38:10 +0000362 shutdown_tts($tts_object);
Jonas Häggqvist17e03e72007-08-25 22:00:13 +0000363}
364
365# Assemble the voicefile
366sub createvoice {
367 our $verbose;
368 my ($language, $target_id) = @_;
369 my $voicefont = dirname($0) . '/voicefont';
370 my $outfile = "";
371 my $i = 0;
372 do {
373 $outfile = sprintf("%s%s.voice", $language, ($i++ == 0 ? '' : '-'.$i));
374 } while (-f $outfile);
375 printf("Saving voice file to %s\n", $outfile) if $verbose;
376 my $cmd = "$voicefont 'voicefontids' $target_id ./ $outfile";
377 print("> $cmd\n") if $verbose;
378 my $output = `$cmd`;
379 print($output) if $verbose;
380}
381
382sub deletemp3s() {
383 for (glob('*.mp3')) {
384 unlink($_);
385 }
386 for (glob('*.wav')) {
387 unlink($_);
388 }
389}
390
391sub panic_cleanup {
392 deletemp3s();
393 die "moo";
394}
395
Jonas Häggqvist42951492007-11-16 19:59:09 +0000396# Generate .talk clips
397sub gentalkclips {
398 our $verbose;
399 my ($dir, $tts_object, $encoder, $encoder_opts, $tts_engine_opts, $i) = @_;
400 my $d = new DirHandle $dir;
401 while (my $file = $d->read) {
402 my ($voice, $wav, $mp3);
Jonas Häggqvist42951492007-11-16 19:59:09 +0000403 # Print some progress information
404 if (++$i % 10 == 0 and !$verbose) {
405 print(".");
406 }
407
408 # Convert to a complete path
409 my $path = sprintf("%s/%s", $dir, $file);
Jonas Häggqvist1b2561b2007-11-16 20:02:02 +0000410
411 $voice = $file;
412 $wav = sprintf("%s.talk.wav", $path);
413
Jonas Häggqvist42951492007-11-16 19:59:09 +0000414 # Ignore dot-dirs and talk files
415 if ($file eq '.' || $file eq '..' || $file =~ /\.talk$/) {
416 next;
417 }
418 # Element is a dir
419 if ( -d $path) {
Jonas Häggqvist39429612007-11-16 23:42:18 +0000420 gentalkclips($path, $tts_object, $encoder, $encoder_opts, $tts_engine_opts, $i);
Jonas Häggqvist42951492007-11-16 19:59:09 +0000421 $mp3 = sprintf("%s/_dirname.talk", $path);
422 }
423 # Element is a file
424 else {
425 $mp3 = sprintf("%s.talk", $path);
426 $voice =~ s/\.[^\.]*$//; # Trim extension
427 }
428
429 printf("Talkclip %s: %s", $mp3, $voice) if $verbose;
430
431 voicestring($voice, $wav, $tts_engine_opts, $tts_object);
432 wavtrim($wav, 500, $tts_object);
433 # 500 seems to be a reasonable default for now
434 encodewav($wav, $mp3, $encoder, $encoder_opts, $tts_object);
435 unlink($wav);
436 }
437}
438
439
Jonas Häggqvist17e03e72007-08-25 22:00:13 +0000440# Check parameters
441my $printusage = 0;
442unless (defined($V) or defined($C)) { print("Missing either -V or -C\n"); $printusage = 1; }
443if (defined($V)) {
444 unless (defined($t)) { print("Missing -t argument\n"); $printusage = 1; }
445 unless (defined($l)) { print("Missing -l argument\n"); $printusage = 1; }
446 unless (defined($i)) { print("Missing -i argument\n"); $printusage = 1; }
447}
448elsif (defined($C)) {
449 unless (defined($ARGV[0])) { print "Missing path argument\n"; $printusage = 1; }
450}
451unless (defined($e)) { print("Missing -e argument\n"); $printusage = 1; }
452unless (defined($E)) { print("Missing -E argument\n"); $printusage = 1; }
453unless (defined($s)) { print("Missing -s argument\n"); $printusage = 1; }
454unless (defined($S)) { print("Missing -S argument\n"); $printusage = 1; }
455if ($printusage == 1) { printusage(); exit 1; }
456
Jonas Häggqvist17e03e72007-08-25 22:00:13 +0000457if (defined($v) or defined($ENV{'V'})) {
458 our $verbose = 1;
459}
460
461
462# Do what we're told
463if ($V == 1) {
Jonas Häggqvist42951492007-11-16 19:59:09 +0000464 # Only do the panic cleanup for voicefiles
465 $SIG{INT} = \&panic_cleanup;
466 $SIG{KILL} = \&panic_cleanup;
467
Jonas Häggqvist17e03e72007-08-25 22:00:13 +0000468 printf("Generating voice\n Target: %s\n Language: %s\n Encoder (options): %s (%s)\n TTS Engine (options): %s (%s)\n",
469 $t, $l, $e, $E, $s, $S);
470 generateclips($l, $t, $e, $E, $s, $S);
471 createvoice($l, $i);
472 deletemp3s();
473}
474elsif ($C) {
Jonas Häggqvist42951492007-11-16 19:59:09 +0000475 printf("Generating .talk clips\n Path: %s\n Language: %s\n Encoder (options): %s (%s)\n TTS Engine (options): %s (%s)\n", $ARGV[0], $l, $e, $E, $s, $S);
476 my $tts_object = init_tts($s, $S, $l);
Thom Johansen75432612007-11-18 17:10:50 +0000477 gentalkclips($ARGV[0], $tts_object, $e, $E, $S, 0);
Jonas Häggqvist42951492007-11-16 19:59:09 +0000478 shutdown_tts($tts_object);
Jonas Häggqvist17e03e72007-08-25 22:00:13 +0000479}
480else {
481 printusage();
482 exit 1;
483}