mirror of
https://github.com/rhasspy/espeak-ng.git
synced 2026-11-12 16:58:52 +00:00
[1.31.05]
<say-as tts:char>, if a character name is not defined, say its English name. phoneme tables, added beforenotvowel2 attribure for lang=tr lang=tr: initial draft git-svn-id: https://espeak.svn.sourceforge.net/svnroot/espeak/trunk@135 d46cf337-b52f-0410-862d-fd96e6ae7743
This commit is contained in:
+26
-26
@@ -58,21 +58,26 @@
|
||||
#define tOLDNAME 14
|
||||
#define tREDUCETO 15
|
||||
#define tFIXEDCODE 16
|
||||
|
||||
#define tBEFOREVOWEL 17
|
||||
#define tBEFOREVOWELPAUSE 18
|
||||
#define tBEFORENOTVOWEL 19
|
||||
#define tLINKOUT 20
|
||||
#define tBEFORENOTVOWEL2 20
|
||||
#define tSWITCHVOICING 21
|
||||
#define tVOWELIN 22
|
||||
#define tVOWELOUT 23
|
||||
#define tAPPENDPH 24 // always insert another phoneme (linkout) after this one
|
||||
#define tIMPORTPH 25
|
||||
#define tBEFOREPAUSE 26
|
||||
|
||||
#define tLINKOUT 23
|
||||
#define tVOWELIN 24
|
||||
#define tVOWELOUT 25
|
||||
#define tAPPENDPH 26 // always insert another phoneme (linkout) after this one
|
||||
#define tIMPORTPH 27
|
||||
#define tBEFOREPAUSE 28
|
||||
|
||||
#define tPHONEMENUMBER 29
|
||||
#define tPHONEMETABLE 30
|
||||
#define tINCLUDE 31
|
||||
|
||||
static const int flags_alternative[] = {phBEFOREVOWEL,phBEFOREVOWELPAUSE,phBEFORENOTVOWEL,phBEFORENOTVOWEL2,phSWITCHVOICING};
|
||||
|
||||
extern void Write4Bytes(FILE *f, int value);
|
||||
extern int Read4Bytes(FILE *f);
|
||||
extern void MakeVowelLists(void);
|
||||
@@ -230,16 +235,17 @@ static keywtab_t keywords[] = {
|
||||
{"length", 12},
|
||||
{"longlength", 13},
|
||||
{"reduceto", 15},
|
||||
{"beforevowel", 17},
|
||||
{"beforevowelpause", 18},
|
||||
{"beforenotvowel",19},
|
||||
{"linkout",20},
|
||||
{"switchvoicing",21},
|
||||
{"vowelin",22},
|
||||
{"vowelout",23},
|
||||
{"appendph",24},
|
||||
{"import_phoneme",25},
|
||||
{"beforepause",26},
|
||||
{"beforevowel", tBEFOREVOWEL},
|
||||
{"beforevowelpause", tBEFOREVOWELPAUSE},
|
||||
{"beforenotvowel",tBEFORENOTVOWEL},
|
||||
{"beforenotvowel2",tBEFORENOTVOWEL2},
|
||||
{"linkout",tLINKOUT},
|
||||
{"switchvoicing",tSWITCHVOICING},
|
||||
{"vowelin",tVOWELIN},
|
||||
{"vowelout",tVOWELOUT},
|
||||
{"appendph",tAPPENDPH},
|
||||
{"import_phoneme",tIMPORTPH},
|
||||
{"beforepause",tBEFOREPAUSE},
|
||||
|
||||
// flags
|
||||
{"wavef", 0x2000000+phWAVE},
|
||||
@@ -1374,18 +1380,12 @@ int Compile::CPhoneme()
|
||||
ph->phflags = (ph->phflags & 0xfffffff) + (value << 28);
|
||||
break;
|
||||
|
||||
case tBEFORENOTVOWEL:
|
||||
ph->phflags |= phBEFORENOTVOWEL; // and drop through to tBEFOREVOWEL
|
||||
case tBEFOREVOWELPAUSE:
|
||||
ph->phflags |= phBEFOREVOWELPAUSE;
|
||||
case tBEFOREVOWEL:
|
||||
if((phcode = NextItem(tPHONEMEMNEM)) == -1)
|
||||
phcode = LookupPhoneme(item_string,1);
|
||||
ph->alternative_ph = phcode;
|
||||
break;
|
||||
|
||||
case tBEFOREVOWELPAUSE:
|
||||
case tBEFORENOTVOWEL:
|
||||
case tBEFORENOTVOWEL2:
|
||||
case tSWITCHVOICING:
|
||||
ph->phflags |= phSWITCHVOICING;
|
||||
ph->phflags |= flags_alternative[item - tBEFOREVOWEL];
|
||||
if((phcode = NextItem(tPHONEMEMNEM)) == -1)
|
||||
phcode = LookupPhoneme(item_string,1);
|
||||
ph->alternative_ph = phcode;
|
||||
|
||||
@@ -1197,6 +1197,23 @@ void Translator::SetWordStress(char *output, unsigned int dictionary_flags, int
|
||||
}
|
||||
break;
|
||||
|
||||
case 7: // LANG=tr, the last syllable for any vowel markes explicitly as unstressed
|
||||
if(stressed_syllable == 0)
|
||||
{
|
||||
stressed_syllable = vowel_count - 1;
|
||||
for(ix=2; ix < vowel_count; ix++)
|
||||
{
|
||||
if(vowel_stress[ix] == 1)
|
||||
{
|
||||
stressed_syllable = ix-1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
vowel_stress[stressed_syllable] = 4;
|
||||
max_stress = 4;
|
||||
}
|
||||
break;
|
||||
|
||||
case 9: // mark all as stressed
|
||||
for(ix=1; ix<vowel_count; ix++)
|
||||
{
|
||||
|
||||
+3
-3
@@ -1160,7 +1160,7 @@ void Test2()
|
||||
|
||||
|
||||
|
||||
const char* text1 = "Hello, World2 <mark name=\"mark2\"/>. This is the second sentence";
|
||||
const char* text1 = "Hello world. Testing.";
|
||||
|
||||
void TestTest(int control)
|
||||
{//=======================
|
||||
@@ -1200,10 +1200,10 @@ if(control==2)
|
||||
|
||||
f_wavtest = OpenWaveFile3("/home/jsd1/speechdata/text/test.wav");
|
||||
f_events = fopen("/home/jsd1/speechdata/text/events","w");
|
||||
fprintf(f_events,"Type Audio Text Length Id\n");
|
||||
fprintf(f_events,"Type Audio Text Length Id\n");
|
||||
fclose(f_events);
|
||||
|
||||
espeak_Initialize(AUDIO_OUTPUT_PLAYBACK,1000,NULL,0);
|
||||
espeak_Initialize(AUDIO_OUTPUT_RETRIEVAL,1000,NULL,1);
|
||||
espeak_SetSynthCallback(TestSynthCallback);
|
||||
espeak_SetUriCallback(TestUriCallback);
|
||||
|
||||
|
||||
+29
-14
@@ -31,6 +31,7 @@
|
||||
#include "speech.h"
|
||||
#include "phoneme.h"
|
||||
#include "synthesize.h"
|
||||
#include "voice.h"
|
||||
#include "translate.h"
|
||||
|
||||
|
||||
@@ -44,6 +45,15 @@ void Translator::LookupLetter(int letter, int next_byte, char *ph_buf1)
|
||||
char ph_stress[2];
|
||||
char ph_buf3[30];
|
||||
|
||||
if((letter <= 32) || iswspace(letter))
|
||||
{
|
||||
// lookup space as _&32 etc.
|
||||
sprintf(&single_letter[1],"_#%d ",letter);
|
||||
Lookup(&single_letter[1],ph_buf1);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
len = utf8_out(letter,&single_letter[2]);
|
||||
single_letter[len+2] = ' ';
|
||||
|
||||
@@ -89,11 +99,13 @@ int Translator::TranslateLetter(char *word, char *phonemes, int control)
|
||||
int n_bytes;
|
||||
int letter;
|
||||
int len;
|
||||
int phoneme_tab_en;
|
||||
char *p2;
|
||||
char *pbuf;
|
||||
char capital[20];
|
||||
char ph_buf[50];
|
||||
char ph_buf2[50];
|
||||
char ph_buf[60];
|
||||
char ph_buf2[60];
|
||||
char ph_buf_en[60];
|
||||
char hexbuf[6];
|
||||
static char single_letter[10] = {0,0};
|
||||
|
||||
@@ -117,15 +129,6 @@ int Translator::TranslateLetter(char *word, char *phonemes, int control)
|
||||
}
|
||||
letter = towlower(letter);
|
||||
|
||||
if((letter <= 32) || iswspace(letter))
|
||||
{
|
||||
// lookup space as _&32 etc.
|
||||
sprintf(&single_letter[1],"_#%d ",letter);
|
||||
Lookup(&single_letter[1],ph_buf);
|
||||
strcat(phonemes,ph_buf);
|
||||
return(n_bytes);
|
||||
}
|
||||
|
||||
LookupLetter(letter, word[n_bytes], ph_buf);
|
||||
|
||||
if(ph_buf[0] == phonSWITCH)
|
||||
@@ -133,6 +136,18 @@ int Translator::TranslateLetter(char *word, char *phonemes, int control)
|
||||
strcpy(phonemes,ph_buf);
|
||||
return(0);
|
||||
}
|
||||
|
||||
if(ph_buf[0] == 0)
|
||||
{
|
||||
phoneme_tab_en = SetTranslator2("en");
|
||||
translator2->LookupLetter(letter, word[n_bytes], ph_buf_en);
|
||||
if(ph_buf_en[0] != 0)
|
||||
{
|
||||
sprintf(ph_buf,"%c%c%s%c%c",phonSWITCH2, phoneme_tab_en + phonTOP, ph_buf_en, phonSWITCH2, voice->phoneme_tab_ix + phonTOP);
|
||||
}
|
||||
SelectPhonemeTable(voice->phoneme_tab_ix); // revert to original phoneme table
|
||||
}
|
||||
|
||||
if(ph_buf[0] == 0)
|
||||
{
|
||||
// character name not found
|
||||
@@ -166,8 +181,8 @@ int Translator::TranslateLetter(char *word, char *phonemes, int control)
|
||||
|
||||
|
||||
|
||||
void Translator::SetSpellingStress(char *phonemes, int control)
|
||||
{//============================================================
|
||||
void Translator::SetSpellingStress(char *phonemes, int control, int n_chars)
|
||||
{//=========================================================================
|
||||
// Individual letter names, reduce the stress of some.
|
||||
int ix;
|
||||
unsigned int c;
|
||||
@@ -188,7 +203,7 @@ void Translator::SetSpellingStress(char *phonemes, int control)
|
||||
count = 0;
|
||||
for(ix=0; (c = buf[ix]) != 0; ix++)
|
||||
{
|
||||
if(c == phonSTRESS_P)
|
||||
if((c == phonSTRESS_P) && (n_chars > 1))
|
||||
{
|
||||
count++;
|
||||
|
||||
|
||||
+5
-2
@@ -45,18 +45,19 @@
|
||||
#define phTRILL 0x80
|
||||
#define phVOWEL2 0x100 // liquid that is considered a vowel
|
||||
#define phPALATAL 0x200
|
||||
#define phLONG 0x1000
|
||||
#define phAPPENDPH 0x2000 // always insert another phoneme (link_out) after this one
|
||||
#define phBRKAFTER 0x4000 // [*] add a post-pause
|
||||
#define phBEFOREPAUSE 0x8000 // replace with the link_out phoneme if the next phoneme is a pause
|
||||
|
||||
#define phALTERNATIVE 0x0c00 // bits 10,11 specifying use of alternative_ph
|
||||
#define phALTERNATIVE 0x1c00 // bits 10,11,12 specifying use of alternative_ph
|
||||
#define phBEFOREVOWEL 0x0000
|
||||
#define phBEFOREVOWELPAUSE 0x0400
|
||||
#define phBEFORENOTVOWEL 0x0c00
|
||||
#define phBEFORENOTVOWEL2 0x1000
|
||||
#define phSWITCHVOICING 0x0800
|
||||
|
||||
#define phNONSYLLABIC 0x100000 // don't count this vowel as a syllable when finding the stress position
|
||||
#define phLONG 0x200000
|
||||
|
||||
// fixed phoneme code numbers, these can be used from the program code
|
||||
#define phonCONTROL 1
|
||||
@@ -86,6 +87,8 @@
|
||||
#define phonT_REDUCED 25
|
||||
#define phonSTRESS_TONIC 26
|
||||
#define phonPAUSE_CLAUSE 27
|
||||
#define phonSWITCH2 28
|
||||
#define phonTOP 28 // highest pre-defined phoneme number
|
||||
|
||||
extern const unsigned char pause_phonemes[8]; // 0, vshort, short, pause, long, glottalstop
|
||||
|
||||
|
||||
@@ -395,6 +395,14 @@ void Translator::MakePhonemeList(int post_pause, int start_sentence)
|
||||
alternative = ph->alternative_ph;
|
||||
break;
|
||||
|
||||
case phBEFORENOTVOWEL2: // LANG=tr
|
||||
if(((plist2+1)->sourceix != 0) ||
|
||||
((next->type != phVOWEL) && ((phoneme_tab[(plist2+2)->phcode]->type != phVOWEL) || ((plist2+2)->sourceix != 0))))
|
||||
{
|
||||
alternative = ph->alternative_ph;
|
||||
}
|
||||
break;
|
||||
|
||||
case phBEFOREVOWELPAUSE:
|
||||
if((next->type == phVOWEL) || (next->type == phPAUSE))
|
||||
alternative = ph->alternative_ph;
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
#endif
|
||||
|
||||
#ifdef _ESPEAKEDIT
|
||||
#define USE_PORTAUDIO
|
||||
#define USE_ASYNC
|
||||
#define LOG_FRAMES // write keyframe info to log-espeakedit
|
||||
#endif
|
||||
|
||||
+2
-2
@@ -35,8 +35,8 @@
|
||||
#include "translate.h"
|
||||
#include "wave.h"
|
||||
|
||||
const char *version_string = "1.31.04 30.Jan.08";
|
||||
const int version_phdata = 0x013100;
|
||||
const char *version_string = "1.31.05 04.Feb.08";
|
||||
const int version_phdata = 0x013105;
|
||||
|
||||
int option_device_number = -1;
|
||||
|
||||
|
||||
@@ -669,15 +669,15 @@ SetLengthMods(tr,3); // all equal
|
||||
case L('t','r'): // Turkish
|
||||
{
|
||||
static const unsigned char stress_amps_tr[8] = {16,16, 20,20, 20,24, 24,22 };
|
||||
static const short stress_lengths_tr[8] = {180,150, 200,180, 0,0, 230,270};
|
||||
static const short stress_lengths_tr[8] = {170,170, 190,170, 0,0, 250,270};
|
||||
|
||||
tr = new Translator();
|
||||
SetupTranslator(tr,stress_lengths_tr,stress_amps_tr);
|
||||
tr->charset_a0 = charsets[9]; // ISO-8859-9 - Latin5
|
||||
|
||||
tr->langopts.stress_rule = 3; // stress on the last syllable
|
||||
tr->langopts.stress_rule = 7; // stress on the last syllable, before any explicitly unstressed syllable
|
||||
|
||||
tr->langopts.numbers = 0x1009;
|
||||
tr->langopts.numbers = 0x1d09;
|
||||
tr->langopts.max_initial_consonants = 2;
|
||||
}
|
||||
break;
|
||||
|
||||
+67
-41
@@ -38,7 +38,7 @@
|
||||
|
||||
|
||||
Translator *translator = NULL; // the main translator
|
||||
static Translator *translator2 = NULL; // secondary translator for certain words
|
||||
Translator *translator2 = NULL; // secondary translator for certain words
|
||||
static char translator2_language[20] = {0};
|
||||
|
||||
FILE *f_trans = NULL; // phoneme output text
|
||||
@@ -750,6 +750,7 @@ if((wmark > 0) && (wmark < 8))
|
||||
while(*wordx != ' ')
|
||||
{
|
||||
wordx += TranslateLetter(wordx, phonemes,spell_word);
|
||||
posn++;
|
||||
if(phonemes[0] == phonSWITCH)
|
||||
{
|
||||
// change to another language in order to translate this word
|
||||
@@ -757,7 +758,7 @@ if((wmark > 0) && (wmark < 8))
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
SetSpellingStress(phonemes,spell_word);
|
||||
SetSpellingStress(phonemes,spell_word,posn);
|
||||
}
|
||||
else
|
||||
if(found == 0)
|
||||
@@ -776,6 +777,7 @@ if((wmark > 0) && (wmark < 8))
|
||||
// find a remainder that we can pronounce.
|
||||
emphasize_allcaps = 0;
|
||||
wordx += TranslateLetter(wordx,phonemes,0);
|
||||
posn++;
|
||||
if(phonemes[0] == phonSWITCH)
|
||||
{
|
||||
// change to another language in order to translate this word
|
||||
@@ -798,7 +800,7 @@ if((wmark > 0) && (wmark < 8))
|
||||
if(length > 0)
|
||||
wordx[-1] = ' '; // prevent this affecting the pronunciation of the pronuncable part
|
||||
}
|
||||
SetSpellingStress(phonemes,0);
|
||||
SetSpellingStress(phonemes,0,posn);
|
||||
|
||||
// anything left ?
|
||||
if(*wordx != ' ')
|
||||
@@ -1164,6 +1166,39 @@ static int CountSyllables(unsigned char *phonemes)
|
||||
return(count);
|
||||
}
|
||||
|
||||
|
||||
int SetTranslator2(const char *new_language)
|
||||
{//=========================================
|
||||
// Set translator2 to a second language
|
||||
int new_phoneme_tab;
|
||||
|
||||
if((new_phoneme_tab = SelectPhonemeTableName(new_language)) >= 0)
|
||||
{
|
||||
if((translator2 != NULL) && (strcmp(new_language,translator2_language) != 0))
|
||||
{
|
||||
// we already have an alternative translator, but not for the required language, delete it
|
||||
delete translator2;
|
||||
translator2 = NULL;
|
||||
}
|
||||
|
||||
if(translator2 == NULL)
|
||||
{
|
||||
translator2 = SelectTranslator(new_language);
|
||||
strcpy(translator2_language,new_language);
|
||||
|
||||
if(translator2->LoadDictionary(new_language,0) != 0)
|
||||
{
|
||||
SelectPhonemeTable(voice->phoneme_tab_ix); // revert to original phoneme table
|
||||
new_phoneme_tab = -1;
|
||||
translator2_language[0] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return(new_phoneme_tab);
|
||||
} // end of SetTranslator2
|
||||
|
||||
|
||||
|
||||
int Translator::TranslateWord2(char *word, WORD_TAB *wtab, int pre_pause, int next_pause)
|
||||
{//======================================================================================
|
||||
int flags=0;
|
||||
@@ -1199,27 +1234,31 @@ int Translator::TranslateWord2(char *word, WORD_TAB *wtab, int pre_pause, int ne
|
||||
if(word_flags & FLAG_EMBEDDED)
|
||||
{
|
||||
embedded_flag = SFLAG_EMBEDDED;
|
||||
value = embedded_list[embedded_read] >> 8;
|
||||
|
||||
switch(embedded_cmd = embedded_list[embedded_read] & 0x1f)
|
||||
do
|
||||
{
|
||||
case EMBED_Y:
|
||||
option_sayas = value;
|
||||
break;
|
||||
embedded_cmd = embedded_list[embedded_read++];
|
||||
value = embedded_cmd >> 8;
|
||||
|
||||
case EMBED_F:
|
||||
option_emphasis = value;
|
||||
break;
|
||||
|
||||
case EMBED_B:
|
||||
// break command
|
||||
if(value == 0)
|
||||
pre_pause = 0; // break=none
|
||||
else
|
||||
pre_pause += value;
|
||||
break;
|
||||
}
|
||||
while((embedded_list[embedded_read++] & 0x80) == 0); // read over the embedded commands for this word
|
||||
switch(embedded_cmd & 0x1f)
|
||||
{
|
||||
case EMBED_Y:
|
||||
option_sayas = value;
|
||||
break;
|
||||
|
||||
case EMBED_F:
|
||||
option_emphasis = value;
|
||||
break;
|
||||
|
||||
case EMBED_B:
|
||||
// break command
|
||||
if(value == 0)
|
||||
pre_pause = 0; // break=none
|
||||
else
|
||||
pre_pause += value;
|
||||
break;
|
||||
}
|
||||
} while((embedded_cmd & 0x80) == 0);
|
||||
}
|
||||
|
||||
if(word[0] == 0)
|
||||
@@ -1328,28 +1367,9 @@ int Translator::TranslateWord2(char *word, WORD_TAB *wtab, int pre_pause, int ne
|
||||
new_language = (char *)(&p[1]);
|
||||
if(new_language[0]==0)
|
||||
new_language = "en";
|
||||
if((switch_phonemes = SelectPhonemeTableName(new_language)) >= 0)
|
||||
{
|
||||
if((translator2 != NULL) && (strcmp(new_language,translator2_language) != 0))
|
||||
{
|
||||
// we already have an alternative translator, but not for the required language, delete it
|
||||
delete translator2;
|
||||
translator2 = NULL;
|
||||
}
|
||||
|
||||
if(translator2 == NULL)
|
||||
{
|
||||
translator2 = SelectTranslator(new_language);
|
||||
strcpy(translator2_language,new_language);
|
||||
switch_phonemes = SetTranslator2(new_language);
|
||||
|
||||
if(translator2->LoadDictionary(new_language,0) != 0)
|
||||
{
|
||||
SelectPhonemeTable(voice->phoneme_tab_ix); // revert to original phoneme table
|
||||
switch_phonemes = -1;
|
||||
translator2_language[0] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(switch_phonemes >= 0)
|
||||
{
|
||||
// re-translate the word using the new translator
|
||||
@@ -1488,6 +1508,12 @@ int Translator::TranslateWord2(char *word, WORD_TAB *wtab, int pre_pause, int ne
|
||||
srcix = source_ix+1;
|
||||
}
|
||||
else
|
||||
if(ph_code == phonSWITCH2)
|
||||
{
|
||||
SetPlist2(&ph_list2[n_ph_list2],phonSWITCH);
|
||||
ph_list2[n_ph_list2++].tone_number = *p++ - phonTOP; // phoneme table number (phonTOP is added to avoid confusion with special phoneme numbers)
|
||||
}
|
||||
else
|
||||
if(ph_code == phonX1)
|
||||
{
|
||||
// a language specific action
|
||||
|
||||
+3
-1
@@ -416,7 +416,7 @@ public:
|
||||
private:
|
||||
int TranslateWord2(char *word, WORD_TAB *wtab, int pre_pause, int next_pause);
|
||||
int TranslateLetter(char *letter, char *phonemes, int control);
|
||||
void SetSpellingStress(char *phonemes, int control);
|
||||
void SetSpellingStress(char *phonemes, int control, int n_chars);
|
||||
void WriteMnemonic(int *ix, int mnem);
|
||||
void MakePhonemeList(int post_pause, int new_sentence);
|
||||
int SubstitutePhonemes(PHONEME_LIST2 *plist_out);
|
||||
@@ -541,6 +541,7 @@ extern unsigned char punctuation_to_tone[INTONATION_TYPES][PUNCT_INTONATIONS];
|
||||
extern int speech_parameters[];
|
||||
|
||||
extern Translator *translator;
|
||||
extern Translator *translator2;
|
||||
extern const unsigned short *charsets[N_CHARSETS];
|
||||
extern char dictionary_name[40];
|
||||
extern char ctrl_embedded; // to allow an alternative CTRL for embedded commands
|
||||
@@ -554,6 +555,7 @@ extern int (* phoneme_callback)(const char *);
|
||||
extern void SetLengthMods(Translator *tr, int value);
|
||||
|
||||
Translator *SelectTranslator(const char *name);
|
||||
int SetTranslator2(const char *name);
|
||||
int CompileDictionary(const char *dsource, const char *dict_name, FILE *log, char *err_name,int flags);
|
||||
void LoadConfig(void);
|
||||
int PhonemeCode(unsigned int mnem);
|
||||
|
||||
Reference in New Issue
Block a user