[1.42.02]

git-svn-id: https://espeak.svn.sourceforge.net/svnroot/espeak/trunk@231 d46cf337-b52f-0410-862d-fd96e6ae7743
This commit is contained in:
jonsd
2009-11-30 13:54:30 +00:00
parent f2eed5229e
commit e404310b8f
83 changed files with 3253 additions and 1591 deletions
+38 -6
View File
@@ -83,7 +83,6 @@ MNEM_TAB mnem_flags[] = {
{"$unstressend",13}, /* reduce stress at end of clause */
{"$atend", 14}, /* use this pronunciation if at end of clause */
{"$dot", 16}, /* ignore '.' after this word (abbreviation) */
{"$abbrev", 17}, /* use this pronuciation rather than split into letters */
{"$stem", 18}, // must have a suffix
@@ -93,6 +92,9 @@ MNEM_TAB mnem_flags[] = {
{"$alt2", 21},
{"$combine", 22}, // Combine with the next word
{"$dot", 24}, // ignore '.' after this word (abbreviation)
{"$hasdot", 25}, // use this pronunciation if there is a dot after the word
{"$max3", 27}, // limit to 3 repetitions
{"$brk", 28}, // a shorter $pause
{"$text", 29}, // word translates to replcement text, not phonemes
@@ -125,6 +127,7 @@ typedef struct {
char name[LEN_GROUP_NAME+1];
unsigned int start;
unsigned int length;
int group3_ix;
} RGROUP;
@@ -345,7 +348,7 @@ step=1; // TEST
break;
case 1:
if((c == '-') && (word[0] != '_'))
if((c == '-') && multiple_words)
{
if(isdigit(word[0]))
{
@@ -734,6 +737,7 @@ static char rule_post[80];
static char rule_match[80];
static char rule_phonemes[80];
static char group_name[LEN_GROUP_NAME+1];
static int group3_ix;
#define N_RULES 2000 // max rules for each group
@@ -1129,7 +1133,10 @@ static int __cdecl string_sorter(char **a, char **b)
static int __cdecl rgroup_sorter(RGROUP *a, RGROUP *b)
{//===================================================
// Sort long names before short names
int ix;
ix = strlen(b->name) - strlen(a->name);
if(ix != 0) return(ix);
ix = strcmp(a->name,b->name);
if(ix != 0) return(ix);
return(a->start-b->start);
@@ -1401,6 +1408,7 @@ static int compile_dictrules(FILE *f_in, FILE *f_out, char *fname_temp)
int n_rules=0;
int count=0;
int different;
int wc;
const char *prev_rgroup_name;
unsigned int char_code;
int compile_mode=0;
@@ -1409,6 +1417,7 @@ static int compile_dictrules(FILE *f_in, FILE *f_out, char *fname_temp)
char *rules[N_RULES];
int n_rgroups = 0;
int n_groups3 = 0;
RGROUP rgroup[N_RULE_GROUP2];
linenum = 0;
@@ -1436,6 +1445,7 @@ static int compile_dictrules(FILE *f_in, FILE *f_out, char *fname_temp)
if(n_rules > 0)
{
strcpy(rgroup[n_rgroups].name,group_name);
rgroup[n_rgroups].group3_ix = group3_ix;
rgroup[n_rgroups].start = ftell(f_temp);
output_rule_group(f_temp,n_rules,rules,group_name);
rgroup[n_rgroups].length = ftell(f_temp) - rgroup[n_rgroups].start;
@@ -1481,7 +1491,8 @@ static int compile_dictrules(FILE *f_in, FILE *f_out, char *fname_temp)
while((*p > ' ') && (ix < LEN_GROUP_NAME))
group_name[ix++] = *p++;
group_name[ix]=0;
group3_ix = 0;
if(sscanf(group_name,"0x%x",&char_code)==1)
{
// group character is given as a character code (max 16 bits)
@@ -1494,8 +1505,19 @@ static int compile_dictrules(FILE *f_in, FILE *f_out, char *fname_temp)
*p++ = char_code;
*p = 0;
}
else
{
if(translator->letter_bits_offset > 0)
{
utf8_in(&wc, group_name);
if(((ix = (wc - translator->letter_bits_offset)) >= 0) && (ix < 128))
{
group3_ix = ix+1; // not zero
}
}
}
if(strlen(group_name) > 2)
if((group3_ix == 0) && (strlen(group_name) > 2))
{
if(utf8_in(&c,group_name) < 2)
{
@@ -1573,7 +1595,17 @@ static int compile_dictrules(FILE *f_in, FILE *f_out, char *fname_temp)
if(gp > 0)
fputc(RULE_GROUP_END,f_out);
fputc(RULE_GROUP_START,f_out);
fprintf(f_out, prev_rgroup_name = rgroup[gp].name);
if(rgroup[gp].group3_ix != 0)
{
n_groups3++;
fputc(1,f_out);
fputc(rgroup[gp].group3_ix, f_out);
}
else
{
fprintf(f_out, "%s", prev_rgroup_name = rgroup[gp].name);
}
fputc(0,f_out);
}
@@ -1593,7 +1625,7 @@ static int compile_dictrules(FILE *f_in, FILE *f_out, char *fname_temp)
fclose(f_temp);
remove(fname_temp);
fprintf(f_log,"\t%d rules, %d groups\n\n",count,n_rgroups);
fprintf(f_log,"\t%d rules, %d groups (%d)\n\n",count,n_rgroups,n_groups3);
return(0);
} // end of compile_dictrules
+72 -59
View File
@@ -36,6 +36,7 @@
#include "translate.h"
int dictionary_skipwords;
char dictionary_name[40];
@@ -146,6 +147,7 @@ static void InitGroups(Translator *tr)
tr->groups2_start[ix]=255; // indicates "not set"
}
memset(tr->letterGroups,0,sizeof(tr->letterGroups));
memset(tr->groups3,0,sizeof(tr->groups3));
p = tr->data_dictrules;
while(*p != 0)
@@ -194,7 +196,8 @@ static void InitGroups(Translator *tr)
len = strlen(p);
p_name = p;
c = p_name[0];
c2 = p_name[1];
p += (len+1);
if(len == 1)
{
@@ -206,13 +209,18 @@ static void InitGroups(Translator *tr)
tr->groups1[0] = p;
}
else
if(c == 1)
{
// index by offset from letter base
tr->groups3[c2 - 1] = p;
}
else
{
if(tr->groups2_start[c] == 255)
tr->groups2_start[c] = tr->n_groups2;
tr->groups2_count[c]++;
tr->groups2[tr->n_groups2] = p;
c2 = p_name[1];
tr->groups2_name[tr->n_groups2++] = (c + (c2 << 8));
}
}
@@ -1255,18 +1263,17 @@ void SetWordStress(Translator *tr, char *output, unsigned int *dictionary_flags,
{
/* no explicit stress - stress the final vowel */
stressed_syllable = vowel_count - 1;
if(max_stress == 0)
while(stressed_syllable > 0)
{
while(stressed_syllable > 0)
// find the last vowel which is not unstressed
if(vowel_stress[stressed_syllable] == 0)
{
if(vowel_stress[stressed_syllable] == 0)
{
vowel_stress[stressed_syllable] = 4;
break;
}
else
stressed_syllable--;
vowel_stress[stressed_syllable] = 4;
break;
}
else
stressed_syllable--;
}
max_stress = 4;
}
@@ -1391,7 +1398,7 @@ void SetWordStress(Translator *tr, char *output, unsigned int *dictionary_flags,
if(vowel_stress[2] == 4)
vowel_stress[1] = 3;
}
#if deleted
if((stressflags & 0x2000) && (vowel_stress[1] == 0))
{
// If there is only one syllable before the primary stress, give it a secondary stress
@@ -1400,7 +1407,6 @@ void SetWordStress(Translator *tr, char *output, unsigned int *dictionary_flags,
vowel_stress[1] = 3;
}
}
#endif
done = 0;
for(v=1; v<vowel_count; v++)
@@ -1621,8 +1627,8 @@ void SetWordStress(Translator *tr, char *output, unsigned int *dictionary_flags,
#ifdef LOG_TRANSLATE
static char *DecodeRule(const char *group, char *rule)
{//==================================================
static char *DecodeRule(const char *group_chars, int group_length, char *rule)
{//===========================================================================
/* Convert compiled match template to ascii */
unsigned char rb;
@@ -1648,7 +1654,13 @@ static char *DecodeRule(const char *group, char *rule)
match_type = 0;
buf_pre[0] = 0;
strcpy(buf,group);
for(ix=0; ix<group_length; ix++)
{
buf[ix] = group_chars[ix];
}
buf[ix] = 0;
p = &buf[strlen(buf)];
while(!finished)
{
@@ -1819,8 +1831,8 @@ void AppendPhonemes(Translator *tr, char *string, int size, const char *ph)
static void MatchRule(Translator *tr, char *word[], const char *group, char *rule, MatchRecord *match_out, int word_flags, int dict_flags)
{//=======================================================================================================================================
static void MatchRule(Translator *tr, char *word[], int group_length, char *rule, MatchRecord *match_out, int word_flags, int dict_flags)
{//======================================================================================================================================
/* Checks a specified word against dictionary rules.
Returns with phoneme code string, or NULL if no match found.
@@ -1865,12 +1877,12 @@ static void MatchRule(Translator *tr, char *word[], const char *group, char *rul
static MatchRecord best;
int total_consumed; /* letters consumed for best match */
int group_length;
unsigned char condition_num;
char *common_phonemes; /* common to a group of entries */
char *group_chars;
group_chars = *word;
if(rule == NULL)
{
@@ -1890,8 +1902,6 @@ static void MatchRule(Translator *tr, char *word[], const char *group, char *rul
best.end_type = 0;
best.del_fwd = NULL;
group_length = strlen(group);
/* search through dictionary rules */
while(rule[0] != RULE_GROUP_END)
{
@@ -2372,7 +2382,7 @@ static void MatchRule(Translator *tr, char *word[], const char *group, char *rul
if(group_length > 1)
pts += 35; // to account for an extra letter matching
DecodePhonemes(match.phonemes,decoded_phonemes);
fprintf(f_trans,"%3d\t%s [%s]\n",pts,DecodeRule(group,rule_start),decoded_phonemes);
fprintf(f_trans,"%3d\t%s [%s]\n",pts,DecodeRule(group_chars, group_length, rule_start),decoded_phonemes);
}
#endif
@@ -2411,7 +2421,7 @@ int TranslateRules(Translator *tr, char *p_start, char *phonemes, int ph_size, c
Append the result to 'phonemes' and any standard prefix/suffix in 'end_phonemes' */
unsigned char c, c2;
unsigned int c12;
unsigned int c12, c123;
int wc=0;
int wc_prev;
int wc_bytes;
@@ -2432,8 +2442,6 @@ int TranslateRules(Translator *tr, char *p_start, char *phonemes, int ph_size, c
char word_copy[N_WORD_BYTES];
static const char str_pause[2] = {phonPAUSE_NOLINK,0};
char group_name[4];
if(tr->data_dictrules == NULL)
return(0);
@@ -2502,12 +2510,22 @@ int TranslateRules(Translator *tr, char *p_start, char *phonemes, int ph_size, c
{
digit_count = 0;
found = 0;
if(n > 0)
if(((ix = wc - tr->letter_bits_offset) >= 0) && (ix < 128))
{
if(tr->groups3[ix] != NULL)
{
MatchRule(tr, &p, wc_bytes, tr->groups3[ix], &match1, word_flags, dict_flags0);
found = 1;
}
}
if(!found && (n > 0))
{
/* there are some 2 byte chains for this initial letter */
c2 = p[1];
c12 = c + (c2 << 8); /* 2 characters */
c123 = c12 + (p[2] << 16);
g1 = tr->groups2_start[c];
for(g=g1; g < (g1+n); g++)
@@ -2516,17 +2534,13 @@ int TranslateRules(Translator *tr, char *p_start, char *phonemes, int ph_size, c
{
found = 1;
group_name[0] = c;
group_name[1] = c2;
group_name[2] = 0;
p2 = p;
MatchRule(tr, &p2, group_name, tr->groups2[g], &match2, word_flags, dict_flags0);
MatchRule(tr, &p2, 2, tr->groups2[g], &match2, word_flags, dict_flags0);
if(match2.points > 0)
match2.points += 35; /* to acount for 2 letters matching */
/* now see whether single letter chain gives a better match ? */
group_name[1] = 0;
MatchRule(tr, &p, group_name, tr->groups1[c], &match1, word_flags, dict_flags0);
MatchRule(tr, &p, 1, tr->groups1[c], &match1, word_flags, dict_flags0);
if(match2.points >= match1.points)
{
@@ -2541,15 +2555,12 @@ int TranslateRules(Translator *tr, char *p_start, char *phonemes, int ph_size, c
if(!found)
{
/* alphabetic, single letter chain */
group_name[0] = c;
group_name[1] = 0;
if(tr->groups1[c] != NULL)
MatchRule(tr, &p, group_name, tr->groups1[c], &match1, word_flags, dict_flags0);
MatchRule(tr, &p, 1, tr->groups1[c], &match1, word_flags, dict_flags0);
else
{
// no group for this letter, use default group
MatchRule(tr, &p, "", tr->groups1[0], &match1, word_flags, dict_flags0);
MatchRule(tr, &p, 0, tr->groups1[0], &match1, word_flags, dict_flags0);
if((match1.points == 0) && ((option_sayas & 0x10) == 0))
{
@@ -2715,9 +2726,8 @@ void ApplySpecialAttribute2(Translator *tr, char *phonemes, int dict_flags)
len = strlen(phonemes);
switch(tr->translator_name)
if(tr->langopts.param[LOPT_ALT] & 2)
{
case L('i','t'):
for(ix=0; ix<(len-1); ix++)
{
if(phonemes[ix] == phonSTRESS_P)
@@ -2740,7 +2750,6 @@ void ApplySpecialAttribute2(Translator *tr, char *phonemes, int dict_flags)
break;
}
}
break;
}
} // end of ApplySpecialAttribute2
@@ -2749,9 +2758,7 @@ void ApplySpecialAttribute(Translator *tr, char *phonemes, int dict_flags)
{//=======================================================================
// Amend the translated phonemes according to an attribute which is specific for the language.
int len;
int ix;
char *p_end;
int phoneme_1;
if((dict_flags & (FLAG_ALT_TRANS | FLAG_ALT2_TRANS)) == 0)
return;
@@ -2772,18 +2779,6 @@ void ApplySpecialAttribute(Translator *tr, char *phonemes, int dict_flags)
}
break;
case L('p','t'):
phoneme_1 = PhonemeCode('o');
for(ix=0; ix<(len-1); ix++)
{
if(phonemes[ix] == phoneme_1)
{
phonemes[ix] = PhonemeCode('O');
break;
}
}
break;
case L('r','o'):
if(p_end[0] == PhonemeCode('j'))
{
@@ -2961,6 +2956,7 @@ static const char *LookupDict2(Translator *tr, const char *word, const char *wor
wlen = strlen(word);
}
hash = HashDictionary(word);
p = tr->dict_hashtab[hash];
@@ -3127,6 +3123,11 @@ static const char *LookupDict2(Translator *tr, const char *word, const char *wor
continue;
}
}
if(dictionary_flags & FLAG_NEEDS_DOT)
{
if(!(wflags & FLAG_HAS_DOT))
continue;
}
if((dictionary_flags & FLAG_ATEND) && (word_end < tr->clause_end))
{
@@ -3267,7 +3268,7 @@ int LookupDictList(Translator *tr, char **wordptr, char *ph_out, unsigned int *f
// set the skip words flag
flags[0] |= FLAG_SKIPWORDS;
dictionary_skipwords = length;
return(flags[0]);
return(1);
}
}
@@ -3367,7 +3368,7 @@ int LookupDictList(Translator *tr, char **wordptr, char *ph_out, unsigned int *f
return(0);
}
return(flags[0]);
return(1);
}
ph_out[0] = 0;
@@ -3384,6 +3385,17 @@ int Lookup(Translator *tr, const char *word, char *ph_out)
return(LookupDictList(tr, &word1, ph_out, flags, 0, NULL));
}
int LookupFlags(Translator *tr, const char *word)
{//==============================================
char buf[100];
static unsigned int flags[2];
flags[0] = flags[1] = 0;
char *word1 = (char *)word;
LookupDictList(tr, &word1, buf, flags, 0, NULL);
return(flags[0]);
}
int RemoveEnding(Translator *tr, char *word, int end_type, char *word_copy)
@@ -3410,7 +3422,8 @@ int RemoveEnding(Translator *tr, char *word, int end_type, char *word_copy)
"ion", NULL };
static const char *add_e_additions[] = {
"c", "rs", "ir", "ur", "ath", "ns", "lu", NULL };
// "c", "rs", "ir", "ur", "ath", "ns", "lu", NULL };
"c", "rs", "ir", "ur", "ath", "ns", "u", NULL };
for(word_end = word; *word_end != ' '; word_end++)
{
+2 -1
View File
@@ -266,6 +266,7 @@ wxSashLayoutWindow *win;
ConfigInit();
LoadConfig();
WavegenInitSound();
if((result = LoadPhData()) != 1)
@@ -320,7 +321,7 @@ void MyFrame::SetVoiceTitle(char *voice_name)
{
sprintf(buf,"Compile &dictionary '%s'",dictionary_name);
data_menu->SetLabel(MENU_COMPILE_DICT, wxString(buf,wxConvLocal));
sprintf(buf,"&Format '%s_rules' file",dictionary_name);
sprintf(buf,"&Layout '%s_rules' file",dictionary_name);
data_menu->SetLabel(MENU_FORMAT_DICTIONARY, wxString(buf,wxConvLocal));
}
}
+3 -3
View File
@@ -214,7 +214,7 @@ static int drops_0[8] = {0x400,0x400,0x700,0x700,0x700,0xa00,0x1800,0x0e00};
//static int drops_2[8] = {0x400,0x400,0x600,0x600,-0x800,0xc00,0x0e00,0x0e00};
static short oflow[] = {0, 20, 12, 4, 0};
static short oflow_emf[] = {5, 24, 15, 10, 5};
static short oflow_emf[] = {5, 26, 16, 10, 5};
static short oflow_less[] = {3, 19, 12, 7, 2};
// static short oflow_test2[] = {20, 0, 20, 0, 20};
// static short back_emf[] = {35, 32, 0};
@@ -262,7 +262,7 @@ static TONE_HEAD tone_head_table[N_TONE_HEAD_TABLE] = {
{20, 25, 34, 22, drops_0, 3, 3, 5, oflow}, // 0 statement
{20, 25, 34, 20, drops_0, 3, 3, 5, oflow}, // 1 comma
{20, 25, 34, 20, drops_0, 3, 3, 5, oflow}, // 2 question
{20, 25, 36, 22, drops_0, 3, 4, 5, oflow_emf}, // 3 exclamation
{20, 25, 39, 22, drops_0, 3, 4, 5, oflow_emf}, // 3 exclamation
{20, 25, 34, 22, drops_0, 3, 3, 5, oflow}, // 4 statement, emphatic
{20, 25, 32, 24, drops_0, 4, 3, 5, oflow_less}, // 5 statement, less intonation
{20, 25, 32, 24, drops_0, 4, 3, 5, oflow_less}, // 6 comma, less intonation
@@ -275,7 +275,7 @@ static TONE_HEAD tone_head_table[N_TONE_HEAD_TABLE] = {
};
static TONE_NUCLEUS tone_nucleus_table[N_TONE_NUCLEUS_TABLE] = {
{PITCHfall, 29, 4, PITCHfall, 32, 9, NULL, 12, 6, 0}, // 0 statement
{PITCHfall, 29, 4, PITCHfall, 31, 8, NULL, 11, 6, 0}, // 0 statement
{PITCHfrise, 35, 8, PITCHfrise2, 35,10, NULL, 15, 23, 0}, // 1 comma
{PITCHfrise, 39,10, PITCHfrise2, 36,10, NULL, 15, 28, 0}, // 2 question
// {PITCHfall, 41, 4, PITCHfall, 41,27, NULL, 16, 4, T_EMPH}, // 3 exclamation
+1 -1
View File
@@ -89,7 +89,7 @@ wxMenuBar *MakeMenu(int type)
data_menu->Append(MENU_COMPILE_DICT_DEBUG, _("Compile dictionary (debu&g)"));
data_menu->Append(MENU_COMPILE_MBROLA, _("Compile &mbrola phonemes list..."));
data_menu->AppendSeparator();
data_menu->Append(MENU_FORMAT_DICTIONARY, _("&Format *_rules file"));
data_menu->Append(MENU_FORMAT_DICTIONARY, _("&Layout *_rules file"));
// OPTIONS MENU
paths_menu = new wxMenu;
+88 -46
View File
@@ -67,6 +67,8 @@
static int n_digit_lookup;
static char *digit_lookup;
static int speak_missing_thousands;
typedef struct {
const char *name;
@@ -589,8 +591,8 @@ void LookupLetter(Translator *tr, unsigned int letter, int next_byte, char *ph_b
int TranslateLetter(Translator *tr, char *word, char *phonemes, int control, int word_length)
{//======================================================================================
int TranslateLetter(Translator *tr, char *word, char *phonemes, int control)
{//=========================================================================
// get pronunciation for an isolated letter
// return number of bytes used by the letter
// control 2=say-as glyphs, 3-say-as chars
@@ -755,27 +757,28 @@ void SetSpellingStress(Translator *tr, char *phonemes, int control, int n_chars)
static char ph_ordinal2[12];
static int CheckDotOrdinal(Translator *tr, char *word, WORD_TAB *wtab, int lowercase)
{//==================================================================================
// nextupper: Next word must start with lower-case
static int CheckDotOrdinal(Translator *tr, char *word, WORD_TAB *wtab, int roman)
{//==============================================================================
int ordinal = 0;
int c2;
if((tr->langopts.numbers & NUM_ORDINAL_DOT) && (word[0] == '.'))
if((tr->langopts.numbers & NUM_ORDINAL_DOT) && ((word[0] == '.') || (wtab[0].flags & FLAG_HAS_DOT)) && !(wtab[1].flags & FLAG_NOSPACE))
{
if((lowercase==0) || !(wtab[1].flags & FLAG_FIRST_UPPER))
if(roman || !(wtab[1].flags & FLAG_FIRST_UPPER))
{
utf8_in(&c2, &word[2]);
if(IsAlpha(c2))
if((word[1] != 0) && IsAlpha(c2))
{
// ordinal number is indicated by dot after the number
// but not if the next word starts with an upper-case letter
ordinal = 2;
word[0] = ' ';
if(tr->translator_name == L('h','u'))
if(word[0] == '.')
word[0] = ' ';
if((roman==0) && (tr->translator_name == L('h','u')))
{
// lang=hu don't treat dot as ordinal indicator if the next word is a month name ($alt)
// lang=hu don't treat dot as ordinal indicator if the next word is a month name ($alt). It may have a suffix.
if(TranslateWord(tr, &word[2], 0, NULL) & FLAG_ALT_TRANS)
ordinal = 0;
}
@@ -799,7 +802,7 @@ int TranslateRoman(Translator *tr, char *word, char *ph_out, WORD_TAB *wtab)
int subtract;
int repeat = 0;
int n_digits = 0;
unsigned int flags;
unsigned int flags[2];
char ph_roman[30];
char number_chars[N_WORD_BYTES];
@@ -809,6 +812,7 @@ int TranslateRoman(Translator *tr, char *word, char *ph_out, WORD_TAB *wtab)
acc = 0;
prev = 0;
subtract = 0x7fff;
ph_out[0] = 0;
if((tr->langopts.numbers & NUM_ROMAN_CAPITALS) && !(wtab[0].flags & FLAG_ALL_UPPER))
return(0);
@@ -861,12 +865,12 @@ int TranslateRoman(Translator *tr, char *word, char *ph_out, WORD_TAB *wtab)
if((tr->langopts.numbers & NUM_ROMAN_AFTER) == 0)
{
strcpy(ph_out,ph_roman);
p = &ph_out[strlen(ph_out)];
p = &ph_out[strlen(ph_roman)];
}
sprintf(number_chars," %d ",acc);
sprintf(number_chars," %d ",acc);
if(CheckDotOrdinal(tr, word, wtab, 0))
if(CheckDotOrdinal(tr, word, wtab, 1))
wtab[0].flags |= FLAG_ORDINAL;
if(tr->langopts.numbers & NUM_ROMAN_ORDINAL)
@@ -876,8 +880,8 @@ int TranslateRoman(Translator *tr, char *word, char *ph_out, WORD_TAB *wtab)
wtab[0].flags |= FLAG_ORDINAL;
}
TranslateNumber(tr, &number_chars[1], p, &flags, wtab);
tr->prev_dict_flags = 0;
TranslateNumber(tr, &number_chars[2], p, flags, wtab);
if(tr->langopts.numbers & NUM_ROMAN_AFTER)
strcat(ph_out,ph_roman);
@@ -922,6 +926,7 @@ static int LookupThousands(Translator *tr, int value, int thousandplex, int thou
char string[12];
char ph_of[12];
char ph_thousands[40];
char ph_buf[40];
ph_of[0] = 0;
@@ -976,10 +981,24 @@ static int LookupThousands(Translator *tr, int value, int thousandplex, int thou
if(Lookup(tr, string, ph_thousands) == 0)
{
// repeat "thousand" if higher order names are not available
sprintf(string,"_%dM1",value);
if((found_value = Lookup(tr, string, ph_thousands)) == 0)
Lookup(tr, "_0M1", ph_thousands);
if(thousandplex > 3)
{
sprintf(string,"_0M%d", thousandplex-1);
if(Lookup(tr, string, ph_buf) == 0)
{
// say "millions" if this name is not available and neither is the next lower
Lookup(tr, "_0M2", ph_thousands);
speak_missing_thousands = 3;
}
}
if(ph_thousands[0] == 0)
{
// repeat "thousand" if higher order names are not available
sprintf(string,"_%dM1",value);
if((found_value = Lookup(tr, string, ph_thousands)) == 0)
Lookup(tr, "_0M1", ph_thousands);
speak_missing_thousands = 2;
}
}
}
}
@@ -1015,6 +1034,9 @@ static int LookupNum2(Translator *tr, int value, int control, char *ph_out)
found = 0;
ph_ordinal[0] = 0;
ph_tens[0] = 0;
ph_digits[0] = 0;
ph_and[0] = 0;
if((control & 2) && (n_digit_lookup == 2))
{
@@ -1366,7 +1388,7 @@ static int TranslateNumber_1(Translator *tr, char *word, char *ph_out, unsigned
int n_digits;
int value;
unsigned int ix;
int ix;
unsigned char c;
int suppress_null = 0;
int decimal_point = 0;
@@ -1376,7 +1398,6 @@ static int TranslateNumber_1(Translator *tr, char *word, char *ph_out, unsigned
int prev_thousands = 0;
int ordinal = 0;
int this_value;
static int prev_value;
int decimal_count;
int max_decimal_count;
int decimal_mode;
@@ -1394,16 +1415,48 @@ static int TranslateNumber_1(Translator *tr, char *word, char *ph_out, unsigned
static const char str_pause[2] = {phonPAUSE_NOLINK,0};
*flags = 0;
n_digit_lookup = 0;
buf_digit_lookup[0] = 0;
digit_lookup = buf_digit_lookup;
for(ix=0; isdigit(word[ix]); ix++) ;
n_digits = ix;
value = this_value = atoi(word);
// is there a previous thousands part (as a previous "word") ?
if((n_digits == 3) && (word[-2] == tr->langopts.thousands_sep) && isdigit(word[-3]))
{
prev_thousands = 1;
}
else
if((tr->langopts.thousands_sep == ' ') || (tr->langopts.numbers & NUM_ALLOW_SPACE))
{
// thousands groups can be separated by spaces
if((n_digits == 3) && isdigit(word[-2]))
{
prev_thousands = 1;
}
}
if(prev_thousands == 0)
{
speak_missing_thousands = 0;
}
ph_ordinal2[0] = 0;
ph_zeros[0] = 0;
ordinal = CheckDotOrdinal(tr, &word[ix], wtab, 1);
if(prev_thousands || (word[0] != '0'))
{
// don't check for ordinal if the number has a leading zero
ordinal = CheckDotOrdinal(tr, &word[ix], wtab, 0);
}
if((word[ix] == '.') && !isdigit(word[ix+1]) && !isdigit(word[ix+2]) && !(wtab[1].flags & FLAG_NOSPACE))
{
// remove dot unless followed by another number
word[ix] = 0;
}
if(ordinal == 0)
{
@@ -1417,7 +1470,7 @@ static int TranslateNumber_1(Translator *tr, char *word, char *ph_out, unsigned
hyphen = 1;
ix++;
}
while((word[ix] != 0) && (word[ix] != ' ') && (ix < (sizeof(suffix)-1)))
while((word[ix] != 0) && (word[ix] != ' ') && (ix < int(sizeof(suffix)-1)))
{
*p++ = word[ix++];
}
@@ -1442,20 +1495,6 @@ static int TranslateNumber_1(Translator *tr, char *word, char *ph_out, unsigned
ph_append[0] = 0;
ph_buf2[0] = 0;
// is there a previous thousands part (as a previous "word") ?
if((n_digits == 3) && (word[-2] == tr->langopts.thousands_sep) && isdigit(word[-3]))
{
prev_thousands = 1;
}
else
if((tr->langopts.thousands_sep == ' ') || (tr->langopts.numbers & NUM_ALLOW_SPACE))
{
// thousands groups can be separated by spaces
if((n_digits == 3) && isdigit(word[-2]))
{
prev_thousands = 1;
}
}
if((word[0] == '0') && (prev_thousands == 0) && (word[1] != ' ') && (word[1] != tr->langopts.decimal_sep))
{
@@ -1532,12 +1571,13 @@ static int TranslateNumber_1(Translator *tr, char *word, char *ph_out, unsigned
}
}
else
if((thousandplex > 1) && prev_thousands && (prev_value > 0))
if(speak_missing_thousands == 1)
{
sprintf(string,"_%s%d",M_Variant(value),thousandplex+1);
// speak this thousandplex if there was no word for the previous thousandplex
sprintf(string,"_0M%d",thousandplex+1);
if(Lookup(tr, string, buf1)==0)
{
// speak this thousandplex if there was no word for the previous thousandplex
sprintf(string,"_0M%d",thousandplex);
Lookup(tr, string, ph_append);
}
@@ -1548,8 +1588,6 @@ static int TranslateNumber_1(Translator *tr, char *word, char *ph_out, unsigned
Lookup(tr, "_.", ph_append);
}
n_digit_lookup = 0;
buf_digit_lookup[0] = 0;
if(thousandplex == 0)
{
char *p2;
@@ -1560,13 +1598,17 @@ static int TranslateNumber_1(Translator *tr, char *word, char *ph_out, unsigned
{
p2 = p - 1;
if(LookupDictList(tr, &p2, buf_digit_lookup, flags, FLAG_SUFX, wtab)) // lookup 2 digits
{
n_digit_lookup = 2;
}
}
if((buf_digit_lookup[0] == 0) && (*p != '0'))
{
// not found, lookup only the last digit
if(LookupDictList(tr, &p, buf_digit_lookup, flags, FLAG_SUFX, wtab)) // don't match '0', or entries with $only
n_digit_lookup = 1;
{
n_digit_lookup = 1;
}
}
}
@@ -1674,7 +1716,7 @@ static int TranslateNumber_1(Translator *tr, char *word, char *ph_out, unsigned
}
*flags |= FLAG_FOUND;
prev_value = this_value;
speak_missing_thousands--;
return(1);
} // end of TranslateNumber_1
+1
View File
@@ -95,6 +95,7 @@ extern const unsigned char pause_phonemes[8]; // 0, vshort, short, pause, long,
// place of articulation
#define phPLACE 0xf0000
#define phPLACE_blb 0x10000
#define phPLACE_pla 0x60000
#define N_PHONEME_TABS 100 // number of phoneme tables
+99 -4
View File
@@ -61,6 +61,7 @@ static int ignore_text=0; // set during <sub> ... </sub> to ignore text which
static int clear_skipping_text = 0; // next clause should clear the skipping_text flag
int count_characters = 0;
static int sayas_mode;
static int sayas_start;
static int ssml_ignore_l_angle = 0;
// alter tone for announce punctuation or capitals
@@ -1521,6 +1522,31 @@ static void SetProsodyParameter(int param_type, wchar_t *attr1, PARAM_STACK *sp)
} // end of SetProsodyParemeter
static int ReplaceKeyName(char *outbuf, int index, int &outix)
{//===========================================================
// Replace some key-names by single characters, so they can be pronounced in different languages
MNEM_TAB keynames[] = {
{"space ",0xe020},
{"tab ", 0xe009},
{"underscore ", 0xe05f},
{"double-quote ", '"'},
{NULL, 0}};
int ix;
int letter;
char *p;
p = &outbuf[index+1];
if((letter = LookupMnem(keynames, p)) != 0)
{
ix = utf8_out(letter, p);
outix = index + ix + 1;
return(letter);
}
return(0);
}
static int ProcessSsmlTag(wchar_t *xml_buf, char *outbuf, int &outix, int n_outbuf, int self_closing)
{//==================================================================================================
@@ -1706,10 +1732,17 @@ static int ProcessSsmlTag(wchar_t *xml_buf, char *outbuf, int &outix, int n_outb
strcpy(&outbuf[outix],buf);
outix += strlen(buf);
sayas_start = outix;
sayas_mode = value; // punctuation doesn't end clause during SAY-AS
break;
case SSML_SAYAS + SSML_CLOSE:
if(sayas_mode == SAYAS_KEY)
{
outbuf[outix] = 0;
ReplaceKeyName(outbuf, sayas_start, outix);
}
outbuf[outix++] = CTRL_EMBEDDED;
outbuf[outix++] = 'Y';
sayas_mode = 0;
@@ -1971,6 +2004,8 @@ int ReadClause(Translator *tr, FILE *f_in, char *buf, short *charix, int *charix
int is_end_clause;
int announced_punctuation;
int stressed_word = 0;
int end_clause_after_tag = 0;
int end_clause_index = 0;
const char *p;
wchar_t xml_buf[N_XML_BUF+1];
@@ -1985,6 +2020,7 @@ int ReadClause(Translator *tr, FILE *f_in, char *buf, short *charix, int *charix
clear_skipping_text = 0;
}
tr->phonemes_repeat_count = 0;
tr->clause_upper_count = 0;
tr->clause_lower_count = 0;
end_of_input = 0;
@@ -2150,6 +2186,9 @@ f_input = f_in; // for GetC etc
if(terminator != 0)
{
if(end_clause_after_tag)
ix = end_clause_index;
buf[ix] = ' ';
buf[ix++] = 0;
@@ -2333,6 +2372,9 @@ f_input = f_in; // for GetC etc
// 2nd newline, assume paragraph
UngetC(c2);
if(end_clause_after_tag)
ix = end_clause_index; // delete clause-end punctiation
buf[ix] = ' ';
buf[ix+1] = 0;
if(parag > 3)
@@ -2359,6 +2401,30 @@ if(option_ssml) parag=1;
{
is_end_clause = 0;
if(end_clause_after_tag)
{
// Because of an xml tag, we are waiting for the
// next non-blank character to decide whether to end the clause
// i.e. is dot followed by an upper-case letter?
if(c1 == '\n')
{
// end_clause_after_tag &= ~CLAUSE_DOT;
}
if(!iswspace(c1))
{
if(iswdigit(c1) || (IsAlpha(c1) && !iswlower(c1)))
{
UngetC(c2);
ungot_char2 = c1;
buf[end_clause_index] = ' '; // delete the end-clause punctuation
buf[end_clause_index+1] = 0;
return(end_clause_after_tag);
}
end_clause_after_tag = 0;
}
}
if((c1 == '.') && (c2 == '.'))
{
while((c_next = GetC()) == '.')
@@ -2396,6 +2462,7 @@ if(option_ssml) parag=1;
// if a list of allowed punctuation has been set up, check whether the character is in it
if((option_punctuation == 1) || (wcschr(option_punctlist,c1) != NULL))
{
tr->phonemes_repeat_count = 0;
if((terminator = AnnouncePunctuation(tr, c1, &c2, buf, &ix, is_end_clause)) >= 0)
return(terminator);
announced_punctuation = c1;
@@ -2432,6 +2499,11 @@ if(option_ssml) parag=1;
}
}
if((c1 == '.') && (nl_count < 2))
{
punct_data |= CLAUSE_DOT;
}
if(nl_count==0)
{
if(c1 == '.')
@@ -2440,14 +2512,21 @@ if(option_ssml) parag=1;
(iswdigit(cprev) || (IsRomanU(cprev) && (IsRomanU(cprev2) || iswspace(cprev2))))) // lang=hu
{
// dot after a number indicates an ordinal number
if(!iswdigit(cprev) || iswlower(c_next) || (c_next == '<'))
is_end_clause = 0; // only if followed by lower-case, (or if there is a XML tag)
if(!iswdigit(cprev))
{
is_end_clause = 0; // Roman number followed by dot
}
else
{
if (iswlower(c_next))
is_end_clause = 0; // only if followed by lower-case, (or if there is a XML tag)
}
}
else
if(iswlower(c_next))
{
// next word has no capital letter, this dot is probably from an abbreviation
c1 = ' ';
// c1 = ' ';
is_end_clause = 0;
}
if(any_alnum==0)
@@ -2466,6 +2545,14 @@ if(option_ssml) parag=1;
is_end_clause = 0;
}
}
if(is_end_clause && (c1 == '.') && (c_next == '<') && option_ssml)
{
// wait until after the end of the xml tag, then look for upper-case letter
is_end_clause = 0;
end_clause_index = ix;
end_clause_after_tag = punct_data;
}
}
if(is_end_clause)
@@ -2473,7 +2560,11 @@ if(option_ssml) parag=1;
UngetC(c_next);
buf[ix] = ' ';
buf[ix+1] = 0;
if(!IsAlpha(c_next))
{
punct_data &= ~CLAUSE_DOT;
}
if(nl_count > 1)
{
if((punct_data == CLAUSE_QUESTION) || (punct_data == CLAUSE_EXCLAMATION))
@@ -2536,6 +2627,10 @@ if(option_ssml) parag=1;
{
ix += utf8_out(CHAR_EMPHASIS, &buf[ix]);
}
if(end_clause_after_tag)
{
ix = end_clause_index; // delete clause-end punctuation
}
buf[ix] = ' ';
buf[ix+1] = 0;
return(CLAUSE_EOF); // end of file
+2 -2
View File
@@ -326,10 +326,10 @@ void CalcLengths(Translator *tr)
case phSTOP:
last_pitch = 0;
if(prev->type == phFRICATIVE)
p->prepause = 20;
p->prepause = 25;
else
if((more_syllables > 0) || (stress < 4))
p->prepause = 40;
p->prepause = 48;
else
p->prepause = 60;
+39 -1
View File
@@ -47,6 +47,7 @@
#include "wave.h"
unsigned char *outbuf=NULL;
extern FILE *f_logespeak;
extern espeak_VOICE voice_selected;
espeak_EVENT *event_list=NULL;
@@ -713,7 +714,12 @@ ENTER("espeak_Initialize");
init_path(path);
initialise();
select_output(output_type);
if(f_logespeak)
{
fprintf(f_logespeak,"INIT mode %d options 0x%x\n",output_type,options);
}
// buflength is in mS, allocate 2 bytes per sample
if(buf_length == 0)
buf_length = 200;
@@ -763,6 +769,12 @@ ESPEAK_API espeak_ERROR espeak_Synth(const void *text, size_t size,
SHOW("espeak_Synth > position=%d, position_type=%d, end_position=%d, flags=%d, user_data=0x%x, text=%s\n", position, position_type, end_position, flags, user_data, text);
#endif
if(f_logespeak)
{
fprintf(f_logespeak,"\nSYNTH posn %d %d %d flags 0x%x\n%s\n",position,end_position,position_type,flags, (const char *)text);
fflush(f_logespeak);
}
espeak_ERROR a_error=EE_INTERNAL_ERROR;
static unsigned int temp_identifier;
@@ -825,6 +837,12 @@ ESPEAK_API espeak_ERROR espeak_Synth_Mark(const void *text, size_t size,
espeak_ERROR a_error=EE_OK;
static unsigned int temp_identifier;
if(f_logespeak)
{
fprintf(f_logespeak,"\nSYNTH MARK %s posn %d flags 0x%x\n%s\n",index_mark,end_position,flags, (const char *)text);
}
if (unique_identifier == NULL)
{
unique_identifier = &temp_identifier;
@@ -875,6 +893,11 @@ ESPEAK_API espeak_ERROR espeak_Key(const char *key)
ENTER("espeak_Key");
// symbolic name, symbolicname_character - is there a system resource of symbolicnames per language
if(f_logespeak)
{
fprintf(f_logespeak,"\nKEY %s\n",key);
}
espeak_ERROR a_error = EE_OK;
if(synchronous_mode)
@@ -901,6 +924,11 @@ ESPEAK_API espeak_ERROR espeak_Char(wchar_t character)
ENTER("espeak_Char");
// is there a system resource of character names per language?
if(f_logespeak)
{
fprintf(f_logespeak,"\nCHAR U+%x\n",character);
}
#ifdef USE_ASYNC
espeak_ERROR a_error;
@@ -997,6 +1025,10 @@ ESPEAK_API espeak_ERROR espeak_SetParameter(espeak_PARAMETER parameter, int valu
{//=============================================================================================
ENTER("espeak_SetParameter");
if(f_logespeak)
{
fprintf(f_logespeak,"SETPARAM %d %d %d\n",parameter,value,relative);
}
#ifdef USE_ASYNC
espeak_ERROR a_error;
@@ -1141,6 +1173,12 @@ ESPEAK_API espeak_ERROR espeak_Terminate(void)
outbuf = NULL;
FreePhData();
if(f_logespeak)
{
fclose(f_logespeak);
f_logespeak = NULL;
}
return EE_OK;
} // end of espeak_Terminate
+1 -1
View File
@@ -507,7 +507,7 @@ const espeak_VOICE **espeak_ListVoices(espeak_VOICE *voice_spec);
The list is terminated by a NULL pointer
If voice_spec is NULL then all voices are listed.
If voice spec is give, then only the voices which are compatible with the voice_spec
If voice spec is given, then only the voices which are compatible with the voice_spec
are listed, and they are listed in preference order.
*/
+14 -2
View File
@@ -35,10 +35,12 @@
#include "translate.h"
#include "wave.h"
const char *version_string = "1.41.32 09.Nov.09";
const int version_phdata = 0x014118;
const char *version_string = "1.42.02 30.Nov.09";
const int version_phdata = 0x014200;
int option_device_number = -1;
FILE *f_logespeak = NULL;
int logging_type;
// copy the current phoneme table into here
int n_phoneme_tab;
@@ -640,6 +642,8 @@ void LoadConfig(void)
char *p;
char string[200];
logging_type = 0;
for(ix=0; ix<N_SOUNDICON_SLOTS; ix++)
{
soundicon_tab[ix].filename = NULL;
@@ -654,6 +658,14 @@ void LoadConfig(void)
while(fgets(buf,sizeof(buf),f)!=NULL)
{
if(buf[0] == '/') continue;
if(memcmp(buf,"log",3)==0)
{
if(sscanf(&buf[4],"%d %s",&logging_type,string)==2)
f_logespeak = fopen(string,"w");
}
else
if(memcmp(buf,"tone",4)==0)
{
ReadTonePoints(&buf[5],tone_points);
+51 -12
View File
@@ -876,36 +876,65 @@ int DoSpect(PHONEME_TAB *this_ph, PHONEME_TAB *prev_ph, PHONEME_TAB *next_ph,
int ix;
long *q;
int len;
int min;
int match_level;
int frame_length;
int frame1_length;
int frame2_length;
int length_factor;
int length_mod;
int length_mod2; // reduced effect length_mod
int total_len = 0;
int len_adjust_factor = 256;
static int wave_flag = 0;
int wcmd_spect = WCMD_SPECT;
length_mod = plist->length;
if(length_mod==0) length_mod=256;
if(which==1)
{
// limit the shortening of sonorants before shortened (eg. unstressed vowels)
if((this_ph->type==phLIQUID) || (prev_ph->type==phLIQUID) || (prev_ph->type==phNASAL))
length_mod2 = (length_mod*(256-speed.speed_factor3) + 256*speed.speed_factor3)/256;
if(which==1)
{
if(length_mod < (len = translator->langopts.param[LOPT_SONORANT_MIN]))
// limit the shortening of sonorants before shortened (eg. unstressed vowels)
if((this_ph->type==phLIQUID) || (prev_ph->type==phLIQUID) || (prev_ph->type==phNASAL))
{
length_mod = len;
if(length_mod < (len = translator->langopts.param[LOPT_SONORANT_MIN]))
{
length_mod = len;
}
}
}
}
modn_flags = 0;
frames = LookupSpect(this_ph,prev_ph,next_ph,which,&match_level,&n_frames, plist);
if(frames == NULL)
return(0); // not found
// if((which==2) && (this_ph->phflags & phLONG))
if((which==2) && (this_ph->std_length >= 200))
{
// apply a minimum length for long vowels at fast speeds, to keep the distinction with short vowels
total_len = 0;
for(frameix=0; frameix<(n_frames-1); frameix++)
{
length_factor = length_mod;
if(frames[frameix].frflags & FRFLAG_LEN_MOD) // reduce effect of length mod
{
length_factor = length_mod2;
}
len = (frames[frameix].length * samplerate)/1000;
len = (len * length_factor)/256;
total_len += len;
}
min = translator->langopts.param[LOPT_MIN_LONG_VOWEL] * (samplerate)/1000;
min = (min * length_mod2)/256;
if(total_len < min)
{
len_adjust_factor = (min*256)/total_len;
}
}
frame1 = frames[0].frame;
frame1_length = frames[0].length;
if(voice->klattv[0])
@@ -960,6 +989,7 @@ if(which==1)
syllable_centre = wcmdq_tail;
}
total_len = 0;
frame_length = frame1_length;
for(frameix=1; frameix<n_frames; frameix++)
{
@@ -978,10 +1008,11 @@ if(which==1)
length_factor = length_mod;
if(frame1->frflags & FRFLAG_LEN_MOD) // reduce effect of length mod
{
length_factor = (length_mod*(256-speed.speed_factor3) + 256*speed.speed_factor3)/256;
length_factor = length_mod2;
}
len = (frame_length * samplerate)/1000;
len = (len * length_factor)/256;
len = (len * len_adjust_factor)/256;
if(modulation >= 0)
{
@@ -1210,8 +1241,16 @@ int Generate(PHONEME_LIST *phoneme_list, int *n_ph, int resume)
case phSTOP:
released = 0;
if(next->type==phVOWEL) released = 1;
if(next->type==phLIQUID && !next->newword) released = 1;
if(next->type==phVOWEL)
{
released = 1;
}
else
if(!next->newword)
{
if(next->type==phLIQUID) released = 1;
// if(((p->ph->phflags & phPLACE) == phPLACE_blb) && (next->ph->phflags & phSIBILANT)) released = 1;
}
if(released)
DoSample(p->ph,next->ph,2,0,0);
@@ -1307,7 +1346,7 @@ int Generate(PHONEME_LIST *phoneme_list, int *n_ph, int resume)
}
}
if((next->type==phVOWEL) || ((next->type==phLIQUID)) && (next->newword==0)) // ?? test 14.Aug.2007
if((next->type==phVOWEL) || ((next->type==phLIQUID) && (next->newword==0))) // ?? test 14.Aug.2007
{
StartSyllable();
if(p->synthflags & SFLAG_LENGTHEN)
+28 -13
View File
@@ -46,6 +46,7 @@
#define OFFSET_GREEK 0x380
#define OFFSET_CYRILLIC 0x420
#define OFFSET_ARMENIAN 0x530
#define OFFSET_ARABIC 0x600
#define OFFSET_DEVANAGARI 0x900
#define OFFSET_BENGALI 0x980
#define OFFSET_GURMUKHI 0xa00
@@ -156,6 +157,7 @@ static Translator* NewTranslator(void)
tr->langopts.param[LOPT_UNPRONOUNCABLE] = 's'; // don't count this character at start of word
tr->langopts.param[LOPT_BRACKET_PAUSE] = 4; // pause at bracket
tr->langopts.param2[LOPT_BRACKET_PAUSE] = 2; // pauses when announcing bracket names
tr->langopts.param[LOPT_MIN_LONG_VOWEL] = 40;
tr->langopts.max_initial_consonants = 3;
tr->langopts.replace_chars = NULL;
tr->langopts.ascii_language = ""; // Non-Latin alphabet languages, use this language to speak Latin words, default is English
@@ -221,7 +223,9 @@ void SetIndicLetters(Translator *tr)
static const char dev_consonants2[] = {0x02,0x03,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f};
memset(tr->letter_bits,0,sizeof(tr->letter_bits));
SetLetterBitsRange(tr,LETTERGP_A,0x04,0x14); // vowel letters only
SetLetterBitsRange(tr,LETTERGP_A,0x04,0x14); // vowel letters
SetLetterBitsRange(tr,LETTERGP_A,0x3e,0x4d); // + vowel signs, and virama
SetLetterBitsRange(tr,LETTERGP_B,0x3e,0x4d); // vowel signs, and virama
SetLetterBitsRange(tr,LETTERGP_C,0x15,0x39); // the main consonant range
@@ -274,6 +278,12 @@ Translator *SelectTranslator(const char *name)
}
break;
case L('a','r'): // Arabic
case L('u','r'): // Urdu
tr->letter_bits_offset = OFFSET_ARABIC;
tr->langopts.param[LOPT_UNPRONOUNCABLE] = 1; // disable check for unpronouncable words
break;
case L('b','n'): // Bengali
{
static const short stress_lengths_bn[8] = {180, 180, 210, 210, 0, 0, 230, 240};
@@ -463,13 +473,15 @@ Translator *SelectTranslator(const char *name)
static const unsigned char stress_amps_eu[8] = {16,16, 18,18, 18,18, 18,18 };
SetupTranslator(tr,stress_lengths_eu,stress_amps_eu);
tr->langopts.stress_rule = STRESSPOSN_2L; // ?? second syllable ??
tr->langopts.numbers = NUM_SINGLE_STRESS + NUM_DECIMAL_COMMA | NUM_AND_UNITS | NUM_HUNDRED_AND | NUM_OMIT_1_HUNDRED | NUM_VIGESIMAL;
tr->langopts.numbers = NUM_SINGLE_STRESS | NUM_DECIMAL_COMMA | NUM_AND_UNITS | NUM_HUNDRED_AND | NUM_OMIT_1_HUNDRED | NUM_VIGESIMAL;
}
break;
case L('f','a'): // Farsi
{
tr->letter_bits_offset = OFFSET_ARABIC;
tr->langopts.numbers = NUM_AND_UNITS | NUM_HUNDRED_AND;
tr->langopts.param[LOPT_UNPRONOUNCABLE] = 1; // disable check for unpronouncable words
}
break;
@@ -486,6 +498,7 @@ Translator *SelectTranslator(const char *name)
tr->langopts.stress_flags = 0x56; // move secondary stress from light to a following heavy syllable
tr->langopts.param[LOPT_IT_DOUBLING] = 1;
tr->langopts.long_stop = 130;
tr->langopts.param[LOPT_MIN_LONG_VOWEL] = 65;
tr->langopts.numbers = NUM_DECIMAL_COMMA + NUM_ALLOW_SPACE;
SetLetterVowel(tr,'y');
@@ -506,7 +519,7 @@ Translator *SelectTranslator(const char *name)
tr->langopts.stress_flags = 0x0024; // don't use secondary stress
tr->langopts.param[LOPT_IT_LENGTHEN] = 1; // remove lengthen indicator from unstressed syllables
tr->langopts.numbers = NUM_SINGLE_STRESS + NUM_DECIMAL_COMMA | NUM_ALLOW_SPACE | NUM_OMIT_1_HUNDRED | NUM_NOPAUSE | NUM_ROMAN | NUM_VIGESIMAL | NUM_DFRACTION_4;
tr->langopts.numbers = NUM_SINGLE_STRESS | NUM_DECIMAL_COMMA | NUM_ALLOW_SPACE | NUM_OMIT_1_HUNDRED | NUM_NOPAUSE | NUM_ROMAN | NUM_VIGESIMAL | NUM_DFRACTION_4;
SetLetterVowel(tr,'y');
}
break;
@@ -558,7 +571,7 @@ Translator *SelectTranslator(const char *name)
tr->langopts.spelling_stress = 1;
tr->langopts.accents = 1;
tr->langopts.numbers = NUM_SINGLE_STRESS + NUM_HUNDRED_AND | NUM_DECIMAL_COMMA | NUM_THOUS_SPACE | NUM_DFRACTION_2 | NUM_ROMAN_UC;
tr->langopts.numbers = NUM_SINGLE_STRESS | NUM_HUNDRED_AND | NUM_OMIT_1_HUNDRED | NUM_DECIMAL_COMMA | NUM_THOUS_SPACE | NUM_DFRACTION_2 | NUM_ROMAN_UC;
tr->langopts.numbers2 = 0x4a; // variant numbers before thousands,milliards
tr->langopts.replace_chars = replace_cyrillic_latin;
@@ -578,11 +591,11 @@ Translator *SelectTranslator(const char *name)
tr->langopts.vowel_pause = 0x20;
tr->langopts.stress_rule = STRESSPOSN_1L;
tr->langopts.stress_flags = 0x8036 | STRS_HYPEN_UNSTRESS;
tr->langopts.stress_flags = 0x8036 | S_HYPEN_UNSTRESS;
tr->langopts.unstressed_wd1 = 2;
tr->langopts.param[LOPT_IT_DOUBLING] = 1;
tr->langopts.param[LOPT_ANNOUNCE_PUNCT] = 2; // don't break clause before announcing . ? !
// tr->langopts.param[LOPT_COMBINE_WORDS] = 9; // combine some prepositions with the following word
tr->langopts.param[LOPT_MIN_LONG_VOWEL] = 65;
tr->langopts.numbers = NUM_DECIMAL_COMMA | NUM_ALLOW_SPACE | NUM_DFRACTION_5 | NUM_ROMAN | NUM_ROMAN_ORDINAL | NUM_ROMAN_CAPITALS | NUM_ORDINAL_DOT | NUM_OMIT_1_HUNDRED;
tr->langopts.min_roman = 1;
@@ -786,7 +799,7 @@ SetLengthMods(tr,3); // all equal
SetupTranslator(tr,stress_lengths_no,NULL);
tr->langopts.stress_rule = STRESSPOSN_1L;
SetLetterVowel(tr,'y');
tr->langopts.numbers = NUM_DECIMAL_COMMA | NUM_HUNDRED_AND | NUM_ALLOW_SPACE | NUM_1900 + NUM_ORDINAL_DOT;
tr->langopts.numbers = NUM_DECIMAL_COMMA | NUM_HUNDRED_AND | NUM_ALLOW_SPACE | NUM_1900 | NUM_ORDINAL_DOT;
}
break;
@@ -822,18 +835,19 @@ 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,22, 22,21 }; // 'diminished' is used to mark a quieter, final unstressed syllable
static const short stress_lengths_pt[8] = {170, 115, 210, 240, 0, 0, 260, 280};
static const unsigned char stress_amps_pt[8] = {16,11, 19,21, 20,22, 22,21 }; // 'diminished' is used to mark a quieter, final unstressed syllable
SetupTranslator(tr,stress_lengths_pt,stress_amps_pt);
tr->langopts.length_mods0 = tr->langopts.length_mods; // don't lengthen vowels in the last syllable
tr->langopts.stress_rule = STRESSPOSN_1R; // stress on final syllable
tr->langopts.stress_flags = 0x6 | 0x10 | 0x20000;
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;
SetLetterVowel(tr,'y');
ResetLetterBits(tr,0x2);
SetLetterBits(tr,1,"bcdfgjkmnpqstvxz"); // B hard consonants, excluding h,l,r,w,y
tr->langopts.param[LOPT_ALT] = 2; // call ApplySpecialAttributes2() if a word has $alt or $alt2
}
break;
@@ -924,7 +938,7 @@ SetLengthMods(tr,3); // all equal
tr->langopts.stress_rule = STRESSPOSN_1L;
SetLetterVowel(tr,'y');
tr->langopts.numbers = NUM_SINGLE_STRESS + NUM_DECIMAL_COMMA | NUM_ALLOW_SPACE | NUM_1900;
tr->langopts.numbers = NUM_SINGLE_STRESS | NUM_DECIMAL_COMMA | NUM_ALLOW_SPACE | NUM_1900;
tr->langopts.accents = 1;
}
break;
@@ -959,7 +973,7 @@ SetLengthMods(tr,3); // all equal
tr->langopts.stress_rule = STRESSPOSN_1L;
tr->langopts.stress_flags = 0x10004; // use 'diminished' for unstressed final syllable
tr->langopts.break_numbers = 0x24a8; // 1000, 100,000 10,000,000
tr->langopts.break_numbers = 0x14a8; // 1000, 100,000 10,000,000
if(name2 == L('t','a'))
{
@@ -1015,7 +1029,7 @@ SetLengthMods(tr,3); // all equal
tr->langopts.stress_rule = 7; // stress on the last syllable, before any explicitly unstressed syllable
tr->langopts.stress_flags = 0x20; //no automatic secondary stress
tr->langopts.numbers = NUM_SINGLE_STRESS + NUM_DECIMAL_COMMA | NUM_ALLOW_SPACE | NUM_OMIT_1_HUNDRED | NUM_DFRACTION_2;
tr->langopts.numbers = NUM_SINGLE_STRESS | NUM_DECIMAL_COMMA | NUM_ALLOW_SPACE | NUM_OMIT_1_HUNDRED | NUM_DFRACTION_2;
tr->langopts.max_initial_consonants = 2;
}
break;
@@ -1093,6 +1107,7 @@ SetLengthMods(tr,3); // all equal
{
tr->langopts.thousands_sep = 0; // don't allow thousands separator, except space
}
return(tr);
} // end of SelectTranslator
+96 -45
View File
@@ -80,7 +80,11 @@ int pre_pause;
// these were previously in translator class
#ifdef PLATFORM_WINDOWS
char word_phonemes[N_WORD_PHONEMES*2]; // longer, because snprint() is not available
#else
char word_phonemes[N_WORD_PHONEMES]; // a word translated into phoneme codes
#endif
int n_ph_list2;
PHONEME_LIST2 ph_list2[N_PHONEME_LIST]; // first stage of text->phonemes
@@ -384,6 +388,9 @@ int IsAlpha(unsigned int c)
return(0);
}
if((c >= 0x64b) && (c <= 0x65e))
return(1); // arabic vowel marks
if((c >= 0x300) && (c <= 0x36f))
return(1); // combining accents
@@ -567,7 +574,6 @@ char *strchr_w(const char *s, int c)
int TranslateWord(Translator *tr, char *word1, int next_pause, WORD_TAB *wtab)
{//===========================================================================
// word1 is terminated by space (0x20) character
@@ -585,17 +591,16 @@ int TranslateWord(Translator *tr, char *word1, int next_pause, WORD_TAB *wtab)
char *wordx;
char phonemes[N_WORD_PHONEMES];
char *ph_limit;
char *phonemes_ptr;
char prefix_phonemes[N_WORD_PHONEMES];
char unpron_phonemes[N_WORD_PHONEMES];
char end_phonemes[N_WORD_PHONEMES];
char word_copy[N_WORD_BYTES];
char prefix_chars[N_WORD_BYTES];
char prefix_chars[41];
int found=0;
int end_flags;
char c_temp; // save a character byte while we temporarily replace it with space
int first_char;
int last_char = 0;
int unpron_length;
int add_plural_suffix = 0;
int prefix_flags = 0;
int confirm_prefix;
@@ -626,6 +631,8 @@ int TranslateWord(Translator *tr, char *word1, int next_pause, WORD_TAB *wtab)
dictionary_flags2[1] = 0;
dictionary_skipwords = 0;
phonemes[0] = 0;
unpron_phonemes[0] = 0;
prefix_phonemes[0] = 0;
end_phonemes[0] = 0;
ph_limit = &phonemes[N_WORD_PHONEMES];
@@ -649,15 +656,22 @@ int TranslateWord(Translator *tr, char *word1, int next_pause, WORD_TAB *wtab)
word_length++;
}
// try an initial lookup in the dictionary list, we may find a pronunciation specified, or
// we may just find some flags
spell_word = 0;
if(option_sayas == SAYAS_KEY)
{
if(word_length == 1)
spell_word = 4;
else
{
// is there a translation for this keyname ?
word1--;
*word1 = '_'; // prefix keyname with '_'
found = LookupDictList(tr, &word1, phonemes, dictionary_flags, 0, wtab);
}
}
// try an initial lookup in the dictionary list, we may find a pronunciation specified, or
// we may just find some flags
if(option_sayas & 0x10)
{
// SAYAS_CHAR, SAYAS_GYLPH, or SAYAS_SINGLE_CHAR
@@ -665,9 +679,10 @@ int TranslateWord(Translator *tr, char *word1, int next_pause, WORD_TAB *wtab)
}
else
{
found = LookupDictList(tr, &word1, phonemes, dictionary_flags, FLAG_ALLOW_TEXTMODE, wtab); // the original word
if(!found)
found = LookupDictList(tr, &word1, phonemes, dictionary_flags, FLAG_ALLOW_TEXTMODE, wtab); // the original word
if((dictionary_flags[0] & FLAG_DOT) && (wordx[1] == '.'))
if((dictionary_flags[0] & (FLAG_ALLOW_DOT || FLAG_NEEDS_DOT)) && (wordx[1] == '.'))
{
wordx[1] = ' '; // remove a Dot after this word
}
@@ -773,7 +788,7 @@ if((wmark > 0) && (wmark < 8))
while(*wordx != ' ')
{
wordx += TranslateLetter(tr,wordx, phonemes,spell_word, word_length);
wordx += TranslateLetter(tr,wordx, phonemes, spell_word);
posn++;
if(phonemes[0] == phonSWITCH)
{
@@ -802,13 +817,13 @@ if((wmark > 0) && (wmark < 8))
// This word looks "unpronouncable", so speak letters individually until we
// find a remainder that we can pronounce.
emphasize_allcaps = 0;
wordx += TranslateLetter(tr,wordx,phonemes,0, word_length);
wordx += TranslateLetter(tr, wordx, unpron_phonemes, 0);
posn++;
if(phonemes[0] == phonSWITCH)
{
// change to another language in order to translate this word
strcpy(word_phonemes,phonemes);
if(strcmp(&phonemes[1],"en")==0)
strcpy(word_phonemes,unpron_phonemes);
if(strcmp(&unpron_phonemes[1],"en")==0)
return(FLAG_SPELLWORD); // _^_en must have been set in TranslateLetter(), not *_rules
return(0);
}
@@ -828,13 +843,12 @@ if((wmark > 0) && (wmark < 8))
if(length > 0)
wordx[-1] = ' '; // prevent this affecting the pronunciation of the pronuncable part
}
SetSpellingStress(tr,phonemes,0,posn);
SetSpellingStress(tr,unpron_phonemes,0,posn);
// anything left ?
if(*wordx != ' ')
{
// Translate the stem
unpron_length = strlen(phonemes);
end_type = TranslateRules(tr, wordx, phonemes, N_WORD_PHONEMES, end_phonemes, wflags, dictionary_flags);
if(phonemes[0] == phonSWITCH)
@@ -855,7 +869,7 @@ if((wmark > 0) && (wmark < 8))
posn = 0;
while((*wordx != ' ') && (*wordx != 0))
{
wordx += TranslateLetter(tr,wordx, phonemes, 4, word_length);
wordx += TranslateLetter(tr,wordx, phonemes, 4);
posn++;
if(phonemes[0] == phonSWITCH)
{
@@ -1000,14 +1014,13 @@ strcpy(phonemes2,phonemes);
// The word has a standard ending, re-translate without this ending
end_flags = RemoveEnding(tr, wordx, end_type, word_copy);
phonemes_ptr = &phonemes[unpron_length];
phonemes_ptr[0] = 0;
phonemes[0] = 0;
if(prefix_phonemes[0] != 0)
{
// lookup the stem without the prefix removed
wordx[-1] = c_temp;
found = LookupDictList(tr, &word1, phonemes_ptr, dictionary_flags2, end_flags, wtab); // include prefix, but not suffix
found = LookupDictList(tr, &word1, phonemes, dictionary_flags2, end_flags, wtab); // include prefix, but not suffix
wordx[-1] = ' ';
if(dictionary_flags[0]==0)
{
@@ -1022,12 +1035,12 @@ strcpy(phonemes2,phonemes);
}
if(found == 0)
{
found = LookupDictList(tr, &wordx, phonemes_ptr, dictionary_flags2, end_flags, wtab); // without prefix and suffix
if(phonemes_ptr[0] == phonSWITCH)
found = LookupDictList(tr, &wordx, phonemes, dictionary_flags2, end_flags, wtab); // without prefix and suffix
if(phonemes[0] == phonSWITCH)
{
// change to another language in order to translate this word
memcpy(wordx,word_copy,strlen(word_copy));
strcpy(word_phonemes,phonemes_ptr);
strcpy(word_phonemes,phonemes);
return(0);
}
if(dictionary_flags[0]==0)
@@ -1115,15 +1128,23 @@ strcpy(phonemes2,phonemes);
*p = phonSTRESS_3;
}
}
strcpy(word_phonemes,prefix_phonemes);
strcat(word_phonemes,phonemes);
#ifdef PLATFORM_WINDOWS
sprintf(word_phonemes, "%s%s%s", unpron_phonemes, prefix_phonemes, phonemes);
#else
snprintf(word_phonemes, sizeof(word_phonemes), "%s%s%s", unpron_phonemes, prefix_phonemes, phonemes);
#endif
word_phonemes[N_WORD_PHONEMES-1] = 0;
SetWordStress(tr, word_phonemes, dictionary_flags, -1, 0);
}
else
{
// stress position affects the whole word, including prefix
strcpy(word_phonemes,prefix_phonemes);
strcat(word_phonemes,phonemes);
#ifdef PLATFORM_WINDOWS
sprintf(word_phonemes, "%s%s%s", unpron_phonemes, prefix_phonemes, phonemes);
#else
snprintf(word_phonemes, sizeof(word_phonemes), "%s%s%s", unpron_phonemes, prefix_phonemes, phonemes);
#endif
word_phonemes[N_WORD_PHONEMES-1] = 0;
SetWordStress(tr, word_phonemes, dictionary_flags, -1, tr->prev_last_stress);
}
}
@@ -1133,14 +1154,20 @@ strcpy(phonemes2,phonemes);
SetWordStress(tr, phonemes, dictionary_flags, -1, tr->prev_last_stress);
else
SetWordStress(tr, phonemes, dictionary_flags, -1, 0);
strcpy(word_phonemes,prefix_phonemes);
strcat(word_phonemes,phonemes);
#ifdef PLATFORM_WINDOWS
sprintf(word_phonemes, "%s%s%s", unpron_phonemes, prefix_phonemes, phonemes);
#else
snprintf(word_phonemes, sizeof(word_phonemes), "%s%s%s", unpron_phonemes, prefix_phonemes, phonemes);
#endif
word_phonemes[N_WORD_PHONEMES-1] = 0;
}
if(end_phonemes[0] != 0)
{
// a suffix had the SUFX_T option set, add the suffix after the stress pattern has been determined
strcat(word_phonemes,end_phonemes);
ix = strlen(word_phonemes);
end_phonemes[N_WORD_PHONEMES-1-ix] = 0; // ensure no buffer overflow
strcpy(&word_phonemes[ix], end_phonemes);
}
if(wflags & FLAG_LAST_WORD)
@@ -1150,7 +1177,7 @@ strcpy(phonemes2,phonemes);
dictionary_flags[0] &= ~FLAG_PAUSE1;
}
if((wflags & FLAG_HYPHEN) && (tr->langopts.stress_flags & STRS_HYPEN_UNSTRESS))
if((wflags & FLAG_HYPHEN) && (tr->langopts.stress_flags & S_HYPEN_UNSTRESS))
{
ChangeWordStress(tr,word_phonemes,3);
}
@@ -1237,7 +1264,7 @@ strcpy(phonemes2,phonemes);
{
// English Specific !!!!
// any single letter before a dot is an abbreviation, except 'I'
dictionary_flags[0] |= FLAG_DOT;
dictionary_flags[0] |= FLAG_ALLOW_DOT;
}
if((tr->langopts.param[LOPT_ALT] & 2) && ((dictionary_flags[0] & (FLAG_ALT_TRANS | FLAG_ALT2_TRANS)) != 0))
@@ -2186,12 +2213,10 @@ void *TranslateClause(Translator *tr, FILE *f_text, const void *vp_input, int *t
}
}
if(option_sayas2 == SAYAS_KEY)
if((option_sayas2 == SAYAS_KEY) && (c != ' '))
{
if(((c == '_') || (c == '-')) && IsAlpha(prev_in))
{
c = ' ';
}
if((prev_in == ' ') && (next_in == ' '))
option_sayas2 = SAYAS_SINGLE_CHARS; // single character, speak its name
c = towlower2(c);
}
@@ -2231,7 +2256,7 @@ void *TranslateClause(Translator *tr, FILE *f_text, const void *vp_input, int *t
}
}
else
if((option_sayas2 & 0x30) == 0)
if((option_sayas2 & 0x10) == 0)
{
// speak as words
@@ -2325,6 +2350,7 @@ if((c == '/') && (tr->langopts.testing & 2) && IsDigit09(next_in) && IsAlpha(pre
// start of word, insert space if not one there already
c = ' ';
space_inserted = 1;
next_word_flags |= FLAG_NOSPACE;
}
else
{
@@ -2402,12 +2428,21 @@ if((c == '/') && (tr->langopts.testing & 2) && IsDigit09(next_in) && IsAlpha(pre
else
if(c=='-')
{
if((IsAlpha(prev_in) || iswdigit(prev_in)) && IsAlpha(next_in))
if(!IsSpace(prev_in) && IsAlpha(next_in))
{
// '-' between two letters is a hyphen, treat as a space
word_flags |= FLAG_HYPHEN;
words[word_count-1].flags |= FLAG_HYPHEN_AFTER;
c = ' ';
if(prev_out != ' ')
{
// previous 'word' not yet ended (not alpha or numeric), start new word now.
c = ' ';
space_inserted = 1;
}
else
{
// '-' between two letters is a hyphen, treat as a space
word_flags |= FLAG_HYPHEN;
words[word_count-1].flags |= FLAG_HYPHEN_AFTER;
c = ' ';
}
}
else
if((prev_in==' ') && (next_in==' '))
@@ -2433,6 +2468,18 @@ if((c == '/') && (tr->langopts.testing & 2) && IsDigit09(next_in) && IsAlpha(pre
}
}
else
if(c == '.')
{
if(!(words[word_count-1].flags & FLAG_NOSPACE) && IsAlpha(prev_in))
{
// dot after a word, with space following, probably an abbreviation
words[word_count-1].flags |= FLAG_HAS_DOT;
if(IsSpace(next_in))
c = ' '; // remove the dot if it's followed by a space, so that it's not pronounced
}
}
else
if(c == '\'')
{
if(iswalnum(prev_in) && IsAlpha(next_in))
@@ -2604,9 +2651,14 @@ if((c == '/') && (tr->langopts.testing & 2) && IsDigit09(next_in) && IsAlpha(pre
words[0].pre_pause = 0; // don't add extra pause at beginning of clause
words[word_count].pre_pause = 8;
if(word_count > 0)
{
words[word_count-1].flags |= FLAG_LAST_WORD;
if((terminator & CLAUSE_DOT) && !(words[word_count-1].flags & FLAG_NOSPACE))
words[word_count-1].flags |= FLAG_HAS_DOT;
}
words[0].flags |= FLAG_FIRST_WORD;
for(ix=0; ix<word_count; ix++)
{
int nx;
@@ -2693,11 +2745,10 @@ if((c == '/') && (tr->langopts.testing & 2) && IsDigit09(next_in) && IsAlpha(pre
}
}
}
word = pw;
pw--;
// include the next few characters, in case there are an ordinal indicator or other suffix
pn[0] = ' ';
memcpy(pn+1, pw, 16);
memcpy(pn, pw, 16);
pn[16] = 0;
for(pw = &number_buf[1]; pw < pn;)
@@ -2732,7 +2783,7 @@ if((c == '/') && (tr->langopts.testing & 2) && IsDigit09(next_in) && IsAlpha(pre
}
}
if((dict_flags & FLAG_DOT) && (ix == word_count-1) && (terminator == CLAUSE_PERIOD))
if((dict_flags & (FLAG_ALLOW_DOT | FLAG_NEEDS_DOT)) && (ix == word_count-1) && (terminator & CLAUSE_DOT))
{
// probably an abbreviation such as Mr. or B. rather than end of sentence
clause_pause = 10;
+26 -7
View File
@@ -48,7 +48,6 @@
#define FLAG_ATEND 0x4000 /* use this pronunciation if at end of clause */
#define FLAG_SPELLWORD 0x8000 // re-translate the word as individual letters, separated by spaces
#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
@@ -57,6 +56,9 @@
#define FLAG_ALT2_TRANS 0x200000 // language specific
#define FLAG_COMBINE 0x400000 // combine with the next word
#define FLAG_ALLOW_DOT 0x01000000 // ignore '.' after word (abbreviation)
#define FLAG_NEEDS_DOT 0x02000000 // only if the word is followed by a dot
#define FLAG_MAX3 0x08000000 // limit to 3 repeats
#define FLAG_PAUSE1 0x10000000 // shorter prepause
#define FLAG_TEXTMODE 0x20000000 // word translates to replacement text, not phonemes
@@ -100,9 +102,10 @@
#define FLAG_SUFFIX_REMOVED 0x2000
#define FLAG_HYPHEN_AFTER 0x4000
#define FLAG_ORDINAL 0x8000 // passed to TranslateNumber() to indicate an ordinal number
#define FLAG_HAS_DOT 0x10000 // dot after this word
#define FLAG_NO_TRACE 0x10000 // passed to TranslateRules() to suppress dictionary lookup printout
#define FLAG_NO_PREFIX 0x20000
#define FLAG_NO_TRACE 0x10000000 // passed to TranslateRules() to suppress dictionary lookup printout
#define FLAG_NO_PREFIX 0x20000000
// 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
@@ -169,12 +172,14 @@
// bit 16 used to distinguish otherwise identical types
// bit 20= punctuation character can be inside a word (Armenian)
// bit 21= speak the name of the punctuation character
// bit 22= dot after the last word
#define CLAUSE_BIT_SENTENCE 0x80000
#define CLAUSE_BIT_CLAUSE 0x40000
#define CLAUSE_BIT_VOICE 0x20000
#define CLAUSE_BITS_INTONATION 0x7000
#define PUNCT_IN_WORD 0x100000
#define PUNCT_SAY_NAME 0x200000
#define CLAUSE_DOT 0x400000
#define CLAUSE_NONE 0 + 0x04000
#define CLAUSE_PARAGRAPH 70 + 0x80000
@@ -215,9 +220,9 @@ typedef struct {
// used to mark words with the source[] buffer
typedef struct{
unsigned int flags;
unsigned short start;
unsigned short sourceix;
unsigned short flags;
unsigned char pre_pause;
unsigned char wmark;
unsigned char length;
@@ -243,7 +248,7 @@ extern const int param_defaults[N_SPEECH_PARAM];
#define N_LOPTS 18
#define N_LOPTS 19
#define LOPT_DIERESES 1
// 1=remove [:] from unstressed syllables, 2= remove from unstressed or non-penultimate syllables
// bit 4=0, if stress < 4, bit 4=1, if not the highest stress in the word
@@ -295,6 +300,7 @@ extern const int param_defaults[N_SPEECH_PARAM];
#define LOPT_IT_DOUBLING 14
// Call ApplySpecialAttributes() if $alt or $alt2 is set for a word
// bit 1: stressed syllable: $alt change [e],[o] to [E],[O], $alt2 change [E],[O] to [e],[o]
#define LOPT_ALT 15
// pause for bracket (default=4), pause when annoucing bracket names (default=2)
@@ -303,6 +309,9 @@ extern const int param_defaults[N_SPEECH_PARAM];
// bit 1, don't break clause before annoucning . ? !
#define LOPT_ANNOUNCE_PUNCT 17
// set minimum length for long vowels at fast speeds, to keep a distinction with short vowels
#define LOPT_MIN_LONG_VOWEL 18
// stress_rule
#define STRESSPOSN_1L 0 // 1st syllable
@@ -321,7 +330,15 @@ typedef struct {
int vowel_pause;
int stress_rule; // 1=first syllable, 2=penultimate, 3=last
#define STRS_HYPEN_UNSTRESS 0x100000
#define S_NO_DIM 0x02
#define S_FINAL_DIM 0x04
#define S_FINAL_NO_2 0x10
#define S_NO_AUTO_2 0x20
#define S_2_TO_HEAVY 0x40
#define S_2_SYL_2 0x1000
#define S_INITIAL_2 0x2000
#define S_NO_AUTO_DIM 0x10000
#define S_HYPEN_UNSTRESS 0x100000
// bit0=don't stress monosyllables, except at end of clause
// bit1=don't set diminished stress,
// bit2=mark unstressed final syllables as diminished
@@ -487,6 +504,7 @@ struct Translator
// the two-letter rules for each letter must be consecutive in the language_rules source
char *groups1[256]; // translation rule lists, index by single letter
char *groups3[128]; // index by offset letter
char *groups2[N_RULE_GROUP2]; // translation rule lists, indexed by two-letter pairs
unsigned int groups2_name[N_RULE_GROUP2]; // the two letter pairs for groups2[]
int n_groups2; // number of groups2[] entries used
@@ -591,13 +609,14 @@ Translator *SelectTranslator(const char *name);
int SetTranslator2(const char *name);
void DeleteTranslator(Translator *tr);
int Lookup(Translator *tr, const char *word, char *ph_out);
int LookupFlags(Translator *tr, const char *word);
int TranslateNumber(Translator *tr, char *word1, char *ph_out, unsigned int *flags, WORD_TAB *wtab);
int TranslateRoman(Translator *tr, char *word, char *ph_out, WORD_TAB *wtab);
void ChangeWordStress(Translator *tr, char *word, int new_stress);
void SetSpellingStress(Translator *tr, char *phonemes, int control, int n_chars);
int TranslateLetter(Translator *tr, char *letter, char *phonemes, int control, int word_length);
int TranslateLetter(Translator *tr, char *letter, char *phonemes, int control);
void LookupLetter(Translator *tr, unsigned int letter, int next_byte, char *ph_buf);
void LookupAccentedLetter(Translator *tr, unsigned int letter, char *ph_buf);
+4 -3
View File
@@ -116,6 +116,7 @@ enum {
static MNEM_TAB options_tab[] = {
{"reduce_t", LOPT_REDUCE_T},
{"bracket", LOPT_BRACKET_PAUSE},
{"fastLongVowel", LOPT_MIN_LONG_VOWEL},
{NULL, -1} };
static MNEM_TAB keyword_tab[] = {
@@ -373,9 +374,9 @@ void VoiceReset(int tone_only)
static int breath_widths[N_PEAKS] = {0,200,200,400,400,400,600,600,600};
// default is: pitch 78,120
voice->pitch_base = 0x45000;
voice->pitch_range = 4536;
// default is: pitch 80,118
voice->pitch_base = 0x47000;
voice->pitch_range = 4104;
// default is: pitch 80,117
// voice->pitch_base = 0x47000;
// voice->pitch_range = 3996;