Add mbrowrap.cpp to emulate the mbrola library which is available in Windows, but not on Linux. mbrola voices in command-line espeak and libespeak now call mbrola directly rather than generating phoneme information as text. Mbrola phonemes as text is still available with the new --pho command-line option. git-svn-id: https://espeak.svn.sourceforge.net/svnroot/espeak/trunk@248 d46cf337-b52f-0410-862d-fd96e6ae7743master
| @@ -1,4 +1,4 @@ | |||
| // PB = Peter Bjarkov - [email protected] | |||
| // PB = Peter Bjarkov - [email protected] | |||
| // This file is UTF8 encoded | |||
| // Spelling-to-phoneme words for Danish | |||
| @@ -113,7 +113,7 @@ _3X tR'&#Dv@ //PB [tR'ADv@] changed to [tR'&#Dv@] | |||
| _4X f'WRV //PB [f'W:*3] changed to [ f'WRV] | |||
| _5X h&l't*es // PB [a] changed to [&] | |||
| _6X t*'es | |||
| _7X halfj'&rs | |||
| _7X h&lfj'&rs // PV a changed to & | |||
| _8X f'irs | |||
| _9X h&lf'Ems // PB a changed to & | |||
| _0C h'un*@:D | |||
| @@ -164,6 +164,7 @@ et ed $u | |||
| her $u | |||
| kun $u | |||
| vel $u+ | |||
| da $u | |||
| // conjunctions | |||
| og V $u+ $pause // and | |||
| @@ -204,7 +205,7 @@ dét de | |||
| vi $u | |||
| i _i $u+ | |||
| mig maj $u // me | |||
| dig daj_| $u | |||
| dig daj $u | |||
| dem $u | |||
| ham $u | |||
| hende $u | |||
| @@ -259,7 +260,7 @@ f Ef | |||
| g ge: | |||
| h hO: | |||
| _i i: | |||
| j joD | |||
| j jVD // PB changed from [o] | |||
| k kO: | |||
| l El | |||
| m Em | |||
| @@ -318,7 +319,6 @@ interface _^_EN | |||
| image _^_EN | |||
| joke _^_EN | |||
| joystick _^_EN | |||
| junkie _^_EN | |||
| laptop _^_EN | |||
| level _^_EN | |||
| login _^_EN | |||
| @@ -2343,7 +2343,7 @@ dessin des'EN $alt | |||
| dioxin $alt | |||
| disciplin $alt | |||
| doktrin $alt | |||
| (drive-in) drajv'in $alt | |||
| //(drive-in) drajv'in $alt | |||
| dusin $alt | |||
| endokrin $alt | |||
| endorfin $alt | |||
| @@ -5153,7 +5153,7 @@ banaliser $alt | |||
| bandagere $alt | |||
| banderolere $alt | |||
| barbariser $alt | |||
| barber $alt | |||
| barbere $alt | |||
| barder $alt | |||
| barrier $alt | |||
| barrikader $alt | |||
| @@ -5178,7 +5178,7 @@ bonbonniere bVNbVNj'E:r $alt | |||
| boniter $alt | |||
| botaniser $alt | |||
| braiser $alt | |||
| briketter $alt | |||
| brikettere $alt | |||
| brillere $alt | |||
| brochere $alt | |||
| brodere $alt | |||
| @@ -5549,7 +5549,7 @@ halver $alt | |||
| harceler $alt | |||
| harmoner $alt | |||
| harmoniser $alt | |||
| harpuner $alt | |||
| harpunere $alt | |||
| havarer $alt | |||
| hektografer $alt | |||
| herbariser $alt | |||
| @@ -5668,7 +5668,7 @@ intriger $alt | |||
| introducer $alt | |||
| intuber $alt | |||
| invader $alt | |||
| invalider $alt | |||
| invalidere $alt | |||
| inventer $alt | |||
| inverter $alt | |||
| invester $alt | |||
| @@ -6188,7 +6188,7 @@ præferer $alt | |||
| præjudicer $alt | |||
| prækvalificer $alt | |||
| præluder $alt | |||
| præmier $alt | |||
| præmiere $alt | |||
| prænumerer $alt | |||
| præparer $alt | |||
| præsenter $alt | |||
| @@ -6490,7 +6490,7 @@ temperer $alt | |||
| tender $alt | |||
| teoretiser $alt | |||
| termografer $alt | |||
| terrasser $alt | |||
| terrassere $alt | |||
| terroriser $alt | |||
| testamentere $alt | |||
| testere $alt | |||
| @@ -10298,23 +10298,24 @@ også Vs@ // also | |||
| idet id'e // in so far as | |||
| bleg blaj | |||
| blegrød blajrWD | |||
| blegrøde blajrWD@ | |||
| //blege blaj@ | |||
| blegemiddel bl&#j@mid@l | |||
| //blegansigt bl&#jansegt | |||
| slags sl'ags // sort, type | |||
| tre tr'e // the number 3 | |||
| barber bab'er // PB barber | |||
| barbere bab'eV // PB barbere | |||
| barberer bab'eV // PB barberer | |||
| //barber bAb'er // PB barber | |||
| //barbere bab'eV // PB barbere | |||
| //barberer bab'eV // PB barberer | |||
| //barberes bab'eVs // PB barberes | |||
| barbererne bab'eVn@ // PB barberene | |||
| barberenes bab'eVn@s // PB barberenes | |||
| //barbererne bab'eVn@ // PB barberene | |||
| //barberenes bab'eVn@s // PB barberenes | |||
| rejicere rejis'eV // PB should not be pronounced [raje] | |||
| rejicerer rejis'eV // PB | |||
| rejiceres rejis'eVs // PB | |||
| rejicering rejis'eRiN // PB | |||
| gele sjel'e // PB gele | |||
| géle sjel'e // PB géle | |||
| gelé sjel'e // PB gelé | |||
| geleen sjel'e@-n // PB geleen | |||
| geleer sjel'e3 // PB geleer | |||
| geleens sjel'e@-ns // PB geleens | |||
| @@ -10359,6 +10360,7 @@ shampu Sjambo // PB Danish pronunciation - oo has been replaced b | |||
| (tour de force) tu:@d@||'fV:s // PB | |||
| (al qaeda) al||k'ajda // PB | |||
| (force majeure) fVrs||,ma'sjW:r // PB | |||
| (diner transportable) din'e|trANspVt'abl@ // PB | |||
| (quiche lorraine) kiS||lor'E:n: | |||
| (fait accompli) fEtakVmpl'i // PB | |||
| wien v'i:n // PB Wien - the town of Vienna | |||
| @@ -10404,6 +10406,8 @@ dna $abbrev | |||
| sos $abbrev // PB the SOS signal | |||
| pharm fA:rm? $hasdot // PB fx cand. pharm. | |||
| phil fil/3 $hasdot // PB fx cand. phil. | |||
| bh $abbrev | |||
| (bh'er) b,e:h'O:V | |||
| // Try to catch errors | |||
| @@ -10471,6 +10475,7 @@ legenderne leg'EndVn3s | |||
| (så længe) sV||l'EN3 | |||
| (så må) sV||m'O | |||
| (så har) sV||har | |||
| så sV $sentence $atstart | |||
| (virkede så) v'irkeD@||sV | |||
| (kom så) kVm||sV | |||
| (koste med) kosd@||mED | |||
| @@ -3,207 +3,626 @@ Phonemes which are used in the *_rules and *_list files | |||
| Dictionary af_dict | |||
| & &: 3: @ @- @L @U a | |||
| A: aI AI aU A~ E e: e@ | |||
| eI e~ i I iu O O: o@ | |||
| OI oI o~ u uI W y Y@ | |||
| Yy | |||
| - : ; ? b c d dZ | |||
| f g h j k l l# m | |||
| n N n^ p r s S t | |||
| T tS v w x x2 z Z | |||
| Dictionary ca_dict | |||
| @ a a# aI e E E2 i | |||
| o O u U | |||
| * ** : ; b B d D | |||
| dZ; f g j J J^ k l | |||
| l^ m n N n^ p Q R | |||
| R2 s S; t T ts tS; v | |||
| v# w z Z Z; | |||
| Dictionary cs_dict | |||
| @- a a: aU e e: eI eU | |||
| i i: l- o o: oU r- u | |||
| u: | |||
| * ; b c d dZ dz f | |||
| g h j J k l l^ m | |||
| n N n^ p r R R^ R^/ | |||
| s S t tS ts v x z | |||
| Z | |||
| Dictionary cy_dict | |||
| @ @- @I @Y a A: aI aU | |||
| AY aY E e: eU I i: Iu | |||
| O o: OI OY U u: uY V | |||
| Y y: Yu | |||
| : b C d D dZ f g | |||
| h j k l l# m n N | |||
| p r s S t T v w | |||
| x z | |||
| Dictionary da_dict | |||
| & &# 0 3 @ @- a A | |||
| e E i o O u V W | |||
| W# y Y | |||
| * - : ? b B d D | |||
| dZ f g h j J k l | |||
| l/2 l/3 m n N p r R | |||
| s S t T tS v w z | |||
| Dictionary hu_dict | |||
| A a: E e: i i: o o: | |||
| u u: Y y y: Y: | |||
| - : b c d dZ dz f | |||
| g h j J k l m n | |||
| n^ p r R R2 s S s2 | |||
| t tS ts v z Z | |||
| Dictionary de_dict | |||
| 3 3: @ @- a A A: aI | |||
| aU E E2 E: e: EI I i2 | |||
| i: n- O o: OY U u: W | |||
| y y: Y: | |||
| * : ; b C d D dZ | |||
| f g g# h j k l m | |||
| n N p pF r s S t | |||
| tS ts v w x z Z | |||
| Dictionary el_dict | |||
| @ @- a aI e i o oI | |||
| u | |||
| * ; b c C d D f | |||
| g j k l l^ m n N | |||
| n^ p Q r R s s; t | |||
| T ts v x z z; | |||
| Dictionary en_dict | |||
| 0 3 3: @ @- @2 @5 @L | |||
| a a# A: A@ aa aI aI@ aU | |||
| aU@ A~ E e: e@ eI i I | |||
| I2 i: i@ i@3 IR O O: o: | |||
| O@ o@ OI oU O~ U u: U@ | |||
| V VR | |||
| : ; ? b C d D dZ | |||
| f g g- h j k l l# | |||
| m n N n^ p Q r r- | |||
| s S t T t2 tS v w | |||
| x z Z | |||
| Dictionary eo_dict | |||
| @- a aI aU e eI eU i | |||
| o oI u uI | |||
| * - b d dZ f g h | |||
| j k l m n p r R | |||
| s S t T tS ts v w | |||
| x z Z | |||
| Dictionary es_dict | |||
| a aI aU e E eI eU i | |||
| o O oI u | |||
| * ** : b B d D f | |||
| g j J J^ k l m n | |||
| N n^ p Q R R2 s t | |||
| T tS v v# w x z | |||
| Dictionary fi_dict | |||
| & &i &y a a2 ai au e | |||
| ei eu ey i I ie iu iy | |||
| o oi ou u ui uo Y y | |||
| Yi yi Yy yY | |||
| : b d f g h j k | |||
| l m n N p r s S | |||
| s2 t v w Z | |||
| Dictionary fr_dict | |||
| @ @- a A~ e E E2 E: | |||
| E~ i I o O o2 o3 O~ | |||
| u u: w W W~ y Y | |||
| - : b d dZ f g h | |||
| j k l m n N n2 n^ | |||
| p p2 r r2 s S t t2 | |||
| t3 tS v z Z z2 z3 | |||
| Dictionary grc_dict | |||
| a aI aU e E EI eU EU | |||
| i o O oI OI OU u y | |||
| yI | |||
| : b d f g h j k | |||
| l m n N p R s t | |||
| T v x z | |||
| Dictionary hbs_dict | |||
| & @ @2 a A a: aI aU | |||
| e E e: i I i: l- o | |||
| O o: oU r* r- u U u: | |||
| * ; b d dZ dz dZ; f | |||
| g h j k l l^ m n | |||
| N n^ p r R R2 s S | |||
| t tS ts tS; v x z Z | |||
| Dictionary hi_dict | |||
| @ @- @2 @3 a a: aI aU | |||
| e E e: E: E~ i I i: | |||
| l- o O o: O: O~ o~ r- | |||
| U u: u~ V | |||
| - : b bh c ch d d. | |||
| dh dh. f g gh h H j | |||
| J Jh k kh l l. m n | |||
| N n. n^ p ph Q q r | |||
| r. s S s. t T t. th | |||
| th. v w x z | |||
| Dictionary ta_dict | |||
| a a: aI aU e E e: i | |||
| I i: o o: u U u: U: | |||
| V V# | |||
| : ; b C d d. dZ f | |||
| g h H j k l l. m | |||
| n N n. n^ p Q r R | |||
| s S s. t T t. th tS | |||
| v w z z. | |||
| Dictionary hy_dict | |||
| @ a aI e eI i i@ o | |||
| u W y | |||
| ** b c d dZ dz f g | |||
| h j k k# l m n p | |||
| p# r R r" s S t t# | |||
| tS ts ts# v X z Z | |||
| Dictionary id_dict | |||
| @ a aI aU e E E2 i | |||
| o O u | |||
| : ? b d dZ f g h | |||
| j k l m n N n^ p | |||
| r R R2 s S t tS v | |||
| w x z | |||
| Dictionary is_dict | |||
| @- a a: aI aI: aU aU: E | |||
| E: eI eI: i I i: I: O | |||
| O: OI oU oU: u u: W W: | |||
| y y: yI Yy Yy: | |||
| * ** : ; b c C d | |||
| D f g h j J k l | |||
| l# m m# n N n# N# n^ | |||
| n^# p Q r R r# R2 s | |||
| S s2 t T tl# v x z | |||
| Dictionary it_dict | |||
| @- a a/ aI aU e E eI | |||
| i I o O u | |||
| * : ; b d dZ f g | |||
| h j k l l^ m n N | |||
| n^ p r R s S t tS | |||
| ts v w w2 z | |||
| Dictionary jbo_dict | |||
| @ a aI aU e eI i l- | |||
| n- o oI r- u | |||
| b d dZ f g h j k | |||
| l m n N p R s S | |||
| t tS v w x z Z | |||
| Dictionary ku_dict | |||
| 8 a e E E# eI eU i | |||
| I o u U y | |||
| * : b c d dZ f g | |||
| h j J k l m n p | |||
| q r R s S t tS v | |||
| w x z Z | |||
| Dictionary la_dict | |||
| @- a a: aI aU E e: EU | |||
| I i: O o: OI U u: y | |||
| y: | |||
| * : ; <h> ? b d f | |||
| g h j k l m n N | |||
| p r R s t w z | |||
| Dictionary lv_dict | |||
| a a: ai au e e: ei i | |||
| i: ie iu o o: u u: ui | |||
| uo | |||
| : b c d dZ f g h | |||
| j J k l l^ m n N | |||
| n^ p r R R2 s S t | |||
| tS ts v z Z | |||
| Dictionary mk_dict | |||
| & @ @- @2 a A a: e | |||
| E e: i I i: l- o o: | |||
| oU r- u u: | |||
| * b d dZ dz dZ; f g | |||
| h j k k^ l l^ m n | |||
| N n^ p r R s S t | |||
| tS ts tS; v x z Z | |||
| Dictionary nci_dict | |||
| a e i o O | |||
| : ? b c d f g j | |||
| k l m n p R s S | |||
| t tS v w x | |||
| Dictionary nl_dict | |||
| 8 @ @- A a: A~ E e: | |||
| EI eU i I O O: o: u | |||
| VU Wy y Y: yU | |||
| * : ; b d f g h | |||
| j k l m n N n^ p | |||
| Q r s S t tS v v# | |||
| w x z | |||
| Dictionary no_dict | |||
| @ @2 a A a: A: AI aI | |||
| aU E E: e: I i: O o: | |||
| OI U u- u-: u-I u: W y | |||
| y: Y: Yy | |||
| : ; b d f g h j | |||
| k l m n N p r R | |||
| s S s; t v w x z | |||
| Dictionary pap_dict | |||
| a a/ aI e E eI i o | |||
| O u y Y | |||
| : ? b d dZ f g h | |||
| j k l m n N n^ p | |||
| R s S t tS v w x | |||
| z Z | |||
| Dictionary pl_dict | |||
| a E E# E~ i O O~ u | |||
| y | |||
| : ; b c C d d; dZ | |||
| dz f g h j k l m | |||
| n N n^ p r R s S | |||
| s; S; t t; tS ts tS; v | |||
| w x z Z Z; | |||
| Dictionary pt_dict | |||
| & &/ &U~ &~ @ @- a A | |||
| aI aU e E eI EI eU EU | |||
| i I i/ iU o O oI OI | |||
| o~ u U uI u~ y | |||
| * : ; b C d dZ f | |||
| g h j k l l^ m n | |||
| N n^ p Q r R r- s | |||
| S s# s; t T tS ts v | |||
| w x z Z | |||
| Dictionary ro_dict | |||
| @ @- @I @U a aI aU e | |||
| ea eI eo eU i i/ I^ iI | |||
| iU o O Oa oI oU u uI | |||
| y Y yI yU | |||
| * *; b b; c C d d; | |||
| dZ f f; g h j k l | |||
| l; m m; n N n; p p; | |||
| r s S S; t t; tS ts | |||
| ts; v v; w w2 x z Z | |||
| z; Z; | |||
| Dictionary ru_dict | |||
| 8 @- a A e E E# E2 | |||
| E3 i I I# I2 I3 I^ ja | |||
| ju o O u u" u# V V# | |||
| y Y | |||
| * ; b d d; dZ; f g | |||
| j k l l^ m m; n n^ | |||
| p r R s S s; S; t | |||
| t; ts tS; v x z Z z; | |||
| Z; | |||
| Dictionary sk_dict | |||
| & @- a a: e e: i i: | |||
| l- l: o o: oU r- r: u | |||
| u: | |||
| * ; b d d; dZ dz f | |||
| g h j k l l^ m n | |||
| N n^ p r R R^ R^/ s | |||
| S t t; tS ts v x z | |||
| Z | |||
| Dictionary sq_dict | |||
| @ @/ a A a/ aI e E | |||
| eI i I I# O OI u V | |||
| y yE | |||
| ** : ; b c d D dZ | |||
| dz dZ; f g h j k l | |||
| L ll m n n^ p r R | |||
| R2 s S t T tS ts v | |||
| w z Z | |||
| Dictionary sv_dict | |||
| 8 @ a A: E E- e: E: | |||
| I i: O o: U u- u: W | |||
| y y: Y: | |||
| : ; b d f g h j | |||
| k l m n N p R s | |||
| S s. S; sx t v w z | |||
| Dictionary sw_dict | |||
| @- a a/ e i m- n- N- | |||
| o u | |||
| * : b d D f g h | |||
| j J k l m n N n^ | |||
| p Q R s S t T tS | |||
| v w x z | |||
| Dictionary sl_dict | |||
| & @ a e E i o O | |||
| u y | |||
| : b d dZ dz f g h | |||
| j k l l^ m n N n^ | |||
| p R R^ s S t tS ts | |||
| v w x z Z | |||
| Dictionary tr_dict | |||
| @ a e E i I o O | |||
| u U W y Y | |||
| * : b c d dZ f g | |||
| G h j J k l m n | |||
| p Q r R s S t tS | |||
| v w z Z | |||
| Dictionary vi_dict | |||
| @ @: @:I @:U @I @U a a: | |||
| a:I a:U aI aU e E eU EU | |||
| i i@ iU o O OI oI u | |||
| u@ uI y y@ yI | |||
| b c d D f g h j | |||
| J k kh l m n N n^ | |||
| p Q r s s. t t[ tS; | |||
| v w x z Z z. | |||
| Dictionary zh_dict | |||
| @ @r a A ai Au E ei | |||
| i i. i[ iA iE io iou N- | |||
| o o- ong ou u u@ ua uai | |||
| uei uo y y& y@ yE yi yu | |||
| ; C f h j k kh l | |||
| l# m n N p ph Q q | |||
| Q" Q^ r R r" R2 R3 s | |||
| s. S; t th ts ts. ts. tS; | |||
| tS; tsh v w x X z. | |||
| Dictionary zhy_dict | |||
| a aa aai aan aau ai au e | |||
| ei eo eoi eu i iu o oe | |||
| oi ong ou u ui yu | |||
| b c d f g h j k | |||
| l m n N p r s t | |||
| tS v w z | |||
| Dictionary am_dict | |||
| @ a e i o u y | |||
| b d h l m q R s | |||
| S t tS | |||
| Dictionary ml_dict | |||
| a a: aI aU e E e: i | |||
| I i: o o: r- u u: V | |||
| y | |||
| : b bh c ch d d. dh | |||
| dh. dZ f g gh h j J | |||
| Jh k kh l l. m n N | |||
| n. n^ p ph R R2 s s. | |||
| S; t t. th th. tS v w | |||
| z z. | |||
| Dictionary ne_dict | |||
| @ @/ @2 @3 a aI aU a~ | |||
| e E eI eU e~ E~ i I | |||
| i~ l- o O o: oI oU O~ | |||
| o~ r- u uI u~ V VI VU | |||
| V~ | |||
| - : b bh c ch d d. | |||
| dh f g gh h H j J | |||
| Jh k kh l l. m n N | |||
| n. n^ p ph Q q r r. | |||
| s S s. t T t. th v | |||
| w x z z. | |||
| Dictionary pa_dict | |||
| @ a a~ e E e~ E~ i | |||
| I i~ I~ o O O~ o~ r- | |||
| u U U~ u~ V V~ | |||
| : ; b bh c ch d d. | |||
| dh dh. f g gh h H j | |||
| J Jh k kh l l. m n | |||
| N n. n^ p ph Q R R2 | |||
| s S t t. th th. v x | |||
| z | |||
| Dictionary prs_dict | |||
| @ A E eI i o u | |||
| : b d dZ f g h j | |||
| k l m n p r R s | |||
| S t tS v w X z Z | |||
| Dictionary rw_dict | |||
| a e i o u | |||
| * : b B c d dZ f | |||
| g h j J k l m n | |||
| N n^ p q R s S S; | |||
| t tS v w x z | |||
| Dictionary ur_dict | |||
| @ a a: aI aU E e: i | |||
| I i: O o: U u: | |||
| : b bh c ch d D d. | |||
| dh dh. dZ f g gh H j | |||
| J Jh k kh l m n N | |||
| p ph Q q R r. s S | |||
| s. t T t. th th. v x | |||
| z Z z. | |||
| Dictionary bg_dict | |||
| @ a e i o u | |||
| ; b C d d; dZ dz f | |||
| g j k l L l^ m n | |||
| n^ p r s S s; t t; | |||
| tS ts v x z Z z; | |||
| Dictionary nso_dict | |||
| @ a e i m- n- N- o | |||
| u | |||
| - : b d D dZ f g | |||
| h j J k l l# m n | |||
| N n^ p Q r R R3 s | |||
| S t T tS v w x z | |||
| @@ -792,6 +792,7 @@ chloroplast $1 | |||
| chocolate tS0kl@t | |||
| cholera k0l@r@ | |||
| cholesterol k@lEst@r0l | |||
| chorizo tSOr'i:zoU | |||
| chromosome kroUm@soUm | |||
| ciao tSaU | |||
| cigar sI2gA@ | |||
| @@ -1494,6 +1495,7 @@ metaphor mEt@fO@ | |||
| metallic mEt'alIk | |||
| miaou mi:'aU | |||
| miaow mi:'aU | |||
| mic maIk | |||
| mica maIk@ | |||
| microorganism maIkroU'O@g@nIz@m | |||
| midday m,Idd'eI | |||
| @@ -746,9 +746,7 @@ | |||
| r) u (_A u | |||
| u (A_ 'u | |||
| ui 'uI | |||
| ui (_ uI | |||
| ui (s 'uI | |||
| ui uI | |||
| u (iu w | |||
| u (iCK u | |||
| uy uI | |||
| @@ -991,13 +991,11 @@ _முகத்தின்_) ப (ாவ b | |||
| சிறு) ப (ிள்ளை p | |||
| ஆண்) ப (ிள்ளை p | |||
| பெண்) ப (ிள்ளை p | |||
| பூம்) ப (ுகார p | |||
| ம்) ப (ுரா b | |||
| இன்) ப (ுற b | |||
| _துன்) ப (ுற b | |||
| ப (ுறK p | |||
| மண்) ப (ுழு p | |||
| பூம்) ப (ுஹார p | |||
| ம்) ப (ூர b | |||
| ராம்) ப (ூர p | |||
| அ) ப (ூர்வ b | |||
| @@ -341,7 +341,7 @@ l/l_ [l/] base | |||
| l/l_@ [l/3] base | |||
| [l/] fr | |||
| l/l@ [l#] base | |||
| [ߵ] base | |||
| [߸] base | |||
| [l] fr | |||
| [l/2] fr | |||
| l/L1_aL [l/] base | |||
| @@ -367,13 +367,13 @@ l/L2_uL [l/2] base | |||
| l/l_3 [l/] de | |||
| l/l_4 [ll] sq | |||
| l/la [l#] base | |||
| [ߵ] base | |||
| [߸] base | |||
| [l] fr | |||
| [l/2] fr | |||
| l/l_a [l/3] base | |||
| [l/] fr | |||
| l/le [l#] base | |||
| [ߵ] base | |||
| [߸] base | |||
| [l] fr | |||
| [l/2] fr | |||
| l/l_e [l/3] base | |||
| @@ -383,7 +383,7 @@ l/L_eL_af [&] af | |||
| l/l_front [L] sq | |||
| l/l_front_ [l/4] sq | |||
| l/li [l#] base | |||
| [ߵ] base | |||
| [߸] base | |||
| [l] fr | |||
| [l/2] fr | |||
| [l] zh | |||
| @@ -395,14 +395,14 @@ ll/_ll [L] bg | |||
| l/l_long [l] base | |||
| [l] fr | |||
| l/lo [l#] base | |||
| [ߵ] base | |||
| [߸] base | |||
| [l] fr | |||
| [l/2] fr | |||
| l/l_o [l/3] base | |||
| [l/] fr | |||
| l^/l_rfx [l.] base | |||
| l/lu [l#] base | |||
| [ߵ] base | |||
| [߸] base | |||
| [l] fr | |||
| [l/2] fr | |||
| l/l_u [l/3] base | |||
| @@ -620,8 +620,8 @@ ufric/f [f] base | |||
| ufric/f_ [f] base | |||
| [f] fr | |||
| [f] pl | |||
| ufric/l# [l#] is | |||
| ufric/ll [l#] base | |||
| ufric/l# [l#] base | |||
| [l#] is | |||
| ufric/s [s] base | |||
| [s] fr | |||
| [z2] fr | |||
| @@ -1943,51 +1943,51 @@ vwl_en_us/oor [0] en-us | |||
| vwl_en_us/or [o@] en-us | |||
| [O:] en-sc | |||
| vwl_en_us/ur [U@] en-us | |||
| vwl_fr/@2r [ߵ] fr | |||
| vwl_fr/a2r [ߵ] fr | |||
| vwl_fr/aa2r [ߵ] fr | |||
| vwl_fr/@2r [߸] fr | |||
| vwl_fr/a2r [߸] fr | |||
| vwl_fr/aa2r [߸] fr | |||
| vwl_fr/br [r/2] fr | |||
| vwl_fr/e2r [ߵ] fr | |||
| vwl_fr/e_2r [ߵ] fr | |||
| vwl_fr/ee2r [ߵ] fr | |||
| vwl_fr/i2r [ߵ] fr | |||
| vwl_fr/e2r [߸] fr | |||
| vwl_fr/e_2r [߸] fr | |||
| vwl_fr/ee2r [߸] fr | |||
| vwl_fr/i2r [߸] fr | |||
| vwl_fr/j [j/] fr | |||
| vwl_fr/o2r [ߵ] fr | |||
| vwl_fr/oo2r [ߵ] fr | |||
| vwl_fr/o2r [߸] fr | |||
| vwl_fr/oo2r [߸] fr | |||
| vwl_fr/r [r] fr | |||
| [r/2] fr | |||
| vwl_fr/r_ [r/] fr | |||
| vwl_fr/r_@ [r/] fr | |||
| vwl_fr/r@ [ߵ] fr | |||
| vwl_fr/r@ [߸] fr | |||
| vwl_fr/@R [x] pt-pt | |||
| vwl_fr/r@2 [ߵ] fr | |||
| vwl_fr/r@2 [߸] fr | |||
| vwl_fr/@R2 [R] fr-ca | |||
| vwl_fr/ra [ߵ] fr | |||
| vwl_fr/ra [߸] fr | |||
| vwl_fr/r_a [r/] fr | |||
| vwl_fr/raa [ߵ] fr | |||
| vwl_fr/re [ߵ] fr | |||
| vwl_fr/raa [߸] fr | |||
| vwl_fr/re [߸] fr | |||
| vwl_fr/r_e [r/] fr | |||
| vwl_fr/re2 [ߵ] fr | |||
| vwl_fr/ree [ߵ] fr | |||
| vwl_fr/ri [ߵ] fr | |||
| vwl_fr/re2 [߸] fr | |||
| vwl_fr/ree [߸] fr | |||
| vwl_fr/ri [߸] fr | |||
| vwl_fr/r_i [r/] fr | |||
| vwl_fr/rj [ߵ] fr | |||
| vwl_fr/rj [߸] fr | |||
| vwl_fr/r_n [r/] fr | |||
| vwl_fr/ro [ߵ] fr | |||
| vwl_fr/ro [߸] fr | |||
| vwl_fr/r_o [r/] fr | |||
| vwl_fr/roo [ߵ] fr | |||
| vwl_fr/roo [߸] fr | |||
| vwl_fr/rr [r/] fr | |||
| vwl_fr/ru [ߵ] fr | |||
| vwl_fr/ru [߸] fr | |||
| vwl_fr/r_u [r/] fr | |||
| vwl_fr/rw [ߵ] fr | |||
| vwl_fr/ry [ߵ] fr | |||
| vwl_fr/rw [߸] fr | |||
| vwl_fr/ry [߸] fr | |||
| vwl_fr/r_y [r/] fr | |||
| vwl_fr/tr [r/2] fr | |||
| vwl_fr/trr [r/] fr | |||
| vwl_fr/u2r [ߵ] fr | |||
| vwl_fr/u2r [߸] fr | |||
| vwl_fr/wa [w] fr | |||
| [w/] fr | |||
| vwl_fr/y2r [ߵ] fr | |||
| vwl_fr/y2r [߸] fr | |||
| vwl_hi/l-voc [l-] base | |||
| [l-] sk | |||
| [l:] sk | |||
| @@ -1,5 +1,3 @@ | |||
| # Makefile for 'espeak', 'speak', and 'libespeak' | |||
| # remove -fno-exceptions if it causes problems with stdio library on some platforms (ARM) | |||
| PREFIX=/usr | |||
| @@ -51,12 +49,12 @@ endif | |||
| speak_SOURCES = speak.cpp compiledict.cpp dictionary.cpp intonation.cpp \ | |||
| readclause.cpp setlengths.cpp numbers.cpp synth_mbrola.cpp \ | |||
| synthdata.cpp synthesize.cpp translate.cpp \ | |||
| synthdata.cpp synthesize.cpp translate.cpp mbrowrap.cpp \ | |||
| tr_languages.cpp voices.cpp wavegen.cpp phonemelist.cpp klatt.cpp | |||
| libespeak_SOURCES = speak_lib.cpp compiledict.cpp dictionary.cpp intonation.cpp \ | |||
| readclause.cpp setlengths.cpp numbers.cpp synth_mbrola.cpp \ | |||
| synthdata.cpp synthesize.cpp translate.cpp \ | |||
| synthdata.cpp synthesize.cpp translate.cpp mbrowrap.cpp \ | |||
| tr_languages.cpp voices.cpp wavegen.cpp phonemelist.cpp \ | |||
| espeak_command.cpp event.cpp fifo.cpp $(WAVE) debug.cpp klatt.cpp | |||
| @@ -2,10 +2,10 @@ | |||
| SRCS= compiledata.cpp compiledict.cpp debug.cpp dictionary.cpp espeak_command.cpp \ | |||
| espeakedit.cpp event.cpp extras.cpp fifo.cpp formantdlg.cpp intonation.cpp \ | |||
| klatt.cpp menus.cpp numbers.cpp options.cpp phonemelist.cpp prosodydisplay.cpp \ | |||
| readclause.cpp setlengths.cpp speak_lib.cpp spect.cpp spectdisplay.cpp \ | |||
| spectseq.cpp synthdata.cpp synthesize.cpp synth_mbrola.cpp translate.cpp \ | |||
| transldlg.cpp tr_languages.cpp voicedlg.cpp voices.cpp vowelchart.cpp \ | |||
| klatt.cpp mbrowrap.cpp menus.cpp numbers.cpp options.cpp phonemelist.cpp \ | |||
| prosodydisplay.cpp readclause.cpp setlengths.cpp speak_lib.cpp spect.cpp \ | |||
| spectdisplay.cpp spectseq.cpp synthdata.cpp synthesize.cpp synth_mbrola.cpp \ | |||
| translate.cpp transldlg.cpp tr_languages.cpp voicedlg.cpp voices.cpp vowelchart.cpp \ | |||
| wave.cpp wavegen.cpp | |||
| OBJS=$(patsubst %.cpp,%.o,$(SRCS)) | |||
| @@ -1744,12 +1744,12 @@ static int LoadWavefile(FILE *f, const char *fname) | |||
| sr2 = Read4Bytes(f); | |||
| fseek(f,40,SEEK_SET); | |||
| if((sr1 != samplerate) || (sr2 != sr1*2)) | |||
| if((sr1 != samplerate_native) || (sr2 != sr1*2)) | |||
| { | |||
| #ifdef PLATFORM_WINDOWS | |||
| if(sr1 != samplerate) | |||
| if(sr1 != samplerate_native) | |||
| { | |||
| fprintf(f_errors,"Wrong samplerate %d, wants %d\n",sr1,samplerate); | |||
| fprintf(f_errors,"Wrong samplerate %d, wants %d\n",sr1,samplerate_native); | |||
| error("Wrong samplerate: %s",fname); | |||
| } | |||
| if(sr2 != sr1*2) | |||
| @@ -1764,7 +1764,7 @@ static int LoadWavefile(FILE *f, const char *fname) | |||
| if((fd_temp = mkstemp(fname_temp)) >= 0) | |||
| { | |||
| close(fd_temp); | |||
| sprintf(command,"sox \"%s%s.wav\" -r %d -c 1 -w %s polyphase\n",path_source,fname,samplerate,fname_temp); | |||
| sprintf(command,"sox \"%s%s.wav\" -r %d -c 1 -w %s polyphase\n",path_source,fname,samplerate_native,fname_temp); | |||
| if(system(command) < 0) | |||
| { | |||
| error("Failed to resample: %s",command); | |||
| @@ -66,8 +66,10 @@ static const char *help_text = | |||
| "\t directory. <voice name> specifies the language\n" | |||
| "--path=\"<path>\"\n" | |||
| "\t Specifies the directory containing the espeak-data directory\n" | |||
| "--pho\n" | |||
| "\t Write mbrola phoneme data (.pho) to stdout, or to the file in --phonout\n" | |||
| "--phonout=\"<filename>\"\n" | |||
| "\t Write output from -x -X commands, and mbrola phoneme data, to this file\n" | |||
| "\t Write phoneme output from -x -X and --pho to this file\n" | |||
| "--punct=\"<characters>\"\n" | |||
| "\t Speak the names of punctuation characters during speaking. If\n" | |||
| "\t =<characters> is omitted, all punctuation is spoken.\n" | |||
| @@ -87,6 +89,7 @@ int samplerate; | |||
| int quiet = 0; | |||
| unsigned int samples_total = 0; | |||
| unsigned int samples_split = 0; | |||
| unsigned int samples_split_seconds = 0; | |||
| unsigned int wavefile_count = 0; | |||
| FILE *f_wavfile = NULL; | |||
| @@ -218,15 +221,18 @@ int OpenWavFile(char *path, int rate) | |||
| else | |||
| f_wavfile = fopen(path,"wb"); | |||
| if(f_wavfile != NULL) | |||
| if(f_wavfile == NULL) | |||
| { | |||
| fwrite(wave_hdr,1,24,f_wavfile); | |||
| Write4Bytes(f_wavfile,rate); | |||
| Write4Bytes(f_wavfile,rate * 2); | |||
| fwrite(&wave_hdr[32],1,12,f_wavfile); | |||
| return(0); | |||
| fprintf(stderr,"Can't write to: '%s'\n",path); | |||
| return(1); | |||
| } | |||
| return(1); | |||
| fwrite(wave_hdr,1,24,f_wavfile); | |||
| Write4Bytes(f_wavfile,rate); | |||
| Write4Bytes(f_wavfile,rate * 2); | |||
| fwrite(&wave_hdr[32],1,12,f_wavfile); | |||
| return(0); | |||
| } // end of OpenWavFile | |||
| @@ -266,25 +272,40 @@ static int SynthCallback(short *wav, int numsamples, espeak_EVENT *events) | |||
| return(0); | |||
| } | |||
| if(samples_split > 0) | |||
| while(events->type != 0) | |||
| { | |||
| // start a new WAV file when this limit is reached, at the next sentence boundary | |||
| while(events->type != 0) | |||
| if(events->type == espeakEVENT_SAMPLERATE) | |||
| { | |||
| if((events->type == espeakEVENT_SENTENCE) && (samples_total > samples_split)) | |||
| samplerate = events->id.number; | |||
| samples_split = samples_split_seconds * samplerate; | |||
| } | |||
| else | |||
| if(events->type == espeakEVENT_SENTENCE) | |||
| { | |||
| // start a new WAV file when the limit is reached, at this sentence boundary | |||
| if((samples_split > 0) && (samples_total > samples_split)) | |||
| { | |||
| CloseWavFile(); | |||
| samples_total = 0; | |||
| wavefile_count++; | |||
| } | |||
| events++; | |||
| } | |||
| events++; | |||
| } | |||
| if(f_wavfile == NULL) | |||
| { | |||
| sprintf(fname,"%s_%.2d%s",wavefile,++wavefile_count,filetype); | |||
| if(OpenWavFile(fname, samplerate) != 0) | |||
| return(1); | |||
| if(samples_split > 0) | |||
| { | |||
| sprintf(fname,"%s_%.2d%s",wavefile,wavefile_count+1,filetype); | |||
| if(OpenWavFile(fname, samplerate) != 0) | |||
| return(1); | |||
| } | |||
| else | |||
| { | |||
| if(OpenWavFile(wavefile, samplerate) != 0) | |||
| return(1); | |||
| } | |||
| } | |||
| if(numsamples > 0) | |||
| @@ -332,7 +353,8 @@ int main (int argc, char **argv) | |||
| {"stdout", no_argument, 0, 0x105}, | |||
| {"split", optional_argument, 0, 0x106}, | |||
| {"path", required_argument, 0, 0x107}, | |||
| {"phonout", required_argument, 0, 0x108}, | |||
| {"phonout", required_argument, 0, 0x108}, | |||
| {"pho", no_argument, 0, 0x109}, | |||
| {0, 0, 0, 0} | |||
| }; | |||
| @@ -360,7 +382,8 @@ int main (int argc, char **argv) | |||
| int wordgap = -1; | |||
| int option_capitals = -1; | |||
| int option_punctuation = -1; | |||
| int option_phonemes = -1; | |||
| int option_phonemes = 0; | |||
| int option_mbrola_phonemes = 0; | |||
| int option_linelength = 0; | |||
| int option_waveout = 0; | |||
| @@ -550,9 +573,9 @@ int main (int argc, char **argv) | |||
| case 0x106: // -- split | |||
| if(optarg2 == NULL) | |||
| samples_split = 30; // default 30 minutes | |||
| samples_split = 30 * 60; // default 30 minutes | |||
| else | |||
| samples_split = atoi(optarg2); | |||
| samples_split = atoi(optarg2) * 60; | |||
| break; | |||
| case 0x107: // --path | |||
| @@ -566,6 +589,10 @@ int main (int argc, char **argv) | |||
| } | |||
| break; | |||
| case 0x109: // --pho | |||
| option_mbrola_phonemes = 8; | |||
| break; | |||
| default: | |||
| exit(0); | |||
| } | |||
| @@ -576,7 +603,7 @@ int main (int argc, char **argv) | |||
| { | |||
| // writing to a file (or no output), we can use synchronous mode | |||
| samplerate = espeak_Initialize(AUDIO_OUTPUT_SYNCHRONOUS,0,data_path,0); | |||
| samples_split = (samplerate * samples_split) * 60; | |||
| samples_split = samplerate * samples_split_seconds; | |||
| espeak_SetSynthCallback(SynthCallback); | |||
| if(samples_split) | |||
| @@ -589,12 +616,6 @@ int main (int argc, char **argv) | |||
| *extn = 0; | |||
| } | |||
| } | |||
| else | |||
| if(option_waveout) | |||
| { | |||
| if(OpenWavFile(wavefile,samplerate) != 0) | |||
| exit(4); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| @@ -641,7 +662,7 @@ int main (int argc, char **argv) | |||
| espeak_SetParameter(espeakLINELENGTH,option_linelength,0); | |||
| if(option_punctuation == 2) | |||
| espeak_SetPunctuationList(option_punctlist); | |||
| espeak_SetPhonemeTrace(option_phonemes,f_phonemes_out); | |||
| espeak_SetPhonemeTrace(option_phonemes | option_mbrola_phonemes,f_phonemes_out); | |||
| if(filename[0]==0) | |||
| { | |||
| @@ -129,8 +129,6 @@ char param[80]; | |||
| if(argc > 1) | |||
| { | |||
| extern void VoiceReset(int control); | |||
| p = argv[1]; | |||
| j = 0; | |||
| while((param[j] = p[j]) != 0) j++; | |||
| @@ -1,205 +0,0 @@ | |||
| #ifndef MBROLIB_H | |||
| #define MBROLIB_H | |||
| /* | |||
| * mbrolib: mbrola wrapper. | |||
| * | |||
| * Copyright (C) 2007 Gilles Casse <[email protected]> | |||
| * | |||
| * This library is free software; you can redistribute it and/or | |||
| * modify it under the terms of the GNU Lesser General Public | |||
| * License as published by the Free Software Foundation; either | |||
| * version 3 of the License, or (at your option) any later version. | |||
| * | |||
| * This library is distributed in the hope that it will be useful, | |||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
| * Lesser General Public License for more details. | |||
| * | |||
| * You should have received a copy of the GNU Lesser General Public | |||
| * License along with this library; if not, write to the Free Software | |||
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
| * | |||
| */ | |||
| #ifdef __cplusplus | |||
| extern "C" { | |||
| #endif | |||
| /* < types */ | |||
| /** Parameters */ | |||
| typedef struct { | |||
| int ignore_error; /* 1=Ignore any fatal error or unknown diphone */ | |||
| char comment_char; /* Comment character */ | |||
| float volume_ratio; /* Volume ratio */ | |||
| float frequency_ratio; /* Applied to pitch points */ | |||
| float time_ratio; /* Applied to phone durations */ | |||
| } mbrolib_parameter; | |||
| /** Returned errors */ | |||
| typedef enum { | |||
| MBROLIB_OK=0, | |||
| MBROLIB_DATABASE_NOT_INSTALLED, | |||
| MBROLIB_INVAL, | |||
| MBROLIB_OUT_OF_MEMORY, | |||
| MBROLIB_OUT_OF_RANGE, | |||
| MBROLIB_READ_ERROR, | |||
| MBROLIB_WRITE_ERROR | |||
| } MBROLIB_ERROR; | |||
| /** Gender */ | |||
| typedef enum { | |||
| MBROLIB_FEMALE, | |||
| MBROLIB_MALE | |||
| } MBROLIB_GENDER; | |||
| /** Voice descriptor */ | |||
| typedef struct { | |||
| char *name; /* name (for example: "en1") */ | |||
| char *filename; /* database pathname (for example: "/usr/share/mbrola/voices/en1) */ | |||
| int rate; /* database sample rate */ | |||
| MBROLIB_GENDER gender; | |||
| const char *language; /* Language and optional dialect qualifier in ascii (e.g. en, fr_ca). */ | |||
| } mbrolib_voice; | |||
| /* > */ | |||
| /** Initialization, returns a new handle. | |||
| First function. | |||
| @param the_sample_rate: output rate in Hz (for example 22050). If 0, keep the original database rate. | |||
| @return handle (or NULL if error). | |||
| */ | |||
| void* mbrolib_init( int sample_rate); | |||
| typedef void* (t_mbrolib_init)(int); | |||
| /** Returns the list of the installed mbrola databases. | |||
| The databases are searched according to the MBROLA_PATH environment variable if set, | |||
| or under a default path otherwise (see MBROLA_PATH in mbrolib.c). | |||
| An array of voices is returned. The last item is set to NULL. | |||
| The caller must not free the returned items or the array. | |||
| @param the_handle previously given by mbrolib_init. | |||
| @return An array of voices. | |||
| */ | |||
| const mbrolib_voice ** mbrolib_list_voices( void* the_handle); | |||
| typedef const mbrolib_voice ** (t_mbrolib_list_voices)(void*); | |||
| /** Set voice | |||
| @param the_handle. | |||
| @param the_database (for example, "en1"). | |||
| @return error code (MBROLIB_OK, MBROLIB_DATABASE_NOT_INSTALLED, MBROLIB_INVAL). | |||
| */ | |||
| MBROLIB_ERROR mbrolib_set_voice( void* the_handle, const char* the_name); | |||
| typedef MBROLIB_ERROR (t_mbrolib_set_voice)( void*, const char*); | |||
| /** Get the current database parameters. | |||
| The caller supplies a pointer to an already allocated structure. | |||
| @param the_handle previously given by mbrolib_init. | |||
| @param the_parameters: pointer to the structure. | |||
| @return error code (MBROLIB_OK, MBROLIB_INVAL). | |||
| */ | |||
| MBROLIB_ERROR mbrolib_get_parameter(void* the_handle, mbrolib_parameter* the_parameter); | |||
| typedef MBROLIB_ERROR (t_mbrolib_get_parameter)(void*, mbrolib_parameter*); | |||
| /** Set the database parameters using the supplied data. | |||
| @param the_handle previously given by mbrolib_init. | |||
| @param the_parameters: pointer to the wished parameters. | |||
| @return error code (MBROLIB_OK, MBROLIB_INVAL). | |||
| */ | |||
| MBROLIB_ERROR mbrolib_set_parameter(void* the_handle, const mbrolib_parameter* the_parameter); | |||
| typedef MBROLIB_ERROR (t_mbrolib_set_parameter)(void*, const mbrolib_parameter*); | |||
| /** Write the mbrola phonemes in the internal buffer. | |||
| @param the_handle. | |||
| @param the_mbrola_phonemes. | |||
| @param the_size in bytes. | |||
| @return error code (MBROLIB_OK, MBROLIB_INVAL, MBROLIB_WRITE_ERROR, MBROLIB_READ_ERROR). | |||
| */ | |||
| MBROLIB_ERROR mbrolib_write(void* the_handle, const char* the_mbrola_phonemes, size_t the_size); | |||
| typedef MBROLIB_ERROR (t_mbrolib_write)(void*, const char*, size_t); | |||
| /** Read n bytes of the output samples. | |||
| @param the_handle. | |||
| @param the_samples (raw audio data, 16bits, mono). | |||
| @param the_size max number of int16 to read. | |||
| @param the_size number of int16 read. | |||
| @return error code (MBROLIB_OK, MBROLIB_INVAL, MBROLIB_READ_ERROR). | |||
| */ | |||
| MBROLIB_ERROR mbrolib_read(void* the_handle, short* the_samples, int the_max_size, int* the_read_size); | |||
| typedef MBROLIB_ERROR (t_mbrolib_read)(void*, short*, int, int*); | |||
| /** Flush | |||
| @param the_handle. | |||
| */ | |||
| void mbrolib_flush(void* the_handle); | |||
| typedef void (t_mbrolib_flush)(void*); | |||
| /** Release the handle | |||
| @param the_handle. | |||
| @return error code (MBROLIB_OK, MBROLIB_INVAL). | |||
| */ | |||
| MBROLIB_ERROR mbrolib_terminate(void* the_handle); | |||
| typedef MBROLIB_ERROR (t_mbrolib_terminate)(void*); | |||
| #ifdef __cplusplus | |||
| } | |||
| #endif | |||
| #endif | |||
| @@ -0,0 +1,578 @@ | |||
| /* | |||
| * mbrowrap -- A wrapper library around the mbrola binary | |||
| * providing a subset of the API from the Windows mbrola DLL. | |||
| * | |||
| * Copyright (C) 2010 by Nicolas Pitre <[email protected]> | |||
| * | |||
| * This program is free software; you can redistribute it and/or modify | |||
| * it under the terms of the GNU General Public License as published by | |||
| * the Free Software Foundation; either version 3 of the License, or | |||
| * (at your option) any later version. | |||
| * | |||
| * This program is distributed in the hope that it will be useful, | |||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| * GNU General Public License for more details. | |||
| */ | |||
| #include <stdarg.h> | |||
| #include <stdio.h> | |||
| #include <unistd.h> | |||
| #include <string.h> | |||
| #include <malloc.h> | |||
| #include <signal.h> | |||
| #include <fcntl.h> | |||
| #include <poll.h> | |||
| #include <errno.h> | |||
| #include <sys/types.h> | |||
| #include <sys/wait.h> | |||
| #include "mbrowrap.h" | |||
| /* | |||
| * mbrola instance parameters | |||
| */ | |||
| enum mbr_state { | |||
| MBR_INACTIVE = 0, | |||
| MBR_IDLE, | |||
| MBR_NEWDATA, | |||
| MBR_AUDIO, | |||
| MBR_WEDGED | |||
| }; | |||
| static enum mbr_state mbr_state; | |||
| static char *mbr_voice_path; | |||
| static int mbr_cmd_fd, mbr_audio_fd, mbr_error_fd, mbr_proc_stat; | |||
| static pid_t mbr_pid; | |||
| static int mbr_samplerate; | |||
| static float mbr_volume = 1.0; | |||
| static char mbr_errorbuf[160]; | |||
| struct datablock { | |||
| struct datablock *next; | |||
| int done; | |||
| int size; | |||
| char buffer[1]; /* 1 or more, dynamically allocated */ | |||
| }; | |||
| static struct datablock *mbr_pending_data_head, *mbr_pending_data_tail; | |||
| /* | |||
| * Private support code. | |||
| */ | |||
| static void log(const char *msg, ...) | |||
| { | |||
| va_list params; | |||
| va_start(params, msg); | |||
| vfprintf(stderr, msg, params); | |||
| fputc('\n', stderr); | |||
| va_end(params); | |||
| } | |||
| static void err(const char *err, ...) | |||
| { | |||
| va_list params; | |||
| va_start(params, err); | |||
| vsnprintf(mbr_errorbuf, sizeof(mbr_errorbuf), err, params); | |||
| va_end(params); | |||
| log("mbrola error: \"%s\"", mbr_errorbuf); | |||
| } | |||
| static int create_pipes(int p1[2], int p2[2], int p3[2]) | |||
| { | |||
| int error=0; | |||
| if (pipe(p1) != -1) { | |||
| if (pipe(p2) != -1) { | |||
| if (pipe(p3) != -1) { | |||
| return 0; | |||
| } else | |||
| error = errno; | |||
| close(p2[0]); | |||
| close(p2[1]); | |||
| } else | |||
| error = errno; | |||
| close(p1[0]); | |||
| close(p1[1]); | |||
| } | |||
| err("pipe(): %s", strerror(error)); | |||
| return -1; | |||
| } | |||
| static void close_pipes(int p1[2], int p2[2], int p3[2]) | |||
| { | |||
| close(p1[0]); | |||
| close(p1[1]); | |||
| close(p2[0]); | |||
| close(p2[1]); | |||
| close(p3[0]); | |||
| close(p3[1]); | |||
| } | |||
| static int start_mbrola(const char *voice_path) | |||
| { | |||
| int error, p_stdin[2], p_stdout[2], p_stderr[2]; | |||
| char charbuf[20]; | |||
| if (mbr_state != MBR_INACTIVE) { | |||
| err("mbrola init request when already initialized"); | |||
| return -1; | |||
| } | |||
| error = create_pipes(p_stdin, p_stdout, p_stderr); | |||
| if (error) | |||
| return -1; | |||
| mbr_pid = fork(); | |||
| if (mbr_pid == -1) { | |||
| error = errno; | |||
| close_pipes(p_stdin, p_stdout, p_stderr); | |||
| err("fork(): %s", strerror(error)); | |||
| return -1; | |||
| } | |||
| if (mbr_pid == 0) { | |||
| int i; | |||
| if (dup2(p_stdin[0], 0) == -1 || | |||
| dup2(p_stdout[1], 1) == -1 || | |||
| dup2(p_stderr[1], 2) == -1) { | |||
| snprintf(mbr_errorbuf, sizeof(mbr_errorbuf), | |||
| "dup2(): %s\n", strerror(errno)); | |||
| write(p_stderr[1], mbr_errorbuf, strlen(mbr_errorbuf)); | |||
| _exit(1); | |||
| } | |||
| for (i = p_stderr[1]; i > 2; i--) | |||
| close(i); | |||
| signal(SIGHUP, SIG_IGN); | |||
| signal(SIGINT, SIG_IGN); | |||
| signal(SIGQUIT, SIG_IGN); | |||
| signal(SIGTERM, SIG_IGN); | |||
| snprintf(charbuf, sizeof(charbuf), "%g", mbr_volume); | |||
| execlp("mbrola", "mbrola", "-e", "-v", charbuf, | |||
| voice_path, "-", "-.wav", (char *)NULL); | |||
| /* if execution reaches this point then the exec() failed */ | |||
| snprintf(mbr_errorbuf, sizeof(mbr_errorbuf), | |||
| "mbrola: %s\n", strerror(errno)); | |||
| write(2, mbr_errorbuf, strlen(mbr_errorbuf)); | |||
| _exit(1); | |||
| } | |||
| snprintf(charbuf, sizeof(charbuf), "/proc/%d/stat", mbr_pid); | |||
| mbr_proc_stat = open(charbuf, O_RDONLY); | |||
| if (mbr_proc_stat == -1) { | |||
| error = errno; | |||
| close_pipes(p_stdin, p_stdout, p_stderr); | |||
| waitpid(mbr_pid, NULL, 0); | |||
| mbr_pid = 0; | |||
| err("/proc is unaccessible: %s", strerror(error)); | |||
| return -1; | |||
| } | |||
| signal(SIGPIPE, SIG_IGN); | |||
| if (fcntl(p_stdin[1], F_SETFL, O_NONBLOCK) == -1 || | |||
| fcntl(p_stdout[0], F_SETFL, O_NONBLOCK) == -1 || | |||
| fcntl(p_stderr[0], F_SETFL, O_NONBLOCK) == -1) { | |||
| error = errno; | |||
| close_pipes(p_stdin, p_stdout, p_stderr); | |||
| waitpid(mbr_pid, NULL, 0); | |||
| mbr_pid = 0; | |||
| err("fcntl(): %s", strerror(error)); | |||
| return -1; | |||
| } | |||
| mbr_cmd_fd = p_stdin[1]; | |||
| mbr_audio_fd = p_stdout[0]; | |||
| mbr_error_fd = p_stderr[0]; | |||
| close(p_stdin[0]); | |||
| close(p_stdout[1]); | |||
| close(p_stderr[1]); | |||
| mbr_state = MBR_IDLE; | |||
| return 0; | |||
| } | |||
| static void stop_mbrola(void) | |||
| { | |||
| if (mbr_state == MBR_INACTIVE) | |||
| return; | |||
| close(mbr_proc_stat); | |||
| close(mbr_cmd_fd); | |||
| close(mbr_audio_fd); | |||
| close(mbr_error_fd); | |||
| if (mbr_pid) { | |||
| kill(mbr_pid, SIGTERM); | |||
| waitpid(mbr_pid, NULL, 0); | |||
| mbr_pid = 0; | |||
| } | |||
| mbr_state = MBR_INACTIVE; | |||
| } | |||
| static void free_pending_data(void) | |||
| { | |||
| struct datablock *p, *head = mbr_pending_data_head; | |||
| while (head) { | |||
| p = head; | |||
| head = head->next; | |||
| free(p); | |||
| } | |||
| mbr_pending_data_head = NULL; | |||
| mbr_pending_data_tail = NULL; | |||
| } | |||
| static int mbrola_has_errors(void) | |||
| { | |||
| int result, error; | |||
| result = read(mbr_error_fd, mbr_errorbuf, sizeof(mbr_errorbuf)-1); | |||
| if (result == -1) { | |||
| if (errno == EAGAIN) | |||
| return 0; | |||
| err("read(error): %s", strerror(errno)); | |||
| return -1; | |||
| } | |||
| if (result != 0) { | |||
| mbr_errorbuf[result] = 0; | |||
| if (mbr_errorbuf[result - 1] == '\n') | |||
| mbr_errorbuf[result - 1] = 0; | |||
| /* inhibit the reset signal message */ | |||
| if (strncmp(mbr_errorbuf, "Got a reset signal", 18) == 0) { | |||
| mbr_errorbuf[0] = 0; | |||
| return 0; | |||
| } | |||
| /* don't consider this fatal at this point */ | |||
| error = 0; | |||
| } else { | |||
| /* EOF on stderr, assume mbrola died. */ | |||
| pid_t pid; | |||
| int status, len; | |||
| const char *msg; | |||
| char msgbuf[80]; | |||
| pid = waitpid(mbr_pid, &status, WNOHANG); | |||
| if (!pid) { | |||
| msg = "mbrola closed stderr and did not exit"; | |||
| } else { | |||
| mbr_pid = 0; | |||
| if (WIFSIGNALED(status)) { | |||
| int sig = WTERMSIG(status); | |||
| snprintf(msgbuf, sizeof(msgbuf), | |||
| "mbrola died by signal %d", sig); | |||
| msg = msgbuf; | |||
| } else if (WIFEXITED(status)) { | |||
| int exst = WEXITSTATUS(status); | |||
| snprintf(msgbuf, sizeof(msgbuf), | |||
| "mbrola exited with status %d", exst); | |||
| msg = msgbuf; | |||
| } else { | |||
| msg = "mbrola died and wait status is weird"; | |||
| } | |||
| } | |||
| len = strlen(mbr_errorbuf); | |||
| if (!len) | |||
| snprintf(mbr_errorbuf, sizeof(mbr_errorbuf), "%s", msg); | |||
| else | |||
| snprintf(mbr_errorbuf+len, sizeof(mbr_errorbuf)-len, | |||
| ", (%s)", msg); | |||
| error = -1; | |||
| } | |||
| log("mbrola error: \"%s\"", mbr_errorbuf); | |||
| return error; | |||
| } | |||
| static int send_to_mbrola(const char *cmd) | |||
| { | |||
| ssize_t result; | |||
| int len; | |||
| if (!mbr_pid) | |||
| return -1; | |||
| len = strlen(cmd); | |||
| result = write(mbr_cmd_fd, cmd, len); | |||
| if (result == -1) { | |||
| int error = errno; | |||
| if (error == EPIPE && mbrola_has_errors()) { | |||
| return -1; | |||
| } else if (error == EAGAIN) { | |||
| result = 0; | |||
| } else { | |||
| err("write(): %s", strerror(error)); | |||
| return -1; | |||
| } | |||
| } | |||
| if (result != len) { | |||
| struct datablock *data; | |||
| data = (struct datablock *)malloc(sizeof(*data) + len - result); | |||
| if (data) { | |||
| data->next = NULL; | |||
| data->done = 0; | |||
| data->size = len - result; | |||
| memcpy(data->buffer, cmd + result, len - result); | |||
| result = len; | |||
| if (!mbr_pending_data_head) | |||
| mbr_pending_data_head = data; | |||
| else | |||
| mbr_pending_data_tail->next = data; | |||
| mbr_pending_data_tail = data; | |||
| } | |||
| } | |||
| return result; | |||
| } | |||
| static int mbrola_is_idle(void) | |||
| { | |||
| char *p; | |||
| char buffer[20]; /* looking for "12345 (mbrola) S" so 20 is plenty*/ | |||
| /* look in /proc to determine if mbrola is still running or sleeping */ | |||
| if (lseek(mbr_proc_stat, 0, SEEK_SET) != 0) | |||
| return 0; | |||
| if (read(mbr_proc_stat, buffer, sizeof(buffer)) != sizeof(buffer)) | |||
| return 0; | |||
| p = (char *)memchr(buffer, ')', sizeof(buffer)); | |||
| if (!p || (unsigned)(p - buffer) >= sizeof(buffer) - 2) | |||
| return 0; | |||
| return (p[1] == ' ' && p[2] == 'S'); | |||
| } | |||
| static ssize_t receive_from_mbrola(void *buffer, size_t bufsize) | |||
| { | |||
| int result, wait = 1; | |||
| size_t cursize = 0; | |||
| if (!mbr_pid) | |||
| return -1; | |||
| do { | |||
| struct pollfd pollfd[3]; | |||
| nfds_t nfds = 0; | |||
| int idle; | |||
| pollfd[0].fd = mbr_audio_fd; | |||
| pollfd[0].events = POLLIN; | |||
| nfds++; | |||
| pollfd[1].fd = mbr_error_fd; | |||
| pollfd[1].events = POLLIN; | |||
| nfds++; | |||
| if (mbr_pending_data_head) { | |||
| pollfd[2].fd = mbr_cmd_fd; | |||
| pollfd[2].events = POLLOUT; | |||
| nfds++; | |||
| } | |||
| idle = mbrola_is_idle(); | |||
| result = poll(pollfd, nfds, idle ? 0 : wait); | |||
| if (result == -1) { | |||
| err("poll(): %s", strerror(errno)); | |||
| return -1; | |||
| } | |||
| if (result == 0) { | |||
| if (idle) { | |||
| mbr_state = MBR_IDLE; | |||
| break; | |||
| } else { | |||
| if (wait >= 5000 * (4-1)/4) { | |||
| mbr_state = MBR_WEDGED; | |||
| err("mbrola process is stalled"); | |||
| break; | |||
| } else { | |||
| wait *= 4; | |||
| continue; | |||
| } | |||
| } | |||
| } | |||
| wait = 1; | |||
| if (pollfd[1].revents && mbrola_has_errors()) | |||
| return -1; | |||
| if (mbr_pending_data_head && pollfd[2].revents) { | |||
| struct datablock *head = mbr_pending_data_head; | |||
| char *data = head->buffer + head->done; | |||
| int left = head->size - head->done; | |||
| result = write(mbr_cmd_fd, data, left); | |||
| if (result == -1) { | |||
| int error = errno; | |||
| if (error == EPIPE && mbrola_has_errors()) | |||
| return -1; | |||
| err("write(): %s", strerror(error)); | |||
| return -1; | |||
| } | |||
| if (result != left) { | |||
| head->done += result; | |||
| } else { | |||
| mbr_pending_data_head = head->next; | |||
| free(head); | |||
| if (!mbr_pending_data_head) | |||
| mbr_pending_data_tail = NULL; | |||
| else | |||
| continue; | |||
| } | |||
| } | |||
| if (pollfd[0].revents) { | |||
| char *curpos = (char *)buffer + cursize; | |||
| size_t space = bufsize - cursize; | |||
| ssize_t obtained = read(mbr_audio_fd, curpos, space); | |||
| if (obtained == -1) { | |||
| err("read(): %s", strerror(errno)); | |||
| return -1; | |||
| } | |||
| cursize += obtained; | |||
| mbr_state = MBR_AUDIO; | |||
| } | |||
| } while (cursize < bufsize); | |||
| return cursize; | |||
| } | |||
| /* | |||
| * API functions. | |||
| */ | |||
| int init_MBR(const char *voice_path) | |||
| { | |||
| int error, result; | |||
| unsigned char wavhdr[45]; | |||
| error = start_mbrola(voice_path); | |||
| if (error) | |||
| return -1; | |||
| result = send_to_mbrola("#\n"); | |||
| if (result != 2) { | |||
| stop_mbrola(); | |||
| return -1; | |||
| } | |||
| /* we should actually be getting only 44 bytes */ | |||
| result = receive_from_mbrola(wavhdr, 45); | |||
| if (result != 44) { | |||
| err("unable to get .wav header from mbrola"); | |||
| stop_mbrola(); | |||
| return -1; | |||
| } | |||
| /* parse wavhdr to get mbrola voice samplerate */ | |||
| if (memcmp(wavhdr, "RIFF", 4) != 0 || | |||
| memcmp(wavhdr+8, "WAVEfmt ", 8) != 0) { | |||
| err("mbrola did not return a .wav header"); | |||
| stop_mbrola(); | |||
| return -1; | |||
| } | |||
| mbr_samplerate = wavhdr[24] + (wavhdr[25]<<8) + | |||
| (wavhdr[26]<<16) + (wavhdr[27]<<24); | |||
| //log("mbrola: voice samplerate = %d", mbr_samplerate); | |||
| /* remember the voice path for setVolumeRatio_MBR() */ | |||
| if (mbr_voice_path != voice_path) { | |||
| free(mbr_voice_path); | |||
| mbr_voice_path = strdup(voice_path); | |||
| } | |||
| return 0; | |||
| } | |||
| void close_MBR(void) | |||
| { | |||
| stop_mbrola(); | |||
| free_pending_data(); | |||
| free(mbr_voice_path); | |||
| mbr_voice_path = NULL; | |||
| mbr_volume = 1.0; | |||
| } | |||
| int reset_MBR() | |||
| { | |||
| int result, success = 1; | |||
| char dummybuf[4096]; | |||
| if (mbr_state == MBR_IDLE) | |||
| return 1; | |||
| if (!mbr_pid) | |||
| return 0; | |||
| if (kill(mbr_pid, SIGUSR1) == -1) | |||
| success = 0; | |||
| free_pending_data(); | |||
| result = write(mbr_cmd_fd, "\n#\n", 3); | |||
| if (result != 3) | |||
| success = 0; | |||
| do { | |||
| result = read(mbr_audio_fd, dummybuf, sizeof(dummybuf)); | |||
| } while (result > 0); | |||
| if (result != -1 || errno != EAGAIN) | |||
| success = 0; | |||
| if (!mbrola_has_errors() && success) | |||
| mbr_state = MBR_IDLE; | |||
| return success; | |||
| } | |||
| int read_MBR(void *buffer, int nb_samples) | |||
| { | |||
| int result = receive_from_mbrola(buffer, nb_samples * 2); | |||
| if (result > 0) | |||
| result /= 2; | |||
| return result; | |||
| } | |||
| int write_MBR(const char *data) | |||
| { | |||
| mbr_state = MBR_NEWDATA; | |||
| return send_to_mbrola(data); | |||
| } | |||
| int flush_MBR(void) | |||
| { | |||
| return send_to_mbrola("\n#\n") == 3; | |||
| } | |||
| int getFreq_MBR(void) | |||
| { | |||
| return mbr_samplerate; | |||
| } | |||
| void setVolumeRatio_MBR(float value) | |||
| { | |||
| if (value == mbr_volume) | |||
| return; | |||
| mbr_volume = value; | |||
| if (mbr_state != MBR_IDLE) | |||
| return; | |||
| /* | |||
| * We have no choice but to kill and restart mbrola with | |||
| * the new argument here. | |||
| */ | |||
| stop_mbrola(); | |||
| init_MBR(mbr_voice_path); | |||
| } | |||
| int lastErrorStr_MBR(char *buffer, int bufsize) | |||
| { | |||
| int result = snprintf(buffer, bufsize, "%s", mbr_errorbuf); | |||
| return result >= bufsize ? (bufsize - 1) : result; | |||
| } | |||
| void resetError_MBR(void) | |||
| { | |||
| mbr_errorbuf[0] = 0; | |||
| } | |||
| @@ -0,0 +1,108 @@ | |||
| /* | |||
| * mbrowrap -- A wrapper library around the mbrola binary | |||
| * providing a subset of the API from the Windows mbrola DLL. | |||
| * | |||
| * Copyright (C) 2010 by Nicolas Pitre <[email protected]> | |||
| * | |||
| * This program is free software; you can redistribute it and/or modify | |||
| * it under the terms of the GNU General Public License as published by | |||
| * the Free Software Foundation; either version 3 of the License, or | |||
| * (at your option) any later version. | |||
| * | |||
| * This program is distributed in the hope that it will be useful, | |||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| * GNU General Public License for more details. | |||
| */ | |||
| #ifndef MBROWRAP_H | |||
| #define MBROWRAP_H | |||
| #ifdef __cplusplus | |||
| extern "C" | |||
| { | |||
| #endif | |||
| /* | |||
| * Initialize mbrola. The 'voice_path' argument must contain the | |||
| * path and file name to the mbrola voice database to be used. Returned | |||
| * value is 0 on success, or an error code otherwise (currently only -1 | |||
| * is returned. If not successful, lastErrorStr_MBR() will provide the | |||
| * error reason. If this is successful, then close_MBR() must be called | |||
| * before init_MBR() can be called again. | |||
| */ | |||
| int init_MBR(const char *voice_path); | |||
| /* | |||
| * Stop mbrola and release any resources. It is necessary to call | |||
| * this after a successful call to init_MBR() before init_MBR() can be | |||
| * called again. | |||
| */ | |||
| void close_MBR(void); | |||
| /* | |||
| * Stop any ongoing processing and flush all buffers. After this call | |||
| * any synthesis request will start afresh. A non-zero value is returned | |||
| * on success, or 0 on failure. If not successful, lastErrorStr_MBR() will | |||
| * provide the error reason. | |||
| */ | |||
| int reset_MBR(); | |||
| /* | |||
| * Return at most 'nb_samples' audio samples into 'buffer'. The returned | |||
| * value is the actual number of samples returned, or -1 on error. | |||
| * If not successful, lastErrorStr_MBR() will provide the error reason. | |||
| * Samples are always 16-bit little endian. | |||
| */ | |||
| int read_MBR(void *buffer, int nb_samples); | |||
| /* | |||
| * Write a NULL terminated string of phoneme in the input buffer. | |||
| * Return the number of chars actually written, or -1 on error. | |||
| * If not successful, lastErrorStr_MBR() will provide the error reason. | |||
| */ | |||
| int write_MBR(const char *data); | |||
| /* | |||
| * Send a flush command to the mbrola input stream. | |||
| * This is currently similar to write_MBR("#\n"). Return 1 on success | |||
| * or 0 on failure. If not successful, lastErrorStr_MBR() will provide | |||
| * the error reason. | |||
| */ | |||
| int flush_MBR(void); | |||
| /* | |||
| * Return the audio sample frequency of the used voice database. | |||
| */ | |||
| int getFreq_MBR(void); | |||
| /* | |||
| * Overall volume. | |||
| */ | |||
| void setVolumeRatio_MBR(float value); | |||
| /* | |||
| * Copy into 'buffer' at most 'bufsize' bytes from the latest error | |||
| * message. This may also contain non-fatal errors from mbrola. The | |||
| * returned value is the actual number of bytes copied. When no error | |||
| * message is pending then an empty string is returned. Consecutive | |||
| * calls to lastErrorStr_MBR() will return the same message unless it | |||
| * is explicitly cleared with resetError_MBR(). | |||
| */ | |||
| int lastErrorStr_MBR(char *buffer, int bufsize); | |||
| /* | |||
| * Clear any pending error message. | |||
| */ | |||
| void resetError_MBR(void); | |||
| /* | |||
| * Tolerance to missing diphones (always active so this is ignored) | |||
| */ | |||
| static inline void setNoError_MBR(int no_error) { } | |||
| #ifdef __cplusplus | |||
| } | |||
| #endif | |||
| #endif | |||
| @@ -140,7 +140,6 @@ void SetSpeed(int control) | |||
| int s1; | |||
| int wpm; | |||
| int wpm2; | |||
| int test=0; | |||
| speed.loud_consonants = 0; | |||
| speed.min_sample_len = 450; | |||
| @@ -172,43 +171,6 @@ void SetSpeed(int control) | |||
| speed.loud_consonants = (wpm - 360) / 8; | |||
| } | |||
| #ifdef deleted | |||
| if(wpm >= 450) | |||
| { | |||
| // TEST | |||
| speed1 = 6; | |||
| speed2 = speed3 = 5; | |||
| speed.pause_factor = 12; | |||
| speed.clause_pause_factor = 15; | |||
| speed.wav_factor = 70; | |||
| speed.lenmod_factor = 53; | |||
| speed.min_sample_len = 400; | |||
| return; | |||
| } | |||
| if(wpm > 390) | |||
| { | |||
| // TEST | |||
| speed1 = 6; | |||
| speed2 = speed3 = 5; | |||
| speed.pause_factor = 13; | |||
| speed.clause_pause_factor = 15; | |||
| if(wpm >= 440) | |||
| { | |||
| speed.wav_factor = 72 - (wpm - 440)/4; | |||
| speed.lenmod_factor = 60 - (wpm - 440)/2; | |||
| speed.min_sample_len = 420 - (wpm - 440); | |||
| } | |||
| else | |||
| { | |||
| speed.wav_factor = 74; | |||
| speed.lenmod_factor = 65 - (wpm - 400)/10; | |||
| speed.min_sample_len = 450 - (wpm - 400)/2; | |||
| } | |||
| return; | |||
| } | |||
| #endif | |||
| wpm2 = wpm; | |||
| if(wpm > 359) wpm2 = 359; | |||
| if(wpm < 80) wpm2 = 80; | |||
| @@ -269,9 +231,6 @@ void SetSpeed(int control) | |||
| speed.min_sample_len = 420 - (wpm - 440); | |||
| } | |||
| if(test > 0) | |||
| speed.wav_factor = test; | |||
| speed.pause_factor = (256 * s1)/115; // full speed adjustment, used for pause length | |||
| speed.clause_pause_factor = 0; | |||
| @@ -98,8 +98,10 @@ static const char *help_text = | |||
| "\t directory. <voice name> specifies the language\n" | |||
| "--path=\"<path>\"\n" | |||
| "\t Specifies the directory containing the espeak-data directory\n" | |||
| "--pho\n" | |||
| "\t Write mbrola phoneme data (.pho) to stdout, or to the file in --phonout\n" | |||
| "--phonout=\"<filename>\"\n" | |||
| "\t Write output from -x -X commands, and mbrola phoneme data, to this file\n" | |||
| "\t Write phoneme output from -x -X and --pho to this file\n" | |||
| "--punct=\"<characters>\"\n" | |||
| "\t Speak the names of punctuation characters during speaking. If\n" | |||
| "\t =<characters> is omitted, all punctuation is spoken.\n" | |||
| @@ -214,7 +216,9 @@ void DisplayVoices(FILE *f_out, char *language) | |||
| } // end of DisplayVoices | |||
| void WVoiceChanged(voice_t *wvoice) | |||
| { | |||
| } | |||
| static int OpenWaveFile(const char *path, int rate) | |||
| //================================================= | |||
| @@ -472,7 +476,8 @@ int main (int argc, char **argv) | |||
| {"stdout", no_argument, 0, 0x105}, | |||
| {"split", optional_argument, 0, 0x106}, | |||
| {"path", required_argument, 0, 0x107}, | |||
| {"phonout", required_argument, 0, 0x108}, | |||
| {"phonout", required_argument, 0, 0x108}, | |||
| {"pho", no_argument, 0, 0x109}, | |||
| {0, 0, 0, 0} | |||
| }; | |||
| @@ -702,6 +707,10 @@ int main (int argc, char **argv) | |||
| } | |||
| break; | |||
| case 0x109: // --pho | |||
| option_mbrola_phonemes = 8; | |||
| break; | |||
| default: | |||
| exit(0); | |||
| } | |||
| @@ -59,6 +59,9 @@ static unsigned int my_unique_identifier=0; | |||
| static void* my_user_data=NULL; | |||
| static espeak_AUDIO_OUTPUT my_mode=AUDIO_OUTPUT_SYNCHRONOUS; | |||
| static int synchronous_mode = 1; | |||
| static int out_samplerate = 0; | |||
| static int voice_samplerate = 22050; | |||
| t_espeak_callback* synth_callback = NULL; | |||
| int (* uri_callback)(int, const char *, const char *) = NULL; | |||
| int (* phoneme_callback)(const char *) = NULL; | |||
| @@ -66,6 +69,13 @@ int (* phoneme_callback)(const char *) = NULL; | |||
| char path_home[N_PATH_HOME]; // this is the espeak-data directory | |||
| void WVoiceChanged(voice_t *wvoice) | |||
| {//================================= | |||
| // Voice change in wavegen | |||
| voice_samplerate = wvoice->samplerate; | |||
| } | |||
| #ifdef USE_ASYNC | |||
| static int dispatch_audio(short* outbuf, int length, espeak_EVENT* event) | |||
| @@ -85,6 +95,34 @@ static int dispatch_audio(short* outbuf, int length, espeak_EVENT* event) | |||
| { | |||
| case AUDIO_OUTPUT_PLAYBACK: | |||
| { | |||
| int event_type=0; | |||
| int event_data=0; | |||
| if(event) | |||
| { | |||
| event_type = event->type; | |||
| event_data = event->id.number; | |||
| } | |||
| if(event_type == espeakEVENT_SAMPLERATE) | |||
| { | |||
| voice_samplerate = event->id.number; | |||
| if(out_samplerate != voice_samplerate) | |||
| { | |||
| if(out_samplerate != 0) | |||
| { | |||
| // sound was previously open with a different sample rate | |||
| wave_close(my_audio); | |||
| sleep(1); | |||
| } | |||
| out_samplerate = voice_samplerate; | |||
| wave_init(voice_samplerate); | |||
| wave_set_callback_is_output_enabled( fifo_is_command_enabled); | |||
| my_audio = wave_open("alsa"); | |||
| event_init(); | |||
| } | |||
| } | |||
| if (outbuf && length && a_wave_can_be_played) | |||
| { | |||
| wave_write (my_audio, (char*)outbuf, 2*length); | |||
| @@ -220,17 +258,13 @@ static void select_output(espeak_AUDIO_OUTPUT output_type) | |||
| my_audio = NULL; | |||
| synchronous_mode = 1; | |||
| option_waveout = 1; // inhibit portaudio callback from wavegen.cpp | |||
| out_samplerate = 0; | |||
| switch(my_mode) | |||
| { | |||
| case AUDIO_OUTPUT_PLAYBACK: | |||
| // wave_init() is now called just before the first wave_write() | |||
| synchronous_mode = 0; | |||
| #ifdef USE_ASYNC | |||
| wave_init(); | |||
| wave_set_callback_is_output_enabled( fifo_is_command_enabled); | |||
| my_audio = wave_open("alsa"); | |||
| event_init(); | |||
| #endif | |||
| break; | |||
| case AUDIO_OUTPUT_RETRIEVAL: | |||
| @@ -734,19 +768,21 @@ ENTER("espeak_Initialize"); | |||
| return(EE_INTERNAL_ERROR); | |||
| option_phonemes = 0; | |||
| option_mbrola_phonemes = 0; | |||
| option_phoneme_events = (options & 1); | |||
| SetVoiceByName("default"); | |||
| VoiceReset(0); | |||
| // SetVoiceByName("default"); | |||
| for(param=0; param<N_SPEECH_PARAM; param++) | |||
| param_stack[0].parameter[param] = param_defaults[param]; | |||
| SetParameter(espeakRATE,170,0); | |||
| SetParameter(espeakRATE,175,0); | |||
| SetParameter(espeakVOLUME,100,0); | |||
| SetParameter(espeakCAPITALS,option_capitals,0); | |||
| SetParameter(espeakPUNCTUATION,option_punctuation,0); | |||
| SetParameter(espeakWORDGAP,0,0); | |||
| DoVoiceChange(voice); | |||
| // DoVoiceChange(voice); | |||
| #ifdef USE_ASYNC | |||
| fifo_init(); | |||
| @@ -1087,8 +1123,10 @@ ESPEAK_API void espeak_SetPhonemeTrace(int value, FILE *stream) | |||
| value=0 No phoneme output (default) | |||
| value=1 Output the translated phoneme symbols for the text | |||
| value=2 as (1), but also output a trace of how the translation was done (matching rules and list entries) | |||
| bit 3: produce mbrola pho data | |||
| */ | |||
| option_phonemes = value; | |||
| option_phonemes = value & 3; | |||
| option_mbrola_phonemes = value & 8; | |||
| f_trans = stream; | |||
| if(stream == NULL) | |||
| f_trans = stderr; | |||
| @@ -1163,6 +1201,7 @@ ESPEAK_API espeak_ERROR espeak_Terminate(void) | |||
| { | |||
| wave_close(my_audio); | |||
| wave_terminate(); | |||
| out_samplerate = 0; | |||
| } | |||
| #endif | |||
| @@ -50,12 +50,13 @@ Revision 5 | |||
| typedef enum { | |||
| espeakEVENT_LIST_TERMINATED = 0, // Retrieval mode: terminates the event list. | |||
| espeakEVENT_WORD = 1, // Start of word | |||
| espeakEVENT_SENTENCE, // Start of sentence | |||
| espeakEVENT_MARK, // Mark | |||
| espeakEVENT_PLAY, // Audio element | |||
| espeakEVENT_END, // End of sentence or clause | |||
| espeakEVENT_MSG_TERMINATED, // End of message | |||
| espeakEVENT_PHONEME // Phoneme, if enabled in espeak_Initialize() | |||
| espeakEVENT_SENTENCE = 2, // Start of sentence | |||
| espeakEVENT_MARK = 3, // Mark | |||
| espeakEVENT_PLAY = 4, // Audio element | |||
| espeakEVENT_END = 5, // End of sentence or clause | |||
| espeakEVENT_MSG_TERMINATED = 6, // End of message | |||
| espeakEVENT_PHONEME = 7, // Phoneme, if enabled in espeak_Initialize() | |||
| espeakEVENT_SAMPLERATE = 8 // internal use, set sample rate | |||
| } espeak_EVENT_TYPE; | |||
| @@ -44,7 +44,6 @@ | |||
| #ifdef LIBRARY | |||
| #define USE_ASYNC | |||
| //#define USE_MBROLA_LIB | |||
| #endif | |||
| #ifdef _ESPEAKEDIT | |||
| @@ -35,15 +35,11 @@ | |||
| extern int Read4Bytes(FILE *f); | |||
| extern void SetPitch2(voice_t *voice, int pitch1, int pitch2, int *pitch_base, int *pitch_range); | |||
| #ifdef USE_MBROLA_LIB | |||
| extern unsigned char *outbuf; | |||
| #ifndef PLATFORM_WINDOWS | |||
| #include "mbrolib.h" | |||
| void * mb_handle; | |||
| #include "mbrowrap.h" | |||
| #else | |||
| #include <windows.h> | |||
| @@ -64,7 +60,7 @@ PROCVV reset_MBR; | |||
| PROCIV lastError_MBR; | |||
| PROCVCI lastErrorStr_MBR; | |||
| PROCVI setNoError_MBR; | |||
| PROCVI setFreq_MBR; | |||
| PROCIV getFreq_MBR; | |||
| PROCVF setVolumeRatio_MBR; | |||
| @@ -103,13 +99,11 @@ void unload_MBR() | |||
| } | |||
| #endif // windows | |||
| #endif // USE_MBROLA_LIB | |||
| static MBROLA_TAB *mbrola_tab = NULL; | |||
| static int mbrola_control = 0; | |||
| int option_mbrola_phonemes; | |||
| espeak_ERROR LoadMbrolaTable(const char *mbrola_voice, const char *phtrans, int srate) | |||
| @@ -133,37 +127,35 @@ espeak_ERROR LoadMbrolaTable(const char *mbrola_voice, const char *phtrans, int | |||
| } | |||
| sprintf(path,"%s/mbrola/%s",path_home,mbrola_voice); | |||
| #ifdef USE_MBROLA_LIB | |||
| #ifdef PLATFORM_POSIX | |||
| if(GetFileLength(path) <= 0) | |||
| { | |||
| // mbrola voice file not found, look in /usr/share | |||
| sprintf(path,"/usr/share/mbrola/%s",mbrola_voice); | |||
| } | |||
| #endif | |||
| #ifdef PLATFORM_WINDOWS | |||
| if(load_MBR() == FALSE) // load mbrola.dll | |||
| return(EE_INTERNAL_ERROR); | |||
| #endif | |||
| if(init_MBR(path) != 0) // initialise the required mbrola voice | |||
| return(EE_NOT_FOUND); | |||
| setNoError_MBR(1); // don't stop on phoneme errors | |||
| #else | |||
| mb_handle = mbrolib_init(srate); | |||
| mbrolib_parameter m_parameters; | |||
| if(mb_handle == NULL) | |||
| return(EE_INTERNAL_ERROR); | |||
| MBROLIB_ERROR a_status = mbrolib_set_voice(mb_handle, mbrola_voice); | |||
| if(a_status != MBROLIB_OK) | |||
| return(EE_NOT_FOUND); | |||
| #endif // not windows | |||
| #endif // USE_MBROLA_LIB | |||
| // read eSpeak's mbrola phoneme translation data, eg. en1_phtrans | |||
| sprintf(path,"%s/mbrola_ph/%s",path_home,phtrans); | |||
| size = GetFileLength(path); | |||
| if((f_in = fopen(path,"r")) == NULL) | |||
| if((f_in = fopen(path,"r")) == NULL) { | |||
| close_MBR(); | |||
| return(EE_NOT_FOUND); | |||
| } | |||
| if((mbrola_tab = (MBROLA_TAB *)realloc(mbrola_tab,size)) == NULL) | |||
| { | |||
| fclose(f_in); | |||
| close_MBR(); | |||
| return(EE_INTERNAL_ERROR); | |||
| } | |||
| @@ -176,26 +168,16 @@ espeak_ERROR LoadMbrolaTable(const char *mbrola_voice, const char *phtrans, int | |||
| fread(mbrola_tab,size,1,f_in); | |||
| fclose(f_in); | |||
| #ifdef USE_MBROLA_LIB | |||
| #ifdef PLATFORM_WINDOWS | |||
| setVolumeRatio_MBR((float)(mbrola_control & 0xff) /16.0f); | |||
| #else | |||
| mbrolib_get_parameter(mb_handle,&m_parameters); | |||
| m_parameters.ignore_error = 1; | |||
| m_parameters.volume_ratio = (float)(mbrola_control & 0xff) /16.0; | |||
| mbrolib_set_parameter(mb_handle,&m_parameters); | |||
| #endif // not windows | |||
| #endif // USE_MBROLA_LIB | |||
| option_quiet = 1; | |||
| // srate = getFreq_MBR(); | |||
| samplerate = srate; | |||
| if(srate == 22050) | |||
| SetParameter(espeakVOICETYPE,0,0); | |||
| else | |||
| SetParameter(espeakVOICETYPE,1,0); | |||
| strcpy(mbrola_name,mbrola_voice); | |||
| mbrola_delay = 3800; // improve synchronization of events | |||
| // mbrola_delay = 3800; // improve synchronization of events | |||
| mbrola_delay = 1000; // improve synchronization of events | |||
| return(EE_OK); | |||
| } // end of LoadMbrolaTable | |||
| @@ -383,155 +365,10 @@ static char *WritePitch(int env, int pitch1, int pitch2, int split, int final) | |||
| } // end of WritePitch | |||
| #ifdef USE_MBROLA_LIB | |||
| static void MbrolaMarker(int type, int char_posn, int length, int value) | |||
| {//===================================================================== | |||
| MarkerEvent(type,(char_posn & 0xffffff) | (length << 24),value,outbuf); | |||
| } | |||
| static void MbrolaEmbedded(int &embix, int sourceix) | |||
| {//================================================= | |||
| // There were embedded commands in the text at this point | |||
| unsigned int word; // bit 7=last command for this word, bits 5,6 sign, bits 0-4 command | |||
| unsigned int value; | |||
| int command; | |||
| int sign=0; | |||
| do { | |||
| word = embedded_list[embix++]; | |||
| value = word >> 8; | |||
| command = word & 0x1f; | |||
| if((word & 0x60) == 0x60) | |||
| sign = -1; | |||
| else | |||
| if((word & 0x60) == 0x40) | |||
| sign = 1; | |||
| if(command < N_EMBEDDED_VALUES) | |||
| { | |||
| if(sign == 0) | |||
| embedded_value[command] = value; | |||
| else | |||
| embedded_value[command] += (value * sign); | |||
| } | |||
| switch(command & 0x1f) | |||
| { | |||
| case EMBED_M: // named marker | |||
| MbrolaMarker(espeakEVENT_MARK, (sourceix & 0x7ff) + clause_start_char, 0, value); | |||
| break; | |||
| } | |||
| } while ((word & 0x80) == 0); | |||
| } | |||
| #ifdef PLATFORM_WINDOWS | |||
| static int MbrolaSynth(char *p_mbrola) | |||
| {//=================================== | |||
| // p_mbrola is a string of mbrola pho lines - Windows | |||
| int len; | |||
| int finished; | |||
| int result=0; | |||
| if(synth_callback == NULL) | |||
| return(1); | |||
| if(p_mbrola == NULL) | |||
| flush_MBR(); | |||
| else | |||
| result = write_MBR(p_mbrola); | |||
| finished = 0; | |||
| while(!finished && ((len = read_MBR((short *)outbuf, outbuf_size/2)) > 0)) | |||
| { | |||
| out_ptr = outbuf + len*2; | |||
| if(event_list) | |||
| { | |||
| event_list[event_list_ix].type = espeakEVENT_LIST_TERMINATED; // indicates end of event list | |||
| event_list[event_list_ix].user_data = 0; | |||
| } | |||
| count_samples += len; | |||
| finished = synth_callback((short *)outbuf, len, event_list); | |||
| event_list_ix=0; | |||
| } | |||
| if(finished) | |||
| { | |||
| // cancelled by user, discard any unused mbrola speech | |||
| flush_MBR(); | |||
| while((len = read_MBR((short *)outbuf, outbuf_size/2)) > 0); | |||
| } | |||
| return(finished); | |||
| } // end of SynthMbrola | |||
| #else | |||
| static int MbrolaSynth(char *p_mbrola) | |||
| {//=================================== | |||
| // p_mbrola is a string of mbrola pho lines - Linux | |||
| // This is wrong | |||
| // It must be called from WavegenFill() | |||
| int len; | |||
| int finished; | |||
| int result=0; | |||
| if(synth_callback == NULL) | |||
| return(1); | |||
| if(p_mbrola == NULL) | |||
| mbrolib_flush(mb_handle); | |||
| else | |||
| result = mbrolib_write(mb_handle,p_mbrola,strlen(p_mbrola)); | |||
| finished = 0; | |||
| while(!finished && (mbrolib_read(mb_handle, (short *)out_ptr, (out_end - out_ptr)/2, &len) == MBROLIB_OK)) | |||
| { | |||
| if(len == 0) | |||
| break; | |||
| out_ptr += (len*2); | |||
| if(event_list) | |||
| { | |||
| event_list[event_list_ix].type = espeakEVENT_LIST_TERMINATED; // indicates end of event list | |||
| event_list[event_list_ix].user_data = 0; | |||
| } | |||
| count_samples += len; | |||
| finished = synth_callback((short *)outbuf, len, event_list); | |||
| event_list_ix=0; | |||
| } | |||
| if(finished) | |||
| { | |||
| // cancelled by user, discard any unused mbrola speech | |||
| mbrolib_flush(mb_handle); | |||
| while(mbrolib_read(mb_handle, (short *)outbuf, outbuf_size/2, &len) == MBROLIB_OK) | |||
| { | |||
| if(len == 0) | |||
| break; | |||
| } | |||
| } | |||
| return(finished); | |||
| } // end of SynthMbrola | |||
| #endif // not windows | |||
| #endif // USE_MBROLA_LIB | |||
| void MbrolaTranslate(PHONEME_LIST *plist, int n_phonemes, FILE *f_mbrola) | |||
| {//====================================================================== | |||
| int MbrolaTranslate(PHONEME_LIST *plist, int n_phonemes, int resume, FILE *f_mbrola) | |||
| {//================================================================================= | |||
| // Generate a mbrola pho file | |||
| unsigned int name; | |||
| int phix; | |||
| int len; | |||
| int len1; | |||
| PHONEME_TAB *ph; | |||
| @@ -552,21 +389,21 @@ void MbrolaTranslate(PHONEME_LIST *plist, int n_phonemes, FILE *f_mbrola) | |||
| char buf[80]; | |||
| char mbr_buf[120]; | |||
| #ifdef USE_MBROLA_LIB | |||
| int embedded_ix=0; | |||
| int word_count=0; | |||
| static int phix; | |||
| static int embedded_ix; | |||
| static int word_count; | |||
| event_list_ix = 0; | |||
| out_ptr = outbuf; | |||
| #ifdef PLATFORM_WINDOWS | |||
| setNoError_MBR(1); // don't stop on phoneme errors | |||
| #endif | |||
| #else | |||
| // fprintf(f_mbrola,";; v=%.2f\n",(float)(mbrola_control & 0xff)/16.0); // ;; v= has no effect on mbrola | |||
| #endif | |||
| if (!resume) { | |||
| phix = 1; | |||
| embedded_ix = 0; | |||
| word_count = 0; | |||
| } | |||
| for(phix=1; phix < n_phonemes; phix++) | |||
| while (phix < n_phonemes) | |||
| { | |||
| if (WcmdqFree() < MIN_WCMDQ) | |||
| return 1; | |||
| mbr_buf[0] = 0; | |||
| p = &plist[phix]; | |||
| @@ -576,24 +413,24 @@ void MbrolaTranslate(PHONEME_LIST *plist, int n_phonemes, FILE *f_mbrola) | |||
| ph_prev = plist[phix-1].ph; | |||
| ph_next = plist[phix+1].ph; | |||
| #ifdef USE_MBROLA_LIB | |||
| if(p->synthflags & SFLAG_EMBEDDED) | |||
| { | |||
| MbrolaEmbedded(embedded_ix, p->sourceix); | |||
| DoEmbedded(embedded_ix, p->sourceix); | |||
| } | |||
| if(p->newword & 4) | |||
| MbrolaMarker(espeakEVENT_SENTENCE, (p->sourceix & 0x7ff) + clause_start_char, 0, count_sentences); | |||
| if(p->newword & 4) | |||
| DoMarker(espeakEVENT_SENTENCE, (p->sourceix & 0x7ff) + clause_start_char, 0, count_sentences); | |||
| if(p->newword & 1) | |||
| MbrolaMarker(espeakEVENT_WORD, (p->sourceix & 0x7ff) + clause_start_char, p->sourceix >> 11, clause_start_word + word_count++); | |||
| #endif | |||
| DoMarker(espeakEVENT_WORD, (p->sourceix & 0x7ff) + clause_start_char, p->sourceix >> 11, clause_start_word + word_count++); | |||
| name = GetMbrName(p,ph,ph_prev,ph_next,&name2,&len_percent,&control); | |||
| if(control & 1) | |||
| phix++; | |||
| if(name == 0) | |||
| if(name == 0) { | |||
| phix++; | |||
| continue; // ignore this phoneme | |||
| } | |||
| if((ph->type == phPAUSE) && (name == ph->mnemonic)) | |||
| { | |||
| @@ -607,9 +444,7 @@ void MbrolaTranslate(PHONEME_LIST *plist, int n_phonemes, FILE *f_mbrola) | |||
| else | |||
| len = (80 * speed.wav_factor)/256; | |||
| #ifdef USE_MBROLA_LIB | |||
| MbrolaMarker(espeakEVENT_PHONEME, (p->sourceix & 0x7ff) + clause_start_char, 0, ph->mnemonic); | |||
| #endif | |||
| DoMarker(espeakEVENT_PHONEME, (p->sourceix & 0x7ff) + clause_start_char, 0, ph->mnemonic); | |||
| sprintf(buf,"%s\t",WordToString(name)); | |||
| strcat(mbr_buf,buf); | |||
| @@ -720,6 +555,7 @@ void MbrolaTranslate(PHONEME_LIST *plist, int n_phonemes, FILE *f_mbrola) | |||
| if(pause) | |||
| { | |||
| len += PauseLength(pause,0); | |||
| sprintf(buf,"_ \t%d\n",PauseLength(pause,0)); | |||
| strcat(mbr_buf,buf); | |||
| pause = 0; | |||
| @@ -731,39 +567,78 @@ void MbrolaTranslate(PHONEME_LIST *plist, int n_phonemes, FILE *f_mbrola) | |||
| } | |||
| else | |||
| { | |||
| #ifdef USE_MBROLA_LIB | |||
| if(MbrolaSynth(mbr_buf) != 0) | |||
| return; | |||
| #endif | |||
| int res = write_MBR(mbr_buf); | |||
| if (res < 0) | |||
| return 0; /* don't get stuck on error */ | |||
| if (res == 0) | |||
| return 1; | |||
| wcmdq[wcmdq_tail][0] = WCMD_MBROLA_DATA; | |||
| wcmdq[wcmdq_tail][1] = len; | |||
| WcmdqInc(); | |||
| } | |||
| } | |||
| #ifdef USE_MBROLA_LIB | |||
| MbrolaSynth(NULL); | |||
| #endif | |||
| } // end of MbrolaTranslate | |||
| phix++; | |||
| } | |||
| #ifdef TEST_MBROLA | |||
| if(!f_mbrola) | |||
| { | |||
| flush_MBR(); | |||
| static PHONEME_LIST mbrola_phlist; | |||
| static int mbrola_n_ph; | |||
| static int mbrola_phix; | |||
| // flush the mbrola output buffer | |||
| wcmdq[wcmdq_tail][0] = WCMD_MBROLA_DATA; | |||
| wcmdq[wcmdq_tail][1] = 500; | |||
| WcmdqInc(); | |||
| } | |||
| return 0; | |||
| } // end of MbrolaTranslate | |||
| int MbrolaFill(int fill_zeros) | |||
| {//=========================== | |||
| } | |||
| int MbrolaGenerate(PHONEME_LIST *phoneme_list, int *n_ph, int resume) | |||
| {//================================================================== | |||
| if(resume == 0) | |||
| FILE *f_mbrola = NULL; | |||
| if(*n_ph == 0) | |||
| return(0); | |||
| if(option_mbrola_phonemes) | |||
| { | |||
| mbrola_phlist = phoneme_list; | |||
| mbrola_n_ph = n_ph; | |||
| mbrola_phix = 0; | |||
| // send mbrola data to a file, not to the mbrola library | |||
| f_mbrola = f_trans; | |||
| } | |||
| resume(0); // finished phoneme list | |||
| int again = MbrolaTranslate(phoneme_list, *n_ph, resume, f_mbrola); | |||
| if (!again) | |||
| *n_ph = 0; | |||
| return again; | |||
| } | |||
| int MbrolaFill(int length, int resume) | |||
| {//=================================== | |||
| // Read audio data from Mbrola (length is in milisecs) | |||
| static int n_samples; | |||
| int req_samples, result; | |||
| if (!resume) | |||
| n_samples = samplerate * length / 1000; | |||
| req_samples = (out_end - out_ptr)/2; | |||
| if (req_samples > n_samples) | |||
| req_samples = n_samples; | |||
| result = read_MBR((short *)out_ptr, req_samples); | |||
| if (result <= 0) | |||
| return 0; | |||
| out_ptr += result*2; | |||
| n_samples -= result; | |||
| return n_samples ? 1 : 0; | |||
| } | |||
| void MbrolaReset(void) | |||
| {//=================== | |||
| // Reset the Mbrola engine and flush the pending audio | |||
| reset_MBR(); | |||
| } | |||
| #endif | |||
| @@ -35,7 +35,7 @@ | |||
| #include "translate.h" | |||
| #include "wave.h" | |||
| const char *version_string = "1.43.46 20.Jun.10"; | |||
| const char *version_string = "1.43.48 28.Jun.10"; | |||
| const int version_phdata = 0x014342; | |||
| int option_device_number = -1; | |||
| @@ -135,7 +135,7 @@ static void EndPitch(int voice_break) | |||
| syllable_centre = -1; | |||
| memset(vowel_transition,0,sizeof(vowel_transition)); | |||
| } | |||
| } // end of Synthesize::EndPitch | |||
| } // end of EndPitch | |||
| @@ -152,7 +152,7 @@ static void DoAmplitude(int amp, unsigned char *amp_env) | |||
| q[2] = (long)amp_env; | |||
| q[3] = amp; | |||
| WcmdqInc(); | |||
| } // end of Synthesize::DoAmplitude | |||
| } // end of DoAmplitude | |||
| @@ -181,7 +181,7 @@ static void DoPitch(unsigned char *env, int pitch1, int pitch2) | |||
| q[2] = (long)env; | |||
| q[3] = (pitch1 << 16) + pitch2; | |||
| WcmdqInc(); | |||
| } // end of Synthesize::DoPitch | |||
| } // end of DoPitch | |||
| @@ -223,7 +223,7 @@ static void DoPause(int length, int control) | |||
| wcmdq[wcmdq_tail][1] = len; | |||
| WcmdqInc(); | |||
| last_frame = NULL; | |||
| } // end of Synthesize::DoPause | |||
| } // end of DoPause | |||
| extern int seq_len_adjust; // temporary fix to advance the start point for playing the wav sample | |||
| @@ -1172,8 +1172,8 @@ if(which==1) | |||
| static void DoMarker(int type, int char_posn, int length, int value) | |||
| {//================================================================= | |||
| void DoMarker(int type, int char_posn, int length, int value) | |||
| {//========================================================== | |||
| // This could be used to return an index to the word currently being spoken | |||
| // Type 1=word, 2=sentence, 3=named marker, 4=play audio, 5=end | |||
| wcmdq[wcmdq_tail][0] = WCMD_MARKER; | |||
| @@ -1182,7 +1182,7 @@ static void DoMarker(int type, int char_posn, int length, int value) | |||
| wcmdq[wcmdq_tail][3] = value; | |||
| WcmdqInc(); | |||
| } // end of Synthesize::DoMarker | |||
| } // end of DoMarker | |||
| void DoVoiceChange(voice_t *v) | |||
| @@ -1198,8 +1198,8 @@ void DoVoiceChange(voice_t *v) | |||
| } | |||
| static void DoEmbedded(int &embix, int sourceix) | |||
| {//============================================= | |||
| void DoEmbedded(int &embix, int sourceix) | |||
| {//====================================== | |||
| // There were embedded commands in the text at this point | |||
| unsigned int word; // bit 7=last command for this word, bits 5,6 sign, bits 0-4 command | |||
| unsigned int value; | |||
| @@ -1279,14 +1279,12 @@ int Generate(PHONEME_LIST *phoneme_list, int *n_ph, int resume) | |||
| PHONEME_DATA phdata_tone; | |||
| FMT_PARAMS fmtp; | |||
| #ifdef TEST_MBROLA | |||
| if(mbrola_name[0] != 0) | |||
| return(MbrolaGenerate(phoneme_list,n_ph,resume)); | |||
| #endif | |||
| if(option_quiet) | |||
| return(0); | |||
| if(mbrola_name[0] != 0) | |||
| return(MbrolaGenerate(phoneme_list,n_ph,resume)); | |||
| if(resume == 0) | |||
| { | |||
| ix = 1; | |||
| @@ -1873,20 +1871,6 @@ int SpeakNextClause(FILE *f_in, const void *text_in, int control) | |||
| return(1); | |||
| } | |||
| if(mbrola_name[0] != 0) | |||
| { | |||
| #ifdef USE_MBROLA_LIB | |||
| MbrolaTranslate(phoneme_list,n_phoneme_list,NULL); | |||
| #else | |||
| { | |||
| FILE *f_mbrola; | |||
| if((f_mbrola = f_trans) == stderr) | |||
| f_mbrola = stdout; | |||
| MbrolaTranslate(phoneme_list,n_phoneme_list,f_mbrola); | |||
| } | |||
| #endif | |||
| } | |||
| Generate(phoneme_list,&n_phoneme_list,0); | |||
| WavegenOpenSound(); | |||
| @@ -462,6 +462,7 @@ extern unsigned char pitch_adjust_tab[MAX_PITCH_VALUE+1]; | |||
| #define WCMD_MARKER 10 | |||
| #define WCMD_VOICE 11 | |||
| #define WCMD_EMBEDDED 12 | |||
| #define WCMD_MBROLA_DATA 13 | |||
| #define N_WCMDQ 160 | |||
| @@ -557,8 +558,12 @@ espeak_ERROR SetVoiceByName(const char *name); | |||
| espeak_ERROR SetVoiceByProperties(espeak_VOICE *voice_selector); | |||
| espeak_ERROR LoadMbrolaTable(const char *mbrola_voice, const char *phtrans, int srate); | |||
| void SetParameter(int parameter, int value, int relative); | |||
| void MbrolaTranslate(PHONEME_LIST *plist, int n_phonemes, FILE *f_mbrola); | |||
| //int MbrolaSynth(char *p_mbrola); | |||
| int MbrolaTranslate(PHONEME_LIST *plist, int n_phonemes, int resume, FILE *f_mbrola); | |||
| int MbrolaGenerate(PHONEME_LIST *phoneme_list, int *n_ph, int resume); | |||
| int MbrolaFill(int length, int resume); | |||
| void MbrolaReset(void); | |||
| void DoEmbedded(int &embix, int sourceix); | |||
| void DoMarker(int type, int char_posn, int length, int value); | |||
| //int DoSample(PHONEME_TAB *ph1, PHONEME_TAB *ph2, int which, int length_mod, int amp); | |||
| int DoSample3(PHONEME_DATA *phdata, int length_mod, int amp); | |||
| int DoSpect2(PHONEME_TAB *this_ph, int which, FMT_PARAMS *fmt_params, PHONEME_LIST *plist, int modulation); | |||
| @@ -545,6 +545,7 @@ extern int option_tone_flags; | |||
| extern int option_waveout; | |||
| extern int option_quiet; | |||
| extern int option_phonemes; | |||
| extern int option_mbrola_phonemes; | |||
| extern int option_phoneme_events; | |||
| extern int option_linelength; // treat lines shorter than this as end-of-clause | |||
| extern int option_multibyte; | |||
| @@ -41,6 +41,7 @@ typedef struct { | |||
| int formant_factor; // adjust nominal formant frequencies by this because of the voice's pitch (256ths) | |||
| int consonant_amp; // amplitude of unvoiced consonants | |||
| int consonant_ampv; // amplitude of the noise component of voiced consonants | |||
| int samplerate; | |||
| int klattv[8]; | |||
| // parameters used by Wavegen | |||
| @@ -77,6 +78,8 @@ espeak_VOICE *SelectVoiceByName(espeak_VOICE **voices, const char *name); | |||
| voice_t *LoadVoice(const char *voice_name, int control); | |||
| voice_t *LoadVoiceVariant(const char *voice_name, int variant); | |||
| void DoVoiceChange(voice_t *v); | |||
| void WVoiceChanged(voice_t *wvoice); | |||
| void WavegenSetVoice(voice_t *v); | |||
| void ReadTonePoints(char *string, int *tone_pts); | |||
| void VoiceReset(int control); | |||
| @@ -408,6 +408,7 @@ void VoiceReset(int tone_only) | |||
| voice->voicing = 64; | |||
| voice->consonant_amp = 100; | |||
| voice->consonant_ampv = 100; | |||
| voice->samplerate = 22050; | |||
| memset(voice->klattv,0,sizeof(voice->klattv)); | |||
| memset(speed.fast_settings,0,sizeof(speed.fast_settings)); | |||
| @@ -921,6 +922,7 @@ voice_t *LoadVoice(const char *vname, int control) | |||
| phtrans[0] = 0; | |||
| sscanf(p,"%s %s %d",name,phtrans,&srate); | |||
| LoadMbrolaTable(name,phtrans,srate); | |||
| voice->samplerate = srate; | |||
| } | |||
| break; | |||
| @@ -56,15 +56,16 @@ enum {ONE_BILLION=1000000000}; | |||
| static t_wave_callback* my_callback_is_output_enabled=NULL; | |||
| #define N_WAV_BUF 10 | |||
| #define SAMPLE_RATE 22050 | |||
| #define MAX_SAMPLE_RATE 22050 | |||
| #define FRAMES_PER_BUFFER 512 | |||
| #define BUFFER_LENGTH (SAMPLE_RATE*2*sizeof(uint16_t)) | |||
| #define THRESHOLD (BUFFER_LENGTH/5) | |||
| #define BUFFER_LENGTH (MAX_SAMPLE_RATE*2*sizeof(uint16_t)) | |||
| //#define THRESHOLD (BUFFER_LENGTH/5) | |||
| static char myBuffer[BUFFER_LENGTH]; | |||
| static char* myRead=NULL; | |||
| static char* myWrite=NULL; | |||
| static int out_channels=1; | |||
| static int my_stream_could_start=0; | |||
| static int wave_samplerate; | |||
| static int mInCallbackFinishedState = false; | |||
| #if (USE_PORTAUDIO == 18) | |||
| @@ -335,7 +336,7 @@ static int wave_open_sound() | |||
| out_channels = 1; | |||
| #if USE_PORTAUDIO == 18 | |||
| // err = Pa_OpenDefaultStream(&pa_stream,0,1,paInt16,SAMPLE_RATE,FRAMES_PER_BUFFER,N_WAV_BUF,pa_callback,(void *)userdata); | |||
| // err = Pa_OpenDefaultStream(&pa_stream,0,1,paInt16,wave_samplerate,FRAMES_PER_BUFFER,N_WAV_BUF,pa_callback,(void *)userdata); | |||
| PaDeviceID playbackDevice = Pa_GetDefaultOutputDeviceID(); | |||
| @@ -351,7 +352,7 @@ static int wave_open_sound() | |||
| paInt16, | |||
| NULL, | |||
| /* general parameters */ | |||
| SAMPLE_RATE, FRAMES_PER_BUFFER, 0, | |||
| wave_samplerate, FRAMES_PER_BUFFER, 0, | |||
| //paClipOff | paDitherOff, | |||
| paNoFlag, | |||
| pa_callback, (void *)userdata); | |||
| @@ -376,12 +377,12 @@ static int wave_open_sound() | |||
| paInt16, | |||
| NULL, | |||
| /* general parameters */ | |||
| SAMPLE_RATE, FRAMES_PER_BUFFER, 0, | |||
| wave_samplerate, FRAMES_PER_BUFFER, 0, | |||
| //paClipOff | paDitherOff, | |||
| paNoFlag, | |||
| pa_callback, (void *)userdata); | |||
| // err = Pa_OpenDefaultStream(&pa_stream,0,2,paInt16, | |||
| // SAMPLE_RATE, | |||
| // wave_samplerate, | |||
| // FRAMES_PER_BUFFER, | |||
| // N_WAV_BUF,pa_callback,(void *)userdata); | |||
| SHOW("wave_open_sound > Pa_OpenDefaultStream(2): err=%d (%s)\n",err, Pa_GetErrorText(err)); | |||
| @@ -395,7 +396,7 @@ static int wave_open_sound() | |||
| &pa_stream, | |||
| NULL, /* no input */ | |||
| &myOutputParameters, | |||
| SAMPLE_RATE, | |||
| wave_samplerate, | |||
| framesPerBuffer, | |||
| paNoFlag, | |||
| // paClipOff | paDitherOff, | |||
| @@ -410,7 +411,7 @@ static int wave_open_sound() | |||
| &pa_stream, | |||
| NULL, /* no input */ | |||
| &myOutputParameters, | |||
| SAMPLE_RATE, | |||
| wave_samplerate, | |||
| framesPerBuffer, | |||
| paNoFlag, | |||
| // paClipOff | paDitherOff, | |||
| @@ -427,14 +428,14 @@ static int wave_open_sound() | |||
| &pa_stream, | |||
| NULL, /* no input */ | |||
| &myOutputParameters, | |||
| SAMPLE_RATE, | |||
| wave_samplerate, | |||
| framesPerBuffer, | |||
| paNoFlag, | |||
| // paClipOff | paDitherOff, | |||
| pa_callback, | |||
| (void *)userdata); | |||
| // err = Pa_OpenDefaultStream(&pa_stream,0,2,paInt16,(double)SAMPLE_RATE,FRAMES_PER_BUFFER,pa_callback,(void *)userdata); | |||
| // err = Pa_OpenDefaultStream(&pa_stream,0,2,paInt16,(double)wave_samplerate,FRAMES_PER_BUFFER,pa_callback,(void *)userdata); | |||
| } | |||
| mInCallbackFinishedState = false; | |||
| #endif | |||
| @@ -526,7 +527,7 @@ static void select_device(const char* the_api) | |||
| defaultAlsaIndex = hostInfo->defaultOutputDevice; | |||
| const PaDeviceInfo *deviceInfo = Pa_GetDeviceInfo( defaultAlsaIndex ); | |||
| update_output_parameters(defaultAlsaIndex, deviceInfo); | |||
| if (Pa_IsFormatSupported(NULL, &myOutputParameters, SAMPLE_RATE) == 0) | |||
| if (Pa_IsFormatSupported(NULL, &myOutputParameters, wave_samplerate) == 0) | |||
| { | |||
| SHOW( "select_device > ALSA (default), name=%s (#%d)\n", deviceInfo->name, defaultAlsaIndex); | |||
| selectedIndex = defaultAlsaIndex; | |||
| @@ -541,7 +542,7 @@ static void select_device(const char* the_api) | |||
| update_output_parameters(i, deviceInfo); | |||
| if (Pa_IsFormatSupported(NULL, &myOutputParameters, SAMPLE_RATE) == 0) | |||
| if (Pa_IsFormatSupported(NULL, &myOutputParameters, wave_samplerate) == 0) | |||
| { | |||
| SHOW( "select_device > ALSA, name=%s (#%d)\n", deviceInfo->name, i); | |||
| @@ -613,12 +614,13 @@ void wave_set_callback_is_output_enabled(t_wave_callback* cb) | |||
| //<wave_init | |||
| // TBD: the arg could be "alsa", "oss",... | |||
| void wave_init() | |||
| void wave_init(int srate) | |||
| { | |||
| ENTER("wave_init"); | |||
| PaError err; | |||
| pa_stream = NULL; | |||
| wave_samplerate = srate; | |||
| mInCallbackFinishedState = false; | |||
| init_buffer(); | |||
| @@ -1023,7 +1025,7 @@ int wave_get_remaining_time(uint32_t sample, uint32_t* time) | |||
| { | |||
| // TBD: take in account time suplied by portaudio V18 API | |||
| a_time = sample - myReadPosition; | |||
| a_time = 0.5 + (a_time * 1000.0) / SAMPLE_RATE; | |||
| a_time = 0.5 + (a_time * 1000.0) / wave_samplerate; | |||
| } | |||
| else | |||
| { | |||
| @@ -1050,7 +1052,7 @@ void *wave_test_get_write_buffer() | |||
| // notdef USE_PORTAUDIO | |||
| void wave_init() {} | |||
| void wave_init(int srate) {} | |||
| void* wave_open(const char* the_api) {return (void *)1;} | |||
| size_t wave_write(void* theHandler, char* theMono16BitsWaveBuffer, size_t theSize) {return theSize;} | |||
| int wave_close(void* theHandler) {return 0;} | |||
| @@ -7,7 +7,7 @@ | |||
| extern int option_device_number; | |||
| extern void wave_init(); | |||
| extern void wave_init(int samplerate); | |||
| // TBD: the arg could be "alsa", "oss",... | |||
| extern void* wave_open(const char* the_api); | |||
| @@ -65,7 +65,6 @@ enum { | |||
| static t_wave_callback* my_callback_is_output_enabled=NULL; | |||
| #define SAMPLE_RATE 22050 | |||
| #define ESPEAK_FORMAT PA_SAMPLE_S16LE | |||
| #define ESPEAK_CHANNEL 1 | |||
| @@ -90,6 +89,7 @@ static int time_offset_msec = 0; | |||
| static int just_flushed = 0; | |||
| static int connected = 0; | |||
| static int wave_samplerate; | |||
| #define CHECK_DEAD_GOTO(label, warn) do { \ | |||
| if (!mainloop || \ | |||
| @@ -475,7 +475,7 @@ static int pulse_open() | |||
| pthread_mutex_init( &pulse_mutex, (const pthread_mutexattr_t *)NULL); | |||
| ss.format = ESPEAK_FORMAT; | |||
| ss.rate = SAMPLE_RATE; | |||
| ss.rate = wave_samplerate; | |||
| ss.channels = ESPEAK_CHANNEL; | |||
| if (!pa_sample_spec_valid(&ss)) | |||
| @@ -677,11 +677,12 @@ void wave_set_callback_is_output_enabled(t_wave_callback* cb) | |||
| //> | |||
| //<wave_init | |||
| void wave_init() | |||
| void wave_init(int srate) | |||
| { | |||
| ENTER("wave_init"); | |||
| stream = NULL; | |||
| wave_samplerate = srate; | |||
| pulse_open(); | |||
| } | |||
| @@ -846,7 +847,7 @@ int wave_get_remaining_time(uint32_t sample, uint32_t* time) | |||
| { | |||
| // TBD: take in account time suplied by portaudio V18 API | |||
| a_time = sample - a_timing_info.read_index; | |||
| a_time = 0.5 + (a_time * 1000.0) / SAMPLE_RATE; | |||
| a_time = 0.5 + (a_time * 1000.0) / wave_samplerate; | |||
| } | |||
| else | |||
| { | |||
| @@ -77,12 +77,14 @@ static uint32_t last_play_position=0; | |||
| // | |||
| //<wave_init | |||
| void wave_init() { | |||
| void wave_init(int srate) { | |||
| ENTER("wave_init"); | |||
| audio_info_t ainfo; | |||
| char *audio_device = NULL; | |||
| wave_samplerate = srate; | |||
| audio_device = getenv("AUDIODEV"); | |||
| if (audio_device != NULL) { | |||
| if ((sun_audio_fd = open(audio_device, O_WRONLY)) < 0) { | |||
| @@ -108,7 +110,7 @@ void wave_init() { | |||
| SHOW("wave_init() play buffer size: %d\n", ainfo.play.buffer_size); | |||
| ainfo.play.encoding = AUDIO_ENCODING_LINEAR; | |||
| ainfo.play.channels = 1; | |||
| ainfo.play.sample_rate = SAMPLE_RATE; | |||
| ainfo.play.sample_rate = wave_samplerate; | |||
| ainfo.play.precision = SAMPLE_SIZE; | |||
| if (ioctl(sun_audio_fd, AUDIO_SETINFO, &ainfo) == -1) { | |||
| @@ -520,7 +522,7 @@ int wave_get_remaining_time(uint32_t sample, uint32_t* time) | |||
| (actual_index <= ainfo.play.samples)) { | |||
| *time = 0; | |||
| } else { | |||
| a_time = ((actual_index - ainfo.play.samples) * 1000) / SAMPLE_RATE; | |||
| a_time = ((actual_index - ainfo.play.samples) * 1000) / wave_samplerate; | |||
| *time = (uint32_t) a_time; | |||
| } | |||
| SHOW("wave_get_remaining_time for %d: %d\n", sample, *time); | |||
| @@ -288,6 +288,8 @@ void WcmdqStop() | |||
| #ifdef USE_PORTAUDIO | |||
| Pa_AbortStream(pa_stream); | |||
| #endif | |||
| if(mbrola_name[0] != 0) | |||
| MbrolaReset(); | |||
| } | |||
| @@ -1563,6 +1565,8 @@ void WavegenSetVoice(voice_t *v) | |||
| option_harmonic1 = 6; | |||
| } | |||
| WavegenSetEcho(); | |||
| MarkerEvent(espeakEVENT_SAMPLERATE,0,wvoice->samplerate,out_ptr); | |||
| // WVoiceChanged(wvoice); | |||
| } | |||
| @@ -1797,11 +1801,6 @@ int WavegenFill(int fill_zeros) | |||
| static int resume=0; | |||
| static int echo_complete=0; | |||
| #ifdef TEST_MBROLA | |||
| if(mbrola_name[0] != 0) | |||
| return(MbrolaFill(fill_zeros)); | |||
| #endif | |||
| while(out_ptr < out_end) | |||
| { | |||
| if(WcmdqUsed() <= 0) | |||
| @@ -1904,6 +1903,10 @@ int WavegenFill(int fill_zeros) | |||
| case WCMD_EMBEDDED: | |||
| SetEmbedded(q[1],q[2]); | |||
| break; | |||
| case WCMD_MBROLA_DATA: | |||
| result = MbrolaFill(length, resume); | |||
| break; | |||
| } | |||
| if(result==0) | |||