Merge branch 'development'

This commit is contained in:
Reece H. Dunn
2013-04-01 00:43:29 +01:00
39 changed files with 785 additions and 663 deletions
+1
View File
@@ -3059,6 +3059,7 @@ int CompilePhoneme(int compile_phoneme)
case kRETURN:
*prog_out++ = i_RETURN;
DecThenCount();
break;
case kINCLUDE:
+29 -2
View File
@@ -699,11 +699,38 @@ int TranslateLetter(Translator *tr, char *word, char *phonemes, int control)
else
language = L('e','n');
if(language != tr->translator_name)
if((language != tr->translator_name) || (language == L('k','o')))
{
char *p3;
int initial, code;
char hangul_buf[12];
// speak in the language for this alphabet (or English)
ph_buf[2] = SetTranslator2(WordToString2(language));
LookupLetter(translator2, letter, word[n_bytes], &ph_buf[3], control & 1);
if(((code = letter - 0xac00) >= 0) && (letter <= 0xd7af))
{
// Special case for Korean letters.
// break a syllable hangul into 2 or 3 individual jamo
hangul_buf[0] = ' ';
p3 = &hangul_buf[1];
if((initial = (code/28)/21) != 11)
{
p3 += utf8_out(initial + 0x1100, p3);
}
utf8_out(((code/28) % 21) + 0x1161, p3); // medial
utf8_out((code % 28) + 0x11a7, &p3[3]); // final
p3[6] = ' ';
p3[7] = 0;
ph_buf[3] = 0;
TranslateRules(translator2, &hangul_buf[1], &ph_buf[3], sizeof(ph_buf)-3, NULL, 0, NULL);
SetWordStress(translator2, &ph_buf[3], NULL, -1, 0);
}
else
{
LookupLetter(translator2, letter, word[n_bytes], &ph_buf[3], control & 1);
}
if(ph_buf[3] == phonSWITCH)
{
+59 -50
View File
@@ -125,6 +125,7 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
int delete_count;
int word_start;
int inserted;
int deleted;
PHONEME_DATA phdata;
int n_ph_list3;
@@ -343,6 +344,7 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
plist3 = &ph_list3[j];
inserted = 0;
deleted = 0;
if(insert_ph != 0)
{
// we have a (linking) phoneme which we need to insert here
@@ -431,23 +433,27 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
plist3->phcode = alternative;
if(alternative == 1)
continue; // NULL phoneme, discard
if(ph->type == phVOWEL)
{
plist3->synthflags |= SFLAG_SYLLABLE;
if(ph2->type != phVOWEL)
plist3->stresslevel = 0; // change from non-vowel to vowel, make sure it's unstressed
deleted = 1; // NULL phoneme, discard
}
else
plist3->synthflags &= ~SFLAG_SYLLABLE;
{
if(ph->type == phVOWEL)
{
plist3->synthflags |= SFLAG_SYLLABLE;
if(ph2->type != phVOWEL)
plist3->stresslevel = 0; // change from non-vowel to vowel, make sure it's unstressed
}
else
plist3->synthflags &= ~SFLAG_SYLLABLE;
// re-interpret the changed phoneme
// But it doesn't obey a second ChangePhoneme()
InterpretPhoneme(tr, 0x100, plist3, &phdata, &worddata);
// re-interpret the changed phoneme
// But it doesn't obey a second ChangePhoneme()
InterpretPhoneme(tr, 0x100, plist3, &phdata, &worddata);
}
}
if(ph->type == phVOWEL)
if((ph->type == phVOWEL) && (deleted == 0))
{
PHONEME_LIST *p;
@@ -552,7 +558,7 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
}
}
if(plist3 != plist3_inserted)
if((plist3 != plist3_inserted) && (ix > 0))
{
if((x = (tr->langopts.word_gap & 0x7)) != 0)
{
@@ -585,51 +591,54 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
// not yet implemented
}
phlist[ix].ph = ph;
phlist[ix].type = ph->type;
phlist[ix].env = PITCHfall; // default, can be changed in the "intonation" module
phlist[ix].synthflags = plist3->synthflags;
phlist[ix].stresslevel = plist3->stresslevel & 0xf;
phlist[ix].wordstress = plist3->wordstress;
phlist[ix].tone_ph = plist3->tone_ph;
phlist[ix].sourceix = 0;
phlist[ix].phcode = ph->code;
if(plist3->sourceix != 0)
if(deleted == 0)
{
phlist[ix].sourceix = plist3->sourceix;
phlist[ix].newword = 1; // this phoneme is the start of a word
phlist[ix].ph = ph;
phlist[ix].type = ph->type;
phlist[ix].env = PITCHfall; // default, can be changed in the "intonation" module
phlist[ix].synthflags = plist3->synthflags;
phlist[ix].stresslevel = plist3->stresslevel & 0xf;
phlist[ix].wordstress = plist3->wordstress;
phlist[ix].tone_ph = plist3->tone_ph;
phlist[ix].sourceix = 0;
phlist[ix].phcode = ph->code;
if(start_sentence)
if(plist3->sourceix != 0)
{
phlist[ix].newword = 5; // start of sentence + start of word
start_sentence = 0;
phlist[ix].sourceix = plist3->sourceix;
phlist[ix].newword = 1; // this phoneme is the start of a word
if(start_sentence)
{
phlist[ix].newword = 5; // start of sentence + start of word
start_sentence = 0;
}
}
else
{
phlist[ix].newword = 0;
}
}
else
{
phlist[ix].newword = 0;
}
// phlist[ix].length = ph->std_length;
phlist[ix].length = phdata.pd_param[i_SET_LENGTH]*2;
if((ph->code == phonPAUSE_LONG) && (option_wordgap > 0))
{
phlist[ix].ph = phoneme_tab[phonPAUSE_SHORT];
phlist[ix].length = option_wordgap*14; // 10mS per unit at the default speed
}
// phlist[ix].length = ph->std_length;
phlist[ix].length = phdata.pd_param[i_SET_LENGTH]*2;
if((ph->code == phonPAUSE_LONG) && (option_wordgap > 0) && (plist3[1].sourceix != 0))
{
phlist[ix].ph = phoneme_tab[phonPAUSE_SHORT];
phlist[ix].length = option_wordgap*14; // 10mS per unit at the default speed
}
if(ph->type==phVOWEL || ph->type==phLIQUID || ph->type==phNASAL || ph->type==phVSTOP || ph->type==phVFRICATIVE || (ph->phflags & phPREVOICE))
{
phlist[ix].length = 128; // length_mod
phlist[ix].env = PITCHfall;
}
if(ph->type==phVOWEL || ph->type==phLIQUID || ph->type==phNASAL || ph->type==phVSTOP || ph->type==phVFRICATIVE || (ph->phflags & phPREVOICE))
{
phlist[ix].length = 128; // length_mod
phlist[ix].env = PITCHfall;
}
phlist[ix].prepause = 0;
phlist[ix].amp = 20; // default, will be changed later
phlist[ix].pitch1 = 255;
phlist[ix].pitch2 = 255;
ix++;
phlist[ix].prepause = 0;
phlist[ix].amp = 20; // default, will be changed later
phlist[ix].pitch1 = 255;
phlist[ix].pitch2 = 255;
ix++;
}
}
phlist[ix].newword = 2; // end of clause
+2
View File
@@ -85,6 +85,7 @@ static const unsigned short punct_chars[] = {',','.','?','!',':',';',
0x055e, // Armenian question
0x055b, // Armenian emphasis mark
0x060c, // Arabic ,
0x061b, // Arabic ;
0x061f, // Arabic ?
0x06d4, // Arabic .
@@ -132,6 +133,7 @@ static const unsigned int punct_attributes [] = { 0,
CLAUSE_QUESTION | PUNCT_IN_WORD, // Armenian question
CLAUSE_PERIOD | PUNCT_IN_WORD, // Armenian emphasis mark
CLAUSE_COMMA, // Arabic ,
CLAUSE_SEMICOLON, // Arabic ;
CLAUSE_QUESTION, // Arabic question mark
CLAUSE_PERIOD, // Arabic full stop
+24 -4
View File
@@ -575,6 +575,7 @@ void CalcLengths(Translator *tr)
int last_pitch = 0;
int pitch_start;
int length_mod;
int next2type;
int len;
int env2;
int end_of_clause;
@@ -689,8 +690,19 @@ void CalcLengths(Translator *tr)
p->prepause = 40;
if((prev->type == phPAUSE) || (prev->type == phVOWEL)) // || (prev->ph->mnemonic == ('/'*256+'r')))
p->prepause = 0;
if(prev->type == phVOWEL)
{
p->prepause = 0; // use murmur instead to link from the preceding vowel
}
else
if(prev->type == phPAUSE)
{
// reduce by the length of the preceding pause
if(prev->length < p->prepause)
p->prepause -= prev->length;
else
p->prepause = 0;
}
else
if(p->newword==0)
{
@@ -827,9 +839,17 @@ if(stress <= 1)
next3 = &phoneme_list[ix+4];
}
next2type = next2->ph->length_mod;
if(more_syllables==0)
{
len = tr->langopts.length_mods0[next2->ph->length_mod *10+ next->ph->length_mod];
if(next->newword || next2->newword)
{
// don't use 2nd phoneme over a word boundary, unless it's a pause
if(next2type != 1)
next2type = 0;
}
len = tr->langopts.length_mods0[next2type *10+ next->ph->length_mod];
if((next->newword) && (tr->langopts.word_gap & 0x20))
{
@@ -841,7 +861,7 @@ if(stress <= 1)
}
else
{
length_mod = tr->langopts.length_mods[next2->ph->length_mod *10+ next->ph->length_mod];
length_mod = tr->langopts.length_mods[next2type *10+ next->ph->length_mod];
if((next->type == phNASAL) && (next2->type == phSTOP || next2->type == phVSTOP) && (next3->ph->phflags & phFORTIS))
length_mod -= 15;
+1 -1
View File
@@ -35,7 +35,7 @@
#include "translate.h"
#include "wave.h"
const char *version_string = "1.47.03e 29.Mar.13";
const char *version_string = "1.47.03f 31.Mar.13";
const int version_phdata = 0x014701;
int option_device_number = -1;
+2 -2
View File
@@ -93,12 +93,12 @@ ALPHABET alphabets [] = {
{"_ti", OFFSET_TIBET, 0xf00, 0xfff, 0, 0},
{"_my", OFFSET_MYANMAR, 0x1000,0x109f, 0, 0},
{"_ka", OFFSET_GEORGIAN, 0x10a0,0x10ff, L('k','a'), AL_WORDS},
{"_ko", OFFSET_KOREAN, 0x1100,0x11ff, 0, 0},
{"_ko", OFFSET_KOREAN, 0x1100,0x11ff, L('k','o'), AL_WORDS},
{"_eth", OFFSET_ETHIOPIC, 0x1200,0x139f, 0, 0},
{"_braille", 0x2800, 0x2800,0x28ff, 0, AL_NO_SYMBOL},
{"_ja", 0x3040, 0x3040,0x30ff, 0, AL_NOT_CODE},
{"_zh", 0x3100, 0x3100,0x9fff, 0, AL_NOT_CODE},
{"_ko", 0xa700, 0xa700,0xd7ff, 0, AL_NOT_CODE},
{"_ko", 0xa700, 0xa700,0xd7ff, L('k','o'), AL_NOT_CODE | AL_WORDS},
{NULL, 0, 0, 0, 0, 0}
};
+31 -31
View File
@@ -1732,6 +1732,7 @@ int SetTranslator2(const char *new_language)
translator2->phoneme_tab_ix = new_phoneme_tab;
}
}
translator2->phonemes_repeat[0] = 0;
return(new_phoneme_tab);
} // end of SetTranslator2
@@ -2440,6 +2441,35 @@ static int TranslateChar(Translator *tr, char *ptr, int prev_in, unsigned int c,
0x72,0x73,0x74,0x75
};
// check for Korean Hangul letters
if(((code = c - 0xac00) >= 0) && (c <= 0xd7af))
{
// break a syllable hangul into 2 or 3 individual jamo
initial = (code/28)/21;
medial = (code/28) % 21;
final = code % 28;
if(initial == 11)
{
// null initial
c = medial + 0x1161;
if(final > 0)
*insert = final + 0x11a7;
}
else
{
// extact the initial and insert the remainder with a null initial
c = initial + 0x1100;
*insert = (11*28*21) + (medial*28) + final + 0xac00;
}
return(c);
}
else if(((code = c - 0x3130) >= 0) && (code < 0x34))
{
// Hangul compatibility jamo
return(hangul_compatibility[code] + 0x1100);
}
switch(tr->translator_name)
{
case L('a','f'):
@@ -2467,36 +2497,6 @@ static int TranslateChar(Translator *tr, char *ptr, int prev_in, unsigned int c,
}
}
break;
case L('k','o'):
if(((code = c - 0xac00) >= 0) && (c <= 0xd7af))
{
// break a syllable hangul into 2 or 3 individual jamo
initial = (code/28)/21;
medial = (code/28) % 21;
final = code % 28;
if(initial == 11)
{
// null initial
c = medial + 0x1161;
if(final > 0)
*insert = final + 0x11a7;
}
else
{
// extact the initial and insert the remainder with a null initial
c = initial + 0x1100;
*insert = (11*28*21) + (medial*28) + final + 0xac00;
}
return(c);
}
else if(((code = c - 0x3130) >= 0) && (code < 0x34))
{
// Hangul compatibility jamo
return(hangul_compatibility[code] + 0x1100);
}
break;
}
return(SubstituteChar(tr, c, next_in, insert, wordflags));
}
@@ -2951,7 +2951,7 @@ if((c == '/') && (tr->langopts.testing & 2) && IsDigit09(next_in) && IsAlpha(pre
}
else
{
if(iswlower(prev_in))
if((iswlower(prev_in)) && (prev_in != 0xba)) // Windows thinks masc.ordinal (0xba) is lower-case
{
// lower case followed by upper case in a word
if(UpperCaseInWord(tr, &sbuf[ix], c) == 1)
+14 -3
View File
@@ -1883,12 +1883,24 @@ void FreeVoiceList()
ESPEAK_API const espeak_VOICE **espeak_ListVoices(espeak_VOICE *voice_spec)
{//========================================================================
#ifndef PLATFORM_RISCOS
char path_voices[sizeof(path_home)+12];
#ifdef PLATFORM_RISCOS
if(n_voices_list == 0)
{
sprintf(path_voices,"%s%cvoices",path_home,PATHSEP);
len_path_voices = strlen(path_voices)+1;
GetVoices(path_voices);
voices_list[n_voices_list] = NULL; // voices list terminator
}
return((const espeak_VOICE **)voices_list);
#else
int ix;
int j;
espeak_VOICE *v;
static espeak_VOICE **voices = NULL;
char path_voices[sizeof(path_home)+12];
// free previous voice list data
FreeVoiceList();
@@ -1926,7 +1938,6 @@ ESPEAK_API const espeak_VOICE **espeak_ListVoices(espeak_VOICE *voice_spec)
}
return((const espeak_VOICE **)voices);
#endif
return((const espeak_VOICE **)voices_list);
} // end of espeak_ListVoices