lang=hr: Recognize Roman numbers only when all-capitals. lang=en: Change to word-final [I] (phoneme [i]). git-svn-id: https://espeak.svn.sourceforge.net/svnroot/espeak/trunk@84 d46cf337-b52f-0410-862d-fd96e6ae7743master
@@ -5092,23 +5092,24 @@ | |||
.group | |||
// non-ascii characters with specified pronunciations | |||
é eI | |||
_) é I2 | |||
ä E | |||
ë E | |||
ï i: | |||
ö 3: | |||
?5 ö VR | |||
ü u: | |||
ç s | |||
ß s | |||
_) ß (_ b'i:t@_ | |||
č tS | |||
š S | |||
ş S | |||
ž Z | |||
þ T | |||
ð D | |||
é eI | |||
_) é I2 | |||
ê E: | |||
ä E | |||
ë E | |||
ï i: | |||
ö 3: | |||
?5 ö VR | |||
ü u: | |||
ç s | |||
ß s | |||
_) ß (_ b'i:t@_ | |||
č tS | |||
š S | |||
ş S | |||
ž Z | |||
þ T | |||
ð D | |||
\\ bakstroUk |
@@ -169,10 +169,10 @@ _1M4 b'ilijUn | |||
?2 _0M4 b'ilijOna | |||
?2 _1M4 b'ilijOn | |||
_dpt _:z'a*Ez_ | |||
_roman @-*'imsko | |||
// not Roman numerals | |||
vi ti | |||
// vi vi // not needed if only all-capitals are spoken as Roman numbers | |||
// Abbreviations |
@@ -2,7 +2,7 @@ | |||
[Setup] | |||
AppName=eSpeak | |||
AppVerName=eSpeak version 1.29.02 | |||
AppVerName=eSpeak version 1.29.03 | |||
DefaultDirName={pf}\eSpeak | |||
DefaultGroupName=eSpeak | |||
@@ -159,7 +159,7 @@ begin | |||
case lang1 of | |||
'af': value := $436; | |||
'bs': value := $141a; | |||
'bs': value := $41a; // should be $141a but Jaws crashes on startup | |||
'cs': value := $405; | |||
'cy': value := $452; | |||
'de': value := $407; |
@@ -298,10 +298,100 @@ STDMETHODIMP CTTSEngObj::SetObjectToken(ISpObjectToken * pToken) | |||
//=== ISpTTSEngine Implementation ============================================ | |||
// | |||
#define L(c1,c2) (c1<<8)+c2 // combine two characters into an integer | |||
static char *phoneme_names_en[] = { | |||
NULL,NULL,NULL," ",NULL,NULL,NULL,NULL,"'",",", | |||
"A:","a","V","0","aU","@","aI", | |||
"b","tS","d","D","E","3:","eI", | |||
"f","g","h","I","i:","dZ","k", | |||
"l","m","n","N","oU","OI","p", | |||
"r","s","S","t","T","U","u:", | |||
"v","w","j","z","Z", | |||
NULL | |||
}; | |||
int CTTSEngObj::WritePhonemes(SPPHONEID *phons, wchar_t *pW) | |||
{//========================================================= | |||
int ph; | |||
int ix=2; | |||
int skip=0; | |||
int maxph = 49; | |||
char *p; | |||
int j; | |||
int lang; | |||
char **phoneme_names; | |||
char phbuf[200]; | |||
espeak_VOICE *voice; | |||
voice = espeak_GetCurrentVoice(); | |||
lang = (voice->languages[1] << 8) + (voice->languages[2]); | |||
phoneme_names = phoneme_names_en; | |||
maxph = 0; | |||
if(lang == L('e','n')) | |||
{ | |||
phoneme_names = phoneme_names_en; | |||
maxph = 49; | |||
} | |||
if(maxph == 0) | |||
return(0); | |||
strcpy(phbuf,"[["); | |||
while(((ph = *phons++) != 0) && (ix < (sizeof(phbuf) - 3))) | |||
{ | |||
if(skip) | |||
{ | |||
skip = 0; | |||
continue; | |||
} | |||
if(ph > maxph) | |||
continue; | |||
p = phoneme_names[phons[0]]; // look at the phoneme after this one | |||
if(p != NULL) | |||
{ | |||
if(p[0] == '\'') | |||
{ | |||
phbuf[ix++] = '\''; // primary stress, put before the vowel, not after | |||
skip=1; | |||
} | |||
if(p[0] == ',') | |||
{ | |||
phbuf[ix++] = ','; // secondary stress | |||
skip=1; | |||
} | |||
} | |||
p = phoneme_names[ph]; // look at this phoneme | |||
if(p != NULL) | |||
{ | |||
strcpy(&phbuf[ix],p); | |||
ix += strlen(p); | |||
} | |||
} | |||
strcpy(&phbuf[ix],"]]"); | |||
ix += 2; | |||
if(pW != NULL) | |||
{ | |||
for(j=0; j<=ix; j++) | |||
{ | |||
pW[j] = phbuf[j]; | |||
} | |||
} | |||
return(strlen(phbuf)); | |||
} | |||
int CTTSEngObj::ProcessFragList(const SPVTEXTFRAG* pTextFragList, wchar_t *pW_start, ISpTTSEngineSite* pOutputSite, int *n_text) | |||
{//============================================================================================================================= | |||
{//============================================================================================================================ | |||
int action; | |||
int control; | |||
@@ -338,6 +428,7 @@ int CTTSEngObj::ProcessFragList(const SPVTEXTFRAG* pTextFragList, wchar_t *pW_st | |||
CheckActions(pOutputSite); | |||
sayas = 0; | |||
state = &pTextFragList->State; | |||
switch(action) | |||
{ | |||
@@ -366,7 +457,6 @@ int CTTSEngObj::ProcessFragList(const SPVTEXTFRAG* pTextFragList, wchar_t *pW_st | |||
} | |||
// first set the volume, rate, pitch | |||
state = &pTextFragList->State; | |||
volume = (state->Volume * master_volume)/100; | |||
speed = ConvertRate(state->RateAdj); | |||
pitch = ConvertPitch(state->PitchAdj.MiddleAdj); | |||
@@ -467,6 +557,14 @@ int CTTSEngObj::ProcessFragList(const SPVTEXTFRAG* pTextFragList, wchar_t *pW_st | |||
} | |||
} | |||
break; | |||
case SPVA_Pronounce: | |||
total += WritePhonemes(state->pPhoneIds, pW); | |||
if(pW != NULL) | |||
{ | |||
pW += total; | |||
} | |||
break; | |||
} | |||
@@ -478,6 +576,7 @@ int CTTSEngObj::ProcessFragList(const SPVTEXTFRAG* pTextFragList, wchar_t *pW_st | |||
*pW = 0; | |||
} | |||
*n_text = frag_count; | |||
return(total); | |||
} // end of ProcessFragList | |||
@@ -600,7 +699,7 @@ STDMETHODIMP CTTSEngObj::Speak( DWORD dwSpeakFlags, | |||
if(size > 0) | |||
{ | |||
espeak_Synth(TextBuf,0,0,POS_CHARACTER,0,espeakCHARS_WCHAR | espeakKEEP_NAMEDATA,NULL,NULL); | |||
espeak_Synth(TextBuf,0,0,POS_CHARACTER,0,espeakCHARS_WCHAR | espeakKEEP_NAMEDATA | espeakPHONEMES,NULL,NULL); | |||
} | |||
} | |||
return hr; |
@@ -384,12 +384,19 @@ int compile_line(char *linebuf, char *dict_line, int *hash) | |||
} | |||
length += n_flag_codes; | |||
if((multiple_string != NULL) && (multiple_words > 0) && (multiple_words <= 4)) | |||
if((multiple_string != NULL) && (multiple_words > 0)) | |||
{ | |||
dict_line[length++] = 40 + multiple_words; | |||
ix = multiple_string_end - multiple_string; | |||
memcpy(&dict_line[length],multiple_string,ix); | |||
length += ix; | |||
if(multiple_words > 10) | |||
{ | |||
fprintf(f_log,"%5d: Two many parts in a multi-word entry: %d\n",linenum,multiple_words); | |||
} | |||
else | |||
{ | |||
dict_line[length++] = 40 + multiple_words; | |||
ix = multiple_string_end - multiple_string; | |||
memcpy(&dict_line[length],multiple_string,ix); | |||
length += ix; | |||
} | |||
} | |||
dict_line[0] = length; | |||
@@ -36,7 +36,7 @@ | |||
#include "translate.h" | |||
int dictionary_skipwords; | |||
char dictionary_name[40]; | |||
extern MNEM_TAB mnem_flags[]; | |||
@@ -2716,12 +2716,13 @@ int Translator::LookupDict2(char *word, char *word2, char *phonetic, unsigned in | |||
else | |||
if(flag > 40) | |||
{ | |||
// flags 41,42,or 43 match more than one word | |||
// flags 41 to 50 match more than one word | |||
// This comes after the other flags | |||
n_chars = next - p; | |||
if(memcmp(word2,p,n_chars)==0) | |||
{ | |||
dictionary_flags |= ((flag-40) << 5); // set (bits 5-7) to 1,2,or 3 | |||
dictionary_flags |= FLAG_SKIPWORDS; | |||
dictionary_skipwords = (flag - 40); | |||
p = next; | |||
word_end = word2 + n_chars; | |||
} |
@@ -214,9 +214,6 @@ int Translator::TranslateRoman(char *word, char *ph_out) | |||
static char *roman_numbers = "ixcmvld"; | |||
static int roman_values[] = {1,10,100,1000,5,50,500}; | |||
if((langopts.numbers & NUM_ROMAN) == 0) | |||
return(0); | |||
acc = 0; | |||
prev = 0; | |||
subtract = 0x7fff; |
@@ -35,7 +35,7 @@ | |||
#include "translate.h" | |||
#include "wave.h" | |||
const char *version_string = "1.29.02 10.Sep.07"; | |||
const char *version_string = "1.29.04 11.Sep.07"; | |||
const int version_phdata = 0x012901; | |||
int option_device_number = -1; | |||
@@ -204,7 +204,7 @@ static unsigned int LookupSound2(int index, unsigned int other_phcode, int contr | |||
{//================================================================================ | |||
// control=1 get formant transition data only | |||
int code; | |||
unsigned int code; | |||
unsigned int value, value2; | |||
while((value = phoneme_index[index++]) != 0) | |||
@@ -223,12 +223,17 @@ static unsigned int LookupSound2(int index, unsigned int other_phcode, int contr | |||
} | |||
break; | |||
case 1: | |||
if(control==0) | |||
seq_len_adjust = value2 >> 8; | |||
if(control==0) | |||
{ | |||
seq_len_adjust = value2 >> 8; | |||
} | |||
break; | |||
case 2: | |||
if(control==0) | |||
seq_len_adjust = -(value2 >> 8); | |||
if(control==0) | |||
{ | |||
seq_len_adjust = value2 >> 8; | |||
seq_len_adjust = -seq_len_adjust; | |||
} | |||
break; | |||
case 3: | |||
if(control==0) |
@@ -304,7 +304,7 @@ Translator *SelectTranslator(const char *name) | |||
tr->langopts.max_initial_consonants = 5; | |||
tr->langopts.spelling_stress = 1; | |||
tr->langopts.numbers = 0x1c0d + 0x4000 + NUM_ROMAN; | |||
tr->langopts.numbers = 0x1c0d + 0x4000 + NUM_ROMAN_UC; | |||
tr->langopts.numbers2 = 0x4a; // variant numbers before thousands,milliards | |||
tr->langopts.replace_chars = replace_cyrillic; | |||
tr->langopts.replacement_chars = replace_cyrillic_latin; |
@@ -671,8 +671,12 @@ if((wmark > 0) && (wmark < 8)) | |||
if(!found & ((word_flags & FLAG_UPPERS) != FLAG_FIRST_UPPER)) | |||
{ | |||
// either all upper or all lower case | |||
if((found = TranslateRoman(word,phonemes)) != 0) | |||
dictionary_flags |= FLAG_ABBREV; // don't spell capital Roman numbers as individual letters | |||
if((langopts.numbers & NUM_ROMAN) || ((langopts.numbers & NUM_ROMAN_UC) && (word_flags & FLAG_ALL_UPPER))) | |||
{ | |||
if((found = TranslateRoman(word,phonemes)) != 0) | |||
dictionary_flags |= FLAG_ABBREV; // don't spell capital Roman numbers as individual letters | |||
} | |||
} | |||
if((wflags & FLAG_ALL_UPPER) && (clause_upper_count <= clause_lower_count) && | |||
@@ -1233,7 +1237,8 @@ int Translator::TranslateWord2(char *word, WORD_TAB *wtab, int pre_pause, int ne | |||
} | |||
else | |||
{ | |||
flags |= FLAG_SKIPWORDS_1; | |||
flags |= FLAG_SKIPWORDS; | |||
dictionary_skipwords = 1; | |||
} | |||
} | |||
} | |||
@@ -1562,7 +1567,7 @@ int Translator::TranslateChar(char *ptr, int prev_in, unsigned int c, unsigned i | |||
int ix; | |||
unsigned int word; | |||
unsigned int new_c, c2; | |||
unsigned int new_c, c2, c_lower; | |||
int upper_case = 0; | |||
static int ignore_next = 0; | |||
@@ -1578,16 +1583,16 @@ int Translator::TranslateChar(char *ptr, int prev_in, unsigned int c, unsigned i | |||
// there is a list of character codes to be substituted with alternative codes | |||
if(iswupper(c)) | |||
if(iswupper(c_lower = c)) | |||
{ | |||
c = towlower(c); | |||
c_lower = towlower(c); | |||
upper_case = 1; | |||
} | |||
new_c = 0; | |||
for(ix=0; (word = langopts.replace_chars[ix]) != 0; ix++) | |||
{ | |||
if(c == (word & 0xffff)) | |||
if(c_lower == (word & 0xffff)) | |||
{ | |||
if((word >> 16) == 0) | |||
{ | |||
@@ -2217,7 +2222,8 @@ if((c == '/') && (langopts.testing & 2) && isdigit(next_in) && IsAlpha(prev_out) | |||
else | |||
{ | |||
dict_flags = TranslateWord2(word, &words[ix], words[ix].pre_pause, words[ix+1].pre_pause); | |||
ix += ((dict_flags >> 5) & 7); // dictionary indicates skip next word(s) | |||
if(dict_flags & FLAG_SKIPWORDS) | |||
ix += dictionary_skipwords; // dictionary indicates skip next word(s) | |||
if((dict_flags & FLAG_DOT) && (ix == word_count-1) && (terminator == CLAUSE_PERIOD)) | |||
{ |
@@ -34,8 +34,7 @@ | |||
/* flags from word dictionary */ | |||
// bits 0-3 stressed syllable, 7=unstressed | |||
#define FLAG_SKIPWORDS 0xe0 /* bits 5,6,7 number of words to skip */ | |||
#define FLAG_SKIPWORDS_1 0x20 | |||
#define FLAG_SKIPWORDS 0x80 | |||
#define FLAG_PREPAUSE 0x100 | |||
#define FLAG_ONLY 0x200 | |||
#define BITNUM_FLAG_ONLY 9 // bit 9 is set | |||
@@ -277,7 +276,8 @@ typedef struct { | |||
unsigned char *length_mods; | |||
unsigned char *length_mods0; | |||
#define NUM_ROMAN 0x20000 | |||
#define NUM_ROMAN 0x20000 | |||
#define NUM_ROMAN_UC 0x40000 | |||
// bits0-1=which numbers routine to use. | |||
// bit2= thousands separator must be space | |||
// bit3= , decimal separator, not . | |||
@@ -293,6 +293,7 @@ typedef struct { | |||
// bits13-15 post-decimal-digits 0=single digits, 1=(LANG=it) 2=(LANG=pl) 3=(LANG=ro) | |||
// bit16=dot after number indicates ordinal | |||
// bit17=recognize roman numbers | |||
// bit18=Roman numbers only if upper case | |||
int numbers; | |||
@@ -501,6 +502,8 @@ extern char ctrl_embedded; // to allow an alternative CTRL for embedded comma | |||
extern char *p_textinput; | |||
extern wchar_t *p_wchar_input; | |||
extern int ungot_char; | |||
extern int dictionary_skipwords; | |||
extern int (* uri_callback)(int, const char *, const char *); | |||
extern int (* phoneme_callback)(const char *); | |||
extern void SetLengthMods(Translator *tr, int value); |