_2X t'y:w | _2X t'y:w | ||||
_3X tR'&#Dv@ //PB [tR'ADv@] changed to [tR'&#Dv@] | _3X tR'&#Dv@ //PB [tR'ADv@] changed to [tR'&#Dv@] | ||||
_4X f'WRV //PB [f'W:*3] changed to [ f'WRV] | _4X f'WRV //PB [f'W:*3] changed to [ f'WRV] | ||||
_5X hal't*es | |||||
_5X h&l't*es // PB [a] changed to [&] | |||||
_6X t*'es | _6X t*'es | ||||
_7X halfj'&rs | |||||
_7X h&lfj'&rs // PV a changed to & | |||||
_8X f'irs | _8X f'irs | ||||
_9X h&lf'Ems // PB a changed to & | _9X h&lf'Ems // PB a changed to & | ||||
_0C h'un*@:D | _0C h'un*@:D | ||||
et ed $u | et ed $u | ||||
her $u | her $u | ||||
kun $u | kun $u | ||||
vel $u+ | |||||
da $u | |||||
// conjunctions | // conjunctions | ||||
og V $u+ $pause // and | og V $u+ $pause // and | ||||
af & // PB changed from [a?] to [&] - sound too short in a sentence | af & // PB changed from [a?] to [&] - sound too short in a sentence | ||||
// Also removed $u from 'af' and other words. They disappeared. | // Also removed $u from 'af' and other words. They disappeared. | ||||
ad &: // PB added 'ad' | ad &: // PB added 'ad' | ||||
ad &D $atend $sentence // PB "Det må ikke skille os ad." | |||||
at &: $u // PB changed from [at] to [&:] | at &: $u // PB changed from [at] to [&:] | ||||
hos // at - PB: removed [$u+] | hos // at - PB: removed [$u+] | ||||
som sVm // which / that - PB: removed [$u+] | som sVm // which / that - PB: removed [$u+] | ||||
g ge: | g ge: | ||||
h hO: | h hO: | ||||
_i i: | _i i: | ||||
j joD | |||||
j jVD // PB changed from [o] | |||||
k kO: | k kO: | ||||
l El | l El | ||||
m Em | m Em | ||||
image _^_EN | image _^_EN | ||||
joke _^_EN | joke _^_EN | ||||
joystick _^_EN | joystick _^_EN | ||||
junkie _^_EN | |||||
laptop _^_EN | laptop _^_EN | ||||
level _^_EN | level _^_EN | ||||
login _^_EN | login _^_EN | ||||
penthouse _^_EN | penthouse _^_EN | ||||
pickup _^_EN | pickup _^_EN | ||||
pidgin _^_EN | pidgin _^_EN | ||||
producer _^_EN | |||||
ranger _^_EN | ranger _^_EN | ||||
receiver _^_EN | receiver _^_EN | ||||
research _^_EN | research _^_EN | ||||
remake _^_EN | remake _^_EN | ||||
roadie _^_EN | roadie _^_EN | ||||
roastbeef _^_EN | |||||
run _^_EN | run _^_EN | ||||
scanner _^_EN | scanner _^_EN | ||||
science _^_EN | science _^_EN | ||||
snob _^_EN | snob _^_EN | ||||
song _^_EN | song _^_EN | ||||
source _^_EN | source _^_EN | ||||
spam _^_EN | |||||
spirit _^_EN | spirit _^_EN | ||||
squaw _^_EN | squaw _^_EN | ||||
sweatshirt _^_EN | sweatshirt _^_EN | ||||
dioxin $alt | dioxin $alt | ||||
disciplin $alt | disciplin $alt | ||||
doktrin $alt | doktrin $alt | ||||
(drive-in) drajv'in $alt | |||||
//(drive-in) drajv'in $alt | |||||
dusin $alt | dusin $alt | ||||
endokrin $alt | endokrin $alt | ||||
endorfin $alt | endorfin $alt | ||||
magasin $alt | magasin $alt | ||||
mandarin $alt | mandarin $alt | ||||
mandolin $alt | mandolin $alt | ||||
mannequin m&n@k'EN $alt | |||||
margin $alt | margin $alt | ||||
marin $alt | marin $alt | ||||
marocain mAro'kEN $alt | marocain mAro'kEN $alt | ||||
adviser $alt | adviser $alt | ||||
advoker $alt | advoker $alt | ||||
afficer $alt | afficer $alt | ||||
aflever $alt | |||||
afmarcher $alt | afmarcher $alt | ||||
afrikaniser $alt | afrikaniser $alt | ||||
agere $alt | agere $alt | ||||
bandagere $alt | bandagere $alt | ||||
banderolere $alt | banderolere $alt | ||||
barbariser $alt | barbariser $alt | ||||
barber $alt | |||||
barbere $alt | |||||
barder $alt | barder $alt | ||||
barrier $alt | barrier $alt | ||||
barrikader $alt | barrikader $alt | ||||
boniter $alt | boniter $alt | ||||
botaniser $alt | botaniser $alt | ||||
braiser $alt | braiser $alt | ||||
briketter $alt | |||||
brikettere $alt | |||||
brillere $alt | brillere $alt | ||||
brochere $alt | brochere $alt | ||||
brodere $alt | brodere $alt | ||||
brunere $alt | brunere $alt | ||||
brutaliser $alt | brutaliser $alt | ||||
bruyere bryj'E:r $alt | bruyere bryj'E:r $alt | ||||
budgetter $alt | |||||
budgettere $alt | |||||
bugser $alt | bugser $alt | ||||
bureaukratiser $alt | bureaukratiser $alt | ||||
cadmier $alt | cadmier $alt | ||||
dereguler $alt | dereguler $alt | ||||
deriver $alt | deriver $alt | ||||
desarmer $alt | desarmer $alt | ||||
deserter $alt | |||||
desertere $alt | |||||
designere $alt | designere $alt | ||||
desinficer $alt | desinficer $alt | ||||
destiller $alt | destiller $alt | ||||
fasciner $alt | fasciner $alt | ||||
favoriser $alt | favoriser $alt | ||||
feminiser $alt | feminiser $alt | ||||
ferier $alt | |||||
feriere $alt | |||||
fermenter $alt | fermenter $alt | ||||
ferniser $alt | ferniser $alt | ||||
fertiliser $alt | fertiliser $alt | ||||
harceler $alt | harceler $alt | ||||
harmoner $alt | harmoner $alt | ||||
harmoniser $alt | harmoniser $alt | ||||
harpuner $alt | |||||
harpunere $alt | |||||
havarer $alt | havarer $alt | ||||
hektografer $alt | hektografer $alt | ||||
herbariser $alt | herbariser $alt | ||||
introducer $alt | introducer $alt | ||||
intuber $alt | intuber $alt | ||||
invader $alt | invader $alt | ||||
invalider $alt | |||||
invalidere $alt | |||||
inventer $alt | inventer $alt | ||||
inverter $alt | inverter $alt | ||||
invester $alt | invester $alt | ||||
lancer $alt | lancer $alt | ||||
lasere $alt | lasere $alt | ||||
latiniser $alt | latiniser $alt | ||||
//lavere $alt | |||||
lavpasteuriser $alt | lavpasteuriser $alt | ||||
legaliser $alt | legaliser $alt | ||||
leger $alt | leger $alt | ||||
planere $alt | planere $alt | ||||
plastificer $alt | plastificer $alt | ||||
platiner $alt | platiner $alt | ||||
pletter $alt | |||||
plettere $alt | |||||
plisser $alt | plisser $alt | ||||
plomber $alt | plomber $alt | ||||
plæder $alt | plæder $alt | ||||
prober $alt | prober $alt | ||||
problematiser $alt | problematiser $alt | ||||
proceder $alt | proceder $alt | ||||
producer $alt | |||||
producere $alt | |||||
profaner $alt | profaner $alt | ||||
professionaliser $alt | professionaliser $alt | ||||
profeter $alt | profeter $alt | ||||
præjudicer $alt | præjudicer $alt | ||||
prækvalificer $alt | prækvalificer $alt | ||||
præluder $alt | præluder $alt | ||||
præmier $alt | |||||
præmiere $alt | |||||
prænumerer $alt | prænumerer $alt | ||||
præparer $alt | præparer $alt | ||||
præsenter $alt | præsenter $alt | ||||
ranger $alt | ranger $alt | ||||
rappeller $alt | rappeller $alt | ||||
rapportere $alt | rapportere $alt | ||||
raser $alt | |||||
rasere $alt | |||||
ratificer $alt | ratificer $alt | ||||
ratihaber $alt | ratihaber $alt | ||||
rationaliser $alt | rationaliser $alt | ||||
reinvester $alt | reinvester $alt | ||||
rejicer $alt | rejicer $alt | ||||
rekapituler $alt | rekapituler $alt | ||||
reklamer $alt | |||||
reklamere $alt | |||||
rekognoscer $alt | rekognoscer $alt | ||||
rekommander $alt | rekommander $alt | ||||
rekompenser $alt | rekompenser $alt | ||||
staffer $alt | staffer $alt | ||||
stagner $alt | stagner $alt | ||||
standardiser $alt | standardiser $alt | ||||
stationer $alt | |||||
stationere $alt | |||||
statuere $alt | statuere $alt | ||||
stenciler $alt | stenciler $alt | ||||
stenografer $alt | stenografer $alt | ||||
tender $alt | tender $alt | ||||
teoretiser $alt | teoretiser $alt | ||||
termografer $alt | termografer $alt | ||||
terrasser $alt | |||||
terrassere $alt | |||||
terroriser $alt | terroriser $alt | ||||
testamenter $alt | |||||
testamentere $alt | |||||
testere $alt | testere $alt | ||||
tiere $alt | tiere $alt | ||||
titrer $alt | titrer $alt | ||||
verificer $alt | verificer $alt | ||||
verser $alt | verser $alt | ||||
versificer $alt | versificer $alt | ||||
versioner $alt | |||||
versionere $alt | |||||
vibrer $alt | vibrer $alt | ||||
vidimer $alt | vidimer $alt | ||||
vikarier $alt | vikarier $alt | ||||
idet id'e // in so far as | idet id'e // in so far as | ||||
bleg blaj | bleg blaj | ||||
blegrød blajrWD | blegrød blajrWD | ||||
blegrøde blajrWD@ | |||||
//blege blaj@ | //blege blaj@ | ||||
blegemiddel bl&#j@mid@l | blegemiddel bl&#j@mid@l | ||||
//blegansigt bl&#jansegt | //blegansigt bl&#jansegt | ||||
slags sl'ags // sort, type | slags sl'ags // sort, type | ||||
tre tr'e // the number 3 | 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 | //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] | rejicere rejis'eV // PB should not be pronounced [raje] | ||||
rejicerer rejis'eV // PB | rejicerer rejis'eV // PB | ||||
rejiceres rejis'eVs // PB | rejiceres rejis'eVs // PB | ||||
rejicering rejis'eRiN // PB | rejicering rejis'eRiN // PB | ||||
gele sjel'e // PB gele | gele sjel'e // PB gele | ||||
géle sjel'e // PB géle | |||||
gelé sjel'e // PB gelé | |||||
geleen sjel'e@-n // PB geleen | geleen sjel'e@-n // PB geleen | ||||
geleer sjel'e3 // PB geleer | geleer sjel'e3 // PB geleer | ||||
geleens sjel'e@-ns // PB geleens | geleens sjel'e@-ns // PB geleens | ||||
(tour de force) tu:@d@||'fV:s // PB | (tour de force) tu:@d@||'fV:s // PB | ||||
(al qaeda) al||k'ajda // PB | (al qaeda) al||k'ajda // PB | ||||
(force majeure) fVrs||,ma'sjW:r // PB | (force majeure) fVrs||,ma'sjW:r // PB | ||||
(diner transportable) din'e|trANspVt'abl@ // PB | |||||
(quiche lorraine) kiS||lor'E:n: | (quiche lorraine) kiS||lor'E:n: | ||||
(fait accompli) fEtakVmpl'i // PB | (fait accompli) fEtakVmpl'i // PB | ||||
wien v'i:n // PB Wien - the town of Vienna | wien v'i:n // PB Wien - the town of Vienna | ||||
sos $abbrev // PB the SOS signal | sos $abbrev // PB the SOS signal | ||||
pharm fA:rm? $hasdot // PB fx cand. pharm. | pharm fA:rm? $hasdot // PB fx cand. pharm. | ||||
phil fil/3 $hasdot // PB fx cand. phil. | phil fil/3 $hasdot // PB fx cand. phil. | ||||
bh $abbrev | |||||
(bh'er) b,e:h'O:V | |||||
// Try to catch errors | // Try to catch errors | ||||
(vi steg) vi||st'e | (vi steg) vi||st'e | ||||
(de steg) di||st'e | (de steg) di||st'e | ||||
(alle steg) &l3||st'e | (alle steg) &l3||st'e | ||||
steg sdaj $atend $sentence | |||||
steget ste@d | steget ste@d | ||||
// PB problem with noun "hav" = ocean and verb "hav(e)" = to have [hAu]/[h&v] | // PB problem with noun "hav" = ocean and verb "hav(e)" = to have [hAu]/[h&v] | ||||
(et hav) ed||h'Au // PB "et hav" = an ocean - not "hav en god dag" - have a nice day | (et hav) ed||h'Au // PB "et hav" = an ocean - not "hav en god dag" - have a nice day | ||||
(så længe) sV||l'EN3 | (så længe) sV||l'EN3 | ||||
(så må) sV||m'O | (så må) sV||m'O | ||||
(så har) sV||har | (så har) sV||har | ||||
så sV $sentence $atstart | |||||
(virkede så) v'irkeD@||sV | (virkede så) v'irkeD@||sV | ||||
(kom så) kVm||sV | (kom så) kVm||sV | ||||
(koste med) kosd@||mED | (koste med) kosd@||mED |
* - : ? b B d D | * - : ? b B d D | ||||
dZ f g h j J k l | dZ f g h j J k l | ||||
l/2 l/3 m n N p r R | l/2 l/3 m n N p r R | ||||
s S t T tS v w | |||||
s S t T tS v w z | |||||
Dictionary hu_dict | Dictionary hu_dict |
chocolate tS0kl@t | chocolate tS0kl@t | ||||
cholera k0l@r@ | cholera k0l@r@ | ||||
cholesterol k@lEst@r0l | cholesterol k@lEst@r0l | ||||
chorizo tSOr'i:zoU | |||||
chromosome kroUm@soUm | chromosome kroUm@soUm | ||||
ciao tSaU | ciao tSaU | ||||
cigar sI2gA@ | cigar sI2gA@ | ||||
dosage doUsI2dZ | dosage doUsI2dZ | ||||
dramatic dr@matIk | dramatic dr@matIk | ||||
drawer drO@ | drawer drO@ | ||||
dreamt drEmpt | |||||
drier draI3 | drier draI3 | ||||
driest draI|@st | driest draI|@st | ||||
duet dju:'Et | duet dju:'Et | ||||
hasty heIstI | hasty heIstI | ||||
hatred heItrI2d | hatred heItrI2d | ||||
hazardous haz3d@s | hazardous haz3d@s | ||||
headfirst $2 | |||||
heh hEh | heh hEh | ||||
hehe hi:h'i: | hehe hi:h'i: | ||||
heifer hEf@ | heifer hEf@ | ||||
metallic mEt'alIk | metallic mEt'alIk | ||||
miaou mi:'aU | miaou mi:'aU | ||||
miaow mi:'aU | miaow mi:'aU | ||||
mic maIk | |||||
mica maIk@ | mica maIk@ | ||||
microorganism maIkroU'O@g@nIz@m | microorganism maIkroU'O@g@nIz@m | ||||
midday m,Idd'eI | midday m,Idd'eI | ||||
prestige prEst'i:Z | prestige prEst'i:Z | ||||
?3 pretense pri:tEns | ?3 pretense pri:tEns | ||||
pretext pri:tEkst | pretext pri:tEkst | ||||
pretrial pri:tr'aI|@L | |||||
pretty prItI | pretty prItI | ||||
privation praIv'eIS@n | privation praIv'eIS@n | ||||
privilege prIvI2lI2dZ | privilege prIvI2lI2dZ | ||||
thine ,DaIn | thine ,DaIn | ||||
me ,mi: $only | me ,mi: $only | ||||
me mi: $atstart $atend | |||||
him ,hIm $only | him ,hIm $only | ||||
us ,Vz $only | us ,Vz $only | ||||
us $abbrev $allcaps | us $abbrev $allcaps |
// 2006-11-18 Gilles Casse <[email protected]> | // 2006-11-18 Gilles Casse <[email protected]> | ||||
// | // | ||||
// Updated 2010-06-11 Michel Such <[email protected]> | |||||
// Updated 2010-06-15 Michel Such <[email protected]> | |||||
// | // | ||||
// * Numbers, a few abbreviations and exceptions. | // * Numbers, a few abbreviations and exceptions. | ||||
// | // | ||||
exocet E2gzosEt | exocet E2gzosEt | ||||
fret fr'Et | fret fr'Et | ||||
budget bydZE2 | budget bydZE2 | ||||
hamlet hamlEt | |||||
hamlet _|amlEt | |||||
knesset knesEt | knesset knesEt | ||||
lazaret lazarE2 | lazaret lazarE2 | ||||
margaret margarEt | margaret margarEt | ||||
dations datjO~z2 | dations datjO~z2 | ||||
désertions dezErtjO~z2 $verb | désertions dezErtjO~z2 $verb | ||||
exploitions EksplwatjO~z2 | exploitions EksplwatjO~z2 | ||||
heurtions hYrtjO~z2 | |||||
heurtions _|WrtjO~z2 | |||||
partions partjO~z2 | partions partjO~z2 | ||||
rations ratjO~z2 $verb | rations ratjO~z2 $verb | ||||
tentions tA~tjO~z2 | tentions tA~tjO~z2 |
r) u (_A u | r) u (_A u | ||||
u (A_ 'u | u (A_ 'u | ||||
ui 'uI | |||||
ui (_ uI | |||||
ui (s 'uI | |||||
ui uI | |||||
u (iu w | u (iu w | ||||
u (iCK u | u (iCK u | ||||
uy uI | uy uI |
_) ட (வல t.V | _) ட (வல t.V | ||||
_) ட (வர t.V | _) ட (வர t.V | ||||
_) ட (ேப t. | _) ட (ேப t. | ||||
_) ட (ாக்ஸி t. | |||||
_) டாக (்ஸி t.a:k | |||||
.group ண | .group ண | ||||
ண n.V | ண n.V | ||||
_) த (ொம் d | _) த (ொம் d | ||||
_) த (ோசை d | _) த (ோசை d | ||||
_) த (ோஷ d | _) த (ோஷ d | ||||
_) த (ுபாய d | |||||
//endsort | //endsort | ||||
//sort | //sort | ||||
ச) த (்ரு t | ச) த (்ரு t | ||||
த) த (்ரூப t | த) த (்ரூப t | ||||
பா) த (்ரூம t | பா) த (்ரூம t | ||||
_ப) த (ஞ்சலி tV | |||||
//endsort | //endsort | ||||
சிறு) ப (ிள்ளை p | சிறு) ப (ிள்ளை p | ||||
ஆண்) ப (ிள்ளை p | ஆண்) ப (ிள்ளை p | ||||
பெண்) ப (ிள்ளை p | பெண்) ப (ிள்ளை p | ||||
பூம்) ப (ுகார p | |||||
ம்) ப (ுரா b | ம்) ப (ுரா b | ||||
இன்) ப (ுற b | இன்) ப (ுற b | ||||
_துன்) ப (ுற b | _துன்) ப (ுற b | ||||
ப (ுறK p | ப (ுறK p | ||||
மண்) ப (ுழு p | மண்) ப (ுழு p | ||||
பூம்) ப (ுஹார p | |||||
ம்) ப (ூர b | ம்) ப (ூர b | ||||
ராம்) ப (ூர p | ராம்) ப (ூர p | ||||
அ) ப (ூர்வ b | அ) ப (ூர்வ b |
id 15 125 | id 15 125 | ||||
sq 33 126 | sq 33 126 | ||||
hy 23 117 | hy 23 117 | ||||
da 23 119 | |||||
da 24 120 | |||||
rw 15 130 | rw 15 130 | ||||
ml 13 150 | ml 13 150 | ||||
ne 18 156 | ne 18 156 | ||||
b/xb [b] base | b/xb [b] base | ||||
[b] fr | [b] fr | ||||
[bh] hi | [bh] hi | ||||
b/xbr [b] fr | |||||
d/d [d] base | d/d [d] base | ||||
[d[] base | [d[] base | ||||
[d] base2 | [d] base2 | ||||
[d] sq | [d] sq | ||||
d/xd3 [dh] hi | d/xd3 [dh] hi | ||||
d/xd_pzd [d;] pl | d/xd_pzd [d;] pl | ||||
d/xdr [d] fr | |||||
d/xdz [dz] consonants | d/xdz [dz] consonants | ||||
d/x_tap [t#] en | d/x_tap [t#] en | ||||
[*] pt | [*] pt | ||||
[g] cy | [g] cy | ||||
[g] fr | [g] fr | ||||
[g] es | [g] es | ||||
g/xgr [g] fr | |||||
h/h_ [h] base | h/h_ [h] base | ||||
[h] fi | [h] fi | ||||
[<h>] la | [<h>] la | ||||
l/l_@ [l/3] base | l/l_@ [l/3] base | ||||
[l/] fr | [l/] fr | ||||
l/l@ [l#] base | l/l@ [l#] base | ||||
[ߵ] base | |||||
[߸] base | |||||
[l] fr | [l] fr | ||||
[l/2] fr | [l/2] fr | ||||
l/L1_aL [l/] base | l/L1_aL [l/] base | ||||
l/l_3 [l/] de | l/l_3 [l/] de | ||||
l/l_4 [ll] sq | l/l_4 [ll] sq | ||||
l/la [l#] base | l/la [l#] base | ||||
[ߵ] base | |||||
[߸] base | |||||
[l] fr | [l] fr | ||||
[l/2] fr | [l/2] fr | ||||
l/l_a [l/3] base | l/l_a [l/3] base | ||||
[l/] fr | [l/] fr | ||||
l/le [l#] base | l/le [l#] base | ||||
[ߵ] base | |||||
[߸] base | |||||
[l] fr | [l] fr | ||||
[l/2] fr | [l/2] fr | ||||
l/l_e [l/3] base | l/l_e [l/3] base | ||||
l/l_front [L] sq | l/l_front [L] sq | ||||
l/l_front_ [l/4] sq | l/l_front_ [l/4] sq | ||||
l/li [l#] base | l/li [l#] base | ||||
[ߵ] base | |||||
[߸] base | |||||
[l] fr | [l] fr | ||||
[l/2] fr | [l/2] fr | ||||
[l] zh | [l] zh | ||||
l/l_long [l] base | l/l_long [l] base | ||||
[l] fr | [l] fr | ||||
l/lo [l#] base | l/lo [l#] base | ||||
[ߵ] base | |||||
[߸] base | |||||
[l] fr | [l] fr | ||||
[l/2] fr | [l/2] fr | ||||
l/l_o [l/3] base | l/l_o [l/3] base | ||||
[l/] fr | [l/] fr | ||||
l^/l_rfx [l.] base | l^/l_rfx [l.] base | ||||
l/lu [l#] base | l/lu [l#] base | ||||
[ߵ] base | |||||
[߸] base | |||||
[l] fr | [l] fr | ||||
[l/2] fr | [l/2] fr | ||||
l/l_u [l/3] base | l/l_u [l/3] base | ||||
ufric/f_ [f] base | ufric/f_ [f] base | ||||
[f] fr | [f] fr | ||||
[f] pl | [f] pl | ||||
ufric/l# [l#] is | |||||
ufric/ll [l#] base | |||||
ufric/l# [l#] base | |||||
[l#] is | |||||
ufric/s [s] base | ufric/s [s] base | ||||
[s] fr | [s] fr | ||||
[z2] fr | [z2] fr | ||||
[a:I] vi | [a:I] vi | ||||
[aI] id | [aI] id | ||||
[aI] hy | [aI] hy | ||||
[aI] da | |||||
vdiph/ai_2 [aI] en | vdiph/ai_2 [aI] en | ||||
[aI] cy | [aI] cy | ||||
[aY] cy | [aY] cy | ||||
vwl_en_us/or [o@] en-us | vwl_en_us/or [o@] en-us | ||||
[O:] en-sc | [O:] en-sc | ||||
vwl_en_us/ur [U@] en-us | 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/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/j [j/] fr | ||||
vwl_fr/o2r [ߵ] fr | |||||
vwl_fr/oo2r [ߵ] fr | |||||
vwl_fr/o2r [߸] fr | |||||
vwl_fr/oo2r [߸] fr | |||||
vwl_fr/r [r] fr | vwl_fr/r [r] fr | ||||
[r/2] fr | [r/2] fr | ||||
vwl_fr/r_ [r/] fr | vwl_fr/r_ [r/] 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 [x] pt-pt | ||||
vwl_fr/r@2 [ߵ] fr | |||||
vwl_fr/r@2 [߸] fr | |||||
vwl_fr/@R2 [R] fr-ca | vwl_fr/@R2 [R] fr-ca | ||||
vwl_fr/ra [ߵ] fr | |||||
vwl_fr/ra [߸] fr | |||||
vwl_fr/r_a [r/] 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/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/r_i [r/] fr | ||||
vwl_fr/rj [ߵ] fr | |||||
vwl_fr/rj [߸] fr | |||||
vwl_fr/r_n [r/] fr | vwl_fr/r_n [r/] fr | ||||
vwl_fr/ro [ߵ] fr | |||||
vwl_fr/ro [߸] fr | |||||
vwl_fr/r_o [r/] fr | vwl_fr/r_o [r/] fr | ||||
vwl_fr/roo [ߵ] fr | |||||
vwl_fr/roo [߸] fr | |||||
vwl_fr/rr [r/] fr | vwl_fr/rr [r/] fr | ||||
vwl_fr/ru [ߵ] fr | |||||
vwl_fr/ru [߸] fr | |||||
vwl_fr/r_u [r/] 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/r_y [r/] fr | ||||
vwl_fr/tr [r/2] fr | vwl_fr/tr [r/2] fr | ||||
vwl_fr/trr [r/] fr | vwl_fr/trr [r/] fr | ||||
vwl_fr/u2r [ߵ] fr | |||||
vwl_fr/u2r [߸] fr | |||||
vwl_fr/wa [w] fr | vwl_fr/wa [w] fr | ||||
[w/] fr | [w/] fr | ||||
vwl_fr/y2r [ߵ] fr | |||||
vwl_fr/y2r [߸] fr | |||||
vwl_hi/l-voc [l-] base | vwl_hi/l-voc [l-] base | ||||
[l-] sk | [l-] sk | ||||
[l:] sk | [l:] sk |
ENVELOPE | |||||
0 60 | |||||
5 63 | |||||
22 92 | |||||
31 100 | |||||
41 95 | |||||
85 12 | |||||
90 5 | |||||
100 0 | |||||
ENVELOPE | |||||
0 0 | |||||
45 95 | |||||
100 0 | |||||
tune s1 | |||||
prehead 46 57 | |||||
headenv fall 16 | |||||
head 4 80 50 -8 -5 | |||||
headextend 0 63 38 13 0 | |||||
nucleus0 fall 64 8 | |||||
nucleus fall 70 18 24 12 | |||||
endtune | |||||
tune c1 | |||||
prehead 46 57 | |||||
headenv fall 16 | |||||
head 4 80 46 -8 -5 | |||||
headextend 0 63 38 13 0 | |||||
nucleus0 fall-rise 80 18 | |||||
nucleus fall-rise2 78 22 34 52 | |||||
endtune | |||||
tune q1 | |||||
prehead 46 57 | |||||
headenv fall 16 | |||||
head 4 75 43 -7 0 | |||||
headextend 25 63 38 13 0 | |||||
nucleus0 fall-rise 88 22 | |||||
nucleus fall-rise2 82 22 34 66 | |||||
endtune | |||||
tune e1 | |||||
prehead 46 57 | |||||
headenv fall 16 | |||||
head 3 90 50 -9 0 | |||||
headextend 16 82 50 32 16 | |||||
nucleus0 fall 92 8 | |||||
nucleus fall 92 80 76 8 | |||||
endtune | |||||
// PB Tunes for the Danish intonation | |||||
// full-stop "." - punktum | |||||
tune s2 | |||||
prehead 46 57 | |||||
headenv fall 16 | |||||
head 4 65 60 -8 -5 | |||||
headextend 0 53 38 13 0 | |||||
nucleus0 fall 44 28 | |||||
nucleus fall 50 42 34 28 // sidste ord før punktu | |||||
onset 75 -5 -5 | |||||
endtune | |||||
// comma "," - komma | |||||
tune c2 | |||||
prehead 46 57 | |||||
headenv fall 16 | |||||
head 4 65 50 -8 -5 | |||||
headextend 0 63 38 13 0 | |||||
nucleus0 rise 60 42 | |||||
nucleus rise 55 42 34 52 // sidste tal: slutniveau | |||||
endtune | |||||
// question mark "?" - spørgsmålste | |||||
tune q2 | |||||
prehead 40 75 | |||||
headenv fall 16 | |||||
head 4 75 43 -7 0 //head 4 35 43 -7 0 | |||||
headextend 25 63 38 13 0 | |||||
nucleus0 rise 70 50 // første tal: slutniveaue | |||||
nucleus rise 35 45 60 70 // sidste tal: slutniveau | |||||
endtune | |||||
// exclamation mark "!" - udråbsteg | |||||
tune e2 | |||||
prehead 46 57 | |||||
headenv fall 16 | |||||
head 3 90 50 -9 0 | |||||
headextend 16 82 50 32 16 | |||||
nucleus0 fall 92 8 | |||||
nucleus fall 92 80 76 8 | |||||
endtune | |||||
// Tunes for the French intonation | |||||
// full-stop "." - point | |||||
tune s3 | |||||
prehead 46 57 | |||||
headenv fall 16 | |||||
head 4 80 50 -8 -5 | |||||
headextend 0 63 38 13 0 | |||||
nucleus0 fall 64 8 | |||||
nucleus fall 70 18 24 12 | |||||
endtune | |||||
// comma "," - virgule | |||||
tune c3 | |||||
prehead 46 57 | |||||
headenv fall 16 | |||||
head 4 80 30 -5 -15 | |||||
headextend 25 63 38 13 0 | |||||
nucleus0 fall-rise 75 40 | |||||
endtune | |||||
// question mark "?" - point d'interrogation | |||||
tune q3 | |||||
prehead 46 57 | |||||
headenv fall 16 | |||||
head 4 75 43 -7 0 | |||||
headextend 25 63 38 13 0 | |||||
nucleus0 fall-rise 88 22 | |||||
nucleus fall-rise2 82 22 34 66 | |||||
endtune | |||||
// exclamation mark "!" - point d'exclamation | |||||
tune e3 | |||||
prehead 46 57 | |||||
headenv fall 16 | |||||
head 3 90 50 -9 0 | |||||
headextend 16 82 50 32 16 | |||||
nucleus0 fall 92 8 | |||||
nucleus fall 92 80 76 8 | |||||
endtune |
FMT(vowel/V) | FMT(vowel/V) | ||||
endphoneme | endphoneme | ||||
phoneme aI | |||||
vowel starttype #a endtype #i | |||||
length 250 | |||||
FMT(vdiph/ai) | |||||
endphoneme | |||||
// CONSONANTS | // CONSONANTS | ||||
// PB added l/3 | // PB added l/3 |
phoneme aI@ | phoneme aI@ | ||||
vowel starttype #a endtype #@ | vowel starttype #a endtype #@ | ||||
length 270 | |||||
length 280 | |||||
IfNextVowelAppend(r-) | IfNextVowelAppend(r-) | ||||
FMT(vwl_en/aI@) | FMT(vwl_en/aI@) | ||||
endphoneme | endphoneme | ||||
phoneme aU@ | phoneme aU@ | ||||
vowel starttype #a endtype #@ | vowel starttype #a endtype #@ | ||||
length 270 | |||||
length 280 | |||||
IfNextVowelAppend(r-) | IfNextVowelAppend(r-) | ||||
FMT(vwl_en/aU@) | FMT(vwl_en/aU@) | ||||
endphoneme | endphoneme |
phoneme aI@ | phoneme aI@ | ||||
vowel starttype #a endtype #@ | vowel starttype #a endtype #@ | ||||
length 270 | |||||
length 280 | |||||
IfNextVowelAppend(r-) | IfNextVowelAppend(r-) | ||||
FMT(vwl_en/aI@) | FMT(vwl_en/aI@) | ||||
endphoneme | endphoneme | ||||
phoneme aU@ | phoneme aU@ | ||||
vowel starttype #a endtype #@ | vowel starttype #a endtype #@ | ||||
length 270 | |||||
length 280 | |||||
IfNextVowelAppend(r-) | IfNextVowelAppend(r-) | ||||
FMT(vwl_en/aU@) | FMT(vwl_en/aU@) | ||||
endphoneme | endphoneme |
phoneme aI@ | phoneme aI@ | ||||
vowel starttype #a endtype #@ | vowel starttype #a endtype #@ | ||||
length 270 | |||||
length 280 | |||||
IfNextVowelAppend(r-) | IfNextVowelAppend(r-) | ||||
FMT(vwl_en/ooi@) | FMT(vwl_en/ooi@) | ||||
endphoneme | endphoneme | ||||
phoneme aU@ | phoneme aU@ | ||||
vowel starttype #a endtype #@ | vowel starttype #a endtype #@ | ||||
length 270 | |||||
length 280 | |||||
IfNextVowelAppend(r-) | IfNextVowelAppend(r-) | ||||
FMT(vwl_en/aU@) | FMT(vwl_en/aU@) | ||||
endphoneme | endphoneme |
//==================================================== | //==================================================== | ||||
// French | // French | ||||
//==================================================== | //==================================================== | ||||
// Updated 2010-06-12 Michel Such <[email protected]> | |||||
// Updated 2010-06-16 Michel Such <[email protected]> | |||||
phoneme #l virtual | phoneme #l virtual | ||||
// Used for l and l/ | // Used for l and l/ | ||||
vcd uvl frc nopause | vcd uvl frc nopause | ||||
rhotic | rhotic | ||||
starttype #r endtype #r | starttype #r endtype #r | ||||
Vowelin f1=1 f2=1600 -500 500 f3=-200 100 len=65 | |||||
Vowelout f1=1 f2=1200 -400 800 f3=200 100 len=60 | |||||
Vowelin f1=0 f2=1500 -400 400 f3=-400 80 | |||||
lengthmod 7 | lengthmod 7 | ||||
IF nextPh(isNotVowel) THEN | IF nextPh(isNotVowel) THEN | ||||
phoneme r/2 | phoneme r/2 | ||||
liquid rhotic uvl nopause | liquid rhotic uvl nopause | ||||
starttype #r endtype #r | starttype #r endtype #r | ||||
Vowelin f1=1 f2=1600 -500 500 f3=-200 100 len=65 amp=8 | |||||
Vowelin f1=0 f2=1500 -400 400 f3=-400 80 | |||||
CALL post_r | CALL post_r | ||||
IF prevPhW(f) OR prevPhW(k) OR prevPhW(p) OR prevPhW(s) OR prevPhW(t) OR prevPhW(S) THEN | IF prevPhW(f) OR prevPhW(k) OR prevPhW(p) OR prevPhW(s) OR prevPhW(t) OR prevPhW(S) THEN | ||||
phoneme l | phoneme l | ||||
liquid nopause | |||||
liquid | |||||
starttype #l endtype #l | starttype #l endtype #l | ||||
lengthmod 7 | lengthmod 7 | ||||
ENDIF | ENDIF | ||||
IF PreVoicing THEN | IF PreVoicing THEN | ||||
FMT(b/xb) | |||||
IF nextPhW(#r) THEN | |||||
FMT(b/xbr) | |||||
ELSE | |||||
FMT(b/xb) | |||||
ENDIF | |||||
ENDIF | ENDIF | ||||
IF nextPh(isPause2) OR nextPh(l) THEN | IF nextPh(isPause2) OR nextPh(l) THEN | ||||
Vowelout f1=2 f2=1700 -300 300 f3=-100 80 | Vowelout f1=2 f2=1700 -300 300 f3=-100 80 | ||||
IF PreVoicing THEN | IF PreVoicing THEN | ||||
FMT(d/xd) | |||||
IF nextPhW(#r) THEN | |||||
FMT(d/xdr) | |||||
ELSE | |||||
FMT(d/xd) | |||||
ENDIF | |||||
ENDIF | ENDIF | ||||
IF nextPh(isPause2) THEN | IF nextPh(isPause2) THEN | ||||
Vowelout f1=1 f2=2300 250 300 f3=-300 80 brk | Vowelout f1=1 f2=2300 250 300 f3=-300 80 brk | ||||
IF PreVoicing THEN | IF PreVoicing THEN | ||||
FMT(g/xg) | |||||
IF nextPhW(#r) THEN | |||||
FMT(g/xgr) | |||||
ELSE | |||||
FMT(g/xg) | |||||
ENDIF | |||||
ENDIF | ENDIF | ||||
IF nextPh(isPause2) THEN | IF nextPh(isPause2) THEN |
//==================================================== | |||||
// Nahuatl (classical) | |||||
//==================================================== | |||||
phoneme : // lengthens the previous vowel by 'length' | |||||
virtual | |||||
length 300 | |||||
endphoneme | |||||
phoneme e | |||||
vowel starttype #e endtype #e | |||||
length 170 | |||||
FMT(vowel/e_mid2) | |||||
endphoneme | |||||
phoneme u | phoneme u | ||||
vowel starttype #u endtype #u | vowel starttype #u endtype #u | ||||
length 110 | length 110 | ||||
ChangeIfNotStressed(U) | |||||
IF prevPhW(isVel) THEN | |||||
ELSE | |||||
ChangeIfNotStressed(U) | |||||
ENDIF | |||||
FMT(vowel/u_6) | FMT(vowel/u_6) | ||||
endphoneme | endphoneme | ||||
VowelEnding(l/xl, -40) | VowelEnding(l/xl, -40) | ||||
ENDIF | ENDIF | ||||
WAV(ufric/ll, 60) | |||||
WAV(ufric/l#, 60) | |||||
endphoneme | endphoneme | ||||
include ph_danish | include ph_danish | ||||
// The following lines are experimental, for future additions. | |||||
// These langauges are not in a usable state. | |||||
// These lines can be deleted. | |||||
phonemetable rw base2 | phonemetable rw base2 | ||||
include ph_kinyarwanda | include ph_kinyarwanda | ||||
//phonemetable mr hi | //phonemetable mr hi | ||||
//include ph_marathi | //include ph_marathi | ||||
//phonemetable eu base2 | //phonemetable eu base2 | ||||
//include ph_basque | //include ph_basque | ||||
speak_SOURCES = speak.cpp compiledict.cpp dictionary.cpp intonation.cpp \ | speak_SOURCES = speak.cpp compiledict.cpp dictionary.cpp intonation.cpp \ | ||||
readclause.cpp setlengths.cpp numbers.cpp synth_mbrola.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 | tr_languages.cpp voices.cpp wavegen.cpp phonemelist.cpp klatt.cpp | ||||
libespeak_SOURCES = speak_lib.cpp compiledict.cpp dictionary.cpp intonation.cpp \ | libespeak_SOURCES = speak_lib.cpp compiledict.cpp dictionary.cpp intonation.cpp \ | ||||
readclause.cpp setlengths.cpp numbers.cpp synth_mbrola.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 \ | tr_languages.cpp voices.cpp wavegen.cpp phonemelist.cpp \ | ||||
espeak_command.cpp event.cpp fifo.cpp $(WAVE) debug.cpp klatt.cpp | espeak_command.cpp event.cpp fifo.cpp $(WAVE) debug.cpp klatt.cpp | ||||
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 wave.cpp \ | |||||
wavegen.cpp | |||||
# Makefile for 'espeakedit' program | |||||
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 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)) | OBJS=$(patsubst %.cpp,%.o,$(SRCS)) | ||||
WX_LIBS = -pthread -lwx_gtk2u_xrc-2.6 -lwx_gtk2u_qa-2.6 -lwx_gtk2u_html-2.6 -lwx_gtk2u_adv-2.6 -lwx_gtk2u_core-2.6 -lwx_baseu_xml-2.6 -lwx_baseu_net-2.6 -lwx_baseu-2.6 | |||||
WX_LIBS = -pthread -lwx_gtk2u_xrc-2.6 -lwx_gtk2u_qa-2.6 -lwx_gtk2u_html-2.6 \ | |||||
-lwx_gtk2u_adv-2.6 -lwx_gtk2u_core-2.6 -lwx_baseu_xml-2.6 -lwx_baseu_net-2.6 -lwx_baseu-2.6 | |||||
LIBS=-lstdc++ -lportaudio | LIBS=-lstdc++ -lportaudio | ||||
CPPFLAGS = -Wall -g -fexceptions -I/usr/lib/wx/include/gtk2-unicode-release-2.6 -I/usr/include/wx-2.6 -DGTK_NO_CHECK_CASTS -D__WXGTK__ -D_FILE_OFFSET_BITS=64 -D_LARGE_FILES -D_LARGEFILE_SOURCE=1 -DNO_GCC_PRAGMA -D_ESPEAKEDIT | |||||
CPPFLAGS = -Wall -g -fexceptions -I/usr/lib/wx/include/gtk2-unicode-release-2.6 | |||||
-I/usr/include/wx-2.6 \ | |||||
-DGTK_NO_CHECK_CASTS -D__WXGTK__ -D_FILE_OFFSET_BITS=64 -D_LARGE_FILES | |||||
-D_LARGEFILE_SOURCE=1 -DNO_GCC_PRAGMA -D_ESPEAKEDIT | |||||
CXXFLAGS = -O2 -g0 -Wall -g -fexceptions -I/usr/lib/wx/include/gtk2-unicode-release-2.6 -I/usr/include/wx-2.6 -DGTK_NO_CHECK_CASTS -D__WXGTK__ -D_FILE_OFFSET_BITS=64 -D_LARGE_FILES -D_LARGEFILE_SOURCE=1 -DNO_GCC_PRAGMA -D_ESPEAKEDIT | |||||
CXXFLAGS = -O2 -g0 -Wall -g -fexceptions -I/usr/lib/wx/include/gtk2-unicode-release-2.6 -I/usr/include/wx-2.6 \ | |||||
-DGTK_NO_CHECK_CASTS -D__WXGTK__ -D_FILE_OFFSET_BITS=64 -D_LARGE_FILES -D_LARGEFILE_SOURCE=1 -DNO_GCC_PRAGMA -D_ESPEAKEDIT | |||||
all: espeakedit | all: espeakedit | ||||
sr2 = Read4Bytes(f); | sr2 = Read4Bytes(f); | ||||
fseek(f,40,SEEK_SET); | fseek(f,40,SEEK_SET); | ||||
if((sr1 != samplerate) || (sr2 != sr1*2)) | |||||
if((sr1 != samplerate_native) || (sr2 != sr1*2)) | |||||
{ | { | ||||
#ifdef PLATFORM_WINDOWS | #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); | error("Wrong samplerate: %s",fname); | ||||
} | } | ||||
if(sr2 != sr1*2) | if(sr2 != sr1*2) | ||||
if((fd_temp = mkstemp(fname_temp)) >= 0) | if((fd_temp = mkstemp(fname_temp)) >= 0) | ||||
{ | { | ||||
close(fd_temp); | 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) | if(system(command) < 0) | ||||
{ | { | ||||
error("Failed to resample: %s",command); | error("Failed to resample: %s",command); |
"\t directory. <voice name> specifies the language\n" | "\t directory. <voice name> specifies the language\n" | ||||
"--path=\"<path>\"\n" | "--path=\"<path>\"\n" | ||||
"\t Specifies the directory containing the espeak-data directory\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" | "--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" | "--punct=\"<characters>\"\n" | ||||
"\t Speak the names of punctuation characters during speaking. If\n" | "\t Speak the names of punctuation characters during speaking. If\n" | ||||
"\t =<characters> is omitted, all punctuation is spoken.\n" | "\t =<characters> is omitted, all punctuation is spoken.\n" | ||||
int quiet = 0; | int quiet = 0; | ||||
unsigned int samples_total = 0; | unsigned int samples_total = 0; | ||||
unsigned int samples_split = 0; | unsigned int samples_split = 0; | ||||
unsigned int samples_split_seconds = 0; | |||||
unsigned int wavefile_count = 0; | unsigned int wavefile_count = 0; | ||||
FILE *f_wavfile = NULL; | FILE *f_wavfile = NULL; | ||||
else | else | ||||
f_wavfile = fopen(path,"wb"); | 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 | } // end of OpenWavFile | ||||
return(0); | 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(); | CloseWavFile(); | ||||
samples_total = 0; | samples_total = 0; | ||||
wavefile_count++; | |||||
} | } | ||||
events++; | |||||
} | } | ||||
events++; | |||||
} | } | ||||
if(f_wavfile == NULL) | 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) | if(numsamples > 0) | ||||
{"stdout", no_argument, 0, 0x105}, | {"stdout", no_argument, 0, 0x105}, | ||||
{"split", optional_argument, 0, 0x106}, | {"split", optional_argument, 0, 0x106}, | ||||
{"path", required_argument, 0, 0x107}, | {"path", required_argument, 0, 0x107}, | ||||
{"phonout", required_argument, 0, 0x108}, | |||||
{"phonout", required_argument, 0, 0x108}, | |||||
{"pho", no_argument, 0, 0x109}, | |||||
{0, 0, 0, 0} | {0, 0, 0, 0} | ||||
}; | }; | ||||
int wordgap = -1; | int wordgap = -1; | ||||
int option_capitals = -1; | int option_capitals = -1; | ||||
int option_punctuation = -1; | int option_punctuation = -1; | ||||
int option_phonemes = -1; | |||||
int option_phonemes = 0; | |||||
int option_mbrola_phonemes = 0; | |||||
int option_linelength = 0; | int option_linelength = 0; | ||||
int option_waveout = 0; | int option_waveout = 0; | ||||
case 0x106: // -- split | case 0x106: // -- split | ||||
if(optarg2 == NULL) | if(optarg2 == NULL) | ||||
samples_split = 30; // default 30 minutes | |||||
samples_split = 30 * 60; // default 30 minutes | |||||
else | else | ||||
samples_split = atoi(optarg2); | |||||
samples_split = atoi(optarg2) * 60; | |||||
break; | break; | ||||
case 0x107: // --path | case 0x107: // --path | ||||
} | } | ||||
break; | break; | ||||
case 0x109: // --pho | |||||
option_mbrola_phonemes = 8; | |||||
break; | |||||
default: | default: | ||||
exit(0); | exit(0); | ||||
} | } | ||||
{ | { | ||||
// writing to a file (or no output), we can use synchronous mode | // writing to a file (or no output), we can use synchronous mode | ||||
samplerate = espeak_Initialize(AUDIO_OUTPUT_SYNCHRONOUS,0,data_path,0); | 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); | espeak_SetSynthCallback(SynthCallback); | ||||
if(samples_split) | if(samples_split) | ||||
*extn = 0; | *extn = 0; | ||||
} | } | ||||
} | } | ||||
else | |||||
if(option_waveout) | |||||
{ | |||||
if(OpenWavFile(wavefile,samplerate) != 0) | |||||
exit(4); | |||||
} | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
espeak_SetParameter(espeakLINELENGTH,option_linelength,0); | espeak_SetParameter(espeakLINELENGTH,option_linelength,0); | ||||
if(option_punctuation == 2) | if(option_punctuation == 2) | ||||
espeak_SetPunctuationList(option_punctlist); | 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) | if(filename[0]==0) | ||||
{ | { |
if(argc > 1) | if(argc > 1) | ||||
{ | { | ||||
extern void VoiceReset(int control); | |||||
p = argv[1]; | p = argv[1]; | ||||
j = 0; | j = 0; | ||||
while((param[j] = p[j]) != 0) j++; | while((param[j] = p[j]) != 0) j++; |
#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 |
/* | |||||
* 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; | |||||
} |
/* | |||||
* 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 |
int s1; | int s1; | ||||
int wpm; | int wpm; | ||||
int wpm2; | int wpm2; | ||||
int test=0; | |||||
speed.loud_consonants = 0; | speed.loud_consonants = 0; | ||||
speed.min_sample_len = 450; | speed.min_sample_len = 450; | ||||
speed.loud_consonants = (wpm - 360) / 8; | 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; | wpm2 = wpm; | ||||
if(wpm > 359) wpm2 = 359; | if(wpm > 359) wpm2 = 359; | ||||
if(wpm < 80) wpm2 = 80; | if(wpm < 80) wpm2 = 80; | ||||
speed.min_sample_len = 420 - (wpm - 440); | 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.pause_factor = (256 * s1)/115; // full speed adjustment, used for pause length | ||||
speed.clause_pause_factor = 0; | speed.clause_pause_factor = 0; | ||||
"\t directory. <voice name> specifies the language\n" | "\t directory. <voice name> specifies the language\n" | ||||
"--path=\"<path>\"\n" | "--path=\"<path>\"\n" | ||||
"\t Specifies the directory containing the espeak-data directory\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" | "--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" | "--punct=\"<characters>\"\n" | ||||
"\t Speak the names of punctuation characters during speaking. If\n" | "\t Speak the names of punctuation characters during speaking. If\n" | ||||
"\t =<characters> is omitted, all punctuation is spoken.\n" | "\t =<characters> is omitted, all punctuation is spoken.\n" | ||||
} // end of DisplayVoices | } // end of DisplayVoices | ||||
void WVoiceChanged(voice_t *wvoice) | |||||
{ | |||||
} | |||||
static int OpenWaveFile(const char *path, int rate) | static int OpenWaveFile(const char *path, int rate) | ||||
//================================================= | //================================================= | ||||
{"stdout", no_argument, 0, 0x105}, | {"stdout", no_argument, 0, 0x105}, | ||||
{"split", optional_argument, 0, 0x106}, | {"split", optional_argument, 0, 0x106}, | ||||
{"path", required_argument, 0, 0x107}, | {"path", required_argument, 0, 0x107}, | ||||
{"phonout", required_argument, 0, 0x108}, | |||||
{"phonout", required_argument, 0, 0x108}, | |||||
{"pho", no_argument, 0, 0x109}, | |||||
{0, 0, 0, 0} | {0, 0, 0, 0} | ||||
}; | }; | ||||
} | } | ||||
break; | break; | ||||
case 0x109: // --pho | |||||
option_mbrola_phonemes = 8; | |||||
break; | |||||
default: | default: | ||||
exit(0); | exit(0); | ||||
} | } |
static void* my_user_data=NULL; | static void* my_user_data=NULL; | ||||
static espeak_AUDIO_OUTPUT my_mode=AUDIO_OUTPUT_SYNCHRONOUS; | static espeak_AUDIO_OUTPUT my_mode=AUDIO_OUTPUT_SYNCHRONOUS; | ||||
static int synchronous_mode = 1; | static int synchronous_mode = 1; | ||||
static int out_samplerate = 0; | |||||
static int voice_samplerate = 22050; | |||||
t_espeak_callback* synth_callback = NULL; | t_espeak_callback* synth_callback = NULL; | ||||
int (* uri_callback)(int, const char *, const char *) = NULL; | int (* uri_callback)(int, const char *, const char *) = NULL; | ||||
int (* phoneme_callback)(const char *) = NULL; | int (* phoneme_callback)(const char *) = NULL; | ||||
char path_home[N_PATH_HOME]; // this is the espeak-data directory | 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 | #ifdef USE_ASYNC | ||||
static int dispatch_audio(short* outbuf, int length, espeak_EVENT* event) | static int dispatch_audio(short* outbuf, int length, espeak_EVENT* event) | ||||
{ | { | ||||
case AUDIO_OUTPUT_PLAYBACK: | 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) | if (outbuf && length && a_wave_can_be_played) | ||||
{ | { | ||||
wave_write (my_audio, (char*)outbuf, 2*length); | wave_write (my_audio, (char*)outbuf, 2*length); | ||||
my_audio = NULL; | my_audio = NULL; | ||||
synchronous_mode = 1; | synchronous_mode = 1; | ||||
option_waveout = 1; // inhibit portaudio callback from wavegen.cpp | option_waveout = 1; // inhibit portaudio callback from wavegen.cpp | ||||
out_samplerate = 0; | |||||
switch(my_mode) | switch(my_mode) | ||||
{ | { | ||||
case AUDIO_OUTPUT_PLAYBACK: | case AUDIO_OUTPUT_PLAYBACK: | ||||
// wave_init() is now called just before the first wave_write() | |||||
synchronous_mode = 0; | 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; | break; | ||||
case AUDIO_OUTPUT_RETRIEVAL: | case AUDIO_OUTPUT_RETRIEVAL: | ||||
return(EE_INTERNAL_ERROR); | return(EE_INTERNAL_ERROR); | ||||
option_phonemes = 0; | option_phonemes = 0; | ||||
option_mbrola_phonemes = 0; | |||||
option_phoneme_events = (options & 1); | option_phoneme_events = (options & 1); | ||||
SetVoiceByName("default"); | |||||
VoiceReset(0); | |||||
// SetVoiceByName("default"); | |||||
for(param=0; param<N_SPEECH_PARAM; param++) | for(param=0; param<N_SPEECH_PARAM; param++) | ||||
param_stack[0].parameter[param] = param_defaults[param]; | param_stack[0].parameter[param] = param_defaults[param]; | ||||
SetParameter(espeakRATE,170,0); | |||||
SetParameter(espeakRATE,175,0); | |||||
SetParameter(espeakVOLUME,100,0); | SetParameter(espeakVOLUME,100,0); | ||||
SetParameter(espeakCAPITALS,option_capitals,0); | SetParameter(espeakCAPITALS,option_capitals,0); | ||||
SetParameter(espeakPUNCTUATION,option_punctuation,0); | SetParameter(espeakPUNCTUATION,option_punctuation,0); | ||||
SetParameter(espeakWORDGAP,0,0); | SetParameter(espeakWORDGAP,0,0); | ||||
DoVoiceChange(voice); | |||||
// DoVoiceChange(voice); | |||||
#ifdef USE_ASYNC | #ifdef USE_ASYNC | ||||
fifo_init(); | fifo_init(); | ||||
value=0 No phoneme output (default) | value=0 No phoneme output (default) | ||||
value=1 Output the translated phoneme symbols for the text | 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) | 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; | f_trans = stream; | ||||
if(stream == NULL) | if(stream == NULL) | ||||
f_trans = stderr; | f_trans = stderr; | ||||
{ | { | ||||
wave_close(my_audio); | wave_close(my_audio); | ||||
wave_terminate(); | wave_terminate(); | ||||
out_samplerate = 0; | |||||
} | } | ||||
#endif | #endif |
typedef enum { | typedef enum { | ||||
espeakEVENT_LIST_TERMINATED = 0, // Retrieval mode: terminates the event list. | espeakEVENT_LIST_TERMINATED = 0, // Retrieval mode: terminates the event list. | ||||
espeakEVENT_WORD = 1, // Start of word | 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; | } espeak_EVENT_TYPE; | ||||
#ifdef LIBRARY | #ifdef LIBRARY | ||||
#define USE_ASYNC | #define USE_ASYNC | ||||
//#define USE_MBROLA_LIB | |||||
#endif | #endif | ||||
#ifdef _ESPEAKEDIT | #ifdef _ESPEAKEDIT |
extern int Read4Bytes(FILE *f); | extern int Read4Bytes(FILE *f); | ||||
extern void SetPitch2(voice_t *voice, int pitch1, int pitch2, int *pitch_base, int *pitch_range); | extern void SetPitch2(voice_t *voice, int pitch1, int pitch2, int *pitch_base, int *pitch_range); | ||||
#ifdef USE_MBROLA_LIB | |||||
extern unsigned char *outbuf; | extern unsigned char *outbuf; | ||||
#ifndef PLATFORM_WINDOWS | #ifndef PLATFORM_WINDOWS | ||||
#include "mbrolib.h" | |||||
void * mb_handle; | |||||
#include "mbrowrap.h" | |||||
#else | #else | ||||
#include <windows.h> | #include <windows.h> | ||||
PROCIV lastError_MBR; | PROCIV lastError_MBR; | ||||
PROCVCI lastErrorStr_MBR; | PROCVCI lastErrorStr_MBR; | ||||
PROCVI setNoError_MBR; | PROCVI setNoError_MBR; | ||||
PROCVI setFreq_MBR; | |||||
PROCIV getFreq_MBR; | |||||
PROCVF setVolumeRatio_MBR; | PROCVF setVolumeRatio_MBR; | ||||
} | } | ||||
#endif // windows | #endif // windows | ||||
#endif // USE_MBROLA_LIB | |||||
static MBROLA_TAB *mbrola_tab = NULL; | static MBROLA_TAB *mbrola_tab = NULL; | ||||
static int mbrola_control = 0; | static int mbrola_control = 0; | ||||
int option_mbrola_phonemes; | |||||
espeak_ERROR LoadMbrolaTable(const char *mbrola_voice, const char *phtrans, int srate) | espeak_ERROR LoadMbrolaTable(const char *mbrola_voice, const char *phtrans, int srate) | ||||
} | } | ||||
sprintf(path,"%s/mbrola/%s",path_home,mbrola_voice); | 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 | #ifdef PLATFORM_WINDOWS | ||||
if(load_MBR() == FALSE) // load mbrola.dll | if(load_MBR() == FALSE) // load mbrola.dll | ||||
return(EE_INTERNAL_ERROR); | return(EE_INTERNAL_ERROR); | ||||
#endif | |||||
if(init_MBR(path) != 0) // initialise the required mbrola voice | if(init_MBR(path) != 0) // initialise the required mbrola voice | ||||
return(EE_NOT_FOUND); | return(EE_NOT_FOUND); | ||||
setNoError_MBR(1); // don't stop on phoneme errors | 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 | // read eSpeak's mbrola phoneme translation data, eg. en1_phtrans | ||||
sprintf(path,"%s/mbrola_ph/%s",path_home,phtrans); | sprintf(path,"%s/mbrola_ph/%s",path_home,phtrans); | ||||
size = GetFileLength(path); | size = GetFileLength(path); | ||||
if((f_in = fopen(path,"r")) == NULL) | |||||
if((f_in = fopen(path,"r")) == NULL) { | |||||
close_MBR(); | |||||
return(EE_NOT_FOUND); | return(EE_NOT_FOUND); | ||||
} | |||||
if((mbrola_tab = (MBROLA_TAB *)realloc(mbrola_tab,size)) == NULL) | if((mbrola_tab = (MBROLA_TAB *)realloc(mbrola_tab,size)) == NULL) | ||||
{ | { | ||||
fclose(f_in); | fclose(f_in); | ||||
close_MBR(); | |||||
return(EE_INTERNAL_ERROR); | return(EE_INTERNAL_ERROR); | ||||
} | } | ||||
fread(mbrola_tab,size,1,f_in); | fread(mbrola_tab,size,1,f_in); | ||||
fclose(f_in); | fclose(f_in); | ||||
#ifdef USE_MBROLA_LIB | |||||
#ifdef PLATFORM_WINDOWS | |||||
setVolumeRatio_MBR((float)(mbrola_control & 0xff) /16.0f); | 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; | samplerate = srate; | ||||
if(srate == 22050) | if(srate == 22050) | ||||
SetParameter(espeakVOICETYPE,0,0); | SetParameter(espeakVOICETYPE,0,0); | ||||
else | else | ||||
SetParameter(espeakVOICETYPE,1,0); | SetParameter(espeakVOICETYPE,1,0); | ||||
strcpy(mbrola_name,mbrola_voice); | 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); | return(EE_OK); | ||||
} // end of LoadMbrolaTable | } // end of LoadMbrolaTable | ||||
} // end of WritePitch | } // 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 | // Generate a mbrola pho file | ||||
unsigned int name; | unsigned int name; | ||||
int phix; | |||||
int len; | int len; | ||||
int len1; | int len1; | ||||
PHONEME_TAB *ph; | PHONEME_TAB *ph; | ||||
char buf[80]; | char buf[80]; | ||||
char mbr_buf[120]; | 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; | mbr_buf[0] = 0; | ||||
p = &plist[phix]; | p = &plist[phix]; | ||||
ph_prev = plist[phix-1].ph; | ph_prev = plist[phix-1].ph; | ||||
ph_next = plist[phix+1].ph; | ph_next = plist[phix+1].ph; | ||||
#ifdef USE_MBROLA_LIB | |||||
if(p->synthflags & SFLAG_EMBEDDED) | 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) | 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); | name = GetMbrName(p,ph,ph_prev,ph_next,&name2,&len_percent,&control); | ||||
if(control & 1) | if(control & 1) | ||||
phix++; | phix++; | ||||
if(name == 0) | |||||
if(name == 0) { | |||||
phix++; | |||||
continue; // ignore this phoneme | continue; // ignore this phoneme | ||||
} | |||||
if((ph->type == phPAUSE) && (name == ph->mnemonic)) | if((ph->type == phPAUSE) && (name == ph->mnemonic)) | ||||
{ | { | ||||
else | else | ||||
len = (80 * speed.wav_factor)/256; | 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)); | sprintf(buf,"%s\t",WordToString(name)); | ||||
strcat(mbr_buf,buf); | strcat(mbr_buf,buf); | ||||
if(pause) | if(pause) | ||||
{ | { | ||||
len += PauseLength(pause,0); | |||||
sprintf(buf,"_ \t%d\n",PauseLength(pause,0)); | sprintf(buf,"_ \t%d\n",PauseLength(pause,0)); | ||||
strcat(mbr_buf,buf); | strcat(mbr_buf,buf); | ||||
pause = 0; | pause = 0; | ||||
} | } | ||||
else | 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) | 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 |
#include "translate.h" | #include "translate.h" | ||||
#include "wave.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; | const int version_phdata = 0x014342; | ||||
int option_device_number = -1; | int option_device_number = -1; |
syllable_centre = -1; | syllable_centre = -1; | ||||
memset(vowel_transition,0,sizeof(vowel_transition)); | memset(vowel_transition,0,sizeof(vowel_transition)); | ||||
} | } | ||||
} // end of Synthesize::EndPitch | |||||
} // end of EndPitch | |||||
q[2] = (long)amp_env; | q[2] = (long)amp_env; | ||||
q[3] = amp; | q[3] = amp; | ||||
WcmdqInc(); | WcmdqInc(); | ||||
} // end of Synthesize::DoAmplitude | |||||
} // end of DoAmplitude | |||||
q[2] = (long)env; | q[2] = (long)env; | ||||
q[3] = (pitch1 << 16) + pitch2; | q[3] = (pitch1 << 16) + pitch2; | ||||
WcmdqInc(); | WcmdqInc(); | ||||
} // end of Synthesize::DoPitch | |||||
} // end of DoPitch | |||||
wcmdq[wcmdq_tail][1] = len; | wcmdq[wcmdq_tail][1] = len; | ||||
WcmdqInc(); | WcmdqInc(); | ||||
last_frame = NULL; | 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 | extern int seq_len_adjust; // temporary fix to advance the start point for playing the wav sample | ||||
else | else | ||||
{ | { | ||||
// increase consonant amplitude at high speeds, depending on the peak consonant amplitude | // increase consonant amplitude at high speeds, depending on the peak consonant amplitude | ||||
x = ((35 - wav_scale) * speed.loud_consonants); | |||||
if(x < 0) x = 0; | |||||
wav_scale = (wav_scale * (x+256))/256; | |||||
// x = ((35 - wav_scale) * speed.loud_consonants); | |||||
// if(x < 0) x = 0; | |||||
// wav_scale = (wav_scale * (x+256))/256; | |||||
} | } | ||||
if(std_length > 0) | if(std_length > 0) | ||||
} // end of DoSample2 | } // end of DoSample2 | ||||
#ifdef deleted | |||||
int DoSample(PHONEME_TAB *ph1, PHONEME_TAB *ph2, int which, int length_mod, int amp) | |||||
{//====================== ========================================================== | |||||
int index; | |||||
int match_level; | |||||
int amp2; | |||||
int result; | |||||
EndPitch(1); | |||||
index = LookupSound(ph1,ph2,which & 0xff,&match_level,0); | |||||
if((index & 0x800000) == 0) | |||||
return(0); // not wavefile data | |||||
amp2 = wavefile_amp; | |||||
if(amp != 0) | |||||
amp2 = (amp * wavefile_amp)/20; | |||||
if(amp == -1) | |||||
amp2 = amp; | |||||
result = DoSample2(index,which,length_mod,0,amp2); | |||||
last_frame = NULL; | |||||
return(result); | |||||
} // end of DoSample | |||||
#endif | |||||
int DoSample3(PHONEME_DATA *phdata, int length_mod, int amp) | int DoSample3(PHONEME_DATA *phdata, int length_mod, int amp) | ||||
{//========================================================= | {//========================================================= | ||||
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 | // 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 | // Type 1=word, 2=sentence, 3=named marker, 4=play audio, 5=end | ||||
wcmdq[wcmdq_tail][0] = WCMD_MARKER; | wcmdq[wcmdq_tail][0] = WCMD_MARKER; | ||||
wcmdq[wcmdq_tail][3] = value; | wcmdq[wcmdq_tail][3] = value; | ||||
WcmdqInc(); | WcmdqInc(); | ||||
} // end of Synthesize::DoMarker | |||||
} // end of DoMarker | |||||
void DoVoiceChange(voice_t *v) | 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 | // 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 word; // bit 7=last command for this word, bits 5,6 sign, bits 0-4 command | ||||
unsigned int value; | unsigned int value; | ||||
PHONEME_DATA phdata_tone; | PHONEME_DATA phdata_tone; | ||||
FMT_PARAMS fmtp; | FMT_PARAMS fmtp; | ||||
#ifdef TEST_MBROLA | |||||
if(mbrola_name[0] != 0) | |||||
return(MbrolaGenerate(phoneme_list,n_ph,resume)); | |||||
#endif | |||||
if(option_quiet) | if(option_quiet) | ||||
return(0); | return(0); | ||||
if(mbrola_name[0] != 0) | |||||
return(MbrolaGenerate(phoneme_list,n_ph,resume)); | |||||
if(resume == 0) | if(resume == 0) | ||||
{ | { | ||||
ix = 1; | ix = 1; | ||||
return(1); | 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); | Generate(phoneme_list,&n_phoneme_list,0); | ||||
WavegenOpenSound(); | WavegenOpenSound(); | ||||
#define WCMD_MARKER 10 | #define WCMD_MARKER 10 | ||||
#define WCMD_VOICE 11 | #define WCMD_VOICE 11 | ||||
#define WCMD_EMBEDDED 12 | #define WCMD_EMBEDDED 12 | ||||
#define WCMD_MBROLA_DATA 13 | |||||
#define N_WCMDQ 160 | #define N_WCMDQ 160 | ||||
espeak_ERROR SetVoiceByProperties(espeak_VOICE *voice_selector); | espeak_ERROR SetVoiceByProperties(espeak_VOICE *voice_selector); | ||||
espeak_ERROR LoadMbrolaTable(const char *mbrola_voice, const char *phtrans, int srate); | espeak_ERROR LoadMbrolaTable(const char *mbrola_voice, const char *phtrans, int srate); | ||||
void SetParameter(int parameter, int value, int relative); | 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 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 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); | int DoSpect2(PHONEME_TAB *this_ph, int which, FMT_PARAMS *fmt_params, PHONEME_LIST *plist, int modulation); |
/*************************************************************************** | |||||
* Copyright (C) 2005 to 2007 by Jonathan Duddington * | |||||
* email: [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. * | |||||
* * | |||||
* You should have received a copy of the GNU General Public License * | |||||
* along with this program; if not, write see: * | |||||
* <http://www.gnu.org/licenses/>. * | |||||
***************************************************************************/ | |||||
#include "StdAfx.h" | |||||
static const short stress_lengths_nl[8] = {160,135, 210,210, 0, 0, 260,280}; | static const short stress_lengths_nl[8] = {160,135, 210,210, 0, 0, 260,280}; | ||||
tr->langopts.stress_rule = STRESSPOSN_1L; | tr->langopts.stress_rule = STRESSPOSN_1L; | ||||
tr->langopts.vowel_pause = 1; | |||||
tr->langopts.vowel_pause = 0x30; // ?? | tr->langopts.vowel_pause = 0x30; // ?? | ||||
tr->langopts.param[LOPT_DIERESES] = 1; | tr->langopts.param[LOPT_DIERESES] = 1; | ||||
tr->langopts.param[LOPT_PREFIXES] = 1; | tr->langopts.param[LOPT_PREFIXES] = 1; |
extern int option_waveout; | extern int option_waveout; | ||||
extern int option_quiet; | extern int option_quiet; | ||||
extern int option_phonemes; | extern int option_phonemes; | ||||
extern int option_mbrola_phonemes; | |||||
extern int option_phoneme_events; | extern int option_phoneme_events; | ||||
extern int option_linelength; // treat lines shorter than this as end-of-clause | extern int option_linelength; // treat lines shorter than this as end-of-clause | ||||
extern int option_multibyte; | extern int option_multibyte; |
int formant_factor; // adjust nominal formant frequencies by this because of the voice's pitch (256ths) | 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_amp; // amplitude of unvoiced consonants | ||||
int consonant_ampv; // amplitude of the noise component of voiced consonants | int consonant_ampv; // amplitude of the noise component of voiced consonants | ||||
int samplerate; | |||||
int klattv[8]; | int klattv[8]; | ||||
// parameters used by Wavegen | // parameters used by Wavegen | ||||
voice_t *LoadVoice(const char *voice_name, int control); | voice_t *LoadVoice(const char *voice_name, int control); | ||||
voice_t *LoadVoiceVariant(const char *voice_name, int variant); | voice_t *LoadVoiceVariant(const char *voice_name, int variant); | ||||
void DoVoiceChange(voice_t *v); | void DoVoiceChange(voice_t *v); | ||||
void WVoiceChanged(voice_t *wvoice); | |||||
void WavegenSetVoice(voice_t *v); | void WavegenSetVoice(voice_t *v); | ||||
void ReadTonePoints(char *string, int *tone_pts); | void ReadTonePoints(char *string, int *tone_pts); | ||||
void VoiceReset(int control); | |||||
voice->voicing = 64; | voice->voicing = 64; | ||||
voice->consonant_amp = 100; | voice->consonant_amp = 100; | ||||
voice->consonant_ampv = 100; | voice->consonant_ampv = 100; | ||||
voice->samplerate = 22050; | |||||
memset(voice->klattv,0,sizeof(voice->klattv)); | memset(voice->klattv,0,sizeof(voice->klattv)); | ||||
memset(speed.fast_settings,0,sizeof(speed.fast_settings)); | memset(speed.fast_settings,0,sizeof(speed.fast_settings)); | ||||
phtrans[0] = 0; | phtrans[0] = 0; | ||||
sscanf(p,"%s %s %d",name,phtrans,&srate); | sscanf(p,"%s %s %d",name,phtrans,&srate); | ||||
LoadMbrolaTable(name,phtrans,srate); | LoadMbrolaTable(name,phtrans,srate); | ||||
voice->samplerate = srate; | |||||
} | } | ||||
break; | break; | ||||
static t_wave_callback* my_callback_is_output_enabled=NULL; | static t_wave_callback* my_callback_is_output_enabled=NULL; | ||||
#define N_WAV_BUF 10 | #define N_WAV_BUF 10 | ||||
#define SAMPLE_RATE 22050 | |||||
#define MAX_SAMPLE_RATE 22050 | |||||
#define FRAMES_PER_BUFFER 512 | #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 myBuffer[BUFFER_LENGTH]; | ||||
static char* myRead=NULL; | static char* myRead=NULL; | ||||
static char* myWrite=NULL; | static char* myWrite=NULL; | ||||
static int out_channels=1; | static int out_channels=1; | ||||
static int my_stream_could_start=0; | static int my_stream_could_start=0; | ||||
static int wave_samplerate; | |||||
static int mInCallbackFinishedState = false; | static int mInCallbackFinishedState = false; | ||||
#if (USE_PORTAUDIO == 18) | #if (USE_PORTAUDIO == 18) | ||||
PaStreamCallbackFlags flags, void *userData ) | PaStreamCallbackFlags flags, void *userData ) | ||||
#endif | #endif | ||||
{ | { | ||||
int aResult=0; // paContinue | |||||
char* aWrite = myWrite; | |||||
size_t n = out_channels*sizeof(uint16_t)*framesPerBuffer; | |||||
int aResult=0; // paContinue | |||||
char* aWrite = myWrite; | |||||
size_t n = out_channels*sizeof(uint16_t)*framesPerBuffer; | |||||
myReadPosition += framesPerBuffer; | |||||
SHOW("pa_callback > myReadPosition=%u, framesPerBuffer=%lu (n=0x%x) \n",(int)myReadPosition, framesPerBuffer, n); | |||||
myReadPosition += framesPerBuffer; | |||||
SHOW("pa_callback > myReadPosition=%u, framesPerBuffer=%lu (n=0x%x) \n",(int)myReadPosition, framesPerBuffer, n); | |||||
if (aWrite >= myRead) | |||||
{ | |||||
if((size_t)(aWrite - myRead) >= n) | |||||
{ | |||||
memcpy(outputBuffer, myRead, n); | |||||
myRead += n; | |||||
} | |||||
else | |||||
{ | |||||
SHOW_TIME("pa_callback > underflow"); | |||||
aResult=1; // paComplete; | |||||
mInCallbackFinishedState = true; | |||||
size_t aUsedMem=0; | |||||
aUsedMem = (size_t)(aWrite - myRead); | |||||
if (aUsedMem) | |||||
{ | |||||
memcpy(outputBuffer, myRead, aUsedMem); | |||||
} | |||||
char* p = (char*)outputBuffer + aUsedMem; | |||||
memset(p, 0, n - aUsedMem); | |||||
// myReadPosition += aUsedMem/(out_channels*sizeof(uint16_t)); | |||||
myRead = aWrite; | |||||
} | |||||
} | |||||
else // myRead > aWrite | |||||
{ | |||||
if ((size_t)(myBuffer + BUFFER_LENGTH - myRead) >= n) | |||||
if (aWrite >= myRead) | |||||
{ | { | ||||
memcpy(outputBuffer, myRead, n); | |||||
myRead += n; | |||||
if((size_t)(aWrite - myRead) >= n) | |||||
{ | |||||
memcpy(outputBuffer, myRead, n); | |||||
myRead += n; | |||||
} | |||||
else | |||||
{ | |||||
SHOW_TIME("pa_callback > underflow"); | |||||
aResult=1; // paComplete; | |||||
mInCallbackFinishedState = true; | |||||
size_t aUsedMem=0; | |||||
aUsedMem = (size_t)(aWrite - myRead); | |||||
if (aUsedMem) | |||||
{ | |||||
memcpy(outputBuffer, myRead, aUsedMem); | |||||
} | |||||
char* p = (char*)outputBuffer + aUsedMem; | |||||
memset(p, 0, n - aUsedMem); | |||||
// myReadPosition += aUsedMem/(out_channels*sizeof(uint16_t)); | |||||
myRead = aWrite; | |||||
} | |||||
} | } | ||||
else if ((size_t)(aWrite + BUFFER_LENGTH - myRead) >= n) | |||||
else // myRead > aWrite | |||||
{ | { | ||||
int aTopMem = myBuffer + BUFFER_LENGTH - myRead; | |||||
if (aTopMem) | |||||
{ | |||||
SHOW("pa_callback > myRead=0x%x, aTopMem=0x%x\n",(int)myRead, (int)aTopMem); | |||||
memcpy(outputBuffer, myRead, aTopMem); | |||||
} | |||||
int aRest = n - aTopMem; | |||||
if (aRest) | |||||
{ | |||||
SHOW("pa_callback > myRead=0x%x, aRest=0x%x\n",(int)myRead, (int)aRest); | |||||
char* p = (char*)outputBuffer + aTopMem; | |||||
memcpy(p, myBuffer, aRest); | |||||
} | |||||
myRead = myBuffer + aRest; | |||||
} | |||||
else | |||||
{ | |||||
SHOW_TIME("pa_callback > underflow"); | |||||
aResult=1; // paComplete; | |||||
int aTopMem = myBuffer + BUFFER_LENGTH - myRead; | |||||
if (aTopMem) | |||||
{ | |||||
SHOW("pa_callback > myRead=0x%x, aTopMem=0x%x\n",(int)myRead, (int)aTopMem); | |||||
memcpy(outputBuffer, myRead, aTopMem); | |||||
} | |||||
int aRest = aWrite - myBuffer; | |||||
if (aRest) | |||||
{ | |||||
SHOW("pa_callback > myRead=0x%x, aRest=0x%x\n",(int)myRead, (int)aRest); | |||||
char* p = (char*)outputBuffer + aTopMem; | |||||
memcpy(p, myBuffer, aRest); | |||||
} | |||||
size_t aUsedMem = aTopMem + aRest; | |||||
char* p = (char*)outputBuffer + aUsedMem; | |||||
memset(p, 0, n - aUsedMem); | |||||
// myReadPosition += aUsedMem/(out_channels*sizeof(uint16_t)); | |||||
myRead = aWrite; | |||||
if ((size_t)(myBuffer + BUFFER_LENGTH - myRead) >= n) | |||||
{ | |||||
memcpy(outputBuffer, myRead, n); | |||||
myRead += n; | |||||
} | |||||
else if ((size_t)(aWrite + BUFFER_LENGTH - myRead) >= n) | |||||
{ | |||||
int aTopMem = myBuffer + BUFFER_LENGTH - myRead; | |||||
if (aTopMem) | |||||
{ | |||||
SHOW("pa_callback > myRead=0x%x, aTopMem=0x%x\n",(int)myRead, (int)aTopMem); | |||||
memcpy(outputBuffer, myRead, aTopMem); | |||||
} | |||||
int aRest = n - aTopMem; | |||||
if (aRest) | |||||
{ | |||||
SHOW("pa_callback > myRead=0x%x, aRest=0x%x\n",(int)myRead, (int)aRest); | |||||
char* p = (char*)outputBuffer + aTopMem; | |||||
memcpy(p, myBuffer, aRest); | |||||
} | |||||
myRead = myBuffer + aRest; | |||||
} | |||||
else | |||||
{ | |||||
SHOW_TIME("pa_callback > underflow"); | |||||
aResult=1; // paComplete; | |||||
int aTopMem = myBuffer + BUFFER_LENGTH - myRead; | |||||
if (aTopMem) | |||||
{ | |||||
SHOW("pa_callback > myRead=0x%x, aTopMem=0x%x\n",(int)myRead, (int)aTopMem); | |||||
memcpy(outputBuffer, myRead, aTopMem); | |||||
} | |||||
int aRest = aWrite - myBuffer; | |||||
if (aRest) | |||||
{ | |||||
SHOW("pa_callback > myRead=0x%x, aRest=0x%x\n",(int)myRead, (int)aRest); | |||||
char* p = (char*)outputBuffer + aTopMem; | |||||
memcpy(p, myBuffer, aRest); | |||||
} | |||||
size_t aUsedMem = aTopMem + aRest; | |||||
char* p = (char*)outputBuffer + aUsedMem; | |||||
memset(p, 0, n - aUsedMem); | |||||
// myReadPosition += aUsedMem/(out_channels*sizeof(uint16_t)); | |||||
myRead = aWrite; | |||||
} | |||||
} | } | ||||
} | |||||
SHOW("pa_callback > myRead=%x\n",(int)myRead); | |||||
SHOW("pa_callback > myRead=%x\n",(int)myRead); | |||||
// #if USE_PORTAUDIO == 18 | // #if USE_PORTAUDIO == 18 | ||||
#endif | #endif | ||||
return(aResult); | |||||
return(aResult); | |||||
//#endif | //#endif | ||||
} // end of WaveCallBack | } // end of WaveCallBack | ||||
out_channels = 1; | out_channels = 1; | ||||
#if USE_PORTAUDIO == 18 | #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(); | PaDeviceID playbackDevice = Pa_GetDefaultOutputDeviceID(); | ||||
paInt16, | paInt16, | ||||
NULL, | NULL, | ||||
/* general parameters */ | /* general parameters */ | ||||
SAMPLE_RATE, FRAMES_PER_BUFFER, 0, | |||||
wave_samplerate, FRAMES_PER_BUFFER, 0, | |||||
//paClipOff | paDitherOff, | //paClipOff | paDitherOff, | ||||
paNoFlag, | paNoFlag, | ||||
pa_callback, (void *)userdata); | pa_callback, (void *)userdata); | ||||
paInt16, | paInt16, | ||||
NULL, | NULL, | ||||
/* general parameters */ | /* general parameters */ | ||||
SAMPLE_RATE, FRAMES_PER_BUFFER, 0, | |||||
wave_samplerate, FRAMES_PER_BUFFER, 0, | |||||
//paClipOff | paDitherOff, | //paClipOff | paDitherOff, | ||||
paNoFlag, | paNoFlag, | ||||
pa_callback, (void *)userdata); | pa_callback, (void *)userdata); | ||||
// err = Pa_OpenDefaultStream(&pa_stream,0,2,paInt16, | // err = Pa_OpenDefaultStream(&pa_stream,0,2,paInt16, | ||||
// SAMPLE_RATE, | |||||
// wave_samplerate, | |||||
// FRAMES_PER_BUFFER, | // FRAMES_PER_BUFFER, | ||||
// N_WAV_BUF,pa_callback,(void *)userdata); | // N_WAV_BUF,pa_callback,(void *)userdata); | ||||
SHOW("wave_open_sound > Pa_OpenDefaultStream(2): err=%d (%s)\n",err, Pa_GetErrorText(err)); | SHOW("wave_open_sound > Pa_OpenDefaultStream(2): err=%d (%s)\n",err, Pa_GetErrorText(err)); | ||||
&pa_stream, | &pa_stream, | ||||
NULL, /* no input */ | NULL, /* no input */ | ||||
&myOutputParameters, | &myOutputParameters, | ||||
SAMPLE_RATE, | |||||
wave_samplerate, | |||||
framesPerBuffer, | framesPerBuffer, | ||||
paNoFlag, | paNoFlag, | ||||
// paClipOff | paDitherOff, | // paClipOff | paDitherOff, | ||||
&pa_stream, | &pa_stream, | ||||
NULL, /* no input */ | NULL, /* no input */ | ||||
&myOutputParameters, | &myOutputParameters, | ||||
SAMPLE_RATE, | |||||
wave_samplerate, | |||||
framesPerBuffer, | framesPerBuffer, | ||||
paNoFlag, | paNoFlag, | ||||
// paClipOff | paDitherOff, | // paClipOff | paDitherOff, | ||||
&pa_stream, | &pa_stream, | ||||
NULL, /* no input */ | NULL, /* no input */ | ||||
&myOutputParameters, | &myOutputParameters, | ||||
SAMPLE_RATE, | |||||
wave_samplerate, | |||||
framesPerBuffer, | framesPerBuffer, | ||||
paNoFlag, | paNoFlag, | ||||
// paClipOff | paDitherOff, | // paClipOff | paDitherOff, | ||||
pa_callback, | pa_callback, | ||||
(void *)userdata); | (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; | mInCallbackFinishedState = false; | ||||
#endif | #endif | ||||
defaultAlsaIndex = hostInfo->defaultOutputDevice; | defaultAlsaIndex = hostInfo->defaultOutputDevice; | ||||
const PaDeviceInfo *deviceInfo = Pa_GetDeviceInfo( defaultAlsaIndex ); | const PaDeviceInfo *deviceInfo = Pa_GetDeviceInfo( defaultAlsaIndex ); | ||||
update_output_parameters(defaultAlsaIndex, deviceInfo); | 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); | SHOW( "select_device > ALSA (default), name=%s (#%d)\n", deviceInfo->name, defaultAlsaIndex); | ||||
selectedIndex = defaultAlsaIndex; | selectedIndex = defaultAlsaIndex; | ||||
update_output_parameters(i, deviceInfo); | 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); | SHOW( "select_device > ALSA, name=%s (#%d)\n", deviceInfo->name, i); | ||||
//<wave_init | //<wave_init | ||||
// TBD: the arg could be "alsa", "oss",... | // TBD: the arg could be "alsa", "oss",... | ||||
void wave_init() | |||||
void wave_init(int srate) | |||||
{ | { | ||||
ENTER("wave_init"); | ENTER("wave_init"); | ||||
PaError err; | PaError err; | ||||
pa_stream = NULL; | pa_stream = NULL; | ||||
wave_samplerate = srate; | |||||
mInCallbackFinishedState = false; | mInCallbackFinishedState = false; | ||||
init_buffer(); | init_buffer(); | ||||
{ | { | ||||
// TBD: take in account time suplied by portaudio V18 API | // TBD: take in account time suplied by portaudio V18 API | ||||
a_time = sample - myReadPosition; | 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 | else | ||||
{ | { | ||||
// notdef USE_PORTAUDIO | // notdef USE_PORTAUDIO | ||||
void wave_init() {} | |||||
void wave_init(int srate) {} | |||||
void* wave_open(const char* the_api) {return (void *)1;} | void* wave_open(const char* the_api) {return (void *)1;} | ||||
size_t wave_write(void* theHandler, char* theMono16BitsWaveBuffer, size_t theSize) {return theSize;} | size_t wave_write(void* theHandler, char* theMono16BitsWaveBuffer, size_t theSize) {return theSize;} | ||||
int wave_close(void* theHandler) {return 0;} | int wave_close(void* theHandler) {return 0;} |
extern int option_device_number; | extern int option_device_number; | ||||
extern void wave_init(); | |||||
extern void wave_init(int samplerate); | |||||
// TBD: the arg could be "alsa", "oss",... | // TBD: the arg could be "alsa", "oss",... | ||||
extern void* wave_open(const char* the_api); | extern void* wave_open(const char* the_api); | ||||
static t_wave_callback* my_callback_is_output_enabled=NULL; | static t_wave_callback* my_callback_is_output_enabled=NULL; | ||||
#define SAMPLE_RATE 22050 | |||||
#define ESPEAK_FORMAT PA_SAMPLE_S16LE | #define ESPEAK_FORMAT PA_SAMPLE_S16LE | ||||
#define ESPEAK_CHANNEL 1 | #define ESPEAK_CHANNEL 1 | ||||
static int just_flushed = 0; | static int just_flushed = 0; | ||||
static int connected = 0; | static int connected = 0; | ||||
static int wave_samplerate; | |||||
#define CHECK_DEAD_GOTO(label, warn) do { \ | #define CHECK_DEAD_GOTO(label, warn) do { \ | ||||
if (!mainloop || \ | if (!mainloop || \ | ||||
pthread_mutex_init( &pulse_mutex, (const pthread_mutexattr_t *)NULL); | pthread_mutex_init( &pulse_mutex, (const pthread_mutexattr_t *)NULL); | ||||
ss.format = ESPEAK_FORMAT; | ss.format = ESPEAK_FORMAT; | ||||
ss.rate = SAMPLE_RATE; | |||||
ss.rate = wave_samplerate; | |||||
ss.channels = ESPEAK_CHANNEL; | ss.channels = ESPEAK_CHANNEL; | ||||
if (!pa_sample_spec_valid(&ss)) | if (!pa_sample_spec_valid(&ss)) | ||||
//> | //> | ||||
//<wave_init | //<wave_init | ||||
void wave_init() | |||||
void wave_init(int srate) | |||||
{ | { | ||||
ENTER("wave_init"); | ENTER("wave_init"); | ||||
stream = NULL; | stream = NULL; | ||||
wave_samplerate = srate; | |||||
pulse_open(); | pulse_open(); | ||||
} | } | ||||
{ | { | ||||
// TBD: take in account time suplied by portaudio V18 API | // TBD: take in account time suplied by portaudio V18 API | ||||
a_time = sample - a_timing_info.read_index; | 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 | else | ||||
{ | { |
// | // | ||||
//<wave_init | //<wave_init | ||||
void wave_init() { | |||||
void wave_init(int srate) { | |||||
ENTER("wave_init"); | ENTER("wave_init"); | ||||
audio_info_t ainfo; | audio_info_t ainfo; | ||||
char *audio_device = NULL; | char *audio_device = NULL; | ||||
wave_samplerate = srate; | |||||
audio_device = getenv("AUDIODEV"); | audio_device = getenv("AUDIODEV"); | ||||
if (audio_device != NULL) { | if (audio_device != NULL) { | ||||
if ((sun_audio_fd = open(audio_device, O_WRONLY)) < 0) { | if ((sun_audio_fd = open(audio_device, O_WRONLY)) < 0) { | ||||
SHOW("wave_init() play buffer size: %d\n", ainfo.play.buffer_size); | SHOW("wave_init() play buffer size: %d\n", ainfo.play.buffer_size); | ||||
ainfo.play.encoding = AUDIO_ENCODING_LINEAR; | ainfo.play.encoding = AUDIO_ENCODING_LINEAR; | ||||
ainfo.play.channels = 1; | ainfo.play.channels = 1; | ||||
ainfo.play.sample_rate = SAMPLE_RATE; | |||||
ainfo.play.sample_rate = wave_samplerate; | |||||
ainfo.play.precision = SAMPLE_SIZE; | ainfo.play.precision = SAMPLE_SIZE; | ||||
if (ioctl(sun_audio_fd, AUDIO_SETINFO, &ainfo) == -1) { | if (ioctl(sun_audio_fd, AUDIO_SETINFO, &ainfo) == -1) { | ||||
(actual_index <= ainfo.play.samples)) { | (actual_index <= ainfo.play.samples)) { | ||||
*time = 0; | *time = 0; | ||||
} else { | } 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; | *time = (uint32_t) a_time; | ||||
} | } | ||||
SHOW("wave_get_remaining_time for %d: %d\n", sample, *time); | SHOW("wave_get_remaining_time for %d: %d\n", sample, *time); |
#ifdef USE_PORTAUDIO | #ifdef USE_PORTAUDIO | ||||
Pa_AbortStream(pa_stream); | Pa_AbortStream(pa_stream); | ||||
#endif | #endif | ||||
if(mbrola_name[0] != 0) | |||||
MbrolaReset(); | |||||
} | } | ||||
option_harmonic1 = 6; | option_harmonic1 = 6; | ||||
} | } | ||||
WavegenSetEcho(); | WavegenSetEcho(); | ||||
MarkerEvent(espeakEVENT_SAMPLERATE,0,wvoice->samplerate,out_ptr); | |||||
// WVoiceChanged(wvoice); | |||||
} | } | ||||
static int resume=0; | static int resume=0; | ||||
static int echo_complete=0; | static int echo_complete=0; | ||||
#ifdef TEST_MBROLA | |||||
if(mbrola_name[0] != 0) | |||||
return(MbrolaFill(fill_zeros)); | |||||
#endif | |||||
while(out_ptr < out_end) | while(out_ptr < out_end) | ||||
{ | { | ||||
if(WcmdqUsed() <= 0) | if(WcmdqUsed() <= 0) | ||||
case WCMD_EMBEDDED: | case WCMD_EMBEDDED: | ||||
SetEmbedded(q[1],q[2]); | SetEmbedded(q[1],q[2]); | ||||
break; | break; | ||||
case WCMD_MBROLA_DATA: | |||||
result = MbrolaFill(length, resume); | |||||
break; | |||||
} | } | ||||
if(result==0) | if(result==0) |