[1.31.20]

Speak accented letter names as base-letter name plus accent name, using a table of Unicode characters up to U+17F.
Added $accent attribute for *_list files, meaning "speak as base-letter name plus accent name".
Added accent names to several languages *_list files.
Added language option to allow vowels to merge between words (used for lang=TA).


git-svn-id: https://espeak.svn.sourceforge.net/svnroot/espeak/trunk@153 d46cf337-b52f-0410-862d-fd96e6ae7743
This commit is contained in:
jonsd
2008-03-01 10:29:46 +00:00
parent 417395b033
commit 58fbde3153
25 changed files with 659 additions and 98 deletions
+1
View File
@@ -103,6 +103,7 @@ MNEM_TAB mnem_flags[] = {
{"$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 */
{"$accent", 0x2b}, // character name is base-character name + accent name
// doesn't set dictionary_flags
{"$?", 100}, // conditional rule, followed by byte giving the condition number
+14 -3
View File
@@ -2390,15 +2390,15 @@ int Translator::TranslateRules(char *p_start, char *phonemes, int ph_size, char
// no group for this letter, use default group
MatchRule(&p, "", groups1[0], &match1, word_flags, dict_flags);
if(match1.points == 0)
if((match1.points == 0) && ((option_sayas & 0x10) == 0))
{
// no match, try removing the accent and re-translating the word
n = utf8_in(&letter,p-1,0)-1;
if((letter >= 0xc0) && (letter <= 0x241))
if((letter >= 0xc0) && (letter <= 0x241) && ((ix = remove_accent[letter-0xc0]) != 0))
{
// within range of the remove_accent table
p2 = p-1;
p[-1] = remove_accent[letter-0xc0];
p[-1] = ix;
while((p[0] = p[n]) != ' ') p++;
while(n-- > 0) *p++ = ' '; // replacement character must be no longer than original
@@ -3020,6 +3020,16 @@ int Translator::LookupDictList(char **wordptr, char *ph_out, unsigned int *flags
found = LookupDict2(word, word1, ph_out, flags, end_flags, wtab);
if((found == 0) && (flags[1] & FLAG_ACCENT))
{
int letter;
word2 = word;
if(*word2 == '_') word2++;
len = utf8_in(&letter, word2, 0);
LookupAccentedLetter(letter, ph_out);
found = word2 + len;
}
if(found == 0)
{
ph_out[0] = 0;
@@ -3086,6 +3096,7 @@ int Translator::LookupDictList(char **wordptr, char *ph_out, unsigned int *flags
int Translator::Lookup(const char *word, char *ph_out)
{//===================================================
unsigned int flags[2];
flags[0] = flags[1] = 0;
char *word1 = (char *)word;
return(LookupDictList(&word1, ph_out, flags, 0, NULL));
}
+298 -1
View File
@@ -36,6 +36,290 @@
#define M_NAME 0
#define M_ACUTE 1
#define M_BREVE 2
#define M_CARON 3
#define M_CEDILLA 4
#define M_CIRCUMFLEX 5
#define M_DIAERESIS 6
#define M_DOUBLE_ACUTE 7
#define M_DOT_ABOVE 8
#define M_GRAVE 9
#define M_MACRON 10
#define M_OGONEK 11
#define M_RING 12
#define M_STROKE 13
#define M_TILDE 14
#define M_MIDDLE_DOT 8 // duplicate of M_DOT_ABOVE
typedef struct {
char *name;
int flags;
} ACCENTS;
// these are tokens to look up in the *_list file.
ACCENTS accents_tab[] = {
{"_lig", 1},
{"_acu", 0}, // acute
{"_brv", 0}, // breve
{"_hac", 0}, // caron/hacek
{"_ced", 0}, // cedilla
{"_cir", 0}, // circumflex
{"_dia", 0}, // diaeresis
{"_ac2", 0}, // double acute
{"_dot", 0}, // dot
{"_grv", 0}, // grave
{"_mcn", 0}, // macron
{"_ogo", 0}, // ogonek
{"_rng", 0}, // ring
{"_stk", 0}, // stroke
{"_tld", 0}, // tilde
};
#define CAPITAL 0
#define LETTER(ch,mod1,mod2) ch+(mod1 << 8)
#define LIGATURE(ch1,ch2,mod1) ch1+(ch2 << 8)+0x8000
// characters U+00e0 to U+017f
const short letter_accents_0e0[] = {
LETTER('a',M_GRAVE,0), // U+00e0
LETTER('a',M_ACUTE,0),
LETTER('a',M_CIRCUMFLEX,0),
LETTER('a',M_TILDE,0),
LETTER('a',M_DIAERESIS,0),
LETTER('a',M_RING,0),
LIGATURE('a','e',0),
LETTER('c',M_CEDILLA,0),
LETTER('e',M_GRAVE,0),
LETTER('e',M_ACUTE,0),
LETTER('e',M_CIRCUMFLEX,0),
LETTER('e',M_DIAERESIS,0),
LETTER('i',M_GRAVE,0),
LETTER('i',M_ACUTE,0),
LETTER('i',M_CIRCUMFLEX,0),
LETTER('i',M_DIAERESIS,0),
LETTER('d',M_NAME,0), // eth // U+00f0
LETTER('n',M_TILDE,0),
LETTER('o',M_GRAVE,0),
LETTER('o',M_ACUTE,0),
LETTER('o',M_CIRCUMFLEX,0),
LETTER('o',M_TILDE,0),
LETTER('o',M_DIAERESIS,0),
0, // division sign
LETTER('o',M_STROKE,0),
LETTER('u',M_GRAVE,0),
LETTER('u',M_ACUTE,0),
LETTER('u',M_CIRCUMFLEX,0),
LETTER('u',M_DIAERESIS,0),
LETTER('y',M_ACUTE,0),
LETTER('t',M_NAME,0), // thorn
LETTER('y',M_DIAERESIS,0),
CAPITAL, // U+0100
LETTER('a',M_MACRON,0),
CAPITAL,
LETTER('a',M_BREVE,0),
CAPITAL,
LETTER('a',M_OGONEK,0),
CAPITAL,
LETTER('c',M_ACUTE,0),
CAPITAL,
LETTER('c',M_CIRCUMFLEX,0),
CAPITAL,
LETTER('c',M_DOT_ABOVE,0),
CAPITAL,
LETTER('c',M_CARON,0),
CAPITAL,
LETTER('d',M_CARON,0),
CAPITAL, // U+0110
LETTER('d',M_STROKE,0),
CAPITAL,
LETTER('e',M_MACRON,0),
CAPITAL,
LETTER('e',M_BREVE,0),
CAPITAL,
LETTER('e',M_DOT_ABOVE,0),
CAPITAL,
LETTER('e',M_OGONEK,0),
CAPITAL,
LETTER('e',M_CARON,0),
CAPITAL,
LETTER('g',M_CIRCUMFLEX,0),
CAPITAL,
LETTER('g',M_BREVE,0),
CAPITAL, // U+0120
LETTER('g',M_DOT_ABOVE,0),
CAPITAL,
LETTER('g',M_CEDILLA,0),
CAPITAL,
LETTER('h',M_CIRCUMFLEX,0),
CAPITAL,
LETTER('h',M_STROKE,0),
CAPITAL,
LETTER('i',M_TILDE,0),
CAPITAL,
LETTER('i',M_MACRON,0),
CAPITAL,
LETTER('i',M_BREVE,0),
CAPITAL,
LETTER('i',M_OGONEK,0),
CAPITAL, // U+0130
LETTER('i',M_NAME,0), // dotless i
CAPITAL,
LIGATURE('i','j',0),
CAPITAL,
LETTER('j',M_CIRCUMFLEX,0),
CAPITAL,
LETTER('k',M_CEDILLA,0),
LETTER('k',M_NAME,0), // kra
CAPITAL,
LETTER('l',M_ACUTE,0),
CAPITAL,
LETTER('l',M_CEDILLA,0),
CAPITAL,
LETTER('1',M_CARON,0),
CAPITAL,
LETTER('1',M_MIDDLE_DOT,0), // U+0140
CAPITAL,
LETTER('1',M_STROKE,0),
CAPITAL,
LETTER('n',M_ACUTE,0),
CAPITAL,
LETTER('n',M_CEDILLA,0),
CAPITAL,
LETTER('n',M_CARON,0),
LETTER('n',M_NAME,0), // apostrophe n
CAPITAL,
LETTER('n',M_NAME,0), // eng
CAPITAL,
LETTER('o',M_MACRON,0),
CAPITAL,
LETTER('o',M_BREVE,0),
CAPITAL, // U+0150
LETTER('o',M_DOUBLE_ACUTE,0),
CAPITAL,
LIGATURE('o','e',0),
CAPITAL,
LETTER('r',M_ACUTE,0),
CAPITAL,
LETTER('r',M_CEDILLA,0),
CAPITAL,
LETTER('r',M_CARON,0),
CAPITAL,
LETTER('s',M_ACUTE,0),
CAPITAL,
LETTER('s',M_CIRCUMFLEX,0),
CAPITAL,
LETTER('s',M_CEDILLA,0),
CAPITAL, // U+0160
LETTER('s',M_CARON,0),
CAPITAL,
LETTER('t',M_CEDILLA,0),
CAPITAL,
LETTER('t',M_CARON,0),
CAPITAL,
LETTER('t',M_STROKE,0),
CAPITAL,
LETTER('u',M_TILDE,0),
CAPITAL,
LETTER('u',M_MACRON,0),
CAPITAL,
LETTER('u',M_BREVE,0),
CAPITAL,
LETTER('u',M_RING,0),
CAPITAL, // U+0170
LETTER('u',M_DOUBLE_ACUTE,0),
CAPITAL,
LETTER('u',M_OGONEK,0),
CAPITAL,
LETTER('w',M_CIRCUMFLEX,0),
CAPITAL,
LETTER('y',M_CIRCUMFLEX,0),
CAPITAL, // Y-DIAERESIS
CAPITAL,
LETTER('z',M_ACUTE,0),
CAPITAL,
LETTER('z',M_DOT_ABOVE,0),
CAPITAL,
LETTER('z',M_CARON,0),
LETTER('s',M_NAME,0), // long-s // U+17f
};
int Translator::LookupLetter2(unsigned int letter, char *ph_buf)
{//=============================================================
int len;
char single_letter[10];
single_letter[0] = 0;
single_letter[1] = '_';
len = utf8_out(letter, &single_letter[2]);
single_letter[2+len] = 0;
if(Lookup(&single_letter[1],ph_buf) == 0)
{
single_letter[1] = ' ';
if(Lookup(&single_letter[2],ph_buf) == 0)
{
TranslateRules(&single_letter[2], ph_buf, 20, NULL,0,0);
}
}
return(ph_buf[0]);
}
void Translator::LookupAccentedLetter(unsigned int letter, char *ph_buf)
{//=====================================================================
// lookup the character in the accents table
int accent_data;
int accent1;
int basic_letter;
int letter2=0;
char ph_letter1[30];
char ph_letter2[30];
char ph_accent1[30];
if((letter >= 0xe0) && (letter < 0x17f))
{
accent_data = letter_accents_0e0[letter - 0xe0];
basic_letter = accent_data & 0x7f;
if((accent1 = (accent_data >> 8) & 0x7f) != 0)
{
if(accent_data & 0x8000)
{
letter2 = accent1;
accent1 = 0;
}
if(Lookup(accents_tab[accent1].name, ph_accent1) != 0)
{
if(LookupLetter2(basic_letter, ph_letter1) != 0)
{
if(accent1 == 0)
{
//ligature
LookupLetter2(letter2, ph_letter2);
sprintf(ph_buf,"%s%c%s%s",ph_accent1, phonPAUSE_VSHORT, ph_letter1, ph_letter2);
}
else
{
if(langopts.accents & 1)
sprintf(ph_buf,"%s%c%s", ph_accent1, phonPAUSE_VSHORT, ph_letter1);
else
sprintf(ph_buf,"%s%c%s%c", ph_letter1, phonPAUSE_VSHORT, ph_accent1, phonPAUSE_VSHORT);
}
}
}
}
}
} // end of LookupAccentedLetter
void Translator::LookupLetter(unsigned int letter, int next_byte, char *ph_buf1)
{//=============================================================================
@@ -43,7 +327,9 @@ void Translator::LookupLetter(unsigned int letter, int next_byte, char *ph_buf1)
unsigned char *p;
static char single_letter[10] = {0,0};
char ph_stress[2];
char ph_buf3[30];
unsigned int dict_flags[2];
char ph_buf3[40];
char *ptr;
ph_buf1[0] = 0;
len = utf8_out(letter,&single_letter[2]);
@@ -83,6 +369,11 @@ void Translator::LookupLetter(unsigned int letter, int next_byte, char *ph_buf1)
single_letter[3+len] = next_byte; // follow by space-space if the end of the word, or space-0x31
single_letter[1] = '_';
// if the $accent flag is set for this letter, use the accents table (below)
dict_flags[1] = 0;
ptr = &single_letter[1];
if(Lookup(&single_letter[1],ph_buf3) == 0)
{
single_letter[1] = ' ';
@@ -92,6 +383,11 @@ void Translator::LookupLetter(unsigned int letter, int next_byte, char *ph_buf1)
}
}
if(ph_buf3[0] == 0)
{
LookupAccentedLetter(letter, ph_buf3);
}
if(ph_buf3[0] == 0)
{
ph_buf1[0] = 0;
@@ -185,6 +481,7 @@ int Translator::TranslateLetter(char *word, char *phonemes, int control, int wor
for(p2 = hexbuf; *p2 != 0; p2++)
{
pbuf += strlen(pbuf);
*pbuf++ = phonPAUSE_VSHORT;
LookupLetter(*p2, 0, pbuf);
}
}
+1
View File
@@ -517,6 +517,7 @@ const char *Translator::LookupSpecial(const char *string, char* text_out)
const char *Translator::LookupCharName(int c)
{//==========================================
// Find the phoneme string (in ascii) to speak the name of character c
// Used for punctuation characters and symbols
int ix;
unsigned int flags[2];
+1 -1
View File
@@ -35,7 +35,7 @@
#include "translate.h"
#include "wave.h"
const char *version_string = "1.31.19 28.Feb.08";
const char *version_string = "1.31.20 01.Mar.08";
const int version_phdata = 0x013105;
int option_device_number = -1;
+3 -1
View File
@@ -1146,7 +1146,9 @@ int Generate(PHONEME_LIST *phoneme_list, int *n_ph, int resume)
if(p->newword)
{
last_frame = NULL;
if(translator->langopts.param[LOPT_WORD_MERGE] == 0)
last_frame = NULL;
sourceix = (p->sourceix & 0x7ff) + clause_start_char;
if(p->newword & 4)
+2
View File
@@ -663,6 +663,7 @@ SetLengthMods(tr,3); // all equal
tr->langopts.stress_rule = 1;
tr->langopts.stress_flags = 0x10004; // use 'diminished' for unstressed final syllable
tr->letter_bits_offset = OFFSET_TAMIL;
tr->langopts.param[LOPT_WORD_MERGE] = 1; // don't break vowels betwen words
memset(tr->letter_bits,0,sizeof(tr->letter_bits));
SetLetterBitsRange(tr,LETTERGP_A,0x05,0x14); // vowel letters
@@ -1055,6 +1056,7 @@ Translator_Afrikaans::Translator_Afrikaans() : Translator()
SetLetterVowel(this,'y'); // add 'y' to vowels
langopts.numbers = 0x8d1 + NUM_ROMAN;
langopts.accents = 1;
memcpy(stress_lengths,stress_lengths2,sizeof(stress_lengths));
}
+15 -4
View File
@@ -74,6 +74,7 @@
#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
#define FLAG_ACCENT 0x800 // character name is base-character name + accent name
@@ -230,7 +231,7 @@ extern const int param_defaults[N_SPEECH_PARAM];
#define N_LOPTS 14
#define N_LOPTS 15
#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
@@ -254,9 +255,8 @@ extern const int param_defaults[N_SPEECH_PARAM];
// increase this to prevent sonorants being shortened before shortened (eg. unstressed) vowels
#define LOPT_SONORANT_MIN 7
// bit 0=Italian "syntactic doubling" of consoants in the word after a word marked with $double attribute
// bit 1=also after a word which ends with a stressed vowel
#define LOPT_IT_DOUBLING 8
// don't break vowels at word boundary
#define LOPT_WORD_MERGE 8
// max. amplitude for vowel at the end of a clause
#define LOPT_MAXAMP_EOC 9
@@ -277,6 +277,11 @@ extern const int param_defaults[N_SPEECH_PARAM];
// stressed syllable is indicated by capitals
#define LOPT_SYLLABLE_CAPS 13
// bit 0=Italian "syntactic doubling" of consoants in the word after a word marked with $double attribute
// bit 1=also after a word which ends with a stressed vowel
#define LOPT_IT_DOUBLING 14
typedef struct {
// bits0-2 separate words with (1=pause_vshort, 2=pause_short, 3=pause, 4=pause_long 5=[?] phonemme)
@@ -341,6 +346,10 @@ typedef struct {
int max_roman;
int thousands_sep;
int decimal_sep;
// bit 0, accent name before the letter name
int accents;
int tone_language; // 1=tone language
int intonation_group;
int long_stop; // extra mS pause for a lengthened stop
@@ -430,6 +439,8 @@ private:
const char *LookupSpecial(const char *string, char *text_out);
const char *LookupCharName(int c);
void LookupLetter(unsigned int letter, int next_byte, char *ph_buf);
int LookupLetter2(unsigned int letter, char *ph_buf);
void LookupAccentedLetter(unsigned int letter, char *ph_buf);
int LookupNum2(int value, int control, char *ph_out);
int LookupNum3(int value, char *ph_out, int suppress_null, int thousandplex, int prev_thousands);
int LookupThousands(int value, int thousandplex, char *ph_out);