@@ -111,9 +111,9 @@ _19 n'ed@-n | |||
_2X t'y:w | |||
_3X tR'&#Dv@ //PB [tR'ADv@] changed to [tR'&#Dv@] | |||
_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 | |||
_7X halfj'&rs | |||
_7X h&lfj'&rs // PV a changed to & | |||
_8X f'irs | |||
_9X h&lf'Ems // PB a changed to & | |||
_0C h'un*@:D | |||
@@ -163,6 +163,8 @@ en e:n $u | |||
et ed $u | |||
her $u | |||
kun $u | |||
vel $u+ | |||
da $u | |||
// conjunctions | |||
og V $u+ $pause // and | |||
@@ -187,6 +189,7 @@ med $u+ // with | |||
af & // PB changed from [a?] to [&] - sound too short in a sentence | |||
// Also removed $u from 'af' and other words. They disappeared. | |||
ad &: // PB added 'ad' | |||
ad &D $atend $sentence // PB "Det må ikke skille os ad." | |||
at &: $u // PB changed from [at] to [&:] | |||
hos // at - PB: removed [$u+] | |||
som sVm // which / that - PB: removed [$u+] | |||
@@ -257,7 +260,7 @@ f Ef | |||
g ge: | |||
h hO: | |||
_i i: | |||
j joD | |||
j jVD // PB changed from [o] | |||
k kO: | |||
l El | |||
m Em | |||
@@ -316,7 +319,6 @@ interface _^_EN | |||
image _^_EN | |||
joke _^_EN | |||
joystick _^_EN | |||
junkie _^_EN | |||
laptop _^_EN | |||
level _^_EN | |||
login _^_EN | |||
@@ -335,13 +337,11 @@ password _^_EN | |||
penthouse _^_EN | |||
pickup _^_EN | |||
pidgin _^_EN | |||
producer _^_EN | |||
ranger _^_EN | |||
receiver _^_EN | |||
research _^_EN | |||
remake _^_EN | |||
roadie _^_EN | |||
roastbeef _^_EN | |||
run _^_EN | |||
scanner _^_EN | |||
science _^_EN | |||
@@ -356,7 +356,6 @@ small _^_EN | |||
snob _^_EN | |||
song _^_EN | |||
source _^_EN | |||
spam _^_EN | |||
spirit _^_EN | |||
squaw _^_EN | |||
sweatshirt _^_EN | |||
@@ -2344,7 +2343,7 @@ dessin des'EN $alt | |||
dioxin $alt | |||
disciplin $alt | |||
doktrin $alt | |||
(drive-in) drajv'in $alt | |||
//(drive-in) drajv'in $alt | |||
dusin $alt | |||
endokrin $alt | |||
endorfin $alt | |||
@@ -2398,7 +2397,6 @@ lupin $alt | |||
magasin $alt | |||
mandarin $alt | |||
mandolin $alt | |||
mannequin m&n@k'EN $alt | |||
margin $alt | |||
marin $alt | |||
marocain mAro'kEN $alt | |||
@@ -5046,6 +5044,7 @@ adstringer $alt | |||
adviser $alt | |||
advoker $alt | |||
afficer $alt | |||
aflever $alt | |||
afmarcher $alt | |||
afrikaniser $alt | |||
agere $alt | |||
@@ -5154,7 +5153,7 @@ banaliser $alt | |||
bandagere $alt | |||
banderolere $alt | |||
barbariser $alt | |||
barber $alt | |||
barbere $alt | |||
barder $alt | |||
barrier $alt | |||
barrikader $alt | |||
@@ -5179,7 +5178,7 @@ bonbonniere bVNbVNj'E:r $alt | |||
boniter $alt | |||
botaniser $alt | |||
braiser $alt | |||
briketter $alt | |||
brikettere $alt | |||
brillere $alt | |||
brochere $alt | |||
brodere $alt | |||
@@ -5188,7 +5187,7 @@ bronzere $alt | |||
brunere $alt | |||
brutaliser $alt | |||
bruyere bryj'E:r $alt | |||
budgetter $alt | |||
budgettere $alt | |||
bugser $alt | |||
bureaukratiser $alt | |||
cadmier $alt | |||
@@ -5274,7 +5273,7 @@ deputer $alt | |||
dereguler $alt | |||
deriver $alt | |||
desarmer $alt | |||
deserter $alt | |||
desertere $alt | |||
designere $alt | |||
desinficer $alt | |||
destiller $alt | |||
@@ -5434,7 +5433,7 @@ farser $alt | |||
fasciner $alt | |||
favoriser $alt | |||
feminiser $alt | |||
ferier $alt | |||
feriere $alt | |||
fermenter $alt | |||
ferniser $alt | |||
fertiliser $alt | |||
@@ -5550,7 +5549,7 @@ halver $alt | |||
harceler $alt | |||
harmoner $alt | |||
harmoniser $alt | |||
harpuner $alt | |||
harpunere $alt | |||
havarer $alt | |||
hektografer $alt | |||
herbariser $alt | |||
@@ -5669,7 +5668,7 @@ intriger $alt | |||
introducer $alt | |||
intuber $alt | |||
invader $alt | |||
invalider $alt | |||
invalidere $alt | |||
inventer $alt | |||
inverter $alt | |||
invester $alt | |||
@@ -5890,7 +5889,6 @@ laminer $alt | |||
lancer $alt | |||
lasere $alt | |||
latiniser $alt | |||
//lavere $alt | |||
lavpasteuriser $alt | |||
legaliser $alt | |||
leger $alt | |||
@@ -6119,7 +6117,7 @@ plakater $alt | |||
planere $alt | |||
plastificer $alt | |||
platiner $alt | |||
pletter $alt | |||
plettere $alt | |||
plisser $alt | |||
plomber $alt | |||
plæder $alt | |||
@@ -6153,7 +6151,7 @@ privileger $alt | |||
prober $alt | |||
problematiser $alt | |||
proceder $alt | |||
producer $alt | |||
producere $alt | |||
profaner $alt | |||
professionaliser $alt | |||
profeter $alt | |||
@@ -6190,7 +6188,7 @@ præferer $alt | |||
præjudicer $alt | |||
prækvalificer $alt | |||
præluder $alt | |||
præmier $alt | |||
præmiere $alt | |||
prænumerer $alt | |||
præparer $alt | |||
præsenter $alt | |||
@@ -6218,7 +6216,7 @@ ramponer $alt | |||
ranger $alt | |||
rappeller $alt | |||
rapportere $alt | |||
raser $alt | |||
rasere $alt | |||
ratificer $alt | |||
ratihaber $alt | |||
rationaliser $alt | |||
@@ -6256,7 +6254,7 @@ reimporter $alt | |||
reinvester $alt | |||
rejicer $alt | |||
rekapituler $alt | |||
reklamer $alt | |||
reklamere $alt | |||
rekognoscer $alt | |||
rekommander $alt | |||
rekompenser $alt | |||
@@ -6418,7 +6416,7 @@ stabiliser $alt | |||
staffer $alt | |||
stagner $alt | |||
standardiser $alt | |||
stationer $alt | |||
stationere $alt | |||
statuere $alt | |||
stenciler $alt | |||
stenografer $alt | |||
@@ -6492,9 +6490,9 @@ temperer $alt | |||
tender $alt | |||
teoretiser $alt | |||
termografer $alt | |||
terrasser $alt | |||
terrassere $alt | |||
terroriser $alt | |||
testamenter $alt | |||
testamentere $alt | |||
testere $alt | |||
tiere $alt | |||
titrer $alt | |||
@@ -6565,7 +6563,7 @@ verbaliser $alt | |||
verificer $alt | |||
verser $alt | |||
versificer $alt | |||
versioner $alt | |||
versionere $alt | |||
vibrer $alt | |||
vidimer $alt | |||
vikarier $alt | |||
@@ -10300,23 +10298,24 @@ også Vs@ // also | |||
idet id'e // in so far as | |||
bleg blaj | |||
blegrød blajrWD | |||
blegrøde blajrWD@ | |||
//blege blaj@ | |||
blegemiddel bl&#j@mid@l | |||
//blegansigt bl&#jansegt | |||
slags sl'ags // sort, type | |||
tre tr'e // the number 3 | |||
barber bab'er // PB barber | |||
barbere bab'eV // PB barbere | |||
barberer bab'eV // PB barberer | |||
//barber bAb'er // PB barber | |||
//barbere bab'eV // PB barbere | |||
//barberer bab'eV // PB barberer | |||
//barberes bab'eVs // PB barberes | |||
barbererne bab'eVn@ // PB barberene | |||
barberenes bab'eVn@s // PB barberenes | |||
//barbererne bab'eVn@ // PB barberene | |||
//barberenes bab'eVn@s // PB barberenes | |||
rejicere rejis'eV // PB should not be pronounced [raje] | |||
rejicerer rejis'eV // PB | |||
rejiceres rejis'eVs // PB | |||
rejicering rejis'eRiN // PB | |||
gele sjel'e // PB gele | |||
géle sjel'e // PB géle | |||
gelé sjel'e // PB gelé | |||
geleen sjel'e@-n // PB geleen | |||
geleer sjel'e3 // PB geleer | |||
geleens sjel'e@-ns // PB geleens | |||
@@ -10361,6 +10360,7 @@ shampu Sjambo // PB Danish pronunciation - oo has been replaced b | |||
(tour de force) tu:@d@||'fV:s // PB | |||
(al qaeda) al||k'ajda // PB | |||
(force majeure) fVrs||,ma'sjW:r // PB | |||
(diner transportable) din'e|trANspVt'abl@ // PB | |||
(quiche lorraine) kiS||lor'E:n: | |||
(fait accompli) fEtakVmpl'i // PB | |||
wien v'i:n // PB Wien - the town of Vienna | |||
@@ -10406,6 +10406,8 @@ dna $abbrev | |||
sos $abbrev // PB the SOS signal | |||
pharm fA:rm? $hasdot // PB fx cand. pharm. | |||
phil fil/3 $hasdot // PB fx cand. phil. | |||
bh $abbrev | |||
(bh'er) b,e:h'O:V | |||
// Try to catch errors | |||
@@ -10439,6 +10441,7 @@ sig si $capital //PB Sig = si with capital S - Sig det med blom | |||
(vi steg) vi||st'e | |||
(de steg) di||st'e | |||
(alle steg) &l3||st'e | |||
steg sdaj $atend $sentence | |||
steget ste@d | |||
// 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 | |||
@@ -10472,6 +10475,7 @@ legenderne leg'EndVn3s | |||
(så længe) sV||l'EN3 | |||
(så må) sV||m'O | |||
(så har) sV||har | |||
så sV $sentence $atstart | |||
(virkede så) v'irkeD@||sV | |||
(kom så) kVm||sV | |||
(koste med) kosd@||mED |
@@ -62,7 +62,7 @@ W# y Y | |||
* - : ? b B d D | |||
dZ f g h j J k l | |||
l/2 l/3 m n N p r R | |||
s S t T tS v w | |||
s S t T tS v w z | |||
Dictionary hu_dict |
@@ -792,6 +792,7 @@ chloroplast $1 | |||
chocolate tS0kl@t | |||
cholera k0l@r@ | |||
cholesterol k@lEst@r0l | |||
chorizo tSOr'i:zoU | |||
chromosome kroUm@soUm | |||
ciao tSaU | |||
cigar sI2gA@ | |||
@@ -1003,6 +1004,7 @@ dose doUs | |||
dosage doUsI2dZ | |||
dramatic dr@matIk | |||
drawer drO@ | |||
dreamt drEmpt | |||
drier draI3 | |||
driest draI|@st | |||
duet dju:'Et | |||
@@ -1221,6 +1223,7 @@ havoc hav@k | |||
hasty heIstI | |||
hatred heItrI2d | |||
hazardous haz3d@s | |||
headfirst $2 | |||
heh hEh | |||
hehe hi:h'i: | |||
heifer hEf@ | |||
@@ -1492,6 +1495,7 @@ metaphor mEt@fO@ | |||
metallic mEt'alIk | |||
miaou mi:'aU | |||
miaow mi:'aU | |||
mic maIk | |||
mica maIk@ | |||
microorganism maIkroU'O@g@nIz@m | |||
midday m,Idd'eI | |||
@@ -1759,6 +1763,7 @@ preset pri:sEt | |||
prestige prEst'i:Z | |||
?3 pretense pri:tEns | |||
pretext pri:tEkst | |||
pretrial pri:tr'aI|@L | |||
pretty prItI | |||
privation praIv'eIS@n | |||
privilege prIvI2lI2dZ | |||
@@ -3096,6 +3101,7 @@ thy ,DaI | |||
thine ,DaIn | |||
me ,mi: $only | |||
me mi: $atstart $atend | |||
him ,hIm $only | |||
us ,Vz $only | |||
us $abbrev $allcaps |
@@ -24,7 +24,7 @@ | |||
// 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. | |||
// | |||
@@ -778,7 +778,7 @@ zut zyt | |||
exocet E2gzosEt | |||
fret fr'Et | |||
budget bydZE2 | |||
hamlet hamlEt | |||
hamlet _|amlEt | |||
knesset knesEt | |||
lazaret lazarE2 | |||
margaret margarEt | |||
@@ -884,7 +884,7 @@ contentions kO~tA~tjO~z2 | |||
dations datjO~z2 | |||
désertions dezErtjO~z2 $verb | |||
exploitions EksplwatjO~z2 | |||
heurtions hYrtjO~z2 | |||
heurtions _|WrtjO~z2 | |||
partions partjO~z2 | |||
rations ratjO~z2 $verb | |||
tentions tA~tjO~z2 |
@@ -746,9 +746,7 @@ | |||
r) u (_A u | |||
u (A_ 'u | |||
ui 'uI | |||
ui (_ uI | |||
ui (s 'uI | |||
ui uI | |||
u (iu w | |||
u (iCK u | |||
uy uI |
@@ -393,7 +393,7 @@ | |||
_) ட (வல t.V | |||
_) ட (வர t.V | |||
_) ட (ேப t. | |||
_) ட (ாக்ஸி t. | |||
_) டாக (்ஸி t.a:k | |||
.group ண | |||
ண n.V | |||
@@ -597,6 +597,7 @@ | |||
_) த (ொம் d | |||
_) த (ோசை d | |||
_) த (ோஷ d | |||
_) த (ுபாய d | |||
//endsort | |||
//sort | |||
@@ -671,6 +672,7 @@ _பார்வ) த (ி t | |||
ச) த (்ரு t | |||
த) த (்ரூப t | |||
பா) த (்ரூம t | |||
_ப) த (ஞ்சலி tV | |||
//endsort | |||
@@ -989,13 +991,11 @@ _முகத்தின்_) ப (ாவ b | |||
சிறு) ப (ிள்ளை p | |||
ஆண்) ப (ிள்ளை p | |||
பெண்) ப (ிள்ளை p | |||
பூம்) ப (ுகார p | |||
ம்) ப (ுரா b | |||
இன்) ப (ுற b | |||
_துன்) ப (ுற b | |||
ப (ுறK p | |||
மண்) ப (ுழு p | |||
பூம்) ப (ுஹார p | |||
ம்) ப (ூர b | |||
ராம்) ப (ூர p | |||
அ) ப (ூர்வ b |
@@ -53,7 +53,7 @@ consonants 9 115 | |||
id 15 125 | |||
sq 33 126 | |||
hy 23 117 | |||
da 23 119 | |||
da 24 120 | |||
rw 15 130 | |||
ml 13 150 | |||
ne 18 156 | |||
@@ -82,6 +82,7 @@ b/bu [b] base | |||
b/xb [b] base | |||
[b] fr | |||
[bh] hi | |||
b/xbr [b] fr | |||
d/d [d] base | |||
[d[] base | |||
[d] base2 | |||
@@ -139,6 +140,7 @@ d/xd [d] base | |||
[d] sq | |||
d/xd3 [dh] hi | |||
d/xd_pzd [d;] pl | |||
d/xdr [d] fr | |||
d/xdz [dz] consonants | |||
d/x_tap [t#] en | |||
[*] pt | |||
@@ -220,6 +222,7 @@ g/xg [g] base | |||
[g] cy | |||
[g] fr | |||
[g] es | |||
g/xgr [g] fr | |||
h/h_ [h] base | |||
[h] fi | |||
[<h>] la | |||
@@ -338,7 +341,7 @@ l/l_ [l/] base | |||
l/l_@ [l/3] base | |||
[l/] fr | |||
l/l@ [l#] base | |||
[ߵ] base | |||
[߸] base | |||
[l] fr | |||
[l/2] fr | |||
l/L1_aL [l/] base | |||
@@ -364,13 +367,13 @@ l/L2_uL [l/2] base | |||
l/l_3 [l/] de | |||
l/l_4 [ll] sq | |||
l/la [l#] base | |||
[ߵ] base | |||
[߸] base | |||
[l] fr | |||
[l/2] fr | |||
l/l_a [l/3] base | |||
[l/] fr | |||
l/le [l#] base | |||
[ߵ] base | |||
[߸] base | |||
[l] fr | |||
[l/2] fr | |||
l/l_e [l/3] base | |||
@@ -380,7 +383,7 @@ l/L_eL_af [&] af | |||
l/l_front [L] sq | |||
l/l_front_ [l/4] sq | |||
l/li [l#] base | |||
[ߵ] base | |||
[߸] base | |||
[l] fr | |||
[l/2] fr | |||
[l] zh | |||
@@ -392,14 +395,14 @@ ll/_ll [L] bg | |||
l/l_long [l] base | |||
[l] fr | |||
l/lo [l#] base | |||
[ߵ] base | |||
[߸] base | |||
[l] fr | |||
[l/2] fr | |||
l/l_o [l/3] base | |||
[l/] fr | |||
l^/l_rfx [l.] base | |||
l/lu [l#] base | |||
[ߵ] base | |||
[߸] base | |||
[l] fr | |||
[l/2] fr | |||
l/l_u [l/3] base | |||
@@ -617,8 +620,8 @@ ufric/f [f] base | |||
ufric/f_ [f] base | |||
[f] fr | |||
[f] pl | |||
ufric/l# [l#] is | |||
ufric/ll [l#] base | |||
ufric/l# [l#] base | |||
[l#] is | |||
ufric/s [s] base | |||
[s] fr | |||
[z2] fr | |||
@@ -923,6 +926,7 @@ vdiph/ai [aI] base2 | |||
[a:I] vi | |||
[aI] id | |||
[aI] hy | |||
[aI] da | |||
vdiph/ai_2 [aI] en | |||
[aI] cy | |||
[aY] cy | |||
@@ -1939,51 +1943,51 @@ vwl_en_us/oor [0] en-us | |||
vwl_en_us/or [o@] en-us | |||
[O:] en-sc | |||
vwl_en_us/ur [U@] en-us | |||
vwl_fr/@2r [ߵ] fr | |||
vwl_fr/a2r [ߵ] fr | |||
vwl_fr/aa2r [ߵ] fr | |||
vwl_fr/@2r [߸] fr | |||
vwl_fr/a2r [߸] fr | |||
vwl_fr/aa2r [߸] fr | |||
vwl_fr/br [r/2] fr | |||
vwl_fr/e2r [ߵ] fr | |||
vwl_fr/e_2r [ߵ] fr | |||
vwl_fr/ee2r [ߵ] fr | |||
vwl_fr/i2r [ߵ] fr | |||
vwl_fr/e2r [߸] fr | |||
vwl_fr/e_2r [߸] fr | |||
vwl_fr/ee2r [߸] fr | |||
vwl_fr/i2r [߸] fr | |||
vwl_fr/j [j/] fr | |||
vwl_fr/o2r [ߵ] fr | |||
vwl_fr/oo2r [ߵ] fr | |||
vwl_fr/o2r [߸] fr | |||
vwl_fr/oo2r [߸] fr | |||
vwl_fr/r [r] fr | |||
[r/2] fr | |||
vwl_fr/r_ [r/] fr | |||
vwl_fr/r_@ [r/] fr | |||
vwl_fr/r@ [ߵ] fr | |||
vwl_fr/r@ [߸] fr | |||
vwl_fr/@R [x] pt-pt | |||
vwl_fr/r@2 [ߵ] fr | |||
vwl_fr/r@2 [߸] fr | |||
vwl_fr/@R2 [R] fr-ca | |||
vwl_fr/ra [ߵ] fr | |||
vwl_fr/ra [߸] fr | |||
vwl_fr/r_a [r/] fr | |||
vwl_fr/raa [ߵ] fr | |||
vwl_fr/re [ߵ] fr | |||
vwl_fr/raa [߸] fr | |||
vwl_fr/re [߸] fr | |||
vwl_fr/r_e [r/] fr | |||
vwl_fr/re2 [ߵ] fr | |||
vwl_fr/ree [ߵ] fr | |||
vwl_fr/ri [ߵ] fr | |||
vwl_fr/re2 [߸] fr | |||
vwl_fr/ree [߸] fr | |||
vwl_fr/ri [߸] fr | |||
vwl_fr/r_i [r/] fr | |||
vwl_fr/rj [ߵ] fr | |||
vwl_fr/rj [߸] fr | |||
vwl_fr/r_n [r/] fr | |||
vwl_fr/ro [ߵ] fr | |||
vwl_fr/ro [߸] fr | |||
vwl_fr/r_o [r/] fr | |||
vwl_fr/roo [ߵ] fr | |||
vwl_fr/roo [߸] fr | |||
vwl_fr/rr [r/] fr | |||
vwl_fr/ru [ߵ] fr | |||
vwl_fr/ru [߸] fr | |||
vwl_fr/r_u [r/] fr | |||
vwl_fr/rw [ߵ] fr | |||
vwl_fr/ry [ߵ] fr | |||
vwl_fr/rw [߸] fr | |||
vwl_fr/ry [߸] fr | |||
vwl_fr/r_y [r/] fr | |||
vwl_fr/tr [r/2] fr | |||
vwl_fr/trr [r/] fr | |||
vwl_fr/u2r [ߵ] fr | |||
vwl_fr/u2r [߸] fr | |||
vwl_fr/wa [w] fr | |||
[w/] fr | |||
vwl_fr/y2r [ߵ] fr | |||
vwl_fr/y2r [߸] fr | |||
vwl_hi/l-voc [l-] base | |||
[l-] sk | |||
[l:] sk |
@@ -0,0 +1,11 @@ | |||
ENVELOPE | |||
0 60 | |||
5 63 | |||
22 92 | |||
31 100 | |||
41 95 | |||
85 12 | |||
90 5 | |||
100 0 | |||
@@ -0,0 +1,6 @@ | |||
ENVELOPE | |||
0 0 | |||
45 95 | |||
100 0 | |||
@@ -0,0 +1,124 @@ | |||
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 |
@@ -114,6 +114,13 @@ phoneme W# | |||
FMT(vowel/V) | |||
endphoneme | |||
phoneme aI | |||
vowel starttype #a endtype #i | |||
length 250 | |||
FMT(vdiph/ai) | |||
endphoneme | |||
// CONSONANTS | |||
// PB added l/3 |
@@ -383,7 +383,7 @@ endphoneme | |||
phoneme aI@ | |||
vowel starttype #a endtype #@ | |||
length 270 | |||
length 280 | |||
IfNextVowelAppend(r-) | |||
FMT(vwl_en/aI@) | |||
endphoneme | |||
@@ -391,7 +391,7 @@ endphoneme | |||
phoneme aU@ | |||
vowel starttype #a endtype #@ | |||
length 270 | |||
length 280 | |||
IfNextVowelAppend(r-) | |||
FMT(vwl_en/aU@) | |||
endphoneme |
@@ -239,7 +239,7 @@ endphoneme | |||
phoneme aI@ | |||
vowel starttype #a endtype #@ | |||
length 270 | |||
length 280 | |||
IfNextVowelAppend(r-) | |||
FMT(vwl_en/aI@) | |||
endphoneme | |||
@@ -247,7 +247,7 @@ endphoneme | |||
phoneme aU@ | |||
vowel starttype #a endtype #@ | |||
length 270 | |||
length 280 | |||
IfNextVowelAppend(r-) | |||
FMT(vwl_en/aU@) | |||
endphoneme |
@@ -222,7 +222,7 @@ endphoneme | |||
phoneme aI@ | |||
vowel starttype #a endtype #@ | |||
length 270 | |||
length 280 | |||
IfNextVowelAppend(r-) | |||
FMT(vwl_en/ooi@) | |||
endphoneme | |||
@@ -230,7 +230,7 @@ endphoneme | |||
phoneme aU@ | |||
vowel starttype #a endtype #@ | |||
length 270 | |||
length 280 | |||
IfNextVowelAppend(r-) | |||
FMT(vwl_en/aU@) | |||
endphoneme |
@@ -1,7 +1,7 @@ | |||
//==================================================== | |||
// French | |||
//==================================================== | |||
// Updated 2010-06-12 Michel Such <[email protected]> | |||
// Updated 2010-06-16 Michel Such <[email protected]> | |||
phoneme #l virtual | |||
// Used for l and l/ | |||
@@ -80,8 +80,7 @@ phoneme r | |||
vcd uvl frc nopause | |||
rhotic | |||
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 | |||
IF nextPh(isNotVowel) THEN | |||
@@ -148,7 +147,7 @@ endphoneme | |||
phoneme r/2 | |||
liquid rhotic uvl nopause | |||
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 | |||
IF prevPhW(f) OR prevPhW(k) OR prevPhW(p) OR prevPhW(s) OR prevPhW(t) OR prevPhW(S) THEN | |||
@@ -163,7 +162,7 @@ endphoneme | |||
phoneme l | |||
liquid nopause | |||
liquid | |||
starttype #l endtype #l | |||
lengthmod 7 | |||
@@ -639,7 +638,11 @@ phoneme b | |||
ENDIF | |||
IF PreVoicing THEN | |||
FMT(b/xb) | |||
IF nextPhW(#r) THEN | |||
FMT(b/xbr) | |||
ELSE | |||
FMT(b/xb) | |||
ENDIF | |||
ENDIF | |||
IF nextPh(isPause2) OR nextPh(l) THEN | |||
@@ -663,7 +666,11 @@ phoneme d | |||
Vowelout f1=2 f2=1700 -300 300 f3=-100 80 | |||
IF PreVoicing THEN | |||
FMT(d/xd) | |||
IF nextPhW(#r) THEN | |||
FMT(d/xdr) | |||
ELSE | |||
FMT(d/xd) | |||
ENDIF | |||
ENDIF | |||
IF nextPh(isPause2) THEN | |||
@@ -699,7 +706,11 @@ phoneme g | |||
Vowelout f1=1 f2=2300 250 300 f3=-300 80 brk | |||
IF PreVoicing THEN | |||
FMT(g/xg) | |||
IF nextPhW(#r) THEN | |||
FMT(g/xgr) | |||
ELSE | |||
FMT(g/xg) | |||
ENDIF | |||
ENDIF | |||
IF nextPh(isPause2) THEN |
@@ -0,0 +1,16 @@ | |||
//==================================================== | |||
// 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 | |||
@@ -80,7 +80,10 @@ endphoneme | |||
phoneme u | |||
vowel starttype #u endtype #u | |||
length 110 | |||
ChangeIfNotStressed(U) | |||
IF prevPhW(isVel) THEN | |||
ELSE | |||
ChangeIfNotStressed(U) | |||
ENDIF | |||
FMT(vowel/u_6) | |||
endphoneme | |||
@@ -1487,7 +1487,7 @@ phoneme l# // Lateral fricative (eg. Welsh "ll") | |||
VowelEnding(l/xl, -40) | |||
ENDIF | |||
WAV(ufric/ll, 60) | |||
WAV(ufric/l#, 60) | |||
endphoneme | |||
@@ -1720,6 +1720,12 @@ phonemetable da base | |||
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 | |||
include ph_kinyarwanda | |||
@@ -1738,7 +1744,6 @@ include ph_nepali | |||
//phonemetable mr hi | |||
//include ph_marathi | |||
//phonemetable eu base2 | |||
//include ph_basque | |||
@@ -49,12 +49,12 @@ endif | |||
speak_SOURCES = speak.cpp compiledict.cpp dictionary.cpp intonation.cpp \ | |||
readclause.cpp setlengths.cpp numbers.cpp synth_mbrola.cpp \ | |||
synthdata.cpp synthesize.cpp translate.cpp \ | |||
synthdata.cpp synthesize.cpp translate.cpp mbrowrap.cpp \ | |||
tr_languages.cpp voices.cpp wavegen.cpp phonemelist.cpp klatt.cpp | |||
libespeak_SOURCES = speak_lib.cpp compiledict.cpp dictionary.cpp intonation.cpp \ | |||
readclause.cpp setlengths.cpp numbers.cpp synth_mbrola.cpp \ | |||
synthdata.cpp synthesize.cpp translate.cpp \ | |||
synthdata.cpp synthesize.cpp translate.cpp mbrowrap.cpp \ | |||
tr_languages.cpp voices.cpp wavegen.cpp phonemelist.cpp \ | |||
espeak_command.cpp event.cpp fifo.cpp $(WAVE) debug.cpp klatt.cpp | |||
@@ -1,20 +1,27 @@ | |||
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)) | |||
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 | |||
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 | |||
@@ -1744,12 +1744,12 @@ static int LoadWavefile(FILE *f, const char *fname) | |||
sr2 = Read4Bytes(f); | |||
fseek(f,40,SEEK_SET); | |||
if((sr1 != samplerate) || (sr2 != sr1*2)) | |||
if((sr1 != samplerate_native) || (sr2 != sr1*2)) | |||
{ | |||
#ifdef PLATFORM_WINDOWS | |||
if(sr1 != samplerate) | |||
if(sr1 != samplerate_native) | |||
{ | |||
fprintf(f_errors,"Wrong samplerate %d, wants %d\n",sr1,samplerate); | |||
fprintf(f_errors,"Wrong samplerate %d, wants %d\n",sr1,samplerate_native); | |||
error("Wrong samplerate: %s",fname); | |||
} | |||
if(sr2 != sr1*2) | |||
@@ -1764,7 +1764,7 @@ static int LoadWavefile(FILE *f, const char *fname) | |||
if((fd_temp = mkstemp(fname_temp)) >= 0) | |||
{ | |||
close(fd_temp); | |||
sprintf(command,"sox \"%s%s.wav\" -r %d -c 1 -w %s polyphase\n",path_source,fname,samplerate,fname_temp); | |||
sprintf(command,"sox \"%s%s.wav\" -r %d -c 1 -w %s polyphase\n",path_source,fname,samplerate_native,fname_temp); | |||
if(system(command) < 0) | |||
{ | |||
error("Failed to resample: %s",command); |
@@ -66,8 +66,10 @@ static const char *help_text = | |||
"\t directory. <voice name> specifies the language\n" | |||
"--path=\"<path>\"\n" | |||
"\t Specifies the directory containing the espeak-data directory\n" | |||
"--pho\n" | |||
"\t Write mbrola phoneme data (.pho) to stdout, or to the file in --phonout\n" | |||
"--phonout=\"<filename>\"\n" | |||
"\t Write output from -x -X commands, and mbrola phoneme data, to this file\n" | |||
"\t Write phoneme output from -x -X and --pho to this file\n" | |||
"--punct=\"<characters>\"\n" | |||
"\t Speak the names of punctuation characters during speaking. If\n" | |||
"\t =<characters> is omitted, all punctuation is spoken.\n" | |||
@@ -87,6 +89,7 @@ int samplerate; | |||
int quiet = 0; | |||
unsigned int samples_total = 0; | |||
unsigned int samples_split = 0; | |||
unsigned int samples_split_seconds = 0; | |||
unsigned int wavefile_count = 0; | |||
FILE *f_wavfile = NULL; | |||
@@ -218,15 +221,18 @@ int OpenWavFile(char *path, int rate) | |||
else | |||
f_wavfile = fopen(path,"wb"); | |||
if(f_wavfile != NULL) | |||
if(f_wavfile == NULL) | |||
{ | |||
fwrite(wave_hdr,1,24,f_wavfile); | |||
Write4Bytes(f_wavfile,rate); | |||
Write4Bytes(f_wavfile,rate * 2); | |||
fwrite(&wave_hdr[32],1,12,f_wavfile); | |||
return(0); | |||
fprintf(stderr,"Can't write to: '%s'\n",path); | |||
return(1); | |||
} | |||
return(1); | |||
fwrite(wave_hdr,1,24,f_wavfile); | |||
Write4Bytes(f_wavfile,rate); | |||
Write4Bytes(f_wavfile,rate * 2); | |||
fwrite(&wave_hdr[32],1,12,f_wavfile); | |||
return(0); | |||
} // end of OpenWavFile | |||
@@ -266,25 +272,40 @@ static int SynthCallback(short *wav, int numsamples, espeak_EVENT *events) | |||
return(0); | |||
} | |||
if(samples_split > 0) | |||
while(events->type != 0) | |||
{ | |||
// start a new WAV file when this limit is reached, at the next sentence boundary | |||
while(events->type != 0) | |||
if(events->type == espeakEVENT_SAMPLERATE) | |||
{ | |||
if((events->type == espeakEVENT_SENTENCE) && (samples_total > samples_split)) | |||
samplerate = events->id.number; | |||
samples_split = samples_split_seconds * samplerate; | |||
} | |||
else | |||
if(events->type == espeakEVENT_SENTENCE) | |||
{ | |||
// start a new WAV file when the limit is reached, at this sentence boundary | |||
if((samples_split > 0) && (samples_total > samples_split)) | |||
{ | |||
CloseWavFile(); | |||
samples_total = 0; | |||
wavefile_count++; | |||
} | |||
events++; | |||
} | |||
events++; | |||
} | |||
if(f_wavfile == NULL) | |||
{ | |||
sprintf(fname,"%s_%.2d%s",wavefile,++wavefile_count,filetype); | |||
if(OpenWavFile(fname, samplerate) != 0) | |||
return(1); | |||
if(samples_split > 0) | |||
{ | |||
sprintf(fname,"%s_%.2d%s",wavefile,wavefile_count+1,filetype); | |||
if(OpenWavFile(fname, samplerate) != 0) | |||
return(1); | |||
} | |||
else | |||
{ | |||
if(OpenWavFile(wavefile, samplerate) != 0) | |||
return(1); | |||
} | |||
} | |||
if(numsamples > 0) | |||
@@ -332,7 +353,8 @@ int main (int argc, char **argv) | |||
{"stdout", no_argument, 0, 0x105}, | |||
{"split", optional_argument, 0, 0x106}, | |||
{"path", required_argument, 0, 0x107}, | |||
{"phonout", required_argument, 0, 0x108}, | |||
{"phonout", required_argument, 0, 0x108}, | |||
{"pho", no_argument, 0, 0x109}, | |||
{0, 0, 0, 0} | |||
}; | |||
@@ -360,7 +382,8 @@ int main (int argc, char **argv) | |||
int wordgap = -1; | |||
int option_capitals = -1; | |||
int option_punctuation = -1; | |||
int option_phonemes = -1; | |||
int option_phonemes = 0; | |||
int option_mbrola_phonemes = 0; | |||
int option_linelength = 0; | |||
int option_waveout = 0; | |||
@@ -550,9 +573,9 @@ int main (int argc, char **argv) | |||
case 0x106: // -- split | |||
if(optarg2 == NULL) | |||
samples_split = 30; // default 30 minutes | |||
samples_split = 30 * 60; // default 30 minutes | |||
else | |||
samples_split = atoi(optarg2); | |||
samples_split = atoi(optarg2) * 60; | |||
break; | |||
case 0x107: // --path | |||
@@ -566,6 +589,10 @@ int main (int argc, char **argv) | |||
} | |||
break; | |||
case 0x109: // --pho | |||
option_mbrola_phonemes = 8; | |||
break; | |||
default: | |||
exit(0); | |||
} | |||
@@ -576,7 +603,7 @@ int main (int argc, char **argv) | |||
{ | |||
// writing to a file (or no output), we can use synchronous mode | |||
samplerate = espeak_Initialize(AUDIO_OUTPUT_SYNCHRONOUS,0,data_path,0); | |||
samples_split = (samplerate * samples_split) * 60; | |||
samples_split = samplerate * samples_split_seconds; | |||
espeak_SetSynthCallback(SynthCallback); | |||
if(samples_split) | |||
@@ -589,12 +616,6 @@ int main (int argc, char **argv) | |||
*extn = 0; | |||
} | |||
} | |||
else | |||
if(option_waveout) | |||
{ | |||
if(OpenWavFile(wavefile,samplerate) != 0) | |||
exit(4); | |||
} | |||
} | |||
else | |||
{ | |||
@@ -641,7 +662,7 @@ int main (int argc, char **argv) | |||
espeak_SetParameter(espeakLINELENGTH,option_linelength,0); | |||
if(option_punctuation == 2) | |||
espeak_SetPunctuationList(option_punctlist); | |||
espeak_SetPhonemeTrace(option_phonemes,f_phonemes_out); | |||
espeak_SetPhonemeTrace(option_phonemes | option_mbrola_phonemes,f_phonemes_out); | |||
if(filename[0]==0) | |||
{ |
@@ -129,8 +129,6 @@ char param[80]; | |||
if(argc > 1) | |||
{ | |||
extern void VoiceReset(int control); | |||
p = argv[1]; | |||
j = 0; | |||
while((param[j] = p[j]) != 0) j++; |
@@ -1,205 +0,0 @@ | |||
#ifndef MBROLIB_H | |||
#define MBROLIB_H | |||
/* | |||
* mbrolib: mbrola wrapper. | |||
* | |||
* Copyright (C) 2007 Gilles Casse <[email protected]> | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public | |||
* License along with this library; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
* | |||
*/ | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
/* < types */ | |||
/** Parameters */ | |||
typedef struct { | |||
int ignore_error; /* 1=Ignore any fatal error or unknown diphone */ | |||
char comment_char; /* Comment character */ | |||
float volume_ratio; /* Volume ratio */ | |||
float frequency_ratio; /* Applied to pitch points */ | |||
float time_ratio; /* Applied to phone durations */ | |||
} mbrolib_parameter; | |||
/** Returned errors */ | |||
typedef enum { | |||
MBROLIB_OK=0, | |||
MBROLIB_DATABASE_NOT_INSTALLED, | |||
MBROLIB_INVAL, | |||
MBROLIB_OUT_OF_MEMORY, | |||
MBROLIB_OUT_OF_RANGE, | |||
MBROLIB_READ_ERROR, | |||
MBROLIB_WRITE_ERROR | |||
} MBROLIB_ERROR; | |||
/** Gender */ | |||
typedef enum { | |||
MBROLIB_FEMALE, | |||
MBROLIB_MALE | |||
} MBROLIB_GENDER; | |||
/** Voice descriptor */ | |||
typedef struct { | |||
char *name; /* name (for example: "en1") */ | |||
char *filename; /* database pathname (for example: "/usr/share/mbrola/voices/en1) */ | |||
int rate; /* database sample rate */ | |||
MBROLIB_GENDER gender; | |||
const char *language; /* Language and optional dialect qualifier in ascii (e.g. en, fr_ca). */ | |||
} mbrolib_voice; | |||
/* > */ | |||
/** Initialization, returns a new handle. | |||
First function. | |||
@param the_sample_rate: output rate in Hz (for example 22050). If 0, keep the original database rate. | |||
@return handle (or NULL if error). | |||
*/ | |||
void* mbrolib_init( int sample_rate); | |||
typedef void* (t_mbrolib_init)(int); | |||
/** Returns the list of the installed mbrola databases. | |||
The databases are searched according to the MBROLA_PATH environment variable if set, | |||
or under a default path otherwise (see MBROLA_PATH in mbrolib.c). | |||
An array of voices is returned. The last item is set to NULL. | |||
The caller must not free the returned items or the array. | |||
@param the_handle previously given by mbrolib_init. | |||
@return An array of voices. | |||
*/ | |||
const mbrolib_voice ** mbrolib_list_voices( void* the_handle); | |||
typedef const mbrolib_voice ** (t_mbrolib_list_voices)(void*); | |||
/** Set voice | |||
@param the_handle. | |||
@param the_database (for example, "en1"). | |||
@return error code (MBROLIB_OK, MBROLIB_DATABASE_NOT_INSTALLED, MBROLIB_INVAL). | |||
*/ | |||
MBROLIB_ERROR mbrolib_set_voice( void* the_handle, const char* the_name); | |||
typedef MBROLIB_ERROR (t_mbrolib_set_voice)( void*, const char*); | |||
/** Get the current database parameters. | |||
The caller supplies a pointer to an already allocated structure. | |||
@param the_handle previously given by mbrolib_init. | |||
@param the_parameters: pointer to the structure. | |||
@return error code (MBROLIB_OK, MBROLIB_INVAL). | |||
*/ | |||
MBROLIB_ERROR mbrolib_get_parameter(void* the_handle, mbrolib_parameter* the_parameter); | |||
typedef MBROLIB_ERROR (t_mbrolib_get_parameter)(void*, mbrolib_parameter*); | |||
/** Set the database parameters using the supplied data. | |||
@param the_handle previously given by mbrolib_init. | |||
@param the_parameters: pointer to the wished parameters. | |||
@return error code (MBROLIB_OK, MBROLIB_INVAL). | |||
*/ | |||
MBROLIB_ERROR mbrolib_set_parameter(void* the_handle, const mbrolib_parameter* the_parameter); | |||
typedef MBROLIB_ERROR (t_mbrolib_set_parameter)(void*, const mbrolib_parameter*); | |||
/** Write the mbrola phonemes in the internal buffer. | |||
@param the_handle. | |||
@param the_mbrola_phonemes. | |||
@param the_size in bytes. | |||
@return error code (MBROLIB_OK, MBROLIB_INVAL, MBROLIB_WRITE_ERROR, MBROLIB_READ_ERROR). | |||
*/ | |||
MBROLIB_ERROR mbrolib_write(void* the_handle, const char* the_mbrola_phonemes, size_t the_size); | |||
typedef MBROLIB_ERROR (t_mbrolib_write)(void*, const char*, size_t); | |||
/** Read n bytes of the output samples. | |||
@param the_handle. | |||
@param the_samples (raw audio data, 16bits, mono). | |||
@param the_size max number of int16 to read. | |||
@param the_size number of int16 read. | |||
@return error code (MBROLIB_OK, MBROLIB_INVAL, MBROLIB_READ_ERROR). | |||
*/ | |||
MBROLIB_ERROR mbrolib_read(void* the_handle, short* the_samples, int the_max_size, int* the_read_size); | |||
typedef MBROLIB_ERROR (t_mbrolib_read)(void*, short*, int, int*); | |||
/** Flush | |||
@param the_handle. | |||
*/ | |||
void mbrolib_flush(void* the_handle); | |||
typedef void (t_mbrolib_flush)(void*); | |||
/** Release the handle | |||
@param the_handle. | |||
@return error code (MBROLIB_OK, MBROLIB_INVAL). | |||
*/ | |||
MBROLIB_ERROR mbrolib_terminate(void* the_handle); | |||
typedef MBROLIB_ERROR (t_mbrolib_terminate)(void*); | |||
#ifdef __cplusplus | |||
} | |||
#endif | |||
#endif |
@@ -0,0 +1,578 @@ | |||
/* | |||
* mbrowrap -- A wrapper library around the mbrola binary | |||
* providing a subset of the API from the Windows mbrola DLL. | |||
* | |||
* Copyright (C) 2010 by Nicolas Pitre <[email protected]> | |||
* | |||
* This program is free software; you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation; either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
*/ | |||
#include <stdarg.h> | |||
#include <stdio.h> | |||
#include <unistd.h> | |||
#include <string.h> | |||
#include <malloc.h> | |||
#include <signal.h> | |||
#include <fcntl.h> | |||
#include <poll.h> | |||
#include <errno.h> | |||
#include <sys/types.h> | |||
#include <sys/wait.h> | |||
#include "mbrowrap.h" | |||
/* | |||
* mbrola instance parameters | |||
*/ | |||
enum mbr_state { | |||
MBR_INACTIVE = 0, | |||
MBR_IDLE, | |||
MBR_NEWDATA, | |||
MBR_AUDIO, | |||
MBR_WEDGED | |||
}; | |||
static enum mbr_state mbr_state; | |||
static char *mbr_voice_path; | |||
static int mbr_cmd_fd, mbr_audio_fd, mbr_error_fd, mbr_proc_stat; | |||
static pid_t mbr_pid; | |||
static int mbr_samplerate; | |||
static float mbr_volume = 1.0; | |||
static char mbr_errorbuf[160]; | |||
struct datablock { | |||
struct datablock *next; | |||
int done; | |||
int size; | |||
char buffer[1]; /* 1 or more, dynamically allocated */ | |||
}; | |||
static struct datablock *mbr_pending_data_head, *mbr_pending_data_tail; | |||
/* | |||
* Private support code. | |||
*/ | |||
static void log(const char *msg, ...) | |||
{ | |||
va_list params; | |||
va_start(params, msg); | |||
vfprintf(stderr, msg, params); | |||
fputc('\n', stderr); | |||
va_end(params); | |||
} | |||
static void err(const char *err, ...) | |||
{ | |||
va_list params; | |||
va_start(params, err); | |||
vsnprintf(mbr_errorbuf, sizeof(mbr_errorbuf), err, params); | |||
va_end(params); | |||
log("mbrola error: \"%s\"", mbr_errorbuf); | |||
} | |||
static int create_pipes(int p1[2], int p2[2], int p3[2]) | |||
{ | |||
int error=0; | |||
if (pipe(p1) != -1) { | |||
if (pipe(p2) != -1) { | |||
if (pipe(p3) != -1) { | |||
return 0; | |||
} else | |||
error = errno; | |||
close(p2[0]); | |||
close(p2[1]); | |||
} else | |||
error = errno; | |||
close(p1[0]); | |||
close(p1[1]); | |||
} | |||
err("pipe(): %s", strerror(error)); | |||
return -1; | |||
} | |||
static void close_pipes(int p1[2], int p2[2], int p3[2]) | |||
{ | |||
close(p1[0]); | |||
close(p1[1]); | |||
close(p2[0]); | |||
close(p2[1]); | |||
close(p3[0]); | |||
close(p3[1]); | |||
} | |||
static int start_mbrola(const char *voice_path) | |||
{ | |||
int error, p_stdin[2], p_stdout[2], p_stderr[2]; | |||
char charbuf[20]; | |||
if (mbr_state != MBR_INACTIVE) { | |||
err("mbrola init request when already initialized"); | |||
return -1; | |||
} | |||
error = create_pipes(p_stdin, p_stdout, p_stderr); | |||
if (error) | |||
return -1; | |||
mbr_pid = fork(); | |||
if (mbr_pid == -1) { | |||
error = errno; | |||
close_pipes(p_stdin, p_stdout, p_stderr); | |||
err("fork(): %s", strerror(error)); | |||
return -1; | |||
} | |||
if (mbr_pid == 0) { | |||
int i; | |||
if (dup2(p_stdin[0], 0) == -1 || | |||
dup2(p_stdout[1], 1) == -1 || | |||
dup2(p_stderr[1], 2) == -1) { | |||
snprintf(mbr_errorbuf, sizeof(mbr_errorbuf), | |||
"dup2(): %s\n", strerror(errno)); | |||
write(p_stderr[1], mbr_errorbuf, strlen(mbr_errorbuf)); | |||
_exit(1); | |||
} | |||
for (i = p_stderr[1]; i > 2; i--) | |||
close(i); | |||
signal(SIGHUP, SIG_IGN); | |||
signal(SIGINT, SIG_IGN); | |||
signal(SIGQUIT, SIG_IGN); | |||
signal(SIGTERM, SIG_IGN); | |||
snprintf(charbuf, sizeof(charbuf), "%g", mbr_volume); | |||
execlp("mbrola", "mbrola", "-e", "-v", charbuf, | |||
voice_path, "-", "-.wav", (char *)NULL); | |||
/* if execution reaches this point then the exec() failed */ | |||
snprintf(mbr_errorbuf, sizeof(mbr_errorbuf), | |||
"mbrola: %s\n", strerror(errno)); | |||
write(2, mbr_errorbuf, strlen(mbr_errorbuf)); | |||
_exit(1); | |||
} | |||
snprintf(charbuf, sizeof(charbuf), "/proc/%d/stat", mbr_pid); | |||
mbr_proc_stat = open(charbuf, O_RDONLY); | |||
if (mbr_proc_stat == -1) { | |||
error = errno; | |||
close_pipes(p_stdin, p_stdout, p_stderr); | |||
waitpid(mbr_pid, NULL, 0); | |||
mbr_pid = 0; | |||
err("/proc is unaccessible: %s", strerror(error)); | |||
return -1; | |||
} | |||
signal(SIGPIPE, SIG_IGN); | |||
if (fcntl(p_stdin[1], F_SETFL, O_NONBLOCK) == -1 || | |||
fcntl(p_stdout[0], F_SETFL, O_NONBLOCK) == -1 || | |||
fcntl(p_stderr[0], F_SETFL, O_NONBLOCK) == -1) { | |||
error = errno; | |||
close_pipes(p_stdin, p_stdout, p_stderr); | |||
waitpid(mbr_pid, NULL, 0); | |||
mbr_pid = 0; | |||
err("fcntl(): %s", strerror(error)); | |||
return -1; | |||
} | |||
mbr_cmd_fd = p_stdin[1]; | |||
mbr_audio_fd = p_stdout[0]; | |||
mbr_error_fd = p_stderr[0]; | |||
close(p_stdin[0]); | |||
close(p_stdout[1]); | |||
close(p_stderr[1]); | |||
mbr_state = MBR_IDLE; | |||
return 0; | |||
} | |||
static void stop_mbrola(void) | |||
{ | |||
if (mbr_state == MBR_INACTIVE) | |||
return; | |||
close(mbr_proc_stat); | |||
close(mbr_cmd_fd); | |||
close(mbr_audio_fd); | |||
close(mbr_error_fd); | |||
if (mbr_pid) { | |||
kill(mbr_pid, SIGTERM); | |||
waitpid(mbr_pid, NULL, 0); | |||
mbr_pid = 0; | |||
} | |||
mbr_state = MBR_INACTIVE; | |||
} | |||
static void free_pending_data(void) | |||
{ | |||
struct datablock *p, *head = mbr_pending_data_head; | |||
while (head) { | |||
p = head; | |||
head = head->next; | |||
free(p); | |||
} | |||
mbr_pending_data_head = NULL; | |||
mbr_pending_data_tail = NULL; | |||
} | |||
static int mbrola_has_errors(void) | |||
{ | |||
int result, error; | |||
result = read(mbr_error_fd, mbr_errorbuf, sizeof(mbr_errorbuf)-1); | |||
if (result == -1) { | |||
if (errno == EAGAIN) | |||
return 0; | |||
err("read(error): %s", strerror(errno)); | |||
return -1; | |||
} | |||
if (result != 0) { | |||
mbr_errorbuf[result] = 0; | |||
if (mbr_errorbuf[result - 1] == '\n') | |||
mbr_errorbuf[result - 1] = 0; | |||
/* inhibit the reset signal message */ | |||
if (strncmp(mbr_errorbuf, "Got a reset signal", 18) == 0) { | |||
mbr_errorbuf[0] = 0; | |||
return 0; | |||
} | |||
/* don't consider this fatal at this point */ | |||
error = 0; | |||
} else { | |||
/* EOF on stderr, assume mbrola died. */ | |||
pid_t pid; | |||
int status, len; | |||
const char *msg; | |||
char msgbuf[80]; | |||
pid = waitpid(mbr_pid, &status, WNOHANG); | |||
if (!pid) { | |||
msg = "mbrola closed stderr and did not exit"; | |||
} else { | |||
mbr_pid = 0; | |||
if (WIFSIGNALED(status)) { | |||
int sig = WTERMSIG(status); | |||
snprintf(msgbuf, sizeof(msgbuf), | |||
"mbrola died by signal %d", sig); | |||
msg = msgbuf; | |||
} else if (WIFEXITED(status)) { | |||
int exst = WEXITSTATUS(status); | |||
snprintf(msgbuf, sizeof(msgbuf), | |||
"mbrola exited with status %d", exst); | |||
msg = msgbuf; | |||
} else { | |||
msg = "mbrola died and wait status is weird"; | |||
} | |||
} | |||
len = strlen(mbr_errorbuf); | |||
if (!len) | |||
snprintf(mbr_errorbuf, sizeof(mbr_errorbuf), "%s", msg); | |||
else | |||
snprintf(mbr_errorbuf+len, sizeof(mbr_errorbuf)-len, | |||
", (%s)", msg); | |||
error = -1; | |||
} | |||
log("mbrola error: \"%s\"", mbr_errorbuf); | |||
return error; | |||
} | |||
static int send_to_mbrola(const char *cmd) | |||
{ | |||
ssize_t result; | |||
int len; | |||
if (!mbr_pid) | |||
return -1; | |||
len = strlen(cmd); | |||
result = write(mbr_cmd_fd, cmd, len); | |||
if (result == -1) { | |||
int error = errno; | |||
if (error == EPIPE && mbrola_has_errors()) { | |||
return -1; | |||
} else if (error == EAGAIN) { | |||
result = 0; | |||
} else { | |||
err("write(): %s", strerror(error)); | |||
return -1; | |||
} | |||
} | |||
if (result != len) { | |||
struct datablock *data; | |||
data = (struct datablock *)malloc(sizeof(*data) + len - result); | |||
if (data) { | |||
data->next = NULL; | |||
data->done = 0; | |||
data->size = len - result; | |||
memcpy(data->buffer, cmd + result, len - result); | |||
result = len; | |||
if (!mbr_pending_data_head) | |||
mbr_pending_data_head = data; | |||
else | |||
mbr_pending_data_tail->next = data; | |||
mbr_pending_data_tail = data; | |||
} | |||
} | |||
return result; | |||
} | |||
static int mbrola_is_idle(void) | |||
{ | |||
char *p; | |||
char buffer[20]; /* looking for "12345 (mbrola) S" so 20 is plenty*/ | |||
/* look in /proc to determine if mbrola is still running or sleeping */ | |||
if (lseek(mbr_proc_stat, 0, SEEK_SET) != 0) | |||
return 0; | |||
if (read(mbr_proc_stat, buffer, sizeof(buffer)) != sizeof(buffer)) | |||
return 0; | |||
p = (char *)memchr(buffer, ')', sizeof(buffer)); | |||
if (!p || (unsigned)(p - buffer) >= sizeof(buffer) - 2) | |||
return 0; | |||
return (p[1] == ' ' && p[2] == 'S'); | |||
} | |||
static ssize_t receive_from_mbrola(void *buffer, size_t bufsize) | |||
{ | |||
int result, wait = 1; | |||
size_t cursize = 0; | |||
if (!mbr_pid) | |||
return -1; | |||
do { | |||
struct pollfd pollfd[3]; | |||
nfds_t nfds = 0; | |||
int idle; | |||
pollfd[0].fd = mbr_audio_fd; | |||
pollfd[0].events = POLLIN; | |||
nfds++; | |||
pollfd[1].fd = mbr_error_fd; | |||
pollfd[1].events = POLLIN; | |||
nfds++; | |||
if (mbr_pending_data_head) { | |||
pollfd[2].fd = mbr_cmd_fd; | |||
pollfd[2].events = POLLOUT; | |||
nfds++; | |||
} | |||
idle = mbrola_is_idle(); | |||
result = poll(pollfd, nfds, idle ? 0 : wait); | |||
if (result == -1) { | |||
err("poll(): %s", strerror(errno)); | |||
return -1; | |||
} | |||
if (result == 0) { | |||
if (idle) { | |||
mbr_state = MBR_IDLE; | |||
break; | |||
} else { | |||
if (wait >= 5000 * (4-1)/4) { | |||
mbr_state = MBR_WEDGED; | |||
err("mbrola process is stalled"); | |||
break; | |||
} else { | |||
wait *= 4; | |||
continue; | |||
} | |||
} | |||
} | |||
wait = 1; | |||
if (pollfd[1].revents && mbrola_has_errors()) | |||
return -1; | |||
if (mbr_pending_data_head && pollfd[2].revents) { | |||
struct datablock *head = mbr_pending_data_head; | |||
char *data = head->buffer + head->done; | |||
int left = head->size - head->done; | |||
result = write(mbr_cmd_fd, data, left); | |||
if (result == -1) { | |||
int error = errno; | |||
if (error == EPIPE && mbrola_has_errors()) | |||
return -1; | |||
err("write(): %s", strerror(error)); | |||
return -1; | |||
} | |||
if (result != left) { | |||
head->done += result; | |||
} else { | |||
mbr_pending_data_head = head->next; | |||
free(head); | |||
if (!mbr_pending_data_head) | |||
mbr_pending_data_tail = NULL; | |||
else | |||
continue; | |||
} | |||
} | |||
if (pollfd[0].revents) { | |||
char *curpos = (char *)buffer + cursize; | |||
size_t space = bufsize - cursize; | |||
ssize_t obtained = read(mbr_audio_fd, curpos, space); | |||
if (obtained == -1) { | |||
err("read(): %s", strerror(errno)); | |||
return -1; | |||
} | |||
cursize += obtained; | |||
mbr_state = MBR_AUDIO; | |||
} | |||
} while (cursize < bufsize); | |||
return cursize; | |||
} | |||
/* | |||
* API functions. | |||
*/ | |||
int init_MBR(const char *voice_path) | |||
{ | |||
int error, result; | |||
unsigned char wavhdr[45]; | |||
error = start_mbrola(voice_path); | |||
if (error) | |||
return -1; | |||
result = send_to_mbrola("#\n"); | |||
if (result != 2) { | |||
stop_mbrola(); | |||
return -1; | |||
} | |||
/* we should actually be getting only 44 bytes */ | |||
result = receive_from_mbrola(wavhdr, 45); | |||
if (result != 44) { | |||
err("unable to get .wav header from mbrola"); | |||
stop_mbrola(); | |||
return -1; | |||
} | |||
/* parse wavhdr to get mbrola voice samplerate */ | |||
if (memcmp(wavhdr, "RIFF", 4) != 0 || | |||
memcmp(wavhdr+8, "WAVEfmt ", 8) != 0) { | |||
err("mbrola did not return a .wav header"); | |||
stop_mbrola(); | |||
return -1; | |||
} | |||
mbr_samplerate = wavhdr[24] + (wavhdr[25]<<8) + | |||
(wavhdr[26]<<16) + (wavhdr[27]<<24); | |||
//log("mbrola: voice samplerate = %d", mbr_samplerate); | |||
/* remember the voice path for setVolumeRatio_MBR() */ | |||
if (mbr_voice_path != voice_path) { | |||
free(mbr_voice_path); | |||
mbr_voice_path = strdup(voice_path); | |||
} | |||
return 0; | |||
} | |||
void close_MBR(void) | |||
{ | |||
stop_mbrola(); | |||
free_pending_data(); | |||
free(mbr_voice_path); | |||
mbr_voice_path = NULL; | |||
mbr_volume = 1.0; | |||
} | |||
int reset_MBR() | |||
{ | |||
int result, success = 1; | |||
char dummybuf[4096]; | |||
if (mbr_state == MBR_IDLE) | |||
return 1; | |||
if (!mbr_pid) | |||
return 0; | |||
if (kill(mbr_pid, SIGUSR1) == -1) | |||
success = 0; | |||
free_pending_data(); | |||
result = write(mbr_cmd_fd, "\n#\n", 3); | |||
if (result != 3) | |||
success = 0; | |||
do { | |||
result = read(mbr_audio_fd, dummybuf, sizeof(dummybuf)); | |||
} while (result > 0); | |||
if (result != -1 || errno != EAGAIN) | |||
success = 0; | |||
if (!mbrola_has_errors() && success) | |||
mbr_state = MBR_IDLE; | |||
return success; | |||
} | |||
int read_MBR(void *buffer, int nb_samples) | |||
{ | |||
int result = receive_from_mbrola(buffer, nb_samples * 2); | |||
if (result > 0) | |||
result /= 2; | |||
return result; | |||
} | |||
int write_MBR(const char *data) | |||
{ | |||
mbr_state = MBR_NEWDATA; | |||
return send_to_mbrola(data); | |||
} | |||
int flush_MBR(void) | |||
{ | |||
return send_to_mbrola("\n#\n") == 3; | |||
} | |||
int getFreq_MBR(void) | |||
{ | |||
return mbr_samplerate; | |||
} | |||
void setVolumeRatio_MBR(float value) | |||
{ | |||
if (value == mbr_volume) | |||
return; | |||
mbr_volume = value; | |||
if (mbr_state != MBR_IDLE) | |||
return; | |||
/* | |||
* We have no choice but to kill and restart mbrola with | |||
* the new argument here. | |||
*/ | |||
stop_mbrola(); | |||
init_MBR(mbr_voice_path); | |||
} | |||
int lastErrorStr_MBR(char *buffer, int bufsize) | |||
{ | |||
int result = snprintf(buffer, bufsize, "%s", mbr_errorbuf); | |||
return result >= bufsize ? (bufsize - 1) : result; | |||
} | |||
void resetError_MBR(void) | |||
{ | |||
mbr_errorbuf[0] = 0; | |||
} |
@@ -0,0 +1,108 @@ | |||
/* | |||
* mbrowrap -- A wrapper library around the mbrola binary | |||
* providing a subset of the API from the Windows mbrola DLL. | |||
* | |||
* Copyright (C) 2010 by Nicolas Pitre <[email protected]> | |||
* | |||
* This program is free software; you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation; either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
*/ | |||
#ifndef MBROWRAP_H | |||
#define MBROWRAP_H | |||
#ifdef __cplusplus | |||
extern "C" | |||
{ | |||
#endif | |||
/* | |||
* Initialize mbrola. The 'voice_path' argument must contain the | |||
* path and file name to the mbrola voice database to be used. Returned | |||
* value is 0 on success, or an error code otherwise (currently only -1 | |||
* is returned. If not successful, lastErrorStr_MBR() will provide the | |||
* error reason. If this is successful, then close_MBR() must be called | |||
* before init_MBR() can be called again. | |||
*/ | |||
int init_MBR(const char *voice_path); | |||
/* | |||
* Stop mbrola and release any resources. It is necessary to call | |||
* this after a successful call to init_MBR() before init_MBR() can be | |||
* called again. | |||
*/ | |||
void close_MBR(void); | |||
/* | |||
* Stop any ongoing processing and flush all buffers. After this call | |||
* any synthesis request will start afresh. A non-zero value is returned | |||
* on success, or 0 on failure. If not successful, lastErrorStr_MBR() will | |||
* provide the error reason. | |||
*/ | |||
int reset_MBR(); | |||
/* | |||
* Return at most 'nb_samples' audio samples into 'buffer'. The returned | |||
* value is the actual number of samples returned, or -1 on error. | |||
* If not successful, lastErrorStr_MBR() will provide the error reason. | |||
* Samples are always 16-bit little endian. | |||
*/ | |||
int read_MBR(void *buffer, int nb_samples); | |||
/* | |||
* Write a NULL terminated string of phoneme in the input buffer. | |||
* Return the number of chars actually written, or -1 on error. | |||
* If not successful, lastErrorStr_MBR() will provide the error reason. | |||
*/ | |||
int write_MBR(const char *data); | |||
/* | |||
* Send a flush command to the mbrola input stream. | |||
* This is currently similar to write_MBR("#\n"). Return 1 on success | |||
* or 0 on failure. If not successful, lastErrorStr_MBR() will provide | |||
* the error reason. | |||
*/ | |||
int flush_MBR(void); | |||
/* | |||
* Return the audio sample frequency of the used voice database. | |||
*/ | |||
int getFreq_MBR(void); | |||
/* | |||
* Overall volume. | |||
*/ | |||
void setVolumeRatio_MBR(float value); | |||
/* | |||
* Copy into 'buffer' at most 'bufsize' bytes from the latest error | |||
* message. This may also contain non-fatal errors from mbrola. The | |||
* returned value is the actual number of bytes copied. When no error | |||
* message is pending then an empty string is returned. Consecutive | |||
* calls to lastErrorStr_MBR() will return the same message unless it | |||
* is explicitly cleared with resetError_MBR(). | |||
*/ | |||
int lastErrorStr_MBR(char *buffer, int bufsize); | |||
/* | |||
* Clear any pending error message. | |||
*/ | |||
void resetError_MBR(void); | |||
/* | |||
* Tolerance to missing diphones (always active so this is ignored) | |||
*/ | |||
static inline void setNoError_MBR(int no_error) { } | |||
#ifdef __cplusplus | |||
} | |||
#endif | |||
#endif |
@@ -140,7 +140,6 @@ void SetSpeed(int control) | |||
int s1; | |||
int wpm; | |||
int wpm2; | |||
int test=0; | |||
speed.loud_consonants = 0; | |||
speed.min_sample_len = 450; | |||
@@ -172,43 +171,6 @@ void SetSpeed(int control) | |||
speed.loud_consonants = (wpm - 360) / 8; | |||
} | |||
#ifdef deleted | |||
if(wpm >= 450) | |||
{ | |||
// TEST | |||
speed1 = 6; | |||
speed2 = speed3 = 5; | |||
speed.pause_factor = 12; | |||
speed.clause_pause_factor = 15; | |||
speed.wav_factor = 70; | |||
speed.lenmod_factor = 53; | |||
speed.min_sample_len = 400; | |||
return; | |||
} | |||
if(wpm > 390) | |||
{ | |||
// TEST | |||
speed1 = 6; | |||
speed2 = speed3 = 5; | |||
speed.pause_factor = 13; | |||
speed.clause_pause_factor = 15; | |||
if(wpm >= 440) | |||
{ | |||
speed.wav_factor = 72 - (wpm - 440)/4; | |||
speed.lenmod_factor = 60 - (wpm - 440)/2; | |||
speed.min_sample_len = 420 - (wpm - 440); | |||
} | |||
else | |||
{ | |||
speed.wav_factor = 74; | |||
speed.lenmod_factor = 65 - (wpm - 400)/10; | |||
speed.min_sample_len = 450 - (wpm - 400)/2; | |||
} | |||
return; | |||
} | |||
#endif | |||
wpm2 = wpm; | |||
if(wpm > 359) wpm2 = 359; | |||
if(wpm < 80) wpm2 = 80; | |||
@@ -269,9 +231,6 @@ void SetSpeed(int control) | |||
speed.min_sample_len = 420 - (wpm - 440); | |||
} | |||
if(test > 0) | |||
speed.wav_factor = test; | |||
speed.pause_factor = (256 * s1)/115; // full speed adjustment, used for pause length | |||
speed.clause_pause_factor = 0; | |||
@@ -98,8 +98,10 @@ static const char *help_text = | |||
"\t directory. <voice name> specifies the language\n" | |||
"--path=\"<path>\"\n" | |||
"\t Specifies the directory containing the espeak-data directory\n" | |||
"--pho\n" | |||
"\t Write mbrola phoneme data (.pho) to stdout, or to the file in --phonout\n" | |||
"--phonout=\"<filename>\"\n" | |||
"\t Write output from -x -X commands, and mbrola phoneme data, to this file\n" | |||
"\t Write phoneme output from -x -X and --pho to this file\n" | |||
"--punct=\"<characters>\"\n" | |||
"\t Speak the names of punctuation characters during speaking. If\n" | |||
"\t =<characters> is omitted, all punctuation is spoken.\n" | |||
@@ -214,7 +216,9 @@ void DisplayVoices(FILE *f_out, char *language) | |||
} // end of DisplayVoices | |||
void WVoiceChanged(voice_t *wvoice) | |||
{ | |||
} | |||
static int OpenWaveFile(const char *path, int rate) | |||
//================================================= | |||
@@ -472,7 +476,8 @@ int main (int argc, char **argv) | |||
{"stdout", no_argument, 0, 0x105}, | |||
{"split", optional_argument, 0, 0x106}, | |||
{"path", required_argument, 0, 0x107}, | |||
{"phonout", required_argument, 0, 0x108}, | |||
{"phonout", required_argument, 0, 0x108}, | |||
{"pho", no_argument, 0, 0x109}, | |||
{0, 0, 0, 0} | |||
}; | |||
@@ -702,6 +707,10 @@ int main (int argc, char **argv) | |||
} | |||
break; | |||
case 0x109: // --pho | |||
option_mbrola_phonemes = 8; | |||
break; | |||
default: | |||
exit(0); | |||
} |
@@ -59,6 +59,9 @@ static unsigned int my_unique_identifier=0; | |||
static void* my_user_data=NULL; | |||
static espeak_AUDIO_OUTPUT my_mode=AUDIO_OUTPUT_SYNCHRONOUS; | |||
static int synchronous_mode = 1; | |||
static int out_samplerate = 0; | |||
static int voice_samplerate = 22050; | |||
t_espeak_callback* synth_callback = NULL; | |||
int (* uri_callback)(int, const char *, const char *) = NULL; | |||
int (* phoneme_callback)(const char *) = NULL; | |||
@@ -66,6 +69,13 @@ int (* phoneme_callback)(const char *) = NULL; | |||
char path_home[N_PATH_HOME]; // this is the espeak-data directory | |||
void WVoiceChanged(voice_t *wvoice) | |||
{//================================= | |||
// Voice change in wavegen | |||
voice_samplerate = wvoice->samplerate; | |||
} | |||
#ifdef USE_ASYNC | |||
static int dispatch_audio(short* outbuf, int length, espeak_EVENT* event) | |||
@@ -85,6 +95,34 @@ static int dispatch_audio(short* outbuf, int length, espeak_EVENT* event) | |||
{ | |||
case AUDIO_OUTPUT_PLAYBACK: | |||
{ | |||
int event_type=0; | |||
int event_data=0; | |||
if(event) | |||
{ | |||
event_type = event->type; | |||
event_data = event->id.number; | |||
} | |||
if(event_type == espeakEVENT_SAMPLERATE) | |||
{ | |||
voice_samplerate = event->id.number; | |||
if(out_samplerate != voice_samplerate) | |||
{ | |||
if(out_samplerate != 0) | |||
{ | |||
// sound was previously open with a different sample rate | |||
wave_close(my_audio); | |||
sleep(1); | |||
} | |||
out_samplerate = voice_samplerate; | |||
wave_init(voice_samplerate); | |||
wave_set_callback_is_output_enabled( fifo_is_command_enabled); | |||
my_audio = wave_open("alsa"); | |||
event_init(); | |||
} | |||
} | |||
if (outbuf && length && a_wave_can_be_played) | |||
{ | |||
wave_write (my_audio, (char*)outbuf, 2*length); | |||
@@ -220,17 +258,13 @@ static void select_output(espeak_AUDIO_OUTPUT output_type) | |||
my_audio = NULL; | |||
synchronous_mode = 1; | |||
option_waveout = 1; // inhibit portaudio callback from wavegen.cpp | |||
out_samplerate = 0; | |||
switch(my_mode) | |||
{ | |||
case AUDIO_OUTPUT_PLAYBACK: | |||
// wave_init() is now called just before the first wave_write() | |||
synchronous_mode = 0; | |||
#ifdef USE_ASYNC | |||
wave_init(); | |||
wave_set_callback_is_output_enabled( fifo_is_command_enabled); | |||
my_audio = wave_open("alsa"); | |||
event_init(); | |||
#endif | |||
break; | |||
case AUDIO_OUTPUT_RETRIEVAL: | |||
@@ -734,19 +768,21 @@ ENTER("espeak_Initialize"); | |||
return(EE_INTERNAL_ERROR); | |||
option_phonemes = 0; | |||
option_mbrola_phonemes = 0; | |||
option_phoneme_events = (options & 1); | |||
SetVoiceByName("default"); | |||
VoiceReset(0); | |||
// SetVoiceByName("default"); | |||
for(param=0; param<N_SPEECH_PARAM; param++) | |||
param_stack[0].parameter[param] = param_defaults[param]; | |||
SetParameter(espeakRATE,170,0); | |||
SetParameter(espeakRATE,175,0); | |||
SetParameter(espeakVOLUME,100,0); | |||
SetParameter(espeakCAPITALS,option_capitals,0); | |||
SetParameter(espeakPUNCTUATION,option_punctuation,0); | |||
SetParameter(espeakWORDGAP,0,0); | |||
DoVoiceChange(voice); | |||
// DoVoiceChange(voice); | |||
#ifdef USE_ASYNC | |||
fifo_init(); | |||
@@ -1087,8 +1123,10 @@ ESPEAK_API void espeak_SetPhonemeTrace(int value, FILE *stream) | |||
value=0 No phoneme output (default) | |||
value=1 Output the translated phoneme symbols for the text | |||
value=2 as (1), but also output a trace of how the translation was done (matching rules and list entries) | |||
bit 3: produce mbrola pho data | |||
*/ | |||
option_phonemes = value; | |||
option_phonemes = value & 3; | |||
option_mbrola_phonemes = value & 8; | |||
f_trans = stream; | |||
if(stream == NULL) | |||
f_trans = stderr; | |||
@@ -1163,6 +1201,7 @@ ESPEAK_API espeak_ERROR espeak_Terminate(void) | |||
{ | |||
wave_close(my_audio); | |||
wave_terminate(); | |||
out_samplerate = 0; | |||
} | |||
#endif |
@@ -50,12 +50,13 @@ Revision 5 | |||
typedef enum { | |||
espeakEVENT_LIST_TERMINATED = 0, // Retrieval mode: terminates the event list. | |||
espeakEVENT_WORD = 1, // Start of word | |||
espeakEVENT_SENTENCE, // Start of sentence | |||
espeakEVENT_MARK, // Mark | |||
espeakEVENT_PLAY, // Audio element | |||
espeakEVENT_END, // End of sentence or clause | |||
espeakEVENT_MSG_TERMINATED, // End of message | |||
espeakEVENT_PHONEME // Phoneme, if enabled in espeak_Initialize() | |||
espeakEVENT_SENTENCE = 2, // Start of sentence | |||
espeakEVENT_MARK = 3, // Mark | |||
espeakEVENT_PLAY = 4, // Audio element | |||
espeakEVENT_END = 5, // End of sentence or clause | |||
espeakEVENT_MSG_TERMINATED = 6, // End of message | |||
espeakEVENT_PHONEME = 7, // Phoneme, if enabled in espeak_Initialize() | |||
espeakEVENT_SAMPLERATE = 8 // internal use, set sample rate | |||
} espeak_EVENT_TYPE; | |||
@@ -44,7 +44,6 @@ | |||
#ifdef LIBRARY | |||
#define USE_ASYNC | |||
//#define USE_MBROLA_LIB | |||
#endif | |||
#ifdef _ESPEAKEDIT |
@@ -35,15 +35,11 @@ | |||
extern int Read4Bytes(FILE *f); | |||
extern void SetPitch2(voice_t *voice, int pitch1, int pitch2, int *pitch_base, int *pitch_range); | |||
#ifdef USE_MBROLA_LIB | |||
extern unsigned char *outbuf; | |||
#ifndef PLATFORM_WINDOWS | |||
#include "mbrolib.h" | |||
void * mb_handle; | |||
#include "mbrowrap.h" | |||
#else | |||
#include <windows.h> | |||
@@ -64,7 +60,7 @@ PROCVV reset_MBR; | |||
PROCIV lastError_MBR; | |||
PROCVCI lastErrorStr_MBR; | |||
PROCVI setNoError_MBR; | |||
PROCVI setFreq_MBR; | |||
PROCIV getFreq_MBR; | |||
PROCVF setVolumeRatio_MBR; | |||
@@ -103,13 +99,11 @@ void unload_MBR() | |||
} | |||
#endif // windows | |||
#endif // USE_MBROLA_LIB | |||
static MBROLA_TAB *mbrola_tab = NULL; | |||
static int mbrola_control = 0; | |||
int option_mbrola_phonemes; | |||
espeak_ERROR LoadMbrolaTable(const char *mbrola_voice, const char *phtrans, int srate) | |||
@@ -133,37 +127,35 @@ espeak_ERROR LoadMbrolaTable(const char *mbrola_voice, const char *phtrans, int | |||
} | |||
sprintf(path,"%s/mbrola/%s",path_home,mbrola_voice); | |||
#ifdef USE_MBROLA_LIB | |||
#ifdef PLATFORM_POSIX | |||
if(GetFileLength(path) <= 0) | |||
{ | |||
// mbrola voice file not found, look in /usr/share | |||
sprintf(path,"/usr/share/mbrola/%s",mbrola_voice); | |||
} | |||
#endif | |||
#ifdef PLATFORM_WINDOWS | |||
if(load_MBR() == FALSE) // load mbrola.dll | |||
return(EE_INTERNAL_ERROR); | |||
#endif | |||
if(init_MBR(path) != 0) // initialise the required mbrola voice | |||
return(EE_NOT_FOUND); | |||
setNoError_MBR(1); // don't stop on phoneme errors | |||
#else | |||
mb_handle = mbrolib_init(srate); | |||
mbrolib_parameter m_parameters; | |||
if(mb_handle == NULL) | |||
return(EE_INTERNAL_ERROR); | |||
MBROLIB_ERROR a_status = mbrolib_set_voice(mb_handle, mbrola_voice); | |||
if(a_status != MBROLIB_OK) | |||
return(EE_NOT_FOUND); | |||
#endif // not windows | |||
#endif // USE_MBROLA_LIB | |||
// read eSpeak's mbrola phoneme translation data, eg. en1_phtrans | |||
sprintf(path,"%s/mbrola_ph/%s",path_home,phtrans); | |||
size = GetFileLength(path); | |||
if((f_in = fopen(path,"r")) == NULL) | |||
if((f_in = fopen(path,"r")) == NULL) { | |||
close_MBR(); | |||
return(EE_NOT_FOUND); | |||
} | |||
if((mbrola_tab = (MBROLA_TAB *)realloc(mbrola_tab,size)) == NULL) | |||
{ | |||
fclose(f_in); | |||
close_MBR(); | |||
return(EE_INTERNAL_ERROR); | |||
} | |||
@@ -176,26 +168,16 @@ espeak_ERROR LoadMbrolaTable(const char *mbrola_voice, const char *phtrans, int | |||
fread(mbrola_tab,size,1,f_in); | |||
fclose(f_in); | |||
#ifdef USE_MBROLA_LIB | |||
#ifdef PLATFORM_WINDOWS | |||
setVolumeRatio_MBR((float)(mbrola_control & 0xff) /16.0f); | |||
#else | |||
mbrolib_get_parameter(mb_handle,&m_parameters); | |||
m_parameters.ignore_error = 1; | |||
m_parameters.volume_ratio = (float)(mbrola_control & 0xff) /16.0; | |||
mbrolib_set_parameter(mb_handle,&m_parameters); | |||
#endif // not windows | |||
#endif // USE_MBROLA_LIB | |||
option_quiet = 1; | |||
// srate = getFreq_MBR(); | |||
samplerate = srate; | |||
if(srate == 22050) | |||
SetParameter(espeakVOICETYPE,0,0); | |||
else | |||
SetParameter(espeakVOICETYPE,1,0); | |||
strcpy(mbrola_name,mbrola_voice); | |||
mbrola_delay = 3800; // improve synchronization of events | |||
// mbrola_delay = 3800; // improve synchronization of events | |||
mbrola_delay = 1000; // improve synchronization of events | |||
return(EE_OK); | |||
} // end of LoadMbrolaTable | |||
@@ -383,155 +365,10 @@ static char *WritePitch(int env, int pitch1, int pitch2, int split, int final) | |||
} // end of WritePitch | |||
#ifdef USE_MBROLA_LIB | |||
static void MbrolaMarker(int type, int char_posn, int length, int value) | |||
{//===================================================================== | |||
MarkerEvent(type,(char_posn & 0xffffff) | (length << 24),value,outbuf); | |||
} | |||
static void MbrolaEmbedded(int &embix, int sourceix) | |||
{//================================================= | |||
// There were embedded commands in the text at this point | |||
unsigned int word; // bit 7=last command for this word, bits 5,6 sign, bits 0-4 command | |||
unsigned int value; | |||
int command; | |||
int sign=0; | |||
do { | |||
word = embedded_list[embix++]; | |||
value = word >> 8; | |||
command = word & 0x1f; | |||
if((word & 0x60) == 0x60) | |||
sign = -1; | |||
else | |||
if((word & 0x60) == 0x40) | |||
sign = 1; | |||
if(command < N_EMBEDDED_VALUES) | |||
{ | |||
if(sign == 0) | |||
embedded_value[command] = value; | |||
else | |||
embedded_value[command] += (value * sign); | |||
} | |||
switch(command & 0x1f) | |||
{ | |||
case EMBED_M: // named marker | |||
MbrolaMarker(espeakEVENT_MARK, (sourceix & 0x7ff) + clause_start_char, 0, value); | |||
break; | |||
} | |||
} while ((word & 0x80) == 0); | |||
} | |||
#ifdef PLATFORM_WINDOWS | |||
static int MbrolaSynth(char *p_mbrola) | |||
{//=================================== | |||
// p_mbrola is a string of mbrola pho lines - Windows | |||
int len; | |||
int finished; | |||
int result=0; | |||
if(synth_callback == NULL) | |||
return(1); | |||
if(p_mbrola == NULL) | |||
flush_MBR(); | |||
else | |||
result = write_MBR(p_mbrola); | |||
finished = 0; | |||
while(!finished && ((len = read_MBR((short *)outbuf, outbuf_size/2)) > 0)) | |||
{ | |||
out_ptr = outbuf + len*2; | |||
if(event_list) | |||
{ | |||
event_list[event_list_ix].type = espeakEVENT_LIST_TERMINATED; // indicates end of event list | |||
event_list[event_list_ix].user_data = 0; | |||
} | |||
count_samples += len; | |||
finished = synth_callback((short *)outbuf, len, event_list); | |||
event_list_ix=0; | |||
} | |||
if(finished) | |||
{ | |||
// cancelled by user, discard any unused mbrola speech | |||
flush_MBR(); | |||
while((len = read_MBR((short *)outbuf, outbuf_size/2)) > 0); | |||
} | |||
return(finished); | |||
} // end of SynthMbrola | |||
#else | |||
static int MbrolaSynth(char *p_mbrola) | |||
{//=================================== | |||
// p_mbrola is a string of mbrola pho lines - Linux | |||
// This is wrong | |||
// It must be called from WavegenFill() | |||
int len; | |||
int finished; | |||
int result=0; | |||
if(synth_callback == NULL) | |||
return(1); | |||
if(p_mbrola == NULL) | |||
mbrolib_flush(mb_handle); | |||
else | |||
result = mbrolib_write(mb_handle,p_mbrola,strlen(p_mbrola)); | |||
finished = 0; | |||
while(!finished && (mbrolib_read(mb_handle, (short *)out_ptr, (out_end - out_ptr)/2, &len) == MBROLIB_OK)) | |||
{ | |||
if(len == 0) | |||
break; | |||
out_ptr += (len*2); | |||
if(event_list) | |||
{ | |||
event_list[event_list_ix].type = espeakEVENT_LIST_TERMINATED; // indicates end of event list | |||
event_list[event_list_ix].user_data = 0; | |||
} | |||
count_samples += len; | |||
finished = synth_callback((short *)outbuf, len, event_list); | |||
event_list_ix=0; | |||
} | |||
if(finished) | |||
{ | |||
// cancelled by user, discard any unused mbrola speech | |||
mbrolib_flush(mb_handle); | |||
while(mbrolib_read(mb_handle, (short *)outbuf, outbuf_size/2, &len) == MBROLIB_OK) | |||
{ | |||
if(len == 0) | |||
break; | |||
} | |||
} | |||
return(finished); | |||
} // end of SynthMbrola | |||
#endif // not windows | |||
#endif // USE_MBROLA_LIB | |||
void MbrolaTranslate(PHONEME_LIST *plist, int n_phonemes, FILE *f_mbrola) | |||
{//====================================================================== | |||
int MbrolaTranslate(PHONEME_LIST *plist, int n_phonemes, int resume, FILE *f_mbrola) | |||
{//================================================================================= | |||
// Generate a mbrola pho file | |||
unsigned int name; | |||
int phix; | |||
int len; | |||
int len1; | |||
PHONEME_TAB *ph; | |||
@@ -552,21 +389,21 @@ void MbrolaTranslate(PHONEME_LIST *plist, int n_phonemes, FILE *f_mbrola) | |||
char buf[80]; | |||
char mbr_buf[120]; | |||
#ifdef USE_MBROLA_LIB | |||
int embedded_ix=0; | |||
int word_count=0; | |||
static int phix; | |||
static int embedded_ix; | |||
static int word_count; | |||
event_list_ix = 0; | |||
out_ptr = outbuf; | |||
#ifdef PLATFORM_WINDOWS | |||
setNoError_MBR(1); // don't stop on phoneme errors | |||
#endif | |||
#else | |||
// fprintf(f_mbrola,";; v=%.2f\n",(float)(mbrola_control & 0xff)/16.0); // ;; v= has no effect on mbrola | |||
#endif | |||
if (!resume) { | |||
phix = 1; | |||
embedded_ix = 0; | |||
word_count = 0; | |||
} | |||
for(phix=1; phix < n_phonemes; phix++) | |||
while (phix < n_phonemes) | |||
{ | |||
if (WcmdqFree() < MIN_WCMDQ) | |||
return 1; | |||
mbr_buf[0] = 0; | |||
p = &plist[phix]; | |||
@@ -576,24 +413,24 @@ void MbrolaTranslate(PHONEME_LIST *plist, int n_phonemes, FILE *f_mbrola) | |||
ph_prev = plist[phix-1].ph; | |||
ph_next = plist[phix+1].ph; | |||
#ifdef USE_MBROLA_LIB | |||
if(p->synthflags & SFLAG_EMBEDDED) | |||
{ | |||
MbrolaEmbedded(embedded_ix, p->sourceix); | |||
DoEmbedded(embedded_ix, p->sourceix); | |||
} | |||
if(p->newword & 4) | |||
MbrolaMarker(espeakEVENT_SENTENCE, (p->sourceix & 0x7ff) + clause_start_char, 0, count_sentences); | |||
if(p->newword & 4) | |||
DoMarker(espeakEVENT_SENTENCE, (p->sourceix & 0x7ff) + clause_start_char, 0, count_sentences); | |||
if(p->newword & 1) | |||
MbrolaMarker(espeakEVENT_WORD, (p->sourceix & 0x7ff) + clause_start_char, p->sourceix >> 11, clause_start_word + word_count++); | |||
#endif | |||
DoMarker(espeakEVENT_WORD, (p->sourceix & 0x7ff) + clause_start_char, p->sourceix >> 11, clause_start_word + word_count++); | |||
name = GetMbrName(p,ph,ph_prev,ph_next,&name2,&len_percent,&control); | |||
if(control & 1) | |||
phix++; | |||
if(name == 0) | |||
if(name == 0) { | |||
phix++; | |||
continue; // ignore this phoneme | |||
} | |||
if((ph->type == phPAUSE) && (name == ph->mnemonic)) | |||
{ | |||
@@ -607,9 +444,7 @@ void MbrolaTranslate(PHONEME_LIST *plist, int n_phonemes, FILE *f_mbrola) | |||
else | |||
len = (80 * speed.wav_factor)/256; | |||
#ifdef USE_MBROLA_LIB | |||
MbrolaMarker(espeakEVENT_PHONEME, (p->sourceix & 0x7ff) + clause_start_char, 0, ph->mnemonic); | |||
#endif | |||
DoMarker(espeakEVENT_PHONEME, (p->sourceix & 0x7ff) + clause_start_char, 0, ph->mnemonic); | |||
sprintf(buf,"%s\t",WordToString(name)); | |||
strcat(mbr_buf,buf); | |||
@@ -720,6 +555,7 @@ void MbrolaTranslate(PHONEME_LIST *plist, int n_phonemes, FILE *f_mbrola) | |||
if(pause) | |||
{ | |||
len += PauseLength(pause,0); | |||
sprintf(buf,"_ \t%d\n",PauseLength(pause,0)); | |||
strcat(mbr_buf,buf); | |||
pause = 0; | |||
@@ -731,39 +567,78 @@ void MbrolaTranslate(PHONEME_LIST *plist, int n_phonemes, FILE *f_mbrola) | |||
} | |||
else | |||
{ | |||
#ifdef USE_MBROLA_LIB | |||
if(MbrolaSynth(mbr_buf) != 0) | |||
return; | |||
#endif | |||
int res = write_MBR(mbr_buf); | |||
if (res < 0) | |||
return 0; /* don't get stuck on error */ | |||
if (res == 0) | |||
return 1; | |||
wcmdq[wcmdq_tail][0] = WCMD_MBROLA_DATA; | |||
wcmdq[wcmdq_tail][1] = len; | |||
WcmdqInc(); | |||
} | |||
} | |||
#ifdef USE_MBROLA_LIB | |||
MbrolaSynth(NULL); | |||
#endif | |||
} // end of MbrolaTranslate | |||
phix++; | |||
} | |||
#ifdef TEST_MBROLA | |||
if(!f_mbrola) | |||
{ | |||
flush_MBR(); | |||
static PHONEME_LIST mbrola_phlist; | |||
static int mbrola_n_ph; | |||
static int mbrola_phix; | |||
// flush the mbrola output buffer | |||
wcmdq[wcmdq_tail][0] = WCMD_MBROLA_DATA; | |||
wcmdq[wcmdq_tail][1] = 500; | |||
WcmdqInc(); | |||
} | |||
return 0; | |||
} // end of MbrolaTranslate | |||
int MbrolaFill(int fill_zeros) | |||
{//=========================== | |||
} | |||
int MbrolaGenerate(PHONEME_LIST *phoneme_list, int *n_ph, int resume) | |||
{//================================================================== | |||
if(resume == 0) | |||
FILE *f_mbrola = NULL; | |||
if(*n_ph == 0) | |||
return(0); | |||
if(option_mbrola_phonemes) | |||
{ | |||
mbrola_phlist = phoneme_list; | |||
mbrola_n_ph = n_ph; | |||
mbrola_phix = 0; | |||
// send mbrola data to a file, not to the mbrola library | |||
f_mbrola = f_trans; | |||
} | |||
resume(0); // finished phoneme list | |||
int again = MbrolaTranslate(phoneme_list, *n_ph, resume, f_mbrola); | |||
if (!again) | |||
*n_ph = 0; | |||
return again; | |||
} | |||
int MbrolaFill(int length, int resume) | |||
{//=================================== | |||
// Read audio data from Mbrola (length is in milisecs) | |||
static int n_samples; | |||
int req_samples, result; | |||
if (!resume) | |||
n_samples = samplerate * length / 1000; | |||
req_samples = (out_end - out_ptr)/2; | |||
if (req_samples > n_samples) | |||
req_samples = n_samples; | |||
result = read_MBR((short *)out_ptr, req_samples); | |||
if (result <= 0) | |||
return 0; | |||
out_ptr += result*2; | |||
n_samples -= result; | |||
return n_samples ? 1 : 0; | |||
} | |||
void MbrolaReset(void) | |||
{//=================== | |||
// Reset the Mbrola engine and flush the pending audio | |||
reset_MBR(); | |||
} | |||
#endif |
@@ -35,7 +35,7 @@ | |||
#include "translate.h" | |||
#include "wave.h" | |||
const char *version_string = "1.43.46 20.Jun.10"; | |||
const char *version_string = "1.43.48 28.Jun.10"; | |||
const int version_phdata = 0x014342; | |||
int option_device_number = -1; |
@@ -135,7 +135,7 @@ static void EndPitch(int voice_break) | |||
syllable_centre = -1; | |||
memset(vowel_transition,0,sizeof(vowel_transition)); | |||
} | |||
} // end of Synthesize::EndPitch | |||
} // end of EndPitch | |||
@@ -152,7 +152,7 @@ static void DoAmplitude(int amp, unsigned char *amp_env) | |||
q[2] = (long)amp_env; | |||
q[3] = amp; | |||
WcmdqInc(); | |||
} // end of Synthesize::DoAmplitude | |||
} // end of DoAmplitude | |||
@@ -181,7 +181,7 @@ static void DoPitch(unsigned char *env, int pitch1, int pitch2) | |||
q[2] = (long)env; | |||
q[3] = (pitch1 << 16) + pitch2; | |||
WcmdqInc(); | |||
} // end of Synthesize::DoPitch | |||
} // end of DoPitch | |||
@@ -223,7 +223,7 @@ static void DoPause(int length, int control) | |||
wcmdq[wcmdq_tail][1] = len; | |||
WcmdqInc(); | |||
last_frame = NULL; | |||
} // end of Synthesize::DoPause | |||
} // end of DoPause | |||
extern int seq_len_adjust; // temporary fix to advance the start point for playing the wav sample | |||
@@ -253,9 +253,9 @@ static int DoSample2(int index, int which, int std_length, int control, int leng | |||
else | |||
{ | |||
// 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) | |||
@@ -383,32 +383,6 @@ static int DoSample2(int index, int which, int std_length, int control, int leng | |||
} // 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) | |||
{//========================================================= | |||
@@ -1198,8 +1172,8 @@ if(which==1) | |||
static void DoMarker(int type, int char_posn, int length, int value) | |||
{//================================================================= | |||
void DoMarker(int type, int char_posn, int length, int value) | |||
{//========================================================== | |||
// This could be used to return an index to the word currently being spoken | |||
// Type 1=word, 2=sentence, 3=named marker, 4=play audio, 5=end | |||
wcmdq[wcmdq_tail][0] = WCMD_MARKER; | |||
@@ -1208,7 +1182,7 @@ static void DoMarker(int type, int char_posn, int length, int value) | |||
wcmdq[wcmdq_tail][3] = value; | |||
WcmdqInc(); | |||
} // end of Synthesize::DoMarker | |||
} // end of DoMarker | |||
void DoVoiceChange(voice_t *v) | |||
@@ -1224,8 +1198,8 @@ void DoVoiceChange(voice_t *v) | |||
} | |||
static void DoEmbedded(int &embix, int sourceix) | |||
{//============================================= | |||
void DoEmbedded(int &embix, int sourceix) | |||
{//====================================== | |||
// There were embedded commands in the text at this point | |||
unsigned int word; // bit 7=last command for this word, bits 5,6 sign, bits 0-4 command | |||
unsigned int value; | |||
@@ -1305,14 +1279,12 @@ int Generate(PHONEME_LIST *phoneme_list, int *n_ph, int resume) | |||
PHONEME_DATA phdata_tone; | |||
FMT_PARAMS fmtp; | |||
#ifdef TEST_MBROLA | |||
if(mbrola_name[0] != 0) | |||
return(MbrolaGenerate(phoneme_list,n_ph,resume)); | |||
#endif | |||
if(option_quiet) | |||
return(0); | |||
if(mbrola_name[0] != 0) | |||
return(MbrolaGenerate(phoneme_list,n_ph,resume)); | |||
if(resume == 0) | |||
{ | |||
ix = 1; | |||
@@ -1899,20 +1871,6 @@ int SpeakNextClause(FILE *f_in, const void *text_in, int control) | |||
return(1); | |||
} | |||
if(mbrola_name[0] != 0) | |||
{ | |||
#ifdef USE_MBROLA_LIB | |||
MbrolaTranslate(phoneme_list,n_phoneme_list,NULL); | |||
#else | |||
{ | |||
FILE *f_mbrola; | |||
if((f_mbrola = f_trans) == stderr) | |||
f_mbrola = stdout; | |||
MbrolaTranslate(phoneme_list,n_phoneme_list,f_mbrola); | |||
} | |||
#endif | |||
} | |||
Generate(phoneme_list,&n_phoneme_list,0); | |||
WavegenOpenSound(); | |||
@@ -462,6 +462,7 @@ extern unsigned char pitch_adjust_tab[MAX_PITCH_VALUE+1]; | |||
#define WCMD_MARKER 10 | |||
#define WCMD_VOICE 11 | |||
#define WCMD_EMBEDDED 12 | |||
#define WCMD_MBROLA_DATA 13 | |||
#define N_WCMDQ 160 | |||
@@ -557,8 +558,12 @@ espeak_ERROR SetVoiceByName(const char *name); | |||
espeak_ERROR SetVoiceByProperties(espeak_VOICE *voice_selector); | |||
espeak_ERROR LoadMbrolaTable(const char *mbrola_voice, const char *phtrans, int srate); | |||
void SetParameter(int parameter, int value, int relative); | |||
void MbrolaTranslate(PHONEME_LIST *plist, int n_phonemes, FILE *f_mbrola); | |||
//int MbrolaSynth(char *p_mbrola); | |||
int MbrolaTranslate(PHONEME_LIST *plist, int n_phonemes, int resume, FILE *f_mbrola); | |||
int MbrolaGenerate(PHONEME_LIST *phoneme_list, int *n_ph, int resume); | |||
int MbrolaFill(int length, int resume); | |||
void MbrolaReset(void); | |||
void DoEmbedded(int &embix, int sourceix); | |||
void DoMarker(int type, int char_posn, int length, int value); | |||
//int DoSample(PHONEME_TAB *ph1, PHONEME_TAB *ph2, int which, int length_mod, int amp); | |||
int DoSample3(PHONEME_DATA *phdata, int length_mod, int amp); | |||
int DoSpect2(PHONEME_TAB *this_ph, int which, FMT_PARAMS *fmt_params, PHONEME_LIST *plist, int modulation); |
@@ -1,21 +0,0 @@ | |||
/*************************************************************************** | |||
* 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" | |||
@@ -881,7 +881,6 @@ SetLengthMods(tr,3); // all equal | |||
static const short stress_lengths_nl[8] = {160,135, 210,210, 0, 0, 260,280}; | |||
tr->langopts.stress_rule = STRESSPOSN_1L; | |||
tr->langopts.vowel_pause = 1; | |||
tr->langopts.vowel_pause = 0x30; // ?? | |||
tr->langopts.param[LOPT_DIERESES] = 1; | |||
tr->langopts.param[LOPT_PREFIXES] = 1; |
@@ -545,6 +545,7 @@ extern int option_tone_flags; | |||
extern int option_waveout; | |||
extern int option_quiet; | |||
extern int option_phonemes; | |||
extern int option_mbrola_phonemes; | |||
extern int option_phoneme_events; | |||
extern int option_linelength; // treat lines shorter than this as end-of-clause | |||
extern int option_multibyte; |
@@ -41,6 +41,7 @@ typedef struct { | |||
int formant_factor; // adjust nominal formant frequencies by this because of the voice's pitch (256ths) | |||
int consonant_amp; // amplitude of unvoiced consonants | |||
int consonant_ampv; // amplitude of the noise component of voiced consonants | |||
int samplerate; | |||
int klattv[8]; | |||
// parameters used by Wavegen | |||
@@ -77,6 +78,8 @@ espeak_VOICE *SelectVoiceByName(espeak_VOICE **voices, const char *name); | |||
voice_t *LoadVoice(const char *voice_name, int control); | |||
voice_t *LoadVoiceVariant(const char *voice_name, int variant); | |||
void DoVoiceChange(voice_t *v); | |||
void WVoiceChanged(voice_t *wvoice); | |||
void WavegenSetVoice(voice_t *v); | |||
void ReadTonePoints(char *string, int *tone_pts); | |||
void VoiceReset(int control); | |||
@@ -408,6 +408,7 @@ void VoiceReset(int tone_only) | |||
voice->voicing = 64; | |||
voice->consonant_amp = 100; | |||
voice->consonant_ampv = 100; | |||
voice->samplerate = 22050; | |||
memset(voice->klattv,0,sizeof(voice->klattv)); | |||
memset(speed.fast_settings,0,sizeof(speed.fast_settings)); | |||
@@ -921,6 +922,7 @@ voice_t *LoadVoice(const char *vname, int control) | |||
phtrans[0] = 0; | |||
sscanf(p,"%s %s %d",name,phtrans,&srate); | |||
LoadMbrolaTable(name,phtrans,srate); | |||
voice->samplerate = srate; | |||
} | |||
break; | |||
@@ -56,15 +56,16 @@ enum {ONE_BILLION=1000000000}; | |||
static t_wave_callback* my_callback_is_output_enabled=NULL; | |||
#define N_WAV_BUF 10 | |||
#define SAMPLE_RATE 22050 | |||
#define MAX_SAMPLE_RATE 22050 | |||
#define FRAMES_PER_BUFFER 512 | |||
#define BUFFER_LENGTH (SAMPLE_RATE*2*sizeof(uint16_t)) | |||
#define THRESHOLD (BUFFER_LENGTH/5) | |||
#define BUFFER_LENGTH (MAX_SAMPLE_RATE*2*sizeof(uint16_t)) | |||
//#define THRESHOLD (BUFFER_LENGTH/5) | |||
static char myBuffer[BUFFER_LENGTH]; | |||
static char* myRead=NULL; | |||
static char* myWrite=NULL; | |||
static int out_channels=1; | |||
static int my_stream_could_start=0; | |||
static int wave_samplerate; | |||
static int mInCallbackFinishedState = false; | |||
#if (USE_PORTAUDIO == 18) | |||
@@ -168,89 +169,89 @@ static int pa_callback(void *inputBuffer, void *outputBuffer, | |||
PaStreamCallbackFlags flags, void *userData ) | |||
#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 | |||
@@ -288,7 +289,7 @@ static int pa_callback(void *inputBuffer, void *outputBuffer, | |||
#endif | |||
return(aResult); | |||
return(aResult); | |||
//#endif | |||
} // end of WaveCallBack | |||
@@ -335,7 +336,7 @@ static int wave_open_sound() | |||
out_channels = 1; | |||
#if USE_PORTAUDIO == 18 | |||
// err = Pa_OpenDefaultStream(&pa_stream,0,1,paInt16,SAMPLE_RATE,FRAMES_PER_BUFFER,N_WAV_BUF,pa_callback,(void *)userdata); | |||
// err = Pa_OpenDefaultStream(&pa_stream,0,1,paInt16,wave_samplerate,FRAMES_PER_BUFFER,N_WAV_BUF,pa_callback,(void *)userdata); | |||
PaDeviceID playbackDevice = Pa_GetDefaultOutputDeviceID(); | |||
@@ -351,7 +352,7 @@ static int wave_open_sound() | |||
paInt16, | |||
NULL, | |||
/* general parameters */ | |||
SAMPLE_RATE, FRAMES_PER_BUFFER, 0, | |||
wave_samplerate, FRAMES_PER_BUFFER, 0, | |||
//paClipOff | paDitherOff, | |||
paNoFlag, | |||
pa_callback, (void *)userdata); | |||
@@ -376,12 +377,12 @@ static int wave_open_sound() | |||
paInt16, | |||
NULL, | |||
/* general parameters */ | |||
SAMPLE_RATE, FRAMES_PER_BUFFER, 0, | |||
wave_samplerate, FRAMES_PER_BUFFER, 0, | |||
//paClipOff | paDitherOff, | |||
paNoFlag, | |||
pa_callback, (void *)userdata); | |||
// err = Pa_OpenDefaultStream(&pa_stream,0,2,paInt16, | |||
// SAMPLE_RATE, | |||
// wave_samplerate, | |||
// FRAMES_PER_BUFFER, | |||
// N_WAV_BUF,pa_callback,(void *)userdata); | |||
SHOW("wave_open_sound > Pa_OpenDefaultStream(2): err=%d (%s)\n",err, Pa_GetErrorText(err)); | |||
@@ -395,7 +396,7 @@ static int wave_open_sound() | |||
&pa_stream, | |||
NULL, /* no input */ | |||
&myOutputParameters, | |||
SAMPLE_RATE, | |||
wave_samplerate, | |||
framesPerBuffer, | |||
paNoFlag, | |||
// paClipOff | paDitherOff, | |||
@@ -410,7 +411,7 @@ static int wave_open_sound() | |||
&pa_stream, | |||
NULL, /* no input */ | |||
&myOutputParameters, | |||
SAMPLE_RATE, | |||
wave_samplerate, | |||
framesPerBuffer, | |||
paNoFlag, | |||
// paClipOff | paDitherOff, | |||
@@ -427,14 +428,14 @@ static int wave_open_sound() | |||
&pa_stream, | |||
NULL, /* no input */ | |||
&myOutputParameters, | |||
SAMPLE_RATE, | |||
wave_samplerate, | |||
framesPerBuffer, | |||
paNoFlag, | |||
// paClipOff | paDitherOff, | |||
pa_callback, | |||
(void *)userdata); | |||
// err = Pa_OpenDefaultStream(&pa_stream,0,2,paInt16,(double)SAMPLE_RATE,FRAMES_PER_BUFFER,pa_callback,(void *)userdata); | |||
// err = Pa_OpenDefaultStream(&pa_stream,0,2,paInt16,(double)wave_samplerate,FRAMES_PER_BUFFER,pa_callback,(void *)userdata); | |||
} | |||
mInCallbackFinishedState = false; | |||
#endif | |||
@@ -526,7 +527,7 @@ static void select_device(const char* the_api) | |||
defaultAlsaIndex = hostInfo->defaultOutputDevice; | |||
const PaDeviceInfo *deviceInfo = Pa_GetDeviceInfo( defaultAlsaIndex ); | |||
update_output_parameters(defaultAlsaIndex, deviceInfo); | |||
if (Pa_IsFormatSupported(NULL, &myOutputParameters, SAMPLE_RATE) == 0) | |||
if (Pa_IsFormatSupported(NULL, &myOutputParameters, wave_samplerate) == 0) | |||
{ | |||
SHOW( "select_device > ALSA (default), name=%s (#%d)\n", deviceInfo->name, defaultAlsaIndex); | |||
selectedIndex = defaultAlsaIndex; | |||
@@ -541,7 +542,7 @@ static void select_device(const char* the_api) | |||
update_output_parameters(i, deviceInfo); | |||
if (Pa_IsFormatSupported(NULL, &myOutputParameters, SAMPLE_RATE) == 0) | |||
if (Pa_IsFormatSupported(NULL, &myOutputParameters, wave_samplerate) == 0) | |||
{ | |||
SHOW( "select_device > ALSA, name=%s (#%d)\n", deviceInfo->name, i); | |||
@@ -613,12 +614,13 @@ void wave_set_callback_is_output_enabled(t_wave_callback* cb) | |||
//<wave_init | |||
// TBD: the arg could be "alsa", "oss",... | |||
void wave_init() | |||
void wave_init(int srate) | |||
{ | |||
ENTER("wave_init"); | |||
PaError err; | |||
pa_stream = NULL; | |||
wave_samplerate = srate; | |||
mInCallbackFinishedState = false; | |||
init_buffer(); | |||
@@ -1023,7 +1025,7 @@ int wave_get_remaining_time(uint32_t sample, uint32_t* time) | |||
{ | |||
// TBD: take in account time suplied by portaudio V18 API | |||
a_time = sample - myReadPosition; | |||
a_time = 0.5 + (a_time * 1000.0) / SAMPLE_RATE; | |||
a_time = 0.5 + (a_time * 1000.0) / wave_samplerate; | |||
} | |||
else | |||
{ | |||
@@ -1050,7 +1052,7 @@ void *wave_test_get_write_buffer() | |||
// notdef USE_PORTAUDIO | |||
void wave_init() {} | |||
void wave_init(int srate) {} | |||
void* wave_open(const char* the_api) {return (void *)1;} | |||
size_t wave_write(void* theHandler, char* theMono16BitsWaveBuffer, size_t theSize) {return theSize;} | |||
int wave_close(void* theHandler) {return 0;} |
@@ -7,7 +7,7 @@ | |||
extern int option_device_number; | |||
extern void wave_init(); | |||
extern void wave_init(int samplerate); | |||
// TBD: the arg could be "alsa", "oss",... | |||
extern void* wave_open(const char* the_api); | |||
@@ -65,7 +65,6 @@ enum { | |||
static t_wave_callback* my_callback_is_output_enabled=NULL; | |||
#define SAMPLE_RATE 22050 | |||
#define ESPEAK_FORMAT PA_SAMPLE_S16LE | |||
#define ESPEAK_CHANNEL 1 | |||
@@ -90,6 +89,7 @@ static int time_offset_msec = 0; | |||
static int just_flushed = 0; | |||
static int connected = 0; | |||
static int wave_samplerate; | |||
#define CHECK_DEAD_GOTO(label, warn) do { \ | |||
if (!mainloop || \ | |||
@@ -475,7 +475,7 @@ static int pulse_open() | |||
pthread_mutex_init( &pulse_mutex, (const pthread_mutexattr_t *)NULL); | |||
ss.format = ESPEAK_FORMAT; | |||
ss.rate = SAMPLE_RATE; | |||
ss.rate = wave_samplerate; | |||
ss.channels = ESPEAK_CHANNEL; | |||
if (!pa_sample_spec_valid(&ss)) | |||
@@ -677,11 +677,12 @@ void wave_set_callback_is_output_enabled(t_wave_callback* cb) | |||
//> | |||
//<wave_init | |||
void wave_init() | |||
void wave_init(int srate) | |||
{ | |||
ENTER("wave_init"); | |||
stream = NULL; | |||
wave_samplerate = srate; | |||
pulse_open(); | |||
} | |||
@@ -846,7 +847,7 @@ int wave_get_remaining_time(uint32_t sample, uint32_t* time) | |||
{ | |||
// TBD: take in account time suplied by portaudio V18 API | |||
a_time = sample - a_timing_info.read_index; | |||
a_time = 0.5 + (a_time * 1000.0) / SAMPLE_RATE; | |||
a_time = 0.5 + (a_time * 1000.0) / wave_samplerate; | |||
} | |||
else | |||
{ |
@@ -77,12 +77,14 @@ static uint32_t last_play_position=0; | |||
// | |||
//<wave_init | |||
void wave_init() { | |||
void wave_init(int srate) { | |||
ENTER("wave_init"); | |||
audio_info_t ainfo; | |||
char *audio_device = NULL; | |||
wave_samplerate = srate; | |||
audio_device = getenv("AUDIODEV"); | |||
if (audio_device != NULL) { | |||
if ((sun_audio_fd = open(audio_device, O_WRONLY)) < 0) { | |||
@@ -108,7 +110,7 @@ void wave_init() { | |||
SHOW("wave_init() play buffer size: %d\n", ainfo.play.buffer_size); | |||
ainfo.play.encoding = AUDIO_ENCODING_LINEAR; | |||
ainfo.play.channels = 1; | |||
ainfo.play.sample_rate = SAMPLE_RATE; | |||
ainfo.play.sample_rate = wave_samplerate; | |||
ainfo.play.precision = SAMPLE_SIZE; | |||
if (ioctl(sun_audio_fd, AUDIO_SETINFO, &ainfo) == -1) { | |||
@@ -520,7 +522,7 @@ int wave_get_remaining_time(uint32_t sample, uint32_t* time) | |||
(actual_index <= ainfo.play.samples)) { | |||
*time = 0; | |||
} else { | |||
a_time = ((actual_index - ainfo.play.samples) * 1000) / SAMPLE_RATE; | |||
a_time = ((actual_index - ainfo.play.samples) * 1000) / wave_samplerate; | |||
*time = (uint32_t) a_time; | |||
} | |||
SHOW("wave_get_remaining_time for %d: %d\n", sample, *time); |
@@ -288,6 +288,8 @@ void WcmdqStop() | |||
#ifdef USE_PORTAUDIO | |||
Pa_AbortStream(pa_stream); | |||
#endif | |||
if(mbrola_name[0] != 0) | |||
MbrolaReset(); | |||
} | |||
@@ -1563,6 +1565,8 @@ void WavegenSetVoice(voice_t *v) | |||
option_harmonic1 = 6; | |||
} | |||
WavegenSetEcho(); | |||
MarkerEvent(espeakEVENT_SAMPLERATE,0,wvoice->samplerate,out_ptr); | |||
// WVoiceChanged(wvoice); | |||
} | |||
@@ -1797,11 +1801,6 @@ int WavegenFill(int fill_zeros) | |||
static int resume=0; | |||
static int echo_complete=0; | |||
#ifdef TEST_MBROLA | |||
if(mbrola_name[0] != 0) | |||
return(MbrolaFill(fill_zeros)); | |||
#endif | |||
while(out_ptr < out_end) | |||
{ | |||
if(WcmdqUsed() <= 0) | |||
@@ -1904,6 +1903,10 @@ int WavegenFill(int fill_zeros) | |||
case WCMD_EMBEDDED: | |||
SetEmbedded(q[1],q[2]); | |||
break; | |||
case WCMD_MBROLA_DATA: | |||
result = MbrolaFill(length, resume); | |||
break; | |||
} | |||
if(result==0) |