From 1150d1d8dabc4fd39c70fae3c42721be9c4185f1 Mon Sep 17 00:00:00 2001 From: jonsd Date: Sat, 22 Nov 2008 22:25:29 +0000 Subject: [PATCH] [1.39.28] Added experimental Klatt synthesizer. Klatt phonemes use a new format of phoneme data. espeakedit, new dialog fields and layout for Klatt phonemes. Added Klatt versions of English phonemes. Fixed some compilation warnings on Windows. Fixed bug in Lettergroups > L10 Increased amplitude of harmonics below F1 peak, to increase bass. Allow 5 (up from 4) pairs of values in "tone" command in voice files. Default to slightly wider pk_shape1. If words are separated by hyphens, don't add word-gap, and don't pass new-word flag onto phoneme processing. git-svn-id: https://espeak.svn.sourceforge.net/svnroot/espeak/trunk@203 d46cf337-b52f-0410-862d-fd96e6ae7743 --- dictsource/af_list | 5 +- dictsource/dict_phonemes | 128 ++-- dictsource/en_list | 14 +- dictsource/en_rules | 10 +- dictsource/eo_list | 77 ++- dictsource/eo_rules | 48 +- dictsource/fr_rules | 6 +- dictsource/it_list | 3 +- phsource/compile_report | 255 +++++++- phsource/ph_czech | 2 + phsource/ph_english | 9 +- phsource/ph_french | 2 +- phsource/ph_polish | 2 +- phsource/phonemes | 3 + phsource/vdiph/aai_2 | Bin 50786 -> 50789 bytes phsource/vdiph/ai_2 | Bin 2320 -> 2320 bytes phsource/vowel/0 | Bin 959 -> 1265 bytes phsource/vowel/V_2 | Bin 6239 -> 6239 bytes phsource/vowel/a | Bin 1281 -> 1281 bytes phsource/vowel/aa_2 | Bin 8480 -> 8480 bytes phsource/vowel/e# | Bin 5202 -> 5202 bytes phsource/vowel/ee# | Bin 13491 -> 13491 bytes phsource/vowel/ee_2 | Bin 879 -> 1168 bytes phsource/vowel/ii_4 | Bin 1268 -> 1268 bytes phsource/vowel/oo_en | Bin 8093 -> 8093 bytes phsource/vowel/y | Bin 10625 -> 10625 bytes phsource/vwl_en/aU@ | Bin 7687 -> 7687 bytes src/compiledata.cpp | 114 ++-- src/compiledict.cpp | 2 +- src/espeakedit.cpp | 2 +- src/formantdlg.cpp | 149 ++++- src/klatt.cpp | 1282 ++++++++++++++++++++++++++++++++++++++ src/klatt.h | 138 ++++ src/readclause.cpp | 2 +- src/speak_lib.cpp | 4 +- src/spect.cpp | 121 +++- src/spect.h | 35 +- src/spectdisplay.cpp | 94 ++- src/spectseq.cpp | 206 ++++-- src/speech.h | 1 + src/synth_mbrola.cpp | 4 +- src/synthdata.cpp | 36 +- src/synthesize.cpp | 36 +- src/synthesize.h | 73 ++- src/tr_languages.cpp | 4 +- src/translate.cpp | 6 +- src/translate.h | 2 +- src/transldlg.cpp | 5 +- src/voice.h | 3 +- src/voices.cpp | 39 +- src/vowelchart.cpp | 15 +- src/wavegen.cpp | 149 +++-- 52 files changed, 2687 insertions(+), 399 deletions(-) create mode 100644 src/klatt.cpp create mode 100644 src/klatt.h diff --git a/dictsource/af_list b/dictsource/af_list index 84689b17..a0a01bd6 100755 --- a/dictsource/af_list +++ b/dictsource/af_list @@ -1,4 +1,4 @@ -//maintainer: Willem van der Walt +//maintainer: Willem van der Walt // email: wvdwalt@csir.co.za // tel: +27 12 8413996 // Meraka Institute, CSIR @@ -103,6 +103,9 @@ _rng 'A:nb&l _stk str'e@p _tld t'Ild@ +// symbols +⅓ d&:rd@ +⅔ tw,e@d'&:rd@s // numeric _0 'nWl diff --git a/dictsource/dict_phonemes b/dictsource/dict_phonemes index ac187a1a..00660450 100644 --- a/dictsource/dict_phonemes +++ b/dictsource/dict_phonemes @@ -28,6 +28,18 @@ r. s S s. t t. t.h th tS x z +Dictionary ca_dict + +@ a a# aI e E i o +O u U + +* ** : b B d D dZ; +f g j J J^ k l l^ +m n N n^ p Q r R +R2 s S; t T tS ts tS; +v v# w z Z Z; + + Dictionary cs_dict @- a a: aU e e: eI eU @@ -109,10 +121,10 @@ Dictionary eo_dict @- a aI aU e eI eU i o oI u uI -* b d dZ f g h j -k l m n p r R s -S t T tS ts v w x -z Z +* - b d dZ f g h +j k l m n p r R +s S t T tS ts v w +x z Z Dictionary es_dict @@ -200,6 +212,16 @@ N n^ p R R2 s S s2 t tS ts v z Z +Dictionary hy_dict + +@ a aI e eI i i@ o +u W y + +** b d dZ f g h j +k l m n p R3 s S +t tS ts v x z Z + + Dictionary id_dict @ a aI aU e E E2 i @@ -246,6 +268,19 @@ s S t tS v w x z Z +Dictionary kn_dict + +a a: aI aU e E e: i +I i: o o: r- u u: V +y + +: b c ch d d. dZ f +g h j J k kh l l. +m n N n. n^ p ph R +R2 s S s. S; t t. t.h +th tS v w z + + Dictionary ko_dict a e E i ji o u u- @@ -279,6 +314,18 @@ g h j k l m n N p r R s t w z +Dictionary lv_dict + +a a: ai au e e: ei i +i: ie iu o o: u u: ui +uo + +: b c d dZ f g h +j J k l l^ m n n^ +p r R R2 s S t tS +ts v x z Z + + Dictionary mk_dict & @ @- @2 a A a: E @@ -344,6 +391,17 @@ k l m n N p r R s S s; t v w x z +Dictionary om_dict + +@# a a: E e I I# i: +O o: U u: + +** : a# b B c` d d` +dZ f g h j k k` l +m n n^ p p` R s S +t t` tS v w z + + Dictionary pl_dict @- a E E# E~ i O O~ @@ -423,8 +481,8 @@ t t; tS ts v x z Z Dictionary sq_dict -@ a A e E i O u -V y yE +@ a A aI e E i O +u V y yE * ** b c d D dZ f g h j J k l ll m @@ -511,61 +569,3 @@ oi ong ou u ui yu b c d f g h j k l m n N p r s t tS v w z - - -Dictionary lv_dict - -a a: ai au e e: ei i -i: ie iu o o: u u: ui -uo - -: b c d dZ f g h -j J k l l^ m n n^ -p r R R2 s S t tS -ts v x z Z - - -Dictionary hy_dict - -@ a aI e eI i i@ o -u W y - -** b d dZ f g h j -k l m n p R3 s S -t tS ts v x z Z - - -Dictionary kn_dict - -a a: aI aU e E e: i -I i: o o: r- u u: V -y - -: b c ch d d. dZ f -g h j J k kh l l. -m n N n. n^ p ph R -R2 s S s. S; t t. t.h -th tS v w z - - -Dictionary om_dict - -@# a a: E e I I# i: -O o: U u: - -** : a# b B c` d d` -dZ f g h j k k` l -m n n^ p p` R s S -t t` tS v w z - - -Dictionary ca_dict - -@ a a# aI e E i o -O u U - -* ** : b B d D dZ; -f g j J J^ k l l^ -m n N n^ p Q r R -R2 s S; t T tS ts tS; -v v# w z Z Z; diff --git a/dictsource/en_list b/dictsource/en_list index 00a39993..57780f54 100644 --- a/dictsource/en_list +++ b/dictsource/en_list @@ -28,7 +28,7 @@ e i: f Ef g dZi: h eItS -_i aI +i aI j dZeI k keI l El @@ -191,17 +191,22 @@ _₠ jU@roU ® rEdZIst3d ° dIgr'i:z − maIn@s -± plVs@maIn@s +± plVsO@m'aIn@s µ maIkroU ¼ a2kwO@t3 ½ a2hA:f ¾ Tri:kwO@t3 +⅓ w0nT'3:d +⅔ tu:T'3:dz × taImz ÷ dI2v'aIdbaI € jU@roUz ♯ SA@p ♭ flat ¬ n0t_|saIn +√ skw,e@r'u:t +∞ Inf'InI2tI2 +≠ n0t'i:kw@LtU ß S,A@p'Es ə SwA: @@ -1091,6 +1096,7 @@ galore ga2lo@ gases gasI2z gauche goUS gauge geIdZ +gecko gEkoU geese gi:s gemini dZEmI2naI geni dZi:nI @@ -2144,6 +2150,7 @@ wretched rEtSI2d writable raIt@b@L writh raID wrongdoing r0Ndu:I2N +wuss wUs xmas Eksma2s @@ -2445,6 +2452,7 @@ Emma Em@ Evan Ev@n Gary garI Geraint gEraInt +Gibbs gIbz Giles gaIlz Glynn glIn Graeme greI@m @@ -2465,7 +2473,9 @@ Isiah aIz'aI@ Ivan aIv@n Jacob dZeIk@b Jamie dZeImI +Jacques Zak Jesus dZi:z@s +Jonah dZoUn@ José hoUs'eI Jose hoUs'eI Juan hwA:n diff --git a/dictsource/en_rules b/dictsource/en_rules index 5dbabcdf..2ecc9526 100644 --- a/dictsource/en_rules +++ b/dictsource/en_rules @@ -159,12 +159,13 @@ h) a (z eI h) a (zar 'a l) a (z eI - r) a (z eI + r) a (zA eI @) a (zi_ 'A: br) a (zil a bl) a (zon eI r) a (zor eI sw) a (B 0 + sw) a (g a sw) a (m_ a sw) a (nk a sw) a (th eI @@ -263,6 +264,7 @@ _) ache (+ eIk d) ache (_ eIk h) ache (_ eIk + k) ache (_ eIk r) ache (_ eIk rt) ache (_ eIk y) ache (_ eIk @@ -291,7 +293,7 @@ acou (st a2ku: ac (quie ,a _) acre eIk@ - ac (rid ak + _) ac (ri ak ac (ro ak m) acro (@ akr@ _) ac (t ak @@ -974,7 +976,7 @@ as (ive 'eIs as (ymp as &) asy (_ @s%I - w) aste eIst + w) ast (e# eIst .group at pal) ate (_ @t @@ -2288,6 +2290,7 @@ _) eth (A i:T ?!3 eth (ane i:T _) eth (a ET + _) eth (el ET eth (ic ET eth (y i:T @C) eth (_S3e @T @@ -4634,6 +4637,7 @@ _) trie traI _) tri (CA traI _) tri (Cy traI + tribe traIb _) tri (bu trI _) tri (g trI _) tri (ni trI diff --git a/dictsource/eo_list b/dictsource/eo_list index 6b23d273..390d397e 100644 --- a/dictsource/eo_list +++ b/dictsource/eo_list @@ -38,6 +38,7 @@ _grv maldekst@-*akoRno _tld tildo + _?? liteRo _. punkto _: dupunkto @@ -48,41 +49,68 @@ _- dividost@-*eko ~ tildo ° gradoI % p@-*otsento -@ po +@ _tSe_ & kaI += ,,egala, +\\ deklivo +/ oblik'vo +* asteRisko +© k'opiraIto v vo // not Roman numbers x ikso -t.e t'e,e // Abbreviations -a.k ,antaUk@-*'isto -a.k. ,antaUk@-*'isto -akk alinome -anst anstataU -bea $abbrev -ekz ekzemple -i.a 'i'a -k.a kaIal'iaI -k.c kaItset'eRe -n.b n'otu||b'one -nro numeRo -pĝ paZo -p.k p,ostk@-*'isto -p.k. p,ostk@-*'isto -uea $abbrev -uk $abbrev +a.k ,antaUk@-*'isto $dot +akk alinome +anst anstataU $dot +bea $abbrev +bv bon,volu% +ekz ekzemple $dot +i.a 'i'a +k.a kaIal'iaI +k.c kaItset'eRe +Kg k'ilog@-*'amoI +Km k'ilom'et-*oI +kp k,omp'aru $dot +k.s kaI,s'im'ile +n.b n'otu||b'one +nro numeRo +pĝ padZo $dot +p.k p,ostk@-*'isto $dot +ps p,ostask@-*'ibo +p.s p,ostask@-*'ibo +str st@-*'ato +t.e tio,estas +t.n t'iel,nom'ata +uea $abbrev +uk $abbrev +ktp kaIt'iel,pl,u_ +k.t.p kaIt'iel,pl,u_ +Jan i,anu'aRo // months +Feb f,eb@-*u'aRo +Mar m'a@-*to +Apr ap@-*'ilo +Maj m'aIo% +Jun iun'io +Jul iul'io +Aŭg augusto% +Sept sep,temb@-*o +Okt ok,tob@-*o +//Nov nov,emb@-*o (problem: no difference between Nov and nov- [es: nov-jorko] ) +Dec detsemb@-*o + l' la la %la ne $u+ // negative -ĉu $u // interogative particle -ĉi $u // interogative particle +ĉu $u $brk // interogative particle and conjunction +ĉi $u // this ia $u // any // prepositions @@ -123,6 +151,10 @@ tra $u $pause eĉ $brk pli pl,i plej pl,eI +//ĝojo dZoIo +//ĉashundo tSas,hundo +//ligno lig,no +//signo sig,no // pronouns mi $u @@ -197,7 +229,7 @@ kio $u+ $pause kiu $u+ $pause kiuj $u+ $pause kiun $pause -kiunj $pause +kiujn $pause kiam $u+ $pause tio $u+ @@ -209,12 +241,13 @@ ke $u $pause // that (conj) aŭ $u $pause ĉar $u $pause kaj $u $pause -sed $u $pause +sed $u $pause //but nek $u $pause se $u $pause ju $u $brk des $u $pause do $pause // therefore, so, then ekde $pause // since +tamen $pause //however (avversative) diff --git a/dictsource/eo_rules b/dictsource/eo_rules index 3cd8cd90..3b730f1d 100644 --- a/dictsource/eo_rules +++ b/dictsource/eo_rules @@ -1,4 +1,4 @@ -// translation rules +// translation rules for Esperanto // This file is UTF-8 encoded // includes both accented characters and ascii digraph alternatives (cx, gx, ux, etc) @@ -21,7 +21,8 @@ D_-_) an (_ %an //'an' after a number D_) a (_ %a //'a' after a number D_) an (_ %an //'an' after a number - + -) ano (_ an%o // 'ano' = member + .group b _) b(_ bo b b @@ -41,6 +42,8 @@ _) d (-ro_ dokt'o _) d (-rino_ d,okto + -) do (_ d%o + .group e _) e(_ e e e @@ -78,7 +81,12 @@ .group k _) k(_ ko k k - + + _) k (-do_ kamaR'a + _) k (-dino_ k'amaRa + _) k (-ino_ k'amaRad + + .group l _) l(_ lo l l @@ -86,7 +94,7 @@ -) lo (_ l%o - + .group m _) m(_ mo m m @@ -125,7 +133,7 @@ rr RR -) ro (_ R%o // d-ro, n-ro - + .group s _) s(_ so _) sh(_ So @@ -135,6 +143,11 @@ _) s (-ino_ s,injoR _) s (-ro_ sinj'o + + _) s (-ano_ s'am,ide + _) s (-anino_ s'am,ide + + _) s (-ta_ s'ank .group t @@ -142,6 +155,8 @@ t t th (K T // foreign words K) th T // foreign words + + -) ta (_ t%a // s-ta = sankta .group u _) u(_ u @@ -161,6 +176,7 @@ .group x _) x(_ ikso x ks + _) x z // foreign words .group y _) y(_ ipsilono @@ -193,11 +209,8 @@ ŭ w - = ,,egala, - \ malantaIst@-*eko - / st@-*eko ' - + plus + + plus_ _) ++ (_ plusplus . punkto @@ -205,13 +218,16 @@ \.) . - * asteRisko £ pundo - £ (D _pundoI_: - ! ,ekk@-*io, - - _ - - (_a + £ (_D _pundoI_: + _! _k@-*isig'no_ + __) - (_D minus_ + D_) - (_D st@-*ek'eto_ + A_) - (_D _ + C_) - (_D _ + --) - + - minus_ + - (_a $ dolaRo - $ (D _dolaRoI_: - + $ (_D _dolaRoI_: diff --git a/dictsource/fr_rules b/dictsource/fr_rules index ab3b5237..f529b1d8 100755 --- a/dictsource/fr_rules +++ b/dictsource/fr_rules @@ -23,7 +23,7 @@ // 2006-11-18 Gilles Casse // -// Updated: 2008-11-01 Michel Such +// Updated: 2008-11-19 Michel Such // // Letter classes: @@ -441,6 +441,8 @@ _) en (A A~n // enivrer -) est (_ Est // -est dg) et (_ Et // Bridget, gadget + Ack) et (_ Et + m) et (_ Et2 eu Y // eu _) eu (ss y // eu @@ -513,7 +515,6 @@ _) en (A A~n // enivrer _) e (xA E Cr) eamer i:mWr Cl) eaner i:nWr - Ack) et (_ Et vert) e (rX W eïn (_ 'Ein @@ -694,6 +695,7 @@ _) half _^_en anqu) ill il // tranquille dist) ill il // distiller _m) ill il // mille + osc) ill il // osciller v) ill il // village qu) ill ij // cuillière cueillir A) ill j // caillou diff --git a/dictsource/it_list b/dictsource/it_list index 2a583580..221267e5 100644 --- a/dictsource/it_list +++ b/dictsource/it_list @@ -4,7 +4,8 @@ // character names -_cap k'apital +_cap maj'uskola + _?? s'imbolo _?A let:'e:Ra diff --git a/phsource/compile_report b/phsource/compile_report index 0f51bb7b..754a2cfd 100644 --- a/phsource/compile_report +++ b/phsource/compile_report @@ -1,4 +1,4 @@ -59 phoneme tables +60 phoneme tables new total base 101 101 base2 24 120 @@ -52,13 +52,14 @@ rw 15 127 ko 18 149 da 15 131 - sq 23 129 + sq 24 129 ml 13 141 kn 15 141 bn 59 147 ne 23 151 hy 17 115 om 21 121 +en_klatt 77 147 Data file Used by b/b [b] base @@ -345,12 +346,190 @@ j/xj [(@)] base [(i)] base [(o)] base [(u)] base +klatt/b/b [b] en_klatt +klatt/b/b_ [b] en_klatt +klatt/b/xb [b] en_klatt +klatt/d/d [d] en_klatt +klatt/d/d_ [d] en_klatt +klatt/d/dr [d] en_klatt +klatt/d/xd [d] en_klatt +klatt/dzh/dzh [dZ] en_klatt +klatt/dzh/dzh_ [dZ] en_klatt +klatt/dzh/xdzh [dZ] en_klatt +klatt/g/g [g] en_klatt + [g-] en_klatt +klatt/g/g_ [g] en_klatt + [g-] en_klatt +klatt/g/xg [g] en_klatt + [g-] en_klatt +klatt/j2/j2 [(@)] en_klatt + [(a)] en_klatt + [(e)] en_klatt + [(i)] en_klatt + [(o)] en_klatt + [(u)] en_klatt +klatt/j2/xj2 [(i)] en_klatt +klatt/j/j [(@)] en_klatt + [(a)] en_klatt + [(e)] en_klatt + [(i)] en_klatt + [(o)] en_klatt + [(u)] en_klatt +klatt/j/_j [j] en_klatt +klatt/j/j_ [j/] en_klatt +klatt/j/xj [(@)] en_klatt + [(a)] en_klatt + [(e)] en_klatt + [(o)] en_klatt + [(u)] en_klatt +klatt/l/l [(@)] en_klatt + [(a)] en_klatt + [(e)] en_klatt + [(i)] en_klatt + [(o)] en_klatt + [(u)] en_klatt +klatt/l/_l [l] en_klatt +klatt/l/L2_eL [(@)] en_klatt + [(a)] en_klatt + [(e)] en_klatt +klatt/l/L2_uL [(i)] en_klatt + [(o)] en_klatt + [(u)] en_klatt +klatt/l/tl [l] en_klatt +klatt/l/xl [(@)] en_klatt + [(a)] en_klatt + [(e)] en_klatt + [(i)] en_klatt + [(o)] en_klatt + [(u)] en_klatt +klatt/m/m [(@)] en_klatt + [(a)] en_klatt + [(e)] en_klatt + [(i)] en_klatt + [(o)] en_klatt + [(u)] en_klatt +klatt/m/_m [m] en_klatt +klatt/m/m_ [m] en_klatt +klatt/m/mj [m] en_klatt +klatt/n/n [(@)] en_klatt + [(a)] en_klatt + [(e)] en_klatt + [(i)] en_klatt + [(o)] en_klatt + [(u)] en_klatt +klatt/n/_n [n] en_klatt +klatt/n/n_ [n] en_klatt +klatt/n/nj [n] en_klatt +klatt/nn/nn [(a)] en_klatt + [(e)] en_klatt + [(i)] en_klatt + [(o)] en_klatt + [(u)] en_klatt +klatt/nn/_nn [N] en_klatt +klatt/nn/nn_ [N] en_klatt +klatt/nn/nnj [N] en_klatt +klatt/r/r [(@)] en_klatt + [(a)] en_klatt + [(e)] en_klatt + [(i)] en_klatt + [(o)] en_klatt + [(u)] en_klatt +klatt/r/_r [r] en_klatt + [r-] en_klatt +klatt/r/r2 [(@)] en_klatt + [(a)] en_klatt + [(e)] en_klatt + [(i)] en_klatt + [(o)] en_klatt + [(u)] en_klatt +klatt/r/tr [r] en_klatt +klatt/r/xr [(@)] en_klatt + [(a)] en_klatt + [(e)] en_klatt + [(i)] en_klatt + [(o)] en_klatt + [(u)] en_klatt +klatt/vdiph2/ii@ [i@] en_klatt + [i@3] en_klatt +klatt/vdiph2/uu@ [U@] en_klatt +klatt/vdiph2/uw_2 [u:] en_klatt +klatt/vdiph/aai [aI] en_klatt +klatt/vdiph/au [aU] en_klatt +klatt/vdiph/eei [eI] en_klatt +klatt/vdiph/eu [eU] en_klatt +klatt/vdiph/ooi [OI] en_klatt +klatt/vdiph/@u_en [oU] en_klatt +klatt/vnasal/aa_n2 [A~] en_klatt +klatt/vnasal/ee_n [E~] en_klatt +klatt/vnasal/oo_n [O~] en_klatt +klatt/voc/dh [D] en_klatt +klatt/voc/dh_ [D] en_klatt +klatt/voc/v [v] en_klatt +klatt/voc/v_ [v] en_klatt +klatt/voc/vj [v] en_klatt +klatt/voc/z [z] en_klatt +klatt/voc/z_ [z] en_klatt +klatt/voc/zh [Z] en_klatt +klatt/voc/zh_ [Z] en_klatt +klatt/vowel/@ [3] en_klatt + [@] en_klatt + [@2] en_klatt + [@5] en_klatt +klatt/vowel/@- [@-] en_klatt +klatt/vowel/0_2 [0] en_klatt +klatt/vowel/3_en [3:] en_klatt +klatt/vowel/a#_3 [a2] en_klatt +klatt/vowel/a_4 [a] en_klatt + [aa] en_klatt +klatt/vowel/aa_2 [A:] en_klatt + [A@] en_klatt +klatt/vowel/e [e:] en_klatt +klatt/vowel/ee_1 [e@] en_klatt +klatt/vowel/ee_2 [E] en_klatt +klatt/vowel/i_en [i:] en_klatt +klatt/vowel/ii_4 [I] en_klatt + [I2] en_klatt +klatt/vowel/ii_en [i] en_klatt +klatt/vowel/o [o:] en_klatt +klatt/vowel/oe [W] en_klatt +klatt/vowel/oo_en [O] en_klatt + [O:] en_klatt + [O@] en_klatt + [o@] en_klatt +klatt/vowelr/V3_r [VR] en_klatt +klatt/vowelr/V_r [IR] en_klatt +klatt/vowel/uu [U] en_klatt +klatt/vowel/V_2 [V] en_klatt +klatt/vowel/y [y:] en_klatt +klatt/vowel/y# [Y:] en_klatt +klatt/vwl_en/aI@ [aI@] en_klatt +klatt/vwl_en/aU@ [aU@] en_klatt +klatt/vwl_en/@L [@L] en_klatt +klatt/w/w [(@)] en_klatt + [(a)] en_klatt + [(e)] en_klatt + [(o)] en_klatt +klatt/w/_w [w] en_klatt +klatt/w/wi [(i)] en_klatt +klatt/w/wu [(u)] en_klatt +klatt/w/xw [(@)] en_klatt + [(a)] en_klatt + [(e)] en_klatt + [(i)] en_klatt + [(o)] en_klatt + [(u)] en_klatt l^/j2@ [(@)] base + [(@)] en_klatt l^/j2a [(a)] base + [(a)] en_klatt l^/j2e [(e)] base + [(e)] en_klatt l^/j2i [(i)] base + [(i)] en_klatt l^/j2o [(o)] base + [(o)] en_klatt l^/j2u [(u)] base + [(u)] en_klatt l^/_l^ [l^] base l^/l^ [l^] base l/l [l] base @@ -390,16 +569,24 @@ l/l_@ [(@)] base [W] fr [Y] fr [W2] fr + [(@)] en_klatt l/l@ [(@)] base [W] fr [Y] fr [W2] fr + [(@)] en_klatt l/L1_aL [(a)] base + [(a)] en_klatt l/L1_eL [(e)] base + [(e)] en_klatt l/L1_iL [(i)] base + [(i)] en_klatt l/L1_@L [(@)] base + [(@)] en_klatt l/L1_oL [(o)] base + [(o)] en_klatt l/L1_uL [(u)] base + [(u)] en_klatt l/L2_aL [(a)] base l/L2_eL [(e)] base l/L2_iL [(i)] base @@ -415,18 +602,22 @@ l/l_4 [ll] sq l/la [(a)] base [a] fr [a2] fr + [(a)] en_klatt l/l_a [(a)] base [a] fr [a2] fr [wA] fr [A~] fr + [(a)] en_klatt l/le [(e)] base [E] fr [e] fr [E2] fr + [(e)] en_klatt l/l_e [(e)] base [E] fr [E2] fr + [(e)] en_klatt l/L_eL_af [&] af [&:] af l/l_front [l] sq @@ -434,11 +625,13 @@ l/li [(i)] base [i] fr [i:] fr [l] zh + [(i)] en_klatt l/l_i [(i)] base [i] fr [i:] fr [w^i] fr [i] sq + [(i)] en_klatt l/l_long [l] base [l] fr [l] la @@ -450,10 +643,12 @@ l/lo [(o)] base [O2] fr [o2] fr [wA] fr + [(o)] en_klatt l/l_o [(o)] base [O] fr [O2] fr [o2] fr + [(o)] en_klatt l^/l_rfx [l.] hi [l.] sq [l.] bn @@ -462,9 +657,11 @@ l/lu [(u)] base [y] fr [u:] fr [w^i] fr + [(u)] en_klatt l/l_u [(u)] base [u] fr [u:] fr + [(u)] en_klatt l/l_y [y] fr l/tl [l] base [l] en @@ -506,6 +703,7 @@ m/mu [(u)] base n^/_n^ [n^] base n^/n^_ [n^] base n^/n^@ [(@)] base + [(@)] en_klatt n^/n^#_ [n^#] is n/_n [n] base [n;] ro @@ -518,10 +716,13 @@ n/n@ [(@)] base n/n#_ [n#] is [n] da n^/n^a [(a)] base + [(a)] en_klatt n/na [(a)] base n^/n^e [(e)] base + [(e)] en_klatt n/ne [(e)] base n^/n^i [(i)] base + [(i)] en_klatt n/ni [(i)] base [n] zh nn/inn [(i)] base @@ -537,6 +738,7 @@ nn/_nn [N] base nn/nn_ [N] base [N] en nn/nn@ [(@)] base + [(@)] en_klatt nn/nn#_ [N#] is nn/nn2_ [N] zh [N-] zh @@ -547,10 +749,12 @@ nn/nnj [N] base nn/nno [(o)] base nn/nnu [(u)] base n^/n^o [(o)] base + [(o)] en_klatt n/no [(o)] base n/_nr [n.] base n/nr_ [n.] base n^/n^u [(u)] base + [(u)] en_klatt n/nu [(u)] base r2/_r2 [r-] base r2/r2@ [(@)] base @@ -562,21 +766,28 @@ r2/r2u [(u)] base r3/r_ [r/] base [r/] af [r/] ru + [r/] en_klatt r3/r_@ [(@)] base [@2] fr + [(@)] en_klatt r3/r#_ [r#] is r3/r_2 [r/2] fr r3/r_a [(a)] base + [(a)] en_klatt r3/r_e [(e)] base + [(e)] en_klatt r3/r_i [(i)] base [i] fr [w^i] fr + [(i)] en_klatt r3/r_n [r/] base [r/2] fr [r/] ru + [r/] en_klatt r3/r_o [(o)] base [O] fr [O2] fr + [(o)] en_klatt r3/r_ru [R4] ru r3/r_ru2 [R4] ru r3/r_sr [r.] bn @@ -603,6 +814,7 @@ r3/r_trill.wav [R2] base [r*] sr [x] pt r3/r_u [(u)] base + [(u)] en_klatt r3/r_ulv [r"] hy r3/r_uvl [r"] hy r3/rx [*] base @@ -618,6 +830,7 @@ r3/rx [*] base [*;] ro [r#] is [Q2] hy + [r/] en_klatt r3/rz_cs [R^] sk [R^/] sk r3/@tap [**] base @@ -642,6 +855,7 @@ r/r_ [r] base [r] ro [r] sw [r.] bn + [r] en_klatt r/r@ [(@)] base r/ra [(a)] base r/re [(e)] base @@ -656,6 +870,7 @@ r/rr [r/] base [r/] ru [r] ro [r] sw + [r/] en_klatt r/ru [(u)] base r/tr [r] base [r] en_sc @@ -670,6 +885,7 @@ r/trr [r/] base [r] ro [r] sv [r] sw + [r/] en_klatt r/xr [(@)] base [(a)] base [(e)] base @@ -711,6 +927,7 @@ ufric/s [s] base [s] es [s#] pt [s`] ko + [s] en_klatt ufric/s_ [s] base [z] base [s2] fi @@ -724,6 +941,8 @@ ufric/s_ [s] base [s#] pt [z;] ro [s2] is + [s] en_klatt + [z] en_klatt ufric/s! [s] base [s2] fi [s] fr @@ -732,6 +951,7 @@ ufric/s! [s] base [s] es [s#] pt [s2] is + [s] en_klatt ufric/s_continue [s2] fi [s2] hu [s2] lv @@ -739,9 +959,11 @@ ufric/s_continue [s2] fi ufric/sh [S] base [S] fr [s#] pt_pt + [S] en_klatt ufric/sh_ [S] base [S] fr [s#] pt_pt + [S] en_klatt ufric/sh3 [S] hr [Z] hr ufric/sh_pzd [S;] base @@ -1108,6 +1330,7 @@ vdiph/8u [oU] en_us vdiph/aae [aI] en_us vdiph/aai [ai] lv [aai] zhy + [aI] sq [aI] ne vdiph/aai_2 [AI] af [AY] cy @@ -1138,7 +1361,8 @@ vdiph/ai [aI] base2 [aI] id [aI] kn [aI] hy -vdiph/ai_2 [aI] cy +vdiph/ai_2 [aI] en + [aI] cy [aY] cy vdiph/ai_3 [aI] no vdiph/ai_4 [aI] af @@ -1148,7 +1372,6 @@ vdiph/ai_6 [aI] en_rp vdiph/ai_7 [aI] en_sc [aI2] en_sc [aI] is -vdiph/ai_en2 [aI] en vdiph/aoo [aU] en_us vdiph/au [aU] en [aU] af @@ -1374,6 +1597,7 @@ voc/vj [v] base [v] fr vocw/dh [D] base [D] es + [D] en_klatt vocw/Q [Q] base [Q^] base vocw/Q_ [Q] base @@ -1386,8 +1610,10 @@ vocw/v [B] base [v] ta [v#] es [v;] ro + [v] en_klatt vocw/zh [Z] base [Z;] ro + [Z] en_klatt vocw/zh_rfx [z.] base voc/z [z] base [z] fr @@ -1474,15 +1700,19 @@ vowel/8_2 [U] en_us vowel/8_3 [eo] zhy vowel/8_5 [8] ku vowel/8_7 [@] lv -vowel/a [a] en_n +vowel/a [a] en + [aa] en + [a] en_n [aa] en_n [a] en_wm [aa] en_wm [a] cy [a] de + [A] fr [a] ta [a:] hu [a:] nl + [a] pl [a] sk [a:] sk [A] hr @@ -1592,10 +1822,6 @@ vowel/aa_8 [0] en_us vowel/aa_9 [a:] hi [a:] bn [a] ne -vowel/a_en [a] en - [aa] en - [A] fr - [a] pl vowel/@_bck [@] hi [@/] hi [@] zh @@ -1654,7 +1880,6 @@ vowel/ee [E] en_n vowel/e_e [E] en_sc [e] is vowel/ee# [E#] pl - [E] sq vowel/ee_1 [E] base2 [e@] en [E] pl @@ -1670,6 +1895,7 @@ vowel/ee_2 [E] en [E#] ku [&] da vowel/ee#_2 [E-] sv + [E] sq vowel/ee_3 [&] af [&:] af [E] pt @@ -2296,8 +2522,10 @@ x/b [b] base [b;] ro [b] is [b] bn + [b] en_klatt x/b_ [b] base [b] fr + [b] en_klatt x/d [d] base [t#] en_us [d] fr @@ -2308,6 +2536,7 @@ x/d [d] base [d] id [d.] bn [d`] om + [d] en_klatt x/d_ [d] base [d[] base [d] base2 @@ -2326,6 +2555,7 @@ x/d_ [d] base [d] id [d] bn [d.] bn + [d] en_klatt x/d_dnt [d[] base [d] base2 [d] fi @@ -2342,6 +2572,7 @@ x/dzh [J] base [dZ] base [J2] hi [J2] bn + [dZ] en_klatt x/dzh_ [dZ] base [dZ;] base [dz;] base @@ -2349,6 +2580,7 @@ x/dzh_ [dZ] base [dZ;] mk [dZ;] ru [J] bn + [dZ] en_klatt x/dz_pzd [dZ;] base [dz;] base [J] hi @@ -2362,6 +2594,7 @@ x/g_ [g] base [g] fr [g] es [g] is + [g] en_klatt x/g2 [g] base [g] cy [g] fr @@ -2369,6 +2602,8 @@ x/g2 [g] base [g] es [g] is [g] bn + [g] en_klatt x/g2_ [g-] base [g] hi [g] bn + [g-] en_klatt diff --git a/phsource/ph_czech b/phsource/ph_czech index 50242af9..620a9a28 100644 --- a/phsource/ph_czech +++ b/phsource/ph_czech @@ -1,3 +1,5 @@ +// Czech phonemes inherit from Slovak + phoneme e vowel starttype (e) endtype (e) length 120 diff --git a/phsource/ph_english b/phsource/ph_english index 99bcef66..d5701a73 100644 --- a/phsource/ph_english +++ b/phsource/ph_english @@ -103,7 +103,8 @@ endphoneme phoneme a vowel starttype (a) endtype (a) length 150 - formants vowel/a_en +// formants vowel/a_en + formants vowel/a reduceto a2 0 endphoneme @@ -120,7 +121,8 @@ endphoneme phoneme aa // 'bath' etc. vowel starttype (a) endtype (a) length 150 - formants vowel/a_en +// formants vowel/a_en + formants vowel/a linkout r- endphoneme @@ -272,7 +274,8 @@ endphoneme phoneme aI vowel starttype (a) endtype (i) length 230 - formants vdiph/ai_en2 +// formants vdiph/ai_en2 + formants vdiph/ai_2 endphoneme diff --git a/phsource/ph_french b/phsource/ph_french index 4d67d23d..7166b15d 100644 --- a/phsource/ph_french +++ b/phsource/ph_french @@ -289,7 +289,7 @@ endphoneme phoneme A // same as [a] vowel starttype (a) endtype (a) length 166 - formants vowel/a_en + formants vowel/a endphoneme diff --git a/phsource/ph_polish b/phsource/ph_polish index 91a14535..075356e7 100644 --- a/phsource/ph_polish +++ b/phsource/ph_polish @@ -7,7 +7,7 @@ phoneme a vowel starttype (a) endtype (a) length 190 - formants vowel/a_en + formants vowel/a reduceto a# 0 endphoneme diff --git a/phsource/phonemes b/phsource/phonemes index 9165e3e6..1daf588e 100644 --- a/phsource/phonemes +++ b/phsource/phonemes @@ -1347,3 +1347,6 @@ include ph_armenian_west phonemetable om base include ph_oromo +phonemetable en_klatt en +include ph_english_klatt +] \ No newline at end of file diff --git a/phsource/vdiph/aai_2 b/phsource/vdiph/aai_2 index 1367237342afb19034fcdbe98ac10169d0c8022e..94f61d3570eb8dca0e7fdac3ce7a2df6e1504014 100644 GIT binary patch delta 42 ycmaFV!~C>|Sui-j)j1^CHIS8ofgv$5Gu~(;-w^}Gu+5hZlzAAVH-ERu?gRiSHV#Dq delta 39 vcmaFb!~Cd+nJ+lN)j1^CHIRvcfx*#pqu>z(#;DEL43v2o<2V1Z$?gOI{{Oq1U*$xPgIj2B(rkf{MIH~9+V4c-bA%{!T(lAjnICf{dvhpBX7xx;*e!C|v9 zYapYi2gf`nHL%Su7#Vmn7=3pYM?YT* M8;pHtvLeTO09}SpP5=M^ delta 337 zcmbOrG(l*B9`jlM`x6a?gHjk67_RzpPKLaaF+(G&S!{j$iG7~o);|*YbAwGp^3D}%BlUo@LnRYOO zNU0CigA7NnFtjrq7=*hr7k4X*ej4zA~yb~Bh zz{a++PvE}56ag0R;GDn>bH)=M2DtO0`4~7M;-(x9(la*iWs_#~yutu7@Dt<_zzj6u-N6Q7n{h<*oq+n+jN`y$MUM9X{}fVQ diff --git a/phsource/vowel/0 b/phsource/vowel/0 index 5a8eb4691a616859bac39a965993c32cc50508de..d99d36391dcf7061e5f8f4c1d076c9d5a455ff8e 100644 GIT binary patch delta 135 zcmdnb{*hB4IKb68B-k~Ok%581fQ2DpqJT8>2?mCZdMb>HEFTz{fWiz64y^YbzzhZ- vphy6a`R)G;1_sW_#f<-r!+(IK5NaG)7C;oE=wm?D_mBB?&7RFAOx}zDaW5UN delta 79 zcmey!xu0DiIKb68B-k~Ok%581fSDm>qJT8>@%QsK>Zvd)vTgwif`9|-eFrdu!H0o~ cAq>d;_WuRL0glN_nf@{N2OrzKjM~!=%s1=D?B0 MEXA_^a}$6 zdkgavrj0>w*w`326_^#6H@mQZV&!09Y~TX(?0Bo#*%}}+`$VL;88bKEly_$Y0FJ&H Ax&QzG delta 136 zcmZ4Bw7@ASIKb68B-k~Og@J(~F)`jqiXjQeLIw`3A09yX4lF0leZfqGm>UBNLkd{z z3j+hY4@(U5#-KNBYy}+inC3BUc47a-%3;9xfeXyD(6V}Qu)6OrO(Oxb)>-klKu D6g(YI diff --git a/phsource/vowel/e# b/phsource/vowel/e# index 94d76bf3391013ef154e28bd253482fbf8f94376..9bec6cff32a69071fd02ccd5588b1c0aa854de9a 100644 GIT binary patch delta 183 zcmcblaYVTOOzuom8GbM_h>9~YGi9>fWLUyBM>vAXifMBR z%QI%RM4(y*2AEn$rfG1sacr9rY8yC!YGY8;+B40AtBqirics6b161pXqSlUS30$ok MTRlSU41rzD02+=dNdN!< delta 183 zcmcblaYVTOOzuom8GbM_h|4f}F=n#eWLUyBNBAG(1IEoI zEYFzLQh;h17+`80nWn+j#<6WisBPc?s*OWYYtJ+ft~P>gDne}!4^XWQids9SC2+NF NZ1o7WGX!=q0|5RIFQNbd diff --git a/phsource/vowel/ee# b/phsource/vowel/ee# index 512151a70235e72896ba2039d3696e7d2dbd227c..c4b15ccdf20b5d0c1e4c5fb32cf669c5a7a81890 100644 GIT binary patch delta 222 zcmdm-xjA!!I4c7PY?R?(Vfp_5_k+nAEVeu{O#c`ku})x+U}F&9T*$JYndQe{jt7%X zIMkKm!OAZ%Fz_s9Qea-f9Ma}>K delta 222 zcmdm-xjA!!III1y*4YgkWjI(^el4B#XR-#1Ezdv32aJzcCoo8`l}KzZWZBQm^6SXm z9g|Hs)Rj^gK;Qxc1J7b61?DA8J`59>IK)62PP5iRG}Ll{G(4`@Fxi2}mWPGu0pl*# zdp5Cy5;xWs0Eu-BtWdy{!2C& yfZX?cC!5FS8U;=k=3|QwZ0=A2GOoypY@VV4WIUX}v3Y?GknvvFWAhpVb`}8mgGxI9 diff --git a/phsource/vowel/ee_2 b/phsource/vowel/ee_2 index 23483a0234aaaed28a228f2d94d762bbc505eb08..7dd29f23b55526f2e132b14095335042c595cf98 100644 GIT binary patch delta 117 zcmaFQHi1((IKb68B-k~Og@J(~H8tLdg&}F8fVB7tAQuE2SpP2oGZ>tJRPshAHbxc} qpyXs9Mrp=|$r+4)6&+ZhD$o>%12t4`j{vKB&HTEeYjYTrBqIQbC>}hSq%XI delta 44 ycmeyu`Gr$BIKb68B-k~Og@J(~Gc(?Vg&}35a5f`X3XuQq{{aRD?#&&HIm`eVe+)aqX<76XADq)fnf!M!)6_}LP-DtObS*2 delta 44 ycmbPhKi6I)IKb68B-k~Om4SgFKR-S-Pm&>iqX<76XFO1Vfnf#1g3UT?g^~aR-U_<_ diff --git a/phsource/vowel/y b/phsource/vowel/y index 303965acd15ff6130b74e999f49fde87d9cb71dd..aae16f511639e3c95785e4c885f6c4bc38f5d9ba 100644 GIT binary patch delta 14 VcmZn+ZVcWaD$JO$Sxh)v3;-l(1U~=( delta 14 VcmZn+ZVcWaD$JO&Sxh)v3;-m61VaD- diff --git a/phsource/vwl_en/aU@ b/phsource/vwl_en/aU@ index 12991e3131ade9dd5f535ffaa66a7595f6f132ab..c3ec6d6d6069aba2ff4a1be11ac20cd9f2ba4479 100644 GIT binary patch delta 602 zcmZp-X}6i6Tfcq(+0^h6l!WmKJ7#u`A@>Gk$}qQGU=w zfLa(?AXYUnGcc@xTD5?cfuRp-)dDUC1{bJRH+UHs;70Nz*lE%Tc7+@R0}m6_Im#gR zWI^T&^$bAw!F)9XXcf#?+kjRfe8s?k@DqG%=>*Cb00gh`$( zrvk%3j$x2sA2|-Oh%bLX wAM6|l)}sf&42Dn!7KW6~r+B&fB^Gd9fGW3RwcvZexC9&_e>gV3m62iu01^{l-2eap diff --git a/src/compiledata.cpp b/src/compiledata.cpp index e698ac3a..61ce3b10 100755 --- a/src/compiledata.cpp +++ b/src/compiledata.cpp @@ -597,17 +597,21 @@ int Compile::LoadSpect(const char *path, int control) int peak; int displ; int frame; + int n_frames; int ix; - int x; + int x, x2; int rms; float total; float pkheight; int marker1_set=0; int frame_vowelbreak=0; + int klatt_flag=0; SpectFrame *fr; + frame_t *fr_out; wxString path_sep = _T("/"); SPECT_SEQ seq_out; + SPECT_SEQK seqk_out; // create SpectSeq and import data spectseq = new SpectSeq; @@ -627,11 +631,14 @@ int Compile::LoadSpect(const char *path, int control) } spectseq->Load(stream); + if(spectseq->synthesizer_type == 1) + klatt_flag = FRFLAG_KLATT; + displ = ftell(f_phdata); seq_out.n_frames=0; seq_out.flags=0; - seq_out.length=0; + seq_out.length_total=0; total = 0; for(frame=0; frame < spectseq->numframes; frame++) @@ -669,7 +676,7 @@ for(ix=0; ix<8; ix++) total += spectseq->frames[frame-1]->length; } } - seq_out.length = int(total); + seq_out.length_total = int(total); if((control & 1) && (marker1_set == 0)) { @@ -678,68 +685,103 @@ for(ix=0; ix<8; ix++) spectseq->frames[frame_vowelbreak]->markers |= FRFLAG_VOWEL_CENTRE; } - ix = 0; + n_frames = 0; for(frame=0; frame < spectseq->numframes; frame++) { fr = spectseq->frames[frame]; if(fr->keyframe) { + if(klatt_flag) + fr_out = &seqk_out.frame[n_frames]; + else + fr_out = (frame_t *)&seq_out.frame[n_frames]; + x = int(fr->length + 0.5); // round to nearest mS if(x > 255) x = 255; - seq_out.frame[ix].length = x; + fr_out->length = x; + + fr_out->frflags = fr->markers | klatt_flag; - seq_out.frame[ix].frflags = fr->markers; rms = int(fr->GetRms(spectseq->amplitude)); if(rms > 255) rms = 255; - seq_out.frame[ix].rms = rms; + fr_out->rms = rms; + + if(n_frames == (seq_out.n_frames-1)) + fr_out->length = 0; // give last frame zero length - if(ix == (seq_out.n_frames-1)) - seq_out.frame[ix].length = 0; // give last frame zero length - // write: peak data count_frames++; for(peak=0; peakpeaks[peak].pkfreq; - pkheight = spectseq->amplitude * fr->amp_adjust * fr->peaks[peak].pkheight; - pkheight = pkheight/640000; - if(pkheight > 255) pkheight = 255; - seq_out.frame[ix].fheight[peak] = int(pkheight); + fr_out->ffreq[peak] = fr->peaks[peak].pkfreq; + + if(klatt_flag) + { + pkheight = fr->peaks[peak].pkheight / 128; + } + else + { + pkheight = spectseq->amplitude * fr->amp_adjust * fr->peaks[peak].pkheight; + pkheight = pkheight/640000; + if(pkheight > 255) pkheight = 255; + } + fr_out->fheight[peak] = int(pkheight); if(peak < 6) { - x = fr->peaks[peak].pkwidth/4; + x = fr->peaks[peak].pkwidth/2; + x2 = fr->peaks[peak].pkright; + if(klatt_flag == 0) + { + x /= 2; + x2 /= 4; + } if(x > 255) x = 255; - seq_out.frame[ix].fwidth[peak] = x; + fr_out->fwidth[peak] = x; - x = fr->peaks[peak].pkright/4; - if(x > 255) x = 255; - seq_out.frame[ix].fright[peak] = x; + if(x2 > 255) x2 = 255; + fr_out->fright[peak] = x2; } } -#ifdef LOG_DETAIL -fprintf(f_errors,"Frame %d %3dmS rms=%3d flags=%2d pk=%4d %4d %4d",ix,seq_out.frame[ix].length, - seq_out.frame[ix].rms,seq_out.frame[ix].flags, - seq_out.frame[ix].peaks[1].pkfreq,seq_out.frame[ix].peaks[2].pkfreq,seq_out.frame[ix].peaks[3].pkfreq); + if(klatt_flag) + { + if(fr->klatt_param[KLATT_Kopen] == 0) + { + Error("Klatt_Kopen has value 0"); + } - if(fr->markers != 0) - { - fprintf(f_errors," [%x]",fr->markers); - } - fputc('\n',f_errors); -#endif - - ix++; + // additional fields + for(ix=0; ixklattp[ix] = fr->klatt_param[ix]; + } + fr_out->fwidth6 = fr->peaks[6].pkwidth/2; + fr_out->fright6 = fr->peaks[6].pkright; + } + + n_frames++; } } - ix = (char *)(&seq_out.frame[seq_out.n_frames]) - (char *)(&seq_out); - ix = (ix+3) & 0xfffc; // round up to multiple of 4 bytes + if(klatt_flag) + { + seqk_out.n_frames = seq_out.n_frames; + seqk_out.flags = seq_out.flags; + seqk_out.length_total = seq_out.length_total; + + ix = (char *)(&seqk_out.frame[seqk_out.n_frames]) - (char *)(&seqk_out); + ix = (ix+3) & 0xfffc; // round up to multiple of 4 bytes + fwrite(&seqk_out,ix,1,f_phdata); + } + else + { + ix = (char *)(&seq_out.frame[seq_out.n_frames]) - (char *)(&seq_out); + ix = (ix+3) & 0xfffc; // round up to multiple of 4 bytes + fwrite(&seq_out,ix,1,f_phdata); + } - fwrite(&seq_out,ix,1,f_phdata); - delete spectseq; return(displ); } // end of Compile::LoadSpect diff --git a/src/compiledict.cpp b/src/compiledict.cpp index 12587373..bae8cd97 100755 --- a/src/compiledict.cpp +++ b/src/compiledict.cpp @@ -1268,7 +1268,7 @@ static int compile_lettergroup(char *input, FILE *f_out) group = atoi(&p[0]); if(group >= N_LETTER_GROUPS) { - fprintf(f_log,"%5d: lettergroup out of range (01-%.2d)\n",linenum,N_LETTER_GROUPS); + fprintf(f_log,"%5d: lettergroup out of range (01-%.2d)\n",linenum,N_LETTER_GROUPS-1); error_count++; return(1); } diff --git a/src/espeakedit.cpp b/src/espeakedit.cpp index e024aa5a..336d6917 100755 --- a/src/espeakedit.cpp +++ b/src/espeakedit.cpp @@ -232,7 +232,7 @@ wxSashLayoutWindow *win; win = new wxSashLayoutWindow(this, ID_WINDOW_LEFT2, wxDefaultPosition, wxSize(200, 30), wxNO_BORDER | wxSW_3D | wxCLIP_CHILDREN); - win->SetDefaultSize(wxSize(208, 1000)); + win->SetDefaultSize(wxSize(212, 1000)); win->SetOrientation(wxLAYOUT_VERTICAL); win->SetAlignment(wxLAYOUT_LEFT); // win->SetBackgroundColour(wxColour(0, 255, 255)); diff --git a/src/formantdlg.cpp b/src/formantdlg.cpp index c0afea4f..3689da3e 100755 --- a/src/formantdlg.cpp +++ b/src/formantdlg.cpp @@ -43,10 +43,10 @@ ByteGraph *pitchgraph=NULL; BEGIN_EVENT_TABLE(FormantDlg, wxPanel) EVT_BUTTON(T_ZOOMOUT,FormantDlg::OnCommand) EVT_BUTTON(T_ZOOMIN,FormantDlg::OnCommand) - EVT_SPINCTRL(T_AMPLITUDE,FormantDlg::OnSpin) - EVT_SPINCTRL(T_TIMESEQ,FormantDlg::OnSpin) - EVT_SPINCTRL(T_AMPFRAME,FormantDlg::OnSpin) - EVT_SPINCTRL(T_TIMEFRAME,FormantDlg::OnSpin) + EVT_SPINCTRL(-1,FormantDlg::OnSpin) +// EVT_SPINCTRL(T_TIMESEQ,FormantDlg::OnSpin) +// EVT_SPINCTRL(T_AMPFRAME,FormantDlg::OnSpin) +// EVT_SPINCTRL(T_TIMEFRAME,FormantDlg::OnSpin) END_EVENT_TABLE() @@ -79,21 +79,19 @@ void FormantDlg::OnSpin(wxSpinEvent& event) switch(id = event.GetId()) { - case T_AMPLITUDE: - case T_TIMESEQ: - case T_TIMEFRAME: - currentcanvas->RefreshDialogValues(0); - break; - case T_AMPFRAME: currentcanvas->RefreshDialogValues(1); break; + + default: + currentcanvas->RefreshDialogValues(0); + break; } currentcanvas->SetFocus(); } FormantDlg::FormantDlg(wxWindow *parent) : wxPanel(parent,-1,wxDefaultPosition,wxSize(400,1000)) -{//========================================================================== +{//============================================================================================= int ix; int y; int xplace; @@ -104,6 +102,7 @@ FormantDlg::FormantDlg(wxWindow *parent) : wxPanel(parent,-1,wxDefaultPosition,w xplace = 28; id = 201; new wxStaticText(this,-1,_T("Formants"),wxPoint(4,5)); + t_lab[4] = new wxStaticText(this,-1,_T(" BW BWp Ap"),wxPoint(78,5),wxSize(300,20)); for(ix=0; ix5) t_pkwidth[ix]->Hide(); } - t_ampframe = new wxSpinCtrl(this,T_AMPFRAME,_T(""), - wxPoint(6,244),wxSize(52,24),wxTE_CENTRE,0,500); - t_lab[3] = new wxStaticText(this,-1,_T("% amp - Frame"),wxPoint(61,248)); - t_timeframe = new wxSpinCtrl(this,T_TIMEFRAME,_T(""), - wxPoint(6,272),wxSize(52,24),wxTE_CENTRE,0,500); - t_orig_frame = new wxStaticText(this,-1,_T("mS"),wxPoint(61,276)); + y=240; + t_timeframe = new wxSpinCtrl(this,T_TIMEFRAME,_T(""), wxPoint(6,y+0), wxSize(52,24), wxTE_CENTRE,0,500); + t_orig_frame = new wxStaticText(this,-1,_T("mS"),wxPoint(57,y+8)); + t_ampframe = new wxSpinCtrl(this,T_AMPFRAME,_T(""), wxPoint(100,y+0), wxSize(52,24), wxTE_CENTRE,0,500); + t_lab[3] = new wxStaticText(this,-1,_T("% amp - Frame"),wxPoint(151,y+8)); - t_zoomout = new wxButton(this,T_ZOOMOUT,_T("Zoom-"),wxPoint(16,310)); - t_zoomin = new wxButton(this,T_ZOOMIN,_T("Zoom+"),wxPoint(106,310)); + s_klatt[KLATT_AV] = new wxSpinCtrl(this,T_AV,_T(""), wxPoint(6,y+32), wxSize(52,24), wxTE_CENTRE,0,500); + t_klatt[KLATT_AV] = new wxStaticText(this,-1,_T("AV"),wxPoint(61,y+36)); + s_klatt[KLATT_AVp] = new wxSpinCtrl(this,T_AVP,_T(""), wxPoint(100,y+32), wxSize(52,24), wxTE_CENTRE,0,500); + t_klatt[KLATT_AVp] = new wxStaticText(this,-1,_T("AVp"),wxPoint(155,y+36)); + + s_klatt[KLATT_Fric] = new wxSpinCtrl(this,T_FRIC,_T(""), wxPoint(6,y+60), wxSize(52,24), wxTE_CENTRE,0,500); + t_klatt[KLATT_Fric] = new wxStaticText(this,-1,_T("Fric"),wxPoint(61,y+64)); + s_klatt[KLATT_FricBP] = new wxSpinCtrl(this,T_FRICBP,_T(""), wxPoint(100,y+60), wxSize(52,24), wxTE_CENTRE,0,500); + t_klatt[KLATT_FricBP] = new wxStaticText(this,-1,_T("FricBP"),wxPoint(155,y+64)); + + s_klatt[KLATT_Aspr] = new wxSpinCtrl(this,T_ASPR,_T(""), wxPoint(6,y+88), wxSize(52,24), wxTE_CENTRE,0,500); + t_klatt[KLATT_Aspr] = new wxStaticText(this,-1,_T("Aspr"),wxPoint(61,y+92)); + s_klatt[KLATT_Turb] = new wxSpinCtrl(this,T_TURB,_T(""), wxPoint(100,y+88), wxSize(52,24), wxTE_CENTRE,0,500); + t_klatt[KLATT_Turb] = new wxStaticText(this,-1,_T("Turb"),wxPoint(155,y+92)); + + s_klatt[KLATT_Skew] = new wxSpinCtrl(this,T_SKEW,_T(""), wxPoint(6,y+116), wxSize(52,24), wxTE_CENTRE,0,500); + t_klatt[KLATT_Skew] = new wxStaticText(this,-1,_T("Skew"),wxPoint(61,y+120)); + s_klatt[KLATT_Tilt] = new wxSpinCtrl(this,T_TILT,_T(""), wxPoint(100,y+116), wxSize(52,24), wxTE_CENTRE,0,500); + t_klatt[KLATT_Tilt] = new wxStaticText(this,-1,_T("Tilt"),wxPoint(155,y+120)); + + s_klatt[KLATT_Kopen] = new wxSpinCtrl(this,T_KOPEN,_T(""), wxPoint(6,y+144), wxSize(52,24), wxTE_CENTRE,0,500); + t_klatt[KLATT_Kopen] = new wxStaticText(this,-1,_T("kopen"),wxPoint(61,y+148)); -// usepitchenv = new wxCheckBox(this,T_USEPITCHENV,_T("???"),wxPoint(20,320)); + t_zoomout = new wxButton(this,T_ZOOMOUT,_T("Zoom-"),wxPoint(16,420)); + t_zoomin = new wxButton(this,T_ZOOMIN,_T("Zoom+"),wxPoint(106,420)); + y=468; t_amplitude = new wxSpinCtrl(this,T_AMPLITUDE,_T(""), - wxPoint(6,370),wxSize(52,24),wxTE_CENTRE,0,500); - t_lab[2] = new wxStaticText(this,-1,_T("% amp - Sequence"),wxPoint(61,374)); + wxPoint(6,y),wxSize(52,24),wxTE_CENTRE,0,y+130); + t_lab[2] = new wxStaticText(this,-1,_T("% amp - Sequence"),wxPoint(61,y+4)); // t_timeseq = new wxSpinCtrl(this,T_TIMESEQ,_T(""), // wxPoint(6,400),wxSize(52,24),wxTE_CENTRE,0,500); - t_orig_seq = new wxStaticText(this,-1,_T("mS"),wxPoint(61,404)); + t_orig_seq = new wxStaticText(this,-1,_T("mS"),wxPoint(61,y+30)); - t_pitch = new wxStaticText(this,-1,_T(""),wxPoint(4,440),wxSize(192,24)); + t_pitch = new wxStaticText(this,-1,_T(""),wxPoint(4,520),wxSize(192,24)); - pitchgraph = new ByteGraph(this,wxPoint(0,460),wxSize(200,140)); + pitchgraph = new ByteGraph(this,wxPoint(0,538),wxSize(200,140)); pitchgraph->SetData(128,env_fall); pitchgraph->ShowSpectrum(1); pitchgraph->Show(); } +void FormantDlg::HideFields(int synth_type) +{//======================================= + int ix; + static int prev_synth_type = -1; + + if(synth_type == prev_synth_type) + return; // no change + + if(synth_type == 0) + { + for(ix=0; ix<9; ix++) + { + s_klatt[ix]->Hide(); + t_klatt[ix]->Hide(); + } + for(ix=6; ix<9; ix++) + { + t_pkfreq[ix]->Show(); + t_pkheight[ix]->Show(); + t_pkwidth[ix]->Hide(); + t_pkright[ix]->Hide(); + } + t_ampframe->Show(); + t_amplitude->Show(); + t_lab[2]->Show(); + t_lab[3]->Show(); + t_labpk[7]->Show(); + t_labpk[8]->Show(); + t_lab[4]->Hide(); + } + else + { + for(ix=0; ix<9; ix++) + { + s_klatt[ix]->Show(); + t_klatt[ix]->Show(); + } + for(ix=7; ix<9; ix++) + { + t_pkfreq[ix]->Hide(); + t_pkheight[ix]->Hide(); + t_pkwidth[ix]->Hide(); + t_pkright[ix]->Hide(); + } + t_pkwidth[6]->Show(1); + t_pkright[6]->Show(1); + t_ampframe->Hide(); + t_amplitude->Hide(); + t_lab[2]->Hide(); + t_lab[3]->Hide(); + t_labpk[7]->Hide(); + t_labpk[8]->Hide(); + t_lab[4]->Show(); + } + prev_synth_type = synth_type; +} + void FormantDlg::ShowFrame(SpectSeq *spectseq, int frame, int pk, int field) {//============================================================== @@ -169,6 +244,8 @@ void FormantDlg::ShowFrame(SpectSeq *spectseq, int frame, int pk, int field) return; sf = spectseq->frames[frame]; + HideFields(spectseq->synthesizer_type); + if(field == 0xff) { // indicate the selected peak @@ -203,10 +280,8 @@ void FormantDlg::ShowFrame(SpectSeq *spectseq, int frame, int pk, int field) { value.Printf(_T("%3d"),sf->peaks[ix].pkwidth); t_pkwidth[ix]->SetValue(value); -#ifdef WIDTH2 value.Printf(_T("%3d"),sf->peaks[ix].pkright); t_pkright[ix]->SetValue(value); -#endif } } @@ -216,6 +291,16 @@ void FormantDlg::ShowFrame(SpectSeq *spectseq, int frame, int pk, int field) t_orig_frame->SetLabel(value); value.Printf(_T("%3d"),sf->amp_adjust); t_ampframe->SetValue(value); + + if(spectseq->synthesizer_type == 1) + { + for(ix=0; ix<9; ix++) + { + SetSpinCtrl(s_klatt[ix], sf->klatt_param[ix]); + } + } + + } // end of FormantDlg::ShowFrame diff --git a/src/klatt.cpp b/src/klatt.cpp new file mode 100644 index 00000000..97ee59ef --- /dev/null +++ b/src/klatt.cpp @@ -0,0 +1,1282 @@ + +/*************************************************************************** + * Copyright (C) 2008 by Jonathan Duddington * + * email: jonsd@users.sourceforge.net * + * * + * Based on a re-implementation by: * + * (c) 1993,94 Jon Iles and Nick Ing-Simmons * + * of the Klatt cascade-parallel formant synthesizer * + * * + * 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, see: * + * . * + ***************************************************************************/ + +// See URL: ftp://svr-ftp.eng.cam.ac.uk/pub/comp.speech/synthesis/klatt.3.04.tar.gz + +#include "StdAfx.h" + +#include +#include +#include +#include +#include "klatt.h" + +#include "speak_lib.h" +#include "speech.h" +#include "phoneme.h" +#include "synthesize.h" +#include "voice.h" + +#ifdef INCLUDE_KLATT // conditional compilation for the whole file + +extern unsigned char *out_ptr; // **JSD +extern unsigned char *out_start; +extern unsigned char *out_end; +extern WGEN_DATA wdata; +static int nsamples; +static int sample_count; + + +#ifdef _MSC_VER +#define getrandom(min,max) ((rand()%(int)(((max)+1)-(min)))+(min)) +#else +#define getrandom(min,max) ((rand()%(long)(((max)+1)-(min)))+(min)) +#endif + + +/* function prototypes for functions private to this file */ + +static void flutter(klatt_frame_ptr); +static double sampled_source (void); +static double impulsive_source (void); +static double natural_source (void); +static void pitch_synch_par_reset (klatt_frame_ptr); +static double gen_noise (double); +static double DBtoLIN (long); +static void frame_init (klatt_frame_ptr); +static void setabc (long,long,resonator_ptr); +static void setzeroabc (long,long,resonator_ptr); + +static klatt_frame_t kt_frame; +static klatt_global_t kt_globals; + +/* +function RESONATOR + +This is a generic resonator function. Internal memory for the resonator +is stored in the globals structure. +*/ + +static double resonator(resonator_ptr r, double input) +{ + double x; + + x = (double) ((double)r->a * (double)input + (double)r->b * (double)r->p1 + (double)r->c * (double)r->p2); + r->p2 = (double)r->p1; + r->p1 = (double)x; + + return (double)x; +} + +static double resonator2(resonator_ptr r, double input) +{ + double x; + + x = (double) ((double)r->a * (double)input + (double)r->b * (double)r->p1 + (double)r->c * (double)r->p2); + r->p2 = (double)r->p1; + r->p1 = (double)x; + + r->a += r->a_inc; + r->b += r->b_inc; + r->c += r->c_inc; + return (double)x; +} + + + +/* +function ANTIRESONATOR + +This is a generic anti-resonator function. The code is the same as resonator +except that a,b,c need to be set with setzeroabc() and we save inputs in +p1/p2 rather than outputs. There is currently only one of these - "rnz" +Output = (rnz.a * input) + (rnz.b * oldin1) + (rnz.c * oldin2) +*/ + +#ifdef deleted +static double antiresonator(resonator_ptr r, double input) +{ + register double x = (double)r->a * (double)input + (double)r->b * (double)r->p1 + (double)r->c * (double)r->p2; + r->p2 = (double)r->p1; + r->p1 = (double)input; + return (double)x; +} +#endif + +static double antiresonator2(resonator_ptr r, double input) +{ + register double x = (double)r->a * (double)input + (double)r->b * (double)r->p1 + (double)r->c * (double)r->p2; + r->p2 = (double)r->p1; + r->p1 = (double)input; + + r->a += r->a_inc; + r->b += r->b_inc; + r->c += r->c_inc; + return (double)x; +} + + + +/* +function FLUTTER + +This function adds F0 flutter, as specified in: + +"Analysis, synthesis and perception of voice quality variations among +female and male talkers" D.H. Klatt and L.C. Klatt JASA 87(2) February 1990. + +Flutter is added by applying a quasi-random element constructed from three +slowly varying sine waves. +*/ + +static void flutter(klatt_frame_ptr frame) +{ + static int time_count; + double delta_f0; + double fla,flb,flc,fld,fle; + + fla = (double) kt_globals.f0_flutter / 50; + flb = (double) kt_globals.original_f0 / 100; +// flc = sin(2*PI*12.7*time_count); +// fld = sin(2*PI*7.1*time_count); +// fle = sin(2*PI*4.7*time_count); + flc = sin(PI*12.7*time_count); // because we are calling flutter() more frequently, every 2.9mS + fld = sin(PI*7.1*time_count); + fle = sin(PI*4.7*time_count); + delta_f0 = fla * flb * (flc + fld + fle) * 10; + frame->F0hz10 = frame->F0hz10 + (long) delta_f0; + time_count++; +} + + + +/* +function SAMPLED_SOURCE + +Allows the use of a glottal excitation waveform sampled from a real +voice. +*/ + +static double sampled_source() +{ + int itemp; + double ftemp; + double result; + double diff_value; + int current_value; + int next_value; + double temp_diff; + + if(kt_globals.T0!=0) + { + ftemp = (double) kt_globals.nper; + ftemp = ftemp / kt_globals.T0; + ftemp = ftemp * kt_globals.num_samples; + itemp = (int) ftemp; + + temp_diff = ftemp - (double) itemp; + + current_value = kt_globals.natural_samples[itemp]; + next_value = kt_globals.natural_samples[itemp+1]; + + diff_value = (double) next_value - (double) current_value; + diff_value = diff_value * temp_diff; + + result = kt_globals.natural_samples[itemp] + diff_value; + result = result * kt_globals.sample_factor; + } + else + { + result = 0; + } + return(result); +} + + + + +/* +function PARWAVE + +Converts synthesis parameters to a waveform. +*/ + + +int parwave(klatt_frame_ptr frame) +{ + double temp; + double outbypas; + double out; + long n4; + double frics; + double glotout; + double aspiration; + double casc_next_in; + double par_glotout; + static double noise; + static double voice; + static double vlast; + static double glotlast; + static double sourc; + int ix; + + frame_init(frame); /* get parameters for next frame of speech */ + + flutter(frame); /* add f0 flutter */ + +#ifdef deleted +{ + FILE *f; + f=fopen("klatt_log","a"); + fprintf(f,"%4dhz %2dAV %4d %3d, %4d %3d, %4d %3d, %4d %3d, %4d, %3d, %4d %3d TLT=%2d\n",frame->F0hz10,frame->AVdb, + frame->F1hz,frame->B1hz,frame->F2hz,frame->B2hz,frame->F3hz,frame->B3hz,frame->F4hz,frame->B4hz,frame->F5hz,frame->B5hz,frame->F6hz,frame->B6hz,frame->TLTdb); + fclose(f); +} +#endif + + /* MAIN LOOP, for each output sample of current frame: */ + + for (kt_globals.ns=0; kt_globals.ns kt_globals.nmod) + { + noise *= (double) 0.5; + } + + /* Compute frication noise */ + frics = kt_globals.amp_frica * noise; + + /* + Compute voicing waveform. Run glottal source simulation at 4 + times normal sample rate to minimize quantization noise in + period of female voice. + */ + + for (n4=0; n4<4; n4++) + { + switch(kt_globals.glsource) + { + case IMPULSIVE: + voice = impulsive_source(); + break; + case NATURAL: + voice = natural_source(); + break; + case SAMPLED: + voice = sampled_source(); + break; + } + + /* Reset period when counter 'nper' reaches T0 */ + if (kt_globals.nper >= kt_globals.T0) + { + kt_globals.nper = 0; + pitch_synch_par_reset(frame); + } + + /* + Low-pass filter voicing waveform before downsampling from 4*samrate + to samrate samples/sec. Resonator f=.09*samrate, bw=.06*samrate + */ + + voice = resonator(&(kt_globals.rsn[RLP]),voice); + + /* Increment counter that keeps track of 4*samrate samples per sec */ + kt_globals.nper++; + } + + /* + Tilt spectrum of voicing source down by soft low-pass filtering, amount + of tilt determined by TLTdb + */ + + voice = (voice * kt_globals.onemd) + (vlast * kt_globals.decay); + vlast = voice; + + /* + Add breathiness during glottal open phase. Amount of breathiness + determined by parameter Aturb Use nrand rather than noise because + noise is low-passed. + */ + + + if (kt_globals.nper < kt_globals.nopen) + { + voice += kt_globals.amp_breth * kt_globals.nrand; + } + + /* Set amplitude of voicing */ + glotout = kt_globals.amp_voice * voice; + par_glotout = kt_globals.par_amp_voice * voice; + + /* Compute aspiration amplitude and add to voicing source */ + aspiration = kt_globals.amp_aspir * noise; + glotout += aspiration; + + par_glotout += aspiration; + + /* + Cascade vocal tract, excited by laryngeal sources. + Nasal antiresonator, then formants FNP, F5, F4, F3, F2, F1 + */ + + out=0; + if(kt_globals.synthesis_model != ALL_PARALLEL) + { + casc_next_in = antiresonator2(&(kt_globals.rsn[Rnz]),glotout); + casc_next_in = resonator(&(kt_globals.rsn[Rnpc]),casc_next_in); + casc_next_in = resonator(&(kt_globals.rsn[R8c]),casc_next_in); + casc_next_in = resonator(&(kt_globals.rsn[R7c]),casc_next_in); + casc_next_in = resonator(&(kt_globals.rsn[R6c]),casc_next_in); + casc_next_in = resonator2(&(kt_globals.rsn[R5c]),casc_next_in); + casc_next_in = resonator2(&(kt_globals.rsn[R4c]),casc_next_in); + casc_next_in = resonator2(&(kt_globals.rsn[R3c]),casc_next_in); + casc_next_in = resonator2(&(kt_globals.rsn[R2c]),casc_next_in); + out = resonator2(&(kt_globals.rsn[R1c]),casc_next_in); + } + + /* Excite parallel F1 and FNP by voicing waveform */ + sourc = par_glotout; /* Source is voicing plus aspiration */ + + /* + Standard parallel vocal tract Formants F6,F5,F4,F3,F2, + outputs added with alternating sign. Sound source for other + parallel resonators is frication plus first difference of + voicing waveform. + */ + + out += resonator(&(kt_globals.rsn[R1p]),sourc); + out += resonator(&(kt_globals.rsn[Rnpp]),sourc); + + sourc = frics + par_glotout - glotlast; + glotlast = par_glotout; + + for(ix=R2p; ix<=R6p; ix++) + { + out = resonator(&(kt_globals.rsn[ix]),sourc) - out; + } + + outbypas = kt_globals.amp_bypas * sourc; + + out = outbypas - out; + +#ifdef deleted +// for testing + if (kt_globals.outsl != 0) + { + switch(kt_globals.outsl) + { + case 1: + out = voice; + break; + case 2: + out = aspiration; + break; + case 3: + out = frics; + break; + case 4: + out = glotout; + break; + case 5: + out = par_glotout; + break; + case 6: + out = outbypas; + break; + case 7: + out = sourc; + break; + } + } +#endif + + out = resonator(&(kt_globals.rsn[Rout]),out); + temp = (out * wdata.amplitude * kt_globals.amp_gain0) ; /* Convert back to integer */ + + + // mix with a recorded WAV if required for this phoneme + { + int z2; + signed char c; + int sample; + + z2 = 0; + if(wdata.mix_wavefile_ix < wdata.n_mix_wavefile) + { + if(wdata.mix_wave_scale == 0) + { + // a 16 bit sample + c = wdata.mix_wavefile[wdata.mix_wavefile_ix+1]; + sample = wdata.mix_wavefile[wdata.mix_wavefile_ix] + (c * 256); + wdata.mix_wavefile_ix += 2; + } + else + { + // a 8 bit sample, scaled + sample = (signed char)wdata.mix_wavefile[wdata.mix_wavefile_ix++] * wdata.mix_wave_scale; + } + z2 = sample * wdata.amplitude_v / 1024; + z2 = (z2 * wdata.mix_wave_amp)/40; + temp += z2; + } + } + + // if fadeout is set, fade to zero over 64 samples, to avoid clicks at end of synthesis + if(kt_globals.fadeout > 0) + { + kt_globals.fadeout--; + temp = (temp * kt_globals.fadeout) / 64; + } + + if (temp < -32768.0) + { + temp = -32768.0; + } + + if (temp > 32767.0) + { + temp = 32767.0; + } + + *out_ptr++ = int(temp); // **JSD + *out_ptr++ = int(temp) >> 8; + sample_count++; + if(out_ptr >= out_end) + { + return(1); + } + } + return(0); +} // end of parwave + + + + +/* +function PARWAVE_INIT + +Initialises all parameters used in parwave, sets resonator internal memory +to zero. +*/ + +void reset_resonators() +{ + int r_ix; + + for(r_ix=0; r_ix < N_RSN; r_ix++) + { + kt_globals.rsn[r_ix].p1 = 0; + kt_globals.rsn[r_ix].p2 = 0; + } +} + +void parwave_init() +{ + kt_globals.FLPhz = (950 * kt_globals.samrate) / 10000; + kt_globals.BLPhz = (630 * kt_globals.samrate) / 10000; + kt_globals.minus_pi_t = -PI / kt_globals.samrate; + kt_globals.two_pi_t = -2.0 * kt_globals.minus_pi_t; + setabc(kt_globals.FLPhz,kt_globals.BLPhz,&(kt_globals.rsn[RLP])); + kt_globals.nper = 0; + kt_globals.T0 = 0; + kt_globals.nopen = 0; + kt_globals.nmod = 0; + + reset_resonators(); +} + + +/* +function FRAME_INIT + +Use parameters from the input frame to set up resonator coefficients. +*/ + +static void frame_init(klatt_frame_ptr frame) +{ + double amp_par[7]; + static double amp_par_factor[7] = {0.6, 0.4, 0.15, 0.06, 0.04, 0.022, 0.03}; + long Gain0_tmp; + int ix; + + kt_globals.original_f0 = frame->F0hz10 / 10; + + frame->AVdb_tmp = frame->AVdb - 7; + if (frame->AVdb_tmp < 0) + { + frame->AVdb_tmp = 0; + } + + kt_globals.amp_aspir = DBtoLIN(frame->ASP) * 0.05; + kt_globals.amp_frica = DBtoLIN(frame->AF) * 0.25; + kt_globals.par_amp_voice = DBtoLIN(frame->AVpdb); + kt_globals.amp_bypas = DBtoLIN(frame->AB) * 0.05; + + for(ix=0; ix <= 6; ix++) + { + // parallel amplitudes F1 to F6, and parallel nasal pole + amp_par[ix] = DBtoLIN(frame->Ap[ix]) * amp_par_factor[ix]; + } + + Gain0_tmp = frame->Gain0 - 3; + if (Gain0_tmp <= 0) + { + Gain0_tmp = 57; + } + kt_globals.amp_gain0 = DBtoLIN(Gain0_tmp) / kt_globals.scale_wav; + + /* Set coefficients of variable cascade resonators */ + for(ix=0; ix<=8; ix++) + { + // formants 1 to 8, plus nasal pole + setabc(frame->Fhz[ix],frame->Bhz[ix],&(kt_globals.rsn[ix])); + + if(ix <= 5) + { + setabc(frame->Fhz_next[ix],frame->Bhz_next[ix],&(kt_globals.rsn_next[ix])); + + kt_globals.rsn[ix].a_inc = (kt_globals.rsn_next[ix].a - kt_globals.rsn[ix].a) / 64.0; + kt_globals.rsn[ix].b_inc = (kt_globals.rsn_next[ix].b - kt_globals.rsn[ix].b) / 64.0; + kt_globals.rsn[ix].c_inc = (kt_globals.rsn_next[ix].c - kt_globals.rsn[ix].c) / 64.0; + } + } + + // nasal zero anti-resonator + setzeroabc(frame->Fhz[F_NZ],frame->Bhz[F_NZ],&(kt_globals.rsn[Rnz])); + setzeroabc(frame->Fhz_next[F_NZ],frame->Bhz_next[F_NZ],&(kt_globals.rsn_next[Rnz])); + kt_globals.rsn[F_NZ].a_inc = (kt_globals.rsn_next[F_NZ].a - kt_globals.rsn[F_NZ].a) / 64.0; + kt_globals.rsn[F_NZ].b_inc = (kt_globals.rsn_next[F_NZ].b - kt_globals.rsn[F_NZ].b) / 64.0; + kt_globals.rsn[F_NZ].c_inc = (kt_globals.rsn_next[F_NZ].c - kt_globals.rsn[F_NZ].c) / 64.0; + + + /* Set coefficients of parallel resonators, and amplitude of outputs */ + + for(ix=0; ix<=6; ix++) + { + setabc(frame->Fhz[ix],frame->Bphz[ix],&(kt_globals.rsn[Rparallel+ix])); + kt_globals.rsn[Rparallel+ix].a *= amp_par[ix]; + } + + /* output low-pass filter */ + + setabc((long)0.0,(long)(kt_globals.samrate/2),&(kt_globals.rsn[Rout])); + +} + + + +/* +function IMPULSIVE_SOURCE + +Generate a low pass filtered train of impulses as an approximation of +a natural excitation waveform. Low-pass filter the differentiated impulse +with a critically-damped second-order filter, time constant proportional +to Kopen. +*/ + + +static double impulsive_source() +{ + static double doublet[] = {0.0,13000000.0,-13000000.0}; + static double vwave; + + if (kt_globals.nper < 3) + { + vwave = doublet[kt_globals.nper]; + } + else + { + vwave = 0.0; + } + + return(resonator(&(kt_globals.rsn[RGL]),vwave)); +} + + + +/* +function NATURAL_SOURCE + +Vwave is the differentiated glottal flow waveform, there is a weak +spectral zero around 800 Hz, magic constants a,b reset pitch synchronously. +*/ + +static double natural_source() +{ + double lgtemp; + static double vwave; + + if (kt_globals.nper < kt_globals.nopen) + { + kt_globals.pulse_shape_a -= kt_globals.pulse_shape_b; + vwave += kt_globals.pulse_shape_a; + lgtemp=vwave * 0.028; + + return(lgtemp); + } + else + { + vwave = 0.0; + return(0.0); + } +} + + + + + +/* +function PITCH_SYNC_PAR_RESET + +Reset selected parameters pitch-synchronously. + + +Constant B0 controls shape of glottal pulse as a function +of desired duration of open phase N0 +(Note that N0 is specified in terms of 40,000 samples/sec of speech) + +Assume voicing waveform V(t) has form: k1 t**2 - k2 t**3 + + If the radiation characterivative, a temporal derivative + is folded in, and we go from continuous time to discrete + integers n: dV/dt = vwave[n] + = sum over i=1,2,...,n of { a - (i * b) } + = a n - b/2 n**2 + + where the constants a and b control the detailed shape + and amplitude of the voicing waveform over the open + potion of the voicing cycle "nopen". + + Let integral of dV/dt have no net dc flow --> a = (b * nopen) / 3 + + Let maximum of dUg(n)/dn be constant --> b = gain / (nopen * nopen) + meaning as nopen gets bigger, V has bigger peak proportional to n + + Thus, to generate the table below for 40 <= nopen <= 263: + + B0[nopen - 40] = 1920000 / (nopen * nopen) +*/ + +static void pitch_synch_par_reset(klatt_frame_ptr frame) +{ + long temp; + double temp1; + static long skew; + static short B0[224] = + { + 1200,1142,1088,1038, 991, 948, 907, 869, 833, 799, 768, 738, 710, 683, 658, + 634, 612, 590, 570, 551, 533, 515, 499, 483, 468, 454, 440, 427, 415, 403, + 391, 380, 370, 360, 350, 341, 332, 323, 315, 307, 300, 292, 285, 278, 272, + 265, 259, 253, 247, 242, 237, 231, 226, 221, 217, 212, 208, 204, 199, 195, + 192, 188, 184, 180, 177, 174, 170, 167, 164, 161, 158, 155, 153, 150, 147, + 145, 142, 140, 137, 135, 133, 131, 128, 126, 124, 122, 120, 119, 117, 115, + 113,111, 110, 108, 106, 105, 103, 102, 100, 99, 97, 96, 95, 93, 92, 91, 90, + 88, 87, 86, 85, 84, 83, 82, 80, 79, 78, 77, 76, 75, 75, 74, 73, 72, 71, + 70, 69, 68, 68, 67, 66, 65, 64, 64, 63, 62, 61, 61, 60, 59, 59, 58, 57, + 57, 56, 56, 55, 55, 54, 54, 53, 53, 52, 52, 51, 51, 50, 50, 49, 49, 48, 48, + 47, 47, 46, 46, 45, 45, 44, 44, 43, 43, 42, 42, 41, 41, 41, 41, 40, 40, + 39, 39, 38, 38, 38, 38, 37, 37, 36, 36, 36, 36, 35, 35, 35, 35, 34, 34,33, + 33, 33, 33, 32, 32, 32, 32, 31, 31, 31, 31, 30, 30, 30, 30, 29, 29, 29, 29, + 28, 28, 28, 28, 27, 27 + }; + + if (frame->F0hz10 > 0) + { + /* T0 is 4* the number of samples in one pitch period */ + + kt_globals.T0 = (40 * kt_globals.samrate) / frame->F0hz10; + + + kt_globals.amp_voice = DBtoLIN(frame->AVdb_tmp); + + /* Duration of period before amplitude modulation */ + + kt_globals.nmod = kt_globals.T0; + if (frame->AVdb_tmp > 0) + { + kt_globals.nmod >>= 1; + } + + /* Breathiness of voicing waveform */ + + kt_globals.amp_breth = DBtoLIN(frame->Aturb) * 0.1; + + /* Set open phase of glottal period where 40 <= open phase <= 263 */ + + kt_globals.nopen = 4 * frame->Kopen; + + if ((kt_globals.glsource == IMPULSIVE) && (kt_globals.nopen > 263)) + { + kt_globals.nopen = 263; + } + + if (kt_globals.nopen >= (kt_globals.T0-1)) + { +// printf("Warning: glottal open period cannot exceed T0, truncated\n"); + kt_globals.nopen = kt_globals.T0 - 2; + } + + if (kt_globals.nopen < 40) + { + /* F0 max = 1000 Hz */ +// printf("Warning: minimum glottal open period is 10 samples.\n"); +// printf("truncated, nopen = %d\n",kt_globals.nopen); + kt_globals.nopen = 40; + } + + + /* Reset a & b, which determine shape of "natural" glottal waveform */ + + kt_globals.pulse_shape_b = B0[kt_globals.nopen-40]; + kt_globals.pulse_shape_a = (kt_globals.pulse_shape_b * kt_globals.nopen) * 0.333; + + /* Reset width of "impulsive" glottal pulse */ + + temp = kt_globals.samrate / kt_globals.nopen; + + setabc((long)0,temp,&(kt_globals.rsn[RGL])); + + /* Make gain at F1 about constant */ + + temp1 = kt_globals.nopen *.00833; + kt_globals.rsn[RGL].a *= temp1 * temp1; + + /* + Truncate skewness so as not to exceed duration of closed phase + of glottal period. + */ + + + temp = kt_globals.T0 - kt_globals.nopen; + if (frame->Kskew > temp) + { +// printf("Kskew duration=%d > glottal closed period=%d, truncate\n", frame->Kskew, kt_globals.T0 - kt_globals.nopen); + frame->Kskew = temp; + } + if (skew >= 0) + { + skew = frame->Kskew; + } + else + { + skew = - frame->Kskew; + } + + /* Add skewness to closed portion of voicing period */ + kt_globals.T0 = kt_globals.T0 + skew; + skew = - skew; + } + else + { + kt_globals.T0 = 4; /* Default for f0 undefined */ + kt_globals.amp_voice = 0.0; + kt_globals.nmod = kt_globals.T0; + kt_globals.amp_breth = 0.0; + kt_globals.pulse_shape_a = 0.0; + kt_globals.pulse_shape_b = 0.0; + } + + /* Reset these pars pitch synchronously or at update rate if f0=0 */ + + if ((kt_globals.T0 != 4) || (kt_globals.ns == 0)) + { + /* Set one-pole low-pass filter that tilts glottal source */ + + kt_globals.decay = (0.033 * frame->TLTdb); + + if (kt_globals.decay > 0.0) + { + kt_globals.onemd = 1.0 - kt_globals.decay; + } + else + { + kt_globals.onemd = 1.0; + } + } +} + + + +/* +function SETABC + +Convert formant freqencies and bandwidth into resonator difference +equation constants. +*/ + + +static void setabc(long int f, long int bw, resonator_ptr rp) +{ + double r; + double arg; + + /* Let r = exp(-pi bw t) */ + arg = kt_globals.minus_pi_t * bw; + r = exp(arg); + + /* Let c = -r**2 */ + rp->c = -(r * r); + + /* Let b = r * 2*cos(2 pi f t) */ + arg = kt_globals.two_pi_t * f; + rp->b = r * cos(arg) * 2.0; + + /* Let a = 1.0 - b - c */ + rp->a = 1.0 - rp->b - rp->c; +} + + +/* +function SETZEROABC + +Convert formant freqencies and bandwidth into anti-resonator difference +equation constants. +*/ + +static void setzeroabc(long int f, long int bw, resonator_ptr rp) +{ + double r; + double arg; + + f = -f; + + if(f>=0) + { + f = -1; + } + + /* First compute ordinary resonator coefficients */ + /* Let r = exp(-pi bw t) */ + arg = kt_globals.minus_pi_t * bw; + r = exp(arg); + + /* Let c = -r**2 */ + rp->c = -(r * r); + + /* Let b = r * 2*cos(2 pi f t) */ + arg = kt_globals.two_pi_t * f; + rp->b = r * cos(arg) * 2.; + + /* Let a = 1.0 - b - c */ + rp->a = 1.0 - rp->b - rp->c; + + /* Now convert to antiresonator coefficients (a'=1/a, b'=b/a, c'=c/a) */ + rp->a = 1.0 / rp->a; + rp->c *= -rp->a; + rp->b *= -rp->a; +} + + +/* +function GEN_NOISE + +Random number generator (return a number between -8191 and +8191) +Noise spectrum is tilted down by soft low-pass filter having a pole near +the origin in the z-plane, i.e. output = input + (0.75 * lastoutput) +*/ + + +static double gen_noise(double noise) +{ + long temp; + static double nlast; + + temp = (long) getrandom(-8191,8191); + kt_globals.nrand = (long) temp; + + noise = kt_globals.nrand + (0.75 * nlast); + nlast = noise; + + return(noise); +} + + +/* +function DBTOLIN + +Convert from decibels to a linear scale factor + + +Conversion table, db to linear, 87 dB --> 32767 + 86 dB --> 29491 (1 dB down = 0.5**1/6) + ... + 81 dB --> 16384 (6 dB down = 0.5) + ... + 0 dB --> 0 + +The just noticeable difference for a change in intensity of a vowel +is approximately 1 dB. Thus all amplitudes are quantized to 1 dB +steps. +*/ + + +static double DBtoLIN(long dB) +{ + static short amptable[88] = + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 7, + 8, 9, 10, 11, 13, 14, 16, 18, 20, 22, 25, 28, 32, + 35, 40, 45, 51, 57, 64, 71, 80, 90, 101, 114, 128, + 142, 159, 179, 202, 227, 256, 284, 318, 359, 405, + 455, 512, 568, 638, 719, 881, 911, 1024, 1137, 1276, + 1438, 1622, 1823, 2048, 2273, 2552, 2875, 3244, 3645, + 4096, 4547, 5104, 5751, 6488, 7291, 8192, 9093, 10207, + 11502, 12976, 14582, 16384, 18350, 20644, 23429, + 26214, 29491, 32767 }; + + if ((dB < 0) || (dB > 87)) + { + return(0); + } + + return(double(amptable[dB]) * 0.001); +} + + + + + +extern voice_t *wvoice; +static wavegen_peaks_t peaks[N_PEAKS]; +static int end_wave; +static int klattp[N_KLATTP]; +static double klattp1[N_KLATTP]; +static double klattp_inc[N_KLATTP]; + +static int scale_wav_tab[] = {45,38,45,45}; // scale output from different voicing sources + + + +int Wavegen_Klatt(int resume) +{//========================== + int pk; + int x; + int ix; + + if(resume==0) + { + sample_count = 0; + } + + while(sample_count < nsamples) + { + kt_frame.F0hz10 = (wdata.pitch * 10) / 4096; + + kt_frame.Fhz[F_NP] = peaks[0].freq; + kt_frame.Fhz[F_NZ] = peaks[0].left; + + // formants F6,F7,F8 are fixed values for cascade resonators, set in KlattInit() + // but F6 is used for parallel resonator + for(ix=1; ix<=6; ix++) + { + if(ix < 6) + { + kt_frame.Fhz[ix] = peaks[ix].freq; + kt_frame.Bhz[ix] = peaks[ix].height; + } + kt_frame.Bphz[ix] = peaks[ix].left; + kt_frame.Ap[ix] = peaks[ix].right; + } + + kt_frame.AVdb = klattp[KLATT_AV]; + kt_frame.AVpdb = klattp[KLATT_AVp]; + kt_frame.AF = klattp[KLATT_Fric]; + kt_frame.AB = klattp[KLATT_FricBP]; + kt_frame.ASP = klattp[KLATT_Aspr]; + kt_frame.Aturb = klattp[KLATT_Turb]; + kt_frame.Kskew = klattp[KLATT_Skew]; + kt_frame.TLTdb = klattp[KLATT_Tilt]; + kt_frame.Kopen = klattp[KLATT_Kopen]; + + // advance formants + for(pk=0; pk>8) > 127) ix = 127; + x = wdata.pitch_env[ix] * wdata.pitch_range; + wdata.pitch = (x>>8) + wdata.pitch_base; + + kt_globals.nspfr = (nsamples - sample_count); + if(kt_globals.nspfr > STEPSIZE) + kt_globals.nspfr = STEPSIZE; + + if(parwave(&kt_frame) == 1) + { + return(1); + } + } + + if(end_wave == 1) + { + // fade out to avoid a click + kt_globals.fadeout = 64; + end_wave = 0; + sample_count -= 64; + kt_globals.nspfr = 64; + if(parwave(&kt_frame) == 1) + { + return(1); + } + } + + return(0); +} + + +void SetSynth_Klatt(int length, int modn, frame_t *fr1, frame_t *fr2, voice_t *v, int control) +{//=========================================================================================== + int ix; + DOUBLEX next; + int qix; + int cmd; + static frame_t prev_fr; + + if(wvoice != NULL) + { + if((wvoice->klatt[0] > 0) && (wvoice->klatt[0] <=3 )) + { + kt_globals.glsource = wvoice->klatt[0]; + kt_globals.scale_wav = scale_wav_tab[kt_globals.glsource]; + } + kt_globals.f0_flutter = wvoice->flutter/32; + } + + end_wave = 0; + if(control & 2) + { + end_wave = 1; // fadeout at the end + } + if(control & 1) + { + end_wave = 1; + for(qix=wcmdq_head+1;;qix++) + { + if(qix >= N_WCMDQ) qix = 0; + if(qix == wcmdq_tail) break; + + cmd = wcmdq[qix][0]; + if(cmd==WCMD_KLATT) + { + end_wave = 0; // next wave generation is from another spectrum + break; + } + if((cmd==WCMD_WAVE) || (cmd==WCMD_PAUSE)) + break; // next is not from spectrum, so continue until end of wave cycle + } + } + +{ +FILE *f; +//f=fopen("klatt_log","a"); +//fprintf(f,"len %4d (%3d %4d %4d) (%3d %4d %4d)\n",length,fr1->ffreq[1],fr1->ffreq[2],fr1->ffreq[3],fr2->ffreq[1],fr2->ffreq[2],fr2->ffreq[3]); +//fclose(f); +} + + if(control & 1) + { + if(wdata.prev_was_synth == 0) + { + // A break, not following on from another synthesized sound. + // Reset the synthesizer + //reset_resonators(&kt_globals); + parwave_init(); + } + else + { + if((prev_fr.ffreq[1] != fr1->ffreq[1]) || (prev_fr.ffreq[2] != fr1->ffreq[2])) + { + + // fade out to avoid a click, but only up to the end of output buffer + ix = (out_end - out_ptr)/2; + if(ix > 64) + ix = 64; + kt_globals.fadeout = ix; + kt_globals.nspfr = ix; + parwave(&kt_frame); + + //reset_resonators(&kt_globals); + parwave_init(); + } + } + wdata.prev_was_synth = 1; + memcpy(&prev_fr,fr2,sizeof(prev_fr)); + } + if(fr2->frflags & FRFLAG_BREAK) + { +// fr2 = fr1; +// reset_resonators(&kt_globals); + } + + for(ix=0; ixklattp[ix]; + klattp_inc[ix] = double((fr2->klattp[ix] - klattp[ix]) * STEPSIZE)/length; + + if((ix>0) && (ix < KLATT_AVp)) + klattp1[ix] = klattp[ix] = (klattp[ix] + wvoice->klatt[ix]); + } + + nsamples = length; + + for(ix=0; ixffreq[ix] * v->freq[ix] / 256.0) + v->freqadd[ix]; + peaks[ix].freq = int(peaks[ix].freq1); + next = (fr2->ffreq[ix] * v->freq[ix] / 256.0) + v->freqadd[ix]; + peaks[ix].freq_inc = ((next - peaks[ix].freq1) * STEPSIZE) / length; // lower headroom for fixed point math + + peaks[ix].height1 = fr1->fheight[ix] * 2; + peaks[ix].height = int(peaks[ix].height1); + next = fr2->fheight[ix] * 2; + peaks[ix].height_inc = ((next - peaks[ix].height1) * STEPSIZE) / length; + + if(ix < 6) + { + peaks[ix].left1 = fr1->fwidth[ix] * 2; + peaks[ix].left = int(peaks[ix].left1); + next = fr2->fwidth[ix] * 2; + peaks[ix].left_inc = ((next - peaks[ix].left1) * STEPSIZE) / length; + + peaks[ix].right1 = fr1->fright[ix]; + peaks[ix].right = int(peaks[ix].right1); + next = fr2->fright[ix]; + peaks[ix].right_inc = ((next - peaks[ix].right1) * STEPSIZE) / length; + } + peaks[6].left1 = fr1->fwidth6 * 2; + peaks[6].left = int(peaks[6].left1); + next = fr2->fwidth6 * 2; + peaks[6].left_inc = ((next - peaks[6].left1) * STEPSIZE) / length; + + peaks[6].right1 = fr1->fright6; + peaks[6].right = int(peaks[6].right1); + next = fr2->fright6; + peaks[6].right_inc = ((next - peaks[6].right1) * STEPSIZE) / length; + } +} // end of SetSynth_Klatt + + +int Wavegen_Klatt2(int length, int modulation, int resume, frame_t *fr1, frame_t *fr2) +{//=================================================================================== + if(resume==0) + SetSynth_Klatt(length, modulation, fr1, fr2, wvoice, 1); + + return(Wavegen_Klatt(resume)); +} + + + +void KlattInit() +{ +#define NUMBER_OF_SAMPLES 100 + + static short natural_samples[NUMBER_OF_SAMPLES]= + { + -310,-400,530,356,224,89,23,-10,-58,-16,461,599,536,701,770, + 605,497,461,560,404,110,224,131,104,-97,155,278,-154,-1165, + -598,737,125,-592,41,11,-247,-10,65,92,80,-304,71,167,-1,122, + 233,161,-43,278,479,485,407,266,650,134,80,236,68,260,269,179, + 53,140,275,293,296,104,257,152,311,182,263,245,125,314,140,44, + 203,230,-235,-286,23,107,92,-91,38,464,443,176,98,-784,-2449, + -1891,-1045,-1600,-1462,-1384,-1261,-949,-730 + }; + static short formant_hz[10] = {280,688,1064,2806,3260,3700,6500,7000,8000,280}; + static short bandwidth[10] = {89,160,70,160,200,200,500,500,500,89}; + static short parallel_amp[10] = { 0,59,59,59,59,59,59,0,0,0}; + static short parallel_bw[10] = {59,59,89,149,200,200,500,0,0,0}; + + int ix; + + sample_count=0; + + kt_globals.synthesis_model = CASCADE_PARALLEL; + kt_globals.samrate = 22050; + + kt_globals.glsource = IMPULSIVE; // IMPULSIVE, NATURAL, SAMPLED + kt_globals.scale_wav = scale_wav_tab[kt_globals.glsource]; + kt_globals.natural_samples = natural_samples; + kt_globals.num_samples = NUMBER_OF_SAMPLES; + kt_globals.sample_factor = 3.0; + kt_globals.nspfr = (kt_globals.samrate * 10) / 1000; + kt_globals.outsl = 0; + kt_globals.f0_flutter = 20; + + parwave_init(); + + // set default values for frame parameters + for(ix=0; ix<=9; ix++) + { + kt_frame.Fhz[ix] = formant_hz[ix]; + kt_frame.Bhz[ix] = bandwidth[ix]; + kt_frame.Ap[ix] = parallel_amp[ix]; + kt_frame.Bphz[ix] = parallel_bw[ix]; + } + kt_frame.Bhz_next[F_NZ] = bandwidth[F_NZ]; + + kt_frame.F0hz10 = 1000; + kt_frame.AVdb = 59; // 59 + kt_frame.ASP = 0; + kt_frame.Kopen = 40; // 40 + kt_frame.Aturb = 0; + kt_frame.TLTdb = 0; + kt_frame.AF =50; + kt_frame.Kskew = 0; + kt_frame.AB = 0; + kt_frame.AVpdb = 0; + kt_frame.Gain0 = 62; +} // end of KlattInit + +#endif // INCLUDE_KLATT diff --git a/src/klatt.h b/src/klatt.h new file mode 100644 index 00000000..812385e6 --- /dev/null +++ b/src/klatt.h @@ -0,0 +1,138 @@ + + +#define CASCADE_PARALLEL 1 /* Type of synthesis model */ +#define ALL_PARALLEL 2 + +#define IMPULSIVE 1 /* Type of voicing source */ +#define NATURAL 2 +#define SAMPLED 3 + +#define PI 3.1415927 + + +/* typedef's that need to be exported */ + +typedef long flag; + +/* Resonator Structure */ + +typedef struct +{ + double a; + double b; + double c; + double p1; + double p2; + double a_inc; + double b_inc; + double c_inc; +} resonator_t, *resonator_ptr; + +/* Structure for Klatt Globals */ + +typedef struct +{ + flag synthesis_model; /* cascade-parallel or all-parallel */ + flag outsl; /* Output waveform selector */ + long samrate; /* Number of output samples per second */ + long FLPhz ; /* Frequeny of glottal downsample low-pass filter */ + long BLPhz ; /* Bandwidth of glottal downsample low-pass filter */ + flag glsource; /* Type of glottal source */ + int f0_flutter; /* Percentage of f0 flutter 0-100 */ + long nspfr; /* number of samples per frame */ + long nper; /* Counter for number of samples in a pitch period */ + long ns; + long T0; /* Fundamental period in output samples times 4 */ + long nopen; /* Number of samples in open phase of period */ + long nmod; /* Position in period to begin noise amp. modul */ + long nrand; /* Varible used by random number generator */ + double pulse_shape_a; /* Makes waveshape of glottal pulse when open */ + double pulse_shape_b; /* Makes waveshape of glottal pulse when open */ + double minus_pi_t; + double two_pi_t; + double onemd; + double decay; + double amp_bypas; /* AB converted to linear gain */ + double amp_voice; /* AVdb converted to linear gain */ + double par_amp_voice; /* AVpdb converted to linear gain */ + double amp_aspir; /* AP converted to linear gain */ + double amp_frica; /* AF converted to linear gain */ + double amp_breth; /* ATURB converted to linear gain */ + double amp_gain0; /* G0 converted to linear gain */ + int num_samples; /* number of glottal samples */ + double sample_factor; /* multiplication factor for glottal samples */ + short *natural_samples; /* pointer to an array of glottal samples */ + long original_f0; /* original value of f0 not modified by flutter */ + + int fadeout; // set to 64 to cause fadeout over 64 samples + int scale_wav; // depends on the voicing source + +#define N_RSN 20 +#define Rnpc 0 +#define R1c 1 +#define R2c 2 +#define R3c 3 +#define R4c 4 +#define R5c 5 +#define R6c 6 +#define R7c 7 +#define R8c 8 +#define Rnz 9 + +#define Rparallel 10 +#define Rnpp 10 +#define R1p 11 +#define R2p 12 +#define R3p 13 +#define R4p 14 +#define R5p 15 +#define R6p 16 + +#define RGL 17 +#define RLP 18 +#define Rout 19 + + resonator_t rsn[N_RSN]; // internal storage for resonators + resonator_t rsn_next[N_RSN]; + +} klatt_global_t, *klatt_global_ptr; + +/* Structure for Klatt Parameters */ + +#define F_NP 0 // nasal zero formant +#define F1 1 +#define F2 2 +#define F3 3 +#define F4 4 +#define F5 5 +#define F6 6 +#define F_NZ 9 // nasal pole formant + + +typedef struct +{ + long F0hz10; /* Voicing fund freq in Hz */ + long AVdb; /* Amp of voicing in dB, 0 to 70 */ + int Fhz[10]; // formant Hz, F_NZ to F6 to F_NP + int Bhz[10]; + int Ap[10]; /* Amp of parallel formants in dB, 0 to 80 */ + int Bphz[10]; /* Parallel formants bw in Hz, 40 to 1000 */ + + long ASP; /* Amp of aspiration in dB, 0 to 70 */ + long Kopen; /* # of samples in open period, 10 to 65 */ + long Aturb; /* Breathiness in voicing, 0 to 80 */ + long TLTdb; /* Voicing spectral tilt in dB, 0 to 24 */ + long AF; /* Amp of frication in dB, 0 to 80 */ + long Kskew; /* Skewness of alternate periods, 0 to 40 in sample#/2 */ + + long AB; /* Amp of bypass fric. in dB, 0 to 80 */ + long AVpdb; /* Amp of voicing, par in dB, 0 to 70 */ + long Gain0; /* Overall gain, 60 dB is unity, 0 to 60 */ + + long AVdb_tmp; //copy of AVdb, which is changed within parwave() + int Fhz_next[10]; // Fhz for the next chunk, so we can do interpolation of resonator (a,b,c) parameters + int Bhz_next[10]; + } klatt_frame_t, *klatt_frame_ptr; + + + diff --git a/src/readclause.cpp b/src/readclause.cpp index 2e1f1ba6..f1987882 100644 --- a/src/readclause.cpp +++ b/src/readclause.cpp @@ -1186,7 +1186,7 @@ static int attr_prosody_value(int param_type, const wchar_t *pw, int *value_out) pw++; sign = -1; } - value = wcstod(pw,&tail); + value = (float)wcstod(pw,&tail); if(tail == pw) { // failed to find a number, return 100% diff --git a/src/speak_lib.cpp b/src/speak_lib.cpp index f766b7a1..4d3fd53a 100644 --- a/src/speak_lib.cpp +++ b/src/speak_lib.cpp @@ -300,10 +300,10 @@ static void init_path(const char *path) } buf[0] = 0; - RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Speech\\Voices\\Tokens\\eSpeak", 0, KEY_READ, &RegKey); + RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Speech\\Voices\\Tokens\\eSpeak", 0, KEY_READ, &RegKey); size = sizeof(buf); var_type = REG_SZ; - RegQueryValueEx(RegKey, "path", 0, &var_type, buf, &size); + RegQueryValueExA(RegKey, "path", 0, &var_type, buf, &size); sprintf(path_home,"%s\\espeak-data",buf); diff --git a/src/spect.cpp b/src/spect.cpp index 10f99286..e8f48edc 100755 --- a/src/spect.cpp +++ b/src/spect.cpp @@ -137,7 +137,8 @@ int SpectFrame::Import(wxInputStream& stream1) double x; unsigned short *spect_data; - wxTextInputStream stream(stream1); + synthesizer_type = 0; + wxTextInputStream stream(stream1); stream >> time; stream >> pitch; @@ -273,12 +274,13 @@ int SpectFrame::ImportSPC2(wxInputStream& stream, float &time_acc) -int SpectFrame::Load(wxInputStream& stream) -{//======================================== +int SpectFrame::Load(wxInputStream& stream, int synth_type) +{//======================================================== int ix; int x; unsigned short *spect_data; + synthesizer_type = synth_type; wxDataInputStream s(stream); time = s.ReadDouble(); @@ -300,6 +302,14 @@ int SpectFrame::Load(wxInputStream& stream) peaks[ix].pkright = s.Read16(); } + if(synthesizer_type == 1) + { + for(ix=0; ixpeaks,sizeof(peaks)); + memcpy(klatt_param, sf->klatt_param, sizeof(klatt_param)); keyframe = sf->keyframe; } @@ -448,6 +467,9 @@ void SpectFrame::DrawPeaks(wxDC *dc, int offy, int frame_width, int seq_amplitud int y1, y2; double yy; int max_ix; + int height; + int pkright; + int pkwidth; int buf[DRAWPEAKWIDTH*2]; max_ix = int(9000 * scale_x); @@ -459,9 +481,24 @@ void SpectFrame::DrawPeaks(wxDC *dc, int offy, int frame_width, int seq_amplitud if((pk->pkfreq == 0) || (pk->pkheight==0)) continue; + if(synthesizer_type==1) + { + if(peak==0) continue; + + height = pk->pkheight + (64 * 64); + height = (500000/height) * 100; + pkright = pkwidth = pk->pkheight / 16; + } + else + { + height = pk->pkheight; + pkright = pk->pkright; + pkwidth = pk->pkwidth; + } + x1 = (int)(pk->pkfreq*scale_x); - x2 = (int)((pk->pkfreq + pk->pkright)*scale_x); - x3 = (int)((pk->pkfreq - pk->pkwidth)*scale_x); + x2 = (int)((pk->pkfreq + pkright)*scale_x); + x3 = (int)((pk->pkfreq - pkwidth)*scale_x); if(x3 >= DRAWPEAKWIDTH) continue; // whole peak is off the scale @@ -469,7 +506,7 @@ void SpectFrame::DrawPeaks(wxDC *dc, int offy, int frame_width, int seq_amplitud if((width = x2-x1) <= 0) continue; for(ix=0; ixpkheight * pk_shape1[(ix*PEAKSHAPEW)/width]; + buf[x1+ix] += height * pk_shape1[(ix*PEAKSHAPEW)/width]; } if((width = x1-x3) <= 0) continue; @@ -477,7 +514,7 @@ void SpectFrame::DrawPeaks(wxDC *dc, int offy, int frame_width, int seq_amplitud { if(x3+ix >= 0) { - buf[x3+ix] += pk->pkheight * pk_shape1[((width-ix)*PEAKSHAPEW)/width]; + buf[x3+ix] += height * pk_shape1[((width-ix)*PEAKSHAPEW)/width]; } } } @@ -633,3 +670,71 @@ void SpectFrame::Draw(wxDC& dc, int offy, int frame_width, double scalex, double } // end of SpectFrame::Draw + +void SpectFrame::KlattDefaults() +{//============================ + // set default values for Klatt parameters + int pk; + int bw; + int bw3; + + synthesizer_type = 1; + + klatt_param[KLATT_AV] = 59; + klatt_param[KLATT_AVp] = 0; + klatt_param[KLATT_Fric] = 0; + klatt_param[KLATT_FricBP] = 0; + klatt_param[KLATT_Aspr] = 0; + klatt_param[KLATT_Turb] = 0; + klatt_param[KLATT_Skew] = 0; + klatt_param[KLATT_Tilt] = 0; + klatt_param[KLATT_Kopen] = 40; + klatt_param[KLATT_spare1] = 0; + + bw = 60; + if(peaks[1].pkfreq < 400) + bw = 55; + if(peaks[1].pkfreq > 600) + bw = 70; + if(peaks[1].pkfreq > 650) + bw = 80; + if(peaks[1].pkfreq > 750) + bw = 90; + peaks[1].pkwidth = bw; + + bw = 90; + bw3 = 150; + if(peaks[2].pkfreq < 1000) + { + bw = 80; + bw3 = 120; + } + if(peaks[2].pkfreq > 1600) + { + bw = 100; + bw3 = 200; + } + if(peaks[2].pkfreq > 2000) + { + bw = 110; + bw3 = 250; + } + peaks[2].pkwidth = bw; + peaks[3].pkwidth = bw3; + peaks[4].pkwidth = 200; + peaks[5].pkwidth = 200; + peaks[6].pkwidth = 500; + peaks[0].pkfreq = 280; // FNP + peaks[0].pkwidth = 280; // FNZ + + peaks[7].pkfreq = 7800; + peaks[7].pkwidth = 0; + peaks[8].pkfreq = 9000; + peaks[8].pkwidth = 0; + + for(pk=0; pk<=8; pk++) + { + peaks[pk].pkheight = peaks[pk].pkwidth << 6; + peaks[pk].pkright = 0; + } +} diff --git a/src/spect.h b/src/spect.h index a7d4fd5a..8d6eaf8d 100755 --- a/src/spect.h +++ b/src/spect.h @@ -39,8 +39,20 @@ #define T_TIMEFRAME 310 #define T_TIMESEQ 311 +#define T_AV 312 +#define T_AVP 313 +#define T_FRIC 314 +#define T_FRICBP 315 +#define T_ASPR 316 +#define T_TURB 317 +#define T_SKEW 318 +#define T_TILT 319 +#define T_KOPEN 320 + + #define FILEID1_SPECTSEQ 0x43455053 -#define FILEID2_SPECTSEQ 0x51455354 +#define FILEID2_SPECTSEQ 0x51455354 // for eSpeak sequence +#define FILEID2_SPECTSEK 0x4b455354 // for Klatt sequence #define FILEID1_SPC2 0x32435053 // an old format for spectrum files @@ -110,7 +122,7 @@ public: ~SpectFrame(); int Import(wxInputStream &stream); int ImportSPC2(wxInputStream &stream, float &time_acc); - int Load(wxInputStream &stream); + int Load(wxInputStream &stream, int synthesizer_type); int Save(wxOutputStream &stream); void Draw(wxDC &dc, int offy, int frame_width, double scalex, double scaley); @@ -122,6 +134,7 @@ public: void MakeWave(int peaks, PitchEnvelope &pitch, int amplitude, int duration); void MakeHtab(int numh, int *htab, int pitch); double GetRms(int amp); + void KlattDefaults(); int selected; int keyframe; @@ -136,8 +149,11 @@ public: int nx; int markers; int max_y; + int synthesizer_type; // 0=eSpeak, 1=Klatt USHORT *spect; // sqrt of harmonic amplitudes, 1-nx at 'pitch' + short klatt_param[N_KLATTP]; + formant_t formants[N_PEAKS]; // this is just the estimate given by Praat peak_t peaks[N_PEAKS]; @@ -171,7 +187,8 @@ public: float GetKeyedLength(); void SetFrameLengths(); void ConstructVowel(void); - + void SetKlattDefaults(void); + int numframes; int amplitude; int spare; @@ -186,6 +203,8 @@ public: int bass_reduction; int max_x; int max_y; + int synthesizer_type; + private: void Load2(wxInputStream& stream, int import, int n); @@ -262,8 +281,9 @@ class FormantDlg : public wxPanel public: FormantDlg(wxWindow *parent); void ShowFrame(SpectSeq *spectseq, int frame, int pk, int field); - void OnCommand(wxCommandEvent& event); - void OnSpin(wxSpinEvent& event); + void OnCommand(wxCommandEvent& event); + void OnSpin(wxSpinEvent& event); + void HideFields(int synth_type); wxCheckBox *usepitchenv; @@ -275,6 +295,9 @@ class FormantDlg : public wxPanel wxStaticText *t_orig_frame; wxStaticText *t_orig_seq; + wxSpinCtrl *s_klatt[N_KLATTP]; + wxStaticText *t_klatt[N_KLATTP]; + private: wxStaticText *t_lab[10]; wxStaticText *t_labpk[N_PEAKS]; @@ -346,7 +369,7 @@ extern void WavegenInit(int samplerate, int wavemult_fact); extern void WavegenInitPkData(int); // initialise envelope data extern void SetPitch(int length, unsigned char *env, int pitch1, int pitch2); extern void SetSynthHtab(int length_mS, USHORT *ht1, int nh1, float pitch1, USHORT *ht2, int nh2, float pitch2); -extern void MakeWaveFile(); +extern void MakeWaveFile(int synthesis_method); extern void MakeWaveBuf(int length, UCHAR *buf); extern int OpenWaveFile(const char *path, int samplerate); diff --git a/src/spectdisplay.cpp b/src/spectdisplay.cpp index 1a8fd355..8f03fae4 100755 --- a/src/spectdisplay.cpp +++ b/src/spectdisplay.cpp @@ -244,10 +244,19 @@ void SpectDisplay::ReadDialogValues() void SpectDisplay::RefreshDialogValues(int type) //{============================================= { + int ix; + SpectFrame *sf; + + sf = spectseq->frames[sframe]; + spectseq->amplitude = formantdlg->t_amplitude->GetValue(); - spectseq->frames[sframe]->amp_adjust = formantdlg->t_ampframe->GetValue(); - spectseq->frames[sframe]->length_adjust = - formantdlg->t_timeframe->GetValue() - spectseq->GetFrameLength(sframe,0,NULL); + sf->amp_adjust = formantdlg->t_ampframe->GetValue(); + sf->length_adjust = formantdlg->t_timeframe->GetValue() - spectseq->GetFrameLength(sframe,0,NULL); + + for(ix=0; ix<9; ix++) + { + sf->klatt_param[ix] = formantdlg->s_klatt[ix]->GetValue(); + } if(type==0) { @@ -472,7 +481,7 @@ void SpectDisplay::OnMenu(wxCommandEvent& event) int code; wxKeyEvent keyevent; SpectFrame *sf; - static int key[] = {0x1044,0x3044,0x104e,0x1047,0x105a,0x1051,0x3051,WXK_F1,WXK_F2,0x1049,WXK_F10}; + static int key[] = {0x1044,0x3044,0x104e,0x1047,0x105a,0x1051,0x3051,WXK_F1,WXK_F2,0x1049,WXK_F10,0x104b}; id = event.GetId(); @@ -624,13 +633,19 @@ void SpectDisplay::OnKey(wxKeyEvent& event) if(event.ControlDown()) { // CTRL, rotate, make right slope steeper - pk->pkright-= 5; + if(spectseq->synthesizer_type==0) + pk->pkright-= 5; pk->pkwidth += 5; } else { - pk->pkright -= 10; + if(spectseq->synthesizer_type==0) + pk->pkright -= 10; pk->pkwidth -= 10; + if(pk->pkright < 0) + pk->pkright = 0; + if(pk->pkwidth < 0) + pk->pkwidth = 0; } field = 4; display = 1; @@ -640,12 +655,14 @@ void SpectDisplay::OnKey(wxKeyEvent& event) if(event.ControlDown()) { // CTRL: rotate, make left slope steeper - pk->pkright += 5; + if(spectseq->synthesizer_type==0) + pk->pkright += 5; pk->pkwidth -= 5; } else { - pk->pkright += 10; + if(spectseq->synthesizer_type==0) + pk->pkright += 10; pk->pkwidth += 10; } field = 4; @@ -653,19 +670,37 @@ void SpectDisplay::OnKey(wxKeyEvent& event) break; case '<': // width-- - pk->pkright -= 2; + if(spectseq->synthesizer_type==0) + pk->pkright -= 2; pk->pkwidth -= 2; + if(pk->pkwidth < 0) + pk->pkwidth = 0; display = 1; field = 4; break; case '>': // width++ - pk->pkright += 2; + if(spectseq->synthesizer_type==0) + pk->pkright += 2; pk->pkwidth += 2; display = 1; field = 4; break; + case '[': // width-- + pk->pkright -= 1; + if(pk->pkright < 0) + pk->pkright = 0; + display = 1; + field = 4; + break; + + case ']': // width++ + pk->pkright += 1; + display = 1; + field = 4; + break; + case '/': // make left=right i = pk->pkwidth + pk->pkright; pk->pkwidth = pk->pkright = i/2; @@ -708,6 +743,11 @@ void SpectDisplay::OnKey(wxKeyEvent& event) display = 2; break; + case 0x104b: // CTRL-K + spectseq->SetKlattDefaults(); + display = 3; + break; + case 0x104d: // CTRL-M sf->ToggleMarker(1); display = 2; @@ -825,25 +865,28 @@ void SpectDisplay::OnKey(wxKeyEvent& event) sf = spectseq->frames[sframe]; pk = &sf->peaks[pk_num]; - if(pk->pkwidth < 50) pk->pkwidth = 50; // min. width - if(pk->pkright < 50) pk->pkright = 50; + if(spectseq->synthesizer_type==0) + { + if(pk->pkwidth < 50) pk->pkwidth = 50; // min. width + if(pk->pkright < 50) pk->pkright = 50; - // ensure minimum separation between peaks & prevent crossover - if(direction > 0) - { - for(i=pk_num+1; i 0) { - if(sf->peaks[i].pkfreq < sf->peaks[i-1].pkfreq + 100) - sf->peaks[i].pkfreq = sf->peaks[i-1].pkfreq + 100; + for(i=pk_num+1; ipeaks[i].pkfreq < sf->peaks[i-1].pkfreq + 100) + sf->peaks[i].pkfreq = sf->peaks[i-1].pkfreq + 100; + } } - } - else - if(direction < 0) - { - for(i=pk_num-1; i>=0; i--) + else + if(direction < 0) { - if(sf->peaks[i].pkfreq > sf->peaks[i+1].pkfreq - 100) - sf->peaks[i].pkfreq = sf->peaks[i+1].pkfreq - 100; + for(i=pk_num-1; i>=0; i--) + { + if(sf->peaks[i].pkfreq > sf->peaks[i+1].pkfreq - 100) + sf->peaks[i].pkfreq = sf->peaks[i+1].pkfreq - 100; + } } } @@ -1008,6 +1051,7 @@ void InitSpectrumDisplay() menu_spectdisplay->Append(202,_T("Copy Peaks Up SHIFT+CTRL+D")); menu_spectdisplay->Append(204,_T("Grid (toggle) CTRL+G")); menu_spectdisplay->Append(210,_T("Interpolate (percentage) CTRL+I")); + menu_spectdisplay->Append(212,_T("Convert sequence to Klatt format CTRL+K")); menu_spectdisplay->Append(203,_T("Marker (toggle) CTRL+N")); menu_spectdisplay->Append(206,_T("Show Interpolation CTRL+Q")); menu_spectdisplay->Append(207,_T("Hide Interpolation CTRL+SHIFT+Q")); diff --git a/src/spectseq.cpp b/src/spectseq.cpp index f92b4b8e..449df1ff 100755 --- a/src/spectseq.cpp +++ b/src/spectseq.cpp @@ -34,8 +34,12 @@ #define MAX_HARMONIC 400 // 400 * 50Hz = 20 kHz, more than enough -int SpeakNextClause(FILE *f_text, const void *text_in, int control); -extern void SetSynth(int length, int modn, frame_t *fr1, frame_t *fr2); +#define KLATT_TEST + +extern void SetSynth_Klatt(int length, int modn, frame_t *fr1, frame_t *fr2, voice_t *v, int control); +extern int Wavegen_Klatt(int resume); + +extern void SetSynth(int length, int modn, frame_t *fr1, frame_t *fr2, voice_t *v); extern int Wavegen(); extern void CloseWaveFile2(); extern FILE *f_wave; @@ -100,18 +104,27 @@ static void PeaksZero(peak_t *sp, peak_t *zero) -void MakeWaveFile() -{//================ +void MakeWaveFile(int synthesis_method) +{//==================================== int result=1; + int resume=0; unsigned char wav_outbuf[1024]; while(result != 0) { out_ptr = out_start = wav_outbuf; out_end = &wav_outbuf[sizeof(wav_outbuf)]; - result = Wavegen(); + +#ifdef KLATT_TEST + if(synthesis_method == 1) + result = Wavegen_Klatt(resume); + else +#endif + result = Wavegen(); + if(f_wave != NULL) fwrite(wav_outbuf, 1, out_ptr - wav_outbuf, f_wave); + resume=1; } } // end of MakeWaveFile @@ -135,6 +148,7 @@ SpectSeq::SpectSeq(int n) max_x = 3000; max_y = 1; + synthesizer_type = 0; } SpectSeq::~SpectSeq() @@ -378,7 +392,7 @@ void SpectSeq::Load2(wxInputStream& stream, int import, int n) } else { - if(frame->Load(stream) != 0) break; + if(frame->Load(stream, synthesizer_type) != 0) break; } frames[numframes++] = frame; @@ -493,8 +507,19 @@ int SpectSeq::Load(wxInputStream & stream) stream.SeekI(4); return(ImportSPC2(stream)); } - if(id1 != FILEID1_SPECTSEQ || id2 != FILEID2_SPECTSEQ) + else + if((id1 == FILEID1_SPECTSEQ) && (id2 == FILEID2_SPECTSEQ)) { + synthesizer_type = 0; // eSpeak formants + } + else + if((id1 == FILEID1_SPECTSEQ) && (id2 == FILEID2_SPECTSEK)) + { + synthesizer_type = 1; // formants for Klatt synthesizer + } + else + { + // Praat analysis data stream.SeekI(0); return(Import(stream)); } @@ -530,7 +555,10 @@ int SpectSeq::Save(wxOutputStream &stream, int selection) wxDataOutputStream s(stream); s.Write32(FILEID1_SPECTSEQ); - s.Write32(FILEID2_SPECTSEQ); + if(synthesizer_type == 1) + s.Write32(FILEID2_SPECTSEK); + else + s.Write32(FILEID2_SPECTSEQ); s.WriteString(name); s.Write16(count); @@ -549,6 +577,23 @@ int SpectSeq::Save(wxOutputStream &stream, int selection) +void SpectSeq::SetKlattDefaults(void) +{//================================== + int ix; + + synthesizer_type = 1; + + for(ix=0; ixkeyframe) + { + frames[ix]->KlattDefaults(); + } + frames[ix]->synthesizer_type = 1; + } +} + + void SpectSeq::ConstructVowel(void) {//================================ @@ -785,6 +830,7 @@ void SpectSeq::CopyDown(int frame, int direction) frames[frame]->peaks[pk].pkwidth = frames[f1]->peaks[pk].pkwidth; frames[frame]->peaks[pk].pkright = frames[f1]->peaks[pk].pkright; } + memcpy(frames[frame]->klatt_param, frames[f1]->klatt_param, sizeof(frames[frame]->klatt_param)); break; } } @@ -878,46 +924,88 @@ void SpectSeq::ApplyAmp_adjust(SpectFrame *sp, peak_t *peaks) int y; memcpy(peaks,sp->peaks,sizeof(*peaks)*N_PEAKS); - for(ix=0; ixamp_adjust * amplitude; - peaks[ix].pkheight = y / 10000; + for(ix=0; ixamp_adjust * amplitude; + peaks[ix].pkheight = y / 10000; + } } } // end of ApplyAmp_adjust -void PeaksToFrame(peak_t *pks, frame_t *fr) -{//======================================== +void PeaksToFrame(SpectFrame *sp1, peak_t *pks, frame_t *fr) +{//========================================================= int ix; - int x; + int x, x2; for(ix=0; ixffreq[ix] = pks[ix].pkfreq; - fr->fheight[ix] = pks[ix].pkheight >> 6; + + if(sp1->synthesizer_type==0) + { + x = pks[ix].pkheight >> 6; + } + else + { + x = pks[ix].pkheight >> 7; + fr->fwidth6 = pks[6].pkwidth >> 1; + fr->fright6 = pks[6].pkright; + } + + if(x > 255) + x = 255; + fr->fheight[ix] = x; + if(ix < 6) { - if((x = (pks[ix].pkwidth >> 2)) > 255) + x = pks[ix].pkwidth/2; + x2 = pks[ix].pkright; + + if(sp1->synthesizer_type == 0) + { + x /= 2; + x2 /= 4; + } + if(x > 255) x = 255; fr->fwidth[ix] = x; - if((x = (pks[ix].pkright >> 2)) > 255) - x = 255; - fr->fright[ix] = x; + if(x2 > 255) + x2 = 255; + fr->fright[ix] = x2; } } + + for(ix=0; ixklattp[ix] = sp1->klatt_param[ix]; + } } -static void SetSynth_mS(int length_mS, peak_t *sp1, peak_t *sp2) -{//============================================================= +static void SetSynth_mS(int length_mS, SpectFrame *sp1, SpectFrame *sp2, peak_t *pks1, peak_t *pks2, int control) +{//============================================================================================================== static frame_t fr1, fr2; - PeaksToFrame(sp1,&fr1); - PeaksToFrame(sp2,&fr2); + PeaksToFrame(sp1,pks1,&fr1); + PeaksToFrame(sp2,pks2,&fr2); + +#ifdef KLATT_TEST + if(sp1->synthesizer_type == 1) + { + SetSynth_Klatt((length_mS * samplerate) / 1000, 0, &fr1, &fr2, voice, control); // convert mS to samples + } + else +#endif + { + SetSynth((length_mS * samplerate) / 1000, 0, &fr1, &fr2, voice); // convert mS to samples + } +}; - SetSynth((length_mS * samplerate) / 1000, 0, &fr1, &fr2); // convert mS to samples -} @@ -939,6 +1027,7 @@ void SpectSeq::MakeWave(int start, int end, PitchEnvelope &pitch) peak_t peaks1[N_PEAKS]; peak_t peaks2[N_PEAKS]; +KlattInit(); SpeakNextClause(NULL,NULL,2); // stop speaking file if(numframes==0) return; @@ -1007,23 +1096,39 @@ void SpectSeq::MakeWave(int start, int end, PitchEnvelope &pitch) { ApplyAmp_adjust(sp1,peaks1); ApplyAmp_adjust(sp2,peaks2); + if(first) { - PeaksZero(peaks1,peaks0); // fade in - SetSynth_mS(20,peaks0,peaks1); - MakeWaveFile(); + if(synthesizer_type == 1) + { + memcpy(peaks0,peaks1,sizeof(peaks0)); + } + else + { + PeaksZero(peaks1,peaks0); // fade in + } + SetSynth_mS(20,sp1,sp1,peaks0,peaks1,0); + MakeWaveFile(synthesizer_type); first=0; } length = int(sp1->length * lfactor); - SetSynth_mS(length,peaks1,peaks2); - MakeWaveFile(); + SetSynth_mS(length,sp1,sp2,peaks1,peaks2,0); + MakeWaveFile(synthesizer_type); } } } - PeaksZero(peaks2,peaks0); // fade out - SetSynth_mS(30,peaks2,peaks0); - MakeWaveFile(); + + if(synthesizer_type == 1) + { + memcpy(peaks0,peaks2,sizeof(peaks0)); + } + else + { + PeaksZero(peaks2,peaks0); // fade out + } + SetSynth_mS(30,sp2,sp2,peaks2,peaks0,2); + MakeWaveFile(synthesizer_type); CloseWaveFile2(); PlayWavFile(fname_speech); @@ -1054,6 +1159,7 @@ void SpectFrame::MakeWave(int control, PitchEnvelope &pitche, int amplitude, int char *fname_speech; // USHORT htab0[600]; +KlattInit(); SpeakNextClause(NULL,NULL,2); // stop speaking file length = duration; @@ -1069,23 +1175,31 @@ void SpectFrame::MakeWave(int control, PitchEnvelope &pitche, int amplitude, int if(OpenWaveFile2(fname_speech) != 0) return; + if(control==0) { memcpy(peaks1,peaks,sizeof(peaks1)); - for(ix=0; ix // conditional compilation options +#define INCLUDE_KLATT #if defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN #define ARCH_BIG diff --git a/src/synth_mbrola.cpp b/src/synth_mbrola.cpp index 708b3072..d5e87d67 100755 --- a/src/synth_mbrola.cpp +++ b/src/synth_mbrola.cpp @@ -77,7 +77,7 @@ BOOL load_MBR() if(hinstDllMBR != NULL) return TRUE; // already loaded - if (!(hinstDllMBR=LoadLibrary("mbrola.dll"))) + if (!(hinstDllMBR=LoadLibraryA("mbrola.dll"))) return FALSE; init_MBR =(PROCIC) GetProcAddress(hinstDllMBR,"init_MBR"); write_MBR =(PROCIC) GetProcAddress(hinstDllMBR,"write_MBR"); @@ -179,7 +179,7 @@ espeak_ERROR LoadMbrolaTable(const char *mbrola_voice, const char *phtrans, int #ifdef USE_MBROLA_LIB #ifdef PLATFORM_WINDOWS - setVolumeRatio_MBR((float)(mbrola_control & 0xff) /16.0); + setVolumeRatio_MBR((float)(mbrola_control & 0xff) /16.0f); #else mbrolib_get_parameter(mb_handle,&m_parameters); m_parameters.ignore_error = 1; diff --git a/src/synthdata.cpp b/src/synthdata.cpp index fbc4710d..55e2efdd 100755 --- a/src/synthdata.cpp +++ b/src/synthdata.cpp @@ -35,7 +35,7 @@ #include "translate.h" #include "wave.h" -const char *version_string = "1.39.26 15.Nov.08"; +const char *version_string = "1.39.28 22.Nov.08"; const int version_phdata = 0x013900; int option_device_number = -1; @@ -375,9 +375,10 @@ frameref_t *LookupSpect(PHONEME_TAB *this_ph, PHONEME_TAB *prev_ph, PHONEME_TAB int length1; int length_std; int length_factor; - SPECT_SEQ *seq; - SPECT_SEQ *seq2; + SPECT_SEQ *seq, *seq2; + SPECT_SEQK *seqk, *seqk2; PHONEME_TAB *next2_ph; + frame_t *frame; static frameref_t frames_buf[N_SEQ_FRAMES]; PHONEME_TAB *other_ph; @@ -389,6 +390,7 @@ frameref_t *LookupSpect(PHONEME_TAB *this_ph, PHONEME_TAB *prev_ph, PHONEME_TAB if((ix = LookupSound(this_ph,other_ph,which,match_level,0)) < 4) return(NULL); seq = (SPECT_SEQ *)(&spects_data[ix]); + seqk = (SPECT_SEQK *)seq; nf = seq->n_frames; @@ -397,15 +399,20 @@ frameref_t *LookupSpect(PHONEME_TAB *this_ph, PHONEME_TAB *prev_ph, PHONEME_TAB seq_break = 0; length1 = 0; + for(ix=0; ixframe[ix]; - frames_buf[ix].frflags = seq->frame[ix].frflags; - frames_buf[ix].length = seq->frame[ix].length; - if(seq->frame[ix].frflags & FRFLAG_VOWEL_CENTRE) + if(seq->frame[0].frflags & FRFLAG_KLATT) + frame = &seqk->frame[ix]; + else + frame = (frame_t *)&seq->frame[ix]; + frames_buf[ix].frame = frame; + frames_buf[ix].frflags = frame->frflags; + frames_buf[ix].length = frame->length; + if(frame->frflags & FRFLAG_VOWEL_CENTRE) seq_break = ix; } - + frames = &frames_buf[0]; if(seq_break > 0) { @@ -462,14 +469,23 @@ frameref_t *LookupSpect(PHONEME_TAB *this_ph, PHONEME_TAB *prev_ph, PHONEME_TAB // a secondary reference has been returned, which is not a wavefile // add these spectra to the main sequence seq2 = (SPECT_SEQ *)(&spects_data[wavefile_ix]); + seqk2 = (SPECT_SEQK *)seq2; // first frame of the addition just sets the length of the last frame of the main seq nf--; for(ix=0; ixn_frames; ix++) { - frames[nf].length = seq2->frame[ix].length; + if(seq2->frame[0].frflags & FRFLAG_KLATT) + frame = &seqk2->frame[ix]; + else + frame = (frame_t *)&seq2->frame[ix]; + + frames[nf].length = frame->length; if(ix > 0) - frames[nf].frame = &seq2->frame[ix]; + { + frames[nf].frame = frame; + frames[nf].frflags = frame->frflags; + } nf++; } wavefile_ix = 0; diff --git a/src/synthesize.cpp b/src/synthesize.cpp index 88ddab07..e8e225bc 100755 --- a/src/synthesize.cpp +++ b/src/synthesize.cpp @@ -354,6 +354,15 @@ static void set_frame_rms(frame_t *fr, int new_rms) 849,851,853,856,858,861,863,865,868,870,872,875,877,879,882,884, 886,889,891,893,896,898,900,902}; + if(fr->frflags & FRFLAG_KLATT) + { + if(new_rms == -1) + { + fr->klattp[KLATT_AV] = 50; + } + return; + } + if(fr->rms == 0) return; // check for divide by zero x = (new_rms * 64)/fr->rms; if(x >= 200) x = 199; @@ -375,6 +384,9 @@ static void formants_reduce_hf(frame_t *fr, int level) int ix; int x; + if(fr->frflags & FRFLAG_KLATT) + return; + for(ix=2; ixfheight[ix] * level; @@ -540,6 +552,10 @@ static short vcolouring[N_VCOLOUR][5] = { next_rms = seq[1].frame->rms; +if(fr->frflags & FRFLAG_KLATT) +{ + fr->klattp[KLATT_AV] = 53; // reduce the amplituide of the start of a vowel +} if(f2 != 0) { if(rms & 0x20) @@ -661,6 +677,9 @@ static void SmoothSpect(void) q = wcmdq[syllable_centre]; frame_centre = (frame_t *)q[2]; +//if(frame_centre->frflags & FRFLAG_KLATT) +// return; // TESTING + // backwards ix = syllable_centre -1; frame = frame2 = frame_centre; @@ -672,7 +691,7 @@ static void SmoothSpect(void) if(q[0] == WCMD_PAUSE || q[0] == WCMD_WAVE) break; - if(q[0] == WCMD_SPECT || q[0] == WCMD_SPECT2) + if(q[0] <= WCMD_SPECT2) { len = q[1] & 0xffff; @@ -759,7 +778,7 @@ static void SmoothSpect(void) if(q[0] == WCMD_PAUSE || q[0] == WCMD_WAVE) break; - if(q[0] == WCMD_SPECT || q[0] == WCMD_SPECT2) + if(q[0] <= WCMD_SPECT2) { len = q[1] & 0xffff; @@ -834,7 +853,7 @@ static void SmoothSpect(void) } syllable_start = syllable_end; -} +} // end of SmoothSpect static void StartSyllable(void) @@ -891,22 +910,29 @@ if(which==1) if(frames == NULL) return(0); // not found + frame1 = frames[0].frame; + frame1_length = frames[0].length; + if(frame1->frflags & FRFLAG_KLATT) + wcmd_spect = WCMD_KLATT; + if(wavefile_ix == 0) { if(wave_flag) { // cancel any wavefile that was playing previously wcmd_spect = WCMD_SPECT2; + if(frame1->frflags & FRFLAG_KLATT) + wcmd_spect = WCMD_KLATT2; wave_flag = 0; } else { wcmd_spect = WCMD_SPECT; + if(frame1->frflags & FRFLAG_KLATT) + wcmd_spect = WCMD_KLATT; } } - frame1 = frames[0].frame; - frame1_length = frames[0].length; if(last_frame != NULL) { if(((last_frame->length < 2) || (last_frame->frflags & FRFLAG_VOWEL_CENTRE)) diff --git a/src/synthesize.h b/src/synthesize.h index b9e02d15..87c5b137 100755 --- a/src/synthesize.h +++ b/src/synthesize.h @@ -22,11 +22,13 @@ #define MAX_HARMONIC 400 // 400 * 50Hz = 20 kHz, more than enough #define N_SEQ_FRAMES 25 // max frames in a spectrum sequence (real max is ablut 8) +#define STEPSIZE 64 // 2.9mS at 22 kHz sample rate #define PITCHfall 0 #define PITCHrise 1 // flags set for frames within a spectrum sequence +#define FRFLAG_KLATT 0x01 // this frame includes extra data for Klatt synthesizer #define FRFLAG_VOWEL_CENTRE 0x02 // centre point of vowel #define FRFLAG_LEN_MOD 0x04 // reduce effect of length adjustment #define FRFLAG_BREAK_LF 0x08 // but keep f3 upwards @@ -75,6 +77,18 @@ typedef struct { short pkright; } peak_t; +#define N_KLATTP 10 // this affects the phoneme data file format +#define KLATT_AV 0 +#define KLATT_Kopen 1 +#define KLATT_Skew 2 +#define KLATT_Tilt 3 +#define KLATT_Turb 4 +#define KLATT_Aspr 5 +#define KLATT_AVp 6 // this is after the parameters which can be change by the Voice +#define KLATT_Fric 7 +#define KLATT_FricBP 8 +#define KLATT_spare1 9 + typedef struct { short frflags; unsigned char length; @@ -83,8 +97,20 @@ typedef struct { unsigned char fheight[9]; unsigned char fwidth[6]; // width/4 unsigned char fright[6]; // width/4 + unsigned char fwidth6, fright6; + unsigned char klattp[N_KLATTP]; } frame_t; +typedef struct { + short frflags; + unsigned char length; + unsigned char rms; + short ffreq[9]; + unsigned char fheight[9]; + unsigned char fwidth[6]; // width/4 + unsigned char fright[6]; // width/4 +} frame_t2; // the original, without Klatt additions, used for file "phondata" + // formant data used by wavegen @@ -103,6 +129,26 @@ typedef struct { DOUBLEX right_inc; } wavegen_peaks_t; +typedef struct { +unsigned char *pitch_env; +int pitch; // pitch Hz*256 +int pitch_ix; // index into pitch envelope (*256) +int pitch_inc; // increment to pitch_ix +int pitch_base; // Hz*256 low, before modified by envelope +int pitch_range; // Hz*256 range of envelope + +unsigned char *mix_wavefile; // wave file to be added to synthesis +int n_mix_wavefile; // length in bytes +int mix_wave_scale; // 0=2 byte samples +int mix_wave_amp; +int mix_wavefile_ix; + +int amplitude; +int amplitude_v; +int prev_was_synth; // previous sound was synthesized (not a played wave or pause) +} WGEN_DATA; + + typedef struct { double a; double b; @@ -113,11 +159,19 @@ typedef struct { typedef struct { - short length; + short length_total; // not used + unsigned char n_frames; + unsigned char flags; + frame_t2 frame[N_SEQ_FRAMES]; // max. frames in a spectrum sequence +} SPECT_SEQ; // sequence of espeak formant frames + +typedef struct { + short length_total; // not used unsigned char n_frames; unsigned char flags; frame_t frame[N_SEQ_FRAMES]; // max. frames in a spectrum sequence -} SPECT_SEQ; +} SPECT_SEQK; // sequence of klatt formants frames + typedef struct { short length; @@ -176,16 +230,18 @@ extern unsigned char env_frise[128]; extern unsigned char pitch_adjust_tab[MAX_PITCH_VALUE+1]; // queue of commands for wavegen -#define WCMD_AMPLITUDE 1 -#define WCMD_PITCH 2 +#define WCMD_KLATT 1 +#define WCMD_KLATT2 2 #define WCMD_SPECT 3 #define WCMD_SPECT2 4 #define WCMD_PAUSE 5 #define WCMD_WAVE 6 #define WCMD_WAVE2 7 -#define WCMD_MARKER 8 -#define WCMD_VOICE 9 -#define WCMD_EMBEDDED 10 +#define WCMD_AMPLITUDE 8 +#define WCMD_PITCH 9 +#define WCMD_MARKER 10 +#define WCMD_VOICE 11 +#define WCMD_EMBEDDED 12 #define N_WCMDQ 160 @@ -278,3 +334,6 @@ int PauseLength(int pause, int control); int LookupPhonemeTable(const char *name); void InitBreath(void); + +void KlattInit(); +int Wavegen_Klatt2(int length, int modulation, int resume, frame_t *fr1, frame_t *fr2); diff --git a/src/tr_languages.cpp b/src/tr_languages.cpp index 85f0a069..843aeb6b 100644 --- a/src/tr_languages.cpp +++ b/src/tr_languages.cpp @@ -515,6 +515,7 @@ SetLengthMods(tr,3); // all equal tr->langopts.param[LOPT_SONORANT_MIN] = 130; // limit the shortening of sonorants before short vowels tr->langopts.param[LOPT_REDUCE] = 1; // reduce vowels even if phonemes are specified in it_list tr->langopts.numbers = 0x2709 + NUM_ROMAN; + tr->langopts.accents = 2; // Say "Capital" after the letter. } break; @@ -769,8 +770,9 @@ SetLengthMods(tr,3); // all equal static const unsigned char stress_amps_sq[8] = {17,12, 17,17, 20,20, 24,22 }; tr = new Translator(); SetupTranslator(tr,stress_lengths_sq,stress_amps_sq); - tr->langopts.stress_flags = 0x4; + tr->langopts.stress_flags = 0x4 + 0x10; SetLetterVowel(tr,'y'); + tr->langopts.numbers = 0x69 + 0x8000; } break; diff --git a/src/translate.cpp b/src/translate.cpp index 19a54eb8..0c22c008 100755 --- a/src/translate.cpp +++ b/src/translate.cpp @@ -1747,7 +1747,11 @@ int Translator::TranslateWord2(char *word, WORD_TAB *wtab, int pre_pause, int ne first_phoneme = 0; } } - plist2->sourceix = source_ix; // ???? + // don't set new-word if there is a hyphen before it + if((word_flags & FLAG_HYPHEN) == 0) + { + plist2->sourceix = source_ix; + } end_stressed_vowel = 0; if((stress >= 4) && (phoneme_tab[ph_list2[n_ph_list2-1].phcode]->type == phVOWEL)) diff --git a/src/translate.h b/src/translate.h index ff12b149..8a8f79a9 100755 --- a/src/translate.h +++ b/src/translate.h @@ -29,7 +29,7 @@ #define N_RULE_GROUP2 120 // max num of two-letter rule chains #define N_HASH_DICT 1024 #define N_CHARSETS 20 -#define N_LETTER_GROUPS 25 +#define N_LETTER_GROUPS 26 /* dictionary flags, word 1 */ diff --git a/src/transldlg.cpp b/src/transldlg.cpp index 76162579..679444b4 100755 --- a/src/transldlg.cpp +++ b/src/transldlg.cpp @@ -249,6 +249,7 @@ void MakeWave2(PHONEME_LIST *p, int n_phonemes) char *fname_speech; int n_ph; + KlattInit(); n_ph = n_phonemes; fname_speech = WavFileName(); OpenWaveFile2(fname_speech); @@ -275,9 +276,9 @@ TranslDlg::TranslDlg(wxWindow *parent) : wxPanel(parent) {//===================================================== t_source = new wxTextCtrl(this,T_SOURCE,_T(""),wxPoint(0,4), - wxSize(200,250),wxTE_MULTILINE); + wxSize(204,250),wxTE_MULTILINE); t_phonetic = new wxTextCtrl(this,T_PHONETIC,_T(""),wxPoint(0,262), - wxSize(200,350),wxTE_MULTILINE); + wxSize(204,350),wxTE_MULTILINE); t_translate = new wxButton(this,T_TRANSLATE,_T("Translate"),wxPoint(4,620)); t_translate = new wxButton(this,T_RULES,_T("Show Rules"),wxPoint(4,652)); diff --git a/src/voice.h b/src/voice.h index de6da774..be0c82eb 100644 --- a/src/voice.h +++ b/src/voice.h @@ -40,6 +40,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 klatt[8]; // parameters used by Wavegen short freq[N_PEAKS]; // 100% = 256 @@ -68,7 +69,7 @@ extern USHORT voice_pcnt[N_PEAKS+1][3]; extern voice_t *voice; -extern int tone_points[10]; +extern int tone_points[12]; const char *SelectVoice(espeak_VOICE *voice_select); espeak_VOICE *SelectVoiceByName(espeak_VOICE **voices, const char *name); diff --git a/src/voices.cpp b/src/voices.cpp index fa001672..8ef7d5af 100755 --- a/src/voices.cpp +++ b/src/voices.cpp @@ -49,8 +49,8 @@ MNEM_TAB genders [] = { {"female", 2}, {NULL, 0 }}; -//int tone_points[10] = {250,140, 1200,110, -1,0, -1,0, -1,0}; -int tone_points[10] = {600,170, 1200,135, 2000,110, 3000,110, -1,0}; +int tone_points[12] = {600,170, 1200,135, 2000,110, 3000,110, -1,0}; +//int tone_points[12] = {250,200, 400,170, 600,170, 1200,135, 2000,110, -1,0}; // limit the rate of change for each formant number //static int formant_rate_22050[9] = {50, 104, 165, 230, 220, 220, 220, 220, 220}; // values for 22kHz sample rate @@ -101,11 +101,13 @@ espeak_VOICE voice_selected; #define V_NUMBERS 25 #define V_OPTION 26 -#define V_MBROLA 27 +#define V_MBROLA 27 +#define V_KLATT 28 // these need a phoneme table to have been specified -#define V_REPLACE 28 -#define V_CONSONANTS 29 +#define V_REPLACE 29 +#define V_CONSONANTS 30 + typedef struct { @@ -144,6 +146,7 @@ static keywtab_t keyword_tab[] = { {"option", V_OPTION}, {"mbrola", V_MBROLA}, {"consonants", V_CONSONANTS}, + {"klatt", V_KLATT}, // these just set a value in langopts.param[] {"l_dieresis", 0x100+LOPT_DIERESES}, @@ -195,7 +198,7 @@ void SetToneAdjust(voice_t *voice, int *tone_pts) int height2; double rate; - for(pt=0; pt<10; pt+=2) + for(pt=0; pt<12; pt+=2) { if(tone_pts[pt] == -1) { @@ -225,15 +228,16 @@ void SetToneAdjust(voice_t *voice, int *tone_pts) void ReadTonePoints(char *string, int *tone_pts) {//============================================= -// tone_pts[] is int[10] +// tone_pts[] is int[12] int ix; - for(ix=0; ix<10; ix++) + for(ix=0; ix<12; ix++) tone_pts[ix] = -1; - sscanf(string,"%d %d %d %d %d %d %d %d", + sscanf(string,"%d %d %d %d %d %d %d %d %d %d", &tone_pts[0],&tone_pts[1],&tone_pts[2],&tone_pts[3], - &tone_pts[4],&tone_pts[5],&tone_pts[6],&tone_pts[7]); + &tone_pts[4],&tone_pts[5],&tone_pts[6],&tone_pts[7], + &tone_pts[8],&tone_pts[9]); } @@ -369,10 +373,11 @@ void VoiceReset(int tone_only) voice->echo_amp = 0; voice->flutter = 64; voice->n_harmonic_peaks = 5; - voice->peak_shape = 1; + voice->peak_shape = 0; voice->voicing = 64; voice->consonant_amp = 100; voice->consonant_ampv = 100; + memset(voice->klatt,0,sizeof(voice->klatt)); #ifdef PLATFORM_RISCOS voice->roughness = 1; @@ -864,6 +869,11 @@ voice_t *LoadVoice(const char *vname, int control) } break; + case V_KLATT: + Read8Numbers(p,voice->klatt); + voice->klatt[KLATT_Kopen] -= 40; + break; + default: if((key & 0xff00) == 0x100) { @@ -1493,13 +1503,12 @@ void GetVoices(const char *path) } #else #ifdef PLATFORM_WINDOWS - WIN32_FIND_DATA FindFileData; + WIN32_FIND_DATAA FindFileData; HANDLE hFind = INVALID_HANDLE_VALUE; - DWORD dwError; #undef UNICODE // we need FindFirstFileA() which takes an 8-bit c-string sprintf(fname,"%s\\*",path); - hFind = FindFirstFile(fname, &FindFileData); + hFind = FindFirstFileA(fname, &FindFileData); if(hFind == INVALID_HANDLE_VALUE) return; @@ -1529,7 +1538,7 @@ void GetVoices(const char *path) voices_list[n_voices_list++] = voice_data; } } - } while(FindNextFile(hFind, &FindFileData) != 0); + } while(FindNextFileA(hFind, &FindFileData) != 0); FindClose(hFind); #else diff --git a/src/vowelchart.cpp b/src/vowelchart.cpp index f376dd80..9298b347 100644 --- a/src/vowelchart.cpp +++ b/src/vowelchart.cpp @@ -510,6 +510,7 @@ void MakeVowelLists(void) PHONEME_TAB *ph; FILE *f; SPECT_SEQ *seq; + SPECT_SEQK *seqk; frame_t *frame; int match_level; char dirname[sizeof(path_source)+20]; @@ -547,10 +548,20 @@ void MakeVowelLists(void) continue; seq = (SPECT_SEQ *)(&spects_data[ix]); - frame = &seq->frame[1]; + seqk = (SPECT_SEQK *)seq; + + if(seq->frame[0].frflags & FRFLAG_KLATT) + frame = &seqk->frame[1]; + else + frame = (frame_t *)&seq->frame[1]; + fprintf(f,"%s\t %3d %4d %4d",WordToString(ph->mnemonic), frame->ffreq[1],frame->ffreq[2],frame->ffreq[3]); - frame = &seq->frame[seq->n_frames-1]; + + if(seq->frame[0].frflags & FRFLAG_KLATT) + frame = &seqk->frame[seqk->n_frames-1]; + else + frame = (frame_t *)&seq->frame[seq->n_frames-1]; fprintf(f," %3d %4d %4d\n",frame->ffreq[1],frame->ffreq[2],frame->ffreq[3]); } fclose(f); diff --git a/src/wavegen.cpp b/src/wavegen.cpp index 814a0969..1e9a41e4 100755 --- a/src/wavegen.cpp +++ b/src/wavegen.cpp @@ -34,6 +34,8 @@ #include "synthesize.h" #include "voice.h" +//#undef INCLUDE_KLATT + #ifdef USE_PORTAUDIO #include "portaudio.h" #undef USE_PORTAUDIO @@ -51,10 +53,9 @@ #define PI 3.1415927 #define PI2 6.283185307 -#define STEPSIZE 64 // 2.9mS at 22 kHz sample rate #define N_WAV_BUF 10 -static voice_t *wvoice; +voice_t *wvoice; FILE *f_log = NULL; int option_waveout = 0; @@ -98,24 +99,13 @@ static int hspect[2][MAX_HARMONIC]; // 2 copies, we interpolate between static int max_hval=0; static int nsamples=0; // number to do -static int amplitude = 32; -static int amplitude_v = 0; static int modulation_type = 0; static int glottal_flag = 0; static int glottal_reduce = 0; -static unsigned char *mix_wavefile = NULL; // wave file to be added to synthesis -static int n_mix_wavefile = 0; // length in bytes -static int mix_wave_scale = 0; // 0=2 byte samples -static int mix_wave_amp = 32; -static int mix_wavefile_ix = 0; -static int pitch; // pitch Hz*256 -static int pitch_ix; // index into pitch envelope (*256) -static int pitch_inc; // increment to pitch_ix -static unsigned char *pitch_env=NULL; -static int pitch_base; // Hz*256 low, before modified by envelope -static int pitch_range; // Hz*256 range of envelope +WGEN_DATA wdata; + static int amp_ix; static int amp_inc; static unsigned char *amplitude_env = NULL; @@ -385,8 +375,8 @@ static void WcmdqIncHead() // data points from which to make the presets for pk_shape1 and pk_shape2 #define PEAKSHAPEW 256 static const float pk_shape_x[2][8] = { - {0,-0.6, 0.0, 0.6, 1.4, 2.5, 4.5, 5.5}, - {0,-0.6, 0.0, 0.6, 1.4, 2.0, 4.5, 5.5 }}; + {0,-0.6f, 0.0f, 0.6f, 1.4f, 2.5f, 4.5f, 5.5f}, + {0,-0.6f, 0.0f, 0.6f, 1.4f, 2.0f, 4.5f, 5.5f }}; static const float pk_shape_y[2][8] = { {0, 67, 81, 67, 31, 14, 0, -6} , {0, 77, 81, 77, 31, 7, 0, -6 }}; @@ -737,6 +727,7 @@ void WavegenInit(int rate, int wavemult_fact) if(wavemult_fact == 0) wavemult_fact=60; // default + wvoice = NULL; samplerate = samplerate_native = rate; PHASE_INC_FACTOR = 0x8000000 / samplerate; // assumes pitch is Hz*32 Flutter_inc = (64 * samplerate)/rate; @@ -745,6 +736,9 @@ void WavegenInit(int rate, int wavemult_fact) wavephase = 0x7fffffff; max_hval = 0; + wdata.amplitude = 32; + wdata.prev_was_synth = 0; + for(ix=0; ix>8) > 127) ix = 127; - x = pitch_env[ix] * pitch_range; - pitch = (x>>8) + pitch_base; + wdata.pitch_ix += wdata.pitch_inc; + if((ix = wdata.pitch_ix>>8) > 127) ix = 127; + x = wdata.pitch_env[ix] * wdata.pitch_range; + wdata.pitch = (x>>8) + wdata.pitch_base; amp_ix += amp_inc; @@ -973,9 +978,9 @@ static void AdvanceParameters() Flutter_ix = 0; x = ((int)(Flutter_tab[Flutter_ix >> 6])-0x80) * flutter_amp; Flutter_ix += Flutter_inc; - pitch += x; - if(pitch < 102400) - pitch = 102400; // min pitch, 25 Hz (25 << 12) + wdata.pitch += x; + if(wdata.pitch < 102400) + wdata.pitch = 102400; // min pitch, 25 Hz (25 << 12) if(samplecount == samplecount_start) return; @@ -1159,26 +1164,26 @@ int Wavegen() { hswitch = 0; harmspect = hspect[0]; - maxh2 = PeaksToHarmspect(peaks,pitch<<4,hspect[0],0); + maxh2 = PeaksToHarmspect(peaks, wdata.pitch<<4, hspect[0], 0); // adjust amplitude to compensate for fewer harmonics at higher pitch - amplitude2 = (amplitude * pitch)/(100 << 11); + amplitude2 = (wdata.amplitude * wdata.pitch)/(100 << 11); // switch sign of harmonics above about 900Hz, to reduce max peak amplitude - h_switch_sign = 890 / (pitch >> 12); + h_switch_sign = 890 / (wdata.pitch >> 12); } else AdvanceParameters(); // pitch is Hz<<12 - phaseinc = (pitch>>7) * PHASE_INC_FACTOR; - cycle_samples = samplerate/(pitch >> 12); // sr/(pitch*2) - hf_factor = pitch >> 11; + phaseinc = (wdata.pitch>>7) * PHASE_INC_FACTOR; + cycle_samples = samplerate/(wdata.pitch >> 12); // sr/(pitch*2) + hf_factor = wdata.pitch >> 11; maxh = maxh2; harmspect = hspect[hswitch]; hswitch ^= 1; - maxh2 = PeaksToHarmspect(peaks,pitch<<4,hspect[hswitch],1); + maxh2 = PeaksToHarmspect(peaks, wdata.pitch<<4, hspect[hswitch], 1); SetBreath(); } @@ -1211,11 +1216,11 @@ int Wavegen() for(pk=wvoice->n_harmonic_peaks+1; pk 0) { @@ -1337,22 +1342,22 @@ int Wavegen() // mix with sampled wave if required z2 = 0; - if(mix_wavefile_ix < n_mix_wavefile) + if(wdata.mix_wavefile_ix < wdata.n_mix_wavefile) { - if(mix_wave_scale == 0) + if(wdata.mix_wave_scale == 0) { // a 16 bit sample - c = mix_wavefile[mix_wavefile_ix+1]; - sample = mix_wavefile[mix_wavefile_ix] + (c * 256); - mix_wavefile_ix += 2; + c = wdata.mix_wavefile[wdata.mix_wavefile_ix+1]; + sample = wdata.mix_wavefile[wdata.mix_wavefile_ix] + (c * 256); + wdata.mix_wavefile_ix += 2; } else { // a 8 bit sample, scaled - sample = (signed char)mix_wavefile[mix_wavefile_ix++] * mix_wave_scale; + sample = (signed char)wdata.mix_wavefile[wdata.mix_wavefile_ix++] * wdata.mix_wave_scale; } - z2 = (sample * amplitude_v) >> 10; - z2 = (z2 * mix_wave_amp)/32; + z2 = (sample * wdata.amplitude_v) >> 10; + z2 = (z2 * wdata.mix_wave_amp)/32; } z1 = z2 + (((total>>8) * amplitude2) >> 13); @@ -1587,8 +1592,8 @@ static void SetAmplitude(int length, unsigned char *amp_env, int value) else amp_inc = (256 * ENV_LEN * STEPSIZE)/length; - amplitude = (value * general_amplitude)/16; - amplitude_v = (amplitude * wvoice->consonant_ampv * 15)/100; // for wave mixed with voiced sounds + wdata.amplitude = (value * general_amplitude)/16; + wdata.amplitude_v = (wdata.amplitude * wvoice->consonant_ampv * 15)/100; // for wave mixed with voiced sounds amplitude_env = amp_env; } @@ -1641,18 +1646,18 @@ if(option_log_frames) } } #endif - if((pitch_env = env)==NULL) - pitch_env = env_fall; // default + if((wdata.pitch_env = env)==NULL) + wdata.pitch_env = env_fall; // default - pitch_ix = 0; + wdata.pitch_ix = 0; if(length==0) - pitch_inc = 0; + wdata.pitch_inc = 0; else - pitch_inc = (256 * ENV_LEN * STEPSIZE)/length; + wdata.pitch_inc = (256 * ENV_LEN * STEPSIZE)/length; - SetPitch2(wvoice, pitch1, pitch2, &pitch_base, &pitch_range); + SetPitch2(wvoice, pitch1, pitch2, &wdata.pitch_base, &wdata.pitch_range); // set initial pitch - pitch = ((pitch_env[0]*pitch_range)>>8) + pitch_base; // Hz << 12 + wdata.pitch = ((wdata.pitch_env[0] * wdata.pitch_range) >>8) + wdata.pitch_base; // Hz << 12 flutter_amp = wvoice->flutter; @@ -1662,15 +1667,14 @@ if(option_log_frames) -void SetSynth(int length, int modn, frame_t *fr1, frame_t *fr2) -{//============================================================ +void SetSynth(int length, int modn, frame_t *fr1, frame_t *fr2, voice_t *v) +{//======================================================================== int ix; DOUBLEX next; int length2; int length4; int qix; int cmd; - voice_t *v; static int glottal_reduce_tab1[4] = {0x30, 0x30, 0x40, 0x50}; // vowel before [?], amp * 1/256 // static int glottal_reduce_tab1[4] = {0x30, 0x40, 0x50, 0x60}; // vowel before [?], amp * 1/256 static int glottal_reduce_tab2[4] = {0x90, 0xa0, 0xb0, 0xc0}; // vowel after [?], amp * 1/256 @@ -1724,8 +1728,6 @@ if(option_log_frames) break; // next is not from spectrum, so continue until end of wave cycle } - v = wvoice; - // round the length to a multiple of the stepsize length2 = (length + STEPSIZE/2) & ~0x3f; if(length2 == 0) @@ -1767,7 +1769,7 @@ if(option_log_frames) static int Wavegen2(int length, int modulation, int resume, frame_t *fr1, frame_t *fr2) {//==================================================================================== if(resume==0) - SetSynth(length,modulation,fr1,fr2); + SetSynth(length, modulation, fr1, fr2, wvoice); return(Wavegen()); } @@ -1839,35 +1841,46 @@ int WavegenFill(int fill_zeros) { echo_complete -= length; } - n_mix_wavefile = 0; + wdata.n_mix_wavefile = 0; + wdata.prev_was_synth = 0; result = PlaySilence(length,resume); break; case WCMD_WAVE: echo_complete = echo_length; - n_mix_wavefile = 0; + wdata.n_mix_wavefile = 0; + wdata.prev_was_synth = 0; result = PlayWave(length,resume,(unsigned char*)q[2], q[3] & 0xff, q[3] >> 8); break; case WCMD_WAVE2: // wave file to be played at the same time as synthesis - mix_wave_amp = q[3] >> 8; - mix_wave_scale = q[3] & 0xff; - if(mix_wave_scale == 0) - n_mix_wavefile = length*2; + wdata.mix_wave_amp = q[3] >> 8; + wdata.mix_wave_scale = q[3] & 0xff; + if(wdata.mix_wave_scale == 0) + wdata.n_mix_wavefile = length*2; else - n_mix_wavefile = length; - mix_wavefile_ix = 0; - mix_wavefile = (unsigned char *)q[2]; + wdata.n_mix_wavefile = length; + wdata.mix_wavefile_ix = 0; + wdata.mix_wavefile = (unsigned char *)q[2]; break; case WCMD_SPECT2: // as WCMD_SPECT but stop any concurrent wave file - n_mix_wavefile = 0; // ... and drop through to WCMD_SPECT case + wdata.n_mix_wavefile = 0; // ... and drop through to WCMD_SPECT case case WCMD_SPECT: echo_complete = echo_length; result = Wavegen2(length & 0xffff,q[1] >> 16,resume,(frame_t *)q[2],(frame_t *)q[3]); break; +#ifdef INCLUDE_KLATT + case WCMD_KLATT2: // as WCMD_SPECT but stop any concurrent wave file + wdata.n_mix_wavefile = 0; // ... and drop through to WCMD_SPECT case + case WCMD_KLATT: + echo_complete = echo_length; + result = Wavegen_Klatt2(length & 0xffff,q[1] >> 16,resume,(frame_t *)q[2],(frame_t *)q[3]); + break; +#endif + case WCMD_MARKER: MarkerEvent(q[1],q[2],q[3],out_ptr); #ifdef LOG_FRAMES