mirror of
https://github.com/rhasspy/espeak-ng.git
synced 2026-11-14 01:32:29 +00:00
[1.45.04] release
Don't speak punctuation names faster at high speeds. lang=ml, recognise "virama + U+200d" (zero-width joiner) to indicte 'chillu' characters. Fix problem of punctuation character announcement repeated at the start of the next sentence after speaking is stopped. Fixed crash due to large numbers of box-drawing characters in text input. Fixed phoneme translation of 't' sounds for US-English voices. git-svn-id: https://espeak.svn.sourceforge.net/svnroot/espeak/trunk@261 d46cf337-b52f-0410-862d-fd96e6ae7743
This commit is contained in:
+2
-2
@@ -524,7 +524,7 @@ step=1; // TEST
|
||||
{
|
||||
multiple_numeric_hyphen = 1;
|
||||
}
|
||||
else
|
||||
// else // ???
|
||||
{
|
||||
flag_codes[n_flag_codes++] = BITNUM_FLAG_HYPHENATED;
|
||||
}
|
||||
@@ -739,7 +739,7 @@ step=1; // TEST
|
||||
ix = multiple_string_end - multiple_string;
|
||||
if(multiple_numeric_hyphen)
|
||||
{
|
||||
dict_line[length++] = ' ';
|
||||
dict_line[length++] = ' '; // ???
|
||||
}
|
||||
memcpy(&dict_line[length],multiple_string,ix);
|
||||
length += ix;
|
||||
|
||||
+3
-3
@@ -1185,8 +1185,8 @@ void SetWordStress(Translator *tr, char *output, unsigned int *dictionary_flags,
|
||||
switch(tr->langopts.stress_rule)
|
||||
{
|
||||
case 8:
|
||||
// stress on first syllable, unless it is a light syllable
|
||||
if(syllable_weight[1] > 0)
|
||||
// stress on first syllable, unless it is a light syllable followed by a heavy syllable
|
||||
if((syllable_weight[1] > 0) || (syllable_weight[2] == 0))
|
||||
break;
|
||||
// else drop through to case 1
|
||||
case 1:
|
||||
@@ -3250,7 +3250,7 @@ int LookupDictList(Translator *tr, char **wordptr, char *ph_out, unsigned int *f
|
||||
}
|
||||
}
|
||||
|
||||
for(length=0; length<N_WORD_BYTES; length++)
|
||||
for(length=0; length<(N_WORD_BYTES-1); length++)
|
||||
{
|
||||
if(((c = *word1++)==0) || (c == ' '))
|
||||
break;
|
||||
|
||||
+12
-1
@@ -171,6 +171,7 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
|
||||
// set consonant clusters to all voiced or all unvoiced
|
||||
// Regressive
|
||||
int type;
|
||||
int word_end_devoice = 0;
|
||||
voicing = 0;
|
||||
|
||||
for(j=n_ph_list2-1; j>=0; j--)
|
||||
@@ -190,7 +191,12 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
|
||||
{
|
||||
// LANG=Russian, [v] amd [v;] don't cause regression, or [R^]
|
||||
if((ph->mnemonic == 'v') || (ph->mnemonic == ((';'<<8)+'v')) || ((ph->mnemonic & 0xff)== 'R'))
|
||||
type = phLIQUID;
|
||||
{
|
||||
if(word_end_devoice == 1)
|
||||
voicing = 0;
|
||||
else
|
||||
type = phLIQUID;
|
||||
}
|
||||
}
|
||||
|
||||
if((type==phSTOP) || type==(phFRICATIVE))
|
||||
@@ -231,6 +237,8 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
|
||||
voicing = 0;
|
||||
}
|
||||
}
|
||||
|
||||
word_end_devoice = 0;
|
||||
if(plist2[j].sourceix)
|
||||
{
|
||||
if(regression & 0x04)
|
||||
@@ -242,7 +250,10 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
|
||||
{
|
||||
// devoice word-final consonants, unless propagating voiced
|
||||
if(voicing == 0)
|
||||
{
|
||||
voicing = 1;
|
||||
word_end_devoice = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+38
-11
@@ -364,10 +364,10 @@ int towlower2(unsigned int c)
|
||||
{
|
||||
c = 0x131; // I -> ı
|
||||
}
|
||||
}
|
||||
#ifdef __WIN32__
|
||||
if(c == 0x130) // uppercase i-dot
|
||||
return('i');
|
||||
}
|
||||
#ifdef __WIN32__
|
||||
if(c == 0x130) // uppercase i-dot
|
||||
return('i');
|
||||
#endif
|
||||
return(towlower(c));
|
||||
}
|
||||
@@ -901,14 +901,21 @@ static int AnnouncePunctuation(Translator *tr, int c1, int *c2_ptr, char *output
|
||||
else
|
||||
if(punct_count < 4)
|
||||
{
|
||||
sprintf(buf,"\001+10S");
|
||||
buf[0] = 0;
|
||||
if(embedded_value[EMBED_S] < 300)
|
||||
sprintf(buf,"\001+10S"); // Speak punctuation name faster, unless we are already speaking fast. It would upset Sonic SpeedUp
|
||||
|
||||
while(punct_count-- > 0)
|
||||
{
|
||||
sprintf(buf2," %s",punctname);
|
||||
strcat(buf, buf2);
|
||||
}
|
||||
sprintf(buf2," \001-10S");
|
||||
strcat(buf, buf2);
|
||||
|
||||
if(embedded_value[EMBED_S] < 300)
|
||||
{
|
||||
sprintf(buf2," \001-10S");
|
||||
strcat(buf, buf2);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2000,6 +2007,15 @@ terminator=0; // ?? Sentence intonation, but no pause ??
|
||||
} // end of ProcessSsmlTag
|
||||
|
||||
|
||||
static void RemoveChar(char *p)
|
||||
{//=======================
|
||||
// Replace a UTF-8 character by spaces
|
||||
int c;
|
||||
|
||||
memset(p, ' ', utf8_in(&c, p));
|
||||
} // end of RemoveChar
|
||||
|
||||
|
||||
static MNEM_TAB xml_char_mnemonics[] = {
|
||||
{"gt",'>'},
|
||||
{"lt", 0xe000 + '<'}, // private usage area, to avoid confusion with XML tag
|
||||
@@ -2354,6 +2370,15 @@ f_input = f_in; // for GetC etc
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(c1 == 0xd4d)
|
||||
{
|
||||
// Malayalam virama, check if next character is Zero-width-joiner
|
||||
if(c2 == 0x200d)
|
||||
{
|
||||
c1 = 0xd4e; // use this unofficial code for chillu-virama
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(iswupper(c1))
|
||||
@@ -2408,8 +2433,9 @@ f_input = f_in; // for GetC etc
|
||||
UngetC(c2);
|
||||
|
||||
if(end_clause_after_tag)
|
||||
ix = end_clause_index; // delete clause-end punctiation
|
||||
|
||||
{
|
||||
RemoveChar(&buf[end_clause_index]); // delete clause-end punctiation
|
||||
}
|
||||
buf[ix] = ' ';
|
||||
buf[ix+1] = 0;
|
||||
if(parag > 3)
|
||||
@@ -2485,7 +2511,7 @@ if(option_ssml) parag=1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if((iswspace(c2) || (punct_data & 0x8000) || IsBracket(c2) || (c2=='?') || Eof())) // don't check for '-' because if prevent recognizing ':-)'
|
||||
if((iswspace(c2) || (punct_data & 0x8000) || IsBracket(c2) || (c2=='?') || Eof() || (c2 == ctrl_embedded))) // don't check for '-' because it prevents recognizing ':-)'
|
||||
// if((iswspace(c2) || (punct_data & 0x8000) || IsBracket(c2) || (c2=='?') || (c2=='-') || Eof()))
|
||||
{
|
||||
// note: (c2='?') is for when a smart-quote has been replaced by '?'
|
||||
@@ -2682,7 +2708,7 @@ if(option_ssml) parag=1;
|
||||
}
|
||||
if(end_clause_after_tag)
|
||||
{
|
||||
ix = end_clause_index; // delete clause-end punctuation
|
||||
RemoveChar(&buf[end_clause_index]); // delete clause-end punctiation
|
||||
}
|
||||
buf[ix] = ' ';
|
||||
buf[ix+1] = 0;
|
||||
@@ -2707,6 +2733,7 @@ void InitText2(void)
|
||||
int param;
|
||||
|
||||
ungot_char = 0;
|
||||
ungot_char2 = 0;
|
||||
|
||||
n_ssml_stack =1;
|
||||
n_param_stack = 1;
|
||||
|
||||
+4
-1
@@ -141,6 +141,7 @@ void SetSpeed(int control)
|
||||
int s1;
|
||||
int wpm;
|
||||
int wpm2;
|
||||
int wpm_value;
|
||||
double sonic;
|
||||
|
||||
speed.loud_consonants = 0;
|
||||
@@ -153,6 +154,8 @@ void SetSpeed(int control)
|
||||
if(control == 2)
|
||||
wpm = embedded_value[EMBED_S2];
|
||||
|
||||
wpm_value = wpm;
|
||||
|
||||
if(voice->speed_percent > 0)
|
||||
{
|
||||
wpm = (wpm * voice->speed_percent)/100;
|
||||
@@ -162,7 +165,7 @@ void SetSpeed(int control)
|
||||
{
|
||||
DoSonicSpeed(1 * 1024);
|
||||
}
|
||||
if((wpm > 450) || ((wpm > speed.fast_settings[0]) && (wpm > 350)))
|
||||
if((wpm_value > 450) || ((wpm_value > speed.fast_settings[0]) && (wpm > 350)))
|
||||
{
|
||||
wpm2 = wpm;
|
||||
wpm = 175;
|
||||
|
||||
@@ -151,7 +151,10 @@ espeak_ERROR LoadMbrolaTable(const char *mbrola_voice, const char *phtrans, int
|
||||
#endif
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
if(load_MBR() == FALSE) // load mbrola.dll
|
||||
return(EE_INTERNAL_ERROR);
|
||||
{
|
||||
fprintf(stderr, "Can't load mbrola.dll\n");
|
||||
return(EE_INTERNAL_ERROR);
|
||||
}
|
||||
#endif
|
||||
|
||||
if(init_MBR(path) != 0) // initialise the required mbrola voice
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@
|
||||
#include "translate.h"
|
||||
#include "wave.h"
|
||||
|
||||
const char *version_string = "1.45.12 01.Apr.11";
|
||||
const char *version_string = "1.45.04 25.Apr.11";
|
||||
const int version_phdata = 0x014500;
|
||||
|
||||
int option_device_number = -1;
|
||||
|
||||
@@ -385,6 +385,7 @@ Translator *SelectTranslator(const char *name)
|
||||
|
||||
case L('a','r'): // Arabic
|
||||
tr->letter_bits_offset = OFFSET_ARABIC;
|
||||
tr->langopts.numbers = NUM_SWAP_TENS | NUM_AND_UNITS | NUM_HUNDRED_AND | NUM_OMIT_1_HUNDRED | NUM_AND_HUNDRED | NUM_THOUSAND_AND | NUM_OMIT_1_THOUSAND;
|
||||
tr->langopts.param[LOPT_UNPRONOUNCABLE] = 1; // disable check for unpronouncable words
|
||||
break;
|
||||
|
||||
@@ -393,7 +394,7 @@ Translator *SelectTranslator(const char *name)
|
||||
SetCyrillicLetters(tr);
|
||||
SetLetterVowel(tr,0x2a);
|
||||
tr->langopts.param[LOPT_UNPRONOUNCABLE] = 0x432; // [v] don't count this character at start of word
|
||||
tr->langopts.param[LOPT_REGRESSIVE_VOICING] = 0x10; // devoice at end of word
|
||||
tr->langopts.param[LOPT_REGRESSIVE_VOICING] = 0x17; // devoice at end of word, and change voicing to match a following consonant (except v)
|
||||
tr->langopts.param[LOPT_REDUCE] = 2;
|
||||
tr->langopts.stress_rule = STRESSPOSN_2R;
|
||||
tr->langopts.numbers = NUM_DECIMAL_COMMA | NUM_ALLOW_SPACE | NUM_OMIT_1_HUNDRED | NUM_HUNDRED_AND | NUM_AND_UNITS | NUM_SINGLE_AND | NUM_ROMAN | NUM_ROMAN_ORDINAL | NUM_ROMAN_CAPITALS ;
|
||||
@@ -470,7 +471,8 @@ Translator *SelectTranslator(const char *name)
|
||||
tr->langopts.param[LOPT_REGRESSIVE_VOICING] = 0x10; // devoice at end of word
|
||||
tr->langopts.param[LOPT_LONG_VOWEL_THRESHOLD] = 175/2;
|
||||
|
||||
tr->langopts.numbers = NUM_DECIMAL_COMMA | NUM_SWAP_TENS | NUM_OMIT_1_HUNDRED | NUM_OMIT_1_THOUSAND | NUM_ALLOW_SPACE | NUM_ORDINAL_DOT | NUM_ROMAN;
|
||||
tr->langopts.numbers = NUM_DECIMAL_COMMA | NUM_SWAP_TENS | NUM_ALLOW_SPACE | NUM_ORDINAL_DOT | NUM_ROMAN;
|
||||
// tr->langopts.numbers = NUM_DECIMAL_COMMA | NUM_SWAP_TENS | NUM_OMIT_1_HUNDRED | NUM_OMIT_1_THOUSAND | NUM_ALLOW_SPACE | NUM_ORDINAL_DOT | NUM_ROMAN;
|
||||
SetLetterVowel(tr,'y');
|
||||
tr->langopts.param[LOPT_UNPRONOUNCABLE] = 2; // use de_rules for unpronouncable rules
|
||||
}
|
||||
@@ -1218,6 +1220,7 @@ SetLengthMods(tr,3); // all equal
|
||||
}
|
||||
tr->langopts.param[LOPT_WORD_MERGE] = 1; // don't break vowels betwen words
|
||||
SetIndicLetters(tr); // call this after setting OFFSET_
|
||||
SetLetterBitsRange(tr,LETTERGP_B,0x4e,0x4e); // chillu-virama (unofficial)
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
+9
-4
@@ -122,7 +122,7 @@ static const unsigned short brackets[] = {
|
||||
static const unsigned short breaks[] = {'_', 0};
|
||||
|
||||
// treat these characters as spaces, in addition to iswspace()
|
||||
static const wchar_t chars_space[] = {0x2500,0}; // box drawing horiz
|
||||
// static const wchar_t chars_space[] = {0x2500,0x2501,0}; // box drawing horiz
|
||||
|
||||
|
||||
// Translate character codes 0xA0 to 0xFF into their unicode values
|
||||
@@ -432,8 +432,10 @@ int IsSpace(unsigned int c)
|
||||
{//========================
|
||||
if(c == 0)
|
||||
return(0);
|
||||
if(wcschr(chars_space,c))
|
||||
return(1);
|
||||
if((c >= 0x2500) && (c < 0x25a0))
|
||||
return(1); // box drawing characters
|
||||
// if(wcschr(chars_space,c))
|
||||
// return(1);
|
||||
return(iswspace(c));
|
||||
}
|
||||
|
||||
@@ -867,6 +869,8 @@ int TranslateWord(Translator *tr, char *word_start, int next_pause, WORD_TAB *wt
|
||||
}
|
||||
|
||||
word_copy_length = wordx - word_start;
|
||||
if(word_copy_length >= N_WORD_BYTES)
|
||||
word_copy_length = N_WORD_BYTES-1;
|
||||
memcpy(word_copy2, word_start, word_copy_length);
|
||||
|
||||
spell_word = 0;
|
||||
@@ -3017,7 +3021,8 @@ if((c == '/') && (tr->langopts.testing & 2) && IsDigit09(next_in) && IsAlpha(pre
|
||||
}
|
||||
else
|
||||
{
|
||||
ix += utf8_out(c,&sbuf[ix]); // sbuf[ix++] = c;
|
||||
if((ix < (N_TR_SOURCE - 4)))
|
||||
ix += utf8_out(c,&sbuf[ix]); // sbuf[ix++] = c;
|
||||
}
|
||||
if(pre_pause_add > pre_pause)
|
||||
pre_pause = pre_pause_add;
|
||||
|
||||
+23
-15
@@ -1540,14 +1540,32 @@ static int SetWithRange0(int value, int max)
|
||||
}
|
||||
|
||||
|
||||
static void SetPitchFormants()
|
||||
{//===========================
|
||||
int ix;
|
||||
int factor;
|
||||
int pitch_value;
|
||||
|
||||
// adjust formants to give better results for a different voice pitch
|
||||
if((pitch_value = embedded_value[EMBED_P]) > MAX_PITCH_VALUE)
|
||||
pitch_value = MAX_PITCH_VALUE;
|
||||
|
||||
factor = 256 + (25 * (pitch_value - 50))/50;
|
||||
for(ix=0; ix<=5; ix++)
|
||||
{
|
||||
wvoice->freq[ix] = (wvoice->freq2[ix] * factor)/256;
|
||||
}
|
||||
factor = embedded_value[EMBED_T]*3;
|
||||
wvoice->height[0] = (wvoice->height2[0] * (256 - factor*2))/256;
|
||||
wvoice->height[1] = (wvoice->height2[1] * (256 - factor))/256;
|
||||
}
|
||||
|
||||
|
||||
void SetEmbedded(int control, int value)
|
||||
{//=====================================
|
||||
// there was an embedded command in the text at this point
|
||||
int sign=0;
|
||||
int command;
|
||||
int ix;
|
||||
int factor;
|
||||
int pitch_value;
|
||||
|
||||
command = control & 0x1f;
|
||||
if((control & 0x60) == 0x60)
|
||||
@@ -1570,18 +1588,7 @@ void SetEmbedded(int control, int value)
|
||||
case EMBED_T:
|
||||
WavegenSetEcho(); // and drop through to case P
|
||||
case EMBED_P:
|
||||
// adjust formants to give better results for a different voice pitch
|
||||
if((pitch_value = embedded_value[EMBED_P]) > MAX_PITCH_VALUE)
|
||||
pitch_value = MAX_PITCH_VALUE;
|
||||
|
||||
factor = 256 + (25 * (pitch_value - 50))/50;
|
||||
for(ix=0; ix<=5; ix++)
|
||||
{
|
||||
wvoice->freq[ix] = (wvoice->freq2[ix] * factor)/256;
|
||||
}
|
||||
factor = embedded_value[EMBED_T]*3;
|
||||
wvoice->height[0] = (wvoice->height2[0] * (256 - factor*2))/256;
|
||||
wvoice->height[1] = (wvoice->height2[1] * (256 - factor))/256;
|
||||
SetPitchFormants();
|
||||
break;
|
||||
|
||||
case EMBED_A: // amplitude
|
||||
@@ -1618,6 +1625,7 @@ void WavegenSetVoice(voice_t *v)
|
||||
option_harmonic1 = 6;
|
||||
}
|
||||
WavegenSetEcho();
|
||||
SetPitchFormants();
|
||||
MarkerEvent(espeakEVENT_SAMPLERATE,0,wvoice->samplerate,out_ptr);
|
||||
// WVoiceChanged(wvoice);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user