diff options
Diffstat (limited to 'talk/po2talk')
-rwxr-xr-x | talk/po2talk | 191 |
1 files changed, 191 insertions, 0 deletions
diff --git a/talk/po2talk b/talk/po2talk new file mode 100755 index 0000000..46fe1fe --- /dev/null +++ b/talk/po2talk @@ -0,0 +1,191 @@ +#! /usr/bin/perl + +use Getopt::Long; + +sub help; +sub read_po; +sub join_id; +sub new_tmp_file; +sub cleanup; + +GetOptions( + 'help' => \&help, + 'compress' => \$opt_compress, +); + +END { cleanup } +$SIG{INT} = \&cleanup; +$SIG{TERM} = \&cleanup; + +my @tmp_files; + +$espeak = "espeak"; + +$magic = 0x692741e8; + +help if @ARGV != 2; + +$po = read_po $ARGV[0]; + +$tmp_txt = new_tmp_file; +$tmp_wav = new_tmp_file; +$tmp_snd = new_tmp_file; + +for $msg (@{$po}) { + $id = join_id $msg, 'id'; + $str = join_id $msg, 'str'; + + next unless $id ne ""; + + eval '$id = "' . $id . '"'; + eval '$str = "' . $str . '"'; + + $str = $id if $str eq ""; + + if(!$snd{$str}) { + open W, ">$tmp_txt"; + print W $str; + close W; + + $punc = length($id) == 1 ? "--punc" : ""; + + system "$espeak $punc -f $tmp_txt -w $tmp_wav"; + system "sox $tmp_wav -b -u -c 1 -r 16000 -t .wav $tmp_snd"; + if($opt_compress) { + system "./sc $tmp_snd $tmp_snd"; + } + + open F, $tmp_snd; + sysread F, $snd_buf, -s $tmp_snd; + close F; + + $snd{$str} = $snd_buf; + } + + $snd_id{$id} = $str; +} + +$file_ofs = 0; +@snds = sort keys %snd; +@snd_ids = sort keys %snd_id; + +for $snd_id (@snd_ids) { + $txt_ofs{$snd_id} = $file_ofs; + $file_ofs += length($snd_id) + 1; +} + +for $snd (@snds) { + $snd_ofs{$snd} = $file_ofs; + $file_ofs += length($snd{$snd}); +} + +$head_size = 8 + 8 * @snd_ids; + +open W, ">$ARGV[1]"; + +print W pack("VV", $magic, scalar(@snd_ids)); +for $snd_id (@snd_ids) { + print W pack("VV", ($txt_ofs{$snd_id} + $head_size, $snd_ofs{$snd_id{$snd_id}} + $head_size)); +} +for $snd_id (@snd_ids) { + print W $snd_id, "\x00"; +} +for $snd (@snds) { + print W $snd{$snd}; +} + +close W; + + +sub help +{ + print STDERR + "Usage: po2talk [options] po_file talk_file\n" . + "Run po file through espeak.\n"; + + exit 0; +} + + +sub read_po +{ + local $_; + my ($msg, $cnt, $id, $f); + + $cnt = 0; + + open F, $_[0]; + while(<F>) { + s/^\s*|\s*$//g; + next if $_ eq ""; + if(/^#,/) { + s/^#,\s*//; + for $f (split /\s*,\s*/) { + ${$msg->[$cnt]{flags}{$f}} = 1 if $f ne ""; + } + next + } + if(/^#(\s|$)/) { push @{$msg->[$cnt]{u_comment}}, $_ ; next } + if(/^#/) { push @{$msg->[$cnt]{a_comment}}, $_; next } + if(s/^msg(id\b|id_plural\b|str(\[\d+\])?)\s*//) { + $id = $1; + if($id eq 'id') { + $msg->[$cnt]{line} = $. unless exists $msg->[$cnt]{$line}; + $cnt++; + } + } + if($cnt && /^"(.*)"$/) { + push @{$msg->[$cnt - 1]{$id}}, $1; + } + else { + print STDERR "$_[0]:$.: invalid po format\n"; + return undef; + } + } + close F; + + # trailing comments + pop @$msg if @$msg > 0 && !$msg->[-1]{id}; + + return $msg; +} + + +sub join_id +{ + my ($msg, $id); + + ($msg, $id) = @_; + + return join '', @{$msg->{$id}}; +} + + +# create new temporary file +sub new_tmp_file +{ + local $_; + + chomp ($_ = `mktemp /tmp/po2talk.XXXXXXXXXX`); + die "error: mktemp failed\n" if $?; + + push @tmp_files, $_; + + return $_; +} + + +# remove temporary files +sub cleanup +{ + local $_; + + for (@tmp_files) { + next unless defined $_; + unlink; + $_ = undef; + } + + undef @tmp_files; +} + |