Also use size_t instead of int in some places where it make sensemaster
void DisplayVoices(FILE *f_out, char *language) | void DisplayVoices(FILE *f_out, char *language) | ||||
{ | { | ||||
int ix; | |||||
const char *p; | const char *p; | ||||
int len; | int len; | ||||
int count; | int count; | ||||
fprintf(f_out, "Pty Language Age/Gender VoiceName File Other Languages\n"); | fprintf(f_out, "Pty Language Age/Gender VoiceName File Other Languages\n"); | ||||
for (ix = 0; (v = voices[ix]) != NULL; ix++) { | |||||
for (int ix = 0; (v = voices[ix]) != NULL; ix++) { | |||||
count = 0; | count = 0; | ||||
p = v->languages; | p = v->languages; | ||||
while (*p != 0) { | while (*p != 0) { | ||||
static void Write4Bytes(FILE *f, int value) | static void Write4Bytes(FILE *f, int value) | ||||
{ | { | ||||
// Write 4 bytes to a file, least significant first | // Write 4 bytes to a file, least significant first | ||||
int ix; | |||||
for (ix = 0; ix < 4; ix++) { | |||||
for (int ix = 0; ix < 4; ix++) { | |||||
fputc(value & 0xff, f); | fputc(value & 0xff, f); | ||||
value = value >> 8; | value = value >> 8; | ||||
} | } | ||||
static void CloseWavFile() | static void CloseWavFile() | ||||
{ | { | ||||
unsigned int pos; | |||||
if ((f_wavfile == NULL) || (f_wavfile == stdout)) | if ((f_wavfile == NULL) || (f_wavfile == stdout)) | ||||
return; | return; | ||||
fflush(f_wavfile); | fflush(f_wavfile); | ||||
pos = ftell(f_wavfile); | |||||
unsigned int pos = ftell(f_wavfile); | |||||
fseek(f_wavfile, 4, SEEK_SET); | fseek(f_wavfile, 4, SEEK_SET); | ||||
Write4Bytes(f_wavfile, pos - 8); | Write4Bytes(f_wavfile, pos - 8); | ||||
static int SynthCallback(short *wav, int numsamples, espeak_EVENT *events) | static int SynthCallback(short *wav, int numsamples, espeak_EVENT *events) | ||||
{ | { | ||||
char fname[210]; | |||||
if (quiet) return 0; // -q quiet mode | if (quiet) return 0; // -q quiet mode | ||||
if (wav == NULL) { | if (wav == NULL) { | ||||
} | } | ||||
if (f_wavfile == NULL) { | if (f_wavfile == NULL) { | ||||
char fname[210]; | |||||
if (samples_split > 0) { | if (samples_split > 0) { | ||||
sprintf(fname, "%s_%.2d%s", wavefile, wavefile_count+1, filetype); | sprintf(fname, "%s_%.2d%s", wavefile, wavefile_count+1, filetype); | ||||
if (OpenWavFile(fname, samplerate) != 0) | if (OpenWavFile(fname, samplerate) != 0) | ||||
int option_index = 0; | int option_index = 0; | ||||
int c; | int c; | ||||
int ix; | |||||
char *optarg2; | char *optarg2; | ||||
int value; | int value; | ||||
int flag_stdin = 0; | int flag_stdin = 0; | ||||
optind = 1; | optind = 1; | ||||
opt_string = ""; | opt_string = ""; | ||||
while (optind < argc) { | while (optind < argc) { | ||||
int len; | |||||
char *p; | char *p; | ||||
if ((c = *opt_string) == 0) { | if ((c = *opt_string) == 0) { | ||||
break; // -- means don't interpret further - as commands | break; // -- means don't interpret further - as commands | ||||
opt_string = ""; | opt_string = ""; | ||||
for (ix = 0;; ix++) { | |||||
for (int ix = 0;; ix++) { | |||||
if (long_options[ix].name == 0) | if (long_options[ix].name == 0) | ||||
break; | break; | ||||
len = strlen(long_options[ix].name); | |||||
size_t len = strlen(long_options[ix].name); | |||||
if (memcmp(long_options[ix].name, p, len) == 0) { | if (memcmp(long_options[ix].name, p, len) == 0) { | ||||
c = long_options[ix].val; | c = long_options[ix].val; | ||||
optarg2 = NULL; | optarg2 = NULL; | ||||
case 0x103: // --punct | case 0x103: // --punct | ||||
option_punctuation = 1; | option_punctuation = 1; | ||||
if (optarg2 != NULL) { | if (optarg2 != NULL) { | ||||
ix = 0; | |||||
int ix = 0; | |||||
while ((ix < N_PUNCTLIST) && ((option_punctlist[ix] = optarg2[ix]) != 0)) ix++; | while ((ix < N_PUNCTLIST) && ((option_punctlist[ix] = optarg2[ix]) != 0)) ix++; | ||||
option_punctlist[N_PUNCTLIST-1] = 0; | option_punctlist[N_PUNCTLIST-1] = 0; | ||||
option_punctuation = 2; | option_punctuation = 2; | ||||
} | } | ||||
} else { | } else { | ||||
// bulk input on stdin | // bulk input on stdin | ||||
ix = 0; | |||||
int ix = 0; | |||||
while (!feof(stdin)) { | while (!feof(stdin)) { | ||||
p_text[ix++] = fgetc(stdin); | p_text[ix++] = fgetc(stdin); | ||||
if (ix >= (max-1)) { | if (ix >= (max-1)) { |
// Read the phondata-manifest file | // Read the phondata-manifest file | ||||
FILE *f; | FILE *f; | ||||
int n_lines = 0; | int n_lines = 0; | ||||
int ix; | |||||
char *p; | char *p; | ||||
unsigned int value; | unsigned int value; | ||||
char buf[sizeof(path_home)+40]; | char buf[sizeof(path_home)+40]; | ||||
rewind(f); | rewind(f); | ||||
if (manifest != NULL) { | if (manifest != NULL) { | ||||
for (ix = 0; ix < n_manifest; ix++) | |||||
for (int ix = 0; ix < n_manifest; ix++) | |||||
free(manifest[ix].name); | free(manifest[ix].name); | ||||
} | } | ||||
static void DecompilePhoneme(FILE *f_out, PHONEME_TAB *ph, int compile_phoneme) | static void DecompilePhoneme(FILE *f_out, PHONEME_TAB *ph, int compile_phoneme) | ||||
{ | { | ||||
USHORT *pc; | USHORT *pc; | ||||
int instn; | |||||
int instn_category; | |||||
int address, address2; | int address, address2; | ||||
int data1; | |||||
int type2; | |||||
int ix; | |||||
int any; | |||||
const char *name; | const char *name; | ||||
char buf[120]; | char buf[120]; | ||||
pc = prog_buf; | pc = prog_buf; | ||||
while (pc < prog_out) { | while (pc < prog_out) { | ||||
instn = *pc++; | |||||
instn_category = (instn >> 12) & 0xf; | |||||
data1 = instn & 0xff; | |||||
type2 = (instn >> 8) & 0xf; | |||||
int instn = *pc++; | |||||
int instn_category = (instn >> 12) & 0xf; | |||||
int data1 = instn & 0xff; | |||||
int type2 = (instn >> 8) & 0xf; | |||||
fprintf(f_out, " %.3x: %.4x %s", (unsigned int)(pc-prog_buf), instn, instn_category_string[instn_category]); | fprintf(f_out, " %.3x: %.4x %s", (unsigned int)(pc-prog_buf), instn, instn_category_string[instn_category]); | ||||
switch (instn_category) | switch (instn_category) | ||||
data1 = 0; | data1 = 0; | ||||
fprintf(f_out, "%s", instn0_string[data1]); | fprintf(f_out, "%s", instn0_string[data1]); | ||||
} else if (type2 == i_IPA_NAME) { | } else if (type2 == i_IPA_NAME) { | ||||
int ix; | |||||
for (ix = 0; ix < data1; ix += 2) { | for (ix = 0; ix < data1; ix += 2) { | ||||
instn = *pc++; | instn = *pc++; | ||||
buf[ix] = instn >> 8; | buf[ix] = instn >> 8; | ||||
} else if (type2 == 8) { | } else if (type2 == 8) { | ||||
// list of numbers | // list of numbers | ||||
fprintf(f_out, " StressLevel("); | fprintf(f_out, " StressLevel("); | ||||
any = 0; | |||||
for (ix = 0; ix < 8; ix++) { | |||||
int any = 0; | |||||
for (int ix = 0; ix < 8; ix++) { | |||||
if (data1 & (1 << ix)) { | if (data1 & (1 << ix)) { | ||||
if (any) | if (any) | ||||
fputc(',', f_out); | fputc(',', f_out); | ||||
static int ref_sorter(char **a, char **b) | static int ref_sorter(char **a, char **b) | ||||
{ | { | ||||
int ix; | |||||
REF_HASH_TAB *p1 = (REF_HASH_TAB *)(*a); | REF_HASH_TAB *p1 = (REF_HASH_TAB *)(*a); | ||||
REF_HASH_TAB *p2 = (REF_HASH_TAB *)(*b); | REF_HASH_TAB *p2 = (REF_HASH_TAB *)(*b); | ||||
ix = strcoll(p1->string, p2->string); | |||||
int ix = strcoll(p1->string, p2->string); | |||||
if (ix != 0) | if (ix != 0) | ||||
return ix; | return ix; | ||||
static void CompileReport(void) | static void CompileReport(void) | ||||
{ | { | ||||
int ix; | int ix; | ||||
int hash; | |||||
int n; | |||||
REF_HASH_TAB *p; | REF_HASH_TAB *p; | ||||
REF_HASH_TAB **list; | REF_HASH_TAB **list; | ||||
const char *data_path; | const char *data_path; | ||||
int prev_table; | |||||
int procedure_num; | |||||
int prev_mnemonic; | |||||
if (f_report == NULL) | if (f_report == NULL) | ||||
return; | return; | ||||
fprintf(f_report, "Data file Used by\n"); | fprintf(f_report, "Data file Used by\n"); | ||||
ix = 0; | ix = 0; | ||||
for (hash = 0; (hash < 256) && (ix < count_references); hash++) { | |||||
for (int hash = 0; (hash < 256) && (ix < count_references); hash++) { | |||||
p = ref_hash_tab[hash]; | p = ref_hash_tab[hash]; | ||||
while (p != NULL) { | while (p != NULL) { | ||||
list[ix++] = p; | list[ix++] = p; | ||||
p = (REF_HASH_TAB *)(p->link); | p = (REF_HASH_TAB *)(p->link); | ||||
} | } | ||||
} | } | ||||
n = ix; | |||||
int n = ix; | |||||
qsort((void *)list, n, sizeof(REF_HASH_TAB *), (int (*)(const void *, const void *))ref_sorter); | qsort((void *)list, n, sizeof(REF_HASH_TAB *), (int (*)(const void *, const void *))ref_sorter); | ||||
data_path = ""; | data_path = ""; | ||||
prev_mnemonic = 0; | |||||
prev_table = 0; | |||||
int prev_mnemonic = 0; | |||||
int prev_table = 0; | |||||
for (ix = 0; ix < n; ix++) { | for (ix = 0; ix < n; ix++) { | ||||
int j = 0; | int j = 0; | ||||
prev_mnemonic = list[ix]->ph_mnemonic; | prev_mnemonic = list[ix]->ph_mnemonic; | ||||
if ((prev_mnemonic >> 24) == 'P') { | if ((prev_mnemonic >> 24) == 'P') { | ||||
// a procedure, not a phoneme | // a procedure, not a phoneme | ||||
procedure_num = atoi(WordToString(prev_mnemonic)); | |||||
int 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); | ||||
static unsigned int StringToWord(const char *string) | static unsigned int StringToWord(const char *string) | ||||
{ | { | ||||
// Pack 4 characters into a word | // Pack 4 characters into a word | ||||
int ix; | |||||
unsigned char c; | unsigned char c; | ||||
unsigned int word; | |||||
if (string == NULL) | if (string == NULL) | ||||
return 0; | return 0; | ||||
word = 0; | |||||
for (ix = 0; ix < 4; ix++) { | |||||
unsigned int word = 0; | |||||
for (int ix = 0; ix < 4; ix++) { | |||||
if (string[ix] == 0) break; | if (string[ix] == 0) break; | ||||
c = string[ix]; | c = string[ix]; | ||||
word |= (c << (ix*8)); | word |= (c << (ix*8)); | ||||
// control = 1 declare phoneme if not found | // control = 1 declare phoneme if not found | ||||
// control = 2 start looking after control & stress phonemes | // control = 2 start looking after control & stress phonemes | ||||
int ix; | |||||
int start; | |||||
int use; | |||||
unsigned int word; | |||||
if (strcmp(string, "NULL") == 0) | if (strcmp(string, "NULL") == 0) | ||||
return 1; | return 1; | ||||
ix = strlen(string); | |||||
int 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); | |||||
unsigned int word = StringToWord(string); | |||||
// don't use phoneme number 0, reserved for string terminator | // don't use phoneme number 0, reserved for string terminator | ||||
start = 1; | |||||
int start = 1; | |||||
if (control == 2) { | if (control == 2) { | ||||
// don't look for control and stress phonemes (allows these characters to be | // don't look for control and stress phonemes (allows these characters to be | ||||
start = 8; | start = 8; | ||||
} | } | ||||
use = 0; | |||||
int use = 0; | |||||
for (ix = start; ix < n_phcodes; ix++) { | for (ix = start; ix < n_phcodes; ix++) { | ||||
if (phoneme_tab2[ix].mnemonic == word) | if (phoneme_tab2[ix].mnemonic == word) | ||||
return ix; | return ix; | ||||
static unsigned int get_char() | static unsigned int get_char() | ||||
{ | { | ||||
unsigned int c; | |||||
c = fgetc(f_in); | |||||
unsigned int c = fgetc(f_in); | |||||
if (c == '\n') | if (c == '\n') | ||||
linenum++; | linenum++; | ||||
return c; | return c; | ||||
int acc; | int acc; | ||||
unsigned char c = 0; | unsigned char c = 0; | ||||
unsigned char c2; | unsigned char c2; | ||||
int ix; | |||||
int sign; | |||||
char *p; | char *p; | ||||
keywtab_t *pk; | keywtab_t *pk; | ||||
return -1; | return -1; | ||||
} | } | ||||
ix = 0; | |||||
int ix = 0; | |||||
while (!feof(f_in) && !isspace(c) && (c != '(') && (c != ')') && (c != ',')) { | while (!feof(f_in) && !isspace(c) && (c != '(') && (c != ')') && (c != ',')) { | ||||
if (c == '\\') | if (c == '\\') | ||||
c = get_char(); | c = get_char(); | ||||
if ((type == tNUMBER) || (type == tSIGNEDNUMBER)) { | if ((type == tNUMBER) || (type == tSIGNEDNUMBER)) { | ||||
acc = 0; | acc = 0; | ||||
sign = 1; | |||||
int sign = 1; | |||||
p = item_string; | p = item_string; | ||||
if ((*p == '-') && (type == tSIGNEDNUMBER)) { | if ((*p == '-') && (type == tSIGNEDNUMBER)) { | ||||
static int NextItemMax(int max) | static int NextItemMax(int max) | ||||
{ | { | ||||
// Get a number, but restrict value to max | // Get a number, but restrict value to max | ||||
int value; | |||||
char msg[80]; | char msg[80]; | ||||
value = NextItem(tNUMBER); | |||||
int value = NextItem(tNUMBER); | |||||
if (value > max) { | if (value > max) { | ||||
sprintf(msg, "Value %d is greater than maximum %d", value, max); | sprintf(msg, "Value %d is greater than maximum %d", value, max); | ||||
error(msg, NULL); | error(msg, NULL); | ||||
// control: bit 0 0= need ( | // control: bit 0 0= need ( | ||||
// bit 1 1= allow comma | // bit 1 1= allow comma | ||||
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); | |||||
int value = NextItem(type); | |||||
if ((control & 2) && (item_terminator == ',')) | if ((control & 2) && (item_terminator == ',')) | ||||
return value; | return value; | ||||
int CompileVowelTransition(int which) | int CompileVowelTransition(int which) | ||||
{ | { | ||||
// Compile a vowel transition | // Compile a vowel transition | ||||
int key; | |||||
int len = 0; | int len = 0; | ||||
int rms = 0; | int rms = 0; | ||||
int f1 = 0; | int f1 = 0; | ||||
int f3_amp = 0; | int f3_amp = 0; | ||||
int flags = 0; | int flags = 0; | ||||
int vcolour = 0; | int vcolour = 0; | ||||
int x; | |||||
int instn = i_VOWELIN; | int instn = i_VOWELIN; | ||||
int word1; | |||||
int word2; | |||||
if (which == 1) { | if (which == 1) { | ||||
len = 50 / 2; // defaults for transition into vowel | len = 50 / 2; // defaults for transition into vowel | ||||
} | } | ||||
for (;;) { | for (;;) { | ||||
key = NextItem(tKEYWORD); | |||||
int key = NextItem(tKEYWORD); | |||||
if (item_type != tTRANSITION) { | if (item_type != tTRANSITION) { | ||||
UngetItem(); | UngetItem(); | ||||
break; | break; | ||||
f2_min = Range(NextItem(tSIGNEDNUMBER), 50, -15, 15) & 0x1f; | f2_min = Range(NextItem(tSIGNEDNUMBER), 50, -15, 15) & 0x1f; | ||||
f2_max = Range(NextItem(tSIGNEDNUMBER), 50, -15, 15) & 0x1f; | f2_max = Range(NextItem(tSIGNEDNUMBER), 50, -15, 15) & 0x1f; | ||||
if (f2_min > f2_max) { | if (f2_min > f2_max) { | ||||
x = f2_min; | |||||
int x = f2_min; | |||||
f2_min = f2_max; | f2_min = f2_max; | ||||
f2_max = x; | f2_max = x; | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
word1 = len + (rms << 6) + (flags << 12); | |||||
word2 = f2 + (f2_min << 6) + (f2_max << 11) + (f3_adj << 16) + (f3_amp << 21) + (f1 << 26) + (vcolour << 29); | |||||
int word1 = len + (rms << 6) + (flags << 12); | |||||
int word2 = f2 + (f2_min << 6) + (f2_max << 11) + (f3_adj << 16) + (f3_amp << 21) + (f1 << 26) + (vcolour << 29); | |||||
prog_out[0] = instn + ((word1 >> 16) & 0xff); | prog_out[0] = instn + ((word1 >> 16) & 0xff); | ||||
prog_out[1] = word1; | prog_out[1] = word1; | ||||
prog_out[2] = word2 >> 16; | prog_out[2] = word2 >> 16; | ||||
int LoadSpect(const char *path, int control) | int LoadSpect(const char *path, int control) | ||||
{ | { | ||||
SpectSeq *spectseq; | SpectSeq *spectseq; | ||||
int peak; | |||||
int displ; | |||||
int frame; | |||||
int n_frames; | |||||
int ix; | int ix; | ||||
int x, x2; | int x, x2; | ||||
int rms; | |||||
float total; | |||||
float pkheight; | float pkheight; | ||||
int marker1_set = 0; | int marker1_set = 0; | ||||
int frame_vowelbreak = 0; | int frame_vowelbreak = 0; | ||||
} | } | ||||
// do we need additional klatt data ? | // do we need additional klatt data ? | ||||
for (frame = 0; frame < spectseq->numframes; frame++) { | |||||
for (int frame = 0; frame < spectseq->numframes; frame++) { | |||||
for (ix = 5; ix < N_KLATTP2; ix++) { | for (ix = 5; ix < N_KLATTP2; ix++) { | ||||
if (spectseq->frames[frame]->klatt_param[ix] != 0) | if (spectseq->frames[frame]->klatt_param[ix] != 0) | ||||
klatt_flag = FRFLAG_KLATT; | klatt_flag = FRFLAG_KLATT; | ||||
} | } | ||||
} | } | ||||
displ = ftell(f_phdata); | |||||
int displ = ftell(f_phdata); | |||||
seq_out.n_frames = 0; | seq_out.n_frames = 0; | ||||
seq_out.sqflags = 0; | seq_out.sqflags = 0; | ||||
seq_out.length_total = 0; | seq_out.length_total = 0; | ||||
total = 0; | |||||
for (frame = 0; frame < spectseq->numframes; frame++) { | |||||
float total = 0.0f; | |||||
for (int 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; | ||||
spectseq->frames[frame_vowelbreak]->markers |= FRFLAG_VOWEL_CENTRE; | spectseq->frames[frame_vowelbreak]->markers |= FRFLAG_VOWEL_CENTRE; | ||||
} | } | ||||
n_frames = 0; | |||||
for (frame = 0; frame < spectseq->numframes; frame++) { | |||||
int n_frames = 0; | |||||
for (int frame = 0; frame < spectseq->numframes; frame++) { | |||||
fr = spectseq->frames[frame]; | fr = spectseq->frames[frame]; | ||||
if (fr->keyframe) { | if (fr->keyframe) { | ||||
fr_out->frflags = fr->markers | klatt_flag; | fr_out->frflags = fr->markers | klatt_flag; | ||||
rms = (int)GetFrameRms(fr, spectseq->amplitude); | |||||
int rms = (int)GetFrameRms(fr, spectseq->amplitude); | |||||
if (rms > 255) rms = 255; | if (rms > 255) rms = 255; | ||||
fr_out->rms = rms; | fr_out->rms = rms; | ||||
// write: peak data | // write: peak data | ||||
count_frames++; | count_frames++; | ||||
for (peak = 0; peak < 8; peak++) { | |||||
for (int peak = 0; peak < 8; peak++) { | |||||
if (peak < 7) | if (peak < 7) | ||||
fr_out->ffreq[peak] = fr->peaks[peak].pkfreq; | fr_out->ffreq[peak] = fr->peaks[peak].pkfreq; | ||||
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 (int 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; | ||||
x = fr->peaks[peak].klt_bp / 2; | x = fr->peaks[peak].klt_bp / 2; | ||||
static int LoadWavefile(FILE *f, const char *fname) | static int LoadWavefile(FILE *f, const char *fname) | ||||
{ | { | ||||
int displ; | |||||
unsigned char c1; | unsigned char c1; | ||||
unsigned char c3; | unsigned char c3; | ||||
int c2; | int c2; | ||||
int sample; | int sample; | ||||
int sample2; | int sample2; | ||||
float x; | |||||
int max = 0; | int max = 0; | ||||
int length; | |||||
int sr1, sr2; | |||||
int failed; | int failed; | ||||
int len; | |||||
int resample_wav = 0; | int resample_wav = 0; | ||||
const char *fname2; | const char *fname2; | ||||
char fname_temp[100]; | char fname_temp[100]; | ||||
int scale_factor = 0; | int scale_factor = 0; | ||||
fseek(f, 24, SEEK_SET); | fseek(f, 24, SEEK_SET); | ||||
sr1 = Read4Bytes(f); | |||||
sr2 = Read4Bytes(f); | |||||
int sr1 = Read4Bytes(f); | |||||
int sr2 = Read4Bytes(f); | |||||
fseek(f, 40, SEEK_SET); | fseek(f, 40, SEEK_SET); | ||||
if ((sr1 != samplerate_native) || (sr2 != sr1*2)) { | if ((sr1 != samplerate_native) || (sr2 != sr1*2)) { | ||||
#endif | #endif | ||||
fname2 = fname; | fname2 = fname; | ||||
len = strlen(fname); | |||||
size_t len = strlen(fname); | |||||
if (strcmp(&fname[len-4], ".wav") == 0) { | if (strcmp(&fname[len-4], ".wav") == 0) { | ||||
strcpy(msg, fname); | strcpy(msg, fname); | ||||
msg[len-4] = 0; | msg[len-4] = 0; | ||||
fseek(f, 40, SEEK_SET); // skip past the WAV header, up to before "data length" | fseek(f, 40, SEEK_SET); // skip past the WAV header, up to before "data length" | ||||
} | } | ||||
displ = ftell(f_phdata); | |||||
int displ = ftell(f_phdata); | |||||
// data contains: 4 bytes of length (n_samples * 2), followed by 2-byte samples (lsb byte first) | // data contains: 4 bytes of length (n_samples * 2), followed by 2-byte samples (lsb byte first) | ||||
length = Read4Bytes(f); | |||||
int length = Read4Bytes(f); | |||||
while (!feof(f)) { | while (!feof(f)) { | ||||
c1 = fgetc(f); | c1 = fgetc(f); | ||||
fputc(sample & 0xff, f_phdata); | fputc(sample & 0xff, f_phdata); | ||||
fputc(sample >> 8, f_phdata); | fputc(sample >> 8, f_phdata); | ||||
} else { | } else { | ||||
x = ((float)sample / scale_factor) + 0.5; | |||||
float x = ((float)sample / scale_factor) + 0.5; | |||||
sample2 = (int)x; | sample2 = (int)x; | ||||
if (sample2 > 127) | if (sample2 > 127) | ||||
sample2 = 127; | sample2 = 127; | ||||
static int LoadEnvelope(FILE *f, const char *fname) | static int LoadEnvelope(FILE *f, const char *fname) | ||||
{ | { | ||||
int displ; | |||||
char buf[128]; | char buf[128]; | ||||
displ = ftell(f_phdata); | |||||
int 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) | ||||
static int LoadEnvelope2(FILE *f, const char *fname) | static int LoadEnvelope2(FILE *f, const char *fname) | ||||
{ | { | ||||
int ix, ix2; | |||||
int n; | int n; | ||||
int x, y; | |||||
int displ; | |||||
int n_points; | |||||
double yy; | |||||
char line_buf[128]; | char line_buf[128]; | ||||
float env_x[20]; | float env_x[20]; | ||||
float env_y[20]; | float env_y[20]; | ||||
int env_lin[20]; | int env_lin[20]; | ||||
unsigned char env[ENV_LEN]; | unsigned char env[ENV_LEN]; | ||||
n_points = 0; | |||||
int n_points = 0; | |||||
fgets(line_buf, sizeof(line_buf), f); // skip first line | fgets(line_buf, sizeof(line_buf), f); // skip first line | ||||
while (!feof(f)) { | while (!feof(f)) { | ||||
if (fgets(line_buf, sizeof(line_buf), f) == NULL) | if (fgets(line_buf, sizeof(line_buf), f) == NULL) | ||||
break; | break; | ||||
env_x[n_points] = env_x[n_points-1]; | env_x[n_points] = env_x[n_points-1]; | ||||
env_y[n_points] = env_y[n_points-1]; | env_y[n_points] = env_y[n_points-1]; | ||||
ix = -1; | |||||
ix2 = 0; | |||||
for (x = 0; x < ENV_LEN; x++) { | |||||
int ix = -1; | |||||
int ix2 = 0; | |||||
int y = 0; | |||||
for (int x = 0; x < ENV_LEN; x++) { | |||||
if (x > env_x[ix+4]) | if (x > env_x[ix+4]) | ||||
ix++; | ix++; | ||||
if (x >= env_x[ix2+1]) | if (x >= env_x[ix2+1]) | ||||
ix2++; | ix2++; | ||||
if (env_lin[ix2] > 0) { | if (env_lin[ix2] > 0) { | ||||
yy = env_y[ix2] + (env_y[ix2+1] - env_y[ix2]) * ((float)x - env_x[ix2]) / (env_x[ix2+1] - env_x[ix2]); | |||||
double yy = env_y[ix2] + (env_y[ix2+1] - env_y[ix2]) * ((float)x - env_x[ix2]) / (env_x[ix2+1] - env_x[ix2]); | |||||
y = (int)(yy * 2.55); | y = (int)(yy * 2.55); | ||||
} else if (n_points > 3) | } else if (n_points > 3) | ||||
y = (int)(polint(&env_x[ix], &env_y[ix], 4, x) * 2.55); // convert to range 0-255 | y = (int)(polint(&env_x[ix], &env_y[ix], 4, x) * 2.55); // convert to range 0-255 | ||||
n_envelopes++; | n_envelopes++; | ||||
} | } | ||||
displ = ftell(f_phdata); | |||||
int displ = ftell(f_phdata); | |||||
fwrite(env, 1, 128, f_phdata); | fwrite(env, 1, 128, f_phdata); | ||||
return displ; | return displ; | ||||
// return index into spect or sample data area. bit 23=1 if a sample | // return index into spect or sample data area. bit 23=1 if a sample | ||||
FILE *f; | FILE *f; | ||||
int id; | |||||
int hash; | |||||
int addr = 0; | int addr = 0; | ||||
int type_code = ' '; | int type_code = ' '; | ||||
REF_HASH_TAB *p, *p2; | REF_HASH_TAB *p, *p2; | ||||
count_references++; | count_references++; | ||||
hash = Hash8(path); | |||||
int hash = Hash8(path); | |||||
p = ref_hash_tab[hash]; | p = ref_hash_tab[hash]; | ||||
while (p != NULL) { | while (p != NULL) { | ||||
if (strcmp(path, p->string) == 0) { | if (strcmp(path, p->string) == 0) { | ||||
} | } | ||||
} | } | ||||
id = Read4Bytes(f); | |||||
int id = Read4Bytes(f); | |||||
rewind(f); | rewind(f); | ||||
if (id == 0x43455053) { | if (id == 0x43455053) { | ||||
static int CompileToneSpec(void) | static int CompileToneSpec(void) | ||||
{ | { | ||||
int pitch1 = 0; | |||||
int pitch2 = 0; | |||||
int pitch_env = 0; | int pitch_env = 0; | ||||
int amp_env = 0; | int amp_env = 0; | ||||
pitch1 = NextItemBrackets(tNUMBER, 2); | |||||
pitch2 = NextItemBrackets(tNUMBER, 3); | |||||
int pitch1 = NextItemBrackets(tNUMBER, 2); | |||||
int pitch2 = NextItemBrackets(tNUMBER, 3); | |||||
if (item_terminator == ',') { | if (item_terminator == ',') { | ||||
NextItemBrackets(tSTRING, 3); | NextItemBrackets(tSTRING, 3); | ||||
int CompileSound(int keyword, int isvowel) | int CompileSound(int keyword, int isvowel) | ||||
{ | { | ||||
int addr; | |||||
int value = 0; | int value = 0; | ||||
char path[N_ITEM_STRING]; | char path[N_ITEM_STRING]; | ||||
static int sound_instns[] = { i_FMT, i_WAV, i_VWLSTART, i_VWLENDING, i_WAVADD }; | static int sound_instns[] = { i_FMT, i_WAV, i_VWLSTART, i_VWLENDING, i_WAVADD }; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
addr = LoadDataFile(path, isvowel); | |||||
int addr = LoadDataFile(path, isvowel); | |||||
addr = addr / 4; // addr is words not bytes | addr = addr / 4; // addr is words not bytes | ||||
*prog_out++ = sound_instns[keyword-kFMT] + ((value & 0xff) << 4) + ((addr >> 16) & 0xf); | *prog_out++ = sound_instns[keyword-kFMT] + ((value & 0xff) << 4) + ((addr >> 16) & 0xf); | ||||
int word = 0; | int word = 0; | ||||
int word2; | int word2; | ||||
int data; | int data; | ||||
int bitmap; | |||||
int brackets; | |||||
int not_flag; | int not_flag; | ||||
USHORT *prog_last_if = NULL; | USHORT *prog_last_if = NULL; | ||||
} | } | ||||
} else if (item_type == tTEST) { | } else if (item_type == tTEST) { | ||||
if (key == kTHISSTRESS) { | if (key == kTHISSTRESS) { | ||||
bitmap = 0; | |||||
brackets = 2; | |||||
int bitmap = 0; | |||||
int brackets = 2; | |||||
do { | do { | ||||
data = NextItemBrackets(tNUMBER, brackets); | data = NextItemBrackets(tNUMBER, brackets); | ||||
if (data > 7) | if (data > 7) | ||||
void FillThen(int add) | void FillThen(int add) | ||||
{ | { | ||||
USHORT *p; | USHORT *p; | ||||
int offset; | |||||
p = if_stack[if_level].p_then; | p = if_stack[if_level].p_then; | ||||
if (p != NULL) { | if (p != NULL) { | ||||
offset = prog_out - p + add; | |||||
int offset = prog_out - p + add; | |||||
if ((then_count == 1) && (if_level == 1)) { | if ((then_count == 1) && (if_level == 1)) { | ||||
// The THEN part only contains one statement, we can remove the THEN jump | // The THEN part only contains one statement, we can remove the THEN jump | ||||
static PHONEME_TAB_LIST *FindPhonemeTable(const char *string) | static PHONEME_TAB_LIST *FindPhonemeTable(const char *string) | ||||
{ | { | ||||
int ix; | |||||
for (ix = 0; ix < n_phoneme_tabs; ix++) { | |||||
for (int 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]; | ||||
} | } | ||||
{ | { | ||||
PHONEME_TAB_LIST *phtab = NULL; | PHONEME_TAB_LIST *phtab = NULL; | ||||
int ix; | int ix; | ||||
unsigned int mnem; | |||||
char *phname; | char *phname; | ||||
char buf[200]; | char buf[200]; | ||||
if (phtab == NULL) | if (phtab == NULL) | ||||
return NULL; // phoneme table not found | return NULL; // phoneme table not found | ||||
mnem = StringToWord(phname); | |||||
unsigned int 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]; | ||||
static void ImportPhoneme(void) | static void ImportPhoneme(void) | ||||
{ | { | ||||
unsigned int ph_mnem; | |||||
unsigned int ph_code; | |||||
PHONEME_TAB *ph; | PHONEME_TAB *ph; | ||||
NextItem(tSTRING); | NextItem(tSTRING); | ||||
if ((ph = FindPhoneme(item_string)) == NULL) | if ((ph = FindPhoneme(item_string)) == NULL) | ||||
return; | return; | ||||
ph_mnem = phoneme_out->mnemonic; | |||||
ph_code = phoneme_out->code; | |||||
unsigned int ph_mnem = phoneme_out->mnemonic; | |||||
unsigned int ph_code = phoneme_out->code; | |||||
memcpy(phoneme_out, ph, sizeof(PHONEME_TAB)); | memcpy(phoneme_out, ph, sizeof(PHONEME_TAB)); | ||||
phoneme_out->mnemonic = ph_mnem; | phoneme_out->mnemonic = ph_mnem; | ||||
phoneme_out->code = ph_code; | phoneme_out->code = ph_code; | ||||
static void InstnPlusPhoneme(int instn) | static void InstnPlusPhoneme(int instn) | ||||
{ | { | ||||
int phcode; | |||||
phcode = NextItemBrackets(tPHONEMEMNEM, 0); | |||||
int phcode = NextItemBrackets(tPHONEMEMNEM, 0); | |||||
*prog_out++ = instn + phcode; | *prog_out++ = instn + phcode; | ||||
} | } | ||||
int keyword; | int keyword; | ||||
int value; | int value; | ||||
int phcode = 0; | int phcode = 0; | ||||
int flags; | |||||
int ix; | |||||
int start; | |||||
int count; | |||||
int c; | int c; | ||||
char *p; | char *p; | ||||
int vowel_length_factor = 100; // for testing | int vowel_length_factor = 100; // for testing | ||||
strcpy(item_string, " "); | strcpy(item_string, " "); | ||||
// copy the string, recognize characters in the form U+9999 | // copy the string, recognize characters in the form U+9999 | ||||
flags = 0; | |||||
count = 0; | |||||
ix = 1; | |||||
int flags = 0; | |||||
int count = 0; | |||||
int ix = 1; | |||||
for (p = item_string; *p != 0;) { | for (p = item_string; *p != 0;) { | ||||
p += utf8_in(&c, p); | p += utf8_in(&c, p); | ||||
ipa_buf[0] = flags; | ipa_buf[0] = flags; | ||||
ipa_buf[ix] = 0; | ipa_buf[ix] = 0; | ||||
start = 1; | |||||
int start = 1; | |||||
if (flags != 0) | if (flags != 0) | ||||
start = 0; // only include the flags byte if bits are set | start = 0; // only include the flags byte if bits are set | ||||
value = strlen(&ipa_buf[start]); // number of UTF-8 bytes | value = strlen(&ipa_buf[start]); // number of UTF-8 bytes | ||||
static void WritePhonemeTables() | static void WritePhonemeTables() | ||||
{ | { | ||||
int ix; | |||||
int j; | |||||
int n; | int n; | ||||
int value; | |||||
int count; | int count; | ||||
PHONEME_TAB *p; | PHONEME_TAB *p; | ||||
value = n_phoneme_tabs; | |||||
int value = n_phoneme_tabs; | |||||
fputc(value, f_phtab); | fputc(value, f_phtab); | ||||
fputc(0, f_phtab); | fputc(0, f_phtab); | ||||
fputc(0, f_phtab); | fputc(0, f_phtab); | ||||
fputc(0, f_phtab); | fputc(0, f_phtab); | ||||
for (ix = 0; ix < n_phoneme_tabs; ix++) { | |||||
for (int ix = 0; ix < n_phoneme_tabs; ix++) { | |||||
p = phoneme_tab_list2[ix].phoneme_tab_ptr; | p = phoneme_tab_list2[ix].phoneme_tab_ptr; | ||||
n = n_phcodes_list[ix]; | n = n_phcodes_list[ix]; | ||||
p[n].mnemonic = 0; // terminate the phoneme table | p[n].mnemonic = 0; // terminate the phoneme table | ||||
// count number of locally declared phonemes | // count number of locally declared phonemes | ||||
count = 0; | count = 0; | ||||
for (j = 0; j < n; j++) { | |||||
for (int j = 0; j < n; j++) { | |||||
if (ix == 0) | if (ix == 0) | ||||
p[j].phflags |= phLOCAL; // write all phonemes in the base phoneme table | p[j].phflags |= phLOCAL; // write all phonemes in the base phoneme table | ||||
fwrite(phoneme_tab_list2[ix].name, 1, N_PHONEME_TAB_NAME, f_phtab); | fwrite(phoneme_tab_list2[ix].name, 1, N_PHONEME_TAB_NAME, f_phtab); | ||||
for (j = 0; j < n; j++) { | |||||
for (int j = 0; j < n; j++) { | |||||
if (p[j].phflags & phLOCAL) { | if (p[j].phflags & phLOCAL) { | ||||
// this bit is set temporarily to incidate a local phoneme, declared in | // this bit is set temporarily to incidate a local phoneme, declared in | ||||
// in the current phoneme file | // in the current phoneme file | ||||
static void StartPhonemeTable(const char *name) | static void StartPhonemeTable(const char *name) | ||||
{ | { | ||||
int ix; | int ix; | ||||
int j; | |||||
PHONEME_TAB *p; | PHONEME_TAB *p; | ||||
fprintf(f_errors, "______________________________\nPhoneme Table: '%s'\n", name); | fprintf(f_errors, "______________________________\nPhoneme Table: '%s'\n", name); | ||||
n_phcodes = n_phcodes_list[ix]; | n_phcodes = n_phcodes_list[ix]; | ||||
// clear "local phoneme" bit" | // clear "local phoneme" bit" | ||||
for (j = 0; j < n_phcodes; j++) | |||||
for (int j = 0; j < n_phcodes; j++) | |||||
phoneme_tab2[j].phflags &= ~phLOCAL; | phoneme_tab2[j].phflags &= ~phLOCAL; | ||||
break; | break; | ||||
} | } | ||||
{ | { | ||||
// a list of phonemes in another language and the equivalent phoneme strings in this language | // a list of phonemes in another language and the equivalent phoneme strings in this language | ||||
int ix; | |||||
int n_names; | int n_names; | ||||
int n_bytes; | int n_bytes; | ||||
int foreign_phoneme; | int foreign_phoneme; | ||||
if ((p = strstr(line_buf, "//")) != NULL) | if ((p = strstr(line_buf, "//")) != NULL) | ||||
*p = 0; | *p = 0; | ||||
for (ix = 0; ix < 6; ix++) | |||||
for (int ix = 0; ix < 6; ix++) | |||||
names[ix][0] = 0; | names[ix][0] = 0; | ||||
n_names = sscanf(line_buf, "%s %s %s %s %s %s", names[0], names[1], names[2], names[3], names[4], names[5]); | n_names = sscanf(line_buf, "%s %s %s %s %s %s", names[0], names[1], names[2], names[3], names[4], names[5]); | ||||
if (n_names < 1) | if (n_names < 1) | ||||
} | } | ||||
} | } | ||||
for (ix = 1; ix < n_names; ix++) | |||||
for (int 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 |
void print_dictionary_flags(unsigned int *flags, char *buf, int buf_len) | void print_dictionary_flags(unsigned int *flags, char *buf, int buf_len) | ||||
{ | { | ||||
int stress; | int stress; | ||||
int ix; | |||||
const char *name; | const char *name; | ||||
int len; | int len; | ||||
int total = 0; | int total = 0; | ||||
buf += total; | buf += total; | ||||
} | } | ||||
for (ix = 8; ix < 64; ix++) { | |||||
for (int ix = 8; ix < 64; ix++) { | |||||
if (((ix < 30) && (flags[0] & (1 << ix))) || ((ix >= 0x20) && (flags[1] & (1 << (ix-0x20))))) { | if (((ix < 30) && (flags[0] & (1 << ix))) || ((ix >= 0x20) && (flags[1] & (1 << (ix-0x20))))) { | ||||
name = LookupMnemName(mnem_flags, ix); | name = LookupMnemName(mnem_flags, ix); | ||||
len = strlen(name) + 1; | len = strlen(name) + 1; | ||||
unsigned char c; | unsigned char c; | ||||
char *p; | char *p; | ||||
char *p_end; | char *p_end; | ||||
int ix; | |||||
int match_type; | |||||
int finished = 0; | int finished = 0; | ||||
int value; | int value; | ||||
int linenum = 0; | int linenum = 0; | ||||
static char symbols_lg[] = { 'A', 'B', 'C', 'H', 'F', 'G', 'Y' }; | static char symbols_lg[] = { 'A', 'B', 'C', 'H', 'F', 'G', 'Y' }; | ||||
match_type = 0; | |||||
int match_type = 0; | |||||
buf_pre[0] = 0; | buf_pre[0] = 0; | ||||
int ix; | |||||
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; | ||||
char *word; | char *word; | ||||
char *phonetic; | char *phonetic; | ||||
unsigned int ix; | unsigned int ix; | ||||
int step; | |||||
unsigned int n_flag_codes = 0; | unsigned int n_flag_codes = 0; | ||||
int flagnum; | |||||
int flag_offset; | |||||
int length; | int length; | ||||
int multiple_words = 0; | int multiple_words = 0; | ||||
int multiple_numeric_hyphen = 0; | int multiple_numeric_hyphen = 0; | ||||
char *multiple_string = NULL; | char *multiple_string = NULL; | ||||
char *multiple_string_end = NULL; | char *multiple_string_end = NULL; | ||||
int len_word; | |||||
int len_phonetic; | |||||
int text_not_phonemes; // this word specifies replacement text, not phonemes | |||||
unsigned int wc; | unsigned int wc; | ||||
int all_upper_case; | |||||
char *mnemptr; | char *mnemptr; | ||||
unsigned char flag_codes[100]; | unsigned char flag_codes[100]; | ||||
char encoded_ph[200]; | char encoded_ph[200]; | ||||
char bad_phoneme_str[4]; | |||||
int bad_phoneme; | |||||
static char nullstring[] = { 0 }; | static char nullstring[] = { 0 }; | ||||
text_not_phonemes = 0; | |||||
int text_not_phonemes = 0; // this word specifies replacement text, not phonemes | |||||
phonetic = word = nullstring; | phonetic = word = nullstring; | ||||
p = linebuf; | p = linebuf; | ||||
step = 0; | |||||
int step = 0; | |||||
c = 0; | c = 0; | ||||
while (c != '\n') { | while (c != '\n') { | ||||
if ((c == '?') && (step == 0)) { | if ((c == '?') && (step == 0)) { | ||||
// conditional rule, allow only if the numbered condition is set for the voice | // conditional rule, allow only if the numbered condition is set for the voice | ||||
flag_offset = 100; | |||||
int flag_offset = 100; | |||||
p++; | p++; | ||||
if (*p == '!') { | if (*p == '!') { | ||||
while (!isspace2(c = *p)) p++; | while (!isspace2(c = *p)) p++; | ||||
*p = 0; | *p = 0; | ||||
flagnum = LookupMnem(mnem_flags, mnemptr); | |||||
int flagnum = LookupMnem(mnem_flags, mnemptr); | |||||
if (flagnum > 0) { | if (flagnum > 0) { | ||||
if (flagnum == 200) | if (flagnum == 200) | ||||
text_mode = 1; | text_mode = 1; | ||||
// 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 { | ||||
int bad_phoneme; | |||||
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) { | ||||
char bad_phoneme_str[4]; | |||||
// unrecognised phoneme, report error | // unrecognised phoneme, report error | ||||
bad_phoneme_str[utf8_out(bad_phoneme, bad_phoneme_str)] = 0; | bad_phoneme_str[utf8_out(bad_phoneme, bad_phoneme_str)] = 0; | ||||
fprintf(f_log, "%5d: Bad phoneme [%s] (U+%x) in: %s %s\n", linenum, bad_phoneme_str, bad_phoneme, word, phonetic); | fprintf(f_log, "%5d: Bad phoneme [%s] (U+%x) in: %s %s\n", linenum, bad_phoneme_str, bad_phoneme, word, phonetic); | ||||
// convert to lower case, and note if the word is all-capitals | // convert to lower case, and note if the word is all-capitals | ||||
int c2; | int c2; | ||||
all_upper_case = 1; | |||||
int all_upper_case = 1; | |||||
p = word; | p = word; | ||||
for (p = word;;) { | for (p = word;;) { | ||||
// this assumes that the lower case char is the same length as the upper case char | // this assumes that the lower case char is the same length as the upper case char | ||||
flag_codes[n_flag_codes++] = BITNUM_FLAG_ALLCAPS; | flag_codes[n_flag_codes++] = BITNUM_FLAG_ALLCAPS; | ||||
} | } | ||||
len_word = strlen(word); | |||||
int 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); | |||||
int len_phonetic = strlen(encoded_ph); | |||||
dict_line[1] = len_word; // bit 6 indicates whether the word has been compressed | dict_line[1] = len_word; // bit 6 indicates whether the word has been compressed | ||||
len_word &= 0x3f; | len_word &= 0x3f; | ||||
static void compile_dictlist_start(void) | static void compile_dictlist_start(void) | ||||
{ | { | ||||
// initialise dictionary list | // initialise dictionary list | ||||
int ix; | |||||
char *p; | char *p; | ||||
char *p2; | char *p2; | ||||
for (ix = 0; ix < N_HASH_DICT; ix++) { | |||||
for (int ix = 0; ix < N_HASH_DICT; ix++) { | |||||
p = hash_chains[ix]; | p = hash_chains[ix]; | ||||
while (p != NULL) { | while (p != NULL) { | ||||
memcpy(&p2, p, sizeof(char *)); | memcpy(&p2, p, sizeof(char *)); | ||||
static void compile_dictlist_end(FILE *f_out) | static void compile_dictlist_end(FILE *f_out) | ||||
{ | { | ||||
// Write out the compiled dictionary list | // Write out the compiled dictionary list | ||||
int hash; | |||||
int length; | int length; | ||||
char *p; | char *p; | ||||
if (f_log != NULL) { | if (f_log != NULL) { | ||||
#ifdef OUTPUT_FORMAT | #ifdef OUTPUT_FORMAT | ||||
for (hash = 0; hash < N_HASH_DICT; hash++) { | |||||
for (int hash = 0; hash < N_HASH_DICT; hash++) { | |||||
fprintf(f_log, "%8d", hash_counts[hash]); | fprintf(f_log, "%8d", hash_counts[hash]); | ||||
if ((hash & 7) == 7) | if ((hash & 7) == 7) | ||||
fputc('\n', f_log); | fputc('\n', f_log); | ||||
#endif | #endif | ||||
} | } | ||||
for (hash = 0; hash < N_HASH_DICT; hash++) { | |||||
for (int hash = 0; hash < N_HASH_DICT; hash++) { | |||||
p = hash_chains[hash]; | p = hash_chains[hash]; | ||||
hash_counts[hash] = (int)ftell(f_out); | hash_counts[hash] = (int)ftell(f_out); | ||||
char *p; | char *p; | ||||
int count = 0; | int count = 0; | ||||
FILE *f_in; | FILE *f_in; | ||||
char buf[200]; | |||||
char fname[sizeof(path_home)+45]; | char fname[sizeof(path_home)+45]; | ||||
char dict_line[128]; | char dict_line[128]; | ||||
linenum = 0; | linenum = 0; | ||||
char buf[200]; | |||||
while (fgets(buf, sizeof(buf), f_in) != NULL) { | while (fgets(buf, sizeof(buf), f_in) != NULL) { | ||||
linenum++; | linenum++; | ||||
int len; | int len; | ||||
char c; | char c; | ||||
int c2, c3; | int c2, c3; | ||||
int sxflags; | |||||
int value; | int value; | ||||
int literal; | int literal; | ||||
int hexdigit_input = 0; | int hexdigit_input = 0; | ||||
rule_phonemes[len++] = ' '; | rule_phonemes[len++] = ' '; | ||||
output = &rule_phonemes[len]; | output = &rule_phonemes[len]; | ||||
} | } | ||||
sxflags = 0x808000; // to ensure non-zero bytes | |||||
int sxflags = 0x808000; // to ensure non-zero bytes | |||||
for (p = string, ix = 0;;) { | for (p = string, ix = 0;;) { | ||||
literal = 0; | literal = 0; | ||||
{ | { | ||||
int ix; | int ix; | ||||
unsigned char c; | unsigned char c; | ||||
int wc; | |||||
char *p; | char *p; | ||||
char *prule; | char *prule; | ||||
int len; | |||||
int len_name; | |||||
int start; | |||||
int state = 2; | int state = 2; | ||||
int finish = 0; | int finish = 0; | ||||
char buf[80]; | char buf[80]; | ||||
char output[150]; | char output[150]; | ||||
int bad_phoneme; | |||||
char bad_phoneme_str[4]; | |||||
buf[0] = 0; | buf[0] = 0; | ||||
rule_cond[0] = 0; | rule_cond[0] = 0; | ||||
return NULL; | return NULL; | ||||
} | } | ||||
int bad_phoneme; | |||||
char bad_phoneme_str[4]; | |||||
EncodePhonemes(rule_phonemes, buf, &bad_phoneme); | EncodePhonemes(rule_phonemes, buf, &bad_phoneme); | ||||
if (bad_phoneme != 0) { | if (bad_phoneme != 0) { | ||||
bad_phoneme_str[utf8_out(bad_phoneme, bad_phoneme_str)] = 0; | bad_phoneme_str[utf8_out(bad_phoneme, bad_phoneme_str)] = 0; | ||||
error_count++; | error_count++; | ||||
} | } | ||||
strcpy(output, buf); | strcpy(output, buf); | ||||
len = strlen(buf)+1; | |||||
size_t len = strlen(buf)+1; | |||||
len_name = strlen(group_name); | |||||
size_t len_name = strlen(group_name); | |||||
if ((len_name > 0) && (memcmp(rule_match, group_name, len_name) != 0)) { | if ((len_name > 0) && (memcmp(rule_match, group_name, len_name) != 0)) { | ||||
int wc; | |||||
utf8_in(&wc, rule_match); | utf8_in(&wc, rule_match); | ||||
if ((group_name[0] == '9') && IsDigit(wc)) { | if ((group_name[0] == '9') && IsDigit(wc)) { | ||||
// numeric group, rule_match starts with a digit, so OK | // numeric group, rule_match starts with a digit, so OK | ||||
} | } | ||||
} | } | ||||
if (rule_pre[0] != 0) { | if (rule_pre[0] != 0) { | ||||
start = 0; | |||||
int start = 0; | |||||
if (rule_pre[0] == RULE_SPACE) { | if (rule_pre[0] == RULE_SPACE) { | ||||
// 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; | ||||
static int __cdecl rgroup_sorter(RGROUP *a, RGROUP *b) | static int __cdecl rgroup_sorter(RGROUP *a, RGROUP *b) | ||||
{ | { | ||||
// Sort long names before short names | // Sort long names before short names | ||||
int ix; | |||||
ix = strlen(b->name) - strlen(a->name); | |||||
int ix = strlen(b->name) - strlen(a->name); | |||||
if (ix != 0) return ix; | if (ix != 0) return ix; | ||||
ix = strcmp(a->name, b->name); | ix = strcmp(a->name, b->name); | ||||
if (ix != 0) return ix; | if (ix != 0) return ix; | ||||
#ifdef OUTPUT_FORMAT | #ifdef OUTPUT_FORMAT | ||||
static void print_rule_group(FILE *f_out, int n_rules, char **rules, char *name) | static void print_rule_group(FILE *f_out, int n_rules, char **rules, char *name) | ||||
{ | { | ||||
int rule; | |||||
int ix; | |||||
unsigned char c; | unsigned char c; | ||||
int len1; | int len1; | ||||
int len2; | int len2; | ||||
int spaces; | |||||
char *p; | char *p; | ||||
char *pout; | char *pout; | ||||
int condition; | int condition; | ||||
fprintf(f_out, "\n$group %s\n", name); | fprintf(f_out, "\n$group %s\n", name); | ||||
for (rule = 0; rule < n_rules; rule++) { | |||||
for (int rule = 0; rule < n_rules; rule++) { | |||||
p = rules[rule]; | p = rules[rule]; | ||||
len1 = strlen(p) + 1; | len1 = strlen(p) + 1; | ||||
p = &p[len1]; | p = &p[len1]; | ||||
condition = 0; | condition = 0; | ||||
pout = rule_match; | pout = rule_match; | ||||
for (ix = 0; ix < len2; ix++) { | |||||
for (int ix = 0; ix < len2; ix++) { | |||||
switch (c = p[ix]) | switch (c = p[ix]) | ||||
{ | { | ||||
case RULE_PRE: | case RULE_PRE: | ||||
} | } | ||||
*pout = 0; | *pout = 0; | ||||
spaces = 12; | |||||
int spaces = 12; | |||||
if (condition > 0) { | if (condition > 0) { | ||||
sprintf(buf, "?%d ", condition); | sprintf(buf, "?%d ", condition); | ||||
spaces -= strlen(buf); | spaces -= strlen(buf); | ||||
if (rule_pre[0] != 0) { | if (rule_pre[0] != 0) { | ||||
p = buf; | p = buf; | ||||
for (ix = strlen(rule_pre)-1; ix >= 0; ix--) | |||||
for (int ix = strlen(rule_pre)-1; ix >= 0; ix--) | |||||
*p++ = rule_pre[ix]; | *p++ = rule_pre[ix]; | ||||
sprintf(p, ") "); | sprintf(p, ") "); | ||||
spaces -= strlen(buf); | spaces -= strlen(buf); | ||||
for (ix = 0; ix < spaces; ix++) | |||||
for (int ix = 0; ix < spaces; ix++) | |||||
fputc(' ', f_out); | fputc(' ', f_out); | ||||
fprintf(f_out, "%s", buf); | fprintf(f_out, "%s", buf); | ||||
spaces = 0; | spaces = 0; | ||||
} | } | ||||
for (ix = 0; ix < spaces; ix++) | |||||
for (int ix = 0; ix < spaces; ix++) | |||||
fputc(' ', f_out); | fputc(' ', f_out); | ||||
spaces = 14; | spaces = 14; | ||||
fprintf(f_out, "%s", buf); | fprintf(f_out, "%s", buf); | ||||
spaces -= strlen(buf); | spaces -= strlen(buf); | ||||
for (ix = 0; ix < spaces; ix++) | |||||
for (int ix = 0; ix < spaces; ix++) | |||||
fputc(' ', f_out); | fputc(' ', f_out); | ||||
DecodePhonemes(rules[rule], buf); | DecodePhonemes(rules[rule], buf); | ||||
fprintf(f_out, "%s\n", buf); // phonemes | fprintf(f_out, "%s\n", buf); // phonemes | ||||
static void output_rule_group(FILE *f_out, int n_rules, char **rules, char *name) | static void output_rule_group(FILE *f_out, int n_rules, char **rules, char *name) | ||||
{ | { | ||||
int ix; | |||||
int len1; | int len1; | ||||
int len2; | int len2; | ||||
int len_name; | |||||
char *p; | char *p; | ||||
char *p2, *p3; | char *p2, *p3; | ||||
const char *common; | const char *common; | ||||
short nextchar_count[256]; | short nextchar_count[256]; | ||||
memset(nextchar_count, 0, sizeof(nextchar_count)); | memset(nextchar_count, 0, sizeof(nextchar_count)); | ||||
len_name = strlen(name); | |||||
int len_name = strlen(name); | |||||
#ifdef OUTPUT_FORMAT | #ifdef OUTPUT_FORMAT | ||||
print_rule_group(f_log, n_rules, rules, name); | print_rule_group(f_log, n_rules, rules, name); | ||||
if (strcmp(name, "9") == 0) | if (strcmp(name, "9") == 0) | ||||
len_name = 0; // don't remove characters from numeric match strings | len_name = 0; // don't remove characters from numeric match strings | ||||
for (ix = 0; ix < n_rules; ix++) { | |||||
for (int ix = 0; ix < n_rules; ix++) { | |||||
p = rules[ix]; | p = rules[ix]; | ||||
len1 = strlen(p) + 1; // phoneme string | len1 = strlen(p) + 1; // phoneme string | ||||
p3 = &p[len1]; | p3 = &p[len1]; | ||||
} | } | ||||
#ifdef LIST_GROUP_INFO | #ifdef LIST_GROUP_INFO | ||||
for (ix = 32; ix < 256; ix++) { | |||||
for (int ix = 32; ix < 256; ix++) { | |||||
if (nextchar_count[ix] > 30) | if (nextchar_count[ix] > 30) | ||||
printf("Group %s %c %d\n", name, ix, nextchar_count[ix]); | printf("Group %s %c %d\n", name, ix, nextchar_count[ix]); | ||||
} | } | ||||
{ | { | ||||
char *p; | char *p; | ||||
char *p_start; | char *p_start; | ||||
int group; | |||||
int ix; | |||||
int n_items; | |||||
int length; | int length; | ||||
int max_length = 0; | int max_length = 0; | ||||
return 1; | return 1; | ||||
} | } | ||||
group = atoi(&p[0]); | |||||
int group = atoi(&p[0]); | |||||
if (group >= N_LETTER_GROUPS) { | if (group >= N_LETTER_GROUPS) { | ||||
fprintf(f_log, "%5d: lettergroup out of range (01-%.2d)\n", linenum, N_LETTER_GROUPS-1); | fprintf(f_log, "%5d: lettergroup out of range (01-%.2d)\n", linenum, N_LETTER_GROUPS-1); | ||||
error_count++; | error_count++; | ||||
} | } | ||||
letterGroupsDefined[group] = 1; | letterGroupsDefined[group] = 1; | ||||
n_items = 0; | |||||
int n_items = 0; | |||||
while (n_items < N_LETTERGP_ITEMS) { | while (n_items < N_LETTERGP_ITEMS) { | ||||
while (isspace2(*p)) p++; | while (isspace2(*p)) p++; | ||||
if (*p == 0) | if (*p == 0) | ||||
// write out the items, longest first | // write out the items, longest first | ||||
while (max_length > 1) { | while (max_length > 1) { | ||||
for (ix = 0; ix < n_items; ix++) { | |||||
for (int ix = 0; ix < n_items; ix++) { | |||||
if (item_length[ix] == max_length) | if (item_length[ix] == max_length) | ||||
fwrite(items[ix], 1, max_length, f_out); | fwrite(items[ix], 1, max_length, f_out); | ||||
} | } | ||||
FILE *f_in; | FILE *f_in; | ||||
FILE *f_out; | FILE *f_out; | ||||
int offset_rules = 0; | |||||
int value; | |||||
char fname_in[sizeof(path_home)+45]; | char fname_in[sizeof(path_home)+45]; | ||||
char fname_out[sizeof(path_home)+15]; | char fname_out[sizeof(path_home)+15]; | ||||
char fname_temp[sizeof(path_home)+15]; | char fname_temp[sizeof(path_home)+15]; | ||||
} | } | ||||
sprintf(fname_temp, "%s%ctemp", path_home, PATHSEP); | sprintf(fname_temp, "%s%ctemp", path_home, PATHSEP); | ||||
value = N_HASH_DICT; | |||||
int value = N_HASH_DICT; | |||||
int offset_rules = 0; | |||||
Write4Bytes(f_out, value); | Write4Bytes(f_out, value); | ||||
Write4Bytes(f_out, offset_rules); | Write4Bytes(f_out, offset_rules); | ||||
static unsigned int StringToWord(const char *string) | static unsigned int StringToWord(const char *string) | ||||
{ | { | ||||
// Pack 4 characters into a word | // Pack 4 characters into a word | ||||
int ix; | |||||
unsigned char c; | unsigned char c; | ||||
unsigned int word; | unsigned int word; | ||||
return 0; | return 0; | ||||
word = 0; | word = 0; | ||||
for (ix = 0; ix < 4; ix++) { | |||||
for (int ix = 0; ix < 4; ix++) { | |||||
if (string[ix] == 0) break; | if (string[ix] == 0) break; | ||||
c = string[ix]; | c = string[ix]; | ||||
word |= (c << (ix*8)); | word |= (c << (ix*8)); |
{ | { | ||||
// reverse the order of bytes from little-endian to big-endian | // reverse the order of bytes from little-endian to big-endian | ||||
#ifdef ARCH_BIG | #ifdef ARCH_BIG | ||||
int ix; | |||||
int word2 = 0; | int word2 = 0; | ||||
for (ix = 0; ix <= 24; ix += 8) { | |||||
for (int ix = 0; ix <= 24; ix += 8) { | |||||
word2 = word2 << 8; | word2 = word2 << 8; | ||||
word2 |= (word >> ix) & 0xff; | word2 |= (word >> ix) & 0xff; | ||||
} | } | ||||
int LoadDictionary(Translator *tr, const char *name, int no_error) | int LoadDictionary(Translator *tr, const char *name, int no_error) | ||||
{ | { | ||||
int hash; | |||||
char *p; | char *p; | ||||
int *pw; | int *pw; | ||||
int length; | |||||
FILE *f; | FILE *f; | ||||
unsigned int size; | |||||
char fname[sizeof(path_home)+20]; | char fname[sizeof(path_home)+20]; | ||||
strcpy(dictionary_name, name); // currently loaded dictionary name | strcpy(dictionary_name, name); // currently loaded dictionary name | ||||
// bytes 0-3: offset to rules data | // bytes 0-3: offset to rules data | ||||
// bytes 4-7: number of hash table entries | // bytes 4-7: number of hash table entries | ||||
sprintf(fname, "%s%c%s_dict", path_home, PATHSEP, name); | sprintf(fname, "%s%c%s_dict", path_home, PATHSEP, name); | ||||
size = GetFileLength(fname); | |||||
unsigned int size = GetFileLength(fname); | |||||
if (tr->data_dictlist != NULL) { | if (tr->data_dictlist != NULL) { | ||||
Free(tr->data_dictlist); | Free(tr->data_dictlist); | ||||
fclose(f); | fclose(f); | ||||
pw = (int *)(tr->data_dictlist); | pw = (int *)(tr->data_dictlist); | ||||
length = Reverse4Bytes(pw[1]); | |||||
int length = Reverse4Bytes(pw[1]); | |||||
if (size <= (N_HASH_DICT + sizeof(int)*2)) { | if (size <= (N_HASH_DICT + sizeof(int)*2)) { | ||||
fprintf(stderr, "Empty _dict file: '%s\n", fname); | fprintf(stderr, "Empty _dict file: '%s\n", fname); | ||||
// set up hash table for data_dictlist | // set up hash table for data_dictlist | ||||
p = &(tr->data_dictlist[8]); | p = &(tr->data_dictlist[8]); | ||||
for (hash = 0; hash < N_HASH_DICT; hash++) { | |||||
for (int 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; | ||||
*/ | */ | ||||
const char *EncodePhonemes(const char *p, char *outptr, int *bad_phoneme) | const char *EncodePhonemes(const char *p, char *outptr, int *bad_phoneme) | ||||
{ | { | ||||
int ix; | |||||
unsigned char c; | unsigned char c; | ||||
int count; // num. of matching characters | int count; // num. of matching characters | ||||
int max; // highest num. of matching found so far | int max; // highest num. of matching found so far | ||||
max = -1; | max = -1; | ||||
max_ph = 0; | max_ph = 0; | ||||
for (ix = 1; ix < n_phoneme_tab; ix++) { | |||||
for (int ix = 1; ix < n_phoneme_tab; ix++) { | |||||
if (phoneme_tab[ix] == NULL) | if (phoneme_tab[ix] == NULL) | ||||
continue; | continue; | ||||
if (phoneme_tab[ix]->type == phINVALID) | if (phoneme_tab[ix]->type == phINVALID) | ||||
char *WritePhMnemonic(char *phon_out, PHONEME_TAB *ph, PHONEME_LIST *plist, int use_ipa, int *flags) | char *WritePhMnemonic(char *phon_out, PHONEME_TAB *ph, PHONEME_LIST *plist, int use_ipa, int *flags) | ||||
{ | { | ||||
int c; | int c; | ||||
int mnem; | |||||
int len; | |||||
int first; | |||||
int ix = 0; | int ix = 0; | ||||
char *p; | char *p; | ||||
PHONEME_DATA phdata; | PHONEME_DATA phdata; | ||||
p++; | p++; | ||||
} | } | ||||
len = strlen(p); | |||||
int len = strlen(p); | |||||
if (len > 0) { | if (len > 0) { | ||||
strcpy(phon_out, p); | strcpy(phon_out, p); | ||||
phon_out += len; | phon_out += len; | ||||
} | } | ||||
} | } | ||||
first = 1; | |||||
for (mnem = ph->mnemonic; (c = mnem & 0xff) != 0; mnem = mnem >> 8) { | |||||
int first = 1; | |||||
for (int mnem = ph->mnemonic; (c = mnem & 0xff) != 0; mnem = mnem >> 8) { | |||||
if ((c == '/') && (option_phoneme_variants == 0)) | if ((c == '/') && (option_phoneme_variants == 0)) | ||||
break; // discard phoneme variant indicator | break; // discard phoneme variant indicator | ||||
*/ | */ | ||||
int ix; | |||||
unsigned int len; | unsigned int len; | ||||
int phon_out_ix = 0; | int phon_out_ix = 0; | ||||
int stress; | int stress; | ||||
use_tie = 0; | use_tie = 0; | ||||
} | } | ||||
for (ix = 1; ix < (n_phoneme_list-2); ix++) { | |||||
for (int ix = 1; ix < (n_phoneme_list-2); ix++) { | |||||
buf = phon_buf; | buf = phon_buf; | ||||
plist = &phoneme_list[ix]; | plist = &phoneme_list[ix]; | ||||
static int Unpronouncable2(Translator *tr, char *word) | static int Unpronouncable2(Translator *tr, char *word) | ||||
{ | { | ||||
int c; | |||||
int end_flags; | |||||
char ph_buf[N_WORD_PHONEMES]; | char ph_buf[N_WORD_PHONEMES]; | ||||
ph_buf[0] = 0; | ph_buf[0] = 0; | ||||
c = word[-1]; | |||||
int c = word[-1]; | |||||
word[-1] = ' '; // ensure there is a space before the "word" | word[-1] = ' '; // ensure there is a space before the "word" | ||||
end_flags = TranslateRules(tr, word, ph_buf, sizeof(ph_buf), NULL, FLAG_UNPRON_TEST, NULL); | |||||
int end_flags = TranslateRules(tr, word, ph_buf, sizeof(ph_buf), NULL, FLAG_UNPRON_TEST, NULL); | |||||
word[-1] = c; | word[-1] = c; | ||||
if ((end_flags == 0) || (end_flags & SUFX_UNPRON)) | if ((end_flags == 0) || (end_flags & SUFX_UNPRON)) | ||||
return 1; | return 1; | ||||
int c; | int c; | ||||
int c1 = 0; | int c1 = 0; | ||||
int vowel_posn = 9; | int vowel_posn = 9; | ||||
int index; | |||||
int count; | |||||
ALPHABET *alphabet; | ALPHABET *alphabet; | ||||
utf8_in(&c, word); | utf8_in(&c, word); | ||||
if (((c = *word) == ' ') || (c == 0) || (c == '\'')) | if (((c = *word) == ' ') || (c == 0) || (c == '\'')) | ||||
return 0; | return 0; | ||||
index = 0; | |||||
count = 0; | |||||
int index = 0; | |||||
int count = 0; | |||||
for (;;) { | for (;;) { | ||||
index += utf8_in(&c, &word[index]); | index += utf8_in(&c, &word[index]); | ||||
if ((c == 0) || (c == ' ')) | if ((c == 0) || (c == ' ')) | ||||
{ | { | ||||
int ix; | int ix; | ||||
unsigned char *p; | unsigned char *p; | ||||
int max_stress; | |||||
int vowel_count; // num of vowels + 1 | int vowel_count; // num of vowels + 1 | ||||
int stressed_syllable = 0; // position of stressed syllable | int stressed_syllable = 0; // position of stressed syllable | ||||
unsigned char phonetic[N_WORD_PHONEMES]; | unsigned char phonetic[N_WORD_PHONEMES]; | ||||
signed char vowel_stress[N_WORD_PHONEMES/2]; | signed char vowel_stress[N_WORD_PHONEMES/2]; | ||||
strcpy((char *)phonetic, word); | strcpy((char *)phonetic, word); | ||||
max_stress = GetVowelStress(tr, phonetic, vowel_stress, &vowel_count, &stressed_syllable, 0); | |||||
int max_stress = GetVowelStress(tr, phonetic, vowel_stress, &vowel_count, &stressed_syllable, 0); | |||||
if (new_stress >= 4) { | if (new_stress >= 4) { | ||||
// promote to primary stress | // promote to primary stress | ||||
int mnem; | int mnem; | ||||
int opt_length; | int opt_length; | ||||
int done; | int done; | ||||
int stressflags; | |||||
int dflags = 0; | int dflags = 0; | ||||
int first_primary; | int first_primary; | ||||
int long_vowel; | int long_vowel; | ||||
3 secondary stress | 3 secondary stress | ||||
4 main stress */ | 4 main stress */ | ||||
stressflags = tr->langopts.stress_flags; | |||||
int stressflags = tr->langopts.stress_flags; | |||||
if (dictionary_flags != NULL) | if (dictionary_flags != NULL) | ||||
dflags = dictionary_flags[0]; | dflags = dictionary_flags[0]; | ||||
{ | { | ||||
// apply after the translation is complete | // apply after the translation is complete | ||||
int ix; | |||||
int len; | |||||
char *p; | char *p; | ||||
len = strlen(phonemes); | |||||
int len = strlen(phonemes); | |||||
if (tr->langopts.param[LOPT_ALT] & 2) { | if (tr->langopts.param[LOPT_ALT] & 2) { | ||||
for (ix = 0; ix < (len-1); ix++) { | |||||
for (int ix = 0; ix < (len-1); ix++) { | |||||
if (phonemes[ix] == phonSTRESS_P) { | if (phonemes[ix] == phonSTRESS_P) { | ||||
p = &phonemes[ix+1]; | p = &phonemes[ix+1]; | ||||
if ((dict_flags & FLAG_ALT2_TRANS) != 0) { | if ((dict_flags & FLAG_ALT2_TRANS) != 0) { | ||||
int c; | int c; | ||||
int c2; | int c2; | ||||
int ix; | int ix; | ||||
int offset; | |||||
int min; | |||||
int max; | |||||
const char *map; | const char *map; | ||||
char *p = text; | char *p = text; | ||||
char *p2; | char *p2; | ||||
int all_alpha = 1; | int all_alpha = 1; | ||||
int bits; | int bits; | ||||
int acc; | int acc; | ||||
int pairs_start; | |||||
const short *pairs_list; | const short *pairs_list; | ||||
int bufix; | |||||
char buf[N_WORD_BYTES+1]; | char buf[N_WORD_BYTES+1]; | ||||
offset = tr->transpose_min - 1; | |||||
min = tr->transpose_min; | |||||
max = tr->transpose_max; | |||||
int offset = tr->transpose_min - 1; | |||||
int min = tr->transpose_min; | |||||
int max = tr->transpose_max; | |||||
map = tr->transpose_map; | map = tr->transpose_map; | ||||
pairs_start = max - min + 2; | |||||
int pairs_start = max - min + 2; | |||||
bufix = 0; | |||||
int bufix = 0; | |||||
do { | do { | ||||
p += utf8_in(&c, p); | p += utf8_in(&c, p); | ||||
if (c != 0) { | if (c != 0) { | ||||
{ | { | ||||
char *p; | char *p; | ||||
char *next; | char *next; | ||||
int hash; | |||||
int phoneme_len; | int phoneme_len; | ||||
int wlen; | int wlen; | ||||
unsigned char flag; | unsigned char flag; | ||||
const char *word_end; | const char *word_end; | ||||
const char *word1; | const char *word1; | ||||
int wflags = 0; | int wflags = 0; | ||||
int lookup_symbol; | |||||
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; | |||||
int lookup_symbol = flags[1] & FLAG_LOOKUP_SYMBOL; | |||||
word1 = word; | word1 = word; | ||||
if (tr->transpose_min > 0) { | if (tr->transpose_min > 0) { | ||||
strncpy0(word_buf, word, N_WORD_BYTES); | strncpy0(word_buf, word, N_WORD_BYTES); | ||||
} else | } else | ||||
wlen = strlen(word); | wlen = strlen(word); | ||||
hash = HashDictionary(word); | |||||
int hash = HashDictionary(word); | |||||
p = tr->dict_hashtab[hash]; | p = tr->dict_hashtab[hash]; | ||||
if (p == NULL) { | if (p == NULL) { | ||||
*/ | */ | ||||
int LookupDictList(Translator *tr, char **wordptr, char *ph_out, unsigned int *flags, int end_flags, WORD_TAB *wtab) | int LookupDictList(Translator *tr, char **wordptr, char *ph_out, unsigned int *flags, int end_flags, WORD_TAB *wtab) | ||||
{ | { | ||||
int length; | |||||
const char *found; | const char *found; | ||||
const char *word1; | const char *word1; | ||||
const char *word2; | const char *word2; | ||||
char word[N_WORD_BYTES]; | char word[N_WORD_BYTES]; | ||||
static char word_replacement[N_WORD_BYTES]; | static char word_replacement[N_WORD_BYTES]; | ||||
length = 0; | |||||
int length = 0; | |||||
word2 = word1 = *wordptr; | word2 = word1 = *wordptr; | ||||
while ((word2[nbytes = utf8_nbytes(word2)] == ' ') && (word2[nbytes+1] == '.')) { | while ((word2[nbytes = utf8_nbytes(word2)] == ' ') && (word2[nbytes+1] == '.')) { | ||||
int flags0; | int flags0; | ||||
unsigned int flags[2]; | unsigned int flags[2]; | ||||
int say_as; | |||||
char *word1 = (char *)word; | char *word1 = (char *)word; | ||||
char text[80]; | char text[80]; | ||||
flags0 = flags[0]; | flags0 = flags[0]; | ||||
if (flags[0] & FLAG_TEXTMODE) { | if (flags[0] & FLAG_TEXTMODE) { | ||||
say_as = option_sayas; | |||||
int say_as = option_sayas; | |||||
option_sayas = 0; // don't speak replacement word as letter names | option_sayas = 0; // don't speak replacement word as letter names | ||||
text[0] = 0; | text[0] = 0; | ||||
strncpy0(&text[1], word1, sizeof(text)); | strncpy0(&text[1], word1, sizeof(text)); | ||||
that were done when the suffix was added to the original word. | that were done when the suffix was added to the original word. | ||||
*/ | */ | ||||
int i; | |||||
char *word_end; | char *word_end; | ||||
int len_ending; | |||||
int end_flags; | |||||
const char *p; | const char *p; | ||||
int len; | int len; | ||||
char ending[50]; | char ending[50]; | ||||
if (*word_end == REPLACED_E) | if (*word_end == REPLACED_E) | ||||
*word_end = 'e'; | *word_end = 'e'; | ||||
} | } | ||||
i = word_end - word; | |||||
int i = word_end - word; | |||||
if (word_copy != NULL) { | if (word_copy != NULL) { | ||||
memcpy(word_copy, word, i); | memcpy(word_copy, word, i); | ||||
} | } | ||||
// look for multibyte characters to increase the number of bytes to remove | // look for multibyte characters to increase the number of bytes to remove | ||||
int len_ending; | |||||
for (len_ending = i = (end_type & 0x3f); i > 0; i--) { // num.of characters of the suffix | for (len_ending = i = (end_type & 0x3f); i > 0; i--) { // num.of characters of the suffix | ||||
word_end--; | word_end--; | ||||
while ((*word_end & 0xc0) == 0x80) { | while ((*word_end & 0xc0) == 0x80) { | ||||
ending[i] = 0; | ending[i] = 0; | ||||
word_end--; // now pointing at last character of stem | word_end--; // now pointing at last character of stem | ||||
end_flags = (end_type & 0xfff0) | FLAG_SUFX; | |||||
int end_flags = (end_type & 0xfff0) | FLAG_SUFX; | |||||
/* add an 'e' to the stem if appropriate, | /* add an 'e' to the stem if appropriate, | ||||
if stem ends in vowel+consonant | if stem ends in vowel+consonant |
double ConvertFromIeeeExtended(unsigned char *bytes /* LCN */) | double ConvertFromIeeeExtended(unsigned char *bytes /* LCN */) | ||||
{ | { | ||||
double f; | double f; | ||||
int expon; | |||||
unsigned long hiMant, loMant; | |||||
expon = ((bytes[0] & 0x7F) << 8) | (bytes[1] & 0xFF); | |||||
hiMant = ((unsigned long)(bytes[2] & 0xFF) << 24) | |||||
int expon = ((bytes[0] & 0x7F) << 8) | (bytes[1] & 0xFF); | |||||
int hiMant = ((unsigned long)(bytes[2] & 0xFF) << 24) | |||||
| ((unsigned long)(bytes[3] & 0xFF) << 16) | | ((unsigned long)(bytes[3] & 0xFF) << 16) | ||||
| ((unsigned long)(bytes[4] & 0xFF) << 8) | | ((unsigned long)(bytes[4] & 0xFF) << 8) | ||||
| ((unsigned long)(bytes[5] & 0xFF)); | | ((unsigned long)(bytes[5] & 0xFF)); | ||||
loMant = ((unsigned long)(bytes[6] & 0xFF) << 24) | |||||
int loMant = ((unsigned long)(bytes[6] & 0xFF) << 24) | |||||
| ((unsigned long)(bytes[7] & 0xFF) << 16) | | ((unsigned long)(bytes[7] & 0xFF) << 16) | ||||
| ((unsigned long)(bytes[8] & 0xFF) << 8) | | ((unsigned long)(bytes[8] & 0xFF) << 8) | ||||
| ((unsigned long)(bytes[9] & 0xFF)); | | ((unsigned long)(bytes[9] & 0xFF)); |
static void count_pitch_vowels(int start, int end, int clause_end) | static void count_pitch_vowels(int start, int end, int clause_end) | ||||
{ | { | ||||
int ix; | |||||
int stress; | int stress; | ||||
int max_stress = 0; | int max_stress = 0; | ||||
int max_stress_posn = 0; // last syllable ot the highest stress | int max_stress_posn = 0; // last syllable ot the highest stress | ||||
number_tail = 0; // number between tonic syllable and next primary | number_tail = 0; // number between tonic syllable and next primary | ||||
last_primary = -1; | last_primary = -1; | ||||
for (ix = start; ix < end; ix++) { | |||||
for (int ix = start; ix < end; ix++) { | |||||
stress = syllable_tab[ix].stress; // marked stress level | stress = syllable_tab[ix].stress; // marked stress level | ||||
if (stress >= max_stress) { | if (stress >= max_stress) { | ||||
// Set the pitch of a vowel in syllable_tab | // Set the pitch of a vowel in syllable_tab | ||||
static void set_pitch(SYLLABLE *syl, int base, int drop) | static void set_pitch(SYLLABLE *syl, int base, int drop) | ||||
{ | { | ||||
int pitch1, pitch2; | |||||
int flags = 0; | int flags = 0; | ||||
if (base < 0) base = 0; | if (base < 0) base = 0; | ||||
pitch2 = base; | |||||
int pitch2 = base; | |||||
if (drop < 0) { | if (drop < 0) { | ||||
flags = SYL_RISE; | flags = SYL_RISE; | ||||
drop = -drop; | drop = -drop; | ||||
} | } | ||||
pitch1 = pitch2 + drop; | |||||
int pitch1 = pitch2 + drop; | |||||
if (pitch1 < 0) | if (pitch1 < 0) | ||||
pitch1 = 0; | pitch1 = 0; | ||||
static int CountUnstressed(int start, int end, int limit) | static int CountUnstressed(int start, int end, int limit) | ||||
{ | { | ||||
int ix; | |||||
int ix; | |||||
for (ix = start; ix <= end; ix++) { | for (ix = start; ix <= end; ix++) { | ||||
if (syllable_tab[ix].stress >= limit) | if (syllable_tab[ix].stress >= limit) | ||||
break; | break; | ||||
int increment = 0; | int increment = 0; | ||||
int n_steps = 0; | int n_steps = 0; | ||||
int stage; // onset, head, last | int stage; // onset, head, last | ||||
int initial; | |||||
int overflow_ix = 0; | int overflow_ix = 0; | ||||
int pitch_range; | |||||
int pitch_range_abs; | |||||
int *drops; | int *drops; | ||||
int n_unstressed = 0; | int n_unstressed = 0; | ||||
int unstressed_ix = 0; | int unstressed_ix = 0; | ||||
int head_final = end_ix; | int head_final = end_ix; | ||||
int secondary = 2; | int secondary = 2; | ||||
pitch_range = (tune->head_end - tune->head_start) << 8; | |||||
pitch_range_abs = abs(pitch_range); | |||||
int pitch_range = (tune->head_end - tune->head_start) << 8; | |||||
int pitch_range_abs = abs(pitch_range); | |||||
drops = drops_0; // this should be controled by tune->head_drops | drops = drops_0; // this should be controled by tune->head_drops | ||||
initial = 1; | |||||
int initial = 1; | |||||
stage = 0; | stage = 0; | ||||
if (tune->onset == 255) | if (tune->onset == 255) | ||||
int initial; | int initial; | ||||
int overflow = 0; | int overflow = 0; | ||||
int n_overflow; | int n_overflow; | ||||
int pitch_range; | |||||
int pitch_range_abs; | |||||
int *drops; | int *drops; | ||||
signed char *overflow_tab; | signed char *overflow_tab; | ||||
SYLLABLE *syl; | SYLLABLE *syl; | ||||
static signed char continue_tab[5] = { -26, 32, 20, 8, 0 }; | static signed char continue_tab[5] = { -26, 32, 20, 8, 0 }; | ||||
drops = th->body_drops; | drops = th->body_drops; | ||||
pitch_range = (th->body_end - th->body_start) << 8; | |||||
pitch_range_abs = abs(pitch_range); | |||||
int pitch_range = (th->body_end - th->body_start) << 8; | |||||
int pitch_range_abs = abs(pitch_range); | |||||
if (continuing) { | if (continuing) { | ||||
initial = 0; | initial = 0; | ||||
// Set a linear pitch change over a number of syllables. | // Set a linear pitch change over a number of syllables. | ||||
// Used for pre-head, unstressed syllables in the body, and the tail | // Used for pre-head, unstressed syllables in the body, and the tail | ||||
int ix; | |||||
int stress; | int stress; | ||||
int pitch; | |||||
int increment; | |||||
int n_increments; | |||||
int drop; | int drop; | ||||
SYLLABLE *syl; | SYLLABLE *syl; | ||||
increment = (end_pitch - start_pitch) << 8; | |||||
n_increments = end_ix - start_ix; | |||||
int increment = (end_pitch - start_pitch) << 8; | |||||
int n_increments = end_ix - start_ix; | |||||
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; | |||||
int pitch = start_pitch << 8; | |||||
for (ix = start_ix; ix < end_ix; ix++) { | |||||
for (int ix = start_ix; ix < end_ix; ix++) { | |||||
syl = &syllable_tab[ix]; | syl = &syllable_tab[ix]; | ||||
stress = syl->stress; | stress = syl->stress; | ||||
// Calculate pitch values for the vowels in this tone group | // Calculate pitch values for the vowels in this tone group | ||||
static int calc_pitches2(int start, int end, int tune_number) | static int calc_pitches2(int start, int end, int tune_number) | ||||
{ | { | ||||
int ix; | |||||
TUNE *tune; | TUNE *tune; | ||||
int drop; | |||||
tune = &tunes[tune_number]; | tune = &tunes[tune_number]; | ||||
ix = start; | |||||
int ix = start; | |||||
// vowels before the first primary stress | // vowels before the first primary stress | ||||
// tonic syllable | // tonic syllable | ||||
int drop; | |||||
if (number_tail == 0) { | if (number_tail == 0) { | ||||
tone_pitch_env = tune->nucleus0_env; | tone_pitch_env = tune->nucleus0_env; | ||||
drop = tune->nucleus0_max - tune->nucleus0_min; | drop = tune->nucleus0_max - tune->nucleus0_min; | ||||
// Calculate pitch values for the vowels in this tone group | // Calculate pitch values for the vowels in this tone group | ||||
static int calc_pitches(int control, int start, int end, int tune_number) | static int calc_pitches(int control, int start, int end, int tune_number) | ||||
{ | { | ||||
int ix; | |||||
TONE_HEAD *th; | TONE_HEAD *th; | ||||
TONE_NUCLEUS *tn; | TONE_NUCLEUS *tn; | ||||
int drop; | |||||
int continuing = 0; | int continuing = 0; | ||||
if (control == 0) | if (control == 0) | ||||
th = &tone_head_table[tune_number]; | th = &tone_head_table[tune_number]; | ||||
tn = &tone_nucleus_table[tune_number]; | tn = &tone_nucleus_table[tune_number]; | ||||
ix = start; | |||||
int ix = start; | |||||
// vowels before the first primary stress | // vowels before the first primary stress | ||||
if (tn->flags & T_EMPH) | if (tn->flags & T_EMPH) | ||||
syllable_tab[ix].flags |= SYL_EMPHASIS; | syllable_tab[ix].flags |= SYL_EMPHASIS; | ||||
int drop; | |||||
if (number_tail == 0) { | if (number_tail == 0) { | ||||
tone_pitch_env = tn->pitch_env0; | tone_pitch_env = tn->pitch_env0; | ||||
drop = tn->tonic_max0 - tn->tonic_min0; | drop = tn->tonic_max0 - tn->tonic_min0; | ||||
// clause_tone: 0=. 1=, 2=?, 3=! 4=none | // clause_tone: 0=. 1=, 2=?, 3=! 4=none | ||||
PHONEME_LIST *p; | PHONEME_LIST *p; | ||||
int ix; | |||||
int count_stressed = 0; | int count_stressed = 0; | ||||
int final_stressed = 0; | int final_stressed = 0; | ||||
// count number of stressed syllables | // count number of stressed syllables | ||||
p = &phoneme_list[0]; | p = &phoneme_list[0]; | ||||
for (ix = 0; ix < n_phoneme_list; ix++, p++) { | |||||
for (int ix = 0; ix < n_phoneme_list; ix++, p++) { | |||||
if ((p->type == phVOWEL) && (p->stresslevel >= 4)) { | if ((p->type == phVOWEL) && (p->stresslevel >= 4)) { | ||||
if (count_stressed == 0) | if (count_stressed == 0) | ||||
final_stressed = ix; | final_stressed = ix; | ||||
prev_tph = prevw_tph = phoneme_tab[phonPAUSE]; | prev_tph = prevw_tph = phoneme_tab[phonPAUSE]; | ||||
// perform tone sandhi | // perform tone sandhi | ||||
for (ix = 0; ix < n_phoneme_list; ix++, p++) { | |||||
for (int ix = 0; ix < n_phoneme_list; ix++, p++) { | |||||
if ((p->type == phPAUSE) && (p->ph->std_length > 50)) { | if ((p->type == phPAUSE) && (p->ph->std_length > 50)) { | ||||
pause = 1; // there is a pause since the previous vowel | pause = 1; // there is a pause since the previous vowel | ||||
prevw_tph = phoneme_tab[phonPAUSE]; // forget previous tone | prevw_tph = phoneme_tab[phonPAUSE]; // forget previous tone | ||||
// convert tone numbers to pitch | // convert tone numbers to pitch | ||||
p = &phoneme_list[0]; | p = &phoneme_list[0]; | ||||
for (ix = 0; ix < n_phoneme_list; ix++, p++) { | |||||
for (int ix = 0; ix < n_phoneme_list; ix++, p++) { | |||||
if (p->synthflags & SFLAG_SYLLABLE) { | if (p->synthflags & SFLAG_SYLLABLE) { | ||||
tone_ph = p->tone_ph; | tone_ph = p->tone_ph; | ||||
int ix; | int ix; | ||||
int x; | int x; | ||||
int st_ix; | int st_ix; | ||||
int n_st; | |||||
int option; | int option; | ||||
int group_tone; | int group_tone; | ||||
int group_tone_comma; | int group_tone_comma; | ||||
int ph_start = 0; | int ph_start = 0; | ||||
int st_start; | |||||
int st_clause_end; | int st_clause_end; | ||||
int count; | int count; | ||||
int n_primary; | |||||
int count_primary; | |||||
PHONEME_TAB *ph; | PHONEME_TAB *ph; | ||||
int ph_end = n_phoneme_list; | int ph_end = n_phoneme_list; | ||||
SYLLABLE syllable_tab2[N_PHONEME_LIST]; | SYLLABLE syllable_tab2[N_PHONEME_LIST]; | ||||
syllable_tab = syllable_tab2; // don't use permanent storage. it's only needed during the call of CalcPitches() | syllable_tab = syllable_tab2; // don't use permanent storage. it's only needed during the call of CalcPitches() | ||||
n_st = 0; | |||||
n_primary = 0; | |||||
int n_st = 0; | |||||
int n_primary = 0; | |||||
for (ix = 0; ix < (n_phoneme_list-1); ix++) { | for (ix = 0; ix < (n_phoneme_list-1); ix++) { | ||||
p = &phoneme_list[ix]; | p = &phoneme_list[ix]; | ||||
if (p->synthflags & SFLAG_SYLLABLE) { | if (p->synthflags & SFLAG_SYLLABLE) { | ||||
else | else | ||||
no_tonic = 0; | no_tonic = 0; | ||||
st_start = 0; | |||||
count_primary = 0; | |||||
int st_start = 0; | |||||
int count_primary = 0; | |||||
for (st_ix = 0; st_ix < n_st; st_ix++) { | for (st_ix = 0; st_ix < n_st; st_ix++) { | ||||
syl = &syllable_tab[st_ix]; | syl = &syllable_tab[st_ix]; | ||||
static double resonator(resonator_ptr r, double input) | static double resonator(resonator_ptr r, double input) | ||||
{ | { | ||||
double x; | |||||
x = (double)((double)r->a * (double)input + (double)r->b * (double)r->p1 + (double)r->c * (double)r->p2); | |||||
double x = (double)((double)r->a * (double)input + (double)r->b * (double)r->p1 + (double)r->c * (double)r->p2); | |||||
r->p2 = (double)r->p1; | r->p2 = (double)r->p1; | ||||
r->p1 = (double)x; | r->p1 = (double)x; | ||||
static double resonator2(resonator_ptr r, double input) | static double resonator2(resonator_ptr r, double input) | ||||
{ | { | ||||
double x; | |||||
x = (double)((double)r->a * (double)input + (double)r->b * (double)r->p1 + (double)r->c * (double)r->p2); | |||||
double x = (double)((double)r->a * (double)input + (double)r->b * (double)r->p1 + (double)r->c * (double)r->p2); | |||||
r->p2 = (double)r->p1; | r->p2 = (double)r->p1; | ||||
r->p1 = (double)x; | r->p1 = (double)x; | ||||
static void flutter(klatt_frame_ptr frame) | static void flutter(klatt_frame_ptr frame) | ||||
{ | { | ||||
static int time_count; | static int time_count; | ||||
double delta_f0; | |||||
double fla, flb, flc, fld, fle; | |||||
fla = (double)kt_globals.f0_flutter / 50; | |||||
flb = (double)kt_globals.original_f0 / 100; | |||||
flc = sin(PI*12.7*time_count); // because we are calling flutter() more frequently, every 2.9mS | |||||
fld = sin(PI*7.1*time_count); | |||||
fle = sin(PI*4.7*time_count); | |||||
delta_f0 = fla * flb * (flc + fld + fle) * 10; | |||||
double fla = (double)kt_globals.f0_flutter / 50; | |||||
double flb = (double)kt_globals.original_f0 / 100; | |||||
double flc = sin(PI*12.7*time_count); // because we are calling flutter() more frequently, every 2.9mS | |||||
double fld = sin(PI*7.1*time_count); | |||||
double fle = sin(PI*4.7*time_count); | |||||
double delta_f0 = fla * flb * (flc + fld + fle) * 10; | |||||
frame->F0hz10 = frame->F0hz10 + (long)delta_f0; | frame->F0hz10 = frame->F0hz10 + (long)delta_f0; | ||||
time_count++; | time_count++; | ||||
} | } | ||||
static double sampled_source(int source_num) | static double sampled_source(int source_num) | ||||
{ | { | ||||
int itemp; | |||||
double ftemp; | |||||
double result; | double result; | ||||
double diff_value; | |||||
int current_value; | |||||
int next_value; | |||||
double temp_diff; | |||||
short *samples; | short *samples; | ||||
if (source_num == 0) { | if (source_num == 0) { | ||||
} | } | ||||
if (kt_globals.T0 != 0) { | if (kt_globals.T0 != 0) { | ||||
ftemp = (double)kt_globals.nper; | |||||
double ftemp = (double)kt_globals.nper; | |||||
ftemp = ftemp / kt_globals.T0; | ftemp = ftemp / kt_globals.T0; | ||||
ftemp = ftemp * kt_globals.num_samples; | ftemp = ftemp * kt_globals.num_samples; | ||||
itemp = (int)ftemp; | |||||
int itemp = (int)ftemp; | |||||
temp_diff = ftemp - (double)itemp; | |||||
double temp_diff = ftemp - (double)itemp; | |||||
current_value = samples[itemp]; | |||||
next_value = samples[itemp+1]; | |||||
int current_value = samples[itemp]; | |||||
int next_value = samples[itemp+1]; | |||||
diff_value = (double)next_value - (double)current_value; | |||||
double diff_value = (double)next_value - (double)current_value; | |||||
diff_value = diff_value * temp_diff; | diff_value = diff_value * temp_diff; | ||||
result = samples[itemp] + diff_value; | result = samples[itemp] + diff_value; | ||||
static double natural_source() | static double natural_source() | ||||
{ | { | ||||
double lgtemp; | |||||
static double vwave; | static double vwave; | ||||
if (kt_globals.nper < kt_globals.nopen) { | if (kt_globals.nper < kt_globals.nopen) { | ||||
kt_globals.pulse_shape_a -= kt_globals.pulse_shape_b; | kt_globals.pulse_shape_a -= kt_globals.pulse_shape_b; | ||||
vwave += kt_globals.pulse_shape_a; | vwave += kt_globals.pulse_shape_a; | ||||
lgtemp = vwave * 0.028; | |||||
double lgtemp = vwave * 0.028; | |||||
return lgtemp; | return lgtemp; | ||||
} | } | ||||
static void setabc(long int f, long int bw, resonator_ptr rp) | static void setabc(long int f, long int bw, resonator_ptr rp) | ||||
{ | { | ||||
double r; | |||||
double arg; | |||||
// Let r = exp(-pi bw t) | // Let r = exp(-pi bw t) | ||||
arg = kt_globals.minus_pi_t * bw; | |||||
r = exp(arg); | |||||
double arg = kt_globals.minus_pi_t * bw; | |||||
double r = exp(arg); | |||||
// Let c = -r**2 | // Let c = -r**2 | ||||
rp->c = -(r * r); | rp->c = -(r * r); | ||||
static void setzeroabc(long int f, long int bw, resonator_ptr rp) | static void setzeroabc(long int f, long int bw, resonator_ptr rp) | ||||
{ | { | ||||
double r; | |||||
double arg; | |||||
f = -f; | f = -f; | ||||
// First compute ordinary resonator coefficients | // First compute ordinary resonator coefficients | ||||
// Let r = exp(-pi bw t) | // Let r = exp(-pi bw t) | ||||
arg = kt_globals.minus_pi_t * bw; | |||||
r = exp(arg); | |||||
double arg = kt_globals.minus_pi_t * bw; | |||||
double r = exp(arg); | |||||
// Let c = -r**2 | // Let c = -r**2 | ||||
rp->c = -(r * r); | rp->c = -(r * r); | ||||
static double gen_noise(double noise) | static double gen_noise(double noise) | ||||
{ | { | ||||
long temp; | |||||
static double nlast; | static double nlast; | ||||
temp = (long)getrandom(-8191, 8191); | |||||
long temp = (long)getrandom(-8191, 8191); | |||||
kt_globals.nrand = (long)temp; | kt_globals.nrand = (long)temp; | ||||
noise = kt_globals.nrand + (0.75 * nlast); | noise = kt_globals.nrand + (0.75 * nlast); | ||||
void KlattInit() | void KlattInit() | ||||
{ | { | ||||
static short formant_hz[10] = { 280, 688, 1064, 2806, 3260, 3700, 6500, 7000, 8000, 280 }; | static short formant_hz[10] = { 280, 688, 1064, 2806, 3260, 3700, 6500, 7000, 8000, 280 }; | ||||
static short bandwidth[10] = { 89, 160, 70, 160, 200, 200, 500, 500, 500, 89 }; | static short bandwidth[10] = { 89, 160, 70, 160, 200, 200, 500, 500, 500, 89 }; | ||||
static short parallel_amp[10] = { 0, 59, 59, 59, 59, 59, 59, 0, 0, 0 }; | static short parallel_amp[10] = { 0, 59, 59, 59, 59, 59, 59, 0, 0, 0 }; | ||||
static short parallel_bw[10] = { 59, 59, 89, 149, 200, 200, 500, 0, 0, 0 }; | static short parallel_bw[10] = { 59, 59, 89, 149, 200, 200, 500, 0, 0, 0 }; | ||||
int ix; | |||||
sample_count = 0; | sample_count = 0; | ||||
kt_globals.synthesis_model = CASCADE_PARALLEL; | kt_globals.synthesis_model = CASCADE_PARALLEL; | ||||
KlattReset(2); | KlattReset(2); | ||||
// set default values for frame parameters | // set default values for frame parameters | ||||
for (ix = 0; ix <= 9; ix++) { | |||||
for (int ix = 0; ix <= 9; ix++) { | |||||
kt_frame.Fhz[ix] = formant_hz[ix]; | kt_frame.Fhz[ix] = formant_hz[ix]; | ||||
kt_frame.Bhz[ix] = bandwidth[ix]; | kt_frame.Bhz[ix] = bandwidth[ix]; | ||||
kt_frame.Ap[ix] = parallel_amp[ix]; | kt_frame.Ap[ix] = parallel_amp[ix]; |
static int start_mbrola(const char *voice_path) | static int start_mbrola(const char *voice_path) | ||||
{ | { | ||||
int error, p_stdin[2], p_stdout[2], p_stderr[2]; | |||||
int p_stdin[2], p_stdout[2], p_stderr[2]; | |||||
ssize_t written; | ssize_t written; | ||||
char charbuf[20]; | char charbuf[20]; | ||||
return -1; | return -1; | ||||
} | } | ||||
error = create_pipes(p_stdin, p_stdout, p_stderr); | |||||
int error = create_pipes(p_stdin, p_stdout, p_stderr); | |||||
if (error) | if (error) | ||||
return -1; | return -1; | ||||
} | } | ||||
if (mbr_pid == 0) { | if (mbr_pid == 0) { | ||||
int i; | |||||
if (dup2(p_stdin[0], 0) == -1 || | if (dup2(p_stdin[0], 0) == -1 || | ||||
dup2(p_stdout[1], 1) == -1 || | dup2(p_stdout[1], 1) == -1 || | ||||
dup2(p_stderr[1], 2) == -1) { | dup2(p_stderr[1], 2) == -1) { | ||||
(void)written; // suppress 'variable not used' warning | (void)written; // suppress 'variable not used' warning | ||||
_exit(1); | _exit(1); | ||||
} | } | ||||
for (i = p_stderr[1]; i > 2; i--) | |||||
for (int i = p_stderr[1]; i > 2; i--) | |||||
close(i); | close(i); | ||||
signal(SIGHUP, SIG_IGN); | signal(SIGHUP, SIG_IGN); | ||||
signal(SIGINT, SIG_IGN); | signal(SIGINT, SIG_IGN); | ||||
static int mbrola_died(void) | static int mbrola_died(void) | ||||
{ | { | ||||
pid_t pid; | pid_t pid; | ||||
int status, len; | |||||
int status; | |||||
const char *msg; | const char *msg; | ||||
char msgbuf[80]; | char msgbuf[80]; | ||||
log("mbrowrap error: %s", msg); | log("mbrowrap error: %s", msg); | ||||
len = strlen(mbr_errorbuf); | |||||
size_t len = strlen(mbr_errorbuf); | |||||
if (!len) | if (!len) | ||||
snprintf(mbr_errorbuf, sizeof(mbr_errorbuf), "%s", msg); | snprintf(mbr_errorbuf, sizeof(mbr_errorbuf), "%s", msg); | ||||
else | else | ||||
static int send_to_mbrola(const char *cmd) | static int send_to_mbrola(const char *cmd) | ||||
{ | { | ||||
ssize_t result; | ssize_t result; | ||||
int len; | |||||
if (!mbr_pid) | if (!mbr_pid) | ||||
return -1; | return -1; | ||||
len = strlen(cmd); | |||||
int len = strlen(cmd); | |||||
result = write(mbr_cmd_fd, cmd, len); | result = write(mbr_cmd_fd, cmd, len); | ||||
if (result == -1) { | if (result == -1) { | ||||
int init_MBR(const char *voice_path) | int init_MBR(const char *voice_path) | ||||
{ | { | ||||
int error, result; | |||||
unsigned char wavhdr[45]; | unsigned char wavhdr[45]; | ||||
error = start_mbrola(voice_path); | |||||
int error = start_mbrola(voice_path); | |||||
if (error) | if (error) | ||||
return -1; | return -1; | ||||
result = send_to_mbrola("#\n"); | |||||
int result = send_to_mbrola("#\n"); | |||||
if (result != 2) { | if (result != 2) { | ||||
stop_mbrola(); | stop_mbrola(); | ||||
return -1; | return -1; | ||||
int reset_MBR() | int reset_MBR() | ||||
{ | { | ||||
int result, success = 1; | |||||
int success = 1; | |||||
char dummybuf[4096]; | char dummybuf[4096]; | ||||
if (mbr_state == MBR_IDLE) | if (mbr_state == MBR_IDLE) | ||||
if (kill(mbr_pid, SIGUSR1) == -1) | if (kill(mbr_pid, SIGUSR1) == -1) | ||||
success = 0; | success = 0; | ||||
free_pending_data(); | free_pending_data(); | ||||
result = write(mbr_cmd_fd, "\n#\n", 3); | |||||
int result = write(mbr_cmd_fd, "\n#\n", 3); | |||||
if (result != 3) | if (result != 3) | ||||
success = 0; | success = 0; | ||||
do { | do { | ||||
int lastErrorStr_MBR(char *buffer, int bufsize) | int lastErrorStr_MBR(char *buffer, int bufsize) | ||||
{ | { | ||||
int result; | |||||
if (mbr_pid) | if (mbr_pid) | ||||
mbrola_has_errors(); | mbrola_has_errors(); | ||||
result = snprintf(buffer, bufsize, "%s", mbr_errorbuf); | |||||
int result = snprintf(buffer, bufsize, "%s", mbr_errorbuf); | |||||
return result >= bufsize ? (bufsize - 1) : result; | return result >= bufsize ? (bufsize - 1) : result; | ||||
} | } | ||||
static int LookupLetter2(Translator *tr, unsigned int letter, char *ph_buf) | static int LookupLetter2(Translator *tr, unsigned int letter, char *ph_buf) | ||||
{ | { | ||||
int len; | |||||
char single_letter[10]; | char single_letter[10]; | ||||
single_letter[0] = 0; | single_letter[0] = 0; | ||||
single_letter[1] = '_'; | single_letter[1] = '_'; | ||||
len = utf8_out(letter, &single_letter[2]); | |||||
int len = utf8_out(letter, &single_letter[2]); | |||||
single_letter[len+2] = ' '; | single_letter[len+2] = ' '; | ||||
single_letter[len+3] = 0; | single_letter[len+3] = 0; | ||||
{ | { | ||||
// control, bit 0: not the first letter of a word | // control, bit 0: not the first letter of a word | ||||
int len; | |||||
static char single_letter[10] = { 0, 0 }; | static char single_letter[10] = { 0, 0 }; | ||||
unsigned int dict_flags[2]; | unsigned int dict_flags[2]; | ||||
char ph_buf3[40]; | char ph_buf3[40]; | ||||
ph_buf1[0] = 0; | ph_buf1[0] = 0; | ||||
len = utf8_out(letter, &single_letter[2]); | |||||
int len = utf8_out(letter, &single_letter[2]); | |||||
single_letter[len+2] = ' '; | single_letter[len+2] = ' '; | ||||
if (next_byte == -1) { | if (next_byte == -1) { | ||||
int IsSuperscript(int letter) | int IsSuperscript(int letter) | ||||
{ | { | ||||
// is this a subscript or superscript letter ? | // is this a subscript or superscript letter ? | ||||
int ix; | |||||
int c; | int c; | ||||
for (ix = 0; (c = derived_letters[ix]) != 0; ix += 2) { | |||||
for (int ix = 0; (c = derived_letters[ix]) != 0; ix += 2) { | |||||
if (c > letter) | if (c > letter) | ||||
break; | break; | ||||
if (c == letter) | if (c == letter) | ||||
// bit 1: say 'capital' | // bit 1: say 'capital' | ||||
// bit 2: say character code for unknown letters | // bit 2: say character code for unknown letters | ||||
int n_bytes; | |||||
int letter; | int letter; | ||||
int len; | int len; | ||||
int ix; | int ix; | ||||
char *pbuf; | char *pbuf; | ||||
const char *modifier; | const char *modifier; | ||||
ALPHABET *alphabet; | ALPHABET *alphabet; | ||||
int al_offset; | |||||
int al_flags; | |||||
int language; | int language; | ||||
int number; | int number; | ||||
int phontab_1; | |||||
int speak_letter_number; | int speak_letter_number; | ||||
char capital[30]; | char capital[30]; | ||||
char ph_buf[80]; | char ph_buf[80]; | ||||
ph_buf[0] = 0; | ph_buf[0] = 0; | ||||
ph_alphabet[0] = 0; | ph_alphabet[0] = 0; | ||||
capital[0] = 0; | capital[0] = 0; | ||||
phontab_1 = translator->phoneme_tab_ix; | |||||
int phontab_1 = translator->phoneme_tab_ix; | |||||
n_bytes = utf8_in(&letter, word); | |||||
int 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 | ||||
LookupLetter(tr, number, 0, ph_buf, control & 1); | LookupLetter(tr, number, 0, ph_buf, control & 1); | ||||
} | } | ||||
al_offset = 0; | |||||
al_flags = 0; | |||||
int al_offset = 0; | |||||
int al_flags = 0; | |||||
if ((alphabet = AlphabetFromChar(letter)) != NULL) { | if ((alphabet = AlphabetFromChar(letter)) != NULL) { | ||||
al_offset = alphabet->offset; | al_offset = alphabet->offset; | ||||
al_flags = alphabet->flags; | al_flags = alphabet->flags; | ||||
unsigned int c; | unsigned int c; | ||||
int n_stress = 0; | int n_stress = 0; | ||||
int prev = 0; | int prev = 0; | ||||
int count; | |||||
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++) { | ||||
} | } | ||||
buf[ix] = 0; | buf[ix] = 0; | ||||
count = 0; | |||||
int count = 0; | |||||
prev = 0; | prev = 0; | ||||
for (ix = 0; (c = buf[ix]) != 0; ix++) { | for (ix = 0; (c = buf[ix]) != 0; ix++) { | ||||
if ((c == phonSTRESS_P) && (n_chars > 1) && (prev != phonSWITCH)) { | if ((c == phonSTRESS_P) && (n_chars > 1) && (prev != phonSWITCH)) { | ||||
int c; | int c; | ||||
char *p; | char *p; | ||||
const char *p2; | const char *p2; | ||||
int acc; | |||||
int prev; | |||||
int value; | int value; | ||||
int subtract; | |||||
int repeat = 0; | int repeat = 0; | ||||
int n_digits = 0; | int n_digits = 0; | ||||
char *word_start; | char *word_start; | ||||
static const char *roman_numbers = "ixcmvld"; | static const char *roman_numbers = "ixcmvld"; | ||||
static int roman_values[] = { 1, 10, 100, 1000, 5, 50, 500 }; | static int roman_values[] = { 1, 10, 100, 1000, 5, 50, 500 }; | ||||
acc = 0; | |||||
prev = 0; | |||||
subtract = 0x7fff; | |||||
int acc = 0; | |||||
int prev = 0; | |||||
int subtract = 0x7fff; | |||||
ph_out[0] = 0; | ph_out[0] = 0; | ||||
flags[0] = 0; | flags[0] = 0; | ||||
flags[1] = 0; | flags[1] = 0; | ||||
// bit 8 followed by decimal fraction | // bit 8 followed by decimal fraction | ||||
// bit 9: use #f form for both tens and units (lang=ml) | // bit 9: use #f form for both tens and units (lang=ml) | ||||
int found; | |||||
int ix; | int ix; | ||||
int units; | |||||
int tens; | |||||
int is_ordinal; | |||||
int used_and = 0; | int used_and = 0; | ||||
int found_ordinal = 0; | int found_ordinal = 0; | ||||
int next_phtype; | int next_phtype; | ||||
char ph_digits[50]; | char ph_digits[50]; | ||||
char ph_and[12]; | char ph_and[12]; | ||||
units = value % 10; | |||||
tens = value / 10; | |||||
int units = value % 10; | |||||
int tens = value / 10; | |||||
found = 0; | |||||
int found = 0; | |||||
ph_ordinal[0] = 0; | ph_ordinal[0] = 0; | ||||
ph_tens[0] = 0; | ph_tens[0] = 0; | ||||
ph_digits[0] = 0; | ph_digits[0] = 0; | ||||
if (control & 0x20) | if (control & 0x20) | ||||
ord_type = 'q'; | ord_type = 'q'; | ||||
is_ordinal = control & 1; | |||||
int is_ordinal = control & 1; | |||||
if ((control & 2) && (n_digit_lookup == 2)) { | if ((control & 2) && (n_digit_lookup == 2)) { | ||||
// pronunciation of the final 2 digits has already been found | // pronunciation of the final 2 digits has already been found | ||||
// bit 8 followed by decimal fraction | // bit 8 followed by decimal fraction | ||||
int found; | int found; | ||||
int hundreds; | |||||
int tensunits; | |||||
int x; | int x; | ||||
int ix; | |||||
int exact; | |||||
int ordinal; | |||||
int tplex; | |||||
int say_zero_hundred = 0; | int say_zero_hundred = 0; | ||||
int say_one_hundred; | |||||
char string[12]; // for looking up entries in **_list | char string[12]; // for looking up entries in **_list | ||||
char buf1[100]; | char buf1[100]; | ||||
char buf2[100]; | char buf2[100]; | ||||
char ph_hundred_and[12]; | char ph_hundred_and[12]; | ||||
char ph_thousand_and[12]; | char ph_thousand_and[12]; | ||||
ordinal = control & 0x22; | |||||
hundreds = value / 100; | |||||
tensunits = value % 100; | |||||
int ordinal = control & 0x22; | |||||
int hundreds = value / 100; | |||||
int tensunits = value % 100; | |||||
buf1[0] = 0; | buf1[0] = 0; | ||||
ph_thousands[0] = 0; | ph_thousands[0] = 0; | ||||
} else if (hundreds >= 10) { | } else if (hundreds >= 10) { | ||||
ph_digits[0] = 0; | ph_digits[0] = 0; | ||||
exact = 0; | |||||
int exact = 0; | |||||
if ((value % 1000) == 0) | if ((value % 1000) == 0) | ||||
exact = 1; | exact = 1; | ||||
tplex = thousandplex+1; | |||||
int tplex = thousandplex+1; | |||||
if (tr->langopts.numbers2 & NUM2_MYRIADS) | if (tr->langopts.numbers2 & NUM2_MYRIADS) | ||||
tplex = 0; | tplex = 0; | ||||
if (found) | if (found) | ||||
ph_100[0] = 0; | ph_100[0] = 0; | ||||
else { | else { | ||||
say_one_hundred = 1; | |||||
int 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; | ||||
} | } | ||||
} else { | } else { | ||||
if (ph_ordinal2[0] != 0) { | if (ph_ordinal2[0] != 0) { | ||||
ix = strlen(buf1); | |||||
int ix = strlen(buf1); | |||||
if ((ix > 0) && (buf1[ix-1] == phonPAUSE_SHORT)) | if ((ix > 0) && (buf1[ix-1] == phonPAUSE_SHORT)) | ||||
buf1[ix-1] = 0; // remove pause before addding ordinal suffix | buf1[ix-1] = 0; // remove pause before addding ordinal suffix | ||||
strcpy(buf2, ph_ordinal2); | strcpy(buf2, ph_ordinal2); |
{ | { | ||||
// Copy the phonemes list and perform any substitutions that are required for the | // Copy the phonemes list and perform any substitutions that are required for the | ||||
// current voice | // current voice | ||||
int ix; | |||||
int k; | int k; | ||||
int replace_flags; | int replace_flags; | ||||
int n_plist_out = 0; | int n_plist_out = 0; | ||||
PHONEME_LIST2 *plist2; | PHONEME_LIST2 *plist2; | ||||
PHONEME_TAB *next = NULL; | PHONEME_TAB *next = NULL; | ||||
for (ix = 0; (ix < n_ph_list2) && (n_plist_out < N_PHONEME_LIST); ix++) { | |||||
for (int ix = 0; (ix < n_ph_list2) && (n_plist_out < N_PHONEME_LIST); ix++) { | |||||
plist2 = &ph_list2[ix]; | plist2 = &ph_list2[ix]; | ||||
// don't do any substitution if the language has been temporarily changed | // don't do any substitution if the language has been temporarily changed | ||||
PHONEME_TAB *next, *next2; | PHONEME_TAB *next, *next2; | ||||
int unstress_count = 0; | int unstress_count = 0; | ||||
int word_stress = 0; | int word_stress = 0; | ||||
int current_phoneme_tab; | |||||
int max_stress; | |||||
int voicing; | int voicing; | ||||
int regression; | int regression; | ||||
int end_sourceix; | |||||
int alternative; | int alternative; | ||||
int delete_count; | |||||
int word_start; | |||||
int inserted; | int inserted; | ||||
int deleted; | int deleted; | ||||
PHONEME_DATA phdata; | PHONEME_DATA phdata; | ||||
int n_ph_list3; | |||||
PHONEME_LIST *plist3; | PHONEME_LIST *plist3; | ||||
PHONEME_LIST *plist3_inserted = NULL; | PHONEME_LIST *plist3_inserted = NULL; | ||||
PHONEME_LIST ph_list3[N_PHONEME_LIST]; | PHONEME_LIST ph_list3[N_PHONEME_LIST]; | ||||
memset(&worddata, 0, sizeof(worddata)); | memset(&worddata, 0, sizeof(worddata)); | ||||
plist2 = ph_list2; | plist2 = ph_list2; | ||||
phlist = phoneme_list; | phlist = phoneme_list; | ||||
end_sourceix = plist2[n_ph_list2-1].sourceix; | |||||
int end_sourceix = plist2[n_ph_list2-1].sourceix; | |||||
// is the last word of the clause unstressed ? | // is the last word of the clause unstressed ? | ||||
max_stress = 0; | |||||
int max_stress = 0; | |||||
for (j = n_ph_list2-3; j >= 0; j--) { | for (j = n_ph_list2-3; j >= 0; j--) { | ||||
// start with the last phoneme (before the terminating pauses) and move backwards | // start with the last phoneme (before the terminating pauses) and move backwards | ||||
if ((plist2[j].stresslevel & 0x7f) > max_stress) | if ((plist2[j].stresslevel & 0x7f) > max_stress) | ||||
} | } | ||||
// look for switch of phoneme tables | // look for switch of phoneme tables | ||||
delete_count = 0; | |||||
current_phoneme_tab = tr->phoneme_tab_ix; | |||||
int delete_count = 0; | |||||
int 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; | ||||
} | } | ||||
} | } | ||||
n_ph_list3 = SubstitutePhonemes(tr, ph_list3) - 2; | |||||
int n_ph_list3 = SubstitutePhonemes(tr, ph_list3) - 2; | |||||
for (j = 0; (j < n_ph_list3) && (ix < N_PHONEME_LIST-3);) { | for (j = 0; (j < n_ph_list3) && (ix < N_PHONEME_LIST-3);) { | ||||
if (ph_list3[j].sourceix) { | if (ph_list3[j].sourceix) { | ||||
// transfer all the phonemes of the clause into phoneme_list | // transfer all the phonemes of the clause into phoneme_list | ||||
ph = phoneme_tab[phonPAUSE]; | ph = phoneme_tab[phonPAUSE]; | ||||
ph_list3[0].ph = ph; | ph_list3[0].ph = ph; | ||||
word_start = 1; | |||||
int word_start = 1; | |||||
for (j = 0; insert_ph || ((j < n_ph_list3) && (ix < N_PHONEME_LIST-3)); j++) { | for (j = 0; insert_ph || ((j < n_ph_list3) && (ix < N_PHONEME_LIST-3)); j++) { | ||||
plist3 = &ph_list3[j]; | plist3 = &ph_list3[j]; |
int towlower(int c) | int towlower(int c) | ||||
{ | { | ||||
int x; | int x; | ||||
int ix; | |||||
if (c < 0x80) | if (c < 0x80) | ||||
return tolower(c); | return tolower(c); | ||||
if (x == 0xfd) { | if (x == 0xfd) { | ||||
// special cases, lookup translation table | // special cases, lookup translation table | ||||
for (ix = 0; wchar_tolower[ix] != 0; ix += 2) { | |||||
for (int ix = 0; wchar_tolower[ix] != 0; ix += 2) { | |||||
if (wchar_tolower[ix] == c) | if (wchar_tolower[ix] == c) | ||||
return wchar_tolower[ix+1]; | return wchar_tolower[ix+1]; | ||||
} | } | ||||
int towupper(int c) | int towupper(int c) | ||||
{ | { | ||||
int ix; | |||||
// check whether a previous character code is the upper-case equivalent of this character | // check whether a previous character code is the upper-case equivalent of this character | ||||
if (towlower(c-32) == c) | if (towlower(c-32) == c) | ||||
return c-32; // yes, use it | return c-32; // yes, use it | ||||
if (towlower(c-1) == c) | if (towlower(c-1) == c) | ||||
return c-1; | return c-1; | ||||
for (ix = 0; wchar_toupper[ix] != 0; ix += 2) { | |||||
for (int ix = 0; wchar_toupper[ix] != 0; ix += 2) { | |||||
if (wchar_toupper[ix] == c) | if (wchar_toupper[ix] == c) | ||||
return wchar_toupper[ix+1]; | return wchar_toupper[ix+1]; | ||||
} | } | ||||
int towlower2(unsigned int c) | int towlower2(unsigned int c) | ||||
{ | { | ||||
int x; | int x; | ||||
int ix; | |||||
// 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 (x == 0xfd) { | if (x == 0xfd) { | ||||
// special cases, lookup translation table | // special cases, lookup translation table | ||||
for (ix = 0; wchar_tolower[ix] != 0; ix += 2) { | |||||
for (int ix = 0; wchar_tolower[ix] != 0; ix += 2) { | |||||
if (wchar_tolower[ix] == (int)c) | if (wchar_tolower[ix] == (int)c) | ||||
return wchar_tolower[ix+1]; | return wchar_tolower[ix+1]; | ||||
} | } | ||||
int towupper2(unsigned int c) | int towupper2(unsigned int c) | ||||
{ | { | ||||
int ix; | |||||
if (c > MAX_WALPHA) | if (c > MAX_WALPHA) | ||||
return towupper(c); | return towupper(c); | ||||
return c-32; // yes, use it | return c-32; // yes, use it | ||||
if (towlower2(c-1) == (int)c) | if (towlower2(c-1) == (int)c) | ||||
return c-1; | return c-1; | ||||
for (ix = 0; wchar_toupper[ix] != 0; ix += 2) { | |||||
for (int ix = 0; wchar_toupper[ix] != 0; ix += 2) { | |||||
if (wchar_toupper[ix] == (int)c) | if (wchar_toupper[ix] == (int)c) | ||||
return wchar_toupper[ix+1]; | return wchar_toupper[ix+1]; | ||||
} | } | ||||
static int GetC_get(void) | static int GetC_get(void) | ||||
{ | { | ||||
unsigned int c; | unsigned int c; | ||||
unsigned int c2; | |||||
if (f_input != NULL) { | if (f_input != NULL) { | ||||
c = fgetc(f_input); | c = fgetc(f_input); | ||||
if (feof(f_input)) c = ' '; | if (feof(f_input)) c = ' '; | ||||
if (option_multibyte == espeakCHARS_16BIT) { | if (option_multibyte == espeakCHARS_16BIT) { | ||||
c2 = fgetc(f_input); | |||||
unsigned int c2 = fgetc(f_input); | |||||
if (feof(f_input)) c2 = 0; | if (feof(f_input)) c2 = 0; | ||||
c = c + (c2 << 8); | c = c + (c2 << 8); | ||||
} | } | ||||
// Returns a unicode wide character | // Returns a unicode wide character | ||||
// Performs UTF8 checking and conversion | // Performs UTF8 checking and conversion | ||||
int c; | |||||
int c1; | int c1; | ||||
int c2; | int c2; | ||||
int cbuf[4]; | int cbuf[4]; | ||||
int ix; | int ix; | ||||
int n_bytes; | |||||
static int ungot2 = 0; | static int ungot2 = 0; | ||||
static const unsigned char mask[4] = { 0xff, 0x1f, 0x0f, 0x07 }; | static const unsigned char mask[4] = { 0xff, 0x1f, 0x0f, 0x07 }; | ||||
if ((option_multibyte < 2) && (c1 & 0x80)) { | if ((option_multibyte < 2) && (c1 & 0x80)) { | ||||
// multi-byte utf8 encoding, convert to unicode | // multi-byte utf8 encoding, convert to unicode | ||||
n_bytes = 0; | |||||
int n_bytes = 0; | |||||
if (((c1 & 0xe0) == 0xc0) && ((c1 & 0x1e) != 0)) | if (((c1 & 0xe0) == 0xc0) && ((c1 & 0x1e) != 0)) | ||||
n_bytes = 1; | n_bytes = 1; | ||||
n_bytes = 3; | n_bytes = 3; | ||||
if ((ix = n_bytes) > 0) { | if ((ix = n_bytes) > 0) { | ||||
c = c1 & mask[ix]; | |||||
int c = c1 & mask[ix]; | |||||
while (ix > 0) { | while (ix > 0) { | ||||
if ((c2 = cbuf[ix] = GetC_get()) == 0) { | if ((c2 = cbuf[ix] = GetC_get()) == 0) { | ||||
if (option_multibyte == espeakCHARS_AUTO) | if (option_multibyte == espeakCHARS_AUTO) | ||||
const char *WordToString2(unsigned int word) | const char *WordToString2(unsigned int word) | ||||
{ | { | ||||
// Convert a language mnemonic word into a string | // Convert a language mnemonic word into a string | ||||
int ix; | |||||
static char buf[5]; | static char buf[5]; | ||||
char *p; | char *p; | ||||
p = buf; | p = buf; | ||||
for (ix = 3; ix >= 0; ix--) { | |||||
for (int ix = 3; ix >= 0; ix--) { | |||||
if ((*p = word >> (ix*8)) != 0) | if ((*p = word >> (ix*8)) != 0) | ||||
p++; | p++; | ||||
} | } | ||||
// Find the phoneme string (in ascii) to speak the name of character c | // Find the phoneme string (in ascii) to speak the name of character c | ||||
// Used for punctuation characters and symbols | // Used for punctuation characters and symbols | ||||
int ix; | |||||
unsigned int flags[2]; | unsigned int flags[2]; | ||||
char single_letter[24]; | char single_letter[24]; | ||||
char phonemes[60]; | char phonemes[60]; | ||||
flags[1] = 0; | flags[1] = 0; | ||||
single_letter[0] = 0; | single_letter[0] = 0; | ||||
single_letter[1] = '_'; | single_letter[1] = '_'; | ||||
ix = utf8_out(c, &single_letter[2]); | |||||
int ix = utf8_out(c, &single_letter[2]); | |||||
single_letter[2+ix] = 0; | single_letter[2+ix] = 0; | ||||
if (only) { | if (only) { | ||||
FILE *f; | FILE *f; | ||||
char *p; | char *p; | ||||
int *ip; | int *ip; | ||||
int length; | |||||
char fname_temp[100]; | char fname_temp[100]; | ||||
char fname2[sizeof(path_home)+13+40]; | char fname2[sizeof(path_home)+13+40]; | ||||
f = NULL; | f = NULL; | ||||
#ifdef PLATFORM_POSIX | #ifdef PLATFORM_POSIX | ||||
if ((f = fopen(fname, "rb")) != NULL) { | if ((f = fopen(fname, "rb")) != NULL) { | ||||
int ix; | |||||
int fd_temp; | int fd_temp; | ||||
int header[3]; | int header[3]; | ||||
char command[sizeof(fname2)+sizeof(fname2)+40]; | char command[sizeof(fname2)+sizeof(fname2)+40]; | ||||
fseek(f, 20, SEEK_SET); | fseek(f, 20, SEEK_SET); | ||||
for (ix = 0; ix < 3; ix++) | |||||
for (int ix = 0; ix < 3; ix++) | |||||
header[ix] = Read4Bytes(f); | header[ix] = Read4Bytes(f); | ||||
// if the sound file is not mono, 16 bit signed, at the correct sample rate, then convert it | // if the sound file is not mono, 16 bit signed, at the correct sample rate, then convert it | ||||
} | } | ||||
} | } | ||||
length = GetFileLength(fname); | |||||
int length = GetFileLength(fname); | |||||
fseek(f, 0, SEEK_SET); | fseek(f, 0, SEEK_SET); | ||||
if ((p = (char *)realloc(soundicon_tab[index].data, length)) == NULL) { | if ((p = (char *)realloc(soundicon_tab[index].data, length)) == NULL) { | ||||
fclose(f); | fclose(f); | ||||
static int LookupSoundicon(int c) | static int LookupSoundicon(int c) | ||||
{ | { | ||||
// Find the sound icon number for a punctuation chatacter | // Find the sound icon number for a punctuation chatacter | ||||
int ix; | |||||
for (ix = N_SOUNDICON_SLOTS; ix < n_soundicon_tab; ix++) { | |||||
for (int ix = N_SOUNDICON_SLOTS; ix < n_soundicon_tab; ix++) { | |||||
if (soundicon_tab[ix].name == c) { | if (soundicon_tab[ix].name == c) { | ||||
if (soundicon_tab[ix].length == 0) { | if (soundicon_tab[ix].length == 0) { | ||||
if (LoadSoundFile(NULL, ix) != 0) | if (LoadSoundFile(NULL, ix) != 0) | ||||
// Load a sound file into one of the reserved slots in the sound icon table | // Load a sound file into one of the reserved slots in the sound icon table | ||||
// (if it'snot already loaded) | // (if it'snot already loaded) | ||||
int ix; | |||||
int ix; | |||||
static int slot = -1; | static int slot = -1; | ||||
for (ix = 0; ix < n_soundicon_tab; ix++) { | for (ix = 0; ix < n_soundicon_tab; ix++) { | ||||
int soundicon; | int soundicon; | ||||
int attributes; | int attributes; | ||||
int short_pause; | int short_pause; | ||||
int c2; | |||||
int len; | |||||
int bufix1; | |||||
char buf[200]; | char buf[200]; | ||||
char buf2[80]; | char buf2[80]; | ||||
char ph_buf[30]; | char ph_buf[30]; | ||||
c2 = *c2_ptr; | |||||
int c2 = *c2_ptr; | |||||
buf[0] = 0; | buf[0] = 0; | ||||
if ((soundicon = LookupSoundicon(c1)) >= 0) { | if ((soundicon = LookupSoundicon(c1)) >= 0) { | ||||
} | } | ||||
} | } | ||||
bufix1 = *bufix; | |||||
len = strlen(buf); | |||||
int bufix1 = *bufix; | |||||
int len = strlen(buf); | |||||
strcpy(&output[*bufix], buf); | strcpy(&output[*bufix], buf); | ||||
*bufix += len; | *bufix += len; | ||||
// Use the voice properties from the SSML stack to choose a voice, and switch | // Use the voice properties from the SSML stack to choose a voice, and switch | ||||
// to that voice if it's not the current voice | // to that voice if it's not the current voice | ||||
int ix; | |||||
const char *p; | const char *p; | ||||
SSML_STACK *sp; | SSML_STACK *sp; | ||||
const char *v_id; | const char *v_id; | ||||
voice_select.variant = ssml_stack[0].voice_variant_number; | voice_select.variant = ssml_stack[0].voice_variant_number; | ||||
voice_select.identifier = NULL; | voice_select.identifier = NULL; | ||||
for (ix = 0; ix < n_ssml_stack; ix++) { | |||||
for (int ix = 0; ix < n_ssml_stack; ix++) { | |||||
sp = &ssml_stack[ix]; | sp = &ssml_stack[ix]; | ||||
voice_name_specified = 0; | voice_name_specified = 0; | ||||
{ | { | ||||
// Set the speech parameters from the parameter stack | // Set the speech parameters from the parameter stack | ||||
int param; | int param; | ||||
int ix; | |||||
int value; | int value; | ||||
char buf[20]; | char buf[20]; | ||||
int new_parameters[N_SPEECH_PARAM]; | int new_parameters[N_SPEECH_PARAM]; | ||||
for (param = 0; param < N_SPEECH_PARAM; param++) | for (param = 0; param < N_SPEECH_PARAM; param++) | ||||
new_parameters[param] = -1; | new_parameters[param] = -1; | ||||
for (ix = 0; ix < n_param_stack; ix++) { | |||||
for (int ix = 0; ix < n_param_stack; ix++) { | |||||
for (param = 0; param < N_SPEECH_PARAM; param++) { | for (param = 0; param < N_SPEECH_PARAM; param++) { | ||||
if (param_stack[ix].parameter[param] >= 0) | if (param_stack[ix].parameter[param] >= 0) | ||||
new_parameters[param] = param_stack[ix].parameter[param]; | new_parameters[param] = param_stack[ix].parameter[param]; | ||||
static PARAM_STACK *PushParamStack(int tag_type) | static PARAM_STACK *PushParamStack(int tag_type) | ||||
{ | { | ||||
int ix; | |||||
PARAM_STACK *sp; | PARAM_STACK *sp; | ||||
sp = ¶m_stack[n_param_stack]; | sp = ¶m_stack[n_param_stack]; | ||||
n_param_stack++; | n_param_stack++; | ||||
sp->type = tag_type; | sp->type = tag_type; | ||||
for (ix = 0; ix < N_SPEECH_PARAM; ix++) | |||||
for (int ix = 0; ix < N_SPEECH_PARAM; ix++) | |||||
sp->parameter[ix] = -1; | sp->parameter[ix] = -1; | ||||
return sp; | return sp; | ||||
} | } | ||||
static void PopParamStack(int tag_type, char *outbuf, int *outix) | static void PopParamStack(int tag_type, char *outbuf, int *outix) | ||||
{ | { | ||||
// unwind the stack up to and including the previous tag of this type | // unwind the stack up to and including the previous tag of this type | ||||
int ix; | |||||
int top = 0; | int top = 0; | ||||
if (tag_type >= SSML_CLOSE) | if (tag_type >= SSML_CLOSE) | ||||
tag_type -= SSML_CLOSE; | tag_type -= SSML_CLOSE; | ||||
for (ix = 0; ix < n_param_stack; ix++) { | |||||
for (int 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; | ||||
} | } | ||||
static int attrcmp(const wchar_t *string1, const char *string2) | static int attrcmp(const wchar_t *string1, const char *string2) | ||||
{ | { | ||||
int ix; | |||||
int ix; | |||||
if (string1 == NULL) | if (string1 == NULL) | ||||
return 1; | return 1; | ||||
{ | { | ||||
int sign = 0; | int sign = 0; | ||||
wchar_t *tail; | wchar_t *tail; | ||||
double value; | |||||
while (iswspace(*pw)) pw++; | while (iswspace(*pw)) pw++; | ||||
if (*pw == '+') { | if (*pw == '+') { | ||||
pw++; | pw++; | ||||
sign = -1; | sign = -1; | ||||
} | } | ||||
value = (double)wcstod(pw, &tail); | |||||
double value = (double)wcstod(pw, &tail); | |||||
if (tail == pw) { | if (tail == pw) { | ||||
// failed to find a number, return 100% | // failed to find a number, return 100% | ||||
*value_out = 100; | *value_out = 100; | ||||
#ifdef PLATFORM_RISCOS | #ifdef PLATFORM_RISCOS | ||||
*value_out = 100; | *value_out = 100; | ||||
#else | #else | ||||
double x; | |||||
// convert from semitones to a frequency percentage | // convert from semitones to a frequency percentage | ||||
x = pow((double)2.0, (double)((value*sign)/12)) * 100; | |||||
double x = pow((double)2.0, (double)((value*sign)/12)) * 100; | |||||
*value_out = (int)x; | *value_out = (int)x; | ||||
#endif | #endif | ||||
return 2; // percentage | return 2; // percentage | ||||
static void SetProsodyParameter(int param_type, wchar_t *attr1, PARAM_STACK *sp) | static void SetProsodyParameter(int param_type, wchar_t *attr1, PARAM_STACK *sp) | ||||
{ | { | ||||
int value; | int value; | ||||
int sign; | |||||
static const MNEM_TAB mnem_volume[] = { | static const MNEM_TAB mnem_volume[] = { | ||||
{ "default", 100 }, | { "default", 100 }, | ||||
// mnemonic specifies a value as a percentage of the base pitch/range/rate/volume | // mnemonic specifies a value as a percentage of the base pitch/range/rate/volume | ||||
sp->parameter[param_type] = (param_stack[0].parameter[param_type] * value)/100; | sp->parameter[param_type] = (param_stack[0].parameter[param_type] * value)/100; | ||||
} else { | } else { | ||||
sign = attr_prosody_value(param_type, attr1, &value); | |||||
int sign = attr_prosody_value(param_type, attr1, &value); | |||||
if (sign == 0) | if (sign == 0) | ||||
sp->parameter[param_type] = value; // absolute value in Hz | sp->parameter[param_type] = value; // absolute value in Hz | ||||
{ NULL, 0 } | { NULL, 0 } | ||||
}; | }; | ||||
int ix; | |||||
int letter; | int letter; | ||||
char *p; | char *p; | ||||
p = &outbuf[index]; | p = &outbuf[index]; | ||||
if ((letter = LookupMnem(keynames, p)) != 0) { | if ((letter = LookupMnem(keynames, p)) != 0) { | ||||
ix = utf8_out(letter, p); | |||||
int ix = utf8_out(letter, p); | |||||
*outix = index + ix; | *outix = index + ix; | ||||
return letter; | return letter; | ||||
} | } | ||||
void InitText2(void) | void InitText2(void) | ||||
{ | { | ||||
int param; | |||||
ungot_char = 0; | ungot_char = 0; | ||||
ungot_char2 = 0; | ungot_char2 = 0; | ||||
n_param_stack = 1; | n_param_stack = 1; | ||||
ssml_stack[0].tag_type = 0; | ssml_stack[0].tag_type = 0; | ||||
for (param = 0; param < N_SPEECH_PARAM; param++) | |||||
for (int param = 0; param < N_SPEECH_PARAM; param++) | |||||
speech_parameters[param] = param_stack[0].parameter[param]; // set all speech parameters to defaults | speech_parameters[param] = param_stack[0].parameter[param]; // set all speech parameters to defaults | ||||
option_punctuation = speech_parameters[espeakPUNCTUATION]; | option_punctuation = speech_parameters[espeakPUNCTUATION]; |
void SetSpeed(int control) | void SetSpeed(int control) | ||||
{ | { | ||||
int x; | int x; | ||||
int s1; | |||||
int wpm; | |||||
int wpm2; | int wpm2; | ||||
int wpm_value; | |||||
double sonic; | |||||
speed.loud_consonants = 0; | speed.loud_consonants = 0; | ||||
speed.min_sample_len = 450; | speed.min_sample_len = 450; | ||||
speed.lenmod2_factor = 100; | speed.lenmod2_factor = 100; | ||||
speed.min_pause = 5; | speed.min_pause = 5; | ||||
wpm = embedded_value[EMBED_S]; | |||||
int wpm = embedded_value[EMBED_S]; | |||||
if (control == 2) | if (control == 2) | ||||
wpm = embedded_value[EMBED_S2]; | wpm = embedded_value[EMBED_S2]; | ||||
wpm_value = wpm; | |||||
int 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; | ||||
speed3 = (x * voice->speedf3)/256; | speed3 = (x * voice->speedf3)/256; | ||||
} | } | ||||
if (control & 2) { | if (control & 2) { | ||||
sonic = ((double)wpm2)/wpm; | |||||
double sonic = ((double)wpm2)/wpm; | |||||
DoSonicSpeed((int)(sonic * 1024)); | DoSonicSpeed((int)(sonic * 1024)); | ||||
speed.pause_factor = 85; | speed.pause_factor = 85; | ||||
speed.clause_pause_factor = 80; | speed.clause_pause_factor = 80; | ||||
speed.lenmod2_factor = 110 - (wpm - 250)/2; | speed.lenmod2_factor = 110 - (wpm - 250)/2; | ||||
} | } | ||||
s1 = (x * voice->speedf1)/256; | |||||
int s1 = (x * voice->speedf1)/256; | |||||
if (wpm >= 170) | if (wpm >= 170) | ||||
speed.wav_factor = 110 + (150*s1)/128; // reduced speed adjustment, used for playing recorded sounds | speed.wav_factor = 110 + (150*s1)/128; // reduced speed adjustment, used for playing recorded sounds | ||||
void SetSpeed(int control) | void SetSpeed(int control) | ||||
{ | { | ||||
// This is the earlier version of SetSpeed() before sonic speed-up was added | // This is the earlier version of SetSpeed() before sonic speed-up was added | ||||
int x; | |||||
int s1; | |||||
int wpm; | |||||
int wpm2; | |||||
speed.loud_consonants = 0; | speed.loud_consonants = 0; | ||||
speed.min_sample_len = 450; | speed.min_sample_len = 450; | ||||
speed.lenmod_factor = 110; // controls the effect of FRFLAG_LEN_MOD reduce length change | speed.lenmod_factor = 110; // controls the effect of FRFLAG_LEN_MOD reduce length change | ||||
speed.lenmod2_factor = 100; | speed.lenmod2_factor = 100; | ||||
wpm = embedded_value[EMBED_S]; | |||||
int wpm = embedded_value[EMBED_S]; | |||||
if (control == 2) | if (control == 2) | ||||
wpm = embedded_value[EMBED_S2]; | wpm = embedded_value[EMBED_S2]; | ||||
if (wpm > 360) | if (wpm > 360) | ||||
speed.loud_consonants = (wpm - 360) / 8; | speed.loud_consonants = (wpm - 360) / 8; | ||||
wpm2 = wpm; | |||||
int wpm2 = wpm; | |||||
if (wpm > 359) wpm2 = 359; | if (wpm > 359) wpm2 = 359; | ||||
if (wpm < 80) wpm2 = 80; | if (wpm < 80) wpm2 = 80; | ||||
x = speed_lookup[wpm2-80]; | |||||
int x = speed_lookup[wpm2-80]; | |||||
if (wpm >= 380) | if (wpm >= 380) | ||||
x = 7; | x = 7; | ||||
speed.lenmod2_factor = 110 - (wpm - 250)/2; | speed.lenmod2_factor = 110 - (wpm - 250)/2; | ||||
} | } | ||||
s1 = (x * voice->speedf1)/256; | |||||
int s1 = (x * voice->speedf1)/256; | |||||
if (wpm >= 170) | if (wpm >= 170) | ||||
speed.wav_factor = 110 + (150*s1)/128; // reduced speed adjustment, used for playing recorded sounds | speed.wav_factor = 110 + (150*s1)/128; // reduced speed adjustment, used for playing recorded sounds | ||||
// relative 0=absolute 1=relative | // relative 0=absolute 1=relative | ||||
int new_value = value; | int new_value = value; | ||||
int default_value; | |||||
if (relative) { | if (relative) { | ||||
if (parameter < 5) { | if (parameter < 5) { | ||||
default_value = param_defaults[parameter]; | |||||
int default_value = param_defaults[parameter]; | |||||
new_value = default_value + (default_value * value)/100; | new_value = default_value + (default_value * value)/100; | ||||
} | } | ||||
} | } | ||||
void CalcLengths(Translator *tr) | void CalcLengths(Translator *tr) | ||||
{ | { | ||||
int ix; | |||||
int ix2; | int ix2; | ||||
PHONEME_LIST *prev; | PHONEME_LIST *prev; | ||||
PHONEME_LIST *next; | PHONEME_LIST *next; | ||||
unsigned char *pitch_env = NULL; | unsigned char *pitch_env = NULL; | ||||
PHONEME_DATA phdata_tone; | PHONEME_DATA phdata_tone; | ||||
for (ix = 1; ix < n_phoneme_list; ix++) { | |||||
for (int ix = 1; ix < n_phoneme_list; ix++) { | |||||
prev = &phoneme_list[ix-1]; | prev = &phoneme_list[ix-1]; | ||||
p = &phoneme_list[ix]; | p = &phoneme_list[ix]; | ||||
stress = p->stresslevel & 0x7; | stress = p->stresslevel & 0x7; |
{ | { | ||||
#ifdef PLATFORM_WINDOWS | #ifdef PLATFORM_WINDOWS | ||||
HKEY RegKey; | HKEY RegKey; | ||||
unsigned long size; | |||||
unsigned long var_type; | |||||
char *env; | char *env; | ||||
unsigned char buf[sizeof(path_home)-13]; | unsigned char buf[sizeof(path_home)-13]; | ||||
buf[0] = 0; | buf[0] = 0; | ||||
RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Speech\\Voices\\Tokens\\eSpeak", 0, KEY_READ, &RegKey); | RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Speech\\Voices\\Tokens\\eSpeak", 0, KEY_READ, &RegKey); | ||||
size = sizeof(buf); | |||||
var_type = REG_SZ; | |||||
unsigned long size = sizeof(buf); | |||||
unsigned long var_type = REG_SZ; | |||||
RegQueryValueExA(RegKey, "path", 0, &var_type, buf, &size); | RegQueryValueExA(RegKey, "path", 0, &var_type, buf, &size); | ||||
sprintf(path_home, "%s\\espeak-data", buf); | sprintf(path_home, "%s\\espeak-data", buf); | ||||
static int initialise(int control) | static int initialise(int control) | ||||
{ | { | ||||
int param; | |||||
int result; | int result; | ||||
int srate = 22050; // default sample rate 22050 Hz | int srate = 22050; // default sample rate 22050 Hz | ||||
SynthesizeInit(); | SynthesizeInit(); | ||||
InitNamedata(); | InitNamedata(); | ||||
for (param = 0; param < N_SPEECH_PARAM; param++) | |||||
for (int param = 0; param < N_SPEECH_PARAM; param++) | |||||
param_stack[0].parameter[param] = param_defaults[param]; | param_stack[0].parameter[param] = param_defaults[param]; | ||||
return 0; | return 0; | ||||
// type: 1=word, 2=sentence, 3=named mark, 4=play audio, 5=end, 7=phoneme | // type: 1=word, 2=sentence, 3=named mark, 4=play audio, 5=end, 7=phoneme | ||||
ENTER("MarkerEvent"); | ENTER("MarkerEvent"); | ||||
espeak_EVENT *ep; | espeak_EVENT *ep; | ||||
double time; | |||||
if ((event_list == NULL) || (event_list_ix >= (n_event_list-2))) | if ((event_list == NULL) || (event_list_ix >= (n_event_list-2))) | ||||
return; | return; | ||||
ep->text_position = char_position & 0xffffff; | ep->text_position = char_position & 0xffffff; | ||||
ep->length = char_position >> 24; | ep->length = char_position >> 24; | ||||
time = ((double)(count_samples + mbrola_delay + (out_ptr - out_start)/2)*1000.0)/samplerate; | |||||
double time = ((double)(count_samples + mbrola_delay + (out_ptr - out_start)/2)*1000.0)/samplerate; | |||||
ep->audio_position = (int)time; | ep->audio_position = (int)time; | ||||
ep->sample = (count_samples + mbrola_delay + (out_ptr - out_start)/2); | ep->sample = (count_samples + mbrola_delay + (out_ptr - out_start)/2); | ||||
{ | { | ||||
// symbolic name, symbolicname_character - is there a system resource of symbolic names per language? | // symbolic name, symbolicname_character - is there a system resource of symbolic names per language? | ||||
int letter; | int letter; | ||||
int ix; | |||||
ix = utf8_in(&letter, key); | |||||
int ix = utf8_in(&letter, key); | |||||
if (key[ix] == 0) { | if (key[ix] == 0) { | ||||
// a single character | // a single character | ||||
sync_espeak_Char(letter); | sync_espeak_Char(letter); | ||||
ESPEAK_API int espeak_Initialize(espeak_AUDIO_OUTPUT output_type, int buf_length, const char *path, int options) | ESPEAK_API int espeak_Initialize(espeak_AUDIO_OUTPUT output_type, int buf_length, const char *path, int options) | ||||
{ | { | ||||
ENTER("espeak_Initialize"); | ENTER("espeak_Initialize"); | ||||
int param; | |||||
// It seems that the wctype functions don't work until the locale has been set | // It seems that the wctype functions don't work until the locale has been set | ||||
// to something other than the default "C". Then, not only Latin1 but also the | // to something other than the default "C". Then, not only Latin1 but also the | ||||
VoiceReset(0); | VoiceReset(0); | ||||
for (param = 0; param < N_SPEECH_PARAM; param++) | |||||
for (int param = 0; param < N_SPEECH_PARAM; param++) | |||||
param_stack[0].parameter[param] = saved_parameters[param] = param_defaults[param]; | param_stack[0].parameter[param] = saved_parameters[param] = param_defaults[param]; | ||||
SetParameter(espeakRATE, 175, 0); | SetParameter(espeakRATE, 175, 0); |
{ | { | ||||
// General polinomial interpolation routine, xa[1...n] ya[1...n] | // General polinomial interpolation routine, xa[1...n] ya[1...n] | ||||
int i, m, ns = 1; | int i, m, ns = 1; | ||||
float den, dif, dift, ho, hp, w; | |||||
float den, dift, ho, hp, w; | |||||
float y; // result | float y; // result | ||||
float c[9], d[9]; | float c[9], d[9]; | ||||
dif = fabs(x-xa[1]); | |||||
float dif = fabs(x-xa[1]); | |||||
for (i = 1; i <= n; i++) { | for (i = 1; i <= n; i++) { | ||||
if ((dift = fabs(x-xa[i])) < dif) { | if ((dift = fabs(x-xa[i])) < dif) { | ||||
static SpectFrame *SpectFrameCreate() | static SpectFrame *SpectFrameCreate() | ||||
{ | { | ||||
int ix; | |||||
SpectFrame *frame; | SpectFrame *frame; | ||||
frame = malloc(sizeof(SpectFrame)); | frame = malloc(sizeof(SpectFrame)); | ||||
frame->amp_adjust = 100; | frame->amp_adjust = 100; | ||||
frame->length_adjust = 0; | frame->length_adjust = 0; | ||||
for (ix = 0; ix < N_PEAKS; ix++) { | |||||
for (int ix = 0; ix < N_PEAKS; ix++) { | |||||
frame->formants[ix].freq = 0; | frame->formants[ix].freq = 0; | ||||
frame->peaks[ix].pkfreq = default_freq[ix]; | frame->peaks[ix].pkfreq = default_freq[ix]; | ||||
frame->peaks[ix].pkheight = 0; | frame->peaks[ix].pkheight = 0; | ||||
{ | { | ||||
int h; | int h; | ||||
float total = 0; | float total = 0; | ||||
int maxh; | |||||
int height; | int height; | ||||
int htab[400]; | int htab[400]; | ||||
wavegen_peaks_t wpeaks[9]; | wavegen_peaks_t wpeaks[9]; | ||||
wpeaks[h].right = frame->peaks[h].pkright << 16; | wpeaks[h].right = frame->peaks[h].pkright << 16; | ||||
} | } | ||||
maxh = PeaksToHarmspect(wpeaks, 90<<16, htab, 0); | |||||
int 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; | ||||
void SpectSeqDestroy(SpectSeq *spect) | void SpectSeqDestroy(SpectSeq *spect) | ||||
{ | { | ||||
int ix; | |||||
if (spect->frames != NULL) { | if (spect->frames != NULL) { | ||||
for (ix = 0; ix < spect->numframes; ix++) { | |||||
for (int ix = 0; ix < spect->numframes; ix++) { | |||||
if (spect->frames[ix] != NULL) | if (spect->frames[ix] != NULL) | ||||
SpectFrameDestroy(spect->frames[ix]); | SpectFrameDestroy(spect->frames[ix]); | ||||
} | } |
{ | { | ||||
// Load a phoneme name translation table from espeak-data/mbrola | // Load a phoneme name translation table from espeak-data/mbrola | ||||
int size; | |||||
int ix; | |||||
int *pw; | int *pw; | ||||
FILE *f_in; | FILE *f_in; | ||||
char path[sizeof(path_home)+15]; | char path[sizeof(path_home)+15]; | ||||
// read eSpeak's mbrola phoneme translation data, eg. en1_phtrans | // read eSpeak's mbrola phoneme translation data, eg. en1_phtrans | ||||
sprintf(path, "%s/mbrola_ph/%s", path_home, phtrans); | sprintf(path, "%s/mbrola_ph/%s", path_home, phtrans); | ||||
size = GetFileLength(path); | |||||
int size = GetFileLength(path); | |||||
if ((f_in = fopen(path, "rb")) == NULL) { | if ((f_in = fopen(path, "rb")) == NULL) { | ||||
close_MBR(); | close_MBR(); | ||||
return EE_NOT_FOUND; | return EE_NOT_FOUND; | ||||
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 (int 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); | ||||
static char *WritePitch(int env, int pitch1, int pitch2, int split, int final) | static char *WritePitch(int env, int pitch1, int pitch2, int split, int final) | ||||
{ | { | ||||
// final=1: only give the final pitch value. | // final=1: only give the final pitch value. | ||||
int x; | |||||
int ix; | |||||
int pitch_base; | int pitch_base; | ||||
int pitch_range; | int pitch_range; | ||||
int p1, p2, p_end; | |||||
int p2; | |||||
unsigned char *pitch_env; | unsigned char *pitch_env; | ||||
int max = -1; | int max = -1; | ||||
int min = 999; | int min = 999; | ||||
int env100 = 80; // apply the pitch change only over this proportion of the mbrola phoneme(s) | int env100 = 80; // apply the pitch change only over this proportion of the mbrola phoneme(s) | ||||
int y2; | int y2; | ||||
int y[4]; | int y[4]; | ||||
int env_split; | |||||
char buf[50]; | char buf[50]; | ||||
static char output[50]; | static char output[50]; | ||||
SetPitch2(voice, pitch1, pitch2, &pitch_base, &pitch_range); | SetPitch2(voice, pitch1, pitch2, &pitch_base, &pitch_range); | ||||
env_split = (split * 128)/100; | |||||
int env_split = (split * 128)/100; | |||||
if (env_split < 0) | if (env_split < 0) | ||||
env_split = 0-env_split; | env_split = 0-env_split; | ||||
// find max and min in the pitch envelope | // find max and min in the pitch envelope | ||||
for (x = 0; x < 128; x++) { | |||||
for (int x = 0; x < 128; x++) { | |||||
if (pitch_env[x] > max) { | if (pitch_env[x] > max) { | ||||
max = pitch_env[x]; | max = pitch_env[x]; | ||||
y_max = x; | y_max = x; | ||||
y[3] = y[2] + (127 - y[2])/2; | y[3] = y[2] + (127 - y[2])/2; | ||||
// set initial pitch | // set initial pitch | ||||
p1 = ((pitch_env[0]*pitch_range)>>8) + pitch_base; // Hz << 12 | |||||
p_end = ((pitch_env[127]*pitch_range)>>8) + pitch_base; | |||||
int p1 = ((pitch_env[0]*pitch_range)>>8) + pitch_base; // Hz << 12 | |||||
int p_end = ((pitch_env[127]*pitch_range)>>8) + pitch_base; | |||||
if (split >= 0) { | if (split >= 0) { | ||||
sprintf(buf, " 0 %d", p1/4096); | sprintf(buf, " 0 %d", p1/4096); | ||||
// don't use intermediate pitch points for linear rise and fall | // don't use intermediate pitch points for linear rise and fall | ||||
if (env > 1) { | if (env > 1) { | ||||
for (ix = 1; ix < 4; ix++) { | |||||
for (int 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) | ||||
// Read audio data from Mbrola (length is in millisecs) | // Read audio data from Mbrola (length is in millisecs) | ||||
static int n_samples; | static int n_samples; | ||||
int req_samples, result; | |||||
int ix; | |||||
short value16; | short value16; | ||||
int value; | int value; | ||||
if (!resume) | if (!resume) | ||||
n_samples = samplerate * length / 1000; | n_samples = samplerate * length / 1000; | ||||
req_samples = (out_end - out_ptr)/2; | |||||
int req_samples = (out_end - out_ptr)/2; | |||||
if (req_samples > n_samples) | if (req_samples > n_samples) | ||||
req_samples = n_samples; | req_samples = n_samples; | ||||
result = read_MBR((short *)out_ptr, req_samples); | |||||
int result = read_MBR((short *)out_ptr, req_samples); | |||||
if (result <= 0) | if (result <= 0) | ||||
return 0; | return 0; | ||||
for (ix = 0; ix < result; ix++) { | |||||
for (int ix = 0; ix < result; ix++) { | |||||
value16 = out_ptr[0] + (out_ptr[1] << 8); | value16 = out_ptr[0] + (out_ptr[1] << 8); | ||||
value = value16 * amplitude; | value = value16 * amplitude; | ||||
value = value / 40; // adjust this constant to give a suitable amplitude for mbrola voices | value = value / 40; // adjust this constant to give a suitable amplitude for mbrola voices |
{ | { | ||||
FILE *f_in; | FILE *f_in; | ||||
char *p; | char *p; | ||||
unsigned int length; | |||||
char buf[sizeof(path_home)+40]; | char buf[sizeof(path_home)+40]; | ||||
sprintf(buf, "%s%c%s", path_home, PATHSEP, fname); | sprintf(buf, "%s%c%s", path_home, PATHSEP, fname); | ||||
length = GetFileLength(buf); | |||||
unsigned int length = GetFileLength(buf); | |||||
if ((f_in = fopen(buf, "rb")) == NULL) { | if ((f_in = fopen(buf, "rb")) == NULL) { | ||||
fprintf(stderr, "Can't read data file: '%s'\n", buf); | fprintf(stderr, "Can't read data file: '%s'\n", buf); | ||||
{ | { | ||||
int ix; | int ix; | ||||
int n_phonemes; | int n_phonemes; | ||||
int version; | |||||
int result = 1; | int result = 1; | ||||
int length; | int length; | ||||
int rate; | |||||
unsigned char *p; | unsigned char *p; | ||||
int *pw; | int *pw; | ||||
n_tunes = length / sizeof(TUNE); | n_tunes = length / sizeof(TUNE); | ||||
// read the version number and sample rate from the first 8 bytes of phondata | // read the version number and sample rate from the first 8 bytes of phondata | ||||
version = 0; // bytes 0-3, version number | |||||
rate = 0; // bytes 4-7, sample rate | |||||
int version = 0; // bytes 0-3, version number | |||||
int rate = 0; // bytes 4-7, sample rate | |||||
for (ix = 0; ix < 4; ix++) { | for (ix = 0; ix < 4; ix++) { | ||||
version += (wavefile_data[ix] << (ix*8)); | version += (wavefile_data[ix] << (ix*8)); | ||||
rate += (wavefile_data[ix+4] << (ix*8)); | rate += (wavefile_data[ix+4] << (ix*8)); | ||||
int PhonemeCode(unsigned int mnem) | int PhonemeCode(unsigned int mnem) | ||||
{ | { | ||||
int ix; | |||||
for (ix = 0; ix < n_phoneme_tab; ix++) { | |||||
for (int ix = 0; ix < n_phoneme_tab; ix++) { | |||||
if (phoneme_tab[ix] == NULL) | if (phoneme_tab[ix] == NULL) | ||||
continue; | continue; | ||||
if (phoneme_tab[ix]->mnemonic == mnem) | if (phoneme_tab[ix]->mnemonic == mnem) | ||||
int LookupPhonemeString(const char *string) | int LookupPhonemeString(const char *string) | ||||
{ | { | ||||
int ix; | |||||
unsigned char c; | unsigned char c; | ||||
unsigned int mnem; | |||||
// Pack up to 4 characters into a word | // Pack up to 4 characters into a word | ||||
mnem = 0; | |||||
for (ix = 0; ix < 4; ix++) { | |||||
unsigned int mnem = 0; | |||||
for (int ix = 0; ix < 4; ix++) { | |||||
if (string[ix] == 0) break; | if (string[ix] == 0) break; | ||||
c = string[ix]; | c = string[ix]; | ||||
mnem |= (c << (ix*8)); | mnem |= (c << (ix*8)); | ||||
frameref_t *LookupSpect(PHONEME_TAB *this_ph, int which, FMT_PARAMS *fmt_params, int *n_frames, PHONEME_LIST *plist) | frameref_t *LookupSpect(PHONEME_TAB *this_ph, int which, FMT_PARAMS *fmt_params, int *n_frames, PHONEME_LIST *plist) | ||||
{ | { | ||||
int ix; | int ix; | ||||
int nf; | |||||
int nf1; | int nf1; | ||||
int seq_break; | |||||
frameref_t *frames; | frameref_t *frames; | ||||
int length1; | int length1; | ||||
int length_std; | int length_std; | ||||
seq = (SPECT_SEQ *)(&phondata_ptr[fmt_params->fmt_addr]); | seq = (SPECT_SEQ *)(&phondata_ptr[fmt_params->fmt_addr]); | ||||
seqk = (SPECT_SEQK *)seq; | seqk = (SPECT_SEQK *)seq; | ||||
nf = seq->n_frames; | |||||
int nf = seq->n_frames; | |||||
if (nf >= N_SEQ_FRAMES) | if (nf >= N_SEQ_FRAMES) | ||||
nf = N_SEQ_FRAMES - 1; | nf = N_SEQ_FRAMES - 1; | ||||
seq_len_adjust = fmt_params->fmt2_lenadj + fmt_params->fmt_length; | seq_len_adjust = fmt_params->fmt2_lenadj + fmt_params->fmt_length; | ||||
seq_break = 0; | |||||
int seq_break = 0; | |||||
for (ix = 0; ix < nf; ix++) { | for (ix = 0; ix < nf; ix++) { | ||||
if (seq->frame[0].frflags & FRFLAG_KLATT) | if (seq->frame[0].frflags & FRFLAG_KLATT) | ||||
static void SetUpPhonemeTable(int number, int recursing) | static void SetUpPhonemeTable(int number, int recursing) | ||||
{ | { | ||||
int ix; | |||||
int includes; | int includes; | ||||
int ph_code; | int ph_code; | ||||
PHONEME_TAB *phtab; | PHONEME_TAB *phtab; | ||||
// now add the phonemes from this table | // now add the phonemes from this table | ||||
phtab = phoneme_tab_list[number].phoneme_tab_ptr; | phtab = phoneme_tab_list[number].phoneme_tab_ptr; | ||||
for (ix = 0; ix < phoneme_tab_list[number].n_phonemes; ix++) { | |||||
for (int ix = 0; ix < phoneme_tab_list[number].n_phonemes; ix++) { | |||||
ph_code = phtab[ix].code; | ph_code = phtab[ix].code; | ||||
phoneme_tab[ph_code] = &phtab[ix]; | phoneme_tab[ph_code] = &phtab[ix]; | ||||
if (ph_code > n_phoneme_tab) | if (ph_code > n_phoneme_tab) | ||||
// condition: | // condition: | ||||
// 0 if diminished, 1 if unstressed, 2 if not stressed, 3 if stressed, 4 if max stress | // 0 if diminished, 1 if unstressed, 2 if not stressed, 3 if stressed, 4 if max stress | ||||
int stress_level; | |||||
PHONEME_LIST *pl; | PHONEME_LIST *pl; | ||||
static int condition_level[4] = { 1, 2, 4, 15 }; | static int condition_level[4] = { 1, 2, 4, 15 }; | ||||
return false; // no stress elevel for this consonant | return false; // no stress elevel for this consonant | ||||
} | } | ||||
stress_level = pl->stresslevel & 0xf; | |||||
int stress_level = pl->stresslevel & 0xf; | |||||
if (tr != NULL) { | if (tr != NULL) { | ||||
if ((control & 1) && (plist->synthflags & SFLAG_DICTIONARY) && ((tr->langopts.param[LOPT_REDUCE] & 1) == 0)) { | if ((control & 1) && (plist->synthflags & SFLAG_DICTIONARY) && ((tr->langopts.param[LOPT_REDUCE] & 1) == 0)) { | ||||
{ | { | ||||
int which; | int which; | ||||
int ix; | int ix; | ||||
unsigned int data; | |||||
int instn; | |||||
int instn2; | |||||
int count; | int count; | ||||
int check_endtype = 0; | int check_endtype = 0; | ||||
PHONEME_TAB *ph; | PHONEME_TAB *ph; | ||||
// bits 8-10 = 7, other conditions | // bits 8-10 = 7, other conditions | ||||
instn = (*p_prog) & 0xfff; | |||||
data = instn & 0xff; | |||||
instn2 = instn >> 8; | |||||
int instn = (*p_prog) & 0xfff; | |||||
unsigned int data = instn & 0xff; | |||||
int instn2 = instn >> 8; | |||||
if (instn2 < 14) { | if (instn2 < 14) { | ||||
plist_this = plist; | plist_this = plist; | ||||
{ | { | ||||
USHORT *prog; | USHORT *prog; | ||||
int voweltype; | int voweltype; | ||||
signed char x; | |||||
if (instn_type == 2) { | if (instn_type == 2) { | ||||
phdata->pd_control |= pd_FORNEXTPH; | phdata->pd_control |= pd_FORNEXTPH; | ||||
if ((voweltype >= 0) && (voweltype < 6)) { | if ((voweltype >= 0) && (voweltype < 6)) { | ||||
prog = *p_prog + voweltype*2; | prog = *p_prog + voweltype*2; | ||||
phdata->sound_addr[instn_type] = (((prog[1] & 0xf) << 16) + prog[2]) * 4; | phdata->sound_addr[instn_type] = (((prog[1] & 0xf) << 16) + prog[2]) * 4; | ||||
x = (prog[1] >> 4) & 0xff; | |||||
signed char x = (prog[1] >> 4) & 0xff; | |||||
phdata->sound_param[instn_type] = x; // sign extend | phdata->sound_param[instn_type] = x; // sign extend | ||||
} | } | ||||
int NumInstnWords(USHORT *prog) | int NumInstnWords(USHORT *prog) | ||||
{ | { | ||||
int instn; | |||||
int instn2; | |||||
int instn_type; | |||||
int n; | int n; | ||||
int type2; | |||||
static const char n_words[16] = { 0, 1, 0, 0, 1, 1, 0, 1, 1, 2, 4, 0, 0, 0, 0, 0 }; | static const char n_words[16] = { 0, 1, 0, 0, 1, 1, 0, 1, 1, 2, 4, 0, 0, 0, 0, 0 }; | ||||
instn = *prog; | |||||
instn_type = instn >> 12; | |||||
int instn2; | |||||
int type2; | |||||
int instn = *prog; | |||||
int instn_type = instn >> 12; | |||||
if ((n = n_words[instn_type]) > 0) | if ((n = n_words[instn_type]) > 0) | ||||
return n; | return n; | ||||
bool truth; | bool truth; | ||||
bool truth2; | bool truth2; | ||||
int data; | int data; | ||||
int end_flag; | |||||
int ix; | int ix; | ||||
signed char param_sc; | signed char param_sc; | ||||
if (ph->program == 0) | if (ph->program == 0) | ||||
return; | return; | ||||
end_flag = 0; | |||||
int end_flag = 0; | |||||
for (prog = &phoneme_index[ph->program]; end_flag != 1; prog++) { | for (prog = &phoneme_index[ph->program]; end_flag != 1; prog++) { | ||||
instn = *prog; | instn = *prog; | ||||
void InterpretPhoneme2(int phcode, PHONEME_DATA *phdata) | void InterpretPhoneme2(int phcode, PHONEME_DATA *phdata) | ||||
{ | { | ||||
// Examine the program of a single isolated phoneme | // Examine the program of a single isolated phoneme | ||||
int ix; | |||||
PHONEME_LIST plist[4]; | PHONEME_LIST plist[4]; | ||||
memset(plist, 0, sizeof(plist)); | memset(plist, 0, sizeof(plist)); | ||||
for (ix = 0; ix < 4; ix++) { | |||||
for (int ix = 0; ix < 4; ix++) { | |||||
plist[ix].phcode = phonPAUSE; | plist[ix].phcode = phonPAUSE; | ||||
plist[ix].ph = phoneme_tab[phonPAUSE]; | plist[ix].ph = phoneme_tab[phonPAUSE]; | ||||
} | } |
const char *WordToString(unsigned int word) | const char *WordToString(unsigned int word) | ||||
{ | { | ||||
// Convert a phoneme mnemonic word into a string | // Convert a phoneme mnemonic word into a string | ||||
int ix; | |||||
static char buf[5]; | static char buf[5]; | ||||
for (ix = 0; ix < 4; ix++) | |||||
for (int ix = 0; ix < 4; ix++) | |||||
buf[ix] = word >> (ix*8); | buf[ix] = word >> (ix*8); | ||||
buf[4] = 0; | buf[4] = 0; | ||||
return buf; | return buf; | ||||
// control = 1, less shortening at fast speeds | // control = 1, less shortening at fast speeds | ||||
unsigned int len; | unsigned int len; | ||||
int srate2; | |||||
if (length == 0) | if (length == 0) | ||||
len = 0; | len = 0; | ||||
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 | |||||
int srate2 = samplerate / 25; // avoid overflow | |||||
len = (len * srate2) / 40; | len = (len * srate2) / 40; | ||||
} | } | ||||
} | } | ||||
static int DoSample2(int index, int which, int std_length, int control, int length_mod, int amp) | static int DoSample2(int index, int which, int std_length, int control, int length_mod, int amp) | ||||
{ | { | ||||
int length; | |||||
int wav_length; | |||||
int wav_scale; | |||||
int min_length; | |||||
int x; | int x; | ||||
int len4; | |||||
intptr_t *q; | intptr_t *q; | ||||
unsigned char *p; | unsigned char *p; | ||||
index = index & 0x7fffff; | index = index & 0x7fffff; | ||||
p = &wavefile_data[index]; | p = &wavefile_data[index]; | ||||
wav_scale = p[2]; | |||||
wav_length = (p[1] * 256); | |||||
int wav_scale = p[2]; | |||||
int wav_length = (p[1] * 256); | |||||
wav_length += p[0]; // length in bytes | wav_length += p[0]; // length in bytes | ||||
if (wav_length == 0) | if (wav_length == 0) | ||||
return 0; | return 0; | ||||
min_length = speed.min_sample_len; | |||||
int min_length = speed.min_sample_len; | |||||
if (wav_scale == 0) | if (wav_scale == 0) | ||||
min_length *= 2; // 16 bit samples | min_length *= 2; // 16 bit samples | ||||
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; | |||||
int length = (std_length * speed.wav_factor)/256; | |||||
if (control & pd_DONTLENGTHEN) { | if (control & pd_DONTLENGTHEN) { | ||||
// this option is used for Stops, with short noise bursts. | // this option is used for Stops, with short noise bursts. | ||||
if (amp < 0) | if (amp < 0) | ||||
return length; | return length; | ||||
len4 = wav_length / 4; | |||||
int len4 = wav_length / 4; | |||||
index += 4; | index += 4; | ||||
// Each frame includes its RMS amplitude value, so to set a new | // Each frame includes its RMS amplitude value, so to set a new | ||||
// RMS just adjust the formant amplitudes by the appropriate ratio | // RMS just adjust the formant amplitudes by the appropriate ratio | ||||
int x; | |||||
int h; | |||||
int ix; | |||||
static const short sqrt_tab[200] = { | static const short sqrt_tab[200] = { | ||||
0, 64, 90, 110, 128, 143, 156, 169, 181, 192, 202, 212, 221, 230, 239, 247, | 0, 64, 90, 110, 128, 143, 156, 169, 181, 192, 202, 212, 221, 230, 239, 247, | ||||
256, 263, 271, 278, 286, 293, 300, 306, 313, 320, 326, 332, 338, 344, 350, 356, | 256, 263, 271, 278, 286, 293, 300, 306, 313, 320, 326, 332, 338, 344, 350, 356, | ||||
} | } | ||||
if (fr->rms == 0) return; // check for divide by zero | if (fr->rms == 0) return; // check for divide by zero | ||||
x = (new_rms * 64)/fr->rms; | |||||
int x = (new_rms * 64)/fr->rms; | |||||
if (x >= 200) x = 199; | if (x >= 200) x = 199; | ||||
x = sqrt_tab[x]; // sqrt(new_rms/fr->rms)*0x200; | x = sqrt_tab[x]; // sqrt(new_rms/fr->rms)*0x200; | ||||
for (ix = 0; ix < 8; ix++) { | |||||
int h; | |||||
for (int ix = 0; ix < 8; ix++) { | |||||
h = fr->fheight[ix] * x; | h = fr->fheight[ix] * x; | ||||
fr->fheight[ix] = h/0x200; | fr->fheight[ix] = h/0x200; | ||||
} | } | ||||
static void formants_reduce_hf(frame_t *fr, int level) | static void formants_reduce_hf(frame_t *fr, int level) | ||||
{ | { | ||||
// change height of peaks 2 to 8, percentage | // change height of peaks 2 to 8, percentage | ||||
int ix; | |||||
int x; | |||||
if (voice->klattv[0]) | if (voice->klattv[0]) | ||||
return; | return; | ||||
for (ix = 2; ix < 8; ix++) { | |||||
int x; | |||||
for (int ix = 2; ix < 8; ix++) { | |||||
x = fr->fheight[ix] * level; | x = fr->fheight[ix] * level; | ||||
fr->fheight[ix] = x/100; | fr->fheight[ix] = x/100; | ||||
} | } | ||||
static void AdjustFormants(frame_t *fr, int target, int min, int max, int f1_adj, int f3_adj, int hf_reduce, int flags) | static void AdjustFormants(frame_t *fr, int target, int min, int max, int f1_adj, int f3_adj, int hf_reduce, int flags) | ||||
{ | { | ||||
int x; | |||||
target = (target * voice->formant_factor)/256; | target = (target * voice->formant_factor)/256; | ||||
x = (target - fr->ffreq[2]) / 2; | |||||
int x = (target - fr->ffreq[2]) / 2; | |||||
if (x > max) x = max; | if (x > max) x = max; | ||||
if (x < min) x = min; | if (x < min) x = min; | ||||
fr->ffreq[2] += x; | fr->ffreq[2] += x; | ||||
int FormantTransition2(frameref_t *seq, int *n_frames, unsigned int data1, unsigned int data2, PHONEME_TAB *other_ph, int which) | int FormantTransition2(frameref_t *seq, int *n_frames, unsigned int data1, unsigned int data2, PHONEME_TAB *other_ph, int which) | ||||
{ | { | ||||
int ix; | |||||
int formant; | |||||
int next_rms; | |||||
int len; | |||||
int rms; | |||||
int f1; | |||||
int f2; | |||||
int f2_min; | |||||
int f2_max; | |||||
int f3_adj; | |||||
int f3_amp; | |||||
int flags; | |||||
int vcolour; | |||||
#define N_VCOLOUR 2 | #define N_VCOLOUR 2 | ||||
// percentage change for each formant in 256ths | // percentage change for each formant in 256ths | ||||
static short vcolouring[N_VCOLOUR][5] = { | static short vcolouring[N_VCOLOUR][5] = { | ||||
if (*n_frames < 2) | if (*n_frames < 2) | ||||
return 0; | return 0; | ||||
len = (data1 & 0x3f) * 2; | |||||
rms = (data1 >> 6) & 0x3f; | |||||
flags = (data1 >> 12); | |||||
int len = (data1 & 0x3f) * 2; | |||||
int rms = (data1 >> 6) & 0x3f; | |||||
int flags = (data1 >> 12); | |||||
f2 = (data2 & 0x3f) * 50; | |||||
f2_min = (((data2 >> 6) & 0x1f) - 15) * 50; | |||||
f2_max = (((data2 >> 11) & 0x1f) - 15) * 50; | |||||
f3_adj = (((data2 >> 16) & 0x1f) - 15) * 50; | |||||
f3_amp = ((data2 >> 21) & 0x1f) * 8; | |||||
f1 = ((data2 >> 26) & 0x7); | |||||
vcolour = (data2 >> 29); | |||||
int f2 = (data2 & 0x3f) * 50; | |||||
int f2_min = (((data2 >> 6) & 0x1f) - 15) * 50; | |||||
int f2_max = (((data2 >> 11) & 0x1f) - 15) * 50; | |||||
int f3_adj = (((data2 >> 16) & 0x1f) - 15) * 50; | |||||
int f3_amp = ((data2 >> 21) & 0x1f) * 8; | |||||
int f1 = ((data2 >> 26) & 0x7); | |||||
int vcolour = (data2 >> 29); | |||||
if ((other_ph != NULL) && (other_ph->mnemonic == '?')) | if ((other_ph != NULL) && (other_ph->mnemonic == '?')) | ||||
flags |= 8; | flags |= 8; | ||||
seq[0].frflags |= FRFLAG_LEN_MOD2; // reduce length modification | seq[0].frflags |= FRFLAG_LEN_MOD2; // reduce length modification | ||||
fr->frflags |= FRFLAG_LEN_MOD2; | fr->frflags |= FRFLAG_LEN_MOD2; | ||||
next_rms = seq[1].frame->rms; | |||||
int 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; | ||||
set_frame_rms(fr, rms); | set_frame_rms(fr, rms); | ||||
if ((vcolour > 0) && (vcolour <= N_VCOLOUR)) { | if ((vcolour > 0) && (vcolour <= N_VCOLOUR)) { | ||||
for (ix = 0; ix < *n_frames; ix++) { | |||||
for (int ix = 0; ix < *n_frames; ix++) { | |||||
fr = CopyFrame(seq[ix].frame, 0); | fr = CopyFrame(seq[ix].frame, 0); | ||||
seq[ix].frame = fr; | seq[ix].frame = fr; | ||||
for (formant = 1; formant <= 5; formant++) { | |||||
for (int formant = 1; formant <= 5; formant++) { | |||||
int x; | int x; | ||||
x = fr->ffreq[formant] * vcolouring[vcolour-1][formant-1]; | x = fr->ffreq[formant] * vcolouring[vcolour-1][formant-1]; | ||||
fr->ffreq[formant] = x / 256; | fr->ffreq[formant] = x / 256; | ||||
frame_t *frame2; | frame_t *frame2; | ||||
frame_t *frame1; | frame_t *frame1; | ||||
frame_t *frame_centre; | frame_t *frame_centre; | ||||
int ix; | |||||
int len; | int len; | ||||
int pk; | int pk; | ||||
int modified; | int modified; | ||||
frame_centre = (frame_t *)q[2]; | frame_centre = (frame_t *)q[2]; | ||||
// backwards | // backwards | ||||
ix = syllable_centre -1; | |||||
int ix = syllable_centre -1; | |||||
frame = frame2 = frame_centre; | frame = frame2 = frame_centre; | ||||
for (;;) { | for (;;) { | ||||
if (ix < 0) ix = N_WCMDQ-1; | if (ix < 0) ix = N_WCMDQ-1; | ||||
int len; | int len; | ||||
int frame_length; | int frame_length; | ||||
int length_factor; | int length_factor; | ||||
int length_mod; | |||||
int length_sum; | |||||
int length_min; | |||||
int total_len = 0; | int total_len = 0; | ||||
static int wave_flag = 0; | static int wave_flag = 0; | ||||
int wcmd_spect = WCMD_SPECT; | int wcmd_spect = WCMD_SPECT; | ||||
if (fmt_params->fmt_addr == 0) | if (fmt_params->fmt_addr == 0) | ||||
return 0; | return 0; | ||||
length_mod = plist->length; | |||||
int length_mod = plist->length; | |||||
if (length_mod == 0) length_mod = 256; | if (length_mod == 0) length_mod = 256; | ||||
length_min = (samplerate/70); // greater than one cycle at low pitch (Hz) | |||||
int length_min = (samplerate/70); // greater than one cycle at low pitch (Hz) | |||||
if (which == 2) { | if (which == 2) { | ||||
if ((translator->langopts.param[LOPT_LONG_VOWEL_THRESHOLD] > 0) && ((this_ph->std_length >= translator->langopts.param[LOPT_LONG_VOWEL_THRESHOLD]) || (plist->synthflags & SFLAG_LENGTHEN) || (this_ph->phflags & phLONG))) | if ((translator->langopts.param[LOPT_LONG_VOWEL_THRESHOLD] > 0) && ((this_ph->std_length >= translator->langopts.param[LOPT_LONG_VOWEL_THRESHOLD]) || (plist->synthflags & SFLAG_LENGTHEN) || (this_ph->phflags & phLONG))) | ||||
length_min *= 2; // ensure long vowels are longer | length_min *= 2; // ensure long vowels are longer | ||||
syllable_centre = wcmdq_tail; | syllable_centre = wcmdq_tail; | ||||
} | } | ||||
length_sum = 0; | |||||
int length_sum = 0; | |||||
for (frameix = 1; frameix < n_frames; frameix++) { | for (frameix = 1; frameix < n_frames; frameix++) { | ||||
length_factor = length_mod; | length_factor = length_mod; | ||||
if (frames[frameix-1].frflags & FRFLAG_LEN_MOD) // reduce effect of length mod | if (frames[frameix-1].frflags & FRFLAG_LEN_MOD) // reduce effect of length mod |
static void ResetLetterBits(Translator *tr, int groups) | static void ResetLetterBits(Translator *tr, int groups) | ||||
{ | { | ||||
// Clear all the specified groups | // Clear all the specified groups | ||||
unsigned int ix; | |||||
unsigned int mask; | |||||
unsigned int mask = ~groups; | |||||
mask = ~groups; | |||||
for (ix = 0; ix < sizeof(tr->letter_bits); ix++) | |||||
for (int 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 bits; | |||||
unsigned char c; | unsigned char c; | ||||
bits = (1L << group); | |||||
int bits = (1L << group); | |||||
while ((c = *string++) != 0) | while ((c = *string++) != 0) | ||||
tr->letter_bits[c] |= bits; | tr->letter_bits[c] |= bits; | ||||
} | } | ||||
static void SetLetterBitsRange(Translator *tr, int group, int first, int last) | static void SetLetterBitsRange(Translator *tr, int group, int first, int last) | ||||
{ | { | ||||
int bits; | |||||
int ix; | |||||
bits = (1L << group); | |||||
for (ix = first; ix <= last; ix++) | |||||
int bits = (1L << group); | |||||
for (int ix = first; ix <= last; ix++) | |||||
tr->letter_bits[ix] |= bits; | tr->letter_bits[ix] |= bits; | ||||
} | } | ||||
static Translator *NewTranslator(void) | static Translator *NewTranslator(void) | ||||
{ | { | ||||
Translator *tr; | Translator *tr; | ||||
int ix; | |||||
static const unsigned char stress_amps2[] = { 18, 18, 20, 20, 20, 22, 22, 20 }; | static const unsigned char stress_amps2[] = { 18, 18, 20, 20, 20, 22, 22, 20 }; | ||||
static const short stress_lengths2[8] = { 182, 140, 220, 220, 220, 240, 260, 280 }; | static const short stress_lengths2[8] = { 182, 140, 220, 220, 220, 240, 260, 280 }; | ||||
static const wchar_t empty_wstring[1] = { 0 }; | static const wchar_t empty_wstring[1] = { 0 }; | ||||
tr->punct_within_word = punct_in_word; | tr->punct_within_word = punct_in_word; | ||||
tr->chars_ignore = chars_ignore_default; | tr->chars_ignore = chars_ignore_default; | ||||
for (ix = 0; ix < 8; ix++) { | |||||
for (int ix = 0; ix < 8; ix++) { | |||||
tr->stress_amps[ix] = stress_amps2[ix]; | tr->stress_amps[ix] = stress_amps2[ix]; | ||||
tr->stress_amps_r[ix] = stress_amps2[ix] - 1; | tr->stress_amps_r[ix] = stress_amps2[ix] - 1; | ||||
tr->stress_lengths[ix] = stress_lengths2[ix]; | tr->stress_lengths[ix] = stress_lengths2[ix]; |
int lookupwchar(const unsigned short *list, int c) | int lookupwchar(const unsigned short *list, int c) | ||||
{ | { | ||||
// Is the character c in the list ? | // Is the character c in the list ? | ||||
int ix; | |||||
for (ix = 0; list[ix] != 0; ix++) { | |||||
for (int ix = 0; list[ix] != 0; ix++) { | |||||
if (list[ix] == c) | if (list[ix] == c) | ||||
return ix+1; | return ix+1; | ||||
} | } | ||||
// Replace character c by another character. | // Replace character c by another character. | ||||
// Returns 0 = not found, 1 = delete character | // Returns 0 = not found, 1 = delete character | ||||
int ix; | |||||
for (ix = 0; list[ix] != 0; ix += 2) { | |||||
for (int ix = 0; list[ix] != 0; ix += 2) { | |||||
if (list[ix] == c) | if (list[ix] == c) | ||||
return list[ix+1]; | return list[ix+1]; | ||||
} | } | ||||
// returns the number of bytes written | // returns the number of bytes written | ||||
int n_bytes; | int n_bytes; | ||||
int j; | |||||
int shift; | |||||
static char unsigned code[4] = { 0, 0xc0, 0xe0, 0xf0 }; | static char unsigned code[4] = { 0, 0xc0, 0xe0, 0xf0 }; | ||||
if (c < 0x80) { | if (c < 0x80) { | ||||
else | else | ||||
n_bytes = 3; | n_bytes = 3; | ||||
shift = 6*n_bytes; | |||||
int shift = 6*n_bytes; | |||||
buf[0] = code[n_bytes] | (c >> shift); | buf[0] = code[n_bytes] | (c >> shift); | ||||
for (j = 0; j < n_bytes; j++) { | |||||
for (int j = 0; j < n_bytes; j++) { | |||||
shift -= 6; | shift -= 6; | ||||
buf[j+1] = 0x80 + ((c >> shift) & 0x3f); | buf[j+1] = 0x80 + ((c >> shift) & 0x3f); | ||||
} | } | ||||
// backwards: set if we are moving backwards through the UTF8 string | // backwards: set if we are moving backwards through the UTF8 string | ||||
int c1; | int c1; | ||||
int n_bytes; | |||||
int ix; | |||||
static const unsigned char mask[4] = { 0xff, 0x1f, 0x0f, 0x07 }; | static const unsigned char mask[4] = { 0xff, 0x1f, 0x0f, 0x07 }; | ||||
// find the start of the next/previous character | // find the start of the next/previous character | ||||
buf++; | buf++; | ||||
} | } | ||||
n_bytes = 0; | |||||
int n_bytes = 0; | |||||
if ((c1 = *buf++) & 0x80) { | if ((c1 = *buf++) & 0x80) { | ||||
if ((c1 & 0xe0) == 0xc0) | if ((c1 & 0xe0) == 0xc0) | ||||
n_bytes = 3; | n_bytes = 3; | ||||
c1 &= mask[n_bytes]; | c1 &= mask[n_bytes]; | ||||
for (ix = 0; ix < n_bytes; ix++) | |||||
for (int ix = 0; ix < n_bytes; ix++) | |||||
c1 = (c1 << 6) + (*buf++ & 0x3f); | c1 = (c1 << 6) + (*buf++ & 0x3f); | ||||
} | } | ||||
*c = c1; | *c = c1; | ||||
int count = 0; | int count = 0; | ||||
int nbytes; | int nbytes; | ||||
int ok; | int ok; | ||||
int ix; | |||||
char *word; | char *word; | ||||
char *wbuf; | char *wbuf; | ||||
char word_buf[80]; | char word_buf[80]; | ||||
word = word1; | word = word1; | ||||
wbuf = word_buf; | wbuf = word_buf; | ||||
ix = 0; | |||||
int ix = 0; | |||||
for (;;) { | for (;;) { | ||||
ok = 0; | ok = 0; | ||||
char *eqlist; | char *eqlist; | ||||
char *p_out; | char *p_out; | ||||
char *p_in; | char *p_in; | ||||
int remove_stress = 0; | |||||
char phonbuf[N_WORD_PHONEMES]; | char phonbuf[N_WORD_PHONEMES]; | ||||
// has a phoneme equivalence table been specified for this language pair? | // has a phoneme equivalence table been specified for this language pair? | ||||
len = (pb[2] << 8) + pb[3]; // size of this table in words | len = (pb[2] << 8) + pb[3]; // size of this table in words | ||||
pb += (len * 4); | pb += (len * 4); | ||||
} | } | ||||
remove_stress = pb[1]; | |||||
int remove_stress = pb[1]; | |||||
if (option_phonemes & espeakPHONEMES_TRACE) { | if (option_phonemes & espeakPHONEMES_TRACE) { | ||||
DecodePhonemes(phonemes, phonbuf); | DecodePhonemes(phonemes, phonbuf); | ||||
// word1 is terminated by space (0x20) character | // word1 is terminated by space (0x20) character | ||||
char *word1; | char *word1; | ||||
int word_length; | |||||
int ix; | int ix; | ||||
char *p; | char *p; | ||||
int pfix; | int pfix; | ||||
char end_phonemes2[N_WORD_PHONEMES]; | char end_phonemes2[N_WORD_PHONEMES]; | ||||
char word_copy[N_WORD_BYTES]; | char word_copy[N_WORD_BYTES]; | ||||
char word_copy2[N_WORD_BYTES]; | char word_copy2[N_WORD_BYTES]; | ||||
int word_copy_length; | |||||
char prefix_chars[0x3f + 2]; | char prefix_chars[0x3f + 2]; | ||||
int found = 0; | int found = 0; | ||||
int end_flags; | int end_flags; | ||||
int spell_word; | int spell_word; | ||||
int stress_bits; | int stress_bits; | ||||
int emphasize_allcaps = 0; | int emphasize_allcaps = 0; | ||||
int wflags; | |||||
int wmark; | |||||
int was_unpronouncable = 0; | int was_unpronouncable = 0; | ||||
int loopcount; | int loopcount; | ||||
int add_suffix_phonemes = 0; | int add_suffix_phonemes = 0; | ||||
memset(wtab_null, 0, sizeof(wtab_null)); | memset(wtab_null, 0, sizeof(wtab_null)); | ||||
wtab = wtab_null; | wtab = wtab_null; | ||||
} | } | ||||
wflags = wtab->flags; | |||||
wmark = wtab->wmark; | |||||
int wflags = wtab->flags; | |||||
int wmark = wtab->wmark; | |||||
dictionary_flags[0] = 0; | dictionary_flags[0] = 0; | ||||
dictionary_flags[1] = 0; | dictionary_flags[1] = 0; | ||||
wordx = word1; | wordx = word1; | ||||
utf8_in(&first_char, wordx); | utf8_in(&first_char, wordx); | ||||
word_length = 0; | |||||
int word_length = 0; | |||||
while ((*wordx != 0) && (*wordx != ' ')) { | while ((*wordx != 0) && (*wordx != ' ')) { | ||||
wordx += utf8_in(&last_char, wordx); | wordx += utf8_in(&last_char, wordx); | ||||
word_length++; | word_length++; | ||||
} | } | ||||
word_copy_length = wordx - word_start; | |||||
int word_copy_length = wordx - word_start; | |||||
if (word_copy_length >= N_WORD_BYTES) | if (word_copy_length >= N_WORD_BYTES) | ||||
word_copy_length = N_WORD_BYTES-1; | word_copy_length = N_WORD_BYTES-1; | ||||
memcpy(word_copy2, word_start, word_copy_length); | memcpy(word_copy2, word_start, word_copy_length); | ||||
// word's pronunciation is not given in the dictionary list, although | // word's pronunciation is not given in the dictionary list, although | ||||
// dictionary_flags may have ben set there | // dictionary_flags may have ben set there | ||||
int posn; | |||||
int non_initial; | |||||
int length; | |||||
posn = 0; | |||||
non_initial = 0; | |||||
length = 999; | |||||
int posn = 0; | |||||
int non_initial = 0; | |||||
int length = 999; | |||||
wordx = word1; | wordx = word1; | ||||
while (((length < 3) && (length > 0)) || (word_length > 1 && Unpronouncable(tr, wordx, posn))) { | while (((length < 3) && (length > 0)) || (word_length > 1 && Unpronouncable(tr, wordx, posn))) { | ||||
int UpperCaseInWord(Translator *tr, char *word, int c) | int UpperCaseInWord(Translator *tr, char *word, int c) | ||||
{ | { | ||||
int ix; | |||||
int len; | int len; | ||||
const char *p; | const char *p; | ||||
if (tr->translator_name == L('g', 'a')) { | if (tr->translator_name == L('g', 'a')) { | ||||
// Irish | // Irish | ||||
for (ix = 0;; ix++) { | |||||
for (int ix = 0;; ix++) { | |||||
if ((p = UCase_ga[ix]) == NULL) | if ((p = UCase_ga[ix]) == NULL) | ||||
break; | break; | ||||
void ReadTonePoints(char *string, int *tone_pts) | void ReadTonePoints(char *string, int *tone_pts) | ||||
{ | { | ||||
// tone_pts[] is int[12] | // tone_pts[] is int[12] | ||||
int ix; | |||||
for (ix = 0; ix < 12; ix++) | |||||
for (int ix = 0; ix < 12; ix++) | |||||
tone_pts[ix] = -1; | tone_pts[ix] = -1; | ||||
sscanf(string, "%d %d %d %d %d %d %d %d %d %d", | sscanf(string, "%d %d %d %d %d %d %d %d %d %d", | ||||
char *p; | char *p; | ||||
espeak_VOICE *voice_data; | espeak_VOICE *voice_data; | ||||
int priority; | int priority; | ||||
int age; | |||||
int n_variants = 4; // default, number of variants of this voice before using another voice | int n_variants = 4; // default, number of variants of this voice before using another voice | ||||
int gender; | |||||
#ifdef PLATFORM_WINDOWS | #ifdef PLATFORM_WINDOWS | ||||
char fname_buf[sizeof(path_home)+15]; | char fname_buf[sizeof(path_home)+15]; | ||||
vname[0] = 0; | vname[0] = 0; | ||||
vgender[0] = 0; | vgender[0] = 0; | ||||
age = 0; | |||||
int age = 0; | |||||
while (fgets_strip(linebuf, sizeof(linebuf), f_in) != NULL) { | while (fgets_strip(linebuf, sizeof(linebuf), f_in) != NULL) { | ||||
if (memcmp(linebuf, "name", 4) == 0) { | if (memcmp(linebuf, "name", 4) == 0) { | ||||
} | } | ||||
languages[langix++] = 0; | languages[langix++] = 0; | ||||
gender = LookupMnem(genders, vgender); | |||||
int 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 | ||||
{ | { | ||||
// Set voice to the default values | // Set voice to the default values | ||||
int pk; | |||||
static unsigned char default_heights[N_PEAKS] = { 130, 128, 120, 116, 100, 100, 128, 128, 128 }; // changed for v.1.47 | static unsigned char default_heights[N_PEAKS] = { 130, 128, 120, 116, 100, 100, 128, 128, 128 }; // changed for v.1.47 | ||||
static unsigned char default_widths[N_PEAKS] = { 140, 128, 128, 160, 171, 171, 128, 128, 128 }; | static unsigned char default_widths[N_PEAKS] = { 140, 128, 128, 160, 171, 171, 128, 128, 128 }; | ||||
#endif | #endif | ||||
InitBreath(); | InitBreath(); | ||||
for (pk = 0; pk < N_PEAKS; pk++) { | |||||
for (int pk = 0; pk < N_PEAKS; pk++) { | |||||
voice->freq[pk] = 256; | voice->freq[pk] = 256; | ||||
voice->height[pk] = default_heights[pk]*2; | voice->height[pk] = default_heights[pk]*2; | ||||
voice->width[pk] = default_widths[pk]*2; | voice->width[pk] = default_widths[pk]*2; | ||||
static void VoiceFormant(char *p) | static void VoiceFormant(char *p) | ||||
{ | { | ||||
// Set parameters for a formant | // Set parameters for a formant | ||||
int ix; | |||||
int formant; | int formant; | ||||
int freq = 100; | int freq = 100; | ||||
int height = 100; | int height = 100; | ||||
int width = 100; | int width = 100; | ||||
int freqadd = 0; | int freqadd = 0; | ||||
ix = sscanf(p, "%d %d %d %d %d", &formant, &freq, &height, &width, &freqadd); | |||||
int ix = sscanf(p, "%d %d %d %d %d", &formant, &freq, &height, &width, &freqadd); | |||||
if (ix < 2) | if (ix < 2) | ||||
return; | return; | ||||
static void PhonemeReplacement(int type, char *p) | static void PhonemeReplacement(int type, char *p) | ||||
{ | { | ||||
int n; | |||||
int phon; | int phon; | ||||
int flags = 0; | int flags = 0; | ||||
char phon_string1[12]; | char phon_string1[12]; | ||||
char phon_string2[12]; | char phon_string2[12]; | ||||
strcpy(phon_string2, "NULL"); | strcpy(phon_string2, "NULL"); | ||||
n = sscanf(p, "%d %s %s", &flags, phon_string1, phon_string2); | |||||
int n = sscanf(p, "%d %s %s", &flags, phon_string1, phon_string2); | |||||
if ((n < 2) || (n_replace_phonemes >= N_REPLACE_PHONEMES)) | if ((n < 2) || (n_replace_phonemes >= N_REPLACE_PHONEMES)) | ||||
return; | return; | ||||
static unsigned int StringToWord2(const char *string) | static unsigned int StringToWord2(const char *string) | ||||
{ | { | ||||
// Convert a language name string to a word such as L('e','n') | // Convert a language name string to a word such as L('e','n') | ||||
int ix; | |||||
int c; | int c; | ||||
unsigned int value = 0; | unsigned int value = 0; | ||||
for (ix = 0; (ix < 4) && ((c = string[ix]) != 0); ix++) | |||||
for (int ix = 0; (ix < 4) && ((c = string[ix]) != 0); ix++) | |||||
value = (value << 8) | (c & 0xff); | value = (value << 8) | (c & 0xff); | ||||
return value; | return value; | ||||
} | } | ||||
static int SetVoiceScores(espeak_VOICE *voice_select, espeak_VOICE **voices, int control) | static int SetVoiceScores(espeak_VOICE *voice_select, espeak_VOICE **voices, int control) | ||||
{ | { | ||||
// control: bit0=1 include mbrola voices | // control: bit0=1 include mbrola voices | ||||
int ix; | |||||
int score; | int score; | ||||
int nv; // number of candidates | int nv; // number of candidates | ||||
int n_parts = 0; | int n_parts = 0; | ||||
if ((voice_select->languages != NULL) && (voice_select->languages[0] != 0)) { | if ((voice_select->languages != NULL) && (voice_select->languages[0] != 0)) { | ||||
n_parts = 1; | n_parts = 1; | ||||
lang_len = strlen(voice_select->languages); | lang_len = strlen(voice_select->languages); | ||||
for (ix = 0; (ix <= lang_len) && ((unsigned)ix < sizeof(language)); ix++) { | |||||
for (int ix = 0; (ix <= lang_len) && ((unsigned)ix < sizeof(language)); ix++) { | |||||
if ((language[ix] = tolower(voice_select->languages[ix])) == '-') | if ((language[ix] = tolower(voice_select->languages[ix])) == '-') | ||||
n_parts++; | n_parts++; | ||||
} | } | ||||
// select those voices which match the specified language | // select those voices which match the specified language | ||||
nv = 0; | nv = 0; | ||||
for (ix = 0; ix < n_voices_list; ix++) { | |||||
for (int ix = 0; ix < n_voices_list; ix++) { | |||||
vp = voices_list[ix]; | vp = voices_list[ix]; | ||||
if (((control & 1) == 0) && (memcmp(vp->identifier, "mb/", 3) == 0)) | if (((control & 1) == 0) && (memcmp(vp->identifier, "mb/", 3) == 0)) | ||||
espeak_VOICE *SelectVoiceByName(espeak_VOICE **voices, const char *name2) | espeak_VOICE *SelectVoiceByName(espeak_VOICE **voices, const char *name2) | ||||
{ | { | ||||
int ix; | |||||
int match_fname = -1; | int match_fname = -1; | ||||
int match_fname2 = -1; | int match_fname2 = -1; | ||||
int match_name = -1; | int match_name = -1; | ||||
const char *id; // this is the filename within espeak-data/voices | const char *id; // this is the filename within espeak-data/voices | ||||
char *variant_name; | char *variant_name; | ||||
int last_part_len; | |||||
char last_part[41]; | char last_part[41]; | ||||
char name[40]; | char name[40]; | ||||
} | } | ||||
sprintf(last_part, "%c%s", PATHSEP, name); | sprintf(last_part, "%c%s", PATHSEP, name); | ||||
last_part_len = strlen(last_part); | |||||
int last_part_len = strlen(last_part); | |||||
for (ix = 0; voices[ix] != NULL; ix++) { | |||||
for (int ix = 0; voices[ix] != NULL; ix++) { | |||||
if (strcmp(name, voices[ix]->name) == 0) { | if (strcmp(name, voices[ix]->name) == 0) { | ||||
match_name = ix; // found matching voice name | match_name = ix; // found matching voice name | ||||
break; | break; | ||||
espeak_ERROR SetVoiceByName(const char *name) | espeak_ERROR SetVoiceByName(const char *name) | ||||
{ | { | ||||
espeak_VOICE *v; | espeak_VOICE *v; | ||||
int ix; | |||||
espeak_VOICE voice_selector; | espeak_VOICE voice_selector; | ||||
char *variant_name; | char *variant_name; | ||||
static char buf[60]; | static char buf[60]; | ||||
variant_name = ExtractVoiceVariantName(buf, 0, 1); | variant_name = ExtractVoiceVariantName(buf, 0, 1); | ||||
for (ix = 0;; ix++) { | |||||
for (int ix = 0;; ix++) { | |||||
// convert voice name to lower case (ascii) | // convert voice name to lower case (ascii) | ||||
if ((buf[ix] = tolower(buf[ix])) == 0) | if ((buf[ix] = tolower(buf[ix])) == 0) | ||||
break; | break; | ||||
void FreeVoiceList() | void FreeVoiceList() | ||||
{ | { | ||||
int ix; | |||||
for (ix = 0; ix < n_voices_list; ix++) { | |||||
for (int ix = 0; ix < n_voices_list; ix++) { | |||||
if (voices_list[ix] != NULL) { | if (voices_list[ix] != NULL) { | ||||
free(voices_list[ix]); | free(voices_list[ix]); | ||||
voices_list[ix] = NULL; | voices_list[ix] = NULL; | ||||
} | } | ||||
return (const espeak_VOICE **)voices_list; | return (const espeak_VOICE **)voices_list; | ||||
#else | #else | ||||
int ix; | |||||
int j; | |||||
espeak_VOICE *v; | espeak_VOICE *v; | ||||
static espeak_VOICE **voices = NULL; | static espeak_VOICE **voices = NULL; | ||||
SetVoiceScores(voice_spec, voices, 1); | SetVoiceScores(voice_spec, voices, 1); | ||||
} else { | } else { | ||||
// list all: omit variant voices and mbrola voices and test voices | // list all: omit variant voices and mbrola voices and test voices | ||||
j = 0; | |||||
for (ix = 0; (v = voices_list[ix]) != NULL; ix++) { | |||||
int j = 0; | |||||
for (int 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; |
char *theMono16BitsWaveBuffer, | char *theMono16BitsWaveBuffer, | ||||
size_t theSize) | size_t theSize) | ||||
{ | { | ||||
size_t num; | |||||
ENTER("wave_write"); | ENTER("wave_write"); | ||||
if (my_callback_is_output_enabled && (0 == my_callback_is_output_enabled())) { | if (my_callback_is_output_enabled && (0 == my_callback_is_output_enabled())) { | ||||
SHOW_TIME("wave_write > my_callback_is_output_enabled: no!"); | SHOW_TIME("wave_write > my_callback_is_output_enabled: no!"); | ||||
} | } | ||||
#endif | #endif | ||||
num = write((int)theHandler, theMono16BitsWaveBuffer, theSize); | |||||
size_t num = write((int)theHandler, theMono16BitsWaveBuffer, theSize); | |||||
// Keep track of the total number of samples sent -- we use this in | // Keep track of the total number of samples sent -- we use this in | ||||
// wave_get_read_position and also use it to help calculate the | // wave_get_read_position and also use it to help calculate the | ||||
// | // | ||||
int wave_close(void *theHandler) | int wave_close(void *theHandler) | ||||
{ | { | ||||
int ret; | |||||
audio_info_t ainfo; | audio_info_t ainfo; | ||||
int audio_fd = (int)theHandler; | int audio_fd = (int)theHandler; | ||||
if (!audio_fd) { | if (!audio_fd) { | ||||
} | } | ||||
ENTER("wave_close"); | ENTER("wave_close"); | ||||
// [[[WDW: maybe do a pause/resume ioctl???]]] | // [[[WDW: maybe do a pause/resume ioctl???]]] | ||||
ret = ioctl(audio_fd, I_FLUSH, FLUSHRW); | |||||
int ret = ioctl(audio_fd, I_FLUSH, FLUSHRW); | |||||
ioctl(audio_fd, AUDIO_GETINFO, &ainfo); | ioctl(audio_fd, AUDIO_GETINFO, &ainfo); | ||||
// Calculate the number of samples that won't get | // Calculate the number of samples that won't get |
int WcmdqFree() | int WcmdqFree() | ||||
{ | { | ||||
int i; | |||||
i = wcmdq_head - wcmdq_tail; | |||||
int i = wcmdq_head - wcmdq_tail; | |||||
if (i <= 0) i += N_WCMDQ; | if (i <= 0) i += N_WCMDQ; | ||||
return i; | return i; | ||||
} | } | ||||
PaStreamCallbackFlags flags, void *userData) | PaStreamCallbackFlags flags, void *userData) | ||||
#endif | #endif | ||||
{ | { | ||||
int ix; | |||||
int result; | |||||
unsigned char *p; | unsigned char *p; | ||||
unsigned char *out_buf; | unsigned char *out_buf; | ||||
unsigned char *out_end2; | unsigned char *out_end2; | ||||
int pa_size; | |||||
pa_size = framesPerBuffer*2; | |||||
int pa_size = framesPerBuffer*2; | |||||
// make a buffer 3x size of the portaudio output | // make a buffer 3x size of the portaudio output | ||||
ix = pa_size*3; | |||||
int ix = pa_size*3; | |||||
if (ix > outbuffer_size) { | if (ix > outbuffer_size) { | ||||
outbuffer = (unsigned char *)realloc(outbuffer, ix); | outbuffer = (unsigned char *)realloc(outbuffer, ix); | ||||
if (outbuffer == NULL) { | if (outbuffer == NULL) { | ||||
event_list_ix = 0; | event_list_ix = 0; | ||||
#endif | #endif | ||||
result = WavegenFill(1); | |||||
int result = WavegenFill(1); | |||||
// copy from the outbut buffer into the portaudio buffer | // copy from the outbut buffer into the portaudio buffer | ||||
if (result && (out_ptr > out_end2)) | if (result && (out_ptr > out_end2)) | ||||
void WavegenInit(int rate, int wavemult_fact) | void WavegenInit(int rate, int wavemult_fact) | ||||
{ | { | ||||
int ix; | |||||
double x; | double x; | ||||
if (wavemult_fact == 0) | if (wavemult_fact == 0) | ||||
wdata.amplitude = 32; | wdata.amplitude = 32; | ||||
wdata.amplitude_fmt = 100; | wdata.amplitude_fmt = 100; | ||||
for (ix = 0; ix < N_EMBEDDED_VALUES; ix++) | |||||
for (int ix = 0; ix < N_EMBEDDED_VALUES; ix++) | |||||
embedded_value[ix] = embedded_default[ix]; | embedded_value[ix] = embedded_default[ix]; | ||||
// set up window to generate a spread of harmonics from a | // set up window to generate a spread of harmonics from a | ||||
if (samplerate != 22050) { | if (samplerate != 22050) { | ||||
// wavemult table has preset values for 22050 Hz, we only need to | // wavemult table has preset values for 22050 Hz, we only need to | ||||
// recalculate them if we have a different sample rate | // recalculate them if we have a different sample rate | ||||
for (ix = 0; ix < wavemult_max; ix++) { | |||||
for (int ix = 0; ix < wavemult_max; ix++) { | |||||
x = 127*(1.0 - cos(PI2*ix/wavemult_max)); | x = 127*(1.0 - cos(PI2*ix/wavemult_max)); | ||||
wavemult[ix] = (int)x; | wavemult[ix] = (int)x; | ||||
} | } | ||||
int GetAmplitude(void) | int GetAmplitude(void) | ||||
{ | { | ||||
int amp; | |||||
// normal, none, reduced, moderate, strong | // normal, none, reduced, moderate, strong | ||||
static const unsigned char amp_emphasis[5] = { 16, 16, 10, 16, 22 }; | static const unsigned char amp_emphasis[5] = { 16, 16, 10, 16, 22 }; | ||||
amp = (embedded_value[EMBED_A])*55/100; | |||||
int amp = (embedded_value[EMBED_A])*55/100; | |||||
general_amplitude = amp * amp_emphasis[embedded_value[EMBED_F]] / 16; | general_amplitude = amp * amp_emphasis[embedded_value[EMBED_F]] / 16; | ||||
return general_amplitude; | return general_amplitude; | ||||
} | } | ||||
static void WavegenSetEcho(void) | static void WavegenSetEcho(void) | ||||
{ | { | ||||
int delay; | |||||
int amp; | |||||
voicing = wvoice->voicing; | voicing = wvoice->voicing; | ||||
delay = wvoice->echo_delay; | |||||
amp = wvoice->echo_amp; | |||||
int delay = wvoice->echo_delay; | |||||
int amp = wvoice->echo_amp; | |||||
if (delay >= N_ECHO_BUF) | if (delay >= N_ECHO_BUF) | ||||
delay = N_ECHO_BUF-1; | delay = N_ECHO_BUF-1; | ||||
int fp; // centre freq of peak | int fp; // centre freq of peak | ||||
int fhi; // high freq of peak | int fhi; // high freq of peak | ||||
int h; // harmonic number | int h; // harmonic number | ||||
int pk; | |||||
int hmax; | |||||
int pk; | |||||
int hmax_samplerate; // highest harmonic allowed for the samplerate | int hmax_samplerate; // highest harmonic allowed for the samplerate | ||||
int x; | int x; | ||||
int ix; | |||||
int h1; | |||||
int ix; | |||||
#ifdef SPECT_EDITOR | #ifdef SPECT_EDITOR | ||||
if (harm_sqrt_n > 0) | if (harm_sqrt_n > 0) | ||||
// initialise as much of *out as we will need | // initialise as much of *out as we will need | ||||
if (wvoice == NULL) | if (wvoice == NULL) | ||||
return 1; | return 1; | ||||
hmax = (peaks[wvoice->n_harmonic_peaks].freq + peaks[wvoice->n_harmonic_peaks].right)/pitch; | |||||
int hmax = (peaks[wvoice->n_harmonic_peaks].freq + peaks[wvoice->n_harmonic_peaks].right)/pitch; | |||||
if (hmax >= MAX_HARMONIC) | if (hmax >= MAX_HARMONIC) | ||||
hmax = MAX_HARMONIC-1; | hmax = MAX_HARMONIC-1; | ||||
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 | // increase bass | ||||
y = peaks[1].height * 10; // addition as a multiple of 1/256s | |||||
h2 = (1000<<16)/pitch; // decrease until 1000Hz | |||||
int y = peaks[1].height * 10; // addition as a multiple of 1/256s | |||||
int h2 = (1000<<16)/pitch; // decrease until 1000Hz | |||||
if (h2 > 0) { | if (h2 > 0) { | ||||
x = y/h2; | x = y/h2; | ||||
h = 1; | h = 1; | ||||
} | } | ||||
// adjust the amplitude of the first harmonic, affects tonal quality | // adjust the amplitude of the first harmonic, affects tonal quality | ||||
h1 = htab[1] * option_harmonic1; | |||||
int h1 = htab[1] * option_harmonic1; | |||||
htab[1] = h1/8; | htab[1] = h1/8; | ||||
// calc intermediate increments of LF harmonics | // calc intermediate increments of LF harmonics | ||||
{ | { | ||||
// Called every 64 samples to increment the formant freq, height, and widths | // Called every 64 samples to increment the formant freq, height, and widths | ||||
int x; | |||||
int ix; | int ix; | ||||
static int Flutter_ix = 0; | static int Flutter_ix = 0; | ||||
// advance the pitch | // advance the pitch | ||||
wdata.pitch_ix += wdata.pitch_inc; | wdata.pitch_ix += wdata.pitch_inc; | ||||
if ((ix = wdata.pitch_ix>>8) > 127) ix = 127; | if ((ix = wdata.pitch_ix>>8) > 127) ix = 127; | ||||
x = wdata.pitch_env[ix] * wdata.pitch_range; | |||||
int x = wdata.pitch_env[ix] * wdata.pitch_range; | |||||
wdata.pitch = (x>>8) + wdata.pitch_base; | wdata.pitch = (x>>8) + wdata.pitch_base; | ||||
amp_ix += amp_inc; | amp_ix += amp_inc; | ||||
#ifndef PLATFORM_RISCOS | #ifndef PLATFORM_RISCOS | ||||
static double resonator(RESONATOR *r, double input) | static double resonator(RESONATOR *r, double input) | ||||
{ | { | ||||
double x; | |||||
x = r->a * input + r->b * r->x1 + r->c * r->x2; | |||||
double x = r->a * input + r->b * r->x1 + r->c * r->x2; | |||||
r->x2 = r->x1; | r->x2 = r->x1; | ||||
r->x1 = x; | r->x1 = x; | ||||
// bwidth Bandwidth of resonator in Hz | // bwidth Bandwidth of resonator in Hz | ||||
// init Initialize internal data | // init Initialize internal data | ||||
double x; | |||||
double arg; | |||||
if (init) { | if (init) { | ||||
rp->x1 = 0; | rp->x1 = 0; | ||||
rp->x2 = 0; | rp->x2 = 0; | ||||
} | } | ||||
arg = minus_pi_t * bwidth; | |||||
x = exp(arg); | |||||
double arg = minus_pi_t * bwidth; | |||||
double x = exp(arg); | |||||
rp->c = -(x * x); | rp->c = -(x * x); | ||||
void InitBreath(void) | void InitBreath(void) | ||||
{ | { | ||||
#ifndef PLATFORM_RISCOS | #ifndef PLATFORM_RISCOS | ||||
int ix; | |||||
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 (int ix = 0; ix < N_PEAKS; ix++) | |||||
setresonator(&rbreath[ix], 2000, 200, 1); | setresonator(&rbreath[ix], 2000, 200, 1); | ||||
#endif | #endif | ||||
} | } | ||||
static void SetBreath() | static void SetBreath() | ||||
{ | { | ||||
#ifndef PLATFORM_RISCOS | #ifndef PLATFORM_RISCOS | ||||
int pk; | |||||
if (wvoice->breath[0] == 0) | if (wvoice->breath[0] == 0) | ||||
return; | return; | ||||
for (pk = 1; pk < N_PEAKS; pk++) { | |||||
for (int pk = 1; pk < N_PEAKS; pk++) { | |||||
if (wvoice->breath[pk] != 0) { | if (wvoice->breath[pk] != 0) { | ||||
// breath[0] indicates that some breath formants are needed | // breath[0] indicates that some breath formants are needed | ||||
// set the freq from the current ynthesis formant and the width from the voice data | // set the freq from the current ynthesis formant and the width from the voice data | ||||
{ | { | ||||
int value = 0; | int value = 0; | ||||
#ifndef PLATFORM_RISCOS | #ifndef PLATFORM_RISCOS | ||||
int noise; | |||||
int ix; | |||||
int amp; | int amp; | ||||
// use two random numbers, for alternate formants | // use two random numbers, for alternate formants | ||||
noise = (rand() & 0x3fff) - 0x2000; | |||||
int noise = (rand() & 0x3fff) - 0x2000; | |||||
for (ix = 1; ix < N_PEAKS; ix++) { | |||||
for (int ix = 1; ix < N_PEAKS; ix++) { | |||||
if ((amp = wvoice->breath[ix]) != 0) { | if ((amp = wvoice->breath[ix]) != 0) { | ||||
amp *= (peaks[ix].height >> 14); | amp *= (peaks[ix].height >> 14); | ||||
value += (int)resonator(&rbreath[ix], noise) * amp; | value += (int)resonator(&rbreath[ix], noise) * amp; | ||||
static void SetPitchFormants() | static void SetPitchFormants() | ||||
{ | { | ||||
int ix; | |||||
int factor = 256; | int factor = 256; | ||||
int pitch_value; | int pitch_value; | ||||
factor = 256 + (25 * (pitch_value - 50))/50; | factor = 256 + (25 * (pitch_value - 50))/50; | ||||
} | } | ||||
for (ix = 0; ix <= 5; ix++) | |||||
for (int 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; | ||||
{ | { | ||||
// there was an embedded command in the text at this point | // there was an embedded command in the text at this point | ||||
int sign = 0; | int sign = 0; | ||||
int command; | |||||
command = control & 0x1f; | |||||
int command = control & 0x1f; | |||||
if ((control & 0x60) == 0x60) | if ((control & 0x60) == 0x60) | ||||
sign = -1; | sign = -1; | ||||
else if ((control & 0x60) == 0x40) | else if ((control & 0x60) == 0x40) | ||||
void SetPitch2(voice_t *voice, int pitch1, int pitch2, int *pitch_base, int *pitch_range) | void SetPitch2(voice_t *voice, int pitch1, int pitch2, int *pitch_base, int *pitch_range) | ||||
{ | { | ||||
int x; | |||||
int base; | |||||
int range; | |||||
int pitch_value; | int pitch_value; | ||||
if (pitch1 > pitch2) { | if (pitch1 > pitch2) { | ||||
x = pitch1; // swap values | |||||
int x = pitch1; // swap values | |||||
pitch1 = pitch2; | pitch1 = pitch2; | ||||
pitch2 = x; | pitch2 = x; | ||||
} | } | ||||
if (pitch_value < 0) | if (pitch_value < 0) | ||||
pitch_value = 0; | pitch_value = 0; | ||||
base = (voice->pitch_base * pitch_adjust_tab[pitch_value])/128; | |||||
range = (voice->pitch_range * embedded_value[EMBED_R])/50; | |||||
int base = (voice->pitch_base * pitch_adjust_tab[pitch_value])/128; | |||||
int range = (voice->pitch_range * embedded_value[EMBED_R])/50; | |||||
// compensate for change in pitch when the range is narrowed or widened | // compensate for change in pitch when the range is narrowed or widened | ||||
base -= (range - voice->pitch_range)*18; | base -= (range - voice->pitch_range)*18; | ||||
{ | { | ||||
int ix; | int ix; | ||||
DOUBLEX next; | DOUBLEX next; | ||||
int length2; | |||||
int length4; | |||||
int qix; | |||||
int cmd; | |||||
static int glottal_reduce_tab1[4] = { 0x30, 0x30, 0x40, 0x50 }; // vowel before [?], amp * 1/256 | static int glottal_reduce_tab1[4] = { 0x30, 0x30, 0x40, 0x50 }; // vowel before [?], amp * 1/256 | ||||
static int glottal_reduce_tab2[4] = { 0x90, 0xa0, 0xb0, 0xc0 }; // vowel after [?], amp * 1/256 | static int glottal_reduce_tab2[4] = { 0x90, 0xa0, 0xb0, 0xc0 }; // vowel after [?], amp * 1/256 | ||||
glottal_reduce = glottal_reduce_tab2[(modn >> 8) & 3]; | glottal_reduce = glottal_reduce_tab2[(modn >> 8) & 3]; | ||||
} | } | ||||
for (qix = wcmdq_head+1;; qix++) { | |||||
for (int qix = wcmdq_head+1;; qix++) { | |||||
if (qix >= N_WCMDQ) qix = 0; | if (qix >= N_WCMDQ) qix = 0; | ||||
if (qix == wcmdq_tail) break; | if (qix == wcmdq_tail) break; | ||||
cmd = wcmdq[qix][0]; | |||||
int cmd = wcmdq[qix][0]; | |||||
if (cmd == WCMD_SPECT) { | if (cmd == WCMD_SPECT) { | ||||
end_wave = 0; // next wave generation is from another spectrum | end_wave = 0; // next wave generation is from another spectrum | ||||
break; | break; | ||||
} | } | ||||
// round the length to a multiple of the stepsize | // round the length to a multiple of the stepsize | ||||
length2 = (length + STEPSIZE/2) & ~0x3f; | |||||
int length2 = (length + STEPSIZE/2) & ~0x3f; | |||||
if (length2 == 0) | if (length2 == 0) | ||||
length2 = STEPSIZE; | length2 = STEPSIZE; | ||||
samplecount_start = samplecount; | samplecount_start = samplecount; | ||||
nsamples += length2; | nsamples += length2; | ||||
length4 = length2/4; | |||||
int length4 = length2/4; | |||||
peaks[7].freq = (7800 * v->freq[7] + v->freqadd[7]*256) << 8; | peaks[7].freq = (7800 * v->freq[7] + v->freqadd[7]*256) << 8; | ||||
peaks[8].freq = (9000 * v->freq[8] + v->freqadd[8]*256) << 8; | peaks[8].freq = (9000 * v->freq[8] + v->freqadd[8]*256) << 8; | ||||
void Write4Bytes(FILE *f, int value) | void Write4Bytes(FILE *f, int value) | ||||
{ | { | ||||
// Write 4 bytes to a file, least significant first | // Write 4 bytes to a file, least significant first | ||||
int ix; | |||||
for (ix = 0; ix < 4; ix++) { | |||||
for (int ix = 0; ix < 4; ix++) { | |||||
fputc(value & 0xff, f); | fputc(value & 0xff, f); | ||||
value = value >> 8; | value = value >> 8; | ||||
} | } | ||||
// Call WavegenFill2, and then speed up the output samples. | // Call WavegenFill2, and then speed up the output samples. | ||||
int WavegenFill(int fill_zeros) | int WavegenFill(int fill_zeros) | ||||
{ | { | ||||
int finished; | |||||
unsigned char *p_start; | unsigned char *p_start; | ||||
p_start = out_ptr; | p_start = out_ptr; | ||||
// fill_zeros is ignored. It is now done in the portaudio callback | // fill_zeros is ignored. It is now done in the portaudio callback | ||||
finished = WavegenFill2(0); | |||||
int finished = WavegenFill2(0); | |||||
#if HAVE_SONIC_H | #if HAVE_SONIC_H | ||||
if (sonicSpeed > 1.0) { | if (sonicSpeed > 1.0) { |
void DisplayVoices(FILE *f_out, char *language) | void DisplayVoices(FILE *f_out, char *language) | ||||
{ | { | ||||
int ix; | |||||
const char *p; | const char *p; | ||||
int len; | int len; | ||||
int count; | int count; | ||||
fprintf(f_out, "Pty Language Age/Gender VoiceName File Other Languages\n"); | fprintf(f_out, "Pty Language Age/Gender VoiceName File Other Languages\n"); | ||||
for (ix = 0; (v = voices[ix]) != NULL; ix++) { | |||||
for (int ix = 0; (v = voices[ix]) != NULL; ix++) { | |||||
count = 0; | count = 0; | ||||
p = v->languages; | p = v->languages; | ||||
while (*p != 0) { | while (*p != 0) { | ||||
static void CloseWaveFile() | static void CloseWaveFile() | ||||
{ | { | ||||
unsigned int pos; | |||||
if ((f_wave == NULL) || (f_wave == stdout)) | if ((f_wave == NULL) || (f_wave == stdout)) | ||||
return; | return; | ||||
fflush(f_wave); | fflush(f_wave); | ||||
pos = ftell(f_wave); | |||||
unsigned int pos = ftell(f_wave); | |||||
fseek(f_wave, 4, SEEK_SET); | fseek(f_wave, 4, SEEK_SET); | ||||
Write4Bytes(f_wave, pos - 8); | Write4Bytes(f_wave, pos - 8); | ||||
fseek(f_wave, 40, SEEK_SET); | fseek(f_wave, 40, SEEK_SET); | ||||
Write4Bytes(f_wave, pos - 44); | Write4Bytes(f_wave, pos - 44); | ||||
fclose(f_wave); | fclose(f_wave); | ||||
f_wave = NULL; | f_wave = NULL; | ||||
} | } | ||||
static int WavegenFile(void) | static int WavegenFile(void) | ||||
{ | { | ||||
int finished; | |||||
unsigned char wav_outbuf[1024]; | unsigned char wav_outbuf[1024]; | ||||
char fname[210]; | char fname[210]; | ||||
out_ptr = out_start = wav_outbuf; | out_ptr = out_start = wav_outbuf; | ||||
out_end = wav_outbuf + sizeof(wav_outbuf); | out_end = wav_outbuf + sizeof(wav_outbuf); | ||||
finished = WavegenFill(0); | |||||
int finished = WavegenFill(0); | |||||
if (quiet) | if (quiet) | ||||
return finished; | return finished; | ||||
static int initialise(void) | static int initialise(void) | ||||
{ | { | ||||
int param; | |||||
int result; | |||||
int srate = 22050; // default sample rate | int srate = 22050; // default sample rate | ||||
// It seems that the wctype functions don't work until the locale has been set | // It seems that the wctype functions don't work until the locale has been set | ||||
} | } | ||||
#endif | #endif | ||||
int result; | |||||
if ((result = LoadPhData(&srate)) != 1) { | if ((result = LoadPhData(&srate)) != 1) { | ||||
if (result == -1) { | if (result == -1) { | ||||
fprintf(stderr, "Failed to load espeak-data\n"); | fprintf(stderr, "Failed to load espeak-data\n"); | ||||
SetVoiceStack(NULL, ""); | SetVoiceStack(NULL, ""); | ||||
SynthesizeInit(); | SynthesizeInit(); | ||||
for (param = 0; param < N_SPEECH_PARAM; param++) | |||||
for (int param = 0; param < N_SPEECH_PARAM; param++) | |||||
param_stack[0].parameter[param] = param_defaults[param]; | param_stack[0].parameter[param] = param_defaults[param]; | ||||
return 0; | return 0; | ||||
int c; | int c; | ||||
int value; | int value; | ||||
int speed = 175; | int speed = 175; | ||||
int ix; | |||||
char *optarg2; | char *optarg2; | ||||
int amp = 100; // default | int amp = 100; // default | ||||
int wordgap = 0; | int wordgap = 0; | ||||
optind = 1; | optind = 1; | ||||
opt_string = ""; | opt_string = ""; | ||||
while (optind < argc) { | while (optind < argc) { | ||||
int len; | |||||
char *p; | char *p; | ||||
if ((c = *opt_string) == 0) { | if ((c = *opt_string) == 0) { | ||||
break; // -- means don't interpret further - as commands | break; // -- means don't interpret further - as commands | ||||
opt_string = ""; | opt_string = ""; | ||||
for (ix = 0;; ix++) { | |||||
for (int ix = 0;; ix++) { | |||||
if (long_options[ix].name == 0) | if (long_options[ix].name == 0) | ||||
break; | break; | ||||
len = strlen(long_options[ix].name); | |||||
size_t len = strlen(long_options[ix].name); | |||||
if (memcmp(long_options[ix].name, p, len) == 0) { | if (memcmp(long_options[ix].name, p, len) == 0) { | ||||
c = long_options[ix].val; | c = long_options[ix].val; | ||||
optarg2 = NULL; | optarg2 = NULL; | ||||
case 0x103: // --punct | case 0x103: // --punct | ||||
option_punctuation = 1; | option_punctuation = 1; | ||||
if (optarg2 != NULL) { | if (optarg2 != NULL) { | ||||
ix = 0; | |||||
int ix = 0; | |||||
while ((ix < N_PUNCTLIST) && ((option_punctlist[ix] = optarg2[ix]) != 0)) ix++; | while ((ix < N_PUNCTLIST) && ((option_punctlist[ix] = optarg2[ix]) != 0)) ix++; | ||||
option_punctlist[N_PUNCTLIST-1] = 0; | option_punctlist[N_PUNCTLIST-1] = 0; | ||||
option_punctuation = 2; | option_punctuation = 2; | ||||
InitText(0); | InitText(0); | ||||
SpeakNextClause(f_text, p_text, 0); | SpeakNextClause(f_text, p_text, 0); | ||||
ix = 1; | |||||
int ix = 1; | |||||
for (;;) { | for (;;) { | ||||
if (WavegenFile() != 0) { | if (WavegenFile() != 0) { | ||||
if (ix == 0) | if (ix == 0) |