summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonas Häggqvist <rasher@rasher.dk>2007-08-25 22:00:13 +0000
committerJonas Häggqvist <rasher@rasher.dk>2007-08-25 22:00:13 +0000
commit17e03e75a43ff75b2cc20ba794b0f4d3131f4a36 (patch)
tree4f04d4d196216b29a7a7f06e33e4e0f159820417
parentb8ded7d674c510da7e69027fa64b62be794d0e2f (diff)
downloadrockbox-17e03e75a43ff75b2cc20ba794b0f4d3131f4a36.tar.gz
rockbox-17e03e75a43ff75b2cc20ba794b0f4d3131f4a36.zip
Replace the voicebuilding with a perl-based approach. Should greatly speed up building on Cygwin. See more in FS#7646.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@14457 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--docs/MAINTAINERS2
-rw-r--r--tools/VOICE_PAUSE.wavbin0 -> 26612 bytes
-rwxr-xr-xtools/configure58
-rwxr-xr-xtools/sapi5_voice_new.vbs67
-rwxr-xr-xtools/voice.pl360
5 files changed, 465 insertions, 22 deletions
diff --git a/docs/MAINTAINERS b/docs/MAINTAINERS
index 023e1aa6cc..fcf03f74bc 100644
--- a/docs/MAINTAINERS
+++ b/docs/MAINTAINERS
@@ -290,7 +290,7 @@ Build Tools
290:scramble: Linus Nielsen Feltzing 290:scramble: Linus Nielsen Feltzing
291:descramble: Linus Nielsen Feltzing 291:descramble: Linus Nielsen Feltzing
292:mkinfo: Daniel Stenberg 292:mkinfo: Daniel Stenberg
293:voice shell scripts: Jonas Häggqvist 293:voice perl script: Jonas Häggqvist
294 294
295Install Tools 295Install Tools
296------------- 296-------------
diff --git a/tools/VOICE_PAUSE.wav b/tools/VOICE_PAUSE.wav
new file mode 100644
index 0000000000..90d07f0ff6
--- /dev/null
+++ b/tools/VOICE_PAUSE.wav
Binary files differ
diff --git a/tools/configure b/tools/configure
index 03182cfde4..6be536e109 100755
--- a/tools/configure
+++ b/tools/configure
@@ -288,7 +288,8 @@ whichadvanced () {
288 288
289 # Ask about languages to build 289 # Ask about languages to build
290 echo "Select a number for the language to use (default is english)" 290 echo "Select a number for the language to use (default is english)"
291 echo "You may enter a comma-separated list of languages to build" 291 # The multiple-language feature is currently broken
292 # echo "You may enter a comma-separated list of languages to build"
292 293
293 picklang 294 picklang
294 voicelanguage=`whichlang` 295 voicelanguage=`whichlang`
@@ -329,7 +330,7 @@ voiceconfig () {
329 330
330 if [ -f "`which flite`" ]; then 331 if [ -f "`which flite`" ]; then
331 FLITE="F(l)ite " 332 FLITE="F(l)ite "
332 FLITE_OPTS="FLITE_OPTS=\"\"" 333 FLITE_OPTS=""
333 DEFAULT_TTS="flite" 334 DEFAULT_TTS="flite"
334 DEFAULT_TTS_OPTS=$FLITE_OPTS 335 DEFAULT_TTS_OPTS=$FLITE_OPTS
335 DEFAULT_NOISEFLOOR="500" 336 DEFAULT_NOISEFLOOR="500"
@@ -337,7 +338,7 @@ voiceconfig () {
337 fi 338 fi
338 if [ -f "`which espeak`" ]; then 339 if [ -f "`which espeak`" ]; then
339 ESPEAK="(e)Speak " 340 ESPEAK="(e)Speak "
340 ESPEAK_OPTS="ESPEAK_OPTS=\"\"" 341 ESPEAK_OPTS=""
341 DEFAULT_TTS="espeak" 342 DEFAULT_TTS="espeak"
342 DEFAULT_TTS_OPTS=$ESPEAK_OPTS 343 DEFAULT_TTS_OPTS=$ESPEAK_OPTS
343 DEFAULT_NOISEFLOOR="500" 344 DEFAULT_NOISEFLOOR="500"
@@ -345,7 +346,23 @@ voiceconfig () {
345 fi 346 fi
346 if [ -f "`which festival`" ]; then 347 if [ -f "`which festival`" ]; then
347 FESTIVAL="(F)estival " 348 FESTIVAL="(F)estival "
348 FESTIVAL_OPTS="FESTIVAL_OPTS=\"\"" 349 case "$thislang" in
350 "italiano")
351 FESTIVAL_OPTS="--language italian"
352 ;;
353 "espanol")
354 FESTIVAL_OPTS="--language spanish"
355 ;;
356 "finnish")
357 FESTIVAL_OPTS="--language finnish"
358 ;;
359 "czech")
360 FESTIVAL_OPTS="--language czech"
361 ;;
362 *)
363 FESTIVAL_OPTS=""
364 ;;
365 esac
349 DEFAULT_TTS="festival" 366 DEFAULT_TTS="festival"
350 DEFAULT_TTS_OPTS=$FESTIVAL_OPTS 367 DEFAULT_TTS_OPTS=$FESTIVAL_OPTS
351 DEFAULT_NOISEFLOOR="500" 368 DEFAULT_NOISEFLOOR="500"
@@ -354,7 +371,7 @@ voiceconfig () {
354 # Allow SAPI if Windows is in use 371 # Allow SAPI if Windows is in use
355 if [ -f "`which winver`" ]; then 372 if [ -f "`which winver`" ]; then
356 SAPI5="(S)API5 " 373 SAPI5="(S)API5 "
357 SAPI5_OPTS="SAPI5_OPTS=\"\"" 374 SAPI5_OPTS=""
358 DEFAULT_TTS="sapi5" 375 DEFAULT_TTS="sapi5"
359 DEFAULT_TTS_OPTS=$SAPI5_OPTS 376 DEFAULT_TTS_OPTS=$SAPI5_OPTS
360 DEFAULT_NOISEFLOOR="500" 377 DEFAULT_NOISEFLOOR="500"
@@ -397,10 +414,10 @@ voiceconfig () {
397 echo "Using $TTS_ENGINE for TTS" 414 echo "Using $TTS_ENGINE for TTS"
398 415
399 # Allow the user to input manual commandline options 416 # Allow the user to input manual commandline options
400 printf "Enter $TTS_ENGINE options (enter for defaults `echo $TTS_OPTS |sed 's/.*=//'`): " 417 printf "Enter $TTS_ENGINE options (enter for defaults \"$TTS_OPTS\"): "
401 USER_TTS_OPTS=`input` 418 USER_TTS_OPTS=`input`
402 if [ -n "$USER_TTS_OPTS" ]; then 419 if [ -n "$USER_TTS_OPTS" ]; then
403 TTS_OPTS="`echo $TTS_OPTS | sed 's/=.*//'`=\"$USER_TTS_OPTS\"" 420 TTS_OPTS="$USER_TTS_OPTS"
404 fi 421 fi
405 422
406 echo "" 423 echo ""
@@ -408,7 +425,7 @@ voiceconfig () {
408 if [ -f "`which oggenc`" ]; then 425 if [ -f "`which oggenc`" ]; then
409 OGGENC="(O)ggenc " 426 OGGENC="(O)ggenc "
410 DEFAULT_ENC="oggenc" 427 DEFAULT_ENC="oggenc"
411 VORBIS_OPTS="VORBIS_OPTS=\"-q0 --downmix\"" 428 VORBIS_OPTS="-q0 --downmix"
412 DEFAULT_ENC_OPTS=$VORBIS_OPTS 429 DEFAULT_ENC_OPTS=$VORBIS_OPTS
413 DEFAULT_CHOICE="O" 430 DEFAULT_CHOICE="O"
414 fi 431 fi
@@ -422,7 +439,7 @@ voiceconfig () {
422 if [ -f "`which lame`" ]; then 439 if [ -f "`which lame`" ]; then
423 LAME="(L)ame " 440 LAME="(L)ame "
424 DEFAULT_ENC="lame" 441 DEFAULT_ENC="lame"
425 LAME_OPTS="LAME_OPTS=\"--resample 12 -t -m m -h -V 9 -S\"" 442 LAME_OPTS="--resample 12 -t -m m -h -V 9 -S -B 64 --vbr-new"
426 DEFAULT_ENC_OPTS=$LAME_OPTS 443 DEFAULT_ENC_OPTS=$LAME_OPTS
427 DEFAULT_CHOICE="L" 444 DEFAULT_CHOICE="L"
428 fi 445 fi
@@ -456,25 +473,16 @@ voiceconfig () {
456 echo "Using $ENCODER for encoding voice clips" 473 echo "Using $ENCODER for encoding voice clips"
457 474
458 # Allow the user to input manual commandline options 475 # Allow the user to input manual commandline options
459 printf "Enter $ENCODER options (enter for defaults `echo $ENC_OPTS |sed 's/.*=//'`): " 476 printf "Enter $ENCODER options (enter for defaults \"$ENC_OPTS\"): "
460 USER_ENC_OPTS=`input` 477 USER_ENC_OPTS=`input`
461 if [ -n "$USER_ENC_OPTS" ]; then 478 if [ -n "$USER_ENC_OPTS" ]; then
462 ENC_OPTS="`echo $ENC_OPTS | sed 's/=.*//'`=\"$USER_ENC_OPTS\"" 479 ENC_OPTS=$USER_ENC_OPTS
463 fi 480 fi
464 481
465 TEMPDIR="${pwd}" 482 TEMPDIR="${pwd}"
466 if [ -f "`which cygpath`" ]; then 483 if [ -f "`which cygpath`" ]; then
467 TEMPDIR=`cygpath . -a -w` 484 TEMPDIR=`cygpath . -a -w`
468 fi 485 fi
469
470 cat > voicesettings-$thislang.sh <<EOF
471TTS_ENGINE="${TTS_ENGINE}"
472ENCODER="${ENCODER}"
473TEMPDIR="$TEMPDIR"
474NOISEFLOOR="${NOISEFLOOR}"
475${TTS_OPTS}
476${ENC_OPTS}
477EOF
478} 486}
479 487
480picklang() { 488picklang() {
@@ -1664,6 +1672,10 @@ sed > Makefile \
1664 -e "${simmagic1}" \ 1672 -e "${simmagic1}" \
1665 -e "${simmagic2}" \ 1673 -e "${simmagic2}" \
1666 -e "s,@MANUALDEV@,${manualdev},g" \ 1674 -e "s,@MANUALDEV@,${manualdev},g" \
1675 -e "s,@ENCODER@,${ENCODER},g" \
1676 -e "s,@ENC_OPTS@,${ENC_OPTS},g" \
1677 -e "s,@TTS_ENGINE@,${TTS_ENGINE},g" \
1678 -e "s,@TTS_OPTS@,${TTS_OPTS},g" \
1667<<EOF 1679<<EOF
1668## Automaticly generated. http://www.rockbox.org/ 1680## Automaticly generated. http://www.rockbox.org/
1669 1681
@@ -1732,6 +1744,10 @@ export GCCVER=@GCCVER@
1732export GCCNUM=@GCCNUM@ 1744export GCCNUM=@GCCNUM@
1733export UNAME=@UNAME@ 1745export UNAME=@UNAME@
1734export MANUALDEV=@MANUALDEV@ 1746export MANUALDEV=@MANUALDEV@
1747export TTS_OPTS=@TTS_OPTS@
1748export TTS_ENGINE=@TTS_ENGINE@
1749export ENC_OPTS=@ENC_OPTS@
1750export ENCODER=@ENCODER@
1735 1751
1736# Do not print "Entering directory ..." 1752# Do not print "Entering directory ..."
1737MAKEFLAGS += --no-print-directory 1753MAKEFLAGS += --no-print-directory
@@ -1866,7 +1882,7 @@ if [ "yes" = "$voice" ]; then
1866 1882
1867voice: tools features 1883voice: tools features
1868 \$(SILENT)for f in \`cat \$(BUILDDIR)/${apps}/features\`; do feat="\$\$feat:\$\$f" ; done ; \\ 1884 \$(SILENT)for f in \`cat \$(BUILDDIR)/${apps}/features\`; do feat="\$\$feat:\$\$f" ; done ; \\
1869 for lang in \`echo \$(VOICELANGUAGE) |sed "s/,/ /g"\`; do \$(TOOLSDIR)/genvoice.sh \$(ROOTDIR) \$\$lang \$(ARCHOS)\$\$feat \$(TARGET_ID) voicesettings-\$\$lang.sh ; done \\ 1885 for lang in \`echo \$(VOICELANGUAGE) |sed "s/,/ /g"\`; do \$(TOOLSDIR)/voice.pl -V -l=\$\$lang -t=\$(ARCHOS)\$\$feat -i=\$(TARGET_ID) -e=\$(ENCODER) -E="\$(ENC_OPTS)" -s=\$(TTS_ENGINE) -S="\$(TTS_OPTS)"; done \\
1870EOF 1886EOF
1871 1887
1872fi 1888fi
diff --git a/tools/sapi5_voice_new.vbs b/tools/sapi5_voice_new.vbs
new file mode 100755
index 0000000000..96c6e2a720
--- /dev/null
+++ b/tools/sapi5_voice_new.vbs
@@ -0,0 +1,67 @@
1'***************************************************************************
2' __________ __ ___.
3' Open \______ \ ____ ____ | | _\_ |__ _______ ___
4' Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5' Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6' Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7' \/ \/ \/ \/ \/
8' $Id: sapi5_voice.vbs$
9'
10' Copyright (C) 2007 Steve Bavin, Jens Arnold, Mesar Hameed
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'
18'***************************************************************************
19' Purpose: Make a voice clip file for the given text on stdin
20
21'To be done:
22' - Allow user to override voice, speed and/or format (currently uses Control Panel defaults for voice/speed)
23' - Voice specific replacements/corrections for pronounciation (this should be at a higher level really)
24
25Const SSFMCreateForWrite = 3
26
27Const SPSF_8kHz16BitMono = 6
28Const SPSF_11kHz16BitMono = 10
29Const SPSF_12kHz16BitMono = 14
30Const SPSF_16kHz16BitMono = 18
31Const SPSF_22kHz16BitMono = 22
32Const SPSF_24kHz16BitMono = 26
33Const SPSF_32kHz16BitMono = 30
34Const SPSF_44kHz16BitMono = 34
35Const SPSF_48kHz16BitMono = 38
36
37Dim oSpVoice, oSpFS, nAudioFormat, sText, sOutputFile
38
39nAudioFormat = SPSF_22kHz16BitMono 'Audio format to use, recommended settings:
40'- for AT&T natural voices, use SPSF_32kHz16BitMono
41'- for MS voices, use SPSF_22kHz16BitMono
42
43Set oSpVoice = CreateObject("SAPI.SpVoice")
44If Err.Number <> 0 Then
45 WScript.Echo "Error - could not get SpVoice object. " & _
46 "SAPI 5 not installed?"
47 Err.Clear
48 WScript.Quit 1
49End If
50
51While 1 > 0
52 sText = WScript.StdIn.ReadLine
53 sOutputFile = WScript.StdIn.ReadLine
54 If sOutputFile = "" Then
55 Set oSpFS = Nothing
56 Set oSpVoice = Nothing
57 Set oArgs = Nothing
58 WScript.Quit 0
59 End If
60 ' WScript.Echo "Saying " + sText + " in " + sOutputFile
61 Set oSpFS = CreateObject("SAPI.SpFileStream")
62 oSpFS.Format.Type = nAudioFormat
63 oSpFS.Open sOutputFile, SSFMCreateForWrite, False
64 Set oSpVoice.AudioOutputStream = oSpFS
65 oSpVoice.Speak sText
66 oSpFS.Close
67Wend
diff --git a/tools/voice.pl b/tools/voice.pl
new file mode 100755
index 0000000000..1635b701f1
--- /dev/null
+++ b/tools/voice.pl
@@ -0,0 +1,360 @@
1#!/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);
24use IPC::Open3;
25use Digest::MD5 qw(md5_hex);
26
27sub printusage {
28 print <<USAGE
29
30Usage: voice.pl [options] [path to dir]
31 -V
32 Create voice file. You must also specify -t and -l.
33
34 -C
35 Create .talk clips.
36
37 -t=<target>
38 Specify which target you want to build voicefile for. Must include
39 any features that target supports.
40
41 -i=<target_id>
42 Numeric target id. Needed for voice building.
43
44 -l=<language>
45 Specify which language you want to build. Without .lang extension.
46
47 -e=<encoder>
48 Which encoder to use for voice strings
49
50 -E=<encoder options>
51 Which encoder options to use when compressing voice strings. Enclose
52 in double quotes if the options include spaces.
53
54 -s=<TTS engine>
55 Which TTS engine to use.
56
57 -S=<TTS engine options>
58 Options to pass to the TTS engine. Enclose in double quotes if the
59 options include spaces.
60
61 -v
62 Be verbose
63USAGE
64;
65}
66
67# Initialize TTS engine. May return an object or value which will be passed
68# to voicestring and shutdown_tts
69sub init_tts {
70 our $verbose;
71 my ($tts_engine, $tts_engine_opts, $language) = @_;
72 my $ret = undef;
73 switch($tts_engine) {
74 case "festival" {
75 print("> festival $tts_engine_opts --server\n") if $verbose;
76 my $pid = open(FESTIVAL_SERVER, "| festival $tts_engine_opts --server > /dev/null 2>&1");
77 $ret = *FESTIVAL_SERVER;
78 $ret = $pid;
79 $SIG{INT} = sub { kill TERM => $pid; print("foo"); panic_cleanup(); };
80 $SIG{KILL} = sub { kill TERM => $pid; print("boo"); panic_cleanup(); };
81 }
82 case "sapi5" {
83 my $toolsdir = dirname($0);
84 my $path = `cygpath $toolsdir -a -w`;
85 chomp($path);
86 $path = $path . "\\sapi5_voice_new.vbs $language $tts_engine_opts";
87 $path =~ s/\\/\\\\/g;
88 print("> cscript /B $path\n") if $verbose;
89 my $pid = open(F, "| cscript /B $path");
90 $ret = *F;
91 $SIG{INT} = sub { print($ret "\r\n\r\n"); panic_cleanup(); };
92 $SIG{KILL} = sub { print($ret "\r\n\r\n"); panic_cleanup(); };
93 }
94 }
95 return $ret;
96}
97
98# Shutdown TTS engine if necessary.
99sub shutdown_tts {
100 my ($tts_engine, $tts_object) = @_;
101 switch($tts_engine) {
102 case "festival" {
103 # Send SIGTERM to festival server
104 kill TERM => $tts_object;
105 }
106 case "sapi5" {
107 print($tts_object "\r\n\r\n");
108 close($tts_object);
109 }
110 }
111}
112
113# Apply corrections to a voice-string to make it sound better
114sub correct_string {
115 our $verbose;
116 my ($string, $language, $tts_engine) = @_;
117 my $orig = $string;
118 switch($language) {
119 # General for all engines and languages (perhaps - just an example)
120 $string =~ s/USB/U S B/;
121
122 case ("deutsch") {
123 switch($tts_engine) {
124 $string =~ s/alphabet/alfabet/;
125 $string =~ s/alkaline/alkalein/;
126 $string =~ s/ampere/amper/;
127 $string =~ s/byte(s?)\b/beit$1/;
128 $string =~ s/\bdezibel\b/de-zibell/;
129 $string =~ s/energie\b/ener-gie/;
130 $string =~ s/\bflash\b/fläsh/g;
131 $string =~ s/\bfirmware(s?)\b/firmwer$1/;
132 $string =~ s/\bid3 tag\b/id3 täg/g; # can't just use "tag" here
133 $string =~ s/\bloudness\b/laudness/;
134 $string =~ s/\bnumerisch\b/numehrisch/;
135 $string =~ s/\brücklauf\b/rück-lauf/;
136 $string =~ s/\bsuchlauf\b/such-lauf/;
137 }
138 }
139 }
140 if ($orig ne $string) {
141 printf("%s -> %s\n", $orig, $string) if $verbose;
142 }
143 return $string;
144}
145
146# Produce a wav file of the text given
147sub voicestring {
148 our $verbose;
149 my ($string, $output, $tts_engine, $tts_engine_opts, $tts_object) = @_;
150 my $cmd;
151 printf("Generate \"%s\" with %s in file %s\n", $string, $tts_engine, $output) if $verbose;
152 switch($tts_engine) {
153 case "festival" {
154 # festival_client lies to us, so we have to do awful soul-eating
155 # work with IPC::open3()
156 $cmd = "festival_client --server localhost --otype riff --ttw --output \"$output\"";
157 print("> $cmd\n") if $verbose;
158 # Open command, and filehandles for STDIN, STDOUT, STDERR
159 my $pid = open3(*CMD_IN, *CMD_OUT, *CMD_ERR, $cmd);
160 # Put the string to speak into STDIN and close it
161 print(CMD_IN $string);
162 close(CMD_IN);
163 # Read all output from festival_client (because it LIES TO US)
164 while (<CMD_ERR>) {
165 }
166 close(CMD_OUT);
167 close(CMD_ERR);
168 }
169 case "flite" {
170 $cmd = "flite $tts_engine_opts -t \"$string\" \"$output\"";
171 print("> $cmd\n") if $verbose;
172 `$cmd`;
173 }
174 case "espeak" {
175 # xxx: $tts_engine_opts isn't used
176 $cmd = "espeak $tts_engine_opts -w $output";
177 print("> $cmd\n") if $verbose;
178 open(ESPEAK, "| $cmd");
179 print ESPEAK $string . "\n";
180 close(ESPEAK);
181 }
182 case "sapi5" {
183 print($tts_object sprintf("%s\r\n%s\r\n", $string, $output));
184 }
185 }
186}
187
188# Encode a wav file into the given destination file
189sub encodewav {
190 our $verbose;
191 my ($input, $output, $encoder, $encoder_opts) = @_;
192 printf("Encode \"%s\" with %s in file %s\n", $input, $encoder, $output) if $verbose;
193 switch ($encoder) {
194 case 'lame' {
195 my $cmd = "lame $encoder_opts \"$input\" \"$output\"";
196 print("> $cmd\n") if $verbose;
197 `lame $encoder_opts "$input" "$output"`;
198 `$cmd`;
199 }
200 case 'vorbis' {
201 `oggenc $encoder_opts "$input" -o "$output"`;
202 }
203 case 'speexenc' {
204 `speexenc $encoder_opts "$input" "$output"`;
205 }
206 }
207}
208
209sub wavtrim {
210 our $verbose;
211 my ($file) = @_;
212 my $cmd = dirname($0) . "/wavtrim \"$file\"";
213 print("> $cmd\n") if $verbose;
214 `$cmd`;
215}
216
217# Run genlang and create voice clips for each string
218sub generateclips {
219 our $verbose;
220 my ($language, $target, $encoder, $encoder_opts, $tts_engine, $tts_engine_opts) = @_;
221 my $genlang = dirname($0) . '/genlang';
222 my $english = dirname($0) . '/../apps/lang/english.lang';
223 my $langfile = dirname($0) . '/../apps/lang/' . $language . '.lang';
224 my $id = '';
225 my $voice = '';
226 my $cmd = "$genlang -o -t=$target -e=$english $langfile 2>/dev/null";
227 my $pool_file;
228 open(VOICEFONTIDS, "> voicefontids");
229 my $i = 0;
230
231 my $tts_object = init_tts($tts_engine, $tts_engine_opts, $language);
232 print("Generating voice clips");
233 print("\n") if $verbose;
234 for (`$cmd`) {
235 my $line = $_;
236 print(VOICEFONTIDS $line);
237 if ($line =~ /^id: (.*)$/) {
238 $id = $1;
239 }
240 elsif ($line =~ /^voice: "(.*)"$/) {
241 $voice = $1;
242 if ($id !~ /^NOT_USED_.*$/ && $voice ne "") {
243 my $wav = $id . '.wav';
244 my $mp3 = $id . '.mp3';
245
246 # Print some progress information
247 if (++$i % 10 == 0 and !$verbose) {
248 print(".");
249 }
250
251 # Apply corrections to the string
252 $voice = correct_string($voice);
253
254 # If we have a pool of snippes, see if the string exists there first
255 if (defined($ENV{'POOL'})) {
256 $pool_file = sprintf("%s/%s-%s-%s.mp3", $ENV{'POOL'}, md5_hex($voice), $language, $tts_engine);
257 if (-f $pool_file) {
258 printf("Re-using %s (%s) from pool\n", $id, $voice) if $verbose;
259 copy($pool_file, $mp3);
260 }
261 }
262
263 # Don't generate MP3 if it already exists (probably from the POOL)
264 if (! -f $mp3) {
265 if ($id eq "VOICE_PAUSE") {
266 print("Use distributed $wav\n") if $verbose;
267 copy(dirname($0)."/VOICE_PAUSE.wav", $wav);
268 }
269 else {
270 voicestring($voice, $wav, $tts_engine, $tts_engine_opts, $tts_object);
271 wavtrim($wav, 500); # 500 seems to be a reasonable default for now
272 }
273
274 encodewav($wav, $mp3, $encoder, $encoder_opts);
275 if (defined($ENV{'POOL'})) {
276 copy($mp3, $pool_file);
277 }
278 unlink($wav);
279 }
280 $voice = "";
281 $id = "";
282 }
283 }
284 }
285 print("\n");
286 close(VOICEFONTIDS);
287 shutdown_tts($tts_engine, $tts_object);
288}
289
290# Assemble the voicefile
291sub createvoice {
292 our $verbose;
293 my ($language, $target_id) = @_;
294 my $voicefont = dirname($0) . '/voicefont';
295 my $outfile = "";
296 my $i = 0;
297 do {
298 $outfile = sprintf("%s%s.voice", $language, ($i++ == 0 ? '' : '-'.$i));
299 } while (-f $outfile);
300 printf("Saving voice file to %s\n", $outfile) if $verbose;
301 my $cmd = "$voicefont 'voicefontids' $target_id ./ $outfile";
302 print("> $cmd\n") if $verbose;
303 my $output = `$cmd`;
304 print($output) if $verbose;
305}
306
307sub deletemp3s() {
308 for (glob('*.mp3')) {
309 unlink($_);
310 }
311 for (glob('*.wav')) {
312 unlink($_);
313 }
314}
315
316sub panic_cleanup {
317 deletemp3s();
318 die "moo";
319}
320
321# Check parameters
322my $printusage = 0;
323unless (defined($V) or defined($C)) { print("Missing either -V or -C\n"); $printusage = 1; }
324if (defined($V)) {
325 unless (defined($t)) { print("Missing -t argument\n"); $printusage = 1; }
326 unless (defined($l)) { print("Missing -l argument\n"); $printusage = 1; }
327 unless (defined($i)) { print("Missing -i argument\n"); $printusage = 1; }
328}
329elsif (defined($C)) {
330 unless (defined($ARGV[0])) { print "Missing path argument\n"; $printusage = 1; }
331}
332unless (defined($e)) { print("Missing -e argument\n"); $printusage = 1; }
333unless (defined($E)) { print("Missing -E argument\n"); $printusage = 1; }
334unless (defined($s)) { print("Missing -s argument\n"); $printusage = 1; }
335unless (defined($S)) { print("Missing -S argument\n"); $printusage = 1; }
336if ($printusage == 1) { printusage(); exit 1; }
337
338$SIG{INT} = \&panic_cleanup;
339$SIG{KILL} = \&panic_cleanup;
340
341if (defined($v) or defined($ENV{'V'})) {
342 our $verbose = 1;
343}
344
345
346# Do what we're told
347if ($V == 1) {
348 printf("Generating voice\n Target: %s\n Language: %s\n Encoder (options): %s (%s)\n TTS Engine (options): %s (%s)\n",
349 $t, $l, $e, $E, $s, $S);
350 generateclips($l, $t, $e, $E, $s, $S);
351 createvoice($l, $i);
352 deletemp3s();
353}
354elsif ($C) {
355 # xxx: Implement .talk clip generation
356}
357else {
358 printusage();
359 exit 1;
360}