/[mbrola]/trunk/mbrola.pl
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /trunk/mbrola.pl

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3 - (hide annotations)
Sat Aug 5 12:44:39 2006 UTC (17 years, 8 months ago) by dpavlin
File MIME type: text/plain
File size: 9528 byte(s)
cleanup and re-structure code (fix $speed nonsenese)
1 dpavlin 1 #!/usr/bin/perl -w
2    
3     # mbrola.pl
4     #
5     # 08/04/2006 07:54:54 PM CEST Dobrica Pavlinusic <dpavlin@rot13.org>
6    
7     use strict;
8     use Data::Dump qw/dump/;
9     use Term::ReadLine;
10    
11     my $term = new Term::ReadLine 'Simple Perl calc';
12     my $prompt = "Prièaj: ";
13     my $OUT = $term->OUT || \*STDOUT;
14    
15    
16     my $letters = {
17     'a' => [['a'],
18     [[170,]]],
19     'A' => [['a'],
20     [[170,]]],
21     'b' => [['b', 'e', 'b', 'e',],
22     [[90,], [15,], [1,], [150,]]],
23     'B' => [['b', 'e', 'b', 'e',],
24     [[90,], [15,], [1,], [150,]]],
25     'c' => [['ts', 'a'],
26     [[30,], [100,]]],
27     'C' => [['ts', 'a'],
28     [[30,], [100,]]],
29     'è' => [['tS', 'a'],
30     [[30,], [100,]]],
31     'È' => [['tS', 'a'],
32     [[30,], [100,]]],
33     'æ' => [['tS\'', 'a'],
34     [[30,], [100,]]],
35     'Æ' => [['tS\'', 'a'],
36     [[30,], [100,]]],
37     'd' => [['d', 'e', 'd', 'e'],
38     [[70,], [15,], [60,], [1, 90, 100]]],
39     'D' => [['d', 'e', 'd', 'e'],
40     [[70,], [15,], [60,], [1, 90, 100]]],
41     'ð'=> [['dZ\'', 'a'],
42     [[100,], [110,]]],
43     'Ð'=> [['dZ\'', 'a'],
44     [[100,], [110,]]],
45     'e' => [['e', 'x', 'e'],
46     [[150, 10, 100], [1,], [50, 50, 90]]],
47     'E' => [['e', 'x', 'e'],
48     [[150, 10, 100], [1,], [50, 50, 90]]],
49     'f' => [['f', 'e'],
50     [[100, 10, 100], [100,]]],
51     'F' => [['f', 'e'],
52     [[100, 10, 100], [100,]]],
53     'g' => [['g', 'a'],
54     [[70,], [150,]]],
55     'G' => [['g', 'a'],
56     [[70,], [150,]]],
57     #'h' => [['x', 'r', 'a'],
58     # [[120,], [1,], [170,]]],
59     'h' => [['x', 'a', 'x', 'a'],
60     [[150,], [170,], [1,], [170,]]],
61     'H' => [['x', 'a', 'x', 'a'],
62     [[150,], [170,], [1,], [170,]]],
63     'i' => [['i'],
64     [[150,]]],
65     'I' => [['i'],
66     [[150,]]],
67     'j' => [['j', 'a', 'r'],
68     [[60,], [10,], [50,]]],
69     'J' => [['j', 'a', 'r'],
70     [[60,], [10,], [50,]]],
71     'k' => [['k', 'a'],
72     [[70,], [150,]]],
73     'K' => [['k', 'a'],
74     [[70,], [150,]]],
75     #'l' => [['l', 'e'],
76     # [[100, 10, 100], [100,]]],
77     'l' => [['e', 'l'],
78     [[100,], [100,10, 100]]],
79     'L' => [['e', 'l'],
80     [[100,], [100,10, 100]]],
81     #'m' => [['m', 'e'],
82     # [[90,], [50,]]],
83     'm' => [['e', 'm'],
84     [[50,], [90,]]],
85     'M' => [['e', 'm'],
86     [[50,], [90,]]],
87     #'n' => [['n', 'e'],
88     # [[90,], [50,]]],
89     'n' => [['e', 'n'],
90     [[50,], [90,]]],
91     'N' => [['e', 'n'],
92     [[50,], [90,]]],
93     'o' => [['o', 'x'],
94     [[71,], [70,]]],
95     'O' => [['o', 'x'],
96     [[71,], [70,]]],
97     #'p' => [['p', 'a'],
98     # [[70,], [150,]]],
99     'p' => [['p', 'e'],
100     [[90,], [120,]]],
101     'P' => [['p', 'e'],
102     [[90,], [120,]]],
103     #'r' => [['r', 'x'],
104     # [[90,], [110,]]],
105     'r' => [['e', 'r', 'x'],
106     [[150,10,100], [90,], [110,]]],
107     'R' => [['e', 'r', 'x'],
108     [[150,10,100], [90,], [110,]]],
109     's' => [['s', 'a'],
110     [[90,], [110,]]],
111     'S' => [['s', 'a'],
112     [[90,], [110,]]],
113     '¹' => [['S', 'a'],
114     [[70,], [110,]]],
115     '©' => [['S', 'a'],
116     [[70,], [110,]]],
117     #'t' => [['t', 'a'],
118     # [[90,], [120,]]],
119     't' => [['t', 'e'],
120     [[90,], [150,]]],
121     'T' => [['t', 'e'],
122     [[90,], [150,]]],
123     'u' => [['u'],
124     [[170,]]],
125     'U' => [['u'],
126     [[170,]]],
127     'v' => [['v', 'a'],
128     [[100,], [120,]]],
129     'V' => [['v', 'a'],
130     [[100,], [120,]]],
131     'z' => [['z', 'a'],
132     [[100,], [110,]]],
133     'Z' => [['z', 'a'],
134     [[100,], [110,]]],
135     '¾' => [['Z', 'a'],
136     [[100,], [110,]]],
137     '®' => [['Z', 'a'],
138     [[100,], [110,]]],
139     'x' => [['i', 'k', 's'],
140     [[60,], [60,], [50,]]],
141     'X' => [['i', 'k', 's'],
142     [[60,], [60,], [50,]]],
143     'y' => [['i', 'p', 's', 'i', 'l', 'o', 'n', 'e'],
144     [[60, 10, 90, 70, 110],
145     [70, 10, 100],
146     [50,], [40,], [60,], [70,], [70,], [10,]]],
147     'Y' => [['i', 'p', 's', 'i', 'l', 'o', 'n', 'e'],
148     [[60, 10, 90, 70, 110],
149     [70, 10, 100],
150     [50,], [40,], [60,], [70,], [70,], [10,]]],
151     'q' => [['k', 'u', 'x'],
152     [[70,], [110,], [1,]]],
153     'Q' => [['k', 'u', 'x'],
154     [[70,], [110,], [1,]]],
155     'w' => [['d', 'u', 'p', 'l', 'o', '_', 'v', 'e'],
156     [[54, 50, 100], [50, 50, 110], [85, 10, 100], [35,],
157     [54, 90, 95], [10,], [100, 90, 110], [120, 20, 95]]],
158     'W' => [['d', 'u', 'p', 'l', 'o', '_', 'v', 'e'],
159     [[54, 50, 100], [50, 50, 110], [85, 10, 100], [35,],
160     [54, 90, 95], [10,], [100, 90, 110], [120, 20, 95]]]}
161     ;
162    
163     my $phonemes = {
164     'a' => 'a', 'b' => 'b', 'c' => 'ts', 'è' => 'tS', 'æ' => 'tS\'', 'd' => 'd',
165     'd¾' => 'dZ', 'ð'=> 'dZ\'', 'e' => 'e', 'f' => 'f', 'g' => 'g', 'h' => 'x',
166     'i' => 'i', 'j' => 'j', 'k' => 'k', 'l' => 'l', 'lj'=> 'L', 'm' => 'm',
167     'n' => 'n', 'nj'=> 'J', 'o' => 'o', 'p' => 'p', 'r' => 'r', 's' => 's',
168     '¹' => 'S', 't' => 't', 'u' => 'u', 'v' => 'v', 'z' => 'z', '¾' => 'Z'
169     };
170    
171     my $durations = {
172     'a' => 61, 'b' => 65, 'ts' => 113, 'tS' => 90, 'tS\''=> 98, 'd' => 54,
173     'dZ' => 56, 'dZ\''=> 61, 'e' => 53, 'f' => 86, 'g' => 56, 'x' => 68,
174     'i' => 49, 'j' => 53, 'k' => 81, 'l' => 35, 'L' => 59, 'm' => 56,
175     'n' => 45, 'J' => 60, 'o' => 54, 'p' => 85, 'r' => 25, 's' => 91,
176     'S' => 99, 't' => 76, 'u' => 50, 'v' => 40, 'z' => 68, 'Z' => 74,
177     # pause
178     '_' => 150 }
179     ;
180    
181     my $token_to_grapheme = {
182     'x' => 'ks',
183     'q' => 'k',
184     'w' => 'v',
185     'y' => 'j',
186     };
187    
188     my $silence = {
189     'word' => 40,
190     'sent' => 100,
191     'comma' => 180,
192     'hard' => 100,
193     'spell' => 150
194     };
195    
196     my $recovery;
197     foreach my $df (qw/ bp oo uks/) {
198     $recovery->{$df}++;
199     }
200    
201     sub speak_hr {
202    
203     my $text = shift @_ || 'ovo je na¹a difonska sinteza govora. kako vam se sviða? mo¾da èak i radi!';
204    
205     my $first = 1;
206     my $zarez = 0;
207    
208     my $speed = 1.2;
209    
210     # FIXME: lj, nj, d¾
211     my @chars = split(//, $text);
212    
213 dpavlin 3 my @pho = ({ char => '_', dur => [ $silence->{word} ] });
214 dpavlin 1
215     my ($g,$f) = ('','');
216    
217 dpavlin 2 my $last_c = '';
218    
219 dpavlin 1 foreach my $i ( 0 .. $#chars ) {
220     my $c = $chars[$i];
221    
222     $g .= $c;
223    
224     if (defined( $phonemes->{$c} )) {
225     $c = $phonemes->{$c};
226     } elsif (defined( $token_to_grapheme->{$c} )) {
227     $c = $token_to_grapheme->{$c};
228     }
229    
230     my $d = $durations->{$c} || $silence->{word};
231    
232     my @dur = ( $d );
233    
234 dpavlin 3 if ($last_c =~ m/[,\.!\? _]/) {
235 dpavlin 1
236     my $from = $#{ $pho[ $i - 1 ]->{dur} };
237     $from = 3 if ($from > 3);
238    
239     my $tmpr = 80;
240    
241     foreach my $j ( -($from) .. 0 ) {
242     $pho[ $i - 1 ]->{dur}->[$j] = $tmpr;
243     $tmpr += 30;
244     }
245    
246 dpavlin 3 # begining of sentence
247     push @dur, ( 10, 120 );
248     }
249 dpavlin 1
250 dpavlin 3 if ($c =~ m/\s/) {
251     $pho[ $#pho ]->{dur}->[0] += $silence->{word};
252     $last_c = $c;
253     next;
254     } elsif ($c =~ m/[\.!\?]/) {
255     $pho[ $#pho ]->{dur}->[0] += $silence->{word};
256     push @pho, {
257     char => '_',
258     dur => [ $silence->{word} ],
259     };
260     $last_c = $c;
261     next;
262     } elsif ($c =~ m/,/) {
263     push @dur, ( 10, 100 );
264 dpavlin 1 }
265    
266 dpavlin 2 # same last chars? double duration
267     if ($last_c eq $c) {
268     $pho[ $#pho ]->{dur}->[0] *= 2;
269     next;
270     }
271    
272     # fixup sequences that need special handling
273     if (defined($recovery->{ $last_c . $c })) {
274     push @pho, {
275     char => '_',
276 dpavlin 3 dur => [ $silence->{word} ],
277 dpavlin 2 };
278     }
279    
280     $last_c = $c;
281 dpavlin 1 push @pho, {
282     char => $c,
283     dur => \@dur,
284     };
285    
286     $f .= $c;
287     }
288    
289 dpavlin 3 push @pho, { char => '_', dur => [ $silence->{sent} ] };
290 dpavlin 1
291 dpavlin 3 # warn "# pho = ",dump(@pho),$/;
292 dpavlin 1
293     my $out;
294    
295     foreach my $p (@pho) {
296     $out .= $p->{char} . ' ' . join(' ', map { $_ * $speed } @{ $p->{dur} }) . "\n";
297     }
298    
299     return ($out, $g, $f);
300     }
301    
302     my $mbrola = './bin/mbrola-linux-i386 ./cr1/cr1';
303    
304     while ( defined ($_ = $term->readline($prompt)) ) {
305    
306     $term->addhistory($_);
307    
308     my ($out,$g,$f) = speak_hr( $_ );
309    
310     open(my $fh, "| $mbrola - tmp.wav") || die "can't open $mbrola: $!";
311    
312 dpavlin 3 print $OUT ">>> $g\n<<< $f\n";
313 dpavlin 1
314     print $fh $out || die "can't pipe to $mbrola";
315     close($fh) || die "error closing pipe to $mbrola";
316    
317 dpavlin 3 $out =~ s/\n/ | /gs;
318     print $OUT "# $out\n";
319    
320 dpavlin 1 system 'play tmp.wav';
321    
322     }
323    
324    
325     __END__
326    
327     foreach my $c (split(//, $text)) {
328     warn "# c = $c\n";
329    
330     if (! defined($letters->{$c})) {
331     print "_ 50\n";
332     next;
333     }
334    
335     my $slova = $letters->{$c}->[0];
336     my $param = $letters->{$c}->[1];
337     warn "# ",dump($slova, $param), $/;
338     foreach my $i ( 0 ... $#$slova ) {
339     print $slova->[$i], " ", join(" ",@{ $param->[$i] }), "\n";
340     }
341    
342     }

Properties

Name Value
svn:executable

  ViewVC Help
Powered by ViewVC 1.1.26