| // 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 (ctx->manifest != NULL) { | if (ctx->manifest != NULL) { | ||||
| for (ix = 0; ix < ctx->n_manifest; ix++) | |||||
| for (int ix = 0; ix < ctx->n_manifest; ix++) | |||||
| free(ctx->manifest[ix].name); | free(ctx->manifest[ix].name); | ||||
| } | } | ||||
| { | { | ||||
| // Reserve phoneme codes which have fixed numbers so that they can be | // Reserve phoneme codes which have fixed numbers so that they can be | ||||
| // referred to from the program code. | // referred to from the program code. | ||||
| unsigned int word; | |||||
| const MNEM_TAB *p; | const MNEM_TAB *p; | ||||
| p = reserved_phonemes; | p = reserved_phonemes; | ||||
| while (p->mnem != NULL) { | while (p->mnem != NULL) { | ||||
| word = StringToWord(p->mnem); | |||||
| ctx->phoneme_tab2[p->value].mnemonic = word; | |||||
| ctx->phoneme_tab2[p->value].mnemonic = StringToWord(p->mnem); | |||||
| ctx->phoneme_tab2[p->value].code = p->value; | ctx->phoneme_tab2[p->value].code = p->value; | ||||
| if (ctx->n_phcodes <= p->value) | if (ctx->n_phcodes <= p->value) | ||||
| ctx->n_phcodes = p->value+1; | ctx->n_phcodes = p->value+1; | ||||
| static int NextItem(CompileContext *ctx, int type) | static int NextItem(CompileContext *ctx, int type) | ||||
| { | { | ||||
| int acc; | |||||
| unsigned char c = 0; | unsigned char c = 0; | ||||
| unsigned char c2; | unsigned char c2; | ||||
| int ix; | int ix; | ||||
| int sign; | |||||
| char *p; | |||||
| const keywtab_t *pk; | const keywtab_t *pk; | ||||
| ctx->item_type = -1; | ctx->item_type = -1; | ||||
| return 0; | return 0; | ||||
| if ((type == tNUMBER) || (type == tSIGNEDNUMBER)) { | if ((type == tNUMBER) || (type == tSIGNEDNUMBER)) { | ||||
| acc = 0; | |||||
| sign = 1; | |||||
| p = ctx->item_string; | |||||
| int acc = 0; | |||||
| int sign = 1; | |||||
| char *p; | |||||
| p = ctx->item_string; | |||||
| if ((*p == '-') && (type == tSIGNEDNUMBER)) { | if ((*p == '-') && (type == tSIGNEDNUMBER)) { | ||||
| sign = -1; | sign = -1; | ||||
| static int CompileVowelTransition(CompileContext *ctx, int which) | static int CompileVowelTransition(CompileContext *ctx, 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; | ||||
| } | } | ||||
| for (;;) { | for (;;) { | ||||
| key = NextItem(ctx, tKEYWORD); | |||||
| int key = NextItem(ctx, tKEYWORD); | |||||
| if (ctx->item_type != tTRANSITION) { | if (ctx->item_type != tTRANSITION) { | ||||
| UngetItem(ctx); | UngetItem(ctx); | ||||
| break; | break; | ||||
| static int LoadEnvelope2(CompileContext *ctx, FILE *f) | static int LoadEnvelope2(CompileContext *ctx, FILE *f) | ||||
| { | { | ||||
| int ix, ix2; | int ix, ix2; | ||||
| int n; | |||||
| int x, y; | |||||
| int displ; | int displ; | ||||
| int n_points; | int n_points; | ||||
| char line_buf[128]; | char line_buf[128]; | ||||
| break; | break; | ||||
| env_lin[n_points] = 0; | env_lin[n_points] = 0; | ||||
| n = sscanf(line_buf, "%f %f %d", &env_x[n_points], &env_y[n_points], &env_lin[n_points]); | |||||
| int n = sscanf(line_buf, "%f %f %d", &env_x[n_points], &env_y[n_points], &env_lin[n_points]); | |||||
| if (n >= 2) { | if (n >= 2) { | ||||
| env_x[n_points] *= (float)1.28; // convert range 0-100 to 0-128 | env_x[n_points] *= (float)1.28; // convert range 0-100 to 0-128 | ||||
| n_points++; | n_points++; | ||||
| ix = 0; | ix = 0; | ||||
| ix2 = 0; | ix2 = 0; | ||||
| if (n_points > 0) for (x = 0; x < ENV_LEN; x++) { | |||||
| if (n_points > 0) for (int x = 0; x < ENV_LEN; x++) { | |||||
| if (n_points > 3 && x > env_x[ix+3]) | if (n_points > 3 && x > env_x[ix+3]) | ||||
| ix++; | ix++; | ||||
| if (n_points > 2 && x >= env_x[ix2+1]) | if (n_points > 2 && x >= env_x[ix2+1]) | ||||
| ix2++; | ix2++; | ||||
| int y; | |||||
| if (env_lin[ix2] > 0) { | if (env_lin[ix2] > 0) { | ||||
| y = (env_y[ix2] + (env_y[ix2+1] - env_y[ix2]) * ((float)x - env_x[ix2]) / (env_x[ix2+1] - env_x[ix2])) * 2.55; | y = (env_y[ix2] + (env_y[ix2+1] - env_y[ix2]) * ((float)x - env_x[ix2]) / (env_x[ix2+1] - env_x[ix2])) * 2.55; | ||||
| } else if (n_points > 3) | } else if (n_points > 3) | ||||
| // load spectrum sequence or sample data from a file. | // load spectrum sequence or sample data from a file. | ||||
| // 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; | |||||
| int id; | |||||
| int hash; | int hash; | ||||
| int type_code = ' '; | |||||
| REF_HASH_TAB *p, *p2; | REF_HASH_TAB *p, *p2; | ||||
| char buf[sizeof(path_home)+150]; | |||||
| if (strcmp(path, "NULL") == 0) | if (strcmp(path, "NULL") == 0) | ||||
| return ENS_OK; | return ENS_OK; | ||||
| } | } | ||||
| if (*addr == 0) { | if (*addr == 0) { | ||||
| char buf[sizeof(path_home)+150]; | |||||
| sprintf(buf, "%s/%s", ctx->phsrc, path); | sprintf(buf, "%s/%s", ctx->phsrc, path); | ||||
| FILE *f; | |||||
| if ((f = fopen(buf, "rb")) == NULL) { | if ((f = fopen(buf, "rb")) == NULL) { | ||||
| sprintf(buf, "%s/%s.wav", ctx->phsrc, path); | sprintf(buf, "%s/%s.wav", ctx->phsrc, path); | ||||
| if ((f = fopen(buf, "rb")) == NULL) { | if ((f = fopen(buf, "rb")) == NULL) { | ||||
| } | } | ||||
| } | } | ||||
| id = Read4Bytes(f); | |||||
| int id = Read4Bytes(f); | |||||
| rewind(f); | rewind(f); | ||||
| espeak_ng_STATUS status = ENS_OK; | espeak_ng_STATUS status = ENS_OK; | ||||
| int type_code = ' '; | |||||
| if (id == 0x43455053) { | if (id == 0x43455053) { | ||||
| status = LoadSpect(ctx, path, control, addr); | status = LoadSpect(ctx, path, control, addr); | ||||
| type_code = 'S'; | type_code = 'S'; | ||||
| */ | */ | ||||
| static int CompileIf(CompileContext *ctx, int elif) | static int CompileIf(CompileContext *ctx, int elif) | ||||
| { | { | ||||
| int key; | |||||
| bool finish = false; | bool finish = false; | ||||
| int word = 0; | int word = 0; | ||||
| int word2; | |||||
| int data; | int data; | ||||
| int bitmap; | int bitmap; | ||||
| int brackets; | int brackets; | ||||
| bool not_flag; | |||||
| unsigned short *prog_last_if = NULL; | unsigned short *prog_last_if = NULL; | ||||
| ctx->then_count = 2; | ctx->then_count = 2; | ||||
| ctx->after_if = true; | ctx->after_if = true; | ||||
| while (!finish) { | while (!finish) { | ||||
| not_flag = false; | |||||
| word2 = 0; | |||||
| bool not_flag = false; | |||||
| int word2 = 0; | |||||
| if (ctx->prog_out >= ctx->prog_out_max) { | if (ctx->prog_out >= ctx->prog_out_max) { | ||||
| error(ctx, "Phoneme program too large"); | error(ctx, "Phoneme program too large"); | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| int key; | |||||
| if ((key = NextItem(ctx, tCONDITION)) < 0) | if ((key = NextItem(ctx, tCONDITION)) < 0) | ||||
| error(ctx, "Expected a condition, not '%s'", ctx->item_string); | error(ctx, "Expected a condition, not '%s'", ctx->item_string); | ||||
| static void FillThen(CompileContext *ctx, int add) | static void FillThen(CompileContext *ctx, int add) | ||||
| { | { | ||||
| unsigned short *p; | unsigned short *p; | ||||
| int offset; | |||||
| p = ctx->if_stack[ctx->if_level].p_then; | p = ctx->if_stack[ctx->if_level].p_then; | ||||
| if (p != NULL) { | if (p != NULL) { | ||||
| offset = ctx->prog_out - p + add; | |||||
| int offset = ctx->prog_out - p + add; | |||||
| if ((ctx->then_count == 1) && (ctx->if_level == 1)) { | if ((ctx->then_count == 1) && (ctx->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 int CompileElse(CompileContext *ctx) | static int CompileElse(CompileContext *ctx) | ||||
| { | { | ||||
| unsigned short *ref; | unsigned short *ref; | ||||
| unsigned short *p; | |||||
| if (ctx->if_level < 1) { | if (ctx->if_level < 1) { | ||||
| error(ctx, "ELSE not expected"); | error(ctx, "ELSE not expected"); | ||||
| ref = ctx->prog_out; | ref = ctx->prog_out; | ||||
| *ctx->prog_out++ = 0; | *ctx->prog_out++ = 0; | ||||
| unsigned short *p; | |||||
| if ((p = ctx->if_stack[ctx->if_level].p_else) != NULL) | if ((p = ctx->if_stack[ctx->if_level].p_else) != NULL) | ||||
| *ref = ref - p; // backwards offset to the previous else | *ref = ref - p; // backwards offset to the previous else | ||||
| ctx->if_stack[ctx->if_level].p_else = ref; | ctx->if_stack[ctx->if_level].p_else = ref; | ||||
| static int CompileEndif(CompileContext *ctx) | static int CompileEndif(CompileContext *ctx) | ||||
| { | { | ||||
| unsigned short *p; | unsigned short *p; | ||||
| int chain; | |||||
| int offset; | |||||
| if (ctx->if_level < 1) { | if (ctx->if_level < 1) { | ||||
| error(ctx, "ENDIF not expected"); | error(ctx, "ENDIF not expected"); | ||||
| FillThen(ctx, 0); | FillThen(ctx, 0); | ||||
| if ((p = ctx->if_stack[ctx->if_level].p_else) != NULL) { | if ((p = ctx->if_stack[ctx->if_level].p_else) != NULL) { | ||||
| int chain; | |||||
| do { | do { | ||||
| chain = *p; // a chain of previous else links | chain = *p; // a chain of previous else links | ||||
| offset = ctx->prog_out - p; | |||||
| int offset = ctx->prog_out - p; | |||||
| if (offset > MAX_JUMP) | if (offset > MAX_JUMP) | ||||
| error(ctx, "IF block is too long"); | error(ctx, "IF block is too long"); | ||||
| *p = i_JUMP + offset; | *p = i_JUMP + offset; | ||||
| static int CompilePhoneme(CompileContext *ctx, int compile_phoneme) | static int CompilePhoneme(CompileContext *ctx, int compile_phoneme) | ||||
| { | { | ||||
| int endphoneme = 0; | int endphoneme = 0; | ||||
| int keyword; | |||||
| int value; | int value; | ||||
| int phcode = 0; | int phcode = 0; | ||||
| int flags; | int flags; | ||||
| ctx->phoneme_out->phflags = 0; | ctx->phoneme_out->phflags = 0; | ||||
| while (!endphoneme && !feof(ctx->f_in)) { | while (!endphoneme && !feof(ctx->f_in)) { | ||||
| int keyword; | |||||
| if ((keyword = NextItem(ctx, tKEYWORD)) < 0) { | if ((keyword = NextItem(ctx, tKEYWORD)) < 0) { | ||||
| if (keyword == -2) { | if (keyword == -2) { | ||||
| error(ctx, "Missing 'endphoneme' before end-of-file"); // end of file | error(ctx, "Missing 'endphoneme' before end-of-file"); // end of file | ||||
| { | { | ||||
| int ix; | int ix; | ||||
| int j; | int j; | ||||
| int n; | |||||
| int value; | int value; | ||||
| int count; | |||||
| PHONEME_TAB *p; | PHONEME_TAB *p; | ||||
| value = ctx->n_phoneme_tabs; | value = ctx->n_phoneme_tabs; | ||||
| for (ix = 0; ix < ctx->n_phoneme_tabs; ix++) { | for (ix = 0; ix < ctx->n_phoneme_tabs; ix++) { | ||||
| p = ctx->phoneme_tab_list2[ix].phoneme_tab_ptr; | p = ctx->phoneme_tab_list2[ix].phoneme_tab_ptr; | ||||
| n = ctx->n_phcodes_list[ix]; | |||||
| int n = ctx->n_phcodes_list[ix]; | |||||
| memset(&p[n], 0, sizeof(p[n])); | memset(&p[n], 0, sizeof(p[n])); | ||||
| 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; | |||||
| int count = 0; | |||||
| for (j = 0; j < n; j++) { | for (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 | ||||
| static void StartPhonemeTable(CompileContext *ctx, const char *name) | static void StartPhonemeTable(CompileContext *ctx, const char *name) | ||||
| { | { | ||||
| int ix; | |||||
| int j; | |||||
| PHONEME_TAB *p; | PHONEME_TAB *p; | ||||
| if (ctx->n_phoneme_tabs >= N_PHONEME_TABS-1) { | if (ctx->n_phoneme_tabs >= N_PHONEME_TABS-1) { | ||||
| if (ctx->n_phoneme_tabs > 0) { | if (ctx->n_phoneme_tabs > 0) { | ||||
| NextItem(ctx, tSTRING); // name of base phoneme table | NextItem(ctx, tSTRING); // name of base phoneme table | ||||
| int ix; | |||||
| for (ix = 0; ix < ctx->n_phoneme_tabs; ix++) { | for (ix = 0; ix < ctx->n_phoneme_tabs; ix++) { | ||||
| if (strcmp(ctx->item_string, ctx->phoneme_tab_list2[ix].name) == 0) { | if (strcmp(ctx->item_string, ctx->phoneme_tab_list2[ix].name) == 0) { | ||||
| ctx->phoneme_tab_list2[ctx->n_phoneme_tabs].includes = ix+1; | ctx->phoneme_tab_list2[ctx->n_phoneme_tabs].includes = ix+1; | ||||
| ctx->n_phcodes = ctx->n_phcodes_list[ix]; | ctx->n_phcodes = ctx->n_phcodes_list[ix]; | ||||
| // clear "local phoneme" bit" | // clear "local phoneme" bit" | ||||
| int j; | |||||
| for (j = 0; j < ctx->n_phcodes; j++) | for (j = 0; j < ctx->n_phcodes; j++) | ||||
| ctx->phoneme_tab2[j].phflags &= ~phLOCAL; | ctx->phoneme_tab2[j].phflags &= ~phLOCAL; | ||||
| break; | break; | ||||
| static void CompilePhonemeFiles(CompileContext *ctx) | static void CompilePhonemeFiles(CompileContext *ctx) | ||||
| { | { | ||||
| int item; | |||||
| FILE *f; | FILE *f; | ||||
| char buf[sizeof(path_home)+120]; | char buf[sizeof(path_home)+120]; | ||||
| ctx->linenum = ctx->stack[ctx->stack_ix].linenum; | ctx->linenum = ctx->stack[ctx->stack_ix].linenum; | ||||
| } | } | ||||
| item = NextItem(ctx, tKEYWORD); | |||||
| int item = NextItem(ctx, tKEYWORD); | |||||
| switch (item) | switch (item) | ||||
| { | { | ||||
| int ix; | int ix; | ||||
| char *p; | char *p; | ||||
| char c; | char c; | ||||
| int keyword; | |||||
| int n_tune_names = 0; | int n_tune_names = 0; | ||||
| bool done_split = false; | bool done_split = false; | ||||
| bool done_onset = false; | bool done_onset = false; | ||||
| } | } | ||||
| while (!feof(ctx->f_in)) { | while (!feof(ctx->f_in)) { | ||||
| keyword = NextItem(ctx, tINTONATION); | |||||
| int keyword = NextItem(ctx, tINTONATION); | |||||
| switch (keyword) | switch (keyword) | ||||
| { | { |