Jonas Häggqvist | 17e03e7 | 2007-08-25 22:00:13 +0000 | [diff] [blame] | 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 | |
| 18 | use strict; |
| 19 | use warnings; |
| 20 | use File::Basename; |
| 21 | use File::Copy; |
| 22 | use Switch; |
| 23 | use vars qw($V $C $t $l $e $E $s $S $i $v); |
Jens Arnold | 080522f | 2007-09-01 08:38:10 +0000 | [diff] [blame] | 24 | use IPC::Open2; |
Jonas Häggqvist | 17e03e7 | 2007-08-25 22:00:13 +0000 | [diff] [blame] | 25 | use IPC::Open3; |
| 26 | use Digest::MD5 qw(md5_hex); |
Jonas Häggqvist | 4295149 | 2007-11-16 19:59:09 +0000 | [diff] [blame] | 27 | use DirHandle; |
Jonas Häggqvist | 17e03e7 | 2007-08-25 22:00:13 +0000 | [diff] [blame] | 28 | |
| 29 | sub printusage { |
| 30 | print <<USAGE |
| 31 | |
| 32 | Usage: 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 |
| 65 | USAGE |
| 66 | ; |
| 67 | } |
| 68 | |
| 69 | # Initialize TTS engine. May return an object or value which will be passed |
| 70 | # to voicestring and shutdown_tts |
| 71 | sub init_tts { |
| 72 | our $verbose; |
| 73 | my ($tts_engine, $tts_engine_opts, $language) = @_; |
Jens Arnold | 080522f | 2007-09-01 08:38:10 +0000 | [diff] [blame] | 74 | my %ret = ("name" => $tts_engine); |
Jonas Häggqvist | 17e03e7 | 2007-08-25 22:00:13 +0000 | [diff] [blame] | 75 | 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 Arnold | 080522f | 2007-09-01 08:38:10 +0000 | [diff] [blame] | 79 | my $dummy = *FESTIVAL_SERVER; #suppress warning |
Jonas Häggqvist | 17e03e7 | 2007-08-25 22:00:13 +0000 | [diff] [blame] | 80 | $SIG{INT} = sub { kill TERM => $pid; print("foo"); panic_cleanup(); }; |
| 81 | $SIG{KILL} = sub { kill TERM => $pid; print("boo"); panic_cleanup(); }; |
Jens Arnold | 080522f | 2007-09-01 08:38:10 +0000 | [diff] [blame] | 82 | $ret{"pid"} = $pid; |
Jonas Häggqvist | 17e03e7 | 2007-08-25 22:00:13 +0000 | [diff] [blame] | 83 | } |
Jens Arnold | 5dbea46 | 2007-09-02 22:32:34 +0000 | [diff] [blame] | 84 | case "sapi" { |
Jonas Häggqvist | 17e03e7 | 2007-08-25 22:00:13 +0000 | [diff] [blame] | 85 | my $toolsdir = dirname($0); |
| 86 | my $path = `cygpath $toolsdir -a -w`; |
| 87 | chomp($path); |
Jens Arnold | 080522f | 2007-09-01 08:38:10 +0000 | [diff] [blame] | 88 | $path = $path . '\\'; |
Jens Arnold | 5dbea46 | 2007-09-02 22:32:34 +0000 | [diff] [blame] | 89 | my $cmd = $path . "sapi_voice.vbs /language:$language $tts_engine_opts"; |
Jens Arnold | 080522f | 2007-09-01 08:38:10 +0000 | [diff] [blame] | 90 | $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 Arnold | df9a166 | 2007-09-04 22:03:05 +0000 | [diff] [blame] | 95 | print(CMD_IN "QUERY\tVENDOR\r\n"); |
| 96 | my $vendor = readline(CMD_OUT); |
| 97 | $vendor =~ s/\r\n//; |
Jens Arnold | 2829aef | 2007-09-04 22:13:52 +0000 | [diff] [blame] | 98 | %ret = (%ret, |
Jens Arnold | df9a166 | 2007-09-04 22:03:05 +0000 | [diff] [blame] | 99 | "stdin" => *CMD_IN, |
| 100 | "stdout" => *CMD_OUT, |
| 101 | "toolspath" => $path, |
| 102 | "vendor" => $vendor); |
Jonas Häggqvist | 17e03e7 | 2007-08-25 22:00:13 +0000 | [diff] [blame] | 103 | } |
| 104 | } |
Jens Arnold | 080522f | 2007-09-01 08:38:10 +0000 | [diff] [blame] | 105 | return \%ret; |
Jonas Häggqvist | 17e03e7 | 2007-08-25 22:00:13 +0000 | [diff] [blame] | 106 | } |
| 107 | |
| 108 | # Shutdown TTS engine if necessary. |
| 109 | sub shutdown_tts { |
Jens Arnold | 080522f | 2007-09-01 08:38:10 +0000 | [diff] [blame] | 110 | my ($tts_object) = @_; |
| 111 | switch($$tts_object{"name"}) { |
Jonas Häggqvist | 17e03e7 | 2007-08-25 22:00:13 +0000 | [diff] [blame] | 112 | case "festival" { |
| 113 | # Send SIGTERM to festival server |
Jens Arnold | 080522f | 2007-09-01 08:38:10 +0000 | [diff] [blame] | 114 | kill TERM => $$tts_object{"pid"}; |
Jonas Häggqvist | 17e03e7 | 2007-08-25 22:00:13 +0000 | [diff] [blame] | 115 | } |
Jens Arnold | 5dbea46 | 2007-09-02 22:32:34 +0000 | [diff] [blame] | 116 | case "sapi" { |
Jens Arnold | 080522f | 2007-09-01 08:38:10 +0000 | [diff] [blame] | 117 | print({$$tts_object{"stdin"}} "QUIT\r\n"); |
| 118 | close($$tts_object{"stdin"}); |
Jonas Häggqvist | 17e03e7 | 2007-08-25 22:00:13 +0000 | [diff] [blame] | 119 | } |
| 120 | } |
| 121 | } |
| 122 | |
| 123 | # Apply corrections to a voice-string to make it sound better |
| 124 | sub correct_string { |
| 125 | our $verbose; |
Jens Arnold | 080522f | 2007-09-01 08:38:10 +0000 | [diff] [blame] | 126 | my ($string, $language, $tts_object) = @_; |
Jonas Häggqvist | 17e03e7 | 2007-08-25 22:00:13 +0000 | [diff] [blame] | 127 | my $orig = $string; |
| 128 | switch($language) { |
Jens Arnold | df9a166 | 2007-09-04 22:03:05 +0000 | [diff] [blame] | 129 | # General for all engines and languages |
Jens Arnold | 2829aef | 2007-09-04 22:13:52 +0000 | [diff] [blame] | 130 | $string =~ s/USB/U S B/g; |
| 131 | $string =~ s/ID3/I D 3/g; |
Jonas Häggqvist | 17e03e7 | 2007-08-25 22:00:13 +0000 | [diff] [blame] | 132 | |
Jens Arnold | df9a166 | 2007-09-04 22:03:05 +0000 | [diff] [blame] | 133 | case "english" { |
Jonas Häggqvist | 29f07cd | 2007-10-02 16:34:06 +0000 | [diff] [blame] | 134 | switch($$tts_object{"name"}) { |
Jonas Häggqvist | 2af3755 | 2007-10-02 17:32:30 +0000 | [diff] [blame] | 135 | case ["sapi","festival"] { |
Jonas Häggqvist | 29f07cd | 2007-10-02 16:34:06 +0000 | [diff] [blame] | 136 | $string =~ s/plugin(s?)/plug-in$1/ig; |
| 137 | } |
| 138 | } |
Jens Arnold | df9a166 | 2007-09-04 22:03:05 +0000 | [diff] [blame] | 139 | } |
| 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äggqvist | 17e03e7 | 2007-08-25 22:00:13 +0000 | [diff] [blame] | 168 | } |
| 169 | } |
Magnus Holmgren | 92d99df | 2007-11-14 17:48:18 +0000 | [diff] [blame] | 170 | 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äggqvist | 17e03e7 | 2007-08-25 22:00:13 +0000 | [diff] [blame] | 191 | } |
| 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 |
| 199 | sub voicestring { |
| 200 | our $verbose; |
Jens Arnold | 080522f | 2007-09-01 08:38:10 +0000 | [diff] [blame] | 201 | my ($string, $output, $tts_engine_opts, $tts_object) = @_; |
Jonas Häggqvist | 17e03e7 | 2007-08-25 22:00:13 +0000 | [diff] [blame] | 202 | my $cmd; |
Jens Arnold | 080522f | 2007-09-01 08:38:10 +0000 | [diff] [blame] | 203 | printf("Generate \"%s\" with %s in file %s\n", $string, $$tts_object{"name"}, $output) if $verbose; |
| 204 | switch($$tts_object{"name"}) { |
Jonas Häggqvist | 17e03e7 | 2007-08-25 22:00:13 +0000 | [diff] [blame] | 205 | 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äggqvist | d35d2d9 | 2007-11-16 21:33:24 +0000 | [diff] [blame] | 228 | $cmd = "espeak $tts_engine_opts -w \"$output\""; |
Jonas Häggqvist | 17e03e7 | 2007-08-25 22:00:13 +0000 | [diff] [blame] | 229 | print("> $cmd\n") if $verbose; |
| 230 | open(ESPEAK, "| $cmd"); |
| 231 | print ESPEAK $string . "\n"; |
| 232 | close(ESPEAK); |
| 233 | } |
Jens Arnold | 5dbea46 | 2007-09-02 22:32:34 +0000 | [diff] [blame] | 234 | case "sapi" { |
| 235 | print({$$tts_object{"stdin"}} "SPEAK\t$output\t$string\r\n"); |
Jonas Häggqvist | 17e03e7 | 2007-08-25 22:00:13 +0000 | [diff] [blame] | 236 | } |
Jonas Häggqvist | 005699f | 2007-09-01 20:03:20 +0000 | [diff] [blame] | 237 | case "swift" { |
Jonas Häggqvist | 4295149 | 2007-11-16 19:59:09 +0000 | [diff] [blame] | 238 | $cmd = "swift $tts_engine_opts -o \"$output\" \"$string\""; |
Jonas Häggqvist | 005699f | 2007-09-01 20:03:20 +0000 | [diff] [blame] | 239 | print("> $cmd\n") if $verbose; |
| 240 | system($cmd); |
| 241 | } |
Jonas Häggqvist | 17e03e7 | 2007-08-25 22:00:13 +0000 | [diff] [blame] | 242 | } |
| 243 | } |
| 244 | |
Jens Arnold | 080522f | 2007-09-01 08:38:10 +0000 | [diff] [blame] | 245 | # trim leading / trailing silence from the clip |
| 246 | sub wavtrim { |
| 247 | our $verbose; |
| 248 | my ($file, $threshold, $tts_object) = @_; |
| 249 | printf("Trim \"%s\"\n", $file) if $verbose; |
Jens Arnold | 5dbea46 | 2007-09-02 22:32:34 +0000 | [diff] [blame] | 250 | if ($$tts_object{"name"} eq "sapi") { |
Jens Arnold | 080522f | 2007-09-01 08:38:10 +0000 | [diff] [blame] | 251 | my $cmd = $$tts_object{"toolspath"}."wavtrim $file $threshold"; |
Jens Arnold | 5dbea46 | 2007-09-02 22:32:34 +0000 | [diff] [blame] | 252 | print({$$tts_object{"stdin"}} "EXEC\t$cmd\r\n"); |
Jens Arnold | 080522f | 2007-09-01 08:38:10 +0000 | [diff] [blame] | 253 | } |
| 254 | else { |
Jonas Häggqvist | 4295149 | 2007-11-16 19:59:09 +0000 | [diff] [blame] | 255 | my $cmd = dirname($0) . "/wavtrim \"$file\" $threshold"; |
Jens Arnold | 080522f | 2007-09-01 08:38:10 +0000 | [diff] [blame] | 256 | print("> $cmd\n") if $verbose; |
| 257 | `$cmd`; |
| 258 | } |
| 259 | } |
| 260 | |
Jonas Häggqvist | 17e03e7 | 2007-08-25 22:00:13 +0000 | [diff] [blame] | 261 | # Encode a wav file into the given destination file |
| 262 | sub encodewav { |
| 263 | our $verbose; |
Jens Arnold | 080522f | 2007-09-01 08:38:10 +0000 | [diff] [blame] | 264 | my ($input, $output, $encoder, $encoder_opts, $tts_object) = @_; |
Jens Arnold | d70857b | 2007-08-29 06:14:45 +0000 | [diff] [blame] | 265 | my $cmd = ''; |
Jonas Häggqvist | 17e03e7 | 2007-08-25 22:00:13 +0000 | [diff] [blame] | 266 | printf("Encode \"%s\" with %s in file %s\n", $input, $encoder, $output) if $verbose; |
Thom Johansen | 7543261 | 2007-11-18 17:10:50 +0000 | [diff] [blame^] | 267 | $cmd = "$encoder $encoder_opts \"$input\" \"$output\""; |
Jens Arnold | 5dbea46 | 2007-09-02 22:32:34 +0000 | [diff] [blame] | 268 | if ($$tts_object{"name"} eq "sapi") { |
| 269 | print({$$tts_object{"stdin"}} "EXEC\t$cmd\r\n"); |
Jens Arnold | 080522f | 2007-09-01 08:38:10 +0000 | [diff] [blame] | 270 | } |
| 271 | else { |
| 272 | print("> $cmd\n") if $verbose; |
| 273 | `$cmd`; |
| 274 | } |
Jonas Häggqvist | 17e03e7 | 2007-08-25 22:00:13 +0000 | [diff] [blame] | 275 | } |
| 276 | |
Jens Arnold | 080522f | 2007-09-01 08:38:10 +0000 | [diff] [blame] | 277 | # synchronize the clip generation / processing if it's running in another process |
| 278 | sub synchronize { |
| 279 | my ($tts_object) = @_; |
Jens Arnold | 5dbea46 | 2007-09-02 22:32:34 +0000 | [diff] [blame] | 280 | if ($$tts_object{"name"} eq "sapi") { |
Jens Arnold | 080522f | 2007-09-01 08:38:10 +0000 | [diff] [blame] | 281 | print({$$tts_object{"stdin"}} "SYNC\t42\r\n"); |
| 282 | my $wait = readline($$tts_object{"stdout"}); |
| 283 | #ignore what's actually returned |
| 284 | } |
Jonas Häggqvist | 17e03e7 | 2007-08-25 22:00:13 +0000 | [diff] [blame] | 285 | } |
| 286 | |
| 287 | # Run genlang and create voice clips for each string |
| 288 | sub 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 Arnold | f2ed1e4 | 2007-09-02 00:50:08 +0000 | [diff] [blame] | 300 | local $| = 1; # make progress indicator work reliably |
Jonas Häggqvist | 17e03e7 | 2007-08-25 22:00:13 +0000 | [diff] [blame] | 301 | |
| 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 Arnold | df9a166 | 2007-09-04 22:03:05 +0000 | [diff] [blame] | 323 | $voice = correct_string($voice, $language, $tts_object); |
Jonas Häggqvist | 17e03e7 | 2007-08-25 22:00:13 +0000 | [diff] [blame] | 324 | |
Jens Arnold | df9a166 | 2007-09-04 22:03:05 +0000 | [diff] [blame] | 325 | # If we have a pool of snippets, see if the string exists there first |
Jonas Häggqvist | 17e03e7 | 2007-08-25 22:00:13 +0000 | [diff] [blame] | 326 | if (defined($ENV{'POOL'})) { |
Jens Arnold | df9a166 | 2007-09-04 22:03:05 +0000 | [diff] [blame] | 327 | $pool_file = sprintf("%s/%s-%s.mp3", $ENV{'POOL'}, |
| 328 | md5_hex("$voice $tts_engine $tts_engine_opts $encoder_opts"), |
| 329 | $language); |
Jonas Häggqvist | 17e03e7 | 2007-08-25 22:00:13 +0000 | [diff] [blame] | 330 | 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 Arnold | 080522f | 2007-09-01 08:38:10 +0000 | [diff] [blame] | 343 | 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äggqvist | 17e03e7 | 2007-08-25 22:00:13 +0000 | [diff] [blame] | 346 | } |
| 347 | |
Jens Arnold | 080522f | 2007-09-01 08:38:10 +0000 | [diff] [blame] | 348 | encodewav($wav, $mp3, $encoder, $encoder_opts, $tts_object); |
| 349 | synchronize($tts_object); |
Jonas Häggqvist | 17e03e7 | 2007-08-25 22:00:13 +0000 | [diff] [blame] | 350 | 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 Arnold | 080522f | 2007-09-01 08:38:10 +0000 | [diff] [blame] | 362 | shutdown_tts($tts_object); |
Jonas Häggqvist | 17e03e7 | 2007-08-25 22:00:13 +0000 | [diff] [blame] | 363 | } |
| 364 | |
| 365 | # Assemble the voicefile |
| 366 | sub 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 | |
| 382 | sub deletemp3s() { |
| 383 | for (glob('*.mp3')) { |
| 384 | unlink($_); |
| 385 | } |
| 386 | for (glob('*.wav')) { |
| 387 | unlink($_); |
| 388 | } |
| 389 | } |
| 390 | |
| 391 | sub panic_cleanup { |
| 392 | deletemp3s(); |
| 393 | die "moo"; |
| 394 | } |
| 395 | |
Jonas Häggqvist | 4295149 | 2007-11-16 19:59:09 +0000 | [diff] [blame] | 396 | # Generate .talk clips |
| 397 | sub 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äggqvist | 4295149 | 2007-11-16 19:59:09 +0000 | [diff] [blame] | 403 | # 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äggqvist | 1b2561b | 2007-11-16 20:02:02 +0000 | [diff] [blame] | 410 | |
| 411 | $voice = $file; |
| 412 | $wav = sprintf("%s.talk.wav", $path); |
| 413 | |
Jonas Häggqvist | 4295149 | 2007-11-16 19:59:09 +0000 | [diff] [blame] | 414 | # 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äggqvist | 3942961 | 2007-11-16 23:42:18 +0000 | [diff] [blame] | 420 | gentalkclips($path, $tts_object, $encoder, $encoder_opts, $tts_engine_opts, $i); |
Jonas Häggqvist | 4295149 | 2007-11-16 19:59:09 +0000 | [diff] [blame] | 421 | $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äggqvist | 17e03e7 | 2007-08-25 22:00:13 +0000 | [diff] [blame] | 440 | # Check parameters |
| 441 | my $printusage = 0; |
| 442 | unless (defined($V) or defined($C)) { print("Missing either -V or -C\n"); $printusage = 1; } |
| 443 | if (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 | } |
| 448 | elsif (defined($C)) { |
| 449 | unless (defined($ARGV[0])) { print "Missing path argument\n"; $printusage = 1; } |
| 450 | } |
| 451 | unless (defined($e)) { print("Missing -e argument\n"); $printusage = 1; } |
| 452 | unless (defined($E)) { print("Missing -E argument\n"); $printusage = 1; } |
| 453 | unless (defined($s)) { print("Missing -s argument\n"); $printusage = 1; } |
| 454 | unless (defined($S)) { print("Missing -S argument\n"); $printusage = 1; } |
| 455 | if ($printusage == 1) { printusage(); exit 1; } |
| 456 | |
Jonas Häggqvist | 17e03e7 | 2007-08-25 22:00:13 +0000 | [diff] [blame] | 457 | if (defined($v) or defined($ENV{'V'})) { |
| 458 | our $verbose = 1; |
| 459 | } |
| 460 | |
| 461 | |
| 462 | # Do what we're told |
| 463 | if ($V == 1) { |
Jonas Häggqvist | 4295149 | 2007-11-16 19:59:09 +0000 | [diff] [blame] | 464 | # Only do the panic cleanup for voicefiles |
| 465 | $SIG{INT} = \&panic_cleanup; |
| 466 | $SIG{KILL} = \&panic_cleanup; |
| 467 | |
Jonas Häggqvist | 17e03e7 | 2007-08-25 22:00:13 +0000 | [diff] [blame] | 468 | 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 | } |
| 474 | elsif ($C) { |
Jonas Häggqvist | 4295149 | 2007-11-16 19:59:09 +0000 | [diff] [blame] | 475 | 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 Johansen | 7543261 | 2007-11-18 17:10:50 +0000 | [diff] [blame^] | 477 | gentalkclips($ARGV[0], $tts_object, $e, $E, $S, 0); |
Jonas Häggqvist | 4295149 | 2007-11-16 19:59:09 +0000 | [diff] [blame] | 478 | shutdown_tts($tts_object); |
Jonas Häggqvist | 17e03e7 | 2007-08-25 22:00:13 +0000 | [diff] [blame] | 479 | } |
| 480 | else { |
| 481 | printusage(); |
| 482 | exit 1; |
| 483 | } |