Valdis Vitolins 9 years ago
parent
commit
9b99340a5b

+ 5
- 10
src/espeak-ng.c View File

voice_select.gender = 0; voice_select.gender = 0;
voice_select.name = NULL; voice_select.name = NULL;
voices = espeak_ListVoices(&voice_select); voices = espeak_ListVoices(&voice_select);
} else {
} else
voices = espeak_ListVoices(NULL); voices = espeak_ListVoices(NULL);
}


fprintf(f_out, "Pty Language Age/Gender VoiceName File Other Languages\n"); fprintf(f_out, "Pty Language Age/Gender VoiceName File Other Languages\n");


} }
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
fprintf(f_out, "(%s %d)", lang_name, p[0]); fprintf(f_out, "(%s %d)", lang_name, p[0]);
}
count++; count++;
p += len+2; p += len+2;
} }
c = long_options[ix].val; c = long_options[ix].val;
optarg2 = NULL; optarg2 = NULL;


if ((long_options[ix].has_arg != 0) && (p[len] == '=')) {
if ((long_options[ix].has_arg != 0) && (p[len] == '='))
optarg2 = &p[len+1]; optarg2 = &p[len+1];
}
break; break;
} }
} }
break; break;


case 0x108: // --phonout case 0x108: // --phonout
if ((f_phonemes_out = fopen(optarg2, "w")) == NULL) {
if ((f_phonemes_out = fopen(optarg2, "w")) == NULL)
fprintf(stderr, "Can't write to: %s\n", optarg2); fprintf(stderr, "Can't write to: %s\n", optarg2);
}
break; break;


case 0x109: // --pho case 0x109: // --pho
p_text = argv[optind]; p_text = argv[optind];
} else { } else {
f_text = stdin; f_text = stdin;
if (flag_stdin == 0) {
if (flag_stdin == 0)
flag_stdin = 2; flag_stdin = 2;
}
} }
} else { } else {
filesize = GetFileLength(filename); filesize = GetFileLength(filename);

+ 55
- 109
src/libespeak-ng/compiledata.c View File



return; return;


if (compile_phoneme) {
if (compile_phoneme)
fprintf(f_out, "\nPhoneme %s (%d)\n", WordToString(ph->mnemonic), ph->code); fprintf(f_out, "\nPhoneme %s (%d)\n", WordToString(ph->mnemonic), ph->code);
} else {
else
fprintf(f_out, "\nProcedure %s\n", proc_names[n_procs]); fprintf(f_out, "\nProcedure %s\n", proc_names[n_procs]);
}


pc = prog_buf; pc = prog_buf;
while (pc < prog_out) { while (pc < prog_out) {


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);
}
fputc('\n', f_report); fputc('\n', f_report);


fprintf(f_report, "Data file Used by\n"); fprintf(f_report, "Data file Used by\n");
// a procedure, not a phoneme // a procedure, not a phoneme
procedure_num = atoi(WordToString(prev_mnemonic)); procedure_num = atoi(WordToString(prev_mnemonic));
fprintf(f_report, " %s %s", phoneme_tab_list2[prev_table = list[ix]->ph_table].name, proc_names[procedure_num]); fprintf(f_report, " %s %s", phoneme_tab_list2[prev_table = list[ix]->ph_table].name, proc_names[procedure_num]);
} else {
} else
fprintf(f_report, " [%s] %s", WordToString(prev_mnemonic), phoneme_tab_list2[prev_table = list[ix]->ph_table].name); fprintf(f_report, " [%s] %s", WordToString(prev_mnemonic), phoneme_tab_list2[prev_table = list[ix]->ph_table].name);
}
fputc('\n', f_report); fputc('\n', f_report);
} }


return 1; return 1;


ix = strlen(string); ix = strlen(string);
if ((ix == 0) || (ix > 4)) {
if ((ix == 0) || (ix > 4))
error("Bad phoneme name '%s'", string); error("Bad phoneme name '%s'", string);
}
word = StringToWord(string); word = StringToWord(string);


// don't use phoneme number 0, reserved for string terminator // don't use phoneme number 0, reserved for string terminator
if (phoneme_tab2[ix].mnemonic == word) if (phoneme_tab2[ix].mnemonic == word)
return ix; return ix;


if ((use == 0) && (phoneme_tab2[ix].mnemonic == 0)) {
if ((use == 0) && (phoneme_tab2[ix].mnemonic == 0))
use = ix; use = ix;
}
} }


if (use == 0) { if (use == 0) {
if ((c2 = get_char()) == '/') { if ((c2 = get_char()) == '/') {
// comment, ignore to end of line // comment, ignore to end of line
while (!feof(f_in) && ((c = get_char()) != '\n')) ; while (!feof(f_in) && ((c = get_char()) != '\n')) ;
} else {
} else
unget_char(c2); unget_char(c2);
}
} }
if (!isspace(c)) {
if (!isspace(c))
break; break;
}
} }
if (feof(f_in)) if (feof(f_in))
return -2; return -2;
} }
item_string[ix] = 0; item_string[ix] = 0;


while (isspace(c)) {
while (isspace(c))
c = get_char(); c = get_char();
}


item_terminator = ' '; item_terminator = ' ';
if ((c == ')') || (c == '(') || (c == ',')) if ((c == ')') || (c == '(') || (c == ','))
if (!feof(f_in)) if (!feof(f_in))
unget_char(c); unget_char(c);


if (type == tSTRING) {
if (type == tSTRING)
return 0; return 0;
}


if ((type == tNUMBER) || (type == tSIGNEDNUMBER)) { if ((type == tNUMBER) || (type == tSIGNEDNUMBER)) {
acc = 0; acc = 0;
item_type = -1; item_type = -1;
return -1; // keyword not found return -1; // keyword not found
} }
if (type == tPHONEMEMNEM) {
if (type == tPHONEMEMNEM)
return LookupPhoneme(item_string, 2); return LookupPhoneme(item_string, 2);
}
return -1; return -1;
} }


int value; int value;


if ((control & 1) == 0) { if ((control & 1) == 0) {
if (!NextItem(tOPENBRACKET)) {
if (!NextItem(tOPENBRACKET))
error("Expected '('", NULL); error("Expected '('", NULL);
}
} }


value = NextItem(type); value = NextItem(type);
if ((control & 2) && (item_terminator == ',')) if ((control & 2) && (item_terminator == ','))
return value; return value;


if (item_terminator != ')') {
if (item_terminator != ')')
error("Expected ')'", NULL); error("Expected ')'", NULL);
}
return value; return value;


} }
total = 0; total = 0;
for (frame = 0; frame < spectseq->numframes; frame++) { for (frame = 0; frame < spectseq->numframes; frame++) {
if (spectseq->frames[frame]->keyframe) { if (spectseq->frames[frame]->keyframe) {
if (seq_out.n_frames == 1) {
if (seq_out.n_frames == 1)
frame_vowelbreak = frame; frame_vowelbreak = frame;
}
if (spectseq->frames[frame]->markers & 0x2) { if (spectseq->frames[frame]->markers & 0x2) {
// marker 1 is set // marker 1 is set
marker1_set = 1; marker1_set = 1;


if (klatt_flag) { if (klatt_flag) {
// additional klatt parameters // additional klatt parameters
for (ix = 0; ix < 5; ix++) {
for (ix = 0; ix < 5; ix++)
fr_out->klattp2[ix] = fr->klatt_param[ix+5]; fr_out->klattp2[ix] = fr->klatt_param[ix+5];
}


for (peak = 0; peak < 7; peak++) { for (peak = 0; peak < 7; peak++) {
fr_out->klatt_ap[ix] = fr->peaks[peak].klt_ap; fr_out->klatt_ap[ix] = fr->peaks[peak].klt_ap;


#ifdef PLATFORM_POSIX #ifdef PLATFORM_POSIX
strcpy(fname_temp, "/tmp/espeakXXXXXX"); strcpy(fname_temp, "/tmp/espeakXXXXXX");
if ((fd_temp = mkstemp(fname_temp)) >= 0) {
if ((fd_temp = mkstemp(fname_temp)) >= 0)
close(fd_temp); close(fd_temp);
}
#else #else
strcpy(fname_temp, tmpnam(NULL)); strcpy(fname_temp, tmpnam(NULL));
#endif #endif
} }


sprintf(command, "sox \"%s/../phsource/%s.wav\" -r %d -c1 -t wav %s\n", path_home, fname2, samplerate_native, fname_temp); 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) {
if (system(command) != 0)
failed = 1; failed = 1;
}




if (failed || (GetFileLength(fname_temp) <= 0)) { if (failed || (GetFileLength(fname_temp) <= 0)) {
if (sr1 != samplerate_native) { if (sr1 != samplerate_native) {
sprintf(msg, "Can't resample (%d to %d): %s", sr1, samplerate_native, fname); sprintf(msg, "Can't resample (%d to %d): %s", sr1, samplerate_native, fname);
error("%s", msg); error("%s", msg);
} else {
} else
error("WAV file is not mono: %s", fname); error("WAV file is not mono: %s", fname);
}
remove(fname_temp); remove(fname_temp);
return 0; return 0;
} }
displ = ftell(f_phdata); displ = ftell(f_phdata);


fseek(f, 12, SEEK_SET); fseek(f, 12, SEEK_SET);
if (fread(buf, 128, 1, f) == 0) {
if (fread(buf, 128, 1, f) == 0)
error("Failed to read envelope: %s", fname); error("Failed to read envelope: %s", fname);
}
fwrite(buf, 128, 1, f_phdata); fwrite(buf, 128, 1, f_phdata);


if (n_envelopes < N_ENVELOPES) { if (n_envelopes < N_ENVELOPES) {
} }
fclose(f); fclose(f);


if (addr > 0) {
if (addr > 0)
fprintf(f_phcontents, "%c 0x%.5x %s\n", type_code, addr & 0x7fffff, path); fprintf(f_phcontents, "%c 0x%.5x %s\n", type_code, addr & 0x7fffff, path);
}
} }


// add this item to the hash table // add this item to the hash table
key = key << 8; key = key << 8;


data = NextItemBrackets(tPROPERTIES, 0); data = NextItemBrackets(tPROPERTIES, 0);
if (data >= 0) {
if (data >= 0)
word = key + data + 0x700; word = key + data + 0x700;
} else {
else {
data = LookupPhoneme(item_string, 2); data = LookupPhoneme(item_string, 2);
word = key + data; word = key + data;
} }
brackets = 3; brackets = 3;
} while (item_terminator == ','); } while (item_terminator == ',');
word = i_StressLevel | bitmap; word = i_StressLevel | bitmap;
} else {
} else
word = key; word = key;
}
} else { } else {
error("Unexpected keyword '%s'", item_string); error("Unexpected keyword '%s'", item_string);


} }
} }


if (finish != 1) {
}

if (elif == 0) { if (elif == 0) {
if_level++; if_level++;
if_stack[if_level].p_else = NULL; if_stack[if_level].p_else = NULL;
} }
prog_out--; prog_out--;
} else { } else {
if (offset > MAX_JUMP) {
if (offset > MAX_JUMP)
error("IF block is too long", NULL); error("IF block is too long", NULL);
}
*p = i_JUMP_FALSE + offset; *p = i_JUMP_FALSE + offset;
} }
if_stack[if_level].p_then = NULL; if_stack[if_level].p_then = NULL;
return 0; return 0;
} }


if (if_stack[if_level].returned == 0) {
if (if_stack[if_level].returned == 0)
FillThen(1); FillThen(1);
} else {
else
FillThen(0); FillThen(0);
}


if (if_stack[if_level].returned == 0) { if (if_stack[if_level].returned == 0) {
ref = prog_out; ref = prog_out;
*prog_out++ = 0; *prog_out++ = 0;


if ((p = if_stack[if_level].p_else) != NULL) {
if ((p = if_stack[if_level].p_else) != NULL)
*ref = ref - p; // backwards offset to the previous else *ref = ref - p; // backwards offset to the previous else
}
if_stack[if_level].p_else = ref; if_stack[if_level].p_else = ref;
} }


chain = *p; // a chain of previous else links chain = *p; // a chain of previous else links


offset = prog_out - p; offset = prog_out - p;
if (offset > MAX_JUMP) {
if (offset > MAX_JUMP)
error("IF block is too long", NULL); error("IF block is too long", NULL);
}
*p = i_JUMP + offset; *p = i_JUMP + offset;


p -= chain; p -= chain;
int ix; int ix;


for (ix = 0; ix < n_phoneme_tabs; ix++) { for (ix = 0; ix < n_phoneme_tabs; ix++) {
if (strcmp(phoneme_tab_list2[ix].name, string) == 0) {
if (strcmp(phoneme_tab_list2[ix].name, string) == 0)
return &phoneme_tab_list2[ix]; return &phoneme_tab_list2[ix];
}
} }
error("Unknown phoneme table: '%s'", string); error("Unknown phoneme table: '%s'", string);
return NULL; return NULL;
char buf[200]; char buf[200];


// is this the name of a phoneme which is in scope // is this the name of a phoneme which is in scope
if ((strlen(string) <= 4) && ((ix = LookupPhoneme(string, 0)) != -1)) {
if ((strlen(string) <= 4) && ((ix = LookupPhoneme(string, 0)) != -1))
return &phoneme_tab2[ix]; return &phoneme_tab2[ix];
}


// no, treat the name as phonemetable/phoneme // no, treat the name as phonemetable/phoneme
strcpy(buf, string); strcpy(buf, string);
if ((phname = strchr(buf, '/')) != 0) {
if ((phname = strchr(buf, '/')) != 0)
*phname++ = 0; *phname++ = 0;
}


phtab = FindPhonemeTable(buf); phtab = FindPhonemeTable(buf);
if (phtab == NULL) {
if (phtab == NULL)
return NULL; // phoneme table not found return NULL; // phoneme table not found
}


mnem = StringToWord(phname); mnem = StringToWord(phname);
for (ix = 1; ix < 256; ix++) { for (ix = 1; ix < 256; ix++) {
if (mnem == phtab->phoneme_tab_ptr[ix].mnemonic) {
if (mnem == phtab->phoneme_tab_ptr[ix].mnemonic)
return &phtab->phoneme_tab_ptr[ix]; return &phtab->phoneme_tab_ptr[ix];
}
} }


error("Phoneme reference not found: '%s'", string); error("Phoneme reference not found: '%s'", string);


case i_SET_LENGTH: case i_SET_LENGTH:
value = NextItemMax(511); value = NextItemMax(511);
if (phoneme_out->type == phVOWEL) {
if (phoneme_out->type == phVOWEL)
value = (value * vowel_length_factor)/100; value = (value * vowel_length_factor)/100;
}


if (after_if == 0) {
if (after_if == 0)
phoneme_out->std_length = value/2; phoneme_out->std_length = value/2;
} else {
else {
*prog_out++ = (i_SET_LENGTH << 8) + value/2; *prog_out++ = (i_SET_LENGTH << 8) + value/2;
DecThenCount(); DecThenCount();
} }
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;
for (ix = 0; ix < value; ix += 2) {
for (ix = 0; ix < value; ix += 2)
*prog_out++ = (ipa_buf[ix+start] << 8) + (ipa_buf[ix+start+1] & 0xff); *prog_out++ = (ipa_buf[ix+start] << 8) + (ipa_buf[ix+start+1] & 0xff);
}
DecThenCount(); DecThenCount();
break; break;
} }
phcode = NextItem(tPHONEMEMNEM); phcode = NextItem(tPHONEMEMNEM);
if (phcode == -1) if (phcode == -1)
phcode = LookupPhoneme(item_string, 1); phcode = LookupPhoneme(item_string, 1);
if (phoneme_out->type == phVOWEL) {
if (phoneme_out->type == phVOWEL)
phoneme_out->end_type = phcode; phoneme_out->end_type = phcode;
} else {
if (phcode != phoneme_out->start_type) {
error("endtype must equal starttype for consonants", NULL);
}
}
else if (phcode != phoneme_out->start_type)
error("endtype must equal starttype for consonants", NULL);
break; break;


case kVOICINGSWITCH: case kVOICINGSWITCH:
case kENDPHONEME: case kENDPHONEME:
case kENDPROCEDURE: case kENDPROCEDURE:
endphoneme = 1; endphoneme = 1;
if (if_level > 0) {
if (if_level > 0)
error("Missing ENDIF", NULL); error("Missing ENDIF", NULL);
}
if ((prog_out > prog_buf) && (if_stack[0].returned == 0)) {
if ((prog_out > prog_buf) && (if_stack[0].returned == 0))
*prog_out++ = i_RETURN; *prog_out++ = i_RETURN;
}
break; break;
} }


} }
} }


if (endphoneme != 1) {
if (endphoneme != 1)
error("'endphoneme' not expected here", NULL); error("'endphoneme' not expected here", NULL);
}


if (compile_phoneme) { if (compile_phoneme) {
if (phoneme_out->type == phINVALID) { if (phoneme_out->type == phINVALID) {


phoneme_out->phflags |= phLOCAL; // declared in this phoneme table phoneme_out->phflags |= phLOCAL; // declared in this phoneme table


if (phoneme_out->type == phDELETED) {
if (phoneme_out->type == phDELETED)
phoneme_out->mnemonic = 0x01; // will not be recognised phoneme_out->mnemonic = 0x01; // will not be recognised
}
} }


DecompilePhoneme(f_errors, phoneme_out, compile_phoneme); DecompilePhoneme(f_errors, phoneme_out, compile_phoneme);
fwrite(&phoneme_prog_log, 1, sizeof(phoneme_prog_log), f_prog_log); fwrite(&phoneme_prog_log, 1, sizeof(phoneme_prog_log), f_prog_log);
} }


if (compile_phoneme == 0) {
if (compile_phoneme == 0)
proc_addr[n_procs++] = ftell(f_phindex) / sizeof(USHORT); proc_addr[n_procs++] = ftell(f_phindex) / sizeof(USHORT);
}
fwrite(prog_buf, sizeof(USHORT), prog_out - prog_buf, f_phindex); fwrite(prog_buf, sizeof(USHORT), prog_out - prog_buf, f_phindex);
} }


if (ix == n_phoneme_tabs) { if (ix == n_phoneme_tabs) {
error("Can't find base phonemetable '%s'", item_string); error("Can't find base phonemetable '%s'", item_string);
} }
} else {
} else
ReservePhCodes(); ReservePhCodes();
}


n_phoneme_tabs++; n_phoneme_tabs++;
} }
strcpy(foreign_table_name, item_string); strcpy(foreign_table_name, item_string);


if ((foreign_table = SelectPhonemeTableName(foreign_table_name)) < 0) { if ((foreign_table = SelectPhonemeTableName(foreign_table_name)) < 0) {
if (strcmp(foreign_table_name, "NULL") != 0) {
if (strcmp(foreign_table_name, "NULL") != 0)
error("Unknown phoneme table '%s'", foreign_table_name); error("Unknown phoneme table '%s'", foreign_table_name);
}
foreign_error = 1; foreign_error = 1;
foreign_phoneme = 0; foreign_phoneme = 0;
} }
} }
} }


for (ix = 1; ix < n_names; ix++) {
for (ix = 1; ix < n_names; ix++)
phcode[ix] = LookupPhoneme(names[ix], 1); phcode[ix] = LookupPhoneme(names[ix], 1);
}


// only write a translation if it has an effect // only write a translation if it has an effect
if ((n_names > 2) || (phcode[0] != phcode[1])) { if ((n_names > 2) || (phcode[0] != phcode[1])) {
strncpy0(current_fname, item_string, sizeof(current_fname)); strncpy0(current_fname, item_string, sizeof(current_fname));
linenum = 1; linenum = 1;


} else {
} else
error("Missing file: %s", item_string); error("Missing file: %s", item_string);
}
break; break;


case kPHONEMETABLE: case kPHONEMETABLE:
sprintf(fname, "%s/%s", path_home, "phontab"); sprintf(fname, "%s/%s", path_home, "phontab");
f_phtab = fopen_log(f_errors, fname, "wb"); f_phtab = fopen_log(f_errors, fname, "wb");


if (f_phdata == NULL || f_phindex == NULL || f_phtab == NULL) {
if (f_phdata == NULL || f_phindex == NULL || f_phtab == NULL)
return ENE_WRITE_ERROR; return ENE_WRITE_ERROR;
}


sprintf(fname, "%s/../phsource/compile_prog_log", path_home); sprintf(fname, "%s/../phsource/compile_prog_log", path_home);
f_prog_log = fopen_log(f_errors, fname, "wb"); f_prog_log = fopen_log(f_errors, fname, "wb");
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(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(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);
while (isspace(*p)) p++; while (isspace(*p)) p++;


ix = 0; ix = 0;
while ((ix < (int)(sizeof(name) - 1)) && !isspace(*p)) {
while ((ix < (int)(sizeof(name) - 1)) && !isspace(*p))
name[ix++] = *p++; name[ix++] = *p++;
}
name[ix] = 0; name[ix] = 0;


found = 0; found = 0;
switch (keyword) switch (keyword)
{ {
case kTUNE: case kTUNE:
if (compiling_tune) {
}
compiling_tune = 1; compiling_tune = 1;
done_split = 0; done_split = 0;


break; break;
} }
} }
if (found == 2) {
if (found == 2)
error("Duplicate tune name: '%s'", new_tune.name); error("Duplicate tune name: '%s'", new_tune.name);
}
if (found == 0) {
if (found == 0)
error("Bad tune name: '%s;", new_tune.name); error("Bad tune name: '%s;", new_tune.name);
}
break; break;


case kENDTUNE: case kENDTUNE:
} }


for (ix = 0; ix < n_preset_tunes; ix++) { for (ix = 0; ix < n_preset_tunes; ix++) {
if (tune_data[ix].name[0] == 0) {
if (tune_data[ix].name[0] == 0)
error("Tune '%s' not defined", preset_tune_names[ix]); error("Tune '%s' not defined", preset_tune_names[ix]);
}
} }
fwrite(tune_data, n_tune_names, sizeof(TUNE), f_out); fwrite(tune_data, n_tune_names, sizeof(TUNE), f_out);
free(tune_data); free(tune_data);

+ 29
- 51
src/libespeak-ng/compiledict.c View File

match_type = 0; match_type = 0;
buf_pre[0] = 0; buf_pre[0] = 0;


for (ix = 0; ix < group_length; ix++) {
for (ix = 0; ix < group_length; ix++)
buf[ix] = group_chars[ix]; buf[ix] = group_chars[ix];
}
buf[ix] = 0; buf[ix] = 0;


p = &buf[strlen(buf)]; p = &buf[strlen(buf)];
strcpy(p, suffix); strcpy(p, suffix);
p += strlen(suffix); p += strlen(suffix);
c = ' '; c = ' ';
} else if (rb == RULE_LETTERGP) {
} else if (rb == RULE_LETTERGP)
c = symbols_lg[*rule++ - 'A']; c = symbols_lg[*rule++ - 'A'];
} else if (rb == RULE_LETTERGP2) {
else if (rb == RULE_LETTERGP2) {
value = *rule++ - 'A'; value = *rule++ - 'A';
p[0] = 'L'; p[0] = 'L';
p[1] = (value / 10) + '0'; p[1] = (value / 10) + '0';


flagnum = LookupMnem(mnem_flags, mnemptr); flagnum = LookupMnem(mnem_flags, mnemptr);
if (flagnum > 0) { if (flagnum > 0) {
if (flagnum == 200) {
if (flagnum == 200)
text_mode = 1; text_mode = 1;
} else if (flagnum == 201) {
else if (flagnum == 201)
text_mode = 0; text_mode = 0;
} else if (flagnum == BITNUM_FLAG_TEXTMODE) {
else if (flagnum == BITNUM_FLAG_TEXTMODE)
text_not_phonemes = 1; text_not_phonemes = 1;
} else {
else
flag_codes[n_flag_codes++] = flagnum; flag_codes[n_flag_codes++] = flagnum;
}
} else { } else {
fprintf(f_log, "%5d: Unknown keyword: %s\n", linenum, mnemptr); fprintf(f_log, "%5d: Unknown keyword: %s\n", linenum, mnemptr);
error_count++; error_count++;


case 1: case 1:
if ((c == '-') && multiple_words) { if ((c == '-') && multiple_words) {
if (IsDigit09(word[0])) {
if (IsDigit09(word[0]))
multiple_numeric_hyphen = 1; multiple_numeric_hyphen = 1;
}
flag_codes[n_flag_codes++] = BITNUM_FLAG_HYPHENATED; flag_codes[n_flag_codes++] = BITNUM_FLAG_HYPHENATED;
c = ' '; c = ' ';
} }
if (multiple_words) { if (multiple_words) {
multiple_string = multiple_string_end = p+1; multiple_string = multiple_string_end = p+1;
step = 2; step = 2;
} else {
} else
step = 3; step = 3;
}
} else if (c == ')') { } else if (c == ')') {
if (multiple_words) { if (multiple_words) {
p[0] = 0; p[0] = 0;
break; break;


case 2: case 2:
if (isspace2(c)) {
if (isspace2(c))
multiple_words++; multiple_words++;
} else if (c == ')') {
else if (c == ')') {
p[0] = ' '; // terminate extra string p[0] = ' '; // terminate extra string
multiple_string_end = p+1; multiple_string_end = p+1;
step = 3; step = 3;
p++; p++;
} }


if (word[0] == 0) {
if (word[0] == 0)
return 0; /* blank line */ return 0; /* blank line */
}


if (text_mode) if (text_mode)
text_not_phonemes = 1; text_not_phonemes = 1;
error_need_dictionary++; error_need_dictionary++;
fprintf(f_log, "%5d: Need to compile dictionary again\n", linenum); fprintf(f_log, "%5d: Need to compile dictionary again\n", linenum);
} }
} else {
} else
// this is replacement text, so don't encode as phonemes. Restrict the length of the replacement word // this is replacement text, so don't encode as phonemes. Restrict the length of the replacement word
strncpy0(encoded_ph, phonetic, N_WORD_BYTES-4); strncpy0(encoded_ph, phonetic, N_WORD_BYTES-4);
}
} else { } else {
EncodePhonemes(phonetic, encoded_ph, &bad_phoneme); EncodePhonemes(phonetic, encoded_ph, &bad_phoneme);
if (strchr(encoded_ph, phonSWITCH) != 0) {
if (strchr(encoded_ph, phonSWITCH) != 0)
flag_codes[n_flag_codes++] = BITNUM_FLAG_ONLY_S; // don't match on suffixes (except 's') when switching languages flag_codes[n_flag_codes++] = BITNUM_FLAG_ONLY_S; // don't match on suffixes (except 's') when switching languages
}


// check for errors in the phonemes codes // check for errors in the phonemes codes
if (bad_phoneme != 0) { if (bad_phoneme != 0) {
} }
} }


if (text_not_phonemes != translator->langopts.textmode) {
if (text_not_phonemes != translator->langopts.textmode)
flag_codes[n_flag_codes++] = BITNUM_FLAG_TEXTMODE; flag_codes[n_flag_codes++] = BITNUM_FLAG_TEXTMODE;
}




if (sscanf(word, "U+%x", &wc) == 1) { if (sscanf(word, "U+%x", &wc) == 1) {
ix = utf8_in(&c2, p); ix = utf8_in(&c2, p);
if (c2 == 0) if (c2 == 0)
break; break;
if (iswupper2(c2)) {
if (iswupper2(c2))
utf8_out(towlower2(c2), p); utf8_out(towlower2(c2), p);
} else {
else
all_upper_case = 0; all_upper_case = 0;
}
p += ix; p += ix;
} }
if (all_upper_case) {
if (all_upper_case)
flag_codes[n_flag_codes++] = BITNUM_FLAG_ALLCAPS; flag_codes[n_flag_codes++] = BITNUM_FLAG_ALLCAPS;
}
} }


len_word = strlen(word); len_word = strlen(word);


if (translator->transpose_min > 0) {
if (translator->transpose_min > 0)
len_word = TransposeAlphabet(translator, word); len_word = TransposeAlphabet(translator, word);
}


*hash = HashDictionary(word); *hash = HashDictionary(word);
len_phonetic = strlen(encoded_ph); len_phonetic = strlen(encoded_ph);
strcpy(&dict_line[(len_word)+2], encoded_ph); strcpy(&dict_line[(len_word)+2], encoded_ph);
} }


for (ix = 0; ix < n_flag_codes; ix++) {
for (ix = 0; ix < n_flag_codes; ix++)
dict_line[ix+length] = flag_codes[ix]; dict_line[ix+length] = flag_codes[ix];
}
length += n_flag_codes; length += n_flag_codes;


if ((multiple_string != NULL) && (multiple_words > 0)) { if ((multiple_string != NULL) && (multiple_words > 0)) {
} else { } else {
dict_line[length++] = 80 + multiple_words; dict_line[length++] = 80 + multiple_words;
ix = multiple_string_end - multiple_string; ix = multiple_string_end - multiple_string;
if (multiple_numeric_hyphen) {
if (multiple_numeric_hyphen)
dict_line[length++] = ' '; // ??? dict_line[length++] = ' '; // ???
}
memcpy(&dict_line[length], multiple_string, ix); memcpy(&dict_line[length], multiple_string, ix);
length += ix; length += ix;
} }
c = c2 * 16 + c3; c = c2 * 16 + c3;
literal = 1; literal = 1;
p++; p++;
} else {
} else
hexdigit_input = 0; hexdigit_input = 0;
}
} }
if ((state == 1) || (state == 3)) { if ((state == 1) || (state == 3)) {
// replace special characters (note: 'E' is reserved for a replaced silent 'e') // replace special characters (note: 'E' is reserved for a replaced silent 'e')
// pre-rule, put the group number before the RULE_LETTERGP command // pre-rule, put the group number before the RULE_LETTERGP command
output[ix++] = c; output[ix++] = c;
c = RULE_LETTERGP2; c = RULE_LETTERGP2;
} else {
} else
output[ix++] = RULE_LETTERGP2; output[ix++] = RULE_LETTERGP2;
}
break; break;


case '$': case '$':
// omit '_' at the beginning of the pre-string and imply it by using RULE_PRE_ATSTART // omit '_' at the beginning of the pre-string and imply it by using RULE_PRE_ATSTART
c = RULE_PRE_ATSTART; c = RULE_PRE_ATSTART;
start = 1; start = 1;
} else {
} else
c = RULE_PRE; c = RULE_PRE;
}
output[len++] = c; output[len++] = c;


// output PRE string in reverse order // output PRE string in reverse order
// group character is given as a character code (max 16 bits) // group character is given as a character code (max 16 bits)
p = (unsigned char *)group_name; p = (unsigned char *)group_name;


if (char_code > 0x100) {
if (char_code > 0x100)
*p++ = (char_code >> 8); *p++ = (char_code >> 8);
}
*p++ = char_code; *p++ = char_code;
*p = 0; *p = 0;
} else { } else {
if (translator->letter_bits_offset > 0) { if (translator->letter_bits_offset > 0) {
utf8_in(&wc, group_name); utf8_in(&wc, group_name);
if (((ix = (wc - translator->letter_bits_offset)) >= 0) && (ix < 128)) {
if (((ix = (wc - translator->letter_bits_offset)) >= 0) && (ix < 128))
group3_ix = ix+1; // not zero group3_ix = ix+1; // not zero
}
} }
} }


case 1: // .group case 1: // .group
prule = compile_rule(buf); prule = compile_rule(buf);
if (prule != NULL) { if (prule != NULL) {
if (n_rules < N_RULES) {
if (n_rules < N_RULES)
rules[n_rules++] = prule; rules[n_rules++] = prule;
} else {
else {
if (err_n_rules == 0) { if (err_n_rules == 0) {
fprintf(stderr, "\nExceeded limit of rules (%d) in group '%s'\n", N_RULES, group_name); fprintf(stderr, "\nExceeded limit of rules (%d) in group '%s'\n", N_RULES, group_name);
error_count++; error_count++;
n_groups3++; n_groups3++;
fputc(1, f_out); fputc(1, f_out);
fputc(rgroup[gp].group3_ix, f_out); fputc(rgroup[gp].group3_ix, f_out);
} else {
} else
fprintf(f_out, "%s", prev_rgroup_name = rgroup[gp].name); fprintf(f_out, "%s", prev_rgroup_name = rgroup[gp].name);
}
fputc(0, f_out); fputc(0, f_out);
} }


c = fgetc(f_temp); c = fgetc(f_temp);
fputc(c, f_out); fputc(c, f_out);
} }

if (different) {
}
} }
fputc(RULE_GROUP_END, f_out); fputc(RULE_GROUP_END, f_out);
fputc(0, f_out); fputc(0, f_out);

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

Write4Bytes(f_out, mbrola_ctrl); Write4Bytes(f_out, mbrola_ctrl);


pw_end = (int *)(&data[count+1]); pw_end = (int *)(&data[count+1]);
for (pw = (int *)data; pw < pw_end; pw++) {
for (pw = (int *)data; pw < pw_end; pw++)
Write4Bytes(f_out, *pw); Write4Bytes(f_out, *pw);
}
fclose(f_out); fclose(f_out);
fprintf(log, "Mbrola translation file: %s -- %d phonemes\n", buf, count); fprintf(log, "Mbrola translation file: %s -- %d phonemes\n", buf, count);
return ENS_OK; return ENS_OK;

+ 6
- 12
src/libespeak-ng/debug.c View File



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


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


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




{ {
va_list args; va_list args;
va_start(args, format); va_start(args, format);
if (!fd_log) {
if (!fd_log)
debug_init(); debug_init();
}
if (fd_log) {
if (fd_log)
vfprintf(fd_log, format, args); vfprintf(fd_log, format, args);
}
va_end(args); va_end(args);
} }




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


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


#endif #endif

+ 72
- 123
src/libespeak-ng/dictionary.c View File

if (p[0] == RULE_REPLACEMENTS) { if (p[0] == RULE_REPLACEMENTS) {
pw = (unsigned int *)(((intptr_t)p+4) & ~3); // advance to next word boundary pw = (unsigned int *)(((intptr_t)p+4) & ~3); // advance to next word boundary
tr->langopts.replace_chars = pw; tr->langopts.replace_chars = pw;
while (pw[0] != 0) {
while (pw[0] != 0)
pw += 2; // find the end of the replacement list, each entry is 2 words. pw += 2; // find the end of the replacement list, each entry is 2 words.
}
p = (char *)(pw+1); p = (char *)(pw+1);


#ifdef ARCH_BIG #ifdef ARCH_BIG
if (p[0] == RULE_LETTERGP2) { if (p[0] == RULE_LETTERGP2) {
ix = p[1] - 'A'; ix = p[1] - 'A';
p += 2; p += 2;
if ((ix >= 0) && (ix < N_LETTER_GROUPS)) {
if ((ix >= 0) && (ix < N_LETTER_GROUPS))
tr->letterGroups[ix] = p; tr->letterGroups[ix] = p;
}
} else { } else {
len = strlen(p); len = strlen(p);
p_name = p; p_name = p;
c2 = p_name[1]; c2 = p_name[1];


p += (len+1); p += (len+1);
if (len == 1) {
if (len == 1)
tr->groups1[c] = p; tr->groups1[c] = p;
} else if (len == 0) {
else if (len == 0)
tr->groups1[0] = p; tr->groups1[0] = p;
} else if (c == 1) {
else if (c == 1) {
// index by offset from letter base // index by offset from letter base
tr->groups3[c2 - 1] = p; tr->groups3[c2 - 1] = p;
} else { } else {
} }


// skip over all the rules in this group // skip over all the rules in this group
while (*p != RULE_GROUP_END) {
while (*p != RULE_GROUP_END)
p += (strlen(p) + 1); p += (strlen(p) + 1);
}
p++; p++;
} }




f = fopen(fname, "rb"); f = fopen(fname, "rb");
if ((f == NULL) || (size <= 0)) { if ((f == NULL) || (size <= 0)) {
if (no_error == 0) {
if (no_error == 0)
fprintf(stderr, "Can't read dictionary file: '%s'\n", fname); fprintf(stderr, "Can't read dictionary file: '%s'\n", fname);
}
if (f != NULL) if (f != NULL)
fclose(f); fclose(f);
return 1; return 1;


for (hash = 0; hash < N_HASH_DICT; hash++) { for (hash = 0; hash < N_HASH_DICT; hash++) {
tr->dict_hashtab[hash] = p; tr->dict_hashtab[hash] = p;
while ((length = *p) != 0) {
while ((length = *p) != 0)
p += length; p += length;
}
p++; // skip over the zero which terminates the list for this hash value p++; // skip over the zero which terminates the list for this hash value
} }


if ((tr->dict_min_size > 0) && (size < (unsigned int)tr->dict_min_size)) {
if ((tr->dict_min_size > 0) && (size < (unsigned int)tr->dict_min_size))
fprintf(stderr, "Full dictionary is not installed for '%s'\n", name); fprintf(stderr, "Full dictionary is not installed for '%s'\n", name);
}


return 0; return 0;
} }
*bad_phoneme = 0; *bad_phoneme = 0;


// skip initial blanks // skip initial blanks
while (isspace(*p)) {
while (isspace(*p))
p++; p++;
}


while (((c = *p) != 0) && !isspace(c)) { while (((c = *p) != 0) && !isspace(c)) {
consumed = 0; consumed = 0;


if (max_ph == 0) { if (max_ph == 0) {
// not recognised, report and ignore // not recognised, report and ignore
if (bad_phoneme != NULL) {
if (bad_phoneme != NULL)
utf8_in(bad_phoneme, p); utf8_in(bad_phoneme, p);
}
*outptr++ = 0; *outptr++ = 0;
return p+1; return p+1;
} }
*p_lang = 0; // don't need "en", it's assumed by default *p_lang = 0; // don't need "en", it's assumed by default
return p; return p;
} }
} else {
} else
*outptr++ = '|'; // more phonemes follow, terminate language string with separator *outptr++ = '|'; // more phonemes follow, terminate language string with separator
}
} }
break; break;
} }
mnem = mnem >> 8; mnem = mnem >> 8;
} }
if (phcode == phonSWITCH) { if (phcode == phonSWITCH) {
while (isalpha(*inptr)) {
while (isalpha(*inptr))
*outptr++ = *inptr++; *outptr++ = *inptr++;
}
} }
} }
} }
// has an ipa name been defined for this phoneme ? // has an ipa name been defined for this phoneme ?
phdata.ipa_string[0] = 0; phdata.ipa_string[0] = 0;


if (plist == NULL) {
if (plist == NULL)
InterpretPhoneme2(ph->code, &phdata); InterpretPhoneme2(ph->code, &phdata);
} else {
else
InterpretPhoneme(NULL, 0, plist, &phdata, NULL); InterpretPhoneme(NULL, 0, plist, &phdata, NULL);
}


p = phdata.ipa_string; p = phdata.ipa_string;
if (*p == 0x20) { if (*p == 0x20) {
c = ipa1[c-0x20]; c = ipa1[c-0x20];


ix += utf8_out(c, &phon_out[ix]); ix += utf8_out(c, &phon_out[ix]);
} else {
} else
phon_out[ix++] = c; phon_out[ix++] = c;
}
first = 0; first = 0;
} }


if ((!plist->newword) || (separate_phonemes == ' ')) { if ((!plist->newword) || (separate_phonemes == ' ')) {
if ((separate_phonemes != 0) && (ix > 1)) { if ((separate_phonemes != 0) && (ix > 1)) {
utf8_in(&c, phon_buf2); utf8_in(&c, phon_buf2);
if ((c < 0x2b0) || (c > 0x36f)) { // not if the phoneme starts with a superscript letter
if ((c < 0x2b0) || (c > 0x36f)) // not if the phoneme starts with a superscript letter
buf += utf8_out(separate_phonemes, buf); buf += utf8_out(separate_phonemes, buf);
}
} }
} }


c = 0x2cc; // ipa, secondary stress c = 0x2cc; // ipa, secondary stress
if (stress > 3) if (stress > 3)
c = 0x02c8; // ipa, primary stress c = 0x02c8; // ipa, primary stress
} else {
} else
c = stress_chars[stress]; c = stress_chars[stress];
}


if (c != 0) {
if (c != 0)
buf += utf8_out(c, buf); buf += utf8_out(c, buf);
}
} }
} }


p += utf8_in(&c, p); p += utf8_in(&c, p);
if (use_tie != 0) { if (use_tie != 0) {
// look for non-inital alphabetic character, but not diacritic, superscript etc. // look for non-inital alphabetic character, but not diacritic, superscript etc.
if ((count > 0) && !(flags & (1 << (count-1))) && ((c < 0x2b0) || (c > 0x36f)) && iswalpha2(c)) {
if ((count > 0) && !(flags & (1 << (count-1))) && ((c < 0x2b0) || (c > 0x36f)) && iswalpha2(c))
buf += utf8_out(use_tie, buf); buf += utf8_out(use_tie, buf);
}
} }
buf += utf8_out(c, buf); buf += utf8_out(c, buf);
count++; count++;
} }


if (plist->ph->code != phonSWITCH) { if (plist->ph->code != phonSWITCH) {
if (plist->synthflags & SFLAG_LENGTHEN) {
if (plist->synthflags & SFLAG_LENGTHEN)
buf = WritePhMnemonic(buf, phoneme_tab[phonLENGTHEN], NULL, use_ipa, NULL); buf = WritePhMnemonic(buf, phoneme_tab[phonLENGTHEN], NULL, use_ipa, NULL);
}
if ((plist->synthflags & SFLAG_SYLLABLE) && (plist->type != phVOWEL)) { if ((plist->synthflags & SFLAG_SYLLABLE) && (plist->type != phVOWEL)) {
// syllablic consonant // syllablic consonant
buf = WritePhMnemonic(buf, phoneme_tab[phonSYLLABIC], NULL, use_ipa, NULL); buf = WritePhMnemonic(buf, phoneme_tab[phonSYLLABIC], NULL, use_ipa, NULL);
} }
if (plist->tone_ph > 0) {
if (plist->tone_ph > 0)
buf = WritePhMnemonic(buf, phoneme_tab[plist->tone_ph], NULL, use_ipa, NULL); buf = WritePhMnemonic(buf, phoneme_tab[plist->tone_ph], NULL, use_ipa, NULL);
}
} }


len = buf - phon_buf; len = buf - phon_buf;
if (pre) { if (pre) {
len = strlen(p); len = strlen(p);
w = word - len + 1; w = word - len + 1;
} else {
} else
w = word; w = word;
}
while ((*p == *w) && (*w != 0)) { while ((*p == *w) && (*w != 0)) {
w++; w++;
p++; p++;
} }


max_stress = max_stress_input = GetVowelStress(tr, phonetic, vowel_stress, &vowel_count, &stressed_syllable, 1); max_stress = max_stress_input = GetVowelStress(tr, phonetic, vowel_stress, &vowel_count, &stressed_syllable, 1);
if ((max_stress < 0) && dictionary_flags) {
if ((max_stress < 0) && dictionary_flags)
max_stress = 0; max_stress = 0;
}


// heavy or light syllables // heavy or light syllables
ix = 1; ix = 1;
// stress on second syllable // stress on second syllable
if ((stressed_syllable == 0) && (vowel_count > 2)) { if ((stressed_syllable == 0) && (vowel_count > 2)) {
stressed_syllable = 2; stressed_syllable = 2;
if (max_stress == 0) {
if (max_stress == 0)
vowel_stress[stressed_syllable] = 4; vowel_stress[stressed_syllable] = 4;
}
max_stress = 4; max_stress = 4;
} }
break; break;
} else { } else {
if ((mnem == 's') && (phoneme_tab[final_ph2]->type == phNASAL)) { if ((mnem == 's') && (phoneme_tab[final_ph2]->type == phNASAL)) {
// -ns stress remains on penultimate syllable // -ns stress remains on penultimate syllable
} else if (((phoneme_tab[final_ph]->type != phNASAL) && (mnem != 's')) || (phoneme_tab[final_ph2]->type != phVOWEL)) {
} else if (((phoneme_tab[final_ph]->type != phNASAL) && (mnem != 's')) || (phoneme_tab[final_ph2]->type != phVOWEL))
stressed_syllable = vowel_count - 1; stressed_syllable = vowel_count - 1;
}
} }
} }
} }


if (stressflags & S_FINAL_LONG) { if (stressflags & S_FINAL_LONG) {
// stress on last syllable if it has a long vowel, but previous syllable has a short vowel // stress on last syllable if it has a long vowel, but previous syllable has a short vowel
if (vowel_length[vowel_count - 1] > vowel_length[vowel_count - 2]) {
if (vowel_length[vowel_count - 1] > vowel_length[vowel_count - 2])
stressed_syllable = vowel_count - 1; stressed_syllable = vowel_count - 1;
}
} }


if ((vowel_stress[stressed_syllable] == 0) || (vowel_stress[stressed_syllable] == 1)) { if ((vowel_stress[stressed_syllable] == 0) || (vowel_stress[stressed_syllable] == 1)) {
if (stressed_syllable < 1) if (stressed_syllable < 1)
stressed_syllable = 1; stressed_syllable = 1;


if (max_stress == 0) {
if (max_stress == 0)
vowel_stress[stressed_syllable] = 4; vowel_stress[stressed_syllable] = 4;
}
max_stress = 4; max_stress = 4;
} }
break; break;


if ((stressflags & S_INITIAL_2) && (vowel_stress[1] < 0)) { if ((stressflags & S_INITIAL_2) && (vowel_stress[1] < 0)) {
// If there is only one syllable before the primary stress, give it a secondary stress // If there is only one syllable before the primary stress, give it a secondary stress
if ((vowel_count > 3) && (vowel_stress[2] >= 4)) {
if ((vowel_count > 3) && (vowel_stress[2] >= 4))
vowel_stress[1] = 3; vowel_stress[1] = 3;
}
} }
} }


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


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


if ((ph = phoneme_tab[phcode]) == NULL) if ((ph = phoneme_tab[phcode]) == NULL)
continue; continue;


if (ph->type == phPAUSE) {
if (ph->type == phPAUSE)
tr->prev_last_stress = 0; tr->prev_last_stress = 0;
} else if (((ph->type == phVOWEL) && !(ph->phflags & phNONSYLLABIC)) || (*p == phonSYLLABIC)) {
else if (((ph->type == phVOWEL) && !(ph->phflags & phNONSYLLABIC)) || (*p == phonSYLLABIC)) {
// a vowel, or a consonant followed by a syllabic consonant marker // a vowel, or a consonant followed by a syllabic consonant marker


v_stress = vowel_stress[v]; v_stress = vowel_stress[v];
*output++ = stress_phonemes[v_stress]; // mark stress of all vowels except 1 (unstressed) *output++ = stress_phonemes[v_stress]; // mark stress of all vowels except 1 (unstressed)




if (vowel_stress[v] > max_stress) {
if (vowel_stress[v] > max_stress)
max_stress = vowel_stress[v]; max_stress = vowel_stress[v];
}


if ((*p == phonLENGTHEN) && ((opt_length = tr->langopts.param[LOPT_IT_LENGTHEN]) & 1)) { if ((*p == phonLENGTHEN) && ((opt_length = tr->langopts.param[LOPT_IT_LENGTHEN]) & 1)) {
// remove lengthen indicator from non-stressed syllables // remove lengthen indicator from non-stressed syllables
int length; int length;


length = strlen(ph) + strlen(string); length = strlen(ph) + strlen(string);
if (length >= size) {
if (length >= size)
return; return;
}


/* any stressable vowel ? */ /* any stressable vowel ? */
unstress_mark = 0; unstress_mark = 0;
if (rb == RULE_LINENUM) if (rb == RULE_LINENUM)
match.phonemes += 2; // skip over line number match.phonemes += 2; // skip over line number
} }
} else {
} else
match.phonemes = ""; match.phonemes = "";
}
rule--; // so we are still pointing at the 0 rule--; // so we are still pointing at the 0
failed = 2; // matched OK failed = 2; // matched OK
break; break;
break; break;


case RULE_NOTVOWEL: case RULE_NOTVOWEL:
if (IsLetter(tr, letter_w, 0) || ((letter_w == ' ') && (word_flags & FLAG_SUFFIX_VOWEL))) {
if (IsLetter(tr, letter_w, 0) || ((letter_w == ' ') && (word_flags & FLAG_SUFFIX_VOWEL)))
failed = 1; failed = 1;
} else {
else {
add_points = (20-distance_right); add_points = (20-distance_right);
post_ptr += letter_xbytes; post_ptr += letter_xbytes;
} }


case RULE_DOLLAR: case RULE_DOLLAR:
command = *rule++; command = *rule++;
if (command == DOLLAR_UNPR) {
if (command == DOLLAR_UNPR)
match.end_type = SUFX_UNPRON; // $unpron match.end_type = SUFX_UNPRON; // $unpron
} else if (command == DOLLAR_NOPREFIX) { // $noprefix
else if (command == DOLLAR_NOPREFIX) { // $noprefix
if (word_flags & FLAG_PREFIX_REMOVED) if (word_flags & FLAG_PREFIX_REMOVED)
failed = 1; // a prefix has been removed failed = 1; // a prefix has been removed
else else
break; break;


case '-': case '-':
if ((letter == '-') || ((letter == ' ') && (word_flags & FLAG_HYPHEN_AFTER))) {
if ((letter == '-') || ((letter == ' ') && (word_flags & FLAG_HYPHEN_AFTER)))
add_points = (22-distance_right); // one point more than match against space add_points = (22-distance_right); // one point more than match against space
} else
else
failed = 1; failed = 1;
break; break;


p2 = p; p2 = p;
p += utf8_in(&letter_w, p); p += utf8_in(&letter_w, p);
} }
if (letter_w == rule_w) {
if (letter_w == rule_w)
post_ptr = p2; post_ptr = p2;
}
} }
break; break;


break; break;


case '-': case '-':
if ((letter == '-') || ((letter == ' ') && (word_flags & FLAG_HYPHEN))) {
if ((letter == '-') || ((letter == ' ') && (word_flags & FLAG_HYPHEN)))
add_points = (22-distance_right); // one point more than match against space add_points = (22-distance_right); // one point more than match against space
} else
else
failed = 1; failed = 1;
break; break;


if (letter == rb) { if (letter == rb) {
if (letter == RULE_SPACE) if (letter == RULE_SPACE)
add_points = 4; add_points = 4;
else {
if ((letter & 0xc0) != 0x80) {
// not for non-initial UTF-8 bytes
add_points = (21-distance_left);
}
else if ((letter & 0xc0) != 0x80) {
// not for non-initial UTF-8 bytes
add_points = (21-distance_left);
} }
} else } else
failed = 1; failed = 1;
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++)
wordbuf[ix] = c; wordbuf[ix] = c;
}
wordbuf[ix] = 0; wordbuf[ix] = 0;
if (word_flags & FLAG_UNPRON_TEST) if (word_flags & FLAG_UNPRON_TEST)
fprintf(f_trans, "Unpronouncable? '%s'\n", wordbuf); fprintf(f_trans, "Unpronouncable? '%s'\n", wordbuf);
return 0; return 0;
} }


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;


p += utf8_in(&c, p); p += utf8_in(&c, p);
if (c != 0) { if (c != 0) {
if ((c >= min) && (c <= max)) { if ((c >= min) && (c <= max)) {
if (map == NULL) {
if (map == NULL)
buf[bufix++] = c - offset; buf[bufix++] = c - offset;
} else {
else {
// get the code from the transpose map // get the code from the transpose map
if (map[c - min] > 0) {
if (map[c - min] > 0)
buf[bufix++] = map[c - min]; buf[bufix++] = map[c - min];
} else {
else {
all_alpha = 0; all_alpha = 0;
break; break;
} }
ix = p2 - buf; ix = p2 - buf;
memcpy(text, buf, ix); memcpy(text, buf, ix);
return ix | 0x40; // bit 6 indicates compressed characters return ix | 0x40; // bit 6 indicates compressed characters
} else {
return strlen(text);
} }
return strlen(text);
} }




char word_buf[N_WORD_BYTES+1]; char word_buf[N_WORD_BYTES+1];
char dict_flags_buf[80]; char dict_flags_buf[80];


if (wtab != NULL) {
if (wtab != NULL)
wflags = wtab->flags; wflags = wtab->flags;
}


lookup_symbol = flags[1] & FLAG_LOOKUP_SYMBOL; lookup_symbol = flags[1] & FLAG_LOOKUP_SYMBOL;
word1 = word; word1 = word;
strncpy0(word_buf, word, N_WORD_BYTES); strncpy0(word_buf, word, N_WORD_BYTES);
wlen = TransposeAlphabet(tr, word_buf); // bit 6 indicates compressed characters wlen = TransposeAlphabet(tr, word_buf); // bit 6 indicates compressed characters
word = word_buf; word = word_buf;
} else {
} else
wlen = strlen(word); wlen = strlen(word);
}


hash = HashDictionary(word); hash = HashDictionary(word);
p = tr->dict_hashtab[hash]; p = tr->dict_hashtab[hash];
// or has an embedded command, such as MARK // or has an embedded command, such as MARK
if (wtab != NULL) { if (wtab != NULL) {
for (ix = 0; ix <= skipwords; ix++) { for (ix = 0; ix <= skipwords; ix++) {
if (wtab[ix].flags & FLAG_EMPHASIZED2) {
if (wtab[ix].flags & FLAG_EMPHASIZED2)
condition_failed = 1; condition_failed = 1;
}
} }
} }


dictionary_flags = (dictionary_flags & ~0xf) | (flag & 0xf); dictionary_flags = (dictionary_flags & ~0xf) | (flag & 0xf);
if ((flag & 0xc) == 0xc) if ((flag & 0xc) == 0xc)
dictionary_flags |= FLAG_STRESS_END; dictionary_flags |= FLAG_STRESS_END;
} else if (flag >= 32) {
} else if (flag >= 32)
dictionary_flags2 |= (1L << (flag-32)); dictionary_flags2 |= (1L << (flag-32));
} else {
else
dictionary_flags |= (1L << flag); dictionary_flags |= (1L << flag);
}
} }


if (condition_failed) { if (condition_failed) {
} }


if (dictionary_flags2 & FLAG_HYPHENATED) { if (dictionary_flags2 & FLAG_HYPHENATED) {
if (!(wflags & FLAG_HYPHEN_AFTER)) {
if (!(wflags & FLAG_HYPHEN_AFTER))
continue; continue;
}
} }
if (dictionary_flags2 & FLAG_CAPITAL) { if (dictionary_flags2 & FLAG_CAPITAL) {
if (!(wflags & FLAG_FIRST_UPPER)) {
if (!(wflags & FLAG_FIRST_UPPER))
continue; continue;
}
} }
if (dictionary_flags2 & FLAG_ALLCAPS) { if (dictionary_flags2 & FLAG_ALLCAPS) {
if (!(wflags & FLAG_ALL_UPPER)) {
if (!(wflags & FLAG_ALL_UPPER))
continue; continue;
}
} }
if (dictionary_flags & FLAG_NEEDS_DOT) { if (dictionary_flags & FLAG_NEEDS_DOT) {
if (!(wflags & FLAG_HAS_DOT)) if (!(wflags & FLAG_HAS_DOT))
memcpy(word_buf, word2, word_end-word2); memcpy(word_buf, word2, word_end-word2);
word_buf[word_end-word2-1] = 0; word_buf[word_end-word2-1] = 0;
fprintf(f_trans, "Found: '%s %s\n", word1, word_buf); fprintf(f_trans, "Found: '%s %s\n", word1, word_buf);
} else {
} else
fprintf(f_trans, "Found: '%s", word1); fprintf(f_trans, "Found: '%s", word1);
}
print_dictionary_flags(flags, dict_flags_buf, sizeof(dict_flags_buf)); print_dictionary_flags(flags, dict_flags_buf, sizeof(dict_flags_buf));
fprintf(f_trans, "' [%s] %s\n", ph_decoded, dict_flags_buf); fprintf(f_trans, "' [%s] %s\n", ph_decoded, dict_flags_buf);
} }
} }


ix = utf8_in(&c, word); ix = utf8_in(&c, word);
if ((word[ix] == 0) && !IsAlpha(c)) {
if ((word[ix] == 0) && !IsAlpha(c))
flags[0] |= FLAG_MAX3; flags[0] |= FLAG_MAX3;
}
return word_end; return word_end;


} }
if (length > 0) { if (length > 0) {
// found an abbreviation containing dots // found an abbreviation containing dots
nbytes = 0; nbytes = 0;
while (((c = word2[nbytes]) != 0) && (c != ' ')) {
while (((c = word2[nbytes]) != 0) && (c != ' '))
nbytes++; nbytes++;
}
memcpy(&word[length], word2, nbytes); memcpy(&word[length], word2, nbytes);
word[length+nbytes] = 0; word[length+nbytes] = 0;
found = LookupDict2(tr, word, word2, ph_out, flags, end_flags, wtab); found = LookupDict2(tr, word, word2, ph_out, flags, end_flags, wtab);
if (flags[0] & FLAG_MAX3) { if (flags[0] & FLAG_MAX3) {
if (strcmp(ph_out, tr->phonemes_repeat) == 0) { if (strcmp(ph_out, tr->phonemes_repeat) == 0) {
tr->phonemes_repeat_count++; tr->phonemes_repeat_count++;
if (tr->phonemes_repeat_count > 3) {
if (tr->phonemes_repeat_count > 3)
ph_out[0] = 0; ph_out[0] = 0;
}
} else { } else {
strncpy0(tr->phonemes_repeat, ph_out, sizeof(tr->phonemes_repeat)); strncpy0(tr->phonemes_repeat, ph_out, sizeof(tr->phonemes_repeat));
tr->phonemes_repeat_count = 1; tr->phonemes_repeat_count = 1;
} }
} else {
} else
tr->phonemes_repeat_count = 0; tr->phonemes_repeat_count = 0;
}




if ((found == 0) && (flags[1] & FLAG_ACCENT)) { if ((found == 0) && (flags[1] & FLAG_ACCENT)) {


flags[0] = 0; flags[0] = 0;
flags[1] = FLAG_LOOKUP_SYMBOL; flags[1] = FLAG_LOOKUP_SYMBOL;
if ((flags0 = LookupDictList(tr, &word1, ph_out, flags, FLAG_ALLOW_TEXTMODE, NULL)) != 0) {
if ((flags0 = LookupDictList(tr, &word1, ph_out, flags, FLAG_ALLOW_TEXTMODE, NULL)) != 0)
flags0 = flags[0]; flags0 = flags[0];
}


if (flags[0] & FLAG_TEXTMODE) { if (flags[0] & FLAG_TEXTMODE) {
say_as = option_sayas; say_as = option_sayas;


for (i = 0; (p = add_e_exceptions[i]) != NULL; i++) { for (i = 0; (p = add_e_exceptions[i]) != NULL; i++) {
len = strlen(p); len = strlen(p);
if (memcmp(p, &word_end[1-len], len) == 0) {
if (memcmp(p, &word_end[1-len], len) == 0)
break; break;
}
} }
if (p == NULL) if (p == NULL)
end_flags |= FLAG_SUFX_E_ADDED; // no exception found end_flags |= FLAG_SUFX_E_ADDED; // no exception found
} }
} }
} }
} else if (tr->langopts.suffix_add_e != 0) {
} else if (tr->langopts.suffix_add_e != 0)
end_flags |= FLAG_SUFX_E_ADDED; end_flags |= FLAG_SUFX_E_ADDED;
}


if (end_flags & FLAG_SUFX_E_ADDED) { if (end_flags & FLAG_SUFX_E_ADDED) {
utf8_out(tr->langopts.suffix_add_e, &word_end[1]); utf8_out(tr->langopts.suffix_add_e, &word_end[1]);


if (option_phonemes & espeakPHONEMES_TRACE) {
if (option_phonemes & espeakPHONEMES_TRACE)
fprintf(f_trans, "add e\n"); fprintf(f_trans, "add e\n");
}
} }
} }



+ 46
- 84
src/libespeak-ng/espeak_command.c View File

t_espeak_text *data = NULL; t_espeak_text *data = NULL;
t_espeak_command *a_command = (t_espeak_command *)malloc(sizeof(t_espeak_command)); t_espeak_command *a_command = (t_espeak_command *)malloc(sizeof(t_espeak_command));


if (!text || !size || !a_command) {
if (!text || !size || !a_command)
goto text_error; goto text_error;
}


a_text = malloc(size+1); a_text = malloc(size+1);
if (!a_text) {
if (!a_text)
goto text_error; goto text_error;
}
memcpy(a_text, text, size); memcpy(a_text, text, size);


a_command->type = ET_TEXT; a_command->type = ET_TEXT;


text_error: text_error:
if (a_error) { if (a_error) {
if (a_text) {
if (a_text)
free(a_text); free(a_text);
}
if (a_command) {
if (a_command)
free(a_command); free(a_command);
}
a_command = NULL; a_command = NULL;
} }


t_espeak_terminated_msg *data = NULL; t_espeak_terminated_msg *data = NULL;
t_espeak_command *a_command = (t_espeak_command *)malloc(sizeof(t_espeak_command)); t_espeak_command *a_command = (t_espeak_command *)malloc(sizeof(t_espeak_command));


if (!a_command) {
if (!a_command)
goto msg_error; goto msg_error;
}


a_command->type = ET_TERMINATED_MSG; a_command->type = ET_TERMINATED_MSG;
a_command->state = CS_UNDEFINED; a_command->state = CS_UNDEFINED;


msg_error: msg_error:
if (a_error) { if (a_error) {
if (a_command) {
if (a_command)
free(a_command); free(a_command);
}
a_command = NULL; a_command = NULL;
} }


t_espeak_mark *data = NULL; t_espeak_mark *data = NULL;
t_espeak_command *a_command = (t_espeak_command *)malloc(sizeof(t_espeak_command)); t_espeak_command *a_command = (t_espeak_command *)malloc(sizeof(t_espeak_command));


if (!text || !size || !index_mark || !a_command) {
if (!text || !size || !index_mark || !a_command)
goto mark_error; goto mark_error;
}


a_text = malloc(size); a_text = malloc(size);
if (!a_text) {
if (!a_text)
goto mark_error; goto mark_error;
}
memcpy(a_text, text, size); memcpy(a_text, text, size);


a_index_mark = strdup(index_mark); a_index_mark = strdup(index_mark);


mark_error: mark_error:
if (a_error) { if (a_error) {
if (a_text) {
if (a_text)
free(a_text); free(a_text);
}
if (a_command) {
if (a_command)
free(a_command); free(a_command);
}
a_command = NULL; a_command = NULL;
if (a_index_mark) {
if (a_index_mark)
free(a_index_mark); free(a_index_mark);
}
} }


SHOW("ET_MARK malloc text=%x, command=%x (uid=%d)\n", a_text, a_command, data->unique_identifier); SHOW("ET_MARK malloc text=%x, command=%x (uid=%d)\n", a_text, a_command, data->unique_identifier);
int a_error = 1; int a_error = 1;
t_espeak_command *a_command = (t_espeak_command *)malloc(sizeof(t_espeak_command)); t_espeak_command *a_command = (t_espeak_command *)malloc(sizeof(t_espeak_command));


if (!key_name || !a_command) {
if (!key_name || !a_command)
goto key_error; goto key_error;
}


a_command->type = ET_KEY; a_command->type = ET_KEY;
a_command->state = CS_UNDEFINED; a_command->state = CS_UNDEFINED;


key_error: key_error:
if (a_error) { if (a_error) {
if (a_command) {
if (a_command)
free(a_command); free(a_command);
}
a_command = NULL; a_command = NULL;
} }


ENTER("create_espeak_char"); ENTER("create_espeak_char");
int a_error = 1; int a_error = 1;
t_espeak_command *a_command = (t_espeak_command *)malloc(sizeof(t_espeak_command)); t_espeak_command *a_command = (t_espeak_command *)malloc(sizeof(t_espeak_command));
if (!a_command) {
if (!a_command)
goto char_error; goto char_error;
}


a_command->type = ET_CHAR; a_command->type = ET_CHAR;
a_command->state = CS_UNDEFINED; a_command->state = CS_UNDEFINED;


char_error: char_error:
if (a_error) { if (a_error) {
if (a_command) {
if (a_command)
free(a_command); free(a_command);
}
a_command = NULL; a_command = NULL;
} }


int a_error = 1; int a_error = 1;
t_espeak_parameter *data = NULL; t_espeak_parameter *data = NULL;
t_espeak_command *a_command = (t_espeak_command *)malloc(sizeof(t_espeak_command)); t_espeak_command *a_command = (t_espeak_command *)malloc(sizeof(t_espeak_command));
if (!a_command) {
if (!a_command)
goto param_error; goto param_error;
}


a_command->type = ET_PARAMETER; a_command->type = ET_PARAMETER;
a_command->state = CS_UNDEFINED; a_command->state = CS_UNDEFINED;


param_error: param_error:
if (a_error) { if (a_error) {
if (a_command) {
if (a_command)
free(a_command); free(a_command);
}
a_command = NULL; a_command = NULL;
} }


int a_error = 1; int a_error = 1;
t_espeak_command *a_command = (t_espeak_command *)malloc(sizeof(t_espeak_command)); t_espeak_command *a_command = (t_espeak_command *)malloc(sizeof(t_espeak_command));


if (!punctlist || !a_command) {
if (!punctlist || !a_command)
goto list_error; goto list_error;
}


a_command->type = ET_PUNCTUATION_LIST; a_command->type = ET_PUNCTUATION_LIST;
a_command->state = CS_UNDEFINED; a_command->state = CS_UNDEFINED;


{
size_t len = (wcslen(punctlist) + 1)*sizeof(wchar_t);
wchar_t *a_list = (wchar_t *)malloc(len);
memcpy(a_list, punctlist, len);
a_command->u.my_punctuation_list = a_list;
}
size_t len = (wcslen(punctlist) + 1)*sizeof(wchar_t);
wchar_t *a_list = (wchar_t *)malloc(len);
memcpy(a_list, punctlist, len);
a_command->u.my_punctuation_list = a_list;


a_error = 0; a_error = 0;


list_error: list_error:
if (a_error) { if (a_error) {
if (a_command) {
if (a_command)
free(a_command); free(a_command);
}
a_command = NULL; a_command = NULL;
} }


int a_error = 1; int a_error = 1;
t_espeak_command *a_command = (t_espeak_command *)malloc(sizeof(t_espeak_command)); t_espeak_command *a_command = (t_espeak_command *)malloc(sizeof(t_espeak_command));


if (!name || !a_command) {
if (!name || !a_command)
goto name_error; goto name_error;
}


a_command->type = ET_VOICE_NAME; a_command->type = ET_VOICE_NAME;
a_command->state = CS_UNDEFINED; a_command->state = CS_UNDEFINED;


name_error: name_error:
if (a_error) { if (a_error) {
if (a_command) {
if (a_command)
free(a_command); free(a_command);
}
a_command = NULL; a_command = NULL;
} }


int a_error = 1; int a_error = 1;
t_espeak_command *a_command = (t_espeak_command *)malloc(sizeof(t_espeak_command)); t_espeak_command *a_command = (t_espeak_command *)malloc(sizeof(t_espeak_command));


if (!voice || !a_command) {
if (!voice || !a_command)
goto spec_error; goto spec_error;
}


a_command->type = ET_VOICE_SPEC; a_command->type = ET_VOICE_SPEC;
a_command->state = CS_UNDEFINED; a_command->state = CS_UNDEFINED;
{
espeak_VOICE *data = &(a_command->u.my_voice_spec);
memcpy(data, voice, sizeof(espeak_VOICE));


if (voice->name) {
data->name = strdup(voice->name);
}
espeak_VOICE *data = &(a_command->u.my_voice_spec);
memcpy(data, voice, sizeof(espeak_VOICE));


if (voice->languages) {
data->languages = strdup(voice->languages);
}
if (voice->name)
data->name = strdup(voice->name);


if (voice->identifier) {
data->identifier = strdup(voice->identifier);
}
if (voice->languages)
data->languages = strdup(voice->languages);


a_error = 0;
}
if (voice->identifier)
data->identifier = strdup(voice->identifier);

a_error = 0;


spec_error: spec_error:
if (a_error) { if (a_error) {
if (a_command) {
if (a_command)
free(a_command); free(a_command);
}
a_command = NULL; a_command = NULL;
} }


break; break;


case ET_MARK: case ET_MARK:
if (the_command->u.my_mark.text) {
if (the_command->u.my_mark.text)
free(the_command->u.my_mark.text); free(the_command->u.my_mark.text);
}
if (the_command->u.my_mark.index_mark) {
if (the_command->u.my_mark.index_mark)
free((void *)(the_command->u.my_mark.index_mark)); free((void *)(the_command->u.my_mark.index_mark));
}
break; break;


case ET_TERMINATED_MSG: case ET_TERMINATED_MSG:
break; break;


case ET_KEY: case ET_KEY:
if (the_command->u.my_key.key_name) {
if (the_command->u.my_key.key_name)
free((void *)(the_command->u.my_key.key_name)); free((void *)(the_command->u.my_key.key_name));
}
break; break;


case ET_CHAR: case ET_CHAR:
break; break;


case ET_PUNCTUATION_LIST: case ET_PUNCTUATION_LIST:
if (the_command->u.my_punctuation_list) {
if (the_command->u.my_punctuation_list)
free((void *)(the_command->u.my_punctuation_list)); free((void *)(the_command->u.my_punctuation_list));
}
break; break;


case ET_VOICE_NAME: case ET_VOICE_NAME:
if (the_command->u.my_voice_name) {
if (the_command->u.my_voice_name)
free((void *)(the_command->u.my_voice_name)); free((void *)(the_command->u.my_voice_name));
}
break; break;


case ET_VOICE_SPEC: case ET_VOICE_SPEC:
{ {
espeak_VOICE *data = &(the_command->u.my_voice_spec); espeak_VOICE *data = &(the_command->u.my_voice_spec);


if (data->name) {
if (data->name)
free((void *)data->name); free((void *)data->name);
}


if (data->languages) {
if (data->languages)
free((void *)data->languages); free((void *)data->languages);
}


if (data->identifier) {
if (data->identifier)
free((void *)data->identifier); free((void *)data->identifier);
}
} }
break; break;




SHOW("command=0x%x\n", the_command); SHOW("command=0x%x\n", the_command);


if (the_command == NULL) {
if (the_command == NULL)
return; return;
}


the_command->state = CS_PROCESSED; the_command->state = CS_PROCESSED;



+ 23
- 45
src/libespeak-ng/event.c View File

ENTER("event_display"); ENTER("event_display");


#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
if (event == NULL) {
if (event == NULL)
SHOW("event_display > event=%s\n", "NULL"); SHOW("event_display > event=%s\n", "NULL");
} else {
else {
static const char *label[] = { static const char *label[] = {
"LIST_TERMINATED", "LIST_TERMINATED",
"WORD", "WORD",
{ {
ENTER("event_copy"); ENTER("event_copy");


if (event == NULL) {
if (event == NULL)
return NULL; return NULL;
}


espeak_EVENT *a_event = (espeak_EVENT *)malloc(sizeof(espeak_EVENT)); espeak_EVENT *a_event = (espeak_EVENT *)malloc(sizeof(espeak_EVENT));
if (a_event) { if (a_event) {
{ {
case espeakEVENT_MARK: case espeakEVENT_MARK:
case espeakEVENT_PLAY: case espeakEVENT_PLAY:
if (event->id.name) {
if (event->id.name)
a_event->id.name = strdup(event->id.name); a_event->id.name = strdup(event->id.name);
}
break; break;


default: default:


event_display(event); event_display(event);


if (event == NULL) {
if (event == NULL)
return 0; return 0;
}


switch (event->type) switch (event->type)
{ {


case espeakEVENT_MARK: case espeakEVENT_MARK:
case espeakEVENT_PLAY: case espeakEVENT_PLAY:
if (event->id.name) {
if (event->id.name)
free((void *)(event->id.name)); free((void *)(event->id.name));
}
break; break;


default: default:


event_display(event); event_display(event);


if (!event) {
if (!event)
return EE_INTERNAL_ERROR; return EE_INTERNAL_ERROR;
}


int a_status = pthread_mutex_lock(&my_mutex); int a_status = pthread_mutex_lock(&my_mutex);
espeak_ERROR a_error = EE_OK; espeak_ERROR a_error = EE_OK;
SHOW_TIME("event_declare > locked\n"); SHOW_TIME("event_declare > locked\n");
espeak_EVENT *a_event = event_copy(event); espeak_EVENT *a_event = event_copy(event);
a_error = push(a_event); a_error = push(a_event);
if (a_error != EE_OK) {
if (a_error != EE_OK)
event_delete(a_event); event_delete(a_event);
}
SHOW_TIME("event_declare > unlocking\n"); SHOW_TIME("event_declare > unlocking\n");
a_status = pthread_mutex_unlock(&my_mutex); a_status = pthread_mutex_unlock(&my_mutex);
} }
SHOW_TIME("event_declare > post my_sem_start_is_required\n"); SHOW_TIME("event_declare > post my_sem_start_is_required\n");
sem_post(&my_sem_start_is_required); sem_post(&my_sem_start_is_required);


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


return a_error; return a_error;
} }
int a_event_is_running = 0; int a_event_is_running = 0;


SHOW_TIME("event_stop > locked\n"); SHOW_TIME("event_stop > locked\n");
if (a_status != 0) {
if (a_status != 0)
return EE_INTERNAL_ERROR; return EE_INTERNAL_ERROR;
}


if (my_event_is_running) { if (my_event_is_running) {
SHOW_TIME("event_stop > post my_sem_stop_is_required\n"); SHOW_TIME("event_stop > post my_sem_stop_is_required\n");
sem_post(&my_sem_stop_is_required); sem_post(&my_sem_stop_is_required);
a_event_is_running = 1; a_event_is_running = 1;
} else {
} else
init(); // clear pending events init(); // clear pending events
}
SHOW_TIME("event_stop > unlocking\n"); SHOW_TIME("event_stop > unlocking\n");
a_status = pthread_mutex_unlock(&my_mutex); a_status = pthread_mutex_unlock(&my_mutex);
if (a_status != 0) {
if (a_status != 0)
return EE_INTERNAL_ERROR; return EE_INTERNAL_ERROR;
}


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


ts.tv_sec, ts.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",


SHOW_TIME("polling_thread > wait for my_sem_start_is_required\n"); SHOW_TIME("polling_thread > wait for my_sem_start_is_required\n");


while ((sem_wait(&my_sem_start_is_required) == -1) && errno == EINTR) {
while ((sem_wait(&my_sem_start_is_required) == -1) && errno == EINTR)
continue; // Restart when interrupted by handler continue; // Restart when interrupted by handler
}


SHOW_TIME("polling_thread > get my_sem_start_is_required\n"); SHOW_TIME("polling_thread > get my_sem_start_is_required\n");


while (0 == sem_trywait(&my_sem_stop_is_required)) { while (0 == sem_trywait(&my_sem_stop_is_required)) {
} }
; ;
} else {
} else
a_stop_is_required = 0; a_stop_is_required = 0;
}


// In this loop, my_event_is_running = 1 // In this loop, my_event_is_running = 1
while (head && (a_stop_is_required <= 0)) { while (head && (a_stop_is_required <= 0)) {
SHOW_TIME("polling_thread > check head\n"); SHOW_TIME("polling_thread > check head\n");
while (0 == sem_trywait(&my_sem_start_is_required)) { while (0 == sem_trywait(&my_sem_start_is_required)) {
} }
;


espeak_EVENT *event = (espeak_EVENT *)(head->data); espeak_EVENT *event = (espeak_EVENT *)(head->data);
assert(event); assert(event);
int err = get_remaining_time((uint32_t)event->sample, int err = get_remaining_time((uint32_t)event->sample,
&time_in_ms, &time_in_ms,
&a_stop_is_required); &a_stop_is_required);
if (a_stop_is_required > 0) {
if (a_stop_is_required > 0)
break; break;
} else if (err != 0) {
else if (err != 0) {
// No available time: the event is deleted. // No available time: the event is deleted.
SHOW("polling_thread > %s\n", "audio device down"); SHOW("polling_thread > %s\n", "audio device down");
a_status = pthread_mutex_lock(&my_mutex); a_status = pthread_mutex_lock(&my_mutex);
SHOW("polling_thread > stop required (%d)\n", __LINE__); SHOW("polling_thread > stop required (%d)\n", __LINE__);
while (0 == sem_trywait(&my_sem_stop_is_required)) { while (0 == sem_trywait(&my_sem_stop_is_required)) {
} }
;
} else {
} else
a_stop_is_required = 0; a_stop_is_required = 0;
}
} else { // The event will be notified soon: sleep until timeout or stop request
} else // The event will be notified soon: sleep until timeout or stop request
a_stop_is_required = sleep_until_timeout_or_stop_request(time_in_ms); a_stop_is_required = sleep_until_timeout_or_stop_request(time_in_ms);
}
} }


a_status = pthread_mutex_lock(&my_mutex); a_status = pthread_mutex_lock(&my_mutex);
SHOW("polling_thread > stop required (%d)\n", __LINE__); SHOW("polling_thread > stop required (%d)\n", __LINE__);
while (0 == sem_trywait(&my_sem_stop_is_required)) { while (0 == sem_trywait(&my_sem_stop_is_required)) {
} }
;
} else {
} else
a_stop_is_required = 0; a_stop_is_required = 0;
}
} }


a_status = pthread_mutex_unlock(&my_mutex); a_status = pthread_mutex_unlock(&my_mutex);
} }


node *n = (node *)malloc(sizeof(node)); node *n = (node *)malloc(sizeof(node));
if (n == NULL) {
if (n == NULL)
return EE_INTERNAL_ERROR; return EE_INTERNAL_ERROR;
}


if (head == NULL) { if (head == NULL) {
head = n; head = n;
SHOW("event > pop > event=0x%x (counter=%d, uid=%d)\n", the_data, node_counter, ((espeak_EVENT *)the_data)->unique_identifier); SHOW("event > pop > event=0x%x (counter=%d, uid=%d)\n", the_data, node_counter, ((espeak_EVENT *)the_data)->unique_identifier);
} }


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


return the_data; return the_data;
} }

+ 17
- 35
src/libespeak-ng/fifo.c View File



// leave once the thread is actually started // leave once the thread is actually started
SHOW_TIME("fifo > wait for my_sem_stop_is_acknowledged\n"); SHOW_TIME("fifo > wait for my_sem_stop_is_acknowledged\n");
while ((sem_wait(&my_sem_stop_is_acknowledged) == -1) && errno == EINTR) {
while ((sem_wait(&my_sem_stop_is_acknowledged) == -1) && errno == EINTR)
continue; // Restart when interrupted by handler continue; // Restart when interrupted by handler
}
SHOW_TIME("fifo > get my_sem_stop_is_acknowledged\n"); SHOW_TIME("fifo > get my_sem_stop_is_acknowledged\n");
} }


} }
} }


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


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


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


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


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


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


// //
int i = 0; 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++;
}


int err = 0; int err = 0;
struct timespec ts; struct timespec ts;
ts.tv_sec, ts.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)
a_start_is_required = 1; a_start_is_required = 1;
}
} }
SHOW_TIME("fifo > sleep_until_start_request_or_inactivity > LEAVE"); SHOW_TIME("fifo > sleep_until_start_request_or_inactivity > LEAVE");
return a_start_is_required; return a_start_is_required;
int a_status = pthread_mutex_lock(&my_mutex); int a_status = pthread_mutex_lock(&my_mutex);
assert(!a_status); assert(!a_status);
int a_stop_is_required = my_stop_is_required; int a_stop_is_required = my_stop_is_required;
if (!a_stop_is_required) {
if (!a_stop_is_required)
my_command_is_running = 1; my_command_is_running = 1;
}
a_status = pthread_mutex_unlock(&my_mutex); a_status = pthread_mutex_unlock(&my_mutex);


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


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


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


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


if (my_command_is_running) {
if (my_command_is_running)
process_espeak_command(a_command); process_espeak_command(a_command);
}
delete_espeak_command(a_command); delete_espeak_command(a_command);
} }
} }
SHOW_TIME("say_thread > purge my_sem_start_is_required\n"); SHOW_TIME("say_thread > purge my_sem_start_is_required\n");
while (0 == sem_trywait(&my_sem_start_is_required)) { while (0 == sem_trywait(&my_sem_start_is_required)) {
} }
;


// acknowledge the stop request // acknowledge the stop request
SHOW_TIME("say_thread > post my_sem_stop_is_acknowledged\n"); SHOW_TIME("say_thread > post my_sem_stop_is_acknowledged\n");
} }


node *n = (node *)malloc(sizeof(node)); node *n = (node *)malloc(sizeof(node));
if (n == NULL) {
if (n == NULL)
return EE_INTERNAL_ERROR; return EE_INTERNAL_ERROR;
}


if (head == NULL) { if (head == NULL) {
head = n; head = n;
SHOW("pop > command=0x%x (counter=%d)\n", the_command, node_counter); SHOW("pop > command=0x%x (counter=%d)\n", the_command, node_counter);
} }


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


display_espeak_command(the_command); display_espeak_command(the_command);


ENTER("fifo > init"); ENTER("fifo > init");
c = pop(); c = pop();
while (c != NULL) { while (c != NULL) {
if (process_parameters && (c->type == ET_PARAMETER || c->type == ET_VOICE_NAME || c->type == ET_VOICE_SPEC)) {
if (process_parameters && (c->type == ET_PARAMETER || c->type == ET_VOICE_NAME || c->type == ET_VOICE_SPEC))
process_espeak_command(c); process_espeak_command(c);
}
delete_espeak_command(c); delete_espeak_command(c);
c = pop(); c = pop();
} }

+ 23
- 37
src/libespeak-ng/intonation.c View File

stress = syllable_tab[ix].stress; /* marked stress level */ stress = syllable_tab[ix].stress; /* marked stress level */


if (stress >= max_stress) { if (stress >= max_stress) {
if (stress > max_stress) {
if (stress > max_stress)
max_stress_posn2 = ix; max_stress_posn2 = ix;
} else {
else
max_stress_posn2 = max_stress_posn; max_stress_posn2 = max_stress_posn;
}
max_stress_posn = ix; max_stress_posn = ix;
max_stress = stress; max_stress = stress;
} }
if (no_tonic) { if (no_tonic) {
tone_posn = tone_posn2 = end; // next position after the end of the truncated clause tone_posn = tone_posn2 = end; // next position after the end of the truncated clause
} else if (last_primary >= 0) { } else if (last_primary >= 0) {
if (end == clause_end) {
if (end == clause_end)
syllable_tab[last_primary].stress = PRIMARY_LAST; syllable_tab[last_primary].stress = PRIMARY_LAST;
}
} else { } else {
// no primary stress. Use the highest stress // no primary stress. Use the highest stress
syllable_tab[tone_posn].stress = PRIMARY_LAST; syllable_tab[tone_posn].stress = PRIMARY_LAST;
if (n_steps > tune->head_max_steps) if (n_steps > tune->head_max_steps)
n_steps = tune->head_max_steps; n_steps = tune->head_max_steps;


if (n_steps > 1) {
if (n_steps > 1)
increment = pitch_range / (n_steps -1); increment = pitch_range / (n_steps -1);
} else
else
increment = 0; increment = 0;


} else if (syl_ix == head_final) { } else if (syl_ix == head_final) {
pitch += increment; pitch += increment;
else { else {
pitch = (tune->head_end << 8) + (pitch_range_abs * tune->head_extend[overflow_ix++])/64; pitch = (tune->head_end << 8) + (pitch_range_abs * tune->head_extend[overflow_ix++])/64;
if (overflow_ix >= tune->n_head_extend) {
if (overflow_ix >= tune->n_head_extend)
overflow_ix = 0; overflow_ix = 0;
}
} }
} }


if (n_steps > th->body_max_steps) if (n_steps > th->body_max_steps)
n_steps = th->body_max_steps; n_steps = th->body_max_steps;


if (n_steps > 1) {
if (n_steps > 1)
increment = pitch_range / (n_steps -1); increment = pitch_range / (n_steps -1);
} else
else
increment = 0; increment = 0;


pitch = th->body_start << 8; pitch = th->body_start << 8;
n_steps--; n_steps--;


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;
}
} }


if (stress >= PRIMARY) { if (stress >= PRIMARY) {
syl->stress = PRIMARY_STRESSED; syl->stress = PRIMARY_STRESSED;
set_pitch(syl, (pitch >> 8), drops[stress]); set_pitch(syl, (pitch >> 8), drops[stress]);
} else if (stress >= SECONDARY) {
} else if (stress >= SECONDARY)
set_pitch(syl, (pitch >> 8), drops[stress]); set_pitch(syl, (pitch >> 8), drops[stress]);
} else {
else {
/* unstressed, drop pitch if preceded by PRIMARY */ /* unstressed, drop pitch if preceded by PRIMARY */
if ((syllable_tab[ix-1].stress & 0x3f) >= SECONDARY) if ((syllable_tab[ix-1].stress & 0x3f) >= SECONDARY)
set_pitch(syl, (pitch >> 8) - th->body_lower_u, drops[stress]); set_pitch(syl, (pitch >> 8) - th->body_lower_u, drops[stress]);
if (n_increments <= 0) if (n_increments <= 0)
return; return;


if (n_increments > 1) {
if (n_increments > 1)
increment = increment / n_increments; increment = increment / n_increments;
}


pitch = start_pitch << 8; pitch = start_pitch << 8;


/* body of tonic segment */ /* body of tonic segment */
/*************************/ /*************************/


if (option_tone_flags & OPTION_EMPHASIZE_PENULTIMATE) {
if (option_tone_flags & OPTION_EMPHASIZE_PENULTIMATE)
tone_posn = tone_posn2; // put tone on the penultimate stressed word tone_posn = tone_posn2; // put tone on the penultimate stressed word
}
ix = SetHeadIntonation(tune, ix, tone_posn, 0); ix = SetHeadIntonation(tune, ix, tone_posn, 0);


if (no_tonic) if (no_tonic)
int drop; int drop;
int continuing = 0; int continuing = 0;


if (control == 0) {
if (control == 0)
return calc_pitches2(start, end, tune_number); return calc_pitches2(start, end, tune_number);
}


if (start > 0) if (start > 0)
continuing = 1; continuing = 1;
/* body of tonic segment */ /* body of tonic segment */
/*************************/ /*************************/


if (option_tone_flags & OPTION_EMPHASIZE_PENULTIMATE) {
if (option_tone_flags & OPTION_EMPHASIZE_PENULTIMATE)
tone_posn = tone_posn2; // put tone on the penultimate stressed word tone_posn = tone_posn2; // put tone on the penultimate stressed word
}
ix = calc_pitch_segment(ix, tone_posn, th, tn, PRIMARY, continuing); ix = calc_pitch_segment(ix, tone_posn, th, tn, PRIMARY, continuing);


if (no_tonic) if (no_tonic)
prevw_tph = phoneme_tab[phonPAUSE]; // forget previous tone prevw_tph = phoneme_tab[phonPAUSE]; // forget previous tone
} }


if (p->newword) {
if (p->newword)
prev_tph = phoneme_tab[phonPAUSE]; // forget across word boundaries prev_tph = phoneme_tab[phonPAUSE]; // forget across word boundaries
}


if (p->synthflags & SFLAG_SYLLABLE) { if (p->synthflags & SFLAG_SYLLABLE) {
tone_ph = p->tone_ph; tone_ph = p->tone_ph;
if (pause || tone_promoted) { if (pause || tone_promoted) {
tone_ph = PhonemeCode2('5', '5'); // no previous vowel, use tone 1 tone_ph = PhonemeCode2('5', '5'); // no previous vowel, use tone 1
tone_promoted = 1; tone_promoted = 1;
} else {
} else
tone_ph = PhonemeCode2('1', '1'); // default tone 5 tone_ph = PhonemeCode2('1', '1'); // default tone 5
}


p->tone_ph = tone_ph; p->tone_ph = tone_ph;
tph = phoneme_tab[tone_ph]; tph = phoneme_tab[tone_ph];


} else {
} else
tone_promoted = 0; tone_promoted = 0;
}


if (ix == final_stressed) { if (ix == final_stressed) {
if ((tph->mnemonic == 0x3535 ) || (tph->mnemonic == 0x3135)) { if ((tph->mnemonic == 0x3535 ) || (tph->mnemonic == 0x3135)) {
else else
prev_p->tone_ph = PhonemeCode2('2', '1'); prev_p->tone_ph = PhonemeCode2('2', '1');
} }
if ((prev_tph->mnemonic == 0x3135) && (tph->mnemonic == 0x3135)) { // [51] + [51]
if ((prev_tph->mnemonic == 0x3135) && (tph->mnemonic == 0x3135)) // [51] + [51]
prev_p->tone_ph = PhonemeCode2('5', '3'); prev_p->tone_ph = PhonemeCode2('5', '3');
}


if (tph->mnemonic == 0x3131) { // [11] Tone 5 if (tph->mnemonic == 0x3131) { // [11] Tone 5
// tone 5, change its level depending on the previous tone (across word boundaries) // tone 5, change its level depending on the previous tone (across word boundaries)


if (p->stresslevel >= 4) if (p->stresslevel >= 4)
n_primary++; n_primary++;
} else if ((p->ph->code == phonPAUSE_CLAUSE) && (n_st > 0)) {
} else if ((p->ph->code == phonPAUSE_CLAUSE) && (n_st > 0))
syllable_tab[n_st-1].flags |= SYL_END_CLAUSE; syllable_tab[n_st-1].flags |= SYL_END_CLAUSE;
}
} }
syllable_tab[n_st].stress = 0; // extra 0 entry at the end syllable_tab[n_st].stress = 0; // extra 0 entry at the end


p->pitch2 = syl->pitch2; p->pitch2 = syl->pitch2;


p->env = PITCHfall; p->env = PITCHfall;
if (syl->flags & SYL_RISE) {
if (syl->flags & SYL_RISE)
p->env = PITCHrise; p->env = PITCHrise;
} else if (p->stresslevel > 5)
else if (p->stresslevel > 5)
p->env = syl->env; p->env = syl->env;


if (p->pitch1 > p->pitch2) { if (p->pitch1 > p->pitch2) {
p->pitch1 = x + ph->start_type; p->pitch1 = x + ph->start_type;
} }


if (syl->flags & SYL_EMPHASIS) {
if (syl->flags & SYL_EMPHASIS)
p->stresslevel |= 8; // emphasized p->stresslevel |= 8; // emphasized
}


st_ix++; st_ix++;
} }

+ 29
- 54
src/libespeak-ng/klatt.c View File



result = samples[itemp] + diff_value; result = samples[itemp] + diff_value;
result = result * kt_globals.sample_factor; result = result * kt_globals.sample_factor;
} else {
} else
result = 0; result = 0;
}
return result; return result;
} }


second half of glottal period) if voicing simultaneously present. second half of glottal period) if voicing simultaneously present.
*/ */


if (kt_globals.nper > kt_globals.nmod) {
if (kt_globals.nper > kt_globals.nmod)
noise *= (double)0.5; noise *= (double)0.5;
}


/* Compute frication noise */ /* Compute frication noise */
frics = kt_globals.amp_frica * noise; frics = kt_globals.amp_frica * noise;
*/ */




if (kt_globals.nper < kt_globals.nopen) {
if (kt_globals.nper < kt_globals.nopen)
voice += kt_globals.amp_breth * kt_globals.nrand; voice += kt_globals.amp_breth * kt_globals.nrand;
}


/* Set amplitude of voicing */ /* Set amplitude of voicing */
glotout = kt_globals.amp_voice * voice; glotout = kt_globals.amp_voice * voice;
sourc = frics + par_glotout - glotlast; sourc = frics + par_glotout - glotlast;
glotlast = par_glotout; glotlast = par_glotout;


for (ix = R2p; ix <= R6p; ix++) {
for (ix = R2p; ix <= R6p; ix++)
out = resonator(&(kt_globals.rsn[ix]), sourc) - out; out = resonator(&(kt_globals.rsn[ix]), sourc) - out;
}


outbypas = kt_globals.amp_bypas * sourc; outbypas = kt_globals.amp_bypas * sourc;


if (echo_tail >= N_ECHO_BUF) if (echo_tail >= N_ECHO_BUF)
echo_tail = 0; echo_tail = 0;


if (value < -32768) {
if (value < -32768)
value = -32768; value = -32768;
}


if (value > 32767) {
if (value > 32767)
value = 32767; value = 32767;
}


*out_ptr++ = value; *out_ptr++ = value;
*out_ptr++ = value >> 8; *out_ptr++ = value >> 8;
echo_head = 0; echo_head = 0;


sample_count++; sample_count++;
if (out_ptr >= out_end) {
if (out_ptr >= out_end)
return 1; return 1;
}
} }
return 0; return 0;
} }
kt_globals.original_f0 = frame->F0hz10 / 10; kt_globals.original_f0 = frame->F0hz10 / 10;


frame->AVdb_tmp = frame->AVdb - 7; frame->AVdb_tmp = frame->AVdb - 7;
if (frame->AVdb_tmp < 0) {
if (frame->AVdb_tmp < 0)
frame->AVdb_tmp = 0; frame->AVdb_tmp = 0;
}


kt_globals.amp_aspir = DBtoLIN(frame->ASP) * 0.05; kt_globals.amp_aspir = DBtoLIN(frame->ASP) * 0.05;
kt_globals.amp_frica = DBtoLIN(frame->AF) * 0.25; kt_globals.amp_frica = DBtoLIN(frame->AF) * 0.25;
} }


Gain0_tmp = frame->Gain0 - 3; Gain0_tmp = frame->Gain0 - 3;
if (Gain0_tmp <= 0) {
if (Gain0_tmp <= 0)
Gain0_tmp = 57; Gain0_tmp = 57;
}
kt_globals.amp_gain0 = DBtoLIN(Gain0_tmp) / kt_globals.scale_wav; kt_globals.amp_gain0 = DBtoLIN(Gain0_tmp) / kt_globals.scale_wav;


/* Set coefficients of variable cascade resonators */ /* Set coefficients of variable cascade resonators */
static double doublet[] = { 0.0, 13000000.0, -13000000.0 }; static double doublet[] = { 0.0, 13000000.0, -13000000.0 };
static double vwave; static double vwave;


if (kt_globals.nper < 3) {
if (kt_globals.nper < 3)
vwave = doublet[kt_globals.nper]; vwave = doublet[kt_globals.nper];
} else {
else
vwave = 0.0; vwave = 0.0;
}


return resonator(&(kt_globals.rsn[RGL]), vwave); return resonator(&(kt_globals.rsn[RGL]), vwave);
} }
lgtemp = vwave * 0.028; lgtemp = vwave * 0.028;


return lgtemp; return lgtemp;
} else {
vwave = 0.0;
return 0.0;
} }
vwave = 0.0;
return 0.0;
} }




/* Duration of period before amplitude modulation */ /* Duration of period before amplitude modulation */


kt_globals.nmod = kt_globals.T0; kt_globals.nmod = kt_globals.T0;
if (frame->AVdb_tmp > 0) {
if (frame->AVdb_tmp > 0)
kt_globals.nmod >>= 1; kt_globals.nmod >>= 1;
}


/* Breathiness of voicing waveform */ /* Breathiness of voicing waveform */




kt_globals.nopen = 4 * frame->Kopen; kt_globals.nopen = 4 * frame->Kopen;


if ((kt_globals.glsource == IMPULSIVE) && (kt_globals.nopen > 263)) {
if ((kt_globals.glsource == IMPULSIVE) && (kt_globals.nopen > 263))
kt_globals.nopen = 263; kt_globals.nopen = 263;
}


if (kt_globals.nopen >= (kt_globals.T0-1)) {
if (kt_globals.nopen >= (kt_globals.T0-1))
kt_globals.nopen = kt_globals.T0 - 2; kt_globals.nopen = kt_globals.T0 - 2;
}


if (kt_globals.nopen < 40) { if (kt_globals.nopen < 40) {
/* F0 max = 1000 Hz */ /* F0 max = 1000 Hz */




temp = kt_globals.T0 - kt_globals.nopen; temp = kt_globals.T0 - kt_globals.nopen;
if (frame->Kskew > temp) {
if (frame->Kskew > temp)
frame->Kskew = temp; frame->Kskew = temp;
}
if (skew >= 0) {
if (skew >= 0)
skew = frame->Kskew; skew = frame->Kskew;
} 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;


kt_globals.decay = (0.033 * frame->TLTdb); kt_globals.decay = (0.033 * frame->TLTdb);


if (kt_globals.decay > 0.0) {
if (kt_globals.decay > 0.0)
kt_globals.onemd = 1.0 - kt_globals.decay; kt_globals.onemd = 1.0 - kt_globals.decay;
} else {
else
kt_globals.onemd = 1.0; kt_globals.onemd = 1.0;
}
} }
} }


26214, 29491, 32767 26214, 29491, 32767
}; };


if ((dB < 0) || (dB > 87)) {
if ((dB < 0) || (dB > 87))
return 0; return 0;
}


return (double)(amptable[dB]) * 0.001; return (double)(amptable[dB]) * 0.001;
} }
int ix; int ix;
int fade; int fade;


if (resume == 0) {
if (resume == 0)
sample_count = 0; sample_count = 0;
}


while (sample_count < nsamples) { while (sample_count < nsamples) {
kt_frame.F0hz10 = (wdata.pitch * 10) / 4096; kt_frame.F0hz10 = (wdata.pitch * 10) / 4096;
// F0 is used for the nasal zero // F0 is used for the nasal zero
for (ix = 0; ix < 6; ix++) { for (ix = 0; ix < 6; ix++) {
kt_frame.Fhz[ix] = peaks[ix].freq; kt_frame.Fhz[ix] = peaks[ix].freq;
if (ix < 4) {
if (ix < 4)
kt_frame.Bhz[ix] = peaks[ix].bw; kt_frame.Bhz[ix] = peaks[ix].bw;
}
} }
for (ix = 1; ix < 7; ix++) {
for (ix = 1; ix < 7; ix++)
kt_frame.Ap[ix] = peaks[ix].ap; kt_frame.Ap[ix] = peaks[ix].ap;
}


kt_frame.AVdb = klattp[KLATT_AV]; kt_frame.AVdb = klattp[KLATT_AV];
kt_frame.AVpdb = klattp[KLATT_AVp]; kt_frame.AVpdb = klattp[KLATT_AVp];


for (ix = 0; ix <= 6; ix++) { for (ix = 0; ix <= 6; ix++) {
kt_frame.Fhz_next[ix] = peaks[ix].freq; kt_frame.Fhz_next[ix] = peaks[ix].freq;
if (ix < 4) {
if (ix < 4)
kt_frame.Bhz_next[ix] = peaks[ix].bw; kt_frame.Bhz_next[ix] = peaks[ix].bw;
}
} }


// advance the pitch // advance the pitch


frame_init(&kt_frame); /* get parameters for next frame of speech */ frame_init(&kt_frame); /* get parameters for next frame of speech */


if (parwave(&kt_frame) == 1) {
if (parwave(&kt_frame) == 1)
return 1; // output buffer is full return 1; // output buffer is full
}
} }


if (end_wave > 0) { if (end_wave > 0) {
end_wave = 0; end_wave = 0;
sample_count -= fade; sample_count -= fade;
kt_globals.nspfr = fade; kt_globals.nspfr = fade;
if (parwave(&kt_frame) == 1) {
if (parwave(&kt_frame) == 1)
return 1; // output buffer is full return 1; // output buffer is full
}
} }


return 0; return 0;
} }


end_wave = 0; end_wave = 0;
if (control & 2) {
if (control & 2)
end_wave = 1; // fadeout at the end end_wave = 1; // fadeout at the end
}
if (control & 1) { if (control & 1) {
end_wave = 1; end_wave = 1;
for (qix = wcmdq_head+1;; qix++) { for (qix = wcmdq_head+1;; qix++) {

+ 11
- 12
src/libespeak-ng/mbrowrap.c View File



if (pipe(p1) != -1) { if (pipe(p1) != -1) {
if (pipe(p2) != -1) { if (pipe(p2) != -1) {
if (pipe(p3) != -1) {
if (pipe(p3) != -1)
return 0; return 0;
} else
else
error = errno; error = errno;
close(p2[0]); close(p2[0]);
close(p2[1]); close(p2[1]);
char msgbuf[80]; char msgbuf[80];


pid = waitpid(mbr_pid, &status, WNOHANG); pid = waitpid(mbr_pid, &status, WNOHANG);
if (!pid) {
if (!pid)
msg = "mbrola closed stderr and did not exit"; msg = "mbrola closed stderr and did not exit";
} else if (pid != mbr_pid) {
else if (pid != mbr_pid)
msg = "waitpid() is confused"; msg = "waitpid() is confused";
} else {
else {
mbr_pid = 0; mbr_pid = 0;
if (WIFSIGNALED(status)) { if (WIFSIGNALED(status)) {
int sig = WTERMSIG(status); int sig = WTERMSIG(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";
}
} }


log("mbrowrap error: %s", msg); log("mbrowrap error: %s", msg);


if (result == -1) { if (result == -1) {
int error = errno; int error = errno;
if (error == EPIPE && mbrola_has_errors()) {
if (error == EPIPE && mbrola_has_errors())
return -1; return -1;
} else if (error == EAGAIN) {
else if (error == EAGAIN)
result = 0; result = 0;
} else {
else {
err("write(): %s", strerror(error)); err("write(): %s", strerror(error));
return -1; return -1;
} }
err("write(): %s", strerror(error)); err("write(): %s", strerror(error));
return -1; return -1;
} }
if (result != left) {
if (result != left)
head->done += result; head->done += result;
} else {
else {
mbr_pending_data_head = head->next; mbr_pending_data_head = head->next;
free(head); free(head);
if (!mbr_pending_data_head) if (!mbr_pending_data_head)

+ 45
- 83
src/libespeak-ng/numbers.c View File



if (Lookup(tr, &single_letter[1], ph_buf) == 0) { if (Lookup(tr, &single_letter[1], ph_buf) == 0) {
single_letter[1] = ' '; single_letter[1] = ' ';
if (Lookup(tr, &single_letter[2], ph_buf) == 0) {
if (Lookup(tr, &single_letter[2], ph_buf) == 0)
TranslateRules(tr, &single_letter[2], ph_buf, 20, NULL, 0, NULL); TranslateRules(tr, &single_letter[2], ph_buf, 20, NULL, 0, NULL);
}
} }
return ph_buf[0]; return ph_buf[0];
} }


ph_accent2[0] = 0; ph_accent2[0] = 0;


if ((letter >= 0xe0) && (letter < 0x17f)) {
if ((letter >= 0xe0) && (letter < 0x17f))
accent_data = letter_accents_0e0[letter - 0xe0]; accent_data = letter_accents_0e0[letter - 0xe0];
} else if ((letter >= 0x250) && (letter <= 0x2a8)) {
else if ((letter >= 0x250) && (letter <= 0x2a8))
accent_data = letter_accents_250[letter - 0x250]; accent_data = letter_accents_250[letter - 0x250];
}


if (accent_data != 0) { if (accent_data != 0) {
basic_letter = (accent_data & 0x3f) + 59; basic_letter = (accent_data & 0x3f) + 59;


if (Lookup(tr, &single_letter[1], ph_buf3) == 0) { if (Lookup(tr, &single_letter[1], ph_buf3) == 0) {
single_letter[1] = ' '; single_letter[1] = ' ';
if (Lookup(tr, &single_letter[2], ph_buf3) == 0) {
if (Lookup(tr, &single_letter[2], ph_buf3) == 0)
TranslateRules(tr, &single_letter[2], ph_buf3, sizeof(ph_buf3), NULL, FLAG_NO_TRACE, NULL); TranslateRules(tr, &single_letter[2], ph_buf3, sizeof(ph_buf3), NULL, FLAG_NO_TRACE, NULL);
}
} }


if (ph_buf3[0] == 0) {
if (ph_buf3[0] == 0)
LookupAccentedLetter(tr, letter, ph_buf3); LookupAccentedLetter(tr, letter, ph_buf3);
}


strcpy(ph_buf1, ph_buf3); strcpy(ph_buf1, ph_buf3);
if ((ph_buf1[0] == 0) || (ph_buf1[0] == phonSWITCH)) {
if ((ph_buf1[0] == 0) || (ph_buf1[0] == phonSWITCH))
return; return;
}


dict_flags[0] = 0; dict_flags[0] = 0;
dict_flags[1] = 0; dict_flags[1] = 0;


n_bytes = utf8_in(&letter, word); n_bytes = utf8_in(&letter, word);


if ((letter & 0xfff00) == 0x0e000) {
if ((letter & 0xfff00) == 0x0e000)
letter &= 0xff; // uncode private usage area letter &= 0xff; // uncode private usage area
}


if (control & 2) { if (control & 2) {
// include CAPITAL information // include CAPITAL information
if (iswupper2(letter)) {
if (iswupper2(letter))
Lookup(tr, "_cap", capital); Lookup(tr, "_cap", capital);
}
} }
letter = towlower2(letter); letter = towlower2(letter);
LookupLetter(tr, letter, word[n_bytes], ph_buf, control & 1); LookupLetter(tr, letter, word[n_bytes], ph_buf, control & 1);
ph_buf[3] = 0; ph_buf[3] = 0;
TranslateRules(translator2, &hangul_buf[1], &ph_buf[3], sizeof(ph_buf)-3, NULL, 0, NULL); TranslateRules(translator2, &hangul_buf[1], &ph_buf[3], sizeof(ph_buf)-3, NULL, 0, NULL);
SetWordStress(translator2, &ph_buf[3], NULL, -1, 0); SetWordStress(translator2, &ph_buf[3], NULL, -1, 0);
} else {
} else
LookupLetter(translator2, letter, word[n_bytes], &ph_buf[3], control & 1); LookupLetter(translator2, letter, word[n_bytes], &ph_buf[3], control & 1);
}


if (ph_buf[3] == phonSWITCH) { if (ph_buf[3] == phonSWITCH) {
// another level of language change // another level of language change
if ((ph_buf[0] == 0) && !iswspace(letter)) if ((ph_buf[0] == 0) && !iswspace(letter))
Lookup(translator, "_??", ph_buf); Lookup(translator, "_??", ph_buf);


if (ph_buf[0] == 0) {
if (ph_buf[0] == 0)
EncodePhonemes("l'et@", ph_buf, NULL); EncodePhonemes("l'et@", ph_buf, NULL);
}
} }


if (!(control & 4) && (al_flags & AL_NOT_CODE)) { if (!(control & 4) && (al_flags & AL_NOT_CODE)) {
// braille dots symbol, list the numbered dots // braille dots symbol, list the numbered dots
p2 = hexbuf; p2 = hexbuf;
for (ix = 0; ix < 8; ix++) { for (ix = 0; ix < 8; ix++) {
if (letter & (1 << ix)) {
if (letter & (1 << ix))
*p2++ = '1'+ix; *p2++ = '1'+ix;
}
} }
*p2 = 0; *p2 = 0;
} else { } else {
unsigned char buf[N_WORD_PHONEMES]; unsigned char buf[N_WORD_PHONEMES];


for (ix = 0; (c = phonemes[ix]) != 0; ix++) { for (ix = 0; (c = phonemes[ix]) != 0; ix++) {
if ((c == phonSTRESS_P) && (prev != phonSWITCH)) {
if ((c == phonSTRESS_P) && (prev != phonSWITCH))
n_stress++; n_stress++;
}
buf[ix] = prev = c; buf[ix] = prev = c;
} }
buf[ix] = 0; buf[ix] = 0;
if ((roman == 0) && (tr->translator_name == L('h', 'u'))) { if ((roman == 0) && (tr->translator_name == L('h', 'u'))) {
// lang=hu don't treat dot as ordinal indicator if the next word is a month name ($alt). It may have a suffix. // lang=hu don't treat dot as ordinal indicator if the next word is a month name ($alt). It may have a suffix.
nextflags = 0; nextflags = 0;
if (IsAlpha(c2)) {
if (IsAlpha(c2))
nextflags = TranslateWord(tr, &word_end[2], 0, NULL, NULL); nextflags = TranslateWord(tr, &word_end[2], 0, NULL, NULL);
}


if ((tr->prev_dict_flags[0] & FLAG_ALT_TRANS) && ((c2 == 0) || (wtab[0].flags & FLAG_COMMA_AFTER) || iswdigit(c2))) if ((tr->prev_dict_flags[0] & FLAG_ALT_TRANS) && ((c2 == 0) || (wtab[0].flags & FLAG_COMMA_AFTER) || iswdigit(c2)))
ordinal = 0; // TEST 09.02.10 ordinal = 0; // TEST 09.02.10
} else } else
return 0; return 0;
} }
} else {
} else
wtab[0].flags |= FLAG_ORDINAL; wtab[0].flags |= FLAG_ORDINAL;
}
} }


tr->prev_dict_flags[0] = 0; tr->prev_dict_flags[0] = 0;
} }


if (found_value == 0) { if (found_value == 0) {
if ((value % 100) >= 20) {
if ((value % 100) >= 20)
Lookup(tr, "_0of", ph_of); Lookup(tr, "_0of", ph_of);
}


found = 0; found = 0;
if (thousands_exact & 1) { if (thousands_exact & 1) {
ph_digits[0] = 0; ph_digits[0] = 0;
ph_and[0] = 0; ph_and[0] = 0;


if (control & 0x20) {
if (control & 0x20)
ord_type = 'q'; ord_type = 'q';
}


is_ordinal = control & 1; is_ordinal = control & 1;


if ((ix > 0) && (phoneme_tab[(unsigned char)(ph_out[ix-1])]->type == phVOWEL)) if ((ix > 0) && (phoneme_tab[(unsigned char)(ph_out[ix-1])]->type == phVOWEL))
ix--; ix--;
sprintf(&ph_out[ix], "%s", ph_ordinal); sprintf(&ph_out[ix], "%s", ph_ordinal);
} else {
} else
sprintf(ph_out, "%s%s%s", ph_tens, ph_digits, ph_ordinal); sprintf(ph_out, "%s%s%s", ph_tens, ph_digits, ph_ordinal);
}
} }
} }


// special form for exact hundreds? // special form for exact hundreds?
found = Lookup(tr, "_0C0", ph_100); found = Lookup(tr, "_0C0", ph_100);
} }
if (!found) {
if (!found)
Lookup(tr, "_0C", ph_100); Lookup(tr, "_0C", ph_100);
}
} }


if (((tr->langopts.numbers & NUM_1900) != 0) && (hundreds == 19)) { if (((tr->langopts.numbers & NUM_1900) != 0) && (hundreds == 19)) {
exact = 1; exact = 1;


tplex = thousandplex+1; tplex = thousandplex+1;
if (tr->langopts.numbers2 & NUM2_MYRIADS) {
if (tr->langopts.numbers2 & NUM2_MYRIADS)
tplex = 0; tplex = 0;
}


if (LookupThousands(tr, hundreds / 10, tplex, exact | ordinal, ph_10T) == 0) { if (LookupThousands(tr, hundreds / 10, tplex, exact | ordinal, ph_10T) == 0) {
x = 0; x = 0;
ph_digits[0] = 0; ph_digits[0] = 0;


if ((hundreds > 0) || say_zero_hundred) { if ((hundreds > 0) || say_zero_hundred) {
if ((tr->langopts.numbers & NUM_AND_HUNDRED) && ((control & 1) || (ph_thousands[0] != 0))) {
if ((tr->langopts.numbers & NUM_AND_HUNDRED) && ((control & 1) || (ph_thousands[0] != 0)))
Lookup(tr, "_0and", ph_thousand_and); Lookup(tr, "_0and", ph_thousand_and);
}


suppress_null = 1; suppress_null = 1;


} }
} }


if ((hundreds == 0) && say_zero_hundred) {
if ((hundreds == 0) && say_zero_hundred)
Lookup(tr, "_0", ph_digits); Lookup(tr, "_0", ph_digits);
} else {
else {
if ((hundreds == 1) && (tr->langopts.numbers2 & NUM2_OMIT_1_HUNDRED_ONLY) && ((control & 1) == 0)) { if ((hundreds == 1) && (tr->langopts.numbers2 & NUM2_OMIT_1_HUNDRED_ONLY) && ((control & 1) == 0)) {
// only look for special 100 if there are previous thousands // only look for special 100 if there are previous thousands
} else { } else {
} }
} }


if (found) {
if (found)
ph_100[0] = 0; ph_100[0] = 0;
} else {
else {
say_one_hundred = 1; say_one_hundred = 1;
if (hundreds == 1) { if (hundreds == 1) {
if ((tr->langopts.numbers & NUM_OMIT_1_HUNDRED) != 0) if ((tr->langopts.numbers & NUM_OMIT_1_HUNDRED) != 0)
say_one_hundred = 0; say_one_hundred = 0;
} }


if (say_one_hundred != 0) {
if (say_one_hundred != 0)
LookupNum2(tr, hundreds, thousandplex, 0, ph_digits); LookupNum2(tr, hundreds, thousandplex, 0, ph_digits);
}
} }
} }
} }
// Don't use "and" if we apply ordinal to both hundreds and units // Don't use "and" if we apply ordinal to both hundreds and units
} else { } else {
if ((value > 100) || ((control & 1) && (thousandplex == 0))) { if ((value > 100) || ((control & 1) && (thousandplex == 0))) {
if ((tr->langopts.numbers & NUM_HUNDRED_AND) || ((tr->langopts.numbers & NUM_HUNDRED_AND_DIGIT) && (tensunits < 10))) {
if ((tr->langopts.numbers & NUM_HUNDRED_AND) || ((tr->langopts.numbers & NUM_HUNDRED_AND_DIGIT) && (tensunits < 10)))
Lookup(tr, "_0and", ph_hundred_and); Lookup(tr, "_0and", ph_hundred_and);
}
} }
if ((tr->langopts.numbers & NUM_THOUSAND_AND) && (hundreds == 0) && ((control & 1) || (ph_thousands[0] != 0))) {
if ((tr->langopts.numbers & NUM_THOUSAND_AND) && (hundreds == 0) && ((control & 1) || (ph_thousands[0] != 0)))
Lookup(tr, "_0and", ph_hundred_and); Lookup(tr, "_0and", ph_hundred_and);
}
} }
} }


x |= 4; // tens and units only, no higher digits x |= 4; // tens and units only, no higher digits
if (ordinal & 0x20) if (ordinal & 0x20)
x |= 0x20; // variant form of ordinal number x |= 0x20; // variant form of ordinal number
} else {
if (tr->langopts.numbers2 & (1 << thousandplex))
x = 8; // use variant (feminine) for before thousands and millions
}
} else if (tr->langopts.numbers2 & (1 << thousandplex))
x = 8; // use variant (feminine) for before thousands and millions


if ((tr->translator_name == L('m', 'l')) && (thousandplex == 1)) {
if ((tr->translator_name == L('m', 'l')) && (thousandplex == 1))
x |= 0x208; // use #f form for both tens and units x |= 0x208; // use #f form for both tens and units
}


if ((tr->langopts.numbers2 & NUM2_ZERO_TENS) && ((control & 1) || (hundreds > 0))) { if ((tr->langopts.numbers2 & NUM2_ZERO_TENS) && ((control & 1) || (hundreds > 0))) {
// LANG=zh, // LANG=zh,
prev_thousands = 1; prev_thousands = 1;
} else if ((tr->langopts.thousands_sep == ' ') || (tr->langopts.numbers & NUM_ALLOW_SPACE)) { } else if ((tr->langopts.thousands_sep == ' ') || (tr->langopts.numbers & NUM_ALLOW_SPACE)) {
// thousands groups can be separated by spaces // thousands groups can be separated by spaces
if ((n_digits == 3) && !(wtab->flags & FLAG_MULTIPLE_SPACES) && IsDigit09(word[-2])) {
if ((n_digits == 3) && !(wtab->flags & FLAG_MULTIPLE_SPACES) && IsDigit09(word[-2]))
prev_thousands = 1; prev_thousands = 1;
}
} }
if (prev_thousands == 0) {
if (prev_thousands == 0)
speak_missing_thousands = 0; speak_missing_thousands = 0;
}


ph_ordinal2[0] = 0; ph_ordinal2[0] = 0;
ph_zeros[0] = 0; ph_zeros[0] = 0;
*p++ = '-'; *p++ = '-';
ix++; ix++;
} }
while ((word[ix] != 0) && (word[ix] != ' ') && (ix < (int)(sizeof(suffix)-1))) {
while ((word[ix] != 0) && (word[ix] != ' ') && (ix < (int)(sizeof(suffix)-1)))
*p++ = word[ix++]; *p++ = word[ix++];
}
*p = 0; *p = 0;


if (suffix[0] != 0) { if (suffix[0] != 0) {
if ((tr->langopts.ordinal_indicator != NULL) && (strcmp(suffix, tr->langopts.ordinal_indicator) == 0)) {
if ((tr->langopts.ordinal_indicator != NULL) && (strcmp(suffix, tr->langopts.ordinal_indicator) == 0))
ordinal = 2; ordinal = 2;
} else if (!IsDigit09(suffix[0])) { // not _#9 (tab)
else if (!IsDigit09(suffix[0])) { // not _#9 (tab)
sprintf(string, "_#%s", suffix); sprintf(string, "_#%s", suffix);
if (Lookup(tr, string, ph_ordinal2)) { if (Lookup(tr, string, ph_ordinal2)) {
// this is an ordinal suffix // this is an ordinal suffix
} }


// speak leading zeros // speak leading zeros
for (ix = 0; (word[ix] == '0') && (ix < (n_digits-1)); ix++) {
for (ix = 0; (word[ix] == '0') && (ix < (n_digits-1)); ix++)
Lookup(tr, "_0", &ph_zeros[strlen(ph_zeros)]); Lookup(tr, "_0", &ph_zeros[strlen(ph_zeros)]);
}
} }
} }


} }
} }


if ((value == 0) && prev_thousands) {
if ((value == 0) && prev_thousands)
suppress_null = 1; suppress_null = 1;
}


if (tr->translator_name == L('h', 'u')) { if (tr->translator_name == L('h', 'u')) {
// variant form of numbers when followed by hyphen and a suffix starting with 'a' or 'e' (but not a, e, az, ez, azt, ezt // variant form of numbers when followed by hyphen and a suffix starting with 'a' or 'e' (but not a, e, az, ez, azt, ezt
if ((wtab[thousandplex].flags & FLAG_HYPHEN_AFTER) && (thousands_exact == 1) && hu_number_e(&word[suffix_ix], thousandplex, value)) {
if ((wtab[thousandplex].flags & FLAG_HYPHEN_AFTER) && (thousands_exact == 1) && hu_number_e(&word[suffix_ix], thousandplex, value))
number_control |= 1; // use _1e variant of number number_control |= 1; // use _1e variant of number
}
} }


if ((word[n_digits] == tr->langopts.decimal_sep) && IsDigit09(word[n_digits+1])) { if ((word[n_digits] == tr->langopts.decimal_sep) && IsDigit09(word[n_digits+1])) {
} }
} }


if ((ph_append[0] == 0) && (word[n_digits] == '.') && (thousandplex == 0)) {
if ((ph_append[0] == 0) && (word[n_digits] == '.') && (thousandplex == 0))
Lookup(tr, "_.", ph_append); Lookup(tr, "_.", ph_append);
}


if (thousandplex == 0) { if (thousandplex == 0) {
char *p2; char *p2;
while (IsDigit09(p[1])) p++; // just use the last digit while (IsDigit09(p[1])) p++; // just use the last digit
if (IsDigit09(p[-1])) { if (IsDigit09(p[-1])) {
p2 = p - 1; p2 = p - 1;
if (LookupDictList(tr, &p2, buf_digit_lookup, flags, FLAG_SUFX, wtab)) { // lookup 2 digits
if (LookupDictList(tr, &p2, buf_digit_lookup, flags, FLAG_SUFX, wtab)) // lookup 2 digits
n_digit_lookup = 2; n_digit_lookup = 2;
}
} }


if ((buf_digit_lookup[0] == 0) && (*p != '0')) { if ((buf_digit_lookup[0] == 0) && (*p != '0')) {
// LANG=hu ? // LANG=hu ?
// not found, lookup only the last digit (?? but not if dot-ordinal has been found) // not found, lookup only the last digit (?? but not if dot-ordinal has been found)
if (LookupDictList(tr, &p, buf_digit_lookup, flags, FLAG_SUFX, wtab)) { // don't match '0', or entries with $only
if (LookupDictList(tr, &p, buf_digit_lookup, flags, FLAG_SUFX, wtab)) // don't match '0', or entries with $only
n_digit_lookup = 1; n_digit_lookup = 1;
}
} }


if (prev_thousands == 0) { if (prev_thousands == 0) {
if ((decimal_point == 0) && (ordinal == 0)) { if ((decimal_point == 0) && (ordinal == 0)) {
// Look for special pronunciation for this number in isolation (LANG=kl) // Look for special pronunciation for this number in isolation (LANG=kl)
sprintf(string, "_%dn", value); sprintf(string, "_%dn", value);
if (Lookup(tr, string, ph_out)) {
if (Lookup(tr, string, ph_out))
return 1; return 1;
}
} }


if (tr->langopts.numbers2 & NUM2_PERCENT_BEFORE) { if (tr->langopts.numbers2 & NUM2_PERCENT_BEFORE) {
// LANG=si, say "percent" before the number // LANG=si, say "percent" before the number
p2 = word; p2 = word;
while ((*p2 != ' ') && (*p2 != 0)) {
while ((*p2 != ' ') && (*p2 != 0))
p2++; p2++;
}
if (p2[1] == '%') { if (p2[1] == '%') {
Lookup(tr, "%", ph_out); Lookup(tr, "%", ph_out);
ph_out += strlen(ph_out); ph_out += strlen(ph_out);
if ((c == tr->langopts.decimal_sep) && IsDigit09(word[n_digits+1])) { if ((c == tr->langopts.decimal_sep) && IsDigit09(word[n_digits+1])) {
Lookup(tr, "_dpt", buf1); Lookup(tr, "_dpt", buf1);
strcat(ph_out, buf1); strcat(ph_out, buf1);
} else {
} else
decimal_point = 0; decimal_point = 0;
}
} }
if ((ph_out[0] != 0) && (ph_out[0] != phonSWITCH)) { if ((ph_out[0] != 0) && (ph_out[0] != phonSWITCH)) {
int next_char; int next_char;
if ((option_sayas == SAYAS_DIGITS1) || (wtab[0].flags & FLAG_INDIVIDUAL_DIGITS)) if ((option_sayas == SAYAS_DIGITS1) || (wtab[0].flags & FLAG_INDIVIDUAL_DIGITS))
return 0; // speak digits individually return 0; // speak digits individually


if (tr->langopts.numbers != 0) {
if (tr->langopts.numbers != 0)
return TranslateNumber_1(tr, word1, ph_out, flags, wtab, control); return TranslateNumber_1(tr, word1, ph_out, flags, wtab, control);
}
return 0; return 0;
} }

+ 19
- 34
src/libespeak-ng/phonemelist.c View File

} }
} }


if (plist2->phcode == 0) {
if (plist2->phcode == 0)
continue; // phoneme has been replaced by NULL, so don't copy it continue; // phoneme has been replaced by NULL, so don't copy it
}
} }


// copy phoneme into the output list // copy phoneme into the output list
delete_count = 0; delete_count = 0;
current_phoneme_tab = tr->phoneme_tab_ix; current_phoneme_tab = tr->phoneme_tab_ix;
for (j = 0; j < n_ph_list2; j++) { for (j = 0; j < n_ph_list2; j++) {
if (current_phoneme_tab != tr->phoneme_tab_ix) {
if (current_phoneme_tab != tr->phoneme_tab_ix)
plist2[j].synthflags |= SFLAG_SWITCHED_LANG; plist2[j].synthflags |= SFLAG_SWITCHED_LANG;
}


if (delete_count > 0) {
if (delete_count > 0)
memcpy(&plist2[j-delete_count], &plist2[j], sizeof(plist2[0])); memcpy(&plist2[j-delete_count], &plist2[j], sizeof(plist2[0]));
}


if (plist2[j].phcode == phonSWITCH) { if (plist2[j].phcode == phonSWITCH) {
if ((!(plist2[j].synthflags & SFLAG_EMBEDDED)) && ( if ((!(plist2[j].synthflags & SFLAG_EMBEDDED)) && (
// 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
delete_count++; delete_count++;
} else {
} else
current_phoneme_tab = plist2[j].tone_ph; current_phoneme_tab = plist2[j].tone_ph;
}
} }


} }
} }


if ((type == phSTOP) || type == (phFRICATIVE)) { if ((type == phSTOP) || type == (phFRICATIVE)) {
if ((voicing == 0) && (regression & 0xf)) {
if ((voicing == 0) && (regression & 0xf))
voicing = 1; voicing = 1;
} else if ((voicing == 2) && (ph->end_type != 0)) { // use end_type field for voicing_switch for consonants
else if ((voicing == 2) && (ph->end_type != 0)) // use end_type field for voicing_switch for consonants
plist2[j].phcode = ph->end_type; // change to voiced equivalent plist2[j].phcode = ph->end_type; // change to voiced equivalent
}
} else if ((type == phVSTOP) || type == (phVFRICATIVE)) { } else if ((type == phVSTOP) || type == (phVFRICATIVE)) {
if ((voicing == 0) && (regression & 0xf)) {
if ((voicing == 0) && (regression & 0xf))
voicing = 2; voicing = 2;
} else if ((voicing == 1) && (ph->end_type != 0)) {
else if ((voicing == 1) && (ph->end_type != 0))
plist2[j].phcode = ph->end_type; // change to unvoiced equivalent plist2[j].phcode = ph->end_type; // change to unvoiced equivalent
}
} else { } else {
if (regression & 0x8) { if (regression & 0x8) {
// LANG=Polish, propagate through liquids and nasals // LANG=Polish, propagate through liquids and nasals
if ((type == phPAUSE) || (type == phVOWEL)) if ((type == phPAUSE) || (type == phVOWEL))
voicing = 0; voicing = 0;
} else {
} else
voicing = 0; voicing = 0;
}
} }
if (stop_propagation) { if (stop_propagation) {
voicing = 0; voicing = 0;
} }
if (regression & 0x100) { if (regression & 0x100) {
// devoice word-final consonants, unless propagating voiced // devoice word-final consonants, unless propagating voiced
if (voicing == 0) {
if (voicing == 0)
voicing = 1; voicing = 1;
}
} }
} }
} }
if (ph_list3[nextw].sourceix) if (ph_list3[nextw].sourceix)
break; // start of the next word break; // start of the next word
} }
for (k = j; k < nextw; k++) {
for (k = j; k < nextw; k++)
ph_list3[k].wordstress = word_stress; ph_list3[k].wordstress = word_stress;
}
j = nextw; j = nextw;
} else {
} else
j++; j++;
}
} }


// transfer all the phonemes of the clause into phoneme_list // transfer all the phonemes of the clause into phoneme_list
if (word_start > 0) { if (word_start > 0) {
k = word_start; k = word_start;
word_start--; word_start--;
} else {
} else
k = 2; // No more space, don't loose the start of word mark at ph_list2[word_start] k = 2; // No more space, don't loose the start of word mark at ph_list2[word_start]
}
for (; k <= j; k++) for (; k <= j; k++)
memcpy(&ph_list3[k-1], &ph_list3[k], sizeof(*plist3)); memcpy(&ph_list3[k-1], &ph_list3[k], sizeof(*plist3));
} }
plist3->ph = ph; plist3->ph = ph;
plist3->phcode = alternative; plist3->phcode = alternative;


if (alternative == 1) {
if (alternative == 1)
deleted = 1; // NULL phoneme, discard deleted = 1; // NULL phoneme, discard
} else {
else {
if (ph->type == phVOWEL) { if (ph->type == phVOWEL) {
plist3->synthflags |= SFLAG_SYLLABLE; plist3->synthflags |= SFLAG_SYLLABLE;
if (ph2->type != phVOWEL) if (ph2->type != phVOWEL)
if ((tr->langopts.stress_flags & S_NO_DIM) || ((word_stress > 3) && ((plist3+1)->sourceix != 0))) { if ((tr->langopts.stress_flags & S_NO_DIM) || ((word_stress > 3) && ((plist3+1)->sourceix != 0))) {
// An unstressed final vowel of a stressed word // An unstressed final vowel of a stressed word
unstress_count = 1; // try again for next syllable unstress_count = 1; // try again for next syllable
} else {
} else
plist3->stresslevel = 0; // change stress to 'diminished' plist3->stresslevel = 0; // change stress to 'diminished'
}
} }
} }
} else { } else {
insert_ph = pause_phonemes[x]; insert_ph = pause_phonemes[x];
} }
} }
if (option_wordgap > 0) {
if (option_wordgap > 0)
insert_ph = phonPAUSE_LONG; insert_ph = phonPAUSE_LONG;
}
} }
} }


next2 = phoneme_tab[plist3[2].phcode]; next2 = phoneme_tab[plist3[2].phcode];
plist3[2].ph = next2; plist3[2].ph = next2;


if ((insert_ph == 0) && (phdata.pd_param[pd_APPENDPHONEME] != 0)) {
if ((insert_ph == 0) && (phdata.pd_param[pd_APPENDPHONEME] != 0))
insert_ph = phdata.pd_param[pd_APPENDPHONEME]; insert_ph = phdata.pd_param[pd_APPENDPHONEME];
}


if (deleted == 0) { if (deleted == 0) {
phlist[ix].ph = ph; phlist[ix].ph = ph;
phlist[ix].newword = 5; // start of sentence + start of word phlist[ix].newword = 5; // start of sentence + start of word
start_sentence = 0; start_sentence = 0;
} }
} else {
} else
phlist[ix].newword = 0; phlist[ix].newword = 0;
}


phlist[ix].length = phdata.pd_param[i_SET_LENGTH]*2; phlist[ix].length = phdata.pd_param[i_SET_LENGTH]*2;
if ((ph->code == phonPAUSE_LONG) && (option_wordgap > 0) && (plist3[1].sourceix != 0)) { if ((ph->code == phonPAUSE_LONG) && (option_wordgap > 0) && (plist3[1].sourceix != 0)) {

+ 48
- 87
src/libespeak-ng/readclause.c View File

{ {
int ix = 0; int ix = 0;


while (*str != 0) {
while (*str != 0)
ix++; ix++;
}
return ix; return ix;
} }
#endif #endif


// check for non-standard upper to lower case conversions // check for non-standard upper to lower case conversions
if (c == 'I') { if (c == 'I') {
if (translator->langopts.dotless_i) {
if (translator->langopts.dotless_i)
c = 0x131; // I -> ı c = 0x131; // I -> ı
}
} }


if (c < 0x80) if (c < 0x80)
if (ungot2 != 0) { if (ungot2 != 0) {
c1 = ungot2; c1 = ungot2;
ungot2 = 0; ungot2 = 0;
} else {
} else
c1 = GetC_get(); c1 = GetC_get();
}


if ((option_multibyte == espeakCHARS_WCHAR) || (option_multibyte == espeakCHARS_16BIT)) { if ((option_multibyte == espeakCHARS_WCHAR) || (option_multibyte == espeakCHARS_16BIT)) {
count_characters++; count_characters++;
string = &single_letter[2]; string = &single_letter[2];
LookupDictList(translator2, &string, phonemes, flags, 0, NULL); LookupDictList(translator2, &string, phonemes, flags, 0, NULL);
} }
if (phonemes[0]) {
if (phonemes[0])
lang_name = "en"; lang_name = "en";
} else {
else
SelectPhonemeTable(voice->phoneme_tab_ix); // revert to original phoneme table SelectPhonemeTable(voice->phoneme_tab_ix); // revert to original phoneme table
}
} }


if (phonemes[0]) { if (phonemes[0]) {
DecodePhonemes(phonemes, phonemes2); DecodePhonemes(phonemes, phonemes2);
sprintf(buf, "[\002%s]] ", phonemes2); sprintf(buf, "[\002%s]] ", phonemes2);
} }
} else if (only == 0) {
} else if (only == 0)
strcpy(buf, "[\002(X1)(X1)(X1)]]"); strcpy(buf, "[\002(X1)(X1)(X1)]]");
}


return buf; return buf;
} }
if ((fd_temp = mkstemp(fname_temp)) >= 0) { if ((fd_temp = mkstemp(fname_temp)) >= 0) {
close(fd_temp); close(fd_temp);
sprintf(command, "sox \"%s\" -r %d -c1 -t wav %s\n", fname, samplerate, fname_temp); sprintf(command, "sox \"%s\" -r %d -c1 -t wav %s\n", fname, samplerate, fname_temp);
if (system(command) == 0) {
if (system(command) == 0)
fname = fname_temp; fname = fname_temp;
}
} }
} }
} }
UngetC(c2); UngetC(c2);
} else { } else {
if ((c1 == '.') && (end_clause) && (c2 != '.')) { if ((c1 == '.') && (end_clause) && (c2 != '.')) {
if (LookupSpecial(tr, "_.p", ph_buf)) {
if (LookupSpecial(tr, "_.p", ph_buf))
punctname = ph_buf; // use word for 'period' instead of 'dot' punctname = ph_buf; // use word for 'period' instead of 'dot'
}
} }
if (punctname == NULL) {
if (punctname == NULL)
punctname = LookupCharName(tr, c1, 0); punctname = LookupCharName(tr, c1, 0);
}


if (punctname == NULL) if (punctname == NULL)
return -1; return -1;
c2 = GetC(); c2 = GetC();
} }
*c2_ptr = c2; *c2_ptr = c2;
if (end_clause) {
if (end_clause)
UngetC(c2); UngetC(c2);
}


if (punct_count == 1) {
if (punct_count == 1)
sprintf(buf, " %s", punctname); // we need the space before punctname, to ensure it doesn't merge with the previous word (eg. "2.-a") sprintf(buf, " %s", punctname); // we need the space before punctname, to ensure it doesn't merge with the previous word (eg. "2.-a")
} else if (punct_count < 4) {
else if (punct_count < 4) {
buf[0] = 0; buf[0] = 0;
if (embedded_value[EMBED_S] < 300) if (embedded_value[EMBED_S] < 300)
sprintf(buf, "\001+10S"); // Speak punctuation name faster, unless we are already speaking fast. It would upset Sonic SpeedUp sprintf(buf, "\001+10S"); // Speak punctuation name faster, unless we are already speaking fast. It would upset Sonic SpeedUp
sprintf(buf2, " \001-10S"); sprintf(buf2, " \001-10S");
strcat(buf, buf2); strcat(buf, buf2);
} }
} else {
} else
sprintf(buf, " %s %d %s", sprintf(buf, " %s %d %s",
punctname, punct_count, punctname); punctname, punct_count, punctname);
}
} else { } else {
// end the clause now and pick up the punctuation next time // end the clause now and pick up the punctuation next time
UngetC(c2); UngetC(c2);
if (voice_name_specified == 0) if (voice_name_specified == 0)
voice_name[0] = 0; // forget a previous voice name if a language is specified voice_name[0] = 0; // forget a previous voice name if a language is specified
} }
if (sp->voice_gender != 0) {
if (sp->voice_gender != 0)
voice_select.gender = sp->voice_gender; voice_select.gender = sp->voice_gender;
}


if (sp->voice_age != 0) if (sp->voice_age != 0)
voice_select.age = sp->voice_age; voice_select.age = sp->voice_age;
n_param_stack++; n_param_stack++;


sp->type = tag_type; sp->type = tag_type;
for (ix = 0; ix < N_SPEECH_PARAM; ix++) {
for (ix = 0; ix < N_SPEECH_PARAM; ix++)
sp->parameter[ix] = -1; sp->parameter[ix] = -1;
}
return sp; return sp;
} }


tag_type -= SSML_CLOSE; tag_type -= SSML_CLOSE;


for (ix = 0; ix < n_param_stack; ix++) { for (ix = 0; ix < n_param_stack; ix++) {
if (param_stack[ix].type == tag_type) {
if (param_stack[ix].type == tag_type)
top = ix; top = ix;
}
} }
if (top > 0) {
if (top > 0)
n_param_stack = top; n_param_stack = top;
}
ProcessParamStack(outbuf, outix); ProcessParamStack(outbuf, outix);
} }


if ((pw == NULL) || !IsDigit09(*pw)) if ((pw == NULL) || !IsDigit09(*pw))
return default_value; return default_value;


while (IsDigit09(*pw)) {
while (IsDigit09(*pw))
value = value*10 + *pw++ - '0'; value = value*10 + *pw++ - '0';
}
if ((type == 1) && (towlower(*pw) == 's')) { if ((type == 1) && (towlower(*pw) == 's')) {
// time: seconds rather than ms // time: seconds rather than ms
value *= 1000; value *= 1000;
if (wide) { if (wide) {
len = (wcslen((const wchar_t *)name)+1)*sizeof(wchar_t); len = (wcslen((const wchar_t *)name)+1)*sizeof(wchar_t);
n_namedata = (n_namedata + sizeof(wchar_t) - 1) % sizeof(wchar_t); // round to wchar_t boundary n_namedata = (n_namedata + sizeof(wchar_t) - 1) % sizeof(wchar_t); // round to wchar_t boundary
} else {
} else
len = strlen(name)+1; len = strlen(name)+1;
}


if (namedata_ix+len >= n_namedata) { if (namedata_ix+len >= n_namedata) {
// allocate more space for marker names // allocate more space for marker names


if (tag_type & SSML_CLOSE) { if (tag_type & SSML_CLOSE) {
// delete a stack frame // delete a stack frame
if (n_ssml_stack > 1) {
if (n_ssml_stack > 1)
n_ssml_stack--; n_ssml_stack--;
}
} else { } else {
// add a stack frame if any voice details are specified // add a stack frame if any voice details are specified
lang = GetSsmlAttribute(pw, "xml:lang"); lang = GetSsmlAttribute(pw, "xml:lang");


if (tag_name[0] == '/') { if (tag_name[0] == '/') {
// closing tag // closing tag
if ((tag_type = LookupMnem(ssmltags, &tag_name[1])) != HTML_NOSPACE) {
if ((tag_type = LookupMnem(ssmltags, &tag_name[1])) != HTML_NOSPACE)
outbuf[(*outix)++] = ' '; outbuf[(*outix)++] = ' ';
}
tag_type += SSML_CLOSE; tag_type += SSML_CLOSE;
} else { } else {
if ((tag_type = LookupMnem(ssmltags, tag_name)) != HTML_NOSPACE) { if ((tag_type = LookupMnem(ssmltags, tag_name)) != HTML_NOSPACE) {


// look for attributes: rate, volume, pitch, range // look for attributes: rate, volume, pitch, range
for (param_type = espeakRATE; param_type <= espeakRANGE; param_type++) { for (param_type = espeakRATE; param_type <= espeakRANGE; param_type++) {
if ((attr1 = GetSsmlAttribute(px, prosody_attr[param_type])) != NULL) {
if ((attr1 = GetSsmlAttribute(px, prosody_attr[param_type])) != NULL)
SetProsodyParameter(param_type, attr1, sp); SetProsodyParameter(param_type, attr1, sp);
}
} }


ProcessParamStack(outbuf, outix); ProcessParamStack(outbuf, outix);
case SSML_EMPHASIS: case SSML_EMPHASIS:
sp = PushParamStack(tag_type); sp = PushParamStack(tag_type);
value = 3; // default is "moderate" value = 3; // default is "moderate"
if ((attr1 = GetSsmlAttribute(px, "level")) != NULL) {
if ((attr1 = GetSsmlAttribute(px, "level")) != NULL)
value = attrlookup(attr1, mnem_emphasis); value = attrlookup(attr1, mnem_emphasis);
}


if (translator->langopts.tone_language == 1) { if (translator->langopts.tone_language == 1) {
static unsigned char emphasis_to_pitch_range[] = { 50, 50, 40, 70, 90, 100 }; static unsigned char emphasis_to_pitch_range[] = { 50, 50, 40, 70, 90, 100 };
if ((xmlbase != NULL) && (buf[0] != '/')) { if ((xmlbase != NULL) && (buf[0] != '/')) {
sprintf(fname, "%s/%s", xmlbase, buf); sprintf(fname, "%s/%s", xmlbase, buf);
index = LoadSoundFile2(fname); index = LoadSoundFile2(fname);
} else {
} else
index = LoadSoundFile2(buf); index = LoadSoundFile2(buf);
}
if (index >= 0) { if (index >= 0) {
sprintf(buf, "%c%dI", CTRL_EMBEDDED, index); sprintf(buf, "%c%dI", CTRL_EMBEDDED, index);
strcpy(&outbuf[*outix], buf); strcpy(&outbuf[*outix], buf);
case SSML_SPEAK: case SSML_SPEAK:
if ((attr1 = GetSsmlAttribute(px, "xml:base")) != NULL) { if ((attr1 = GetSsmlAttribute(px, "xml:base")) != NULL) {
attrcopy_utf8(buf, attr1, sizeof(buf)); attrcopy_utf8(buf, attr1, sizeof(buf));
if ((index = AddNameData(buf, 0)) >= 0) {
if ((index = AddNameData(buf, 0)) >= 0)
xmlbase = &namedata[index]; xmlbase = &namedata[index];
}
} }
if (GetVoiceAttributes(px, tag_type) == 0) if (GetVoiceAttributes(px, tag_type) == 0)
return 0; // no voice change return 0; // no voice change


case SSML_SPEAK + SSML_CLOSE: case SSML_SPEAK + SSML_CLOSE:
// unwind stack until the previous <voice> or <speak> tag // unwind stack until the previous <voice> or <speak> tag
while ((n_ssml_stack > 1) && (ssml_stack[n_ssml_stack-1].tag_type != SSML_SPEAK)) {
while ((n_ssml_stack > 1) && (ssml_stack[n_ssml_stack-1].tag_type != SSML_SPEAK))
n_ssml_stack--; n_ssml_stack--;
}
return CLAUSE_PERIOD + GetVoiceAttributes(px, tag_type); return CLAUSE_PERIOD + GetVoiceAttributes(px, tag_type);


case SSML_VOICE + SSML_CLOSE: case SSML_VOICE + SSML_CLOSE:
// unwind stack until the previous <voice> or <speak> tag // unwind stack until the previous <voice> or <speak> tag
while ((n_ssml_stack > 1) && (ssml_stack[n_ssml_stack-1].tag_type != SSML_VOICE)) {
while ((n_ssml_stack > 1) && (ssml_stack[n_ssml_stack-1].tag_type != SSML_VOICE))
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);
ungot_word = NULL; ungot_word = NULL;
} }


if (ungot_char2 != 0) {
if (ungot_char2 != 0)
c2 = ungot_char2; c2 = ungot_char2;
} else {
else
c2 = GetC(); c2 = GetC();
}


while (!Eof() || (ungot_char != 0) || (ungot_char2 != 0) || (ungot_string_ix >= 0)) { while (!Eof() || (ungot_char != 0) || (ungot_char2 != 0) || (ungot_string_ix >= 0)) {
if (!iswalnum(c1)) { if (!iswalnum(c1)) {
ungot_string_ix = -1; ungot_string_ix = -1;
} }


if ((ungot_string_ix == 0) && (ungot_char2 == 0)) {
if ((ungot_string_ix == 0) && (ungot_char2 == 0))
c1 = ungot_string[ungot_string_ix++]; c1 = ungot_string[ungot_string_ix++];
}
if (ungot_string_ix >= 0) {
if (ungot_string_ix >= 0)
c2 = ungot_string[ungot_string_ix++]; c2 = ungot_string[ungot_string_ix++];
} else {
else {
c2 = GetC(); c2 = GetC();


if (Eof()) {
if (Eof())
c2 = ' '; c2 = ' ';
}
} }
ungot_char2 = 0; ungot_char2 = 0;


c2 = ' '; c2 = ' ';
} }
} }
} else {
} else
found = -1; found = -1;
}


if (found <= 0) { if (found <= 0) {
ungot_string_ix = 0; ungot_string_ix = 0;
} else if ((c1 == '<') && (ssml_ignore_l_angle != '<')) { } else if ((c1 == '<') && (ssml_ignore_l_angle != '<')) {
if ((c2 == '!') || (c2 == '?')) { if ((c2 == '!') || (c2 == '?')) {
// a comment, ignore until closing '<' (or <?xml tag ) // a comment, ignore until closing '<' (or <?xml tag )
while (!Eof() && (c1 != '>')) {
while (!Eof() && (c1 != '>'))
c1 = GetC(); c1 = GetC();
}
c2 = ' '; c2 = ' ';
} else if ((c2 == '/') || iswalpha2(c2)) { } else if ((c2 == '/') || iswalpha2(c2)) {
// check for space in the output buffer for embedded commands produced by the SSML tag // check for space in the output buffer for embedded commands produced by the SSML tag
buf[ix] = ' '; buf[ix] = ' ';
buf[ix++] = 0; buf[ix++] = 0;


if (terminator & CLAUSE_BIT_VOICE) {
if (terminator & CLAUSE_BIT_VOICE)
strcpy(voice_change, current_voice_id); strcpy(voice_change, current_voice_id);
}
return terminator; return terminator;
} }
c1 = ' '; c1 = ' ';
*charix_top = ix; *charix_top = ix;
ix += utf8_out(c1, &buf[ix]); ix += utf8_out(c1, &buf[ix]);
terminator = CLAUSE_PERIOD; // line doesn't end in punctuation, assume period terminator = CLAUSE_PERIOD; // line doesn't end in punctuation, assume period
} else {
} else
terminator = punct_attributes[punct]; terminator = punct_attributes[punct];
}
buf[ix] = ' '; buf[ix] = ' ';
buf[ix+1] = 0; buf[ix+1] = 0;
return terminator; return terminator;


if (c1 == 0xd4d) { if (c1 == 0xd4d) {
// Malayalam virama, check if next character is Zero-width-joiner // Malayalam virama, check if next character is Zero-width-joiner
if (c2 == 0x200d) {
if (c2 == 0x200d)
c1 = 0xd4e; // use this unofficial code for chillu-virama c1 = 0xd4e; // use this unofficial code for chillu-virama
}
} }
} }


// 2nd newline, assume paragraph // 2nd newline, assume paragraph
UngetC(c2); UngetC(c2);


if (end_clause_after_tag) {
if (end_clause_after_tag)
RemoveChar(&buf[end_clause_index]); // delete clause-end punctiation RemoveChar(&buf[end_clause_index]); // delete clause-end punctiation
}
buf[ix] = ' '; buf[ix] = ' ';
buf[ix+1] = 0; buf[ix+1] = 0;
if (parag > 3) if (parag > 3)
} }
} }


if ((c1 == '.') && (nl_count < 2)) {
if ((c1 == '.') && (nl_count < 2))
punct_data |= CLAUSE_DOT; punct_data |= CLAUSE_DOT;
}


if (nl_count == 0) { if (nl_count == 0) {
if ((c1 == ',') && (cprev == '.') && (tr->translator_name == L('h', 'u')) && iswdigit(cprev2) && (iswdigit(c_next) || (iswlower2(c_next)))) { if ((c1 == ',') && (cprev == '.') && (tr->translator_name == L('h', 'u')) && iswdigit(cprev2) && (iswdigit(c_next) || (iswlower2(c_next)))) {
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))
is_end_clause = 0; // Roman number followed by dot is_end_clause = 0; // Roman number followed by dot
} else {
else {
if (iswlower2(c_next) || (c_next == '-')) // hyphen is needed for lang-hu (eg. 2.-kal) if (iswlower2(c_next) || (c_next == '-')) // hyphen is needed for lang-hu (eg. 2.-kal)
is_end_clause = 0; // only if followed by lower-case, (or if there is a XML tag) is_end_clause = 0; // only if followed by lower-case, (or if there is a XML tag)
} }
} else if (c_next == '\'') {
} else if (c_next == '\'')
is_end_clause = 0; // eg. u.s.a.'s is_end_clause = 0; // eg. u.s.a.'s
}
if (iswlower2(c_next)) { if (iswlower2(c_next)) {
// next word has no capital letter, this dot is probably from an abbreviation // next word has no capital letter, this dot is probably from an abbreviation
is_end_clause = 0; is_end_clause = 0;
buf[ix] = ' '; buf[ix] = ' ';
buf[ix+1] = 0; buf[ix+1] = 0;


if (iswdigit(cprev) && !IsAlpha(c_next)) { // ????
if (iswdigit(cprev) && !IsAlpha(c_next)) // ????
punct_data &= ~CLAUSE_DOT; punct_data &= ~CLAUSE_DOT;
}
if (nl_count > 1) { if (nl_count > 1) {
if ((punct_data == CLAUSE_QUESTION) || (punct_data == CLAUSE_EXCLAMATION)) if ((punct_data == CLAUSE_QUESTION) || (punct_data == CLAUSE_EXCLAMATION))
return punct_data + 35; // with a longer pause return punct_data + 35; // with a longer pause
if (c1 == announced_punctuation) { if (c1 == announced_punctuation) {
// This character has already been announced, so delete it so that it isn't spoken a second time. // This character has already been announced, so delete it so that it isn't spoken a second time.
// Unless it's a hyphen or apostrophe (which is used by TranslateClause() ) // Unless it's a hyphen or apostrophe (which is used by TranslateClause() )
if (IsBracket(c1)) {
if (IsBracket(c1))
c1 = 0xe000 + '('; // Unicode private useage area. So TranslateRules() knows the bracket name has been spoken c1 = 0xe000 + '('; // Unicode private useage area. So TranslateRules() knows the bracket name has been spoken
} else if (c1 != '-') {
else if (c1 != '-')
c1 = ' '; c1 = ' ';
}
} }


j = ix+1; j = ix+1;
} }
} }


if (stressed_word) {
if (stressed_word)
ix += utf8_out(CHAR_EMPHASIS, &buf[ix]); ix += utf8_out(CHAR_EMPHASIS, &buf[ix]);
}
if (end_clause_after_tag) {
if (end_clause_after_tag)
RemoveChar(&buf[end_clause_index]); // delete clause-end punctiation RemoveChar(&buf[end_clause_index]); // delete clause-end punctiation
}
buf[ix] = ' '; buf[ix] = ' ';
buf[ix+1] = 0; buf[ix+1] = 0;
return CLAUSE_EOF; // end of file return CLAUSE_EOF; // end of file

+ 32
- 56
src/libespeak-ng/setlengths.c View File



wpm_value = wpm; wpm_value = wpm;


if (voice->speed_percent > 0) {
if (voice->speed_percent > 0)
wpm = (wpm * voice->speed_percent)/100; wpm = (wpm * voice->speed_percent)/100;
}


if (control & 2) {
if (control & 2)
DoSonicSpeed(1 * 1024); DoSonicSpeed(1 * 1024);
}
if ((wpm_value >= 450) || ((wpm_value > speed.fast_settings[0]) && (wpm > 350))) { if ((wpm_value >= 450) || ((wpm_value > speed.fast_settings[0]) && (wpm > 350))) {
wpm2 = wpm; wpm2 = wpm;
wpm = 175; wpm = 175;
if (wpm > 450) if (wpm > 450)
wpm = 450; wpm = 450;


if (wpm > 360) {
if (wpm > 360)
speed.loud_consonants = (wpm - 360) / 8; speed.loud_consonants = (wpm - 360) / 8;
}


wpm2 = wpm; wpm2 = wpm;
if (wpm > 359) wpm2 = 359; if (wpm > 359) wpm2 = 359;
else else
speed.wav_factor = 128 + (128*s1)/130; // = 215 at 170 wpm speed.wav_factor = 128 + (128*s1)/130; // = 215 at 170 wpm


if (wpm >= 350) {
if (wpm >= 350)
speed.wav_factor = wav_factor_350[wpm-350]; speed.wav_factor = wav_factor_350[wpm-350];
}


if (wpm >= 390) { if (wpm >= 390) {
speed.min_sample_len = 450 - (wpm - 400)/2; speed.min_sample_len = 450 - (wpm - 400)/2;
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;


if (wpm > 430) {
if (wpm > 430)
speed.pause_factor = 12; speed.pause_factor = 12;
} else if (wpm > 400) {
else if (wpm > 400)
speed.pause_factor = 13; speed.pause_factor = 13;
} else if (wpm > 374) {
else if (wpm > 374)
speed.pause_factor = 14; speed.pause_factor = 14;
} else if (wpm > 350) {
else if (wpm > 350)
speed.pause_factor = pause_factor_350[wpm - 350]; speed.pause_factor = pause_factor_350[wpm - 350];
}


if (speed.clause_pause_factor == 0) { if (speed.clause_pause_factor == 0) {
// restrict the reduction of pauses between clauses // restrict the reduction of pauses between clauses
if (control == 2) if (control == 2)
wpm = embedded_value[EMBED_S2]; wpm = embedded_value[EMBED_S2];


if (voice->speed_percent > 0) {
if (voice->speed_percent > 0)
wpm = (wpm * voice->speed_percent)/100; wpm = (wpm * voice->speed_percent)/100;
}
if (wpm > 450) if (wpm > 450)
wpm = 450; wpm = 450;


if (wpm > 360) {
if (wpm > 360)
speed.loud_consonants = (wpm - 360) / 8; speed.loud_consonants = (wpm - 360) / 8;
}


wpm2 = wpm; wpm2 = wpm;
if (wpm > 359) wpm2 = 359; if (wpm > 359) wpm2 = 359;
else else
speed.wav_factor = 128 + (128*s1)/130; // = 215 at 170 wpm speed.wav_factor = 128 + (128*s1)/130; // = 215 at 170 wpm


if (wpm >= 350) {
if (wpm >= 350)
speed.wav_factor = wav_factor_350[wpm-350]; speed.wav_factor = wav_factor_350[wpm-350];
}


if (wpm >= 390) { if (wpm >= 390) {
speed.min_sample_len = 450 - (wpm - 400)/2; speed.min_sample_len = 450 - (wpm - 400)/2;
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;


if (wpm > 430) {
if (wpm > 430)
speed.pause_factor = 12; speed.pause_factor = 12;
} else if (wpm > 400) {
else if (wpm > 400)
speed.pause_factor = 13; speed.pause_factor = 13;
} else if (wpm > 374) {
else if (wpm > 374)
speed.pause_factor = 14; speed.pause_factor = 14;
} else if (wpm > 350) {
else if (wpm > 350)
speed.pause_factor = pause_factor_350[wpm - 350]; speed.pause_factor = pause_factor_350[wpm - 350];
}


if (speed.clause_pause_factor == 0) { if (speed.clause_pause_factor == 0) {
// restrict the reduction of pauses between clauses // restrict the reduction of pauses between clauses


next = &phoneme_list[ix+1]; next = &phoneme_list[ix+1];


if (p->synthflags & SFLAG_EMBEDDED) {
if (p->synthflags & SFLAG_EMBEDDED)
DoEmbedded2(&embedded_ix); DoEmbedded2(&embedded_ix);
}


type = p->type; type = p->type;
if (p->synthflags & SFLAG_SYLLABLE) if (p->synthflags & SFLAG_SYLLABLE)
case phFRICATIVE: case phFRICATIVE:
if (p->newword) { if (p->newword) {
if ((prev->type == phVOWEL) && (p->ph->phflags & phNOPAUSE)) { if ((prev->type == phVOWEL) && (p->ph->phflags & phNOPAUSE)) {
} else {
} else
p->prepause = 15; p->prepause = 15;
}
} }


if (next->type == phPAUSE && prev->type == phNASAL && !(p->ph->phflags&phFORTIS)) if (next->type == phPAUSE && prev->type == phNASAL && !(p->ph->phflags&phFORTIS))
p->length = 256; p->length = 256;


if (type == phVFRICATIVE) { if (type == phVFRICATIVE) {
if (next->type == phVOWEL) {
if (next->type == phVOWEL)
pre_voiced = 1; pre_voiced = 1;
}
if ((prev->type == phVOWEL) || (prev->type == phLIQUID)) {
if ((prev->type == phVOWEL) || (prev->type == phLIQUID))
p->length = (255 + prev->length)/2; p->length = (255 + prev->length)/2;
}
} }
break; break;


} }
} }


if (next->type == phVOWEL) {
if (next->type == phVOWEL)
pre_sonorant = 1; pre_sonorant = 1;
} else {
else {
p->pitch2 = last_pitch; p->pitch2 = last_pitch;


if ((prev->type == phVOWEL) || (prev->type == phLIQUID)) { if ((prev->type == phVOWEL) || (prev->type == phLIQUID)) {
p->length = prev->length; p->length = prev->length;


if (p->type == phLIQUID) {
if (p->type == phLIQUID)
p->length = speed1; p->length = speed1;
}


if (next->type == phVSTOP) {
if (next->type == phVSTOP)
p->length = (p->length * 160)/100; p->length = (p->length * 160)/100;
}
if (next->type == phVFRICATIVE) {
if (next->type == phVFRICATIVE)
p->length = (p->length * 120)/100; p->length = (p->length * 120)/100;
}
} else { } else {
for (ix2 = ix; ix2 < n_phoneme_list; ix2++) { for (ix2 = ix; ix2 < n_phoneme_list; ix2++) {
if (phoneme_list[ix2].type == phVOWEL) { if (phoneme_list[ix2].type == phVOWEL) {
} }


p->pitch1 = p->pitch2-16; p->pitch1 = p->pitch2-16;
if (p->pitch2 < 16) {
if (p->pitch2 < 16)
p->pitch1 = 0; p->pitch1 = 0;
}
p->env = PITCHfall; p->env = PITCHfall;
pre_voiced = 0; pre_voiced = 0;
} }


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


if (stress <= 1) {
if (stress <= 1)
stress = stress ^ 1; // swap diminished and unstressed (until we swap stress_amps,stress_lengths in tr_languages) 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
if (p2->ph->code == phonPAUSE_CLAUSE) if (p2->ph->code == phonPAUSE_CLAUSE)
end_of_clause = 2; end_of_clause = 2;


if ((p2->newword & 2) && (more_syllables == 0)) {
if ((p2->newword & 2) && (more_syllables == 0))
end_of_clause = 2; end_of_clause = 2;
}


// calc length modifier // calc length modifier
if ((next->ph->code == phonPAUSE_VSHORT) && (next2->type == phPAUSE)) { if ((next->ph->code == phonPAUSE_VSHORT) && (next2->type == phPAUSE)) {
length_mod += tr->langopts.lengthen_tonic; length_mod += tr->langopts.lengthen_tonic;
if (emphasized) if (emphasized)
length_mod += (tr->langopts.lengthen_tonic/2); length_mod += (tr->langopts.lengthen_tonic/2);
} else if (emphasized) {
} else if (emphasized)
length_mod += tr->langopts.lengthen_tonic; length_mod += tr->langopts.lengthen_tonic;
}


if ((len = tr->stress_lengths[stress]) == 0) if ((len = tr->stress_lengths[stress]) == 0)
len = tr->stress_lengths[6]; len = tr->stress_lengths[6];
if (p->tone_ph != 0) { if (p->tone_ph != 0) {
InterpretPhoneme2(p->tone_ph, &phdata_tone); InterpretPhoneme2(p->tone_ph, &phdata_tone);
pitch_env = GetEnvelope(phdata_tone.pitch_env); pitch_env = GetEnvelope(phdata_tone.pitch_env);
} else {
} else
pitch_env = envelope_data[env2]; pitch_env = envelope_data[env2];
}


pitch_start = p->pitch1 + ((p->pitch2-p->pitch1)*pitch_env[0])/256; pitch_start = p->pitch1 + ((p->pitch2-p->pitch1)*pitch_env[0])/256;


if (last_pitch < pitch_start) { if (last_pitch < pitch_start) {
prev->env = PITCHrise; prev->env = PITCHrise;
p->env = env2; p->env = env2;
} else {
} else
prev->env = PITCHfall; prev->env = PITCHfall;
}


prev->length = length_mod; prev->length = length_mod;


if (next->type == phLIQUID) { if (next->type == phLIQUID) {
next->synthflags |= SFLAG_SEQCONTINUE; next->synthflags |= SFLAG_SEQCONTINUE;


if (next2->type == phVOWEL) {
if (next2->type == phVOWEL)
next->synthflags &= ~SFLAG_SEQCONTINUE; next->synthflags &= ~SFLAG_SEQCONTINUE;
}


if (next2->type != phVOWEL) { if (next2->type != phVOWEL) {
if (next->ph->mnemonic == ('/'*256+'r')) {
if (next->ph->mnemonic == ('/'*256+'r'))
next->synthflags &= ~SFLAG_SEQCONTINUE; next->synthflags &= ~SFLAG_SEQCONTINUE;
}
} }
} }



+ 35
- 68
src/libespeak-ng/speak_lib.c View File

case AUDIO_OUTPUT_PLAYBACK: case AUDIO_OUTPUT_PLAYBACK:
{ {
int event_type = 0; int event_type = 0;
if (event) {
if (event)
event_type = event->type; event_type = event->type;
}


if (event_type == espeakEVENT_SAMPLERATE) { if (event_type == espeakEVENT_SAMPLERATE) {
voice_samplerate = event->id.number; voice_samplerate = event->id.number;
// TBD: For example sentence "or ALT)." returns three words // TBD: For example sentence "or ALT)." returns three words
// "or", "ALT" and "". // "or", "ALT" and "".
// TBD: the last one has its size=0. // TBD: the last one has its size=0.
if (event && (event->type == espeakEVENT_WORD) && (event->length == 0)) {
if (event && (event->type == espeakEVENT_WORD) && (event->length == 0))
break; break;
}
espeak_ERROR a_error = event_declare(event); espeak_ERROR a_error = event_declare(event);
if (a_error != EE_BUFFER_FULL) {
if (a_error != EE_BUFFER_FULL)
break; break;
}
SHOW_TIME("dispatch_audio > EE_BUFFER_FULL\n"); SHOW_TIME("dispatch_audio > EE_BUFFER_FULL\n");
usleep(10000); usleep(10000);
a_wave_can_be_played = fifo_is_command_enabled(); a_wave_can_be_played = fifo_is_command_enabled();
break; break;


case AUDIO_OUTPUT_RETRIEVAL: case AUDIO_OUTPUT_RETRIEVAL:
if (synth_callback) {
if (synth_callback)
synth_callback(outbuf, length, event); synth_callback(outbuf, length, event);
}
break; break;


case AUDIO_OUTPUT_SYNCHRONOUS: case AUDIO_OUTPUT_SYNCHRONOUS:
break; break;
} }


if (!a_wave_can_be_played) {
if (!a_wave_can_be_played)
SHOW_TIME("dispatch_audio > synth must be stopped!\n"); SHOW_TIME("dispatch_audio > synth must be stopped!\n");
}


SHOW_TIME("LEAVE dispatch_audio\n"); SHOW_TIME("LEAVE dispatch_audio\n");




do { // for each event do { // for each event
espeak_EVENT *event; espeak_EVENT *event;
if (event_list_ix == 0) {
if (event_list_ix == 0)
event = NULL; event = NULL;
} else {
else {
event = event_list + i; event = event_list + i;
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
SHOW("Synthesize: event->sample(%d) + %d = %d\n", event->sample, the_write_pos, event->sample + the_write_pos); SHOW("Synthesize: event->sample(%d) + %d = %d\n", event->sample, the_write_pos, event->sample + the_write_pos);
if (my_mode == AUDIO_OUTPUT_PLAYBACK) { if (my_mode == AUDIO_OUTPUT_PLAYBACK) {
while (1) { while (1) {
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);
} }
} else { } else {
if (synth_callback) {
if (synth_callback)
finished = synth_callback(NULL, 0, event_list); finished = synth_callback(NULL, 0, event_list);
}
} }
return finished; return finished;
} }
} }


snprintf(path_home, sizeof(path_home), "%s/espeak-data", getenv("HOME")); snprintf(path_home, sizeof(path_home), "%s/espeak-data", getenv("HOME"));
if (access(path_home, R_OK) != 0) {
if (access(path_home, R_OK) != 0)
strcpy(path_home, PATH_ESPEAK_DATA); strcpy(path_home, PATH_ESPEAK_DATA);
}
#endif #endif
} }


if ((result = LoadPhData(&srate)) != 1) { // reads sample rate from espeak-data/phontab if ((result = LoadPhData(&srate)) != 1) { // reads sample rate from espeak-data/phontab
if (result == -1) { if (result == -1) {
fprintf(stderr, "Failed to load espeak-data\n"); fprintf(stderr, "Failed to load espeak-data\n");
if ((control & espeakINITIALIZE_DONT_EXIT) == 0) {
if ((control & espeakINITIALIZE_DONT_EXIT) == 0)
exit(1); exit(1);
}
} else } else
fprintf(stderr, "Wrong version of espeak-data 0x%x (expects 0x%x) at %s\n", result, version_phdata, path_home); fprintf(stderr, "Wrong version of espeak-data 0x%x (expects 0x%x) at %s\n", result, version_phdata, path_home);
} }


#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
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 ((outbuf == NULL) || (event_list == NULL)) if ((outbuf == NULL) || (event_list == NULL))
count_samples = 0; count_samples = 0;


#ifdef USE_ASYNC #ifdef USE_ASYNC
if (my_mode == AUDIO_OUTPUT_PLAYBACK) {
if (my_mode == AUDIO_OUTPUT_PLAYBACK)
a_write_pos = wave_get_write_position(my_audio); a_write_pos = wave_get_write_position(my_audio);
}
#endif #endif


if (translator == NULL) {
if (translator == NULL)
SetVoiceByName("default"); SetVoiceByName("default");
}


SpeakNextClause(NULL, text, 0); SpeakNextClause(NULL, text, 0);


return EE_INTERNAL_ERROR; return EE_INTERNAL_ERROR;
length = 0; // the wave data are played once. length = 0; // the wave data are played once.
#endif #endif
} else {
} else
finished = synth_callback((short *)outbuf, length, event_list); finished = synth_callback((short *)outbuf, length, event_list);
}
if (finished) { if (finished) {
SpeakNextClause(NULL, 0, 2); // stop SpeakNextClause(NULL, 0, 2); // stop
break; break;
if (my_mode == AUDIO_OUTPUT_PLAYBACK) { if (my_mode == AUDIO_OUTPUT_PLAYBACK) {
if (dispatch_audio(NULL, 0, NULL) < 0) // TBD: test case if (dispatch_audio(NULL, 0, NULL) < 0) // TBD: test case
return err = EE_INTERNAL_ERROR; return err = EE_INTERNAL_ERROR;
} else {
} else
synth_callback(NULL, 0, event_list); // NULL buffer ptr indicates end of data synth_callback(NULL, 0, event_list); // NULL buffer ptr indicates end of data
}
#else #else
synth_callback(NULL, 0, event_list); // NULL buffer ptr indicates end of data synth_callback(NULL, 0, event_list); // NULL buffer ptr indicates end of data
#endif #endif
p = (int *)(ep->id.string); p = (int *)(ep->id.string);
p[0] = value; p[0] = value;
p[1] = value2; p[1] = value2;
} else {
} else
ep->id.number = value; ep->id.number = value;
}
} }




initialise(options); initialise(options);
select_output(output_type); select_output(output_type);


if (f_logespeak) {
if (f_logespeak)
fprintf(f_logespeak, "INIT mode %d options 0x%x\n", output_type, options); fprintf(f_logespeak, "INIT mode %d options 0x%x\n", output_type, options);
}


// buflength is in mS, allocate 2 bytes per sample // buflength is in mS, allocate 2 bytes per sample
if ((buf_length == 0) || (output_type == AUDIO_OUTPUT_PLAYBACK) || (output_type == AUDIO_OUTPUT_SYNCH_PLAYBACK)) if ((buf_length == 0) || (output_type == AUDIO_OUTPUT_PLAYBACK) || (output_type == AUDIO_OUTPUT_SYNCH_PLAYBACK))
espeak_ERROR a_error = EE_INTERNAL_ERROR; espeak_ERROR a_error = EE_INTERNAL_ERROR;
static unsigned int temp_identifier; static unsigned int temp_identifier;


if (unique_identifier == NULL) {
if (unique_identifier == NULL)
unique_identifier = &temp_identifier; unique_identifier = &temp_identifier;
}
*unique_identifier = 0; *unique_identifier = 0;


if (synchronous_mode) {
if (synchronous_mode)
return sync_espeak_Synth(0, text, size, position, position_type, end_position, flags, user_data); return sync_espeak_Synth(0, text, size, position, position_type, end_position, flags, user_data);
}


#ifdef USE_ASYNC #ifdef USE_ASYNC
// Create the text command // Create the text command
espeak_ERROR a_error = EE_OK; espeak_ERROR a_error = EE_OK;
static unsigned int temp_identifier; static unsigned int temp_identifier;


if (f_logespeak) {
if (f_logespeak)
fprintf(f_logespeak, "\nSYNTH MARK %s posn %d flags 0x%x\n%s\n", index_mark, end_position, flags, (const char *)text); fprintf(f_logespeak, "\nSYNTH MARK %s posn %d flags 0x%x\n%s\n", index_mark, end_position, flags, (const char *)text);
}




if (unique_identifier == NULL) {
if (unique_identifier == NULL)
unique_identifier = &temp_identifier; unique_identifier = &temp_identifier;
}
*unique_identifier = 0; *unique_identifier = 0;


if (synchronous_mode) {
if (synchronous_mode)
return sync_espeak_Synth_Mark(0, text, size, index_mark, end_position, flags, user_data); return sync_espeak_Synth_Mark(0, text, size, index_mark, end_position, flags, user_data);
}


#ifdef USE_ASYNC #ifdef USE_ASYNC
// Create the mark command // Create the mark command
ENTER("espeak_Key"); ENTER("espeak_Key");
// symbolic name, symbolicname_character - is there a system resource of symbolicnames per language // symbolic name, symbolicname_character - is there a system resource of symbolicnames per language


if (f_logespeak) {
if (f_logespeak)
fprintf(f_logespeak, "\nKEY %s\n", key); fprintf(f_logespeak, "\nKEY %s\n", key);
}


espeak_ERROR a_error = EE_OK; espeak_ERROR a_error = EE_OK;


#ifdef USE_ASYNC #ifdef USE_ASYNC
t_espeak_command *c = create_espeak_key(key, NULL); t_espeak_command *c = create_espeak_key(key, NULL);
a_error = fifo_add_command(c); a_error = fifo_add_command(c);
if (a_error != EE_OK) {
if (a_error != EE_OK)
delete_espeak_command(c); delete_espeak_command(c);
}


#endif #endif
return a_error; return a_error;
ENTER("espeak_Char"); ENTER("espeak_Char");
// is there a system resource of character names per language? // is there a system resource of character names per language?


if (f_logespeak) {
if (f_logespeak)
fprintf(f_logespeak, "\nCHAR U+%x\n", character); fprintf(f_logespeak, "\nCHAR U+%x\n", character);
}


#ifdef USE_ASYNC #ifdef USE_ASYNC
espeak_ERROR a_error; espeak_ERROR a_error;


t_espeak_command *c = create_espeak_char(character, NULL); t_espeak_command *c = create_espeak_char(character, NULL);
a_error = fifo_add_command(c); a_error = fifo_add_command(c);
if (a_error != EE_OK) {
if (a_error != EE_OK)
delete_espeak_command(c); delete_espeak_command(c);
}
return a_error; return a_error;
#else #else
sync_espeak_Char(character); sync_espeak_Char(character);
{ {
ENTER("espeak_GetParameter"); ENTER("espeak_GetParameter");
// current: 0=default value, 1=current value // current: 0=default value, 1=current value
if (current) {
if (current)
return param_stack[0].parameter[parameter]; return param_stack[0].parameter[parameter];
} else {
return param_defaults[parameter];
}
return param_defaults[parameter];
} }




{ {
ENTER("espeak_SetParameter"); ENTER("espeak_SetParameter");


if (f_logespeak) {
if (f_logespeak)
fprintf(f_logespeak, "SETPARAM %d %d %d\n", parameter, value, relative); fprintf(f_logespeak, "SETPARAM %d %d %d\n", parameter, value, relative);
}
#ifdef USE_ASYNC #ifdef USE_ASYNC
espeak_ERROR a_error; espeak_ERROR a_error;


t_espeak_command *c = create_espeak_parameter(parameter, value, relative); t_espeak_command *c = create_espeak_parameter(parameter, value, relative);


a_error = fifo_add_command(c); a_error = fifo_add_command(c);
if (a_error != EE_OK) {
if (a_error != EE_OK)
delete_espeak_command(c); delete_espeak_command(c);
}
return a_error; return a_error;
#else #else
SetParameter(parameter, value, relative); SetParameter(parameter, value, relative);


t_espeak_command *c = create_espeak_punctuation_list(punctlist); t_espeak_command *c = create_espeak_punctuation_list(punctlist);
a_error = fifo_add_command(c); a_error = fifo_add_command(c);
if (a_error != EE_OK) {
if (a_error != EE_OK)
delete_espeak_command(c); delete_espeak_command(c);
}
return a_error; return a_error;
#else #else
sync_espeak_SetPunctuationList(punctlist); sync_espeak_SetPunctuationList(punctlist);
fifo_stop(); fifo_stop();
event_clear_all(); event_clear_all();


if (my_mode == AUDIO_OUTPUT_PLAYBACK) {
if (my_mode == AUDIO_OUTPUT_PLAYBACK)
wave_close(my_audio); wave_close(my_audio);
}
SHOW_TIME("espeak_Cancel > LEAVE"); SHOW_TIME("espeak_Cancel > LEAVE");
#endif #endif
embedded_value[EMBED_T] = 0; // reset echo for pronunciation announcements embedded_value[EMBED_T] = 0; // reset echo for pronunciation announcements
espeak_ERROR berr = err; espeak_ERROR berr = err;
#ifdef USE_ASYNC #ifdef USE_ASYNC
SHOW_TIME("espeak_Synchronize > ENTER"); SHOW_TIME("espeak_Synchronize > ENTER");
while (espeak_IsPlaying()) {
while (espeak_IsPlaying())
usleep(20000); usleep(20000);
}
#endif #endif
err = EE_OK; err = EE_OK;
SHOW_TIME("espeak_Synchronize > LEAVE"); SHOW_TIME("espeak_Synchronize > LEAVE");


ESPEAK_API const char *espeak_Info(const char **ptr) ESPEAK_API const char *espeak_Info(const char **ptr)
{ {
if (ptr != NULL) {
if (ptr != NULL)
*ptr = path_home; *ptr = path_home;
}
return version_string; return version_string;
} }



+ 7
- 10
src/libespeak-ng/spect.c View File

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];
if ((den = ho-hp) == 0.0) {
if ((den = ho-hp) == 0.0)
return ya[2]; // two input xa are identical return ya[2]; // two input xa are identical
}
den = w/den; den = w/den;
d[i] = hp*den; d[i] = hp*den;
c[i] = ho*den; c[i] = ho*den;
} }


if (file_format_type > 0) { if (file_format_type > 0) {
for (ix = 0; ix < N_KLATTP2; ix++) {
for (ix = 0; ix < N_KLATTP2; ix++)
fread(frame->klatt_param + ix, sizeof(short), 1, stream); fread(frame->klatt_param + ix, sizeof(short), 1, stream);
}
} }


spect_data = malloc(sizeof(USHORT) * frame->nx); spect_data = malloc(sizeof(USHORT) * frame->nx);
} }


maxh = PeaksToHarmspect(wpeaks, 90<<16, htab, 0); maxh = PeaksToHarmspect(wpeaks, 90<<16, htab, 0);
for (h = 1; h < maxh; h++) {
for (h = 1; h < maxh; h++)
total += ((htab[h] * htab[h]) >> 10); total += ((htab[h] * htab[h]) >> 10);
}
frame->rms = sqrt(total) / 7.25; frame->rms = sqrt(total) / 7.25;
return frame->rms; return frame->rms;
} }
fread(&id1, sizeof(uint32_t), 1, stream); fread(&id1, sizeof(uint32_t), 1, stream);
fread(&id2, sizeof(uint32_t), 1, stream); fread(&id2, sizeof(uint32_t), 1, stream);


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 if ((id1 == FILEID1_SPECTSEQ) && (id2 == FILEID2_SPECTSEK)) {
else if ((id1 == FILEID1_SPECTSEQ) && (id2 == FILEID2_SPECTSEK))
spect->file_format = 1; // formants for Klatt synthesizer spect->file_format = 1; // formants for Klatt synthesizer
} else if ((id1 == FILEID1_SPECTSEQ) && (id2 == FILEID2_SPECTSQ2)) {
else 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 {
fprintf(stderr, "Unsupported spectral file format.\n"); fprintf(stderr, "Unsupported spectral file format.\n");
fclose(stream); fclose(stream);
return 1; return 1;

+ 14
- 22
src/libespeak-ng/synth_mbrola.c View File

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


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


mbrola_control = Read4Bytes(f_in); mbrola_control = Read4Bytes(f_in);
pw = (int *)mbrola_tab; pw = (int *)mbrola_tab;
for (ix = 4; ix < size; ix += 4) {
for (ix = 4; ix < size; ix += 4)
*pw++ = Read4Bytes(f_in); *pw++ = Read4Bytes(f_in);
}
size = fread(mbrola_tab, 1, size, f_in); size = fread(mbrola_tab, 1, size, f_in);
fclose(f_in); fclose(f_in);


if (mnem == pr->name) { if (mnem == pr->name) {
if (pr->next_phoneme == 0) if (pr->next_phoneme == 0)
found = 1; found = 1;
else if ((pr->next_phoneme == ':') && (plist->synthflags & SFLAG_LENGTHEN)) {
else if ((pr->next_phoneme == ':') && (plist->synthflags & SFLAG_LENGTHEN))
found = 1; found = 1;
} else {
else {
if (pr->control & 2) if (pr->control & 2)
other_ph = ph_prev; other_ph = ph_prev;
else if ((pr->control & 8) && ((plist+1)->newword)) else if ((pr->control & 8) && ((plist+1)->newword))


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 == 2) && (other_ph->type == phVOWEL)) ||
((pr->next_phoneme == '_') && (other_ph->type == phPAUSE))) {
((pr->next_phoneme == '_') && (other_ph->type == phPAUSE)))
found = 1; found = 1;
}
} }


if ((pr->control & 4) && (plist->newword == 0)) // only at start of word if ((pr->control & 4) && (plist->newword == 0)) // only at start of word
pr++; pr++;
} }


if (mbr_name_prefix != 0) {
if (mbr_name_prefix != 0)
mnem = (mnem << 8) | (mbr_name_prefix & 0xff); mnem = (mnem << 8) | (mbr_name_prefix & 0xff);
}
mbr_name_prefix = 0; mbr_name_prefix = 0;
return mnem; return mnem;
} }
// set an additional pitch point half way through the phoneme. // set an additional pitch point half way through the phoneme.
// but look for a maximum or a minimum and use that instead // but look for a maximum or a minimum and use that instead
y[2] = 64; y[2] = 64;
if ((y_max > 0) && (y_max < 127)) {
if ((y_max > 0) && (y_max < 127))
y[2] = y_max; y[2] = y_max;
}
if ((y_min > 0) && (y_min < 127)) {
if ((y_min > 0) && (y_min < 127))
y[2] = y_min; y[2] = y_min;
}
y[1] = y[2] / 2; y[1] = y[2] / 2;
y[3] = y[2] + (127 - y[2])/2; y[3] = y[2] + (127 - y[2])/2;


for (ix = 1; ix < 4; ix++) { for (ix = 1; ix < 4; ix++) {
p2 = ((pitch_env[y[ix]]*pitch_range)>>8) + pitch_base; p2 = ((pitch_env[y[ix]]*pitch_range)>>8) + pitch_base;


if (split > 0) {
if (split > 0)
y2 = (y[ix] * env100)/env_split; y2 = (y[ix] * env100)/env_split;
} else if (split < 0) {
else if (split < 0)
y2 = ((y[ix]-env_split) * env100)/env_split; y2 = ((y[ix]-env_split) * env100)/env_split;
} else {
else
y2 = (y[ix] * env100)/128; y2 = (y[ix] * env100)/128;
}
if ((y2 > 0) && (y2 <= env100)) { if ((y2 > 0) && (y2 <= env100)) {
sprintf(buf, " %d %d", y2, p2/4096); sprintf(buf, " %d %d", y2, p2/4096);
strcat(output, buf); strcat(output, buf);
ph_prev = plist[phix-1].ph; ph_prev = plist[phix-1].ph;
ph_next = plist[phix+1].ph; ph_next = plist[phix+1].ph;


if (p->synthflags & SFLAG_EMBEDDED) {
if (p->synthflags & SFLAG_EMBEDDED)
DoEmbedded(&embedded_ix, p->sourceix); DoEmbedded(&embedded_ix, p->sourceix);
}


if (p->newword & 4) if (p->newword & 4)
DoMarker(espeakEVENT_SENTENCE, (p->sourceix & 0x7ff) + clause_start_char, 0, count_sentences); DoMarker(espeakEVENT_SENTENCE, (p->sourceix & 0x7ff) + clause_start_char, 0, count_sentences);
pause = 0; pause = 0;
} }


if (f_mbrola) {
if (f_mbrola)
fwrite(mbr_buf, 1, (ptr-mbr_buf), f_mbrola); // write .pho to a file fwrite(mbr_buf, 1, (ptr-mbr_buf), f_mbrola); // write .pho to a file
} else {
else {
int res = write_MBR(mbr_buf); int res = write_MBR(mbr_buf);
if (res < 0) if (res < 0)
return 0; /* don't get stuck on error */ return 0; /* don't get stuck on error */

+ 26
- 41
src/libespeak-ng/synthdata.c View File

rate += (wavefile_data[ix+4] << (ix*8)); rate += (wavefile_data[ix+4] << (ix*8));
} }


if (version != version_phdata) {
if (version != version_phdata)
result = version; result = version;
}


// set up phoneme tables // set up phoneme tables
p = phoneme_tab_data; p = phoneme_tab_data;


frames = &frames_buf[0]; frames = &frames_buf[0];
if (seq_break > 0) { if (seq_break > 0) {
if (which == 1) {
if (which == 1)
nf = seq_break + 1; nf = seq_break + 1;
} else {
else {
frames = &frames_buf[seq_break]; // body of vowel, skip past initial frames frames = &frames_buf[seq_break]; // body of vowel, skip past initial frames
nf -= seq_break; nf -= seq_break;
} }
} }


// do we need to modify a frame for blending with a consonant? // do we need to modify a frame for blending with a consonant?
if ((this_ph->type == phVOWEL) && (fmt_params->fmt2_addr == 0) && (fmt_params->use_vowelin)) {
if ((this_ph->type == phVOWEL) && (fmt_params->fmt2_addr == 0) && (fmt_params->use_vowelin))
seq_len_adjust += FormantTransition2(frames, &nf, fmt_params->transition0, fmt_params->transition1, NULL, which); seq_len_adjust += FormantTransition2(frames, &nf, fmt_params->transition0, fmt_params->transition1, NULL, which);
}


length1 = 0; length1 = 0;
nf1 = nf - 1; nf1 = nf - 1;


length_factor = (length_std * 256)/ length1; length_factor = (length_std * 256)/ length1;


for (ix = 0; ix < nf1; ix++) {
for (ix = 0; ix < nf1; ix++)
frames[ix].length = (frames[ix].length * length_factor)/256; frames[ix].length = (frames[ix].length * length_factor)/256;
}
} else { } else {
if (which == 1) { if (which == 1) {
// front of a vowel // front of a vowel
} }
} else { } else {
// not a vowel // not a vowel
if (fmt_params->std_length > 0) {
if (fmt_params->std_length > 0)
seq_len_adjust += (fmt_params->std_length - length1); seq_len_adjust += (fmt_params->std_length - length1);
}
} }


if (seq_len_adjust != 0) { if (seq_len_adjust != 0) {
length_factor = ((length1 + seq_len_adjust) * 256)/length1; length_factor = ((length1 + seq_len_adjust) * 256)/length1;
for (ix = 0; ix < nf1; ix++) {
for (ix = 0; ix < nf1; ix++)
frames[ix].length = (frames[ix].length * length_factor)/256; frames[ix].length = (frames[ix].length * length_factor)/256;
}
} }
} }
} }
int ph_code; int ph_code;
PHONEME_TAB *phtab; PHONEME_TAB *phtab;


if (recursing == 0) {
if (recursing == 0)
memset(phoneme_tab_flags, 0, sizeof(phoneme_tab_flags)); memset(phoneme_tab_flags, 0, sizeof(phoneme_tab_flags));
}


if ((includes = phoneme_tab_list[number].includes) > 0) { if ((includes = phoneme_tab_list[number].includes) > 0) {
// recursively include base phoneme tables // recursively include base phoneme tables
} }


sprintf(buf, "%s%c%s", path_home, PATHSEP, "config"); sprintf(buf, "%s%c%s", path_home, PATHSEP, "config");
if ((f = fopen(buf, "r")) == NULL) {
if ((f = fopen(buf, "r")) == NULL)
return; return;
}


while (fgets(buf, sizeof(buf), f) != NULL) { while (fgets(buf, sizeof(buf), f) != NULL) {
if (buf[0] == '/') continue; if (buf[0] == '/') continue;
fclose(f_logespeak); fclose(f_logespeak);
f_logespeak = fopen(string, "w"); f_logespeak = fopen(string, "w");
} }
} else if (memcmp(buf, "tone", 4) == 0) {
} else if (memcmp(buf, "tone", 4) == 0)
ReadTonePoints(&buf[5], tone_points); ReadTonePoints(&buf[5], tone_points);
} else if (memcmp(buf, "pa_device", 9) == 0) {
else if (memcmp(buf, "pa_device", 9) == 0)
sscanf(&buf[10], "%d", &option_device_number); sscanf(&buf[10], "%d", &option_device_number);
} else if (memcmp(buf, "soundicon", 9) == 0) {
else if (memcmp(buf, "soundicon", 9) == 0) {
ix = sscanf(&buf[10], "_%c %s", &c1, string); ix = sscanf(&buf[10], "_%c %s", &c1, string);
if (ix == 2) { if (ix == 2) {
soundicon_tab[n_soundicon_tab].name = c1; soundicon_tab[n_soundicon_tab].name = c1;
PHONEME_LIST *pl; PHONEME_LIST *pl;
static int condition_level[4] = { 1, 2, 4, 15 }; static int condition_level[4] = { 1, 2, 4, 15 };


if (phoneme_tab[plist[0].phcode]->type == phVOWEL) {
if (phoneme_tab[plist[0].phcode]->type == phVOWEL)
pl = plist; pl = plist;
} else {
else {
// consonant, get stress from the following vowel // consonant, get stress from the following vowel
if (phoneme_tab[plist[1].phcode]->type == phVOWEL) {
if (phoneme_tab[plist[1].phcode]->type == phVOWEL)
pl = &plist[1]; pl = &plist[1];
} else
else
return false; // no stress elevel for this consonant return false; // no stress elevel for this consonant
} }


} }
} }


if (condition == 4) {
if (condition == 4)
return stress_level >= pl->wordstress; return stress_level >= pl->wordstress;
}


if (condition == 3) { if (condition == 3) {
// if stressed // if stressed
if (instn_type == 2) { if (instn_type == 2) {
phdata->pd_control |= pd_FORNEXTPH; phdata->pd_control |= pd_FORNEXTPH;
voweltype = plist[1].ph->start_type; // SwitchNextVowelType voweltype = plist[1].ph->start_type; // SwitchNextVowelType
} else {
} else
voweltype = plist[-1].ph->end_type; // SwitchPrevVowelType voweltype = plist[-1].ph->end_type; // SwitchPrevVowelType
}


voweltype -= phonVOWELTYPES; voweltype -= phonVOWELTYPES;
if ((voweltype >= 0) && (voweltype < 6)) { if ((voweltype >= 0) && (voweltype < 6)) {
// This instruction is followed by addWav(), 2 more words // This instruction is followed by addWav(), 2 more words
return 4; return 4;
} }
if (instn2 == i_CONTINUE) {
if (instn2 == i_CONTINUE)
return 3; return 3;
}
return 2; return 2;
} }
} }
phdata->pd_param[i_SET_LENGTH] = ph->std_length; phdata->pd_param[i_SET_LENGTH] = ph->std_length;
phdata->pd_param[i_LENGTH_MOD] = ph->length_mod; phdata->pd_param[i_LENGTH_MOD] = ph->length_mod;


if (ph->program == 0) {
if (ph->program == 0)
return; return;
}


end_flag = 0; end_flag = 0;


} }
phdata->ipa_string[ix] = 0; phdata->ipa_string[ix] = 0;
} else if (instn2 < N_PHONEME_DATA_PARAM) { } else if (instn2 < N_PHONEME_DATA_PARAM) {
if (instn2 == i_CHANGE_PHONEME2) {
if (instn2 == i_CHANGE_PHONEME2)
phdata->pd_param[i_CHANGE_PHONEME] = data; // also set ChangePhoneme phdata->pd_param[i_CHANGE_PHONEME] = data; // also set ChangePhoneme
}
phdata->pd_param[instn2] = data; phdata->pd_param[instn2] = data;
if ((instn2 == i_CHANGE_PHONEME) && (control & 0x100)) { if ((instn2 == i_CHANGE_PHONEME) && (control & 0x100)) {
// found ChangePhoneme() in PhonemeList mode, exit // found ChangePhoneme() in PhonemeList mode, exit
end_flag = 1; end_flag = 1;
} }
} else {
} else
InvalidInstn(ph, instn); InvalidInstn(ph, instn);
}
break; break;


case 1: case 1:
} }


if (truth == false) { if (truth == false) {
if ((instn & 0xf800) == i_JUMP_FALSE) {
if ((instn & 0xf800) == i_JUMP_FALSE)
prog += instn & 0xff; prog += instn & 0xff;
} else {
else {
// instruction after a condition is not JUMP_FALSE, so skip the instruction. // instruction after a condition is not JUMP_FALSE, so skip the instruction.
prog += NumInstnWords(prog); prog += NumInstnWords(prog);
if ((prog[0] & 0xfe00) == 0x6000) if ((prog[0] & 0xfe00) == 0x6000)
break; break;
} }


if (ph->phflags & phSINGLE_INSTN) {
if (ph->phflags & phSINGLE_INSTN)
end_flag = 1; // this phoneme has a one-instruction program, with an implicit Return end_flag = 1; // this phoneme has a one-instruction program, with an implicit Return
}


if ((end_flag == 1) && (n_return > 0)) { if ((end_flag == 1) && (n_return > 0)) {
// return from called procedure or phoneme // return from called procedure or phoneme
} }
} }


if ((worddata != NULL) && (plist->type == phVOWEL)) {
if ((worddata != NULL) && (plist->type == phVOWEL))
memcpy(&worddata->prev_vowel, &plist[0], sizeof(PHONEME_LIST)); memcpy(&worddata->prev_vowel, &plist[0], sizeof(PHONEME_LIST));
}


plist->std_length = phdata->pd_param[i_SET_LENGTH]; plist->std_length = phdata->pd_param[i_SET_LENGTH];
if (phdata->sound_addr[0] != 0) { if (phdata->sound_addr[0] != 0) {

+ 41
- 73
src/libespeak-ng/synthesize.c View File

else { else {
len = PauseLength(length, control); len = PauseLength(length, control);


if (len < 90000) {
if (len < 90000)
len = (len * samplerate) / 1000; // convert from mS to number of samples len = (len * samplerate) / 1000; // convert from mS to number of samples
} else {
else {
srate2 = samplerate / 25; // avoid overflow srate2 = samplerate / 25; // avoid overflow
len = (len * srate2) / 40; len = (len * srate2) / 40;
} }
std_length = wav_length; std_length = wav_length;
} }


if (length_mod > 0) {
if (length_mod > 0)
std_length = (std_length * length_mod)/256; std_length = (std_length * length_mod)/256;
}


length = (std_length * speed.wav_factor)/256; length = (std_length * speed.wav_factor)/256;




seq_len_adjust = 0; seq_len_adjust = 0;


if (phdata->sound_addr[pd_WAV] == 0) {
if (phdata->sound_addr[pd_WAV] == 0)
len = 0; len = 0;
} else {
else
len = DoSample2(phdata->sound_addr[pd_WAV], 2, phdata->pd_param[pd_LENGTHMOD]*2, phdata->pd_control, length_mod, amp2); len = DoSample2(phdata->sound_addr[pd_WAV], 2, phdata->pd_param[pd_LENGTHMOD]*2, phdata->pd_control, length_mod, amp2);
}
last_frame = NULL; last_frame = NULL;
return len; return len;
} }
}; };


if (voice->klattv[0]) { if (voice->klattv[0]) {
if (new_rms == -1) {
if (new_rms == -1)
fr->klattp[KLATT_AV] = 50; fr->klattp[KLATT_AV] = 50;
}
return; return;
} }


fr->ffreq[2] += x; fr->ffreq[2] += x;
fr->ffreq[3] += f3_adj; fr->ffreq[3] += f3_adj;


if (flags & 0x20) {
if (flags & 0x20)
f3_adj = -f3_adj; // . reverse direction for f4,f5 change f3_adj = -f3_adj; // . reverse direction for f4,f5 change
}
fr->ffreq[4] += f3_adj; fr->ffreq[4] += f3_adj;
fr->ffreq[5] += f3_adj; fr->ffreq[5] += f3_adj;




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


if (voice->klattv[0]) {
if (voice->klattv[0])
fr->klattp[KLATT_AV] = seq[1].frame->klattp[KLATT_AV] - 4; fr->klattp[KLATT_AV] = seq[1].frame->klattp[KLATT_AV] - 4;
}
if (f2 != 0) { if (f2 != 0) {
if (rms & 0x20) {
if (rms & 0x20)
set_frame_rms(fr, (next_rms * (rms & 0x1f))/30); set_frame_rms(fr, (next_rms * (rms & 0x1f))/30);
}
AdjustFormants(fr, f2, f2_min, f2_max, f1, f3_adj, f3_amp, flags); AdjustFormants(fr, f2, f2_min, f2_max, f1, f3_adj, f3_amp, flags);


if ((rms & 0x20) == 0) {
if ((rms & 0x20) == 0)
set_frame_rms(fr, rms*2); set_frame_rms(fr, rms*2);
}
} else { } else {
if (flags & 8) if (flags & 8)
set_frame_rms(fr, (next_rms*24)/32); set_frame_rms(fr, (next_rms*24)/32);
set_frame_rms(fr, RMS_START); set_frame_rms(fr, RMS_START);
} }


if (flags & 8) {
if (flags & 8)
modn_flags = 0x800 + (VowelCloseness(fr) << 8); modn_flags = 0x800 + (VowelCloseness(fr) << 8);
}
} else { } else {
// exit from vowel // exit from vowel
rms = rms*2; rms = rms*2;
if (len > 36) if (len > 36)
seq_len_adjust += (len - 36); seq_len_adjust += (len - 36);


if (f2 != 0) {
if (f2 != 0)
AdjustFormants(fr, f2, f2_min, f2_max, f1, f3_adj, f3_amp, flags); AdjustFormants(fr, f2, f2_min, f2_max, f1, f3_adj, f3_amp, flags);
}
} }


set_frame_rms(fr, rms); set_frame_rms(fr, rms);
f2 = frame->ffreq[pk]; f2 = frame->ffreq[pk];


// backwards // backwards
if ((diff = f2 - f1) > 0) {
if ((diff = f2 - f1) > 0)
allowed = f1*2 + f2; allowed = f1*2 + f2;
} else {
else
allowed = f1 + f2*2; allowed = f1 + f2*2;
}


// the allowed change is specified as percentage (%*10) of the frequency // the allowed change is specified as percentage (%*10) of the frequency
// take "frequency" as 1/3 from the lower freq // take "frequency" as 1/3 from the lower freq
f2 = frame->ffreq[pk]; f2 = frame->ffreq[pk];


// forwards // forwards
if ((diff = f2 - f1) > 0) {
if ((diff = f2 - f1) > 0)
allowed = f1*2 + f2; allowed = f1*2 + f2;
} else {
else
allowed = f1 + f2*2; allowed = f1 + f2*2;
}
allowed = (allowed * formant_rate[pk])/3000; allowed = (allowed * formant_rate[pk])/3000;
allowed = (allowed * len)/256; allowed = (allowed * len)/256;


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




if ((length_sum > 0) && (length_sum < length_min)) { if ((length_sum > 0) && (length_sum < length_min)) {
// lengthen, so that the sequence is greater than one cycle at low pitch // lengthen, so that the sequence is greater than one cycle at low pitch
for (frameix = 1; frameix < n_frames; frameix++) {
for (frameix = 1; frameix < n_frames; frameix++)
frame_lengths[frameix] = (frame_lengths[frameix] * length_min) / length_sum; frame_lengths[frameix] = (frame_lengths[frameix] * length_min) / length_sum;
}
} }


for (frameix = 1; frameix < n_frames; frameix++) { for (frameix = 1; frameix < n_frames; frameix++) {
} }


if (modulation >= 0) { if (modulation >= 0) {
if (frame1->frflags & FRFLAG_MODULATE) {
if (frame1->frflags & FRFLAG_MODULATE)
modulation = 6; modulation = 6;
}
if ((frameix == n_frames-1) && (modn_flags & 0xf00)) if ((frameix == n_frames-1) && (modn_flags & 0xf00))
modulation |= modn_flags; // before or after a glottal stop modulation |= modn_flags; // before or after a glottal stop
} }
next = &phoneme_list[ix+1]; next = &phoneme_list[ix+1];
next2 = &phoneme_list[ix+2]; next2 = &phoneme_list[ix+2];


if (p->synthflags & SFLAG_EMBEDDED) {
if (p->synthflags & SFLAG_EMBEDDED)
DoEmbedded(&embedded_ix, p->sourceix); DoEmbedded(&embedded_ix, p->sourceix);
}


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
last_frame = NULL; last_frame = NULL;
}


sourceix = (p->sourceix & 0x7ff) + clause_start_char; sourceix = (p->sourceix & 0x7ff) + clause_start_char;


if (p->newword & 4) if (p->newword & 4)
DoMarker(espeakEVENT_SENTENCE, sourceix, 0, count_sentences); // start of sentence DoMarker(espeakEVENT_SENTENCE, sourceix, 0, count_sentences); // start of sentence


// if(p->newword & 2)
// DoMarker(espeakEVENT_END, count_characters, 0, count_sentences); // end of clause

if (p->newword & 1) if (p->newword & 1)
DoMarker(espeakEVENT_WORD, sourceix, p->sourceix >> 11, clause_start_word + word_count++); // NOTE, this count doesn't include multiple-word pronunciations in *_list. eg (of a) DoMarker(espeakEVENT_WORD, sourceix, p->sourceix >> 11, clause_start_word + word_count++); // NOTE, this count doesn't include multiple-word pronunciations in *_list. eg (of a)
} }
case phSTOP: case phSTOP:
released = 0; released = 0;
ph = p->ph; ph = p->ph;
if (next->type == phVOWEL) {
if (next->type == phVOWEL)
released = 1; released = 1;
} else if (!next->newword) {
else if (!next->newword) {
if (next->type == phLIQUID) released = 1; if (next->type == phLIQUID) released = 1;
} }
if (released == 0) if (released == 0)
case phFRICATIVE: case phFRICATIVE:
InterpretPhoneme(NULL, 0, p, &phdata, &worddata); InterpretPhoneme(NULL, 0, p, &phdata, &worddata);


if (p->synthflags & SFLAG_LENGTHEN) {
if (p->synthflags & SFLAG_LENGTHEN)
DoSample3(&phdata, p->length, 0); // play it twice for [s:] etc. DoSample3(&phdata, p->length, 0); // play it twice for [s:] etc.
}
DoSample3(&phdata, p->length, 0); DoSample3(&phdata, p->length, 0);
break; break;


DoSpect2(ph, 0, &fmtp, p, 0); DoSpect2(ph, 0, &fmtp, p, 0);
} }
} else { } else {
if (p->synthflags & SFLAG_LENGTHEN) {
if (p->synthflags & SFLAG_LENGTHEN)
DoPause(50, 0); DoPause(50, 0);
}
} }


if (pre_voiced) { if (pre_voiced) {
// followed by a vowel, or liquid + vowel // followed by a vowel, or liquid + vowel
StartSyllable(); StartSyllable();
} else {
} else
p->synthflags |= SFLAG_NEXT_PAUSE; p->synthflags |= SFLAG_NEXT_PAUSE;
}
InterpretPhoneme(NULL, 0, p, &phdata, &worddata); InterpretPhoneme(NULL, 0, p, &phdata, &worddata);
fmtp.fmt_addr = phdata.sound_addr[pd_FMT]; fmtp.fmt_addr = phdata.sound_addr[pd_FMT];
fmtp.fmt_amp = phdata.sound_param[pd_FMT]; fmtp.fmt_amp = phdata.sound_param[pd_FMT];
} }
} }


if ((next->type == phVOWEL) || ((next->type == phLIQUID) && (next->newword == 0))) { // ?? test 14.Aug.2007
if ((next->type == phVOWEL) || ((next->type == phLIQUID) && (next->newword == 0))) // ?? test 14.Aug.2007
StartSyllable(); StartSyllable();
} else {
else
p->synthflags |= SFLAG_NEXT_PAUSE; p->synthflags |= SFLAG_NEXT_PAUSE;
}
InterpretPhoneme(NULL, 0, p, &phdata, &worddata); InterpretPhoneme(NULL, 0, p, &phdata, &worddata);
memset(&fmtp, 0, sizeof(fmtp)); memset(&fmtp, 0, sizeof(fmtp));
fmtp.std_length = phdata.pd_param[i_SET_LENGTH]*2; fmtp.std_length = phdata.pd_param[i_SET_LENGTH]*2;
DoPitch(envelope_data[p->env], p->pitch1, p->pitch2); DoPitch(envelope_data[p->env], p->pitch1, p->pitch2);
} }


if (prev->type == phNASAL) {
if (prev->type == phNASAL)
last_frame = NULL; last_frame = NULL;
}


InterpretPhoneme(NULL, 0, p, &phdata, &worddata); InterpretPhoneme(NULL, 0, p, &phdata, &worddata);
fmtp.std_length = phdata.pd_param[i_SET_LENGTH]*2; fmtp.std_length = phdata.pd_param[i_SET_LENGTH]*2;
if (next->type == phVOWEL) { if (next->type == phVOWEL) {
StartSyllable(); StartSyllable();
DoSpect2(p->ph, 0, &fmtp, p, 0); DoSpect2(p->ph, 0, &fmtp, p, 0);
} else if (prev->type == phVOWEL && (p->synthflags & SFLAG_SEQCONTINUE)) {
} else if (prev->type == phVOWEL && (p->synthflags & SFLAG_SEQCONTINUE))
DoSpect2(p->ph, 0, &fmtp, p, 0); DoSpect2(p->ph, 0, &fmtp, p, 0);
} else {
else {
last_frame = NULL; // only for nasal ? last_frame = NULL; // only for nasal ?
DoSpect2(p->ph, 0, &fmtp, p, 0); DoSpect2(p->ph, 0, &fmtp, p, 0);
last_frame = NULL; last_frame = NULL;
DoPitch(envelope_data[p->env], p->pitch1, p->pitch2); DoPitch(envelope_data[p->env], p->pitch1, p->pitch2);
} }


if (prev->type == phNASAL) {
if (prev->type == phNASAL)
last_frame = NULL; last_frame = NULL;
}


if (next->type == phVOWEL) {
if (next->type == phVOWEL)
StartSyllable(); StartSyllable();
}
InterpretPhoneme(NULL, 0, p, &phdata, &worddata); InterpretPhoneme(NULL, 0, p, &phdata, &worddata);


if ((value = (phdata.pd_param[i_PAUSE_BEFORE] - p->prepause)) > 0) {
if ((value = (phdata.pd_param[i_PAUSE_BEFORE] - p->prepause)) > 0)
DoPause(value, 1); DoPause(value, 1);
}
fmtp.std_length = phdata.pd_param[i_SET_LENGTH]*2; fmtp.std_length = phdata.pd_param[i_SET_LENGTH]*2;
fmtp.fmt_addr = phdata.sound_addr[pd_FMT]; fmtp.fmt_addr = phdata.sound_addr[pd_FMT];
fmtp.fmt_amp = phdata.sound_param[pd_FMT]; fmtp.fmt_amp = phdata.sound_param[pd_FMT];
fmtp.transition0 = 0; fmtp.transition0 = 0;
fmtp.transition1 = 0; fmtp.transition1 = 0;


if ((fmtp.fmt2_addr = phdata.sound_addr[pd_VWLEND]) != 0) {
if ((fmtp.fmt2_addr = phdata.sound_addr[pd_VWLEND]) != 0)
fmtp.fmt2_lenadj = phdata.sound_param[pd_VWLEND]; fmtp.fmt2_lenadj = phdata.sound_param[pd_VWLEND];
} else if (next->type != phPAUSE) {
else if (next->type != phPAUSE) {
fmtp.fmt2_lenadj = 0; fmtp.fmt2_lenadj = 0;
InterpretPhoneme(NULL, 0, next, &phdata_next, NULL); InterpretPhoneme(NULL, 0, next, &phdata_next, NULL);




int SynthOnTimer() int SynthOnTimer()
{ {
if (!timer_on) {
if (!timer_on)
return WavegenCloseSound(); return WavegenCloseSound();
}


do { do {
if (WcmdqUsed() > 0) if (WcmdqUsed() > 0)
WavegenOpenSound(); WavegenOpenSound();


if (Generate(phoneme_list, &n_phoneme_list, 1) == 0) {
if (Generate(phoneme_list, &n_phoneme_list, 1) == 0)
SpeakNextClause(NULL, NULL, 1); SpeakNextClause(NULL, NULL, 1);
}
} while (skipping_text); } while (skipping_text);


return 0; return 0;
return 0; return 0;
} }


if (current_phoneme_table != voice->phoneme_tab_ix) {
if (current_phoneme_table != voice->phoneme_tab_ix)
SelectPhonemeTable(voice->phoneme_tab_ix); SelectPhonemeTable(voice->phoneme_tab_ix);
}


// read the next clause from the input text file, translate it, and generate // read the next clause from the input text file, translate it, and generate
// entries in the wavegen command queue // entries in the wavegen command queue


if ((option_phonemes & 0xf) || (phoneme_callback != NULL)) { if ((option_phonemes & 0xf) || (phoneme_callback != NULL)) {
phon_out = GetTranslatedPhonemeString(option_phonemes); phon_out = GetTranslatedPhonemeString(option_phonemes);
if (option_phonemes & 0xf) {
if (option_phonemes & 0xf)
fprintf(f_trans, "%s\n", phon_out); fprintf(f_trans, "%s\n", phon_out);
}
if (phoneme_callback != NULL) {
if (phoneme_callback != NULL)
phoneme_callback(phon_out); phoneme_callback(phon_out);
}
} }





+ 11
- 17
src/libespeak-ng/tr_languages.c View File



mask = ~groups; mask = ~groups;


for (ix = 0; ix < sizeof(tr->letter_bits); ix++) {
for (ix = 0; ix < sizeof(tr->letter_bits); ix++)
tr->letter_bits[ix] &= mask; tr->letter_bits[ix] &= mask;
}
} }


static void SetLetterBits(Translator *tr, int group, const char *string) static void SetLetterBits(Translator *tr, int group, const char *string)
int ix; int ix;


bits = (1L << group); bits = (1L << group);
for (ix = first; ix <= last; ix++) {
for (ix = first; ix <= last; ix++)
tr->letter_bits[ix] |= bits; tr->letter_bits[ix] |= bits;
}
} }


// ignore these characters // ignore these characters
// stress last syllable unless word ends with a vowel // stress last syllable unless word ends with a vowel
tr->langopts.stress_rule = STRESSPOSN_1R; tr->langopts.stress_rule = STRESSPOSN_1R;
tr->langopts.stress_flags = S_FINAL_VOWEL_UNSTRESSED | S_FINAL_DIM_ONLY | S_FINAL_NO_2 | S_NO_AUTO_2; tr->langopts.stress_flags = S_FINAL_VOWEL_UNSTRESSED | S_FINAL_DIM_ONLY | S_FINAL_NO_2 | S_NO_AUTO_2;
} else {
} else
tr->langopts.param[LOPT_UNPRONOUNCABLE] = 2; // use es_rules for unpronouncable rules tr->langopts.param[LOPT_UNPRONOUNCABLE] = 2; // use es_rules for unpronouncable rules
}
} }
break; break;


tr->langopts.break_numbers = 0x14aa8; // for languages which have numbers for 100,000 and 100,00,000, eg Hindi tr->langopts.break_numbers = 0x14aa8; // for languages which have numbers for 100,000 and 100,00,000, eg Hindi
tr->letter_bits_offset = OFFSET_DEVANAGARI; tr->letter_bits_offset = OFFSET_DEVANAGARI;


if (name2 == L('p', 'a')) {
if (name2 == L('p', 'a'))
tr->letter_bits_offset = OFFSET_GURMUKHI; tr->letter_bits_offset = OFFSET_GURMUKHI;
} else if (name2 == L('g', 'u')) {
else if (name2 == L('g', 'u')) {
SetupTranslator(tr, stress_lengths_equal, stress_amps_equal); SetupTranslator(tr, stress_lengths_equal, stress_amps_equal);
tr->letter_bits_offset = OFFSET_GUJARATI; tr->letter_bits_offset = OFFSET_GUJARATI;
tr->langopts.stress_rule = STRESSPOSN_2R; tr->langopts.stress_rule = STRESSPOSN_2R;
tr->langopts.break_numbers = 0x2aaaa8; tr->langopts.break_numbers = 0x2aaaa8;
tr->langopts.max_digits = 22; tr->langopts.max_digits = 22;
tr->langopts.numbers2 |= NUM2_ENGLISH_NUMERALS; tr->langopts.numbers2 |= NUM2_ENGLISH_NUMERALS;
} else if (name2 == L('o', 'r')) {
} else if (name2 == L('o', 'r'))
tr->letter_bits_offset = OFFSET_ORIYA; tr->letter_bits_offset = OFFSET_ORIYA;
}
SetIndicLetters(tr); SetIndicLetters(tr);
} }
break; break;
tr->langopts.numbers = NUM_OMIT_1_THOUSAND; tr->langopts.numbers = NUM_OMIT_1_THOUSAND;
tr->langopts.numbers2 = NUM2_ORDINAL_AND_THOUSANDS; tr->langopts.numbers2 = NUM2_ORDINAL_AND_THOUSANDS;
tr->langopts.param[LOPT_WORD_MERGE] = 1; // don't break vowels betwen words tr->langopts.param[LOPT_WORD_MERGE] = 1; // don't break vowels betwen words
} else if (name2 == L('m', 'r')) {
} else if (name2 == L('m', 'r'))
tr->letter_bits_offset = OFFSET_DEVANAGARI; tr->letter_bits_offset = OFFSET_DEVANAGARI;
} else if (name2 == L('m', 'l')) {
else if (name2 == L('m', 'l')) {
static const short stress_lengths_ml[8] = { 180, 160, 240, 240, 0, 0, 260, 260 }; static const short stress_lengths_ml[8] = { 180, 160, 240, 240, 0, 0, 260, 260 };
SetupTranslator(tr, stress_lengths_ml, stress_amps_equal); SetupTranslator(tr, stress_lengths_ml, stress_amps_equal);
tr->letter_bits_offset = OFFSET_MALAYALAM; tr->letter_bits_offset = OFFSET_MALAYALAM;
tr->langopts.dotless_i = 1; tr->langopts.dotless_i = 1;
tr->langopts.param[LOPT_SUFFIX] = 1; tr->langopts.param[LOPT_SUFFIX] = 1;


if (name2 == L('a', 'z')) {
if (name2 == L('a', 'z'))
tr->langopts.numbers = NUM_SINGLE_STRESS | NUM_DECIMAL_COMMA | NUM_ALLOW_SPACE | NUM_OMIT_1_HUNDRED | NUM_OMIT_1_THOUSAND | NUM_DFRACTION_2; tr->langopts.numbers = NUM_SINGLE_STRESS | NUM_DECIMAL_COMMA | NUM_ALLOW_SPACE | NUM_OMIT_1_HUNDRED | NUM_OMIT_1_THOUSAND | NUM_DFRACTION_2;
} else {
else
tr->langopts.numbers = NUM_SINGLE_STRESS | NUM_DECIMAL_COMMA | NUM_OMIT_1_HUNDRED | NUM_OMIT_1_THOUSAND | NUM_DFRACTION_2; tr->langopts.numbers = NUM_SINGLE_STRESS | NUM_DECIMAL_COMMA | NUM_OMIT_1_HUNDRED | NUM_OMIT_1_THOUSAND | NUM_DFRACTION_2;
}
tr->langopts.max_initial_consonants = 2; tr->langopts.max_initial_consonants = 2;
} }
break; break;
langopts->thousands_sep = '.'; langopts->thousands_sep = '.';
langopts->decimal_sep = ','; langopts->decimal_sep = ',';
} }
if (langopts->numbers & NUM_THOUS_SPACE) {
if (langopts->numbers & NUM_THOUS_SPACE)
langopts->thousands_sep = 0; // don't allow thousands separator, except space langopts->thousands_sep = 0; // don't allow thousands separator, except space
}
} }





+ 49
- 90
src/libespeak-ng/translate.c View File

int value2; int value2;


tr->langopts.length_mods0 = tr->langopts.length_mods = length_mod_tabs[value % 100]; tr->langopts.length_mods0 = tr->langopts.length_mods = length_mod_tabs[value % 100];
if ((value2 = value / 100) != 0) {
if ((value2 = value / 100) != 0)
tr->langopts.length_mods0 = length_mod_tabs[value2]; tr->langopts.length_mods0 = length_mod_tabs[value2];
}
} }




n_bytes = 3; n_bytes = 3;


c1 &= mask[n_bytes]; c1 &= mask[n_bytes];
for (ix = 0; ix < n_bytes; ix++) {
for (ix = 0; ix < n_bytes; ix++)
c1 = (c1 << 6) + (*buf++ & 0x3f); c1 = (c1 << 6) + (*buf++ & 0x3f);
}
} }
*c = c1; *c = c1;
return n_bytes+1; return n_bytes+1;
} }
*p_out = 0; *p_out = 0;


if (remove_stress) {
if (remove_stress)
SetWordStress(tr, phonbuf, NULL, -1, 0); SetWordStress(tr, phonbuf, NULL, -1, 0);
}


strcpy(phonemes, phonbuf); strcpy(phonemes, phonbuf);


found = LookupDictList(tr, &word1, phonemes, dictionary_flags, FLAG_ALLOW_TEXTMODE, wtab); // the original word found = LookupDictList(tr, &word1, phonemes, dictionary_flags, FLAG_ALLOW_TEXTMODE, wtab); // the original word




if ((dictionary_flags[0] & (FLAG_ALLOW_DOT | FLAG_NEEDS_DOT)) && (wordx[1] == '.')) {
if ((dictionary_flags[0] & (FLAG_ALLOW_DOT | FLAG_NEEDS_DOT)) && (wordx[1] == '.'))
wordx[1] = ' '; // remove a Dot after this word wordx[1] = ' '; // remove a Dot after this word
}


if (dictionary_flags[0] & FLAG_TEXTMODE) { if (dictionary_flags[0] & FLAG_TEXTMODE) {
if (word_out != NULL) if (word_out != NULL)
// ?? should we say super/sub-script numbers and letters here? // ?? should we say super/sub-script numbers and letters here?
utf8_in(&wc, wordx); utf8_in(&wc, wordx);
if ((word_length == 1) && (IsAlpha(wc) || IsSuperscript(wc))) { if ((word_length == 1) && (IsAlpha(wc) || IsSuperscript(wc))) {
if ((wordx = SpeakIndividualLetters(tr, wordx, phonemes, spell_word)) == NULL) {
if ((wordx = SpeakIndividualLetters(tr, wordx, phonemes, spell_word)) == NULL)
return 0; return 0;
}
strcpy(word_phonemes, phonemes); strcpy(word_phonemes, phonemes);
return 0; return 0;
} }
for (ix = 0; ix < n_chars; ix++) { // num. of bytes to remove for (ix = 0; ix < n_chars; ix++) { // num. of bytes to remove
prefix_chars[pfix++] = *wordx++; prefix_chars[pfix++] = *wordx++;


if ((prefix_type & SUFX_B) && (ix == (n_chars-1))) {
if ((prefix_type & SUFX_B) && (ix == (n_chars-1)))
prefix_chars[pfix-1] = 0; // discard the last character of the prefix, this is the separator character prefix_chars[pfix-1] = 0; // discard the last character of the prefix, this is the separator character
}
} }
prefix_chars[pfix] = 0; prefix_chars[pfix] = 0;
} }


// look for stress marker or $abbrev // look for stress marker or $abbrev
found = LookupDictList(tr, &wordpf, phonemes, dictionary_flags, 0, wtab); found = LookupDictList(tr, &wordpf, phonemes, dictionary_flags, 0, wtab);
if (found) {
if (found)
strcpy(prefix_phonemes, phonemes); strcpy(prefix_phonemes, phonemes);
}
if (dictionary_flags[0] & FLAG_ABBREV) { if (dictionary_flags[0] & FLAG_ABBREV) {
prefix_phonemes[0] = 0; prefix_phonemes[0] = 0;
SpeakIndividualLetters(tr, wordpf, prefix_phonemes, 1); SpeakIndividualLetters(tr, wordpf, prefix_phonemes, 1);
} }
} else {
} else
strcat(prefix_phonemes, end_phonemes); strcat(prefix_phonemes, end_phonemes);
}
end_phonemes[0] = 0; end_phonemes[0] = 0;


end_type = 0; end_type = 0;
return 0; return 0;
} }


if (dictionary_flags2[0] & FLAG_ABBREV) {
// Removing the suffix leaves a word which should be spoken as individual letters
// Not yet implemented
}
if (dictionary_flags[0] == 0) { if (dictionary_flags[0] == 0) {
dictionary_flags[0] = dictionary_flags2[0]; dictionary_flags[0] = dictionary_flags2[0];
dictionary_flags[1] = dictionary_flags2[1]; dictionary_flags[1] = dictionary_flags2[1];
/* determine stress pattern for this word */ /* determine stress pattern for this word */
/******************************************/ /******************************************/
add_suffix_phonemes = 0; add_suffix_phonemes = 0;
if (end_phonemes[0] != 0) {
if (end_phonemes[0] != 0)
add_suffix_phonemes = 2; add_suffix_phonemes = 2;
}


prefix_stress = 0; prefix_stress = 0;
for (p = prefix_phonemes; *p != 0; p++) { for (p = prefix_phonemes; *p != 0; p++) {
if ((*p == phonSTRESS_P) || (*p == phonSTRESS_P2)) {
if ((*p == phonSTRESS_P) || (*p == phonSTRESS_P2))
prefix_stress = *p; prefix_stress = *p;
}
} }
if (prefix_flags || (prefix_stress != 0)) { if (prefix_flags || (prefix_stress != 0)) {
if ((tr->langopts.param[LOPT_PREFIXES]) || (prefix_type & SUFX_T)) { if ((tr->langopts.param[LOPT_PREFIXES]) || (prefix_type & SUFX_T)) {
dictionary_flags[0] &= ~FLAG_PAUSE1; dictionary_flags[0] &= ~FLAG_PAUSE1;
} }


if ((wflags & FLAG_HYPHEN) && (tr->langopts.stress_flags & S_HYPEN_UNSTRESS)) {
if ((wflags & FLAG_HYPHEN) && (tr->langopts.stress_flags & S_HYPEN_UNSTRESS))
ChangeWordStress(tr, word_phonemes, 3); ChangeWordStress(tr, word_phonemes, 3);
} else if (wflags & FLAG_EMPHASIZED2) {
else if (wflags & FLAG_EMPHASIZED2) {
// A word is indicated in the source text as stressed // A word is indicated in the source text as stressed
// Give it stress level 6 (for the intonation module) // Give it stress level 6 (for the intonation module)
ChangeWordStress(tr, word_phonemes, 6); ChangeWordStress(tr, word_phonemes, 6);
dictionary_flags[0] |= FLAG_ALLOW_DOT; dictionary_flags[0] |= FLAG_ALLOW_DOT;
} }


if ((tr->langopts.param[LOPT_ALT] & 2) && ((dictionary_flags[0] & (FLAG_ALT_TRANS | FLAG_ALT2_TRANS)) != 0)) {
if ((tr->langopts.param[LOPT_ALT] & 2) && ((dictionary_flags[0] & (FLAG_ALT_TRANS | FLAG_ALT2_TRANS)) != 0))
ApplySpecialAttribute2(tr, word_phonemes, dictionary_flags[0]); ApplySpecialAttribute2(tr, word_phonemes, dictionary_flags[0]);
}


dictionary_flags[0] |= was_unpronouncable; dictionary_flags[0] |= was_unpronouncable;
memcpy(word_start, word_copy2, word_copy_length); memcpy(word_start, word_copy2, word_copy_length);
translator2->dict_condition = 0x48; // bits 3, 6 translator2->dict_condition = 0x48; // bits 3, 6
translator2->langopts.param[LOPT_REDUCE_T] = 1; translator2->langopts.param[LOPT_REDUCE_T] = 1;
} }
if (dialect == DICTDIALECT_ES_LA) {
if (dialect == DICTDIALECT_ES_LA)
translator2->dict_condition = 0x04; // bit 2 translator2->dict_condition = 0x04; // bit 2
}
} }
translator2->phoneme_tab_ix = new_phoneme_tab; translator2->phoneme_tab_ix = new_phoneme_tab;
} }
word_phonemes[1] = ix; word_phonemes[1] = ix;
word_phonemes[2] = 0; word_phonemes[2] = 0;
} }
} else {
} else
EncodePhonemes(word, word_phonemes, &bad_phoneme); EncodePhonemes(word, word_phonemes, &bad_phoneme);
}
flags = FLAG_FOUND; flags = FLAG_FOUND;
} else { } else {
int c2; int c2;
while (*p2 != ' ') p2++; while (*p2 != ' ') p2++;


utf8_in(&c_word2, p2+1); // first character of the next word; utf8_in(&c_word2, p2+1); // first character of the next word;
if (!iswalpha2(c_word2)) {
if (!iswalpha2(c_word2))
ok = 0; ok = 0;
}


if (ok != 0) { if (ok != 0) {
strcpy(ph_buf, word_phonemes); strcpy(ph_buf, word_phonemes);


if (sylimit & 0x100) { if (sylimit & 0x100) {
// only if the second word has $alt attribute // only if the second word has $alt attribute
if ((flags2[0] & FLAG_ALT_TRANS) == 0) {
if ((flags2[0] & FLAG_ALT_TRANS) == 0)
ok = 0; ok = 0;
}
} }


if ((sylimit & 0x200) && ((wtab+1)->flags & FLAG_LAST_WORD)) { if ((sylimit & 0x200) && ((wtab+1)->flags & FLAG_LAST_WORD)) {
ok = 0; ok = 0;
} }


if (ok == 0) {
if (ok == 0)
strcpy(word_phonemes, ph_buf); strcpy(word_phonemes, ph_buf);
}
} }


if (ok) { if (ok) {
if (ph_list2[n_ph_list2-1].phcode == phonSWITCH) { if (ph_list2[n_ph_list2-1].phcode == phonSWITCH) {
// previous phoneme is also a phonSWITCH, just change its phoneme table number // previous phoneme is also a phonSWITCH, just change its phoneme table number
n_ph_list2--; n_ph_list2--;
} else {
} else
SetPlist2(&ph_list2[n_ph_list2], phonSWITCH); SetPlist2(&ph_list2[n_ph_list2], phonSWITCH);
}
ph_list2[n_ph_list2++].tone_ph = switch_phonemes; // temporary phoneme table number ph_list2[n_ph_list2++].tone_ph = switch_phonemes; // temporary phoneme table number
} }
} }
next_stress = ph->std_length; next_stress = ph->std_length;
else { else {
// for tone languages, the tone number for a syllable follows the vowel // for tone languages, the tone number for a syllable follows the vowel
if (prev_vowel >= 0) {
if (prev_vowel >= 0)
ph_list2[prev_vowel].tone_ph = ph_code; ph_list2[prev_vowel].tone_ph = ph_code;
} else {
else
next_tone = ph_code; // no previous vowel, apply to the next vowel next_tone = ph_code; // no previous vowel, apply to the next vowel
}
} }
} else if (ph_code == phonSYLLABIC) { } else if (ph_code == phonSYLLABIC) {
// mark the previous phoneme as a syllabic consonant // mark the previous phoneme as a syllabic consonant
prev_vowel = n_ph_list2-1; prev_vowel = n_ph_list2-1;
ph_list2[prev_vowel].synthflags |= SFLAG_SYLLABLE; ph_list2[prev_vowel].synthflags |= SFLAG_SYLLABLE;
ph_list2[prev_vowel].stresslevel = next_stress; ph_list2[prev_vowel].stresslevel = next_stress;
} else if (ph_code == phonLENGTHEN) {
} else if (ph_code == phonLENGTHEN)
ph_list2[n_ph_list2-1].synthflags |= SFLAG_LENGTHEN; ph_list2[n_ph_list2-1].synthflags |= SFLAG_LENGTHEN;
} else if (ph_code == phonEND_WORD) {
else if (ph_code == phonEND_WORD) {
// a || symbol in a phoneme string was used to indicate a word boundary // a || symbol in a phoneme string was used to indicate a word boundary
// Don't add this phoneme to the list, but make sure the next phoneme has // Don't add this phoneme to the list, but make sure the next phoneme has
// a newword indication // a newword indication
srcix = source_ix+1; srcix = source_ix+1;
} else if (ph_code == phonX1) { } else if (ph_code == phonX1) {
// a language specific action // a language specific action
if (tr->langopts.param[LOPT_IT_DOUBLING]) {
if (tr->langopts.param[LOPT_IT_DOUBLING])
flags |= FLAG_DOUBLING; flags |= FLAG_DOUBLING;
}
} else { } else {
ph_list2[n_ph_list2].phcode = ph_code; ph_list2[n_ph_list2].phcode = ph_code;
ph_list2[n_ph_list2].tone_ph = 0; ph_list2[n_ph_list2].tone_ph = 0;
stress = next_stress; stress = next_stress;
next_stress = 1; // default is 'unstressed' next_stress = 1; // default is 'unstressed'


if (stress >= 4) {
if (stress >= 4)
any_stressed_words = 1; any_stressed_words = 1;
}


if ((prev_vowel >= 0) && (n_ph_list2-1) != prev_vowel) if ((prev_vowel >= 0) && (n_ph_list2-1) != prev_vowel)
ph_list2[n_ph_list2-1].stresslevel = stress; // set stress for previous consonant ph_list2[n_ph_list2-1].stresslevel = stress; // set stress for previous consonant
} }
} }


if (word_flags & FLAG_COMMA_AFTER) {
if (word_flags & FLAG_COMMA_AFTER)
SetPlist2(&ph_list2[n_ph_list2++], phonPAUSE_CLAUSE); SetPlist2(&ph_list2[n_ph_list2++], phonPAUSE_CLAUSE);
}


// don't set new-word if there is a hyphen before it // don't set new-word if there is a hyphen before it
if ((word_flags & FLAG_HYPHEN) == 0) {
if ((word_flags & FLAG_HYPHEN) == 0)
plist2->sourceix = source_ix; plist2->sourceix = source_ix;
}


tr->end_stressed_vowel = 0; tr->end_stressed_vowel = 0;
if ((stress >= 4) && (phoneme_tab[ph_list2[n_ph_list2-1].phcode]->type == phVOWEL)) {
if ((stress >= 4) && (phoneme_tab[ph_list2[n_ph_list2-1].phcode]->type == phVOWEL))
tr->end_stressed_vowel = 1; // word ends with a stressed vowel tr->end_stressed_vowel = 1; // word ends with a stressed vowel
}


if (switch_phonemes >= 0) { if (switch_phonemes >= 0) {
// this word uses a different phoneme table, now switch back // this word uses a different phoneme table, now switch back
int tone; int tone;
int tone2; int tone2;


if (tr == NULL) {
if (tr == NULL)
return NULL; return NULL;
}


p_textinput = (unsigned char *)vp_input; p_textinput = (unsigned char *)vp_input;
p_wchar_input = (wchar_t *)vp_input; p_wchar_input = (wchar_t *)vp_input;
} }


for (p = source; *p != 0; p++) { for (p = source; *p != 0; p++) {
if (!isspace2(*p)) {
if (!isspace2(*p))
break; break;
}
} }
if (*p == 0) { if (*p == 0) {
// No characters except spaces. This is not a sentence. // No characters except spaces. This is not a sentence.
if (prev_in_save != 0) { if (prev_in_save != 0) {
prev_in = prev_in_save; prev_in = prev_in_save;
prev_in_save = 0; prev_in_save = 0;
} else if (source_index > 0) {
} else if (source_index > 0)
utf8_in2(&prev_in, &source[source_index-1], 1); // prev_in = source[source_index-1]; utf8_in2(&prev_in, &source[source_index-1], 1); // prev_in = source[source_index-1];
}


prev_source_index = source_index; prev_source_index = source_index;


c = ' '; c = ' ';
space_inserted = 1; space_inserted = 1;


if (!IsBracket(prev_out)) { // ?? perhaps only set FLAG_NOSPACE for . - / (hyphenated words, URLs, etc)
if (!IsBracket(prev_out)) // ?? perhaps only set FLAG_NOSPACE for . - / (hyphenated words, URLs, etc)
next_word_flags |= FLAG_NOSPACE; next_word_flags |= FLAG_NOSPACE;
}
} else { } else {
if (iswupper2(c)) if (iswupper2(c))
word_flags |= FLAG_FIRST_UPPER; word_flags |= FLAG_FIRST_UPPER;
if (((prev_in == '.') || iswalnum(prev_in)) && IsAlpha(next_in)) { if (((prev_in == '.') || iswalnum(prev_in)) && IsAlpha(next_in)) {
// between two letters, or in an abbreviation (eg. u.s.a.'s). Consider the apostrophe as part of the word // between two letters, or in an abbreviation (eg. u.s.a.'s). Consider the apostrophe as part of the word
single_quoted = 0; single_quoted = 0;
} else if ((tr->langopts.param[LOPT_APOSTROPHE] & 1) && IsAlpha(next_in)) {
} else if ((tr->langopts.param[LOPT_APOSTROPHE] & 1) && IsAlpha(next_in))
single_quoted = 0; // apostrophe at start of word is part of the word single_quoted = 0; // apostrophe at start of word is part of the word
} else if ((tr->langopts.param[LOPT_APOSTROPHE] & 2) && IsAlpha(prev_in)) {
else if ((tr->langopts.param[LOPT_APOSTROPHE] & 2) && IsAlpha(prev_in))
single_quoted = 0; // apostrophe at end of word is part of the word single_quoted = 0; // apostrophe at end of word is part of the word
} else if ((wcschr(tr->char_plus_apostrophe, prev_in) != 0) && (prev_out2 == ' ')) {
else if ((wcschr(tr->char_plus_apostrophe, prev_in) != 0) && (prev_out2 == ' ')) {
// consider single character plus apostrophe as a word // consider single character plus apostrophe as a word
single_quoted = 0; single_quoted = 0;
if (next_in == ' ') {
if (next_in == ' ')
source_index++; // skip following space source_index++; // skip following space
}
} else { } else {
if ((prev_out == 's') && (single_quoted == 0)) { if ((prev_out == 's') && (single_quoted == 0)) {
// looks like apostrophe after an 's' // looks like apostrophe after an 's'
c = ' '; c = ' ';
} }
} }
} else if (lookupwchar(breaks, c) != 0) {
} else if (lookupwchar(breaks, c) != 0)
c = ' '; // various characters to treat as space c = ' '; // various characters to treat as space
} else if (iswdigit(c)) {
else if (iswdigit(c)) {
if (tr->langopts.tone_numbers && IsAlpha(prev_out) && !IsDigit(next_in)) { if (tr->langopts.tone_numbers && IsAlpha(prev_out) && !IsDigit(next_in)) {
} else if ((prev_out != ' ') && !iswdigit(prev_out)) { } else if ((prev_out != ' ') && !iswdigit(prev_out)) {
if ((prev_out != tr->langopts.decimal_sep) || ((decimal_sep_count > 0) && (tr->langopts.decimal_sep == ','))) { if ((prev_out != tr->langopts.decimal_sep) || ((decimal_sep_count > 0) && (tr->langopts.decimal_sep == ','))) {
c = ' '; c = ' ';
space_inserted = 1; space_inserted = 1;
} else {
} else
decimal_sep_count = 1; decimal_sep_count = 1;
}
} else if ((prev_out == ' ') && IsAlpha(prev_out2) && !IsAlpha(prev_in)) { } 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' // insert extra space between a word and a number, to distinguish 'a 2' from 'a2'
sbuf[ix++] = ' '; sbuf[ix++] = ' ';
continue; // multiple spaces continue; // multiple spaces
} }


if ((cc == 0x09) || (cc == 0x0a)) {
if ((cc == 0x09) || (cc == 0x0a))
next_word_flags |= FLAG_MULTIPLE_SPACES; // tab or newline, not a simple space next_word_flags |= FLAG_MULTIPLE_SPACES; // tab or newline, not a simple space
}


if (space_inserted) { if (space_inserted) {
// count the number of characters since the start of the word // count the number of characters since the start of the word


if (pre_pause > 0) { if (pre_pause > 0) {
// insert an extra space before the word, to prevent influence from previous word across the pause // insert an extra space before the word, to prevent influence from previous word across the pause
for (j = ix; j > words[word_count].start; j--) {
for (j = ix; j > words[word_count].start; j--)
sbuf[j] = sbuf[j-1]; sbuf[j] = sbuf[j-1];
}
sbuf[j] = ' '; sbuf[j] = ' ';
words[word_count].start++; words[word_count].start++;
ix++; ix++;
// Languages with 100000 numbers. Remove thousands separators so that we can insert them again later // Languages with 100000 numbers. Remove thousands separators so that we can insert them again later
pn = number_buf; pn = number_buf;
while (pn < &number_buf[sizeof(number_buf)-20]) { while (pn < &number_buf[sizeof(number_buf)-20]) {
if (iswdigit(*pw)) {
if (iswdigit(*pw))
*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"
if ((nx > 0) && (tr->langopts.break_numbers & (1 << nx))) { if ((nx > 0) && (tr->langopts.break_numbers & (1 << nx))) {
memcpy(&num_wtab[nw++], &words[ix], sizeof(WORD_TAB)); // copy the 'words' entry for each word of numbers memcpy(&num_wtab[nw++], &words[ix], sizeof(WORD_TAB)); // copy the 'words' entry for each word of numbers


if (tr->langopts.thousands_sep != ' ') {
if (tr->langopts.thousands_sep != ' ')
*pn++ = tr->langopts.thousands_sep; *pn++ = tr->langopts.thousands_sep;
}
*pn++ = ' '; *pn++ = ' ';


if ((words[ix].flags & FLAG_INDIVIDUAL_DIGITS) == 0) { if ((words[ix].flags & FLAG_INDIVIDUAL_DIGITS) == 0) {
pw--; pw--;
memcpy(&num_wtab[nw], &words[ix], sizeof(WORD_TAB)*2); // the original number word, and the word after it memcpy(&num_wtab[nw], &words[ix], sizeof(WORD_TAB)*2); // the original number word, and the word after it


for (j = 1; j <= nw; j++) {
for (j = 1; j <= nw; j++)
num_wtab[j].flags &= ~(FLAG_MULTIPLE_SPACES | FLAG_EMBEDDED); // don't use these flags for subsequent parts when splitting a number num_wtab[j].flags &= ~(FLAG_MULTIPLE_SPACES | FLAG_EMBEDDED); // don't use these flags for subsequent parts when splitting a number
}


// include the next few characters, in case there are an ordinal indicator or other suffix // include the next few characters, in case there are an ordinal indicator or other suffix
memcpy(pn, pw, 16); memcpy(pn, pw, 16);
} }
n_ph_list2 += 2; n_ph_list2 += 2;


if (count_words == 0) {
if (count_words == 0)
clause_pause = 0; clause_pause = 0;
}
if (Eof() && ((word_count == 0) || (option_endpause == 0))) {
if (Eof() && ((word_count == 0) || (option_endpause == 0)))
clause_pause = 10; clause_pause = 10;
}


MakePhonemeList(tr, clause_pause, new_sentence2); MakePhonemeList(tr, clause_pause, new_sentence2);
phoneme_list[N_PHONEME_LIST].ph = NULL; // recognize end of phoneme_list array, in Generate() phoneme_list[N_PHONEME_LIST].ph = NULL; // recognize end of phoneme_list array, in Generate()
*tone_out = tone; *tone_out = tone;


new_sentence = 0; new_sentence = 0;
if (terminator & CLAUSE_BIT_SENTENCE) {
if (terminator & CLAUSE_BIT_SENTENCE)
new_sentence = 1; // next clause is a new sentence new_sentence = 1; // next clause is a new sentence
}




if (voice_change != NULL) { if (voice_change != NULL) {


InitText2(); InitText2();


if ((control & espeakKEEP_NAMEDATA) == 0) {
if ((control & espeakKEEP_NAMEDATA) == 0)
InitNamedata(); InitNamedata();
}
} }

+ 40
- 66
src/libespeak-ng/voices.c View File

langix += len; langix += len;
n_languages++; n_languages++;
} }
} else if (memcmp(linebuf, "gender", 6) == 0) {
} else if (memcmp(linebuf, "gender", 6) == 0)
sscanf(&linebuf[6], "%s %d", vgender, &age); sscanf(&linebuf[6], "%s %d", vgender, &age);
} else if (memcmp(linebuf, "variants", 8) == 0) {
else if (memcmp(linebuf, "variants", 8) == 0)
sscanf(&linebuf[8], "%d", &n_variants); sscanf(&linebuf[8], "%d", &n_variants);
}
} }
languages[langix++] = 0; languages[langix++] = 0;


gender = LookupMnem(genders, vgender); gender = LookupMnem(genders, vgender);


if (n_languages == 0) {
if (n_languages == 0)
return NULL; // no language lines in the voice file return NULL; // no language lines in the voice file
}


p = (char *)calloc(sizeof(espeak_VOICE) + langix + strlen(fname) + strlen(vname) + 3, 1); p = (char *)calloc(sizeof(espeak_VOICE) + langix + strlen(fname) + strlen(vname) + 3, 1);
voice_data = (espeak_VOICE *)p; voice_data = (espeak_VOICE *)p;
int c; int c;
unsigned int value = 0; unsigned int value = 0;


for (ix = 0; (ix < 4) && ((c = string[ix]) != 0); ix++) {
for (ix = 0; (ix < 4) && ((c = string[ix]) != 0); ix++)
value = (value << 8) | (c & 0xff); value = (value << 8) | (c & 0xff);
}
return value; return value;
} }




if (GetFileLength(buf) <= 0) { if (GetFileLength(buf) <= 0) {
// then look in the appropriate subdirectory // then look in the appropriate subdirectory
if ((voicename[0] == 'm') && (voicename[1] == 'b')) {
if ((voicename[0] == 'm') && (voicename[1] == 'b'))
voice_dir = "mb"; // mbrola voices voice_dir = "mb"; // mbrola voices
} else {
else {
sprintf(name2, "%s ", voicename); sprintf(name2, "%s ", voicename);
if (strstr(voices_europe, voicename) != NULL) if (strstr(voices_europe, voicename) != NULL)
voice_dir = "europe"; voice_dir = "europe";
((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;
} else {
} else
fprintf(stderr, "Bad voice option: %s %s\n", buf, p); fprintf(stderr, "Bad voice option: %s %s\n", buf, p);
}
break; break;


case V_ECHO: case V_ECHO:
name1[0] = name2[0] = 0; name1[0] = name2[0] = 0;
sscanf(p, "%s %s", name1, name2); sscanf(p, "%s %s", name1, name2);


if (strcmp(name1, "latin") == 0) {
if (strcmp(name1, "latin") == 0)
strncpy0(langopts->ascii_language, name2, sizeof(langopts->ascii_language)); strncpy0(langopts->ascii_language, name2, sizeof(langopts->ascii_language));
} else if ((alphabet = AlphabetFromName(name1)) != 0) {
else if ((alphabet = AlphabetFromName(name1)) != 0) {
langopts->alt_alphabet = alphabet->offset; langopts->alt_alphabet = alphabet->offset;
langopts->alt_alphabet_lang = StringToWord2(name2); langopts->alt_alphabet_lang = StringToWord2(name2);
} else {
} else
fprintf(stderr, "alphabet name '%s' not found\n", name1); fprintf(stderr, "alphabet name '%s' not found\n", name1);
}
} }
break; 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
if (sscanf(p, "%s", name1) == 1) { if (sscanf(p, "%s", name1) == 1) {
if ((ix = LookupMnem(dict_dialects, name1)) > 0) {
if ((ix = LookupMnem(dict_dialects, name1)) > 0)
langopts->dict_dialect |= (1 << ix); langopts->dict_dialect |= (1 << ix);
} else {
else
fprintf(stderr, "dictdialect name '%s' not recognized\n", name1); fprintf(stderr, "dictdialect name '%s' not recognized\n", name1);
}
} }
break; break;


default: default:
if ((key & 0xff00) == 0x100) {
if ((key & 0xff00) == 0x100)
sscanf(p, "%d", &langopts->param[key &0xff]); sscanf(p, "%d", &langopts->param[key &0xff]);
} else {
else
fprintf(stderr, "Bad voice attribute: %s\n", buf); fprintf(stderr, "Bad voice attribute: %s\n", buf);
}
break; break;
} }
} }
voice->width2[ix] = voice->width[ix]; voice->width2[ix] = voice->width[ix];
} }


if (tone_only) {
if (tone_only)
new_translator = translator; new_translator = translator;
} else {
else {
if ((ix = SelectPhonemeTableName(phonemes_name)) < 0) { if ((ix = SelectPhonemeTableName(phonemes_name)) < 0) {
fprintf(stderr, "Unknown phoneme table: '%s'\n", phonemes_name); fprintf(stderr, "Unknown phoneme table: '%s'\n", phonemes_name);
ix = 0; ix = 0;
langopts = &new_translator->langopts; langopts = &new_translator->langopts;




if ((value = langopts->param[LOPT_LENGTH_MODS]) != 0) {
if ((value = langopts->param[LOPT_LENGTH_MODS]) != 0)
SetLengthMods(new_translator, value); SetLengthMods(new_translator, value);
}


voice->width[0] = (voice->width[0] * 105)/100; voice->width[0] = (voice->width[0] * 105)/100;


if (!tone_only) {
if (!tone_only)
translator = new_translator; translator = new_translator;
}




// relative lengths of different stress syllables // relative lengths of different stress syllables
for (ix = 0; ix < stress_lengths_set; ix++) {
for (ix = 0; ix < stress_lengths_set; ix++)
translator->stress_lengths[ix] = stress_lengths[ix]; translator->stress_lengths[ix] = stress_lengths[ix];
}
for (ix = 0; ix < stress_add_set; ix++) {
for (ix = 0; ix < stress_add_set; ix++)
translator->stress_lengths[ix] += stress_add[ix]; translator->stress_lengths[ix] += stress_add[ix];
}
for (ix = 0; ix < stress_amps_set; ix++) { for (ix = 0; ix < stress_amps_set; ix++) {
translator->stress_amps[ix] = stress_amps[ix]; translator->stress_amps[ix] = stress_amps[ix];
translator->stress_amps_r[ix] = stress_amps[ix] -1; translator->stress_amps_r[ix] = stress_amps[ix] -1;
// The voice name has a +variant suffix // The voice name has a +variant suffix
variant_num = 0; variant_num = 0;
*p++ = 0; // delete the suffix from the voice name *p++ = 0; // delete the suffix from the voice name
if (IsDigit09(*p)) {
if (IsDigit09(*p))
variant_num = atoi(p); // variant number variant_num = atoi(p); // variant number
} else {
else {
// voice variant name, not number // voice variant name, not number
sprintf(variant_name, "%s%s", variant_prefix, p); sprintf(variant_name, "%s%s", variant_prefix, p);
} }
if ((v = LoadVoice(buf, 0)) == NULL) if ((v = LoadVoice(buf, 0)) == NULL)
return NULL; return NULL;


if (variant_name[0] != 0) {
if (variant_name[0] != 0)
v = LoadVoice(variant_name, 2); v = LoadVoice(variant_name, 2);
}
return v; return v;
} }


return 0; return 0;
} }


if (spec_n_parts == 0) {
if (spec_n_parts == 0)
score = 100; score = 100;
} else {
else {
if ((*p == 0) && (strcmp(spec_language, "variants") == 0)) { if ((*p == 0) && (strcmp(spec_language, "variants") == 0)) {
// match on a voice with no languages if the required language is "variants" // match on a voice with no languages if the required language is "variants"
score = 100; score = 100;
if ((c2 = p[ix]) == '-') if ((c2 = p[ix]) == '-')
c2 = 0; c2 = 0;


if (c1 != c2) {
if (c1 != c2)
matching = 0; matching = 0;
}


if (p[ix] == '-') { if (p[ix] == '-') {
n_parts++; n_parts++;
if (strcmp(voice_spec->name, voice->name) == 0) { if (strcmp(voice_spec->name, voice->name) == 0) {
// match on voice name // match on voice name
score += 500; score += 500;
} else if (strcmp(voice_spec->name, voice->identifier) == 0) {
} else if (strcmp(voice_spec->name, voice->identifier) == 0)
score += 400; score += 400;
}
} }


if (((voice_spec->gender == 1) || (voice_spec->gender == 2)) && if (((voice_spec->gender == 1) || (voice_spec->gender == 2)) &&
score -= 50; score -= 50;
} }


if ((voice_spec->age <= 12) && (voice->gender == 2) && (voice->age > 12)) {
if ((voice_spec->age <= 12) && (voice->gender == 2) && (voice->age > 12))
score += 5; // give some preference for non-child female voice if a child is requested score += 5; // give some preference for non-child female voice if a child is requested
}


if (voice->age != 0) { if (voice->age != 0) {
if (voice_spec->age == 0) if (voice_spec->age == 0)
break; break;
} else { } else {
id = voices[ix]->identifier; id = voices[ix]->identifier;
if (strcmp(name, id) == 0) {
if (strcmp(name, id) == 0)
match_fname = ix; // matching identifier, use this if no matching name match_fname = ix; // matching identifier, use this if no matching name
} else if (strcmp(last_part, &id[strlen(id)-last_part_len]) == 0) {
else if (strcmp(last_part, &id[strlen(id)-last_part_len]) == 0)
match_fname2 = ix; match_fname2 = ix;
}
} }
} }


// is the main voice the required gender? // is the main voice the required gender?
skip = 0; skip = 0;


if ((gender != 0) && (vp->gender != gender)) {
if ((gender != 0) && (vp->gender != gender))
skip = 1; skip = 1;
}
if ((ix2 == 0) && aged && (vp->age < AGE_OLD)) {
if ((ix2 == 0) && aged && (vp->age < AGE_OLD))
skip = 1; skip = 1;
}


if (skip == 0) {
if (skip == 0)
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) {


while (regs.r[3] > 0) { while (regs.r[3] > 0) {
error = _kernel_swi(0x0c+0x20000, &regs, &regs); /* OS_GBPB 10, read directory entries */ error = _kernel_swi(0x0c+0x20000, &regs, &regs); /* OS_GBPB 10, read directory entries */
if ((error != NULL) || (regs.r[3] == 0)) {
if ((error != NULL) || (regs.r[3] == 0))
break; break;
}
type = (int *)(&buf[16]); type = (int *)(&buf[16]);
len = strlen(&buf[20]); len = strlen(&buf[20]);
sprintf(fname, "%s.%s", path, &buf[20]); sprintf(fname, "%s.%s", path, &buf[20]);
voice_data = ReadVoiceFile(f_voice, fname+len_path_voices, &buf[20]); voice_data = ReadVoiceFile(f_voice, fname+len_path_voices, &buf[20]);
fclose(f_voice); fclose(f_voice);


if (voice_data != NULL) {
if (voice_data != NULL)
voices_list[n_voices_list++] = voice_data; voices_list[n_voices_list++] = voice_data;
}
} }
} }
#else #else
voice_data = ReadVoiceFile(f_voice, fname+len_path_voices, FindFileData.cFileName); voice_data = ReadVoiceFile(f_voice, fname+len_path_voices, FindFileData.cFileName);
fclose(f_voice); fclose(f_voice);


if (voice_data != NULL) {
if (voice_data != NULL)
voices_list[n_voices_list++] = voice_data; voices_list[n_voices_list++] = voice_data;
}
} }
} }
} while (FindNextFileA(hFind, &FindFileData) != 0); } while (FindNextFileA(hFind, &FindFileData) != 0);
voice_data = ReadVoiceFile(f_voice, fname+len_path_voices, ent->d_name); voice_data = ReadVoiceFile(f_voice, fname+len_path_voices, ent->d_name);
fclose(f_voice); fclose(f_voice);


if (voice_data != NULL) {
if (voice_data != NULL)
voices_list[n_voices_list++] = voice_data; voices_list[n_voices_list++] = voice_data;
}
} }
} }
closedir(dir); closedir(dir);
// This may avoid the need to call espeak_ListVoices(). // This may avoid the need to call espeak_ListVoices().


if (LoadVoice(buf, 1) != NULL) { if (LoadVoice(buf, 1) != NULL) {
if (variant_name[0] != 0) {
if (variant_name[0] != 0)
LoadVoice(variant_name, 2); LoadVoice(variant_name, 2);
}


DoVoiceChange(voice); DoVoiceChange(voice);
voice_selector.languages = voice->language_name; voice_selector.languages = voice->language_name;


if ((v = SelectVoiceByName(voices_list, buf)) != NULL) { if ((v = SelectVoiceByName(voices_list, buf)) != NULL) {
if (LoadVoice(v->identifier, 0) != NULL) { if (LoadVoice(v->identifier, 0) != NULL) {
if (variant_name[0] != 0) {
if (variant_name[0] != 0)
LoadVoice(variant_name, 2); LoadVoice(variant_name, 2);
}
DoVoiceChange(voice); DoVoiceChange(voice);
voice_selector.languages = voice->language_name; voice_selector.languages = voice->language_name;
SetVoiceStack(&voice_selector, variant_name); SetVoiceStack(&voice_selector, variant_name);
j = 0; j = 0;
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;
}
} }
voices[j] = NULL; voices[j] = NULL;
} }

+ 37
- 53
src/libespeak-ng/wave.c View File

&& (aWrite >= myBuffer) && (aWrite >= myBuffer)
&& (aWrite <= myBuffer + BUFFER_LENGTH)); && (aWrite <= myBuffer + BUFFER_LENGTH));


if (aRead < aWrite) {
if (aRead < aWrite)
used = aWrite - aRead; used = aWrite - aRead;
} else {
else
used = aWrite + BUFFER_LENGTH - aRead; used = aWrite + BUFFER_LENGTH - aRead;
}
SHOW("get_used_mem > %d\n", used); SHOW("get_used_mem > %d\n", used);


return used; return used;
memset(p, 0, n - aUsedMem); memset(p, 0, n - aUsedMem);
myRead = aWrite; myRead = aWrite;
} }
} else { // myRead > aWrite
} else {
if ((size_t)(myBuffer + BUFFER_LENGTH - myRead) >= n) { if ((size_t)(myBuffer + BUFFER_LENGTH - myRead) >= n) {
memcpy(outputBuffer, myRead, n); memcpy(outputBuffer, myRead, n);
myRead += n; myRead += n;
SHOW("pa_callback > myRead=%x\n", (int)myRead); SHOW("pa_callback > myRead=%x\n", (int)myRead);


#ifdef ARCH_BIG #ifdef ARCH_BIG
{
// BIG-ENDIAN, swap the order of bytes in each sound sample in the portaudio buffer
int c;
unsigned char *out_ptr;
unsigned char *out_end;
out_ptr = (unsigned char *)outputBuffer;
out_end = out_ptr + framesPerBuffer*2 * out_channels;
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 in the portaudio buffer
int c;
unsigned char *out_ptr;
unsigned char *out_end;
out_ptr = (unsigned char *)outputBuffer;
out_end = out_ptr + framesPerBuffer*2 * out_channels;
while (out_ptr < out_end) {
c = out_ptr[0];
out_ptr[0] = out_ptr[1];
out_ptr[1] = c;
out_ptr += 2;
} }
#endif #endif


{ {
ENTER("wave_flush"); ENTER("wave_flush");


if (my_stream_could_start) {
if (my_stream_could_start)
start_stream(); start_stream();
}
} }


static int wave_open_sound() static int wave_open_sound()
active = Pa_IsStreamActive(pa_stream); active = Pa_IsStreamActive(pa_stream);
#endif #endif


if (active == 1) {
if (active == 1)
SHOW_TIME("wave_open_sound > already active"); SHOW_TIME("wave_open_sound > already active");
return 0; return 0;
}
if (active < 0) { if (active < 0) {
out_channels = 1; out_channels = 1;


for (i = 0; i < numDevices; i++) { for (i = 0; i < numDevices; i++) {
deviceInfo = Pa_GetDeviceInfo(i); deviceInfo = Pa_GetDeviceInfo(i);


if (deviceInfo == NULL) {
if (deviceInfo == NULL)
break; break;
}
const PaHostApiInfo *hostInfo = Pa_GetHostApiInfo(deviceInfo->hostApi); const PaHostApiInfo *hostInfo = Pa_GetHostApiInfo(deviceInfo->hostApi);


if (hostInfo && hostInfo->type == paALSA) { if (hostInfo && hostInfo->type == paALSA) {
} }
} }


if (selectedDeviceInfo) {
if (selectedDeviceInfo)
update_output_parameters(selectedIndex, selectedDeviceInfo); update_output_parameters(selectedIndex, selectedDeviceInfo);
} else {
else {
i = Pa_GetDefaultOutputDevice(); i = Pa_GetDefaultOutputDevice();
deviceInfo = Pa_GetDeviceInfo(i); deviceInfo = Pa_GetDeviceInfo(i);
update_output_parameters(i, deviceInfo); update_output_parameters(i, deviceInfo);
// PortAudio sound output library // PortAudio sound output library
err = Pa_Initialize(); err = Pa_Initialize();
pa_init_err = err; pa_init_err = err;
if (err != paNoError) {
if (err != paNoError)
SHOW_TIME("wave_init > Failed to initialise the PortAudio sound"); SHOW_TIME("wave_init > Failed to initialise the PortAudio sound");
}
return err == paNoError; return err == paNoError;
} }


a_dest[2*i+1] = a_src[i]; a_dest[2*i+1] = a_src[i];
} }
bytes_written = 2*theSizeInBytes; bytes_written = 2*theSizeInBytes;
} // end if(out_channels==1)
} // end if ((src != NULL) && dest != NULL)
}
}


return bytes_written; return bytes_written;
} }
return 0; return 0;
} }
my_stream_could_start = 1; my_stream_could_start = 1;
} else if (!wave_is_busy(NULL)) {
} else if (!wave_is_busy(NULL))
my_stream_could_start = 1; my_stream_could_start = 1;
}
assert(BUFFER_LENGTH >= bytes_to_write); assert(BUFFER_LENGTH >= bytes_to_write);


if (myWrite >= myBuffer + BUFFER_LENGTH) {
if (myWrite >= myBuffer + BUFFER_LENGTH)
myWrite = myBuffer; myWrite = myBuffer;
} // end if (myWrite >= myBuffer + BUFFER_LENGTH)


size_t aTotalFreeMem = 0; size_t aTotalFreeMem = 0;
char *aRead = myRead; char *aRead = myRead;
aRead = myRead; aRead = myRead;


// write pointer is before read pointer? // write pointer is before read pointer?
if (myWrite >= aRead) {
if (myWrite >= aRead)
aTotalFreeMem = aRead + BUFFER_LENGTH - myWrite; aTotalFreeMem = aRead + BUFFER_LENGTH - myWrite;
} else { // read pointer is before write pointer!
else // read pointer is before write pointer!
aTotalFreeMem = aRead - myWrite; aTotalFreeMem = aRead - myWrite;
} // end if (myWrite >= aRead)


if (aTotalFreeMem > 1) { if (aTotalFreeMem > 1) {
// -1 because myWrite must be different of aRead // -1 because myWrite must be different of aRead
// otherwise buffer would be considered as empty // otherwise buffer would be considered as empty
aTotalFreeMem -= 1; aTotalFreeMem -= 1;
} // end if (aTotalFreeMem>1)
}


if (aTotalFreeMem >= bytes_to_write) {
if (aTotalFreeMem >= bytes_to_write)
break; break;
} // end if (aTotalFreeMem >= bytes_to_write)


SHOW("wave_write > wait: aTotalFreeMem=%d\n", aTotalFreeMem); SHOW("wave_write > wait: aTotalFreeMem=%d\n", aTotalFreeMem);
SHOW("wave_write > aRead=%x, myWrite=%x\n", (int)aRead, (int)myWrite); SHOW("wave_write > aRead=%x, myWrite=%x\n", (int)aRead, (int)myWrite);
usleep(10000); usleep(10000);
} // end while (1)
}


aRead = myRead; aRead = myRead;


copyBuffer(myWrite, theMono16BitsWaveBuffer, aFreeMem); copyBuffer(myWrite, theMono16BitsWaveBuffer, aFreeMem);
myWrite = myBuffer; myWrite = myBuffer;
myWrite += copyBuffer(myWrite, theMono16BitsWaveBuffer+aFreeMem, theSize - aFreeMem); myWrite += copyBuffer(myWrite, theMono16BitsWaveBuffer+aFreeMem, theSize - aFreeMem);
} // end if (out_channels == 2)
} // end if (aFreeMem >= bytes_to_write)
} // if (myWrite >= aRead)
else { // read pointer is ahead the write pointer
}
}
} else { // read pointer is ahead the write pointer
SHOW_TIME("wave_write > myWrite <= aRead"); SHOW_TIME("wave_write > myWrite <= aRead");
myWrite += copyBuffer(myWrite, theMono16BitsWaveBuffer, theSize); myWrite += copyBuffer(myWrite, theMono16BitsWaveBuffer, theSize);
} // end if (myWrite >= aRead)
}


bytes_written = bytes_to_write; bytes_written = bytes_to_write;
myWritePosition += theSize/sizeof(uint16_t); // add number of samples myWritePosition += theSize/sizeof(uint16_t); // add number of samples


if (my_stream_could_start && (get_used_mem() >= out_channels * sizeof(uint16_t) * FRAMES_PER_BUFFER)) {
if (my_stream_could_start && (get_used_mem() >= out_channels * sizeof(uint16_t) * FRAMES_PER_BUFFER))
start_stream(); start_stream();
} // end if (my_stream_could_start && (get_used_mem() >= out_channels * sizeof(uint16_t) * FRAMES_PER_BUFFER))


SHOW_TIME("wave_write > LEAVE"); SHOW_TIME("wave_write > LEAVE");


// TBD: take in account time suplied by portaudio V18 API // TBD: take in account time suplied by portaudio V18 API
a_time = sample - myReadPosition; a_time = sample - myReadPosition;
a_time = 0.5 + (a_time * 1000.0) / wave_samplerate; a_time = 0.5 + (a_time * 1000.0) / wave_samplerate;
} else {
} else
a_time = 0; a_time = 0;
}


SHOW("wave_get_remaining_time > sample=%d, time=%d\n", sample, (uint32_t)a_time); SHOW("wave_get_remaining_time > sample=%d, time=%d\n", sample, (uint32_t)a_time);


{ {
struct timeval tv; struct timeval tv;


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


assert(gettimeofday(&tv, NULL) != -1); assert(gettimeofday(&tv, NULL) != -1);
ts->tv_sec = tv.tv_sec; ts->tv_sec = tv.tv_sec;


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) {
if (!ts)
return; return;
}


uint64_t t_ns = (uint64_t)ts->tv_nsec + 1000000 * (uint64_t)time_in_ms; uint64_t t_ns = (uint64_t)ts->tv_nsec + 1000000 * (uint64_t)time_in_ms;
while (t_ns >= ONE_BILLION) { while (t_ns >= ONE_BILLION) {

+ 7
- 13
src/libespeak-ng/wave_pulse.c View File

for (;;) { for (;;) {
CHECK_DEAD_GOTO(fail, 1); CHECK_DEAD_GOTO(fail, 1);


if ((i = pa_stream_get_timing_info(stream))) {
if ((i = pa_stream_get_timing_info(stream)))
break; break;
}
if (pa_context_errno(context) != PA_ERR_NODATA) { if (pa_context_errno(context) != PA_ERR_NODATA) {
SHOW("pa_stream_get_timing_info() failed: %s", pa_strerror(pa_context_errno(context))); SHOW("pa_stream_get_timing_info() failed: %s", pa_strerror(pa_context_errno(context)));
goto fail; goto fail;
} }
SHOW_TIME("pa_threaded_mainloop_wait (ret)"); SHOW_TIME("pa_threaded_mainloop_wait (ret)");


if (!success) {
if (!success)
SHOW("pa_stream_drain() failed: %s\n", pa_strerror(pa_context_errno(context))); SHOW("pa_stream_drain() failed: %s\n", pa_strerror(pa_context_errno(context)));
} else {
else
ret = PULSE_OK; ret = PULSE_OK;
}


fail: fail:
SHOW_TIME("pa_operation_unref (call)"); SHOW_TIME("pa_operation_unref (call)");
pa_threaded_mainloop_free(mainloop); pa_threaded_mainloop_free(mainloop);
mainloop = NULL; mainloop = NULL;
} }
} else {
} else
pulse_close(); pulse_close();
}


SHOW_TIME("pulse_open (ret false)"); SHOW_TIME("pulse_open (ret false)");


} }


// TBD: check if really helpful // TBD: check if really helpful
if (aTotalFreeMem >= MAXLENGTH*2) {
if (aTotalFreeMem >= MAXLENGTH*2)
aTotalFreeMem = MAXLENGTH*2; aTotalFreeMem = MAXLENGTH*2;
}


SHOW("wave_write > wait: aTotalFreeMem(%d) < bytes_to_write(%d)\n", aTotalFreeMem, bytes_to_write); SHOW("wave_write > wait: aTotalFreeMem(%d) < bytes_to_write(%d)\n", aTotalFreeMem, bytes_to_write);


{ {
struct timeval tv; struct timeval tv;


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


assert(gettimeofday(&tv, NULL) != -1); assert(gettimeofday(&tv, NULL) != -1);
ts->tv_sec = tv.tv_sec; ts->tv_sec = tv.tv_sec;


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) {
if (!ts)
return; return;
}


uint64_t t_ns = (uint64_t)ts->tv_nsec + 1000000 * (uint64_t)time_in_ms; uint64_t t_ns = (uint64_t)ts->tv_nsec + 1000000 * (uint64_t)time_in_ms;
while (t_ns >= ONE_BILLION) { while (t_ns >= ONE_BILLION) {

+ 19
- 25
src/libespeak-ng/wave_sada.c View File

/* /*
* Copyright (C) 2008, Sun Microsystems, Inc. * Copyright (C) 2008, Sun Microsystems, Inc.
* Copyright (C) 2015 Reece H. Dunn
* eSpeak driver for Solaris Audio Device Architecture (SADA) * eSpeak driver for Solaris Audio Device Architecture (SADA)
* Written by Willie Walker, based on the eSpeak PulseAudio driver * Written by Willie Walker, based on the eSpeak PulseAudio driver
* from Gilles Casse * from Gilles Casse


SHOW("wave_init() sun_audio_fd: %d\n", sun_audio_fd); SHOW("wave_init() sun_audio_fd: %d\n", sun_audio_fd);


if (sun_audio_fd < 0) {
if (sun_audio_fd < 0)
return 0; return 0;
}


ioctl(sun_audio_fd, AUDIO_GETINFO, &ainfo); ioctl(sun_audio_fd, AUDIO_GETINFO, &ainfo);
SHOW("wave_init() play buffer size: %d\n", ainfo.play.buffer_size); SHOW("wave_init() play buffer size: %d\n", ainfo.play.buffer_size);
} }


#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


// //
total_samples_sent += num / 2; total_samples_sent += num / 2;


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


SHOW_TIME("wave_write > LEAVE"); SHOW_TIME("wave_write > LEAVE");
return num; return num;
int wave_is_busy(void *theHandler) int wave_is_busy(void *theHandler)
{ {
uint32_t time; uint32_t time;
if (total_samples_sent >= 1) {
if (total_samples_sent >= 1)
wave_get_remaining_time(total_samples_sent - 1, &time); wave_get_remaining_time(total_samples_sent - 1, &time);
} else {
else
time = 0; time = 0;
}
return time != 0; return time != 0;
} }


{ {
struct timeval tv; struct timeval tv;


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


assert(gettimeofday(&tv, NULL) != -1); assert(gettimeofday(&tv, NULL) != -1);
ts->tv_sec = tv.tv_sec; ts->tv_sec = tv.tv_sec;


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) {
if (!ts)
return; return;
}


uint64_t t_ns = (uint64_t)ts->tv_nsec + 1000000 * (uint64_t)time_in_ms; uint64_t t_ns = (uint64_t)ts->tv_nsec + 1000000 * (uint64_t)time_in_ms;
while (t_ns >= ONE_BILLION) { while (t_ns >= ONE_BILLION) {

+ 30
- 51
src/libespeak-ng/wavegen.c View File

pa_stream = NULL; pa_stream = NULL;
return 1; return 1;
} }
} else {
} else
WavegenOpenSound(); // still items in the queue, shouldn't be closed WavegenOpenSound(); // still items in the queue, shouldn't be closed
}
} }
return 0; return 0;
} }
h = ((p->freq - p->left) / pitch) + 1; h = ((p->freq - p->left) / pitch) + 1;
if (h <= 0) h = 1; if (h <= 0) h = 1;


for (f = pitch*h; f < fp; f += pitch) {
for (f = pitch*h; f < fp; f += pitch)
htab[h++] += pk_shape[(fp-f)/(p->left>>8)] * p->height; htab[h++] += pk_shape[(fp-f)/(p->left>>8)] * p->height;
}
for (; f < fhi; f += pitch) {
for (; f < fhi; f += pitch)
htab[h++] += pk_shape[(f-fp)/(p->right>>8)] * p->height; htab[h++] += pk_shape[(f-fp)/(p->right>>8)] * p->height;
}
} }


{
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) {
htab[h++] += y;
y -= x;
}
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) {
htab[h++] += y;
y -= x;
} }
} }


x = htab[h] >> 15; x = htab[h] >> 15;
htab[h] = (x * x) >> 8; htab[h] = (x * x) >> 8;


if ((ix = (f >> 19)) < N_TONE_ADJUST) {
if ((ix = (f >> 19)) < N_TONE_ADJUST)
htab[h] = (htab[h] * wvoice->tone_adjust[ix]) >> 13; // index tone_adjust with Hz/8 htab[h] = (htab[h] * wvoice->tone_adjust[ix]) >> 13; // index tone_adjust with Hz/8
}
} }


// adjust the amplitude of the first harmonic, affects tonal quality // adjust the amplitude of the first harmonic, affects tonal quality


// calc intermediate increments of LF harmonics // calc intermediate increments of LF harmonics
if (control & 1) { if (control & 1) {
for (h = 1; h < N_LOWHARM; h++) {
for (h = 1; h < N_LOWHARM; h++)
harm_inc[h] = (htab[h] - harmspect[h]) >> 3; harm_inc[h] = (htab[h] - harmspect[h]) >> 3;
}
} }


return hmax; // highest harmonic number return hmax; // highest harmonic number
if (ix < 3) { if (ix < 3) {
peaks[ix].right1 += peaks[ix].right_inc; peaks[ix].right1 += peaks[ix].right_inc;
peaks[ix].right = (int)peaks[ix].right1; peaks[ix].right = (int)peaks[ix].right1;
} else {
} else
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
minus_pi_t = -PI / samplerate; minus_pi_t = -PI / samplerate;
two_pi_t = -2.0 * minus_pi_t; two_pi_t = -2.0 * minus_pi_t;


for (ix = 0; ix < N_PEAKS; ix++) {
for (ix = 0; ix < N_PEAKS; ix++)
setresonator(&rbreath[ix], 2000, 200, 1); setresonator(&rbreath[ix], 2000, 200, 1);
}
#endif #endif
} }




SetBreath(); SetBreath();
} else if ((samplecount & 0x07) == 0) { } else if ((samplecount & 0x07) == 0) {
for (h = 1; h < N_LOWHARM && h <= maxh2 && h <= maxh; h++) {
for (h = 1; h < N_LOWHARM && h <= maxh2 && h <= maxh; h++)
harmspect[h] += harm_inc[h]; harmspect[h] += harm_inc[h];
}


// bring automctic gain control back towards unity // bring automctic gain control back towards unity
if (agc < 256) agc++; if (agc < 256) agc++;
// This is the start of the second cycle, reduce its amplitude // This is the start of the second cycle, reduce its amplitude
glottal_flag = 2; glottal_flag = 2;
amplitude2 = (amplitude2 * glottal_reduce)/256; amplitude2 = (amplitude2 * glottal_reduce)/256;
} else {
} else
glottal_flag--; glottal_flag--;
}
} }


if (amplitude_env != NULL) { if (amplitude_env != NULL) {
} }
} }
} }
} else {
} else
wavephase += phaseinc; wavephase += phaseinc;
}
waveph = (unsigned short)(wavephase >> 16); waveph = (unsigned short)(wavephase >> 16);
total = 0; total = 0;


} }
#endif #endif


if (voicing != 64) {
if (voicing != 64)
total = (total >> 6) * voicing; total = (total >> 6) * voicing;
}


#ifndef PLATFORM_RISCOS #ifndef PLATFORM_RISCOS
if (wvoice->breath[0]) {
if (wvoice->breath[0])
total += ApplyBreath(); total += ApplyBreath();
}
#endif #endif


// mix with sampled wave if required // mix with sampled wave if required
factor = 256 + (25 * (pitch_value - 50))/50; factor = 256 + (25 * (pitch_value - 50))/50;
} }


for (ix = 0; ix <= 5; ix++) {
for (ix = 0; ix <= 5; ix++)
wvoice->freq[ix] = (wvoice->freq2[ix] * factor)/256; wvoice->freq[ix] = (wvoice->freq2[ix] * factor)/256;
}


factor = embedded_value[EMBED_T]*3; factor = embedded_value[EMBED_T]*3;
wvoice->height[0] = (wvoice->height2[0] * (256 - factor*2))/256; wvoice->height[0] = (wvoice->height2[0] * (256 - factor*2))/256;
break; break;


case WCMD_PAUSE: case WCMD_PAUSE:
if (resume == 0) {
if (resume == 0)
echo_complete -= length; echo_complete -= length;
}
wdata.n_mix_wavefile = 0; wdata.n_mix_wavefile = 0;
wdata.amplitude_fmt = 100; wdata.amplitude_fmt = 100;
#ifdef INCLUDE_KLATT #ifdef INCLUDE_KLATT
case WCMD_MARKER: case WCMD_MARKER:
marker_type = q[0] >> 8; marker_type = q[0] >> 8;
MarkerEvent(marker_type, q[1], q[2], q[3], out_ptr); MarkerEvent(marker_type, q[1], q[2], q[3], out_ptr);
if (marker_type == 1) { // word marker
if (marker_type == 1) // word marker
current_source_index = q[1] & 0xffffff; current_source_index = q[1] & 0xffffff;
}
break; break;


case WCMD_AMPLITUDE: case WCMD_AMPLITUDE:
if (result == 0) { if (result == 0) {
WcmdqIncHead(); WcmdqIncHead();
resume = 0; resume = 0;
} else {
} else
resume = 1; resume = 1;
}
} }


return 0; return 0;
static int SpeedUp(short *outbuf, int length_in, int length_out, int end_of_text) static int SpeedUp(short *outbuf, int length_in, int length_out, int end_of_text)
{ {
if (length_in > 0) { if (length_in > 0) {
if (sonicSpeedupStream == NULL) {
if (sonicSpeedupStream == NULL)
sonicSpeedupStream = sonicCreateStream(22050, 1); sonicSpeedupStream = sonicCreateStream(22050, 1);
}
if (sonicGetSpeed(sonicSpeedupStream) != sonicSpeed) {
if (sonicGetSpeed(sonicSpeedupStream) != sonicSpeed)
sonicSetSpeed(sonicSpeedupStream, sonicSpeed); sonicSetSpeed(sonicSpeedupStream, sonicSpeed);
}


sonicWriteShortToStream(sonicSpeedupStream, outbuf, length_in); sonicWriteShortToStream(sonicSpeedupStream, outbuf, length_in);
} }
if (sonicSpeedupStream == NULL) if (sonicSpeedupStream == NULL)
return 0; return 0;


if (end_of_text) {
if (end_of_text)
sonicFlushStream(sonicSpeedupStream); sonicFlushStream(sonicSpeedupStream);
}
return sonicReadShortFromStream(sonicSpeedupStream, outbuf, length_out); return sonicReadShortFromStream(sonicSpeedupStream, outbuf, length_out);
} }
#endif #endif

+ 6
- 12
src/speak-ng.c View File

voice_select.gender = 0; voice_select.gender = 0;
voice_select.name = NULL; voice_select.name = NULL;
voices = espeak_ListVoices(&voice_select); voices = espeak_ListVoices(&voice_select);
} else {
} else
voices = espeak_ListVoices(NULL); voices = espeak_ListVoices(NULL);
}


fprintf(f_out, "Pty Language Age/Gender VoiceName File Other Languages\n"); fprintf(f_out, "Pty Language Age/Gender VoiceName File Other Languages\n");


} }
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
fprintf(f_out, "(%s %d)", lang_name, p[0]); fprintf(f_out, "(%s %d)", lang_name, p[0]);
}
count++; count++;
p += len+2; p += len+2;
} }
} }


snprintf(path_home, sizeof(path_home), "%s/espeak-data", getenv("HOME")); snprintf(path_home, sizeof(path_home), "%s/espeak-data", getenv("HOME"));
if (access(path_home, R_OK) != 0) {
if (access(path_home, R_OK) != 0)
strcpy(path_home, PATH_ESPEAK_DATA); strcpy(path_home, PATH_ESPEAK_DATA);
}
#endif #endif
#endif #endif
} }
c = long_options[ix].val; c = long_options[ix].val;
optarg2 = NULL; optarg2 = NULL;


if ((long_options[ix].has_arg != 0) && (p[len] == '=')) {
if ((long_options[ix].has_arg != 0) && (p[len] == '='))
optarg2 = &p[len+1]; optarg2 = &p[len+1];
}
break; break;
} }
} }
if (flag_stdin == 0) if (flag_stdin == 0)
option_linelength = -1; // single input lines on stdin option_linelength = -1; // single input lines on stdin
} }
} else {
} else
f_text = fopen(filename, "r"); f_text = fopen(filename, "r");
}


if ((f_text == NULL) && (p_text == NULL)) { if ((f_text == NULL) && (p_text == NULL)) {
fprintf(stderr, "%sfile '%s'\n", err_load, filename); fprintf(stderr, "%sfile '%s'\n", err_load, filename);
break; // finished, wavegen command queue is empty break; // finished, wavegen command queue is empty
} }


if (Generate(phoneme_list, &n_phoneme_list, 1) == 0) {
if (Generate(phoneme_list, &n_phoneme_list, 1) == 0)
ix = SpeakNextClause(NULL, NULL, 1); ix = SpeakNextClause(NULL, NULL, 1);
}
} }


CloseWaveFile(); CloseWaveFile();

Loading…
Cancel
Save