[1.41.17]

espeakedit: add "format *_rules file" feature.


git-svn-id: https://espeak.svn.sourceforge.net/svnroot/espeak/trunk@228 d46cf337-b52f-0410-862d-fd96e6ae7743
This commit is contained in:
jonsd
2009-10-16 09:35:25 +00:00
parent 1ef2aa6091
commit 7fc0ab97e1
20 changed files with 925 additions and 527 deletions
+26 -14
View File
@@ -59,6 +59,7 @@ const char *path_data;
extern void TestTest(int control);
extern void CompareLexicon(int);
extern void ConvertToUtf8();
extern void FormatDictionary(const char *dictname);
extern void init_z();
extern void CompileInit(void);
@@ -73,6 +74,10 @@ extern void MakeWordFreqList();
extern const char *dict_name;
extern wxMenu *speak_menu;
extern wxMenu *data_menu;
MyFrame *myframe = NULL;
SpectDisplay *currentcanvas = NULL;
@@ -158,21 +163,21 @@ extern void VoiceReset(int control);
// Create the main frame window
myframe = new MyFrame(NULL, -1, AppName, wxPoint(0, 0), wxSize(1024, 768),
myframe = new MyFrame(NULL, -1, AppName, wxPoint(0, 0), wxSize(1024, 768),
wxDEFAULT_FRAME_STYLE |
wxNO_FULL_REPAINT_ON_RESIZE |
wxHSCROLL | wxVSCROLL);
// Make a menubar
myframe->SetMenuBar(MakeMenu(0));
// Make a menubar
myframe->SetMenuBar(MakeMenu(0));
myframe->CreateStatusBar();
myframe->SetVoiceTitle(voice_name2);
myframe->CreateStatusBar();
myframe->Maximize();
myframe->Show(TRUE);
myframe->Maximize();
myframe->Show(TRUE);
SetTopWindow(myframe);
SetTopWindow(myframe);
wxInitAllImageHandlers();
// wxImage::AddHandler(wxPNGHandler);
return TRUE;
@@ -194,6 +199,7 @@ BEGIN_EVENT_TABLE(MyFrame, wxMDIParentFrame)
EVT_MENU(MENU_COMPILE_PH, MyFrame::OnTools)
EVT_MENU(MENU_COMPILE_DICT, MyFrame::OnTools)
EVT_MENU(MENU_COMPILE_DICT_DEBUG, MyFrame::OnTools)
EVT_MENU(MENU_FORMAT_DICTIONARY, MyFrame::OnTools)
EVT_MENU(MENU_COMPILE_MBROLA, MyFrame::OnTools)
EVT_MENU(MENU_CLOSE_ALL, MyFrame::OnQuit)
EVT_MENU(MENU_QUIT, MyFrame::OnQuit)
@@ -284,10 +290,6 @@ wxSashLayoutWindow *win;
wxLogError(_T("Failed to load voice data"));
strcpy(dictionary_name,"en");
}
else
{
SetVoiceTitle(voice_name2);
}
WavegenSetVoice(voice);
for(param=0; param<N_SPEECH_PARAM; param++)
@@ -312,7 +314,15 @@ wxSashLayoutWindow *win;
void MyFrame::SetVoiceTitle(char *voice_name)
{//==========================================
char buf[100];
SetTitle(AppName + _T(" - ") + wxString(voice_name,wxConvLocal) + _T(" voice"));
if(data_menu != NULL)
{
sprintf(buf,"Compile &dictionary '%s'",dictionary_name);
data_menu->SetLabel(MENU_COMPILE_DICT, wxString(buf,wxConvLocal));
sprintf(buf,"&Format '%s_rules' file",dictionary_name);
data_menu->SetLabel(MENU_FORMAT_DICTIONARY, wxString(buf,wxConvLocal));
}
}
@@ -605,6 +615,10 @@ void MyFrame::OnTools(wxCommandEvent& event)
fclose(log);
break;
case MENU_FORMAT_DICTIONARY:
FormatDictionary(dictionary_name);
break;
case MENU_VOWELCHART1:
MakeVowelLists();
break;
@@ -623,8 +637,6 @@ void MyFrame::OnTools(wxCommandEvent& event)
}
}
extern wxMenu *speak_menu;
void MyFrame::OnSpeak(wxCommandEvent& event)
{//=========================================
switch(event.GetId())
+257
View File
@@ -1312,6 +1312,263 @@ void ConvertToUtf8()
//******************************************************************************************************
void FormatDictionary(const char *dictname)
{//========================================
// Format the *_rules file for the current voice
FILE *f_in;
FILE *f_out;
char *p;
char *p_start;
unsigned short *pw;
unsigned short *pw_match;
unsigned short *pw_post;
unsigned short *pw_phonemes;
int c;
int ix;
int n_pre;
int n_match;
int n_post;
int n_phonemes;
int n_spaces;
int n_out;
int formatting;
int comment;
char buf[200];
unsigned short bufw[200];
char conditional[80];
char fname_in[200];
char fname_out[200];
const int tab1 = 8;
const int tab2 = 18;
const int tab3 = 28;
sprintf(fname_in,"%s/%s_rules",path_dsource,dictname);
sprintf(fname_out,"%s_formatted",fname_in);
if((f_in = fopen(fname_in,"r")) == NULL)
{
wxLogError(_T("Can't open rules file: ") + wxString(fname_in,wxConvLocal));
return;
}
if((f_out = fopen(fname_out,"w")) == NULL)
{
wxLogError(_T("Can't write to file: ") + wxString(fname_out,wxConvLocal));
fclose(f_in);
return;
}
formatting = 0;
n_match = 0;
while(fgets(buf, sizeof(buf)-1, f_in) != NULL)
{
buf[sizeof(buf)-1] = 0; // ensure zero byte terminator
ix = strlen(buf) - 1;
while((buf[ix]=='\n') || (buf[ix]==' ') || (buf[ix]=='\t')) ix--;
buf[ix+1] = 0; // strip tailing spaces
p_start = buf;
while((*p_start==' ') || (*p_start == '\t')) p_start++; // skip leading spaces
comment = 0;
if((p_start[0]=='/') && (p_start[1]=='/'))
comment = 1;
ix = 0;
if(*p_start == '?')
{
// conditional rule
while(!isspace(*p_start) && (*p_start != 0))
{
conditional[ix++] = *p_start++;
}
while((*p_start == ' ') || (*p_start == '\t')) p_start++;
}
conditional[ix] = 0;
if(buf[0] == '.')
{
formatting = 0;
}
if(memcmp(p_start, ".group", 6) == 0)
{
formatting = 2;
if(n_match > 0)
{
// previous line was not blank, so add a blank line
fprintf(f_out,"\n");
}
}
n_match = 0;
if((formatting == 1) && (comment==0))
{
// convert from UTF-8 to UTF-16
p = p_start;
pw = bufw;
do {
p += utf8_in(&c, p);
*pw++ = c;
} while (c != 0);
pw = bufw;
while((*pw != ')') && (*pw != 0) && !iswspace(*pw)) pw++;
n_pre = 0;
n_post = 0;
n_phonemes = 0;
n_spaces = 0;
if(*pw != 0)
n_spaces = tab1;
if(*pw == ')')
{
// there is a pre-condition
n_pre = pw - bufw + 1;
n_spaces = tab1 - n_pre - 1;
pw++;
while((*pw==' ') || (*pw=='\t')) pw++;
}
else
{
pw = bufw;
}
pw_match = pw;
while(((c = *pw)!= ' ') && (c != '\t') && (c != '(') && (c != 0))
{
pw++;
}
n_match = pw - pw_match;
while(((c = *pw)==' ') || (c == '\t')) pw++;
if(*pw == '(')
{
pw_post = pw;
while(((c = *pw)!=' ') && (c != '\t') && (c != 0)) pw++;
n_post = pw - pw_post;
while(((c = *pw)==' ') || (c == '\t')) pw++;
}
if((*pw != 0) && ((*pw != '/') || (pw[1] != '/')))
{
pw_phonemes = pw;
while(((c = *pw)!=' ') && (c != '\t') && (c != 0)) pw++;
n_phonemes = pw - pw_phonemes;
while(((c = *pw)==' ') || (c == '\t')) pw++;
}
// write formatted line
p = buf;
if(conditional[0] != 0)
{
ix = 0;
while(conditional[ix] != 0)
{
*p++ = conditional[ix++];
n_spaces--;
}
*p++ = ' ';
n_spaces--;
}
while(n_spaces-- > 0)
{
*p++ = ' ';
}
if(n_pre > 0)
{
ix = 0;
for(ix=0; ix<n_pre; ix++)
{
p += utf8_out(bufw[ix], p);
}
*p++ = ' ';
}
// write the match condition
if(n_match > 0)
{
ix = 0;
for(ix=0; ix<n_match; ix++)
{
p += utf8_out(pw_match[ix], p);
}
*p++ = ' ';
}
// write the post condition
if(n_post > 0)
{
for(ix=0; ix<n_post; ix++)
{
p += utf8_out(pw_post[ix], p);
}
*p++ = ' ';
n_post++;
}
n_out = tab1 + n_match + n_post;
if(n_pre >= tab1)
n_out += (n_pre - tab1 + 1);
if(n_phonemes > 0)
{
n_spaces = tab2 - n_out;
while(n_spaces-- > 0)
{
*p++ = ' ';
n_out++;
}
// write the phoneme codes
for(ix=0; ix<n_phonemes; ix++)
{
p += utf8_out(pw_phonemes[ix], p);
}
}
if(*pw != 0)
{
*p++ = ' ';
n_phonemes++;
n_spaces = tab3 - (n_out + n_phonemes);
while(n_spaces-- > 0)
{
*p++ = ' ';
}
}
// write the remainer of the line
while(*pw != 0)
{
p+= utf8_out(*pw++, p);
}
*p = 0;
}
if(formatting > 1)
formatting--;
fprintf(f_out, "%s\n", buf);
}
fclose(f_in);
fclose(f_out);
wxLogStatus(_("Written to file: ") + wxString(fname_out,wxConvLocal));
} // end of FormatDictionary
//******************************************************************************************************
//#define calcspeedtab
+2 -1
View File
@@ -51,6 +51,7 @@ class MyFrame: public wxMDIParentFrame
void OnNewWindow(wxCommandEvent& event);
void OnProsody(wxCommandEvent& event);
void SetVoiceTitle(char *voice_name);
protected:
@@ -58,7 +59,6 @@ protected:
wxSashLayoutWindow* m_leftWindow1;
wxSashLayoutWindow* m_leftWindow2;
wxSashLayoutWindow* m_bottomWindow;
void SetVoiceTitle(char *voice_name);
wxTimer m_timer;
DECLARE_EVENT_TABLE()
@@ -135,6 +135,7 @@ enum {
MENU_COMPILE_PH,
MENU_COMPILE_DICT,
MENU_COMPILE_DICT_DEBUG,
MENU_FORMAT_DICTIONARY,
MENU_COMPILE_MBROLA,
MENU_SPEAK_TRANSLATE,
+4 -2
View File
@@ -24,6 +24,7 @@
wxMenu *speak_menu;
wxMenu *data_menu = NULL;
wxMenuBar *MakeMenu(int type)
{//==========================
@@ -32,7 +33,6 @@ wxMenuBar *MakeMenu(int type)
wxMenu *help_menu;
wxMenu *option_menu = NULL;
wxMenu *paths_menu;
wxMenu *data_menu = NULL;
wxMenu *tools_menu;
wxMenu *voice_menu;
wxMenu *vowelchart_menu;
@@ -86,8 +86,10 @@ wxMenuBar *MakeMenu(int type)
data_menu = new wxMenu;
data_menu->Append(MENU_COMPILE_PH, _("Compile &phoneme data"));
data_menu->Append(MENU_COMPILE_DICT, _("Compile &dictionary"));
data_menu->Append(MENU_COMPILE_DICT_DEBUG, _("Compile dictionary (&debug)"));
data_menu->Append(MENU_COMPILE_DICT_DEBUG, _("Compile dictionary (debu&g)"));
data_menu->Append(MENU_COMPILE_MBROLA, _("Compile &mbrola phonemes list..."));
data_menu->AppendSeparator();
data_menu->Append(MENU_FORMAT_DICTIONARY, _("&Format *_rules file"));
// OPTIONS MENU
paths_menu = new wxMenu;
+55 -24
View File
@@ -751,8 +751,40 @@ void SetSpellingStress(Translator *tr, char *phonemes, int control, int n_chars)
static char ph_ordinal2[12];
int TranslateRoman(Translator *tr, char *word, char *ph_out)
{//=====================================================
static int CheckDotOrdinal(Translator *tr, char *word, WORD_TAB *wtab, int lowercase)
{//==================================================================================
// nextupper: Next word must start with lower-case
int ordinal = 0;
int c2;
if((tr->langopts.numbers & NUM_ORDINAL_DOT) && (word[0] == '.'))
{
if((lowercase==0) || !(wtab[1].flags & FLAG_FIRST_UPPER))
{
utf8_in(&c2, &word[2]);
if(IsAlpha(c2))
{
// ordinal number is indicated by dot after the number
// but not if the next word starts with an upper-case letter
ordinal = 2;
word[0] = ' ';
if(tr->translator_name == L('h','u'))
{
// lang=hu don't treat dot as ordinal indicator if the next word is a month name ($alt)
if(TranslateWord(tr, &word[2], 0, NULL) & FLAG_ALT_TRANS)
ordinal = 0;
}
}
}
}
return(ordinal);
} // end of CheckDotOrdinal
int TranslateRoman(Translator *tr, char *word, char *ph_out, WORD_TAB *wtab)
{//=========================================================================
int c;
char *p;
const char *p2;
@@ -761,7 +793,7 @@ int TranslateRoman(Translator *tr, char *word, char *ph_out)
int value;
int subtract;
int repeat = 0;
WORD_TAB wtab[2];
int n_digits = 0;
unsigned int flags;
char ph_roman[30];
char number_chars[N_WORD_BYTES];
@@ -772,7 +804,9 @@ int TranslateRoman(Translator *tr, char *word, char *ph_out)
acc = 0;
prev = 0;
subtract = 0x7fff;
memset(wtab, 0, sizeof(wtab));
if((tr->langopts.numbers & NUM_ROMAN_CAPITALS) && !(wtab[0].flags & FLAG_ALL_UPPER))
return(0);
while((c = *word++) != ' ')
{
@@ -807,9 +841,10 @@ int TranslateRoman(Translator *tr, char *word, char *ph_out)
else
acc += prev;
prev = value;
n_digits++;
}
acc += prev;
if(acc < 2)
if(acc < tr->langopts.min_roman)
return(0);
if(acc > tr->langopts.max_roman)
@@ -826,12 +861,22 @@ int TranslateRoman(Translator *tr, char *word, char *ph_out)
sprintf(number_chars," %d ",acc);
if(tr->langopts.numbers & NUM_ROMAN_ORDINAL)
if(CheckDotOrdinal(tr, word, wtab, 0))
wtab[0].flags |= FLAG_ORDINAL;
if(tr->langopts.numbers & NUM_ROMAN_ORDINAL)
{
if((n_digits <= 1) && !(wtab[0].flags & FLAG_ORDINAL))
return(0);
wtab[0].flags |= FLAG_ORDINAL;
}
TranslateNumber(tr, &number_chars[1], p, &flags, wtab);
if(tr->langopts.numbers & NUM_ROMAN_AFTER)
strcat(ph_out,ph_roman);
return(1);
} // end of TranslateRoman
@@ -1313,8 +1358,6 @@ static int TranslateNumber_1(Translator *tr, char *word, char *ph_out, unsigned
char ph_buf[200];
char ph_buf2[50];
char suffix[20];
char *wordptr;
unsigned int dictflags;
static const char str_pause[2] = {phonPAUSE_NOLINK,0};
@@ -1325,22 +1368,10 @@ static int TranslateNumber_1(Translator *tr, char *word, char *ph_out, unsigned
value = this_value = atoi(word);
ph_ordinal2[0] = 0;
if((tr->langopts.numbers & NUM_ORDINAL_DOT) && (word[ix] == '.') && IsAlpha(word[ix+2]) && !(wtab[1].flags & FLAG_FIRST_UPPER))
{
// ordinal number is indicated by dot after the number
// but not if the next word starts with an upper-case letter
ordinal = 2;
word[ix] = ' ';
if(tr->translator_name == L('h','u'))
{
// lang=hu don't treat dot as ordinal indicator if the next word is a month name ($alt)
wordptr = &word[ix+2];
dictflags = TranslateWord(tr, &word[ix+2], 0, NULL);
if(dictflags & FLAG_ALT_TRANS)
ordinal = 0;
}
}
else
ordinal = CheckDotOrdinal(tr, &word[ix], wtab, 1);
if(ordinal == 0)
{
// look for an ordinal number suffix after the number
ix++;
+12 -2
View File
@@ -357,6 +357,15 @@ int towlower2(unsigned int c)
return(towlower(c));
}
static int IsRomanU(unsigned int c)
{//================================
if((c=='I') || (c=='V') || (c=='X') || (c=='L'))
return(1);
return(0);
}
static void GetC_unget(int c)
{//==========================
// This is only called with UTF8 input, not wchar input
@@ -2388,10 +2397,11 @@ if(option_ssml) parag=1;
if((nl_count==0) && (c1 == '.'))
{
if(iswdigit(cprev) && (tr->langopts.numbers & NUM_ORDINAL_DOT))
if((tr->langopts.numbers & NUM_ORDINAL_DOT) &&
(iswdigit(cprev) || (IsRomanU(cprev) && (IsRomanU(cprev2) || iswspace(cprev2))))) // lang=hu
{
// dot after a number indicates an ordinal number
if(islower(c_next) || (c_next == '<'))
if(!iswdigit(cprev) || iswlower(c_next) || (c_next == '<'))
is_end_clause = 0; // only if followed by lower-case, (or if there is a XML tag)
}
else
+1 -1
View File
@@ -35,7 +35,7 @@
#include "translate.h"
#include "wave.h"
const char *version_string = "1.41.15 12.Oct.09";
const char *version_string = "1.41.17 15.Oct.09";
const int version_phdata = 0x014100;
int option_device_number = -1;
+3 -1
View File
@@ -164,6 +164,7 @@ static Translator* NewTranslator(void)
tr->langopts.long_stop = 100;
tr->langopts.max_roman = 49;
tr->langopts.min_roman = 2;
tr->langopts.thousands_sep = ',';
tr->langopts.decimal_sep = '.';
tr->langopts.break_numbers = BREAK_THOUSANDS; // 1000, 1000,000 1,000,000 etc
@@ -588,7 +589,8 @@ Translator *SelectTranslator(const char *name)
tr->langopts.param[LOPT_IT_DOUBLING] = 1;
tr->langopts.param[LOPT_COMBINE_WORDS] = 99; // combine some prepositions with the following word
tr->langopts.numbers = NUM_DECIMAL_COMMA | NUM_ALLOW_SPACE | NUM_DFRACTION_5 | NUM_ROMAN | NUM_ROMAN_ORDINAL | NUM_ORDINAL_DOT | NUM_OMIT_1_HUNDRED;
tr->langopts.numbers = NUM_DECIMAL_COMMA | NUM_ALLOW_SPACE | NUM_DFRACTION_5 | NUM_ROMAN | NUM_ROMAN_ORDINAL | NUM_ROMAN_CAPITALS | NUM_ORDINAL_DOT | NUM_OMIT_1_HUNDRED;
tr->langopts.min_roman = 1;
SetLetterVowel(tr,'y');
tr->langopts.spelling_stress = 1;
SetLengthMods(tr,3); // all equal
+1 -1
View File
@@ -740,7 +740,7 @@ if((wmark > 0) && (wmark < 8))
if((tr->langopts.numbers & NUM_ROMAN) || ((tr->langopts.numbers & NUM_ROMAN_UC) && (wflags & FLAG_ALL_UPPER)))
{
if((found = TranslateRoman(tr, word1, phonemes)) != 0)
if((found = TranslateRoman(tr, word1, phonemes, wtab)) != 0)
dictionary_flags[0] |= FLAG_ABBREV; // prevent emphasis if capitals
}
}
+4 -1
View File
@@ -352,6 +352,7 @@ typedef struct {
#define NUM_ROMAN_AFTER 0x200000
#define NUM_VIGESIMAL 0x400000
#define NUM_ROMAN_ORDINAL 0x800000
#define NUM_ROMAN_CAPITALS 0x1000000
// bits0-1=which numbers routine to use.
// bit2= thousands separator must be space
@@ -374,6 +375,7 @@ typedef struct {
// bit21= say "roman" after the number, not before
// bit22= vigesimal number, if tens are not found
// bit23=Roman numbers are ordinal numbers
// bit24=Roman numbers must be capital letters
int numbers;
// bits 1-4 use variant form of numbers before thousands,millions,etc.
@@ -386,6 +388,7 @@ typedef struct {
#define BREAK_THOUSANDS 0x49249248
int break_numbers; // which digits to break the number into thousands, millions, etc (Hindi has 100,000 not 1,000,000)
int max_roman;
int min_roman;
int thousands_sep;
int decimal_sep;
@@ -570,7 +573,7 @@ void DeleteTranslator(Translator *tr);
int Lookup(Translator *tr, const char *word, char *ph_out);
int TranslateNumber(Translator *tr, char *word1, char *ph_out, unsigned int *flags, WORD_TAB *wtab);
int TranslateRoman(Translator *tr, char *word, char *ph_out);
int TranslateRoman(Translator *tr, char *word, char *ph_out, WORD_TAB *wtab);
void ChangeWordStress(Translator *tr, char *word, int new_stress);
void SetSpellingStress(Translator *tr, char *phonemes, int control, int n_chars);