mirror of
https://github.com/rhasspy/espeak-ng.git
synced 2026-11-04 22:38:33 +00:00
Numbers: Support "myriad" (10^4) based number systems (lang=ko).
Lang=pt: fix ordinal numbers 11-19. Lang=en-us: minor vowel changes. git-svn-id: https://espeak.svn.sourceforge.net/svnroot/espeak/trunk@291 d46cf337-b52f-0410-862d-fd96e6ae7743
This commit is contained in:
+64
-18
@@ -1137,8 +1137,8 @@ static int LookupThousands(Translator *tr, int value, int thousandplex, int thou
|
||||
} // end f LookupThousands
|
||||
|
||||
|
||||
static int LookupNum2(Translator *tr, int value, int control, char *ph_out)
|
||||
{//========================================================================
|
||||
static int LookupNum2(Translator *tr, int value, const int control, char *ph_out)
|
||||
{//=============================================================================
|
||||
// Lookup a 2 digit number
|
||||
// control bit 0: ordinal number
|
||||
// control bit 1: final tens and units (not number of thousands) (use special form of '1', LANG=de "eins")
|
||||
@@ -1151,6 +1151,7 @@ static int LookupNum2(Translator *tr, int value, int control, char *ph_out)
|
||||
int ix;
|
||||
int units;
|
||||
int tens;
|
||||
int is_ordinal;
|
||||
int used_and=0;
|
||||
int found_ordinal = 0;
|
||||
int next_phtype;
|
||||
@@ -1175,6 +1176,8 @@ static int LookupNum2(Translator *tr, int value, int control, char *ph_out)
|
||||
ord_type = 'q';
|
||||
}
|
||||
|
||||
is_ordinal = control & 1;
|
||||
|
||||
if((control & 2) && (n_digit_lookup == 2))
|
||||
{
|
||||
// pronunciation of the final 2 digits has already been found
|
||||
@@ -1187,11 +1190,12 @@ static int LookupNum2(Translator *tr, int value, int control, char *ph_out)
|
||||
// is there a special pronunciation for this 2-digit number
|
||||
if(control & 8)
|
||||
{
|
||||
// is there a feminine form?
|
||||
sprintf(string,"_%df",value);
|
||||
found = Lookup(tr, string, ph_digits);
|
||||
}
|
||||
else
|
||||
if(control & 1)
|
||||
if(is_ordinal)
|
||||
{
|
||||
strcpy(ph_ordinal, ph_ordinal2);
|
||||
|
||||
@@ -1229,8 +1233,15 @@ static int LookupNum2(Translator *tr, int value, int control, char *ph_out)
|
||||
|
||||
if(!found)
|
||||
{
|
||||
sprintf(string,"_%d",value);
|
||||
found = Lookup(tr, string, ph_digits);
|
||||
if((is_ordinal) && (tr->langopts.numbers2 & NUM2_NO_TEEN_ORDINALS))
|
||||
{
|
||||
// don't use numbers 10-99 to make ordinals, always use _1Xo etc (lang=pt)
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(string,"_%d",value);
|
||||
found = Lookup(tr, string, ph_digits);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1251,7 +1262,7 @@ static int LookupNum2(Translator *tr, int value, int control, char *ph_out)
|
||||
else
|
||||
{
|
||||
|
||||
if((control & 1) &&
|
||||
if((is_ordinal) &&
|
||||
((units == 0) || (tr->langopts.numbers & NUM_SWAP_TENS) || (tr->langopts.numbers2 & NUM2_MULTIPLE_ORDINAL)))
|
||||
{
|
||||
sprintf(string,"_%dX%c", tens, ord_type);
|
||||
@@ -1300,7 +1311,7 @@ static int LookupNum2(Translator *tr, int value, int control, char *ph_out)
|
||||
sprintf(string,"_%df",units);
|
||||
found = Lookup(tr, string, ph_digits);
|
||||
}
|
||||
if((control & 1) && ((tr->langopts.numbers & NUM_SWAP_TENS) == 0))
|
||||
if((is_ordinal) && ((tr->langopts.numbers & NUM_SWAP_TENS) == 0))
|
||||
{
|
||||
// ordinal
|
||||
sprintf(string,"_%d%c",units,ord_type);
|
||||
@@ -1335,7 +1346,7 @@ static int LookupNum2(Translator *tr, int value, int control, char *ph_out)
|
||||
}
|
||||
}
|
||||
|
||||
if((control & 1) && (found_ordinal == 0) && (ph_ordinal[0] == 0))
|
||||
if((is_ordinal) && (found_ordinal == 0) && (ph_ordinal[0] == 0))
|
||||
{
|
||||
if((value >= 20) && (((value % 10) == 0) || (tr->langopts.numbers & NUM_SWAP_TENS)))
|
||||
Lookup(tr, "_ord20", ph_ordinal);
|
||||
@@ -1347,7 +1358,7 @@ static int LookupNum2(Translator *tr, int value, int control, char *ph_out)
|
||||
{
|
||||
Lookup(tr, "_0and", ph_and);
|
||||
|
||||
if((control & 1) && (tr->langopts.numbers2 & NUM2_MULTIPLE_ORDINAL))
|
||||
if((is_ordinal) && (tr->langopts.numbers2 & NUM2_MULTIPLE_ORDINAL))
|
||||
ph_and[0] = 0;
|
||||
|
||||
if(tr->langopts.numbers & NUM_SWAP_TENS)
|
||||
@@ -1406,6 +1417,7 @@ static int LookupNum3(Translator *tr, int value, char *ph_out, int suppress_null
|
||||
int ix;
|
||||
int exact;
|
||||
int ordinal;
|
||||
int tplex;
|
||||
int say_zero_hundred=0;
|
||||
char string[12]; // for looking up entries in **_list
|
||||
char buf1[100];
|
||||
@@ -1465,10 +1477,16 @@ static int LookupNum3(Translator *tr, int value, char *ph_out, int suppress_null
|
||||
if ((value % 1000) == 0)
|
||||
exact = 1;
|
||||
|
||||
if(LookupThousands(tr, hundreds / 10, thousandplex+1, exact | ordinal, ph_10T) == 0)
|
||||
tplex = thousandplex+1;
|
||||
if(tr->langopts.numbers2 & NUM2_MYRIADS)
|
||||
{
|
||||
tplex = 0;
|
||||
}
|
||||
|
||||
if(LookupThousands(tr, hundreds / 10, tplex, exact | ordinal, ph_10T) == 0)
|
||||
{
|
||||
x = 0;
|
||||
if(tr->langopts.numbers2 & (1 << (thousandplex+1)))
|
||||
if(tr->langopts.numbers2 & (1 << tplex))
|
||||
x = 8; // use variant (feminine) for before thousands and millions
|
||||
LookupNum2(tr, hundreds/10, x, ph_digits);
|
||||
}
|
||||
@@ -1615,6 +1633,23 @@ static int LookupNum3(Translator *tr, int value, char *ph_out, int suppress_null
|
||||
} // end of LookupNum3
|
||||
|
||||
|
||||
bool CheckThousandsGroup(char *word, int group_len)
|
||||
{//================================================
|
||||
// Is this a group of 3 digits which looks like a thousands group?
|
||||
int ix;
|
||||
|
||||
if(isdigit(word[group_len]) || isdigit(-1))
|
||||
return(false);
|
||||
|
||||
for(ix=0; ix < group_len; ix++)
|
||||
{
|
||||
if(!isdigit(word[ix]))
|
||||
return(false);
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
|
||||
|
||||
static int TranslateNumber_1(Translator *tr, char *word, char *ph_out, unsigned int *flags, WORD_TAB *wtab, int control)
|
||||
{//=====================================================================================================================
|
||||
// Number translation with various options
|
||||
@@ -1640,6 +1675,7 @@ static int TranslateNumber_1(Translator *tr, char *word, char *ph_out, unsigned
|
||||
int decimal_mode;
|
||||
int suffix_ix;
|
||||
int skipwords = 0;
|
||||
int group_len;
|
||||
char *p;
|
||||
char string[32]; // for looking up entries in **_list
|
||||
char buf1[100];
|
||||
@@ -1662,8 +1698,12 @@ static int TranslateNumber_1(Translator *tr, char *word, char *ph_out, unsigned
|
||||
n_digits = ix;
|
||||
value = this_value = atoi(word);
|
||||
|
||||
group_len = 3;
|
||||
if(tr->langopts.numbers2 & NUM2_MYRIADS)
|
||||
group_len = 4;
|
||||
|
||||
// is there a previous thousands part (as a previous "word") ?
|
||||
if((n_digits == 3) && (word[-2] == tr->langopts.thousands_sep) && isdigit(word[-3]))
|
||||
if((n_digits == group_len) && (word[-2] == tr->langopts.thousands_sep) && isdigit(word[-3]))
|
||||
{
|
||||
prev_thousands = 1;
|
||||
}
|
||||
@@ -1777,14 +1817,19 @@ static int TranslateNumber_1(Translator *tr, char *word, char *ph_out, unsigned
|
||||
// a "thousand"/"million" suffix to this one
|
||||
digix = n_digits + thousands_inc;
|
||||
|
||||
while(((wtab[thousandplex+1].flags & FLAG_MULTIPLE_SPACES) == 0) &&
|
||||
isdigit(word[digix]) && isdigit(word[digix+1]) && isdigit(word[digix+2]) && !isdigit(word[digix+3]) && !isdigit(word[digix-1]))
|
||||
while(((wtab[thousandplex+1].flags & FLAG_MULTIPLE_SPACES) == 0) && CheckThousandsGroup(&word[digix], group_len))
|
||||
{
|
||||
if((word[digix] != '0') || (word[digix+1] != '0') || (word[digix+2] != '0'))
|
||||
thousands_exact = 0;
|
||||
for(ix=0; ix<group_len; ix++)
|
||||
{
|
||||
if(word[digix+ix] != '0')
|
||||
{
|
||||
thousands_exact = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
thousandplex++;
|
||||
digix += 3;
|
||||
digix += group_len;
|
||||
if((word[digix] == tr->langopts.thousands_sep) || ((tr->langopts.numbers & NUM_ALLOW_SPACE) && (word[digix] == ' ')))
|
||||
{
|
||||
suffix_ix = digix+2;
|
||||
@@ -1820,7 +1865,8 @@ static int TranslateNumber_1(Translator *tr, char *word, char *ph_out, unsigned
|
||||
{
|
||||
if(thousands_inc > 0)
|
||||
{
|
||||
if((thousandplex > 0) && (value < 1000))
|
||||
if(thousandplex > 0)
|
||||
// if((thousandplex > 0) && (value < 1000))
|
||||
{
|
||||
if((suppress_null == 0) && (LookupThousands(tr,value,thousandplex, thousands_exact, ph_append)))
|
||||
{
|
||||
|
||||
+34
-16
@@ -881,39 +881,57 @@ static void SwitchOnVowelType(PHONEME_LIST *plist, PHONEME_DATA *phdata, USHORT
|
||||
} // end of SwitchVowelType
|
||||
|
||||
|
||||
static int NumInstnWords(USHORT *prog)
|
||||
{//===================================
|
||||
int NumInstnWords(USHORT *prog)
|
||||
{//============================
|
||||
int instn;
|
||||
int instn2;
|
||||
int instn_type;
|
||||
int n;
|
||||
static const char n_words[16] = {1,1,0,0,1,1,1,1,1,2,4,0,0,0,0,0};
|
||||
int type2;
|
||||
static const char n_words[16] = {0,1,0,0,1,1,0,1,1,2,4,0,0,0,0,0};
|
||||
|
||||
instn = *prog;
|
||||
instn_type = instn >> 12;
|
||||
if((n = n_words[instn_type]) > 0)
|
||||
return(n);
|
||||
|
||||
if(instn_type < 4)
|
||||
switch(instn_type)
|
||||
{
|
||||
case 0:
|
||||
if(((instn & 0xf00) >> 8) == i_IPA_NAME)
|
||||
{
|
||||
n = ((instn & 0xff) + 1) / 2;
|
||||
return(n+1);
|
||||
}
|
||||
return(1);;
|
||||
|
||||
case 6:
|
||||
type2 = (instn & 0xf00) >> 9;
|
||||
if((type2 == 5) || (type2 == 6))
|
||||
return(12); // switch on vowel type
|
||||
return(1);
|
||||
|
||||
case 2:
|
||||
case 3:
|
||||
// a condition, check for a 2-word instruction
|
||||
if(((n = instn & 0x0f00) == 0x600) || (n == 0x0d00))
|
||||
return(2);
|
||||
return(1);
|
||||
}
|
||||
|
||||
// instn_type 11 to 15, 2 words
|
||||
instn2 = prog[2];
|
||||
if((instn2 >> 12) == 0xf)
|
||||
{
|
||||
// This instruction is followed by addWav(), 2 more words
|
||||
return(4);
|
||||
default:
|
||||
// instn_type 11 to 15, 2 words
|
||||
instn2 = prog[2];
|
||||
if((instn2 >> 12) == 0xf)
|
||||
{
|
||||
// This instruction is followed by addWav(), 2 more words
|
||||
return(4);
|
||||
}
|
||||
if(instn2 == i_CONTINUE)
|
||||
{
|
||||
return(3);
|
||||
}
|
||||
return(2);
|
||||
}
|
||||
if(instn2 == i_CONTINUE)
|
||||
{
|
||||
return(3);
|
||||
}
|
||||
return(2);
|
||||
} // end of NumInstnWords
|
||||
|
||||
|
||||
|
||||
@@ -571,6 +571,7 @@ int DoSpect2(PHONEME_TAB *this_ph, int which, FMT_PARAMS *fmt_params, PHONEME_L
|
||||
int PauseLength(int pause, int control);
|
||||
int LookupPhonemeTable(const char *name);
|
||||
unsigned char *GetEnvelope(int index);
|
||||
int NumInstnWords(USHORT *prog);
|
||||
|
||||
void InitBreath(void);
|
||||
|
||||
|
||||
@@ -957,7 +957,8 @@ SetLengthMods(tr,3); // all equal
|
||||
tr->langopts.stress_rule = 8; // ?? 1st syllable if it is heavy, else 2nd syllable
|
||||
tr->langopts.param[LOPT_UNPRONOUNCABLE] = 1; // disable check for unpronouncable words
|
||||
tr->langopts.numbers = NUM_OMIT_1_HUNDRED;
|
||||
tr->langopts.break_numbers = 0x9999998;
|
||||
tr->langopts.numbers2 = NUM2_MYRIADS;
|
||||
tr->langopts.break_numbers = 0x1111110;
|
||||
tr->langopts.max_digits = 20;
|
||||
}
|
||||
break;
|
||||
@@ -1115,7 +1116,7 @@ SetLengthMods(tr,3); // all equal
|
||||
tr->langopts.stress_rule = STRESSPOSN_1R; // stress on final syllable
|
||||
tr->langopts.stress_flags = 0x6 | 0x10 | 0x2000 | 0x20000;
|
||||
tr->langopts.numbers = NUM_DECIMAL_COMMA | NUM_DFRACTION_2 | NUM_HUNDRED_AND | NUM_AND_UNITS | NUM_ROMAN;
|
||||
tr->langopts.numbers2 = NUM2_MULTIPLE_ORDINAL;
|
||||
tr->langopts.numbers2 = NUM2_MULTIPLE_ORDINAL | NUM2_NO_TEEN_ORDINALS;
|
||||
SetLetterVowel(tr,'y');
|
||||
ResetLetterBits(tr,0x2);
|
||||
SetLetterBits(tr,1,"bcdfgjkmnpqstvxz"); // B hard consonants, excluding h,l,r,w,y
|
||||
|
||||
+6
-2
@@ -445,7 +445,9 @@ typedef struct {
|
||||
int numbers;
|
||||
|
||||
#define NUM2_MULTIPLE_ORDINAL 0x1000
|
||||
#define NUM2_ENGLISH_NUMERALS 0x2000
|
||||
#define NUM2_NO_TEEN_ORDINALS 0x2000
|
||||
#define NUM2_MYRIADS 0x4000
|
||||
#define NUM2_ENGLISH_NUMERALS 0x8000
|
||||
#define NUM2_THOUSANDS_VAR1 0x40
|
||||
#define NUM2_THOUSANDS_VAR2 0x80
|
||||
#define NUM2_THOUSANDS_VAR3 0xc0
|
||||
@@ -455,7 +457,9 @@ typedef struct {
|
||||
// bits 6-8 use different forms of thousand, million, etc (M MA MB)
|
||||
// bit9=(LANG=rw) say "thousand" and "million" before its number, not after
|
||||
// bit12=(LANG=el,es) use ordinal form of hundreds and tens as well as units
|
||||
// bit13=(LANG=ne) speak (non-replaced) English numerals in English
|
||||
// bit13=(LANG=pt) don't use 11-19 numbers to make ordinals
|
||||
// bit14=(LANG=ko) use myriads (groups of 4 digits) not thousands (groups of 3)
|
||||
// bit15=(LANG=ne) speak (non-replaced) English numerals in English
|
||||
int numbers2;
|
||||
|
||||
#define BREAK_THOUSANDS 0x49249248
|
||||
|
||||
+3
-28
@@ -525,42 +525,17 @@ static void FindVowelFmt(int prog_start, int length)
|
||||
prog_end = prog_start + length;
|
||||
n_vowelfmt_addr = 0;
|
||||
|
||||
for(prog = &phoneme_index[prog_start]; prog < &phoneme_index[prog_end]; prog++)
|
||||
for(prog = &phoneme_index[prog_start]; prog < &phoneme_index[prog_end]; prog += NumInstnWords(prog))
|
||||
{
|
||||
instn = *prog;
|
||||
|
||||
switch(instn >> 12)
|
||||
if((instn >> 12) == 11)
|
||||
{
|
||||
case 2:
|
||||
case 3:
|
||||
// conditions
|
||||
while((instn & 0xe000) == 0x2000)
|
||||
{
|
||||
instn = *(++prog);
|
||||
}
|
||||
prog--;
|
||||
break;
|
||||
|
||||
case 10: // Vowelin, Vowelout
|
||||
prog += 3;
|
||||
break;
|
||||
|
||||
case 9:
|
||||
case 12: // WAV
|
||||
case 13: // VowelStart
|
||||
case 14: // VowelEnd
|
||||
case 15: // addWav
|
||||
prog++;
|
||||
break;
|
||||
|
||||
case 11: // FMT
|
||||
// FMT instruction
|
||||
if(n_vowelfmt_addr < N_VOWELFMT_ADDR)
|
||||
{
|
||||
vowelfmt_addr[n_vowelfmt_addr++] = ((instn & 0xf) << 18) + (prog[1] << 2);
|
||||
}
|
||||
prog++;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
} // end of FindVowelFmt
|
||||
|
||||
Reference in New Issue
Block a user