/[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

Contents of /trunk/mbrola.pl

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (show annotations)
Sat Aug 5 10:54:32 2006 UTC (17 years, 8 months ago) by dpavlin
File MIME type: text/plain
File size: 9246 byte(s)
import current mbrola, cr1 database and perl pho generator for Croatian

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 my @pho = ({ char => '_', dur => [50] });
214
215 my ($g,$f) = ('','');
216
217 foreach my $i ( 0 .. $#chars ) {
218 my $c = $chars[$i];
219
220 $g .= $c;
221
222 if (defined( $phonemes->{$c} )) {
223 $c = $phonemes->{$c};
224 } elsif (defined( $token_to_grapheme->{$c} )) {
225 $c = $token_to_grapheme->{$c};
226 } else {
227 $pho[ $#pho ]->{dur}->[0] = $silence->{word};
228 next;
229 }
230
231 my $d = $durations->{$c} || $silence->{word};
232
233 my @dur = ( $d );
234
235 if ($first) {
236 $first = 0;
237
238 push @dur, ( 10, 120 );
239 }
240
241 if ($zarez) {
242 $zarez = 0;
243 push @dur, ( 10, 100 );
244 }
245
246
247 if ($c =~ m/[,\.!\? _]/) {
248
249 my $from = $#{ $pho[ $i - 1 ]->{dur} };
250 $from = 3 if ($from > 3);
251
252 my $tmpr = 80;
253
254 foreach my $j ( -($from) .. 0 ) {
255 $pho[ $i - 1 ]->{dur}->[$j] = $tmpr;
256 $tmpr += 30;
257 }
258
259 if ($c =~ m/,/) {
260 $zarez = 1;
261 @dur = ( $silence->{comma} );
262 } else {
263 @dur = ( $silence->{sentence} );
264 $first = 1;
265 }
266
267 }
268
269 push @pho, {
270 char => $c,
271 dur => \@dur,
272 };
273
274 $f .= $c;
275 }
276
277 push @pho, { char => '_', dur => [50] };
278
279 warn "# pho = ",dump(@pho),$/;
280
281 my $out;
282
283 my $last_c = '';
284
285 foreach my $p (@pho) {
286 if (defined($recovery->{ $last_c . $p->{char} })) {
287 $out .= '_ ' . ( $silence->{word} * $speed ) . "\n";
288 }
289 $out .= $p->{char} . ' ' . join(' ', map { $_ * $speed } @{ $p->{dur} }) . "\n";
290
291 $last_c = $p->{char};
292 }
293
294 return ($out, $g, $f);
295 }
296
297 my $mbrola = './bin/mbrola-linux-i386 ./cr1/cr1';
298
299 while ( defined ($_ = $term->readline($prompt)) ) {
300
301 $term->addhistory($_);
302
303 my ($out,$g,$f) = speak_hr( $_ );
304
305 open(my $fh, "| $mbrola - tmp.wav") || die "can't open $mbrola: $!";
306
307 print $OUT ">>> $g\n>>> $f\n$out\n";
308
309 print $fh $out || die "can't pipe to $mbrola";
310 close($fh) || die "error closing pipe to $mbrola";
311
312 system 'play tmp.wav';
313
314 }
315
316
317 __END__
318
319 foreach my $c (split(//, $text)) {
320 warn "# c = $c\n";
321
322 if (! defined($letters->{$c})) {
323 print "_ 50\n";
324 next;
325 }
326
327 my $slova = $letters->{$c}->[0];
328 my $param = $letters->{$c}->[1];
329 warn "# ",dump($slova, $param), $/;
330 foreach my $i ( 0 ... $#$slova ) {
331 print $slova->[$i], " ", join(" ",@{ $param->[$i] }), "\n";
332 }
333
334 }

Properties

Name Value
svn:executable

  ViewVC Help
Powered by ViewVC 1.1.26