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); | ||||
#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); | ||||
} | } |
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); |
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; | ||||
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 |
'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) | ||||
{ | { |
#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); |
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) | ||||
{ | { |
#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); |
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 | |||||
} | } |
#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(); |
/* 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) | ||||
{ | { |
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) |
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 { |
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; | ||||
} | } |
/* | /* | ||||
* 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 | ||||
} | } |
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))) | ||||
{ | { |
// 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; | ||||
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; |
// 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 = ¶m_stack[n_param_stack]; | sp = ¶m_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)) |
// 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)) |
#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 | ||||
} | } |
#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); |
#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++) | ||||
{ | { |
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; |
#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); | ||||
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; | ||||
} | } |
{ | { | ||||
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]; | |||||
} | } | ||||
} | } | ||||
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) |
} 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 |
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); |
// 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 | ||||
{"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; | ||||
} | } |
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 |
#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); |
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) | ||||
{ | { |