--- trunk/mbrola.pl 2006/08/05 10:54:32 1 +++ trunk/mbrola.pl 2006/08/08 15:06:33 5 @@ -7,11 +7,7 @@ use strict; use Data::Dump qw/dump/; use Term::ReadLine; - -my $term = new Term::ReadLine 'Simple Perl calc'; -my $prompt = "Pričaj: "; -my $OUT = $term->OUT || \*STDOUT; - +use File::Slurp; my $letters = { 'a' => [['a'], @@ -194,7 +190,7 @@ }; my $recovery; -foreach my $df (qw/ bp oo uks/) { +foreach my $df (qw/bp oo uks/) { $recovery->{$df}++; } @@ -210,41 +206,44 @@ # FIXME: lj, nj, dľ my @chars = split(//, $text); - my @pho = ({ char => '_', dur => [50] }); + my @pho = ({ char => '_', dur => [ $silence->{word} ] }); my ($g,$f) = ('',''); - foreach my $i ( 0 .. $#chars ) { - my $c = $chars[$i]; + my $last_c = ''; + + my $i = 0; + while (@chars) { + my $c = shift @chars; $g .= $c; - if (defined( $phonemes->{$c} )) { - $c = $phonemes->{$c}; - } elsif (defined( $token_to_grapheme->{$c} )) { - $c = $token_to_grapheme->{$c}; - } else { - $pho[ $#pho ]->{dur}->[0] = $silence->{word}; - next; + if (defined( $phonemes->{ lc($c) } )) { + $c = $phonemes->{ lc($c) }; + } elsif (defined( $token_to_grapheme->{ lc($c) } )) { + my $tmp = $token_to_grapheme->{ lc($c) }; + if (length($tmp) > 1) { + my @tmp_c = split(//, $tmp); + warn "### $c --> $tmp\n"; + $c = shift @tmp_c; + unshift @chars, ( @tmp_c ); + } else { + $c = $tmp; + } } - my $d = $durations->{$c} || $silence->{word}; - - my @dur = ( $d ); - - if ($first) { - $first = 0; + my $d = $durations->{$c} || $durations->{ lc($c) }; - push @dur, ( 10, 120 ); - } - - if ($zarez) { - $zarez = 0; - push @dur, ( 10, 100 ); + if (! $d) { + next if ($c =~ m/\s/); + warn "### skipped: $c\n"; + $c = '_'; + $d = $silence->{word}; } + my @dur = ( $d ); - if ($c =~ m/[,\.!\? _]/) { + if ($last_c =~ m/[,\.!\? _]/) { my $from = $#{ $pho[ $i - 1 ]->{dur} }; $from = 3 if ($from > 3); @@ -256,16 +255,41 @@ $tmpr += 30; } - if ($c =~ m/,/) { - $zarez = 1; - @dur = ( $silence->{comma} ); - } else { - @dur = ( $silence->{sentence} ); - $first = 1; - } + # begining of sentence + push @dur, ( 10, 120 ); + } + if ($c =~ m/\s/) { + $pho[ $#pho ]->{dur}->[0] += $silence->{word}; + $last_c = $c; + next; + } elsif ($c =~ m/[\.!\?]/) { + $pho[ $#pho ]->{dur}->[0] += $silence->{word}; + push @pho, { + char => '_', + dur => [ $silence->{sent} ], + }; + $last_c = $c; + next; + } elsif ($c =~ m/,/) { + push @dur, ( 10, 100 ); } + # same last chars? double duration + if ($last_c eq $c) { + $pho[ $#pho ]->{dur}->[0] *= 2; + next; + } + + # fixup sequences that need special handling + if (defined($recovery->{ $last_c . $c })) { + push @pho, { + char => '_', + dur => [ $silence->{word} ], + }; + } + + $last_c = $c; push @pho, { char => $c, dur => \@dur, @@ -274,21 +298,14 @@ $f .= $c; } - push @pho, { char => '_', dur => [50] }; + push @pho, { char => '_', dur => [ $silence->{sent} ] }; - warn "# pho = ",dump(@pho),$/; +# warn "# pho = ",dump(@pho),$/; my $out; - my $last_c = ''; - foreach my $p (@pho) { - if (defined($recovery->{ $last_c . $p->{char} })) { - $out .= '_ ' . ( $silence->{word} * $speed ) . "\n"; - } $out .= $p->{char} . ' ' . join(' ', map { $_ * $speed } @{ $p->{dur} }) . "\n"; - - $last_c = $p->{char}; } return ($out, $g, $f); @@ -296,21 +313,47 @@ my $mbrola = './bin/mbrola-linux-i386 ./cr1/cr1'; -while ( defined ($_ = $term->readline($prompt)) ) { +my $term = new Term::ReadLine 'Mbrola croatian speaker'; +my $OUT = $term->OUT || \*STDOUT; - $term->addhistory($_); +sub play_speak_hr { + my $text = shift || return; - my ($out,$g,$f) = speak_hr( $_ ); + my ($out,$g,$f) = speak_hr( $text ); open(my $fh, "| $mbrola - tmp.wav") || die "can't open $mbrola: $!"; - print $OUT ">>> $g\n>>> $f\n$out\n"; + print $OUT ">>> $g\n<<< $f\n"; print $fh $out || die "can't pipe to $mbrola"; close($fh) || die "error closing pipe to $mbrola"; + $out =~ s/\n/ | /gs; + print $OUT "# $out\n"; + system 'play tmp.wav'; +} + + +if (my $path = shift @ARGV) { + my $text = read_file($path) || die "can't read $path: $!"; + + # strip html + $text =~ s!]+>! !gs; + + $text =~ s!\s+! !gs; + + print "-- $text --"; + play_speak_hr( $text ); + exit; +} + +my $prompt = "Pričaj: "; + +while ( defined ($_ = $term->readline($prompt)) ) { + $term->addhistory( $_ ); + play_speak_hr( $_ ); }