Index: voice.pl =================================================================== --- voice.pl (revision 15167) +++ voice.pl (working copy) @@ -20,7 +20,7 @@ use File::Basename; use File::Copy; use Switch; -use vars qw($V $C $t $l $e $E $s $S $i $v); +use vars qw($V $C $D $t $l $e $E $s $S $i $v); use IPC::Open2; use IPC::Open3; use Digest::MD5 qw(md5_hex); @@ -34,6 +34,9 @@ -C Create .talk clips. + + -D + Create .talk clips for Database. -t= Specify which target you want to build voicefile for. Must include @@ -367,7 +370,100 @@ print($output) if $verbose; } -sub deletemp3s() { +# Read a long or a short from a database file +sub ecread { + my ($fh, $length) = @_; + my $string; + read($fh, $string, $length); + if ($length == 4) { + $string = unpack("V", $string); + } + elsif ($length == 2) { + $string = unpack("v", $string); + } + return $string; +} + +# This function is somwhat stricter than it needs to be +sub fatsafe { + my ($string) = @_; + return $string; +} + +# Must be kept in sync with the implementation in Rockbox +sub dbtalkname { + my ($string) = @_; + $string = sprintf("%.100s", $string); + $string =~ tr/[\x00-\x2F\x3A-\x40\x5B-\x60\x7B-\xFF]/_/; + $string = $string.".talk"; +} + +# Generate .talk clips for database +sub databaseclips { + our $verbose; + my ($dir, $language, $encoder, $encoder_opts, $tts_engine, $tts_engine_opts) = @_; + + my $tts_object = init_tts($tts_engine, $tts_engine_opts, $language); + + if (! -d sprintf("%s/.rockbox/talkclips", $dir)) { + mkdir(sprintf("%s/.rockbox/talkclips", $dir)); + } + + # Create clips for all labels in tagnavi.config + open(TAGNAVI, sprintf("%s/.rockbox/tagnavi.config", $dir)); + while () { + my $line = $_; + if ($line =~ /^"([^"]+)"/) { + my $voice = $1; + $voice = correct_string($voice, $language, $tts_object); + my $mp3 = sprintf("%s/.rockbox/talkclips/%s.mp3", $dir, dbtalkname($voice)); + if ( ! -f $mp3) { + my $wav = sprintf("/tmp/%s.wav", dbtalkname($voice)); + voicestring($voice, $wav, $tts_engine_opts, $tts_object); + wavtrim($wav, 500, $tts_object); + encodewav($wav, $mp3, $encoder, $encoder_opts, $tts_object); + unlink($wav); + } + } + } + close(TAGNAVI); + + for my $file (glob(sprintf("%s/.rockbox/database_[0-9]*.tcd", $dir))) { + # Ignore the db with filenames + if ($file eq sprintf("%s/.rockbox/database_4.tcd", $dir)) { + next; + } + open(TCD, $file); + read(TCD, my $magic, 4); + # Add an elsif if the format changes + if ($magic eq pack("V", 0x5443480b)) { + my $datasize = ecread(*TCD, 4); + my $entrycount = ecread(*TCD, 4); + for (my $i = 1; $i <= $entrycount; $i++) { + my $fieldsize = ecread(*TCD, 2); + my $discard = ecread(*TCD, 2); + + read(TCD, my $voice, $fieldsize); + $voice =~ s/\0.*//; + $voice = correct_string($voice, $language, $tts_object); + my $mp3 = sprintf("%s/.rockbox/talkclips/%s.mp3", $dir, dbtalkname($voice)); + if ( ! -f $mp3) { + my $wav = sprintf("/tmp/%s.wav", dbtalkname($voice)); + voicestring($voice, $wav, $tts_engine_opts, $tts_object); + wavtrim($wav, 500, $tts_object); + encodewav($wav, $mp3, $encoder, $encoder_opts, $tts_object); + unlink($wav); + } + } + } + else { + die("Unknown file: $file"); + } + close(TCD); + } +} + +sub deletemp3s { for (glob('*.mp3')) { unlink($_); } @@ -383,15 +479,20 @@ # Check parameters my $printusage = 0; -unless (defined($V) or defined($C)) { print("Missing either -V or -C\n"); $printusage = 1; } +unless (defined($V) or defined($C) or defined($D)) { print("Missing either -V, -C or -D\n"); $printusage = 1; } if (defined($V)) { unless (defined($t)) { print("Missing -t argument\n"); $printusage = 1; } unless (defined($l)) { print("Missing -l argument\n"); $printusage = 1; } unless (defined($i)) { print("Missing -i argument\n"); $printusage = 1; } } elsif (defined($C)) { + unless (defined($l)) { print("Missing -l argument\n"); $printusage = 1; } unless (defined($ARGV[0])) { print "Missing path argument\n"; $printusage = 1; } } +elsif (defined($D)) { + unless (defined($l)) { print("Missing -l argument\n"); $printusage = 1; } + unless (defined($ARGV[0])) { print "Missing path argument\n"; $printusage = 1; } +} unless (defined($e)) { print("Missing -e argument\n"); $printusage = 1; } unless (defined($E)) { print("Missing -E argument\n"); $printusage = 1; } unless (defined($s)) { print("Missing -s argument\n"); $printusage = 1; } @@ -407,16 +508,20 @@ # Do what we're told -if ($V == 1) { +if (defined($V)) { printf("Generating voice\n Target: %s\n Language: %s\n Encoder (options): %s (%s)\n TTS Engine (options): %s (%s)\n", $t, $l, $e, $E, $s, $S); generateclips($l, $t, $e, $E, $s, $S); createvoice($l, $i); deletemp3s(); } -elsif ($C) { +elsif (defined($C)) { # xxx: Implement .talk clip generation } +elsif (defined($D)) { + # xxx: Implement .talk clip generation for Database + databaseclips($ARGV[0], $l, $e, $E, $s, $S); +} else { printusage(); exit 1;