mirror of
https://github.com/rhasspy/espeak-ng.git
synced 2026-11-05 06:45:39 +00:00
Merge branch 'development'
This commit is contained in:
@@ -3059,6 +3059,7 @@ int CompilePhoneme(int compile_phoneme)
|
||||
|
||||
case kRETURN:
|
||||
*prog_out++ = i_RETURN;
|
||||
DecThenCount();
|
||||
break;
|
||||
|
||||
case kINCLUDE:
|
||||
|
||||
+29
-2
@@ -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
@@ -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
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user