| error("Missing 'endphoneme' before end-of-file"); // end of file | error("Missing 'endphoneme' before end-of-file"); // end of file | ||||
| break; | break; | ||||
| } | } | ||||
| if (phoneme_add_feature(phoneme_out, item_string, NULL) == ENS_OK) | |||||
| phoneme_feature_t feature = phoneme_feature_from_string(item_string); | |||||
| if (phoneme_add_feature(phoneme_out, feature) == ENS_OK) | |||||
| continue; | continue; | ||||
| error("Bad keyword in phoneme definition '%s'", item_string); | error("Bad keyword in phoneme definition '%s'", item_string); | ||||
| continue; | continue; |
| return ENS_VERSION_MISMATCH; | return ENS_VERSION_MISMATCH; | ||||
| } | } | ||||
| espeak_ng_STATUS | |||||
| create_name_error_context(espeak_ng_ERROR_CONTEXT *context, | |||||
| espeak_ng_STATUS status, | |||||
| const char *name) | |||||
| { | |||||
| if (context) { | |||||
| if (*context) { | |||||
| free((*context)->name); | |||||
| } else { | |||||
| *context = malloc(sizeof(espeak_ng_ERROR_CONTEXT_)); | |||||
| if (!*context) | |||||
| return ENOMEM; | |||||
| } | |||||
| (*context)->type = ERROR_CONTEXT_NAME; | |||||
| (*context)->name = strdup(name); | |||||
| (*context)->version = 0; | |||||
| (*context)->expected_version = 0; | |||||
| } | |||||
| return status; | |||||
| } | |||||
| #pragma GCC visibility push(default) | #pragma GCC visibility push(default) | ||||
| ESPEAK_NG_API void | ESPEAK_NG_API void | ||||
| fprintf(out, "Error: %s at '%s' (expected 0x%x, got 0x%x).\n", | fprintf(out, "Error: %s at '%s' (expected 0x%x, got 0x%x).\n", | ||||
| error, context->name, context->expected_version, context->version); | error, context->name, context->expected_version, context->version); | ||||
| break; | break; | ||||
| case ERROR_CONTEXT_NAME: | |||||
| fprintf(out, "Error: %s (got \"%s\").\n", error, context->name); | |||||
| break; | |||||
| } | } | ||||
| } else | } else | ||||
| fprintf(out, "Error: %s.\n", error); | fprintf(out, "Error: %s.\n", error); |
| { | { | ||||
| ERROR_CONTEXT_FILE, | ERROR_CONTEXT_FILE, | ||||
| ERROR_CONTEXT_VERSION, | ERROR_CONTEXT_VERSION, | ||||
| ERROR_CONTEXT_NAME, | |||||
| } espeak_ng_CONTEXT_TYPE; | } espeak_ng_CONTEXT_TYPE; | ||||
| typedef struct espeak_ng_ERROR_CONTEXT_ | typedef struct espeak_ng_ERROR_CONTEXT_ | ||||
| int version, | int version, | ||||
| int expected_version); | int expected_version); | ||||
| espeak_ng_STATUS | |||||
| create_name_error_context(espeak_ng_ERROR_CONTEXT *context, | |||||
| espeak_ng_STATUS status, | |||||
| const char *name); | |||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||
| } | } | ||||
| #endif | #endif |
| #include <espeak-ng/speak_lib.h> | #include <espeak-ng/speak_lib.h> | ||||
| #include "phoneme.h" | #include "phoneme.h" | ||||
| #include "error.h" | |||||
| uint32_t lookup_feature(const char *feature) { | |||||
| if (strlen(feature) != 3) | |||||
| phoneme_feature_t phoneme_feature_from_string(const char *feature) | |||||
| { | |||||
| if (!feature || strlen(feature) != 3) | |||||
| return inv; | return inv; | ||||
| return (feature[0] << 16) | (feature[1] << 8) | feature[2]; | return (feature[0] << 16) | (feature[1] << 8) | feature[2]; | ||||
| } | } | ||||
| espeak_ng_STATUS | espeak_ng_STATUS | ||||
| phoneme_add_feature(PHONEME_TAB *phoneme, | phoneme_add_feature(PHONEME_TAB *phoneme, | ||||
| const char *feature, | |||||
| espeak_ng_ERROR_CONTEXT *context) | |||||
| phoneme_feature_t feature) | |||||
| { | { | ||||
| if (!phoneme || !feature) return EINVAL; | |||||
| switch (lookup_feature(feature)) | |||||
| if (!phoneme) return EINVAL; | |||||
| switch (feature) | |||||
| { | { | ||||
| // manner of articulation | // manner of articulation | ||||
| case nas: | case nas: | ||||
| break; | break; | ||||
| // invalid phoneme feature | // invalid phoneme feature | ||||
| default: | default: | ||||
| return create_name_error_context(context, ENS_UNKNOWN_PHONEME_FEATURE, feature); | |||||
| return ENS_UNKNOWN_PHONEME_FEATURE; | |||||
| } | } | ||||
| return ENS_OK; | return ENS_OK; | ||||
| } | } |
| #endif | #endif | ||||
| // See docs/phonemes.md for the list of supported features. | // See docs/phonemes.md for the list of supported features. | ||||
| enum feature_t { | |||||
| typedef enum { | |||||
| # define FEATURE_T(a, b, c) ((a << 16) | (b << 8) | (c)) | # define FEATURE_T(a, b, c) ((a << 16) | (b << 8) | (c)) | ||||
| // invalid phoneme feature name | // invalid phoneme feature name | ||||
| inv = 0, | inv = 0, | ||||
| fts = FEATURE_T('f', 't', 's'), | fts = FEATURE_T('f', 't', 's'), | ||||
| lns = FEATURE_T('l', 'n', 's'), | lns = FEATURE_T('l', 'n', 's'), | ||||
| # undef FEATURE_T | # undef FEATURE_T | ||||
| }; | |||||
| } phoneme_feature_t; | |||||
| phoneme_feature_t phoneme_feature_from_string(const char *feature); | |||||
| // phoneme types | // phoneme types | ||||
| #define phPAUSE 0 | #define phPAUSE 0 | ||||
| espeak_ng_STATUS | espeak_ng_STATUS | ||||
| phoneme_add_feature(PHONEME_TAB *phoneme, | phoneme_add_feature(PHONEME_TAB *phoneme, | ||||
| const char *feature, | |||||
| espeak_ng_ERROR_CONTEXT *context); | |||||
| phoneme_feature_t feature); | |||||
| // Several phoneme tables may be loaded into memory. phoneme_tab points to | // Several phoneme tables may be loaded into memory. phoneme_tab points to | ||||
| // one for the current voice | // one for the current voice |