Browse Source

Use the default uncrustify config (with indentation changes) to reformat the code.

master
Reece H. Dunn 9 years ago
parent
commit
36be9ac13f
40 changed files with 5696 additions and 5583 deletions
  1. 101
    100
      src/espeak-ng.c
  2. 243
    236
      src/libespeak-ng/compiledata.c
  3. 38
    39
      src/libespeak-ng/compiledict.c
  4. 1
    1
      src/libespeak-ng/compilembrola.c
  5. 31
    31
      src/libespeak-ng/debug.c
  6. 150
    151
      src/libespeak-ng/dictionary.c
  7. 524
    524
      src/libespeak-ng/espeak_command.c
  8. 65
    65
      src/libespeak-ng/espeak_command.h
  9. 73
    74
      src/libespeak-ng/event.c
  10. 14
    14
      src/libespeak-ng/event.h
  11. 329
    330
      src/libespeak-ng/fifo.c
  12. 10
    10
      src/libespeak-ng/fifo.h
  13. 214
    202
      src/libespeak-ng/intonation.c
  14. 174
    173
      src/libespeak-ng/klatt.c
  15. 34
    34
      src/libespeak-ng/klatt.h
  16. 13
    13
      src/libespeak-ng/mbrowrap.c
  17. 2
    1
      src/libespeak-ng/mbrowrap.h
  18. 80
    78
      src/libespeak-ng/numbers.c
  19. 8
    8
      src/libespeak-ng/phoneme.h
  20. 10
    10
      src/libespeak-ng/phonemelist.c
  21. 213
    193
      src/libespeak-ng/readclause.c
  22. 108
    106
      src/libespeak-ng/setlengths.c
  23. 257
    257
      src/libespeak-ng/sintab.h
  24. 65
    64
      src/libespeak-ng/speak_lib.c
  25. 25
    25
      src/libespeak-ng/spect.c
  26. 20
    20
      src/libespeak-ng/spect.h
  27. 3
    3
      src/libespeak-ng/speech.h
  28. 26
    26
      src/libespeak-ng/synth_mbrola.c
  29. 75
    75
      src/libespeak-ng/synthdata.c
  30. 67
    66
      src/libespeak-ng/synthesize.c
  31. 40
    40
      src/libespeak-ng/synthesize.h
  32. 1072
    1066
      src/libespeak-ng/tr_languages.c
  33. 39
    39
      src/libespeak-ng/translate.c
  34. 76
    76
      src/libespeak-ng/translate.h
  35. 50
    50
      src/libespeak-ng/voices.c
  36. 439
    420
      src/libespeak-ng/wave.c
  37. 528
    510
      src/libespeak-ng/wave_pulse.c
  38. 205
    186
      src/libespeak-ng/wave_sada.c
  39. 171
    165
      src/libespeak-ng/wavegen.c
  40. 103
    102
      src/speak-ng.c

+ 101
- 100
src/espeak-ng.c View File





static const char *help_text = static const char *help_text =
"\nespeak-ng [options] [\"<words>\"]\n\n"
"-f <text file> Text file to speak\n"
"--stdin Read text input from stdin instead of a file\n\n"
"If neither -f nor --stdin, then <words> are spoken, or if none then text\n"
"is spoken from stdin, each line separately.\n\n"
"-a <integer>\n"
"\t Amplitude, 0 to 200, default is 100\n"
"-g <integer>\n"
"\t Word gap. Pause between words, units of 10mS at the default speed\n"
"-k <integer>\n"
"\t Indicate capital letters with: 1=sound, 2=the word \"capitals\",\n"
"\t higher values indicate a pitch increase (try -k20).\n"
"-l <integer>\n"
"\t Line length. If not zero (which is the default), consider\n"
"\t lines less than this length as end-of-clause\n"
"-p <integer>\n"
"\t Pitch adjustment, 0 to 99, default is 50\n"
"-s <integer>\n"
"\t Speed in approximate words per minute. The default is 175\n"
"-v <voice name>\n"
"\t Use voice file of this name from espeak-data/voices\n"
"-w <wave file name>\n"
"\t Write speech to this WAV file, rather than speaking it directly\n"
"-b\t Input text encoding, 1=UTF8, 2=8 bit, 4=16 bit \n"
"-m\t Interpret SSML markup, and ignore other < > tags\n"
"-q\t Quiet, don't produce any speech (may be useful with -x)\n"
"-x\t Write phoneme mnemonics to stdout\n"
"-X\t Write phonemes mnemonics and translation trace to stdout\n"
"-z\t No final sentence pause at the end of the text\n"
"--compile=<voice name>\n"
"\t Compile pronunciation rules and dictionary from the current\n"
"\t directory. <voice name> specifies the language\n"
"--compile-mbrola=<voice name>\n"
"\t Compile an MBROLA voice\n"
"--compile-intonations\n"
"\t Compile the intonation data\n"
"--compile-phonemes\n"
"\t Compile the phoneme data\n"
"--ipa Write phonemes to stdout using International Phonetic Alphabet\n"
"--path=\"<path>\"\n"
"\t Specifies the directory containing the espeak-data directory\n"
"--pho Write mbrola phoneme data (.pho) to stdout or to the file in --phonout\n"
"--phonout=\"<filename>\"\n"
"\t Write phoneme output from -x -X --ipa and --pho to this file\n"
"--punct=\"<characters>\"\n"
"\t Speak the names of punctuation characters during speaking. If\n"
"\t =<characters> is omitted, all punctuation is spoken.\n"
"--sep=<character>\n"
"\t Separate phonemes (from -x --ipa) with <character>.\n"
"\t Default is space, z means ZWJN character.\n"
"--split=<minutes>\n"
"\t Starts a new WAV file every <minutes>. Used with -w\n"
"--stdout Write speech output to stdout\n"
"--tie=<character>\n"
"\t Use a tie character within multi-letter phoneme names.\n"
"\t Default is U+361, z means ZWJ character.\n"
"--version Shows version number and date, and location of espeak-data\n"
"--voices=<language>\n"
"\t List the available voices for the specified language.\n"
"\t If <language> is omitted, then list all voices.\n";
"\nespeak-ng [options] [\"<words>\"]\n\n"
"-f <text file> Text file to speak\n"
"--stdin Read text input from stdin instead of a file\n\n"
"If neither -f nor --stdin, then <words> are spoken, or if none then text\n"
"is spoken from stdin, each line separately.\n\n"
"-a <integer>\n"
"\t Amplitude, 0 to 200, default is 100\n"
"-g <integer>\n"
"\t Word gap. Pause between words, units of 10mS at the default speed\n"
"-k <integer>\n"
"\t Indicate capital letters with: 1=sound, 2=the word \"capitals\",\n"
"\t higher values indicate a pitch increase (try -k20).\n"
"-l <integer>\n"
"\t Line length. If not zero (which is the default), consider\n"
"\t lines less than this length as end-of-clause\n"
"-p <integer>\n"
"\t Pitch adjustment, 0 to 99, default is 50\n"
"-s <integer>\n"
"\t Speed in approximate words per minute. The default is 175\n"
"-v <voice name>\n"
"\t Use voice file of this name from espeak-data/voices\n"
"-w <wave file name>\n"
"\t Write speech to this WAV file, rather than speaking it directly\n"
"-b\t Input text encoding, 1=UTF8, 2=8 bit, 4=16 bit \n"
"-m\t Interpret SSML markup, and ignore other < > tags\n"
"-q\t Quiet, don't produce any speech (may be useful with -x)\n"
"-x\t Write phoneme mnemonics to stdout\n"
"-X\t Write phonemes mnemonics and translation trace to stdout\n"
"-z\t No final sentence pause at the end of the text\n"
"--compile=<voice name>\n"
"\t Compile pronunciation rules and dictionary from the current\n"
"\t directory. <voice name> specifies the language\n"
"--compile-mbrola=<voice name>\n"
"\t Compile an MBROLA voice\n"
"--compile-intonations\n"
"\t Compile the intonation data\n"
"--compile-phonemes\n"
"\t Compile the phoneme data\n"
"--ipa Write phonemes to stdout using International Phonetic Alphabet\n"
"--path=\"<path>\"\n"
"\t Specifies the directory containing the espeak-data directory\n"
"--pho Write mbrola phoneme data (.pho) to stdout or to the file in --phonout\n"
"--phonout=\"<filename>\"\n"
"\t Write phoneme output from -x -X --ipa and --pho to this file\n"
"--punct=\"<characters>\"\n"
"\t Speak the names of punctuation characters during speaking. If\n"
"\t =<characters> is omitted, all punctuation is spoken.\n"
"--sep=<character>\n"
"\t Separate phonemes (from -x --ipa) with <character>.\n"
"\t Default is space, z means ZWJN character.\n"
"--split=<minutes>\n"
"\t Starts a new WAV file every <minutes>. Used with -w\n"
"--stdout Write speech output to stdout\n"
"--tie=<character>\n"
"\t Use a tie character within multi-letter phoneme names.\n"
"\t Default is U+361, z means ZWJ character.\n"
"--version Shows version number and date, and location of espeak-data\n"
"--voices=<language>\n"
"\t List the available voices for the specified language.\n"
"\t If <language> is omitted, then list all voices.\n";






break; break;
} }
fprintf(f_out,"%2d %-12s%s%c %-20s %-13s ", fprintf(f_out,"%2d %-12s%s%c %-20s %-13s ",
p[0],lang_name,age_buf,genders[v->gender],buf,v->identifier);
p[0],lang_name,age_buf,genders[v->gender],buf,v->identifier);
} }
else else
{ {
static unsigned char wave_hdr[44] = { static unsigned char wave_hdr[44] = {
'R','I','F','F',0x24,0xf0,0xff,0x7f,'W','A','V','E','f','m','t',' ', 'R','I','F','F',0x24,0xf0,0xff,0x7f,'W','A','V','E','f','m','t',' ',
0x10,0,0,0,1,0,1,0, 9,0x3d,0,0,0x12,0x7a,0,0, 0x10,0,0,0,1,0,1,0, 9,0x3d,0,0,0x12,0x7a,0,0,
2,0,0x10,0,'d','a','t','a', 0x00,0xf0,0xff,0x7f};
2,0,0x10,0,'d','a','t','a', 0x00,0xf0,0xff,0x7f
};


if(path == NULL) if(path == NULL)
return(2); return(2);
else else
f_wavfile = fopen(path,"wb"); f_wavfile = fopen(path,"wb");
} }
if(f_wavfile == NULL) if(f_wavfile == NULL)
{ {
fprintf(stderr,"Can't write to: '%s'\n",path); fprintf(stderr,"Can't write to: '%s'\n",path);




#ifdef NEED_GETOPT #ifdef NEED_GETOPT
struct option {
char *name;
int has_arg;
int *flag;
int val;
};
int optind;
static int optional_argument;
static const char *arg_opts = "abfgklpsvw"; // which options have arguments
static char *opt_string="";
struct option {
char *name;
int has_arg;
int *flag;
int val;
};
int optind;
static int optional_argument;
static const char *arg_opts = "abfgklpsvw"; // which options have arguments
static char *opt_string="";
#define no_argument 0 #define no_argument 0
#define required_argument 1 #define required_argument 1
#define optional_argument 2 #define optional_argument 2
int main (int argc, char **argv) int main (int argc, char **argv)
{ {
static struct option long_options[] = static struct option long_options[] =
{
{
{"help", no_argument, 0, 'h'}, {"help", no_argument, 0, 'h'},
{"stdin", no_argument, 0, 0x100}, {"stdin", no_argument, 0, 0x100},
{"compile-debug", optional_argument, 0, 0x101}, {"compile-debug", optional_argument, 0, 0x101},
{"compile-intonations", no_argument, 0, 0x10f}, {"compile-intonations", no_argument, 0, 0x10f},
{"compile-phonemes", no_argument, 0, 0x110}, {"compile-phonemes", no_argument, 0, 0x110},
{0, 0, 0, 0} {0, 0, 0, 0}
};
};


static const char* err_load = "Failed to read "; static const char* err_load = "Failed to read ";


break; // -- means don't interpret further - as commands break; // -- means don't interpret further - as commands


opt_string=""; opt_string="";
for(ix=0; ;ix++)
for(ix=0;; ix++)
{ {
if(long_options[ix].name == 0) if(long_options[ix].name == 0)
break; break;
while(true) while(true)
{ {
c = getopt_long (argc, argv, "a:b:f:g:hk:l:mp:qs:v:w:xXz", c = getopt_long (argc, argv, "a:b:f:g:hk:l:mp:qs:v:w:xXz",
long_options, &option_index);
long_options, &option_index);


/* Detect the end of the options. */ /* Detect the end of the options. */
if (c == -1) if (c == -1)
synth_flags &= ~espeakENDPAUSE; synth_flags &= ~espeakENDPAUSE;
break; break;


case 0x100: // --stdin
case 0x100: // --stdin
flag_stdin = 1; flag_stdin = 1;
break; break;


case 0x105: // --stdout
case 0x105: // --stdout
option_waveout = 1; option_waveout = 1;
strcpy(wavefile,"stdout"); strcpy(wavefile,"stdout");
break; break;


case 0x101: // --compile-debug case 0x101: // --compile-debug
case 0x102: // --compile
case 0x102: // --compile
strncpy0(voicename,optarg2,sizeof(voicename)); strncpy0(voicename,optarg2,sizeof(voicename));
flag_compile = c; flag_compile = c;
quiet = 1; quiet = 1;
break; break;


case 0x103: // --punct
case 0x103: // --punct
option_punctuation = 1; option_punctuation = 1;
if(optarg2 != NULL) if(optarg2 != NULL)
{ {
// deprecated and obsolete // deprecated and obsolete
switch(atoi(optarg2)) switch(atoi(optarg2))
{ {
case 1:
phonemes_separator = '_';
break;
case 2:
phonemes_separator = 0x0361;
phoneme_options |= espeakPHONEMES_TIE;
break;
case 3:
phonemes_separator = 0x200d; // ZWJ
phoneme_options |= espeakPHONEMES_TIE;
break;
case 1:
phonemes_separator = '_';
break;
case 2:
phonemes_separator = 0x0361;
phoneme_options |= espeakPHONEMES_TIE;
break;
case 3:
phonemes_separator = 0x200d; // ZWJ
phoneme_options |= espeakPHONEMES_TIE;
break;
} }
} }
break; break;


case 0x10b: // --version case 0x10b: // --version
PrintVersion(); PrintVersion();
exit(0); exit(0);
case 0x10c: // --sep case 0x10c: // --sep
phoneme_options |= espeakPHONEMES_SHOW; phoneme_options |= espeakPHONEMES_SHOW;
if(optarg2 == 0) if(optarg2 == 0)
phonemes_separator = ' '; phonemes_separator = ' ';
else else
utf8_in(&phonemes_separator, optarg2); utf8_in(&phonemes_separator, optarg2);
if(phonemes_separator == 'z')
phonemes_separator = 0x200c; // ZWNJ
if(phonemes_separator == 'z')
phonemes_separator = 0x200c; // ZWNJ
break; break;


case 0x10d: // --tie case 0x10d: // --tie
phonemes_separator = 0x0361; // default: combining-double-inverted-breve phonemes_separator = 0x0361; // default: combining-double-inverted-breve
else else
utf8_in(&phonemes_separator, optarg2); utf8_in(&phonemes_separator, optarg2);
if(phonemes_separator == 'z')
phonemes_separator = 0x200d; // ZWJ
if(phonemes_separator == 'z')
phonemes_separator = 0x200d; // ZWJ
break; break;


case 0x10e: // --compile-mbrola case 0x10e: // --compile-mbrola
// play the sound output // play the sound output
samplerate = espeak_Initialize(AUDIO_OUTPUT_PLAYBACK,0,data_path,0); samplerate = espeak_Initialize(AUDIO_OUTPUT_PLAYBACK,0,data_path,0);
} }


if(voicename[0] == 0) if(voicename[0] == 0)
strcpy(voicename,"default"); strcpy(voicename,"default");
espeak_SetParameter(espeakLINELENGTH,option_linelength,0); espeak_SetParameter(espeakLINELENGTH,option_linelength,0);
if(option_punctuation == 2) if(option_punctuation == 2)
espeak_SetPunctuationList(option_punctlist); espeak_SetPunctuationList(option_punctlist);


espeak_SetPhonemeTrace(phoneme_options | (phonemes_separator << 8), f_phonemes_out); espeak_SetPhonemeTrace(phoneme_options | (phonemes_separator << 8), f_phonemes_out);



+ 243
- 236
src/libespeak-ng/compiledata.c View File

#endif #endif


typedef struct { typedef struct {
unsigned int value;
char *name;
unsigned int value;
char *name;
} NAMETAB; } NAMETAB;


NAMETAB *manifest = NULL; NAMETAB *manifest = NULL;
{"flag3", tPHONEME_FLAG, phFLAG3}, {"flag3", tPHONEME_FLAG, phFLAG3},


// voiced / unvoiced // voiced / unvoiced
{"vcd", tPHONEME_FLAG, phVOICED},
{"vls", tPHONEME_FLAG, phFORTIS},
{"vcd", tPHONEME_FLAG, phVOICED},
{"vls", tPHONEME_FLAG, phFORTIS},


// place of articulation, set bits 16-19 of phflags // place of articulation, set bits 16-19 of phflags
{"blb", tPLACE, 1},
{"lbd", tPLACE, 2},
{"dnt", tPLACE, 3},
{"alv", tPLACE, 4},
{"rfx", tPLACE, 5},
{"pla", tPLACE, 6},
{"pal", tPLACE, 7},
{"vel", tPLACE, 8},
{"lbv", tPLACE, 9},
{"uvl", tPLACE, 10},
{"phr", tPLACE, 11},
{"glt", tPLACE, 12},
{"blb", tPLACE, 1},
{"lbd", tPLACE, 2},
{"dnt", tPLACE, 3},
{"alv", tPLACE, 4},
{"rfx", tPLACE, 5},
{"pla", tPLACE, 6},
{"pal", tPLACE, 7},
{"vel", tPLACE, 8},
{"lbv", tPLACE, 9},
{"uvl", tPLACE, 10},
{"phr", tPLACE, 11},
{"glt", tPLACE, 12},


// vowel transition attributes // vowel transition attributes
{"len=", tTRANSITION, 1},
{"rms=", tTRANSITION, 2},
{"f1=", tTRANSITION, 3},
{"len=", tTRANSITION, 1},
{"rms=", tTRANSITION, 2},
{"f1=", tTRANSITION, 3},
{"f2=", tTRANSITION, 4}, {"f2=", tTRANSITION, 4},
{"f3=", tTRANSITION, 5},
{"f3=", tTRANSITION, 5},
{"brk", tTRANSITION, 6}, {"brk", tTRANSITION, 6},
{"rate", tTRANSITION, 7}, {"rate", tTRANSITION, 7},
{"glstop", tTRANSITION, 8}, {"glstop", tTRANSITION, 8},




static keywtab_t *keyword_tabs[] = { static keywtab_t *keyword_tabs[] = {
keywords, k_conditions, k_properties, k_intonation };
keywords, k_conditions, k_properties, k_intonation
};




static PHONEME_TAB *phoneme_out; static PHONEME_TAB *phoneme_out;


#define N_PROCS 50 #define N_PROCS 50
int n_procs; int n_procs;
int proc_addr[N_PROCS];
int proc_addr[N_PROCS];
char proc_names[40][N_PROCS]; char proc_names[40][N_PROCS];


#define MAX_PROG_BUF 2000 #define MAX_PROG_BUF 2000


static void ReadPhondataManifest() static void ReadPhondataManifest()
{ {
// Read the phondata-manifest file
FILE *f;
int n_lines=0;
int ix;
char *p;
unsigned int value;
char buf[sizeof(path_home)+40];
char name[120];
// Read the phondata-manifest file
FILE *f;
int n_lines=0;
int ix;
char *p;
unsigned int value;
char buf[sizeof(path_home)+40];
char name[120];


sprintf(buf,"%s%c%s",path_home,PATHSEP,"phondata-manifest"); sprintf(buf,"%s%c%s",path_home,PATHSEP,"phondata-manifest");
if((f = fopen(buf, "r")) == NULL)
return;
while(fgets(buf, sizeof(buf), f) != NULL)
n_lines++;
rewind(f);
if(manifest != NULL)
{
for(ix=0; ix < n_manifest; ix++)
free(manifest[ix].name);
}
if((manifest = (NAMETAB *)realloc(manifest, n_lines * sizeof(NAMETAB))) == NULL)
{
fclose(f);
return;
}
n_manifest = 0;
while(fgets(buf, sizeof(buf), f) != NULL)
{
if(!isalpha(buf[0]))
continue;
if(sscanf(&buf[2], "%x %s", &value, name) == 2)
{
if((p = (char *)malloc(strlen(name)+1)) != NULL)
{
strcpy(p, name);
manifest[n_manifest].value = value;
manifest[n_manifest].name = p;
n_manifest++;
}
}
}
fclose(f);
if((f = fopen(buf, "r")) == NULL)
return;
while(fgets(buf, sizeof(buf), f) != NULL)
n_lines++;
rewind(f);
if(manifest != NULL)
{
for(ix=0; ix < n_manifest; ix++)
free(manifest[ix].name);
}
if((manifest = (NAMETAB *)realloc(manifest, n_lines * sizeof(NAMETAB))) == NULL)
{
fclose(f);
return;
}
n_manifest = 0;
while(fgets(buf, sizeof(buf), f) != NULL)
{
if(!isalpha(buf[0]))
continue;
if(sscanf(&buf[2], "%x %s", &value, name) == 2)
{
if((p = (char *)malloc(strlen(name)+1)) != NULL)
{
strcpy(p, name);
manifest[n_manifest].value = value;
manifest[n_manifest].name = p;
n_manifest++;
}
}
}
fclose(f);
} }


static const char *KeyToMnem(keywtab_t *ktab, int type, int value) static const char *KeyToMnem(keywtab_t *ktab, int type, int value)
"", "", "IF", "IF OR", "", "", "IF", "IF OR",
"", "", "", "", "", "", "", "",
"", "", "", "FMT", "", "", "", "FMT",
"WAV", "NextVowelStart", "PrevVowelEnd", "+wav" };
"WAV", "NextVowelStart", "PrevVowelEnd", "+wav"
};


static const char *nextPh_string[6] = { static const char *nextPh_string[6] = {
"prevPh", "thisPh", "nextPh", "next2Ph", "nextPhW", "**", "prevPh", "thisPh", "nextPh", "next2Ph", "nextPhW", "**",


static const char *instn_jumps[] = { static const char *instn_jumps[] = {
"JMP", "Invalid", "Invalid", "Invalid", "JMP", "Invalid", "Invalid", "Invalid",
"JMP false", "SwitchNextVowelType", "SwitchPrevVowelType", "Invalid"};
"JMP false", "SwitchNextVowelType", "SwitchPrevVowelType", "Invalid"
};


static char instn1_paramtype[] = { static char instn1_paramtype[] = {
0, 3, 3, 3, 3, 3, 3, 1, 0, 3, 3, 3, 3, 3, 3, 1,
1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
0, 0, 0, 0, 0, 0, 0, 0};
0, 0, 0, 0, 0, 0, 0, 0
};


return;
return;


if(compile_phoneme) if(compile_phoneme)
{ {


typedef struct { typedef struct {
FILE *file; FILE *file;
int linenum;
int linenum;
char fname[80]; char fname[80];
} STACK; } STACK;


typedef struct { typedef struct {
USHORT *p_then; USHORT *p_then;
USHORT *p_else; USHORT *p_else;
int returned;
int returned;
} IF_STACK; } IF_STACK;
IF_STACK if_stack[N_IF_STACK]; IF_STACK if_stack[N_IF_STACK];


int procedure_num; int procedure_num;
int prev_mnemonic; int prev_mnemonic;


if(f_report == NULL)
return;
if(f_report == NULL)
return;


// make a list of all the references and sort it // make a list of all the references and sort it
list = (REF_HASH_TAB **)malloc((count_references)* sizeof(REF_HASH_TAB *)); list = (REF_HASH_TAB **)malloc((count_references)* sizeof(REF_HASH_TAB *));
return; return;


fprintf(f_report,"\n%d phoneme tables\n",n_phoneme_tabs); fprintf(f_report,"\n%d phoneme tables\n",n_phoneme_tabs);
fprintf(f_report," new total\n");
fprintf(f_report," new total\n");
for(ix=0; ix<n_phoneme_tabs; ix++) for(ix=0; ix<n_phoneme_tabs; ix++)
{ {
fprintf(f_report,"%8s %3d %4d\n",phoneme_tab_list2[ix].name, phoneme_tab_list2[ix].n_phonemes, n_phcodes_list[ix]+1); fprintf(f_report,"%8s %3d %4d\n",phoneme_tab_list2[ix].name, phoneme_tab_list2[ix].n_phonemes, n_phcodes_list[ix]+1);
int ix=0; int ix=0;
int diff; int diff;


for(;;)
for(;; )
{ {
if((diff = (tolower(s1[ix]) - tolower(s2[ix]))) != 0) if((diff = (tolower(s1[ix]) - tolower(s2[ix]))) != 0)
return(diff); return(diff);
return(ix); return(ix);


strcpy(mnem1,WordToString(p1->mnemonic)); strcpy(mnem1,WordToString(p1->mnemonic));
return(strcasecmp(mnem1,WordToString(p2->mnemonic)));
return(strcasecmp(mnem1,WordToString(p2->mnemonic)));
} }




static unsigned int StringToWord(const char *string) static unsigned int StringToWord(const char *string)
{ {
// Pack 4 characters into a word // Pack 4 characters into a word
int ix;
int ix;
unsigned char c; unsigned char c;
unsigned int word; unsigned int word;


{"#i", phonVOWELTYPES+3}, {"#i", phonVOWELTYPES+3},
{"#o", phonVOWELTYPES+4}, {"#o", phonVOWELTYPES+4},
{"#u", phonVOWELTYPES+5}, {"#u", phonVOWELTYPES+5},
{NULL, 0} };
{NULL, 0}
};




static void ReservePhCodes() static void ReservePhCodes()
// control = 1 declare phoneme if not found // control = 1 declare phoneme if not found
// control = 2 start looking after control & stress phonemes // control = 2 start looking after control & stress phonemes


int ix;
int start;
int use;
int ix;
int start;
int use;
unsigned int word; unsigned int word;


if(strcmp(string,"NULL")==0) if(strcmp(string,"NULL")==0)


if(control==2) if(control==2)
start = 8; // don't look for control and stress phonemes (allows these characters to be start = 8; // don't look for control and stress phonemes (allows these characters to be
// used for other purposes)
// used for other purposes)


use = 0; use = 0;
for(ix=start; ix<n_phcodes; ix++) for(ix=start; ix<n_phcodes; ix++)


static int NextItem(int type) static int NextItem(int type)
{ {
int acc;
unsigned char c=0;
int acc;
unsigned char c=0;
unsigned char c2; unsigned char c2;
int ix;
int sign;
int ix;
int sign;
char *p; char *p;
keywtab_t *pk; keywtab_t *pk;


static int NextItemMax(int max) static int NextItemMax(int max)
{ {
// Get a number, but restrict value to max // Get a number, but restrict value to max
int value;
char msg[80];
value = NextItem(tNUMBER);
if(value > max)
{
sprintf(msg, "Value %d is greater than maximum %d", value, max);
error(msg, NULL);
value = max;
}
return(value);
int value;
char msg[80];
value = NextItem(tNUMBER);
if(value > max)
{
sprintf(msg, "Value %d is greater than maximum %d", value, max);
error(msg, NULL);
value = max;
}
return(value);
} }




rms = 16 / 2; rms = 16 / 2;
} }


for(;;)
for(;; )
{ {
key = NextItem(tKEYWORD); key = NextItem(tKEYWORD);
if(item_type != tTRANSITION) if(item_type != tTRANSITION)


if((sr1 != samplerate_native) || (sr2 != sr1*2)) if((sr1 != samplerate_native) || (sr2 != sr1*2))
{ {
int fd_temp;
char command[sizeof(path_home)+250];
int fd_temp;
char command[sizeof(path_home)+250];


failed = 0;
failed = 0;


#ifdef PLATFORM_POSIX #ifdef PLATFORM_POSIX
strcpy(fname_temp,"/tmp/espeakXXXXXX"); strcpy(fname_temp,"/tmp/espeakXXXXXX");
strcpy(fname_temp,tmpnam(NULL)); strcpy(fname_temp,tmpnam(NULL));
#endif #endif


fname2 = fname;
len = strlen(fname);
if(strcmp(&fname[len-4], ".wav") == 0)
{
strcpy(msg, fname);
msg[len-4] = 0;
fname2 = msg;
}
sprintf(command,"sox \"%s/../phsource/%s.wav\" -r %d -c1 -t wav %s\n",path_home,fname2,samplerate_native, fname_temp);
if(system(command) != 0)
{
failed = 1;
}
if(failed || (GetFileLength(fname_temp) <= 0))
{
if(resample_fails < 2)
error("Resample command failed: %s", command);
resample_fails++;
if(sr1 != samplerate_native)
{
sprintf(msg, "Can't resample (%d to %d): %s", sr1, samplerate_native, fname);
error("%s", msg);
}
else
{
error("WAV file is not mono: %s", fname);
}
remove(fname_temp);
return(0);
}
f = fopen(fname_temp,"rb");
if(f == NULL)
{
error("Can't read temp file: %s",fname_temp);
return(0);
}
if(f_report != NULL)
fprintf(f_report, "resampled %s\n", fname);
resample_count++;
resample_wav = 1;
fseek(f,40,SEEK_SET); // skip past the WAV header, up to before "data length"
fname2 = fname;
len = strlen(fname);
if(strcmp(&fname[len-4], ".wav") == 0)
{
strcpy(msg, fname);
msg[len-4] = 0;
fname2 = msg;
}
sprintf(command,"sox \"%s/../phsource/%s.wav\" -r %d -c1 -t wav %s\n",path_home,fname2,samplerate_native, fname_temp);
if(system(command) != 0)
{
failed = 1;
}
if(failed || (GetFileLength(fname_temp) <= 0))
{
if(resample_fails < 2)
error("Resample command failed: %s", command);
resample_fails++;
if(sr1 != samplerate_native)
{
sprintf(msg, "Can't resample (%d to %d): %s", sr1, samplerate_native, fname);
error("%s", msg);
}
else
{
error("WAV file is not mono: %s", fname);
}
remove(fname_temp);
return(0);
}
f = fopen(fname_temp,"rb");
if(f == NULL)
{
error("Can't read temp file: %s",fname_temp);
return(0);
}
if(f_report != NULL)
fprintf(f_report, "resampled %s\n", fname);
resample_count++;
resample_wav = 1;
fseek(f,40,SEEK_SET); // skip past the WAV header, up to before "data length"
} }


displ = ftell(f_phdata); displ = ftell(f_phdata);


if(feof(f)) break; if(feof(f)) break;


if(scale_factor <= MIN_FACTOR)
if(scale_factor <= MIN_FACTOR)
{ {
fputc(sample & 0xff,f_phdata); fputc(sample & 0xff,f_phdata);
fputc(sample >> 8,f_phdata); fputc(sample >> 8,f_phdata);
/* Generate a hash code from the specified string */ /* Generate a hash code from the specified string */
static int Hash8(const char *string) static int Hash8(const char *string)
{ {
int c;
int chars=0;
int hash=0;
while((c = *string++) != 0)
{
c = tolower(c) - 'a';
hash = hash * 8 + c;
hash = (hash & 0x1ff) ^ (hash >> 8); /* exclusive or */
int c;
int chars=0;
int hash=0;
while((c = *string++) != 0)
{
c = tolower(c) - 'a';
hash = hash * 8 + c;
hash = (hash & 0x1ff) ^ (hash >> 8); /* exclusive or */
chars++; chars++;
}
}


return((hash+chars) & 0xff);
return((hash+chars) & 0xff);
} }








/* /*
Condition
bits 14,15 1
bit 13 1 = AND, 0 = OR
bit 12 spare
bit 8-11
=0-3 p,t,n,n2 data=phoneme code
=4-7 p,t,n,n2 data=(bits5-7: phtype, place, property, special) (bits0-4: data)
=8 data = stress bitmap
=9 special tests
*/
Condition
bits 14,15 1
bit 13 1 = AND, 0 = OR
bit 12 spare
bit 8-11
=0-3 p,t,n,n2 data=phoneme code
=4-7 p,t,n,n2 data=(bits5-7: phtype, place, property, special) (bits0-4: data)
=8 data = stress bitmap
=9 special tests
*/


int CompileIf(int elif) int CompileIf(int elif)
{ {
// prevPh(), thisPh(), nextPh(), next2Ph() etc // prevPh(), thisPh(), nextPh(), next2Ph() etc
if(key >= 6) if(key >= 6)
{ {
// put the 'which' code in the next instruction
word2 = key;
key = 6;
// put the 'which' code in the next instruction
word2 = key;
key = 6;
} }
key = key << 8; key = key << 8;


count = 0; count = 0;
ix = 1; ix = 1;


for(p=item_string; *p != 0;)
for(p=item_string; *p != 0; )
{ {
p += utf8_in(&c, p);
if((c == '|') && (count > 0))
{
// '|' means don't allow a tie or joiner before this letter
flags |= (1 << (count -1));
}
else
p += utf8_in(&c, p);
if((c == '|') && (count > 0))
{
// '|' means don't allow a tie or joiner before this letter
flags |= (1 << (count -1));
}
else
if((c=='U') && (p[0]=='+')) if((c=='U') && (p[0]=='+'))
{ {
int j;
int j;
// U+9999 // U+9999
p++; p++;
memcpy(number_buf,p,4); // U+ should be followed by 4 hex digits memcpy(number_buf,p,4); // U+ should be followed by 4 hex digits
// move past the 4 hexdecimal digits // move past the 4 hexdecimal digits
for(j=0; j<4; j++) for(j=0; j<4; j++)
{ {
if(!isalnum(*p))
break;
p++;
if(!isalnum(*p))
break;
p++;
} }
ix += utf8_out(c, &ipa_buf[ix]); ix += utf8_out(c, &ipa_buf[ix]);
count++; count++;
} }
else else
{ {
ix += utf8_out(c, &ipa_buf[ix]);
ix += utf8_out(c, &ipa_buf[ix]);
count++; count++;
} }
} }
ipa_buf[0] = flags; ipa_buf[0] = flags;
ipa_buf[ix] = 0; ipa_buf[ix] = 0;


start = 1;
if(flags != 0)
start = 0; // only include the flags byte if bits are set
start = 1;
if(flags != 0)
start = 0; // only include the flags byte if bits are set
value = strlen(&ipa_buf[start]); // number of UTF-8 bytes value = strlen(&ipa_buf[start]); // number of UTF-8 bytes


*prog_out++ = (i_IPA_NAME << 8) + value; *prog_out++ = (i_IPA_NAME << 8) + value;


static void EndPhonemeTable() static void EndPhonemeTable()
{ {
int ix;
int ix;
int *pw; int *pw;
int length; int length;


if(phoneme_tab2[ix].type == phINVALID) if(phoneme_tab2[ix].type == phINVALID)
{ {
fprintf(f_errors,"%3d: Phoneme [%s] not declared, referenced at line %d\n",linenum, fprintf(f_errors,"%3d: Phoneme [%s] not declared, referenced at line %d\n",linenum,
WordToString(phoneme_tab2[ix].mnemonic),(int)(phoneme_tab2[ix].program));
WordToString(phoneme_tab2[ix].mnemonic),(int)(phoneme_tab2[ix].program));
error_count++; error_count++;
phoneme_tab2[ix].type = 0; // prevent the error message repeating phoneme_tab2[ix].type = 0; // prevent the error message repeating
} }


if(n_phoneme_tabs > 0) if(n_phoneme_tabs > 0)
{ {
NextItem(tSTRING); // name of base phoneme table
NextItem(tSTRING); // name of base phoneme table
for(ix=0; ix<n_phoneme_tabs; ix++) for(ix=0; ix<n_phoneme_tabs; ix++)
{ {
if(strcmp(item_string,phoneme_tab_list2[ix].name)==0) if(strcmp(item_string,phoneme_tab_list2[ix].name)==0)
count_frames = 0; count_frames = 0;
n_procs = 0; n_procs = 0;


for(;;)
for(;; )
{ {
if(feof(f_in)) if(feof(f_in))
{ {


switch(item) switch(item)
{ {
case kUTF8_BOM:
break; // ignore bytes 0xef 0xbb 0xbf
case kUTF8_BOM:
break; // ignore bytes 0xef 0xbb 0xbf


case kINCLUDE: case kINCLUDE:
NextItem(tSTRING); NextItem(tSTRING);


case kPHONEMETABLE: case kPHONEMETABLE:
EndPhonemeTable(); EndPhonemeTable();
NextItem(tSTRING); // name of the new phoneme table
NextItem(tSTRING); // name of the new phoneme table
StartPhonemeTable(item_string); StartPhonemeTable(item_string);
break; break;


sprintf(fname,"%s/../phsource",path_home); sprintf(fname,"%s/../phsource",path_home);


#ifdef MAKE_ENVELOPES #ifdef MAKE_ENVELOPES
make_envs();
make_envs();
#endif #endif


fprintf(log,"Compiling phoneme data: %s\n",fname); fprintf(log,"Compiling phoneme data: %s\n",fname);
f_phcontents = stderr; f_phcontents = stderr;


fprintf (f_phcontents, fprintf (f_phcontents,
"# This file lists the type of data that has been compiled into the\n"
"# phondata file\n"
"#\n"
"# The first character of a line indicates the type of data:\n"
"# S - A SPECT_SEQ structure\n"
"# W - A wavefile segment\n"
"# E - An envelope\n"
"# Q - Phoneme equivalence tables\n"
"#\n"
"# Address is the displacement within phondata of this item\n"
"#\n"
"# Address Data file\n"
"# ------- ---------\n");
"# This file lists the type of data that has been compiled into the\n"
"# phondata file\n"
"#\n"
"# The first character of a line indicates the type of data:\n"
"# S - A SPECT_SEQ structure\n"
"# W - A wavefile segment\n"
"# E - An envelope\n"
"# Q - Phoneme equivalence tables\n"
"#\n"
"# Address is the displacement within phondata of this item\n"
"#\n"
"# Address Data file\n"
"# ------- ---------\n");




fprintf(f_errors, "Source data path = '%s/../phsource'\n", path_home); fprintf(f_errors, "Source data path = '%s/../phsource'\n", path_home);
EndPhonemeTable(); EndPhonemeTable();
WritePhonemeTables(); WritePhonemeTables();


fprintf(f_errors,"\nRefs %d, Reused %d\n",count_references,duplicate_references);
fprintf(f_errors,"\nRefs %d, Reused %d\n",count_references,duplicate_references);
fclose(f_in); fclose(f_in);
fclose(f_phdata); fclose(f_phdata);
if(f_prog_log != NULL)
fclose(f_prog_log);
if(f_prog_log != NULL)
fclose(f_prog_log);
fclose(f_phindex); fclose(f_phindex);
fclose(f_phtab); fclose(f_phtab);
fclose(f_phcontents); fclose(f_phcontents);


if(resample_count > 0) if(resample_count > 0)
{ {
fprintf(f_errors, "\n%d WAV files resampled to %d Hz\n", resample_count, samplerate_native);
fprintf(log,"Compiled phonemes: %d errors, %d files resampled to %d Hz.\n",error_count, resample_count, samplerate_native);
fprintf(f_errors, "\n%d WAV files resampled to %d Hz\n", resample_count, samplerate_native);
fprintf(log,"Compiled phonemes: %d errors, %d files resampled to %d Hz.\n",error_count, resample_count, samplerate_native);
} }
else else
{ {
fprintf(log,"Compiled phonemes: %d errors.\n",error_count);
fprintf(log,"Compiled phonemes: %d errors.\n",error_count);
} }


if(f_errors != stderr) if(f_errors != stderr)
fclose(f_errors);
fclose(f_errors);


ReadPhondataManifest();
return ENS_OK;
ReadPhondataManifest();
return ENS_OK;
} }




static const char *preset_tune_names[] = { static const char *preset_tune_names[] = {
"s1", "c1", "q1", "e1", NULL};
"s1", "c1", "q1", "e1", NULL
};


static const TUNE default_tune = { static const TUNE default_tune = {
{0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0},
{0, 40, 24, 8, 0, 0, 0, 0},
46, 57, PITCHfall, 16, 0, 0,
255, 78, 50, 255,
3, 5,
{-7,-7,-7}, {-7,-7,-7},
PITCHfall, 64, 8,
PITCHfall, 70, 18, 24, 12,
PITCHfall, 70, 18, 24, 12, 0,
{0,0,0,0,0,0,0,0}, 0
{0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0},
{0, 40, 24, 8, 0, 0, 0, 0},
46, 57, PITCHfall, 16, 0, 0,
255, 78, 50, 255,
3, 5,
{-7,-7,-7}, {-7,-7,-7},
PITCHfall, 64, 8,
PITCHfall, 70, 18, 24, 12,
PITCHfall, 70, 18, 24, 12, 0,
{0,0,0,0,0,0,0,0}, 0
}; };


#define N_TUNE_NAMES 100 #define N_TUNE_NAMES 100
{"fall2", 14}, {"fall2", 14},
{"rise2", 16}, {"rise2", 16},
{"rise-fall-rise", 18}, {"rise-fall-rise", 18},
{NULL, -1} };
{NULL, -1}
};


int LookupEnvelopeName(const char *name) int LookupEnvelopeName(const char *name)
{ {


espeak_ng_STATUS espeak_ng_CompilePhonemeData(long rate, FILE *log) espeak_ng_STATUS espeak_ng_CompilePhonemeData(long rate, FILE *log)
{ {
WavegenInit(rate, 0);
WavegenInit(rate, 0);
WavegenSetVoice(voice); WavegenSetVoice(voice);
return CompilePhonemeData2("phonemes", log); return CompilePhonemeData2("phonemes", log);
} }

+ 38
- 39
src/libespeak-ng/compiledict.c View File

unsigned char c; unsigned char c;
char *p; char *p;
char *p_end; char *p_end;
int ix;
int match_type;
int finished=0;
int value;
int linenum=0;
int flags;
int suffix_char;
int condition_num=0;
int at_start = 0;
int ix;
int match_type;
int finished=0;
int value;
int linenum=0;
int flags;
int suffix_char;
int condition_num=0;
int at_start = 0;
const char *name; const char *name;
char buf[200]; char buf[200];
char buf_pre[200]; char buf_pre[200];
static char output[80]; static char output[80];


static char symbols[] = static char symbols[] =
{' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
'&','%','+','#','S','D','Z','A','L','!',' ','@','?','J','N','K','V','?','T','X','?','W'
};
{' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
'&','%','+','#','S','D','Z','A','L','!',' ','@','?','J','N','K','V','?','T','X','?','W'};


static char symbols_lg[] = {'A','B','C','H','F','G','Y'}; static char symbols_lg[] = {'A','B','C','H','F','G','Y'};


static int compile_line(char *linebuf, char *dict_line, int *hash) static int compile_line(char *linebuf, char *dict_line, int *hash)
{ {
// Compile a line in the language_list file // Compile a line in the language_list file
unsigned char c;
unsigned char c;
char *p; char *p;
char *word; char *word;
char *phonetic; char *phonetic;
unsigned int ix;
int step;
unsigned int n_flag_codes = 0;
unsigned int ix;
int step;
unsigned int n_flag_codes = 0;
int flagnum; int flagnum;
int flag_offset;
int length;
int multiple_words = 0;
int multiple_numeric_hyphen = 0;
int flag_offset;
int length;
int multiple_words = 0;
int multiple_numeric_hyphen = 0;
char *multiple_string = NULL; char *multiple_string = NULL;
char *multiple_string_end = NULL; char *multiple_string_end = NULL;


int len_word; int len_word;
int len_phonetic; int len_phonetic;
int text_not_phonemes; // this word specifies replacement text, not phonemes int text_not_phonemes; // this word specifies replacement text, not phonemes
unsigned int wc;
unsigned int wc;
int all_upper_case; int all_upper_case;


char *mnemptr; char *mnemptr;


all_upper_case = 1; all_upper_case = 1;
p = word; p = word;
for(p=word;;)
for(p=word;; )
{ {
// this assumes that the lower case char is the same length as the upper case char // this assumes that the lower case char is the same length as the upper case char
// OK, except for Turkish "I", but use towlower() rather than towlower2() // OK, except for Turkish "I", but use towlower() rather than towlower2()


static int compile_dictlist_file(const char *path, const char* filename) static int compile_dictlist_file(const char *path, const char* filename)
{ {
int length;
int hash;
int length;
int hash;
char *p; char *p;
int count=0;
int count=0;
FILE *f_in; FILE *f_in;
char buf[200]; char buf[200];
char fname[sizeof(path_home)+45]; char fname[sizeof(path_home)+45];
static char group_name[LEN_GROUP_NAME+1]; static char group_name[LEN_GROUP_NAME+1];
static int group3_ix; static int group3_ix;


#define N_RULES 3000 // max rules for each group
#define N_RULES 3000 // max rules for each group






int len; int len;
char c; char c;
int c2, c3; int c2, c3;
int sxflags;
int value;
int literal;
int hexdigit_input = 0;
int sxflags;
int value;
int literal;
int hexdigit_input = 0;
int state = *state_out; int state = *state_out;
MNEM_TAB *mr; MNEM_TAB *mr;


} }
sxflags = 0x808000; // to ensure non-zero bytes sxflags = 0x808000; // to ensure non-zero bytes


for(p=string,ix=0;;)
for(p=string,ix=0;; )
{ {
literal = 0; literal = 0;
c = *p++; c = *p++;
case 'i': case 'i':
sxflags |= SUFX_I; sxflags |= SUFX_I;
break; break;
case 'p': // obsolete, replaced by 'P' above
case 'p': // obsolete, replaced by 'P' above
sxflags |= SUFX_P; sxflags |= SUFX_P;
break; break;
case 'v': case 'v':


switch(c = input[ix]) switch(c = input[ix])
{ {
case ')': // end of prefix section
case ')': // end of prefix section
*p = 0; *p = 0;
state = 1; state = 1;
copy_rule_string(buf,&state); copy_rule_string(buf,&state);
p = buf; p = buf;
break; break;


case '(': // start of suffix section
case '(': // start of suffix section
*p = 0; *p = 0;
state = 2; state = 2;
copy_rule_string(buf,&state); copy_rule_string(buf,&state);
} }
break; break;


case '\n': // end of line
case '\n': // end of line
case '\r': case '\r':
case 0: // end of line
case 0: // end of line
*p = 0; *p = 0;
copy_rule_string(buf,&state); copy_rule_string(buf,&state);
finish=1; finish=1;
break; break;


case '\t': // end of section section
case '\t': // end of section section
case ' ': case ' ':
*p = 0; *p = 0;
copy_rule_string(buf,&state); copy_rule_string(buf,&state);
if((common[0] != 0) && (strcmp(p,common)==0)) if((common[0] != 0) && (strcmp(p,common)==0))
{ {
fwrite(p2,len2,1,f_out); fwrite(p2,len2,1,f_out);
fputc(0,f_out); // no phoneme string, it's the same as previous rule
fputc(0,f_out); // no phoneme string, it's the same as previous rule
} }
else else
{ {
if((f_temp = fopen_log(fname_temp,"wb")) == NULL) if((f_temp = fopen_log(fname_temp,"wb")) == NULL)
return(1); return(1);


for(;;)
for(;; )
{ {
linenum++; linenum++;
buf = fgets(buf1,sizeof(buf1),f_in); buf = fgets(buf1,sizeof(buf1),f_in);

+ 1
- 1
src/libespeak-ng/compilembrola.c View File

static unsigned int StringToWord(const char *string) static unsigned int StringToWord(const char *string)
{ {
// Pack 4 characters into a word // Pack 4 characters into a word
int ix;
int ix;
unsigned char c; unsigned char c;
unsigned int word; unsigned int word;



+ 31
- 31
src/libespeak-ng/debug.c View File



void debug_enter(const char* text) void debug_enter(const char* text)
{ {
struct timeval tv;
struct timeval tv;


gettimeofday(&tv, NULL);
gettimeofday(&tv, NULL);


if (!fd_log)
{
debug_init();
}
if (!fd_log)
{
debug_init();
}


if (fd_log)
{
fprintf(fd_log, "%03d.%03dms > ENTER %s\n",(int)(tv.tv_sec%1000), (int)(tv.tv_usec/1000), text);
}
if (fd_log)
{
fprintf(fd_log, "%03d.%03dms > ENTER %s\n",(int)(tv.tv_sec%1000), (int)(tv.tv_usec/1000), text);
}
} }




void debug_show(const char *format, ...) void debug_show(const char *format, ...)
{ {
va_list args;
va_start(args, format);
if (!fd_log)
{
debug_init();
}
if (fd_log)
{
vfprintf(fd_log, format, args);
}
va_end(args);
va_list args;
va_start(args, format);
if (!fd_log)
{
debug_init();
}
if (fd_log)
{
vfprintf(fd_log, format, args);
}
va_end(args);
} }


void debug_time(const char* text) void debug_time(const char* text)
{ {
struct timeval tv;
struct timeval tv;


gettimeofday(&tv, NULL);
gettimeofday(&tv, NULL);


if (!fd_log)
{
debug_init();
}
if (fd_log)
{
fprintf(fd_log, "%03d.%03dms > %s\n",(int)(tv.tv_sec%1000), (int)(tv.tv_usec/1000), text);
}
if (!fd_log)
{
debug_init();
}
if (fd_log)
{
fprintf(fd_log, "%03d.%03dms > %s\n",(int)(tv.tv_sec%1000), (int)(tv.tv_usec/1000), text);
}
} }


#endif #endif

+ 150
- 151
src/libespeak-ng/dictionary.c View File

'a','a','a','a','a','a','a','c','e','e','e','e','i','i','i','i', // 0c0 'a','a','a','a','a','a','a','c','e','e','e','e','i','i','i','i', // 0c0
'd','n','o','o','o','o','o', 0, 'o','u','u','u','u','y','t','s', // 0d0 'd','n','o','o','o','o','o', 0, 'o','u','u','u','u','y','t','s', // 0d0
'a','a','a','a','a','a','a','c','e','e','e','e','i','i','i','i', // 0e0 'a','a','a','a','a','a','a','c','e','e','e','e','i','i','i','i', // 0e0
'd','n','o','o','o','o','o', 0 ,'o','u','u','u','u','y','t','y', // 0f0
'd','n','o','o','o','o','o', 0,'o','u','u','u','u','y','t','y', // 0f0


'a','a','a','a','a','a','c','c','c','c','c','c','c','c','d','d', // 100 'a','a','a','a','a','a','c','c','c','c','c','c','c','c','d','d', // 100
'd','d','e','e','e','e','e','e','e','e','e','e','g','g','g','g', // 110 'd','d','e','e','e','e','e','e','e','e','e','e','g','g','g','g', // 110
// for single-letters and two-letter combinations // for single-letters and two-letter combinations




int ix;
int ix;
char *p; char *p;
char *p_name; char *p_name;
unsigned int *pw; unsigned int *pw;
} }


if((Reverse4Bytes(pw[0]) != N_HASH_DICT) || if((Reverse4Bytes(pw[0]) != N_HASH_DICT) ||
(length <= 0) || (length > 0x8000000))
(length <= 0) || (length > 0x8000000))
{ {
fprintf(stderr,"Bad data: '%s' (%x length=%x)\n",fname,Reverse4Bytes(pw[0]),length); fprintf(stderr,"Bad data: '%s' (%x length=%x)\n",fname,Reverse4Bytes(pw[0]),length);
return(2); return(2);




/* Generate a hash code from the specified string /* Generate a hash code from the specified string
This is used to access the dictionary_2 word-lookup dictionary
*/
This is used to access the dictionary_2 word-lookup dictionary
*/
int HashDictionary(const char *string) int HashDictionary(const char *string)
{ {
int c;
int chars=0;
int hash=0;
int c;
int chars=0;
int hash=0;


while((c = (*string++ & 0xff)) != 0) while((c = (*string++ & 0xff)) != 0)
{ {
Returns advanced 'p' Returns advanced 'p'
outptr contains encoded phonemes, unrecognized phoneme stops the encoding outptr contains encoded phonemes, unrecognized phoneme stops the encoding
bad_phoneme must point to char array of length 2 of more bad_phoneme must point to char array of length 2 of more
*/
*/
const char *EncodePhonemes(const char *p, char *outptr, int *bad_phoneme) const char *EncodePhonemes(const char *p, char *outptr, int *bad_phoneme)
{ {
int ix; int ix;
unsigned char c;
int count; /* num. of matching characters */
int max; /* highest num. of matching found so far */
int max_ph; /* corresponding phoneme with highest matching */
int consumed;
unsigned int mnemonic_word;
unsigned char c;
int count; /* num. of matching characters */
int max; /* highest num. of matching found so far */
int max_ph; /* corresponding phoneme with highest matching */
int consumed;
unsigned int mnemonic_word;


if(bad_phoneme != NULL) if(bad_phoneme != NULL)
*bad_phoneme = 0; *bad_phoneme = 0;
mnemonic_word = phoneme_tab[ix]->mnemonic; mnemonic_word = phoneme_tab[ix]->mnemonic;


while(((c = p[count]) > ' ') && (count < 4) && while(((c = p[count]) > ' ') && (count < 4) &&
(c == ((mnemonic_word >> (count*8)) & 0xff)))
(c == ((mnemonic_word >> (count*8)) & 0xff)))
count++; count++;


if((count > max) && if((count > max) &&
((count == 4) || (((mnemonic_word >> (count*8)) & 0xff)==0)))
((count == 4) || (((mnemonic_word >> (count*8)) & 0xff)==0)))
{ {
max = count; max = count;
max_ph = phoneme_tab[ix]->code; max_ph = phoneme_tab[ix]->code;
// Translate from internal phoneme codes into phoneme mnemonics // Translate from internal phoneme codes into phoneme mnemonics
unsigned char phcode; unsigned char phcode;
unsigned char c; unsigned char c;
unsigned int mnem;
unsigned int mnem;
PHONEME_TAB *ph; PHONEME_TAB *ph;
static const char *stress_chars = "==,,'* "; static const char *stress_chars = "==,,'* ";


bit 7: use tie between letters in multi-character phoneme names bit 7: use tie between letters in multi-character phoneme names
bits 8-23 tie or separator character bits 8-23 tie or separator character


*/
*/


int ix;
unsigned int len;
int phon_out_ix=0;
int stress;
int ix;
unsigned int len;
int phon_out_ix=0;
int stress;
int c; int c;
char *p; char *p;
char *buf; char *buf;


flags = 0; flags = 0;
count = 0; count = 0;
for(p=phon_buf2; *p != 0;)
for(p=phon_buf2; *p != 0; )
{ {
p += utf8_in(&c, p); p += utf8_in(&c, p);
if(use_tie != 0) if(use_tie != 0)
// match the word against a list of utf-8 strings // match the word against a list of utf-8 strings
char *p; char *p;
char *w; char *w;
int len=0;
int len=0;


p = tr->letterGroups[group]; p = tr->letterGroups[group];
if(p == NULL) if(p == NULL)


static int Unpronouncable2(Translator *tr, char *word) static int Unpronouncable2(Translator *tr, char *word)
{ {
int c;
int c;
int end_flags; int end_flags;
char ph_buf[N_WORD_PHONEMES]; char ph_buf[N_WORD_PHONEMES];


int Unpronouncable(Translator *tr, char *word, int posn) int Unpronouncable(Translator *tr, char *word, int posn)
{ {
/* Determines whether a word in 'unpronouncable', i.e. whether it should /* Determines whether a word in 'unpronouncable', i.e. whether it should
be spoken as individual letters.
be spoken as individual letters.


This function may be language specific. This is a generic version.
*/
This function may be language specific. This is a generic version.
*/


int c;
int c1=0;
int vowel_posn=9;
int index;
int count;
int c;
int c1=0;
int vowel_posn=9;
int index;
int count;
ALPHABET *alphabet; ALPHABET *alphabet;


utf8_in(&c,word); utf8_in(&c,word);


index = 0; index = 0;
count = 0; count = 0;
for(;;)
for(;; )
{ {
index += utf8_in(&c,&word[index]); index += utf8_in(&c,&word[index]);
if((c==0) || (c==' ')) if((c==0) || (c==' '))




static char stress_phonemes[] = {phonSTRESS_D, phonSTRESS_U, phonSTRESS_2, phonSTRESS_3, static char stress_phonemes[] = {phonSTRESS_D, phonSTRESS_U, phonSTRESS_2, phonSTRESS_3,
phonSTRESS_P, phonSTRESS_P2, phonSTRESS_TONIC
};
phonSTRESS_P, phonSTRESS_P2, phonSTRESS_TONIC};




void ChangeWordStress(Translator *tr, char *word, int new_stress) void ChangeWordStress(Translator *tr, char *word, int new_stress)
{ {
int ix; int ix;
unsigned char *p; unsigned char *p;
int max_stress;
int vowel_count; // num of vowels + 1
int stressed_syllable=0; // position of stressed syllable
int max_stress;
int vowel_count; // num of vowels + 1
int stressed_syllable=0; // position of stressed syllable
unsigned char phonetic[N_WORD_PHONEMES]; unsigned char phonetic[N_WORD_PHONEMES];
signed char vowel_stress[N_WORD_PHONEMES/2]; signed char vowel_stress[N_WORD_PHONEMES/2];


'output' is used for input and output 'output' is used for input and output


'dictionary_flags' has bits 0-3 position of stressed vowel (if > 0) 'dictionary_flags' has bits 0-3 position of stressed vowel (if > 0)
or unstressed (if == 7) or syllables 1 and 2 (if == 6)
bits 8... dictionary flags
or unstressed (if == 7) or syllables 1 and 2 (if == 6)
bits 8... dictionary flags


If 'tonic' is set (>= 0), replace highest stress by this value. If 'tonic' is set (>= 0), replace highest stress by this value.


control: bit 0 This is an individual symbol, not a word
control: bit 0 This is an individual symbol, not a word
bit 1 Suffix phonemes are still to be added bit 1 Suffix phonemes are still to be added
*/
*/


unsigned char phcode; unsigned char phcode;
unsigned char *p; unsigned char *p;
PHONEME_TAB *ph; PHONEME_TAB *ph;
int stress;
int max_stress;
int max_stress_input; // any stress specified in the input?
int vowel_count; // num of vowels + 1
int ix;
int v;
int v_stress;
int stressed_syllable; // position of stressed syllable
int max_stress_posn;
int unstressed_word = 0;
int stress;
int max_stress;
int max_stress_input; // any stress specified in the input?
int vowel_count; // num of vowels + 1
int ix;
int v;
int v_stress;
int stressed_syllable; // position of stressed syllable
int max_stress_posn;
int unstressed_word = 0;
char *max_output; char *max_output;
int final_ph; int final_ph;
int final_ph2; int final_ph2;




/* stress numbers STRESS_BASE + /* stress numbers STRESS_BASE +
0 diminished, unstressed within a word
1 unstressed, weak
2
3 secondary stress
4 main stress */
0 diminished, unstressed within a word
1 unstressed, weak
2
3 secondary stress
4 main stress */


stressflags = tr->langopts.stress_flags; stressflags = tr->langopts.stress_flags;


// stress on first syllable, unless it is a light syllable followed by a heavy syllable // stress on first syllable, unless it is a light syllable followed by a heavy syllable
if((syllable_weight[1] > 0) || (syllable_weight[2] == 0)) if((syllable_weight[1] > 0) || (syllable_weight[2] == 0))
break; break;
// else drop through to case 1
// else drop through to case 1
case 1: case 1:
// stress on second syllable // stress on second syllable
if((stressed_syllable == 0) && (vowel_count > 2)) if((stressed_syllable == 0) && (vowel_count > 2))
break; break;
} }
} }
// drop through to next case
// drop through to next case
case 2: case 2:
// a language with stress on penultimate vowel // a language with stress on penultimate vowel


break; break;
} }


if((stressflags & S_FINAL_VOWEL_UNSTRESSED) && ((control & 2) == 0) && (vowel_count > 2) && (max_stress_input < 3) && (vowel_stress[vowel_count - 1] == 4))
{
if((stressflags & S_FINAL_VOWEL_UNSTRESSED) && ((control & 2) == 0) && (vowel_count > 2) && (max_stress_input < 3) && (vowel_stress[vowel_count - 1] == 4))
{
// Don't allow stress on a word-final vowel // Don't allow stress on a word-final vowel
// Only do this if there is no suffix phonemes to be added, and if a stress position was not given explicitly // Only do this if there is no suffix phonemes to be added, and if a stress position was not given explicitly
if(phoneme_tab[final_ph]->type == phVOWEL) if(phoneme_tab[final_ph]->type == phVOWEL)
vowel_stress[vowel_count - 1] = 1; vowel_stress[vowel_count - 1] = 1;
vowel_stress[vowel_count - 2] = 4; vowel_stress[vowel_count - 2] = 4;
} }
}
}


/* now guess the complete stress pattern */ /* now guess the complete stress pattern */
if(max_stress < 4) if(max_stress < 4)
ph = phoneme_tab[p[0]]; ph = phoneme_tab[p[0]];
} }


if((tr->langopts.vowel_pause & 0x30) && (ph->type == phVOWEL))
{
// word starts with a vowel
if((tr->langopts.vowel_pause & 0x30) && (ph->type == phVOWEL))
{
// word starts with a vowel


if((tr->langopts.vowel_pause & 0x20) && (vowel_stress[1] >= 4))
{
*output++ = phonPAUSE_NOLINK; // not to be replaced by link
}
else
{
*output++ = phonPAUSE_VSHORT; // break, but no pause
}
if((tr->langopts.vowel_pause & 0x20) && (vowel_stress[1] >= 4))
{
*output++ = phonPAUSE_NOLINK; // not to be replaced by link
}
else
{
*output++ = phonPAUSE_VSHORT; // break, but no pause
} }
}
} }


p = phonetic; p = phonetic;
void AppendPhonemes(Translator *tr, char *string, int size, const char *ph) void AppendPhonemes(Translator *tr, char *string, int size, const char *ph)
{ {
/* Add new phoneme string "ph" to "string" /* Add new phoneme string "ph" to "string"
Keeps count of the number of vowel phonemes in the word, and whether these
Keeps count of the number of vowel phonemes in the word, and whether these
can be stressed syllables. These values can be used in translation rules can be stressed syllables. These values can be used in translation rules
*/
*/
const char *p; const char *p;
unsigned char c;
int unstress_mark;
unsigned char c;
int unstress_mark;
int length; int length;


length = strlen(ph) + strlen(string); length = strlen(ph) + strlen(string);
if(phoneme_tab[c]->type == phVOWEL) if(phoneme_tab[c]->type == phVOWEL)
{ {
if(((phoneme_tab[c]->phflags & phUNSTRESSED) == 0) && if(((phoneme_tab[c]->phflags & phUNSTRESSED) == 0) &&
(unstress_mark == 0))
(unstress_mark == 0))
{ {
tr->word_stressed_count++; tr->word_stressed_count++;
} }
static void MatchRule(Translator *tr, char *word[], char *word_start, int group_length, char *rule, MatchRecord *match_out, int word_flags, int dict_flags) static void MatchRule(Translator *tr, char *word[], char *word_start, int group_length, char *rule, MatchRecord *match_out, int word_flags, int dict_flags)
{ {
/* Checks a specified word against dictionary rules. /* Checks a specified word against dictionary rules.
Returns with phoneme code string, or NULL if no match found.
Returns with phoneme code string, or NULL if no match found.


word (indirect) points to current character group within the input word
This is advanced by this procedure as characters are consumed
word (indirect) points to current character group within the input word
This is advanced by this procedure as characters are consumed


group: the initial characters used to choose the rules group
group: the initial characters used to choose the rules group


rule: address of dictionary rule data for this character group
rule: address of dictionary rule data for this character group


match_out: returns best points score
match_out: returns best points score


word_flags: indicates whether this is a retranslation after a suffix has been removed
*/
word_flags: indicates whether this is a retranslation after a suffix has been removed
*/


unsigned char rb; // current instuction from rule unsigned char rb; // current instuction from rule
unsigned char letter; // current letter from input word, single byte unsigned char letter; // current letter from input word, single byte


char *rule_start; /* start of current match template */ char *rule_start; /* start of current match template */
char *p; char *p;
int ix;
int match_type; /* left, right, or consume */
int failed;
int unpron_ignore;
int consumed; /* number of letters consumed from input */
int syllable_count;
int vowel;
int letter_group;
int distance_right;
int distance_left;
int lg_pts;
int n_bytes;
int ix;
int match_type; /* left, right, or consume */
int failed;
int unpron_ignore;
int consumed; /* number of letters consumed from input */
int syllable_count;
int vowel;
int letter_group;
int distance_right;
int distance_left;
int lg_pts;
int n_bytes;
int add_points; int add_points;
int command; int command;
int check_atstart; int check_atstart;
MatchRecord match; MatchRecord match;
static MatchRecord best; static MatchRecord best;


int total_consumed; /* letters consumed for best match */
int total_consumed; /* letters consumed for best match */


unsigned char condition_num; unsigned char condition_num;
char *common_phonemes; /* common to a group of entries */ char *common_phonemes; /* common to a group of entries */
end_type = (rule[0] << 16) + ((rule[1] & 0x7f) << 8) + (rule[2] & 0x7f); end_type = (rule[0] << 16) + ((rule[1] & 0x7f) << 8) + (rule[2] & 0x7f);


if((tr->word_vowel_count == 0) && !(end_type & SUFX_P) && (tr->langopts.param[LOPT_SUFFIX] & 1)) if((tr->word_vowel_count == 0) && !(end_type & SUFX_P) && (tr->langopts.param[LOPT_SUFFIX] & 1))
failed = 1; // don't match a suffix rule if there are no previous syllables (needed for lang=tr).
failed = 1; // don't match a suffix rule if there are no previous syllables (needed for lang=tr).
else else
{ {
match.end_type = end_type; match.end_type = end_type;
/* Translate a word bounded by space characters /* Translate a word bounded by space characters
Append the result to 'phonemes' and any standard prefix/suffix in 'end_phonemes' */ Append the result to 'phonemes' and any standard prefix/suffix in 'end_phonemes' */


unsigned char c, c2;
unsigned int c12;
unsigned char c, c2;
unsigned int c12;
int wc=0; int wc=0;
int wc_bytes; int wc_bytes;
char *p2; /* copy of p for use in double letter chain match */ char *p2; /* copy of p for use in double letter chain match */
int found;
int g; /* group chain number */
int g1; /* first group for this letter */
int n;
int letter;
int any_alpha=0;
int ix;
unsigned int digit_count=0;
int found;
int g; /* group chain number */
int g1; /* first group for this letter */
int n;
int letter;
int any_alpha=0;
int ix;
unsigned int digit_count=0;
char *p; char *p;
ALPHABET *alphabet; ALPHABET *alphabet;
int dict_flags0=0;
int dict_flags0=0;
MatchRecord match1; MatchRecord match1;
MatchRecord match2; MatchRecord match2;
char ph_buf[40]; char ph_buf[40];
if(dict_flags != NULL) if(dict_flags != NULL)
dict_flags0 = dict_flags[0]; dict_flags0 = dict_flags[0];


for(ix=0; ix<(N_WORD_BYTES-1);)
for(ix=0; ix<(N_WORD_BYTES-1); )
{ {
c = p_start[ix]; c = p_start[ix];
word_copy[ix++] = c; word_copy[ix++] = c;
if((option_phonemes & espeakPHONEMES_TRACE) && ((word_flags & FLAG_NO_TRACE)==0)) if((option_phonemes & espeakPHONEMES_TRACE) && ((word_flags & FLAG_NO_TRACE)==0))
{ {
char wordbuf[120]; char wordbuf[120];
unsigned int ix;
unsigned int ix;


for(ix=0; ((c = p_start[ix]) != ' ') && (c != 0) && (ix < (sizeof(wordbuf)-1)); ix++) for(ix=0; ((c = p_start[ix]) != ' ') && (c != 0) && (ix < (sizeof(wordbuf)-1)); ix++)
{ {


if((option_phonemes & espeakPHONEMES_TRACE) && ((word_flags & FLAG_NO_TRACE)==0)) if((option_phonemes & espeakPHONEMES_TRACE) && ((word_flags & FLAG_NO_TRACE)==0))
{ {
fprintf(f_trans,"\n");
fprintf(f_trans,"\n");
} }


match1.end_type &= ~SUFX_UNPRON; match1.end_type &= ~SUFX_UNPRON;
/* Find an entry in the word_dict file for a specified word. /* Find an entry in the word_dict file for a specified word.
Returns NULL if no match, else returns 'word_end' Returns NULL if no match, else returns 'word_end'


word zero terminated word to match
word2 pointer to next word(s) in the input text (terminated by space)
word zero terminated word to match
word2 pointer to next word(s) in the input text (terminated by space)


flags: returns dictionary flags which are associated with a matched word
flags: returns dictionary flags which are associated with a matched word


end_flags: indicates whether this is a retranslation after removing a suffix
*/
end_flags: indicates whether this is a retranslation after removing a suffix
*/
static const char *LookupDict2(Translator *tr, const char *word, const char *word2, static const char *LookupDict2(Translator *tr, const char *word, const char *word2,
char *phonetic, unsigned int *flags, int end_flags, WORD_TAB *wtab)
char *phonetic, unsigned int *flags, int end_flags, WORD_TAB *wtab)
{ {
char *p; char *p;
char *next; char *next;
int hash;
int phoneme_len;
int wlen;
int hash;
int phoneme_len;
int wlen;
unsigned char flag; unsigned char flag;
unsigned int dictionary_flags;
unsigned int dictionary_flags2;
int condition_failed=0;
int n_chars;
int no_phonemes;
int skipwords;
int ix;
int c;
unsigned int dictionary_flags;
unsigned int dictionary_flags2;
int condition_failed=0;
int n_chars;
int no_phonemes;
int skipwords;
int ix;
int c;
const char *word_end; const char *word_end;
const char *word1; const char *word1;
int wflags = 0; int wflags = 0;
else else
{ {
/* don't use the 'verb' pronunciation unless we are /* don't use the 'verb' pronunciation unless we are
expecting a verb */
expecting a verb */
continue; continue;
} }
} }
if(!tr->expect_past) if(!tr->expect_past)
{ {
/* don't use the 'past' pronunciation unless we are /* don't use the 'past' pronunciation unless we are
expecting past tense */
expecting past tense */
continue; continue;
} }
} }
if((!tr->expect_noun) || (end_flags & SUFX_V)) if((!tr->expect_noun) || (end_flags & SUFX_V))
{ {
/* don't use the 'noun' pronunciation unless we are /* don't use the 'noun' pronunciation unless we are
expecting a noun */
expecting a noun */
continue; continue;
} }
} }
Returns phonetic data in 'phonetic' and bits in 'flags' Returns phonetic data in 'phonetic' and bits in 'flags'


end_flags: indicates if a suffix has been removed end_flags: indicates if a suffix has been removed
*/
*/
int LookupDictList(Translator *tr, char **wordptr, char *ph_out, unsigned int *flags, int end_flags, WORD_TAB *wtab) int LookupDictList(Translator *tr, char **wordptr, char *ph_out, unsigned int *flags, int end_flags, WORD_TAB *wtab)
{ {
int length;
int length;
const char *found; const char *found;
const char *word1; const char *word1;
const char *word2; const char *word2;
unsigned char c; unsigned char c;
int nbytes;
int len;
int nbytes;
int len;
char word[N_WORD_BYTES]; char word[N_WORD_BYTES];
static char word_replacement[N_WORD_BYTES]; static char word_replacement[N_WORD_BYTES];


{ {
/* Removes a standard suffix from a word, once it has been indicated by the dictionary rules. /* Removes a standard suffix from a word, once it has been indicated by the dictionary rules.
end_type: bits 0-6 number of letters end_type: bits 0-6 number of letters
bits 8-14 suffix flags
bits 8-14 suffix flags


word_copy: make a copy of the original word
This routine is language specific. In English it deals with reversing y->i and e-dropping
that were done when the suffix was added to the original word.
*/
word_copy: make a copy of the original word
This routine is language specific. In English it deals with reversing y->i and e-dropping
that were done when the suffix was added to the original word.
*/


int i;
int i;
char *word_end; char *word_end;
int len_ending; int len_ending;
int end_flags; int end_flags;
const char *p; const char *p;
int len;
int len;
char ending[50]; char ending[50];


// these lists are language specific, but are only relevent if the 'e' suffix flag is used // these lists are language specific, but are only relevent if the 'e' suffix flag is used
} }


// look for multibyte characters to increase the number of bytes to remove // look for multibyte characters to increase the number of bytes to remove
for(len_ending = i = (end_type & 0x3f); i>0 ; i--) // num.of characters of the suffix
for(len_ending = i = (end_type & 0x3f); i>0; i--) // num.of characters of the suffix
{ {
word_end--; word_end--;
while((*word_end & 0xc0) == 0x80) while((*word_end & 0xc0) == 0x80)
end_flags = (end_type & 0xfff0) | FLAG_SUFX; end_flags = (end_type & 0xfff0) | FLAG_SUFX;


/* add an 'e' to the stem if appropriate, /* add an 'e' to the stem if appropriate,
if stem ends in vowel+consonant
or stem ends in 'c' (add 'e' to soften it) */
if stem ends in vowel+consonant
or stem ends in 'c' (add 'e' to soften it) */


if(end_type & SUFX_I) if(end_type & SUFX_I)
{ {

+ 524
- 524
src/libespeak-ng/espeak_command.c
File diff suppressed because it is too large
View File


+ 65
- 65
src/libespeak-ng/espeak_command.h View File

#endif #endif


typedef enum typedef enum
{
ET_TEXT,
ET_MARK,
ET_KEY,
ET_CHAR,
ET_PARAMETER,
ET_PUNCTUATION_LIST,
ET_VOICE_NAME,
ET_VOICE_SPEC,
ET_TERMINATED_MSG
} t_espeak_type;

typedef struct
{ {
unsigned int unique_identifier;
void* text;
size_t size;
unsigned int position;
espeak_POSITION_TYPE position_type;
unsigned int end_position;
unsigned int flags;
void* user_data;
ET_TEXT,
ET_MARK,
ET_KEY,
ET_CHAR,
ET_PARAMETER,
ET_PUNCTUATION_LIST,
ET_VOICE_NAME,
ET_VOICE_SPEC,
ET_TERMINATED_MSG
} t_espeak_type;

typedef struct
{
unsigned int unique_identifier;
void* text;
size_t size;
unsigned int position;
espeak_POSITION_TYPE position_type;
unsigned int end_position;
unsigned int flags;
void* user_data;
} t_espeak_text; } t_espeak_text;


typedef struct
typedef struct
{ {
unsigned int unique_identifier;
void* text;
size_t size;
const char* index_mark;
unsigned int end_position;
unsigned int flags;
void* user_data;
unsigned int unique_identifier;
void* text;
size_t size;
const char* index_mark;
unsigned int end_position;
unsigned int flags;
void* user_data;
} t_espeak_mark; } t_espeak_mark;


typedef struct
typedef struct
{ {
unsigned int unique_identifier; unsigned int unique_identifier;
void* user_data; void* user_data;
wchar_t character;
wchar_t character;
} t_espeak_character; } t_espeak_character;


typedef struct
typedef struct
{ {
unsigned int unique_identifier; unsigned int unique_identifier;
void* user_data; void* user_data;
const char* key_name;
const char* key_name;
} t_espeak_key; } t_espeak_key;




typedef struct
typedef struct
{ {
unsigned int unique_identifier;
void* user_data;
unsigned int unique_identifier;
void* user_data;
} t_espeak_terminated_msg; } t_espeak_terminated_msg;




typedef struct
typedef struct
{ {
espeak_PARAMETER parameter;
int value;
int relative;
espeak_PARAMETER parameter;
int value;
int relative;
} t_espeak_parameter; } t_espeak_parameter;


typedef enum typedef enum
{ {
CS_UNDEFINED, // The command has just been created
CS_PENDING, // stored in the fifo
CS_PROCESSED // processed
CS_UNDEFINED, // The command has just been created
CS_PENDING, // stored in the fifo
CS_PROCESSED // processed
} t_command_state; } t_command_state;


typedef struct
typedef struct
{ {
t_espeak_type type;
t_command_state state;
union command
{
t_espeak_text my_text;
t_espeak_mark my_mark;
t_espeak_key my_key;
t_espeak_character my_char;
t_espeak_parameter my_param;
const wchar_t* my_punctuation_list;
const char *my_voice_name;
espeak_VOICE my_voice_spec;
t_espeak_terminated_msg my_terminated_msg;
} u;
t_espeak_type type;
t_command_state state;
union command
{
t_espeak_text my_text;
t_espeak_mark my_mark;
t_espeak_key my_key;
t_espeak_character my_char;
t_espeak_parameter my_param;
const wchar_t* my_punctuation_list;
const char *my_voice_name;
espeak_VOICE my_voice_spec;
t_espeak_terminated_msg my_terminated_msg;
} u;
} t_espeak_command; } t_espeak_command;




void display_espeak_command(t_espeak_command* the_command); void display_espeak_command(t_espeak_command* the_command);




espeak_ERROR sync_espeak_Synth(unsigned int unique_identifier, const void *text, size_t size,
unsigned int position, espeak_POSITION_TYPE position_type,
unsigned int end_position, unsigned int flags, void* user_data);
espeak_ERROR sync_espeak_Synth_Mark(unsigned int unique_identifier, const void *text, size_t size,
const char *index_mark, unsigned int end_position,
unsigned int flags, void* user_data);
espeak_ERROR sync_espeak_Synth(unsigned int unique_identifier, const void *text, size_t size,
unsigned int position, espeak_POSITION_TYPE position_type,
unsigned int end_position, unsigned int flags, void* user_data);
espeak_ERROR sync_espeak_Synth_Mark(unsigned int unique_identifier, const void *text, size_t size,
const char *index_mark, unsigned int end_position,
unsigned int flags, void* user_data);
void sync_espeak_Key(const char *key); void sync_espeak_Key(const char *key);
void sync_espeak_Char(wchar_t character); void sync_espeak_Char(wchar_t character);
void sync_espeak_SetPunctuationList(const wchar_t *punctlist); void sync_espeak_SetPunctuationList(const wchar_t *punctlist);

+ 73
- 74
src/libespeak-ng/event.c View File

static int my_event_is_running=0; static int my_event_is_running=0;


enum {MIN_TIMEOUT_IN_MS=10, enum {MIN_TIMEOUT_IN_MS=10,
ACTIVITY_TIMEOUT=50, // in ms, check that the stream is active
MAX_ACTIVITY_CHECK=6
};
ACTIVITY_TIMEOUT=50, // in ms, check that the stream is active
MAX_ACTIVITY_CHECK=6};




typedef struct t_node typedef struct t_node
{ {
void* data;
struct t_node *next;
void* data;
struct t_node *next;
} node; } node;


static node* head=NULL; static node* head=NULL;


void event_set_callback(t_espeak_callback* SynthCallback) void event_set_callback(t_espeak_callback* SynthCallback)
{ {
my_callback = SynthCallback;
my_callback = SynthCallback;
} }


void event_init(void) void event_init(void)
{ {
ENTER("event_init");
my_event_is_running=0;
// security
pthread_mutex_init( &my_mutex, (const pthread_mutexattr_t *)NULL);
init();
assert(-1 != sem_init(&my_sem_start_is_required, 0, 0));
assert(-1 != sem_init(&my_sem_stop_is_required, 0, 0));
assert(-1 != sem_init(&my_sem_stop_is_acknowledged, 0, 0));
pthread_attr_t a_attrib;
if (pthread_attr_init (&a_attrib) == 0
&& pthread_attr_setdetachstate(&a_attrib, PTHREAD_CREATE_JOINABLE) == 0)
{
thread_inited = (0 == pthread_create(&my_thread,
&a_attrib,
polling_thread,
(void*)NULL));
}
assert(thread_inited);
pthread_attr_destroy(&a_attrib);
ENTER("event_init");
my_event_is_running=0;
// security
pthread_mutex_init( &my_mutex, (const pthread_mutexattr_t *)NULL);
init();
assert(-1 != sem_init(&my_sem_start_is_required, 0, 0));
assert(-1 != sem_init(&my_sem_stop_is_required, 0, 0));
assert(-1 != sem_init(&my_sem_stop_is_acknowledged, 0, 0));
pthread_attr_t a_attrib;
if (pthread_attr_init (&a_attrib) == 0
&& pthread_attr_setdetachstate(&a_attrib, PTHREAD_CREATE_JOINABLE) == 0)
{
thread_inited = (0 == pthread_create(&my_thread,
&a_attrib,
polling_thread,
(void*)NULL));
}
assert(thread_inited);
pthread_attr_destroy(&a_attrib);
} }


static void event_display(espeak_EVENT* event) static void event_display(espeak_EVENT* event)
{ {
ENTER("event_display");
ENTER("event_display");


#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
if (event==NULL) if (event==NULL)
else else
{ {
static const char* label[] = { static const char* label[] = {
"LIST_TERMINATED",
"WORD",
"SENTENCE",
"MARK",
"PLAY",
"END",
"MSG_TERMINATED",
"PHONEME",
"SAMPLERATE",
"??"
"LIST_TERMINATED",
"WORD",
"SENTENCE",
"MARK",
"PLAY",
"END",
"MSG_TERMINATED",
"PHONEME",
"SAMPLERATE",
"??"
}; };


SHOW("event_display > event=0x%x\n",event); SHOW("event_display > event=0x%x\n",event);
{ {
a_event->id.name = strdup(event->id.name); a_event->id.name = strdup(event->id.name);
} }
break;
break;


default: default:
break; break;


static void event_notify(espeak_EVENT* event) static void event_notify(espeak_EVENT* event)
{ {
ENTER("event_notify");
ENTER("event_notify");
static unsigned int a_old_uid = 0; static unsigned int a_old_uid = 0;


espeak_EVENT events[2]; espeak_EVENT events[2];
break; break;


default: default:
case espeakEVENT_LIST_TERMINATED:
case espeakEVENT_PLAY:
break;
case espeakEVENT_LIST_TERMINATED:
case espeakEVENT_PLAY:
break;
} }
} }
} }


static int event_delete(espeak_EVENT* event) static int event_delete(espeak_EVENT* event)
{ {
ENTER("event_delete");
ENTER("event_delete");


event_display(event); event_display(event);




espeak_ERROR event_declare (espeak_EVENT* event) espeak_ERROR event_declare (espeak_EVENT* event)
{ {
ENTER("event_declare");
ENTER("event_declare");


event_display(event); event_display(event);




static int sleep_until_timeout_or_stop_request(uint32_t time_in_ms) static int sleep_until_timeout_or_stop_request(uint32_t time_in_ms)
{ {
ENTER("sleep_until_timeout_or_stop_request");
ENTER("sleep_until_timeout_or_stop_request");


int a_stop_is_required=0; int a_stop_is_required=0;
struct timespec ts; struct timespec ts;
add_time_in_ms( &ts, time_in_ms); add_time_in_ms( &ts, time_in_ms);


SHOW("polling_thread > sleep_until_timeout_or_stop_request > start sem_timedwait from %d.%09lu to %d.%09lu \n", SHOW("polling_thread > sleep_until_timeout_or_stop_request > start sem_timedwait from %d.%09lu to %d.%09lu \n",
to.tv_sec, to.tv_nsec,
ts.tv_sec, ts.tv_nsec);
to.tv_sec, to.tv_nsec,
ts.tv_sec, ts.tv_nsec);


while ((err = sem_timedwait(&my_sem_stop_is_required, &ts)) == -1 while ((err = sem_timedwait(&my_sem_stop_is_required, &ts)) == -1
&& errno == EINTR)
&& errno == EINTR)
{ {
continue; // Restart when interrupted by handler continue; // Restart when interrupted by handler
} }


assert (gettimeofday(&tv, NULL) != -1); assert (gettimeofday(&tv, NULL) != -1);
SHOW("polling_thread > sleep_until_timeout_or_stop_request > stop sem_timedwait %d.%09lu \n", SHOW("polling_thread > sleep_until_timeout_or_stop_request > stop sem_timedwait %d.%09lu \n",
tv.tv_sec, tv.tv_usec*1000);
tv.tv_sec, tv.tv_usec*1000);


if (err == 0) if (err == 0)
{ {


static int get_remaining_time(uint32_t sample, uint32_t* time_in_ms, int* stop_is_required) static int get_remaining_time(uint32_t sample, uint32_t* time_in_ms, int* stop_is_required)
{ {
ENTER("get_remaining_time");
ENTER("get_remaining_time");


int err = 0; int err = 0;
*stop_is_required = 0; *stop_is_required = 0;


if (err || wave_is_busy(NULL) || (*time_in_ms == 0)) if (err || wave_is_busy(NULL) || (*time_in_ms == 0))
{ // if err, stream not available: quit { // if err, stream not available: quit
// if wave is busy, time_in_ms is known: quit
// if wave is not busy but remaining time == 0, event is reached: quit
break;
}
// if wave is busy, time_in_ms is known: quit
// if wave is not busy but remaining time == 0, event is reached: quit
break;
}


// stream opened but not active
//
// Several possible states:
// * the stream is opened but not yet started:
//
// wait for the start of stream
//
// * some samples have already been played,
// ** the end of stream is reached
// ** or there is an underrun
//
// wait for the close of stream
// stream opened but not active
//
// Several possible states:
// * the stream is opened but not yet started:
//
// wait for the start of stream
//
// * some samples have already been played,
// ** the end of stream is reached
// ** or there is an underrun
//
// wait for the close of stream


*stop_is_required = sleep_until_timeout_or_stop_request( ACTIVITY_TIMEOUT); *stop_is_required = sleep_until_timeout_or_stop_request( ACTIVITY_TIMEOUT);
} }


static void* polling_thread(void*p) static void* polling_thread(void*p)
{ {
ENTER("polling_thread");
ENTER("polling_thread");


while(1) while(1)
{ {
uint32_t time_in_ms = 0; uint32_t time_in_ms = 0;


int err = get_remaining_time((uint32_t)event->sample, int err = get_remaining_time((uint32_t)event->sample,
&time_in_ms,
&a_stop_is_required);
&time_in_ms,
&a_stop_is_required);
if (a_stop_is_required > 0) if (a_stop_is_required > 0)
{ {
break; break;


void event_terminate() void event_terminate()
{ {
ENTER("event_terminate");
ENTER("event_terminate");


if (thread_inited) if (thread_inited)
{ {

+ 14
- 14
src/libespeak-ng/event.h View File

#ifndef EVENT_H #ifndef EVENT_H
#define EVENT_H #define EVENT_H


/*
Manage events (sentence, word, mark, end,...), is responsible of calling the external
callback as soon as the relevant audio sample is played.
/*
Manage events (sentence, word, mark, end,...), is responsible of calling the external
callback as soon as the relevant audio sample is played.




The audio stream is composed of samples from synthetised messages or audio icons.
Each event is associated to a sample.
The audio stream is composed of samples from synthetised messages or audio icons.
Each event is associated to a sample.


Scenario:
Scenario:


- event_declare is called for each expected event.
- event_declare is called for each expected event.


- A timeout is started for the first pending event.
- A timeout is started for the first pending event.


- When the timeout happens, the synth_callback is called.
- When the timeout happens, the synth_callback is called.


Note: the timeout is checked against the real progress of the audio stream, which depends on pauses or underruns. If the real progress is lower than the expected one, a new timeout starts.
Note: the timeout is checked against the real progress of the audio stream, which depends on pauses or underruns. If the real progress is lower than the expected one, a new timeout starts.


*/
*/


#include "speak_lib.h" #include "speak_lib.h"




// Clear any pending event. // Clear any pending event.
// //
// Return: EE_OK: operation achieved
// Return: EE_OK: operation achieved
// EE_INTERNAL_ERROR. // EE_INTERNAL_ERROR.
espeak_ERROR event_clear_all (); espeak_ERROR event_clear_all ();


// Declare a future event // Declare a future event
// //
// Return: EE_OK: operation achieved
// EE_BUFFER_FULL: the event can not be buffered;
// Return: EE_OK: operation achieved
// EE_BUFFER_FULL: the event can not be buffered;
// you may try after a while to call the function again. // you may try after a while to call the function again.
// EE_INTERNAL_ERROR. // EE_INTERNAL_ERROR.
espeak_ERROR event_declare (espeak_EVENT* event); espeak_ERROR event_declare (espeak_EVENT* event);

+ 329
- 330
src/libespeak-ng/fifo.c View File

static void init(int process_parameters); static void init(int process_parameters);
static int node_counter=0; static int node_counter=0;
enum {MAX_NODE_COUNTER=400, enum {MAX_NODE_COUNTER=400,
INACTIVITY_TIMEOUT=50, // in ms, check that the stream is inactive
MAX_INACTIVITY_CHECK=2
};
INACTIVITY_TIMEOUT=50, // in ms, check that the stream is inactive
MAX_INACTIVITY_CHECK=2};


void fifo_init() void fifo_init()
{ {
ENTER("fifo_init");
// security
pthread_mutex_init( &my_mutex, (const pthread_mutexattr_t *)NULL);
init(0);
assert(-1 != sem_init(&my_sem_start_is_required, 0, 0));
assert(-1 != sem_init(&my_sem_stop_is_acknowledged, 0, 0));
pthread_attr_t a_attrib;
if (pthread_attr_init (& a_attrib)
|| pthread_attr_setdetachstate(&a_attrib, PTHREAD_CREATE_JOINABLE)
|| pthread_create( &my_thread,
& a_attrib,
say_thread,
(void*)NULL))
{
assert(0);
}
pthread_attr_destroy(&a_attrib);
// leave once the thread is actually started
SHOW_TIME("fifo > wait for my_sem_stop_is_acknowledged\n");
while ((sem_wait(&my_sem_stop_is_acknowledged) == -1) && errno == EINTR)
{
continue; // Restart when interrupted by handler
}
SHOW_TIME("fifo > get my_sem_stop_is_acknowledged\n");
ENTER("fifo_init");
// security
pthread_mutex_init( &my_mutex, (const pthread_mutexattr_t *)NULL);
init(0);
assert(-1 != sem_init(&my_sem_start_is_required, 0, 0));
assert(-1 != sem_init(&my_sem_stop_is_acknowledged, 0, 0));
pthread_attr_t a_attrib;
if (pthread_attr_init (&a_attrib)
|| pthread_attr_setdetachstate(&a_attrib, PTHREAD_CREATE_JOINABLE)
|| pthread_create( &my_thread,
&a_attrib,
say_thread,
(void*)NULL))
{
assert(0);
}
pthread_attr_destroy(&a_attrib);
// leave once the thread is actually started
SHOW_TIME("fifo > wait for my_sem_stop_is_acknowledged\n");
while ((sem_wait(&my_sem_stop_is_acknowledged) == -1) && errno == EINTR)
{
continue; // Restart when interrupted by handler
}
SHOW_TIME("fifo > get my_sem_stop_is_acknowledged\n");
} }


espeak_ERROR fifo_add_command (t_espeak_command* the_command) espeak_ERROR fifo_add_command (t_espeak_command* the_command)
{ {
ENTER("fifo_add_command");

int a_status = pthread_mutex_lock(&my_mutex);
espeak_ERROR a_error = EE_OK;

if (!a_status)
{
SHOW_TIME("fifo_add_command > locked\n");
a_error = push(the_command);
SHOW_TIME("fifo_add_command > unlocking\n");
a_status = pthread_mutex_unlock(&my_mutex);
}

if (!a_status && !my_command_is_running && (a_error == EE_OK))
{
// quit when command is actually started
// (for possible forthcoming 'end of command' checks)
SHOW_TIME("fifo_add_command > post my_sem_start_is_required\n");
sem_post(&my_sem_start_is_required);
int val=1;
while (val > 0)
ENTER("fifo_add_command");

int a_status = pthread_mutex_lock(&my_mutex);
espeak_ERROR a_error = EE_OK;

if (!a_status)
{
SHOW_TIME("fifo_add_command > locked\n");
a_error = push(the_command);
SHOW_TIME("fifo_add_command > unlocking\n");
a_status = pthread_mutex_unlock(&my_mutex);
}

if (!a_status && !my_command_is_running && (a_error == EE_OK))
{ {
usleep(50000); // TBD: event?
sem_getvalue(&my_sem_start_is_required, &val);
// quit when command is actually started
// (for possible forthcoming 'end of command' checks)
SHOW_TIME("fifo_add_command > post my_sem_start_is_required\n");
sem_post(&my_sem_start_is_required);
int val=1;
while (val > 0)
{
usleep(50000); // TBD: event?
sem_getvalue(&my_sem_start_is_required, &val);
}
} }
}


if (a_status != 0)
{
a_error = EE_INTERNAL_ERROR;
}
if (a_status != 0)
{
a_error = EE_INTERNAL_ERROR;
}


SHOW_TIME("LEAVE fifo_add_command");
return a_error;
SHOW_TIME("LEAVE fifo_add_command");
return a_error;
} }


espeak_ERROR fifo_add_commands (t_espeak_command* command1, t_espeak_command* command2) espeak_ERROR fifo_add_commands (t_espeak_command* command1, t_espeak_command* command2)
{ {
ENTER("fifo_add_command");
ENTER("fifo_add_command");


int a_status = pthread_mutex_lock(&my_mutex);
espeak_ERROR a_error = EE_OK;
int a_status = pthread_mutex_lock(&my_mutex);
espeak_ERROR a_error = EE_OK;


if (!a_status)
{
SHOW_TIME("fifo_add_commands > locked\n");

if (node_counter+1 >= MAX_NODE_COUNTER)
if (!a_status)
{ {
SHOW("push > %s\n", "EE_BUFFER_FULL");
a_error = EE_BUFFER_FULL;
SHOW_TIME("fifo_add_commands > locked\n");

if (node_counter+1 >= MAX_NODE_COUNTER)
{
SHOW("push > %s\n", "EE_BUFFER_FULL");
a_error = EE_BUFFER_FULL;
}
else
{
push(command1);
push(command2);
}
SHOW_TIME("fifo_add_command > unlocking\n");
a_status = pthread_mutex_unlock(&my_mutex);
} }
else

if (!a_status && !my_command_is_running && (a_error == EE_OK))
{ {
push(command1);
push(command2);
// quit when one command is actually started
// (for possible forthcoming 'end of command' checks)
SHOW_TIME("fifo_add_command > post my_sem_start_is_required\n");
sem_post(&my_sem_start_is_required);
int val=1;
while (val > 0)
{
usleep(50000); // TBD: event?
sem_getvalue(&my_sem_start_is_required, &val);
}
} }
SHOW_TIME("fifo_add_command > unlocking\n");
a_status = pthread_mutex_unlock(&my_mutex);
}

if (!a_status && !my_command_is_running && (a_error == EE_OK))
{
// quit when one command is actually started
// (for possible forthcoming 'end of command' checks)
SHOW_TIME("fifo_add_command > post my_sem_start_is_required\n");
sem_post(&my_sem_start_is_required);
int val=1;
while (val > 0)

if (a_status != 0)
{ {
usleep(50000); // TBD: event?
sem_getvalue(&my_sem_start_is_required, &val);
a_error = EE_INTERNAL_ERROR;
} }
}


if (a_status != 0)
{
a_error = EE_INTERNAL_ERROR;
}

SHOW_TIME("LEAVE fifo_add_commands");
return a_error;
SHOW_TIME("LEAVE fifo_add_commands");
return a_error;
} }


espeak_ERROR fifo_stop () espeak_ERROR fifo_stop ()
{ {
ENTER("fifo_stop");

int a_command_is_running = 0;
int a_status = pthread_mutex_lock(&my_mutex);
SHOW_TIME("fifo_stop > locked\n");
if (a_status != 0)
{
return EE_INTERNAL_ERROR;
}

if (my_command_is_running)
{
a_command_is_running = 1;
my_stop_is_required = 1;
SHOW_TIME("fifo_stop > my_stop_is_required = 1\n");
}
SHOW_TIME("fifo_stop > unlocking\n");
a_status = pthread_mutex_unlock(&my_mutex);
if (a_status != 0)
{
return EE_INTERNAL_ERROR;
}

if (a_command_is_running)
{
SHOW_TIME("fifo_stop > wait for my_sem_stop_is_acknowledged\n");
while ((sem_wait(&my_sem_stop_is_acknowledged) == -1) && errno == EINTR)
ENTER("fifo_stop");

int a_command_is_running = 0;
int a_status = pthread_mutex_lock(&my_mutex);
SHOW_TIME("fifo_stop > locked\n");
if (a_status != 0)
{
return EE_INTERNAL_ERROR;
}

if (my_command_is_running)
{ {
continue; // Restart when interrupted by handler
a_command_is_running = 1;
my_stop_is_required = 1;
SHOW_TIME("fifo_stop > my_stop_is_required = 1\n");
}
SHOW_TIME("fifo_stop > unlocking\n");
a_status = pthread_mutex_unlock(&my_mutex);
if (a_status != 0)
{
return EE_INTERNAL_ERROR;
}

if (a_command_is_running)
{
SHOW_TIME("fifo_stop > wait for my_sem_stop_is_acknowledged\n");
while ((sem_wait(&my_sem_stop_is_acknowledged) == -1) && errno == EINTR)
{
continue; // Restart when interrupted by handler
}
SHOW_TIME("fifo_stop > get my_sem_stop_is_acknowledged\n");
} }
SHOW_TIME("fifo_stop > get my_sem_stop_is_acknowledged\n");
}


SHOW_TIME("fifo_stop > my_stop_is_required = 0\n");
my_stop_is_required = 0;
SHOW_TIME("LEAVE fifo_stop\n");
SHOW_TIME("fifo_stop > my_stop_is_required = 0\n");
my_stop_is_required = 0;
SHOW_TIME("LEAVE fifo_stop\n");


return EE_OK;
return EE_OK;
} }


int fifo_is_busy () int fifo_is_busy ()
{ {
SHOW("fifo_is_busy > aResult = %d\n",my_command_is_running);
return my_command_is_running;
SHOW("fifo_is_busy > aResult = %d\n",my_command_is_running);
return my_command_is_running;
} }


static int sleep_until_start_request_or_inactivity() static int sleep_until_start_request_or_inactivity()
{ {
SHOW_TIME("fifo > sleep_until_start_request_or_inactivity > ENTER");
int a_start_is_required=0;
// Wait for the start request (my_sem_start_is_required).
// Besides this, if the audio stream is still busy,
// check from time to time its end.
// The end of the stream is confirmed by several checks
// for filtering underflow.
//
int i=0;
SHOW_TIME("fifo > sleep_until_start_request_or_inactivity > ENTER");
int a_start_is_required=0;
// Wait for the start request (my_sem_start_is_required).
// Besides this, if the audio stream is still busy,
// check from time to time its end.
// The end of the stream is confirmed by several checks
// for filtering underflow.
//
int i=0;
while((i<= MAX_INACTIVITY_CHECK) && !a_start_is_required) while((i<= MAX_INACTIVITY_CHECK) && !a_start_is_required)
{ {
if (wave_is_busy( NULL) ) if (wave_is_busy( NULL) )
{ {
i = 0; i = 0;
} }
else
else
{ {
i++; i++;
} }
add_time_in_ms( &ts, INACTIVITY_TIMEOUT); add_time_in_ms( &ts, INACTIVITY_TIMEOUT);


SHOW("fifo > sleep_until_start_request_or_inactivity > start sem_timedwait (start_is_required) from %d.%09lu to %d.%09lu \n", SHOW("fifo > sleep_until_start_request_or_inactivity > start sem_timedwait (start_is_required) from %d.%09lu to %d.%09lu \n",
to.tv_sec, to.tv_nsec,
ts.tv_sec, ts.tv_nsec);
to.tv_sec, to.tv_nsec,
ts.tv_sec, ts.tv_nsec);


while ((err = sem_timedwait(&my_sem_start_is_required, &ts)) == -1 while ((err = sem_timedwait(&my_sem_start_is_required, &ts)) == -1
&& errno == EINTR)
&& errno == EINTR)
{ {
continue; continue;
} }


assert (gettimeofday(&tv, NULL) != -1); assert (gettimeofday(&tv, NULL) != -1);
SHOW("fifo > sleep_until_start_request_or_inactivity > stop sem_timedwait (start_is_required, err=%d) %d.%09lu \n", err, SHOW("fifo > sleep_until_start_request_or_inactivity > stop sem_timedwait (start_is_required, err=%d) %d.%09lu \n", err,
tv.tv_sec, tv.tv_usec*1000);
tv.tv_sec, tv.tv_usec*1000);


if (err==0) if (err==0)
{ {


static void close_stream() static void close_stream()
{ {
SHOW_TIME("fifo > close_stream > ENTER\n");
SHOW_TIME("fifo > close_stream > ENTER\n");


// Warning: a wave_close can be already required by
// an external command (espeak_Cancel + fifo_stop), if so:
// my_stop_is_required = 1;
// Warning: a wave_close can be already required by
// an external command (espeak_Cancel + fifo_stop), if so:
// my_stop_is_required = 1;


int a_status = pthread_mutex_lock(&my_mutex);
assert (!a_status);
int a_stop_is_required = my_stop_is_required;
if (!a_stop_is_required)
{
my_command_is_running = 1;
}
a_status = pthread_mutex_unlock(&my_mutex);
int a_status = pthread_mutex_lock(&my_mutex);
assert (!a_status);
int a_stop_is_required = my_stop_is_required;
if (!a_stop_is_required)
{
my_command_is_running = 1;
}
a_status = pthread_mutex_unlock(&my_mutex);


if (!a_stop_is_required)
{
wave_close(NULL);
if (!a_stop_is_required)
{
wave_close(NULL);


int a_status = pthread_mutex_lock(&my_mutex);
assert (!a_status);
my_command_is_running = 0;
int a_status = pthread_mutex_lock(&my_mutex);
assert (!a_status);
my_command_is_running = 0;


a_stop_is_required = my_stop_is_required;
a_status = pthread_mutex_unlock(&my_mutex);
a_stop_is_required = my_stop_is_required;
a_status = pthread_mutex_unlock(&my_mutex);


if (a_stop_is_required)
{
// acknowledge the stop request
SHOW_TIME("fifo > close_stream > post my_sem_stop_is_acknowledged\n");
int a_status = sem_post(&my_sem_stop_is_acknowledged);
assert( a_status != -1);
if (a_stop_is_required)
{
// acknowledge the stop request
SHOW_TIME("fifo > close_stream > post my_sem_stop_is_acknowledged\n");
int a_status = sem_post(&my_sem_stop_is_acknowledged);
assert( a_status != -1);
}
} }
}


SHOW_TIME("fifo > close_stream > LEAVE\n");
SHOW_TIME("fifo > close_stream > LEAVE\n");
} }


static void* say_thread(void*p) static void* say_thread(void*p)
{ {
ENTER("say_thread");

SHOW_TIME("say_thread > post my_sem_stop_is_acknowledged\n");

// announce that thread is started
sem_post(&my_sem_stop_is_acknowledged);
ENTER("say_thread");


int look_for_inactivity=0;
SHOW_TIME("say_thread > post my_sem_stop_is_acknowledged\n");


while(1)
{
SHOW_TIME("say_thread > wait for my_sem_start_is_required\n");
// announce that thread is started
sem_post(&my_sem_stop_is_acknowledged);


int a_start_is_required = 0;
if (look_for_inactivity)
{
a_start_is_required = sleep_until_start_request_or_inactivity();
if (!a_start_is_required)
{
close_stream();
}
}
look_for_inactivity = 1;
int look_for_inactivity=0;


if (!a_start_is_required)
while(1)
{ {
while ((sem_wait(&my_sem_start_is_required) == -1) && errno == EINTR)
{
continue; // Restart when interrupted by handler
}
}
SHOW_TIME("say_thread > get my_sem_start_is_required\n");
SHOW_TIME("say_thread > wait for my_sem_start_is_required\n");


SHOW_TIME("say_thread > my_command_is_running = 1\n");
my_command_is_running = 1;

while( my_command_is_running)
{
SHOW_TIME("say_thread > locking\n");
int a_status = pthread_mutex_lock(&my_mutex);
assert (!a_status);
t_espeak_command* a_command = (t_espeak_command*)pop();

if (a_command == NULL)
{
SHOW_TIME("say_thread > text empty (talking=0) \n");
a_status = pthread_mutex_unlock(&my_mutex);
SHOW_TIME("say_thread > unlocked\n");
SHOW_TIME("say_thread > my_command_is_running = 0\n");
my_command_is_running = 0;
}
else
{
display_espeak_command(a_command);
// purge start semaphore
SHOW_TIME("say_thread > purge my_sem_start_is_required\n");
while(0 == sem_trywait(&my_sem_start_is_required))
int a_start_is_required = 0;
if (look_for_inactivity)
{ {
};
a_start_is_required = sleep_until_start_request_or_inactivity();
if (!a_start_is_required)
{
close_stream();
}
}
look_for_inactivity = 1;


if (my_stop_is_required)
if (!a_start_is_required)
{ {
SHOW_TIME("say_thread > my_command_is_running = 0\n");
my_command_is_running = 0;
while ((sem_wait(&my_sem_start_is_required) == -1) && errno == EINTR)
{
continue; // Restart when interrupted by handler
}
} }
SHOW_TIME("say_thread > unlocking\n");
a_status = pthread_mutex_unlock(&my_mutex);
SHOW_TIME("say_thread > get my_sem_start_is_required\n");

SHOW_TIME("say_thread > my_command_is_running = 1\n");
my_command_is_running = 1;


if (my_command_is_running)
while( my_command_is_running)
{ {
process_espeak_command(a_command);
SHOW_TIME("say_thread > locking\n");
int a_status = pthread_mutex_lock(&my_mutex);
assert (!a_status);
t_espeak_command* a_command = (t_espeak_command*)pop();

if (a_command == NULL)
{
SHOW_TIME("say_thread > text empty (talking=0) \n");
a_status = pthread_mutex_unlock(&my_mutex);
SHOW_TIME("say_thread > unlocked\n");
SHOW_TIME("say_thread > my_command_is_running = 0\n");
my_command_is_running = 0;
}
else
{
display_espeak_command(a_command);
// purge start semaphore
SHOW_TIME("say_thread > purge my_sem_start_is_required\n");
while(0 == sem_trywait(&my_sem_start_is_required))
{
};

if (my_stop_is_required)
{
SHOW_TIME("say_thread > my_command_is_running = 0\n");
my_command_is_running = 0;
}
SHOW_TIME("say_thread > unlocking\n");
a_status = pthread_mutex_unlock(&my_mutex);

if (my_command_is_running)
{
process_espeak_command(a_command);
}
delete_espeak_command(a_command);
}
} }
delete_espeak_command(a_command);
}
}


if (my_stop_is_required)
{
// no mutex required since the stop command is synchronous
// and waiting for my_sem_stop_is_acknowledged
init(1);

// purge start semaphore
SHOW_TIME("say_thread > purge my_sem_start_is_required\n");
while(0==sem_trywait(&my_sem_start_is_required))
{
};

// acknowledge the stop request
SHOW_TIME("say_thread > post my_sem_stop_is_acknowledged\n");
int a_status = sem_post(&my_sem_stop_is_acknowledged);
assert( a_status != -1);
if (my_stop_is_required)
{
// no mutex required since the stop command is synchronous
// and waiting for my_sem_stop_is_acknowledged
init(1);

// purge start semaphore
SHOW_TIME("say_thread > purge my_sem_start_is_required\n");
while(0==sem_trywait(&my_sem_start_is_required))
{
};

// acknowledge the stop request
SHOW_TIME("say_thread > post my_sem_stop_is_acknowledged\n");
int a_status = sem_post(&my_sem_stop_is_acknowledged);
assert( a_status != -1);
}
// and wait for the next start
SHOW_TIME("say_thread > wait for my_sem_start_is_required\n");
} }
// and wait for the next start
SHOW_TIME("say_thread > wait for my_sem_start_is_required\n");
}


return NULL;
return NULL;
} }


int fifo_is_command_enabled() int fifo_is_command_enabled()
{ {
SHOW("ENTER fifo_is_command_enabled=%d\n",(int)(0 == my_stop_is_required));
return (0 == my_stop_is_required);
SHOW("ENTER fifo_is_command_enabled=%d\n",(int)(0 == my_stop_is_required));
return (0 == my_stop_is_required);
} }


typedef struct t_node typedef struct t_node
{ {
t_espeak_command* data;
struct t_node *next;
t_espeak_command* data;
struct t_node *next;
} node; } node;


static node* head=NULL; static node* head=NULL;


static espeak_ERROR push(t_espeak_command* the_command) static espeak_ERROR push(t_espeak_command* the_command)
{ {
ENTER("fifo > push");
assert((!head && !tail) || (head && tail));
if (the_command == NULL)
{
SHOW("push > command=0x%x\n", NULL);
return EE_INTERNAL_ERROR;
}
if (node_counter >= MAX_NODE_COUNTER)
{
SHOW("push > %s\n", "EE_BUFFER_FULL");
return EE_BUFFER_FULL;
}
node *n = (node *)malloc(sizeof(node));
if (n == NULL)
{
return EE_INTERNAL_ERROR;
}
if (head == NULL)
{
head = n;
tail = n;
}
else
{
tail->next = n;
tail = n;
}
tail->next = NULL;
tail->data = the_command;
node_counter++;
SHOW("push > counter=%d\n",node_counter);
the_command->state = CS_PENDING;
display_espeak_command(the_command);
return EE_OK;
ENTER("fifo > push");
assert((!head && !tail) || (head && tail));
if (the_command == NULL)
{
SHOW("push > command=0x%x\n", NULL);
return EE_INTERNAL_ERROR;
}
if (node_counter >= MAX_NODE_COUNTER)
{
SHOW("push > %s\n", "EE_BUFFER_FULL");
return EE_BUFFER_FULL;
}
node *n = (node *)malloc(sizeof(node));
if (n == NULL)
{
return EE_INTERNAL_ERROR;
}
if (head == NULL)
{
head = n;
tail = n;
}
else
{
tail->next = n;
tail = n;
}
tail->next = NULL;
tail->data = the_command;
node_counter++;
SHOW("push > counter=%d\n",node_counter);
the_command->state = CS_PENDING;
display_espeak_command(the_command);
return EE_OK;
} }


static t_espeak_command* pop() static t_espeak_command* pop()
{ {
ENTER("fifo > pop");
t_espeak_command* the_command = NULL;
ENTER("fifo > pop");
t_espeak_command* the_command = NULL;


assert((!head && !tail) || (head && tail));
assert((!head && !tail) || (head && tail));


if (head != NULL)
{
node* n = head;
the_command = n->data;
head = n->next;
free(n);
node_counter--;
SHOW("pop > command=0x%x (counter=%d)\n",the_command, node_counter);
}
if (head != NULL)
{
node* n = head;
the_command = n->data;
head = n->next;
free(n);
node_counter--;
SHOW("pop > command=0x%x (counter=%d)\n",the_command, node_counter);
}


if(head == NULL)
{
tail = NULL;
}
if(head == NULL)
{
tail = NULL;
}


display_espeak_command(the_command);
display_espeak_command(the_command);


return the_command;
return the_command;
} }


static void init(int process_parameters) static void init(int process_parameters)


void fifo_terminate() void fifo_terminate()
{ {
ENTER("fifo_terminate");
ENTER("fifo_terminate");


pthread_cancel(my_thread);
pthread_join(my_thread,NULL);
pthread_mutex_destroy(&my_mutex);
sem_destroy(&my_sem_start_is_required);
sem_destroy(&my_sem_stop_is_acknowledged);
pthread_cancel(my_thread);
pthread_join(my_thread,NULL);
pthread_mutex_destroy(&my_mutex);
sem_destroy(&my_sem_start_is_required);
sem_destroy(&my_sem_stop_is_acknowledged);


init(0); // purge fifo
init(0); // purge fifo
} }

+ 10
- 10
src/libespeak-ng/fifo.h View File

#ifndef FIFO_H #ifndef FIFO_H
#define FIFO_H #define FIFO_H


// Helps to add espeak commands in a first-in first-out queue
// Helps to add espeak commands in a first-in first-out queue
// and run them asynchronously. // and run them asynchronously.


#include "espeak_command.h" #include "espeak_command.h"
// Add an espeak command. // Add an espeak command.
// //
// Note: this function fails if too many commands are already buffered. // Note: this function fails if too many commands are already buffered.
// In such a case, the calling function could wait and then add again its command.
// In such a case, the calling function could wait and then add again its command.
// //
// Return: EE_OK: operation achieved
// EE_BUFFER_FULL: the command can not be buffered;
// Return: EE_OK: operation achieved
// EE_BUFFER_FULL: the command can not be buffered;
// you may try after a while to call the function again. // you may try after a while to call the function again.
// EE_INTERNAL_ERROR. // EE_INTERNAL_ERROR.
espeak_ERROR fifo_add_command (t_espeak_command* c); espeak_ERROR fifo_add_command (t_espeak_command* c);
// Add two espeak commands in a single transaction. // Add two espeak commands in a single transaction.
// //
// Note: this function fails if too many commands are already buffered. // Note: this function fails if too many commands are already buffered.
// In such a case, the calling function could wait and then add again these commands.
// In such a case, the calling function could wait and then add again these commands.
// //
// Return: EE_OK: operation achieved
// EE_BUFFER_FULL: at least one command can not be buffered;
// Return: EE_OK: operation achieved
// EE_BUFFER_FULL: at least one command can not be buffered;
// you may try after a while to call the function again. // you may try after a while to call the function again.
// EE_INTERNAL_ERROR. // EE_INTERNAL_ERROR.
espeak_ERROR fifo_add_commands (t_espeak_command* c1, t_espeak_command* c2); espeak_ERROR fifo_add_commands (t_espeak_command* c1, t_espeak_command* c2);


// The current running command must be stopped and the awaiting commands are cleared. // The current running command must be stopped and the awaiting commands are cleared.
// Return: EE_OK: operation achieved
// Return: EE_OK: operation achieved
// EE_INTERNAL_ERROR. // EE_INTERNAL_ERROR.
espeak_ERROR fifo_stop (); espeak_ERROR fifo_stop ();


// Indicates if the running command is still enabled. // Indicates if the running command is still enabled.
// //
// Note: this function is mainly called by the SynthCallback (speak_lib.cpp) // Note: this function is mainly called by the SynthCallback (speak_lib.cpp)
// It indicates if the actual wave sample can still be played. It is helpful for
// stopping speech as soon as a cancel command is applied.
// It indicates if the actual wave sample can still be played. It is helpful for
// stopping speech as soon as a cancel command is applied.
// //
// Returns 1 if yes, or 0 otherwise. // Returns 1 if yes, or 0 otherwise.
int fifo_is_command_enabled(); int fifo_is_command_enabled();

+ 214
- 202
src/libespeak-ng/intonation.c View File



/* Note this module is mostly old code that needs to be rewritten to /* Note this module is mostly old code that needs to be rewritten to
provide a more flexible intonation system. provide a more flexible intonation system.
*/
*/


// bits in SYLLABLE.flags // bits in SYLLABLE.flags
#define SYL_RISE 1 #define SYL_RISE 1


/* 0 fall */ /* 0 fall */
unsigned char env_fall[128] = { unsigned char env_fall[128] = {
0xff, 0xfd, 0xfa, 0xf8, 0xf6, 0xf4, 0xf2, 0xf0, 0xee, 0xec, 0xea, 0xe8, 0xe6, 0xe4, 0xe2, 0xe0,
0xde, 0xdc, 0xda, 0xd8, 0xd6, 0xd4, 0xd2, 0xd0, 0xce, 0xcc, 0xca, 0xc8, 0xc6, 0xc4, 0xc2, 0xc0,
0xbe, 0xbc, 0xba, 0xb8, 0xb6, 0xb4, 0xb2, 0xb0, 0xae, 0xac, 0xaa, 0xa8, 0xa6, 0xa4, 0xa2, 0xa0,
0x9e, 0x9c, 0x9a, 0x98, 0x96, 0x94, 0x92, 0x90, 0x8e, 0x8c, 0x8a, 0x88, 0x86, 0x84, 0x82, 0x80,
0x7e, 0x7c, 0x7a, 0x78, 0x76, 0x74, 0x72, 0x70, 0x6e, 0x6c, 0x6a, 0x68, 0x66, 0x64, 0x62, 0x60,
0x5e, 0x5c, 0x5a, 0x58, 0x56, 0x54, 0x52, 0x50, 0x4e, 0x4c, 0x4a, 0x48, 0x46, 0x44, 0x42, 0x40,
0x3e, 0x3c, 0x3a, 0x38, 0x36, 0x34, 0x32, 0x30, 0x2e, 0x2c, 0x2a, 0x28, 0x26, 0x24, 0x22, 0x20,
0x1e, 0x1c, 0x1a, 0x18, 0x16, 0x14, 0x12, 0x10, 0x0e, 0x0c, 0x0a, 0x08, 0x06, 0x04, 0x02, 0x00 };
0xff, 0xfd, 0xfa, 0xf8, 0xf6, 0xf4, 0xf2, 0xf0, 0xee, 0xec, 0xea, 0xe8, 0xe6, 0xe4, 0xe2, 0xe0,
0xde, 0xdc, 0xda, 0xd8, 0xd6, 0xd4, 0xd2, 0xd0, 0xce, 0xcc, 0xca, 0xc8, 0xc6, 0xc4, 0xc2, 0xc0,
0xbe, 0xbc, 0xba, 0xb8, 0xb6, 0xb4, 0xb2, 0xb0, 0xae, 0xac, 0xaa, 0xa8, 0xa6, 0xa4, 0xa2, 0xa0,
0x9e, 0x9c, 0x9a, 0x98, 0x96, 0x94, 0x92, 0x90, 0x8e, 0x8c, 0x8a, 0x88, 0x86, 0x84, 0x82, 0x80,
0x7e, 0x7c, 0x7a, 0x78, 0x76, 0x74, 0x72, 0x70, 0x6e, 0x6c, 0x6a, 0x68, 0x66, 0x64, 0x62, 0x60,
0x5e, 0x5c, 0x5a, 0x58, 0x56, 0x54, 0x52, 0x50, 0x4e, 0x4c, 0x4a, 0x48, 0x46, 0x44, 0x42, 0x40,
0x3e, 0x3c, 0x3a, 0x38, 0x36, 0x34, 0x32, 0x30, 0x2e, 0x2c, 0x2a, 0x28, 0x26, 0x24, 0x22, 0x20,
0x1e, 0x1c, 0x1a, 0x18, 0x16, 0x14, 0x12, 0x10, 0x0e, 0x0c, 0x0a, 0x08, 0x06, 0x04, 0x02, 0x00
};


/* 1 rise */ /* 1 rise */
unsigned char env_rise[128] = { unsigned char env_rise[128] = {
0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,
0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e,
0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e,
0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e,
0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e,
0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe,
0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde,
0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfd, 0xff };
0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,
0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e,
0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e,
0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e,
0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e,
0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe,
0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde,
0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfd, 0xff
};


unsigned char env_frise[128] = { unsigned char env_frise[128] = {
0xff, 0xf4, 0xea, 0xe0, 0xd6, 0xcc, 0xc3, 0xba, 0xb1, 0xa8, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x78,
0x71, 0x6a, 0x63, 0x5c, 0x56, 0x50, 0x4a, 0x44, 0x3f, 0x39, 0x34, 0x2f, 0x2b, 0x26, 0x22, 0x1e,
0x1a, 0x17, 0x13, 0x10, 0x0d, 0x0b, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x07, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x13, 0x15, 0x17,
0x1a, 0x1d, 0x1f, 0x22, 0x25, 0x28, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x39, 0x3b, 0x3d, 0x40,
0x42, 0x45, 0x47, 0x4a, 0x4c, 0x4f, 0x51, 0x54, 0x57, 0x5a, 0x5d, 0x5f, 0x62, 0x65, 0x68, 0x6b,
0x6e, 0x71, 0x74, 0x78, 0x7b, 0x7e, 0x81, 0x85, 0x88, 0x8b, 0x8f, 0x92, 0x96, 0x99, 0x9d, 0xa0,
0xa4, 0xa8, 0xac, 0xaf, 0xb3, 0xb7, 0xbb, 0xbf, 0xc3, 0xc7, 0xcb, 0xcf, 0xd3, 0xd7, 0xdb, 0xe0 };
0xff, 0xf4, 0xea, 0xe0, 0xd6, 0xcc, 0xc3, 0xba, 0xb1, 0xa8, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x78,
0x71, 0x6a, 0x63, 0x5c, 0x56, 0x50, 0x4a, 0x44, 0x3f, 0x39, 0x34, 0x2f, 0x2b, 0x26, 0x22, 0x1e,
0x1a, 0x17, 0x13, 0x10, 0x0d, 0x0b, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x07, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x13, 0x15, 0x17,
0x1a, 0x1d, 0x1f, 0x22, 0x25, 0x28, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x39, 0x3b, 0x3d, 0x40,
0x42, 0x45, 0x47, 0x4a, 0x4c, 0x4f, 0x51, 0x54, 0x57, 0x5a, 0x5d, 0x5f, 0x62, 0x65, 0x68, 0x6b,
0x6e, 0x71, 0x74, 0x78, 0x7b, 0x7e, 0x81, 0x85, 0x88, 0x8b, 0x8f, 0x92, 0x96, 0x99, 0x9d, 0xa0,
0xa4, 0xa8, 0xac, 0xaf, 0xb3, 0xb7, 0xbb, 0xbf, 0xc3, 0xc7, 0xcb, 0xcf, 0xd3, 0xd7, 0xdb, 0xe0
};


static unsigned char env_r_frise[128] = { static unsigned char env_r_frise[128] = {
0xcf, 0xcc, 0xc9, 0xc6, 0xc3, 0xc0, 0xbd, 0xb9, 0xb4, 0xb0, 0xab, 0xa7, 0xa2, 0x9c, 0x97, 0x92,
0x8c, 0x86, 0x81, 0x7b, 0x75, 0x6f, 0x69, 0x63, 0x5d, 0x57, 0x50, 0x4a, 0x44, 0x3e, 0x38, 0x33,
0x2d, 0x27, 0x22, 0x1c, 0x17, 0x12, 0x0d, 0x08, 0x04, 0x02, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x01, 0x02, 0x03, 0x04, 0x05, 0x07, 0x08, 0x0a, 0x0c, 0x0d, 0x0f, 0x12, 0x14, 0x16,
0x19, 0x1b, 0x1e, 0x21, 0x24, 0x27, 0x2a, 0x2d, 0x30, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3f, 0x41,
0x43, 0x46, 0x48, 0x4b, 0x4d, 0x50, 0x52, 0x55, 0x58, 0x5a, 0x5d, 0x60, 0x63, 0x66, 0x69, 0x6c,
0x6f, 0x72, 0x75, 0x78, 0x7b, 0x7e, 0x81, 0x85, 0x88, 0x8b, 0x8f, 0x92, 0x96, 0x99, 0x9d, 0xa0,
0xa4, 0xa8, 0xac, 0xaf, 0xb3, 0xb7, 0xbb, 0xbf, 0xc3, 0xc7, 0xcb, 0xcf, 0xd3, 0xd7, 0xdb, 0xe0 };
0xcf, 0xcc, 0xc9, 0xc6, 0xc3, 0xc0, 0xbd, 0xb9, 0xb4, 0xb0, 0xab, 0xa7, 0xa2, 0x9c, 0x97, 0x92,
0x8c, 0x86, 0x81, 0x7b, 0x75, 0x6f, 0x69, 0x63, 0x5d, 0x57, 0x50, 0x4a, 0x44, 0x3e, 0x38, 0x33,
0x2d, 0x27, 0x22, 0x1c, 0x17, 0x12, 0x0d, 0x08, 0x04, 0x02, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x01, 0x02, 0x03, 0x04, 0x05, 0x07, 0x08, 0x0a, 0x0c, 0x0d, 0x0f, 0x12, 0x14, 0x16,
0x19, 0x1b, 0x1e, 0x21, 0x24, 0x27, 0x2a, 0x2d, 0x30, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3f, 0x41,
0x43, 0x46, 0x48, 0x4b, 0x4d, 0x50, 0x52, 0x55, 0x58, 0x5a, 0x5d, 0x60, 0x63, 0x66, 0x69, 0x6c,
0x6f, 0x72, 0x75, 0x78, 0x7b, 0x7e, 0x81, 0x85, 0x88, 0x8b, 0x8f, 0x92, 0x96, 0x99, 0x9d, 0xa0,
0xa4, 0xa8, 0xac, 0xaf, 0xb3, 0xb7, 0xbb, 0xbf, 0xc3, 0xc7, 0xcb, 0xcf, 0xd3, 0xd7, 0xdb, 0xe0
};


static unsigned char env_frise2[128] = { static unsigned char env_frise2[128] = {
0xff, 0xf9, 0xf4, 0xee, 0xe9, 0xe4, 0xdf, 0xda, 0xd5, 0xd0, 0xcb, 0xc6, 0xc1, 0xbd, 0xb8, 0xb3,
0xaf, 0xaa, 0xa6, 0xa1, 0x9d, 0x99, 0x95, 0x90, 0x8c, 0x88, 0x84, 0x80, 0x7d, 0x79, 0x75, 0x71,
0x6e, 0x6a, 0x67, 0x63, 0x60, 0x5d, 0x59, 0x56, 0x53, 0x50, 0x4d, 0x4a, 0x47, 0x44, 0x41, 0x3e,
0x3c, 0x39, 0x37, 0x34, 0x32, 0x2f, 0x2d, 0x2b, 0x28, 0x26, 0x24, 0x22, 0x20, 0x1e, 0x1c, 0x1a,
0x19, 0x17, 0x15, 0x14, 0x12, 0x11, 0x0f, 0x0e, 0x0d, 0x0c, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05,
0x05, 0x04, 0x03, 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x04, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09, 0x0a, 0x0b, 0x0c, 0x0e, 0x0f, 0x10, 0x12, 0x13, 0x15, 0x17, 0x18, 0x1a, 0x1c, 0x1e, 0x20 };
0xff, 0xf9, 0xf4, 0xee, 0xe9, 0xe4, 0xdf, 0xda, 0xd5, 0xd0, 0xcb, 0xc6, 0xc1, 0xbd, 0xb8, 0xb3,
0xaf, 0xaa, 0xa6, 0xa1, 0x9d, 0x99, 0x95, 0x90, 0x8c, 0x88, 0x84, 0x80, 0x7d, 0x79, 0x75, 0x71,
0x6e, 0x6a, 0x67, 0x63, 0x60, 0x5d, 0x59, 0x56, 0x53, 0x50, 0x4d, 0x4a, 0x47, 0x44, 0x41, 0x3e,
0x3c, 0x39, 0x37, 0x34, 0x32, 0x2f, 0x2d, 0x2b, 0x28, 0x26, 0x24, 0x22, 0x20, 0x1e, 0x1c, 0x1a,
0x19, 0x17, 0x15, 0x14, 0x12, 0x11, 0x0f, 0x0e, 0x0d, 0x0c, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05,
0x05, 0x04, 0x03, 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x04, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09, 0x0a, 0x0b, 0x0c, 0x0e, 0x0f, 0x10, 0x12, 0x13, 0x15, 0x17, 0x18, 0x1a, 0x1c, 0x1e, 0x20
};


static unsigned char env_r_frise2[128] = { static unsigned char env_r_frise2[128] = {
0xd0, 0xce, 0xcd, 0xcc, 0xca, 0xc8, 0xc7, 0xc5, 0xc3, 0xc1, 0xc0, 0xbd, 0xbb, 0xb8, 0xb5, 0xb3,
0xb0, 0xad, 0xaa, 0xa7, 0xa3, 0xa0, 0x9d, 0x99, 0x96, 0x92, 0x8f, 0x8b, 0x87, 0x84, 0x80, 0x7c,
0x78, 0x74, 0x70, 0x6d, 0x69, 0x65, 0x61, 0x5d, 0x59, 0x55, 0x51, 0x4d, 0x4a, 0x46, 0x42, 0x3e,
0x3b, 0x37, 0x34, 0x31, 0x2f, 0x2d, 0x2a, 0x28, 0x26, 0x24, 0x22, 0x20, 0x1e, 0x1c, 0x1a, 0x19,
0x17, 0x15, 0x14, 0x12, 0x11, 0x0f, 0x0e, 0x0d, 0x0c, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x05,
0x04, 0x03, 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x04, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09, 0x0a, 0x0b, 0x0c, 0x0e, 0x0f, 0x10, 0x12, 0x13, 0x15, 0x17, 0x18, 0x1a, 0x1c, 0x1e, 0x20 };
0xd0, 0xce, 0xcd, 0xcc, 0xca, 0xc8, 0xc7, 0xc5, 0xc3, 0xc1, 0xc0, 0xbd, 0xbb, 0xb8, 0xb5, 0xb3,
0xb0, 0xad, 0xaa, 0xa7, 0xa3, 0xa0, 0x9d, 0x99, 0x96, 0x92, 0x8f, 0x8b, 0x87, 0x84, 0x80, 0x7c,
0x78, 0x74, 0x70, 0x6d, 0x69, 0x65, 0x61, 0x5d, 0x59, 0x55, 0x51, 0x4d, 0x4a, 0x46, 0x42, 0x3e,
0x3b, 0x37, 0x34, 0x31, 0x2f, 0x2d, 0x2a, 0x28, 0x26, 0x24, 0x22, 0x20, 0x1e, 0x1c, 0x1a, 0x19,
0x17, 0x15, 0x14, 0x12, 0x11, 0x0f, 0x0e, 0x0d, 0x0c, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x05,
0x04, 0x03, 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x04, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09, 0x0a, 0x0b, 0x0c, 0x0e, 0x0f, 0x10, 0x12, 0x13, 0x15, 0x17, 0x18, 0x1a, 0x1c, 0x1e, 0x20
};


static unsigned char env_risefall[128] = { static unsigned char env_risefall[128] = {
0x98, 0x99, 0x99, 0x9a, 0x9c, 0x9d, 0x9f, 0xa1, 0xa4, 0xa7, 0xa9, 0xac, 0xb0, 0xb3, 0xb6, 0xba,
0xbe, 0xc1, 0xc5, 0xc9, 0xcd, 0xd1, 0xd4, 0xd8, 0xdc, 0xdf, 0xe3, 0xe6, 0xea, 0xed, 0xf0, 0xf2,
0xf5, 0xf7, 0xf9, 0xfb, 0xfc, 0xfd, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfd,
0xfb, 0xfa, 0xf8, 0xf6, 0xf3, 0xf1, 0xee, 0xec, 0xe9, 0xe6, 0xe4, 0xe0, 0xdd, 0xda, 0xd7, 0xd3,
0xd0, 0xcc, 0xc8, 0xc4, 0xc0, 0xbc, 0xb8, 0xb4, 0xb0, 0xac, 0xa7, 0xa3, 0x9f, 0x9a, 0x96, 0x91,
0x8d, 0x88, 0x84, 0x7f, 0x7b, 0x76, 0x72, 0x6d, 0x69, 0x65, 0x60, 0x5c, 0x58, 0x54, 0x50, 0x4c,
0x48, 0x44, 0x40, 0x3c, 0x39, 0x35, 0x32, 0x2f, 0x2b, 0x28, 0x26, 0x23, 0x20, 0x1d, 0x1a, 0x17,
0x15, 0x12, 0x0f, 0x0d, 0x0a, 0x08, 0x07, 0x05, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 };
0x98, 0x99, 0x99, 0x9a, 0x9c, 0x9d, 0x9f, 0xa1, 0xa4, 0xa7, 0xa9, 0xac, 0xb0, 0xb3, 0xb6, 0xba,
0xbe, 0xc1, 0xc5, 0xc9, 0xcd, 0xd1, 0xd4, 0xd8, 0xdc, 0xdf, 0xe3, 0xe6, 0xea, 0xed, 0xf0, 0xf2,
0xf5, 0xf7, 0xf9, 0xfb, 0xfc, 0xfd, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfd,
0xfb, 0xfa, 0xf8, 0xf6, 0xf3, 0xf1, 0xee, 0xec, 0xe9, 0xe6, 0xe4, 0xe0, 0xdd, 0xda, 0xd7, 0xd3,
0xd0, 0xcc, 0xc8, 0xc4, 0xc0, 0xbc, 0xb8, 0xb4, 0xb0, 0xac, 0xa7, 0xa3, 0x9f, 0x9a, 0x96, 0x91,
0x8d, 0x88, 0x84, 0x7f, 0x7b, 0x76, 0x72, 0x6d, 0x69, 0x65, 0x60, 0x5c, 0x58, 0x54, 0x50, 0x4c,
0x48, 0x44, 0x40, 0x3c, 0x39, 0x35, 0x32, 0x2f, 0x2b, 0x28, 0x26, 0x23, 0x20, 0x1d, 0x1a, 0x17,
0x15, 0x12, 0x0f, 0x0d, 0x0a, 0x08, 0x07, 0x05, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00
};


static unsigned char env_rise2[128] = { static unsigned char env_rise2[128] = {
0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, 0x04, 0x05, 0x06, 0x06,
0x07, 0x08, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
0x16, 0x17, 0x18, 0x19, 0x1b, 0x1c, 0x1d, 0x1f, 0x20, 0x22, 0x23, 0x25, 0x26, 0x28, 0x29, 0x2b,
0x2d, 0x2f, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e, 0x40, 0x42, 0x44, 0x47, 0x49, 0x4b,
0x4e, 0x50, 0x52, 0x55, 0x57, 0x5a, 0x5d, 0x5f, 0x62, 0x65, 0x67, 0x6a, 0x6d, 0x70, 0x73, 0x76,
0x79, 0x7c, 0x7f, 0x82, 0x86, 0x89, 0x8c, 0x90, 0x93, 0x96, 0x9a, 0x9d, 0xa0, 0xa3, 0xa6, 0xa9,
0xac, 0xaf, 0xb2, 0xb5, 0xb8, 0xbb, 0xbe, 0xc1, 0xc4, 0xc7, 0xca, 0xcd, 0xd0, 0xd3, 0xd6, 0xd9,
0xdc, 0xdf, 0xe2, 0xe4, 0xe7, 0xe9, 0xec, 0xee, 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfb, 0xfd };
0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, 0x04, 0x05, 0x06, 0x06,
0x07, 0x08, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
0x16, 0x17, 0x18, 0x19, 0x1b, 0x1c, 0x1d, 0x1f, 0x20, 0x22, 0x23, 0x25, 0x26, 0x28, 0x29, 0x2b,
0x2d, 0x2f, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e, 0x40, 0x42, 0x44, 0x47, 0x49, 0x4b,
0x4e, 0x50, 0x52, 0x55, 0x57, 0x5a, 0x5d, 0x5f, 0x62, 0x65, 0x67, 0x6a, 0x6d, 0x70, 0x73, 0x76,
0x79, 0x7c, 0x7f, 0x82, 0x86, 0x89, 0x8c, 0x90, 0x93, 0x96, 0x9a, 0x9d, 0xa0, 0xa3, 0xa6, 0xa9,
0xac, 0xaf, 0xb2, 0xb5, 0xb8, 0xbb, 0xbe, 0xc1, 0xc4, 0xc7, 0xca, 0xcd, 0xd0, 0xd3, 0xd6, 0xd9,
0xdc, 0xdf, 0xe2, 0xe4, 0xe7, 0xe9, 0xec, 0xee, 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfb, 0xfd
};


static unsigned char env_fall2[128] = { static unsigned char env_fall2[128] = {
0xfe, 0xfe, 0xfd, 0xfd, 0xfc, 0xfb, 0xfb, 0xfa, 0xfa, 0xf9, 0xf8, 0xf8, 0xf7, 0xf7, 0xf6, 0xf6,
0xf5, 0xf4, 0xf4, 0xf3, 0xf3, 0xf2, 0xf2, 0xf1, 0xf0, 0xf0, 0xef, 0xee, 0xee, 0xed, 0xec, 0xeb,
0xea, 0xea, 0xe9, 0xe8, 0xe7, 0xe6, 0xe5, 0xe4, 0xe3, 0xe2, 0xe1, 0xe0, 0xde, 0xdd, 0xdc, 0xdb,
0xd9, 0xd8, 0xd6, 0xd5, 0xd3, 0xd2, 0xd0, 0xce, 0xcc, 0xcb, 0xc9, 0xc7, 0xc5, 0xc3, 0xc0, 0xbe,
0xbc, 0xb9, 0xb7, 0xb5, 0xb2, 0xaf, 0xad, 0xaa, 0xa7, 0xa4, 0xa1, 0x9e, 0x9a, 0x97, 0x94, 0x90,
0x8d, 0x89, 0x85, 0x81, 0x7d, 0x79, 0x75, 0x71, 0x6d, 0x68, 0x64, 0x61, 0x5e, 0x5b, 0x57, 0x54,
0x51, 0x4d, 0x4a, 0x46, 0x43, 0x40, 0x3c, 0x39, 0x35, 0x32, 0x2e, 0x2a, 0x27, 0x23, 0x1f, 0x1c,
0x18, 0x14, 0x11, 0x0d, 0x0b, 0x09, 0x07, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00 };
0xfe, 0xfe, 0xfd, 0xfd, 0xfc, 0xfb, 0xfb, 0xfa, 0xfa, 0xf9, 0xf8, 0xf8, 0xf7, 0xf7, 0xf6, 0xf6,
0xf5, 0xf4, 0xf4, 0xf3, 0xf3, 0xf2, 0xf2, 0xf1, 0xf0, 0xf0, 0xef, 0xee, 0xee, 0xed, 0xec, 0xeb,
0xea, 0xea, 0xe9, 0xe8, 0xe7, 0xe6, 0xe5, 0xe4, 0xe3, 0xe2, 0xe1, 0xe0, 0xde, 0xdd, 0xdc, 0xdb,
0xd9, 0xd8, 0xd6, 0xd5, 0xd3, 0xd2, 0xd0, 0xce, 0xcc, 0xcb, 0xc9, 0xc7, 0xc5, 0xc3, 0xc0, 0xbe,
0xbc, 0xb9, 0xb7, 0xb5, 0xb2, 0xaf, 0xad, 0xaa, 0xa7, 0xa4, 0xa1, 0x9e, 0x9a, 0x97, 0x94, 0x90,
0x8d, 0x89, 0x85, 0x81, 0x7d, 0x79, 0x75, 0x71, 0x6d, 0x68, 0x64, 0x61, 0x5e, 0x5b, 0x57, 0x54,
0x51, 0x4d, 0x4a, 0x46, 0x43, 0x40, 0x3c, 0x39, 0x35, 0x32, 0x2e, 0x2a, 0x27, 0x23, 0x1f, 0x1c,
0x18, 0x14, 0x11, 0x0d, 0x0b, 0x09, 0x07, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00
};


static unsigned char env_fallrise3[128] = { static unsigned char env_fallrise3[128] = {
0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf4, 0xf1, 0xee, 0xeb,
0xe8, 0xe5, 0xe1, 0xde, 0xda, 0xd6, 0xd2, 0xcd, 0xc9, 0xc4, 0xbf, 0xba, 0xb6, 0xb0, 0xab, 0xa6,
0xa1, 0x9c, 0x96, 0x91, 0x8b, 0x86, 0x80, 0x7b, 0x75, 0x6f, 0x6a, 0x64, 0x5f, 0x59, 0x54, 0x4f,
0x49, 0x44, 0x3f, 0x3a, 0x35, 0x30, 0x2b, 0x26, 0x22, 0x1d, 0x19, 0x15, 0x11, 0x0d, 0x0a, 0x07,
0x04, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x04, 0x05,
0x07, 0x09, 0x0b, 0x0d, 0x10, 0x12, 0x15, 0x18, 0x1b, 0x1e, 0x22, 0x25, 0x29, 0x2d, 0x31, 0x35,
0x3a, 0x3e, 0x43, 0x48, 0x4c, 0x51, 0x57, 0x5b, 0x5e, 0x62, 0x65, 0x68, 0x6b, 0x6e, 0x71, 0x74,
0x76, 0x78, 0x7b, 0x7c, 0x7e, 0x80, 0x81, 0x82, 0x83, 0x83, 0x84, 0x84, 0x83, 0x83, 0x82, 0x81 };
0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf4, 0xf1, 0xee, 0xeb,
0xe8, 0xe5, 0xe1, 0xde, 0xda, 0xd6, 0xd2, 0xcd, 0xc9, 0xc4, 0xbf, 0xba, 0xb6, 0xb0, 0xab, 0xa6,
0xa1, 0x9c, 0x96, 0x91, 0x8b, 0x86, 0x80, 0x7b, 0x75, 0x6f, 0x6a, 0x64, 0x5f, 0x59, 0x54, 0x4f,
0x49, 0x44, 0x3f, 0x3a, 0x35, 0x30, 0x2b, 0x26, 0x22, 0x1d, 0x19, 0x15, 0x11, 0x0d, 0x0a, 0x07,
0x04, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x04, 0x05,
0x07, 0x09, 0x0b, 0x0d, 0x10, 0x12, 0x15, 0x18, 0x1b, 0x1e, 0x22, 0x25, 0x29, 0x2d, 0x31, 0x35,
0x3a, 0x3e, 0x43, 0x48, 0x4c, 0x51, 0x57, 0x5b, 0x5e, 0x62, 0x65, 0x68, 0x6b, 0x6e, 0x71, 0x74,
0x76, 0x78, 0x7b, 0x7c, 0x7e, 0x80, 0x81, 0x82, 0x83, 0x83, 0x84, 0x84, 0x83, 0x83, 0x82, 0x81
};


static unsigned char env_fallrise4[128] = { static unsigned char env_fallrise4[128] = {
0x72, 0x72, 0x71, 0x71, 0x70, 0x6f, 0x6d, 0x6c, 0x6a, 0x68, 0x66, 0x64, 0x61, 0x5f, 0x5c, 0x5a,
0x57, 0x54, 0x51, 0x4e, 0x4b, 0x48, 0x45, 0x42, 0x3f, 0x3b, 0x38, 0x35, 0x32, 0x2f, 0x2c, 0x29,
0x26, 0x23, 0x20, 0x1d, 0x1b, 0x18, 0x16, 0x14, 0x12, 0x10, 0x0e, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x06,
0x07, 0x07, 0x08, 0x09, 0x0a, 0x0c, 0x0d, 0x0f, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1b, 0x1d, 0x20,
0x23, 0x26, 0x29, 0x2c, 0x2f, 0x33, 0x37, 0x3b, 0x3f, 0x43, 0x47, 0x4c, 0x51, 0x56, 0x5b, 0x60,
0x65, 0x6a, 0x6f, 0x74, 0x79, 0x7f, 0x84, 0x89, 0x8f, 0x95, 0x9b, 0xa1, 0xa7, 0xad, 0xb3, 0xba,
0xc0, 0xc7, 0xce, 0xd5, 0xdc, 0xe3, 0xea, 0xf1, 0xf5, 0xf7, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xff };
0x72, 0x72, 0x71, 0x71, 0x70, 0x6f, 0x6d, 0x6c, 0x6a, 0x68, 0x66, 0x64, 0x61, 0x5f, 0x5c, 0x5a,
0x57, 0x54, 0x51, 0x4e, 0x4b, 0x48, 0x45, 0x42, 0x3f, 0x3b, 0x38, 0x35, 0x32, 0x2f, 0x2c, 0x29,
0x26, 0x23, 0x20, 0x1d, 0x1b, 0x18, 0x16, 0x14, 0x12, 0x10, 0x0e, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x06,
0x07, 0x07, 0x08, 0x09, 0x0a, 0x0c, 0x0d, 0x0f, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1b, 0x1d, 0x20,
0x23, 0x26, 0x29, 0x2c, 0x2f, 0x33, 0x37, 0x3b, 0x3f, 0x43, 0x47, 0x4c, 0x51, 0x56, 0x5b, 0x60,
0x65, 0x6a, 0x6f, 0x74, 0x79, 0x7f, 0x84, 0x89, 0x8f, 0x95, 0x9b, 0xa1, 0xa7, 0xad, 0xb3, 0xba,
0xc0, 0xc7, 0xce, 0xd5, 0xdc, 0xe3, 0xea, 0xf1, 0xf5, 0xf7, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xff
};


static unsigned char env_risefallrise[128] = { static unsigned char env_risefallrise[128] = {
0x7f, 0x7f, 0x7f, 0x80, 0x81, 0x83, 0x84, 0x87, 0x89, 0x8c, 0x8f, 0x92, 0x96, 0x99, 0x9d, 0xa1,
0xa5, 0xaa, 0xae, 0xb2, 0xb7, 0xbb, 0xc0, 0xc5, 0xc9, 0xcd, 0xd2, 0xd6, 0xda, 0xde, 0xe2, 0xe6,
0xea, 0xed, 0xf0, 0xf3, 0xf5, 0xf8, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xfe, 0xfd, 0xfc, 0xfb, 0xf9,
0xf7, 0xf4, 0xf0, 0xec, 0xe7, 0xe2, 0xdc, 0xd5, 0xce, 0xc6, 0xbd, 0xb4, 0xa9, 0x9e, 0x92, 0x88,
0x82, 0x7d, 0x77, 0x72, 0x6c, 0x66, 0x60, 0x5a, 0x54, 0x4e, 0x49, 0x42, 0x3c, 0x37, 0x32, 0x2d,
0x28, 0x24, 0x1f, 0x1b, 0x18, 0x14, 0x11, 0x0e, 0x0c, 0x09, 0x07, 0x06, 0x05, 0x04, 0x04, 0x04,
0x04, 0x05, 0x06, 0x08, 0x0a, 0x0d, 0x10, 0x14, 0x18, 0x1d, 0x23, 0x29, 0x2f, 0x37, 0x3e, 0x47,
0x50, 0x5a, 0x64, 0x70, 0x7c, 0x83, 0x85, 0x88, 0x8a, 0x8c, 0x8e, 0x8f, 0x91, 0x92, 0x93, 0x93 };
0x7f, 0x7f, 0x7f, 0x80, 0x81, 0x83, 0x84, 0x87, 0x89, 0x8c, 0x8f, 0x92, 0x96, 0x99, 0x9d, 0xa1,
0xa5, 0xaa, 0xae, 0xb2, 0xb7, 0xbb, 0xc0, 0xc5, 0xc9, 0xcd, 0xd2, 0xd6, 0xda, 0xde, 0xe2, 0xe6,
0xea, 0xed, 0xf0, 0xf3, 0xf5, 0xf8, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xfe, 0xfd, 0xfc, 0xfb, 0xf9,
0xf7, 0xf4, 0xf0, 0xec, 0xe7, 0xe2, 0xdc, 0xd5, 0xce, 0xc6, 0xbd, 0xb4, 0xa9, 0x9e, 0x92, 0x88,
0x82, 0x7d, 0x77, 0x72, 0x6c, 0x66, 0x60, 0x5a, 0x54, 0x4e, 0x49, 0x42, 0x3c, 0x37, 0x32, 0x2d,
0x28, 0x24, 0x1f, 0x1b, 0x18, 0x14, 0x11, 0x0e, 0x0c, 0x09, 0x07, 0x06, 0x05, 0x04, 0x04, 0x04,
0x04, 0x05, 0x06, 0x08, 0x0a, 0x0d, 0x10, 0x14, 0x18, 0x1d, 0x23, 0x29, 0x2f, 0x37, 0x3e, 0x47,
0x50, 0x5a, 0x64, 0x70, 0x7c, 0x83, 0x85, 0x88, 0x8a, 0x8c, 0x8e, 0x8f, 0x91, 0x92, 0x93, 0x93
};






env_fall2, env_fall2, env_fall2, env_fall2,
env_rise2, env_rise2, env_rise2, env_rise2,
env_risefallrise, env_risefallrise env_risefallrise, env_risefallrise
};
};






#define T_EMPH 1 #define T_EMPH 1


static TONE_HEAD tone_head_table[N_TONE_HEAD_TABLE] = { static TONE_HEAD tone_head_table[N_TONE_HEAD_TABLE] = {
{46, 57, 78, 50, drops_0, 3, 7, 5, oflow}, // 0 statement
{46, 57, 78, 46, drops_0, 3, 7, 5, oflow}, // 1 comma
{46, 57, 78, 46, drops_0, 3, 7, 5, oflow}, // 2 question
{46, 57, 90, 50, drops_0, 3, 9, 5, oflow_emf}, // 3 exclamation
{46, 57, 78, 50, drops_0, 3, 7, 5, oflow}, // 4 statement, emphatic
{46, 57, 74, 55, drops_0, 4, 7, 5, oflow_less}, // 5 statement, less intonation
{46, 57, 74, 55, drops_0, 4, 7, 5, oflow_less}, // 6 comma, less intonation
{46, 57, 74, 55, drops_0, 4, 7, 5, oflow_less}, // 7 comma, less intonation, less rise
{46, 57, 78, 50, drops_0, 3, 7, 5, oflow}, // 8 pitch raises at end of sentence
{46, 57, 78, 46, drops_0, 3, 7, 5, oflow}, // 9 comma
{46, 57, 78, 50, drops_0, 3, 7, 5, oflow}, // 10 question
{34, 41, 41, 32, drops_0, 3, 7, 5, oflow_less}, // 11 test
{46, 57, 55, 50, drops_0, 3, 7, 5, oflow_less}, // 12 test
{46, 57, 78, 50, drops_0, 3, 7, 5, oflow}, // 0 statement
{46, 57, 78, 46, drops_0, 3, 7, 5, oflow}, // 1 comma
{46, 57, 78, 46, drops_0, 3, 7, 5, oflow}, // 2 question
{46, 57, 90, 50, drops_0, 3, 9, 5, oflow_emf}, // 3 exclamation
{46, 57, 78, 50, drops_0, 3, 7, 5, oflow}, // 4 statement, emphatic
{46, 57, 74, 55, drops_0, 4, 7, 5, oflow_less},// 5 statement, less intonation
{46, 57, 74, 55, drops_0, 4, 7, 5, oflow_less},// 6 comma, less intonation
{46, 57, 74, 55, drops_0, 4, 7, 5, oflow_less},// 7 comma, less intonation, less rise
{46, 57, 78, 50, drops_0, 3, 7, 5, oflow}, // 8 pitch raises at end of sentence
{46, 57, 78, 46, drops_0, 3, 7, 5, oflow}, // 9 comma
{46, 57, 78, 50, drops_0, 3, 7, 5, oflow}, // 10 question
{34, 41, 41, 32, drops_0, 3, 7, 5, oflow_less}, // 11 test
{46, 57, 55, 50, drops_0, 3, 7, 5, oflow_less}, // 12 test
}; };


static TONE_NUCLEUS tone_nucleus_table[N_TONE_NUCLEUS_TABLE] = { static TONE_NUCLEUS tone_nucleus_table[N_TONE_NUCLEUS_TABLE] = {
{PITCHfall, 64, 8, PITCHfall, 70,18, NULL, 24, 12, 0}, // 0 statement
{PITCHfrise, 80,18, PITCHfrise2, 78,22, NULL, 34, 52, 0}, // 1 comma
{PITCHfrise, 88,22, PITCHfrise2, 82,22, NULL, 34, 64, 0}, // 2 question
{PITCHfall, 92, 8, PITCHfall, 92,80, NULL, 76, 8, T_EMPH}, // 3 exclamation
{PITCHfall, 86, 4, PITCHfall, 94,66, NULL, 34, 10, 0}, // 4 statement, emphatic
{PITCHfall, 62,10, PITCHfall, 62,20, NULL, 28, 16, 0}, // 5 statement, less intonation
{PITCHfrise, 68,18, PITCHfrise2, 68,22, NULL, 30, 44, 0}, // 6 comma, less intonation
{PITCHfrise2, 64,16, PITCHfall, 66,32, NULL, 32, 18, 0}, // 7 comma, less intonation, less rise
{PITCHrise, 68,46, PITCHfall, 42,32, NULL, 46, 58, 0}, // 8 pitch raises at end of sentence
{PITCHfrise, 78,24, PITCHfrise2, 72,22, NULL, 42, 52, 0}, // 9 comma
{PITCHfrise, 88,34, PITCHfall, 64,32, NULL, 46, 82, 0}, // 10 question
{PITCHfall, 56,12, PITCHfall, 56,20, NULL, 24, 12, 0}, // 11 test
{PITCHfall, 70,18, PITCHfall, 70,24, NULL, 32, 20, 0}, // 12 test
{PITCHfall, 64, 8, PITCHfall, 70,18, NULL, 24, 12, 0}, // 0 statement
{PITCHfrise, 80,18, PITCHfrise2, 78,22, NULL, 34, 52, 0}, // 1 comma
{PITCHfrise, 88,22, PITCHfrise2, 82,22, NULL, 34, 64, 0}, // 2 question
{PITCHfall, 92, 8, PITCHfall, 92,80, NULL, 76, 8, T_EMPH}, // 3 exclamation
{PITCHfall, 86, 4, PITCHfall, 94,66, NULL, 34, 10, 0}, // 4 statement, emphatic
{PITCHfall, 62,10, PITCHfall, 62,20, NULL, 28, 16, 0}, // 5 statement, less intonation
{PITCHfrise, 68,18, PITCHfrise2, 68,22, NULL, 30, 44, 0}, // 6 comma, less intonation
{PITCHfrise2, 64,16, PITCHfall, 66,32, NULL, 32, 18, 0}, // 7 comma, less intonation, less rise
{PITCHrise, 68,46, PITCHfall, 42,32, NULL, 46, 58, 0}, // 8 pitch raises at end of sentence
{PITCHfrise, 78,24, PITCHfrise2, 72,22, NULL, 42, 52, 0}, // 9 comma
{PITCHfrise, 88,34, PITCHfall, 64,32, NULL, 46, 82, 0}, // 10 question
{PITCHfall, 56,12, PITCHfall, 56,20, NULL, 24, 12, 0}, // 11 test
{PITCHfall, 70,18, PITCHfall, 70,24, NULL, 32, 20, 0}, // 12 test
}; };




#define PRIMARY_LAST 7 #define PRIMARY_LAST 7




static int number_pre;
static int number_body;
static int number_tail;
static int last_primary;
static int tone_posn;
static int tone_posn2;
static int no_tonic;
static int number_pre;
static int number_body;
static int number_tail;
static int last_primary;
static int tone_posn;
static int tone_posn2;
static int no_tonic;




static void count_pitch_vowels(int start, int end, int clause_end) static void count_pitch_vowels(int start, int end, int clause_end)
{ {
int ix;
int stress;
int max_stress = 0;
int max_stress_posn = 0; // last syllable ot the highest stress
int max_stress_posn2 = 0; // penuntimate syllable of the highest stress
int ix;
int stress;
int max_stress = 0;
int max_stress_posn = 0; // last syllable ot the highest stress
int max_stress_posn2 = 0; // penuntimate syllable of the highest stress


number_pre = -1; /* number of vowels before 1st primary stress */ number_pre = -1; /* number of vowels before 1st primary stress */
number_body = 0; number_body = 0;
/* Count number of primary stresses up to tonic syllable or body_reset */ /* Count number of primary stresses up to tonic syllable or body_reset */
static int count_increments(int ix, int end_ix, int min_stress) static int count_increments(int ix, int end_ix, int min_stress)
{ {
int count = 0;
int stress;
int count = 0;
int stress;


while(ix < end_ix) while(ix < end_ix)
{ {
// Set the pitch of a vowel in syllable_tab // Set the pitch of a vowel in syllable_tab
static void set_pitch(SYLLABLE *syl, int base, int drop) static void set_pitch(SYLLABLE *syl, int base, int drop)
{ {
int pitch1, pitch2;
int flags = 0;
int pitch1, pitch2;
int flags = 0;


if(base < 0) base = 0; if(base < 0) base = 0;




static int SetHeadIntonation(TUNE *tune, int syl_ix, int end_ix, int control) static int SetHeadIntonation(TUNE *tune, int syl_ix, int end_ix, int control)
{ {
int stress;
int stress;
SYLLABLE *syl; SYLLABLE *syl;
int ix;
int pitch=0;
int increment=0;
int n_steps=0;
int stage; // onset, head, last
int initial;
int overflow_ix=0;
int pitch_range;
int pitch_range_abs;
int ix;
int pitch=0;
int increment=0;
int n_steps=0;
int stage; // onset, head, last
int initial;
int overflow_ix=0;
int pitch_range;
int pitch_range_abs;
int *drops; int *drops;
int n_unstressed=0;
int unstressed_ix=0;
int unstressed_inc;
int used_onset = 0;
int head_final = end_ix;
int secondary=2; // 2
int n_unstressed=0;
int unstressed_ix=0;
int unstressed_inc;
int used_onset = 0;
int head_final = end_ix;
int secondary=2; // 2


pitch_range = (tune->head_end - tune->head_start) << 8; pitch_range = (tune->head_end - tune->head_start) << 8;
pitch_range_abs = abs(pitch_range); pitch_range_abs = abs(pitch_range);




/* Calculate pitches until next RESET or tonic syllable, or end. /* Calculate pitches until next RESET or tonic syllable, or end.
Increment pitch if stress is >= min_stress.
Used for tonic segment */
Increment pitch if stress is >= min_stress.
Used for tonic segment */
static int calc_pitch_segment(int ix, int end_ix, TONE_HEAD *th, TONE_NUCLEUS *tn, int min_stress, int continuing) static int calc_pitch_segment(int ix, int end_ix, TONE_HEAD *th, TONE_NUCLEUS *tn, int min_stress, int continuing)
{ {
int stress;
int pitch=0;
int increment=0;
int n_primary=0;
int n_steps=0;
int initial;
int overflow=0;
int n_overflow;
int pitch_range;
int pitch_range_abs;
int stress;
int pitch=0;
int increment=0;
int n_primary=0;
int n_steps=0;
int initial;
int overflow=0;
int n_overflow;
int pitch_range;
int pitch_range_abs;
int *drops; int *drops;
signed char *overflow_tab; signed char *overflow_tab;
SYLLABLE *syl; SYLLABLE *syl;
n_primary--; n_primary--;
if((tn->backwards) && (n_primary < 2)) if((tn->backwards) && (n_primary < 2))
{ {
pitch = tn->backwards[n_primary] << 8;
pitch = tn->backwards[n_primary] << 8;
} }
} }


// Set a linear pitch change over a number of syllables. // Set a linear pitch change over a number of syllables.
// Used for pre-head, unstressed syllables in the body, and the tail // Used for pre-head, unstressed syllables in the body, and the tail


int ix;
int stress;
int pitch;
int increment;
int n_increments;
int drop;
int ix;
int stress;
int pitch;
int increment;
int n_increments;
int drop;
SYLLABLE *syl; SYLLABLE *syl;


increment = (end_pitch - start_pitch) << 8; increment = (end_pitch - start_pitch) << 8;
// Calculate pitch values for the vowels in this tone group // Calculate pitch values for the vowels in this tone group
static int calc_pitches2(int start, int end, int tune_number) static int calc_pitches2(int start, int end, int tune_number)
{ {
int ix;
int ix;
TUNE *tune; TUNE *tune;
int drop;
int drop;


tune = &tunes[tune_number]; tune = &tunes[tune_number];
ix = start; ix = start;
// Calculate pitch values for the vowels in this tone group // Calculate pitch values for the vowels in this tone group
static int calc_pitches(int control, int start, int end, int tune_number) static int calc_pitches(int control, int start, int end, int tune_number)
{ {
int ix;
int ix;
TONE_HEAD *th; TONE_HEAD *th;
TONE_NUCLEUS *tn; TONE_NUCLEUS *tn;
int drop;
int drop;
int continuing = 0; int continuing = 0;


if(control == 0) if(control == 0)
{ {
// clause_tone: 0=. 1=, 2=?, 3=! 4=none // clause_tone: 0=. 1=, 2=?, 3=! 4=none
PHONEME_LIST *p; PHONEME_LIST *p;
int ix;
int count_stressed=0;
int final_stressed=0;
int ix;
int count_stressed=0;
int final_stressed=0;


int tone_ph;
int tone_ph;
int pause; int pause;
int tone_promoted; int tone_promoted;
PHONEME_TAB *tph; PHONEME_TAB *tph;
PHONEME_TAB *prevw_tph; // remember across word boundary PHONEME_TAB *prevw_tph; // remember across word boundary
PHONEME_LIST *prev_p; PHONEME_LIST *prev_p;


int pitch_adjust = 0; // pitch gradient through the clause - inital value
int pitch_decrement = 0; // decrease by this for each stressed syllable
int pitch_low = 0; // until it drops to this
int pitch_high = 0; // then reset to this
int pitch_adjust = 0; // pitch gradient through the clause - inital value
int pitch_decrement = 0; // decrease by this for each stressed syllable
int pitch_low = 0; // until it drops to this
int pitch_high = 0; // then reset to this


// count number of stressed syllables // count number of stressed syllables
p = &phoneme_list[0]; p = &phoneme_list[0];
// clause_type: 0=. 1=, 2=?, 3=! 4=none // clause_type: 0=. 1=, 2=?, 3=! 4=none
PHONEME_LIST *p; PHONEME_LIST *p;
SYLLABLE *syl; SYLLABLE *syl;
int ix;
int x;
int st_ix;
int ix;
int x;
int st_ix;
int n_st; int n_st;
int option;
int group_tone;
int group_tone_emph;
int group_tone_comma;
int option;
int group_tone;
int group_tone_emph;
int group_tone_comma;
int ph_start=0; int ph_start=0;
int st_start; int st_start;
int st_clause_end; int st_clause_end;
p->pitch2 = x; p->pitch2 = x;
} }


if(p->tone_ph)
{
ph = phoneme_tab[p->tone_ph];
x = (p->pitch1 + p->pitch2)/2;
p->pitch2 = x + ph->end_type;
p->pitch1 = x + ph->start_type;
}
if(p->tone_ph)
{
ph = phoneme_tab[p->tone_ph];
x = (p->pitch1 + p->pitch2)/2;
p->pitch2 = x + ph->end_type;
p->pitch1 = x + ph->start_type;
}


if(syl->flags & SYL_EMPHASIS) if(syl->flags & SYL_EMPHASIS)
{ {

+ 174
- 173
src/libespeak-ng/klatt.c View File

static void setabc (long,long,resonator_ptr); static void setabc (long,long,resonator_ptr);
static void setzeroabc (long,long,resonator_ptr); static void setzeroabc (long,long,resonator_ptr);


static klatt_frame_t kt_frame;
static klatt_frame_t kt_frame;
static klatt_global_t kt_globals; static klatt_global_t kt_globals;


#define NUMBER_OF_SAMPLES 100 #define NUMBER_OF_SAMPLES 100
static int scale_wav_tab[] = {45,38,45,45,55}; // scale output from different voicing sources static int scale_wav_tab[] = {45,38,45,45,55}; // scale output from different voicing sources


// For testing, this can be overwritten in KlattInit() // For testing, this can be overwritten in KlattInit()
static short natural_samples2[256]= {
2583, 2516, 2450, 2384, 2319, 2254, 2191, 2127,
2067, 2005, 1946, 1890, 1832, 1779, 1726, 1675,
1626, 1579, 1533, 1491, 1449, 1409, 1372, 1336,
1302, 1271, 1239, 1211, 1184, 1158, 1134, 1111,
1089, 1069, 1049, 1031, 1013, 996, 980, 965,
950, 936, 921, 909, 895, 881, 869, 855,
843, 830, 818, 804, 792, 779, 766, 754,
740, 728, 715, 702, 689, 676, 663, 651,
637, 626, 612, 601, 588, 576, 564, 552,
540, 530, 517, 507, 496, 485, 475, 464,
454, 443, 434, 424, 414, 404, 394, 385,
375, 366, 355, 347, 336, 328, 317, 308,
299, 288, 280, 269, 260, 250, 240, 231,
220, 212, 200, 192, 181, 172, 161, 152,
142, 133, 123, 113, 105, 94, 86, 76,
67, 57, 49, 39, 30, 22, 11, 4,
-5, -14, -23, -32, -41, -50, -60, -69,
-78, -87, -96, -107, -115, -126, -134, -144,
-154, -164, -174, -183, -193, -203, -213, -222,
-233, -242, -252, -262, -271, -281, -291, -301,
-310, -320, -330, -339, -349, -357, -368, -377,
-387, -397, -406, -417, -426, -436, -446, -456,
-467, -477, -487, -499, -509, -521, -532, -543,
-555, -567, -579, -591, -603, -616, -628, -641,
-653, -666, -679, -692, -705, -717, -732, -743,
-758, -769, -783, -795, -808, -820, -834, -845,
-860, -872, -885, -898, -911, -926, -939, -955,
-968, -986, -999, -1018, -1034, -1054, -1072, -1094,
-1115, -1138, -1162, -1188, -1215, -1244, -1274, -1307,
-1340, -1377, -1415, -1453, -1496, -1538, -1584, -1631,
-1680, -1732, -1783, -1839, -1894, -1952, -2010, -2072,
-2133, -2196, -2260, -2325, -2390, -2456, -2522, -2589,
static short natural_samples2[256]= {
2583, 2516, 2450, 2384, 2319, 2254, 2191, 2127,
2067, 2005, 1946, 1890, 1832, 1779, 1726, 1675,
1626, 1579, 1533, 1491, 1449, 1409, 1372, 1336,
1302, 1271, 1239, 1211, 1184, 1158, 1134, 1111,
1089, 1069, 1049, 1031, 1013, 996, 980, 965,
950, 936, 921, 909, 895, 881, 869, 855,
843, 830, 818, 804, 792, 779, 766, 754,
740, 728, 715, 702, 689, 676, 663, 651,
637, 626, 612, 601, 588, 576, 564, 552,
540, 530, 517, 507, 496, 485, 475, 464,
454, 443, 434, 424, 414, 404, 394, 385,
375, 366, 355, 347, 336, 328, 317, 308,
299, 288, 280, 269, 260, 250, 240, 231,
220, 212, 200, 192, 181, 172, 161, 152,
142, 133, 123, 113, 105, 94, 86, 76,
67, 57, 49, 39, 30, 22, 11, 4,
-5, -14, -23, -32, -41, -50, -60, -69,
-78, -87, -96, -107, -115, -126, -134, -144,
-154, -164, -174, -183, -193, -203, -213, -222,
-233, -242, -252, -262, -271, -281, -291, -301,
-310, -320, -330, -339, -349, -357, -368, -377,
-387, -397, -406, -417, -426, -436, -446, -456,
-467, -477, -487, -499, -509, -521, -532, -543,
-555, -567, -579, -591, -603, -616, -628, -641,
-653, -666, -679, -692, -705, -717, -732, -743,
-758, -769, -783, -795, -808, -820, -834, -845,
-860, -872, -885, -898, -911, -926, -939, -955,
-968, -986, -999, -1018, -1034, -1054, -1072, -1094,
-1115, -1138, -1162, -1188, -1215, -1244, -1274, -1307,
-1340, -1377, -1415, -1453, -1496, -1538, -1584, -1631,
-1680, -1732, -1783, -1839, -1894, -1952, -2010, -2072,
-2133, -2196, -2260, -2325, -2390, -2456, -2522, -2589,
};
static short natural_samples[100]=
{
-310,-400,530,356,224,89,23,-10,-58,-16,461,599,536,701,770,
605,497,461,560,404,110,224,131,104,-97,155,278,-154,-1165,
-598,737,125,-592,41,11,-247,-10,65,92,80,-304,71,167,-1,122,
233,161,-43,278,479,485,407,266,650,134,80,236,68,260,269,179,
53,140,275,293,296,104,257,152,311,182,263,245,125,314,140,44,
203,230,-235,-286,23,107,92,-91,38,464,443,176,98,-784,-2449,
-1891,-1045,-1600,-1462,-1384,-1261,-949,-730
}; };
static short natural_samples[100]=
{
-310,-400,530,356,224,89,23,-10,-58,-16,461,599,536,701,770,
605,497,461,560,404,110,224,131,104,-97,155,278,-154,-1165,
-598,737,125,-592,41,11,-247,-10,65,92,80,-304,71,167,-1,122,
233,161,-43,278,479,485,407,266,650,134,80,236,68,260,269,179,
53,140,275,293,296,104,257,152,311,182,263,245,125,314,140,44,
203,230,-235,-286,23,107,92,-91,38,464,443,176,98,-784,-2449,
-1891,-1045,-1600,-1462,-1384,-1261,-949,-730
};


/* /*
function RESONATOR
function RESONATOR


This is a generic resonator function. Internal memory for the resonator
is stored in the globals structure.
*/
This is a generic resonator function. Internal memory for the resonator
is stored in the globals structure.
*/


static double resonator(resonator_ptr r, double input) static double resonator(resonator_ptr r, double input)
{ {




/* /*
function FLUTTER
function FLUTTER


This function adds F0 flutter, as specified in:
This function adds F0 flutter, as specified in:


"Analysis, synthesis and perception of voice quality variations among
female and male talkers" D.H. Klatt and L.C. Klatt JASA 87(2) February 1990.
"Analysis, synthesis and perception of voice quality variations among
female and male talkers" D.H. Klatt and L.C. Klatt JASA 87(2) February 1990.


Flutter is added by applying a quasi-random element constructed from three
slowly varying sine waves.
*/
Flutter is added by applying a quasi-random element constructed from three
slowly varying sine waves.
*/


static void flutter(klatt_frame_ptr frame) static void flutter(klatt_frame_ptr frame)
{ {




/* /*
function SAMPLED_SOURCE
function SAMPLED_SOURCE


Allows the use of a glottal excitation waveform sampled from a real
voice.
*/
Allows the use of a glottal excitation waveform sampled from a real
voice.
*/


static double sampled_source(int source_num) static double sampled_source(int source_num)
{ {




/* /*
function PARWAVE
function PARWAVE


Converts synthesis parameters to a waveform.
*/
Converts synthesis parameters to a waveform.
*/




static int parwave(klatt_frame_ptr frame) static int parwave(klatt_frame_ptr frame)
flutter(frame); /* add f0 flutter */ flutter(frame); /* add f0 flutter */


#ifdef LOG_FRAMES #ifdef LOG_FRAMES
if(option_log_frames)
{
FILE *f;
f=fopen("log-klatt","a");
fprintf(f,"%4dhz %2dAV %4d %3d, %4d %3d, %4d %3d, %4d %3d, %4d, %3d, FNZ=%3d TLT=%2d\n",frame->F0hz10,frame->AVdb,
frame->Fhz[1],frame->Bhz[1],frame->Fhz[2],frame->Bhz[2],frame->Fhz[3],frame->Bhz[3],frame->Fhz[4],frame->Bhz[4],frame->Fhz[5],frame->Bhz[5],frame->Fhz[0],frame->TLTdb);
fclose(f);
}
if(option_log_frames)
{
FILE *f;
f=fopen("log-klatt","a");
fprintf(f,"%4dhz %2dAV %4d %3d, %4d %3d, %4d %3d, %4d %3d, %4d, %3d, FNZ=%3d TLT=%2d\n",frame->F0hz10,frame->AVdb,
frame->Fhz[1],frame->Bhz[1],frame->Fhz[2],frame->Bhz[2],frame->Fhz[3],frame->Bhz[3],frame->Fhz[4],frame->Bhz[4],frame->Fhz[5],frame->Bhz[5],frame->Fhz[0],frame->TLTdb);
fclose(f);
}
#endif #endif


/* MAIN LOOP, for each output sample of current frame: */ /* MAIN LOOP, for each output sample of current frame: */
noise = gen_noise(noise); noise = gen_noise(noise);


/* /*
Amplitude modulate noise (reduce noise amplitude during
second half of glottal period) if voicing simultaneously present.
*/
Amplitude modulate noise (reduce noise amplitude during
second half of glottal period) if voicing simultaneously present.
*/


if (kt_globals.nper > kt_globals.nmod) if (kt_globals.nper > kt_globals.nmod)
{ {
frics = kt_globals.amp_frica * noise; frics = kt_globals.amp_frica * noise;


/* /*
Compute voicing waveform. Run glottal source simulation at 4
times normal sample rate to minimize quantization noise in
period of female voice.
*/
Compute voicing waveform. Run glottal source simulation at 4
times normal sample rate to minimize quantization noise in
period of female voice.
*/


for (n4=0; n4<4; n4++) for (n4=0; n4<4; n4++)
{ {
} }


/* /*
Low-pass filter voicing waveform before downsampling from 4*samrate
to samrate samples/sec. Resonator f=.09*samrate, bw=.06*samrate
*/
Low-pass filter voicing waveform before downsampling from 4*samrate
to samrate samples/sec. Resonator f=.09*samrate, bw=.06*samrate
*/


voice = resonator(&(kt_globals.rsn[RLP]),voice); voice = resonator(&(kt_globals.rsn[RLP]),voice);


} }


/* /*
Tilt spectrum of voicing source down by soft low-pass filtering, amount
of tilt determined by TLTdb
*/
Tilt spectrum of voicing source down by soft low-pass filtering, amount
of tilt determined by TLTdb
*/


voice = (voice * kt_globals.onemd) + (vlast * kt_globals.decay); voice = (voice * kt_globals.onemd) + (vlast * kt_globals.decay);
vlast = voice; vlast = voice;


/* /*
Add breathiness during glottal open phase. Amount of breathiness
determined by parameter Aturb Use nrand rather than noise because
noise is low-passed.
*/
Add breathiness during glottal open phase. Amount of breathiness
determined by parameter Aturb Use nrand rather than noise because
noise is low-passed.
*/




if (kt_globals.nper < kt_globals.nopen) if (kt_globals.nper < kt_globals.nopen)
par_glotout += aspiration; par_glotout += aspiration;


/* /*
Cascade vocal tract, excited by laryngeal sources.
Nasal antiresonator, then formants FNP, F5, F4, F3, F2, F1
*/
Cascade vocal tract, excited by laryngeal sources.
Nasal antiresonator, then formants FNP, F5, F4, F3, F2, F1
*/


out=0; out=0;
if(kt_globals.synthesis_model != ALL_PARALLEL) if(kt_globals.synthesis_model != ALL_PARALLEL)
sourc = par_glotout; /* Source is voicing plus aspiration */ sourc = par_glotout; /* Source is voicing plus aspiration */


/* /*
Standard parallel vocal tract Formants F6,F5,F4,F3,F2,
outputs added with alternating sign. Sound source for other
parallel resonators is frication plus first difference of
voicing waveform.
*/
Standard parallel vocal tract Formants F6,F5,F4,F3,F2,
outputs added with alternating sign. Sound source for other
parallel resonators is frication plus first difference of
voicing waveform.
*/


out += resonator(&(kt_globals.rsn[R1p]),sourc); out += resonator(&(kt_globals.rsn[R1p]),sourc);
out += resonator(&(kt_globals.rsn[Rnpp]),sourc); out += resonator(&(kt_globals.rsn[Rnpp]),sourc);
out = outbypas - out; out = outbypas - out;


out = resonator(&(kt_globals.rsn[Rout]),out); out = resonator(&(kt_globals.rsn[Rout]),out);
temp = (int)(out * wdata.amplitude * kt_globals.amp_gain0) ; /* Convert back to integer */
temp = (int)(out * wdata.amplitude * kt_globals.amp_gain0); /* Convert back to integer */




// mix with a recorded WAV if required for this phoneme // mix with a recorded WAV if required for this phoneme




/* /*
function FRAME_INIT
function FRAME_INIT


Use parameters from the input frame to set up resonator coefficients.
*/
Use parameters from the input frame to set up resonator coefficients.
*/


static void frame_init(klatt_frame_ptr frame) static void frame_init(klatt_frame_ptr frame)
{ {




/* /*
function IMPULSIVE_SOURCE
function IMPULSIVE_SOURCE


Generate a low pass filtered train of impulses as an approximation of
a natural excitation waveform. Low-pass filter the differentiated impulse
with a critically-damped second-order filter, time constant proportional
to Kopen.
*/
Generate a low pass filtered train of impulses as an approximation of
a natural excitation waveform. Low-pass filter the differentiated impulse
with a critically-damped second-order filter, time constant proportional
to Kopen.
*/




static double impulsive_source() static double impulsive_source()




/* /*
function NATURAL_SOURCE
function NATURAL_SOURCE


Vwave is the differentiated glottal flow waveform, there is a weak
spectral zero around 800 Hz, magic constants a,b reset pitch synchronously.
*/
Vwave is the differentiated glottal flow waveform, there is a weak
spectral zero around 800 Hz, magic constants a,b reset pitch synchronously.
*/


static double natural_source() static double natural_source()
{ {




/* /*
function PITCH_SYNC_PAR_RESET
function PITCH_SYNC_PAR_RESET


Reset selected parameters pitch-synchronously.
Reset selected parameters pitch-synchronously.




Constant B0 controls shape of glottal pulse as a function
of desired duration of open phase N0
(Note that N0 is specified in terms of 40,000 samples/sec of speech)
Constant B0 controls shape of glottal pulse as a function
of desired duration of open phase N0
(Note that N0 is specified in terms of 40,000 samples/sec of speech)


Assume voicing waveform V(t) has form: k1 t**2 - k2 t**3
Assume voicing waveform V(t) has form: k1 t**2 - k2 t**3


If the radiation characterivative, a temporal derivative
is folded in, and we go from continuous time to discrete
integers n: dV/dt = vwave[n]
If the radiation characterivative, a temporal derivative
is folded in, and we go from continuous time to discrete
integers n: dV/dt = vwave[n]
= sum over i=1,2,...,n of { a - (i * b) } = sum over i=1,2,...,n of { a - (i * b) }
= a n - b/2 n**2 = a n - b/2 n**2


where the constants a and b control the detailed shape
and amplitude of the voicing waveform over the open
potion of the voicing cycle "nopen".
where the constants a and b control the detailed shape
and amplitude of the voicing waveform over the open
potion of the voicing cycle "nopen".


Let integral of dV/dt have no net dc flow --> a = (b * nopen) / 3
Let integral of dV/dt have no net dc flow --> a = (b * nopen) / 3


Let maximum of dUg(n)/dn be constant --> b = gain / (nopen * nopen)
meaning as nopen gets bigger, V has bigger peak proportional to n
Let maximum of dUg(n)/dn be constant --> b = gain / (nopen * nopen)
meaning as nopen gets bigger, V has bigger peak proportional to n


Thus, to generate the table below for 40 <= nopen <= 263:
Thus, to generate the table below for 40 <= nopen <= 263:


B0[nopen - 40] = 1920000 / (nopen * nopen)
*/
B0[nopen - 40] = 1920000 / (nopen * nopen)
*/


static void pitch_synch_par_reset(klatt_frame_ptr frame) static void pitch_synch_par_reset(klatt_frame_ptr frame)
{ {
kt_globals.rsn[RGL].a *= temp1 * temp1; kt_globals.rsn[RGL].a *= temp1 * temp1;


/* /*
Truncate skewness so as not to exceed duration of closed phase
of glottal period.
*/
Truncate skewness so as not to exceed duration of closed phase
of glottal period.
*/




temp = kt_globals.T0 - kt_globals.nopen; temp = kt_globals.T0 - kt_globals.nopen;
} }
else else
{ {
skew = - frame->Kskew;
skew = -frame->Kskew;
} }


/* Add skewness to closed portion of voicing period */ /* Add skewness to closed portion of voicing period */
kt_globals.T0 = kt_globals.T0 + skew; kt_globals.T0 = kt_globals.T0 + skew;
skew = - skew;
skew = -skew;
} }
else else
{ {




/* /*
function SETABC
function SETABC


Convert formant freqencies and bandwidth into resonator difference
equation constants.
*/
Convert formant freqencies and bandwidth into resonator difference
equation constants.
*/




static void setabc(long int f, long int bw, resonator_ptr rp) static void setabc(long int f, long int bw, resonator_ptr rp)




/* /*
function SETZEROABC
function SETZEROABC


Convert formant freqencies and bandwidth into anti-resonator difference
equation constants.
*/
Convert formant freqencies and bandwidth into anti-resonator difference
equation constants.
*/


static void setzeroabc(long int f, long int bw, resonator_ptr rp) static void setzeroabc(long int f, long int bw, resonator_ptr rp)
{ {




/* /*
function GEN_NOISE
function GEN_NOISE


Random number generator (return a number between -8191 and +8191)
Noise spectrum is tilted down by soft low-pass filter having a pole near
the origin in the z-plane, i.e. output = input + (0.75 * lastoutput)
*/
Random number generator (return a number between -8191 and +8191)
Noise spectrum is tilted down by soft low-pass filter having a pole near
the origin in the z-plane, i.e. output = input + (0.75 * lastoutput)
*/




static double gen_noise(double noise) static double gen_noise(double noise)




/* /*
function DBTOLIN
function DBTOLIN


Convert from decibels to a linear scale factor
Convert from decibels to a linear scale factor




Conversion table, db to linear, 87 dB --> 32767
Conversion table, db to linear, 87 dB --> 32767
86 dB --> 29491 (1 dB down = 0.5**1/6) 86 dB --> 29491 (1 dB down = 0.5**1/6)
... ...
81 dB --> 16384 (6 dB down = 0.5) 81 dB --> 16384 (6 dB down = 0.5)
... ...
0 dB --> 0 0 dB --> 0


The just noticeable difference for a change in intensity of a vowel
is approximately 1 dB. Thus all amplitudes are quantized to 1 dB
steps.
*/
The just noticeable difference for a change in intensity of a vowel
is approximately 1 dB. Thus all amplitudes are quantized to 1 dB
steps.
*/




static double DBtoLIN(long dB) static double DBtoLIN(long dB)
static short amptable[88] = static short amptable[88] =
{ {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 7,
8, 9, 10, 11, 13, 14, 16, 18, 20, 22, 25, 28, 32,
8, 9, 10, 11, 13, 14, 16, 18, 20, 22, 25, 28, 32,
35, 40, 45, 51, 57, 64, 71, 80, 90, 101, 114, 128, 35, 40, 45, 51, 57, 64, 71, 80, 90, 101, 114, 128,
142, 159, 179, 202, 227, 256, 284, 318, 359, 405, 142, 159, 179, 202, 227, 256, 284, 318, 359, 405,
455, 512, 568, 638, 719, 881, 911, 1024, 1137, 1276, 455, 512, 568, 638, 719, 881, 911, 1024, 1137, 1276,
1438, 1622, 1823, 2048, 2273, 2552, 2875, 3244, 3645, 1438, 1622, 1823, 2048, 2273, 2552, 2875, 3244, 3645,
4096, 4547, 5104, 5751, 6488, 7291, 8192, 9093, 10207, 4096, 4547, 5104, 5751, 6488, 7291, 8192, 9093, 10207,
11502, 12976, 14582, 16384, 18350, 20644, 23429, 11502, 12976, 14582, 16384, 18350, 20644, 23429,
26214, 29491, 32767 };
26214, 29491, 32767
};


if ((dB < 0) || (dB > 87)) if ((dB < 0) || (dB > 87))
{ {
if(control & 1) if(control & 1)
{ {
end_wave = 1; end_wave = 1;
for(qix=wcmdq_head+1;;qix++)
for(qix=wcmdq_head+1;; qix++)
{ {
if(qix >= N_WCMDQ) qix = 0; if(qix >= N_WCMDQ) qix = 0;
if(qix == wcmdq_tail) break; if(qix == wcmdq_tail) break;
} }


#ifdef LOG_FRAMES #ifdef LOG_FRAMES
if(option_log_frames)
{
FILE *f_log;
f_log=fopen("log-espeakedit","a");
if(f_log != NULL)
{
fprintf(f_log,"K %3dmS %3d %3d %4d %4d %4d %4d (%2d) to %3d %3d %4d %4d %4d %4d (%2d)\n",length*1000/samplerate,
fr1->klattp[KLATT_FNZ]*2,fr1->ffreq[1],fr1->ffreq[2],fr1->ffreq[3],fr1->ffreq[4],fr1->ffreq[5], fr1->klattp[KLATT_AV],
fr2->klattp[KLATT_FNZ]*2,fr2->ffreq[1],fr2->ffreq[2],fr2->ffreq[3],fr1->ffreq[4],fr1->ffreq[5], fr2->klattp[KLATT_AV] );
fclose(f_log);
}
f_log=fopen("log-klatt","a");
if(f_log != NULL)
if(option_log_frames)
{ {
fprintf(f_log,"K %3dmS %3d %3d %4d %4d (%2d) to %3d %3d %4d %4d (%2d)\n",length*1000/samplerate,
fr1->klattp[KLATT_FNZ]*2,fr1->ffreq[1],fr1->ffreq[2],fr1->ffreq[3], fr1->klattp[KLATT_AV],
fr2->klattp[KLATT_FNZ]*2,fr2->ffreq[1],fr2->ffreq[2],fr2->ffreq[3], fr2->klattp[KLATT_AV] );
FILE *f_log;
f_log=fopen("log-espeakedit","a");
if(f_log != NULL)
{
fprintf(f_log,"K %3dmS %3d %3d %4d %4d %4d %4d (%2d) to %3d %3d %4d %4d %4d %4d (%2d)\n",length*1000/samplerate,
fr1->klattp[KLATT_FNZ]*2,fr1->ffreq[1],fr1->ffreq[2],fr1->ffreq[3],fr1->ffreq[4],fr1->ffreq[5], fr1->klattp[KLATT_AV],
fr2->klattp[KLATT_FNZ]*2,fr2->ffreq[1],fr2->ffreq[2],fr2->ffreq[3],fr1->ffreq[4],fr1->ffreq[5], fr2->klattp[KLATT_AV] );
fclose(f_log);
}
f_log=fopen("log-klatt","a");
if(f_log != NULL)
{
fprintf(f_log,"K %3dmS %3d %3d %4d %4d (%2d) to %3d %3d %4d %4d (%2d)\n",length*1000/samplerate,
fr1->klattp[KLATT_FNZ]*2,fr1->ffreq[1],fr1->ffreq[2],fr1->ffreq[3], fr1->klattp[KLATT_AV],
fr2->klattp[KLATT_FNZ]*2,fr2->ffreq[1],fr2->ffreq[2],fr2->ffreq[3], fr2->klattp[KLATT_AV] );


fclose(f_log);
fclose(f_log);
}
} }
}
#endif #endif


if(control & 1) if(control & 1)

+ 34
- 34
src/libespeak-ng/klatt.h View File



typedef struct typedef struct
{ {
flag synthesis_model; /* cascade-parallel or all-parallel */
flag outsl; /* Output waveform selector */
long samrate; /* Number of output samples per second */
long FLPhz ; /* Frequeny of glottal downsample low-pass filter */
long BLPhz ; /* Bandwidth of glottal downsample low-pass filter */
flag glsource; /* Type of glottal source */
int f0_flutter; /* Percentage of f0 flutter 0-100 */
long nspfr; /* number of samples per frame */
long nper; /* Counter for number of samples in a pitch period */
long ns;
long T0; /* Fundamental period in output samples times 4 */
long nopen; /* Number of samples in open phase of period */
long nmod; /* Position in period to begin noise amp. modul */
long nrand; /* Varible used by random number generator */
double pulse_shape_a; /* Makes waveshape of glottal pulse when open */
double pulse_shape_b; /* Makes waveshape of glottal pulse when open */
double minus_pi_t;
double two_pi_t;
double onemd;
double decay;
double amp_bypas; /* AB converted to linear gain */
double amp_voice; /* AVdb converted to linear gain */
double par_amp_voice; /* AVpdb converted to linear gain */
double amp_aspir; /* AP converted to linear gain */
double amp_frica; /* AF converted to linear gain */
double amp_breth; /* ATURB converted to linear gain */
double amp_gain0; /* G0 converted to linear gain */
int num_samples; /* number of glottal samples */
double sample_factor; /* multiplication factor for glottal samples */
short *natural_samples; /* pointer to an array of glottal samples */
long original_f0; /* original value of f0 not modified by flutter */
flag synthesis_model; /* cascade-parallel or all-parallel */
flag outsl; /* Output waveform selector */
long samrate; /* Number of output samples per second */
long FLPhz; /* Frequeny of glottal downsample low-pass filter */
long BLPhz; /* Bandwidth of glottal downsample low-pass filter */
flag glsource; /* Type of glottal source */
int f0_flutter; /* Percentage of f0 flutter 0-100 */
long nspfr; /* number of samples per frame */
long nper; /* Counter for number of samples in a pitch period */
long ns;
long T0; /* Fundamental period in output samples times 4 */
long nopen; /* Number of samples in open phase of period */
long nmod; /* Position in period to begin noise amp. modul */
long nrand; /* Varible used by random number generator */
double pulse_shape_a; /* Makes waveshape of glottal pulse when open */
double pulse_shape_b; /* Makes waveshape of glottal pulse when open */
double minus_pi_t;
double two_pi_t;
double onemd;
double decay;
double amp_bypas; /* AB converted to linear gain */
double amp_voice; /* AVdb converted to linear gain */
double par_amp_voice; /* AVpdb converted to linear gain */
double amp_aspir; /* AP converted to linear gain */
double amp_frica; /* AF converted to linear gain */
double amp_breth; /* ATURB converted to linear gain */
double amp_gain0; /* G0 converted to linear gain */
int num_samples; /* number of glottal samples */
double sample_factor; /* multiplication factor for glottal samples */
short *natural_samples; /* pointer to an array of glottal samples */
long original_f0; /* original value of f0 not modified by flutter */


int fadeout; // set to 64 to cause fadeout over 64 samples int fadeout; // set to 64 to cause fadeout over 64 samples
int scale_wav; // depends on the voicing source int scale_wav; // depends on the voicing source
#define RLP 18 #define RLP 18
#define Rout 19 #define Rout 19


resonator_t rsn[N_RSN]; // internal storage for resonators
resonator_t rsn_next[N_RSN];
resonator_t rsn[N_RSN]; // internal storage for resonators
resonator_t rsn_next[N_RSN];


} klatt_global_t, *klatt_global_ptr; } klatt_global_t, *klatt_global_ptr;


int AVdb_tmp; //copy of AVdb, which is changed within parwave() int AVdb_tmp; //copy of AVdb, which is changed within parwave()
int Fhz_next[10]; // Fhz for the next chunk, so we can do interpolation of resonator (a,b,c) parameters int Fhz_next[10]; // Fhz for the next chunk, so we can do interpolation of resonator (a,b,c) parameters
int Bhz_next[10]; int Bhz_next[10];
} klatt_frame_t, *klatt_frame_ptr;
} klatt_frame_t, *klatt_frame_ptr;




typedef struct { typedef struct {

+ 13
- 13
src/libespeak-ng/mbrowrap.c View File

dup2(p_stdout[1], 1) == -1 || dup2(p_stdout[1], 1) == -1 ||
dup2(p_stderr[1], 2) == -1) { dup2(p_stderr[1], 2) == -1) {
snprintf(mbr_errorbuf, sizeof(mbr_errorbuf), snprintf(mbr_errorbuf, sizeof(mbr_errorbuf),
"dup2(): %s\n", strerror(errno));
"dup2(): %s\n", strerror(errno));
written = write(p_stderr[1], mbr_errorbuf, strlen(mbr_errorbuf)); written = write(p_stderr[1], mbr_errorbuf, strlen(mbr_errorbuf));
(void)written; // suppress 'variable not used' warning (void)written; // suppress 'variable not used' warning
_exit(1); _exit(1);


snprintf(charbuf, sizeof(charbuf), "%g", mbr_volume); snprintf(charbuf, sizeof(charbuf), "%g", mbr_volume);
execlp("mbrola", "mbrola", "-e", "-v", charbuf, execlp("mbrola", "mbrola", "-e", "-v", charbuf,
voice_path, "-", "-.wav", (char *)NULL);
voice_path, "-", "-.wav", (char *)NULL);
/* if execution reaches this point then the exec() failed */ /* if execution reaches this point then the exec() failed */
snprintf(mbr_errorbuf, sizeof(mbr_errorbuf), snprintf(mbr_errorbuf, sizeof(mbr_errorbuf),
"mbrola: %s\n", strerror(errno));
"mbrola: %s\n", strerror(errno));
written = write(2, mbr_errorbuf, strlen(mbr_errorbuf)); written = write(2, mbr_errorbuf, strlen(mbr_errorbuf));
(void)written; // suppress 'variable not used' warning (void)written; // suppress 'variable not used' warning
_exit(1); _exit(1);
if (WIFSIGNALED(status)) { if (WIFSIGNALED(status)) {
int sig = WTERMSIG(status); int sig = WTERMSIG(status);
snprintf(msgbuf, sizeof(msgbuf), snprintf(msgbuf, sizeof(msgbuf),
"mbrola died by signal %d", sig);
"mbrola died by signal %d", sig);
msg = msgbuf; msg = msgbuf;
} else if (WIFEXITED(status)) { } else if (WIFEXITED(status)) {
int exst = WEXITSTATUS(status); int exst = WEXITSTATUS(status);
snprintf(msgbuf, sizeof(msgbuf), snprintf(msgbuf, sizeof(msgbuf),
"mbrola exited with status %d", exst);
"mbrola exited with status %d", exst);
msg = msgbuf; msg = msgbuf;
} else { } else {
msg = "mbrola died and wait status is weird"; msg = "mbrola died and wait status is weird";
snprintf(mbr_errorbuf, sizeof(mbr_errorbuf), "%s", msg); snprintf(mbr_errorbuf, sizeof(mbr_errorbuf), "%s", msg);
else else
snprintf(mbr_errorbuf + len, sizeof(mbr_errorbuf) - len, snprintf(mbr_errorbuf + len, sizeof(mbr_errorbuf) - len,
", (%s)", msg);
", (%s)", msg);
return -1; return -1;
} }


char *buf_ptr, *lf; char *buf_ptr, *lf;


buf_ptr = buffer; buf_ptr = buffer;
for (;;) {
for (;; ) {
result = read(mbr_error_fd, buf_ptr, result = read(mbr_error_fd, buf_ptr,
sizeof(buffer) - (buf_ptr - buffer) - 1);
sizeof(buffer) - (buf_ptr - buffer) - 1);
if (result == -1) { if (result == -1) {
if (errno == EAGAIN) if (errno == EAGAIN)
return 0; return 0;
/* is this the last line? */ /* is this the last line? */
if (lf == &buf_ptr[result - 1]) { if (lf == &buf_ptr[result - 1]) {
snprintf(mbr_errorbuf, sizeof(mbr_errorbuf), snprintf(mbr_errorbuf, sizeof(mbr_errorbuf),
"%s", buf_ptr);
"%s", buf_ptr);
/* don't consider this fatal at this point */ /* don't consider this fatal at this point */
return 0; return 0;
} }
{ {
ssize_t result; ssize_t result;
int len; int len;
if (!mbr_pid) if (!mbr_pid)
return -1; return -1;


return -1; return -1;
} }
} }
if (result != len) { if (result != len) {
struct datablock *data; struct datablock *data;
data = (struct datablock *)malloc(sizeof(*data) + len - result); data = (struct datablock *)malloc(sizeof(*data) + len - result);
return -1; return -1;
} }
mbr_samplerate = wavhdr[24] + (wavhdr[25]<<8) + mbr_samplerate = wavhdr[24] + (wavhdr[25]<<8) +
(wavhdr[26]<<16) + (wavhdr[27]<<24);
(wavhdr[26]<<16) + (wavhdr[27]<<24);
//log("mbrowrap: voice samplerate = %d", mbr_samplerate); //log("mbrowrap: voice samplerate = %d", mbr_samplerate);


/* remember the voice path for setVolumeRatio_MBR() */ /* remember the voice path for setVolumeRatio_MBR() */
if (mbr_voice_path != voice_path) { if (mbr_voice_path != voice_path) {
free(mbr_voice_path); free(mbr_voice_path);
mbr_voice_path = strdup(voice_path); mbr_voice_path = strdup(voice_path);
}
}


return 0; return 0;
} }

+ 2
- 1
src/libespeak-ng/mbrowrap.h View File

/* /*
* Tolerance to missing diphones (always active so this is ignored) * Tolerance to missing diphones (always active so this is ignored)
*/ */
static inline void setNoError_MBR(int no_error) { }
static inline void setNoError_MBR(int no_error) {
}


#ifdef __cplusplus #ifdef __cplusplus
} }

+ 80
- 78
src/libespeak-ng/numbers.c View File



typedef struct { typedef struct {
const char *name; const char *name;
int accent_flags; // bit 0, say before the letter name
int accent_flags; // bit 0, say before the letter name
} ACCENTS; } ACCENTS;


// these are tokens to look up in the *_list file. // these are tokens to look up in the *_list file.


// characters U+0250 to U+029F // characters U+0250 to U+029F
static const unsigned short letter_accents_250[] = { static const unsigned short letter_accents_250[] = {
LETTER('a',M_TURNED,0), // U+250
LETTER('a',M_TURNED,0), // U+250
LETTER(L_ALPHA,0,0), LETTER(L_ALPHA,0,0),
LETTER(L_ALPHA,M_TURNED,0), LETTER(L_ALPHA,M_TURNED,0),
LETTER('b',M_IMPLOSIVE,0), LETTER('b',M_IMPLOSIVE,0),
LETTER('c',M_CURL,0), LETTER('c',M_CURL,0),
LETTER('d',M_RETROFLEX,0), LETTER('d',M_RETROFLEX,0),
LETTER('d',M_IMPLOSIVE,0), LETTER('d',M_IMPLOSIVE,0),
LETTER('e',M_REVERSED,0), // U+258
LETTER('e',M_REVERSED,0), // U+258
0, // schwa 0, // schwa
LETTER(L_SCHWA,M_HOOK,0), LETTER(L_SCHWA,M_HOOK,0),
0, // open-e 0, // open-e
LETTER(L_OPEN_E,M_HOOK,M_REVERSED), LETTER(L_OPEN_E,M_HOOK,M_REVERSED),
0, 0,
LETTER('j',M_BAR,0), LETTER('j',M_BAR,0),
LETTER('g',M_IMPLOSIVE,0), // U+260
LETTER('g',M_IMPLOSIVE,0), // U+260
LETTER('g',0,0), LETTER('g',0,0),
LETTER('g',M_SMALLCAP,0), LETTER('g',M_SMALLCAP,0),
LETTER(L_GAMMA,0,0), LETTER(L_GAMMA,0,0),
LETTER('h',M_TURNED,0), LETTER('h',M_TURNED,0),
LETTER('h',M_HOOK,0), LETTER('h',M_HOOK,0),
0, 0,
LETTER('i',M_BAR,0), // U+268
LETTER('i',M_BAR,0), // U+268
LETTER(L_IOTA,0,0), LETTER(L_IOTA,0,0),
LETTER('i',M_SMALLCAP,0), LETTER('i',M_SMALLCAP,0),
LETTER('l',M_TILDE,0), LETTER('l',M_TILDE,0),
LETTER('o',M_BAR,0), LETTER('o',M_BAR,0),
LIGATURE('o','e',M_SMALLCAP), LIGATURE('o','e',M_SMALLCAP),
0, 0,
LETTER(L_PHI,0,0), // U+278
LETTER(L_PHI,0,0), // U+278
LETTER('r',M_TURNED,0), LETTER('r',M_TURNED,0),
LETTER(L_RLONG,M_TURNED,0), LETTER(L_RLONG,M_TURNED,0),
LETTER('r',M_RETROFLEX,M_TURNED), LETTER('r',M_RETROFLEX,M_TURNED),
LETTER('r',M_RETROFLEX,0), LETTER('r',M_RETROFLEX,0),
0, // r-tap 0, // r-tap
LETTER(L_RTAP,M_REVERSED,0), LETTER(L_RTAP,M_REVERSED,0),
LETTER('r',M_SMALLCAP,0), // U+280
LETTER('r',M_SMALLCAP,0), // U+280
LETTER('r',M_TURNED,M_SMALLCAP), LETTER('r',M_TURNED,M_SMALLCAP),
LETTER('s',M_RETROFLEX,0), LETTER('s',M_RETROFLEX,0),
0, // esh 0, // esh
LETTER(L_ESH,M_REVERSED,0), LETTER(L_ESH,M_REVERSED,0),
LETTER(L_ESH,M_CURL,0), LETTER(L_ESH,M_CURL,0),
LETTER('t',M_TURNED,0), LETTER('t',M_TURNED,0),
LETTER('t',M_RETROFLEX,0), // U+288
LETTER('t',M_RETROFLEX,0), // U+288
LETTER('u',M_BAR,0), LETTER('u',M_BAR,0),
LETTER(L_UPSILON,0,0), LETTER(L_UPSILON,0,0),
LETTER('v',M_HOOK,0), LETTER('v',M_HOOK,0),
LETTER('w',M_TURNED,0), LETTER('w',M_TURNED,0),
LETTER('y',M_TURNED,0), LETTER('y',M_TURNED,0),
LETTER('y',M_SMALLCAP,0), LETTER('y',M_SMALLCAP,0),
LETTER('z',M_RETROFLEX,0), // U+290
LETTER('z',M_RETROFLEX,0), // U+290
LETTER('z',M_CURL,0), LETTER('z',M_CURL,0),
0, // ezh 0, // ezh
LETTER(L_EZH,M_CURL,0), LETTER(L_EZH,M_CURL,0),
0x660, 0x6f0, // arabic 0x660, 0x6f0, // arabic
0x966, 0x9e6, 0xa66, 0xae6, 0xb66, 0xbe6, 0xc66, 0xce6, 0xd66, // indic 0x966, 0x9e6, 0xa66, 0xae6, 0xb66, 0xbe6, 0xc66, 0xce6, 0xd66, // indic
0xe50, 0xed0, 0xf20, 0x1040, 0x1090, 0xe50, 0xed0, 0xf20, 0x1040, 0x1090,
0 }; // these must be in ascending order
0
}; // these must be in ascending order




int NonAsciiNumber(int letter) int NonAsciiNumber(int letter)
0x209a, 'p'+L_SUB, 0x209a, 'p'+L_SUB,
0x209b, 's'+L_SUB, 0x209b, 's'+L_SUB,
0x209c, 't'+L_SUB, 0x209c, 't'+L_SUB,
0,0};
0,0
};




static const char *hex_letters[] = {"'e:j","b'i:","s'i:","d'i:","'i:","'ef"}; // names, using phonemes available to all languages static const char *hex_letters[] = {"'e:j","b'i:","s'i:","d'i:","'i:","'ef"}; // names, using phonemes available to all languages


found = 0; found = 0;
if((ordinal) if((ordinal)
&& ((tensunits == 0) || (tr->langopts.numbers2 & NUM2_MULTIPLE_ORDINAL)))
&& ((tensunits == 0) || (tr->langopts.numbers2 & NUM2_MULTIPLE_ORDINAL)))
{ {
// ordinal number // ordinal number
sprintf(string, "_%dCo", hundreds); sprintf(string, "_%dCo", hundreds);
digit_lookup = buf_digit_lookup; digit_lookup = buf_digit_lookup;
number_control = control; number_control = control;


for(ix=0; IsDigit09(word[ix]); ix++) ;
for(ix=0; IsDigit09(word[ix]); ix++);
n_digits = ix; n_digits = ix;
value = this_value = atoi(word); value = this_value = atoi(word);


} }
else else


if(speak_missing_thousands == 1)
if(speak_missing_thousands == 1)
{
// speak this thousandplex if there was no word for the previous thousandplex
sprintf(string,"_0M%d",thousandplex+1);
if(Lookup(tr, string, buf1)==0)
{ {
// speak this thousandplex if there was no word for the previous thousandplex
sprintf(string,"_0M%d",thousandplex+1);
if(Lookup(tr, string, buf1)==0)
{
sprintf(string,"_0M%d",thousandplex);
Lookup(tr, string, ph_append);
}
sprintf(string,"_0M%d",thousandplex);
Lookup(tr, string, ph_append);
} }
}


if((ph_append[0] == 0) && (word[n_digits] == '.') && (thousandplex == 0)) if((ph_append[0] == 0) && (word[n_digits] == '.') && (thousandplex == 0))
{ {
while(IsDigit09(word[n_digits+decimal_count])) while(IsDigit09(word[n_digits+decimal_count]))
decimal_count++; decimal_count++;


max_decimal_count = 2;
switch(decimal_mode = (tr->langopts.numbers & 0xe000))
max_decimal_count = 2;
switch(decimal_mode = (tr->langopts.numbers & 0xe000))
{
case NUM_DFRACTION_4:
max_decimal_count = 5;
case NUM_DFRACTION_2:
// French/Polish decimal fraction
while(word[n_digits] == '0')
{ {
case NUM_DFRACTION_4:
max_decimal_count = 5;
case NUM_DFRACTION_2:
// French/Polish decimal fraction
while(word[n_digits] == '0')
{
Lookup(tr, "_0", buf1);
strcat(ph_out,buf1);
decimal_count--;
n_digits++;
}
if((decimal_count <= max_decimal_count) && IsDigit09(word[n_digits]))
{
LookupNum3(tr, atoi(&word[n_digits]), buf1, 0,0,0);
strcat(ph_out,buf1);
n_digits += decimal_count;
}
break;

case NUM_DFRACTION_1: // italian, say "hundredths" if leading zero
case NUM_DFRACTION_5: // hungarian, always say "tenths" etc.
case NUM_DFRACTION_6: // kazakh, always say "tenths" etc, before the decimal fraction
LookupNum3(tr, atoi(&word[n_digits]), ph_buf, 0,0,0);
if((word[n_digits]=='0') || (decimal_mode != NUM_DFRACTION_1))
{
// decimal part has leading zeros, so add a "hundredths" or "thousandths" suffix
sprintf(string,"_0Z%d",decimal_count);
if(Lookup(tr, string, buf1) == 0)
break; // revert to speaking single digits

if(decimal_mode == NUM_DFRACTION_6)
strcat(ph_out, buf1);
else
strcat(ph_buf, buf1);
}
strcat(ph_out,ph_buf);
Lookup(tr, "_0", buf1);
strcat(ph_out,buf1);
decimal_count--;
n_digits++;
}
if((decimal_count <= max_decimal_count) && IsDigit09(word[n_digits]))
{
LookupNum3(tr, atoi(&word[n_digits]), buf1, 0,0,0);
strcat(ph_out,buf1);
n_digits += decimal_count; n_digits += decimal_count;
break;
}
break;


case NUM_DFRACTION_3:
// Romanian decimal fractions
if((decimal_count <= 4) && (word[n_digits] != '0'))
{
LookupNum3(tr, atoi(&word[n_digits]), buf1, 0,0,0);
strcat(ph_out,buf1);
n_digits += decimal_count;
}
break;
case NUM_DFRACTION_1: // italian, say "hundredths" if leading zero
case NUM_DFRACTION_5: // hungarian, always say "tenths" etc.
case NUM_DFRACTION_6: // kazakh, always say "tenths" etc, before the decimal fraction
LookupNum3(tr, atoi(&word[n_digits]), ph_buf, 0,0,0);
if((word[n_digits]=='0') || (decimal_mode != NUM_DFRACTION_1))
{
// decimal part has leading zeros, so add a "hundredths" or "thousandths" suffix
sprintf(string,"_0Z%d",decimal_count);
if(Lookup(tr, string, buf1) == 0)
break; // revert to speaking single digits


case NUM_DFRACTION_7:
// alternative form of decimal fraction digits, except the final digit
while(decimal_count-- > 1)
{
sprintf(string,"_%cd", word[n_digits]);
if(Lookup(tr, string, buf1) == 0)
break;
n_digits++;
if(decimal_mode == NUM_DFRACTION_6)
strcat(ph_out, buf1); strcat(ph_out, buf1);
}
else
strcat(ph_buf, buf1);
} }
strcat(ph_out,ph_buf);
n_digits += decimal_count;
break;

case NUM_DFRACTION_3:
// Romanian decimal fractions
if((decimal_count <= 4) && (word[n_digits] != '0'))
{
LookupNum3(tr, atoi(&word[n_digits]), buf1, 0,0,0);
strcat(ph_out,buf1);
n_digits += decimal_count;
}
break;

case NUM_DFRACTION_7:
// alternative form of decimal fraction digits, except the final digit
while(decimal_count-- > 1)
{
sprintf(string,"_%cd", word[n_digits]);
if(Lookup(tr, string, buf1) == 0)
break;
n_digits++;
strcat(ph_out, buf1);
}
}


while(IsDigit09(c = word[n_digits]) && (strlen(ph_out) < (N_WORD_PHONEMES - 10))) while(IsDigit09(c = word[n_digits]) && (strlen(ph_out) < (N_WORD_PHONEMES - 10)))
{ {

+ 8
- 8
src/libespeak-ng/phoneme.h View File

// main table of phonemes, index by phoneme number (1-254) // main table of phonemes, index by phoneme number (1-254)


typedef struct { typedef struct {
unsigned int mnemonic; // Up to 4 characters. The first char is in the l.s.byte
unsigned int phflags; // bits 16-19 place of articulation
unsigned int mnemonic; // Up to 4 characters. The first char is in the l.s.byte
unsigned int phflags; // bits 16-19 place of articulation
unsigned short program; // index into phondata file unsigned short program; // index into phondata file
unsigned char code; // the phoneme number
unsigned char type; // phVOWEL, phPAUSE, phSTOP etc
unsigned char start_type;
unsigned char end_type;
unsigned char std_length; // for vowels, in mS/2; for phSTRESS phonemes, this is the stress/tone type
unsigned char length_mod; // a length_mod group number, used to access length_mod_tab
unsigned char code; // the phoneme number
unsigned char type; // phVOWEL, phPAUSE, phSTOP etc
unsigned char start_type;
unsigned char end_type;
unsigned char std_length; // for vowels, in mS/2; for phSTRESS phonemes, this is the stress/tone type
unsigned char length_mod; // a length_mod group number, used to access length_mod_tab


} PHONEME_TAB; } PHONEME_TAB;



+ 10
- 10
src/libespeak-ng/phonemelist.c View File





extern int n_ph_list2; extern int n_ph_list2;
extern PHONEME_LIST2 ph_list2[N_PHONEME_LIST]; // first stage of text->phonemes
extern PHONEME_LIST2 ph_list2[N_PHONEME_LIST]; // first stage of text->phonemes






void MakePhonemeList(Translator *tr, int post_pause, int start_sentence) void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
{ {


int ix=0;
int j;
int insert_ph = 0;
int ix=0;
int j;
int insert_ph = 0;
PHONEME_LIST *phlist; PHONEME_LIST *phlist;
PHONEME_TAB *ph; PHONEME_TAB *ph;
PHONEME_TAB *next, *next2; PHONEME_TAB *next, *next2;
if(plist2[j].phcode == phonSWITCH) if(plist2[j].phcode == phonSWITCH)
{ {
if((!(plist2[j].synthflags & SFLAG_EMBEDDED)) && ( if((!(plist2[j].synthflags & SFLAG_EMBEDDED)) && (
(plist2[j].tone_ph == current_phoneme_tab) ||
(plist2[j+1].phcode == phonSWITCH) ||
((plist2[j+1].phcode == phonPAUSE) && (plist2[j+2].phcode == phonSWITCH))
))
(plist2[j].tone_ph == current_phoneme_tab) ||
(plist2[j+1].phcode == phonSWITCH) ||
((plist2[j+1].phcode == phonPAUSE) && (plist2[j+2].phcode == phonSWITCH))
))
{ {
// delete this phonSWITCH if it's switching to the current phoneme table, or // delete this phonSWITCH if it's switching to the current phoneme table, or
// delete this phonSWITCH if its followed by another phonSWITCH // delete this phonSWITCH if its followed by another phonSWITCH


n_ph_list3 = SubstitutePhonemes(tr,ph_list3) - 2; n_ph_list3 = SubstitutePhonemes(tr,ph_list3) - 2;


for(j=0; (j < n_ph_list3) && (ix < N_PHONEME_LIST-3);)
for(j=0; (j < n_ph_list3) && (ix < N_PHONEME_LIST-3); )
{ {
if(ph_list3[j].sourceix) if(ph_list3[j].sourceix)
{ {
word_stress = 0; word_stress = 0;


// find the highest stress level in this word // find the highest stress level in this word
for(nextw=j; nextw < n_ph_list3;)
for(nextw=j; nextw < n_ph_list3; )
{ {
if(ph_list3[nextw].stresslevel > word_stress) if(ph_list3[nextw].stresslevel > word_stress)
word_stress = ph_list3[nextw].stresslevel; word_stress = ph_list3[nextw].stresslevel;

+ 213
- 193
src/libespeak-ng/readclause.c View File



// punctuations symbols that can end a clause // punctuations symbols that can end a clause
static const unsigned short punct_chars[] = {',','.','?','!',':',';', static const unsigned short punct_chars[] = {',','.','?','!',':',';',
0x00a1, // inverted exclamation
0x00bf, // inverted question
0x2013, // en-dash
0x2014, // em-dash
0x2026, // elipsis
0x037e, // Greek question mark (looks like semicolon)
0x0387, // Greek semicolon, ano teleia
0x0964, // Devanagari Danda (fullstop)
0x0589, // Armenian period
0x055d, // Armenian comma
0x055c, // Armenian exclamation
0x055e, // Armenian question
0x055b, // Armenian emphasis mark
0x060c, // Arabic ,
0x061b, // Arabic ;
0x061f, // Arabic ?
0x06d4, // Arabic .
0x0df4, // Singhalese Kunddaliya
0x0f0d, // Tibet Shad
0x0f0e,
0x1362, // Ethiopic period
0x1363,
0x1364,
0x1365,
0x1366,
0x1367,
0x1368,
0x10fb, // Georgian paragraph
0x3001, // ideograph comma
0x3002, // ideograph period
0xff01, // fullwidth exclamation
0xff0c, // fullwidth comma
0xff0e, // fullwidth period
0xff1a, // fullwidth colon
0xff1b, // fullwidth semicolon
0xff1f, // fullwidth question mark
0};
0x00a1, // inverted exclamation
0x00bf, // inverted question
0x2013, // en-dash
0x2014, // em-dash
0x2026, // elipsis
0x037e, // Greek question mark (looks like semicolon)
0x0387, // Greek semicolon, ano teleia
0x0964, // Devanagari Danda (fullstop)
0x0589, // Armenian period
0x055d, // Armenian comma
0x055c, // Armenian exclamation
0x055e, // Armenian question
0x055b, // Armenian emphasis mark
0x060c, // Arabic ,
0x061b, // Arabic ;
0x061f, // Arabic ?
0x06d4, // Arabic .
0x0df4, // Singhalese Kunddaliya
0x0f0d, // Tibet Shad
0x0f0e,
0x1362, // Ethiopic period
0x1363,
0x1364,
0x1365,
0x1366,
0x1367,
0x1368,
0x10fb, // Georgian paragraph
0x3001, // ideograph comma
0x3002, // ideograph period
0xff01, // fullwidth exclamation
0xff0c, // fullwidth comma
0xff0e, // fullwidth period
0xff1a, // fullwidth colon
0xff1b, // fullwidth semicolon
0xff1f, // fullwidth question mark
0};




// indexed by (entry num. in punct_chars) + 1 // indexed by (entry num. in punct_chars) + 1
// bits 0-7 pause x 10mS, bits 12-14 intonation type, bit 15 don't need following space or bracket // bits 0-7 pause x 10mS, bits 12-14 intonation type, bit 15 don't need following space or bracket
static const unsigned int punct_attributes [] = { 0, static const unsigned int punct_attributes [] = { 0,
CLAUSE_COMMA, CLAUSE_PERIOD, CLAUSE_QUESTION, CLAUSE_EXCLAMATION, CLAUSE_COLON, CLAUSE_SEMICOLON,
CLAUSE_SEMICOLON | 0x8000, // inverted exclamation
CLAUSE_SEMICOLON | 0x8000, // inverted question
CLAUSE_SEMICOLON, // en-dash
CLAUSE_SEMICOLON, // em-dash
CLAUSE_SEMICOLON | PUNCT_SAY_NAME | 0x8000, // elipsis
CLAUSE_QUESTION, // Greek question mark
CLAUSE_SEMICOLON, // Greek semicolon
CLAUSE_PERIOD | 0x8000, // Devanagari Danda (fullstop)
CLAUSE_PERIOD | 0x8000, // Armenian period
CLAUSE_COMMA, // Armenian comma
CLAUSE_EXCLAMATION | PUNCT_IN_WORD, // Armenian exclamation
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
CLAUSE_PERIOD+0x8000, // Singhalese period
CLAUSE_PERIOD+0x8000, // Tibet period
CLAUSE_PARAGRAPH,
CLAUSE_PERIOD, // Ethiopic period
CLAUSE_COMMA, // Ethiopic comma
CLAUSE_SEMICOLON, // Ethiopic semicolon
CLAUSE_COLON, // Ethiopic colon
CLAUSE_COLON, // Ethiopic preface colon
CLAUSE_QUESTION, // Ethiopic question mark
CLAUSE_PARAGRAPH, // Ethiopic paragraph
CLAUSE_PARAGRAPH, // Georgian paragraph
CLAUSE_COMMA+0x8000, // ideograph comma
CLAUSE_PERIOD+0x8000, // ideograph period
CLAUSE_EXCLAMATION+0x8000, // fullwidth
CLAUSE_COMMA+0x8000,
CLAUSE_PERIOD+0x8000,
CLAUSE_COLON+0x8000,
CLAUSE_SEMICOLON+0x8000,
CLAUSE_QUESTION+0x8000,
CLAUSE_SEMICOLON, // spare
0 };
CLAUSE_COMMA, CLAUSE_PERIOD, CLAUSE_QUESTION, CLAUSE_EXCLAMATION, CLAUSE_COLON, CLAUSE_SEMICOLON,
CLAUSE_SEMICOLON | 0x8000, // inverted exclamation
CLAUSE_SEMICOLON | 0x8000, // inverted question
CLAUSE_SEMICOLON, // en-dash
CLAUSE_SEMICOLON, // em-dash
CLAUSE_SEMICOLON | PUNCT_SAY_NAME | 0x8000, // elipsis
CLAUSE_QUESTION, // Greek question mark
CLAUSE_SEMICOLON, // Greek semicolon
CLAUSE_PERIOD | 0x8000, // Devanagari Danda (fullstop)
CLAUSE_PERIOD | 0x8000, // Armenian period
CLAUSE_COMMA, // Armenian comma
CLAUSE_EXCLAMATION | PUNCT_IN_WORD, // Armenian exclamation
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
CLAUSE_PERIOD+0x8000, // Singhalese period
CLAUSE_PERIOD+0x8000, // Tibet period
CLAUSE_PARAGRAPH,
CLAUSE_PERIOD, // Ethiopic period
CLAUSE_COMMA, // Ethiopic comma
CLAUSE_SEMICOLON, // Ethiopic semicolon
CLAUSE_COLON, // Ethiopic colon
CLAUSE_COLON, // Ethiopic preface colon
CLAUSE_QUESTION, // Ethiopic question mark
CLAUSE_PARAGRAPH, // Ethiopic paragraph
CLAUSE_PARAGRAPH, // Georgian paragraph
CLAUSE_COMMA+0x8000, // ideograph comma
CLAUSE_PERIOD+0x8000, // ideograph period
CLAUSE_EXCLAMATION+0x8000, // fullwidth
CLAUSE_COMMA+0x8000,
CLAUSE_PERIOD+0x8000,
CLAUSE_COLON+0x8000,
CLAUSE_SEMICOLON+0x8000,
CLAUSE_QUESTION+0x8000,
CLAUSE_SEMICOLON, // spare
0 };




// stack for language and voice properties // stack for language and voice properties
int saved_parameters[N_SPEECH_PARAM]; //Parameters saved on synthesis start int saved_parameters[N_SPEECH_PARAM]; //Parameters saved on synthesis start


const int param_defaults[N_SPEECH_PARAM] = { const int param_defaults[N_SPEECH_PARAM] = {
0, // silence (internal use)
175, // rate wpm
100, // volume
50, // pitch
50, // range
0, // punctuation
0, // capital letters
0, // wordgap
0, // options
0, // intonation
0,
0,
0, // emphasis
0, // line length
0, // voice type
0, // silence (internal use)
175, // rate wpm
100, // volume
50, // pitch
50, // range
0, // punctuation
0, // capital letters
0, // wordgap
0, // options
0, // intonation
0,
0,
0, // emphasis
0, // line length
0, // voice type
}; };




// 0=not alphabetic, 0xff=lower case, 0xfe=no case, 0xfd=use wchar_tolower // 0=not alphabetic, 0xff=lower case, 0xfe=no case, 0xfd=use wchar_tolower
// other=value to add to upper case to convert to lower case // other=value to add to upper case to convert to lower case
static unsigned char walpha_tab[MAX_WALPHA-0x7f] = { static unsigned char walpha_tab[MAX_WALPHA-0x7f] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 080
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 090
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xfe, 0, 0, 0, 0, 0, // 0a0
0, 0, 0, 0, 0, 0xff, 0, 0, 0, 0, 0xfe, 0, 0, 0, 0, 0, // 0b0
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, // 0c0
32, 32, 32, 32, 32, 32, 32, 0, 32, 32, 32, 32, 32, 32, 32, 0xff, // 0d0
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // 0e0
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // 0f0
1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, // 100
1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, // 110
1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, // 120
0xfd, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 0xfe, 1, 0xff, 1, 0xff, 1, 0xff, 1, // 130
0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 0xfe, 1, 0xff, 1, 0xff, 1, 0xff, // 140
1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, // 150
1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, // 160
1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 0xfd, 1, 0xff, 1, 0xff, 1, 0xff, 0xff, // 170
0xff, 210, 1, 0xff, 1, 0xff, 206, 1, 0xff, 205, 205, 1, 0xff, 0xfe, 79, 202, // 180
203, 1, 0xff, 205, 207, 0xff, 211, 209, 1, 0xff, 0xff, 0xfe, 211, 213, 0xff, 214, // 190
1, 0xff, 1, 0xff, 1, 0xff, 218, 1, 0xff, 218, 0xfe, 0xfe, 1, 0xff, 218, 1, // 1a0
0xff, 217, 217, 1, 0xff, 1, 0xff, 219, 1, 0xff, 0xfe, 0xfe, 1, 0xff, 0xfe, 0xff, // 1b0
0xfe, 0xfe, 0xfe, 0xfe, 2, 0xff, 0xff, 2, 0xff, 0xff, 2, 0xff, 0xff, 1, 0xff, 1, // 1c0
0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 0xff, 1, 0xff, // 1d0
1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, // 1e0
0xfe, 2, 0xff, 0xff, 1, 0xff, 0xfd, 0xfd, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, // 1f0
1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, // 200
1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, // 210
0xfd, 0xfe, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, // 220
1, 0xff, 1, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 1, 0xff, 0xfd, 0xfd, 0xfe, // 230
0xfe, 1, 0xff, 0xfd, 69, 71, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff}; // 240
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 080
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 090
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xfe, 0, 0, 0, 0, 0, // 0a0
0, 0, 0, 0, 0, 0xff, 0, 0, 0, 0, 0xfe, 0, 0, 0, 0, 0, // 0b0
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,// 0c0
32, 32, 32, 32, 32, 32, 32, 0, 32, 32, 32, 32, 32, 32, 32, 0xff,// 0d0
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // 0e0
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,// 0f0
1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, // 100
1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, // 110
1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, // 120
0xfd, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 0xfe, 1, 0xff, 1, 0xff, 1, 0xff, 1,// 130
0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 0xfe, 1, 0xff, 1, 0xff, 1, 0xff,// 140
1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, // 150
1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, // 160
1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 0xfd, 1, 0xff, 1, 0xff, 1, 0xff, 0xff, // 170
0xff, 210, 1, 0xff, 1, 0xff, 206, 1, 0xff, 205, 205, 1, 0xff, 0xfe, 79, 202,// 180
203, 1, 0xff, 205, 207, 0xff, 211, 209, 1, 0xff, 0xff, 0xfe, 211, 213, 0xff, 214,// 190
1, 0xff, 1, 0xff, 1, 0xff, 218, 1, 0xff, 218, 0xfe, 0xfe, 1, 0xff, 218, 1, // 1a0
0xff, 217, 217, 1, 0xff, 1, 0xff, 219, 1, 0xff, 0xfe, 0xfe, 1, 0xff, 0xfe, 0xff,// 1b0
0xfe, 0xfe, 0xfe, 0xfe, 2, 0xff, 0xff, 2, 0xff, 0xff, 2, 0xff, 0xff, 1, 0xff, 1,// 1c0
0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 0xff, 1, 0xff,// 1d0
1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, // 1e0
0xfe, 2, 0xff, 0xff, 1, 0xff, 0xfd, 0xfd, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff,// 1f0
1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, // 200
1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, // 210
0xfd, 0xfe, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff,// 220
1, 0xff, 1, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 1, 0xff, 0xfd, 0xfd, 0xfe, // 230
0xfe, 1, 0xff, 0xfd, 69, 71, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff, 1, 0xff
}; // 240


static const short wchar_tolower[] = { static const short wchar_tolower[] = {
0x130, 0x069, 0x130, 0x069,
0x23d, 0x19a, 0x23d, 0x19a,
0x23e, 0x2c66, 0x23e, 0x2c66,
0x243, 0x180, 0x243, 0x180,
0,0 };
0,0
};


static const short wchar_toupper[] = { static const short wchar_toupper[] = {
0x0b5, 0x39c, 0x0b5, 0x39c,
0x1cc, 0x1ca, 0x1cc, 0x1ca,
0x1dd, 0x18e, 0x1dd, 0x18e,
0x1f3, 0x1f1, 0x1f3, 0x1f1,
0,0 };
0,0
};




#ifdef NEED_WCHAR_FUNCTIONS #ifdef NEED_WCHAR_FUNCTIONS


const wchar_t *wcschr(const wchar_t *str, int c) const wchar_t *wcschr(const wchar_t *str, int c)
{ {
while(*str != 0)
{
if(*str == c)
return(str);
str++;
}
return(NULL);
while(*str != 0)
{
if(*str == c)
return(str);
str++;
}
return(NULL);
} }


#ifndef WINCE #ifndef WINCE


float wcstod(const wchar_t *str, wchar_t **tailptr) float wcstod(const wchar_t *str, wchar_t **tailptr)
{ {
int ix;
char buf[80];
while(isspace(*str)) str++;
for(ix=0; ix<80; ix++)
{
buf[ix] = str[ix];
if(isspace(buf[ix]))
break;
}
*tailptr = (wchar_t *)&str[ix];
return(atof(buf));
int ix;
char buf[80];
while(isspace(*str)) str++;
for(ix=0; ix<80; ix++)
{
buf[ix] = str[ix];
if(isspace(buf[ix]))
break;
}
*tailptr = (wchar_t *)&str[ix];
return(atof(buf));
} }
#endif #endif


const char *WordToString2(unsigned int word) const char *WordToString2(unsigned int word)
{ {
// Convert a language mnemonic word into a string // Convert a language mnemonic word into a string
int ix;
int ix;
static char buf[5]; static char buf[5];
char *p; char *p;


FILE *f; FILE *f;
char *p; char *p;
int *ip; int *ip;
int length;
int length;
char fname_temp[100]; char fname_temp[100];
char fname2[sizeof(path_home)+13+40]; char fname2[sizeof(path_home)+13+40];


else else
{ {
sprintf(buf," %s %d %s", sprintf(buf," %s %d %s",
punctname,punct_count,punctname);
punctname,punct_count,punctname);
} }
} }
else else
{"strong", HTML_NOSPACE}, {"strong", HTML_NOSPACE},
{"em", HTML_NOSPACE}, {"em", HTML_NOSPACE},
{"code", HTML_NOSPACE}, {"code", HTML_NOSPACE},
{NULL,0}};
{NULL,0}
};








static PARAM_STACK *PushParamStack(int tag_type) static PARAM_STACK *PushParamStack(int tag_type)
{ {
int ix;
int ix;
PARAM_STACK *sp; PARAM_STACK *sp;


sp = &param_stack[n_param_stack]; sp = &param_stack[n_param_stack];


static int attrcmp(const wchar_t *string1, const char *string2) static int attrcmp(const wchar_t *string1, const char *string2)
{ {
int ix;
int ix;


if(string1 == NULL) if(string1 == NULL)
return(1); return(1);
{"male", 1}, {"male", 1},
{"female", 2}, {"female", 2},
{"neutral", 3}, {"neutral", 3},
{NULL, 0}};
{NULL, 0}
};


if(tag_type & SSML_CLOSE) if(tag_type & SSML_CLOSE)
{ {
{"medium",100}, {"medium",100},
{"loud",150}, {"loud",150},
{"x-loud",230}, {"x-loud",230},
{NULL, -1}};
{NULL, -1}
};


static const MNEM_TAB mnem_rate[] = { static const MNEM_TAB mnem_rate[] = {
{"default",100}, {"default",100},
{"medium",100}, {"medium",100},
{"fast",125}, {"fast",125},
{"x-fast",160}, {"x-fast",160},
{NULL, -1}};
{NULL, -1}
};


static const MNEM_TAB mnem_pitch[] = { static const MNEM_TAB mnem_pitch[] = {
{"default",100}, {"default",100},
{"medium",100}, {"medium",100},
{"high",110}, {"high",110},
{"x-high",120}, {"x-high",120},
{NULL, -1}};
{NULL, -1}
};


static const MNEM_TAB mnem_range[] = { static const MNEM_TAB mnem_range[] = {
{"default",100}, {"default",100},
{"medium",100}, {"medium",100},
{"high",140}, {"high",140},
{"x-high",180}, {"x-high",180},
{NULL, -1}};
{NULL, -1}
};


static const MNEM_TAB *mnem_tabs[5] = { static const MNEM_TAB *mnem_tabs[5] = {
NULL, mnem_rate, mnem_volume, mnem_pitch, mnem_range };
NULL, mnem_rate, mnem_volume, mnem_pitch, mnem_range
};




if((value = attrlookup(attr1,mnem_tabs[param_type])) >= 0) if((value = attrlookup(attr1,mnem_tabs[param_type])) >= 0)
{ {
// Replace some key-names by single characters, so they can be pronounced in different languages // Replace some key-names by single characters, so they can be pronounced in different languages
static MNEM_TAB keynames[] = { static MNEM_TAB keynames[] = {
{"space ",0xe020},
{"tab ", 0xe009},
{"underscore ", 0xe05f},
{"double-quote ", '"'},
{NULL, 0}};
{"space ",0xe020},
{"tab ", 0xe009},
{"underscore ", 0xe05f},
{"double-quote ", '"'},
{NULL, 0}
};


int ix; int ix;
int letter; int letter;


static const MNEM_TAB mnem_phoneme_alphabet[] = { static const MNEM_TAB mnem_phoneme_alphabet[] = {
{"espeak",1}, {"espeak",1},
{NULL, -1}};
{NULL, -1}
};


static const MNEM_TAB mnem_punct[] = { static const MNEM_TAB mnem_punct[] = {
{"none", 1}, {"none", 1},
{"all", 2}, {"all", 2},
{"some", 3}, {"some", 3},
{NULL, -1}};
{NULL, -1}
};


static const MNEM_TAB mnem_capitals[] = { static const MNEM_TAB mnem_capitals[] = {
{"no", 0}, {"no", 0},
{"spelling", 2}, {"spelling", 2},
{"icon", 1}, {"icon", 1},
{"pitch", 20}, // this is the amount by which to raise the pitch {"pitch", 20}, // this is the amount by which to raise the pitch
{NULL, -1}};
{NULL, -1}
};


static const MNEM_TAB mnem_interpret_as[] = { static const MNEM_TAB mnem_interpret_as[] = {
{"characters",SAYAS_CHARS}, {"characters",SAYAS_CHARS},
{"tts:key",SAYAS_KEY}, {"tts:key",SAYAS_KEY},
{"tts:digits",SAYAS_DIGITS}, {"tts:digits",SAYAS_DIGITS},
{"telephone",SAYAS_DIGITS1}, {"telephone",SAYAS_DIGITS1},
{NULL, -1}};
{NULL, -1}
};


static const MNEM_TAB mnem_sayas_format[] = { static const MNEM_TAB mnem_sayas_format[] = {
{"glyphs",1}, {"glyphs",1},
{NULL, -1}};
{NULL, -1}
};


static const MNEM_TAB mnem_break[] = { static const MNEM_TAB mnem_break[] = {
{"none",0}, {"none",0},
{"medium",3}, {"medium",3},
{"strong",4}, {"strong",4},
{"x-strong",5}, {"x-strong",5},
{NULL,-1}};
{NULL,-1}
};


static const MNEM_TAB mnem_emphasis[] = { static const MNEM_TAB mnem_emphasis[] = {
{"none",1}, {"none",1},
{"moderate",3}, {"moderate",3},
{"strong",4}, {"strong",4},
{"x-strong",5}, {"x-strong",5},
{NULL,-1}};
{NULL,-1}
};


static const char *prosody_attr[5] = { static const char *prosody_attr[5] = {
NULL, "rate", "volume", "pitch", "range" };
NULL, "rate", "volume", "pitch", "range"
};


for(ix=0; ix<(sizeof(tag_name)-1); ix++) for(ix=0; ix<(sizeof(tag_name)-1); ix++)
{ {
n_ssml_stack--; n_ssml_stack--;
} }


terminator=0; // ?? Sentence intonation, but no pause ??
terminator=0; // ?? Sentence intonation, but no pause ??
return(terminator + GetVoiceAttributes(px, tag_type)); return(terminator + GetVoiceAttributes(px, tag_type));


case HTML_BREAK: case HTML_BREAK:
{"quot", '"'}, {"quot", '"'},
{"nbsp", ' '}, {"nbsp", ' '},
{"apos", '\''}, {"apos", '\''},
{NULL,-1}};
{NULL,-1}
};




int ReadClause(Translator *tr, FILE *f_in, char *buf, short *charix, int *charix_top, int n_buf, int *tone_type, char *voice_change) int ReadClause(Translator *tr, FILE *f_in, char *buf, short *charix, int *charix_top, int n_buf, int *tone_type, char *voice_change)
{ {
/* Find the end of the current clause. /* Find the end of the current clause.
Write the clause into buf
Write the clause into buf


returns: clause type (bits 0-7: pause x10mS, bits 8-11 intonation type)
returns: clause type (bits 0-7: pause x10mS, bits 8-11 intonation type)


Also checks for blank line (paragraph) as end-of-clause indicator.
Also checks for blank line (paragraph) as end-of-clause indicator.


Does not end clause for:
punctuation immediately followed by alphanumeric eg. 1.23 !Speak :path
repeated punctuation, eg. ... !!!
*/
Does not end clause for:
punctuation immediately followed by alphanumeric eg. 1.23 !Speak :path
repeated punctuation, eg. ... !!!
*/
int c1=' '; // current character int c1=' '; // current character
int c2; // next character int c2; // next character
int cprev=' '; // previous character int cprev=' '; // previous character
*tone_type = 0; *tone_type = 0;
*voice_change = 0; *voice_change = 0;


f_input = f_in; // for GetC etc
f_input = f_in; // for GetC etc


if(ungot_word != NULL) if(ungot_word != NULL)
{ {
buf[ix+1] = 0; buf[ix+1] = 0;
if(parag > 3) if(parag > 3)
parag = 3; parag = 3;
if(option_ssml) parag=1;
if(option_ssml) parag=1;
return((CLAUSE_PARAGRAPH-30) + 30*parag); // several blank lines, longer pause return((CLAUSE_PARAGRAPH-30) + 30*parag); // several blank lines, longer pause
} }


if(c1 == '.') if(c1 == '.')
{ {
if((tr->langopts.numbers & NUM_ORDINAL_DOT) && if((tr->langopts.numbers & NUM_ORDINAL_DOT) &&
(iswdigit(cprev) || (IsRomanU(cprev) && (IsRomanU(cprev2) || iswspace(cprev2))))) // lang=hu
(iswdigit(cprev) || (IsRomanU(cprev) && (IsRomanU(cprev2) || iswspace(cprev2))))) // lang=hu
{ {
// dot after a number indicates an ordinal number // dot after a number indicates an ordinal number
if(!iswdigit(cprev)) if(!iswdigit(cprev))

+ 108
- 106
src/libespeak-ng/setlengths.c View File

// convert from words-per-minute to internal speed factor // convert from words-per-minute to internal speed factor
// Use this to calibrate speed for wpm 80-350 // Use this to calibrate speed for wpm 80-350
static unsigned char speed_lookup[] = { static unsigned char speed_lookup[] = {
255, 255, 255, 255, 255, // 80
253, 249, 245, 242, 238, // 85
235, 232, 228, 225, 222, // 90
218, 216, 213, 210, 207, // 95
204, 201, 198, 196, 193, // 100
191, 188, 186, 183, 181, // 105
179, 176, 174, 172, 169, // 110
168, 165, 163, 161, 159, // 115
158, 155, 153, 152, 150, // 120
148, 146, 145, 143, 141, // 125
139, 137, 136, 135, 133, // 130
131, 130, 129, 127, 126, // 135
124, 123, 122, 120, 119, // 140
118, 117, 115, 114, 113, // 145
112, 111, 110, 109, 107, // 150
106, 105, 104, 103, 102, // 155
101, 100, 99, 98, 97, // 160
96, 95, 94, 93, 92, // 165
91, 90, 89, 89, 88, // 170
87, 86, 85, 84, 83, // 175
82, 82, 81, 80, 80, // 180
79, 78, 77, 76, 76, // 185
75, 75, 74, 73, 72, // 190
71, 71, 70, 69, 69, // 195
68, 67, 67, 66, 66, // 200
65, 64, 64, 63, 62, // 205
62, 61, 61, 60, 59, // 210
59, 58, 58, 57, 57, // 215
56, 56, 55, 54, 54, // 220
53, 53, 52, 52, 52, // 225
51, 50, 50, 49, 49, // 230
48, 48, 47, 47, 46, // 235
46, 46, 45, 45, 44, // 240
44, 44, 43, 43, 42, // 245
41, 40, 40, 40, 39, // 250
39, 39, 38, 38, 38, // 255
37, 37, 37, 36, 36, // 260
35, 35, 35, 35, 34, // 265
34, 34, 33, 33, 33, // 270
32, 32, 31, 31, 31, // 275
30, 30, 30, 29, 29, // 280
29, 29, 28, 28, 27, // 285
27, 27, 27, 26, 26, // 290
26, 26, 25, 25, 25, // 295
24, 24, 24, 24, 23, // 300
23, 23, 23, 22, 22, // 305
22, 21, 21, 21, 21, // 310
20, 20, 20, 20, 19, // 315
19, 19, 18, 18, 17, // 320
17, 17, 16, 16, 16, // 325
16, 16, 16, 15, 15, // 330
15, 15, 14, 14, 14, // 335
13, 13, 13, 12, 12, // 340
12, 12, 11, 11, 11, // 345
11, 10, 10, 10, 9, // 350
9, 9, 8, 8, 8, // 355
255, 255, 255, 255, 255, // 80
253, 249, 245, 242, 238, // 85
235, 232, 228, 225, 222, // 90
218, 216, 213, 210, 207, // 95
204, 201, 198, 196, 193, // 100
191, 188, 186, 183, 181, // 105
179, 176, 174, 172, 169, // 110
168, 165, 163, 161, 159, // 115
158, 155, 153, 152, 150, // 120
148, 146, 145, 143, 141, // 125
139, 137, 136, 135, 133, // 130
131, 130, 129, 127, 126, // 135
124, 123, 122, 120, 119, // 140
118, 117, 115, 114, 113, // 145
112, 111, 110, 109, 107, // 150
106, 105, 104, 103, 102, // 155
101, 100, 99, 98, 97,// 160
96, 95, 94, 93, 92, // 165
91, 90, 89, 89, 88, // 170
87, 86, 85, 84, 83, // 175
82, 82, 81, 80, 80, // 180
79, 78, 77, 76, 76, // 185
75, 75, 74, 73, 72, // 190
71, 71, 70, 69, 69, // 195
68, 67, 67, 66, 66, // 200
65, 64, 64, 63, 62, // 205
62, 61, 61, 60, 59, // 210
59, 58, 58, 57, 57, // 215
56, 56, 55, 54, 54, // 220
53, 53, 52, 52, 52, // 225
51, 50, 50, 49, 49, // 230
48, 48, 47, 47, 46, // 235
46, 46, 45, 45, 44, // 240
44, 44, 43, 43, 42, // 245
41, 40, 40, 40, 39, // 250
39, 39, 38, 38, 38, // 255
37, 37, 37, 36, 36, // 260
35, 35, 35, 35, 34, // 265
34, 34, 33, 33, 33, // 270
32, 32, 31, 31, 31, // 275
30, 30, 30, 29, 29, // 280
29, 29, 28, 28, 27, // 285
27, 27, 27, 26, 26, // 290
26, 26, 25, 25, 25, // 295
24, 24, 24, 24, 23, // 300
23, 23, 23, 22, 22, // 305
22, 21, 21, 21, 21, // 310
20, 20, 20, 20, 19, // 315
19, 19, 18, 18, 17, // 320
17, 17, 16, 16, 16, // 325
16, 16, 16, 15, 15, // 330
15, 15, 14, 14, 14, // 335
13, 13, 13, 12, 12, // 340
12, 12, 11, 11, 11, // 345
11, 10, 10, 10, 9, // 350
9, 9, 8, 8, 8, // 355
}; };




// speed_factor1 adjustments for speeds 350 to 374: pauses // speed_factor1 adjustments for speeds 350 to 374: pauses
static unsigned char pause_factor_350[] = { static unsigned char pause_factor_350[] = {
22,22,22,22,22,22,22,21,21,21, // 350
21,20,20,19,19,18,17,16,15,15, // 360
15,15,15,15,15}; // 370
22,22,22,22,22,22,22,21,21,21, // 350
21,20,20,19,19,18,17,16,15,15, // 360
15,15,15,15,15
}; // 370


// wav_factor adjustments for speeds 350 to 450 // wav_factor adjustments for speeds 350 to 450
// Use this to calibrate speed for wpm 350-450 // Use this to calibrate speed for wpm 350-450
static unsigned char wav_factor_350[] = { static unsigned char wav_factor_350[] = {
120, 121, 120, 119, 119, // 350
118, 118, 117, 116, 116, // 355
115, 114, 113, 112, 112, // 360
111, 111, 110, 109, 108, // 365
107, 106, 106, 104, 103, // 370
103, 102, 102, 102, 101, // 375
101, 99, 98, 98, 97, // 380
96, 96, 95, 94, 93, // 385
91, 90, 91, 90, 89, // 390
88, 86, 85, 86, 85, // 395
85, 84, 82, 81, 80, // 400
79, 77, 78, 78, 76, // 405
77, 75, 75, 74, 73, // 410
71, 72, 70, 69, 69, // 415
69, 67, 65, 64, 63, // 420
63, 63, 61, 61, 59, // 425
59, 59, 58, 56, 57, // 430
58, 56, 54, 53, 52, // 435
52, 53, 52, 52, 50, // 440
48, 47, 47, 45, 46, // 445
45}; // 450
120, 121, 120, 119, 119, // 350
118, 118, 117, 116, 116, // 355
115, 114, 113, 112, 112, // 360
111, 111, 110, 109, 108, // 365
107, 106, 106, 104, 103, // 370
103, 102, 102, 102, 101, // 375
101, 99, 98, 98, 97,// 380
96, 96, 95, 94, 93, // 385
91, 90, 91, 90, 89, // 390
88, 86, 85, 86, 85, // 395
85, 84, 82, 81, 80, // 400
79, 77, 78, 78, 76, // 405
77, 75, 75, 74, 73, // 410
71, 72, 70, 69, 69, // 415
69, 67, 65, 64, 63, // 420
63, 63, 61, 61, 59, // 425
59, 59, 58, 56, 57, // 430
58, 56, 54, 53, 52, // 435
52, 53, 52, 52, 50, // 440
48, 47, 47, 45, 46, // 445
45
}; // 450


static int speed1 = 130; static int speed1 = 130;
static int speed2 = 121; static int speed2 = 121;
} }


// adjust for different sample rates // adjust for different sample rates
speed.min_sample_len = (speed.min_sample_len * samplerate_native) / 22050;
speed.min_sample_len = (speed.min_sample_len * samplerate_native) / 22050;


speed.pause_factor = (256 * s1)/115; // full speed adjustment, used for pause length speed.pause_factor = (256 * s1)/115; // full speed adjustment, used for pause length
speed.clause_pause_factor = 0; speed.clause_pause_factor = 0;
PHONEME_LIST *p; PHONEME_LIST *p;
PHONEME_LIST *p2; PHONEME_LIST *p2;


int stress;
int type;
static int more_syllables=0;
int pre_sonorant=0;
int pre_voiced=0;
int last_pitch = 0;
int pitch_start;
int length_mod;
int next2type;
int len;
int env2;
int end_of_clause;
int embedded_ix = 0;
int min_drop;
int pitch1;
int stress;
int type;
static int more_syllables=0;
int pre_sonorant=0;
int pre_voiced=0;
int last_pitch = 0;
int pitch_start;
int length_mod;
int next2type;
int len;
int env2;
int end_of_clause;
int embedded_ix = 0;
int min_drop;
int pitch1;
int emphasized; int emphasized;
int tone_mod;
int tone_mod;
unsigned char *pitch_env=NULL; unsigned char *pitch_env=NULL;
PHONEME_DATA phdata_tone; PHONEME_DATA phdata_tone;




if(stress > 7) stress = 7; if(stress > 7) stress = 7;


if(stress <= 1)
{
stress = stress ^ 1; // swap diminished and unstressed (until we swap stress_amps,stress_lengths in tr_languages)
}
if(stress <= 1)
{
stress = stress ^ 1; // swap diminished and unstressed (until we swap stress_amps,stress_lengths in tr_languages)
}
if(pre_sonorant) if(pre_sonorant)
p->amp = tr->stress_amps[stress]-1; p->amp = tr->stress_amps[stress]-1;
else else


length_mod = length_mod / 128; length_mod = length_mod / 128;


if(p->type != phVOWEL)
{
length_mod = 256; // syllabic consonant
min_drop = 16;
}
if(p->type != phVOWEL)
{
length_mod = 256; // syllabic consonant
min_drop = 16;
}
p->length = length_mod; p->length = length_mod;


if(p->env >= (N_ENVELOPE_DATA-1)) if(p->env >= (N_ENVELOPE_DATA-1))

+ 257
- 257
src/libespeak-ng/sintab.h View File

#endif #endif


short int sin_tab[2048] = { short int sin_tab[2048] = {
0, -25, -50, -75, -100, -125, -150, -175,
-201, -226, -251, -276, -301, -326, -351, -376,
-401, -427, -452, -477, -502, -527, -552, -577,
-602, -627, -652, -677, -702, -727, -752, -777,
-802, -827, -852, -877, -902, -927, -952, -977,
-1002, -1027, -1052, -1077, -1102, -1127, -1152, -1177,
-1201, -1226, -1251, -1276, -1301, -1326, -1350, -1375,
-1400, -1425, -1449, -1474, -1499, -1523, -1548, -1573,
-1597, -1622, -1647, -1671, -1696, -1721, -1745, -1770,
-1794, -1819, -1843, -1868, -1892, -1917, -1941, -1965,
-1990, -2014, -2038, -2063, -2087, -2111, -2136, -2160,
-2184, -2208, -2233, -2257, -2281, -2305, -2329, -2353,
-2377, -2401, -2425, -2449, -2473, -2497, -2521, -2545,
-2569, -2593, -2617, -2640, -2664, -2688, -2712, -2735,
-2759, -2783, -2806, -2830, -2853, -2877, -2900, -2924,
-2947, -2971, -2994, -3018, -3041, -3064, -3088, -3111,
-3134, -3157, -3180, -3204, -3227, -3250, -3273, -3296,
-3319, -3342, -3365, -3388, -3410, -3433, -3456, -3479,
-3502, -3524, -3547, -3570, -3592, -3615, -3637, -3660,
-3682, -3705, -3727, -3749, -3772, -3794, -3816, -3839,
-3861, -3883, -3905, -3927, -3949, -3971, -3993, -4015,
-4037, -4059, -4080, -4102, -4124, -4146, -4167, -4189,
-4211, -4232, -4254, -4275, -4296, -4318, -4339, -4360,
-4382, -4403, -4424, -4445, -4466, -4487, -4508, -4529,
-4550, -4571, -4592, -4613, -4633, -4654, -4675, -4695,
-4716, -4736, -4757, -4777, -4798, -4818, -4838, -4859,
-4879, -4899, -4919, -4939, -4959, -4979, -4999, -5019,
-5039, -5059, -5078, -5098, -5118, -5137, -5157, -5176,
-5196, -5215, -5235, -5254, -5273, -5292, -5311, -5331,
-5350, -5369, -5388, -5406, -5425, -5444, -5463, -5482,
-5500, -5519, -5537, -5556, -5574, -5593, -5611, -5629,
-5648, -5666, -5684, -5702, -5720, -5738, -5756, -5774,
-5791, -5809, -5827, -5844, -5862, -5880, -5897, -5914,
-5932, -5949, -5966, -5984, -6001, -6018, -6035, -6052,
-6069, -6085, -6102, -6119, -6136, -6152, -6169, -6185,
-6202, -6218, -6235, -6251, -6267, -6283, -6299, -6315,
-6331, -6347, -6363, -6379, -6395, -6410, -6426, -6441,
-6457, -6472, -6488, -6503, -6518, -6533, -6549, -6564,
-6579, -6594, -6608, -6623, -6638, -6653, -6667, -6682,
-6696, -6711, -6725, -6739, -6754, -6768, -6782, -6796,
-6810, -6824, -6838, -6852, -6865, -6879, -6893, -6906,
-6920, -6933, -6946, -6960, -6973, -6986, -6999, -7012,
-7025, -7038, -7051, -7064, -7076, -7089, -7101, -7114,
-7126, -7139, -7151, -7163, -7175, -7187, -7199, -7211,
-7223, -7235, -7247, -7259, -7270, -7282, -7293, -7305,
-7316, -7327, -7338, -7349, -7361, -7372, -7382, -7393,
-7404, -7415, -7425, -7436, -7446, -7457, -7467, -7478,
-7488, -7498, -7508, -7518, -7528, -7538, -7548, -7557,
-7567, -7577, -7586, -7596, -7605, -7614, -7623, -7633,
-7642, -7651, -7660, -7668, -7677, -7686, -7695, -7703,
-7712, -7720, -7728, -7737, -7745, -7753, -7761, -7769,
-7777, -7785, -7793, -7800, -7808, -7816, -7823, -7830,
-7838, -7845, -7852, -7859, -7866, -7873, -7880, -7887,
-7894, -7900, -7907, -7914, -7920, -7926, -7933, -7939,
-7945, -7951, -7957, -7963, -7969, -7975, -7980, -7986,
-7991, -7997, -8002, -8008, -8013, -8018, -8023, -8028,
-8033, -8038, -8043, -8047, -8052, -8057, -8061, -8066,
-8070, -8074, -8078, -8082, -8086, -8090, -8094, -8098,
-8102, -8105, -8109, -8113, -8116, -8119, -8123, -8126,
-8129, -8132, -8135, -8138, -8141, -8143, -8146, -8149,
-8151, -8153, -8156, -8158, -8160, -8162, -8164, -8166,
-8168, -8170, -8172, -8174, -8175, -8177, -8178, -8179,
-8181, -8182, -8183, -8184, -8185, -8186, -8187, -8187,
-8188, -8189, -8189, -8190, -8190, -8190, -8190, -8190,
-8191, -8190, -8190, -8190, -8190, -8190, -8189, -8189,
-8188, -8187, -8187, -8186, -8185, -8184, -8183, -8182,
-8181, -8179, -8178, -8177, -8175, -8174, -8172, -8170,
-8168, -8166, -8164, -8162, -8160, -8158, -8156, -8153,
-8151, -8149, -8146, -8143, -8141, -8138, -8135, -8132,
-8129, -8126, -8123, -8119, -8116, -8113, -8109, -8105,
-8102, -8098, -8094, -8090, -8086, -8082, -8078, -8074,
-8070, -8066, -8061, -8057, -8052, -8047, -8043, -8038,
-8033, -8028, -8023, -8018, -8013, -8008, -8002, -7997,
-7991, -7986, -7980, -7975, -7969, -7963, -7957, -7951,
-7945, -7939, -7933, -7926, -7920, -7914, -7907, -7900,
-7894, -7887, -7880, -7873, -7866, -7859, -7852, -7845,
-7838, -7830, -7823, -7816, -7808, -7800, -7793, -7785,
-7777, -7769, -7761, -7753, -7745, -7737, -7728, -7720,
-7712, -7703, -7695, -7686, -7677, -7668, -7660, -7651,
-7642, -7633, -7623, -7614, -7605, -7596, -7586, -7577,
-7567, -7557, -7548, -7538, -7528, -7518, -7508, -7498,
-7488, -7478, -7467, -7457, -7446, -7436, -7425, -7415,
-7404, -7393, -7382, -7372, -7361, -7349, -7338, -7327,
-7316, -7305, -7293, -7282, -7270, -7259, -7247, -7235,
-7223, -7211, -7199, -7187, -7175, -7163, -7151, -7139,
-7126, -7114, -7101, -7089, -7076, -7064, -7051, -7038,
-7025, -7012, -6999, -6986, -6973, -6960, -6946, -6933,
-6920, -6906, -6893, -6879, -6865, -6852, -6838, -6824,
-6810, -6796, -6782, -6768, -6754, -6739, -6725, -6711,
-6696, -6682, -6667, -6653, -6638, -6623, -6608, -6594,
-6579, -6564, -6549, -6533, -6518, -6503, -6488, -6472,
-6457, -6441, -6426, -6410, -6395, -6379, -6363, -6347,
-6331, -6315, -6299, -6283, -6267, -6251, -6235, -6218,
-6202, -6185, -6169, -6152, -6136, -6119, -6102, -6085,
-6069, -6052, -6035, -6018, -6001, -5984, -5966, -5949,
-5932, -5914, -5897, -5880, -5862, -5844, -5827, -5809,
-5791, -5774, -5756, -5738, -5720, -5702, -5684, -5666,
-5648, -5629, -5611, -5593, -5574, -5556, -5537, -5519,
-5500, -5482, -5463, -5444, -5425, -5406, -5388, -5369,
-5350, -5331, -5311, -5292, -5273, -5254, -5235, -5215,
-5196, -5176, -5157, -5137, -5118, -5098, -5078, -5059,
-5039, -5019, -4999, -4979, -4959, -4939, -4919, -4899,
-4879, -4859, -4838, -4818, -4798, -4777, -4757, -4736,
-4716, -4695, -4675, -4654, -4633, -4613, -4592, -4571,
-4550, -4529, -4508, -4487, -4466, -4445, -4424, -4403,
-4382, -4360, -4339, -4318, -4296, -4275, -4254, -4232,
-4211, -4189, -4167, -4146, -4124, -4102, -4080, -4059,
-4037, -4015, -3993, -3971, -3949, -3927, -3905, -3883,
-3861, -3839, -3816, -3794, -3772, -3749, -3727, -3705,
-3682, -3660, -3637, -3615, -3592, -3570, -3547, -3524,
-3502, -3479, -3456, -3433, -3410, -3388, -3365, -3342,
-3319, -3296, -3273, -3250, -3227, -3204, -3180, -3157,
-3134, -3111, -3088, -3064, -3041, -3018, -2994, -2971,
-2947, -2924, -2900, -2877, -2853, -2830, -2806, -2783,
-2759, -2735, -2712, -2688, -2664, -2640, -2617, -2593,
-2569, -2545, -2521, -2497, -2473, -2449, -2425, -2401,
-2377, -2353, -2329, -2305, -2281, -2257, -2233, -2208,
-2184, -2160, -2136, -2111, -2087, -2063, -2038, -2014,
-1990, -1965, -1941, -1917, -1892, -1868, -1843, -1819,
-1794, -1770, -1745, -1721, -1696, -1671, -1647, -1622,
-1597, -1573, -1548, -1523, -1499, -1474, -1449, -1425,
-1400, -1375, -1350, -1326, -1301, -1276, -1251, -1226,
-1201, -1177, -1152, -1127, -1102, -1077, -1052, -1027,
-1002, -977, -952, -927, -902, -877, -852, -827,
-802, -777, -752, -727, -702, -677, -652, -627,
-602, -577, -552, -527, -502, -477, -452, -427,
-401, -376, -351, -326, -301, -276, -251, -226,
-201, -175, -150, -125, -100, -75, -50, -25,
0, 25, 50, 75, 100, 125, 150, 175,
201, 226, 251, 276, 301, 326, 351, 376,
401, 427, 452, 477, 502, 527, 552, 577,
602, 627, 652, 677, 702, 727, 752, 777,
802, 827, 852, 877, 902, 927, 952, 977,
1002, 1027, 1052, 1077, 1102, 1127, 1152, 1177,
1201, 1226, 1251, 1276, 1301, 1326, 1350, 1375,
1400, 1425, 1449, 1474, 1499, 1523, 1548, 1573,
1597, 1622, 1647, 1671, 1696, 1721, 1745, 1770,
1794, 1819, 1843, 1868, 1892, 1917, 1941, 1965,
1990, 2014, 2038, 2063, 2087, 2111, 2136, 2160,
2184, 2208, 2233, 2257, 2281, 2305, 2329, 2353,
2377, 2401, 2425, 2449, 2473, 2497, 2521, 2545,
2569, 2593, 2617, 2640, 2664, 2688, 2712, 2735,
2759, 2783, 2806, 2830, 2853, 2877, 2900, 2924,
2947, 2971, 2994, 3018, 3041, 3064, 3088, 3111,
3134, 3157, 3180, 3204, 3227, 3250, 3273, 3296,
3319, 3342, 3365, 3388, 3410, 3433, 3456, 3479,
3502, 3524, 3547, 3570, 3592, 3615, 3637, 3660,
3682, 3705, 3727, 3749, 3772, 3794, 3816, 3839,
3861, 3883, 3905, 3927, 3949, 3971, 3993, 4015,
4037, 4059, 4080, 4102, 4124, 4146, 4167, 4189,
4211, 4232, 4254, 4275, 4296, 4318, 4339, 4360,
4382, 4403, 4424, 4445, 4466, 4487, 4508, 4529,
4550, 4571, 4592, 4613, 4633, 4654, 4675, 4695,
4716, 4736, 4757, 4777, 4798, 4818, 4838, 4859,
4879, 4899, 4919, 4939, 4959, 4979, 4999, 5019,
5039, 5059, 5078, 5098, 5118, 5137, 5157, 5176,
5196, 5215, 5235, 5254, 5273, 5292, 5311, 5331,
5350, 5369, 5388, 5406, 5425, 5444, 5463, 5482,
5500, 5519, 5537, 5556, 5574, 5593, 5611, 5629,
5648, 5666, 5684, 5702, 5720, 5738, 5756, 5774,
5791, 5809, 5827, 5844, 5862, 5880, 5897, 5914,
5932, 5949, 5966, 5984, 6001, 6018, 6035, 6052,
6069, 6085, 6102, 6119, 6136, 6152, 6169, 6185,
6202, 6218, 6235, 6251, 6267, 6283, 6299, 6315,
6331, 6347, 6363, 6379, 6395, 6410, 6426, 6441,
6457, 6472, 6488, 6503, 6518, 6533, 6549, 6564,
6579, 6594, 6608, 6623, 6638, 6653, 6667, 6682,
6696, 6711, 6725, 6739, 6754, 6768, 6782, 6796,
6810, 6824, 6838, 6852, 6865, 6879, 6893, 6906,
6920, 6933, 6946, 6960, 6973, 6986, 6999, 7012,
7025, 7038, 7051, 7064, 7076, 7089, 7101, 7114,
7126, 7139, 7151, 7163, 7175, 7187, 7199, 7211,
7223, 7235, 7247, 7259, 7270, 7282, 7293, 7305,
7316, 7327, 7338, 7349, 7361, 7372, 7382, 7393,
7404, 7415, 7425, 7436, 7446, 7457, 7467, 7478,
7488, 7498, 7508, 7518, 7528, 7538, 7548, 7557,
7567, 7577, 7586, 7596, 7605, 7614, 7623, 7633,
7642, 7651, 7660, 7668, 7677, 7686, 7695, 7703,
7712, 7720, 7728, 7737, 7745, 7753, 7761, 7769,
7777, 7785, 7793, 7800, 7808, 7816, 7823, 7830,
7838, 7845, 7852, 7859, 7866, 7873, 7880, 7887,
7894, 7900, 7907, 7914, 7920, 7926, 7933, 7939,
7945, 7951, 7957, 7963, 7969, 7975, 7980, 7986,
7991, 7997, 8002, 8008, 8013, 8018, 8023, 8028,
8033, 8038, 8043, 8047, 8052, 8057, 8061, 8066,
8070, 8074, 8078, 8082, 8086, 8090, 8094, 8098,
8102, 8105, 8109, 8113, 8116, 8119, 8123, 8126,
8129, 8132, 8135, 8138, 8141, 8143, 8146, 8149,
8151, 8153, 8156, 8158, 8160, 8162, 8164, 8166,
8168, 8170, 8172, 8174, 8175, 8177, 8178, 8179,
8181, 8182, 8183, 8184, 8185, 8186, 8187, 8187,
8188, 8189, 8189, 8190, 8190, 8190, 8190, 8190,
8191, 8190, 8190, 8190, 8190, 8190, 8189, 8189,
8188, 8187, 8187, 8186, 8185, 8184, 8183, 8182,
8181, 8179, 8178, 8177, 8175, 8174, 8172, 8170,
8168, 8166, 8164, 8162, 8160, 8158, 8156, 8153,
8151, 8149, 8146, 8143, 8141, 8138, 8135, 8132,
8129, 8126, 8123, 8119, 8116, 8113, 8109, 8105,
8102, 8098, 8094, 8090, 8086, 8082, 8078, 8074,
8070, 8066, 8061, 8057, 8052, 8047, 8043, 8038,
8033, 8028, 8023, 8018, 8013, 8008, 8002, 7997,
7991, 7986, 7980, 7975, 7969, 7963, 7957, 7951,
7945, 7939, 7933, 7926, 7920, 7914, 7907, 7900,
7894, 7887, 7880, 7873, 7866, 7859, 7852, 7845,
7838, 7830, 7823, 7816, 7808, 7800, 7793, 7785,
7777, 7769, 7761, 7753, 7745, 7737, 7728, 7720,
7712, 7703, 7695, 7686, 7677, 7668, 7660, 7651,
7642, 7633, 7623, 7614, 7605, 7596, 7586, 7577,
7567, 7557, 7548, 7538, 7528, 7518, 7508, 7498,
7488, 7478, 7467, 7457, 7446, 7436, 7425, 7415,
7404, 7393, 7382, 7372, 7361, 7349, 7338, 7327,
7316, 7305, 7293, 7282, 7270, 7259, 7247, 7235,
7223, 7211, 7199, 7187, 7175, 7163, 7151, 7139,
7126, 7114, 7101, 7089, 7076, 7064, 7051, 7038,
7025, 7012, 6999, 6986, 6973, 6960, 6946, 6933,
6920, 6906, 6893, 6879, 6865, 6852, 6838, 6824,
6810, 6796, 6782, 6768, 6754, 6739, 6725, 6711,
6696, 6682, 6667, 6653, 6638, 6623, 6608, 6594,
6579, 6564, 6549, 6533, 6518, 6503, 6488, 6472,
6457, 6441, 6426, 6410, 6395, 6379, 6363, 6347,
6331, 6315, 6299, 6283, 6267, 6251, 6235, 6218,
6202, 6185, 6169, 6152, 6136, 6119, 6102, 6085,
6069, 6052, 6035, 6018, 6001, 5984, 5966, 5949,
5932, 5914, 5897, 5880, 5862, 5844, 5827, 5809,
5791, 5774, 5756, 5738, 5720, 5702, 5684, 5666,
5648, 5629, 5611, 5593, 5574, 5556, 5537, 5519,
5500, 5482, 5463, 5444, 5425, 5406, 5388, 5369,
5350, 5331, 5311, 5292, 5273, 5254, 5235, 5215,
5196, 5176, 5157, 5137, 5118, 5098, 5078, 5059,
5039, 5019, 4999, 4979, 4959, 4939, 4919, 4899,
4879, 4859, 4838, 4818, 4798, 4777, 4757, 4736,
4716, 4695, 4675, 4654, 4633, 4613, 4592, 4571,
4550, 4529, 4508, 4487, 4466, 4445, 4424, 4403,
4382, 4360, 4339, 4318, 4296, 4275, 4254, 4232,
4211, 4189, 4167, 4146, 4124, 4102, 4080, 4059,
4037, 4015, 3993, 3971, 3949, 3927, 3905, 3883,
3861, 3839, 3816, 3794, 3772, 3749, 3727, 3705,
3682, 3660, 3637, 3615, 3592, 3570, 3547, 3524,
3502, 3479, 3456, 3433, 3410, 3388, 3365, 3342,
3319, 3296, 3273, 3250, 3227, 3204, 3180, 3157,
3134, 3111, 3088, 3064, 3041, 3018, 2994, 2971,
2947, 2924, 2900, 2877, 2853, 2830, 2806, 2783,
2759, 2735, 2712, 2688, 2664, 2640, 2617, 2593,
2569, 2545, 2521, 2497, 2473, 2449, 2425, 2401,
2377, 2353, 2329, 2305, 2281, 2257, 2233, 2208,
2184, 2160, 2136, 2111, 2087, 2063, 2038, 2014,
1990, 1965, 1941, 1917, 1892, 1868, 1843, 1819,
1794, 1770, 1745, 1721, 1696, 1671, 1647, 1622,
1597, 1573, 1548, 1523, 1499, 1474, 1449, 1425,
1400, 1375, 1350, 1326, 1301, 1276, 1251, 1226,
1201, 1177, 1152, 1127, 1102, 1077, 1052, 1027,
1002, 977, 952, 927, 902, 877, 852, 827,
802, 777, 752, 727, 702, 677, 652, 627,
602, 577, 552, 527, 502, 477, 452, 427,
401, 376, 351, 326, 301, 276, 251, 226,
201, 175, 150, 125, 100, 75, 50, 25,
};
0, -25, -50, -75, -100, -125, -150, -175,
-201, -226, -251, -276, -301, -326, -351, -376,
-401, -427, -452, -477, -502, -527, -552, -577,
-602, -627, -652, -677, -702, -727, -752, -777,
-802, -827, -852, -877, -902, -927, -952, -977,
-1002, -1027, -1052, -1077, -1102, -1127, -1152, -1177,
-1201, -1226, -1251, -1276, -1301, -1326, -1350, -1375,
-1400, -1425, -1449, -1474, -1499, -1523, -1548, -1573,
-1597, -1622, -1647, -1671, -1696, -1721, -1745, -1770,
-1794, -1819, -1843, -1868, -1892, -1917, -1941, -1965,
-1990, -2014, -2038, -2063, -2087, -2111, -2136, -2160,
-2184, -2208, -2233, -2257, -2281, -2305, -2329, -2353,
-2377, -2401, -2425, -2449, -2473, -2497, -2521, -2545,
-2569, -2593, -2617, -2640, -2664, -2688, -2712, -2735,
-2759, -2783, -2806, -2830, -2853, -2877, -2900, -2924,
-2947, -2971, -2994, -3018, -3041, -3064, -3088, -3111,
-3134, -3157, -3180, -3204, -3227, -3250, -3273, -3296,
-3319, -3342, -3365, -3388, -3410, -3433, -3456, -3479,
-3502, -3524, -3547, -3570, -3592, -3615, -3637, -3660,
-3682, -3705, -3727, -3749, -3772, -3794, -3816, -3839,
-3861, -3883, -3905, -3927, -3949, -3971, -3993, -4015,
-4037, -4059, -4080, -4102, -4124, -4146, -4167, -4189,
-4211, -4232, -4254, -4275, -4296, -4318, -4339, -4360,
-4382, -4403, -4424, -4445, -4466, -4487, -4508, -4529,
-4550, -4571, -4592, -4613, -4633, -4654, -4675, -4695,
-4716, -4736, -4757, -4777, -4798, -4818, -4838, -4859,
-4879, -4899, -4919, -4939, -4959, -4979, -4999, -5019,
-5039, -5059, -5078, -5098, -5118, -5137, -5157, -5176,
-5196, -5215, -5235, -5254, -5273, -5292, -5311, -5331,
-5350, -5369, -5388, -5406, -5425, -5444, -5463, -5482,
-5500, -5519, -5537, -5556, -5574, -5593, -5611, -5629,
-5648, -5666, -5684, -5702, -5720, -5738, -5756, -5774,
-5791, -5809, -5827, -5844, -5862, -5880, -5897, -5914,
-5932, -5949, -5966, -5984, -6001, -6018, -6035, -6052,
-6069, -6085, -6102, -6119, -6136, -6152, -6169, -6185,
-6202, -6218, -6235, -6251, -6267, -6283, -6299, -6315,
-6331, -6347, -6363, -6379, -6395, -6410, -6426, -6441,
-6457, -6472, -6488, -6503, -6518, -6533, -6549, -6564,
-6579, -6594, -6608, -6623, -6638, -6653, -6667, -6682,
-6696, -6711, -6725, -6739, -6754, -6768, -6782, -6796,
-6810, -6824, -6838, -6852, -6865, -6879, -6893, -6906,
-6920, -6933, -6946, -6960, -6973, -6986, -6999, -7012,
-7025, -7038, -7051, -7064, -7076, -7089, -7101, -7114,
-7126, -7139, -7151, -7163, -7175, -7187, -7199, -7211,
-7223, -7235, -7247, -7259, -7270, -7282, -7293, -7305,
-7316, -7327, -7338, -7349, -7361, -7372, -7382, -7393,
-7404, -7415, -7425, -7436, -7446, -7457, -7467, -7478,
-7488, -7498, -7508, -7518, -7528, -7538, -7548, -7557,
-7567, -7577, -7586, -7596, -7605, -7614, -7623, -7633,
-7642, -7651, -7660, -7668, -7677, -7686, -7695, -7703,
-7712, -7720, -7728, -7737, -7745, -7753, -7761, -7769,
-7777, -7785, -7793, -7800, -7808, -7816, -7823, -7830,
-7838, -7845, -7852, -7859, -7866, -7873, -7880, -7887,
-7894, -7900, -7907, -7914, -7920, -7926, -7933, -7939,
-7945, -7951, -7957, -7963, -7969, -7975, -7980, -7986,
-7991, -7997, -8002, -8008, -8013, -8018, -8023, -8028,
-8033, -8038, -8043, -8047, -8052, -8057, -8061, -8066,
-8070, -8074, -8078, -8082, -8086, -8090, -8094, -8098,
-8102, -8105, -8109, -8113, -8116, -8119, -8123, -8126,
-8129, -8132, -8135, -8138, -8141, -8143, -8146, -8149,
-8151, -8153, -8156, -8158, -8160, -8162, -8164, -8166,
-8168, -8170, -8172, -8174, -8175, -8177, -8178, -8179,
-8181, -8182, -8183, -8184, -8185, -8186, -8187, -8187,
-8188, -8189, -8189, -8190, -8190, -8190, -8190, -8190,
-8191, -8190, -8190, -8190, -8190, -8190, -8189, -8189,
-8188, -8187, -8187, -8186, -8185, -8184, -8183, -8182,
-8181, -8179, -8178, -8177, -8175, -8174, -8172, -8170,
-8168, -8166, -8164, -8162, -8160, -8158, -8156, -8153,
-8151, -8149, -8146, -8143, -8141, -8138, -8135, -8132,
-8129, -8126, -8123, -8119, -8116, -8113, -8109, -8105,
-8102, -8098, -8094, -8090, -8086, -8082, -8078, -8074,
-8070, -8066, -8061, -8057, -8052, -8047, -8043, -8038,
-8033, -8028, -8023, -8018, -8013, -8008, -8002, -7997,
-7991, -7986, -7980, -7975, -7969, -7963, -7957, -7951,
-7945, -7939, -7933, -7926, -7920, -7914, -7907, -7900,
-7894, -7887, -7880, -7873, -7866, -7859, -7852, -7845,
-7838, -7830, -7823, -7816, -7808, -7800, -7793, -7785,
-7777, -7769, -7761, -7753, -7745, -7737, -7728, -7720,
-7712, -7703, -7695, -7686, -7677, -7668, -7660, -7651,
-7642, -7633, -7623, -7614, -7605, -7596, -7586, -7577,
-7567, -7557, -7548, -7538, -7528, -7518, -7508, -7498,
-7488, -7478, -7467, -7457, -7446, -7436, -7425, -7415,
-7404, -7393, -7382, -7372, -7361, -7349, -7338, -7327,
-7316, -7305, -7293, -7282, -7270, -7259, -7247, -7235,
-7223, -7211, -7199, -7187, -7175, -7163, -7151, -7139,
-7126, -7114, -7101, -7089, -7076, -7064, -7051, -7038,
-7025, -7012, -6999, -6986, -6973, -6960, -6946, -6933,
-6920, -6906, -6893, -6879, -6865, -6852, -6838, -6824,
-6810, -6796, -6782, -6768, -6754, -6739, -6725, -6711,
-6696, -6682, -6667, -6653, -6638, -6623, -6608, -6594,
-6579, -6564, -6549, -6533, -6518, -6503, -6488, -6472,
-6457, -6441, -6426, -6410, -6395, -6379, -6363, -6347,
-6331, -6315, -6299, -6283, -6267, -6251, -6235, -6218,
-6202, -6185, -6169, -6152, -6136, -6119, -6102, -6085,
-6069, -6052, -6035, -6018, -6001, -5984, -5966, -5949,
-5932, -5914, -5897, -5880, -5862, -5844, -5827, -5809,
-5791, -5774, -5756, -5738, -5720, -5702, -5684, -5666,
-5648, -5629, -5611, -5593, -5574, -5556, -5537, -5519,
-5500, -5482, -5463, -5444, -5425, -5406, -5388, -5369,
-5350, -5331, -5311, -5292, -5273, -5254, -5235, -5215,
-5196, -5176, -5157, -5137, -5118, -5098, -5078, -5059,
-5039, -5019, -4999, -4979, -4959, -4939, -4919, -4899,
-4879, -4859, -4838, -4818, -4798, -4777, -4757, -4736,
-4716, -4695, -4675, -4654, -4633, -4613, -4592, -4571,
-4550, -4529, -4508, -4487, -4466, -4445, -4424, -4403,
-4382, -4360, -4339, -4318, -4296, -4275, -4254, -4232,
-4211, -4189, -4167, -4146, -4124, -4102, -4080, -4059,
-4037, -4015, -3993, -3971, -3949, -3927, -3905, -3883,
-3861, -3839, -3816, -3794, -3772, -3749, -3727, -3705,
-3682, -3660, -3637, -3615, -3592, -3570, -3547, -3524,
-3502, -3479, -3456, -3433, -3410, -3388, -3365, -3342,
-3319, -3296, -3273, -3250, -3227, -3204, -3180, -3157,
-3134, -3111, -3088, -3064, -3041, -3018, -2994, -2971,
-2947, -2924, -2900, -2877, -2853, -2830, -2806, -2783,
-2759, -2735, -2712, -2688, -2664, -2640, -2617, -2593,
-2569, -2545, -2521, -2497, -2473, -2449, -2425, -2401,
-2377, -2353, -2329, -2305, -2281, -2257, -2233, -2208,
-2184, -2160, -2136, -2111, -2087, -2063, -2038, -2014,
-1990, -1965, -1941, -1917, -1892, -1868, -1843, -1819,
-1794, -1770, -1745, -1721, -1696, -1671, -1647, -1622,
-1597, -1573, -1548, -1523, -1499, -1474, -1449, -1425,
-1400, -1375, -1350, -1326, -1301, -1276, -1251, -1226,
-1201, -1177, -1152, -1127, -1102, -1077, -1052, -1027,
-1002, -977, -952, -927, -902, -877, -852, -827,
-802, -777, -752, -727, -702, -677, -652, -627,
-602, -577, -552, -527, -502, -477, -452, -427,
-401, -376, -351, -326, -301, -276, -251, -226,
-201, -175, -150, -125, -100, -75, -50, -25,
0, 25, 50, 75, 100, 125, 150, 175,
201, 226, 251, 276, 301, 326, 351, 376,
401, 427, 452, 477, 502, 527, 552, 577,
602, 627, 652, 677, 702, 727, 752, 777,
802, 827, 852, 877, 902, 927, 952, 977,
1002, 1027, 1052, 1077, 1102, 1127, 1152, 1177,
1201, 1226, 1251, 1276, 1301, 1326, 1350, 1375,
1400, 1425, 1449, 1474, 1499, 1523, 1548, 1573,
1597, 1622, 1647, 1671, 1696, 1721, 1745, 1770,
1794, 1819, 1843, 1868, 1892, 1917, 1941, 1965,
1990, 2014, 2038, 2063, 2087, 2111, 2136, 2160,
2184, 2208, 2233, 2257, 2281, 2305, 2329, 2353,
2377, 2401, 2425, 2449, 2473, 2497, 2521, 2545,
2569, 2593, 2617, 2640, 2664, 2688, 2712, 2735,
2759, 2783, 2806, 2830, 2853, 2877, 2900, 2924,
2947, 2971, 2994, 3018, 3041, 3064, 3088, 3111,
3134, 3157, 3180, 3204, 3227, 3250, 3273, 3296,
3319, 3342, 3365, 3388, 3410, 3433, 3456, 3479,
3502, 3524, 3547, 3570, 3592, 3615, 3637, 3660,
3682, 3705, 3727, 3749, 3772, 3794, 3816, 3839,
3861, 3883, 3905, 3927, 3949, 3971, 3993, 4015,
4037, 4059, 4080, 4102, 4124, 4146, 4167, 4189,
4211, 4232, 4254, 4275, 4296, 4318, 4339, 4360,
4382, 4403, 4424, 4445, 4466, 4487, 4508, 4529,
4550, 4571, 4592, 4613, 4633, 4654, 4675, 4695,
4716, 4736, 4757, 4777, 4798, 4818, 4838, 4859,
4879, 4899, 4919, 4939, 4959, 4979, 4999, 5019,
5039, 5059, 5078, 5098, 5118, 5137, 5157, 5176,
5196, 5215, 5235, 5254, 5273, 5292, 5311, 5331,
5350, 5369, 5388, 5406, 5425, 5444, 5463, 5482,
5500, 5519, 5537, 5556, 5574, 5593, 5611, 5629,
5648, 5666, 5684, 5702, 5720, 5738, 5756, 5774,
5791, 5809, 5827, 5844, 5862, 5880, 5897, 5914,
5932, 5949, 5966, 5984, 6001, 6018, 6035, 6052,
6069, 6085, 6102, 6119, 6136, 6152, 6169, 6185,
6202, 6218, 6235, 6251, 6267, 6283, 6299, 6315,
6331, 6347, 6363, 6379, 6395, 6410, 6426, 6441,
6457, 6472, 6488, 6503, 6518, 6533, 6549, 6564,
6579, 6594, 6608, 6623, 6638, 6653, 6667, 6682,
6696, 6711, 6725, 6739, 6754, 6768, 6782, 6796,
6810, 6824, 6838, 6852, 6865, 6879, 6893, 6906,
6920, 6933, 6946, 6960, 6973, 6986, 6999, 7012,
7025, 7038, 7051, 7064, 7076, 7089, 7101, 7114,
7126, 7139, 7151, 7163, 7175, 7187, 7199, 7211,
7223, 7235, 7247, 7259, 7270, 7282, 7293, 7305,
7316, 7327, 7338, 7349, 7361, 7372, 7382, 7393,
7404, 7415, 7425, 7436, 7446, 7457, 7467, 7478,
7488, 7498, 7508, 7518, 7528, 7538, 7548, 7557,
7567, 7577, 7586, 7596, 7605, 7614, 7623, 7633,
7642, 7651, 7660, 7668, 7677, 7686, 7695, 7703,
7712, 7720, 7728, 7737, 7745, 7753, 7761, 7769,
7777, 7785, 7793, 7800, 7808, 7816, 7823, 7830,
7838, 7845, 7852, 7859, 7866, 7873, 7880, 7887,
7894, 7900, 7907, 7914, 7920, 7926, 7933, 7939,
7945, 7951, 7957, 7963, 7969, 7975, 7980, 7986,
7991, 7997, 8002, 8008, 8013, 8018, 8023, 8028,
8033, 8038, 8043, 8047, 8052, 8057, 8061, 8066,
8070, 8074, 8078, 8082, 8086, 8090, 8094, 8098,
8102, 8105, 8109, 8113, 8116, 8119, 8123, 8126,
8129, 8132, 8135, 8138, 8141, 8143, 8146, 8149,
8151, 8153, 8156, 8158, 8160, 8162, 8164, 8166,
8168, 8170, 8172, 8174, 8175, 8177, 8178, 8179,
8181, 8182, 8183, 8184, 8185, 8186, 8187, 8187,
8188, 8189, 8189, 8190, 8190, 8190, 8190, 8190,
8191, 8190, 8190, 8190, 8190, 8190, 8189, 8189,
8188, 8187, 8187, 8186, 8185, 8184, 8183, 8182,
8181, 8179, 8178, 8177, 8175, 8174, 8172, 8170,
8168, 8166, 8164, 8162, 8160, 8158, 8156, 8153,
8151, 8149, 8146, 8143, 8141, 8138, 8135, 8132,
8129, 8126, 8123, 8119, 8116, 8113, 8109, 8105,
8102, 8098, 8094, 8090, 8086, 8082, 8078, 8074,
8070, 8066, 8061, 8057, 8052, 8047, 8043, 8038,
8033, 8028, 8023, 8018, 8013, 8008, 8002, 7997,
7991, 7986, 7980, 7975, 7969, 7963, 7957, 7951,
7945, 7939, 7933, 7926, 7920, 7914, 7907, 7900,
7894, 7887, 7880, 7873, 7866, 7859, 7852, 7845,
7838, 7830, 7823, 7816, 7808, 7800, 7793, 7785,
7777, 7769, 7761, 7753, 7745, 7737, 7728, 7720,
7712, 7703, 7695, 7686, 7677, 7668, 7660, 7651,
7642, 7633, 7623, 7614, 7605, 7596, 7586, 7577,
7567, 7557, 7548, 7538, 7528, 7518, 7508, 7498,
7488, 7478, 7467, 7457, 7446, 7436, 7425, 7415,
7404, 7393, 7382, 7372, 7361, 7349, 7338, 7327,
7316, 7305, 7293, 7282, 7270, 7259, 7247, 7235,
7223, 7211, 7199, 7187, 7175, 7163, 7151, 7139,
7126, 7114, 7101, 7089, 7076, 7064, 7051, 7038,
7025, 7012, 6999, 6986, 6973, 6960, 6946, 6933,
6920, 6906, 6893, 6879, 6865, 6852, 6838, 6824,
6810, 6796, 6782, 6768, 6754, 6739, 6725, 6711,
6696, 6682, 6667, 6653, 6638, 6623, 6608, 6594,
6579, 6564, 6549, 6533, 6518, 6503, 6488, 6472,
6457, 6441, 6426, 6410, 6395, 6379, 6363, 6347,
6331, 6315, 6299, 6283, 6267, 6251, 6235, 6218,
6202, 6185, 6169, 6152, 6136, 6119, 6102, 6085,
6069, 6052, 6035, 6018, 6001, 5984, 5966, 5949,
5932, 5914, 5897, 5880, 5862, 5844, 5827, 5809,
5791, 5774, 5756, 5738, 5720, 5702, 5684, 5666,
5648, 5629, 5611, 5593, 5574, 5556, 5537, 5519,
5500, 5482, 5463, 5444, 5425, 5406, 5388, 5369,
5350, 5331, 5311, 5292, 5273, 5254, 5235, 5215,
5196, 5176, 5157, 5137, 5118, 5098, 5078, 5059,
5039, 5019, 4999, 4979, 4959, 4939, 4919, 4899,
4879, 4859, 4838, 4818, 4798, 4777, 4757, 4736,
4716, 4695, 4675, 4654, 4633, 4613, 4592, 4571,
4550, 4529, 4508, 4487, 4466, 4445, 4424, 4403,
4382, 4360, 4339, 4318, 4296, 4275, 4254, 4232,
4211, 4189, 4167, 4146, 4124, 4102, 4080, 4059,
4037, 4015, 3993, 3971, 3949, 3927, 3905, 3883,
3861, 3839, 3816, 3794, 3772, 3749, 3727, 3705,
3682, 3660, 3637, 3615, 3592, 3570, 3547, 3524,
3502, 3479, 3456, 3433, 3410, 3388, 3365, 3342,
3319, 3296, 3273, 3250, 3227, 3204, 3180, 3157,
3134, 3111, 3088, 3064, 3041, 3018, 2994, 2971,
2947, 2924, 2900, 2877, 2853, 2830, 2806, 2783,
2759, 2735, 2712, 2688, 2664, 2640, 2617, 2593,
2569, 2545, 2521, 2497, 2473, 2449, 2425, 2401,
2377, 2353, 2329, 2305, 2281, 2257, 2233, 2208,
2184, 2160, 2136, 2111, 2087, 2063, 2038, 2014,
1990, 1965, 1941, 1917, 1892, 1868, 1843, 1819,
1794, 1770, 1745, 1721, 1696, 1671, 1647, 1622,
1597, 1573, 1548, 1523, 1499, 1474, 1449, 1425,
1400, 1375, 1350, 1326, 1301, 1276, 1251, 1226,
1201, 1177, 1152, 1127, 1102, 1077, 1052, 1027,
1002, 977, 952, 927, 902, 877, 852, 827,
802, 777, 752, 727, 702, 677, 652, 627,
602, 577, 552, 527, 502, 477, 452, 427,
401, 376, 351, 326, 301, 276, 251, 226,
201, 175, 150, 125, 100, 75, 50, 25,
};


#ifdef __cplusplus #ifdef __cplusplus
} }

+ 65
- 64
src/libespeak-ng/speak_lib.c View File



#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
SHOW("*** dispatch_audio > uid=%d, [write=%p (%d bytes)], sample=%d, a_wave_can_be_played = %d\n", SHOW("*** dispatch_audio > uid=%d, [write=%p (%d bytes)], sample=%d, a_wave_can_be_played = %d\n",
(event) ? event->unique_identifier : 0, wave_test_get_write_buffer(), 2*length,
(event) ? event->sample : 0,
a_wave_can_be_played);
(event) ? event->unique_identifier : 0, wave_test_get_write_buffer(), 2*length,
(event) ? event->sample : 0,
a_wave_can_be_played);
#endif #endif


switch(my_mode) switch(my_mode)
{ {
event = NULL; event = NULL;
} }
else
else
{ {
event = event_list + i; event = event_list + i;
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
espeak_ERROR a_error = event_declare(event_list); espeak_ERROR a_error = event_declare(event_list);
if (a_error != EE_BUFFER_FULL) if (a_error != EE_BUFFER_FULL)
{ {
break;
break;
} }
SHOW_TIME("sync_espeak_terminated_msg > EE_BUFFER_FULL\n"); SHOW_TIME("sync_espeak_terminated_msg > EE_BUFFER_FULL\n");
usleep(10000); usleep(10000);
my_mode = output_type; my_mode = output_type;
my_audio = NULL; my_audio = NULL;
synchronous_mode = 1; synchronous_mode = 1;
option_waveout = 1; // inhibit portaudio callback from wavegen.cpp
option_waveout = 1; // inhibit portaudio callback from wavegen.cpp
out_samplerate = 0; out_samplerate = 0;


switch(my_mode) switch(my_mode)
ENTER("Synthesize"); ENTER("Synthesize");
if (text) if (text)
{ {
SHOW("Synthesize > uid=%d, flags=%d, >>>text=%s<<<\n", unique_identifier, flags, text);
SHOW("Synthesize > uid=%d, flags=%d, >>>text=%s<<<\n", unique_identifier, flags, text);
} }
#endif #endif




if(my_mode == AUDIO_OUTPUT_SYNCH_PLAYBACK) if(my_mode == AUDIO_OUTPUT_SYNCH_PLAYBACK)
{ {
for(;;)
for(;; )
{ {
#ifdef PLATFORM_WINDOWS #ifdef PLATFORM_WINDOWS
Sleep(300); // 0.3s Sleep(300); // 0.3s
return(EE_OK); return(EE_OK);
} }


for(;;)
for(;; )
{ {
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
SHOW("Synthesize > %s\n","for (next)"); SHOW("Synthesize > %s\n","for (next)");


#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
static const char* label[] = { static const char* label[] = {
"END_OF_EVENT_LIST",
"WORD",
"SENTENCE",
"MARK",
"PLAY",
"END",
"MSG_TERMINATED",
"PHONEME",
"SAMPLERATE",
"??" };
"END_OF_EVENT_LIST",
"WORD",
"SENTENCE",
"MARK",
"PLAY",
"END",
"MSG_TERMINATED",
"PHONEME",
"SAMPLERATE",
"??"
};
#endif #endif




#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
SHOW("MarkerEvent > count_samples=%d, out_ptr=%x, out_start=0x%x\n",count_samples, out_ptr, out_start); SHOW("MarkerEvent > count_samples=%d, out_ptr=%x, out_start=0x%x\n",count_samples, out_ptr, out_start);
SHOW("*** MarkerEvent > type=%s, uid=%d, text_pos=%d, length=%d, audio_position=%d, sample=%d\n", SHOW("*** MarkerEvent > type=%s, uid=%d, text_pos=%d, length=%d, audio_position=%d, sample=%d\n",
label[ep->type], ep->unique_identifier, ep->text_position, ep->length,
ep->audio_position, ep->sample);
label[ep->type], ep->unique_identifier, ep->text_position, ep->length,
ep->audio_position, ep->sample);
#endif #endif


if((type == espeakEVENT_MARK) || (type == espeakEVENT_PLAY)) if((type == espeakEVENT_MARK) || (type == espeakEVENT_PLAY))




espeak_ERROR sync_espeak_Synth(unsigned int unique_identifier, const void *text, size_t size, espeak_ERROR sync_espeak_Synth(unsigned int unique_identifier, const void *text, size_t size,
unsigned int position, espeak_POSITION_TYPE position_type,
unsigned int end_position, unsigned int flags, void* user_data)
unsigned int position, espeak_POSITION_TYPE position_type,
unsigned int end_position, unsigned int flags, void* user_data)
{ {


#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
saved_parameters[i] = param_stack[0].parameter[i]; saved_parameters[i] = param_stack[0].parameter[i];


switch(position_type) switch(position_type)
{
case POS_CHARACTER:
skip_characters = position;
break;
{
case POS_CHARACTER:
skip_characters = position;
break;


case POS_WORD:
skip_words = position;
break;
case POS_WORD:
skip_words = position;
break;


case POS_SENTENCE:
skip_sentences = position;
break;
case POS_SENTENCE:
skip_sentences = position;
break;


}
}
if(skip_characters || skip_words || skip_sentences) if(skip_characters || skip_words || skip_sentences)
skipping_text = 1; skipping_text = 1;






espeak_ERROR sync_espeak_Synth_Mark(unsigned int unique_identifier, const void *text, size_t size, espeak_ERROR sync_espeak_Synth_Mark(unsigned int unique_identifier, const void *text, size_t size,
const char *index_mark, unsigned int end_position,
unsigned int flags, void* user_data)
const char *index_mark, unsigned int end_position,
unsigned int flags, void* user_data)
{ {
espeak_ERROR aStatus; espeak_ERROR aStatus;


my_user_data = user_data; my_user_data = user_data;


if(index_mark != NULL) if(index_mark != NULL)
{
{
strncpy0(skip_marker, index_mark, sizeof(skip_marker)); strncpy0(skip_marker, index_mark, sizeof(skip_marker));
skipping_text = 1; skipping_text = 1;
}
}


end_character_position = end_position; end_character_position = end_position;




ESPEAK_API int espeak_Initialize(espeak_AUDIO_OUTPUT output_type, int buf_length, const char *path, int options) ESPEAK_API int espeak_Initialize(espeak_AUDIO_OUTPUT output_type, int buf_length, const char *path, int options)
{ {
ENTER("espeak_Initialize");
ENTER("espeak_Initialize");
int param; int param;


// It seems that the wctype functions don't work until the locale has been set // It seems that the wctype functions don't work until the locale has been set
fifo_init(); fifo_init();
#endif #endif


return(samplerate);
return(samplerate);
} }






ESPEAK_API espeak_ERROR espeak_Synth(const void *text, size_t size, ESPEAK_API espeak_ERROR espeak_Synth(const void *text, size_t size,
unsigned int position,
espeak_POSITION_TYPE position_type,
unsigned int end_position, unsigned int flags,
unsigned int* unique_identifier, void* user_data)
unsigned int position,
espeak_POSITION_TYPE position_type,
unsigned int end_position, unsigned int flags,
unsigned int* unique_identifier, void* user_data)
{ {
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
ENTER("espeak_Synth"); ENTER("espeak_Synth");




ESPEAK_API espeak_ERROR espeak_Synth_Mark(const void *text, size_t size, ESPEAK_API espeak_ERROR espeak_Synth_Mark(const void *text, size_t size,
const char *index_mark,
unsigned int end_position,
unsigned int flags,
unsigned int* unique_identifier,
void* user_data)
const char *index_mark,
unsigned int end_position,
unsigned int flags,
unsigned int* unique_identifier,
void* user_data)
{ {
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
ENTER("espeak_Synth_Mark");
SHOW("espeak_Synth_Mark > index_mark=%s, end_position=%d, flags=%d, text=%s\n", index_mark, end_position, flags, text);
ENTER("espeak_Synth_Mark");
SHOW("espeak_Synth_Mark > index_mark=%s, end_position=%d, flags=%d, text=%s\n", index_mark, end_position, flags, text);
#endif #endif


espeak_ERROR a_error=EE_OK; espeak_ERROR a_error=EE_OK;
#ifdef USE_ASYNC #ifdef USE_ASYNC
// Create the mark command // Create the mark command
t_espeak_command* c1 = create_espeak_mark(text, size, index_mark, end_position, t_espeak_command* c1 = create_espeak_mark(text, size, index_mark, end_position,
flags, user_data);
flags, user_data);


// Retrieve the unique identifier // Retrieve the unique identifier
*unique_identifier = c1->u.my_mark.unique_identifier; *unique_identifier = c1->u.my_mark.unique_identifier;
} }


#endif #endif
return a_error;
return a_error;
} }




ESPEAK_API espeak_ERROR espeak_Char(wchar_t character) ESPEAK_API espeak_ERROR espeak_Char(wchar_t character)
{ {
ENTER("espeak_Char");
// is there a system resource of character names per language?
ENTER("espeak_Char");
// is there a system resource of character names per language?


if(f_logespeak) if(f_logespeak)
{ {


ESPEAK_API espeak_ERROR espeak_SetVoiceByName(const char *name) ESPEAK_API espeak_ERROR espeak_SetVoiceByName(const char *name)
{ {
ENTER("espeak_SetVoiceByName");
ENTER("espeak_SetVoiceByName");


return(SetVoiceByName(name)); return(SetVoiceByName(name));
} }


ESPEAK_API espeak_ERROR espeak_SetVoiceByProperties(espeak_VOICE *voice_selector) ESPEAK_API espeak_ERROR espeak_SetVoiceByProperties(espeak_VOICE *voice_selector)
{ {
ENTER("espeak_SetVoiceByProperties");
ENTER("espeak_SetVoiceByProperties");


return(SetVoiceByProperties(voice_selector)); return(SetVoiceByProperties(voice_selector));
} }


ESPEAK_API espeak_ERROR espeak_SetParameter(espeak_PARAMETER parameter, int value, int relative) ESPEAK_API espeak_ERROR espeak_SetParameter(espeak_PARAMETER parameter, int value, int relative)
{ {
ENTER("espeak_SetParameter");
ENTER("espeak_SetParameter");


if(f_logespeak) if(f_logespeak)
{ {


ESPEAK_API espeak_ERROR espeak_SetPunctuationList(const wchar_t *punctlist) ESPEAK_API espeak_ERROR espeak_SetPunctuationList(const wchar_t *punctlist)
{ {
ENTER("espeak_SetPunctuationList");
// Set the list of punctuation which are spoken for "some".
ENTER("espeak_SetPunctuationList");
// Set the list of punctuation which are spoken for "some".


#ifdef USE_ASYNC #ifdef USE_ASYNC
espeak_ERROR a_error; espeak_ERROR a_error;
bits 8-23: separator character, between phoneme names bits 8-23: separator character, between phoneme names


stream output stream for the phoneme symbols (and trace). If stream=NULL then it uses stdout. stream output stream for the phoneme symbols (and trace). If stream=NULL then it uses stdout.
*/
*/
option_phonemes = phonememode; option_phonemes = phonememode;
f_trans = stream; f_trans = stream;
if(stream == NULL) if(stream == NULL)
{ {
/* phoneme_mode /* phoneme_mode
bit 1: 0=eSpeak's ascii phoneme names, 1= International Phonetic Alphabet (as UTF-8 characters). bit 1: 0=eSpeak's ascii phoneme names, 1= International Phonetic Alphabet (as UTF-8 characters).
bit 7: use (bits 8-23) as a tie within multi-letter phonemes names
bits 8-23: separator character, between phoneme names
*/
bit 7: use (bits 8-23) as a tie within multi-letter phonemes names
bits 8-23: separator character, between phoneme names
*/


option_multibyte = textmode & 7; option_multibyte = textmode & 7;
*textptr = TranslateClause(translator, NULL, *textptr, NULL, NULL); *textptr = TranslateClause(translator, NULL, *textptr, NULL, NULL);

+ 25
- 25
src/libespeak-ng/spect.c View File

#define PEAKSHAPEW 256 #define PEAKSHAPEW 256


static int default_freq[N_PEAKS] = static int default_freq[N_PEAKS] =
{200,500,1200,3000,3500,4000,6900,7800,9000};
{200,500,1200,3000,3500,4000,6900,7800,9000};
static int default_width[N_PEAKS] = static int default_width[N_PEAKS] =
{750,500,550,550,600,700,700,700,700};
{750,500,550,550,600,700,700,700,700};
static int default_klt_bw[N_PEAKS] = static int default_klt_bw[N_PEAKS] =
{89,90,140,260,260,260,500,500,500};
{89,90,140,260,260,260,500,500,500};


static double read_double(FILE *stream) static double read_double(FILE *stream)
{ {


dif=fabs(x-xa[1]); dif=fabs(x-xa[1]);


for(i=1;i<=n;i++){
for(i=1; i<=n; i++) {
if((dift=fabs(x-xa[i])) < dif) { if((dift=fabs(x-xa[i])) < dif) {
ns=i; ns=i;
dif=dift; dif=dift;
d[i]=ya[i]; d[i]=ya[i];
} }
y=ya[ns--]; y=ya[ns--];
for(m=1;m<n;m++) {
for(i=1;i<=n-m;i++) {
for(m=1; m<n; m++) {
for(i=1; i<=n-m; i++) {
ho=xa[i]-x; ho=xa[i]-x;
hp=xa[i+m]-x; hp=xa[i+m]-x;
w=c[i+1]-d[i]; w=c[i+1]-d[i];


static SpectFrame *SpectFrameCreate() static SpectFrame *SpectFrameCreate()
{ {
int ix;
int ix;
SpectFrame *frame; SpectFrame *frame;


frame = malloc(sizeof(SpectFrame)); frame = malloc(sizeof(SpectFrame));
frame->length_adjust = 0; frame->length_adjust = 0;


for(ix=0; ix<N_PEAKS; ix++) for(ix=0; ix<N_PEAKS; ix++)
{
{
frame->formants[ix].freq = 0; frame->formants[ix].freq = 0;
frame->peaks[ix].pkfreq = default_freq[ix]; frame->peaks[ix].pkfreq = default_freq[ix];
frame->peaks[ix].pkheight = 0; frame->peaks[ix].pkheight = 0;
frame->peaks[ix].klt_bw = default_klt_bw[ix]; frame->peaks[ix].klt_bw = default_klt_bw[ix];
frame->peaks[ix].klt_ap = 0; frame->peaks[ix].klt_ap = 0;
frame->peaks[ix].klt_bp = default_klt_bw[ix]; frame->peaks[ix].klt_bp = default_klt_bw[ix];
}
}


memset(frame->klatt_param, 0, sizeof(frame->klatt_param)); memset(frame->klatt_param, 0, sizeof(frame->klatt_param));
frame->klatt_param[KLATT_AV] = 59; frame->klatt_param[KLATT_AV] = 59;
spect_data[ix] = x; spect_data[ix] = x;
if(x > frame->max_y) frame->max_y = x; if(x > frame->max_y) frame->max_y = x;
} }
frame->spect = spect_data;
frame->spect = spect_data;


return(0); return(0);
} }
spect->numframes = 0; spect->numframes = 0;
spect->frames = NULL; spect->frames = NULL;
spect->name = NULL; spect->name = NULL;
pk_select = 1; pk_select = 1;
spect->grid = 1; spect->grid = 1;
spect->duration = 0;
spect->pitch1 = 0;
spect->pitch2 = 0;
spect->duration = 0;
spect->pitch1 = 0;
spect->pitch2 = 0;
spect->bass_reduction = 0; spect->bass_reduction = 0;


spect->max_x = 3000; spect->max_x = 3000;


static float GetFrameLength(SpectSeq *spect, int frame) static float GetFrameLength(SpectSeq *spect, int frame)
{ {
int ix;
float adjust=0;
int ix;
float adjust=0;


if(frame >= spect->numframes-1) return(0); if(frame >= spect->numframes-1) return(0);
for(ix=frame+1; ix<spect->numframes-1; ix++) for(ix=frame+1; ix<spect->numframes-1; ix++)
{ {
if(spect->frames[ix]->keyframe) break; // reached next keyframe if(spect->frames[ix]->keyframe) break; // reached next keyframe


if((id1 == FILEID1_SPECTSEQ) && (id2 == FILEID2_SPECTSEQ)) if((id1 == FILEID1_SPECTSEQ) && (id2 == FILEID2_SPECTSEQ))
{ {
spect->file_format = 0; // eSpeak formants
spect->file_format = 0; // eSpeak formants
} }
else else
if((id1 == FILEID1_SPECTSEQ) && (id2 == FILEID2_SPECTSEK)) if((id1 == FILEID1_SPECTSEQ) && (id2 == FILEID2_SPECTSEK))
{ {
spect->file_format = 1; // formants for Klatt synthesizer
spect->file_format = 1; // formants for Klatt synthesizer
} }
else else
if((id1 == FILEID1_SPECTSEQ) && (id2 == FILEID2_SPECTSQ2)) if((id1 == FILEID1_SPECTSEQ) && (id2 == FILEID2_SPECTSQ2))
{ {
spect->file_format = 2; // formants for Klatt synthesizer
spect->file_format = 2; // formants for Klatt synthesizer
} }
else else
{ {
spect->max_y = frame->max_y; spect->max_y = frame->max_y;
if(frame->nx * frame->dx > spect->max_x) spect->max_x = (int)(frame->nx * frame->dx); if(frame->nx * frame->dx > spect->max_x) spect->max_x = (int)(frame->nx * frame->dx);
} }
spect->max_x = 9000; // disable auto-xscaling
spect->max_x = 9000; // disable auto-xscaling


frame_width = (int)((FRAME_WIDTH*spect->max_x)/MAX_DISPLAY_FREQ); frame_width = (int)((FRAME_WIDTH*spect->max_x)/MAX_DISPLAY_FREQ);
if(frame_width > FRAME_WIDTH) frame_width = FRAME_WIDTH; if(frame_width > FRAME_WIDTH) frame_width = FRAME_WIDTH;
spect->pitch2 = spect->pitchenv.pitch2; spect->pitch2 = spect->pitchenv.pitch2;
spect->duration = (int)(spect->frames[spect->numframes-1]->time * 1000); spect->duration = (int)(spect->frames[spect->numframes-1]->time * 1000);


if(spect->max_y < 400)
spect->max_y = 200;
else
spect->max_y = 29000; // disable auto height scaling
if(spect->max_y < 400)
spect->max_y = 200;
else
spect->max_y = 29000; // disable auto height scaling


for(ix=0; ix<spect->numframes; ix++) for(ix=0; ix<spect->numframes; ix++)
{ {

+ 20
- 20
src/libespeak-ng/spect.h View File

float length_adjust; float length_adjust;
double rms; double rms;


float time;
float pitch;
float length;
float dx;
unsigned short nx;
short markers;
int max_y;
USHORT *spect; // sqrt of harmonic amplitudes, 1-nx at 'pitch'
short klatt_param[N_KLATTP2];
formant_t formants[N_PEAKS]; // this is just the estimate given by Praat
peak_t peaks[N_PEAKS];
float time;
float pitch;
float length;
float dx;
unsigned short nx;
short markers;
int max_y;
USHORT *spect; // sqrt of harmonic amplitudes, 1-nx at 'pitch'
short klatt_param[N_KLATTP2];
formant_t formants[N_PEAKS]; // this is just the estimate given by Praat
peak_t peaks[N_PEAKS];
} SpectFrame; } SpectFrame;


double GetFrameRms(SpectFrame *frame, int amp); double GetFrameRms(SpectFrame *frame, int amp);


typedef struct typedef struct
{ {
int numframes;
int numframes;
short amplitude; short amplitude;
int spare;
int spare;
char *name; char *name;


SpectFrame **frames; SpectFrame **frames;
PitchEnvelope pitchenv; PitchEnvelope pitchenv;
int pitch1;
int pitch2;
int duration;
int grid;
int bass_reduction;
int pitch1;
int pitch2;
int duration;
int grid;
int bass_reduction;
int max_x; int max_x;
short max_y; short max_y;
int file_format; int file_format;

+ 3
- 3
src/libespeak-ng/speech.h View File

#endif #endif


typedef unsigned short USHORT; typedef unsigned short USHORT;
typedef unsigned char UCHAR;
typedef unsigned char UCHAR;
typedef double DOUBLEX; typedef double DOUBLEX;
typedef unsigned long long64; // use this for conversion between pointers and integers typedef unsigned long long64; // use this for conversion between pointers and integers






typedef struct { typedef struct {
const char *mnem;
int value;
const char *mnem;
int value;
} MNEM_TAB; } MNEM_TAB;
int LookupMnem(MNEM_TAB *table, const char *string); int LookupMnem(MNEM_TAB *table, const char *string);



+ 26
- 26
src/libespeak-ng/synth_mbrola.c View File

typedef void (WINAPI *PROCVI)(int); typedef void (WINAPI *PROCVI)(int);
typedef void (WINAPI *PROCVF)(float); typedef void (WINAPI *PROCVF)(float);
typedef int (WINAPI *PROCIV)(); typedef int (WINAPI *PROCIV)();
typedef int (WINAPI *PROCIC) (char *);
typedef int (WINAPI *PROCIC)(char *);
typedef int (WINAPI *PROCISI)(short *,int); typedef int (WINAPI *PROCISI)(short *,int);
typedef char* (WINAPI *PROCVCI)(char *,int); typedef char* (WINAPI *PROCVCI)(char *,int);


PROCIC init_MBR;
PROCIC write_MBR;
PROCIV flush_MBR;
PROCISI read_MBR;
PROCVV close_MBR;
PROCVV reset_MBR;
PROCIV lastError_MBR;
PROCVCI lastErrorStr_MBR;
PROCVI setNoError_MBR;
PROCIV getFreq_MBR;
PROCVF setVolumeRatio_MBR;
PROCIC init_MBR;
PROCIC write_MBR;
PROCIV flush_MBR;
PROCISI read_MBR;
PROCVV close_MBR;
PROCVV reset_MBR;
PROCIV lastError_MBR;
PROCVCI lastErrorStr_MBR;
PROCVI setNoError_MBR;
PROCIV getFreq_MBR;
PROCVF setVolumeRatio_MBR;






HINSTANCE hinstDllMBR = NULL;
HINSTANCE hinstDllMBR = NULL;




BOOL load_MBR() BOOL load_MBR()


if ((hinstDllMBR=LoadLibraryA("mbrola.dll")) == 0) if ((hinstDllMBR=LoadLibraryA("mbrola.dll")) == 0)
return FALSE; return FALSE;
init_MBR =(PROCIC) GetProcAddress(hinstDllMBR,"init_MBR");
write_MBR =(PROCIC) GetProcAddress(hinstDllMBR,"write_MBR");
flush_MBR =(PROCIV) GetProcAddress(hinstDllMBR,"flush_MBR");
read_MBR =(PROCISI) GetProcAddress(hinstDllMBR,"read_MBR");
close_MBR =(PROCVV) GetProcAddress(hinstDllMBR,"close_MBR");
reset_MBR =(PROCVV) GetProcAddress(hinstDllMBR,"reset_MBR");
lastError_MBR =(PROCIV) GetProcAddress(hinstDllMBR,"lastError_MBR");
lastErrorStr_MBR =(PROCVCI) GetProcAddress(hinstDllMBR,"lastErrorStr_MBR");
setNoError_MBR =(PROCVI) GetProcAddress(hinstDllMBR,"setNoError_MBR");
setVolumeRatio_MBR =(PROCVF) GetProcAddress(hinstDllMBR,"setVolumeRatio_MBR");
init_MBR =(PROCIC) GetProcAddress(hinstDllMBR,"init_MBR");
write_MBR =(PROCIC) GetProcAddress(hinstDllMBR,"write_MBR");
flush_MBR =(PROCIV) GetProcAddress(hinstDllMBR,"flush_MBR");
read_MBR =(PROCISI) GetProcAddress(hinstDllMBR,"read_MBR");
close_MBR =(PROCVV) GetProcAddress(hinstDllMBR,"close_MBR");
reset_MBR =(PROCVV) GetProcAddress(hinstDllMBR,"reset_MBR");
lastError_MBR =(PROCIV) GetProcAddress(hinstDllMBR,"lastError_MBR");
lastErrorStr_MBR =(PROCVCI) GetProcAddress(hinstDllMBR,"lastErrorStr_MBR");
setNoError_MBR =(PROCVI) GetProcAddress(hinstDllMBR,"setNoError_MBR");
setVolumeRatio_MBR =(PROCVF) GetProcAddress(hinstDllMBR,"setVolumeRatio_MBR");
return TRUE; return TRUE;
} }


// usr/share/mbrola/xx, /usr/share/mbrola/xx/xx, /usr/share/mbrola/voices/xx // usr/share/mbrola/xx, /usr/share/mbrola/xx/xx, /usr/share/mbrola/voices/xx
if(GetFileLength(path) <= 0) if(GetFileLength(path) <= 0)
{ {
sprintf(path,"/usr/share/mbrola/%s",mbrola_voice);
sprintf(path,"/usr/share/mbrola/%s",mbrola_voice);


if(GetFileLength(path) <= 0) if(GetFileLength(path) <= 0)
{ {
other_ph = ph_next; other_ph = ph_next;


if((pr->next_phoneme == other_ph->mnemonic) || if((pr->next_phoneme == other_ph->mnemonic) ||
((pr->next_phoneme == 2) && (other_ph->type == phVOWEL)) ||
((pr->next_phoneme == '_') && (other_ph->type == phPAUSE)))
((pr->next_phoneme == 2) && (other_ph->type == phVOWEL)) ||
((pr->next_phoneme == '_') && (other_ph->type == phPAUSE)))
{ {
found = 1; found = 1;
} }

+ 75
- 75
src/libespeak-ng/synthdata.c View File

{ {
FILE *f_in; FILE *f_in;
char *p; char *p;
unsigned int length;
unsigned int length;
char buf[sizeof(path_home)+40]; char buf[sizeof(path_home)+40];


sprintf(buf,"%s%c%s",path_home,PATHSEP,fname); sprintf(buf,"%s%c%s",path_home,PATHSEP,fname);
return(-1); return(-1);
if((tunes = (TUNE *)ReadPhFile((void *)(tunes),"intonations",&length)) == NULL) if((tunes = (TUNE *)ReadPhFile((void *)(tunes),"intonations",&length)) == NULL)
return(-1); return(-1);
wavefile_data = (unsigned char *)phondata_ptr;
wavefile_data = (unsigned char *)phondata_ptr;
n_tunes = length / sizeof(TUNE); n_tunes = length / sizeof(TUNE);


// read the version number and sample rate from the first 8 bytes of phondata // read the version number and sample rate from the first 8 bytes of phondata
if(phoneme_tab_number >= n_phoneme_tables) if(phoneme_tab_number >= n_phoneme_tables)
phoneme_tab_number = 0; phoneme_tab_number = 0;


if(srate != NULL)
*srate = rate;
if(srate != NULL)
*srate = rate;
return(result); return(result);
} }




int LookupPhonemeString(const char *string) int LookupPhonemeString(const char *string)
{ {
int ix;
int ix;
unsigned char c; unsigned char c;
unsigned int mnem;
unsigned int mnem;


// Pack up to 4 characters into a word // Pack up to 4 characters into a word
mnem = 0; mnem = 0;


frameref_t *LookupSpect(PHONEME_TAB *this_ph, int which, FMT_PARAMS *fmt_params, int *n_frames, PHONEME_LIST *plist) frameref_t *LookupSpect(PHONEME_TAB *this_ph, int which, FMT_PARAMS *fmt_params, int *n_frames, PHONEME_LIST *plist)
{ {
int ix;
int nf;
int nf1;
int seq_break;
int ix;
int nf;
int nf1;
int seq_break;
frameref_t *frames; frameref_t *frames;
int length1;
int length_std;
int length_factor;
int length1;
int length_std;
int length_factor;
SPECT_SEQ *seq, *seq2; SPECT_SEQ *seq, *seq2;
SPECT_SEQK *seqk, *seqk2; SPECT_SEQK *seqk, *seqk2;
frame_t *frame; frame_t *frame;
{ {
int count = 0; int count = 0;


for(;;)
for(;; )
{ {
if(plist->ph->type == phVOWEL) if(plist->ph->type == phVOWEL)
count++; count++;


if(which==6) if(which==6)
{ {
// the 'which' code is in the next instruction
p_prog++;
which = (*p_prog);
// the 'which' code is in the next instruction
p_prog++;
which = (*p_prog);
} }


if(which==4) if(which==4)
return(false); return(false);
} }
if(which==6) if(which==6)
{
// next2PhW, not word boundary
if(plist[1].sourceix || plist[2].sourceix)
return(false);
}
switch(which)
{
case 0: // prevPh
case 5: // prevPhW
plist--;
check_endtype = 1;
break;
case 1: // thisPh
break;
case 2: // nextPh
case 4: // nextPhW
plist++;
break;
case 3: // next2Ph
case 6: // next2PhW
plist += 2;
break;
case 7:
{
// next2PhW, not word boundary
if(plist[1].sourceix || plist[2].sourceix)
return(false);
}
switch(which)
{
case 0: // prevPh
case 5: // prevPhW
plist--;
check_endtype = 1;
break;
case 1: // thisPh
break;
case 2: // nextPh
case 4: // nextPhW
plist++;
break;
case 3: // next2Ph
case 6: // next2PhW
plist += 2;
break;
case 7:
// nextVowel, not word boundary // nextVowel, not word boundary
for(which=1;;which++)
for(which=1;; which++)
{ {
if(plist[which].sourceix) if(plist[which].sourceix)
return(false); return(false);
} }
break; break;


case 8: // prevVowel in this word
if((worddata==NULL) || (worddata->prev_vowel.ph == NULL))
return(false); // no previous vowel
plist = &(worddata->prev_vowel);
case 8: // prevVowel in this word
if((worddata==NULL) || (worddata->prev_vowel.ph == NULL))
return(false); // no previous vowel
plist = &(worddata->prev_vowel);
check_endtype = 1; check_endtype = 1;
break;
break;


case 9: // next3PhW case 9: // next3PhW
for(ix=1; ix<=3; ix++) for(ix=1; ix<=3; ix++)
plist-=2; plist-=2;
check_endtype = 1; check_endtype = 1;
break; break;
}
}


if((which == 0) || (which == 5)) if((which == 0) || (which == 5))
{ {
return(ph->type != phVOWEL); return(ph->type != phVOWEL);


case 11: // isFinalVowel case 11: // isFinalVowel
for(;;)
for(;; )
{ {
plist++; plist++;
// plist->ph = phoneme_tab[plist->phcode]; // Why was this line here?? It corrupts plist if we have language switching if phoneme_tab is wrong language // plist->ph = phoneme_tab[plist->phcode]; // Why was this line here?? It corrupts plist if we have language switching if phoneme_tab is wrong language
return(false); // this is the first phoneme in the word, so no. return(false); // this is the first phoneme in the word, so no.


count = 0; count = 0;
for(;;)
for(;; )
{ {
plist--; plist--;
if(plist->ph->type == phVOWEL) if(plist->ph->type == phVOWEL)


if((worddata != NULL) && (plist->sourceix)) if((worddata != NULL) && (plist->sourceix))
{ {
// start of a word, reset word data
worddata->prev_vowel.ph = NULL;
// start of a word, reset word data
worddata->prev_vowel.ph = NULL;
} }


memset(phdata, 0, sizeof(PHONEME_DATA)); memset(phdata, 0, sizeof(PHONEME_DATA));
} }
} }
prog--; prog--;
break;
break;


case 6: case 6:
// JUMP // JUMP
SwitchOnVowelType(plist, phdata, &prog, 3); SwitchOnVowelType(plist, phdata, &prog, 3);
break; break;
} }
break;
break;


case 9: case 9:
data = ((instn & 0xf) << 16) + prog[1]; data = ((instn & 0xf) << 16) + prog[1];
phdata->sound_param[instn2] = param_sc; // sign extend phdata->sound_param[instn2] = param_sc; // sign extend
} }
} }
break;
break;


default: default:
InvalidInstn(ph,instn); InvalidInstn(ph,instn);
} }
} }


if((worddata != NULL) && (plist->type == phVOWEL))
{
memcpy(&worddata->prev_vowel, &plist[0], sizeof(PHONEME_LIST));
}
plist->std_length = phdata->pd_param[i_SET_LENGTH];
if(phdata->sound_addr[0] != 0)
{
plist->phontab_addr = phdata->sound_addr[0]; // FMT address
plist->sound_param = phdata->sound_param[0];
}
else
{
plist->phontab_addr = phdata->sound_addr[1]; // WAV address
plist->sound_param = phdata->sound_param[1];
if((worddata != NULL) && (plist->type == phVOWEL))
{
memcpy(&worddata->prev_vowel, &plist[0], sizeof(PHONEME_LIST));
}
plist->std_length = phdata->pd_param[i_SET_LENGTH];
if(phdata->sound_addr[0] != 0)
{
plist->phontab_addr = phdata->sound_addr[0]; // FMT address
plist->sound_param = phdata->sound_param[0];
}
else
{
plist->phontab_addr = phdata->sound_addr[1]; // WAV address
plist->sound_param = phdata->sound_param[1];
} }
} }



+ 67
- 66
src/libespeak-ng/synthesize.c View File



SPEED_FACTORS speed; SPEED_FACTORS speed;


static int last_pitch_cmd;
static int last_amp_cmd;
static int last_pitch_cmd;
static int last_amp_cmd;
static frame_t *last_frame; static frame_t *last_frame;
static int last_wcmdq;
static int pitch_length;
static int amp_length;
static int modn_flags;
static int fmt_amplitude=0;
static int last_wcmdq;
static int pitch_length;
static int amp_length;
static int modn_flags;
static int fmt_amplitude=0;


static int syllable_start;
static int syllable_end;
static int syllable_centre;
static int syllable_start;
static int syllable_end;
static int syllable_centre;


static voice_t *new_voice=NULL; static voice_t *new_voice=NULL;


const char *WordToString(unsigned int word) const char *WordToString(unsigned int word)
{ {
// Convert a phoneme mnemonic word into a string // Convert a phoneme mnemonic word into a string
int ix;
int ix;
static char buf[5]; static char buf[5];


for(ix=0; ix<4; ix++) for(ix=0; ix<4; ix++)
int ix; int ix;


static const short sqrt_tab[200] = { static const short sqrt_tab[200] = {
0, 64, 90,110,128,143,156,169,181,192,202,212,221,230,239,247,
256,263,271,278,286,293,300,306,313,320,326,332,338,344,350,356,
362,367,373,378,384,389,394,399,404,409,414,419,424,429,434,438,
443,448,452,457,461,465,470,474,478,483,487,491,495,499,503,507,
512,515,519,523,527,531,535,539,543,546,550,554,557,561,565,568,
572,576,579,583,586,590,593,596,600,603,607,610,613,617,620,623,
627,630,633,636,640,643,646,649,652,655,658,662,665,668,671,674,
677,680,683,686,689,692,695,698,701,704,706,709,712,715,718,721,
724,726,729,732,735,738,740,743,746,749,751,754,757,759,762,765,
768,770,773,775,778,781,783,786,789,791,794,796,799,801,804,807,
809,812,814,817,819,822,824,827,829,832,834,836,839,841,844,846,
849,851,853,856,858,861,863,865,868,870,872,875,877,879,882,884,
886,889,891,893,896,898,900,902};
0, 64, 90,110,128,143,156,169,181,192,202,212,221,230,239,247,
256,263,271,278,286,293,300,306,313,320,326,332,338,344,350,356,
362,367,373,378,384,389,394,399,404,409,414,419,424,429,434,438,
443,448,452,457,461,465,470,474,478,483,487,491,495,499,503,507,
512,515,519,523,527,531,535,539,543,546,550,554,557,561,565,568,
572,576,579,583,586,590,593,596,600,603,607,610,613,617,620,623,
627,630,633,636,640,643,646,649,652,655,658,662,665,668,671,674,
677,680,683,686,689,692,695,698,701,704,706,709,712,715,718,721,
724,726,729,732,735,738,740,743,746,749,751,754,757,759,762,765,
768,770,773,775,778,781,783,786,789,791,794,796,799,801,804,807,
809,812,814,817,819,822,824,827,829,832,834,836,839,841,844,846,
849,851,853,856,858,861,863,865,868,870,872,875,877,879,882,884,
886,889,891,893,896,898,900,902
};


if(voice->klattv[0]) if(voice->klattv[0])
{ {
static void formants_reduce_hf(frame_t *fr, int level) static void formants_reduce_hf(frame_t *fr, int level)
{ {
// change height of peaks 2 to 8, percentage // change height of peaks 2 to 8, percentage
int ix;
int x;
int ix;
int x;


if(voice->klattv[0]) if(voice->klattv[0])
return; return;


#define N_VCOLOUR 2 #define N_VCOLOUR 2
// percentage change for each formant in 256ths // percentage change for each formant in 256ths
static short vcolouring[N_VCOLOUR][5] = {
{243,272,256,256,256}, // palatal consonant follows
{256,256,240,240,240}, // retroflex
};
static short vcolouring[N_VCOLOUR][5] = {
{243,272,256,256,256}, // palatal consonant follows
{256,256,240,240,240}, // retroflex
};


frame_t *fr = NULL; frame_t *fr = NULL;




next_rms = seq[1].frame->rms; next_rms = seq[1].frame->rms;


if(voice->klattv[0])
{
fr->klattp[KLATT_AV] = seq[1].frame->klattp[KLATT_AV] - 4;
}
if(voice->klattv[0])
{
fr->klattp[KLATT_AV] = seq[1].frame->klattp[KLATT_AV] - 4;
}
if(f2 != 0) if(f2 != 0)
{ {
if(rms & 0x20) if(rms & 0x20)
// backwards // backwards
ix = syllable_centre -1; ix = syllable_centre -1;
frame = frame2 = frame_centre; frame = frame2 = frame_centre;
for(;;)
for(;; )
{ {
if(ix < 0) ix = N_WCMDQ-1; if(ix < 0) ix = N_WCMDQ-1;
q = wcmdq[ix]; q = wcmdq[ix];
ix = syllable_centre; ix = syllable_centre;


frame = NULL; frame = NULL;
for(;;)
for(;; )
{ {
q = wcmdq[ix]; q = wcmdq[ix];


// length_mod: 256 = 100% // length_mod: 256 = 100%
// modulation: -1 = don't write to wcmdq // modulation: -1 = don't write to wcmdq


int n_frames;
int n_frames;
frameref_t *frames; frameref_t *frames;
int frameix;
int frameix;
frame_t *frame1; frame_t *frame1;
frame_t *frame2; frame_t *frame2;
frame_t *fr; frame_t *fr;
int ix;
int ix;
long64 *q; long64 *q;
int len;
int frame_length;
int length_factor;
int length_mod;
int length_sum;
int length_min;
int total_len = 0;
int len;
int frame_length;
int length_factor;
int length_mod;
int length_sum;
int length_min;
int total_len = 0;
static int wave_flag = 0; static int wave_flag = 0;
int wcmd_spect = WCMD_SPECT; int wcmd_spect = WCMD_SPECT;
int frame_lengths[N_SEQ_FRAMES]; int frame_lengths[N_SEQ_FRAMES];
length_min *= 2; // ensure long vowels are longer length_min *= 2; // ensure long vowels are longer
} }


if(which==1)
{
// limit the shortening of sonorants before shortened (eg. unstressed vowels)
if((this_ph->type==phLIQUID) || (plist[-1].type==phLIQUID) || (plist[-1].type==phNASAL))
if(which==1)
{ {
if(length_mod < (len = translator->langopts.param[LOPT_SONORANT_MIN]))
// limit the shortening of sonorants before shortened (eg. unstressed vowels)
if((this_ph->type==phLIQUID) || (plist[-1].type==phLIQUID) || (plist[-1].type==phNASAL))
{ {
length_mod = len;
if(length_mod < (len = translator->langopts.param[LOPT_SONORANT_MIN]))
{
length_mod = len;
}
} }
} }
}


modn_flags = 0; modn_flags = 0;
frames = LookupSpect(this_ph, which, fmt_params, &n_frames, plist); frames = LookupSpect(this_ph, which, fmt_params, &n_frames, plist);
if(last_frame != NULL) if(last_frame != NULL)
{ {
if(((last_frame->length < 2) || (last_frame->frflags & FRFLAG_VOWEL_CENTRE)) if(((last_frame->length < 2) || (last_frame->frflags & FRFLAG_VOWEL_CENTRE))
&& !(last_frame->frflags & FRFLAG_BREAK))
&& !(last_frame->frflags & FRFLAG_BREAK))
{ {
// last frame of previous sequence was zero-length, replace with first of this sequence // last frame of previous sequence was zero-length, replace with first of this sequence
wcmdq[last_wcmdq][3] = (long64)frame1; wcmdq[last_wcmdq][3] = (long64)frame1;


int Generate(PHONEME_LIST *phoneme_list, int *n_ph, int resume) int Generate(PHONEME_LIST *phoneme_list, int *n_ph, int resume)
{ {
static int ix;
static int embedded_ix;
static int word_count;
static int ix;
static int embedded_ix;
static int word_count;
PHONEME_LIST *prev; PHONEME_LIST *prev;
PHONEME_LIST *next; PHONEME_LIST *next;
PHONEME_LIST *next2; PHONEME_LIST *next2;
PHONEME_LIST *p; PHONEME_LIST *p;
int released;
int stress;
int modulation;
int pre_voiced;
int free_min;
int value;
int released;
int stress;
int modulation;
int pre_voiced;
int free_min;
int value;
unsigned char *pitch_env=NULL; unsigned char *pitch_env=NULL;
unsigned char *amp_env; unsigned char *amp_env;
PHONEME_TAB *ph; PHONEME_TAB *ph;
if(p->newword) if(p->newword)
{ {
if(((p->type == phVOWEL) && (translator->langopts.param[LOPT_WORD_MERGE] & 1)) || if(((p->type == phVOWEL) && (translator->langopts.param[LOPT_WORD_MERGE] & 1)) ||
(p->ph->phflags & phNOPAUSE))
(p->ph->phflags & phNOPAUSE))
{ {
} }
else else
{ {
case phPAUSE: case phPAUSE:
DoPause(p->length,0); DoPause(p->length,0);
p->std_length = p->ph->std_length;
p->std_length = p->ph->std_length;
break; break;


case phSTOP: case phSTOP:
ph = p->ph; ph = p->ph;
if(next->type==phVOWEL) if(next->type==phVOWEL)
{ {
released = 1;
released = 1;
} }
else else
if(!next->newword) if(!next->newword)

+ 40
- 40
src/libespeak-ng/synthesize.h View File

} wavegen_peaks_t; } wavegen_peaks_t;


typedef struct { typedef struct {
unsigned char *pitch_env;
int pitch; // pitch Hz*256
int pitch_ix; // index into pitch envelope (*256)
int pitch_inc; // increment to pitch_ix
int pitch_base; // Hz*256 low, before modified by envelope
int pitch_range; // Hz*256 range of envelope
unsigned char *mix_wavefile; // wave file to be added to synthesis
int n_mix_wavefile; // length in bytes
int mix_wave_scale; // 0=2 byte samples
int mix_wave_amp;
int mix_wavefile_ix;
int mix_wavefile_max; // length of available WAV data (in bytes)
int mix_wavefile_offset;
int amplitude;
int amplitude_v;
int amplitude_fmt; // percentage amplitude adjustment for formant synthesis
unsigned char *pitch_env;
int pitch; // pitch Hz*256
int pitch_ix; // index into pitch envelope (*256)
int pitch_inc; // increment to pitch_ix
int pitch_base; // Hz*256 low, before modified by envelope
int pitch_range; // Hz*256 range of envelope
unsigned char *mix_wavefile; // wave file to be added to synthesis
int n_mix_wavefile; // length in bytes
int mix_wave_scale; // 0=2 byte samples
int mix_wave_amp;
int mix_wavefile_ix;
int mix_wavefile_max; // length of available WAV data (in bytes)
int mix_wavefile_offset;
int amplitude;
int amplitude_v;
int amplitude_fmt; // percentage amplitude adjustment for formant synthesis
} WGEN_DATA; } WGEN_DATA;








typedef struct { typedef struct {
short length_total; // not used
unsigned char n_frames;
unsigned char sqflags;
frame_t2 frame[N_SEQ_FRAMES]; // max. frames in a spectrum sequence
short length_total; // not used
unsigned char n_frames;
unsigned char sqflags;
frame_t2 frame[N_SEQ_FRAMES]; // max. frames in a spectrum sequence
} SPECT_SEQ; // sequence of espeak formant frames } SPECT_SEQ; // sequence of espeak formant frames


typedef struct { typedef struct {
short length_total; // not used
unsigned char n_frames;
unsigned char sqflags;
frame_t frame[N_SEQ_FRAMES]; // max. frames in a spectrum sequence
short length_total; // not used
unsigned char n_frames;
unsigned char sqflags;
frame_t frame[N_SEQ_FRAMES]; // max. frames in a spectrum sequence
} SPECT_SEQK; // sequence of klatt formants frames } SPECT_SEQK; // sequence of klatt formants frames




} FMT_PARAMS; } FMT_PARAMS;


typedef struct { typedef struct {
PHONEME_LIST prev_vowel;
PHONEME_LIST prev_vowel;
} WORD_PH_DATA; } WORD_PH_DATA;


// instructions // instructions
} SOUND_ICON; } SOUND_ICON;


typedef struct { typedef struct {
int name;
unsigned int next_phoneme;
int mbr_name;
int mbr_name2;
int percent; // percentage length of first component
int control;
int name;
unsigned int next_phoneme;
int mbr_name;
int mbr_name2;
int percent; // percentage length of first component
int control;
} MBROLA_TAB; } MBROLA_TAB;


typedef struct { typedef struct {
extern unsigned char pitch_adjust_tab[MAX_PITCH_VALUE+1]; extern unsigned char pitch_adjust_tab[MAX_PITCH_VALUE+1];


// queue of commands for wavegen // queue of commands for wavegen
#define WCMD_KLATT 1
#define WCMD_KLATT2 2
#define WCMD_SPECT 3
#define WCMD_SPECT2 4
#define WCMD_PAUSE 5
#define WCMD_KLATT 1
#define WCMD_KLATT2 2
#define WCMD_SPECT 3
#define WCMD_SPECT2 4
#define WCMD_PAUSE 5
#define WCMD_WAVE 6 #define WCMD_WAVE 6
#define WCMD_WAVE2 7 #define WCMD_WAVE2 7
#define WCMD_AMPLITUDE 8 #define WCMD_AMPLITUDE 8
#define WCMD_PITCH 9
#define WCMD_MARKER 10
#define WCMD_PITCH 9
#define WCMD_MARKER 10
#define WCMD_VOICE 11 #define WCMD_VOICE 11
#define WCMD_EMBEDDED 12 #define WCMD_EMBEDDED 12
#define WCMD_MBROLA_DATA 13 #define WCMD_MBROLA_DATA 13

+ 1072
- 1066
src/libespeak-ng/tr_languages.c
File diff suppressed because it is too large
View File


+ 39
- 39
src/libespeak-ng/translate.c View File

char word_phonemes[N_WORD_PHONEMES]; // a word translated into phoneme codes char word_phonemes[N_WORD_PHONEMES]; // a word translated into phoneme codes
#endif #endif
int n_ph_list2; int n_ph_list2;
PHONEME_LIST2 ph_list2[N_PHONEME_LIST]; // first stage of text->phonemes
PHONEME_LIST2 ph_list2[N_PHONEME_LIST]; // first stage of text->phonemes






// Replacement for iswalph() which also checks for some in-word symbols // Replacement for iswalph() which also checks for some in-word symbols


static const unsigned short extra_indic_alphas[] = { static const unsigned short extra_indic_alphas[] = {
0xa70,0xa71, // Gurmukhi: tippi, addak
0xa70,0xa71, // Gurmukhi: tippi, addak
0 0
}; };


wbuf = word_buf; wbuf = word_buf;
ix = 0; ix = 0;


for(;;)
for(;; )
{ {
ok = 0; ok = 0;
nbytes = utf8_in(&wc, word); nbytes = utf8_in(&wc, word);


int ix; int ix;
int len; int len;
char phon;
char phon;
char *p; char *p;
unsigned char *pb; unsigned char *pb;
char *eqlist; char *eqlist;
char *p_out; char *p_out;
char *p_in; char *p_in;
int remove_stress = 0;
int remove_stress = 0;
char phonbuf[N_WORD_PHONEMES]; char phonbuf[N_WORD_PHONEMES];


// has a phoneme equivalence table been specified for thus language pair? // has a phoneme equivalence table been specified for thus language pair?


pb = (unsigned char *)&phondata_ptr[ix]; pb = (unsigned char *)&phondata_ptr[ix];


for(;;)
for(;; )
{ {
if(pb[0] == 0) if(pb[0] == 0)
return(0); // table not found return(0); // table not found
emphasize_allcaps = FLAG_EMPHASIZED; emphasize_allcaps = FLAG_EMPHASIZED;
} }
else if(!found && !(dictionary_flags[0] & FLAG_SKIPWORDS) && (word_length<4) && (tr->clause_lower_count > 3) else if(!found && !(dictionary_flags[0] & FLAG_SKIPWORDS) && (word_length<4) && (tr->clause_lower_count > 3)
&& (tr->clause_upper_count <= tr->clause_lower_count))
&& (tr->clause_upper_count <= tr->clause_lower_count))
{ {
// An upper case word in a lower case clause. This could be an abbreviation. // An upper case word in a lower case clause. This could be an abbreviation.
spell_word = 1; spell_word = 1;
{ {
// switch languages // switch languages
word+=3; word+=3;
for(ix=0;;)
for(ix=0;; )
{ {
c1 = *word++; c1 = *word++;
if((c1==' ') || (c1==0)) if((c1==' ') || (c1==0))
if(first_phoneme && tr->langopts.param[LOPT_IT_DOUBLING]) if(first_phoneme && tr->langopts.param[LOPT_IT_DOUBLING])
{ {
if(((tr->prev_dict_flags[0] & FLAG_DOUBLING) && (tr->langopts.param[LOPT_IT_DOUBLING] & 1)) || if(((tr->prev_dict_flags[0] & FLAG_DOUBLING) && (tr->langopts.param[LOPT_IT_DOUBLING] & 1)) ||
(tr->end_stressed_vowel && (tr->langopts.param[LOPT_IT_DOUBLING] & 2)))
(tr->end_stressed_vowel && (tr->langopts.param[LOPT_IT_DOUBLING] & 2)))
{ {
// italian, double the initial consonant if the previous word ends with a // italian, double the initial consonant if the previous word ends with a
// stressed vowel, or is marked with a flag // stressed vowel, or is marked with a flag
if(tr->translator_name == L('g','a')) if(tr->translator_name == L('g','a'))
{ {
// Irish // Irish
for(ix=0; ; ix++)
for(ix=0;; ix++)
{ {
if((p = UCase_ga[ix]) == NULL) if((p = UCase_ga[ix]) == NULL)
break; break;


clause_pause = (terminator & 0xfff) * 10; // mS clause_pause = (terminator & 0xfff) * 10; // mS
if(terminator & CLAUSE_PAUSE_LONG) if(terminator & CLAUSE_PAUSE_LONG)
clause_pause = clause_pause * 32 ; // pause value is *320mS not *10mS
clause_pause = clause_pause * 32; // pause value is *320mS not *10mS


tone = (terminator >> 12) & 0x7; tone = (terminator >> 12) & 0x7;
if(tone2 != 0) if(tone2 != 0)
if(tr->letter_bits_offset > 0) if(tr->letter_bits_offset > 0)
{ {
if(((c < 0x250) && (prev_out >= tr->letter_bits_offset)) || if(((c < 0x250) && (prev_out >= tr->letter_bits_offset)) ||
((c >= tr->letter_bits_offset) && (letter_count > 1) && (prev_out < 0x250)))
((c >= tr->letter_bits_offset) && (letter_count > 1) && (prev_out < 0x250)))
{ {
// Don't mix native and Latin characters in the same word // Don't mix native and Latin characters in the same word
// Break into separate words // Break into separate words
} }
} }
else else
if(lookupwchar(breaks,c) != 0)
if(lookupwchar(breaks,c) != 0)
{
c = ' '; // various characters to treat as space
}
else if(iswdigit(c))
{
if(tr->langopts.tone_numbers && IsAlpha(prev_out) && !IsDigit(next_in))
{
}
else if((prev_out != ' ') && !iswdigit(prev_out))
{
if((prev_out != tr->langopts.decimal_sep) || ((decimal_sep_count > 0) && (tr->langopts.decimal_sep == ',')))
{ {
c = ' '; // various characters to treat as space
c = ' ';
space_inserted = 1;
} }
else if(iswdigit(c))
else
{ {
if(tr->langopts.tone_numbers && IsAlpha(prev_out) && !IsDigit(next_in))
{
}
else if((prev_out != ' ') && !iswdigit(prev_out))
{
if((prev_out != tr->langopts.decimal_sep) || ((decimal_sep_count > 0) && (tr->langopts.decimal_sep == ',')))
{
c = ' ';
space_inserted = 1;
}
else
{
decimal_sep_count = 1;
}
}
else if((prev_out == ' ') && IsAlpha(prev_out2) && !IsAlpha(prev_in))
{
// insert extra space between a word and a number, to distinguish 'a 2' from 'a2'
sbuf[ix++] = ' ';
words[word_count].start++;
}
decimal_sep_count = 1;
} }
}
else if((prev_out == ' ') && IsAlpha(prev_out2) && !IsAlpha(prev_in))
{
// insert extra space between a word and a number, to distinguish 'a 2' from 'a2'
sbuf[ix++] = ' ';
words[word_count].start++;
}
}
} }


if(IsSpace(c)) if(IsSpace(c))
*pn++ = *pw++; *pn++ = *pw++;
} }
else if((*pw == tr->langopts.thousands_sep) && (pw[1] == ' ') else if((*pw == tr->langopts.thousands_sep) && (pw[1] == ' ')
&& iswdigit(pw[2]) && (pw[3] != ' ') && (pw[4] != ' ')) // don't allow only 1 or 2 digits in the final part
&& iswdigit(pw[2]) && (pw[3] != ' ') && (pw[4] != ' ')) // don't allow only 1 or 2 digits in the final part
{ {
pw += 2; pw += 2;
ix++; // skip "word" ix++; // skip "word"
pn[16] = 0; pn[16] = 0;
nw = 0; nw = 0;


for(pw = &number_buf[1]; pw < pn;)
for(pw = &number_buf[1]; pw < pn; )
{ {
// keep wflags for each part, for FLAG_HYPHEN_AFTER // keep wflags for each part, for FLAG_HYPHEN_AFTER
dict_flags = TranslateWord2(tr, pw, &num_wtab[nw++], words[ix].pre_pause,0 ); dict_flags = TranslateWord2(tr, pw, &num_wtab[nw++], words[ix].pre_pause,0 );
if(dict_flags & FLAG_SPELLWORD) if(dict_flags & FLAG_SPELLWORD)
{ {
// redo the word, speaking single letters // redo the word, speaking single letters
for(pw = word; *pw != ' ';)
for(pw = word; *pw != ' '; )
{ {
memset(number_buf,' ',9); memset(number_buf,' ',9);
nx = utf8_in(&c_temp, pw); nx = utf8_in(&c_temp, pw);

+ 76
- 76
src/libespeak-ng/translate.h View File





// codes in dictionary rules // codes in dictionary rules
#define RULE_PRE 1
#define RULE_POST 2
#define RULE_PHONEMES 3
#define RULE_PH_COMMON 4 // At start of rule. Its phoneme string is used by subsequent rules
#define RULE_CONDITION 5 // followed by condition number (byte)
#define RULE_PRE 1
#define RULE_POST 2
#define RULE_PHONEMES 3
#define RULE_PH_COMMON 4 // At start of rule. Its phoneme string is used by subsequent rules
#define RULE_CONDITION 5 // followed by condition number (byte)
#define RULE_GROUP_START 6 #define RULE_GROUP_START 6
#define RULE_GROUP_END 7
#define RULE_GROUP_END 7
#define RULE_PRE_ATSTART 8 // as RULE_PRE but also match with 'start of word' #define RULE_PRE_ATSTART 8 // as RULE_PRE but also match with 'start of word'
#define RULE_LINENUM 9 // next 2 bytes give a line number, for debugging purposes
#define RULE_SPACE 32 // ascii space
#define RULE_SYLLABLE 21 // @
#define RULE_STRESSED 10 // &
#define RULE_DOUBLE 11 // %
#define RULE_INC_SCORE 12 // +
#define RULE_DEL_FWD 13 // #
#define RULE_ENDING 14 // S
#define RULE_DIGIT 15 // D digit
#define RULE_NONALPHA 16 // Z non-alpha
#define RULE_LINENUM 9 // next 2 bytes give a line number, for debugging purposes
#define RULE_SPACE 32 // ascii space
#define RULE_SYLLABLE 21 // @
#define RULE_STRESSED 10 // &
#define RULE_DOUBLE 11 // %
#define RULE_INC_SCORE 12 // +
#define RULE_DEL_FWD 13 // #
#define RULE_ENDING 14 // S
#define RULE_DIGIT 15 // D digit
#define RULE_NONALPHA 16 // Z non-alpha
#define RULE_LETTERGP 17 // A B C H F G Y letter group number #define RULE_LETTERGP 17 // A B C H F G Y letter group number
#define RULE_LETTERGP2 18 // L + letter group number #define RULE_LETTERGP2 18 // L + letter group number
#define RULE_CAPITAL 19 // ! word starts with a capital letter #define RULE_CAPITAL 19 // ! word starts with a capital letter
#define DOLLAR_LIST 0x03 #define DOLLAR_LIST 0x03




#define LETTERGP_A 0
#define LETTERGP_B 1
#define LETTERGP_C 2
#define LETTERGP_H 3
#define LETTERGP_F 4
#define LETTERGP_G 5
#define LETTERGP_Y 6
#define LETTERGP_A 0
#define LETTERGP_B 1
#define LETTERGP_C 2
#define LETTERGP_H 3
#define LETTERGP_F 4
#define LETTERGP_G 5
#define LETTERGP_Y 6
#define LETTERGP_VOWEL2 7 #define LETTERGP_VOWEL2 7




typedef const char * constcharptr; typedef const char * constcharptr;


typedef struct { typedef struct {
int points;
int points;
const char *phonemes; const char *phonemes;
int end_type;
int end_type;
char *del_fwd; char *del_fwd;
} MatchRecord; } MatchRecord;




// used to mark words with the source[] buffer // used to mark words with the source[] buffer
typedef struct{
typedef struct {
unsigned int flags; unsigned int flags;
unsigned short start; unsigned short start;
unsigned char pre_pause; unsigned char pre_pause;




typedef struct { typedef struct {
const char *name;
int offset;
unsigned short range_min, range_max;
int language;
int flags;
const char *name;
int offset;
unsigned short range_min, range_max;
int language;
int flags;
} ALPHABET; } ALPHABET;


extern ALPHABET alphabets[]; extern ALPHABET alphabets[];


#define N_LOPTS 21 #define N_LOPTS 21
#define LOPT_DIERESES 1 #define LOPT_DIERESES 1
// 1=remove [:] from unstressed syllables, 2= remove from unstressed or non-penultimate syllables
// bit 4=0, if stress < 4, bit 4=1, if not the highest stress in the word
// 1=remove [:] from unstressed syllables, 2= remove from unstressed or non-penultimate syllables
// bit 4=0, if stress < 4, bit 4=1, if not the highest stress in the word
#define LOPT_IT_LENGTHEN 2 #define LOPT_IT_LENGTHEN 2


// 1=german
// 1=german
#define LOPT_PREFIXES 3 #define LOPT_PREFIXES 3


// non-zero, change voiced/unoiced to match last consonant in a cluster
// bit 0=use regressive voicing
// bit 1=LANG=cz,bg don't propagate over [v]
// bit 2=don't propagate acress word boundaries
// bit 3=LANG=pl, propagate over liquids and nasals
// bit 4=LANG=cz,sk don't progagate to [v]
// bit 8=devoice word-final consonants
// non-zero, change voiced/unoiced to match last consonant in a cluster
// bit 0=use regressive voicing
// bit 1=LANG=cz,bg don't propagate over [v]
// bit 2=don't propagate acress word boundaries
// bit 3=LANG=pl, propagate over liquids and nasals
// bit 4=LANG=cz,sk don't progagate to [v]
// bit 8=devoice word-final consonants
#define LOPT_REGRESSIVE_VOICING 4 #define LOPT_REGRESSIVE_VOICING 4


// 0=default, 1=no check, other allow this character as an extra initial letter (default is 's')
// 0=default, 1=no check, other allow this character as an extra initial letter (default is 's')
#define LOPT_UNPRONOUNCABLE 5 #define LOPT_UNPRONOUNCABLE 5


// select length_mods tables, (length_mod_tab) + (length_mod_tab0 * 100)
// select length_mods tables, (length_mod_tab) + (length_mod_tab0 * 100)
#define LOPT_LENGTH_MODS 6 #define LOPT_LENGTH_MODS 6


// increase this to prevent sonorants being shortened before shortened (eg. unstressed) vowels
// increase this to prevent sonorants being shortened before shortened (eg. unstressed) vowels
#define LOPT_SONORANT_MIN 7 #define LOPT_SONORANT_MIN 7


// bit 0: don't break vowels at word boundary
// bit 0: don't break vowels at word boundary
#define LOPT_WORD_MERGE 8 #define LOPT_WORD_MERGE 8


// max. amplitude for vowel at the end of a clause
// max. amplitude for vowel at the end of a clause
#define LOPT_MAXAMP_EOC 9 #define LOPT_MAXAMP_EOC 9


// bit 0=reduce even if phonemes are specified in the **_list file
// bit 1=don't reduce the strongest vowel in a word which is marked 'unstressed'
// bit 0=reduce even if phonemes are specified in the **_list file
// bit 1=don't reduce the strongest vowel in a word which is marked 'unstressed'
#define LOPT_REDUCE 10 #define LOPT_REDUCE 10


// LANG=cs,sk combine some prepositions with the following word, if the combination has N or fewer syllables
// bits 0-3 N syllables
// bit 4=only if the second word has $alt attribute
// bit 5=not if the second word is end-of-sentence
// LANG=cs,sk combine some prepositions with the following word, if the combination has N or fewer syllables
// bits 0-3 N syllables
// bit 4=only if the second word has $alt attribute
// bit 5=not if the second word is end-of-sentence
#define LOPT_COMBINE_WORDS 11 #define LOPT_COMBINE_WORDS 11


// change [t] when followed by unstressed vowel
// change [t] when followed by unstressed vowel
#define LOPT_REDUCE_T 12 #define LOPT_REDUCE_T 12


// 1 = allow capitals inside a word
// 2 = stressed syllable is indicated by capitals
// 1 = allow capitals inside a word
// 2 = stressed syllable is indicated by capitals
#define LOPT_CAPS_IN_WORD 13 #define LOPT_CAPS_IN_WORD 13


// bit 0=Italian "syntactic doubling" of consoants in the word after a word marked with $double attribute
// bit 1=also after a word which ends with a stressed vowel
// bit 0=Italian "syntactic doubling" of consoants in the word after a word marked with $double attribute
// bit 1=also after a word which ends with a stressed vowel
#define LOPT_IT_DOUBLING 14 #define LOPT_IT_DOUBLING 14


// Call ApplySpecialAttributes() if $alt or $alt2 is set for a word
// bit 1: stressed syllable: $alt change [e],[o] to [E],[O], $alt2 change [E],[O] to [e],[o]
// Call ApplySpecialAttributes() if $alt or $alt2 is set for a word
// bit 1: stressed syllable: $alt change [e],[o] to [E],[O], $alt2 change [E],[O] to [e],[o]
#define LOPT_ALT 15 #define LOPT_ALT 15


// pause for bracket (default=4), pause when annoucing bracket names (default=2)
// pause for bracket (default=4), pause when annoucing bracket names (default=2)
#define LOPT_BRACKET_PAUSE 16 #define LOPT_BRACKET_PAUSE 16


// bit 1, don't break clause before annoucning . ? !
// bit 1, don't break clause before annoucning . ? !
#define LOPT_ANNOUNCE_PUNCT 17 #define LOPT_ANNOUNCE_PUNCT 17


// recognize long vowels (0 = don't recognize)
// recognize long vowels (0 = don't recognize)
#define LOPT_LONG_VOWEL_THRESHOLD 18 #define LOPT_LONG_VOWEL_THRESHOLD 18


// bit 0: Don't allow suffices if there is no previous syllable
// bit 0: Don't allow suffices if there is no previous syllable
#define LOPT_SUFFIX 19 #define LOPT_SUFFIX 19


// bit 0 Apostrophe at start of word is part of the word
// bit 1 Apostrophe at end of word is part of the word
// bit 0 Apostrophe at start of word is part of the word
// bit 1 Apostrophe at end of word is part of the word
#define LOPT_APOSTROPHE 20 #define LOPT_APOSTROPHE 20




// stress_rule // stress_rule
#define STRESSPOSN_1L 0 // 1st syllable
#define STRESSPOSN_2L 1 // 2nd syllable
#define STRESSPOSN_2R 2 // penultimate
#define STRESSPOSN_1R 3 // final syllable
#define STRESSPOSN_3R 4 // antipenultimate
#define STRESSPOSN_1L 0 // 1st syllable
#define STRESSPOSN_2L 1 // 2nd syllable
#define STRESSPOSN_2R 2 // penultimate
#define STRESSPOSN_1R 3 // final syllable
#define STRESSPOSN_3R 4 // antipenultimate




typedef struct { typedef struct {
// bit5='and' between tens and units // bit5='and' between tens and units
// bit6=add "and" after hundred or thousand // bit6=add "and" after hundred or thousand
// bit7=don't have "and" both after hundreds and also between tens and units // bit7=don't have "and" both after hundreds and also between tens and units
// bit8=only one primary stress in tens+units
// bit8=only one primary stress in tens+units
// bit9=only one vowel betwen tens and units // bit9=only one vowel betwen tens and units
// bit10=omit "one" before "hundred" // bit10=omit "one" before "hundred"
// bit11=say 19** as nineteen hundred // bit11=say 19** as nineteen hundred
// bit25= Roman numbers only if upper case // bit25= Roman numbers only if upper case
// bit26= say "roman" after the number, not before // bit26= say "roman" after the number, not before
// bit27= Roman numbers are ordinal numbers // bit27= Roman numbers are ordinal numbers
// bit28= only one primary stress in tens+units (on the tens)
// bit28= only one primary stress in tens+units (on the tens)
int numbers; int numbers;


#define NUM2_THOUSANDS_VAR1 0x40 #define NUM2_THOUSANDS_VAR1 0x40
char dictionary_name[40]; char dictionary_name[40];


char phonemes_repeat[20]; char phonemes_repeat[20];
int phonemes_repeat_count;
int phoneme_tab_ix;
int phonemes_repeat_count;
int phoneme_tab_ix;


unsigned char stress_amps[8]; unsigned char stress_amps[8];
unsigned char stress_amps_r[8]; unsigned char stress_amps_r[8];
void InterpretPhoneme2(int phcode, PHONEME_DATA *phdata); void InterpretPhoneme2(int phcode, PHONEME_DATA *phdata);
char *WritePhMnemonic(char *phon_out, PHONEME_TAB *ph, PHONEME_LIST *plist, int use_ipa, int *flags); char *WritePhMnemonic(char *phon_out, PHONEME_TAB *ph, PHONEME_LIST *plist, int use_ipa, int *flags);


extern FILE *f_trans; // for logging
extern FILE *f_trans; // for logging
extern FILE *f_logespeak; extern FILE *f_logespeak;
extern int logging_type; // from config file extern int logging_type; // from config file



+ 50
- 50
src/libespeak-ng/voices.c View File

{"stressAdd", V_STRESSADD}, {"stressAdd", V_STRESSADD},
{"intonation", V_INTONATION}, {"intonation", V_INTONATION},
{"tunes", V_TUNES}, {"tunes", V_TUNES},
{"dictrules", V_DICTRULES},
{"dictrules", V_DICTRULES},
{"stressrule", V_STRESSRULE}, {"stressrule", V_STRESSRULE},
{"stressopt", V_STRESSOPT}, {"stressopt", V_STRESSOPT},
{"charset", V_CHARSET}, {"charset", V_CHARSET},
tone_pts[ix] = -1; tone_pts[ix] = -1;


sscanf(string,"%d %d %d %d %d %d %d %d %d %d", sscanf(string,"%d %d %d %d %d %d %d %d %d %d",
&tone_pts[0],&tone_pts[1],&tone_pts[2],&tone_pts[3],
&tone_pts[4],&tone_pts[5],&tone_pts[6],&tone_pts[7],
&tone_pts[8],&tone_pts[9]);
&tone_pts[0],&tone_pts[1],&tone_pts[2],&tone_pts[3],
&tone_pts[4],&tone_pts[5],&tone_pts[6],&tone_pts[7],
&tone_pts[8],&tone_pts[9]);
} }




{ {
// Set voice to the default values // Set voice to the default values


int pk;
int pk;
static unsigned char default_heights[N_PEAKS] = {130,128,120,116,100,100,128,128,128}; // changed for v.1.47 static unsigned char default_heights[N_PEAKS] = {130,128,120,116,100,100,128,128,128}; // changed for v.1.47
static unsigned char default_widths[N_PEAKS] = {140,128,128,160,171,171,128,128,128}; static unsigned char default_widths[N_PEAKS] = {140,128,128,160,171,171,128,128,128};


static void PhonemeReplacement(int type, char *p) static void PhonemeReplacement(int type, char *p)
{ {
int n; int n;
int phon;
int phon;
int flags = 0; int flags = 0;
char phon_string1[12]; char phon_string1[12];
char phon_string2[12]; char phon_string2[12];
// Read 8 integer numbers // Read 8 integer numbers
memset(data, 0, 8+sizeof(int)); memset(data, 0, 8+sizeof(int));
return(sscanf(data_in,"%d %d %d %d %d %d %d %d", return(sscanf(data_in,"%d %d %d %d %d %d %d %d",
&data[0],&data[1],&data[2],&data[3],&data[4],&data[5],&data[6],&data[7]));
&data[0],&data[1],&data[2],&data[3],&data[4],&data[5],&data[6],&data[7]));
} }






FILE *f_voice = NULL; FILE *f_voice = NULL;
char *p; char *p;
int key;
int ix;
int n;
int value;
int value2;
int langix = 0;
int tone_only = control & 2;
int language_set = 0;
int phonemes_set = 0;
int stress_amps_set = 0;
int stress_lengths_set = 0;
int stress_add_set = 0;
int conditional_rules = 0;
int key;
int ix;
int n;
int value;
int value2;
int langix = 0;
int tone_only = control & 2;
int language_set = 0;
int phonemes_set = 0;
int stress_amps_set = 0;
int stress_lengths_set = 0;
int stress_add_set = 0;
int conditional_rules = 0;
LANGUAGE_OPTIONS *langopts = NULL; LANGUAGE_OPTIONS *langopts = NULL;


Translator *new_translator = NULL; Translator *new_translator = NULL;


// which directory to look for a named voice. List of voice names, must end in a space. // which directory to look for a named voice. List of voice names, must end in a space.
static const char *voices_asia = static const char *voices_asia =
"az bn fa fa-pin gu hi hy hy-west id ka kn ku ml ms ne pa ta te tr vi vi-hue vi-sgn zh zh-yue ";
"az bn fa fa-pin gu hi hy hy-west id ka kn ku ml ms ne pa ta te tr vi vi-hue vi-sgn zh zh-yue ";
static const char *voices_europe = static const char *voices_europe =
"an bg bs ca cs cy da de el en en-us es et eu fi fr fr-be ga hr hu is it lt lv mk nl no pl pt-pt ro ru sk sq sr sv ";
"an bg bs ca cs cy da de el en en-us es et eu fi fr fr-be ga hr hu is it lt lv mk nl no pl pt-pt ro ru sk sq sr sv ";




strncpy0(voicename, vname, sizeof(voicename)); strncpy0(voicename, vname, sizeof(voicename));


case V_STRESSRULE: case V_STRESSRULE:
sscanf(p,"%d %d %d %d",&langopts->stress_rule, sscanf(p,"%d %d %d %d",&langopts->stress_rule,
&langopts->stress_flags,
&langopts->unstressed_wd1,
&langopts->unstressed_wd2);
&langopts->stress_flags,
&langopts->unstressed_wd1,
&langopts->unstressed_wd2);
break; break;


case V_CHARSET: case V_CHARSET:
case V_OPTION: case V_OPTION:
value2 = 0; value2 = 0;
if(((sscanf(p,"%s %d %d",option_name,&value,&value2) >= 2) && ((ix = LookupMnem(options_tab, option_name)) >= 0)) || if(((sscanf(p,"%s %d %d",option_name,&value,&value2) >= 2) && ((ix = LookupMnem(options_tab, option_name)) >= 0)) ||
((sscanf(p,"%d %d %d",&ix,&value,&value2) >= 2) && (ix < N_LOPTS)))
((sscanf(p,"%d %d %d",&ix,&value,&value2) >= 2) && (ix < N_LOPTS)))
{ {
langopts->param[ix] = value; langopts->param[ix] = value;
langopts->param2[ix] = value2; langopts->param2[ix] = value2;
break; break;


case V_ALPHABET2: case V_ALPHABET2:
{
ALPHABET *alphabet;
name1[0] = name2[0] = 0;
sscanf(p, "%s %s", name1, name2);
{
ALPHABET *alphabet;
name1[0] = name2[0] = 0;
sscanf(p, "%s %s", name1, name2);


if(strcmp(name1, "latin") == 0)
{
strncpy0(langopts->ascii_language,name2,sizeof(langopts->ascii_language));
}
else if((alphabet = AlphabetFromName(name1)) != 0)
{
langopts->alt_alphabet = alphabet->offset;
langopts->alt_alphabet_lang = StringToWord2(name2);
}
else
{
fprintf(stderr,"alphabet name '%s' not found\n", name1);
}
if(strcmp(name1, "latin") == 0)
{
strncpy0(langopts->ascii_language,name2,sizeof(langopts->ascii_language));
} }
break;
else if((alphabet = AlphabetFromName(name1)) != 0)
{
langopts->alt_alphabet = alphabet->offset;
langopts->alt_alphabet_lang = StringToWord2(name2);
}
else
{
fprintf(stderr,"alphabet name '%s' not found\n", name1);
}
}
break;


case V_DICTDIALECT: case V_DICTDIALECT:
// specify a dialect to use for foreign words, eg, en-us for _^_EN // specify a dialect to use for foreign words, eg, en-us for _^_EN
matching_parts = 0; matching_parts = 0;
n_parts = 1; n_parts = 1;


for(ix=0; ; ix++)
for(ix=0;; ix++)
{ {
if((ix >= spec_lang_len) || ((c1 = spec_language[ix]) == '-')) if((ix >= spec_lang_len) || ((c1 = spec_language[ix]) == '-'))
c1 = 0; c1 = 0;
} }


if(((voice_spec->gender == 1) || (voice_spec->gender == 2)) && if(((voice_spec->gender == 1) || (voice_spec->gender == 2)) &&
((voice->gender == 1) || (voice->gender == 2)))
((voice->gender == 1) || (voice->gender == 2)))
{ {
if(voice_spec->gender == voice->gender) if(voice_spec->gender == voice->gender)
score += 50; score += 50;
voices2[ix2++] = vp; voices2[ix2++] = vp;
} }


for(j=0; (j < vp->xx1) && (n_variants < N_VOICE_VARIANTS);)
for(j=0; (j < vp->xx1) && (n_variants < N_VOICE_VARIANTS); )
{ {
if((variant_number = *p) == 0) if((variant_number = *p) == 0)
{ {


variant_name = ExtractVoiceVariantName(buf, 0, 1); variant_name = ExtractVoiceVariantName(buf, 0, 1);


for(ix=0; ; ix++)
for(ix=0;; ix++)
{ {
// convert voice name to lower case (ascii) // convert voice name to lower case (ascii)
if((buf[ix] = tolower(buf[ix])) == 0) if((buf[ix] = tolower(buf[ix])) == 0)


// sort the voices list // sort the voices list
qsort(voices_list,n_voices_list,sizeof(espeak_VOICE *), qsort(voices_list,n_voices_list,sizeof(espeak_VOICE *),
(int (__cdecl *)(const void *,const void *))VoiceNameSorter);
(int (__cdecl *)(const void *,const void *))VoiceNameSorter);




if(voice_spec) if(voice_spec)
for(ix=0; (v = voices_list[ix]) != NULL; ix++) for(ix=0; (v = voices_list[ix]) != NULL; ix++)
{ {
if((v->languages[0] != 0) && (strcmp(&v->languages[1],"variant") != 0) if((v->languages[0] != 0) && (strcmp(&v->languages[1],"variant") != 0)
&& (memcmp(v->identifier,"mb/",3) != 0) && (memcmp(v->identifier,"test/",5) != 0))
&& (memcmp(v->identifier,"mb/",3) != 0) && (memcmp(v->identifier,"test/",5) != 0))
{ {
voices[j++] = v; voices[j++] = v;
} }

+ 439
- 420
src/libespeak-ng/wave.c
File diff suppressed because it is too large
View File


+ 528
- 510
src/libespeak-ng/wave_pulse.c
File diff suppressed because it is too large
View File


+ 205
- 186
src/libespeak-ng/wave_sada.c View File



static uint32_t wave_samplerate; static uint32_t wave_samplerate;


// wave_init
// wave_init
// //
// DESCRIPTION: // DESCRIPTION:
// //
// audio device. // audio device.
// //
int wave_init(int srate) { int wave_init(int srate) {
ENTER("wave_init");
ENTER("wave_init");


audio_info_t ainfo;
char *audio_device = NULL;
audio_info_t ainfo;
char *audio_device = NULL;


wave_samplerate = srate; wave_samplerate = srate;


audio_device = getenv("AUDIODEV");
if (audio_device != NULL) {
if ((sun_audio_fd = open(audio_device, O_WRONLY)) < 0) {
SHOW("wave_init() could not open: %s (%d)\n",
audio_device, sun_audio_fd);
}
}
if (sun_audio_fd < 0) {
if ((sun_audio_fd = open(sun_audio_device, O_WRONLY)) < 0) {
SHOW("wave_init() could not open: %s (%d)\n",
sun_audio_device, sun_audio_fd);
}
}
SHOW("wave_init() sun_audio_fd: %d\n", sun_audio_fd);
if (sun_audio_fd < 0) {
return(0);
}
ioctl(sun_audio_fd, AUDIO_GETINFO, &ainfo);
SHOW("wave_init() play buffer size: %d\n", ainfo.play.buffer_size);
ainfo.play.encoding = AUDIO_ENCODING_LINEAR;
ainfo.play.channels = 1;
ainfo.play.sample_rate = wave_samplerate;
ainfo.play.precision = SAMPLE_SIZE;
if (ioctl(sun_audio_fd, AUDIO_SETINFO, &ainfo) == -1) {
SHOW("wave_init() failed to set audio params: %s\n", strerror(errno));
close(sun_audio_fd);
return(0);
}
return(1);
audio_device = getenv("AUDIODEV");
if (audio_device != NULL) {
if ((sun_audio_fd = open(audio_device, O_WRONLY)) < 0) {
SHOW("wave_init() could not open: %s (%d)\n",
audio_device, sun_audio_fd);
}
}
if (sun_audio_fd < 0) {
if ((sun_audio_fd = open(sun_audio_device, O_WRONLY)) < 0) {
SHOW("wave_init() could not open: %s (%d)\n",
sun_audio_device, sun_audio_fd);
}
}
SHOW("wave_init() sun_audio_fd: %d\n", sun_audio_fd);
if (sun_audio_fd < 0) {
return(0);
}
ioctl(sun_audio_fd, AUDIO_GETINFO, &ainfo);
SHOW("wave_init() play buffer size: %d\n", ainfo.play.buffer_size);
ainfo.play.encoding = AUDIO_ENCODING_LINEAR;
ainfo.play.channels = 1;
ainfo.play.sample_rate = wave_samplerate;
ainfo.play.precision = SAMPLE_SIZE;
if (ioctl(sun_audio_fd, AUDIO_SETINFO, &ainfo) == -1) {
SHOW("wave_init() failed to set audio params: %s\n", strerror(errno));
close(sun_audio_fd);
return(0);
}
return(1);
} }


// wave_open // wave_open
// //
void* wave_open(const char* the_api) void* wave_open(const char* the_api)
{ {
ENTER("wave_open");
return((void*) sun_audio_fd);
ENTER("wave_open");
return((void*) sun_audio_fd);
} }


// wave_write // wave_write
// //
// total_samples_sent: modified based upon 16-bit samples sent // total_samples_sent: modified based upon 16-bit samples sent
// //
// RETURNS:
// RETURNS:
// //
// the number of bytes (not 16-bit samples) sent // the number of bytes (not 16-bit samples) sent
// //
size_t wave_write(void* theHandler,
char* theMono16BitsWaveBuffer,
size_t theSize)
size_t wave_write(void* theHandler,
char* theMono16BitsWaveBuffer,
size_t theSize)
{ {
size_t num;
ENTER("wave_write");
if (my_callback_is_output_enabled && (0==my_callback_is_output_enabled())) {
SHOW_TIME("wave_write > my_callback_is_output_enabled: no!");
return 0;
}
size_t num;
ENTER("wave_write");
if (my_callback_is_output_enabled && (0==my_callback_is_output_enabled())) {
SHOW_TIME("wave_write > my_callback_is_output_enabled: no!");
return 0;
}


#if defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN #if defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN
{
// BIG-ENDIAN, swap the order of bytes in each sound sample
int c;
char *out_ptr;
char *out_end;
out_ptr = (char *)theMono16BitsWaveBuffer;
out_end = out_ptr + theSize;
while(out_ptr < out_end)
{
c = out_ptr[0];
out_ptr[0] = out_ptr[1];
out_ptr[1] = c;
out_ptr += 2;
}
}
{
// BIG-ENDIAN, swap the order of bytes in each sound sample
int c;
char *out_ptr;
char *out_end;
out_ptr = (char *)theMono16BitsWaveBuffer;
out_end = out_ptr + theSize;
while(out_ptr < out_end)
{
c = out_ptr[0];
out_ptr[0] = out_ptr[1];
out_ptr[1] = c;
out_ptr += 2;
}
}
#endif #endif


num = write((int) theHandler, theMono16BitsWaveBuffer, theSize);
num = write((int) theHandler, theMono16BitsWaveBuffer, theSize);


// Keep track of the total number of samples sent -- we use this in
// wave_get_read_position and also use it to help calculate the
// total_samples_skipped in wave_close.
//
total_samples_sent += num / 2;
// Keep track of the total number of samples sent -- we use this in
// wave_get_read_position and also use it to help calculate the
// total_samples_skipped in wave_close.
//
total_samples_sent += num / 2;


if (num < theSize) {
SHOW("ERROR: wave_write only wrote %d of %d bytes\n", num, theSize);
} else {
SHOW("wave_write wrote %d bytes\n", theSize);
}
if (num < theSize) {
SHOW("ERROR: wave_write only wrote %d of %d bytes\n", num, theSize);
} else {
SHOW("wave_write wrote %d bytes\n", theSize);
}


SHOW_TIME("wave_write > LEAVE");
return num;
SHOW_TIME("wave_write > LEAVE");
return num;
} }


// wave_close // wave_close
// total_samples_skipped: modified to hold the total number of 16-bit // total_samples_skipped: modified to hold the total number of 16-bit
// samples sent to wave_write, but which were // samples sent to wave_write, but which were
// never played // never played
// sun_audio_fd: used because some calls to wave_close seem to
// sun_audio_fd: used because some calls to wave_close seem to
// pass a NULL for theHandler for some odd reason // pass a NULL for theHandler for some odd reason
// //
// RETURNS:
// RETURNS:
// //
// The result of the ioctl call (non-0 means failure) // The result of the ioctl call (non-0 means failure)
// //
int wave_close(void* theHandler) int wave_close(void* theHandler)
{ {
int ret;
audio_info_t ainfo;
int audio_fd = (int) theHandler;
if (!audio_fd) {
audio_fd = sun_audio_fd;
}
ENTER("wave_close");
// [[[WDW: maybe do a pause/resume ioctl???]]]
ret = ioctl(audio_fd, I_FLUSH, FLUSHRW);
ioctl(audio_fd, AUDIO_GETINFO, &ainfo);
// Calculate the number of samples that won't get
// played. We also keep track of the last_play_position
// because wave_close can be called multiple times
// before another call to wave_write.
//
if (last_play_position != ainfo.play.samples) {
last_play_position = ainfo.play.samples;
total_samples_skipped = total_samples_sent - last_play_position;
}
SHOW_TIME("wave_close > LEAVE");
return ret;
int ret;
audio_info_t ainfo;
int audio_fd = (int) theHandler;
if (!audio_fd) {
audio_fd = sun_audio_fd;
}
ENTER("wave_close");
// [[[WDW: maybe do a pause/resume ioctl???]]]
ret = ioctl(audio_fd, I_FLUSH, FLUSHRW);
ioctl(audio_fd, AUDIO_GETINFO, &ainfo);
// Calculate the number of samples that won't get
// played. We also keep track of the last_play_position
// because wave_close can be called multiple times
// before another call to wave_write.
//
if (last_play_position != ainfo.play.samples) {
last_play_position = ainfo.play.samples;
total_samples_skipped = total_samples_sent - last_play_position;
}
SHOW_TIME("wave_close > LEAVE");
return ret;
} }


// wave_is_busy // wave_is_busy
// //
// GLOBALS USED/MODIFIED: // GLOBALS USED/MODIFIED:
// //
// sun_audio_fd: used because some calls to wave_is_busy seem to
// sun_audio_fd: used because some calls to wave_is_busy seem to
// pass a NULL for theHandler for some odd reason // pass a NULL for theHandler for some odd reason
// //
// RETURNS: // RETURNS:
// //
int wave_is_busy(void* theHandler) int wave_is_busy(void* theHandler)
{ {
uint32_t time;
if (total_samples_sent >= 1) {
wave_get_remaining_time(total_samples_sent - 1, &time);
} else {
time = 0;
}
return time != 0;
uint32_t time;
if (total_samples_sent >= 1) {
wave_get_remaining_time(total_samples_sent - 1, &time);
} else {
time = 0;
}
return time != 0;
} }


// wave_terminate // wave_terminate
// //
void wave_terminate() void wave_terminate()
{ {
ENTER("wave_terminate");
close(sun_audio_fd);
sun_audio_fd = -1;
SHOW_TIME("wave_terminate > LEAVE");
ENTER("wave_terminate");
close(sun_audio_fd);
sun_audio_fd = -1;
SHOW_TIME("wave_terminate > LEAVE");
} }


// wave_flush // wave_flush
// //
void wave_flush(void* theHandler) void wave_flush(void* theHandler)
{ {
ENTER("wave_flush");
SHOW_TIME("wave_flush > LEAVE");
ENTER("wave_flush");
SHOW_TIME("wave_flush > LEAVE");
} }


// wave_set_callback_is_output_enabled // wave_set_callback_is_output_enabled
// //
void wave_set_callback_is_output_enabled(t_wave_callback* cb) void wave_set_callback_is_output_enabled(t_wave_callback* cb)
{ {
my_callback_is_output_enabled = cb;
my_callback_is_output_enabled = cb;
} }


// wave_test_get_write_buffer // wave_test_get_write_buffer
// //
void *wave_test_get_write_buffer() void *wave_test_get_write_buffer()
{ {
return NULL;
return NULL;
} }


// wave_get_read_position // wave_get_read_position
// //
uint32_t wave_get_read_position(void* theHandler) uint32_t wave_get_read_position(void* theHandler)
{ {
audio_info_t ainfo;
ENTER("wave_get_read_position");
ioctl((int) theHandler, AUDIO_GETINFO, &ainfo);
SHOW("wave_get_read_position: %d\n", ainfo.play.samples);
SHOW_TIME("wave_get_read_position > LEAVE");
return ainfo.play.samples;
audio_info_t ainfo;
ENTER("wave_get_read_position");
ioctl((int) theHandler, AUDIO_GETINFO, &ainfo);
SHOW("wave_get_read_position: %d\n", ainfo.play.samples);
SHOW_TIME("wave_get_read_position > LEAVE");
return ainfo.play.samples;
} }


// wave_get_write_position // wave_get_write_position
// //
uint32_t wave_get_write_position(void* theHandler) uint32_t wave_get_write_position(void* theHandler)
{ {
ENTER("wave_get_write_position");
SHOW("wave_get_write_position: %d\n", total_samples_sent);
SHOW_TIME("wave_get_write_position > LEAVE");
return total_samples_sent;
ENTER("wave_get_write_position");
SHOW("wave_get_write_position: %d\n", total_samples_sent);
SHOW_TIME("wave_get_write_position > LEAVE");
return total_samples_sent;
} }


// wave_get_remaining_time // wave_get_remaining_time
// //
int wave_get_remaining_time(uint32_t sample, uint32_t* time) int wave_get_remaining_time(uint32_t sample, uint32_t* time)
{ {
uint32_t a_time=0;
uint32_t actual_index;
audio_info_t ainfo;
ENTER("wave_get_remaining_time");
if (!time) {
return(-1);
SHOW_TIME("wave_get_remaining_time > LEAVE");
}
ioctl(sun_audio_fd, AUDIO_GETINFO, &ainfo);
// See if this sample has already been played or is currently
// playing.
//
actual_index = sample - total_samples_skipped;
if ((sample < total_samples_skipped) ||
(actual_index <= ainfo.play.samples)) {
*time = 0;
} else {
a_time = ((actual_index - ainfo.play.samples) * 1000) / wave_samplerate;
*time = (uint32_t) a_time;
}
SHOW("wave_get_remaining_time for %d: %d\n", sample, *time);
SHOW_TIME("wave_get_remaining_time > LEAVE");
return 0;
uint32_t a_time=0;
uint32_t actual_index;
audio_info_t ainfo;
ENTER("wave_get_remaining_time");
if (!time) {
return(-1);
SHOW_TIME("wave_get_remaining_time > LEAVE");
}
ioctl(sun_audio_fd, AUDIO_GETINFO, &ainfo);
// See if this sample has already been played or is currently
// playing.
//
actual_index = sample - total_samples_skipped;
if ((sample < total_samples_skipped) ||
(actual_index <= ainfo.play.samples)) {
*time = 0;
} else {
a_time = ((actual_index - ainfo.play.samples) * 1000) / wave_samplerate;
*time = (uint32_t) a_time;
}
SHOW("wave_get_remaining_time for %d: %d\n", sample, *time);
SHOW_TIME("wave_get_remaining_time > LEAVE");
return 0;
} }


#else #else


init wave_init() {return 1;}
void* wave_open(const char* the_api) {return (void *)1;}
size_t wave_write(void* theHandler, char* theMono16BitsWaveBuffer, size_t theSize) {return theSize;}
int wave_close(void* theHandler) {return 0;}
int wave_is_busy(void* theHandler) {return 0;}
void wave_terminate() {}
uint32_t wave_get_read_position(void* theHandler) {return 0;}
uint32_t wave_get_write_position(void* theHandler) {return 0;}
void wave_flush(void* theHandler) {}
init wave_init() {
return 1;
}
void* wave_open(const char* the_api) {
return (void *)1;
}
size_t wave_write(void* theHandler, char* theMono16BitsWaveBuffer, size_t theSize) {
return theSize;
}
int wave_close(void* theHandler) {
return 0;
}
int wave_is_busy(void* theHandler) {
return 0;
}
void wave_terminate() {
}
uint32_t wave_get_read_position(void* theHandler) {
return 0;
}
uint32_t wave_get_write_position(void* theHandler) {
return 0;
}
void wave_flush(void* theHandler) {
}
typedef int (t_wave_callback)(void); typedef int (t_wave_callback)(void);
void wave_set_callback_is_output_enabled(t_wave_callback* cb) {}
extern void* wave_test_get_write_buffer() {return NULL;}
void wave_set_callback_is_output_enabled(t_wave_callback* cb) {
}
extern void* wave_test_get_write_buffer() {
return NULL;
}


int wave_get_remaining_time(uint32_t sample, uint32_t* time) int wave_get_remaining_time(uint32_t sample, uint32_t* time)
{ {


void clock_gettime2(struct timespec *ts) void clock_gettime2(struct timespec *ts)
{ {
struct timeval tv;
struct timeval tv;


if (!ts)
{
return;
}
if (!ts)
{
return;
}


assert (gettimeofday(&tv, NULL) != -1);
ts->tv_sec = tv.tv_sec;
ts->tv_nsec = tv.tv_usec*1000;
assert (gettimeofday(&tv, NULL) != -1);
ts->tv_sec = tv.tv_sec;
ts->tv_nsec = tv.tv_usec*1000;
} }


void add_time_in_ms(struct timespec *ts, int time_in_ms) void add_time_in_ms(struct timespec *ts, int time_in_ms)
{ {
if (!ts)
{
return;
}
uint64_t t_ns = (uint64_t)ts->tv_nsec + 1000000 * (uint64_t)time_in_ms;
while(t_ns >= ONE_BILLION)
{
SHOW("event > add_time_in_ms ns: %d sec %Lu nsec \n", ts->tv_sec, t_ns);
ts->tv_sec += 1;
t_ns -= ONE_BILLION;
}
ts->tv_nsec = (long int)t_ns;
if (!ts)
{
return;
}
uint64_t t_ns = (uint64_t)ts->tv_nsec + 1000000 * (uint64_t)time_in_ms;
while(t_ns >= ONE_BILLION)
{
SHOW("event > add_time_in_ms ns: %d sec %Lu nsec \n", ts->tv_sec, t_ns);
ts->tv_sec += 1;
t_ns -= ONE_BILLION;
}
ts->tv_nsec = (long int)t_ns;
} }


#endif // USE_ASYNC #endif // USE_ASYNC

+ 171
- 165
src/libespeak-ng/wavegen.c View File

#define N_FLUTTER 0x170 #define N_FLUTTER 0x170
static int Flutter_inc; static int Flutter_inc;
static const unsigned char Flutter_tab[N_FLUTTER] = { static const unsigned char Flutter_tab[N_FLUTTER] = {
0x80, 0x9b, 0xb5, 0xcb, 0xdc, 0xe8, 0xed, 0xec,
0xe6, 0xdc, 0xce, 0xbf, 0xb0, 0xa3, 0x98, 0x90,
0x8c, 0x8b, 0x8c, 0x8f, 0x92, 0x94, 0x95, 0x92,
0x8c, 0x83, 0x78, 0x69, 0x59, 0x49, 0x3c, 0x31,
0x2a, 0x29, 0x2d, 0x36, 0x44, 0x56, 0x69, 0x7d,
0x8f, 0x9f, 0xaa, 0xb1, 0xb2, 0xad, 0xa4, 0x96,
0x87, 0x78, 0x69, 0x5c, 0x53, 0x4f, 0x4f, 0x55,
0x5e, 0x6b, 0x7a, 0x88, 0x96, 0xa2, 0xab, 0xb0,
0xb1, 0xae, 0xa8, 0xa0, 0x98, 0x91, 0x8b, 0x88,
0x89, 0x8d, 0x94, 0x9d, 0xa8, 0xb2, 0xbb, 0xc0,
0xc1, 0xbd, 0xb4, 0xa5, 0x92, 0x7c, 0x63, 0x4a,
0x32, 0x1e, 0x0e, 0x05, 0x02, 0x05, 0x0f, 0x1e,
0x30, 0x44, 0x59, 0x6d, 0x7f, 0x8c, 0x96, 0x9c,
0x9f, 0x9f, 0x9d, 0x9b, 0x99, 0x99, 0x9c, 0xa1,
0xa9, 0xb3, 0xbf, 0xca, 0xd5, 0xdc, 0xe0, 0xde,
0xd8, 0xcc, 0xbb, 0xa6, 0x8f, 0x77, 0x60, 0x4b,
0x3a, 0x2e, 0x28, 0x29, 0x2f, 0x3a, 0x48, 0x59,
0x6a, 0x7a, 0x86, 0x90, 0x94, 0x95, 0x91, 0x89,
0x80, 0x75, 0x6b, 0x62, 0x5c, 0x5a, 0x5c, 0x61,
0x69, 0x74, 0x80, 0x8a, 0x94, 0x9a, 0x9e, 0x9d,
0x98, 0x90, 0x86, 0x7c, 0x71, 0x68, 0x62, 0x60,
0x63, 0x6b, 0x78, 0x88, 0x9b, 0xaf, 0xc2, 0xd2,
0xdf, 0xe6, 0xe7, 0xe2, 0xd7, 0xc6, 0xb2, 0x9c,
0x84, 0x6f, 0x5b, 0x4b, 0x40, 0x39, 0x37, 0x38,
0x3d, 0x43, 0x4a, 0x50, 0x54, 0x56, 0x55, 0x52,
0x4d, 0x48, 0x42, 0x3f, 0x3e, 0x41, 0x49, 0x56,
0x67, 0x7c, 0x93, 0xab, 0xc3, 0xd9, 0xea, 0xf6,
0xfc, 0xfb, 0xf4, 0xe7, 0xd5, 0xc0, 0xaa, 0x94,
0x80, 0x71, 0x64, 0x5d, 0x5a, 0x5c, 0x61, 0x68,
0x70, 0x77, 0x7d, 0x7f, 0x7f, 0x7b, 0x74, 0x6b,
0x61, 0x57, 0x4e, 0x48, 0x46, 0x48, 0x4e, 0x59,
0x66, 0x75, 0x84, 0x93, 0x9f, 0xa7, 0xab, 0xaa,
0xa4, 0x99, 0x8b, 0x7b, 0x6a, 0x5b, 0x4e, 0x46,
0x43, 0x45, 0x4d, 0x5a, 0x6b, 0x7f, 0x92, 0xa6,
0xb8, 0xc5, 0xcf, 0xd3, 0xd2, 0xcd, 0xc4, 0xb9,
0xad, 0xa1, 0x96, 0x8e, 0x89, 0x87, 0x87, 0x8a,
0x8d, 0x91, 0x92, 0x91, 0x8c, 0x84, 0x78, 0x68,
0x55, 0x41, 0x2e, 0x1c, 0x0e, 0x05, 0x01, 0x05,
0x0f, 0x1f, 0x34, 0x4d, 0x68, 0x81, 0x9a, 0xb0,
0xc1, 0xcd, 0xd3, 0xd3, 0xd0, 0xc8, 0xbf, 0xb5,
0xab, 0xa4, 0x9f, 0x9c, 0x9d, 0xa0, 0xa5, 0xaa,
0xae, 0xb1, 0xb0, 0xab, 0xa3, 0x96, 0x87, 0x76,
0x63, 0x51, 0x42, 0x36, 0x2f, 0x2d, 0x31, 0x3a,
0x48, 0x59, 0x6b, 0x7e, 0x8e, 0x9c, 0xa6, 0xaa,
0xa9, 0xa3, 0x98, 0x8a, 0x7b, 0x6c, 0x5d, 0x52,
0x4a, 0x48, 0x4a, 0x50, 0x5a, 0x67, 0x75, 0x82
0x80, 0x9b, 0xb5, 0xcb, 0xdc, 0xe8, 0xed, 0xec,
0xe6, 0xdc, 0xce, 0xbf, 0xb0, 0xa3, 0x98, 0x90,
0x8c, 0x8b, 0x8c, 0x8f, 0x92, 0x94, 0x95, 0x92,
0x8c, 0x83, 0x78, 0x69, 0x59, 0x49, 0x3c, 0x31,
0x2a, 0x29, 0x2d, 0x36, 0x44, 0x56, 0x69, 0x7d,
0x8f, 0x9f, 0xaa, 0xb1, 0xb2, 0xad, 0xa4, 0x96,
0x87, 0x78, 0x69, 0x5c, 0x53, 0x4f, 0x4f, 0x55,
0x5e, 0x6b, 0x7a, 0x88, 0x96, 0xa2, 0xab, 0xb0,
0xb1, 0xae, 0xa8, 0xa0, 0x98, 0x91, 0x8b, 0x88,
0x89, 0x8d, 0x94, 0x9d, 0xa8, 0xb2, 0xbb, 0xc0,
0xc1, 0xbd, 0xb4, 0xa5, 0x92, 0x7c, 0x63, 0x4a,
0x32, 0x1e, 0x0e, 0x05, 0x02, 0x05, 0x0f, 0x1e,
0x30, 0x44, 0x59, 0x6d, 0x7f, 0x8c, 0x96, 0x9c,
0x9f, 0x9f, 0x9d, 0x9b, 0x99, 0x99, 0x9c, 0xa1,
0xa9, 0xb3, 0xbf, 0xca, 0xd5, 0xdc, 0xe0, 0xde,
0xd8, 0xcc, 0xbb, 0xa6, 0x8f, 0x77, 0x60, 0x4b,
0x3a, 0x2e, 0x28, 0x29, 0x2f, 0x3a, 0x48, 0x59,
0x6a, 0x7a, 0x86, 0x90, 0x94, 0x95, 0x91, 0x89,
0x80, 0x75, 0x6b, 0x62, 0x5c, 0x5a, 0x5c, 0x61,
0x69, 0x74, 0x80, 0x8a, 0x94, 0x9a, 0x9e, 0x9d,
0x98, 0x90, 0x86, 0x7c, 0x71, 0x68, 0x62, 0x60,
0x63, 0x6b, 0x78, 0x88, 0x9b, 0xaf, 0xc2, 0xd2,
0xdf, 0xe6, 0xe7, 0xe2, 0xd7, 0xc6, 0xb2, 0x9c,
0x84, 0x6f, 0x5b, 0x4b, 0x40, 0x39, 0x37, 0x38,
0x3d, 0x43, 0x4a, 0x50, 0x54, 0x56, 0x55, 0x52,
0x4d, 0x48, 0x42, 0x3f, 0x3e, 0x41, 0x49, 0x56,
0x67, 0x7c, 0x93, 0xab, 0xc3, 0xd9, 0xea, 0xf6,
0xfc, 0xfb, 0xf4, 0xe7, 0xd5, 0xc0, 0xaa, 0x94,
0x80, 0x71, 0x64, 0x5d, 0x5a, 0x5c, 0x61, 0x68,
0x70, 0x77, 0x7d, 0x7f, 0x7f, 0x7b, 0x74, 0x6b,
0x61, 0x57, 0x4e, 0x48, 0x46, 0x48, 0x4e, 0x59,
0x66, 0x75, 0x84, 0x93, 0x9f, 0xa7, 0xab, 0xaa,
0xa4, 0x99, 0x8b, 0x7b, 0x6a, 0x5b, 0x4e, 0x46,
0x43, 0x45, 0x4d, 0x5a, 0x6b, 0x7f, 0x92, 0xa6,
0xb8, 0xc5, 0xcf, 0xd3, 0xd2, 0xcd, 0xc4, 0xb9,
0xad, 0xa1, 0x96, 0x8e, 0x89, 0x87, 0x87, 0x8a,
0x8d, 0x91, 0x92, 0x91, 0x8c, 0x84, 0x78, 0x68,
0x55, 0x41, 0x2e, 0x1c, 0x0e, 0x05, 0x01, 0x05,
0x0f, 0x1f, 0x34, 0x4d, 0x68, 0x81, 0x9a, 0xb0,
0xc1, 0xcd, 0xd3, 0xd3, 0xd0, 0xc8, 0xbf, 0xb5,
0xab, 0xa4, 0x9f, 0x9c, 0x9d, 0xa0, 0xa5, 0xaa,
0xae, 0xb1, 0xb0, 0xab, 0xa3, 0x96, 0x87, 0x76,
0x63, 0x51, 0x42, 0x36, 0x2f, 0x2d, 0x31, 0x3a,
0x48, 0x59, 0x6b, 0x7e, 0x8e, 0x9c, 0xa6, 0xaa,
0xa9, 0xa3, 0x98, 0x8a, 0x7b, 0x6c, 0x5d, 0x52,
0x4a, 0x48, 0x4a, 0x50, 0x5a, 0x67, 0x75, 0x82
}; };


// waveform shape table for HF peaks, formants 6,7,8 // waveform shape table for HF peaks, formants 6,7,8
// the presets are for 22050 Hz sample rate. // the presets are for 22050 Hz sample rate.
// A different rate will need to recalculate the presets in WavegenInit() // A different rate will need to recalculate the presets in WavegenInit()
static unsigned char wavemult[N_WAVEMULT] = { static unsigned char wavemult[N_WAVEMULT] = {
0, 0, 0, 2, 3, 5, 8, 11, 14, 18, 22, 27, 32, 37, 43, 49,
55, 62, 69, 76, 83, 90, 98,105,113,121,128,136,144,152,159,166,
174,181,188,194,201,207,213,218,224,228,233,237,240,244,246,249,
251,252,253,253,253,253,252,251,249,246,244,240,237,233,228,224,
218,213,207,201,194,188,181,174,166,159,152,144,136,128,121,113,
105, 98, 90, 83, 76, 69, 62, 55, 49, 43, 37, 32, 27, 22, 18, 14,
11, 8, 5, 3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
0, 0, 0, 2, 3, 5, 8, 11, 14, 18, 22, 27, 32, 37, 43, 49,
55, 62, 69, 76, 83, 90, 98,105,113,121,128,136,144,152,159,166,
174,181,188,194,201,207,213,218,224,228,233,237,240,244,246,249,
251,252,253,253,253,253,252,251,249,246,244,240,237,233,228,224,
218,213,207,201,194,188,181,174,166,159,152,144,136,128,121,113,
105, 98, 90, 83, 76, 69, 62, 55, 49, 43, 37, 32, 27, 22, 18, 14,
11, 8, 5, 3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};




// set from y = pow(2,x) * 128, x=-1 to 1 // set from y = pow(2,x) * 128, x=-1 to 1
unsigned char pitch_adjust_tab[MAX_PITCH_VALUE+1] = { unsigned char pitch_adjust_tab[MAX_PITCH_VALUE+1] = {
64, 65, 66, 67, 68, 69, 70, 71,
72, 73, 74, 75, 76, 77, 78, 79,
80, 81, 82, 83, 84, 86, 87, 88,
89, 91, 92, 93, 94, 96, 97, 98,
100,101,103,104,105,107,108,110,
111,113,115,116,118,119,121,123,
124,126,128,130,132,133,135,137,
139,141,143,145,147,149,151,153,
155,158,160,162,164,167,169,171,
174,176,179,181,184,186,189,191,
194,197,199,202,205,208,211,214,
217,220,223,226,229,232,236,239,
242,246,249,252, 254,255 };
64, 65, 66, 67, 68, 69, 70, 71,
72, 73, 74, 75, 76, 77, 78, 79,
80, 81, 82, 83, 84, 86, 87, 88,
89, 91, 92, 93, 94, 96, 97, 98,
100,101,103,104,105,107,108,110,
111,113,115,116,118,119,121,123,
124,126,128,130,132,133,135,137,
139,141,143,145,147,149,151,153,
155,158,160,162,164,167,169,171,
174,176,179,181,184,186,189,191,
194,197,199,202,205,208,211,214,
217,220,223,226,229,232,236,239,
242,246,249,252, 254,255
};




#ifdef LOG_FRAMES #ifdef LOG_FRAMES


int WcmdqUsed() int WcmdqUsed()
{ {
return(N_WCMDQ - WcmdqFree());
return(N_WCMDQ - WcmdqFree());
} }




#define PEAKSHAPEW 256 #define PEAKSHAPEW 256
static const float pk_shape_x[2][8] = { static const float pk_shape_x[2][8] = {
{0,-0.6f, 0.0f, 0.6f, 1.4f, 2.5f, 4.5f, 5.5f}, {0,-0.6f, 0.0f, 0.6f, 1.4f, 2.5f, 4.5f, 5.5f},
{0,-0.6f, 0.0f, 0.6f, 1.4f, 2.0f, 4.5f, 5.5f }};
{0,-0.6f, 0.0f, 0.6f, 1.4f, 2.0f, 4.5f, 5.5f }
};
static const float pk_shape_y[2][8] = { static const float pk_shape_y[2][8] = {
{0, 67, 81, 67, 31, 14, 0, -6} ,
{0, 77, 81, 77, 31, 7, 0, -6 }};
{0, 67, 81, 67, 31, 14, 0, -6},
{0, 77, 81, 77, 31, 7, 0, -6 }
};


unsigned char pk_shape1[PEAKSHAPEW+1] = { unsigned char pk_shape1[PEAKSHAPEW+1] = {
255,254,254,254,254,254,253,253,252,251,251,250,249,248,247,246,
245,244,242,241,239,238,236,234,233,231,229,227,225,223,220,218,
216,213,211,209,207,205,203,201,199,197,195,193,191,189,187,185,
183,180,178,176,173,171,169,166,164,161,159,156,154,151,148,146,
143,140,138,135,132,129,126,123,120,118,115,112,108,105,102, 99,
96, 95, 93, 91, 90, 88, 86, 85, 83, 82, 80, 79, 77, 76, 74, 73,
72, 70, 69, 68, 67, 66, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55,
55, 54, 53, 52, 52, 51, 50, 50, 49, 48, 48, 47, 47, 46, 46, 46,
45, 45, 45, 44, 44, 44, 44, 44, 44, 44, 43, 43, 43, 43, 44, 43,
42, 42, 41, 40, 40, 39, 38, 38, 37, 36, 36, 35, 35, 34, 33, 33,
32, 32, 31, 30, 30, 29, 29, 28, 28, 27, 26, 26, 25, 25, 24, 24,
23, 23, 22, 22, 21, 21, 20, 20, 19, 19, 18, 18, 18, 17, 17, 16,
16, 15, 15, 15, 14, 14, 13, 13, 13, 12, 12, 11, 11, 11, 10, 10,
10, 9, 9, 9, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 5, 5,
5, 5, 4, 4, 4, 4, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2,
2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0 };
255,254,254,254,254,254,253,253,252,251,251,250,249,248,247,246,
245,244,242,241,239,238,236,234,233,231,229,227,225,223,220,218,
216,213,211,209,207,205,203,201,199,197,195,193,191,189,187,185,
183,180,178,176,173,171,169,166,164,161,159,156,154,151,148,146,
143,140,138,135,132,129,126,123,120,118,115,112,108,105,102, 99,
96, 95, 93, 91, 90, 88, 86, 85, 83, 82, 80, 79, 77, 76, 74, 73,
72, 70, 69, 68, 67, 66, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55,
55, 54, 53, 52, 52, 51, 50, 50, 49, 48, 48, 47, 47, 46, 46, 46,
45, 45, 45, 44, 44, 44, 44, 44, 44, 44, 43, 43, 43, 43, 44, 43,
42, 42, 41, 40, 40, 39, 38, 38, 37, 36, 36, 35, 35, 34, 33, 33,
32, 32, 31, 30, 30, 29, 29, 28, 28, 27, 26, 26, 25, 25, 24, 24,
23, 23, 22, 22, 21, 21, 20, 20, 19, 19, 18, 18, 18, 17, 17, 16,
16, 15, 15, 15, 14, 14, 13, 13, 13, 12, 12, 11, 11, 11, 10, 10,
10, 9, 9, 9, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 5, 5,
5, 5, 4, 4, 4, 4, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2,
2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0
};


static unsigned char pk_shape2[PEAKSHAPEW+1] = { static unsigned char pk_shape2[PEAKSHAPEW+1] = {
255,254,254,254,254,254,254,254,254,254,253,253,253,253,252,252,
252,251,251,251,250,250,249,249,248,248,247,247,246,245,245,244,
243,243,242,241,239,237,235,233,231,229,227,225,223,221,218,216,
213,211,208,205,203,200,197,194,191,187,184,181,178,174,171,167,
163,160,156,152,148,144,140,136,132,127,123,119,114,110,105,100,
96, 94, 91, 88, 86, 83, 81, 78, 76, 74, 71, 69, 66, 64, 62, 60,
57, 55, 53, 51, 49, 47, 44, 42, 40, 38, 36, 34, 32, 30, 29, 27,
25, 23, 21, 19, 18, 16, 14, 12, 11, 9, 7, 6, 4, 3, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0 };
255,254,254,254,254,254,254,254,254,254,253,253,253,253,252,252,
252,251,251,251,250,250,249,249,248,248,247,247,246,245,245,244,
243,243,242,241,239,237,235,233,231,229,227,225,223,221,218,216,
213,211,208,205,203,200,197,194,191,187,184,181,178,174,171,167,
163,160,156,152,148,144,140,136,132,127,123,119,114,110,105,100,
96, 94, 91, 88, 86, 83, 81, 78, 76, 74, 71, 69, 66, 64, 62, 60,
57, 55, 53, 51, 49, 47, 44, 42, 40, 38, 36, 34, 32, 30, 29, 27,
25, 23, 21, 19, 18, 16, 14, 12, 11, 9, 7, 6, 4, 3, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0
};


static unsigned char *pk_shape; static unsigned char *pk_shape;




#if USE_PORTAUDIO == 18 #if USE_PORTAUDIO == 18
static int WaveCallback(void *inputBuffer, void *outputBuffer, static int WaveCallback(void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer, PaTimestamp outTime, void *userData )
unsigned long framesPerBuffer, PaTimestamp outTime, void *userData )
#else #else
static int WaveCallback(const void *inputBuffer, void *outputBuffer, static int WaveCallback(const void *inputBuffer, void *outputBuffer,
long unsigned int framesPerBuffer, const PaStreamCallbackTimeInfo *outTime,
PaStreamCallbackFlags flags, void *userData )
long unsigned int framesPerBuffer, const PaStreamCallbackTimeInfo *outTime,
PaStreamCallbackFlags flags, void *userData )
#endif #endif
{ {
int ix; int ix;
is broken */ is broken */


static PaError Pa_OpenDefaultStream2( PaStream** stream, static PaError Pa_OpenDefaultStream2( PaStream** stream,
int inputChannelCount,
int outputChannelCount,
PaSampleFormat sampleFormat,
double sampleRate,
unsigned long framesPerBuffer,
PaStreamCallback *streamCallback,
void *userData )
int inputChannelCount,
int outputChannelCount,
PaSampleFormat sampleFormat,
double sampleRate,
unsigned long framesPerBuffer,
PaStreamCallback *streamCallback,
void *userData )
{ {
PaError result; PaError result;
PaStreamParameters hostApiOutputParameters; PaStreamParameters hostApiOutputParameters;
defaultLowOutputLatency because it is more important for the default defaultLowOutputLatency because it is more important for the default
stream to work reliably than it is for it to work with the lowest stream to work reliably than it is for it to work with the lowest
latency. latency.
*/
*/
hostApiOutputParameters.suggestedLatency = hostApiOutputParameters.suggestedLatency =
Pa_GetDeviceInfo( hostApiOutputParameters.device )->defaultHighOutputLatency;
Pa_GetDeviceInfo( hostApiOutputParameters.device )->defaultHighOutputLatency;
hostApiOutputParameters.hostApiSpecificStreamInfo = NULL; hostApiOutputParameters.hostApiSpecificStreamInfo = NULL;


result = Pa_OpenStream( result = Pa_OpenStream(
stream, NULL, &hostApiOutputParameters, sampleRate, framesPerBuffer, paNoFlag, streamCallback, userData );
stream, NULL, &hostApiOutputParameters, sampleRate, framesPerBuffer, paNoFlag, streamCallback, userData );


return(result); return(result);
} }


void WavegenInit(int rate, int wavemult_fact) void WavegenInit(int rate, int wavemult_fact)
{ {
int ix;
int ix;
double x; double x;


if(wavemult_fact == 0) if(wavemult_fact == 0)
#endif #endif


#ifdef LOG_FRAMES #ifdef LOG_FRAMES
remove("log-espeakedit");
remove("log-klatt");
remove("log-espeakedit");
remove("log-klatt");
#endif #endif
} }




// control 0=initial call, 1=every 64 cycles // control 0=initial call, 1=every 64 cycles


// pitch and freqs are Hz<<16
// pitch and freqs are Hz<<16


int f; int f;
wavegen_peaks_t *p; wavegen_peaks_t *p;
if(hmax > hmax_samplerate) if(hmax > hmax_samplerate)
hmax = hmax_samplerate; hmax = hmax_samplerate;


for(h=0;h<=hmax;h++)
for(h=0; h<=hmax; h++)
htab[h]=0; htab[h]=0;


h=0; h=0;
} }
} }


{
int y;
int h2;
// increase bass
y = peaks[1].height * 10; // addition as a multiple of 1/256s
h2 = (1000<<16)/pitch; // decrease until 1000Hz
if(h2 > 0)
{ {
x = y/h2;
h = 1;
while(y > 0)
int y;
int h2;
// increase bass
y = peaks[1].height * 10; // addition as a multiple of 1/256s
h2 = (1000<<16)/pitch; // decrease until 1000Hz
if(h2 > 0)
{ {
htab[h++] += y;
y -= x;
x = y/h2;
h = 1;
while(y > 0)
{
htab[h++] += y;
y -= x;
}
} }
} }
}


// find the nearest harmonic for HF peaks where we don't use shape // find the nearest harmonic for HF peaks where we don't use shape
for(; pk<N_PEAKS; pk++) for(; pk<N_PEAKS; pk++)
peaks[ix].right = peaks[ix].left; peaks[ix].right = peaks[ix].left;
} }
} }
for(;ix < 8; ix++)
for(; ix < 8; ix++)
{ {
// formants 6,7,8 don't have a width parameter // formants 6,7,8 don't have a width parameter
if(ix < 7) if(ix < 7)
r->x2 = r->x1; r->x2 = r->x1;
r->x1 = x; r->x1 = x;


return x;
return x;
} }




// continue until the output buffer is full, or // continue until the output buffer is full, or
// the required number of samples have been produced // the required number of samples have been produced


for(;;)
for(;; )
{ {
if((end_wave==0) && (samplecount==nsamples)) if((end_wave==0) && (samplecount==nsamples))
return(0); return(0);
// adjust amplitude to compensate for fewer harmonics at higher pitch // adjust amplitude to compensate for fewer harmonics at higher pitch
amplitude2 = (wdata.amplitude * (wdata.pitch >> 8) * wdata.amplitude_fmt)/(10000 << 3); amplitude2 = (wdata.amplitude * (wdata.pitch >> 8) * wdata.amplitude_fmt)/(10000 << 3);


// switch sign of harmonics above about 900Hz, to reduce max peak amplitude
// switch sign of harmonics above about 900Hz, to reduce max peak amplitude
h_switch_sign = 890 / (wdata.pitch >> 12); h_switch_sign = 890 / (wdata.pitch >> 12);
} }
else else
// length in samples // length in samples


#ifdef LOG_FRAMES #ifdef LOG_FRAMES
if(option_log_frames)
{
f_log=fopen("log-espeakedit","a");
if(f_log != NULL)
if(option_log_frames)
{ {
fprintf(f_log," pitch %3d %3d %3dmS\n",pitch1,pitch2,(length*1000)/samplerate);
fclose(f_log);
f_log=NULL;
f_log=fopen("log-espeakedit","a");
if(f_log != NULL)
{
fprintf(f_log," pitch %3d %3d %3dmS\n",pitch1,pitch2,(length*1000)/samplerate);
fclose(f_log);
f_log=NULL;
}
} }
}
#endif #endif
if((wdata.pitch_env = env)==NULL) if((wdata.pitch_env = env)==NULL)
wdata.pitch_env = env_fall; // default wdata.pitch_env = env_fall; // default
static int glottal_reduce_tab2[4] = {0x90, 0xa0, 0xb0, 0xc0}; // vowel after [?], amp * 1/256 static int glottal_reduce_tab2[4] = {0x90, 0xa0, 0xb0, 0xc0}; // vowel after [?], amp * 1/256


#ifdef LOG_FRAMES #ifdef LOG_FRAMES
if(option_log_frames)
{
f_log=fopen("log-espeakedit","a");
if(f_log != NULL)
if(option_log_frames)
{ {
fprintf(f_log,"%3dmS %3d %3d %4d %4d (%3d %3d %3d %3d) to %3d %3d %4d %4d (%3d %3d %3d %3d)\n",length*1000/samplerate,
fr1->ffreq[0],fr1->ffreq[1],fr1->ffreq[2],fr1->ffreq[3], fr1->fheight[0],fr1->fheight[1],fr1->fheight[2],fr1->fheight[3],
fr2->ffreq[0],fr2->ffreq[1],fr2->ffreq[2],fr2->ffreq[3], fr2->fheight[0],fr2->fheight[1],fr2->fheight[2],fr2->fheight[3] );
f_log=fopen("log-espeakedit","a");
if(f_log != NULL)
{
fprintf(f_log,"%3dmS %3d %3d %4d %4d (%3d %3d %3d %3d) to %3d %3d %4d %4d (%3d %3d %3d %3d)\n",length*1000/samplerate,
fr1->ffreq[0],fr1->ffreq[1],fr1->ffreq[2],fr1->ffreq[3], fr1->fheight[0],fr1->fheight[1],fr1->fheight[2],fr1->fheight[3],
fr2->ffreq[0],fr2->ffreq[1],fr2->ffreq[2],fr2->ffreq[3], fr2->fheight[0],fr2->fheight[1],fr2->fheight[2],fr2->fheight[3] );


fclose(f_log);
f_log=NULL;
fclose(f_log);
f_log=NULL;
}
} }
}
#endif #endif


harm_sqrt_n = 0; harm_sqrt_n = 0;
glottal_reduce = glottal_reduce_tab2[(modn >> 8) & 3]; glottal_reduce = glottal_reduce_tab2[(modn >> 8) & 3];
} }


for(qix=wcmdq_head+1;;qix++)
for(qix=wcmdq_head+1;; qix++)
{ {
if(qix >= N_WCMDQ) qix = 0; if(qix >= N_WCMDQ) qix = 0;
if(qix == wcmdq_tail) break; if(qix == wcmdq_tail) break;
} }
if(sonicGetSpeed(sonicSpeedupStream) != sonicSpeed) if(sonicGetSpeed(sonicSpeedupStream) != sonicSpeed)
{ {
sonicSetSpeed(sonicSpeedupStream, sonicSpeed);
sonicSetSpeed(sonicSpeedupStream, sonicSpeed);
} }


sonicWriteShortToStream(sonicSpeedupStream, outbuf, length_in); sonicWriteShortToStream(sonicSpeedupStream, outbuf, length_in);

+ 103
- 102
src/speak-ng.c View File

int end_of_sentence = 0; int end_of_sentence = 0;


static const char *help_text = static const char *help_text =
"\nspeak-ng [options] [\"<words>\"]\n\n"
"-f <text file> Text file to speak\n"
"--stdin Read text input from stdin instead of a file\n\n"
"If neither -f nor --stdin, then <words> are spoken, or if none then text\n"
"is spoken from stdin, each line separately.\n\n"
"-a <integer>\n"
"\t Amplitude, 0 to 200, default is 100\n"
"-g <integer>\n"
"\t Word gap. Pause between words, units of 10mS at the default speed\n"
"-k <integer>\n"
"\t Indicate capital letters with: 1=sound, 2=the word \"capitals\",\n"
"\t higher values indicate a pitch increase (try -k20).\n"
"-l <integer>\n"
"\t Line length. If not zero (which is the default), consider\n"
"\t lines less than this length as end-of-clause\n"
"-p <integer>\n"
"\t Pitch adjustment, 0 to 99, default is 50\n"
"-s <integer>\n"
"\t Speed in approximate words per minute. The default is 175\n"
"-v <voice name>\n"
"\t Use voice file of this name from espeak-data/voices\n"
"-w <wave file name>\n"
"\t Write speech to this WAV file, rather than speaking it directly\n"
"-b\t Input text encoding, 1=UTF8, 2=8 bit, 4=16 bit \n"
"-m\t Interpret SSML markup, and ignore other < > tags\n"
"-q\t Quiet, don't produce any speech (may be useful with -x)\n"
"-x\t Write phoneme mnemonics to stdout\n"
"-X\t Write phonemes mnemonics and translation trace to stdout\n"
"-z\t No final sentence pause at the end of the text\n"
"--compile=<voice name>\n"
"\t Compile pronunciation rules and dictionary from the current\n"
"\t directory. <voice name> specifies the language\n"
"--ipa Write phonemes to stdout using International Phonetic Alphabet\n"
"--path=\"<path>\"\n"
"\t Specifies the directory containing the espeak-data directory\n"
"--pho Write mbrola phoneme data (.pho) to stdout or to the file in --phonout\n"
"--phonout=\"<filename>\"\n"
"\t Write phoneme output from -x -X --ipa and --pho to this file\n"
"--punct=\"<characters>\"\n"
"\t Speak the names of punctuation characters during speaking. If\n"
"\t =<characters> is omitted, all punctuation is spoken.\n"
"--sep=<character>\n"
"\t Separate phonemes (from -x --ipa) with <character>.\n"
"\t Default is space, z means ZWJN character.\n"
"--split=<minutes>\n"
"\t Starts a new WAV file every <minutes>. Used with -w\n"
"--stdout Write speech output to stdout\n"
"--tie=<character>\n"
"\t Use a tie character within multi-letter phoneme names.\n"
"\t Default is U+361, z means ZWJ character.\n"
"--version Shows version number and date, and location of espeak-data\n"
"--voices=<language>\n"
"\t List the available voices for the specified language.\n"
"\t If <language> is omitted, then list all voices.\n";
"\nspeak-ng [options] [\"<words>\"]\n\n"
"-f <text file> Text file to speak\n"
"--stdin Read text input from stdin instead of a file\n\n"
"If neither -f nor --stdin, then <words> are spoken, or if none then text\n"
"is spoken from stdin, each line separately.\n\n"
"-a <integer>\n"
"\t Amplitude, 0 to 200, default is 100\n"
"-g <integer>\n"
"\t Word gap. Pause between words, units of 10mS at the default speed\n"
"-k <integer>\n"
"\t Indicate capital letters with: 1=sound, 2=the word \"capitals\",\n"
"\t higher values indicate a pitch increase (try -k20).\n"
"-l <integer>\n"
"\t Line length. If not zero (which is the default), consider\n"
"\t lines less than this length as end-of-clause\n"
"-p <integer>\n"
"\t Pitch adjustment, 0 to 99, default is 50\n"
"-s <integer>\n"
"\t Speed in approximate words per minute. The default is 175\n"
"-v <voice name>\n"
"\t Use voice file of this name from espeak-data/voices\n"
"-w <wave file name>\n"
"\t Write speech to this WAV file, rather than speaking it directly\n"
"-b\t Input text encoding, 1=UTF8, 2=8 bit, 4=16 bit \n"
"-m\t Interpret SSML markup, and ignore other < > tags\n"
"-q\t Quiet, don't produce any speech (may be useful with -x)\n"
"-x\t Write phoneme mnemonics to stdout\n"
"-X\t Write phonemes mnemonics and translation trace to stdout\n"
"-z\t No final sentence pause at the end of the text\n"
"--compile=<voice name>\n"
"\t Compile pronunciation rules and dictionary from the current\n"
"\t directory. <voice name> specifies the language\n"
"--ipa Write phonemes to stdout using International Phonetic Alphabet\n"
"--path=\"<path>\"\n"
"\t Specifies the directory containing the espeak-data directory\n"
"--pho Write mbrola phoneme data (.pho) to stdout or to the file in --phonout\n"
"--phonout=\"<filename>\"\n"
"\t Write phoneme output from -x -X --ipa and --pho to this file\n"
"--punct=\"<characters>\"\n"
"\t Speak the names of punctuation characters during speaking. If\n"
"\t =<characters> is omitted, all punctuation is spoken.\n"
"--sep=<character>\n"
"\t Separate phonemes (from -x --ipa) with <character>.\n"
"\t Default is space, z means ZWJN character.\n"
"--split=<minutes>\n"
"\t Starts a new WAV file every <minutes>. Used with -w\n"
"--stdout Write speech output to stdout\n"
"--tie=<character>\n"
"\t Use a tie character within multi-letter phoneme names.\n"
"\t Default is U+361, z means ZWJ character.\n"
"--version Shows version number and date, and location of espeak-data\n"
"--voices=<language>\n"
"\t List the available voices for the specified language.\n"
"\t If <language> is omitted, then list all voices.\n";




void DisplayVoices(FILE *f_out, char *language); void DisplayVoices(FILE *f_out, char *language);
break; break;
} }
fprintf(f_out,"%2d %-12s%s%c %-20s %-13s ", fprintf(f_out,"%2d %-12s%s%c %-20s %-13s ",
p[0],lang_name,age_buf,genders[v->gender],buf,v->identifier);
p[0],lang_name,age_buf,genders[v->gender],buf,v->identifier);
} }
else else
{ {
static unsigned char wave_hdr[44] = { static unsigned char wave_hdr[44] = {
'R','I','F','F',0x24,0xf0,0xff,0x7f,'W','A','V','E','f','m','t',' ', 'R','I','F','F',0x24,0xf0,0xff,0x7f,'W','A','V','E','f','m','t',' ',
0x10,0,0,0,1,0,1,0, 9,0x3d,0,0,0x12,0x7a,0,0, 0x10,0,0,0,1,0,1,0, 9,0x3d,0,0,0x12,0x7a,0,0,
2,0,0x10,0,'d','a','t','a', 0x00,0xf0,0xff,0x7f};
2,0,0x10,0,'d','a','t','a', 0x00,0xf0,0xff,0x7f
};


if(path == NULL) if(path == NULL)
return(2); return(2);


static void CloseWaveFile() static void CloseWaveFile()
{ {
unsigned int pos;
unsigned int pos;


if((f_wave == NULL) || (f_wave == stdout))
return;
if((f_wave == NULL) || (f_wave == stdout))
return;


fflush(f_wave);
pos = ftell(f_wave);
fflush(f_wave);
pos = ftell(f_wave);


fseek(f_wave,4,SEEK_SET); fseek(f_wave,4,SEEK_SET);
Write4Bytes(f_wave,pos - 8); Write4Bytes(f_wave,pos - 8);
Write4Bytes(f_wave,pos - 44); Write4Bytes(f_wave,pos - 44);




fclose(f_wave);
f_wave = NULL;
fclose(f_wave);
f_wave = NULL;


} }


sprintf(path_home,"%s\\espeak-data",buf); sprintf(path_home,"%s\\espeak-data",buf);
#else #else
#ifdef PLATFORM_DOS #ifdef PLATFORM_DOS
strcpy(path_home,PATH_ESPEAK_DATA);
strcpy(path_home,PATH_ESPEAK_DATA);
#else #else
char *env; char *env;
if((env = getenv("ESPEAK_DATA_PATH")) != NULL) if((env = getenv("ESPEAK_DATA_PATH")) != NULL)
{ {
snprintf(path_home,sizeof(path_home),"%s/espeak-data",env); snprintf(path_home,sizeof(path_home),"%s/espeak-data",env);
if(GetFileLength(path_home) == -2) if(GetFileLength(path_home) == -2)
return; // an espeak-data directory exists
return; // an espeak-data directory exists
} }


snprintf(path_home,sizeof(path_home),"%s/espeak-data",getenv("HOME")); snprintf(path_home,sizeof(path_home),"%s/espeak-data",getenv("HOME"));
// to something other than the default "C". Then, not only Latin1 but also the // to something other than the default "C". Then, not only Latin1 but also the
// other characters give the correct results with iswalpha() etc. // other characters give the correct results with iswalpha() etc.
#ifdef PLATFORM_RISCOS #ifdef PLATFORM_RISCOS
setlocale(LC_CTYPE,"ISO8859-1");
setlocale(LC_CTYPE,"ISO8859-1");
#else #else
if(setlocale(LC_CTYPE,"en_US.UTF-8") == NULL) if(setlocale(LC_CTYPE,"en_US.UTF-8") == NULL)
{ {




#ifdef NEED_GETOPT #ifdef NEED_GETOPT
struct option {
char *name;
int has_arg;
int *flag;
int val;
};
int optind;
static int optional_argument;
static const char *arg_opts = "abfgklpsvw"; // which options have arguments
static char *opt_string="";
struct option {
char *name;
int has_arg;
int *flag;
int val;
};
int optind;
static int optional_argument;
static const char *arg_opts = "abfgklpsvw"; // which options have arguments
static char *opt_string="";
#define no_argument 0 #define no_argument 0
#define required_argument 1 #define required_argument 1
#define optional_argument 2 #define optional_argument 2
int main (int argc, char **argv) int main (int argc, char **argv)
{ {
static struct option long_options[] = static struct option long_options[] =
{
{
{"help", no_argument, 0, 'h'}, {"help", no_argument, 0, 'h'},
{"stdin", no_argument, 0, 0x100}, {"stdin", no_argument, 0, 0x100},
{"compile-debug", optional_argument, 0, 0x101}, {"compile-debug", optional_argument, 0, 0x101},
{"sep", optional_argument, 0, 0x10c}, {"sep", optional_argument, 0, 0x10c},
{"tie", optional_argument, 0, 0x10d}, {"tie", optional_argument, 0, 0x10d},
{0, 0, 0, 0} {0, 0, 0, 0}
};
};


static const char *err_load = "Failed to read "; static const char *err_load = "Failed to read ";


break; // -- means don't interpret further - as commands break; // -- means don't interpret further - as commands


opt_string=""; opt_string="";
for(ix=0; ;ix++)
for(ix=0;; ix++)
{ {
if(long_options[ix].name == 0) if(long_options[ix].name == 0)
break; break;
while(true) while(true)
{ {
c = getopt_long (argc, argv, "a:b:f:g:hk:l:p:qs:v:w:xXmz", // NOTE: also change arg_opts to indicate which commands have a numeric value c = getopt_long (argc, argv, "a:b:f:g:hk:l:p:qs:v:w:xXmz", // NOTE: also change arg_opts to indicate which commands have a numeric value
long_options, &option_index);
long_options, &option_index);


/* Detect the end of the options. */ /* Detect the end of the options. */
if (c == -1) if (c == -1)
option_endpause = 0; option_endpause = 0;
break; break;


case 0x100: // --stdin
case 0x100: // --stdin
flag_stdin = 1; flag_stdin = 1;
break; break;


case 0x105: // --stdout
case 0x105: // --stdout
option_waveout = 1; option_waveout = 1;
strcpy(wavefile,"stdout"); strcpy(wavefile,"stdout");
break; break;


case 0x101: // --compile-debug case 0x101: // --compile-debug
case 0x102: // --compile
case 0x102: // --compile
if(optarg2 != NULL) if(optarg2 != NULL)
strncpy0(voicename,optarg2,sizeof(voicename)); strncpy0(voicename,optarg2,sizeof(voicename));
flag_compile = c; flag_compile = c;
break; break;


case 0x103: // --punct
case 0x103: // --punct
option_punctuation = 1; option_punctuation = 1;
if(optarg2 != NULL) if(optarg2 != NULL)
{ {
// deprecated and obsolete // deprecated and obsolete
switch(atoi(optarg2)) switch(atoi(optarg2))
{ {
case 1:
phonemes_separator = '_';
break;
case 2:
phonemes_separator = 0x0361;
phoneme_options |= espeakPHONEMES_TIE;
break;
case 3:
phonemes_separator = 0x200d; // ZWJ
phoneme_options |= espeakPHONEMES_TIE;
break;
case 1:
phonemes_separator = '_';
break;
case 2:
phonemes_separator = 0x0361;
phoneme_options |= espeakPHONEMES_TIE;
break;
case 3:
phonemes_separator = 0x200d; // ZWJ
phoneme_options |= espeakPHONEMES_TIE;
break;
} }
} }
break; break;


init_path(argv[0],data_path); init_path(argv[0],data_path);
printf("speak text-to-speech: %s Data at: %s\n",version_string,path_home); printf("speak text-to-speech: %s Data at: %s\n",version_string,path_home);
exit(0); exit(0);
case 0x10c: // --sep case 0x10c: // --sep
phoneme_options |= espeakPHONEMES_SHOW; phoneme_options |= espeakPHONEMES_SHOW;
if(optarg2 == 0) if(optarg2 == 0)
phonemes_separator = ' '; phonemes_separator = ' ';
else else
utf8_in(&phonemes_separator, optarg2); utf8_in(&phonemes_separator, optarg2);
if(phonemes_separator == 'z')
phonemes_separator = 0x200c; // ZWNJ
if(phonemes_separator == 'z')
phonemes_separator = 0x200c; // ZWNJ
break; break;


case 0x10d: // --tie case 0x10d: // --tie
phonemes_separator = 0x0361; // default: combining-double-inverted-breve phonemes_separator = 0x0361; // default: combining-double-inverted-breve
else else
utf8_in(&phonemes_separator, optarg2); utf8_in(&phonemes_separator, optarg2);
if(phonemes_separator == 'z')
phonemes_separator = 0x200d; // ZWJ
if(phonemes_separator == 'z')
phonemes_separator = 0x200d; // ZWJ
break; break;


default: default:
SpeakNextClause(f_text,p_text,0); SpeakNextClause(f_text,p_text,0);


ix = 1; ix = 1;
for(;;)
for(;; )
{ {
if(WavegenFile() != 0) if(WavegenFile() != 0)
{ {

Loading…
Cancel
Save