-
Notifications
You must be signed in to change notification settings - Fork 60
/
Copy pathdocumentation301.html
2583 lines (2281 loc) · 132 KB
/
documentation301.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<HTML>
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
<META NAME="Generator" CONTENT="Microsoft Word 97">
<TITLE>MBROLA Speech Synth Documentation</TITLE>
</HEAD>
<BODY LINK="#0000ff">
<FONT SIZE=3><P ALIGN="JUSTIFY"></P>
</FONT><B><FONT FACE="Arial" SIZE=4><P> </P>
<P> </P>
<P> </P>
</B></FONT><FONT SIZE=4><P ALIGN="JUSTIFY"> </P><IMG SRC="Image1.gif" WIDTH=89 HEIGHT=144 ALIGN="LEFT" HSPACE=9>
</FONT><FONT SIZE=3><P ALIGN="JUSTIFY"> </P>
</FONT><FONT FACE="Arial" SIZE=5><P> </P><DIR>
<DIR>
</FONT><B><FONT FACE="Arial" SIZE=7><P>MBROLA </P>
</B></FONT><FONT FACE="Arial" SIZE=5><P>(<B>M</B>ulti<B>-B</B>and<B> R</B>esynthesis<B> O</B>ver<B>L</B>ap<B> A</B>dd)</P>
</FONT><FONT SIZE=3><P ALIGN="JUSTIFY"></P></DIR>
</DIR>
</FONT><B><FONT FACE="Arial" SIZE=4><P ALIGN="RIGHT">System documentation</P>
<P ALIGN="RIGHT">Edition 6.0 - Mbrola release 3.01g</P>
<P ALIGN="RIGHT">October 20<SUP>st</SUP>, 1998</P>
</FONT><FONT FACE="Arial" SIZE=7>
</B></FONT><FONT FACE="Arial" SIZE=3><P> </P>
<P> </P>
</FONT><FONT FACE="Arial" SIZE=5><P> </P>
<P> </P>
<P> </P>
<P> </P>
<P> </P><DIR>
<DIR>
<DIR>
<DIR>
<DIR>
</FONT><I><P ALIGN="JUSTIFY">"It would be a considerable invention indeed, that of a machine able to mimic speech, with its sounds and articulations. I think it is not impossible."</P>
</I><P ALIGN="JUSTIFY"></P></DIR>
</DIR>
</DIR>
</DIR>
<P ALIGN="JUSTIFY">								Leonhard Euler (1761)</P>
<FONT SIZE=3><P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY"> </P>
<P ALIGN="JUSTIFY"> </P>
<P ALIGN="JUSTIFY"> </P>
<P ALIGN="JUSTIFY"> </P>
<P ALIGN="JUSTIFY"> </P>
<P ALIGN="JUSTIFY"> </P>
<P ALIGN="JUSTIFY"> </P>
<P ALIGN="JUSTIFY"> </P>
<P ALIGN="JUSTIFY"> </P></DIR>
</FONT><B><FONT FACE="Arial" SIZE=4><P ALIGN="RIGHT">by Vincent Pagel and Thierry Dutoit</P>
</B></FONT><FONT FACE="Arial" SIZE=5><P> </P>
<B><P ALIGN="CENTER">MBROLA release 3.01g, table of Content</P>
</B></FONT><P ALIGN="JUSTIFY">1.	MBROLA Sources General condition of use	<A HREF="#_Toc431812918">*</A>
<P ALIGN="JUSTIFY">2.	A brief description of MBROLA	<A HREF="#_Toc431812919">*</A></P>
<P ALIGN="JUSTIFY">3.	Distribution	<A HREF="#_Toc431812920">*</A></P>
<P ALIGN="JUSTIFY">4.	Installation and Tests	<A HREF="#_Toc431812921">*</A></P><DIR>
<P ALIGN="JUSTIFY">4.1	On Unix	<A HREF="#_Toc431812922">*</A></P>
<P ALIGN="JUSTIFY">4.2	On PCs/Dos	<A HREF="#_Toc431812923">*</A></P>
<P ALIGN="JUSTIFY">4.3	On PC/Windows	<A HREF="#_Toc431812924">*</A></P>
<P ALIGN="JUSTIFY">4.3.1	Black magic	<A HREF="#_Toc431812925">*</A></P>
<P ALIGN="JUSTIFY">4.4	Using the standalone binary	<A HREF="#_Toc431812926">*</A></P>
<P ALIGN="JUSTIFY">4.4.1	Changing the pitch	<A HREF="#_Toc431812927">*</A></P>
<P ALIGN="JUSTIFY">4.4.2	Renaming and Cloning phonemes	<A HREF="#_Toc431812928">*</A></P>
<P ALIGN="JUSTIFY">4.5	Machine dependant hints for best using Mbrola	<A HREF="#_Toc431812929">*</A></P>
<P ALIGN="JUSTIFY">4.5.1	On MSDOS	<A HREF="#_Toc431812930">*</A></P>
<P ALIGN="JUSTIFY">4.5.2	On modern Unix systems such as Solaris or HPUX or Linux	<A HREF="#_Toc431812931">*</A></P>
<P ALIGN="JUSTIFY">4.5.3	On Sun4 ( old audio interface )	<A HREF="#_Toc431812932">*</A></P>
<P ALIGN="JUSTIFY">4.5.4	On VAX or AXP workstations	<A HREF="#_Toc431812933">*</A></P></DIR>
<P ALIGN="JUSTIFY">5.	Default Parser Manual	<A HREF="#_Toc431812934">*</A></P><DIR>
<P ALIGN="JUSTIFY">5.1	Input file format	<A HREF="#_Toc431812935">*</A></P>
<P ALIGN="JUSTIFY">5.1.1	Changing the Frequency Ratio or Time Ratio	<A HREF="#_Toc431812936">*</A></P>
<P ALIGN="JUSTIFY">5.1.2	Flush the output stream	<A HREF="#_Toc431812937">*</A></P>
<P ALIGN="JUSTIFY">5.2	Limitations of MBROLA	<A HREF="#_Toc431812938">*</A></P></DIR>
<P ALIGN="JUSTIFY">6.	Programmer's Manual	<A HREF="#_Toc431812939">*</A></P><DIR>
<P ALIGN="JUSTIFY">6.1	Philosophy and architecture	<A HREF="#_Toc431812940">*</A></P>
<P ALIGN="JUSTIFY">6.1.1	Encapsulation of Object's attributes	<A HREF="#_Toc431812941">*</A></P>
<P ALIGN="JUSTIFY">6.1.2	Inheritance and Polymorphism	<A HREF="#_Toc431812942">*</A></P>
<P ALIGN="JUSTIFY">Inheritance and cross-reference graph	<A HREF="#_Toc431812943">*</A></P>
<P ALIGN="JUSTIFY">6.2	Application Programming Interface	<A HREF="#_Toc431812944">*</A></P>
<P ALIGN="JUSTIFY">6.2.1	One channel mode	<A HREF="#_Toc431812945">*</A></P>
<P ALIGN="JUSTIFY">6.2.2	Multi channel mode	<A HREF="#_Toc431812946">*</A></P>
<P ALIGN="JUSTIFY">6.2.3	Designing and plugging your own parser	<A HREF="#_Toc431812947">*</A></P></DIR>
<P ALIGN="JUSTIFY">7.	Mbrola architecture	<A HREF="#_Toc431812948">*</A></P><DIR>
<P ALIGN="JUSTIFY">7.1	File: Misc/common.h	<A HREF="#_Toc431812949">*</A></P>
<P ALIGN="JUSTIFY">7.2	File: Misc/incdll.h	<A HREF="#_Toc431812950">*</A></P>
<P ALIGN="JUSTIFY">7.3	File: Misc/mbralloc.h	<A HREF="#_Toc431812951">*</A></P>
<P ALIGN="JUSTIFY">7.4	File: Misc/vp_error.h	<A HREF="#_Toc431812952">*</A></P>
<P ALIGN="JUSTIFY">7.5	File: Misc/audio.h	<A HREF="#_Toc431812953">*</A></P>
<P ALIGN="JUSTIFY">7.6	File: Database/database.h	<A HREF="#_Toc431812954">*</A></P>
<P ALIGN="JUSTIFY">7.7	File: Database/database_bacon.h	<A HREF="#_Toc431812955">*</A></P>
<P ALIGN="JUSTIFY">7.8	File: Database/database_old.h	<A HREF="#_Toc431812956">*</A></P>
<P ALIGN="JUSTIFY">7.9	File: Database/diphone_info.h	<A HREF="#_Toc431812957">*</A></P>
<P ALIGN="JUSTIFY">7.10	File: Database/hash_tab.h	<A HREF="#_Toc431812958">*</A></P>
<P ALIGN="JUSTIFY">7.11	File: Database/little_big.h	<A HREF="#_Toc431812959">*</A></P>
<P ALIGN="JUSTIFY">7.12	File: Database/rename_list.h	<A HREF="#_Toc431812960">*</A></P>
<P ALIGN="JUSTIFY">7.13	File: Engine/diphone.h	<A HREF="#_Toc431812961">*</A></P>
<P ALIGN="JUSTIFY">7.14	File: Engine/mbrola.h	<A HREF="#_Toc431812962">*</A></P>
<P ALIGN="JUSTIFY">7.15	File: Parser/fifo.h	<A HREF="#_Toc431812963">*</A></P>
<P ALIGN="JUSTIFY">7.16	File: Parser/input.h	<A HREF="#_Toc431812964">*</A></P>
<P ALIGN="JUSTIFY">7.17	File: Parser/input_fifo.h	<A HREF="#_Toc431812965">*</A></P>
<P ALIGN="JUSTIFY">7.18	File: Parser/input_file.h	<A HREF="#_Toc431812966">*</A></P>
<P ALIGN="JUSTIFY">7.19	File: Parser/parser.h	<A HREF="#_Toc431812967">*</A></P>
<P ALIGN="JUSTIFY">7.20	File: Parser/parser_input.h	<A HREF="#_Toc431812968">*</A></P>
<P ALIGN="JUSTIFY">7.21	File: Parser/phonbuff.h	<A HREF="#_Toc431812969">*</A></P>
<P ALIGN="JUSTIFY">7.22	File: Parser/phone.h	<A HREF="#_Toc431812970">*</A></P>
<P ALIGN="JUSTIFY">7.23	File: Standalone/synth.h	<A HREF="#_Toc431812971">*</A></P>
<P ALIGN="JUSTIFY">7.24	File: LibOneChannel/onechannel.h	<A HREF="#_Toc431812972">*</A></P>
<P ALIGN="JUSTIFY">7.25	File: LibMultiChannel/multichannel.h	<A HREF="#_Toc431812973">*</A></P>
<P ALIGN="JUSTIFY">7.26	Index of symbols	<A HREF="#_Toc431812974">*</A></P></DIR>
<P ALIGN="JUSTIFY">8.	Support	<A HREF="#_Toc431812975">*</A></P>
<P ALIGN="JUSTIFY"></P></P>
<OL>
<LI><A NAME="_Toc431812918"><B><FONT FACE="Arial" SIZE=5>MBROLA Sources General condition of use</A></LI>
</B></FONT><P ALIGN="JUSTIFY">The source code of MBROLA may only be used to produce the object code sold by your company. It is confidential and should remain safely locked, as well as its documentation.</P>
<LI><A NAME="_Toc431812919"><B><FONT FACE="Arial" SIZE=5>A brief description of MBROLA</A></LI></OL>
</B></FONT><P ALIGN="JUSTIFY">MBROLA v3.01 is a speech synthesizer based on the concatenation of diphones. One synthesis channel takes a list of phonemes as input, together with prosodic information (duration of phonemes and a piecewise linear description of pitch), and produces speech samples on 16 bits (linear), at the sampling frequency of the diphone database. It is therefore <B>not</B> a Text-To-Speech synthesizer, since it does not accept raw text as input. </P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">It is distributed as a ZIP file whose name respect the format <B><I>"mbrXXXX.zip"</B></I> where XXXX represent the version number (e.g. <B><I>"mbr3.01e.zip"</B></I>).</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">It may be compiled in 3 modes depending on which stream drives the process: </P>
<P ALIGN="JUSTIFY"></P>
<UL>
<P ALIGN="JUSTIFY"><LI>Driven by the input phonetic file: it is compiled as a standalone program named <I>"<B>synth</B>"</I> which outputs audio in a file or a pipe. This mode is a good choice under Unix platforms for end-user applications. In the following we call this mode <B><I>"standalone mode"</B></I>.</LI></P></UL>
<P ALIGN="JUSTIFY"></P>
<UL>
<P ALIGN="JUSTIFY"><LI>Driven by the audio output: compiled as a library, which outputs audio data into buffers of the size, requested by the main program. This allows you to easily include MBROLA inside your TTS application without temporary file mechanisms. In the following we call this mode <B><I>"library mode"</B></I>.</LI></P></UL>
<P ALIGN="JUSTIFY"></P>
<UL>
<P ALIGN="JUSTIFY"><LI>Same as above, included in a DLL for Windows95-98/NT (which is of course the preferred mode for Windows platforms). In the following we call this mode <B><I>"DLL mode"</B></I>.</LI></P></UL>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">While using <B><I>library</B></I> or <B><I>DLL</B></I> mode, we now differentiate <B>one channel</B> and <B>multi channel</B> mbrola. In the first mode, one <B><I>database</B></I> is associated to one and only one <B><I>synthesis</B> <B>channel</B></I>, which generally fits for end-user applications. In the second mode, one can run many <I>synthesis channel</I> instantiations with one or more <I>Database</I> instances and many <I>phonetic input streams</I>. This second solution is adapted to multi channel telecom TTS applications.</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">In all those compilation modes MBROLA requires a language/voice database to run properly. For your internal use (i.e. non-commercial) you can test the voices made available on the MBROLA project homepage:</P>
<B><I><P ALIGN="JUSTIFY"></P><DIR>
<DIR>
<P ALIGN="JUSTIFY"></B></I><A HREF="http://tcts.fpms.ac.be/synthesis"><B><I>http://tcts.fpms.ac.be/synthesis</B></I></A></P>
<B><I><P ALIGN="JUSTIFY"></P></DIR>
</DIR>
</B></I><P ALIGN="JUSTIFY">Refer to your contract to check your rights for commercial exploitation of the different Diphone Databases.</P>
<OL>
<LI><A NAME="_Toc431812920"><B><FONT FACE="Arial" SIZE=5>Distribution</A></LI>
</B></FONT><P ALIGN="JUSTIFY">Since release 3.01, Mbrola has been transformed into pure ANSI/C code, and object like programming with a strong encapsulation of data (strong because we have respected the fences we put!). One file in the distribution is generally equivalent to one object (pointer on <B><I>struct</B></I>). You can find an exhaustive description in the programmer's section 6.</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">This distribution of MBROLA contains the following files: </P>
<P ALIGN="JUSTIFY"></P>
<B><P ALIGN="JUSTIFY">Makefile:</B> Unix makefile for Gnu Make (gmake command)</P>
<B><P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">DOCUMENTATION/Programmer/documentation301e.doc:</B> this document</P>
<B><P ALIGN="JUSTIFY">DOCUMENTATION/Programmer/HISTORY.txt:</B> history of revisions</P>
<B><P ALIGN="JUSTIFY">DOCUMENTATION/User/readme.txt:</B> standalone version manual</P>
<B><P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">Database: </B>handling of different database formats </P>
<B><P ALIGN="JUSTIFY">Database/database.c</B>: functions to read diphones in the speech database</P>
<B><P ALIGN="JUSTIFY">Database/database.h</P>
<P ALIGN="JUSTIFY">Database/database_bacon.c<I>: </B></I>functions to read compressed diphone databases</P>
<B><P ALIGN="JUSTIFY">Database/database_bacon.h</P>
<P ALIGN="JUSTIFY">Database/database_old.c<I>: </B></I>functions to read diphone databases older than 2.06</P>
<B><P ALIGN="JUSTIFY">Database/database_old.h</P>
<P ALIGN="JUSTIFY">Database/diphone_info.c</B>: description of the diphone structures</P>
<B><P ALIGN="JUSTIFY">Database/diphone_info.h</P>
<P ALIGN="JUSTIFY">Database/hash_tab.c</B>: hash table of DiphoneInfo (access to the diphone database)</P>
<B><P ALIGN="JUSTIFY">Database/hash_tab.h</P>
<P ALIGN="JUSTIFY">Database/little_big.c:</B> handles the little and big endian numeric conversions</P>
<B><P ALIGN="JUSTIFY">Database/little_big.h</P>
<P ALIGN="JUSTIFY">Database/rename_list.c:</B> list of phoneme pairs (used for renaming and cloning)</P>
<B><P ALIGN="JUSTIFY">Database/rename_list.h</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">Parser:</B> functions to read phonemes in the input stream</P>
<B><P ALIGN="JUSTIFY">Parser/fifo.c:</B> First In First Out with chars</P>
<B><P ALIGN="JUSTIFY">Parser/fifo.h</P>
<P ALIGN="JUSTIFY">Parser/input.h:</B> define abstract input stream </P>
<B><P ALIGN="JUSTIFY">Parser/input_fifo.c:</B> instantiation of input.h with Fifo</P>
<B><P ALIGN="JUSTIFY">Parser/input_fifo.h</P>
<P ALIGN="JUSTIFY">Parser/input_file.c:</B> instantiation of input.h with File</P>
<B><P ALIGN="JUSTIFY">Parser/input_file.h</P>
<P ALIGN="JUSTIFY">Parser/parser.h:</B> define abstract phoneme parser</P>
<B><P ALIGN="JUSTIFY">Parser/parser_input.c:</B> instantiation of parser.h with Input</P>
<B><P ALIGN="JUSTIFY">Parser/parser_input.h</P>
<P ALIGN="JUSTIFY">Parser/phonbuff.c:</B> handle a phoneme buffer for pitch interpolation</P>
<B><P ALIGN="JUSTIFY">Parser/phonbuff.h</P>
<P ALIGN="JUSTIFY">Parser/phone.c:</B> phoneme type</P>
<B><P ALIGN="JUSTIFY">Parser/phone.h</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">Engine:</B> Mbrola synthesis engine</P>
<B><P ALIGN="JUSTIFY">Engine/diphone.c</B>: diphone with info for synthesis</P>
<B><P ALIGN="JUSTIFY">Engine/diphone.h</P>
<P ALIGN="JUSTIFY">Engine/mbrola.c</B>: mbrola algorithm (Ola, Smoothing...)</P>
<B><P ALIGN="JUSTIFY">Engine/mbrola.h</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">Misc:</B> Miscellaneous functions basically unrelated to synthesis </P>
<B><P ALIGN="JUSTIFY">Misc/audio.c</B>: audio output and audio file header (au, wav, aiff, raw)</P>
<B><P ALIGN="JUSTIFY">Misc/audio.h</P>
<P ALIGN="JUSTIFY">Misc/common.c</B>: useful little functions (uppercase, swab...)</P>
<B><P ALIGN="JUSTIFY">Misc/common.h</P>
<P ALIGN="JUSTIFY">Misc/g711.c:</B> G711 audio coding (ALAW and MULAW)</P>
<B><P ALIGN="JUSTIFY">Misc/g711.h</P>
<P ALIGN="JUSTIFY">Misc/incdll.h<I>:</B></I> external definitions used outside of the Mbrola package</P>
<B><P ALIGN="JUSTIFY">Misc/mbralloc.c:</B> memory allocators are here and ONLY here</P>
<B><P ALIGN="JUSTIFY">Misc/mbralloc.h</P>
<P ALIGN="JUSTIFY">Misc/vp_error.c:</B> deals with fatal error and warnings</P>
<B><P ALIGN="JUSTIFY">Misc/vp_error.h</B>: macros for debugging purposes</P>
<B><P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">Standalone:</B> Standalone compilation front-end</P>
<B><P ALIGN="JUSTIFY">Standalone/Posix</P>
<P ALIGN="JUSTIFY">Standalone/Posix/getopt.c</B>: provided for non-POSIX Unixes</P>
<B><P ALIGN="JUSTIFY">Standalone/Posix/getopt.h</P>
<P ALIGN="JUSTIFY">Standalone/synth.c</B>: front-end for the compilation in the <B><I>standalone mode</B></I>. Main()</P>
<B><P ALIGN="JUSTIFY">Standalone/synth.h</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">LibOneChannel</B>: library providing one MBROLA synthesis channel</P>
<B><P ALIGN="JUSTIFY">LibOneChannel/demo1.c</B>: small demonstration program running with the library<B> LibOneChannel/demo1b.c: </B>small demo showing error handling with the library</P>
<B><P ALIGN="JUSTIFY">LibOneChannel/onechannel.c</B>: library providing one mbrola channel at a time</P>
<B><P ALIGN="JUSTIFY">LibOneChannel/onechannel.h</P>
<P ALIGN="JUSTIFY">LibOneChannel/lib1.c</B>: wrapper file to build the library lib1.c (mono channel)</P>
<B><P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">LibMultiChannel:</B> library for multi MBROLA synthesis channel for telecom</P>
<B><P ALIGN="JUSTIFY">LibMultiChannel/multichannel.c</B>: many synthesis channel from one dba</P>
<B><P ALIGN="JUSTIFY">LibMultiChannel/multichannel.h</P>
<P ALIGN="JUSTIFY">LibMultiChannel/demo2.c:</B> demo using lib2</P>
<B><P ALIGN="JUSTIFY">LibMultiChannel/lib2.c:</B> wrapper file to build the library lib2.c (multi channel)</P>
<B><P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">VisualC++: </B>compilation projects for Microsoft Visual C++</P>
<B><P ALIGN="JUSTIFY">VisualC++/DLL: </B>Visual C++ project to build the DLL</P>
<B><P ALIGN="JUSTIFY">VisualC++/DLL_USE: </B>sample program using the DLL</P>
<B><P ALIGN="JUSTIFY">VisualC++/Standalone: </B>Visual C++ project to build a standalone binary</P>
<B><P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">Bin: </B>directory containing the output of the compilation with Make under Unix architectures.<B>	</P>
</B><LI><A NAME="_Toc431812921"><B><FONT FACE="Arial" SIZE=5>Installation and Tests</A></LI>
<OL>
<P ALIGN="JUSTIFY"><LI><A NAME="_Toc431812922"></FONT><FONT FACE="Arial" SIZE=4>On Unix</A></LI></P></OL>
</OL>
</B></FONT><P ALIGN="JUSTIFY">You must first unzip the distribution file <B><I>mbrXXXX.zip</B></I> where XXXX stand for the version number:</P><DIR>
<DIR>
<B><I><P ALIGN="JUSTIFY">unzip mbrXXXX.zip</P>
</B></I><P ALIGN="JUSTIFY"></P></DIR>
</DIR>
<P ALIGN="JUSTIFY">Mbrola can be compiled with the <B><I>'gmake'</B></I> (gnu make) command on the following platforms:</P><DIR>
<DIR>
<DIR>
<DIR>
<DIR>
<DIR>
<P ALIGN="JUSTIFY">SUN Sparc 5/S5R4 (Solaris2.4)</P>
<P ALIGN="JUSTIFY">HPUX9.0 and HPUX10.0 </P>
<P ALIGN="JUSTIFY">VAX/VMS V6.2 (V5.5-2 won't work)</P>
<P ALIGN="JUSTIFY">DECALPHA(AXP)/VMS 6.2</P>
<P ALIGN="JUSTIFY">AlphaStation 200 4/233</P>
<P ALIGN="JUSTIFY">AlphaStation 200 4/166</P>
<P ALIGN="JUSTIFY">IBM RS6000 Aix 4.12</P>
<P ALIGN="JUSTIFY">PC/LINUX 1.2.11</P>
<P ALIGN="JUSTIFY">PCPentium120/Solaris2.4</P>
<P ALIGN="JUSTIFY">OS/2</P>
<P ALIGN="JUSTIFY">BeBox</P>
<P ALIGN="JUSTIFY">QNX OS</P>
<P ALIGN="JUSTIFY"></P></DIR>
</DIR>
</DIR>
</DIR>
</DIR>
</DIR>
<P ALIGN="JUSTIFY">Though, as Mbrola is written in standard ANSI/C, we also support POSIX compliant UNIX Platforms. Please send acknowledgment when Mbrola works on a machine/system not listed here.</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">Before you compile anything you must define some symbols depending on the architecture you're working with:</P>
<P ALIGN="JUSTIFY"></P>
<UL>
<B><I><P ALIGN="JUSTIFY"><LI>LITTLE_ENDIAN</B></I> <FONT FACE="Symbol">®</FONT>
80x86 based platforms</LI></P>
<B><I><P ALIGN="JUSTIFY"><LI>BIG_ENDIAN</B></I> <FONT FACE="Symbol">®</FONT>
motorola or HP based platforms </LI></P>
<B><I><P ALIGN="JUSTIFY"><LI>VMS</I> <FONT FACE="Symbol">®</FONT>
</B> VAX/VMS stations</LI></P>
<B><I><P ALIGN="JUSTIFY"><LI>DOS</B></I> <FONT FACE="Symbol">®</FONT>
PC80x86 with Dos or Windows</LI></P>
<B><I><P ALIGN="JUSTIFY"><LI>SUN4</B></I> <FONT FACE="Symbol">®</FONT>
old Sun4 stations (not Posix compliant)</LI></P>
<B><I><P ALIGN="JUSTIFY"><LI>DEBUG <FONT FACE="Symbol">®</FONT>
</B></I> Huge debugging flag</LI></P>
<B><P ALIGN="JUSTIFY"><LI>DEBUG_HASH</B> <FONT FACE="Symbol">®</FONT>
Runs the database and print info about the hash table management (used to tune the memory management of the database)</LI></P></UL>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">According to the compilation mode you wish, you can comment or uncomment following lines of Makefile : </P>
<I><P ALIGN="JUSTIFY">#CFLAGS += -DDEBUG</P>
<P ALIGN="JUSTIFY">#CFLAGS += -DDEBUG_HASH</P>
<P ALIGN="JUSTIFY">#CFLAGS += -DLITTLE_ENDIAN</P>
<P ALIGN="JUSTIFY">CFLAGS += -DBIG_ENDIAN</P>
</I><P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">You can add any definitions to the <B><I>CFLAGS</B></I> (compilation flags) variable of the Makefile, as in the following example:</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">optimized compilation on a Sun Station :</P><DIR>
<DIR>
<B><I><P ALIGN="JUSTIFY">CFLAGS= -Wall -DBIG_ENDIAN -O6</P>
<P ALIGN="JUSTIFY"></P></DIR>
</DIR>
</B></I><P ALIGN="JUSTIFY">debug mode on a VAX/VMS :</P><DIR>
<DIR>
<B><I><P ALIGN="JUSTIFY">CFLAGS= -Wall -DLITTLE_ENDIAN -DVMS -g -DDEBUG</P>
<P ALIGN="JUSTIFY"></P></DIR>
</DIR>
</B></I><P ALIGN="JUSTIFY">By default the compiler is set with <B><I>CC = gcc</B></I> ; though on many platforms <B><I>cc</B></I> may also work. As the hardware manufacturer generally provides<B> cc,</B> it is preferred when possible since the object code performance can be higher by an order of magnitude.</P>
<P ALIGN="JUSTIFY"> </P>
<P ALIGN="JUSTIFY">You can type :</P>
<UL>
<B><I><P ALIGN="JUSTIFY"><LI>"make"</B></I> or <B><I>"make all"</B></I> to generate the <B><I>'synth'</I> </B>binary (<B><I>standalone mode</B></I>).</LI></P>
<B><I><P ALIGN="JUSTIFY"><LI>"make clean"</B></I> removes the entire object files and binaries.</LI></P>
<B><I><P ALIGN="JUSTIFY"><LI>"make lib1"</B></I> compiles lib1.c in the <B><I>library mode </B>(one channel synth)</LI></P>
<B><P ALIGN="JUSTIFY"><LI>"make demo1" </B>builds a demo exemplifying the use of lib1</LI></P>
<B><P ALIGN="JUSTIFY"><LI>"make lib2"</B></I> compiles lib1.c in the <B><I>library mode </B>(multi channel synth)</LI></P>
<B><P ALIGN="JUSTIFY"><LI>"make demo2" </B></I>builds a demo exemplifying the use of lib2</LI></P>
<B><I><P ALIGN="JUSTIFY"><LI>"make tags" </B></I>to build Emacs popular tags (helps finding your way through the code with ESC-. ). SUN Workshop uses an internal btags program for that purpose.</LI></P></UL>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">The intermediate object code goes into a <B>Bin</B> directory that is created on the occasion.</P>
<OL>
<OL>
<P ALIGN="JUSTIFY"><LI><A NAME="_Toc431812923"><B><FONT FACE="Arial" SIZE=4>On PCs/Dos</A></LI></P>
</B></FONT><P ALIGN="JUSTIFY">On PC/Dos platforms, use <B><I>"pkunzip synthXXXX.zip</B>"</I> to restore the files (don't forget to restore the embedded paths in the archive).</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">Mbrola can be compiled with <B><I>Microsoft Visual C++ </B></I>(4 .0 or higher), or <B><I>Borland C++</B></I> (4 .5 or higher), on the following platforms:</P>
<P ALIGN="JUSTIFY">PC486/DOS6 (but other PC/DOS should do, too)</P>
<P ALIGN="JUSTIFY">PC486/Windows 3.1</P>
<P ALIGN="JUSTIFY">PC486/Windows 95 </P>
<P ALIGN="JUSTIFY">PC-Pentium/Windows 98</P>
<P ALIGN="JUSTIFY">PC-Pentium/Windows NT</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">Always check that in your project the following preprocessor directives are defined: LITTLE_ENDIAN and DOS. A project to build such a release with Visual C++ is provided under VisualC++/Standalone.</P>
<P ALIGN="JUSTIFY"><LI><A NAME="_Toc431812924"><B><FONT FACE="Arial" SIZE=4>On PC/Windows</A></LI></P>
</B></FONT><P ALIGN="JUSTIFY">First proceed like for the PC/DOS platforms. Once <B><I>synthXXXX</B></I> is installed you can start building a DLL in the VisualC++\DLL directory. <B>MbrolaDll.dsw</B> is a Microsoft VisualC++ 5.0 project file to build a DLL. In any project you make to build a DLL with Mbrola don't forget to define the DLL, LITTLE_ENDIAN, DOS preprocessor definitions.</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">The Mbrola source files and a wrapper DLL interface is included in the project, it should compile smoothly. In case you have to build a new project from scratch remember that you should include only file from either <I>LibOneChannel/</I> or <I>LibMultiChannel</I>/. Never include files from <I>Standalone</I>/, as this directory is only relevant for a standalone mode (see section above for an exe binary).</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">Several compilation modes are available, the <B><I>"Win32 Bacon Static"</B></I> is a good one to start with (Bacon compression scheme is included, DLL are statically linked).</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">In the directory VisualC++/DLL_USE , little sample programs are given that use the Mbrola DLL.</P>
<OL>
<P ALIGN="JUSTIFY"><LI><A NAME="_Toc431812925"><B><FONT FACE="Arial">Black magic</A></LI></P></OL>
</B></FONT><P ALIGN="JUSTIFY">There is a strange bug in Visual C++, when you compile the project you sometime get:</P>
<P ALIGN="JUSTIFY"></P>
<B><I><P ALIGN="JUSTIFY">Linking...</P>
<P ALIGN="JUSTIFY">nafxcw.lib(dllmodul.cbj) : error LNK2005: _DllMain@12 already defined in LIBCMT.lib(dllmain.cbj)</P>
<P ALIGN="JUSTIFY">nafxcw.lib(afxmem.cbj) : error LNK2005: "void * __cdecl operator new(unsigned int)" (??2@YAPAXI@Z) already defined in LIBCMT.lib(new.cbj)</P>
<P ALIGN="JUSTIFY">nafxcw.lib(afxmem.cbj) : error LNK2005: "void __cdecl operator delete(void *)" (??3@YAXPAX@Z) already defined in LIBCMT.lib(delete.cbj)</P>
<P ALIGN="JUSTIFY">nafxcw.lib(dllmodul.cbj) : warning LNK4006: _DllMain@12 already defined in LIBCMT.lib(dllmain.cbj); second definition ignored</P>
<P ALIGN="JUSTIFY">nafxcw.lib(afxmem.cbj) : warning LNK4006: "void * __cdecl operator new(unsigned int)" (??2@YAPAXI@Z) already defined in LIBCMT.lib(new.cbj); second definition ignored</P>
<P ALIGN="JUSTIFY">nafxcw.lib(afxmem.cbj) : warning LNK4006: "void __cdecl operator delete(void *)" (??3@YAXPAX@Z) already defined in LIBCMT.lib(delete.cbj); second definition ignored</P>
<P ALIGN="JUSTIFY"> Creating library MbrolaDl/Mbrola.lib and object MbrolaDl/Mbrola.exp</P>
<P ALIGN="JUSTIFY">Output\Release_Static\Mbrola.dll : fatal error LNK1169: one or more multiply defined symbols found</P>
<P ALIGN="JUSTIFY">Error executing link.exe.</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">Mbrola.dll - 4 error(s), 7 warning(s)</P>
</B></I><P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">Solution: remove one file from the project and include it again in the list of source files, and build the project again. The problem vanishes.</P>
<P ALIGN="JUSTIFY"><LI><A NAME="_Toc431812926"><B><FONT FACE="Arial" SIZE=4>Using the standalone binary</A></LI></P>
</B></FONT><P ALIGN="JUSTIFY">You are now ready to test the program. First try: <B><I>"synth"</B></I> to get an information screen about the copyright. Then, for a help screen on how to use the standalone version of the software, try :</P>
<B><I><P ALIGN="JUSTIFY">synth -h </P>
<P ALIGN="JUSTIFY"></P>
</B></I><P ALIGN="JUSTIFY">You get a help screen like the following:</P>
<B><I><P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">> USAGE: ./synth [COMMAND LINE OPTIONS] database pho_file+ output_file</P>
<P ALIGN="JUSTIFY">></P>
<P ALIGN="JUSTIFY">>A - instead of pho_file or output_file means stdin or stdout</P>
<P ALIGN="JUSTIFY">>Extension of output_file ( raw, au, wav, aiff ) tells the wanted audio format</P>
<P ALIGN="JUSTIFY">></P>
<P ALIGN="JUSTIFY">> Options can be any of the following:</P>
<P ALIGN="JUSTIFY">> -i = display the database information if any</P>
<P ALIGN="JUSTIFY">> -e = IGNORE fatal errors on unknown diphone</P>
<P ALIGN="JUSTIFY">> -c CC = set COMMENT char (escape sequence in pho files)</P>
<P ALIGN="JUSTIFY">> -F FC = set FLUSH command name</P>
<P ALIGN="JUSTIFY">> -v VR = VOLUME ratio, float ratio applied to ouput samples</P>
<P ALIGN="JUSTIFY">> -f FR = FREQ ratio, float ratio applied to pitch points</P>
<P ALIGN="JUSTIFY">> -t TR = TIME ratio, float ratio applied to phone durations</P>
<P ALIGN="JUSTIFY">> -l VF = VOICE freq, target freq for voice quality</P>
<P ALIGN="JUSTIFY">> -R RL = Phoneme RENAME list of the form a A b B ...</P>
<P ALIGN="JUSTIFY">> -C CL = Phoneme CLONE list of the form a A b B ...</P>
<P ALIGN="JUSTIFY">> </P>
<P ALIGN="JUSTIFY">> -I IF = Initialization file containing one command per line</P>
<P ALIGN="JUSTIFY">> CLONE, RENAME, VOICE, TIME, FREQ, VOLUME, FLUSH, </P>
<P ALIGN="JUSTIFY">> COMMENT, and IGNORE are available</P>
<P ALIGN="JUSTIFY"></P>
</B></I><P ALIGN="JUSTIFY">Now in order to go further, you need to get a version of an MBROLA language/voice database from the MBROLA project homepage. Let us assume you have copied the FR1 database and referred to the accompanying fr1.txt file for its installation.</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">Then try: </P>
<B><I><P ALIGN="JUSTIFY">synth fr1/fr1 fr1/TEST/bonjour.pho bonjour.wav</P>
</B></I><P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">it uses the format:</P>
<P ALIGN="JUSTIFY"></P>
<B><I><P ALIGN="JUSTIFY">synth diphone_database command_file1 command_file2 ... output_file</P>
</B></I><P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">and creates a sound file for the word 'bonjour' (Hello! in French)</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">Basically the output file is composed of signed integer numbers on 16 bits, corresponding to samples at the sampling frequency of the MBROLA voice/language database (16 kHz for the diphone database supplied by the authors of MBROLA : Fr1). MBROLA can produce different audio file formats: <B>.au</B>, <B>.wav</B>, <B>.aiff</B>, <B>.aif</B>, and <B>.raw</B> files depending on the ouput_file extension. If the extension is not recognized, the format is RAW (no header). We recommend .wav for Windows, and .au for Unix platforms.</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">To display information about the phoneme set used by the database, type:</P>
<B><I><P ALIGN="JUSTIFY">		 synth -i fr1/fr1</P>
</B></I><P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">It displays the phonetic alphabet as well as copyright information about the database.</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">Option <B><I>-e</B></I> makes Mbrola ignore wrong or missing diphone sequences (replaced by silence) which can be quite useful when debugging your TTS. Equivalent to "IGNORE" directive in the initialization file (N.B replace the obsolete ;;E=OFF , unsupported in .pho file).</P>
<P ALIGN="JUSTIFY"> </P>
<OL>
<P ALIGN="JUSTIFY"><LI><A NAME="_Toc431812927"><B><FONT FACE="Arial">Changing the pitch</A></LI></P>
</B></FONT><P ALIGN="JUSTIFY">Optional parameters let you shorten or lengthen synthetic speech and transpose it by providing optional time and frequency ratios:</P>
<P ALIGN="JUSTIFY"></P>
<B><I><P ALIGN="JUSTIFY">synth -t 1.2 -f 0.8 -v 0.7 fr1/fr1 TEST/bonjour.pho bonjour.wav</P>
</B></I><P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">or its equivalent in the initialization file:</P>
<P ALIGN="JUSTIFY"></P>
<B><I><P ALIGN="JUSTIFY">TIME 1.2</P>
<P ALIGN="JUSTIFY">FREQ 0.8</P>
</B></I><P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">for instance, will result in a RIFF Wav file bonjour.wav 1.2 times longer than the previous one (slower rate), and containing speech in which all fundamental frequency values have been multiplied by 0.8 (sounds lower). You can also set the values of these coefficients directly in a .pho file by adding special escape sequence like :</P>
<P ALIGN="JUSTIFY"></P>
<B><I><P ALIGN="JUSTIFY">;; F=0.8</P>
<P ALIGN="JUSTIFY">;; T=1.2</P>
</B></I><P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">You can change the voice characteristics with the -l parameter. If the sampling rate of your database is 16000, indicating <B><I>-l 18000</B></I> allows you to shorten the vocal tract by a ratio 16/18 (children voice, or women voice depending on the voice you're working on). With <B><I>-l 10000</B></I>,you can lengthen the vocal tract by a ratio 18/10 (namely the voice of a Troll). The same command in an initialization file becomes "VOICE 10000".</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">Option "<B><I>-v</B></I>" gives a VolumeRatio that multiplies each output sample. In the example below, each sample is multiplied by 0.7 (the loudness goes down). Warning: setting VolumeRatio too high generates saturation.</P>
<P ALIGN="JUSTIFY"></P>
<B><P ALIGN="JUSTIFY">synth -v 0.7 fr1/fr1 TEST/bonjour.pho bonjour.wav</P>
</B><P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">or add the line "<B>VOLUME 0.7</B>" in an initialization file</P>
<B><P ALIGN="JUSTIFY"></P>
</B><P ALIGN="JUSTIFY">The -c option lets you specify which symbol will be used as an escape sequence for comments and commands in .pho files. The default value is the semi-colon ';', but you may want to change this if your phonetic alphabet use this symbol, like in:</P>
<P ALIGN="JUSTIFY"></P>
<B><I><P ALIGN="JUSTIFY">synth -c ! fr1/fr1 TEST/test1.pho test2.pho test.wav</P>
</B></I><P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">equivalent to "<B>COMMENT !</B>" in an initialization file</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">The -F option lets you specify which symbol will be used to Flush the audio output. The default value is #, you may want to change the symbol like in:</P>
<P ALIGN="JUSTIFY"></P>
<B><I><P ALIGN="JUSTIFY">mbrola -F FLUSH_COMMAND fr1/fr1 test.pho test.wav</P>
</B></I><P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">equivalent to "<B>FLUSH FLUSH_COMMAND</B>" in the initialization file.</P>
<B><FONT FACE="Arial"><P ALIGN="JUSTIFY"><LI>Using Pipes</LI></P>
</B></FONT><P ALIGN="JUSTIFY">A - instead of command_file or output_file means stdin or stdout. On multitasking machines, it is easy to run the synthesizer in real time to obtain audio output from the audio device, by using pipes.</P>
<P ALIGN="JUSTIFY"><LI><A NAME="_Toc431812928"><B><FONT FACE="Arial">Renaming and Cloning phonemes</A></LI></P></OL>
</B></FONT><P ALIGN="JUSTIFY">It may happen that the language-processing module connected to MBROLA doesn't use the same phonemic alphabet as the voice used. The Renaming and Cloning mechanisms help you to quickly solve such problems (without adding extra CPU load). The only limitation about phoneme names is that they can't contain blank characters.</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">If, for instance, phoneme <B>a </B>in the mbrola voice you use is called <B>my_a </B>in your alphabet, and phoneme <B>b</B> is called <B>my_b</B>, then the following command solves the problem:</P>
<P ALIGN="JUSTIFY"></P>
<B><I><P ALIGN="JUSTIFY">synth -R "a my_a b my_b" fr1/fr1 test.pho test.wav</P>
</B></I><P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">You can give as many renaming pairs as you want. Circular definition is not a problem. E.g. <B>"a b b c"</B> will rename original [<B>a]</B> into [<B>b</B>] and original [<B>b]</B> into [<B>c]</B> independently ([<B>a]</B> won't be renamed to [<B>c]</B>).</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">LIMITATION: you can't rename a phoneme into another that already exists.</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">The cloning mechanism does exactly the same thing, though the old phoneme still exists after renaming. This is useful if you have 2 allophones in your alphabet, but the Mbrola voice only provides one.</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">Imagine for instance, that you make the distinction between the voiced [r] and its unvoiced counterpart [r0] and that you are using a syllabic version [r=]. If as a first approximation using [r] for both is OK, then you may use an Mbrola voice that only provides one version of [r] by running:</P>
<P ALIGN="JUSTIFY"></P>
<B><I><P ALIGN="JUSTIFY">synth -C "r r0 r r=" fr1/fr1 test.pho test.wav</P>
</B></I><P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">which tells the synthesizer that [r0] and [r=] should be both synthesized as [r]. You can write a long cloning list of phoneme pairs to fit your needs. </P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">Renaming and cloning eats CPU since the complete diphone hash table has to be rebuilt, but once the renaming or cloning has occurred there is absolutely NO RELATED PERFORMANCE DROP. So using this feature is more efficient than a pre-processor is, though a simple phoneme mapping cannot always solve incompatibilities.</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">Before renaming anything as #<B>,</B> check section 5.1.2</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">When one has long cloning and renaming lists, you can conveniently write them into an initialization file according to the following format:</P>
<P ALIGN="JUSTIFY"></P>
<B><I><P ALIGN="JUSTIFY">RENAME a my_a</P>
<P ALIGN="JUSTIFY">RENAME b my_b</P>
<P ALIGN="JUSTIFY">CLONE r r0</P>
<P ALIGN="JUSTIFY">CLONE r r=</P>
</B></I><P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">The obsolete ";; RENAME a my_a" can't be used in .pho file anymore, but is correctly parsed in initialization files. Note to EN1 and MRPA users: the consequence of the change above is that you must change the previous call format "mbrola en1 en1mrpa..." into "mbrola -I en1mrpa en1 ...".</P>
<P ALIGN="JUSTIFY"> </P>
<P ALIGN="JUSTIFY"><LI><A NAME="_Toc431812929"><B><FONT FACE="Arial" SIZE=4>Machine dependant hints for best using Mbrola</A></LI></P>
<OL>
<P ALIGN="JUSTIFY"><LI><A NAME="_Toc431812930"></FONT><FONT FACE="Arial">On MSDOS</A></LI></P>
</B></FONT><P ALIGN="JUSTIFY">With the standalone version, generating wav files is easier:</P>
<B><I><P ALIGN="JUSTIFY">synth fr1/fr1 TEST/bonjour.pho bonjour.wav</P>
</B></I><P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">Then you can play the RIFF Wav file with your favorite DOS or Windows sound utility. On OS/2 pipes may be used just like below.</P>
<P ALIGN="JUSTIFY"><LI><A NAME="_Toc431812931"><B><FONT FACE="Arial">On modern Unix systems such as Solaris or HPUX or Linux</A></LI></P>
</B></FONT><P ALIGN="JUSTIFY">Type:</P>
<B><I><P ALIGN="JUSTIFY">synth fr1 bonjour.pho -.au | audioplay</P>
</B></I><P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">where audioplay is your audio file player (* the name vary with the platform, e.g. splayer for HPUX *).</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">If your audioplayer has problems with sun .AU files, try with .wav or .raw. Never use .wav format when you pipe the output (mbrola can't rewind the file to write the audio size in the header). Wav format was not developed for Unix (on the contrary Au format let you specify in the header "we're on a pipe, read until end of file"). </P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">NOTE FOR LINUX: you can use the GPL rawplay program provided at</P>
<P ALIGN="JUSTIFY"> ftp://tcts.fpms.ac.be/pub/mbrola/pclinux/</P>
<P ALIGN="JUSTIFY"> </P>
<P ALIGN="JUSTIFY"><LI><A NAME="_Toc431812932"><B><FONT FACE="Arial">On Sun4 ( old audio interface )</A></LI></P>
</B></FONT><P ALIGN="JUSTIFY">Those machines are now quite old and only provide a mulaw 8Khz output. A hack is:</P>
<B><I><P ALIGN="JUSTIFY">synth fr1 input.pho - | sox -t raw -sw -r 16000 - -t raw -Ub -r 8000 - > /dev/audio</P>
</B></I><P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">Provided you have the public domain sox utility developed by Ircam, you should hear 'bonjour' without the need to create intermediate files. Note that we strongly recommend that you DON'T use SOX, since its resampling method (linear interpolation) will permanently damage the sound.</P>
<P ALIGN="JUSTIFY"> </P>
<P ALIGN="JUSTIFY">Other solution: The UTILITY.ZIP file available from the MBROLA homepage provides RAW2SUN that does this conversion.</P>
<P ALIGN="JUSTIFY"><LI><A NAME="_Toc431812933"><B><FONT FACE="Arial">On VAX or AXP workstations</A></LI></P></OL>
</OL>
</OL>
</B></FONT><P ALIGN="JUSTIFY">To make it easier for users to find MBROLA, you should add the following command to your system startup procedure: </P>
<P ALIGN="JUSTIFY"></P><DIR>
<DIR>
<B><I><P ALIGN="JUSTIFY"> $ DEFINE/SYSTEM/EXEC MBROLA_DIR disk:[dir]</P>
</B></I><P ALIGN="JUSTIFY"></P></DIR>
</DIR>
<P ALIGN="JUSTIFY">where "disk:[dir]" is the name of the directory you created for the MBROLA_DIR files. You could also add the following command to your system login command procedure: </P>
<P ALIGN="JUSTIFY"></P><DIR>
<DIR>
<B><I><P ALIGN="JUSTIFY">$ MBROLA :== $MBROLA_DIR:MBROLA.EXE</P>
<P ALIGN="JUSTIFY">$ RAW2SUN :== $MBROLA_DIR:RAW2SUN.EXE</P>
</B></I><P ALIGN="JUSTIFY"></P></DIR>
</DIR>
<P ALIGN="JUSTIFY">to use the decsound device:</P>
<P ALIGN="JUSTIFY"></P><DIR>
<DIR>
<B><I><P ALIGN="JUSTIFY">$ MCR DECSOUND - volume 40 -play sound.au </P>
</B></I><P ALIGN="JUSTIFY"></P></DIR>
</DIR>
<P ALIGN="JUSTIFY">See also the MBR_OLA.COM batch file in the UTILITY.ZIP file available from the MBROLA Homepage if you cannot play 16 bits sound files on your machine. </P>
<OL>
<LI><A NAME="_Toc431812934"><B><FONT FACE="Arial" SIZE=5>Default Parser Manual</A></LI>
</B></FONT><P ALIGN="JUSTIFY">The default parser is the parser that was provided before release 3.01. Implicitly it means that you can replace it with your own one, thanks to the setParser_MBR function. Basically the work of the parser is to return to Mbrola a phoneme with a length, and its pitch points.</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">We provide a default parser that allows you to give optional pitch points, the intonation curve being linearly interpolated between those points.</P>
<OL>
<P ALIGN="JUSTIFY"><LI><A NAME="_Toc431812935"><B><FONT FACE="Arial" SIZE=4>Input file format</A></LI></P>
</B></FONT><P ALIGN="JUSTIFY">Example of a command line :</P>
<B><I><P ALIGN="JUSTIFY">synth fr1/fr1 bonjour.pho bonjour.wav </P>
</B></I><P ALIGN="JUSTIFY">For example the phonetic input file bonjour.pho simply contains : </P>
<P ALIGN="JUSTIFY"></P>
<B><I><FONT SIZE=2><P ALIGN="JUSTIFY">; Bonjour</P>
<P ALIGN="JUSTIFY">_ 51 25 114</P>
<P ALIGN="JUSTIFY">b 62 </P>
<P ALIGN="JUSTIFY">o~ 127 48 170.42 </P>
<P ALIGN="JUSTIFY">Z 110 53.5 116 </P>
<P ALIGN="JUSTIFY">u 211 </P>
<P ALIGN="JUSTIFY">R 150 50 91 </P>
<P ALIGN="JUSTIFY">_ 91</P>
</B></I></FONT><P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">This shows the format of the input data required by MBROLA. Each line contains a phoneme name, a duration (in ms), and a series (possibly none) of pitch pattern points composed of two float numbers each: the position of the pitch pattern point within the phoneme (in % of its total duration), and the pitch value (in Hz) at this position.</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">Hence, the second line of bonjour.pho : </P>
<B><I><P ALIGN="JUSTIFY"> _ 51 25 114 </P>
</B></I><P ALIGN="JUSTIFY">tells the synthesizer to produce a silence of <B><I>51</B></I> <B><I>ms</B></I>, and to put a pitch pattern point of <B><I>114</B></I> <B><I>Hz</B></I> at <B><I>25%</B></I> of <B><I>51 ms</B></I>. Pitch pattern points define a piecewise linear pitch curve. Notice that the pitch pattern they define is continuous, since the program automatically drops pitch information when synthesizing unvoiced phones.</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">Blank characters or tabs separate the data on each line. Comments can optionally be introduced in command files, starting with a semi-colon ';'. This default can be overrun with the -c option of the command line.</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">Another special escape sequence ';;' allow the user to introduce commands in the middle of .pho files as described below. This escape sequence is also affected by the -c option.</P>
<OL>
<P ALIGN="JUSTIFY"><LI><A NAME="_Toc431812936"><B><FONT FACE="Arial">Changing the Frequency Ratio or Time Ratio</A></LI></P>
</B></FONT><P ALIGN="JUSTIFY">A command escape sequence containing a line like "T=x.x" modifies the time ratio to x.x, the same result is obtained on the fundamental frequency by replacing T with F, like in:</P>
<B><I><P ALIGN="JUSTIFY">;; T = 1.2</P>
<P ALIGN="JUSTIFY">;;F=0.8</P>
<P ALIGN="JUSTIFY"><LI><A NAME="_Ref431120090"><A NAME="_Toc431812937"></I><FONT FACE="Arial">Flush the output stream</A></A></LI></P></OL>
</B></FONT><P ALIGN="JUSTIFY">Note, finally, that the synthesizer outputs chunks of synthetic speech determined as sections of the piecewise linear pitch curve. Phones inside a section of this curve are synthesized in one go. The last one of each chunk, however, cannot be properly synthesized while the next phone is not known (since the program uses diphones as base speech units). When using mbrola with pipes, this may be a problem. Imagine, for instance, that mbrola is used to create a pipe-based speaking clock on a HP:</P>
<B><I><P ALIGN="JUSTIFY">speaking_clock | mbrola fr1 - -.au | splayer</P>
</B></I><P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">which tells the time, say, every 30 seconds. The last phone of each time announcement will only be synthesized when the next announcement starts. To bypass this problem, mbrola accepts a special command phone, which flushes the synthesis buffer : "#"</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">This default character can be replaced by another symbol thanks to the command:</P>
<B><I><P ALIGN="JUSTIFY">;; FLUSH new_flush_symbol</P>
</B></I><P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">Another important issue with piping under UNIX, is the possibility to prematurely end the audio output, if for example the user presses the stop button of your application. Since release 3.01, Mbrola handles signals.</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">If in the previous example the user wants to interrupt the speaking clock message, the application just needs to send the USR1 signal. You can send such a signal from the console with:</P>
<P ALIGN="JUSTIFY"></P>
<B><I><P ALIGN="JUSTIFY">kill -16 mbrola_process_number</P>
</B></I><P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">Once mbrola catches the signal, it reads its input stream until it gets EOF or a FLUSH command (hence, surrounding sections with flush is a good habit).</P>
<P ALIGN="JUSTIFY"><LI><A NAME="_Toc431812938"><B><FONT FACE="Arial" SIZE=4>Limitations of MBROLA</A></LI></P></OL>
</B></FONT><P ALIGN="JUSTIFY">There is no more limitation on the number of pitch points one can assign to a phoneme, or on the number of phonemes without pitch points. There is no more limitation on extra low pitch (sometime used to produce vocal fry).</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">Phonemes can be synthesized with a maximum duration that depends on the fundamental frequency with which they are produced. The higher the frequency, the lower the duration. For a frequency of 133 Hz, the maximum duration is 7.5 sec. For a frequency of 66.5 Hz, is 5 sec. For a frequency of 266 Hz, is 3.75 sec.</P>
<B><FONT FACE="Arial" SIZE=5><LI></LI>
<LI><A NAME="_Ref431120310"><A NAME="_Toc431812939">Programmer's Manual</A></A></LI>
</B></FONT><P ALIGN="JUSTIFY">First, we describe in this section the object oriented philosophy used since release 3.01.</P>
<P ALIGN="JUSTIFY"> </P>
<OL>
<P ALIGN="JUSTIFY"><LI><A NAME="_Toc431812940"><B><FONT FACE="Arial" SIZE=4>Philosophy and architecture</A></LI></P></OL>
</OL>
</B></FONT><P ALIGN="JUSTIFY">Actually nothing (or nearly nothing) prevents us to program in standard C/ANSI with an object like convention which authorize: </P>
<UL>
<P ALIGN="JUSTIFY"><LI>"weak" encapsulation</LI></P>
<P ALIGN="JUSTIFY"><LI>Inheritance</LI></P></UL>
<UL>
<P ALIGN="JUSTIFY"><LI>Polymorphism</LI></P></UL>
<P ALIGN="JUSTIFY"> </P>
<OL>
<OL>
<OL>
<P ALIGN="JUSTIFY"><LI><A NAME="_Toc431812941"><B><FONT FACE="Arial">Encapsulation of Object's attributes</A></LI></P>
</B></FONT><P ALIGN="JUSTIFY">Let's exemplify the programming conventions with the char Fifo found in Parser/fifo.h. First we define a structure describing a Fifo.</P>
<P ALIGN="JUSTIFY"></P>
<B><I><P ALIGN="JUSTIFY">typedef struct </P>
<P ALIGN="JUSTIFY">{</P>
<P ALIGN="JUSTIFY"> char* charbuff;		 /* circular buffer for phonetic input */</P>
<P ALIGN="JUSTIFY"> int buffer_pos;			 /* Current position */</P>
<P ALIGN="JUSTIFY"> int buffer_end;			 /* Last available phoneme */</P>
<P ALIGN="JUSTIFY"> int buffer_size;		 /* number of chars in Phobuffer */</P>
<P ALIGN="JUSTIFY">} Fifo;</P>
</B></I><P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">To make distinction between public and private data, the convention is to never directly access the features of a Fifo out of its fifo.c implementation file. To reach this goal we exclusively access members through function-like macros.</P>
<P ALIGN="JUSTIFY"></P>
<B><I><P ALIGN="JUSTIFY">#define charbuff(ff) ff->charbuff</P>
<P ALIGN="JUSTIFY">#define buffer_pos(ff) ff->buffer_pos</P>
<P ALIGN="JUSTIFY">#define buffer_end(ff) ff->buffer_end</P>
<P ALIGN="JUSTIFY">#define buffer_size(ff) ff->buffer_size</P>
</B></I><P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">It allows the following: </P>
<P ALIGN="JUSTIFY"></P>
<B><I><P ALIGN="JUSTIFY">Fifo* my_fifo; </P>
<P ALIGN="JUSTIFY">�..</P>
<P ALIGN="JUSTIFY">int length= buffer_size(my_fifo);</P>
</B></I><P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">The programmer should not cheat to discover whether buffer_size is a function or a macro, thus encapsulating the data and making them independent of the Fifo's real implementation (modulo a complete recompiling). C is not C++ and your compiler won't be able to carry out strong type checking just as with inline functions, that's the reason why attributes don't respect the full convention below (according to our conventions we should have use the name buffer_size_Fifo() ).</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">The methods always respect the format: functionname_ObjectName just like below and take a pointer on the object as a first argument. Methods beginning with <B>init</B> are always constructor, and those beginning with <B>close</B> are destructors:</P>
<P ALIGN="JUSTIFY"></P>
<B><I><P ALIGN="JUSTIFY">Fifo* init_Fifo(int size);</P>
<P ALIGN="JUSTIFY">/*</P>
<P ALIGN="JUSTIFY"> * Constructor with size of the buffer</P>
<P ALIGN="JUSTIFY"> */</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">void close_Fifo(Fifo* ff); </P>
<P ALIGN="JUSTIFY">/*</P>
<P ALIGN="JUSTIFY"> * Release the memory</P>
<P ALIGN="JUSTIFY"> */</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">void reset_Fifo(Fifo* ff);</P>
<P ALIGN="JUSTIFY">/*</P>
<P ALIGN="JUSTIFY"> * Forget previously entered data in the circular buffer</P>
<P ALIGN="JUSTIFY"> */</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">int write_Fifo(Fifo* ff, char *buffer_in);</P>
<P ALIGN="JUSTIFY">/*</P>
<P ALIGN="JUSTIFY"> * Write a string of phoneme in the input buffer</P>
<P ALIGN="JUSTIFY"> * Return the number of chars actually written</P>
<P ALIGN="JUSTIFY"> */</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">int readline_Fifo(Fifo* ff, char *line, int size);</P>
<P ALIGN="JUSTIFY">/* </P>
<P ALIGN="JUSTIFY"> * Read a line from the input stream in a circular buffer</P>
<P ALIGN="JUSTIFY"> * Return 0 if there's nothing to read</P>
<P ALIGN="JUSTIFY"> */</P>
<P ALIGN="JUSTIFY"><LI><A NAME="_Toc431812942"></I><FONT FACE="Arial">Inheritance and Polymorphism</A></LI></P>
</B></FONT><P ALIGN="JUSTIFY">Inheritance alone can always be simulated through the <B>is_a_client_of</B> relation, the most interesting case being polymorphism. Polymorphism is interesting for multiple format database handling, and live input parser definition inside of the synthesizer.</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">The abstract type below specifies an <B>Input</B> object providing the methods <B><I>close</B></I>, <B><I>reset</B></I> and <B><I>readline</B></I> .</P>
<P ALIGN="JUSTIFY"></P>
<B><I><P ALIGN="JUSTIFY">typedef struct Input Input;</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">typedef int (*readline_InputFunction)(Input* in, char *line, int size);</P>
<P ALIGN="JUSTIFY">typedef void (*close_InputFunction)(Input* in);</P>
<P ALIGN="JUSTIFY">typedef void (*reset_InputFunction)(Input* in);</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">struct Input</P>
<P ALIGN="JUSTIFY">{</P>
<P ALIGN="JUSTIFY"> void* self;</P>
<P ALIGN="JUSTIFY"> readline_InputFunction readline_Input;</P>
<P ALIGN="JUSTIFY"> close_InputFunction close_Input;</P>
<P ALIGN="JUSTIFY"> close_InputFunction reset_Input;</P>
<P ALIGN="JUSTIFY">};</P>
</B></I><P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">This type can be derived into <B>Input_File</B> (the input stream is a file) or <B>Input_Fifo</B> (the input stream comes from a Fifo as described above). The part of the object corresponding to the features overloaded on the basic <B>Input</B> type is stored in the <B>self</B> part.</P>
<P ALIGN="JUSTIFY"></P>
<B><I><P ALIGN="JUSTIFY">#include "input.h"</P>
<P ALIGN="JUSTIFY">#include "fifo.h"</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">static int readline_InputFifo(Input* in, char *line, int size)</P>
<P ALIGN="JUSTIFY">{ return( readline_Fifo((Fifo*) in->self,line,size) ); }</P>
<P ALIGN="JUSTIFY"> </P>
<P ALIGN="JUSTIFY">static void reset_InputFifo(Input* in)</P>
<P ALIGN="JUSTIFY">{ reset_Fifo((Fifo*) in->self); }</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">static void close_InputFifo(Input* in)</P>
<P ALIGN="JUSTIFY">{ MBR_free(in); }</P>
<P ALIGN="JUSTIFY"> </P>
<P ALIGN="JUSTIFY">Input* init_InputFifo(Fifo* my_fifo)</P>
<P ALIGN="JUSTIFY">{</P>
<P ALIGN="JUSTIFY"> Input* self= (Input*) MBR_malloc( sizeof(Input) );</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY"> self->self= (void*) my_fifo;</P>
<P ALIGN="JUSTIFY"> self->readline_Input= readline_InputFifo;</P>
<P ALIGN="JUSTIFY"> self->close_Input= close_InputFifo;</P>
<P ALIGN="JUSTIFY"> self->reset_Input= reset_InputFifo;</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY"> return self;</P>
<P ALIGN="JUSTIFY">}</P>
</I><P ALIGN="JUSTIFY"> </P>
<FONT FACE="Arial"><P ALIGN="JUSTIFY"><LI></LI></P>
<P ALIGN="JUSTIFY"><LI><A NAME="_Toc431812943">Inheritance and cross-reference graph</A></LI></P></OL>
</OL>
</OL>
</B></FONT><P ALIGN="JUSTIFY">The <B><I>Database</B></I>, <B><I>Input</B></I> and <B><I>Parser</B></I> objects contain deferred (=virtual) methods and thus allow polymorphism.</P>
<P ALIGN="JUSTIFY"> </P>
<OL>
<OL>
<P ALIGN="JUSTIFY"><LI><A NAME="_Toc431812944"><B><FONT FACE="Arial" SIZE=4>Application Programming Interface</A></LI></P>
</B></FONT><P ALIGN="JUSTIFY">The explanations given in the previous section are particularly useful to the user who wants to design ad-hoc parsers. Though one can keep on working with the default parser.</P>
<OL>
<P ALIGN="JUSTIFY"><LI><A NAME="_Toc431812945"><B><FONT FACE="Arial">One channel mode</A></LI></P>
</B></FONT><P ALIGN="JUSTIFY">You can build a demo by running <B><I>"make demo1"</B></I> under Unix, or simply build the library with <B><I>"make lib1"</B></I>. With Windows and Visual C++ the DLL project builds an equivalent of <B><I>lib1</B>,</I> and numerous examples are provided in the DLL_USE directory. The complete <B>one channel</B> mode interface is given section 7.24. Let's exemplify the use below:</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">First, initialize the engine with a diphone database. All the functions in the API return an error code. A negative value means there was a flaw during the process, in case of error, an explicit error message can be obtained from lastErrorStr_MBR().</P>
<P ALIGN="JUSTIFY"></P>
<B><I><P ALIGN="JUSTIFY">err_code= init_MBR("h:/mbrola/database/fr1" );</P>
<P ALIGN="JUSTIFY">if (err_code<0) </P>
<P ALIGN="JUSTIFY"> handle_error();</P>
</B></I><P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">If the default parser is plugged, one can use the regular syntax in write_MBR to send phonemes to the engine:</P>
<P ALIGN="JUSTIFY"></P>
<B><I><P ALIGN="JUSTIFY">if ( ( write_MBR("_ 51 \n b 62 \n") < 0) ||</P>
<P ALIGN="JUSTIFY"> ( write_MBR("o~ 127 50 170 \n Z 110\n") <0) ||</P>
<P ALIGN="JUSTIFY"> ( WriteSpeechFile(output)<0) ||</P>
<P ALIGN="JUSTIFY"> ( write_MBR("u 211 100 200\n R 150 \n_ 9\n#\n") < 0) ||</P>
<P ALIGN="JUSTIFY"> ( WriteSpeechFile(output)<0) )</P>
<P ALIGN="JUSTIFY">handle_error();</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">close_MBR();</P>
<P ALIGN="JUSTIFY"> </P>
</B></I><P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">Each time one calls <B><I>init_MBR</B></I>(), one should call a pending <B><I>close_MBR</B></I>() to release allocated memory. Once <B><I>close_MBR</B></I>() is called, one can call <B><I>init_MBR</B></I>() for a brand new database. If one wish to work with the same database but forget previously entered phonemes, then use <B><I>reset_MBR</B></I>().</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">Let's describe how WriteSpeechFile works:</P>
<P ALIGN="JUSTIFY"> </P>
<B><I><P ALIGN="JUSTIFY">int WriteSpeechFile(FILE *output)</P>
<P ALIGN="JUSTIFY">{</P>
<P ALIGN="JUSTIFY"> int i;</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY"> while ( (i=readtype_MBR(buffer, 16000, LIN16)) == 16000)</P>
<P ALIGN="JUSTIFY"> fwrite(buffer, 2, i, output);</P>
<P ALIGN="JUSTIFY"> if (i>0)</P>
<P ALIGN="JUSTIFY"> { /* write last chunk */</P>
<P ALIGN="JUSTIFY"> fwrite(buffer,size,i,output);</P>
<P ALIGN="JUSTIFY"> return 0;</P>
<P ALIGN="JUSTIFY"> }</P>
<P ALIGN="JUSTIFY"> else</P>
<P ALIGN="JUSTIFY"> return i; /* return an error code */</P>
<P ALIGN="JUSTIFY">}</P>
</B></I><P ALIGN="JUSTIFY">It reads sample buffers from the engine until it can't get any more ( <B><I>readtype_MBR</B></I> returns 0), or an error occurs. <B><I>Readtype</B></I> can return 0 for two reasons: either a flush has been encountered, either we don't have enough data in the default parser, as it needs a look ahead to interpolate pitch values. This is the case after<B><I> write_MBR("o~ 127 50 170 \n Z 110\n")</B></I>, synthesis on the /<B><I>Z</B></I>/ can't be carried out until we get the pitch point on<B><I> "u 211 100 200"</B></I>. This way asynchronous read/write operations are allowed.</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">The small error handling function simply does:</P>
<B><I><P ALIGN="JUSTIFY">void handle_error()</P>
<P ALIGN="JUSTIFY">{</P>
<P ALIGN="JUSTIFY"> char err[255];</P>
<P ALIGN="JUSTIFY"> </P>
<P ALIGN="JUSTIFY"> lastErrorStr_MBR(err,sizeof(err));</P>
<P ALIGN="JUSTIFY"> </P>
<P ALIGN="JUSTIFY"> printf("Code %i\n%s\n", lastError_MBR(), err);</P>
<P ALIGN="JUSTIFY"> exit(-1);</P>
<P ALIGN="JUSTIFY">}</P>
</B></I><P ALIGN="JUSTIFY">At any time, one can use the get_* and set_* functions to modify internal parameters of the synthesizer.</P>
<P ALIGN="JUSTIFY"></P>
<B><P ALIGN="JUSTIFY">Important note about the vocal tract length capabilities</B>: one can modify the size of the speaker's throat with setFreq_MBR. The lower this frequency, the deeper the voice. This very simple method takes advantage of the playback sampling rate to shift the formants up and down, just like when changing the speed of a tape player. Thus, to be effective, any call to setFreq_MBR must be accompanied with a call to the audio hardware setting the requested playback sample rate. Otherwise the speed and pitch will sound odd.</P>
<P ALIGN="JUSTIFY"><LI><A NAME="_Toc431812946"><B><FONT FACE="Arial">Multi channel mode</A></LI></P>
</B></FONT><P ALIGN="JUSTIFY">One can build a demo by running "make demo2" under Unix, or simply build the library with <B><I>"make lib2"</B></I>. The complete <B>multi channel</B> mode interface is given section 7.25. </P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">It looks strangely close to the one channel mode, except that one passes a pointer to a synthesizer structure for every function. Another point is that it doesn't hide any more the parser's details to the user. Thus if one wants to use the default parser, one has to effectively build it. </P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">The following code build 3 independent default phoneme parsers: </P>
<P ALIGN="JUSTIFY"></P>
<B><I><P ALIGN="JUSTIFY">/* Input Fifo with a buffer of 100 chars */</P>
<P ALIGN="JUSTIFY"> fifo1= init_Fifo(100);</P>
<P ALIGN="JUSTIFY"> fifo2= init_Fifo(100);</P>
<P ALIGN="JUSTIFY"> fifo3= init_Fifo(100);</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY"> /* Input stream of the synthesizer */</P>
<P ALIGN="JUSTIFY"> input1= init_InputFifo(fifo1);</P>
<P ALIGN="JUSTIFY"> input2= init_InputFifo(fifo2);</P>
<P ALIGN="JUSTIFY"> input3= init_InputFifo(fifo3);</P>
<P ALIGN="JUSTIFY"> </P>
<P ALIGN="JUSTIFY"> /* Plug the fifos on the default parsers */</P>
<P ALIGN="JUSTIFY"> parser1= init_ParserInput(input1,"_",120.0,";",1.0,1.0);</P>
<P ALIGN="JUSTIFY"> parser2= init_ParserInput(input2,"_",120.0,";",1.0,1.0);</P>
<P ALIGN="JUSTIFY"> parser3= init_ParserInput(input3,"_",120.0,";",1.0,1.0);</P>
</B></I><P ALIGN="JUSTIFY"> </P>
<P ALIGN="JUSTIFY">To use one's own parser, see the next section. Once this is done, as many databases as synthesis channels must be opened (let's say 3 channels in this example).</P>
<P ALIGN="JUSTIFY"></P>
<B><I><P ALIGN="JUSTIFY">Database* main_dba= init_DatabaseMBR2(argv[1],NULL,NULL); </P>
<P ALIGN="JUSTIFY">if (!main_dba)</P>
<P ALIGN="JUSTIFY"> handle_error(True);</P>
</B></I><P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">Of course opening 3 or more times the same database would spoil a lot of memory since many internal structures could be shared. Instead of using init_DatabaseMBR2 one can clone an already opened database:</P>
<B><I><P ALIGN="JUSTIFY">Database* clone_dba1= copyconstructor_DatabaseMBR2(main_dba);</P>
<P ALIGN="JUSTIFY">Database* clone_dba2= copyconstructor_DatabaseMBR2(main_dba);</P>
<P ALIGN="JUSTIFY">Database* clone_dba3= copyconstructor_DatabaseMBR2(main_dba);</P>
</B></I><P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">Cloned database just behave like regular Database, i.e. their destructor must be called before leaving. Once we have a Parser input and a Database, we can open a synthesis channel:</P>
<B><I><P ALIGN="JUSTIFY">Mbrola* channel1= init_MBR2(clone_dba1,parser1);</P>
<P ALIGN="JUSTIFY">Mbrola* channel2= init_MBR2(clone_dba2,parser2);</P>
<P ALIGN="JUSTIFY">Mbrola* channel3= init_MBR2(clone_dba3,parser3);</P>
<P ALIGN="JUSTIFY"></P>
</B></I><P ALIGN="JUSTIFY">In this particular example, one can write phonemes in the parser, and read samples from the synthesis engine with instructions such as:</P>
<B><I><P ALIGN="JUSTIFY">write_Fifo(fifo1,"_ 51 \n b 62 \n o~ 100\n Z 120")</P>
<P ALIGN="JUSTIFY">while ((i=readtype_MBR2(channel1, buffer, 16000, LIN16))==16000)</P>
<P ALIGN="JUSTIFY"> fwrite(buffer,size,i,output);</P>
<P ALIGN="JUSTIFY"></P>
</B></I><P ALIGN="JUSTIFY">Of course the call to <B>write_Fifo</B> is completely dependent of the fact that this example uses the default phoneme parser. In this particular case, the polymorphic object <B>Parser</B>, which was passed to the constructor of <B>channel</B>, reads its input data from <B>Fifo1</B>.</P>
<P ALIGN="JUSTIFY"><LI><A NAME="_Toc431812947"><B><FONT FACE="Arial">Designing and plugging your own parser</A></LI></P></OL>
</OL>
</OL>
</B></FONT><P ALIGN="JUSTIFY">The user can write his own implementation of a Parser, as long as it follows the definition of <B>Parser/parser.h</B>. The file <B>parser_simple.c</B> below gives an example of a parser that reads phonetic inputs with the format: Phoneme Duration Pitch_At_0% Pitch_At_100%.</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">In practice this example does not take into account that the Engine synthesize diphones. As the word states, a diphone is made of two phonemes, thus one must know both parts of the diphones to utter it. Thus each phoneme file being used with parser<B>_simple</B> must end with two silences: the first one reveal 1st half of the last phoneme, and the second one reveal the second half (a complete example is provided in <I>VisualC++/DLL_USE/mbrola/parser_simple.cpp</I>). Many people forget to include the second silence as the result sounds correct without. Though, the total length of the synthetic message won't agree with the requested one.</P>
<P ALIGN="JUSTIFY"></P><DIR>
<DIR>
<B><I><P ALIGN="JUSTIFY">/*</P>
<P ALIGN="JUSTIFY"> * FPMs-TCTS SOFTWARE LIBRARY</P>
<P ALIGN="JUSTIFY"> *</P>
<P ALIGN="JUSTIFY"> * File: parser_simple.c</P>
<P ALIGN="JUSTIFY"> * Purpose: parse a simple "pho file" (demonstration of the mbrola DLL)</P>
<P ALIGN="JUSTIFY"> * Instanciation of parser.h</P>
<P ALIGN="JUSTIFY"> *</P>
<P ALIGN="JUSTIFY"> * Author: Vincent Pagel</P>
<P ALIGN="JUSTIFY"> * Email : [email protected]</P>
<P ALIGN="JUSTIFY"> *</P>
<P ALIGN="JUSTIFY"> * Copyright (c) 1995-2018 Faculte Polytechnique de Mons (TCTS lab)</P>
<P ALIGN="JUSTIFY"> *</P>
<P ALIGN="JUSTIFY"> * 18/09/98 : Created</P>
<P ALIGN="JUSTIFY"> */</P>
<P ALIGN="JUSTIFY">#include <stdio.h></P>
<P ALIGN="JUSTIFY">#include "mbrola.h"</P>
<P ALIGN="JUSTIFY">#include "parser_simple.h"</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">static void reset_ParserSimple(Parser* parse)</P>
<P ALIGN="JUSTIFY">{</P>
<P ALIGN="JUSTIFY"> /* nothing to do */</P>
<P ALIGN="JUSTIFY"> fseek( (File*) parse->self,0,SEEK_SET);</P>
<P ALIGN="JUSTIFY">}</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">static StatePhone nextphone_ParserSimple(Parser* parse, LPPHONE* ph)</P>
<P ALIGN="JUSTIFY">{</P>
<P ALIGN="JUSTIFY"> char phoneme[255]; /* phoneme name */</P>
<P ALIGN="JUSTIFY"> float length; /* length in milliseconds */</P>
<P ALIGN="JUSTIFY"> float pitch0; /* pitch at 0% */</P>
<P ALIGN="JUSTIFY"> float pitch100; /* pitch at 100% */</P>
<P ALIGN="JUSTIFY"> </P>
<P ALIGN="JUSTIFY"> if ( fscanf( (FILE*)parse->self," %s %f %f %f ",phoneme,&length,&pitch0,&pitch100 ) ==4 )</P>
<P ALIGN="JUSTIFY"> {</P>
<P ALIGN="JUSTIFY">*ph= init_Phone(phoneme,length);</P>
<P ALIGN="JUSTIFY">	appendf0_Phone(*ph, 0.0 , pitch0);</P>
<P ALIGN="JUSTIFY">	appendf0_Phone(*ph, 100.0, pitch100);</P>
<P ALIGN="JUSTIFY">	return PHO_OK;</P>
<P ALIGN="JUSTIFY"> }</P>
<P ALIGN="JUSTIFY"> else	</P>
<P ALIGN="JUSTIFY"> {</P>
<P ALIGN="JUSTIFY"> return PHO_EOF;</P>
<P ALIGN="JUSTIFY"> }</P>
<P ALIGN="JUSTIFY">}</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">static void close_ParserSimple(Parser* parse)</P>
<P ALIGN="JUSTIFY">	 /* Destructor */</P>
<P ALIGN="JUSTIFY">{</P>
<P ALIGN="JUSTIFY"> fclose( (FILE*) parse->self);</P>
<P ALIGN="JUSTIFY"> free(parse);</P>
<P ALIGN="JUSTIFY">}</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">Parser* init_ParserSimple(char* input_name)</P>
<P ALIGN="JUSTIFY">/*</P>
<P ALIGN="JUSTIFY"> * Constructor of the parser. Parse a text file of the form</P>
<P ALIGN="JUSTIFY"> * PHONEME LENGTH PITCH_AT_BEGINNING PITCH_AT_END</P>
<P ALIGN="JUSTIFY"> */</P>
<P ALIGN="JUSTIFY">{</P>
<P ALIGN="JUSTIFY"> FILE* input;</P>
<P ALIGN="JUSTIFY"> Parser* parse;</P>
<P ALIGN="JUSTIFY"> </P>
<P ALIGN="JUSTIFY"> /* open the text file */</P>
<P ALIGN="JUSTIFY"> input=fopen(input_name,"rt");</P>
<P ALIGN="JUSTIFY"> if (!input)</P>
<P ALIGN="JUSTIFY">	 return NULL;</P>
<P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY"> parse= (Parser*) MBR_alloc( sizeof( struct Parser) );</P>
<P ALIGN="JUSTIFY"> parse->reset_Parser= reset_ParserSimple;</P>
<P ALIGN="JUSTIFY"> parse->close_Parser= close_ParserSimple;</P>
<P ALIGN="JUSTIFY"> parse->nextphone_Parser= nextphone_ParserSimple; </P>
<P ALIGN="JUSTIFY"> parse->self= (void*) input;</P>
<P ALIGN="JUSTIFY"> return(parse);</P>
<P ALIGN="JUSTIFY">}</P>
</B></I><P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY"> </P>
<P ALIGN="JUSTIFY"> </P></DIR>
</DIR>
<OL>
<B><FONT FACE="Arial" SIZE=5><LI></LI>
<LI><A NAME="_Toc431812948">Mbrola architecture</A></LI>
</B></FONT><P ALIGN="JUSTIFY">In following chapters the exported functions and variables of all the source files in the project are described. After the file descriptions, a symbol index is provided to allow fast localization of any function, variable or define.</P>
<OL>
<P ALIGN="JUSTIFY"><LI><A NAME="_Toc431812949"><B><FONT FACE="Arial" SIZE=4>File: Misc/common.h</A></LI></P>
</B></FONT><FONT FACE="Courier New" SIZE=2><P>/*</P>
<P> * Purpose: common utilities and defines</P>
<P> * Author: Vincent Pagel</P>
<P> */</P>
<P>/******************</P>
<P> * Definitions *</P>
<P> ******************/</P>
<P>/* Release number (automatically changed by "make version") */</P>
<P>#define SYNTH_VERSION "3.01e2"</P>
<P>#define WWW_ADDRESS "http://tcts.fpms.ac.be/synthesis"</P>
<P>/* General trace */</P>
<P>/*	#define DEBUG */</P>
<P>/* Trace of the hash table -> this debug make the program stop and</P>
<P> * and print the access statistics in the hash table (may help to</P>
<P> * check and tune access time on new databases)</P>
<P> */</P>
<P>/* #define DEBUG_HASH */</P>
<P>/*</P>
<P> * True and False should be used instead of integer values</P>
<P> */</P>
<P>/* Argh ! Depends on the compiler! Comment it if yours is not C/ANSI */</P>
<P>#define bool int</P>
<P>#define False 0</P>
<P>#define True 1</P>
<P>/*</P>
<P> * ARCHITECTURE DEPENDENT !!!</P>
<P> * These definitions should be imposed so that int8, int16 and int32</P>
<P> * always refer to 8, 16 and 32 bits integer</P>
<P> */</P>
<P>#define uint8 unsigned char</P>
<P>#define int8 char</P>
<P>#define int16 short</P>
<P>#define uint16 unsigned short</P>
<P>#define int32 long</P>
<P ALIGN="JUSTIFY"><LI><A NAME="_Toc431812950"></FONT><B><FONT FACE="Arial" SIZE=4>File: Misc/incdll.h</A></LI></P>
</B></FONT><FONT FACE="Courier New" SIZE=2><P>/*</P>
<P> * Purpose: symbols needed outside of the mbrola sources</P>