From 363753f38823677c37dc6f00de7e96f1e4ca329e Mon Sep 17 00:00:00 2001 From: jonsd Date: Wed, 12 Dec 2007 10:46:48 +0000 Subject: [PATCH] [1.29.24] Fixed problem where espeak_GetCurrentVoice() gave a newline character after the voice name. git-svn-id: https://espeak.svn.sourceforge.net/svnroot/espeak/trunk@110 d46cf337-b52f-0410-862d-fd96e6ae7743 --- dictsource/dict_phonemes | 8 +- dictsource/en_list | 6 +- dictsource/en_rules | 2 +- dictsource/hu_rules | 1 + dictsource/zh_list | 2 +- phsource/phonemes | 2 +- src/compiledict.cpp | 27 ++++--- src/dictionary.cpp | 133 ++++++++++++++++++++----------- src/intonation.cpp | 125 ++++++++++++++--------------- src/readclause.cpp | 6 +- src/setlengths.cpp | 7 +- src/speak.cpp | 5 ++ src/synthdata.cpp | 4 +- src/tr_english.cpp | 2 +- src/tr_languages.cpp | 85 ++++++++++---------- src/translate.cpp | 165 ++++++++++++++++++++++++--------------- src/translate.h | 42 ++++++---- src/voices.cpp | 28 +++++-- src/wavegen.cpp | 2 +- 19 files changed, 382 insertions(+), 270 deletions(-) diff --git a/dictsource/dict_phonemes b/dictsource/dict_phonemes index 67c41092..2c397cf2 100644 --- a/dictsource/dict_phonemes +++ b/dictsource/dict_phonemes @@ -337,10 +337,10 @@ Dictionary zh_dict i i. i[ iou o o- ou u uai y -f j k kh l m n N -p ph R R2 R3 s s. S; -t th ts ts. ts. tS; tS; tsh -v w x z z. +: f j k kh l m n +N p ph R R2 R3 s s. +S; t th ts ts. ts. tS; tS; +tsh v w x z z. Dictionary hbs_dict diff --git a/dictsource/en_list b/dictsource/en_list index b71ed3aa..9e75333a 100644 --- a/dictsource/en_list +++ b/dictsource/en_list @@ -1344,7 +1344,7 @@ peculiar pI2kju:lI3 pedalo pEd@loU pejorative p@dZ0r@tIv penal pi:n@L -?4 penchant p0nS0n +penchant p0nS0n peninsula p@n'InsjUl@ penis pi:nI2s perfectly p3:fEktlI2 @@ -1388,8 +1388,8 @@ politer p@l'aIt3 politic p0l@tIk poll poUl polls poUlz -penchant p0nS0n portend po@t'End +posse p0sI postage poUstIdZ practise praktIs prayer pre@ @@ -2631,11 +2631,11 @@ also $verbf already O:lr,EdI2 $verbf $strend2 not ,n0t $verbextend $only $strend -not n0t $capital $abbrev // don't spell "NOT"; speak it with stress (not have) n0ta2v $pastf $u1 (not have) n0thav $pastf $atend (not have to) ,n0thavt@5 $pastf $strend (not a) ,n0t@ $nounf +not n0t $allcaps $verbextend // don't spell "NOT"; speak it with stress only oUnlI2 $verbextend any ,EnI2 $nounf $only diff --git a/dictsource/en_rules b/dictsource/en_rules index 6b48953d..a66a1a17 100644 --- a/dictsource/en_rules +++ b/dictsource/en_rules @@ -1484,7 +1484,7 @@ de (lph dE _) de (lt dE delu (g dElju: - de (lv dE + de (lv+ dE de (ma dI2 de (mea dI2 de (men dI2 diff --git a/dictsource/hu_rules b/dictsource/hu_rules index d9a320d2..d5d0724d 100644 --- a/dictsource/hu_rules +++ b/dictsource/hu_rules @@ -308,6 +308,7 @@ vörösmar) ty ti nehé) z (sé z pén) z z szá) z (sz z + tí) z (sz z tű) z (sz z ví) z (sz z tor) z (szülött z diff --git a/dictsource/zh_list b/dictsource/zh_list index 03a15233..efb63b20 100644 --- a/dictsource/zh_list +++ b/dictsource/zh_list @@ -1,5 +1,5 @@ -_?? @11 // unrecognized character +_?? @:11 // unrecognized character //numbers _0 liN35 diff --git a/phsource/phonemes b/phsource/phonemes index 4230552c..2314841a 100644 --- a/phsource/phonemes +++ b/phsource/phonemes @@ -72,7 +72,7 @@ endphoneme phoneme '' // Primary stress (priority) stress - length 5 + length 6 endphoneme phoneme = // Place stress on previous vowel diff --git a/src/compiledict.cpp b/src/compiledict.cpp index 4ed5dbcf..6f3aa2a6 100755 --- a/src/compiledict.cpp +++ b/src/compiledict.cpp @@ -78,7 +78,6 @@ MNEM_TAB mnem_flags[] = { {"$unstressend",13}, /* reduce stress at end of clause */ {"$atend", 14}, /* use this pronunciation if at end of clause */ - {"$capital", 15}, /* use this pronunciation if initial letter is upper case */ {"$dot", 16}, /* ignore '.' after this word (abbreviation) */ {"$abbrev", 17}, /* use this pronuciation rather than split into letters */ {"$stem", 18}, // must have a suffix @@ -87,17 +86,23 @@ MNEM_TAB mnem_flags[] = { {"$double", 19}, // IT double the initial consonant of next word {"$alt", 20}, // use alternative pronunciation {"$alt2", 21}, + - {"$verbf", 22}, /* verb follows */ - {"$verbsf", 23}, /* verb follows, allow -s suffix */ - {"$nounf", 24}, /* noun follows */ - {"$verb", 25}, /* use this pronunciation when its a verb */ - {"$past", 26}, /* use this pronunciation when its past tense */ - {"$pastf", 27}, /* past tense follows */ - {"$verbextend",28}, /* extend influence of 'verb follows' */ - + {"$brk", 28}, // a shorter $pause {"$text", 29}, // word translates to replcement text, not phonemes - {"$brk", 30}, // a shorter $pause + +// flags in dictionary word 2 + {"$verbf", 0x20}, /* verb follows */ + {"$verbsf", 0x21}, /* verb follows, allow -s suffix */ + {"$nounf", 0x22}, /* noun follows */ + {"$pastf", 0x23}, /* past tense follows */ + {"$verb", 0x24}, /* use this pronunciation when its a verb */ + {"$noun", 0x25}, /* use this pronunciation when its a noun */ + {"$past", 0x26}, /* use this pronunciation when its past tense */ + {"$verbextend",0x28}, /* extend influence of 'verb follows' */ + {"$capital", 0x29}, /* use this pronunciation if initial letter is upper case */ + {"$allcaps", 0x2a}, /* use this pronunciation if initial letter is upper case */ + // doesn't set dictionary_flags {"$?", 100}, // conditional rule, followed by byte giving the condition number @@ -455,7 +460,7 @@ static char nullstring[] = {0}; } else { - dict_line[length++] = 40 + multiple_words; + dict_line[length++] = 80 + multiple_words; ix = multiple_string_end - multiple_string; memcpy(&dict_line[length],multiple_string,ix); length += ix; diff --git a/src/dictionary.cpp b/src/dictionary.cpp index 69238cc8..932f0c32 100755 --- a/src/dictionary.cpp +++ b/src/dictionary.cpp @@ -752,9 +752,9 @@ void SetLetterBitsRange(Translator *tr, int group, int first, int last) -static int GetVowelStress(Translator *tr, unsigned char *phonemes, unsigned char *vowel_stress, int &vowel_count, int &stressed_syllable) -{//====================================================================================================================================== - +static int GetVowelStress(Translator *tr, unsigned char *phonemes, unsigned char *vowel_stress, int &vowel_count, int &stressed_syllable, int control) +{//==================================================================================================================================================== +// control = 1, set stress to 1 for forced unstressed vowels unsigned char phcode; PHONEME_TAB *ph; unsigned char *ph_out = phonemes; @@ -825,7 +825,7 @@ static int GetVowelStress(Translator *tr, unsigned char *phonemes, unsigned char max_stress = stress; } - if((stress == 0) && (ph->phflags & phUNSTRESSED)) + if((stress == 0) && (control & 1) && (ph->phflags & phUNSTRESSED)) vowel_stress[count] = 1; /* weak vowel, must be unstressed */ count++; @@ -836,7 +836,7 @@ static int GetVowelStress(Translator *tr, unsigned char *phonemes, unsigned char { // previous consonant phoneme is syllablic vowel_stress[count] = (char)stress; - if(stress == 0) + if((stress == 0) && (control & 1)) vowel_stress[count++] = 1; // syllabic consonant, usually unstressed } @@ -900,14 +900,14 @@ void ChangeWordStress(Translator *tr, char *word, int new_stress) unsigned char vowel_stress[N_WORD_PHONEMES/2]; strcpy((char *)phonetic,word); - max_stress = GetVowelStress(tr, phonetic,vowel_stress,vowel_count,stressed_syllable); + max_stress = GetVowelStress(tr, phonetic, vowel_stress, vowel_count, stressed_syllable, 0); if(new_stress >= 4) { // promote to primary stress for(ix=1; ix= max_stress) { vowel_stress[ix] = new_stress; break; @@ -919,7 +919,7 @@ void ChangeWordStress(Translator *tr, char *word, int new_stress) // remove primary stress for(ix=1; ix new_stress) + if(vowel_stress[ix] > new_stress) // >= allows for diminished stress (=1) vowel_stress[ix] = new_stress; } } @@ -1013,7 +1013,7 @@ void Translator::SetWordStress(char *output, unsigned int dictionary_flags, int unstressed_word = 1; } - max_stress = GetVowelStress(this,phonetic,vowel_stress,vowel_count,stressed_syllable); + max_stress = GetVowelStress(this, phonetic, vowel_stress, vowel_count, stressed_syllable, 1); // heavy or light syllables ix = 1; @@ -2598,18 +2598,18 @@ int TransposeAlphabet(char *text, int offset, int min, int max) -char *print_dflags(int flags) -{//========================== +char *print_dflags(unsigned int *flags) +{//==================================== static char buf[20]; - sprintf(buf,"%s 0x%x",LookupMnem(mnem_flags,(flags & 0xf)+0x40), flags); + sprintf(buf,"%s 0x%x/%x",LookupMnem(mnem_flags,(flags[0] & 0xf)+0x40), flags[0], flags[1]); return(buf); } -const char *Translator::LookupDict2(const char *word, const char *word2, char *phonetic, unsigned int *flags, int end_flags) -//==================================================================================================================== +const char *Translator::LookupDict2(const char *word, const char *word2, char *phonetic, unsigned int *flags, int end_flags, WORD_TAB *wtab) +//========================================================================================================================================== /* Find an entry in the word_dict file for a specified word. Returns NULL if no match, else returns 'word_end' @@ -2628,9 +2628,12 @@ const char *Translator::LookupDict2(const char *word, const char *word2, char *p int wlen; unsigned char flag; unsigned int dictionary_flags; + unsigned int dictionary_flags2; int condition_failed=0; int n_chars; int no_phonemes; + int skipwords; + int ix; const char *word_end; const char *word1; char word_buf[N_WORD_BYTES]; @@ -2675,6 +2678,7 @@ const char *Translator::LookupDict2(const char *word, const char *word2, char *p word_end = word2; dictionary_flags = 0; + dictionary_flags2 = 0; no_phonemes = p[1] & 0x80; p += ((p[1] & 0x3f) + 2); @@ -2713,6 +2717,37 @@ const char *Translator::LookupDict2(const char *word, const char *word2, char *p } } else + if(flag > 80) + { + // flags 81 to 90 match more than one word + // This comes after the other flags + n_chars = next - p; + skipwords = flag - 80; + + // don't use the contraction if any of the words are emphasized + for(ix=0; ix <= skipwords; ix++) + { + if((wtab != NULL) && (wtab[ix].flags & FLAG_EMPHASIZED)) + { + condition_failed = 1; + } + } + + if(memcmp(word2,p,n_chars) != 0) + condition_failed = 1; + + if(condition_failed) + { + p = next; + break; + } + + dictionary_flags |= FLAG_SKIPWORDS; + dictionary_skipwords = skipwords; + p = next; + word_end = word2 + n_chars; + } + else if(flag > 64) { // stressed syllable information, put in bits 0-3 @@ -2721,24 +2756,9 @@ const char *Translator::LookupDict2(const char *word, const char *word2, char *p dictionary_flags |= FLAG_STRESS_END; } else - if(flag > 40) + if(flag >= 32) { - // flags 41 to 50 match more than one word - // This comes after the other flags - n_chars = next - p; - if(memcmp(word2,p,n_chars)==0) - { - dictionary_flags |= FLAG_SKIPWORDS; - dictionary_skipwords = (flag - 40); - p = next; - word_end = word2 + n_chars; - } - else - { - p = next; - condition_failed = 1; - break; - } + dictionary_flags2 |= (1L << (flag-32)); } else { @@ -2775,13 +2795,20 @@ const char *Translator::LookupDict2(const char *word, const char *word2, char *p } } - if(dictionary_flags & FLAG_CAPITAL) + if(dictionary_flags2 & FLAG_CAPITAL) { if(!(word_flags & FLAG_FIRST_UPPER)) { continue; } } + if(dictionary_flags2 & FLAG_ALLCAPS) + { + if(!(word_flags & FLAG_ALL_UPPER)) + { + continue; + } + } if((dictionary_flags & FLAG_ATEND) && (word_end < clause_end)) { @@ -2789,7 +2816,7 @@ const char *Translator::LookupDict2(const char *word, const char *word2, char *p continue; } - if(dictionary_flags & FLAG_VERB) + if(dictionary_flags2 & FLAG_VERB) { // this is a verb-form pronunciation @@ -2804,7 +2831,7 @@ const char *Translator::LookupDict2(const char *word, const char *word2, char *p continue; } } - if(dictionary_flags & FLAG_PAST) + if(dictionary_flags2 & FLAG_PAST) { if(!expect_past) { @@ -2813,21 +2840,33 @@ const char *Translator::LookupDict2(const char *word, const char *word2, char *p continue; } } + if(dictionary_flags2 & FLAG_NOUN) + { + if(!expect_noun) + { + /* don't use the 'noun' pronunciation unless we are + expecting a noun */ + continue; + } + } if(flags != NULL) - *flags = dictionary_flags; + { + flags[0] = dictionary_flags | FLAG_FOUND_ATTRIBUTES; + flags[1] = dictionary_flags2; + } if(phoneme_len == 0) { if(option_phonemes == 2) { - fprintf(f_trans,"Flags: %s %s\n",word1,print_dflags(*flags)); + fprintf(f_trans,"Flags: %s %s\n",word1,print_dflags(flags)); } return(0); // no phoneme translation found here, only flags. So use rules } if(flags != NULL) - *flags |= FLAG_FOUND; // this flag indicates word was found in dictionary + flags[0] |= FLAG_FOUND; // this flag indicates word was found in dictionary if(option_phonemes == 2) { @@ -2837,7 +2876,7 @@ const char *Translator::LookupDict2(const char *word, const char *word2, char *p DecodePhonemes(phonetic,ph_decoded); if(flags != NULL) - flags1 = *flags; + flags1 = flags[0]; if((dictionary_flags & FLAG_TEXTMODE) == 0) textmode = 0; @@ -2847,7 +2886,7 @@ const char *Translator::LookupDict2(const char *word, const char *word2, char *p if(textmode == translator->langopts.textmode) { // only show this line if the word translates to phonemes, not replacement text - fprintf(f_trans,"Found: %s [%s] %s\n",word1,ph_decoded,print_dflags(flags1)); + fprintf(f_trans,"Found: %s [%s] %s\n",word1,ph_decoded,print_dflags(flags)); } } return(word_end); @@ -2858,8 +2897,8 @@ const char *Translator::LookupDict2(const char *word, const char *word2, char *p -int Translator::LookupDictList(char **wordptr, char *ph_out, unsigned int *flags, int end_flags) -//============================================================================================== +int Translator::LookupDictList(char **wordptr, char *ph_out, unsigned int *flags, int end_flags, WORD_TAB *wtab) +//============================================================================================================== /* Lookup a specified word in the word dictionary. Returns phonetic data in 'phonetic' and bits in 'flags' @@ -2895,7 +2934,7 @@ int Translator::LookupDictList(char **wordptr, char *ph_out, unsigned int *flags nbytes = utf8_in(&c2,word2,0); memcpy(&word[length],word2,nbytes); word[length+nbytes] = 0; - found = LookupDict2(word,word2,ph_out,flags,end_flags); + found = LookupDict2(word, word2, ph_out, flags, end_flags, wtab); if(found) { *flags = *flags & ~(7 << 5) | (length << 5); @@ -2911,7 +2950,7 @@ int Translator::LookupDictList(char **wordptr, char *ph_out, unsigned int *flags } word[length] = 0; - found = LookupDict2(word,word1,ph_out,flags,end_flags); + found = LookupDict2(word, word1, ph_out, flags, end_flags, wtab); if(found == 0) { @@ -2923,14 +2962,14 @@ int Translator::LookupDictList(char **wordptr, char *ph_out, unsigned int *flags { // try removing an 'e' which has been added by RemoveEnding word[length-1] = 0; - found = LookupDict2(word,word1,ph_out,flags,end_flags); + found = LookupDict2(word, word1, ph_out, flags, end_flags, wtab); } else if((end_flags & SUFX_D) && (word[length-1] == word[length-2])) { // try removing a double letter word[length-1] = 0; - found = LookupDict2(word,word1,ph_out,flags,end_flags); + found = LookupDict2(word, word1, ph_out, flags, end_flags, wtab); } } @@ -2977,9 +3016,9 @@ int Translator::LookupDictList(char **wordptr, char *ph_out, unsigned int *flags int Translator::Lookup(const char *word, char *ph_out) {//=================================================== - unsigned int flags; + unsigned int flags[2]; char *word1 = (char *)word; - return(LookupDictList(&word1,ph_out,&flags,0)); + return(LookupDictList(&word1, ph_out, flags, 0, NULL)); } diff --git a/src/intonation.cpp b/src/intonation.cpp index b6876d95..7bfbf69b 100755 --- a/src/intonation.cpp +++ b/src/intonation.cpp @@ -228,7 +228,7 @@ unsigned char *envelope_data[16] = { /* all pitches given in Hz above pitch_base */ // pitch change during the main part of the clause -static int drops_0[8] = {0x400,0x400,0x700,0x700,0x700,0xa00,0x0e00,0x0e00}; +static int drops_0[8] = {0x400,0x400,0x700,0x700,0x700,0xa00,0x1800,0x0e00}; static int drops_1[8] = {0x400,0x400,0x600,0x600,0xc00,0xc00,0x0e00,0x0e00}; static int drops_2[8] = {0x400,0x400,0x600,0x600,-0x800,0xc00,0x0e00,0x0e00}; @@ -241,6 +241,9 @@ typedef struct { unsigned char tonic_max1; unsigned char tonic_min1; + unsigned char emph_level; + unsigned char emph_next; + unsigned char pre_start; unsigned char pre_end; @@ -260,16 +263,19 @@ typedef struct { static TONE_TABLE tone_table[N_TONE_TABLE] = { {PITCHfall, 30, 5, PITCHfall, 30, 7, // statement +12, 10, 20, 25, 34, 22, drops_0, 3, 3, 12, 8, 0}, {PITCHfrise, 38,10, PITCHfrise2, 36,10, // comma, or question +30, 20, 20, 25, 34, 20, drops_0, 3, 3, 15, 25, 0}, {PITCHdrop, 38, 1, PITCHdrop, 42,25, // exclamation +30, 20, 20, 25, 34, 22, drops_0, 3, 3, 12, 8, 0}, - +#ifdef deleted {PITCHfall, 30, 5, PITCHfall, 30, 7, // statement 20, 25, 34, 22, drops_1, 3, 3, 12, 8, 0}, @@ -301,23 +307,23 @@ static TONE_TABLE tone_table[N_TONE_TABLE] = { {PITCHfall, 36, 6, PITCHfall, 36, 8, 30, 20, 18, 34, drops_0, 3, 3, 12, 8, 0}, - +#endif }; /* indexed by stress */ -static int min_drop[] = {0x300,0x300,0x300,0x300,0x300,0x500,0xc00,0xc00}; +static int min_drop[] = {0x300,0x300,0x400,0x400,0x900,0x900,0x900,0x900}; #define SECONDARY 3 #define PRIMARY 4 +#define PRIMARY_STRESSED 5 #define PRIMARY_MARKED 6 -#define BODY_RESET 7 -#define FIRST_TONE 8 /* first of the tone types */ +#define PRIMARY_LAST 7 static int number_pre; @@ -335,15 +341,13 @@ static void count_pitch_vowels() { int ix; int stress; - int stage=0; /* 0=pre, 1=body, 2=tail */ int max_stress = 0; int max_stress_posn = 0; - int tone_type_marker = 0; - int marked_stress_count = 0; - number_pre=0; /* number of vowels before 1st primary stress */ - number_body=0; - number_tail=0; /* number between tonic syllable and next primary */ + number_pre = -1; /* number of vowels before 1st primary stress */ + number_body = 0; + number_tail = 0; /* number between tonic syllable and next primary */ + last_primary = 0; for(ix=vowel_ix; ix= PRIMARY) { - if(stress > PRIMARY) - { - marked_stress_count++; - } + if(number_pre < 0) + number_pre = ix; last_primary = ix; } - switch(stage) - { - case 0: - if(stress < PRIMARY) - number_pre++; - else - { - stage = 1; - ix = ix-1; - } - break; - - case 1: - if(stress >= FIRST_TONE) - { - tone_type_marker = stress; - tone_posn = ix; - stage = 2; - } - break; - - case 2: - if(stress < PRIMARY) - number_tail++; - else - stage = 3; - break; - } } + if(number_pre < 0) + number_pre = 0; + + number_tail = vowel_ix_top - max_stress_posn - 1; + tone_posn = max_stress_posn; +tone_posn = last_primary; + if(no_tonic) { tone_posn = vowel_ix_top; } else - if((tone_type_marker >= FIRST_TONE) && (tone_type_marker < (N_TONE_TABLE + FIRST_TONE))) +// if((last_primary - max_stress_posn) > 2) { - tone_type = tone_type_marker - FIRST_TONE; + if(vowel_tab[last_primary] < PRIMARY_MARKED) + vowel_tab[last_primary] = PRIMARY_LAST; } - else - { - /* no tonic syllable found, use highest stress */ - vowel_tab[max_stress_posn] = FIRST_TONE; - number_tail = vowel_ix_top - max_stress_posn - 1; - tone_posn = max_stress_posn; - } - - if(marked_stress_count > 1) - annotation = 1; - else - annotation = 0; } /* end of count_pitch_vowels */ @@ -429,9 +399,9 @@ static int count_increments(int ix, int end_ix, int min_stress) while(ix < end_ix) { stress = vowel_tab[ix++] & 0x3f; - if(stress >= BODY_RESET) - break; - else +// if(stress >= PRIMARY_MARKED) +// break; + if(stress >= min_stress) count++; } @@ -494,9 +464,10 @@ static int calc_pitch_segment(int ix, int end_ix, TONE_TABLE *t, int min_stress) int n_primary=0; int initial; int overflow=0; + int marking=0; int *drops; - static char overflow_tab[5] = {0, 5, 3, 1, 0}; + static char overflow_tab[5] = {0, 20, 12, 4, 0}; drops = t->body_drops; @@ -505,11 +476,13 @@ static int calc_pitch_segment(int ix, int end_ix, TONE_TABLE *t, int min_stress) { stress = vowel_tab[ix] & 0x3f; - if(stress == BODY_RESET) - initial = 1; +// if(stress == PRIMARY_MARKED) +// initial = 1; // reset the intonation pattern if(initial || (stress >= min_stress)) { + // a primary stress + if(initial) { initial = 0; @@ -535,14 +508,34 @@ static int calc_pitch_segment(int ix, int end_ix, TONE_TABLE *t, int min_stress) pitch += increment; else { - pitch = (t->body_end << 8) - (increment * overflow_tab[overflow++])/4; + pitch = (t->body_end << 8) - (increment * overflow_tab[overflow++])/16; if(overflow > 4) overflow = 0; } } + + if(stress == PRIMARY_MARKED) + { + pitch = (t->emph_level << 8); + marking = 2; + n_primary = marking+1; // move into overflow region + } + else + if(marking > 0) + { + marking--; + pitch = (t->emph_next << 8); + } + + n_primary--; } - if(((annotation==0) && (stress >= PRIMARY)) || (stress >= PRIMARY_MARKED)) + if((annotation==0) && (stress >= PRIMARY)) + { + vowel_tab[ix] = PRIMARY_STRESSED; + set_pitch(ix,pitch,drops[stress]); + } + if(stress >= PRIMARY_MARKED) { vowel_tab[ix] = PRIMARY_MARKED; set_pitch(ix,pitch,drops[stress]); diff --git a/src/readclause.cpp b/src/readclause.cpp index 1e0f50e1..42f83b0c 100644 --- a/src/readclause.cpp +++ b/src/readclause.cpp @@ -460,15 +460,15 @@ static void UngetC(int c) const char *Translator::LookupSpecial(const char *string) {//====================================================== - unsigned int flags; + unsigned int flags[2]; char phonemes[55]; char phonemes2[55]; static char buf[60]; char *string1 = (char *)string; - if(LookupDictList(&string1,phonemes,&flags,0)) + if(LookupDictList(&string1,phonemes,flags,0,NULL)) { - SetWordStress(phonemes,flags,-1,0); + SetWordStress(phonemes,flags[0],-1,0); DecodePhonemes(phonemes,phonemes2); sprintf(buf,"[[%s]] ",phonemes2); option_phoneme_input = 1; diff --git a/src/setlengths.cpp b/src/setlengths.cpp index e2c2e86c..123f1076 100755 --- a/src/setlengths.cpp +++ b/src/setlengths.cpp @@ -499,13 +499,16 @@ void Translator::CalcLengths() if(length_mod < 8) length_mod = 8; // restrict how much lengths can be reduced - if(stress >= 7) + if(stress >= 6) { // tonic syllable, include a constant component so it doesn't decrease directly with speed length_mod += 20; } - length_mod = (length_mod * stress_lengths[stress])/128; + if((len = stress_lengths[stress]) == 0) + len = stress_lengths[6]; + + length_mod = (length_mod * len)/128; if(end_of_clause == 2) { diff --git a/src/speak.cpp b/src/speak.cpp index 7dd944f6..beb60967 100755 --- a/src/speak.cpp +++ b/src/speak.cpp @@ -630,6 +630,11 @@ int main (int argc, char **argv) exit(1); } +{ +espeak_VOICE *v; +v = espeak_GetCurrentVoice(); +printf("Voice id='%s' name='%s' langs={%x %x %x %x}\n",v->identifier,v->name,v->languages[0],v->languages[1],v->languages[2],v->languages[3]); +} if(option_waveout || quiet) { if(quiet) diff --git a/src/synthdata.cpp b/src/synthdata.cpp index 7b744faa..03cb9fc6 100755 --- a/src/synthdata.cpp +++ b/src/synthdata.cpp @@ -35,8 +35,8 @@ #include "translate.h" #include "wave.h" -const char *version_string = "1.29.23 01.Dec.07"; -const int version_phdata = 0x012901; +const char *version_string = "1.29.24 12.Dec.07"; +const int version_phdata = 0x012924; int option_device_number = -1; diff --git a/src/tr_english.cpp b/src/tr_english.cpp index 6818d584..1f53f2a4 100644 --- a/src/tr_english.cpp +++ b/src/tr_english.cpp @@ -37,7 +37,7 @@ Translator_English::Translator_English() : Translator() {//=================================== // static int stress_lengths2[8] = {182,140, 220,220, 220,240, 248,270}; - static const short stress_lengths2[8] = {182,140, 220,220, 0,0, 248,275}; + static const short stress_lengths2[8] = {182,140, 220,220, 248,248, 275,275}; memcpy(stress_lengths,stress_lengths2,sizeof(stress_lengths)); langopts.stress_rule = 0; diff --git a/src/tr_languages.cpp b/src/tr_languages.cpp index 41e85e61..5e7fef21 100644 --- a/src/tr_languages.cpp +++ b/src/tr_languages.cpp @@ -111,8 +111,8 @@ Translator *SelectTranslator(const char *name) case L('c','y'): // Welsh { - static const short stress_lengths_cy[8] = {170,230, 190,190, 0, 0, 250,270}; - static const unsigned char stress_amps_cy[8] = {16,15, 18,18, 0,0, 24,22 }; // 'diminished' is used to mark a quieter, final unstressed syllable + static const short stress_lengths_cy[8] = {170,230, 190,190, 250, 250, 270,270}; + static const unsigned char stress_amps_cy[8] = {16,15, 18,18, 20,24, 24,21 }; // 'diminished' is used to mark a quieter, final unstressed syllable tr = new Translator(); SetupTranslator(tr,stress_lengths_cy,stress_amps_cy); @@ -136,7 +136,7 @@ Translator *SelectTranslator(const char *name) case L('d','e'): { - static const short stress_lengths_de[8] = {150,130, 190,190, 0, 0, 260,275}; + static const short stress_lengths_de[8] = {150,130, 190,190, 260, 260, 275,275}; tr = new Translator(); tr->langopts.stress_rule = 0; tr->langopts.word_gap = 0x8; // don't use linking phonemes @@ -156,8 +156,8 @@ Translator *SelectTranslator(const char *name) case L('e','l'): // Greek case L_grc: // Ancient Greek { - static const short stress_lengths_el[8] = {155, 180, 210, 210, 0, 0, 270, 300}; - static const unsigned char stress_amps_el[8] = {15,12, 20,20, 20,24, 24,22 }; // 'diminished' is used to mark a quieter, final unstressed syllable + static const short stress_lengths_el[8] = {155, 180, 210, 210, 270, 270, 300, 300}; + static const unsigned char stress_amps_el[8] = {15,12, 20,20, 20,24, 24,21 }; // 'diminished' is used to mark a quieter, final unstressed syllable // character codes offset by 0x380 static const char el_vowels[] = {0x10,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x35,0x37,0x39,0x3f,0x45,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0}; @@ -199,8 +199,8 @@ Translator *SelectTranslator(const char *name) case L('e','o'): { - static const short stress_lengths_eo[8] = {145, 180, 200, 190, 0, 0, 300, 320}; - static const unsigned char stress_amps_eo[] = {16,14, 20,20, 20,24, 24,22 }; + static const short stress_lengths_eo[8] = {145, 180, 200, 190, 300, 300, 320, 320}; + static const unsigned char stress_amps_eo[] = {16,14, 20,20, 20,24, 24,21 }; static const wchar_t eo_char_apostrophe[2] = {'l',0}; tr = new Translator(); @@ -222,8 +222,8 @@ Translator *SelectTranslator(const char *name) case L('e','s'): // Spanish { - static const short stress_lengths_es[8] = {170, 200, 180, 180, 0, 0, 220, 250}; - static const unsigned char stress_amps_es[8] = {16,12, 18,18, 20,22, 22,22 }; // 'diminished' is used to mark a quieter, final unstressed syllable + static const short stress_lengths_es[8] = {170, 200, 180, 180, 220, 220, 250, 250}; + static const unsigned char stress_amps_es[8] = {16,12, 18,18, 20,22, 22,21 }; // 'diminished' is used to mark a quieter, final unstressed syllable tr = new Translator(); SetupTranslator(tr,stress_lengths_es,stress_amps_es); @@ -245,8 +245,8 @@ Translator *SelectTranslator(const char *name) case L('f','i'): // Finnish { - static const unsigned char stress_amps_fi[8] = {18,16, 22,22, 20,22, 22,22 }; - static const short stress_lengths_fi[8] = {150,170, 200,200, 0,0, 210,250}; + static const short stress_lengths_fi[8] = {150,170, 200,200, 210,210, 250,240}; + static const unsigned char stress_amps_fi[8] = {18,16, 22,22, 20,22, 22,21 }; tr = new Translator(); SetupTranslator(tr,stress_lengths_fi,stress_amps_fi); @@ -267,7 +267,7 @@ Translator *SelectTranslator(const char *name) case L('f','r'): // french { - static const short stress_lengths_fr[8] = {190, 170, 190, 200, 0, 0, 235, 235}; + static const short stress_lengths_fr[8] = {190, 170, 190, 200, 235, 235, 235, 235}; static const unsigned char stress_amps_fr[8] = {16,14, 20,20, 20,24, 24,22 }; tr = new Translator(); @@ -284,8 +284,8 @@ Translator *SelectTranslator(const char *name) case L('h','i'): { static const char dev_consonants2[] = {0x02,0x03,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f}; - static const short stress_lengths_hi[8] = {190, 190, 210, 210, 0, 0, 230, 250}; - static const unsigned char stress_amps_hi[8] = {17,14, 20,19, 20,24, 24,22 }; + static const short stress_lengths_hi[8] = {190, 190, 210, 210, 230, 230, 250, 250}; + static const unsigned char stress_amps_hi[8] = {17,14, 20,19, 20,24, 24,21 }; tr = new Translator(); SetupTranslator(tr,stress_lengths_hi,stress_amps_hi); @@ -312,8 +312,8 @@ Translator *SelectTranslator(const char *name) case L('b','s'): // Bosnian case L('s','r'): // Serbian { - static const unsigned char stress_amps_hr[8] = {16,16, 20,20, 20,24, 24,22 }; - static const short stress_lengths_hr[8] = {180,160, 200,200, 0,0, 220,230}; + static const unsigned char stress_amps_hr[8] = {16,16, 20,20, 20,24, 24,21 }; + static const short stress_lengths_hr[8] = {180,160, 200,200, 220,220, 230,230}; tr = new Translator(); SetupTranslator(tr,stress_lengths_hr,stress_amps_hr); @@ -337,8 +337,8 @@ Translator *SelectTranslator(const char *name) case L('h','u'): // Hungarian { - static const unsigned char stress_amps_hu[8] = {17,17, 19,19, 20,24, 24,22 }; - static const short stress_lengths_hu[8] = {185,195, 195,190, 0,0, 210,220}; + static const unsigned char stress_amps_hu[8] = {17,17, 19,19, 20,24, 24,21 }; + static const short stress_lengths_hu[8] = {185,195, 195,190, 210,210, 220,220}; tr = new Translator(); SetupTranslator(tr,stress_lengths_hu,stress_amps_hu); @@ -361,8 +361,8 @@ SetLengthMods(tr,3); // all equal case L('i','s'): // Icelandic { - static const unsigned char stress_amps_is[] = {16,16, 20,20, 20,24, 24,22 }; - static const short stress_lengths_is[8] = {180,160, 200,200, 0,0, 240,250}; + static const unsigned char stress_amps_is[] = {16,16, 20,20, 20,24, 24,21 }; + static const short stress_lengths_is[8] = {180,160, 200,200, 240,240, 250,250}; static const wchar_t is_lettergroup_B[] = {'c','f','h','k','p','t','x',0xfe,0}; // voiceless conants, including 'þ' ?? 's' tr = new Translator(); @@ -384,8 +384,8 @@ SetLengthMods(tr,3); // all equal case L('i','t'): // Italian { - static const short stress_lengths_it[8] = {150, 140, 180, 180, 0, 0, 270, 320}; - static const unsigned char stress_amps_it[8] = {15,14, 19,19, 20,24, 24,22 }; + static const short stress_lengths_it[8] = {150, 140, 180, 180, 270, 270, 320, 320}; + static const unsigned char stress_amps_it[8] = {15,14, 19,19, 20,24, 24,21 }; tr = new Translator(); SetupTranslator(tr,stress_lengths_it,stress_amps_it); @@ -421,8 +421,8 @@ SetLengthMods(tr,3); // all equal { static wchar_t vowels_cyrillic[] = {0x440, // also include 'р' [R] 0x430,0x435,0x438,0x439,0x43e,0x443,0x44b,0x44d,0x44e,0x44f,0x450,0x451,0x456,0x457,0x45d,0x45e,0}; - static const unsigned char stress_amps_mk[8] = {16,16, 20,20, 20,24, 24,22 }; - static const short stress_lengths_mk[8] = {180,160, 200,200, 0,0, 220,230}; + static const unsigned char stress_amps_mk[8] = {16,16, 20,20, 20,24, 24,21 }; + static const short stress_lengths_mk[8] = {180,160, 200,200, 220,220, 230,230}; tr = new Translator(); SetupTranslator(tr,stress_lengths_mk,stress_amps_mk); @@ -438,7 +438,7 @@ SetLengthMods(tr,3); // all equal case L('n','l'): // Dutch { - static const short stress_lengths_nl[8] = {160,135, 210,210, 0, 0, 260,280}; + static const short stress_lengths_nl[8] = {160,135, 210,210, 260, 260, 280,280}; tr = new Translator(); tr->langopts.stress_rule = 0; @@ -454,8 +454,8 @@ SetLengthMods(tr,3); // all equal case L('n','o'): // Norwegian { - static const unsigned char stress_amps_no[] = {16,16, 20,20, 20,24, 24,22 }; - static const short stress_lengths_no[8] = {160,140, 200,190, 0,0, 220,240}; + static const short stress_lengths_no[8] = {160,140, 200,190, 220,220, 240,240}; + static const unsigned char stress_amps_no[] = {16,16, 20,20, 20,24, 24,21 }; tr = new Translator(); SetupTranslator(tr,stress_lengths_no,stress_amps_no); @@ -467,8 +467,8 @@ SetLengthMods(tr,3); // all equal case L('p','l'): // Polish { - static const short stress_lengths_pl[8] = {160, 180, 175, 175, 0, 0, 260, 290}; - static const unsigned char stress_amps_pl[8] = {17,14, 19,19, 20,24, 24,22 }; // 'diminished' is used to mark a quieter, final unstressed syllable + static const short stress_lengths_pl[8] = {160, 180, 175, 175, 260, 260, 290, 290}; + static const unsigned char stress_amps_pl[8] = {17,14, 19,19, 20,24, 24,21 }; // 'diminished' is used to mark a quieter, final unstressed syllable tr = new Translator(); SetupTranslator(tr,stress_lengths_pl,stress_amps_pl); @@ -487,8 +487,8 @@ SetLengthMods(tr,3); // all equal case L('p','t'): // Portuguese { - static const short stress_lengths_pt[8] = {180, 125, 210, 210, 0, 0, 270, 295}; - static const unsigned char stress_amps_pt[8] = {16,13, 19,19, 20,24, 24,22 }; // 'diminished' is used to mark a quieter, final unstressed syllable + static const short stress_lengths_pt[8] = {180, 125, 210, 210, 270, 270, 295, 295}; + static const unsigned char stress_amps_pt[8] = {16,13, 19,19, 20,24, 24,21 }; // 'diminished' is used to mark a quieter, final unstressed syllable tr = new Translator(); SetupTranslator(tr,stress_lengths_pt,stress_amps_pt); tr->langopts.length_mods0 = tr->langopts.length_mods; // don't lengthen vowels in the last syllable @@ -504,8 +504,8 @@ SetLengthMods(tr,3); // all equal case L('r','o'): // Romanian { - static const short stress_lengths_ro[8] = {170, 170, 180, 180, 0, 0, 240, 260}; - static const unsigned char stress_amps_ro[8] = {15,13, 18,18, 20,22, 22,22 }; + static const short stress_lengths_ro[8] = {170, 170, 180, 180, 240, 240, 260, 260}; + static const unsigned char stress_amps_ro[8] = {15,13, 18,18, 20,22, 22,21 }; tr = new Translator(); SetupTranslator(tr,stress_lengths_ro,stress_amps_ro); @@ -526,8 +526,8 @@ SetLengthMods(tr,3); // all equal case L('s','k'): // Slovak case L('c','s'): // Czech { + static const short stress_lengths_sk[8] = {190,190, 210,210, 210,210, 210,210}; static const unsigned char stress_amps_sk[8] = {16,16, 20,20, 20,24, 24,22 }; - static const short stress_lengths_sk[8] = {190,190, 210,210, 0,0, 210,210}; static const char *sk_voiced = "bdgjlmnrvwzaeiouy"; tr = new Translator(); @@ -560,21 +560,20 @@ SetLengthMods(tr,3); // all equal case L('s','v'): // Swedish { + static const short stress_lengths_sv[8] = {160,135, 220,220, 250,250, 250,280}; static const unsigned char stress_amps_sv[] = {16,16, 20,20, 20,24, 24,22 }; - static const short stress_lengths_sv[8] = {160,135, 220,220, 0,0, 250,280}; tr = new Translator(); SetupTranslator(tr,stress_lengths_sv,stress_amps_sv); tr->langopts.stress_rule = 0; SetLetterVowel(tr,'y'); -// SetLetterBits(tr,6,"eiyäö"); // soft vowels NOTE accented letters don't work in SetLetterBits tr->langopts.numbers = 0x1109; } break; case L('s','w'): // Swahili { - static const short stress_lengths_sw[8] = {160, 170, 200, 200, 0, 0, 320, 340}; + static const short stress_lengths_sw[8] = {150, 160, 190, 190, 300, 300, 320, 320}; static const unsigned char stress_amps_sw[] = {16,12, 19,19, 20,24, 24,22 }; tr = new Translator(); @@ -592,8 +591,8 @@ SetLengthMods(tr,3); // all equal case L('t','r'): // Turkish { - static const unsigned char stress_amps_tr[8] = {16,16, 20,20, 20,24, 24,22 }; - static const short stress_lengths_tr[8] = {180,150, 200,180, 0,0, 230,270}; + static const short stress_lengths_tr[8] = {180,150, 200,180, 230,230, 270,270}; + static const unsigned char stress_amps_tr[8] = {16,16, 20,20, 20,24, 24,21 }; tr = new Translator(); SetupTranslator(tr,stress_lengths_tr,stress_amps_tr); @@ -608,7 +607,7 @@ SetLengthMods(tr,3); // all equal case L('v','i'): // Vietnamese { - static const short stress_lengths_vi[8] = {150, 150, 180, 180, 210, 220, 220, 280}; + static const short stress_lengths_vi[8] = {150, 150, 180, 180, 220, 220, 280, 280}; static const unsigned char stress_amps_vi[] = {16,16, 16,16, 24,24, 24,22 }; static wchar_t vowels_vi[] = { 0x61, 0xe0, 0xe1, 0x1ea3, 0xe3, 0x1ea1, // a @@ -642,7 +641,7 @@ SetLengthMods(tr,3); // all equal case L('z','h'): case L_zhy: { - static const short stress_lengths_zh[8] = {230,150, 230,230, 230,0, 230,250}; + static const short stress_lengths_zh[8] = {230,150, 230,230, 230,230, 250,250}; static const unsigned char stress_amps_zh[] = {22,16, 22,22, 22,22, 22,22 }; tr = new Translator; @@ -691,8 +690,8 @@ SetLengthMods(tr,3); // all equal Translator_Russian::Translator_Russian() : Translator() {//=================================== + static const short stress_lengths_ru[8] = {150,140, 220,220, 260,260, 280,280}; static const unsigned char stress_amps_ru[] = {16,16, 18,18, 20,24, 24,22 }; - static const short stress_lengths_ru[8] = {150,140, 220,220, 0,0, 260,280}; // character codes offset by 0x420 @@ -945,7 +944,7 @@ Translator_Afrikaans::Translator_Afrikaans() : Translator() {//========================================= // Initialise options for this language - static const short stress_lengths2[8] = {170,140, 220,220, 0, 0, 250,270}; + static const short stress_lengths2[8] = {170,140, 220,220, 250, 250, 270,270}; langopts.stress_rule = 0; langopts.vowel_pause = 0x30; langopts.param[LOPT_DIERESES] = 1; diff --git a/src/translate.cpp b/src/translate.cpp index 44265b95..6d86ff9f 100755 --- a/src/translate.cpp +++ b/src/translate.cpp @@ -52,7 +52,9 @@ int option_capitals = 0; int option_punctuation = 0; int option_sayas = 0; int option_sayas2 = 0; // used in translate_clause() -int option_emphasis = 0; +int option_emphasis = 0; // 0=normal, 1=normal, 2=weak, 3=moderate, 4=strong +int word_emphasis = 0; // set if emphasis level 3 or 4 +int option_emphasize_allcaps = 0; int option_ssml = 0; int option_phoneme_input = 1; // allow [[phonemes]] in input int option_phoneme_variants = 0; // 0= don't display phoneme variant mnemonics @@ -394,7 +396,7 @@ Translator::Translator() {//===================== int ix; static const unsigned char stress_amps2[] = {16,16, 20,20, 20,24, 24,21 }; - static const short stress_lengths2[8] = {182,140, 220,220, 220,240, 260,280}; + static const short stress_lengths2[8] = {182,140, 220,220, 250,260, 280,280}; static const wchar_t empty_wstring[1] = {0}; charset_a0 = charsets[1]; // ISO-8859-1, this is for when the input is not utf8 @@ -595,8 +597,8 @@ int Translator::TranslateWord(char *word1, int next_pause, WORD_TAB *wtab) int word_length; int ix; int posn; - unsigned int dictionary_flags=0; - unsigned int dictionary_flags2=0; + unsigned int dictionary_flags[2]; + unsigned int dictionary_flags2[2]; int end_type=0; int prefix_type=0; char *wordx; @@ -616,6 +618,7 @@ int Translator::TranslateWord(char *word1, int next_pause, WORD_TAB *wtab) int prefix_flags = 0; int confirm_prefix; int spell_word; + int emphasize_allcaps = 0; int wflags = wtab->flags; int wmark = wtab->wmark; @@ -625,6 +628,12 @@ int Translator::TranslateWord(char *word1, int next_pause, WORD_TAB *wtab) static char word_iz[4] = {0,'i','z',0}; static char word_ss[4] = {0,'s','s',0}; + dictionary_flags[0] = 0; + dictionary_flags[1] = 0; + dictionary_flags2[0] = 0; + dictionary_flags2[1] = 0; + dictionary_skipwords = 0; + prefix_phonemes[0] = 0; end_phonemes[0] = 0; ph_limit = &phonemes[N_WORD_PHONEMES]; @@ -649,7 +658,7 @@ int Translator::TranslateWord(char *word1, int next_pause, WORD_TAB *wtab) else { spell_word = 0; - found = LookupDictList(&word1,phonemes,&dictionary_flags,FLAG_ALLOW_TEXTMODE | wflags << 16); // the original word + found = LookupDictList(&word1, phonemes, dictionary_flags, FLAG_ALLOW_TEXTMODE, wtab); // the original word if(phonemes[0] == phonSWITCH) { @@ -661,10 +670,10 @@ int Translator::TranslateWord(char *word1, int next_pause, WORD_TAB *wtab) if((wmark > 0) && (wmark < 8)) { // the stressed syllable has been specified in the text (TESTING) - dictionary_flags = (dictionary_flags & ~0xf) | wmark; + dictionary_flags[0] = (dictionary_flags[0] & ~0xf) | wmark; } - if(!found && (dictionary_flags & FLAG_ABBREV)) + if(!found && (dictionary_flags[0] & FLAG_ABBREV)) { // the word has $abbrev flag, but no pronunciation specified. Speak as individual letters spell_word = 1; @@ -676,7 +685,7 @@ if((wmark > 0) && (wmark < 8)) if(word_phonemes[0] == phonSWITCH) return(0); - found = TranslateNumber(word1,phonemes,&dictionary_flags,wflags); + found = TranslateNumber(word1,phonemes,dictionary_flags,wflags); } if(!found & ((word_flags & FLAG_UPPERS) != FLAG_FIRST_UPPER)) @@ -686,15 +695,23 @@ if((wmark > 0) && (wmark < 8)) if((langopts.numbers & NUM_ROMAN) || ((langopts.numbers & NUM_ROMAN_UC) && (word_flags & FLAG_ALL_UPPER))) { if((found = TranslateRoman(word1,phonemes)) != 0) - dictionary_flags |= FLAG_ABBREV; // don't spell capital Roman numbers as individual letters + dictionary_flags[0] |= FLAG_ABBREV; // prevent emphasis if capitals } } - if((wflags & FLAG_ALL_UPPER) && (clause_upper_count <= clause_lower_count) && - !(dictionary_flags & (FLAG_ABBREV | FLAG_SKIPWORDS)) && (word_length>1) && (word_length<4) && iswalpha(first_char)) + if((wflags & FLAG_ALL_UPPER) && (word_length > 1) && (clause_lower_count > 3) && iswalpha(first_char)) { - // An upper case word in a lower case clause. This could be an abbreviation. - spell_word = 1; + if((option_emphasize_allcaps) && !(dictionary_flags[0] & FLAG_ABBREV)) + { + // emphasize words which are in capitals + emphasize_allcaps = FLAG_EMPHASIZED; + } + else + if(!found && !(dictionary_flags[0] & FLAG_SKIPWORDS) && (word_length<4) && (clause_upper_count <= clause_lower_count)) + { + // An upper case word in a lower case clause. This could be an abbreviation. + spell_word = 1; + } } } @@ -733,6 +750,7 @@ if((wmark > 0) && (wmark < 8)) char *p; // This word looks "unpronouncable", so speak letters individually until we // find a remainder that we can pronounce. + emphasize_allcaps = 0; wordx += TranslateLetter(wordx,phonemes,0); if(phonemes[0] == phonSWITCH) { @@ -763,7 +781,7 @@ if((wmark > 0) && (wmark < 8)) { // Translate the stem unpron_length = strlen(phonemes); - end_type = TranslateRules(wordx, phonemes, N_WORD_PHONEMES, end_phonemes, wflags, dictionary_flags); + end_type = TranslateRules(wordx, phonemes, N_WORD_PHONEMES, end_phonemes, wflags, dictionary_flags[0]); if(phonemes[0] == phonSWITCH) { @@ -788,11 +806,11 @@ if((wmark > 0) && (wmark < 8)) // remove any standard suffix and confirm that the prefix is still recognised phonemes2[0] = 0; - end2 = TranslateRules(wordx, phonemes2, N_WORD_PHONEMES, end_phonemes2, wflags|FLAG_NO_PREFIX|FLAG_NO_TRACE, dictionary_flags); + end2 = TranslateRules(wordx, phonemes2, N_WORD_PHONEMES, end_phonemes2, wflags|FLAG_NO_PREFIX|FLAG_NO_TRACE, dictionary_flags[0]); if(end2) { RemoveEnding(wordx,end2,word_copy); - end_type = TranslateRules(wordx, phonemes, N_WORD_PHONEMES, end_phonemes, wflags|FLAG_NO_TRACE, dictionary_flags); + end_type = TranslateRules(wordx, phonemes, N_WORD_PHONEMES, end_phonemes, wflags|FLAG_NO_TRACE, dictionary_flags[0]); memcpy(wordx,word_copy,strlen(word_copy)); if((end_type & SUFX_P) == 0) { @@ -832,14 +850,17 @@ if((wmark > 0) && (wmark < 8)) confirm_prefix = 1; end_type = 0; - found = LookupDictList(&wordx,phonemes,&dictionary_flags2,SUFX_P | (wflags << 16)); // without prefix - if(dictionary_flags==0) - dictionary_flags = dictionary_flags2; + found = LookupDictList(&wordx, phonemes, dictionary_flags2, SUFX_P, wtab); // without prefix + if(dictionary_flags[0]==0) + { + dictionary_flags[0] = dictionary_flags2[0]; + dictionary_flags[1] = dictionary_flags2[1]; + } else prefix_flags = 1; if(found == 0) { - end_type = TranslateRules(wordx, phonemes, N_WORD_PHONEMES, end_phonemes, 0, dictionary_flags); + end_type = TranslateRules(wordx, phonemes, N_WORD_PHONEMES, end_phonemes, 0, dictionary_flags[0]); if(phonemes[0] == phonSWITCH) { @@ -866,19 +887,22 @@ strcpy(phonemes2,phonemes); { // lookup the stem without the prefix removed wordx[-1] = c_temp; - found = LookupDictList(&word1,phonemes_ptr,&dictionary_flags2,end_flags | (wflags << 16)); // include prefix, but not suffix + found = LookupDictList(&word1, phonemes_ptr, dictionary_flags2, end_flags, wtab); // include prefix, but not suffix wordx[-1] = ' '; - if(dictionary_flags==0) - dictionary_flags = dictionary_flags2; + if(dictionary_flags[0]==0) + { + dictionary_flags[0] = dictionary_flags2[0]; + dictionary_flags[1] = dictionary_flags2[1]; + } if(found) prefix_phonemes[0] = 0; // matched whole word, don't need prefix now - if((found==0) && (dictionary_flags2 != 0)) + if((found==0) && (dictionary_flags2[0] != 0)) prefix_flags = 1; } if(found == 0) { - found = LookupDictList(&wordx,phonemes_ptr,&dictionary_flags2,end_flags | (wflags << 16)); // without prefix and suffix + found = LookupDictList(&wordx, phonemes_ptr, dictionary_flags2, end_flags, wtab); // without prefix and suffix if(phonemes_ptr[0] == phonSWITCH) { // change to another language in order to translate this word @@ -886,8 +910,11 @@ strcpy(phonemes2,phonemes); strcpy(word_phonemes,phonemes_ptr); return(0); } - if(dictionary_flags==0) - dictionary_flags = dictionary_flags2; + if(dictionary_flags[0]==0) + { + dictionary_flags[0] = dictionary_flags2[0]; + dictionary_flags[1] = dictionary_flags2[1]; + } } if(found == 0) { @@ -897,14 +924,14 @@ strcpy(phonemes2,phonemes); strcpy(phonemes,phonemes2); // language specific changes - ApplySpecialAttribute(phonemes,dictionary_flags); + ApplySpecialAttribute(phonemes,dictionary_flags[0]); } else { if(end_flags & FLAG_SUFX) - TranslateRules(wordx, phonemes, N_WORD_PHONEMES, NULL,wflags | FLAG_SUFFIX_REMOVED, dictionary_flags); + TranslateRules(wordx, phonemes, N_WORD_PHONEMES, NULL,wflags | FLAG_SUFFIX_REMOVED, dictionary_flags[0]); else - TranslateRules(wordx, phonemes, N_WORD_PHONEMES, NULL,wflags,dictionary_flags); + TranslateRules(wordx, phonemes, N_WORD_PHONEMES, NULL,wflags,dictionary_flags[0]); if(phonemes[0] == phonSWITCH) { @@ -940,6 +967,8 @@ strcpy(phonemes2,phonemes); TranslateRules(&word_iz[1], phonemes, N_WORD_PHONEMES, NULL, 0, 0); } + wflags |= emphasize_allcaps; + /* determine stress pattern for this word */ /******************************************/ @@ -951,7 +980,7 @@ strcpy(phonemes2,phonemes); { char *p; // German, keep a secondary stress on the stem - SetWordStress(phonemes,dictionary_flags,3,0); + SetWordStress(phonemes,dictionary_flags[0],3,0); // reduce all but the first primary stress ix=0; @@ -967,22 +996,22 @@ strcpy(phonemes2,phonemes); } strcpy(word_phonemes,prefix_phonemes); strcat(word_phonemes,phonemes); - SetWordStress(word_phonemes,dictionary_flags,-1,0); + SetWordStress(word_phonemes,dictionary_flags[0],-1,0); } else { // stress position affects the whole word, including prefix strcpy(word_phonemes,prefix_phonemes); strcat(word_phonemes,phonemes); - SetWordStress(word_phonemes,dictionary_flags,-1,prev_last_stress); + SetWordStress(word_phonemes,dictionary_flags[0],-1,prev_last_stress); } } else { if(prefix_phonemes[0] == 0) - SetWordStress(phonemes,dictionary_flags,-1,prev_last_stress); + SetWordStress(phonemes,dictionary_flags[0],-1,prev_last_stress); else - SetWordStress(phonemes,dictionary_flags,-1,0); + SetWordStress(phonemes,dictionary_flags[0],-1,0); strcpy(word_phonemes,prefix_phonemes); strcat(word_phonemes,phonemes); } @@ -993,26 +1022,23 @@ strcpy(phonemes2,phonemes); strcat(word_phonemes,end_phonemes); } -// if(next_pause > 2) - ix = ((dictionary_flags >> 5) & 7); // dictionary indicates skip next word(s) - if(wtab[ix].flags & FLAG_LAST_WORD) - { - // the word has attribute to stress or unstress when at end of clause - if(dictionary_flags & (FLAG_STRESS_END | FLAG_STRESS_END2)) - ChangeWordStress(this,word_phonemes,4); -// SetWordStress(word_phonemes,0,4,prev_last_stress); - else - if(dictionary_flags & FLAG_UNSTRESS_END) - ChangeWordStress(this,word_phonemes,3); -// SetWordStress(word_phonemes,0,3,prev_last_stress); - } - if(wflags & FLAG_STRESSED_WORD) + if(wflags & FLAG_EMPHASIZED) { // A word is indicated in the source text as stressed // we need to improve the intonation module to deal better with a clauses tonic // stress being early in the clause, before enabling this - //SetWordStress(word_phonemes,0,5,prev_last_stress); + ChangeWordStress(this,word_phonemes,6); + } + else + if(wtab[dictionary_skipwords].flags & FLAG_LAST_WORD) + { + // the word has attribute to stress or unstress when at end of clause + if(dictionary_flags[0] & (FLAG_STRESS_END | FLAG_STRESS_END2)) + ChangeWordStress(this,word_phonemes,4); + else + if(dictionary_flags[0] & FLAG_UNSTRESS_END) + ChangeWordStress(this,word_phonemes,3); } // dictionary flags for this word give a clue about which alternative pronunciations of @@ -1024,56 +1050,63 @@ strcpy(phonemes2,phonemes); expect_verb_s = 2; } - if(dictionary_flags & FLAG_PASTF) + if(dictionary_flags[1] & FLAG_PASTF) { /* expect perfect tense in next two words */ expect_past = 3; expect_verb = 0; + expect_noun = 0; } else - if(dictionary_flags & FLAG_VERBF) + if(dictionary_flags[1] & FLAG_VERBF) { /* expect a verb in the next word */ expect_verb = 2; expect_verb_s = 0; /* verb won't have -s suffix */ + expect_noun = 0; } else - if(dictionary_flags & FLAG_VERBSF) + if(dictionary_flags[1] & FLAG_VERBSF) { // expect a verb, must have a -s suffix expect_verb = 0; expect_verb_s = 2; expect_past = 0; + expect_noun = 0; } else - if(dictionary_flags & FLAG_NOUNF) + if(dictionary_flags[1] & FLAG_NOUNF) { /* not expecting a verb next */ + expect_noun = 3; expect_verb = 0; expect_verb_s = 0; expect_past = 0; } - if((wordx[0] != 0) && (!(dictionary_flags & FLAG_VERB_EXT))) + if((wordx[0] != 0) && (!(dictionary_flags[1] & FLAG_VERB_EXT))) { if(expect_verb > 0) - expect_verb -= 1; + expect_verb--; if(expect_verb_s > 0) - expect_verb_s -= 1; + expect_verb_s--; + + if(expect_noun >0) + expect_noun--; if(expect_past > 0) - expect_past -= 1; + expect_past--; } if((word_length == 1) && iswalpha(first_char) && (first_char != 'i')) { // English Specific !!!! // any single letter before a dot is an abbreviation, except 'I' - dictionary_flags |= FLAG_DOT; + dictionary_flags[0] |= FLAG_DOT; } - return(dictionary_flags); + return(dictionary_flags[0]); } // end of TranslateWord @@ -1565,12 +1598,20 @@ static int EmbeddedCommand(unsigned int &source_index) option_sayas2 = value; count_sayas_digits = 0; } + if(cmd == EMBED_F) + { + if(value >= 3) + word_emphasis = FLAG_EMPHASIZED; + else + word_emphasis = 0; + } embedded_list[embedded_ix++] = cmd + sign + (value << 8); return(1); } // end of EmbeddedCommand + int SubstituteChar(Translator *tr, unsigned int c, unsigned int next_in, int *insert) {//================================================================================== int ix; @@ -1752,6 +1793,7 @@ void *Translator::TranslateClause(FILE *f_text, const void *vp_input, int *tone_ word_flags = 0; next_word_flags = 0; expect_verb=0; + expect_noun=0; expect_past=0; expect_verb_s=0; end_stressed_vowel=0; @@ -2144,7 +2186,7 @@ if((c == '/') && (langopts.testing & 2) && IsDigit09(next_in) && IsAlpha(prev_ou embedded_count = 0; } words[word_count].pre_pause = pre_pause; - words[word_count].flags |= (all_upper_case | word_flags); + words[word_count].flags |= (all_upper_case | word_flags | word_emphasis); words[word_count].wmark = word_mark; if(pre_pause > 0) @@ -2342,6 +2384,7 @@ void InitText(int control) option_sayas = 0; option_sayas2 = 0; option_emphasis = 0; + word_emphasis = 0; InitText2(); diff --git a/src/translate.h b/src/translate.h index b32ce27d..dcfffc4c 100755 --- a/src/translate.h +++ b/src/translate.h @@ -32,7 +32,7 @@ #define N_LETTER_GROUPS 20 -/* flags from word dictionary */ +/* dictionary flags, word 1 */ // bits 0-3 stressed syllable, 7=unstressed #define FLAG_SKIPWORDS 0x80 #define FLAG_PREPAUSE 0x100 @@ -47,7 +47,6 @@ #define FLAG_UNSTRESS_END 0x2000 /* reduce stress at end of clause */ #define FLAG_ATEND 0x4000 /* use this pronunciation if at end of clause */ -#define FLAG_CAPITAL 0x8000 /* pronunciation if initial letter is upper case */ #define FLAG_DOT 0x10000 /* ignore '.' after word (abbreviation) */ #define FLAG_ABBREV 0x20000 // spell as letters, even with a vowel, OR use specified pronunciation rather than split into letters #define FLAG_STEM 0x40000 // must have a suffix @@ -56,19 +55,27 @@ #define FLAG_ALT_TRANS 0x100000 // language specific #define FLAG_ALT2_TRANS 0x200000 // language specific -#define FLAG_VERBF 0x400000 /* verb follows */ -#define FLAG_VERBSF 0x800000 /* verb follows, may have -s suffix */ -#define FLAG_NOUNF 0x1000000 /* noun follows */ -#define FLAG_VERB 0x2000000 /* pronunciation for verb */ -#define FLAG_PAST 0x4000000 /* pronunciation for past tense */ -#define FLAG_PASTF 0x8000000 /* past tense follows */ -#define FLAG_VERB_EXT 0x10000000 /* extend the 'verb follows' */ +#define FLAG_PAUSE1 0x10000000 // shorter prepause #define FLAG_TEXTMODE 0x20000000 // word translates to replacement text, not phonemes #define BITNUM_FLAG_TEXTMODE 29 -#define FLAG_PAUSE1 0x40000000 // shorter prepause -#define FLAG_FOUND 0x80000000 /* pronunciation was found in the dictionary list */ +#define FLAG_FOUND_ATTRIBUTES 0x40000000 // word was found in the dictionary list (has attributes) +#define FLAG_FOUND 0x80000000 // pronunciation was found in the dictionary list + +// dictionary flags, word 2 +#define FLAG_VERBF 0x1 /* verb follows */ +#define FLAG_VERBSF 0x2 /* verb follows, may have -s suffix */ +#define FLAG_NOUNF 0x4 /* noun follows */ +#define FLAG_PASTF 0x8 /* past tense follows */ +#define FLAG_VERB 0x10 /* pronunciation for verb */ +#define FLAG_NOUN 0x20 /* pronunciation for noun */ +#define FLAG_PAST 0x40 /* pronunciation for past tense */ +#define FLAG_VERB_EXT 0x100 /* extend the 'verb follows' */ +#define FLAG_CAPITAL 0x200 /* pronunciation if initial letter is upper case */ +#define FLAG_ALLCAPS 0x400 // only if the word is all capitals + + // wordflags, flags in source word #define FLAG_ALL_UPPER 0x1 /* no lower case letters in the word */ @@ -77,15 +84,17 @@ #define FLAG_HAS_PLURAL 0x4 /* upper-case word with s or 's lower-case ending */ #define FLAG_PHONEMES 0x8 /* word is phonemes */ #define FLAG_LAST_WORD 0x10 /* last word in clause */ -#define FLAG_STRESSED_WORD 0x20 /* this word has explicit stress */ +//#define FLAG_STRESSED_WORD 0x20 /* this word has explicit stress */ #define FLAG_EMBEDDED 0x40 /* word is preceded by embedded commands */ #define FLAG_HYPHEN 0x80 #define FLAG_NOSPACE 0x100 // word is not seperated from previous word by a space #define FLAG_DONT_SWITCH_TRANSLATOR 0x1000 #define FLAG_SUFFIX_REMOVED 0x2000 #define FLAG_HYPHEN_AFTER 0x4000 -#define FLAG_NO_PREFIX 0x8000 -#define FLAG_NO_TRACE 0x10000 +#define FLAG_EMPHASIZED 0x8000 + +#define FLAG_NO_TRACE 0x10000 // passed to TranslateRules() to suppress dictionary lookup printout +#define FLAG_NO_PREFIX 0x20000 // prefix/suffix flags (bits 8 to 14, bits 16 to 22) don't use 0x8000, 0x800000 #define SUFX_E 0x0100 // e may have been added @@ -394,7 +403,7 @@ private: int ReadClause(FILE *f_in, char *buf, unsigned short *charix, int n_buf); int AnnouncePunctuation(int c1, int c2, char *buf, int ix); - const char *LookupDict2(const char *word, const char *word2, char *phonetic, unsigned int *flags, int end_flags); + const char *LookupDict2(const char *word, const char *word2, char *phonetic, unsigned int *flags, int end_flags, WORD_TAB *wtab); const char *LookupSpecial(const char *string); const char *LookupCharName(int c); int LookupNum2(int value, int control, char *ph_out); @@ -424,7 +433,7 @@ protected: virtual int ChangePhonemes(PHONEME_LIST2 *phlist, int n_ph, int index, PHONEME_TAB *ph, CHANGEPH *ch); int IsVowel(int letter); - int LookupDictList(char **wordptr, char *ph_out, unsigned int *flags, int end_flags); + int LookupDictList(char **wordptr, char *ph_out, unsigned int *flags, int end_flags, WORD_TAB *wtab); int Lookup(const char *word, char *ph_out); @@ -448,6 +457,7 @@ protected: int expect_verb; int expect_past; // expect past tense int expect_verb_s; + int expect_noun; int word_flags; // word is all upper case int prev_last_stress; int prepause_timeout; diff --git a/src/voices.cpp b/src/voices.cpp index d9b09c79..e98c376c 100755 --- a/src/voices.cpp +++ b/src/voices.cpp @@ -161,6 +161,25 @@ const char *variant_lists[3] = {variants_either, variants_male, variants_female} voice_t voicedata; voice_t *voice = &voicedata; +char *fgets_strip(char *buf, int size, FILE *f_in) +{//=============================================== +// strip trailing spaces, and truncate lines at // comment + int len; + char *p; + + if(fgets(buf,size,f_in) == NULL) + return(NULL); + + len = strlen(buf); + while((--len > 0) && isspace(buf[len])) + buf[len] = 0; + + if((p = strstr(buf,"//")) != NULL) + *p = 0; + + return(buf); +} + void SetToneAdjust(voice_t *voice, int *tone_pts) {//============================================== @@ -257,10 +276,8 @@ static espeak_VOICE *ReadVoiceFile(FILE *f_in, const char *fname, const char*lea vgender[0] = 0; age = 0; - while(fgets(linebuf,sizeof(linebuf),f_in) != NULL) + while(fgets_strip(linebuf,sizeof(linebuf),f_in) != NULL) { - linebuf[strlen(linebuf)-1] = 0; - if(memcmp(linebuf,"name",4)==0) { p = &linebuf[4]; @@ -571,11 +588,8 @@ voice_t *LoadVoice(const char *vname, int control) SelectPhonemeTableName(phonemes_name); // set up phoneme_tab - while((f_voice != NULL) && (fgets(buf,sizeof(buf),f_voice) != NULL)) + while((f_voice != NULL) && (fgets_strip(buf,sizeof(buf),f_voice) != NULL)) { - if((p = strstr(buf,"//")) != NULL) - *p = 0; - // isolate the attribute name for(p=buf; (*p != 0) && !isspace(*p); p++); *p++ = 0; diff --git a/src/wavegen.cpp b/src/wavegen.cpp index d8df444e..6936cc5a 100755 --- a/src/wavegen.cpp +++ b/src/wavegen.cpp @@ -787,7 +787,7 @@ int GetAmplitude(void) int amp; // normal, none, reduced, moderate, strong - static const unsigned char amp_emphasis[5] = {16, 16, 8, 24, 32}; + static const unsigned char amp_emphasis[5] = {16, 16, 8, 16, 26}; amp = (embedded_value[EMBED_A])*60/100; general_amplitude = amp * amp_emphasis[embedded_value[EMBED_F]] / 16;