Added runtime detection of pulseaudio, with fallback to portaudio if pulse is not running. Use build option "AUDIO=runtime" in the makefile. Phoneme programs. Added condition "isTranslationGiven" to test whether a phoneme has been specified explicitly for a word in *_list. *_rules files. Suffix rules are now considered only if there is a previous vowel in the word. git-svn-id: https://espeak.svn.sourceforge.net/svnroot/espeak/trunk@274 d46cf337-b52f-0410-862d-fd96e6ae7743master
| @@ -66,7 +66,7 @@ R3 s S t T tS v w | |||
| x z Z | |||
| Dictionary hu_dict 2011-09-07 | |||
| Dictionary hu_dict 2011-09-15 | |||
| a A a: E e: i i: o | |||
| o: u u: Y y y: Y: | |||
| @@ -102,7 +102,7 @@ p Q r R s s; t T | |||
| ts v x z | |||
| Dictionary en_dict 2011-09-07 | |||
| Dictionary en_dict 2011-09-08 | |||
| 0 3 3: @ @- @2 @5 @L | |||
| a a# A: A@ aa aI aI@ aU | |||
| @@ -202,7 +202,7 @@ q r r. s S s. t T | |||
| t. th th. v w x z | |||
| Dictionary ta_dict 2011-09-07 | |||
| Dictionary ta_dict 2011-09-13 | |||
| a a: aI aU e E e: i | |||
| I i: o o: u U u2 u: | |||
| @@ -327,7 +327,7 @@ k l m n p R s S | |||
| t tS v w x | |||
| Dictionary nl_dict 2011-08-26 | |||
| Dictionary nl_dict 2011-09-12 | |||
| 8 @ @- a A a: A~ e | |||
| E e# E2 e: EI eU i I | |||
| @@ -476,7 +476,7 @@ p R R^ s S t tS ts | |||
| v w x z Z | |||
| Dictionary tr_dict 2011-04-22 | |||
| Dictionary tr_dict 2011-09-16 | |||
| @ a e E i I o O | |||
| u U W y Y | |||
| @@ -1967,6 +1967,24 @@ használatáról $unstressend | |||
| gyártót $unstressend | |||
| bírja $unstressend | |||
| azon $unstressend | |||
| kultúráját $unstressend | |||
| célja $unstressend | |||
| hirdeti $unstressend | |||
| munkához $unstressend | |||
| teremtsen $unstressend | |||
| munkát $unstressend | |||
| programmal $unstressend | |||
| alkotott $unstressend | |||
| válaszokat $unstressend | |||
| környezetben $unstressend | |||
| elfogadtak $unstressend | |||
| érkezik $unstressend | |||
| kiállításon $unstressend | |||
| területén $unstressend | |||
| gyengén $unstressend | |||
| jelentőségű $unstressend | |||
| elárulta $unstressend | |||
| bolygón $unstressend | |||
| // word pairs | |||
| @@ -124,6 +124,7 @@ szanité) c (cs ts | |||
| bohó) c (sipk ts | |||
| kilen) c (sáv ts | |||
| cszs tSZ | |||
| kilen) c (schill ts | |||
| .group ch | |||
| anar) ch (i h | |||
| @@ -1178,6 +1179,14 @@ gaboná) szs (ák SZ | |||
| para) szt (segg st | |||
| azbe) szt (sisak st | |||
| nyu) szt (süveg st | |||
| serté) szs (ír SZ | |||
| szere) szs (ák SZ | |||
| rizse) szs (ák SZ | |||
| tá) szs (in SZ | |||
| ruhá) szs (ák SZ | |||
| ro) szs (ák SZ | |||
| va) szs (ír SZ | |||
| széná) szs (ák SZ | |||
| .group t | |||
| t t | |||
| @@ -93,33 +93,33 @@ __ ,alttSIzg'I | |||
| € avRO | |||
| _0 s@f@R | |||
| _1 biR | |||
| _2 ici | |||
| _3 YtS | |||
| _4 dWRt | |||
| _5 beS | |||
| _6 alt@ | |||
| _7 jedi | |||
| _8 seciz | |||
| _9 dokuz | |||
| _10 on | |||
| _0 s@f'@R | |||
| _1 b'iR | |||
| _2 ic'i | |||
| _3 'ytS | |||
| _4 d'WRt | |||
| _5 b'ES | |||
| _6 alt'@ | |||
| _7 jed'i | |||
| _8 sec'Iz | |||
| _9 d'okuz | |||
| _10 'on | |||
| _11 'onbiR | |||
| _12 'onici | |||
| _1X on | |||
| _2X jiRmi | |||
| _3X otuz | |||
| _4X k@Rk | |||
| _5X elli | |||
| _6X altm@S | |||
| _7X jetmiS | |||
| _8X seksEn | |||
| _9X doksan | |||
| _0C jyz | |||
| _1X 'on | |||
| _2X jiRm'i | |||
| _3X ot'uz | |||
| _4X k'@Rk | |||
| _5X ell'i | |||
| _6X altm'@S | |||
| _7X jetm'iS | |||
| _8X seks'En | |||
| _9X doks'an | |||
| _0C 'jyz | |||
| _2C 'icijyz | |||
| _0M1 bIn | |||
| _0M2 miljon | |||
| _0M3 miljar | |||
| _0M1 b'in | |||
| _0M2 milj'on | |||
| _0M3 milj'ar | |||
| _dpt _viRg,Yl_| | |||
| @@ -394,8 +394,8 @@ l/l_ [l] base | |||
| [l/] fr | |||
| l/l_@ [l/3] base | |||
| [l/] fr | |||
| l/l@ [l#] base | |||
| [”¦] base | |||
| l/l@ [hÖq] base | |||
| [l#] base | |||
| [l] fr | |||
| [l/2] fr | |||
| [K] nso | |||
| @@ -428,16 +428,16 @@ l/L2_oL [l/2] base | |||
| l/L2_uL [l/2] base | |||
| l/l_3 [l/] de | |||
| l/l_4 [ll] sq | |||
| l/la [l#] base | |||
| [”¦] base | |||
| l/la [hÖq] base | |||
| [l#] base | |||
| [l] fr | |||
| [l/2] fr | |||
| [K] nso | |||
| [K] tn | |||
| l/l_a [l/3] base | |||
| [l/] fr | |||
| l/le [l#] base | |||
| [”¦] base | |||
| l/le [hÖq] base | |||
| [l#] base | |||
| [l] fr | |||
| [l/2] fr | |||
| [K] nso | |||
| @@ -448,8 +448,8 @@ l/L_eL_af [&] af | |||
| [&:] af | |||
| l/l_front [L] sq | |||
| l/l_front_ [l/4] sq | |||
| l/li [l#] base | |||
| [”¦] base | |||
| l/li [hÖq] base | |||
| [l#] base | |||
| [l] fr | |||
| [l/2] fr | |||
| [l] zh | |||
| @@ -462,8 +462,8 @@ ll/ll [L] bg | |||
| ll/_ll [L] bg | |||
| l/l_long [l] base | |||
| [l] fr | |||
| l/lo [l#] base | |||
| [”¦] base | |||
| l/lo [hÖq] base | |||
| [l#] base | |||
| [l/2] fr | |||
| [K] nso | |||
| [K] tn | |||
| @@ -472,8 +472,8 @@ l/l_o [l/3] base | |||
| l^/l_rfx [l.] base | |||
| [l] ru | |||
| [l^] ru | |||
| l/lu [l#] base | |||
| [”¦] base | |||
| l/lu [hÖq] base | |||
| [l#] base | |||
| [l] fr | |||
| [l/2] fr | |||
| [K] nso | |||
| @@ -1870,7 +1870,6 @@ vowel/ii_3 [I] cy | |||
| [I] hr | |||
| [I] sv | |||
| [I] no | |||
| [I] tr | |||
| [I] pa | |||
| [i] sl | |||
| vowel/ii#_3 [I2] en-us | |||
| @@ -1882,6 +1881,7 @@ vowel/ii_5 [i1] et | |||
| [i] bg | |||
| [I] la | |||
| [i] zh | |||
| [I] tr | |||
| [i] az | |||
| [i] am | |||
| vowel/ii_6 [I] en-wm | |||
| @@ -3,11 +3,15 @@ | |||
| phoneme i | |||
| vowel starttype #i endtype #i | |||
| length 150 | |||
| IF thisPh(isFinalVowel) THEN | |||
| ChangePhoneme(I) | |||
| ENDIF | |||
| IF nextPh(isNotVowel) AND next2Ph(isNotVowel) THEN | |||
| ChangePhoneme(I) | |||
| IF thisPh(isTranslationGiven) THEN | |||
| // don't reduce the vowel if phonemes are explicitly given | |||
| ELSE | |||
| IF thisPh(isFinalVowel) THEN | |||
| ChangePhoneme(I) | |||
| ENDIF | |||
| IF nextPh(isNotVowel) AND next2Ph(isNotVowel) THEN | |||
| ChangePhoneme(I) | |||
| ENDIF | |||
| ENDIF | |||
| FMT(vowel/i_6) | |||
| endphoneme | |||
| @@ -15,17 +19,22 @@ endphoneme | |||
| phoneme I | |||
| vowel starttype #i endtype #i | |||
| length 150 | |||
| FMT(vowel/ii_3) | |||
| FMT(vowel/ii_5) | |||
| endphoneme | |||
| phoneme y | |||
| vowel starttype #u endtype #u | |||
| length 155 | |||
| IF thisPh(isFinalVowel) THEN | |||
| ChangePhoneme(Y) | |||
| ENDIF | |||
| IF nextPh(isNotVowel) AND next2Ph(isNotVowel) THEN | |||
| ChangePhoneme(Y) | |||
| IF thisPh(isTranslationGiven) THEN | |||
| // don't reduce the vowel if phonemes are explicitly given | |||
| ELSE | |||
| IF thisPh(isFinalVowel) THEN | |||
| ChangePhoneme(Y) | |||
| ENDIF | |||
| IF nextPh(isNotVowel) AND next2Ph(isNotVowel) THEN | |||
| ChangePhoneme(Y) | |||
| ENDIF | |||
| ENDIF | |||
| FMT(vowel/y_5) | |||
| endphoneme | |||
| @@ -41,11 +50,15 @@ endphoneme | |||
| phoneme e | |||
| vowel starttype #e endtype #e | |||
| length 180 | |||
| IF thisPh(isFinalVowel) THEN | |||
| ChangePhoneme(E) | |||
| ENDIF | |||
| IF nextPh(isNotVowel) AND next2Ph(isNotVowel) THEN | |||
| ChangePhoneme(E) | |||
| IF thisPh(isTranslationGiven) THEN | |||
| // don't reduce the vowel if phonemes are explicitly given | |||
| ELSE | |||
| IF thisPh(isFinalVowel) THEN | |||
| ChangePhoneme(E) | |||
| ENDIF | |||
| IF nextPh(isNotVowel) AND next2Ph(isNotVowel) THEN | |||
| ChangePhoneme(E) | |||
| ENDIF | |||
| ENDIF | |||
| FMT(vowel/e_mid2) | |||
| endphoneme | |||
| @@ -56,6 +69,7 @@ phoneme E | |||
| FMT(vowel/e_mid) | |||
| endphoneme | |||
| phoneme W | |||
| vowel starttype #@ endtype #@ | |||
| length 180 | |||
| @@ -63,7 +77,6 @@ phoneme W | |||
| endphoneme | |||
| phoneme a | |||
| vowel starttype #a endtype #a | |||
| length 190 | |||
| @@ -75,16 +88,19 @@ endphoneme | |||
| phoneme u | |||
| vowel starttype #u endtype #u | |||
| length 150 | |||
| IF thisPh(isFinalVowel) THEN | |||
| ChangePhoneme(U) | |||
| ENDIF | |||
| IF nextPh(isNotVowel) AND next2Ph(isNotVowel) THEN | |||
| ChangePhoneme(U) | |||
| IF thisPh(isTranslationGiven) THEN | |||
| // don't reduce the vowel if phonemes are explicitly given | |||
| ELSE | |||
| IF thisPh(isFinalVowel) THEN | |||
| ChangePhoneme(U) | |||
| ENDIF | |||
| IF nextPh(isNotVowel) AND next2Ph(isNotVowel) THEN | |||
| ChangePhoneme(U) | |||
| ENDIF | |||
| ENDIF | |||
| FMT(vowel/u_2) | |||
| endphoneme | |||
| phoneme U | |||
| vowel starttype #u endtype #u | |||
| length 150 | |||
| @@ -104,11 +120,15 @@ endphoneme | |||
| phoneme o | |||
| vowel starttype #o endtype #o | |||
| length 190 | |||
| IF thisPh(isFinalVowel) THEN | |||
| ChangePhoneme(O) | |||
| ENDIF | |||
| IF nextPh(isNotVowel) AND next2Ph(isNotVowel) THEN | |||
| ChangePhoneme(O) | |||
| IF thisPh(isTranslationGiven) THEN | |||
| // don't reduce the vowel if phonemes are explicitly given | |||
| ELSE | |||
| IF thisPh(isFinalVowel) THEN | |||
| ChangePhoneme(O) | |||
| ENDIF | |||
| IF nextPh(isNotVowel) AND next2Ph(isNotVowel) THEN | |||
| ChangePhoneme(O) | |||
| ENDIF | |||
| ENDIF | |||
| FMT(vowel/o_mid) | |||
| endphoneme | |||
| @@ -25,12 +25,19 @@ INSTALL = install | |||
| LN_SF = /bin/ln -sf | |||
| MKDIR = mkdir -p | |||
| # 'runtime' uses pulseaudio if it is running, else uses portaudio | |||
| #AUDIO = runtime | |||
| AUDIO = portaudio | |||
| #AUDIO = portaudio0 | |||
| #AUDIO = portaudio2 | |||
| #AUDIO = pulseaudio | |||
| #AUDIO = sada | |||
| ifeq ($(AUDIO),runtime) | |||
| WAVE=wave.cpp wave_pulse.cpp | |||
| LIB_AUDIO=-lpulse -lpulse-simple -lportaudio | |||
| USE_AUDIO=-DUSE_PULSEAUDIO -DUSE_PORTAUDIO | |||
| else | |||
| ifeq ($(AUDIO),pulseaudio) | |||
| WAVE=wave_pulse.cpp | |||
| LIB_AUDIO=-lpulse | |||
| @@ -61,6 +68,7 @@ endif | |||
| endif | |||
| endif | |||
| endif | |||
| endif | |||
| speak_SOURCES = speak.cpp compiledict.cpp dictionary.cpp intonation.cpp \ | |||
| readclause.cpp setlengths.cpp numbers.cpp synth_mbrola.cpp \ | |||
| @@ -20,7 +20,7 @@ CPPFLAGS = -Wall -g -fexceptions -I/usr/lib/wx/include/gtk2-unicode-release-2.6 | |||
| -DGTK_NO_CHECK_CASTS -D__WXGTK__ -D_FILE_OFFSET_BITS=64 -D_LARGE_FILES | |||
| -D_LARGEFILE_SOURCE=1 -DNO_GCC_PRAGMA -D_ESPEAKEDIT | |||
| CXXFLAGS = -O2 -g0 -Wall -g -fexceptions -I/usr/lib/wx/include/gtk2-unicode-release-2.6 -I/usr/include/wx-2.6 \ | |||
| CXXFLAGS = -O2 -Wall -fexceptions -I/usr/lib/wx/include/gtk2-unicode-release-2.6 -I/usr/include/wx-2.6 \ | |||
| -DGTK_NO_CHECK_CASTS -D__WXGTK__ -D_FILE_OFFSET_BITS=64 -D_LARGE_FILES -D_LARGEFILE_SOURCE=1 -DNO_GCC_PRAGMA -D_ESPEAKEDIT | |||
| all: espeakedit | |||
| @@ -95,8 +95,8 @@ static keywtab_t k_conditions[] = { | |||
| {"nextPh", tWHICH_PHONEME, 0x200}, | |||
| {"next2Ph", tWHICH_PHONEME, 0x300}, | |||
| {"nextPhW", tWHICH_PHONEME, 0x400}, | |||
| {"next2PhW", tWHICH_PHONEME, 0x700}, | |||
| {"nextVowel",tWHICH_PHONEME, 0x600}, | |||
| // {"next2PhW", tWHICH_PHONEME, 0x700}, | |||
| // {"numVowels", tTEST, 0x000}, | |||
| // {"afterStress", tTEST, 0x000}, | |||
| @@ -144,6 +144,7 @@ static keywtab_t k_properties[] = { | |||
| {"isFirstVowel", 0, i_isFirstVowel}, | |||
| {"isSecondVowel", 0, i_isSecondVowel}, | |||
| {"isSeqFlag1", 0, i_isSeqFlag1}, | |||
| {"isTranslationGiven", 0, i_IsTranslationGiven}, // phoneme translation given in **_list or as [[...]] | |||
| {NULL, 0, 0} | |||
| }; | |||
| @@ -2161,9 +2161,19 @@ static void MatchRule(Translator *tr, char *word[], char *word_start, int group_ | |||
| break; | |||
| case RULE_ENDING: | |||
| // next 3 bytes are a (non-zero) ending type. 2 bytes of flags + suffix length | |||
| match.end_type = (rule[0] << 16) + ((rule[1] & 0x7f) << 8) + (rule[2] & 0x7f); | |||
| rule += 3; | |||
| { | |||
| int end_type; | |||
| // next 3 bytes are a (non-zero) ending type. 2 bytes of flags + suffix length | |||
| end_type = (rule[0] << 16) + ((rule[1] & 0x7f) << 8) + (rule[2] & 0x7f); | |||
| if((tr->word_vowel_count == 0) && !(end_type & SUFX_P)) | |||
| failed = 1; // don't match a suffix rule if there are no previous syllables (needed for lang=tr). | |||
| else | |||
| { | |||
| match.end_type = end_type; | |||
| rule += 3; | |||
| } | |||
| } | |||
| break; | |||
| case RULE_NO_SUFFIX: | |||
| @@ -448,50 +448,6 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence) | |||
| } | |||
| } | |||
| #ifdef deleted | |||
| while((ph->reduce_to != 0) && (!(plist3->synthflags & SFLAG_DICTIONARY) || (tr->langopts.param[LOPT_REDUCE] & 1))) | |||
| { | |||
| int reduce_level; | |||
| int stress_level; | |||
| int reduce = 0; | |||
| reduce_level = (ph->phflags >> 28) & 7; | |||
| if(ph->type == phVOWEL) | |||
| { | |||
| stress_level = plist3->stress; | |||
| } | |||
| else | |||
| { | |||
| // consonant, get stress from the following vowel | |||
| if(next->type == phVOWEL) | |||
| stress_level = (plist3+1)->stress; | |||
| else | |||
| break; | |||
| } | |||
| if((stress_level == 1) && (first_vowel)) | |||
| stress_level = 0; // ignore 'dimished' stress on first syllable | |||
| if(stress_level == 1) | |||
| reduce = 1; // stress = 'reduced' | |||
| if(stress_level < reduce_level) | |||
| reduce =1; | |||
| if((word_stress < 4) && (tr->langopts.param[LOPT_REDUCE] & 0x2) && (stress_level >= word_stress)) | |||
| { | |||
| // don't reduce the most stressed syllable in an unstressed word | |||
| reduce = 0; | |||
| } | |||
| if(reduce) | |||
| ph = phoneme_tab[ph->reduce_to]; | |||
| else | |||
| break; | |||
| } | |||
| #endif | |||
| if(ph->type == phVOWEL) | |||
| first_vowel = 0; | |||
| @@ -1192,6 +1192,7 @@ ESPEAK_API espeak_ERROR espeak_Synchronize(void) | |||
| extern void FreePhData(void); | |||
| extern void FreeVoiceList(void); | |||
| ESPEAK_API espeak_ERROR espeak_Terminate(void) | |||
| {//=========================================== | |||
| @@ -1214,6 +1215,7 @@ ESPEAK_API espeak_ERROR espeak_Terminate(void) | |||
| Free(outbuf); | |||
| outbuf = NULL; | |||
| FreePhData(); | |||
| FreeVoiceList(); | |||
| if(f_logespeak) | |||
| { | |||
| @@ -35,7 +35,7 @@ | |||
| #include "translate.h" | |||
| #include "wave.h" | |||
| const char *version_string = "1.45.41 07.Sep.11"; | |||
| const char *version_string = "1.45.43 16.Sep.11"; | |||
| const int version_phdata = 0x014500; | |||
| int option_device_number = -1; | |||
| @@ -172,6 +172,7 @@ void FreePhData(void) | |||
| Free(phoneme_tab_data); | |||
| Free(phoneme_index); | |||
| Free(phondata_ptr); | |||
| Free(tunes); | |||
| phoneme_tab_data=NULL; | |||
| phoneme_index=NULL; | |||
| phondata_ptr=NULL; | |||
| @@ -613,7 +614,16 @@ static bool InterpretCondition(Translator *tr, int control, PHONEME_LIST *plist, | |||
| int count; | |||
| PHONEME_TAB *ph; | |||
| PHONEME_LIST *plist_this; | |||
| static int ph_position[8] = {0, 1, 2, 3, 2, 0, 1, 3}; // prevPh, thisPh, nextPh, next2Ph, nextPhW, prevPhW, nextVowel, next2PhW | |||
| static int ph_position[8] = {0, 1, 2, 3, 2, 0, 1, 3}; // prevPh, thisPh, nextPh, next2Ph, nextPhW, prevPhW, nextVowel, (other conditions) | |||
| // instruction: 2xxx, 3xxx | |||
| // bits 8-10 = 0 to 6, which phoneme | |||
| // bit 11 = 0, bits 0-7 are a phoneme code | |||
| // bit 11 = 1, bits 5-7 type of data, bits 0-4 data value | |||
| // bits 8-10 = 7, other conditions | |||
| data = instn & 0xff; | |||
| instn2 = instn >> 8; | |||
| @@ -634,12 +644,12 @@ static bool InterpretCondition(Translator *tr, int control, PHONEME_LIST *plist, | |||
| if(plist[0].sourceix) | |||
| return(false); | |||
| } | |||
| if(which==7) | |||
| { | |||
| // nextPh2 not word boundary | |||
| if((plist[1].sourceix) || (plist[2].sourceix)) | |||
| return(false); | |||
| } | |||
| // if(which==7) | |||
| // { | |||
| // // nextPh2 not word boundary | |||
| // if((plist[1].sourceix) || (plist[2].sourceix)) | |||
| // return(false); | |||
| // } | |||
| if(which==6) | |||
| { | |||
| @@ -676,7 +686,7 @@ static bool InterpretCondition(Translator *tr, int control, PHONEME_LIST *plist, | |||
| } | |||
| ph = plist->ph; | |||
| if(instn2 < 7) | |||
| if(instn2 < 8) | |||
| { | |||
| // 'data' is a phoneme number | |||
| if((phoneme_tab[data]->mnemonic == ph->mnemonic) == true) | |||
| @@ -783,6 +793,9 @@ static bool InterpretCondition(Translator *tr, int control, PHONEME_LIST *plist, | |||
| break; | |||
| } | |||
| return(count > 0); | |||
| case 0x10: // isTranslationGiven | |||
| return((plist->synthflags & SFLAG_DICTIONARY) != 0); | |||
| } | |||
| break; | |||
| @@ -903,7 +916,7 @@ void InterpretPhoneme(Translator *tr, int control, PHONEME_LIST *plist, PHONEME_ | |||
| switch(instn >> 12) | |||
| { | |||
| case 0: | |||
| case 0: // 0xxx | |||
| data = instn & 0xff; | |||
| if(instn2 == 0) | |||
| @@ -329,6 +329,8 @@ typedef struct { | |||
| #define i_isFirstVowel 0x8d | |||
| #define i_isSecondVowel 0x8e | |||
| #define i_isSeqFlag1 0x8f | |||
| #define i_IsTranslationGiven 0x90 | |||
| // place of articulation | |||
| #define i_isVel 0x28 | |||
| @@ -122,7 +122,7 @@ | |||
| #define SUFX_I 0x0200 // y may have been changed to i | |||
| #define SUFX_P 0x0400 // prefix | |||
| #define SUFX_V 0x0800 // suffix means use the verb form pronunciation | |||
| #define SUFX_D 0x1000 // previous letter may have been doubles | |||
| #define SUFX_D 0x1000 // previous letter may have been doubled | |||
| #define SUFX_F 0x2000 // verb follows | |||
| #define SUFX_Q 0x4000 // don't retranslate | |||
| #define SUFX_T 0x10000 // don't affect the stress position in the stem | |||
| @@ -1745,6 +1745,18 @@ espeak_ERROR SetVoiceByProperties(espeak_VOICE *voice_selector) | |||
| } // end of SetVoiceByProperties | |||
| void FreeVoiceList() | |||
| {//================= | |||
| for(int ix=0; ix<n_voices_list; ix++) | |||
| { | |||
| if(voices_list[ix] != NULL) | |||
| { | |||
| free(voices_list[ix]); | |||
| voices_list[ix] = NULL; | |||
| } | |||
| } | |||
| n_voices_list = 0; | |||
| } | |||
| //======================================================================= | |||
| @@ -1763,13 +1775,7 @@ ESPEAK_API const espeak_VOICE **espeak_ListVoices(espeak_VOICE *voice_spec) | |||
| char path_voices[sizeof(path_home)+12]; | |||
| // free previous voice list data | |||
| for(ix=0; ix<n_voices_list; ix++) | |||
| { | |||
| if(voices_list[ix] != NULL) | |||
| free(voices_list[ix]); | |||
| } | |||
| n_voices_list = 0; | |||
| FreeVoiceList(); | |||
| sprintf(path_voices,"%s%cvoices",path_home,PATHSEP); | |||
| len_path_voices = strlen(path_voices)+1; | |||
| @@ -53,6 +53,148 @@ enum {ONE_BILLION=1000000000}; | |||
| #endif | |||
| #ifdef USE_PULSEAUDIO | |||
| // create some wrappers for runtime detection | |||
| // checked on wave_init | |||
| static int pulse_running; | |||
| // wave.cpp (this file) | |||
| void wave_port_init(int); | |||
| void* wave_port_open(const char* the_api); | |||
| size_t wave_port_write(void* theHandler, char* theMono16BitsWaveBuffer, size_t theSize); | |||
| int wave_port_close(void* theHandler); | |||
| int wave_port_is_busy(void* theHandler); | |||
| void wave_port_terminate(); | |||
| uint32_t wave_port_get_read_position(void* theHandler); | |||
| uint32_t wave_port_get_write_position(void* theHandler); | |||
| void wave_port_flush(void* theHandler); | |||
| void wave_port_set_callback_is_output_enabled(t_wave_callback* cb); | |||
| void* wave_port_test_get_write_buffer(); | |||
| int wave_port_get_remaining_time(uint32_t sample, uint32_t* time); | |||
| // wave_pulse.cpp | |||
| int is_pulse_running(); | |||
| void wave_pulse_init(int); | |||
| void* wave_pulse_open(const char* the_api); | |||
| size_t wave_pulse_write(void* theHandler, char* theMono16BitsWaveBuffer, size_t theSize); | |||
| int wave_pulse_close(void* theHandler); | |||
| int wave_pulse_is_busy(void* theHandler); | |||
| void wave_pulse_terminate(); | |||
| uint32_t wave_pulse_get_read_position(void* theHandler); | |||
| uint32_t wave_pulse_get_write_position(void* theHandler); | |||
| void wave_pulse_flush(void* theHandler); | |||
| void wave_pulse_set_callback_is_output_enabled(t_wave_callback* cb); | |||
| void* wave_pulse_test_get_write_buffer(); | |||
| int wave_pulse_get_remaining_time(uint32_t sample, uint32_t* time); | |||
| // wrappers | |||
| void wave_init(int srate) { | |||
| pulse_running = is_pulse_running(); | |||
| if (pulse_running) | |||
| wave_pulse_init(srate); | |||
| else | |||
| wave_port_init(srate); | |||
| } | |||
| void* wave_open(const char* the_api) { | |||
| if (pulse_running) | |||
| return wave_pulse_open(the_api); | |||
| else | |||
| return wave_port_open(the_api); | |||
| } | |||
| size_t wave_write(void* theHandler, char* theMono16BitsWaveBuffer, size_t theSize) { | |||
| if (pulse_running) | |||
| return wave_pulse_write(theHandler, theMono16BitsWaveBuffer, theSize); | |||
| else | |||
| return wave_port_write(theHandler, theMono16BitsWaveBuffer, theSize); | |||
| } | |||
| int wave_close(void* theHandler) { | |||
| if (pulse_running) | |||
| return wave_pulse_close(theHandler); | |||
| else | |||
| return wave_port_close(theHandler); | |||
| } | |||
| int wave_is_busy(void* theHandler) { | |||
| if (pulse_running) | |||
| return wave_pulse_is_busy(theHandler); | |||
| else | |||
| return wave_port_is_busy(theHandler); | |||
| } | |||
| void wave_terminate() { | |||
| if (pulse_running) | |||
| wave_pulse_terminate(); | |||
| else | |||
| wave_port_terminate(); | |||
| } | |||
| uint32_t wave_get_read_position(void* theHandler) { | |||
| if (pulse_running) | |||
| return wave_pulse_get_read_position(theHandler); | |||
| else | |||
| return wave_port_get_read_position(theHandler); | |||
| } | |||
| uint32_t wave_get_write_position(void* theHandler) { | |||
| if (pulse_running) | |||
| return wave_pulse_get_write_position(theHandler); | |||
| else | |||
| return wave_port_get_write_position(theHandler); | |||
| } | |||
| void wave_flush(void* theHandler) { | |||
| if (pulse_running) | |||
| wave_pulse_flush(theHandler); | |||
| else | |||
| wave_port_flush(theHandler); | |||
| } | |||
| void wave_set_callback_is_output_enabled(t_wave_callback* cb) { | |||
| if (pulse_running) | |||
| wave_pulse_set_callback_is_output_enabled(cb); | |||
| else | |||
| wave_port_set_callback_is_output_enabled(cb); | |||
| } | |||
| void* wave_test_get_write_buffer() { | |||
| if (pulse_running) | |||
| return wave_pulse_test_get_write_buffer(); | |||
| else | |||
| return wave_port_test_get_write_buffer(); | |||
| } | |||
| int wave_get_remaining_time(uint32_t sample, uint32_t* time) | |||
| { | |||
| if (pulse_running) | |||
| return wave_pulse_get_remaining_time(sample, time); | |||
| else | |||
| return wave_port_get_remaining_time(sample, time); | |||
| } | |||
| // rename functions to be wrapped | |||
| #define wave_init wave_port_init | |||
| #define wave_open wave_port_open | |||
| #define wave_write wave_port_write | |||
| #define wave_close wave_port_close | |||
| #define wave_is_busy wave_port_is_busy | |||
| #define wave_terminate wave_port_terminate | |||
| #define wave_get_read_position wave_port_get_read_position | |||
| #define wave_get_write_position wave_port_get_write_position | |||
| #define wave_flush wave_port_flush | |||
| #define wave_set_callback_is_output_enabled wave_port_set_callback_is_output_enabled | |||
| #define wave_test_get_write_buffer wave_port_test_get_write_buffer | |||
| #define wave_get_remaining_time wave_port_get_remaining_time | |||
| #endif // USE_PULSEAUDIO | |||
| static t_wave_callback* my_callback_is_output_enabled=NULL; | |||
| #define N_WAV_BUF 10 | |||
| @@ -65,6 +65,7 @@ enum { | |||
| static t_wave_callback* my_callback_is_output_enabled=NULL; | |||
| #define SAMPLE_RATE 22050 | |||
| #define ESPEAK_FORMAT PA_SAMPLE_S16LE | |||
| #define ESPEAK_CHANNEL 1 | |||
| @@ -74,6 +75,39 @@ static t_wave_callback* my_callback_is_output_enabled=NULL; | |||
| #define MINREQ 880 | |||
| #define FRAGSIZE 0 | |||
| #ifdef USE_PORTAUDIO | |||
| // rename functions to be wrapped | |||
| #define wave_init wave_pulse_init | |||
| #define wave_open wave_pulse_open | |||
| #define wave_write wave_pulse_write | |||
| #define wave_close wave_pulse_close | |||
| #define wave_is_busy wave_pulse_is_busy | |||
| #define wave_terminate wave_pulse_terminate | |||
| #define wave_get_read_position wave_pulse_get_read_position | |||
| #define wave_get_write_position wave_pulse_get_write_position | |||
| #define wave_flush wave_pulse_flush | |||
| #define wave_set_callback_is_output_enabled wave_pulse_set_callback_is_output_enabled | |||
| #define wave_test_get_write_buffer wave_pulse_test_get_write_buffer | |||
| #define wave_get_remaining_time wave_pulse_get_remaining_time | |||
| // check whether we can connect to PulseAudio | |||
| #include <pulse/simple.h> | |||
| int is_pulse_running() | |||
| { | |||
| pa_sample_spec ss; | |||
| ss.format = ESPEAK_FORMAT; | |||
| ss.rate = SAMPLE_RATE; | |||
| ss.channels = ESPEAK_CHANNEL; | |||
| pa_simple *s = pa_simple_new(NULL, "eSpeak", PA_STREAM_PLAYBACK, NULL, "is_pulse_running", &ss, NULL, NULL, NULL); | |||
| if (s) { | |||
| pa_simple_free(s); | |||
| return 1; | |||
| } else | |||
| return 0; | |||
| } | |||
| #endif // USE_PORTAUDIO | |||
| static pthread_mutex_t pulse_mutex; | |||
| static pa_context *context = NULL; | |||
| @@ -843,8 +877,9 @@ int wave_get_remaining_time(uint32_t sample, uint32_t* time) | |||
| return 0; | |||
| } | |||
| #endif // of USE_PORTAUDIO | |||
| #endif // of USE_PULSEAUDIO | |||
| #ifndef USE_PORTAUDIO | |||
| //> | |||
| //<clock_gettime2, add_time_in_ms | |||
| @@ -878,6 +913,7 @@ void add_time_in_ms(struct timespec *ts, int time_in_ms) | |||
| } | |||
| ts->tv_nsec = (long int)t_ns; | |||
| } | |||
| #endif // ifndef USE_PORTAUDIO | |||
| #endif // USE_ASYNC | |||