summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xtools/voice.pl88
1 files changed, 57 insertions, 31 deletions
diff --git a/tools/voice.pl b/tools/voice.pl
index 8e603308f3..216d514065 100755
--- a/tools/voice.pl
+++ b/tools/voice.pl
@@ -19,7 +19,7 @@ use strict;
19use warnings; 19use warnings;
20use File::Basename; 20use File::Basename;
21use File::Copy; 21use File::Copy;
22use vars qw($V $C $t $l $e $E $s $S $i $v); 22use vars qw($V $C $t $l $e $E $s $S $i $v $f);
23use IPC::Open2; 23use IPC::Open2;
24use IPC::Open3; 24use IPC::Open3;
25use Digest::MD5 qw(md5_hex); 25use Digest::MD5 qw(md5_hex);
@@ -33,7 +33,7 @@ sub printusage {
33 33
34Usage: voice.pl [options] [path to dir] 34Usage: voice.pl [options] [path to dir]
35 -V 35 -V
36 Create voice file. You must also specify -t and -l. 36 Create voice file. You must also specify -l, -i, and -t or -f
37 37
38 -C 38 -C
39 Create .talk clips. 39 Create .talk clips.
@@ -42,6 +42,8 @@ Usage: voice.pl [options] [path to dir]
42 Specify which target you want to build voicefile for. Must include 42 Specify which target you want to build voicefile for. Must include
43 any features that target supports. 43 any features that target supports.
44 44
45 -f=<file> Use existing voiceids file
46
45 -i=<target_id> 47 -i=<target_id>
46 Numeric target id. Needed for voice building. 48 Numeric target id. Needed for voice building.
47 49
@@ -328,21 +330,32 @@ sub synchronize {
328# Run genlang and create voice clips for each string 330# Run genlang and create voice clips for each string
329sub generateclips { 331sub generateclips {
330 our $verbose; 332 our $verbose;
331 my ($language, $target, $encoder, $encoder_opts, $tts_engine, $tts_engine_opts) = @_; 333 my ($language, $target, $encoder, $encoder_opts, $tts_engine, $tts_engine_opts, $existingids) = @_;
332 my $english = dirname($0) . '/../apps/lang/english.lang'; 334 my $english = dirname($0) . '/../apps/lang/english.lang';
333 my $langfile = dirname($0) . '/../apps/lang/' . $language . '.lang'; 335 my $langfile = dirname($0) . '/../apps/lang/' . $language . '.lang';
334 my $correctionsfile = dirname($0) . '/voice-corrections.txt'; 336 my $correctionsfile = dirname($0) . '/voice-corrections.txt';
337 my $idfile = "$language.vid";
338 my $updfile = "$language-update.lang";
335 my $id = ''; 339 my $id = '';
336 my $voice = ''; 340 my $voice = '';
337 my $cmd = "genlang -o -t=$target -e=$english $language-update.lang 2>/dev/null"; 341 my $cmd;
338 my $pool_file; 342 my $pool_file;
339 open(VOICEFONTIDS, "> voicefontids");
340 my $i = 0; 343 my $i = 0;
341 local $| = 1; # make progress indicator work reliably 344 local $| = 1; # make progress indicator work reliably
342 345
343 # First run the language through an update pass so any missing strings 346 # First run the language through an update pass so any missing strings
344 # are backfilled from English. Without this, BADNESS. 347 # are backfilled from English. Without this, BADNESS.
345 system("genlang -u -e=$english $langfile > $language-update.lang"); 348 if ($existingids) {
349 $idfile = $existingids;
350 } else {
351 $cmd = "genlang -u -e=$english $langfile > $updfile";
352 print("> $cmd\n") if $verbose;
353 system($cmd);
354 $cmd = "genlang -o -t=$target -e=$english $updfile 2>/dev/null > $idfile";
355 print("> $cmd\n") if $verbose;
356 system($cmd);
357 }
358 open(VOICEFONTIDS, " < $idfile");
346 359
347 my $tts_object = init_tts($tts_engine, $tts_engine_opts, $language); 360 my $tts_object = init_tts($tts_engine, $tts_engine_opts, $language);
348 # add string corrections to tts_object. 361 # add string corrections to tts_object.
@@ -378,9 +391,8 @@ sub generateclips {
378 391
379 print("Generating voice clips"); 392 print("Generating voice clips");
380 print("\n") if $verbose; 393 print("\n") if $verbose;
381 for (`$cmd`) { 394 for (<VOICEFONTIDS>) {
382 my $line = $_; 395 my $line = $_;
383 print(VOICEFONTIDS $line);
384 if ($line =~ /^id: (.*)$/) { 396 if ($line =~ /^id: (.*)$/) {
385 $id = $1; 397 $id = $1;
386 } 398 }
@@ -388,7 +400,7 @@ sub generateclips {
388 $voice = $1; 400 $voice = $1;
389 if ($id !~ /^NOT_USED_.*$/ && $voice ne "") { 401 if ($id !~ /^NOT_USED_.*$/ && $voice ne "") {
390 my $wav = $id . '.wav'; 402 my $wav = $id . '.wav';
391 my $mp3 = $id . '.mp3'; 403 my $enc = $id . '.mp3';
392 404
393 # Print some progress information 405 # Print some progress information
394 if (++$i % 10 == 0 and !$verbose) { 406 if (++$i % 10 == 0 and !$verbose) {
@@ -405,12 +417,12 @@ sub generateclips {
405 $language); 417 $language);
406 if (-f $pool_file) { 418 if (-f $pool_file) {
407 printf("Re-using %s (%s) from pool\n", $id, $voice) if $verbose; 419 printf("Re-using %s (%s) from pool\n", $id, $voice) if $verbose;
408 copy($pool_file, $mp3); 420 copy($pool_file, $enc);
409 } 421 }
410 } 422 }
411 423
412 # Don't generate MP3 if it already exists (probably from the POOL) 424 # Don't generate encoded file if it already exists (probably from the POOL)
413 if (! -f $mp3) { 425 if (! -f $enc) {
414 if ($id eq "VOICE_PAUSE") { 426 if ($id eq "VOICE_PAUSE") {
415 print("Use distributed $wav\n") if $verbose; 427 print("Use distributed $wav\n") if $verbose;
416 copy(dirname($0)."/VOICE_PAUSE.wav", $wav); 428 copy(dirname($0)."/VOICE_PAUSE.wav", $wav);
@@ -422,14 +434,14 @@ sub generateclips {
422 } 434 }
423 } 435 }
424 if ($tts_object->{'format'} eq "wav" || $id eq "VOICE_PAUSE") { 436 if ($tts_object->{'format'} eq "wav" || $id eq "VOICE_PAUSE") {
425 encodewav($wav, $mp3, $encoder, $encoder_opts, $tts_object); 437 encodewav($wav, $enc, $encoder, $encoder_opts, $tts_object);
426 } else { 438 } else {
427 copy($wav, $mp3); 439 copy($wav, $enc);
428 } 440 }
429 441
430 synchronize($tts_object); 442 synchronize($tts_object);
431 if (defined($ENV{'POOL'})) { 443 if (defined($ENV{'POOL'})) {
432 copy($mp3, $pool_file); 444 copy($enc, $pool_file);
433 } 445 }
434 unlink($wav); 446 unlink($wav);
435 } 447 }
@@ -438,25 +450,36 @@ sub generateclips {
438 } 450 }
439 } 451 }
440 } 452 }
441 print("\n");
442 close(VOICEFONTIDS); 453 close(VOICEFONTIDS);
454
455 print("\n");
456
457 unlink($updfile) if (-f $updfile);
443 shutdown_tts($tts_object); 458 shutdown_tts($tts_object);
444} 459}
445 460
446# Assemble the voicefile 461# Assemble the voicefile
447sub createvoice { 462sub createvoice {
448 our $verbose; 463 our $verbose;
449 my ($language, $target_id) = @_; 464 my ($language, $target_id, $existingids) = @_;
450 my $outfile = ""; 465 my $outfile = "";
466 my $vfile = "$language.vid";
467
468 if ($existingids) {
469 $vfile = $existingids;
470 }
451 $outfile = sprintf("%s.voice", $language); 471 $outfile = sprintf("%s.voice", $language);
452 printf("Saving voice file to %s\n", $outfile) if $verbose; 472 printf("Saving voice file to %s\n", $outfile) if $verbose;
453 my $cmd = "voicefont 'voicefontids' $target_id ./ $outfile"; 473 my $cmd = "voicefont '$vfile' $target_id ./ $outfile";
454 print("> $cmd\n") if $verbose; 474 print("> $cmd\n") if $verbose;
455 my $output = `$cmd`; 475 my $output = `$cmd`;
456 print($output) if $verbose; 476 print($output) if $verbose;
477 if (!$existingids) {
478 unlink("$vfile");
479 }
457} 480}
458 481
459sub deletemp3s() { 482sub deleteencs() {
460 for (glob('*.mp3')) { 483 for (glob('*.mp3')) {
461 unlink($_); 484 unlink($_);
462 } 485 }
@@ -466,7 +489,7 @@ sub deletemp3s() {
466} 489}
467 490
468sub panic_cleanup { 491sub panic_cleanup {
469 deletemp3s(); 492 deletencs();
470 die "moo"; 493 die "moo";
471} 494}
472 495
@@ -476,7 +499,7 @@ sub gentalkclips {
476 my ($dir, $tts_object, $encoder, $encoder_opts, $tts_engine_opts, $i) = @_; 499 my ($dir, $tts_object, $encoder, $encoder_opts, $tts_engine_opts, $i) = @_;
477 my $d = new DirHandle $dir; 500 my $d = new DirHandle $dir;
478 while (my $file = $d->read) { 501 while (my $file = $d->read) {
479 my ($voice, $wav, $mp3); 502 my ($voice, $wav, $enc);
480 # Print some progress information 503 # Print some progress information
481 if (++$i % 10 == 0 and !$verbose) { 504 if (++$i % 10 == 0 and !$verbose) {
482 print("."); 505 print(".");
@@ -495,20 +518,20 @@ sub gentalkclips {
495 # Element is a dir 518 # Element is a dir
496 if ( -d $path) { 519 if ( -d $path) {
497 gentalkclips($path, $tts_object, $encoder, $encoder_opts, $tts_engine_opts, $i); 520 gentalkclips($path, $tts_object, $encoder, $encoder_opts, $tts_engine_opts, $i);
498 $mp3 = sprintf("%s/_dirname.talk", $path); 521 $enc = sprintf("%s/_dirname.talk", $path);
499 } 522 }
500 # Element is a file 523 # Element is a file
501 else { 524 else {
502 $mp3 = sprintf("%s.talk", $path); 525 $enc = sprintf("%s.talk", $path);
503 $voice =~ s/\.[^\.]*$//; # Trim extension 526 $voice =~ s/\.[^\.]*$//; # Trim extension
504 } 527 }
505 528
506 printf("Talkclip %s: %s", $mp3, $voice) if $verbose; 529 printf("Talkclip %s: %s", $enc, $voice) if $verbose;
507 530
508 voicestring($voice, $wav, $tts_engine_opts, $tts_object); 531 voicestring($voice, $wav, $tts_engine_opts, $tts_object);
509 wavtrim($wav, 500, $tts_object); 532 wavtrim($wav, 500, $tts_object);
510 # 500 seems to be a reasonable default for now 533 # 500 seems to be a reasonable default for now
511 encodewav($wav, $mp3, $encoder, $encoder_opts, $tts_object); 534 encodewav($wav, $enc, $encoder, $encoder_opts, $tts_object);
512 synchronize($tts_object); 535 synchronize($tts_object);
513 unlink($wav); 536 unlink($wav);
514 } 537 }
@@ -519,9 +542,12 @@ sub gentalkclips {
519my $printusage = 0; 542my $printusage = 0;
520unless (defined($V) or defined($C)) { print("Missing either -V or -C\n"); $printusage = 1; } 543unless (defined($V) or defined($C)) { print("Missing either -V or -C\n"); $printusage = 1; }
521if (defined($V)) { 544if (defined($V)) {
522 unless (defined($t)) { print("Missing -t argument\n"); $printusage = 1; }
523 unless (defined($l)) { print("Missing -l argument\n"); $printusage = 1; } 545 unless (defined($l)) { print("Missing -l argument\n"); $printusage = 1; }
524 unless (defined($i)) { print("Missing -i argument\n"); $printusage = 1; } 546 unless (defined($i)) { print("Missing -i argument\n"); $printusage = 1; }
547 if (defined($t) && defined($f) ||
548 !defined($t) && !defined($f)) {
549 print("Missing either -t or -f argument\n"); $printusage = 1;
550 }
525} 551}
526elsif (defined($C)) { 552elsif (defined($C)) {
527 unless (defined($ARGV[0])) { print "Missing path argument\n"; $printusage = 1; } 553 unless (defined($ARGV[0])) { print "Missing path argument\n"; $printusage = 1; }
@@ -539,7 +565,6 @@ if (defined($v) or defined($ENV{'V'})) {
539# add the tools dir to the path temporarily, for calling various tools 565# add the tools dir to the path temporarily, for calling various tools
540$ENV{'PATH'} = dirname($0) . ':' . $ENV{'PATH'}; 566$ENV{'PATH'} = dirname($0) . ':' . $ENV{'PATH'};
541 567
542
543# Do what we're told 568# Do what we're told
544if ($V == 1) { 569if ($V == 1) {
545 # Only do the panic cleanup for voicefiles 570 # Only do the panic cleanup for voicefiles
@@ -547,10 +572,11 @@ if ($V == 1) {
547 $SIG{KILL} = \&panic_cleanup; 572 $SIG{KILL} = \&panic_cleanup;
548 573
549 printf("Generating voice\n Target: %s\n Language: %s\n Encoder (options): %s (%s)\n TTS Engine (options): %s (%s)\n", 574 printf("Generating voice\n Target: %s\n Language: %s\n Encoder (options): %s (%s)\n TTS Engine (options): %s (%s)\n",
550 $t, $l, $e, $E, $s, $S); 575 defined($t) ? $t : "unknown",
551 generateclips($l, $t, $e, $E, $s, $S); 576 $l, $e, $E, $s, $S);
552 createvoice($l, $i); 577 generateclips($l, $t, $e, $E, $s, $S, $f);
553 deletemp3s(); 578 createvoice($l, $i, $f);
579 deleteencs();
554} 580}
555elsif ($C) { 581elsif ($C) {
556 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); 582 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);