// This version of the command-line speak program uses the | // This version of the command-line speak program uses the | ||||
// libespeak.so.1 library | // libespeak.so.1 library | ||||
static const char *help_text = | static const char *help_text = | ||||
"\nespeak-ng [options] [\"<words>\"]\n\n" | "\nespeak-ng [options] [\"<words>\"]\n\n" | ||||
"-f <text file> Text file to speak\n" | "-f <text file> Text file to speak\n" | ||||
"\t List the available voices for the specified language.\n" | "\t List the available voices for the specified language.\n" | ||||
"\t If <language> is omitted, then list all voices.\n"; | "\t If <language> is omitted, then list all voices.\n"; | ||||
int samplerate; | int samplerate; | ||||
int quiet = 0; | int quiet = 0; | ||||
unsigned int samples_total = 0; | unsigned int samples_total = 0; | ||||
char filetype[5]; | char filetype[5]; | ||||
char wavefile[200]; | char wavefile[200]; | ||||
void DisplayVoices(FILE *f_out, char *language) | void DisplayVoices(FILE *f_out, char *language) | ||||
{ | { | ||||
int ix; | int ix; | ||||
} | } | ||||
} | } | ||||
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 OpenWavFile(char *path, int rate) | int OpenWavFile(char *path, int rate) | ||||
{ | { | ||||
static unsigned char wave_hdr[44] = { | static unsigned char wave_hdr[44] = { | ||||
return 1; | return 1; | ||||
} | } | ||||
fwrite(wave_hdr, 1, 24, f_wavfile); | fwrite(wave_hdr, 1, 24, f_wavfile); | ||||
Write4Bytes(f_wavfile, rate); | Write4Bytes(f_wavfile, rate); | ||||
Write4Bytes(f_wavfile, rate * 2); | Write4Bytes(f_wavfile, rate * 2); | ||||
return 0; | return 0; | ||||
} | } | ||||
static void CloseWavFile() | static void CloseWavFile() | ||||
{ | { | ||||
unsigned int pos; | unsigned int pos; | ||||
} | } | ||||
static int SynthCallback(short *wav, int numsamples, espeak_EVENT *events) | static int SynthCallback(short *wav, int numsamples, espeak_EVENT *events) | ||||
{ | { | ||||
char fname[210]; | char fname[210]; | ||||
return 0; | return 0; | ||||
} | } | ||||
static void PrintVersion() | static void PrintVersion() | ||||
{ | { | ||||
const char *version; | const char *version; | ||||
printf("eSpeak text-to-speech: %s Data at: %s\n", version, path_data); | printf("eSpeak text-to-speech: %s Data at: %s\n", version, path_data); | ||||
} | } | ||||
#ifdef NEED_GETOPT | #ifdef NEED_GETOPT | ||||
struct option { | struct option { | ||||
char *name; | char *name; | ||||
static const char *err_load = "Failed to read "; | static const char *err_load = "Failed to read "; | ||||
FILE *f_text = NULL; | FILE *f_text = NULL; | ||||
char *p_text = NULL; | char *p_text = NULL; | ||||
FILE *f_phonemes_out = stdout; | FILE *f_phonemes_out = stdout; | ||||
else | else | ||||
synth_flags |= espeakCHARS_8BIT; | synth_flags |= espeakCHARS_8BIT; | ||||
break; | break; | ||||
case 'h': | case 'h': | ||||
printf("\n"); | printf("\n"); | ||||
PrintVersion(); | PrintVersion(); | ||||
printf("%s", help_text); | printf("%s", help_text); | ||||
exit(0); | exit(0); | ||||
break; | break; | ||||
case 'k': | case 'k': | ||||
option_capitals = atoi(optarg2); | option_capitals = atoi(optarg2); | ||||
break; | break; | ||||
case 'x': | case 'x': | ||||
phoneme_options |= espeakPHONEMES_SHOW; | phoneme_options |= espeakPHONEMES_SHOW; | ||||
break; | break; | ||||
case 'X': | case 'X': | ||||
phoneme_options |= espeakPHONEMES_TRACE; | phoneme_options |= espeakPHONEMES_TRACE; | ||||
break; | break; | ||||
case 'm': | case 'm': | ||||
synth_flags |= espeakSSML; | synth_flags |= espeakSSML; | ||||
break; | break; | ||||
case 'p': | case 'p': | ||||
pitch = atoi(optarg2); | pitch = atoi(optarg2); | ||||
break; | break; | ||||
case 'q': | case 'q': | ||||
quiet = 1; | quiet = 1; | ||||
break; | break; | ||||
case 'f': | case 'f': | ||||
strncpy0(filename, optarg2, sizeof(filename)); | strncpy0(filename, optarg2, sizeof(filename)); | ||||
break; | break; | ||||
case 'l': | case 'l': | ||||
option_linelength = atoi(optarg2); | option_linelength = atoi(optarg2); | ||||
break; | break; | ||||
case 'a': | case 'a': | ||||
volume = atoi(optarg2); | volume = atoi(optarg2); | ||||
break; | break; | ||||
case 's': | case 's': | ||||
speed = atoi(optarg2); | speed = atoi(optarg2); | ||||
break; | break; | ||||
case 'g': | case 'g': | ||||
wordgap = atoi(optarg2); | wordgap = atoi(optarg2); | ||||
break; | break; | ||||
case 'v': | case 'v': | ||||
strncpy0(voicename, optarg2, sizeof(voicename)); | strncpy0(voicename, optarg2, sizeof(voicename)); | ||||
break; | break; | ||||
case 'w': | case 'w': | ||||
option_waveout = 1; | option_waveout = 1; | ||||
strncpy0(wavefile, optarg2, sizeof(filename)); | strncpy0(wavefile, optarg2, sizeof(filename)); | ||||
break; | break; | ||||
case 'z': // remove pause from the end of a sentence | case 'z': // remove pause from the end of a sentence | ||||
synth_flags &= ~espeakENDPAUSE; | synth_flags &= ~espeakENDPAUSE; | ||||
break; | break; | ||||
case 0x100: // --stdin | case 0x100: // --stdin | ||||
flag_stdin = 1; | flag_stdin = 1; | ||||
break; | break; | ||||
case 0x105: // --stdout | case 0x105: // --stdout | ||||
option_waveout = 1; | option_waveout = 1; | ||||
strcpy(wavefile, "stdout"); | strcpy(wavefile, "stdout"); | ||||
break; | break; | ||||
case 0x101: // --compile-debug | case 0x101: // --compile-debug | ||||
case 0x102: // --compile | case 0x102: // --compile | ||||
strncpy0(voicename, optarg2, sizeof(voicename)); | strncpy0(voicename, optarg2, sizeof(voicename)); | ||||
flag_compile = c; | flag_compile = c; | ||||
quiet = 1; | quiet = 1; | ||||
break; | break; | ||||
case 0x103: // --punct | case 0x103: // --punct | ||||
option_punctuation = 1; | option_punctuation = 1; | ||||
if (optarg2 != NULL) { | if (optarg2 != NULL) { | ||||
option_punctuation = 2; | option_punctuation = 2; | ||||
} | } | ||||
break; | break; | ||||
case 0x104: // --voices | case 0x104: // --voices | ||||
espeak_Initialize(AUDIO_OUTPUT_SYNCHRONOUS, 0, data_path, 0); | espeak_Initialize(AUDIO_OUTPUT_SYNCHRONOUS, 0, data_path, 0); | ||||
DisplayVoices(stdout, optarg2); | DisplayVoices(stdout, optarg2); | ||||
exit(0); | exit(0); | ||||
case 0x106: // -- split | case 0x106: // -- split | ||||
if (optarg2 == NULL) | if (optarg2 == NULL) | ||||
samples_split_seconds = 30 * 60; // default 30 minutes | samples_split_seconds = 30 * 60; // default 30 minutes | ||||
else | else | ||||
samples_split_seconds = atoi(optarg2) * 60; | samples_split_seconds = atoi(optarg2) * 60; | ||||
break; | break; | ||||
case 0x107: // --path | case 0x107: // --path | ||||
data_path = optarg2; | data_path = optarg2; | ||||
break; | break; | ||||
case 0x108: // --phonout | case 0x108: // --phonout | ||||
if ((f_phonemes_out = fopen(optarg2, "w")) == NULL) | if ((f_phonemes_out = fopen(optarg2, "w")) == NULL) | ||||
fprintf(stderr, "Can't write to: %s\n", optarg2); | fprintf(stderr, "Can't write to: %s\n", optarg2); | ||||
break; | break; | ||||
case 0x109: // --pho | case 0x109: // --pho | ||||
phoneme_options |= espeakPHONEMES_MBROLA; | phoneme_options |= espeakPHONEMES_MBROLA; | ||||
break; | break; | ||||
case 0x10a: // --ipa | case 0x10a: // --ipa | ||||
phoneme_options |= espeakPHONEMES_IPA; | phoneme_options |= espeakPHONEMES_IPA; | ||||
if (optarg2 != NULL) { | if (optarg2 != NULL) { | ||||
} | } | ||||
break; | break; | ||||
case 0x10b: // --version | case 0x10b: // --version | ||||
PrintVersion(); | PrintVersion(); | ||||
exit(0); | exit(0); | ||||
case 0x10c: // --sep | case 0x10c: // --sep | ||||
phoneme_options |= espeakPHONEMES_SHOW; | phoneme_options |= espeakPHONEMES_SHOW; | ||||
if (optarg2 == 0) | if (optarg2 == 0) | ||||
if (phonemes_separator == 'z') | if (phonemes_separator == 'z') | ||||
phonemes_separator = 0x200c; // ZWNJ | phonemes_separator = 0x200c; // ZWNJ | ||||
break; | break; | ||||
case 0x10d: // --tie | case 0x10d: // --tie | ||||
phoneme_options |= (espeakPHONEMES_SHOW | espeakPHONEMES_TIE); | phoneme_options |= (espeakPHONEMES_SHOW | espeakPHONEMES_TIE); | ||||
if (optarg2 == 0) | if (optarg2 == 0) | ||||
if (phonemes_separator == 'z') | if (phonemes_separator == 'z') | ||||
phonemes_separator = 0x200d; // ZWJ | phonemes_separator = 0x200d; // ZWJ | ||||
break; | break; | ||||
case 0x10e: // --compile-mbrola | case 0x10e: // --compile-mbrola | ||||
samplerate = espeak_Initialize(AUDIO_OUTPUT_PLAYBACK, 0, data_path, 0); | samplerate = espeak_Initialize(AUDIO_OUTPUT_PLAYBACK, 0, data_path, 0); | ||||
espeak_ng_CompileMbrolaVoice(optarg2, stdout); | espeak_ng_CompileMbrolaVoice(optarg2, stdout); | ||||
exit(0); | exit(0); | ||||
case 0x10f: // --compile-intonations | case 0x10f: // --compile-intonations | ||||
samplerate = espeak_Initialize(AUDIO_OUTPUT_PLAYBACK, 0, data_path, espeakINITIALIZE_PATH_ONLY); | samplerate = espeak_Initialize(AUDIO_OUTPUT_PLAYBACK, 0, data_path, espeakINITIALIZE_PATH_ONLY); | ||||
espeak_ng_CompileIntonation(stdout); | espeak_ng_CompileIntonation(stdout); | ||||
exit(0); | exit(0); | ||||
case 0x110: // --compile-phonemes | case 0x110: // --compile-phonemes | ||||
samplerate = espeak_Initialize(AUDIO_OUTPUT_PLAYBACK, 0, data_path, espeakINITIALIZE_PATH_ONLY); | samplerate = espeak_Initialize(AUDIO_OUTPUT_PLAYBACK, 0, data_path, espeakINITIALIZE_PATH_ONLY); | ||||
espeak_ng_CompilePhonemeData(22050, stdout); | espeak_ng_CompilePhonemeData(22050, stdout); | ||||
exit(0); | exit(0); | ||||
default: | default: | ||||
exit(0); | exit(0); | ||||
} | } | ||||
} | } | ||||
if (option_waveout || quiet) { | if (option_waveout || quiet) { | ||||
// writing to a file (or no output), we can use synchronous mode | // writing to a file (or no output), we can use synchronous mode | ||||
samplerate = espeak_Initialize(AUDIO_OUTPUT_SYNCHRONOUS, 0, data_path, 0); | samplerate = espeak_Initialize(AUDIO_OUTPUT_SYNCHRONOUS, 0, data_path, 0); | ||||
samplerate = espeak_Initialize(AUDIO_OUTPUT_PLAYBACK, 0, data_path, 0); | samplerate = espeak_Initialize(AUDIO_OUTPUT_PLAYBACK, 0, data_path, 0); | ||||
} | } | ||||
if (voicename[0] == 0) | if (voicename[0] == 0) | ||||
strcpy(voicename, "default"); | strcpy(voicename, "default"); | ||||
if (option_punctuation == 2) | if (option_punctuation == 2) | ||||
espeak_SetPunctuationList(option_punctlist); | espeak_SetPunctuationList(option_punctlist); | ||||
espeak_SetPhonemeTrace(phoneme_options | (phonemes_separator << 8), f_phonemes_out); | espeak_SetPhonemeTrace(phoneme_options | (phonemes_separator << 8), f_phonemes_out); | ||||
if (filename[0] == 0) { | if (filename[0] == 0) { | ||||
exit(1); | exit(1); | ||||
} | } | ||||
if (p_text != NULL) { | if (p_text != NULL) { | ||||
int size; | int size; | ||||
size = strlen(p_text); | size = strlen(p_text); |
{ NULL, 0, 0 } | { NULL, 0, 0 } | ||||
}; | }; | ||||
static keywtab_t k_properties[] = { | static keywtab_t k_properties[] = { | ||||
{ "isPause", 0, phPAUSE }, | { "isPause", 0, phPAUSE }, | ||||
{ "isVowel", 0, phVOWEL }, | { "isVowel", 0, phVOWEL }, | ||||
{ "afr", tPHONEME_TYPE, phSTOP }, // treat as stop | { "afr", tPHONEME_TYPE, phSTOP }, // treat as stop | ||||
{ "apr", tPHONEME_TYPE, phFRICATIVE }, // [h] voiceless approximant | { "apr", tPHONEME_TYPE, phFRICATIVE }, // [h] voiceless approximant | ||||
// keywords | // keywords | ||||
{ "phonemenumber", tSTATEMENT, kPHONEMENUMBER }, | { "phonemenumber", tSTATEMENT, kPHONEMENUMBER }, | ||||
{ "phonemetable", tSTATEMENT, kPHONEMETABLE }, | { "phonemetable", tSTATEMENT, kPHONEMETABLE }, | ||||
{ "endtype", tSTATEMENT, kENDTYPE }, | { "endtype", tSTATEMENT, kENDTYPE }, | ||||
{ "voicingswitch", tSTATEMENT, kVOICINGSWITCH }, | { "voicingswitch", tSTATEMENT, kVOICINGSWITCH }, | ||||
{ "IF", tSTATEMENT, kIF }, | { "IF", tSTATEMENT, kIF }, | ||||
{ "ELSE", tSTATEMENT, kELSE }, | { "ELSE", tSTATEMENT, kELSE }, | ||||
{ "ELIF", tSTATEMENT, kELIF }, | { "ELIF", tSTATEMENT, kELIF }, | ||||
{ "VowelEnding", tSTATEMENT, kVOWELENDING }, | { "VowelEnding", tSTATEMENT, kVOWELENDING }, | ||||
{ "addWav", tSTATEMENT, kANDWAV }, | { "addWav", tSTATEMENT, kANDWAV }, | ||||
{ "Vowelin", tSTATEMENT, kVOWELIN }, | { "Vowelin", tSTATEMENT, kVOWELIN }, | ||||
{ "Vowelout", tSTATEMENT, kVOWELOUT }, | { "Vowelout", tSTATEMENT, kVOWELOUT }, | ||||
{ "Continue", tSTATEMENT, kCONTINUE }, | { "Continue", tSTATEMENT, kCONTINUE }, | ||||
{ NULL, 0, -1 } | { NULL, 0, -1 } | ||||
}; | }; | ||||
static keywtab_t *keyword_tabs[] = { | static keywtab_t *keyword_tabs[] = { | ||||
keywords, k_conditions, k_properties, k_intonation | keywords, k_conditions, k_properties, k_intonation | ||||
}; | }; | ||||
static PHONEME_TAB *phoneme_out; | static PHONEME_TAB *phoneme_out; | ||||
static int n_phcodes_list[N_PHONEME_TABS]; | static int n_phcodes_list[N_PHONEME_TABS]; | ||||
static char *p_equivalence; | static char *p_equivalence; | ||||
static char equivalence_buf[20000]; | static char equivalence_buf[20000]; | ||||
#define N_PROCS 50 | #define N_PROCS 50 | ||||
int n_procs; | int n_procs; | ||||
int proc_addr[N_PROCS]; | int proc_addr[N_PROCS]; | ||||
fprintf(f_out, ")"); | fprintf(f_out, ")"); | ||||
} | } | ||||
break; | break; | ||||
case 2: | case 2: | ||||
case 3: | case 3: | ||||
if (type2 < 12) { | if (type2 < 12) { | ||||
} | } | ||||
fprintf(f_out, ")"); | fprintf(f_out, ")"); | ||||
break; | break; | ||||
case 6: | case 6: | ||||
fprintf(f_out, "%s", instn_jumps[(instn >> 9) & 7]); | fprintf(f_out, "%s", instn_jumps[(instn >> 9) & 7]); | ||||
fprintf(f_out, " %d", instn & 0x1ff); | fprintf(f_out, " %d", instn & 0x1ff); | ||||
break; | break; | ||||
case 9: | case 9: | ||||
address = ((data1 & 0xf) << 4) + *pc++; | address = ((data1 & 0xf) << 4) + *pc++; | ||||
fprintf(f_out, "CALL %.5x", address); | fprintf(f_out, "CALL %.5x", address); | ||||
break; | break; | ||||
case 10: | case 10: | ||||
fprintf(f_out, "%s", instn10_string[type2]); | fprintf(f_out, "%s", instn10_string[type2]); | ||||
switch (type2) | switch (type2) | ||||
break; | break; | ||||
} | } | ||||
break; | break; | ||||
case 11: | case 11: | ||||
case 12: | case 12: | ||||
case 13: | case 13: | ||||
} | } | ||||
} | } | ||||
static int n_phoneme_tabs; | static int n_phoneme_tabs; | ||||
static int n_phcodes; | static int n_phcodes; | ||||
static FILE *f_prog_log = NULL; | static FILE *f_prog_log = NULL; | ||||
static FILE *f_report; | static FILE *f_report; | ||||
static FILE *f_in; | static FILE *f_in; | ||||
static int f_in_linenum; | static int f_in_linenum; | ||||
static int f_in_displ; | static int f_in_displ; | ||||
static int linenum; | static int linenum; | ||||
static int count_references = 0; | static int count_references = 0; | ||||
static int duplicate_references = 0; | static int duplicate_references = 0; | ||||
static REF_HASH_TAB *ref_hash_tab[256]; | static REF_HASH_TAB *ref_hash_tab[256]; | ||||
#define N_ENVELOPES 30 | #define N_ENVELOPES 30 | ||||
int n_envelopes = 0; | int n_envelopes = 0; | ||||
char envelope_paths[N_ENVELOPES][80]; | char envelope_paths[N_ENVELOPES][80]; | ||||
unsigned char envelope_dat[N_ENVELOPES][ENV_LEN]; | unsigned char envelope_dat[N_ENVELOPES][ENV_LEN]; | ||||
typedef struct { | typedef struct { | ||||
FILE *file; | FILE *file; | ||||
int linenum; | int linenum; | ||||
} IF_STACK; | } IF_STACK; | ||||
IF_STACK if_stack[N_IF_STACK]; | IF_STACK if_stack[N_IF_STACK]; | ||||
enum { | enum { | ||||
tENDFILE = 1, | tENDFILE = 1, | ||||
tSTRING, | tSTRING, | ||||
#define N_ITEM_STRING 256 | #define N_ITEM_STRING 256 | ||||
char item_string[N_ITEM_STRING]; | char item_string[N_ITEM_STRING]; | ||||
static int ref_sorter(char **a, char **b) | static int ref_sorter(char **a, char **b) | ||||
{ | { | ||||
int ix; | int ix; | ||||
return p1->ph_mnemonic - p2->ph_mnemonic; | return p1->ph_mnemonic - p2->ph_mnemonic; | ||||
} | } | ||||
static void CompileReport(void) | static void CompileReport(void) | ||||
{ | { | ||||
int ix; | int ix; | ||||
fclose(f_report); | fclose(f_report); | ||||
} | } | ||||
static void error(const char *format, const char *string) | static void error(const char *format, const char *string) | ||||
{ | { | ||||
if (string == NULL) | if (string == NULL) | ||||
return f; | return f; | ||||
} | } | ||||
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 | ||||
return word; | return word; | ||||
} | } | ||||
static MNEM_TAB reserved_phonemes[] = { | static MNEM_TAB reserved_phonemes[] = { | ||||
{ "_\001", phonCONTROL }, // NOT USED | { "_\001", phonCONTROL }, // NOT USED | ||||
{ "%", phonSTRESS_U }, | { "%", phonSTRESS_U }, | ||||
{ NULL, 0 } | { NULL, 0 } | ||||
}; | }; | ||||
static void ReservePhCodes() | static void ReservePhCodes() | ||||
{ | { | ||||
// Reserve phoneme codes which have fixed numbers so that they can be | // Reserve phoneme codes which have fixed numbers so that they can be | ||||
} | } | ||||
} | } | ||||
static int LookupPhoneme(const char *string, int control) | static int LookupPhoneme(const char *string, int control) | ||||
{ | { | ||||
// control = 0 explicit declaration | // control = 0 explicit declaration | ||||
return use; | return use; | ||||
} | } | ||||
static unsigned int get_char() | static unsigned int get_char() | ||||
{ | { | ||||
unsigned int c; | unsigned int c; | ||||
linenum--; | linenum--; | ||||
} | } | ||||
int CheckNextChar() | int CheckNextChar() | ||||
{ | { | ||||
int c; | int c; | ||||
return c; | return c; | ||||
} | } | ||||
static int NextItem(int type) | static int NextItem(int type) | ||||
{ | { | ||||
int acc; | int acc; | ||||
return acc * sign; | return acc * sign; | ||||
} | } | ||||
if ((type >= tKEYWORD) && (type <= tINTONATION)) { | if ((type >= tKEYWORD) && (type <= tINTONATION)) { | ||||
pk = keyword_tabs[type-tKEYWORD]; | pk = keyword_tabs[type-tKEYWORD]; | ||||
while (pk->mnem != NULL) { | while (pk->mnem != NULL) { | ||||
return -1; | return -1; | ||||
} | } | ||||
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 | ||||
return value; | return value; | ||||
} | } | ||||
static int NextItemBrackets(int type, int control) | static int NextItemBrackets(int type, int control) | ||||
{ | { | ||||
// Expect a parameter inside parantheses | // Expect a parameter inside parantheses | ||||
if (item_terminator != ')') | if (item_terminator != ')') | ||||
error("Expected ')'", NULL); | error("Expected ')'", NULL); | ||||
return value; | return value; | ||||
} | } | ||||
static void UngetItem() | static void UngetItem() | ||||
{ | { | ||||
fseek(f_in, f_in_displ, SEEK_SET); | fseek(f_in, f_in_displ, SEEK_SET); | ||||
linenum = f_in_linenum; | linenum = f_in_linenum; | ||||
} | } | ||||
static int Range(int value, int divide, int min, int max) | static int Range(int value, int divide, int min, int max) | ||||
{ | { | ||||
if (value < 0) | if (value < 0) | ||||
return value - min; | return value - min; | ||||
} | } | ||||
int CompileVowelTransition(int which) | int CompileVowelTransition(int which) | ||||
{ | { | ||||
// Compile a vowel transition | // Compile a vowel transition | ||||
return 0; | return 0; | ||||
} | } | ||||
int LoadSpect(const char *path, int control) | int LoadSpect(const char *path, int control) | ||||
{ | { | ||||
SpectSeq *spectseq; | SpectSeq *spectseq; | ||||
return displ; | return displ; | ||||
} | } | ||||
static int LoadWavefile(FILE *f, const char *fname) | static int LoadWavefile(FILE *f, const char *fname) | ||||
{ | { | ||||
int displ; | int displ; | ||||
if (system(command) != 0) | if (system(command) != 0) | ||||
failed = 1; | failed = 1; | ||||
if (failed || (GetFileLength(fname_temp) <= 0)) { | if (failed || (GetFileLength(fname_temp) <= 0)) { | ||||
if (resample_fails < 2) | if (resample_fails < 2) | ||||
error("Resample command failed: %s", command); | error("Resample command failed: %s", command); | ||||
max = sample; | max = sample; | ||||
else if (sample < -max) | else if (sample < -max) | ||||
max = -sample; | max = -sample; | ||||
} | } | ||||
scale_factor = (max / 127) + 1; | scale_factor = (max / 127) + 1; | ||||
return displ | 0x800000; // set bit 23 to indicate a wave file rather than a spectrum | return displ | 0x800000; // set bit 23 to indicate a wave file rather than a spectrum | ||||
} | } | ||||
static int LoadEnvelope(FILE *f, const char *fname) | static int LoadEnvelope(FILE *f, const char *fname) | ||||
{ | { | ||||
int displ; | int displ; | ||||
return displ; | return displ; | ||||
} | } | ||||
/* Generate a hash code from the specified string */ | /* Generate a hash code from the specified string */ | ||||
static int Hash8(const char *string) | static int Hash8(const char *string) | ||||
{ | { | ||||
return (hash+chars) & 0xff; | return (hash+chars) & 0xff; | ||||
} | } | ||||
static int LoadEnvelope2(FILE *f, const char *fname) | static int LoadEnvelope2(FILE *f, const char *fname) | ||||
{ | { | ||||
int ix, ix2; | int ix, ix2; | ||||
env[x] = y; | env[x] = y; | ||||
} | } | ||||
if (n_envelopes < N_ENVELOPES) { | if (n_envelopes < N_ENVELOPES) { | ||||
strncpy0(envelope_paths[n_envelopes], fname, sizeof(envelope_paths[0])); | strncpy0(envelope_paths[n_envelopes], fname, sizeof(envelope_paths[0])); | ||||
memcpy(envelope_dat[n_envelopes], env, ENV_LEN); | memcpy(envelope_dat[n_envelopes], env, ENV_LEN); | ||||
return addr; | return addr; | ||||
} | } | ||||
static int CompileToneSpec(void) | static int CompileToneSpec(void) | ||||
{ | { | ||||
int pitch1 = 0; | int pitch1 = 0; | ||||
return 0; | return 0; | ||||
} | } | ||||
/* | /* | ||||
Condition | Condition | ||||
bits 14,15 1 | bits 14,15 1 | ||||
=8 data = stress bitmap | =8 data = stress bitmap | ||||
=9 special tests | =9 special tests | ||||
*/ | */ | ||||
int CompileIf(int elif) | int CompileIf(int elif) | ||||
{ | { | ||||
int key; | int key; | ||||
return 0; | return 0; | ||||
} | } | ||||
void FillThen(int add) | void FillThen(int add) | ||||
{ | { | ||||
USHORT *p; | USHORT *p; | ||||
then_count = 0; | then_count = 0; | ||||
} | } | ||||
int CompileElse(void) | int CompileElse(void) | ||||
{ | { | ||||
USHORT *ref; | USHORT *ref; | ||||
return 0; | return 0; | ||||
} | } | ||||
int CompileElif(void) | int CompileElif(void) | ||||
{ | { | ||||
if (if_level < 1) { | if (if_level < 1) { | ||||
return 0; | return 0; | ||||
} | } | ||||
int CompileEndif(void) | int CompileEndif(void) | ||||
{ | { | ||||
USHORT *p; | USHORT *p; | ||||
return 0; | return 0; | ||||
} | } | ||||
static int CompileSwitch(int type) | static int CompileSwitch(int type) | ||||
{ | { | ||||
// Type 0: EndSwitch | // Type 0: EndSwitch | ||||
return 0; | return 0; | ||||
} | } | ||||
static PHONEME_TAB_LIST *FindPhonemeTable(const char *string) | static PHONEME_TAB_LIST *FindPhonemeTable(const char *string) | ||||
{ | { | ||||
int ix; | int ix; | ||||
return NULL; | return NULL; | ||||
} | } | ||||
static PHONEME_TAB *FindPhoneme(const char *string) | static PHONEME_TAB *FindPhoneme(const char *string) | ||||
{ | { | ||||
PHONEME_TAB_LIST *phtab = NULL; | PHONEME_TAB_LIST *phtab = NULL; | ||||
return NULL; | return NULL; | ||||
} | } | ||||
static void ImportPhoneme(void) | static void ImportPhoneme(void) | ||||
{ | { | ||||
unsigned int ph_mnem; | unsigned int ph_mnem; | ||||
if (phoneme_out->type != phVOWEL) { | if (phoneme_out->type != phVOWEL) { | ||||
phoneme_out->end_type = 0; // voicingswitch, this must be set later to refer to a local phoneme | phoneme_out->end_type = 0; // voicingswitch, this must be set later to refer to a local phoneme | ||||
} | } | ||||
} | } | ||||
static void CallPhoneme(void) | static void CallPhoneme(void) | ||||
{ | { | ||||
PHONEME_TAB *ph; | PHONEME_TAB *ph; | ||||
*prog_out++ = addr; | *prog_out++ = addr; | ||||
} | } | ||||
static void DecThenCount() | static void DecThenCount() | ||||
{ | { | ||||
if (then_count > 0) | if (then_count > 0) | ||||
*prog_out++ = instn + phcode; | *prog_out++ = instn + phcode; | ||||
} | } | ||||
int CompilePhoneme(int compile_phoneme) | int CompilePhoneme(int compile_phoneme) | ||||
{ | { | ||||
int endphoneme = 0; | int endphoneme = 0; | ||||
error("More than one phoneme type: %s", item_string); | error("More than one phoneme type: %s", item_string); | ||||
phoneme_out->type = keyword; | phoneme_out->type = keyword; | ||||
break; | break; | ||||
case tPLACE: | case tPLACE: | ||||
if (place_articulation > 0) | if (place_articulation > 0) | ||||
error("Place of articulation has already been given: %s", item_string); | error("Place of articulation has already been given: %s", item_string); | ||||
place_articulation = keyword; | place_articulation = keyword; | ||||
break; | break; | ||||
case tPHONEME_FLAG: | case tPHONEME_FLAG: | ||||
phoneme_flags |= keyword; | phoneme_flags |= keyword; | ||||
break; | break; | ||||
case tINSTRN1: | case tINSTRN1: | ||||
// instruction group 0, with 8 bit operands which set data in PHONEME_DATA | // instruction group 0, with 8 bit operands which set data in PHONEME_DATA | ||||
switch (keyword) | switch (keyword) | ||||
InstnPlusPhoneme(keyword << 8); | InstnPlusPhoneme(keyword << 8); | ||||
DecThenCount(); | DecThenCount(); | ||||
break; | break; | ||||
case i_PAUSE_BEFORE: | case i_PAUSE_BEFORE: | ||||
value = NextItemMax(255); | value = NextItemMax(255); | ||||
*prog_out++ = (i_PAUSE_BEFORE << 8) + value; | *prog_out++ = (i_PAUSE_BEFORE << 8) + value; | ||||
DecThenCount(); | DecThenCount(); | ||||
break; | break; | ||||
case i_PAUSE_AFTER: | case i_PAUSE_AFTER: | ||||
value = NextItemMax(255); | value = NextItemMax(255); | ||||
*prog_out++ = (i_PAUSE_AFTER << 8) + value; | *prog_out++ = (i_PAUSE_AFTER << 8) + value; | ||||
DecThenCount(); | DecThenCount(); | ||||
break; | break; | ||||
case i_SET_LENGTH: | case i_SET_LENGTH: | ||||
value = NextItemMax(511); | value = NextItemMax(511); | ||||
if (phoneme_out->type == phVOWEL) | if (phoneme_out->type == phVOWEL) | ||||
DecThenCount(); | DecThenCount(); | ||||
} | } | ||||
break; | break; | ||||
case i_ADD_LENGTH: | case i_ADD_LENGTH: | ||||
value = NextItem(tSIGNEDNUMBER) / 2; | value = NextItem(tSIGNEDNUMBER) / 2; | ||||
*prog_out++ = (i_ADD_LENGTH << 8) + (value & 0xff); | *prog_out++ = (i_ADD_LENGTH << 8) + (value & 0xff); | ||||
DecThenCount(); | DecThenCount(); | ||||
break; | break; | ||||
case i_LENGTH_MOD: | case i_LENGTH_MOD: | ||||
value = NextItem(tNUMBER); | value = NextItem(tNUMBER); | ||||
phoneme_out->length_mod = value; | phoneme_out->length_mod = value; | ||||
break; | break; | ||||
case i_IPA_NAME: | case i_IPA_NAME: | ||||
NextItem(tSTRING); | NextItem(tSTRING); | ||||
break; | break; | ||||
} | } | ||||
break; | break; | ||||
case tSTATEMENT: | case tSTATEMENT: | ||||
switch (keyword) | switch (keyword) | ||||
{ | { | ||||
ImportPhoneme(); | ImportPhoneme(); | ||||
phoneme_flags = phoneme_out->phflags; | phoneme_flags = phoneme_out->phflags; | ||||
break; | break; | ||||
case kSTARTTYPE: | case kSTARTTYPE: | ||||
phcode = NextItem(tPHONEMEMNEM); | phcode = NextItem(tPHONEMEMNEM); | ||||
if (phcode == -1) | if (phcode == -1) | ||||
phcode = LookupPhoneme(item_string, 1); | phcode = LookupPhoneme(item_string, 1); | ||||
phoneme_out->start_type = phcode; | phoneme_out->start_type = phcode; | ||||
break; | break; | ||||
case kENDTYPE: | case kENDTYPE: | ||||
phcode = NextItem(tPHONEMEMNEM); | phcode = NextItem(tPHONEMEMNEM); | ||||
if (phcode == -1) | if (phcode == -1) | ||||
else if (phcode != phoneme_out->start_type) | else if (phcode != phoneme_out->start_type) | ||||
error("endtype must equal starttype for consonants", NULL); | error("endtype must equal starttype for consonants", NULL); | ||||
break; | break; | ||||
case kVOICINGSWITCH: | case kVOICINGSWITCH: | ||||
phcode = NextItem(tPHONEMEMNEM); | phcode = NextItem(tPHONEMEMNEM); | ||||
if (phcode == -1) | if (phcode == -1) | ||||
phcode = LookupPhoneme(item_string, 1); | phcode = LookupPhoneme(item_string, 1); | ||||
phoneme_out->end_type = phcode; // use end_type field for consonants as voicing_switch | phoneme_out->end_type = phcode; // use end_type field for consonants as voicing_switch | ||||
break; | break; | ||||
case kSTRESSTYPE: | case kSTRESSTYPE: | ||||
value = NextItem(tNUMBER); | value = NextItem(tNUMBER); | ||||
phoneme_out->std_length = value; | phoneme_out->std_length = value; | ||||
prog_out = prog_buf; | prog_out = prog_buf; | ||||
} | } | ||||
break; | break; | ||||
case kIF: | case kIF: | ||||
endphoneme = CompileIf(0); | endphoneme = CompileIf(0); | ||||
break; | break; | ||||
case kELSE: | case kELSE: | ||||
endphoneme = CompileElse(); | endphoneme = CompileElse(); | ||||
break; | break; | ||||
case kELIF: | case kELIF: | ||||
endphoneme = CompileElif(); | endphoneme = CompileElif(); | ||||
break; | break; | ||||
case kENDIF: | case kENDIF: | ||||
endphoneme = CompileEndif(); | endphoneme = CompileEndif(); | ||||
break; | break; | ||||
case kENDSWITCH: | case kENDSWITCH: | ||||
break; | break; | ||||
case kSWITCH_PREVVOWEL: | case kSWITCH_PREVVOWEL: | ||||
endphoneme = CompileSwitch(1); | endphoneme = CompileSwitch(1); | ||||
break; | break; | ||||
case kSWITCH_NEXTVOWEL: | case kSWITCH_NEXTVOWEL: | ||||
endphoneme = CompileSwitch(2); | endphoneme = CompileSwitch(2); | ||||
break; | break; | ||||
case kCALLPH: | case kCALLPH: | ||||
CallPhoneme(); | CallPhoneme(); | ||||
DecThenCount(); | DecThenCount(); | ||||
break; | break; | ||||
case kFMT: | case kFMT: | ||||
if_stack[if_level].returned = 1; | if_stack[if_level].returned = 1; | ||||
DecThenCount(); | DecThenCount(); | ||||
else | else | ||||
endphoneme = CompileSound(keyword, 0); | endphoneme = CompileSound(keyword, 0); | ||||
break; | break; | ||||
case kWAV: | case kWAV: | ||||
if_stack[if_level].returned = 1; | if_stack[if_level].returned = 1; | ||||
// fallthrough: | |||||
case kVOWELSTART: | case kVOWELSTART: | ||||
case kVOWELENDING: | case kVOWELENDING: | ||||
case kANDWAV: | case kANDWAV: | ||||
DecThenCount(); | DecThenCount(); | ||||
endphoneme = CompileSound(keyword, 0); | endphoneme = CompileSound(keyword, 0); | ||||
break; | break; | ||||
case kVOWELIN: | case kVOWELIN: | ||||
DecThenCount(); | DecThenCount(); | ||||
endphoneme = CompileVowelTransition(1); | endphoneme = CompileVowelTransition(1); | ||||
break; | break; | ||||
case kVOWELOUT: | case kVOWELOUT: | ||||
DecThenCount(); | DecThenCount(); | ||||
endphoneme = CompileVowelTransition(2); | endphoneme = CompileVowelTransition(2); | ||||
break; | break; | ||||
case kTONESPEC: | case kTONESPEC: | ||||
DecThenCount(); | DecThenCount(); | ||||
endphoneme = CompileToneSpec(); | endphoneme = CompileToneSpec(); | ||||
break; | break; | ||||
case kCONTINUE: | case kCONTINUE: | ||||
*prog_out++ = i_CONTINUE; | *prog_out++ = i_CONTINUE; | ||||
DecThenCount(); | DecThenCount(); | ||||
break; | break; | ||||
case kRETURN: | case kRETURN: | ||||
*prog_out++ = i_RETURN; | *prog_out++ = i_RETURN; | ||||
DecThenCount(); | DecThenCount(); | ||||
break; | break; | ||||
case kINCLUDE: | case kINCLUDE: | ||||
case kPHONEMENUMBER: | case kPHONEMENUMBER: | ||||
case kPHONEMETABLE: | case kPHONEMETABLE: | ||||
error("Missing 'endphoneme' before '%s'", item_string); // drop through to endphoneme | error("Missing 'endphoneme' before '%s'", item_string); // drop through to endphoneme | ||||
// fallthrough: | |||||
case kENDPHONEME: | case kENDPHONEME: | ||||
case kENDPROCEDURE: | case kENDPROCEDURE: | ||||
endphoneme = 1; | endphoneme = 1; | ||||
*prog_out++ = i_RETURN; | *prog_out++ = i_RETURN; | ||||
break; | break; | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
return 0; | return 0; | ||||
} | } | ||||
static void WritePhonemeTables() | static void WritePhonemeTables() | ||||
{ | { | ||||
int ix; | int ix; | ||||
} | } | ||||
} | } | ||||
static void EndPhonemeTable() | static void EndPhonemeTable() | ||||
{ | { | ||||
int ix; | int ix; | ||||
} | } | ||||
} | } | ||||
static void StartPhonemeTable(const char *name) | static void StartPhonemeTable(const char *name) | ||||
{ | { | ||||
int ix; | int ix; | ||||
n_phoneme_tabs++; | n_phoneme_tabs++; | ||||
} | } | ||||
static void CompileEquivalents() | static void CompileEquivalents() | ||||
{ | { | ||||
// 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 | ||||
p_start[3] = n_bytes; | p_start[3] = n_bytes; | ||||
} | } | ||||
static void CompilePhonemeFiles() | static void CompilePhonemeFiles() | ||||
{ | { | ||||
int item; | int item; | ||||
{ | { | ||||
case kUTF8_BOM: | case kUTF8_BOM: | ||||
break; // ignore bytes 0xef 0xbb 0xbf | break; // ignore bytes 0xef 0xbb 0xbf | ||||
case kINCLUDE: | case kINCLUDE: | ||||
NextItem(tSTRING); | NextItem(tSTRING); | ||||
sprintf(buf, "%s/../phsource/%s", path_home, item_string); | sprintf(buf, "%s/../phsource/%s", path_home, item_string); | ||||
f_in = f; | f_in = f; | ||||
strncpy0(current_fname, item_string, sizeof(current_fname)); | strncpy0(current_fname, item_string, sizeof(current_fname)); | ||||
linenum = 1; | linenum = 1; | ||||
} else | } else | ||||
error("Missing file: %s", item_string); | error("Missing file: %s", item_string); | ||||
break; | break; | ||||
case kPHONEMETABLE: | case kPHONEMETABLE: | ||||
EndPhonemeTable(); | EndPhonemeTable(); | ||||
NextItem(tSTRING); // name of the new phoneme table | NextItem(tSTRING); // name of the new phoneme table | ||||
StartPhonemeTable(item_string); | StartPhonemeTable(item_string); | ||||
break; | break; | ||||
case kPHONEMESTART: | case kPHONEMESTART: | ||||
if (n_phoneme_tabs == 0) { | if (n_phoneme_tabs == 0) { | ||||
Error("phonemetable is missing"); | Error("phonemetable is missing"); | ||||
} | } | ||||
CompilePhoneme(1); | CompilePhoneme(1); | ||||
break; | break; | ||||
case kPROCEDURE: | case kPROCEDURE: | ||||
CompilePhoneme(0); | CompilePhoneme(0); | ||||
break; | break; | ||||
case kEQUIVALENTS: | case kEQUIVALENTS: | ||||
CompileEquivalents(); | CompileEquivalents(); | ||||
break; | break; | ||||
default: | default: | ||||
if (!feof(f_in)) | if (!feof(f_in)) | ||||
Error("Keyword 'phoneme' expected"); | Error("Keyword 'phoneme' expected"); | ||||
phoneme_tab2[n_phcodes+1].mnemonic = 0; // terminator | phoneme_tab2[n_phcodes+1].mnemonic = 0; // terminator | ||||
} | } | ||||
static espeak_ng_STATUS CompilePhonemeData2(const char *source, FILE *log) | static espeak_ng_STATUS CompilePhonemeData2(const char *source, FILE *log) | ||||
{ | { | ||||
char fname[sizeof(path_home)+40]; | char fname[sizeof(path_home)+40]; | ||||
"# Address Data file\n" | "# Address Data file\n" | ||||
"# ------- ---------\n"); | "# ------- ---------\n"); | ||||
fprintf(f_errors, "Source data path = '%s/../phsource'\n", path_home); | fprintf(f_errors, "Source data path = '%s/../phsource'\n", path_home); | ||||
fprintf(f_errors, "Master phonemes file = '%s/../phsource/phonemes'\n", path_home); | fprintf(f_errors, "Master phonemes file = '%s/../phsource/phonemes'\n", path_home); | ||||
fprintf(f_errors, "Output to '%s/'\n\n", path_home); | fprintf(f_errors, "Output to '%s/'\n\n", path_home); | ||||
return ENS_OK; | return ENS_OK; | ||||
} | } | ||||
static const char *preset_tune_names[] = { | static const char *preset_tune_names[] = { | ||||
"s1", "c1", "q1", "e1", NULL | "s1", "c1", "q1", "e1", NULL | ||||
}; | }; | ||||
return LookupMnem(envelope_names, name); | return LookupMnem(envelope_names, name); | ||||
} | } | ||||
#pragma GCC visibility push(default) | #pragma GCC visibility push(default) | ||||
espeak_ng_STATUS espeak_ng_CompileIntonation(FILE *log) | espeak_ng_STATUS espeak_ng_CompileIntonation(FILE *log) | ||||
TUNE *tune_data; | TUNE *tune_data; | ||||
TUNE new_tune; | TUNE new_tune; | ||||
char name[12]; | char name[12]; | ||||
char tune_names[N_TUNE_NAMES][12]; | char tune_names[N_TUNE_NAMES][12]; | ||||
char buf[sizeof(path_home)+150]; | char buf[sizeof(path_home)+150]; | ||||
} | } | ||||
} | } | ||||
for (ix = 0; preset_tune_names[ix] != NULL; ix++) { | for (ix = 0; preset_tune_names[ix] != NULL; ix++) { | ||||
strcpy(tune_names[ix], preset_tune_names[ix]); | strcpy(tune_names[ix], preset_tune_names[ix]); | ||||
} | } | ||||
if (found == 0) | if (found == 0) | ||||
error("Bad tune name: '%s;", new_tune.name); | error("Bad tune name: '%s;", new_tune.name); | ||||
break; | break; | ||||
case kENDTUNE: | case kENDTUNE: | ||||
compiling_tune = 0; | compiling_tune = 0; | ||||
} | } | ||||
memcpy(&tune_data[tune_number], &new_tune, sizeof(TUNE)); | memcpy(&tune_data[tune_number], &new_tune, sizeof(TUNE)); | ||||
break; | break; | ||||
case kTUNE_PREHEAD: | case kTUNE_PREHEAD: | ||||
new_tune.prehead_start = NextItem(tNUMBER); | new_tune.prehead_start = NextItem(tNUMBER); | ||||
new_tune.prehead_end = NextItem(tNUMBER); | new_tune.prehead_end = NextItem(tNUMBER); | ||||
break; | break; | ||||
case kTUNE_ONSET: | case kTUNE_ONSET: | ||||
new_tune.onset = NextItem(tNUMBER); | new_tune.onset = NextItem(tNUMBER); | ||||
new_tune.unstr_start[0] = NextItem(tSIGNEDNUMBER); | new_tune.unstr_start[0] = NextItem(tSIGNEDNUMBER); | ||||
new_tune.unstr_end[0] = NextItem(tSIGNEDNUMBER); | new_tune.unstr_end[0] = NextItem(tSIGNEDNUMBER); | ||||
done_onset = 1; | done_onset = 1; | ||||
break; | break; | ||||
case kTUNE_HEADLAST: | case kTUNE_HEADLAST: | ||||
new_tune.head_last = NextItem(tNUMBER); | new_tune.head_last = NextItem(tNUMBER); | ||||
new_tune.unstr_start[2] = NextItem(tSIGNEDNUMBER); | new_tune.unstr_start[2] = NextItem(tSIGNEDNUMBER); | ||||
new_tune.unstr_end[2] = NextItem(tSIGNEDNUMBER); | new_tune.unstr_end[2] = NextItem(tSIGNEDNUMBER); | ||||
done_last = 1; | done_last = 1; | ||||
break; | break; | ||||
case kTUNE_HEADENV: | case kTUNE_HEADENV: | ||||
NextItem(tSTRING); | NextItem(tSTRING); | ||||
if ((ix = LookupEnvelopeName(item_string)) < 0) | if ((ix = LookupEnvelopeName(item_string)) < 0) | ||||
new_tune.stressed_env = ix; | new_tune.stressed_env = ix; | ||||
new_tune.stressed_drop = NextItem(tNUMBER); | new_tune.stressed_drop = NextItem(tNUMBER); | ||||
break; | break; | ||||
case kTUNE_HEAD: | case kTUNE_HEAD: | ||||
new_tune.head_max_steps = NextItem(tNUMBER); | new_tune.head_max_steps = NextItem(tNUMBER); | ||||
new_tune.head_start = NextItem(tNUMBER); | new_tune.head_start = NextItem(tNUMBER); | ||||
new_tune.unstr_start[1] = NextItem(tSIGNEDNUMBER); | new_tune.unstr_start[1] = NextItem(tSIGNEDNUMBER); | ||||
new_tune.unstr_end[1] = NextItem(tSIGNEDNUMBER); | new_tune.unstr_end[1] = NextItem(tSIGNEDNUMBER); | ||||
break; | break; | ||||
case kTUNE_HEADEXTEND: | case kTUNE_HEADEXTEND: | ||||
// up to 8 numbers | // up to 8 numbers | ||||
for (ix = 0; ix < (int)(sizeof(new_tune.head_extend)); ix++) { | for (ix = 0; ix < (int)(sizeof(new_tune.head_extend)); ix++) { | ||||
} | } | ||||
new_tune.n_head_extend = ix; // number of values | new_tune.n_head_extend = ix; // number of values | ||||
break; | break; | ||||
case kTUNE_NUCLEUS0: | case kTUNE_NUCLEUS0: | ||||
NextItem(tSTRING); | NextItem(tSTRING); | ||||
if ((ix = LookupEnvelopeName(item_string)) < 0) { | if ((ix = LookupEnvelopeName(item_string)) < 0) { | ||||
new_tune.nucleus0_max = NextItem(tNUMBER); | new_tune.nucleus0_max = NextItem(tNUMBER); | ||||
new_tune.nucleus0_min = NextItem(tNUMBER); | new_tune.nucleus0_min = NextItem(tNUMBER); | ||||
break; | break; | ||||
case kTUNE_NUCLEUS1: | case kTUNE_NUCLEUS1: | ||||
NextItem(tSTRING); | NextItem(tSTRING); | ||||
if ((ix = LookupEnvelopeName(item_string)) < 0) { | if ((ix = LookupEnvelopeName(item_string)) < 0) { | ||||
new_tune.split_tail_end = new_tune.tail_end; | new_tune.split_tail_end = new_tune.tail_end; | ||||
} | } | ||||
break; | break; | ||||
case kTUNE_SPLIT: | case kTUNE_SPLIT: | ||||
NextItem(tSTRING); | NextItem(tSTRING); | ||||
if ((ix = LookupEnvelopeName(item_string)) < 0) { | if ((ix = LookupEnvelopeName(item_string)) < 0) { | ||||
else | else | ||||
new_tune.split_tune = ix; | new_tune.split_tune = ix; | ||||
break; | break; | ||||
default: | default: | ||||
error("Unexpected: '%s'", item_string); | error("Unexpected: '%s'", item_string); | ||||
break; | break; | ||||
return error_count > 0 ? ENE_COMPILE_ERRORS : ENS_OK; | return error_count > 0 ? ENE_COMPILE_ERRORS : ENS_OK; | ||||
} | } | ||||
espeak_ng_STATUS espeak_ng_CompilePhonemeData(long rate, FILE *log) | espeak_ng_STATUS espeak_ng_CompilePhonemeData(long rate, FILE *log) | ||||
{ | { | ||||
if (!log) log = stderr; | if (!log) log = stderr; |
{ "$u2+", 0x4e }, | { "$u2+", 0x4e }, | ||||
{ "$u3+", 0x4f }, | { "$u3+", 0x4f }, | ||||
// these set the corresponding numbered bit if dictionary_flags | // these set the corresponding numbered bit if dictionary_flags | ||||
{ "$pause", 8 }, // ensure pause before this word | { "$pause", 8 }, // ensure pause before this word | ||||
{ "$strend", 9 }, // full stress if at end of clause | { "$strend", 9 }, // full stress if at end of clause | ||||
{ NULL, -1 } | { NULL, -1 } | ||||
}; | }; | ||||
#define LEN_GROUP_NAME 12 | #define LEN_GROUP_NAME 12 | ||||
typedef struct { | typedef struct { | ||||
int group3_ix; | int group3_ix; | ||||
} RGROUP; | } RGROUP; | ||||
int isspace2(unsigned int c) | int isspace2(unsigned int c) | ||||
{ | { | ||||
// can't use isspace() because on Windows, isspace(0xe1) gives TRUE ! | // can't use isspace() because on Windows, isspace(0xe1) gives TRUE ! | ||||
return 1; | return 1; | ||||
} | } | ||||
static FILE *fopen_log(const char *fname, const char *access) | static FILE *fopen_log(const char *fname, const char *access) | ||||
{ | { | ||||
// performs fopen, but produces error message to f_log if it fails | // performs fopen, but produces error message to f_log if it fails | ||||
return f; | return f; | ||||
} | } | ||||
/* Lookup a mnemonic string in a table, return its name */ | /* Lookup a mnemonic string in a table, return its name */ | ||||
const char *LookupMnemName(MNEM_TAB *table, const int value) | const char *LookupMnemName(MNEM_TAB *table, const int value) | ||||
{ | { | ||||
return ""; /* not found */ | return ""; /* not found */ | ||||
} | } | ||||
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; | ||||
} | } | ||||
} | } | ||||
char *DecodeRule(const char *group_chars, int group_length, char *rule, int control) | char *DecodeRule(const char *group_chars, int group_length, char *rule, int control) | ||||
{ | { | ||||
/* Convert compiled match template to ascii */ | /* Convert compiled match template to ascii */ | ||||
return output; | return output; | ||||
} | } | ||||
static int compile_line(char *linebuf, char *dict_line, int *hash) | static int compile_line(char *linebuf, char *dict_line, int *hash) | ||||
{ | { | ||||
// Compile a line in the language_list file | // Compile a line in the language_list file | ||||
step = 1; | step = 1; | ||||
} | } | ||||
break; | break; | ||||
case 1: | case 1: | ||||
if ((c == '-') && multiple_words) { | if ((c == '-') && multiple_words) { | ||||
if (IsDigit09(word[0])) | if (IsDigit09(word[0])) | ||||
} | } | ||||
} | } | ||||
break; | break; | ||||
case 2: | case 2: | ||||
if (isspace2(c)) | if (isspace2(c)) | ||||
multiple_words++; | multiple_words++; | ||||
step = 3; | step = 3; | ||||
} | } | ||||
break; | break; | ||||
case 3: | case 3: | ||||
if (!isspace2(c)) { | if (!isspace2(c)) { | ||||
phonetic = p; | phonetic = p; | ||||
step = 4; | step = 4; | ||||
} | } | ||||
break; | break; | ||||
case 4: | case 4: | ||||
if (isspace2(c)) { | if (isspace2(c)) { | ||||
p[0] = 0; /* terminate phonetic */ | p[0] = 0; /* terminate phonetic */ | ||||
step = 5; | step = 5; | ||||
} | } | ||||
break; | break; | ||||
case 5: | case 5: | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
dict_line[0] = length; | dict_line[0] = length; | ||||
return length; | return length; | ||||
} | } | ||||
static void compile_dictlist_start(void) | static void compile_dictlist_start(void) | ||||
{ | { | ||||
// initialise dictionary list | // initialise dictionary list | ||||
} | } | ||||
} | } | ||||
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 | ||||
} | } | ||||
} | } | ||||
static int compile_dictlist_file(const char *path, const char *filename) | static int compile_dictlist_file(const char *path, const char *filename) | ||||
{ | { | ||||
int length; | int length; | ||||
return 0; | return 0; | ||||
} | } | ||||
static char rule_cond[80]; | static char rule_cond[80]; | ||||
static char rule_pre[80]; | static char rule_pre[80]; | ||||
static char rule_post[80]; | static char rule_post[80]; | ||||
#define N_RULES 3000 // max rules for each group | #define N_RULES 3000 // max rules for each group | ||||
int isHexDigit(int c) | int isHexDigit(int c) | ||||
{ | { | ||||
if ((c >= '0') && (c <= '9')) | if ((c >= '0') && (c <= '9')) | ||||
return -1; | return -1; | ||||
} | } | ||||
static void copy_rule_string(char *string, int *state_out) | static void copy_rule_string(char *string, int *state_out) | ||||
{ | { | ||||
// state 0: conditional, 1=pre, 2=match, 3=post, 4=phonemes | // state 0: conditional, 1=pre, 2=match, 3=post, 4=phonemes | ||||
} else | } else | ||||
output[ix++] = RULE_LETTERGP2; | output[ix++] = RULE_LETTERGP2; | ||||
break; | break; | ||||
case '$': | case '$': | ||||
value = 0; | value = 0; | ||||
mr = mnem_rules; | mr = mnem_rules; | ||||
error_count++; | error_count++; | ||||
} | } | ||||
break; | break; | ||||
case 'P': | case 'P': | ||||
sxflags |= SUFX_P; // Prefix, now drop through to Suffix | sxflags |= SUFX_P; // Prefix, now drop through to Suffix | ||||
// fallthrough | |||||
case 'S': | case 'S': | ||||
output[ix++] = RULE_ENDING; | output[ix++] = RULE_ENDING; | ||||
value = 0; | value = 0; | ||||
*state_out = next_state[state]; | *state_out = next_state[state]; | ||||
} | } | ||||
static char *compile_rule(char *input) | static char *compile_rule(char *input) | ||||
{ | { | ||||
int ix; | int ix; | ||||
copy_rule_string(buf, &state); | copy_rule_string(buf, &state); | ||||
p = buf; | p = buf; | ||||
break; | break; | ||||
case '(': // start of suffix section | case '(': // start of suffix section | ||||
*p = 0; | *p = 0; | ||||
state = 2; | state = 2; | ||||
error_count++; | error_count++; | ||||
} | } | ||||
break; | break; | ||||
case '\n': // end of line | case '\n': // end of line | ||||
case '\r': | case '\r': | ||||
case 0: // end of line | case 0: // end of line | ||||
copy_rule_string(buf, &state); | copy_rule_string(buf, &state); | ||||
finish = 1; | finish = 1; | ||||
break; | break; | ||||
case '\t': // end of section section | case '\t': // end of section section | ||||
case ' ': | case ' ': | ||||
*p = 0; | *p = 0; | ||||
copy_rule_string(buf, &state); | copy_rule_string(buf, &state); | ||||
p = buf; | p = buf; | ||||
break; | break; | ||||
case '?': | case '?': | ||||
if (state == 2) | if (state == 2) | ||||
state = 0; | state = 0; | ||||
else | else | ||||
*p++ = c; | *p++ = c; | ||||
break; | break; | ||||
default: | default: | ||||
*p++ = c; | *p++ = c; | ||||
break; | break; | ||||
return prule; | return prule; | ||||
} | } | ||||
int __cdecl string_sorter(char **a, char **b) | int __cdecl string_sorter(char **a, char **b) | ||||
{ | { | ||||
char *pa, *pb; | char *pa, *pb; | ||||
return strcmp(pa, pb); | return strcmp(pa, pb); | ||||
} | } | ||||
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 | ||||
return a->start-b->start; | return a->start-b->start; | ||||
} | } | ||||
#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) | ||||
{ | { | ||||
} | } | ||||
#endif | #endif | ||||
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 ix; | ||||
#endif | #endif | ||||
} | } | ||||
static int compile_lettergroup(char *input, FILE *f_out) | static int compile_lettergroup(char *input, FILE *f_out) | ||||
{ | { | ||||
char *p; | char *p; | ||||
return 0; | return 0; | ||||
} | } | ||||
static int compile_dictrules(FILE *f_in, FILE *f_out, char *fname_temp) | static int compile_dictrules(FILE *f_in, FILE *f_out, char *fname_temp) | ||||
{ | { | ||||
char *prule; | char *prule; | ||||
} | } | ||||
break; | break; | ||||
case 2: // .replace | case 2: // .replace | ||||
{ | { | ||||
int replace1; | int replace1; | ||||
return 0; | return 0; | ||||
} | } | ||||
int CompileDictionary(const char *dsource, const char *dict_name, FILE *log, char *fname_err, int flags) | int CompileDictionary(const char *dsource, const char *dict_name, FILE *log, char *fname_err, int flags) | ||||
{ | { | ||||
// fname: space to write the filename in case of error | // fname: space to write the filename in case of error |
#include "synthesize.h" | #include "synthesize.h" | ||||
#include "translate.h" | #include "translate.h" | ||||
int dictionary_skipwords; | int dictionary_skipwords; | ||||
char dictionary_name[40]; | char dictionary_name[40]; | ||||
'a', 'a', 'a', 'b', 'o', 'c', 'd', 'd', 'e', 'e', 'e', 'e', 'e', 'e' | 'a', 'a', 'a', 'b', 'o', 'c', 'd', 'd', 'e', 'e', 'e', 'e', 'e', 'e' | ||||
}; | }; | ||||
#pragma GCC visibility push(default) | #pragma GCC visibility push(default) | ||||
void strncpy0(char *to, const char *from, int size) | void strncpy0(char *to, const char *from, int size) | ||||
{ | { | ||||
} | } | ||||
#pragma GCC visibility pop | #pragma GCC visibility pop | ||||
int Reverse4Bytes(int word) | int Reverse4Bytes(int word) | ||||
{ | { | ||||
// reverse the order of bytes from little-endian to big-endian | // reverse the order of bytes from little-endian to big-endian | ||||
#endif | #endif | ||||
} | } | ||||
int LookupMnem(MNEM_TAB *table, const char *string) | int LookupMnem(MNEM_TAB *table, const char *string) | ||||
{ | { | ||||
while (table->mnem != NULL) { | while (table->mnem != NULL) { | ||||
return table->value; | return table->value; | ||||
} | } | ||||
static void InitGroups(Translator *tr) | static void InitGroups(Translator *tr) | ||||
{ | { | ||||
// Called after dictionary 1 is loaded, to set up table of entry points for translation rule chains | // Called after dictionary 1 is loaded, to set up table of entry points for translation rule chains | ||||
// for single-letters and two-letter combinations | // for single-letters and two-letter combinations | ||||
int ix; | int ix; | ||||
char *p; | char *p; | ||||
char *p_name; | char *p_name; | ||||
p += (strlen(p) + 1); | p += (strlen(p) + 1); | ||||
p++; | p++; | ||||
} | } | ||||
} | } | ||||
int LoadDictionary(Translator *tr, const char *name, int no_error) | int LoadDictionary(Translator *tr, const char *name, int no_error) | ||||
{ | { | ||||
int hash; | int hash; | ||||
size = fread(tr->data_dictlist, 1, size, f); | size = fread(tr->data_dictlist, 1, size, f); | ||||
fclose(f); | fclose(f); | ||||
pw = (int *)(tr->data_dictlist); | pw = (int *)(tr->data_dictlist); | ||||
length = Reverse4Bytes(pw[1]); | length = Reverse4Bytes(pw[1]); | ||||
return 0; | return 0; | ||||
} | } | ||||
/* Generate a hash code from the specified string | /* Generate a hash code from the specified string | ||||
This is used to access the dictionary_2 word-lookup dictionary | This is used to access the dictionary_2 word-lookup dictionary | ||||
*/ | */ | ||||
return (hash+chars) & 0x3ff; // a 10 bit hash code | return (hash+chars) & 0x3ff; // a 10 bit hash code | ||||
} | } | ||||
/* Translate a phoneme string from ascii mnemonics to internal phoneme numbers, | /* Translate a phoneme string from ascii mnemonics to internal phoneme numbers, | ||||
from 'p' up to next blank . | from 'p' up to next blank . | ||||
Returns advanced 'p' | Returns advanced 'p' | ||||
p++; | p++; | ||||
break; | break; | ||||
} | } | ||||
default: | default: | ||||
// lookup the phoneme mnemonic, find the phoneme with the highest number of | // lookup the phoneme mnemonic, find the phoneme with the highest number of | ||||
// matching characters | // matching characters | ||||
return p; | return p; | ||||
} | } | ||||
void DecodePhonemes(const char *inptr, char *outptr) | void DecodePhonemes(const char *inptr, char *outptr) | ||||
{ | { | ||||
// Translate from internal phoneme codes into phoneme mnemonics | // Translate from internal phoneme codes into phoneme mnemonics | ||||
*outptr = 0; /* string terminator */ | *outptr = 0; /* string terminator */ | ||||
} | } | ||||
// using Kirschenbaum to IPA translation, ascii 0x20 to 0x7f | // using Kirschenbaum to IPA translation, ascii 0x20 to 0x7f | ||||
unsigned short ipa1[96] = { | unsigned short ipa1[96] = { | ||||
0x20, 0x21, 0x22, 0x2b0, 0x24, 0x25, 0x0e6, 0x2c8, 0x28, 0x29, 0x27e, 0x2b, 0x2cc, 0x2d, 0x2e, 0x2f, | 0x20, 0x21, 0x22, 0x2b0, 0x24, 0x25, 0x0e6, 0x2c8, 0x28, 0x29, 0x27e, 0x2b, 0x2cc, 0x2d, 0x2e, 0x2f, | ||||
static char *phon_out_buf = NULL; // passes the result of GetTranslatedPhonemeString() | static char *phon_out_buf = NULL; // passes the result of GetTranslatedPhonemeString() | ||||
static unsigned int phon_out_size = 0; | static unsigned int phon_out_size = 0; | ||||
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; | ||||
return phon_out; | return phon_out; | ||||
} | } | ||||
const char *GetTranslatedPhonemeString(int phoneme_mode) | const char *GetTranslatedPhonemeString(int phoneme_mode) | ||||
{ | { | ||||
/* Called after a clause has been translated into phonemes, in order | /* Called after a clause has been translated into phonemes, in order | ||||
use_tie = 0; | use_tie = 0; | ||||
} | } | ||||
for (ix = 1; ix < (n_phoneme_list-2); ix++) { | for (ix = 1; ix < (n_phoneme_list-2); ix++) { | ||||
buf = phon_buf; | buf = phon_buf; | ||||
return phon_out_buf; | return phon_out_buf; | ||||
} | } | ||||
static int IsLetterGroup(Translator *tr, char *word, int group, int pre) | static int IsLetterGroup(Translator *tr, char *word, int group, int pre) | ||||
{ | { | ||||
// match the word against a list of utf-8 strings | // match the word against a list of utf-8 strings | ||||
return 0; | return 0; | ||||
} | } | ||||
static int IsLetter(Translator *tr, int letter, int group) | static int IsLetter(Translator *tr, int letter, int group) | ||||
{ | { | ||||
int letter2; | int letter2; | ||||
return 0; | return 0; | ||||
} | } | ||||
int IsVowel(Translator *tr, int letter) | int IsVowel(Translator *tr, int letter) | ||||
{ | { | ||||
return IsLetter(tr, letter, LETTERGP_VOWEL2); | return IsLetter(tr, letter, LETTERGP_VOWEL2); | ||||
} | } | ||||
static int Unpronouncable2(Translator *tr, char *word) | static int Unpronouncable2(Translator *tr, char *word) | ||||
{ | { | ||||
int c; | int c; | ||||
return 0; | return 0; | ||||
} | } | ||||
int Unpronouncable(Translator *tr, char *word, int posn) | int Unpronouncable(Translator *tr, char *word, int posn) | ||||
{ | { | ||||
/* Determines whether a word in 'unpronouncable', i.e. whether it should | /* Determines whether a word in 'unpronouncable', i.e. whether it should | ||||
return 1; // no vowel, or no vowel in first few letters | return 1; // no vowel, or no vowel in first few letters | ||||
return 0; | return 0; | ||||
} | } | ||||
static int GetVowelStress(Translator *tr, unsigned char *phonemes, signed char *vowel_stress, int *vowel_count, int *stressed_syllable, int control) | static int GetVowelStress(Translator *tr, unsigned char *phonemes, signed char *vowel_stress, int *vowel_count, int *stressed_syllable, int control) | ||||
{ | { | ||||
// control = 1, set stress to 1 for forced unstressed vowels | // control = 1, set stress to 1 for forced unstressed vowels | ||||
return max_stress; | return max_stress; | ||||
} | } | ||||
static char stress_phonemes[] = { phonSTRESS_D, phonSTRESS_U, phonSTRESS_2, phonSTRESS_3, | static char stress_phonemes[] = { phonSTRESS_D, phonSTRESS_U, phonSTRESS_2, phonSTRESS_3, | ||||
phonSTRESS_P, phonSTRESS_P2, phonSTRESS_TONIC }; | phonSTRESS_P, phonSTRESS_P2, phonSTRESS_TONIC }; | ||||
void ChangeWordStress(Translator *tr, char *word, int new_stress) | void ChangeWordStress(Translator *tr, char *word, int new_stress) | ||||
{ | { | ||||
int ix; | int ix; | ||||
*word = 0; | *word = 0; | ||||
} | } | ||||
void SetWordStress(Translator *tr, char *output, unsigned int *dictionary_flags, int tonic, int control) | void SetWordStress(Translator *tr, char *output, unsigned int *dictionary_flags, int tonic, int control) | ||||
{ | { | ||||
/* Guess stress pattern of word. This is language specific | /* Guess stress pattern of word. This is language specific | ||||
static char consonant_types[16] = { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0 }; | static char consonant_types[16] = { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0 }; | ||||
/* stress numbers STRESS_BASE + | /* stress numbers STRESS_BASE + | ||||
0 diminished, unstressed within a word | 0 diminished, unstressed within a word | ||||
1 unstressed, weak | 1 unstressed, weak | ||||
} | } | ||||
} | } | ||||
switch (tr->langopts.stress_rule) | switch (tr->langopts.stress_rule) | ||||
{ | { | ||||
case 8: | case 8: | ||||
// stress on first syllable, unless it is a light syllable followed by a heavy syllable | // stress on first syllable, unless it is a light syllable followed by a heavy syllable | ||||
if ((syllable_weight[1] > 0) || (syllable_weight[2] == 0)) | if ((syllable_weight[1] > 0) || (syllable_weight[2] == 0)) | ||||
break; | break; | ||||
// else drop through to case 1 | |||||
// fallthrough | |||||
case 1: | case 1: | ||||
// stress on second syllable | // stress on second syllable | ||||
if ((stressed_syllable == 0) && (vowel_count > 2)) { | if ((stressed_syllable == 0) && (vowel_count > 2)) { | ||||
max_stress = 4; | max_stress = 4; | ||||
} | } | ||||
break; | break; | ||||
case 10: // penultimate, but final if only 1 or 2 syllables | case 10: // penultimate, but final if only 1 or 2 syllables | ||||
if (stressed_syllable == 0) { | if (stressed_syllable == 0) { | ||||
if (vowel_count < 4) { | if (vowel_count < 4) { | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
// drop through to next case | |||||
// fallthrough | |||||
case 2: | case 2: | ||||
// a language with stress on penultimate vowel | // a language with stress on penultimate vowel | ||||
} | } | ||||
} | } | ||||
break; | break; | ||||
case 3: | case 3: | ||||
// stress on last vowel | // stress on last vowel | ||||
if (stressed_syllable == 0) { | if (stressed_syllable == 0) { | ||||
max_stress = 4; | max_stress = 4; | ||||
} | } | ||||
break; | break; | ||||
case 4: // stress on antipenultimate vowel | case 4: // stress on antipenultimate vowel | ||||
if (stressed_syllable == 0) { | if (stressed_syllable == 0) { | ||||
stressed_syllable = vowel_count - 3; | stressed_syllable = vowel_count - 3; | ||||
max_stress = 4; | max_stress = 4; | ||||
} | } | ||||
break; | break; | ||||
case 5: | case 5: | ||||
// LANG=Russian | // LANG=Russian | ||||
if (stressed_syllable == 0) { | if (stressed_syllable == 0) { | ||||
max_stress = 4; | max_stress = 4; | ||||
} | } | ||||
break; | break; | ||||
case 6: // LANG=hi stress on the last heaviest syllable | case 6: // LANG=hi stress on the last heaviest syllable | ||||
if (stressed_syllable == 0) { | if (stressed_syllable == 0) { | ||||
int wt; | int wt; | ||||
max_stress = 4; | max_stress = 4; | ||||
} | } | ||||
break; | break; | ||||
case 7: // LANG=tr, the last syllable for any vowel marked explicitly as unstressed | case 7: // LANG=tr, the last syllable for any vowel marked explicitly as unstressed | ||||
if (stressed_syllable == 0) { | if (stressed_syllable == 0) { | ||||
stressed_syllable = vowel_count - 1; | stressed_syllable = vowel_count - 1; | ||||
max_stress = 4; | max_stress = 4; | ||||
} | } | ||||
break; | break; | ||||
case 9: // mark all as stressed | case 9: // mark all as stressed | ||||
for (ix = 1; ix < vowel_count; ix++) { | for (ix = 1; ix < vowel_count; ix++) { | ||||
if (vowel_stress[ix] < 0) | if (vowel_stress[ix] < 0) | ||||
vowel_stress[ix] = 4; | vowel_stress[ix] = 4; | ||||
} | } | ||||
break; | break; | ||||
case 12: // LANG=kl (Greenlandic) | case 12: // LANG=kl (Greenlandic) | ||||
long_vowel = 0; | long_vowel = 0; | ||||
for (ix = 1; ix < vowel_count; ix++) { | for (ix = 1; ix < vowel_count; ix++) { | ||||
vowel_stress[stressed_syllable] = 4; | vowel_stress[stressed_syllable] = 4; | ||||
max_stress = 4; | max_stress = 4; | ||||
break; | break; | ||||
case 13: // LANG=ml, 1st unless 1st vowel is short and 2nd is long | case 13: // LANG=ml, 1st unless 1st vowel is short and 2nd is long | ||||
if (stressed_syllable == 0) { | if (stressed_syllable == 0) { | ||||
stressed_syllable = 1; | stressed_syllable = 1; | ||||
else | else | ||||
stress = 3; | stress = 3; | ||||
if (unstressed_word == 0) { | if (unstressed_word == 0) { | ||||
if ((stressflags & S_2_SYL_2) && (vowel_count == 3)) { | if ((stressflags & S_2_SYL_2) && (vowel_count == 3)) { | ||||
// Two syllable word, if one syllable has primary stress, then give the other secondary stress | // Two syllable word, if one syllable has primary stress, then give the other secondary stress | ||||
max_stress = tonic; | max_stress = tonic; | ||||
} | } | ||||
/* produce output phoneme string */ | /* produce output phoneme string */ | ||||
p = phonetic; | p = phonetic; | ||||
v = 1; | v = 1; | ||||
if (!(control & 1) && ((ph = phoneme_tab[*p]) != NULL)) { | if (!(control & 1) && ((ph = phoneme_tab[*p]) != NULL)) { | ||||
while ((ph->type == phSTRESS) || (*p == phonEND_WORD)) { | while ((ph->type == phSTRESS) || (*p == phonEND_WORD)) { | ||||
p++; | p++; | ||||
ph = phoneme_tab[p[0]]; | ph = phoneme_tab[p[0]]; | ||||
return; | return; | ||||
} | } | ||||
void AppendPhonemes(Translator *tr, char *string, int size, const char *ph) | void AppendPhonemes(Translator *tr, char *string, int size, const char *ph) | ||||
{ | { | ||||
/* Add new phoneme string "ph" to "string" | /* Add new phoneme string "ph" to "string" | ||||
strcat(string, ph); | strcat(string, ph); | ||||
} | } | ||||
static void MatchRule(Translator *tr, char *word[], char *word_start, int group_length, char *rule, MatchRecord *match_out, int word_flags, int dict_flags) | static void MatchRule(Translator *tr, char *word[], char *word_start, int group_length, char *rule, MatchRecord *match_out, int word_flags, int dict_flags) | ||||
{ | { | ||||
/* Checks a specified word against dictionary rules. | /* Checks a specified word against dictionary rules. | ||||
return; | return; | ||||
} | } | ||||
total_consumed = 0; | total_consumed = 0; | ||||
common_phonemes = NULL; | common_phonemes = NULL; | ||||
match_type = 0; | match_type = 0; | ||||
rule--; // so we are still pointing at the 0 | rule--; // so we are still pointing at the 0 | ||||
failed = 2; // matched OK | failed = 2; // matched OK | ||||
break; | break; | ||||
case RULE_PRE_ATSTART: // pre rule with implied 'start of word' | case RULE_PRE_ATSTART: // pre rule with implied 'start of word' | ||||
check_atstart = 1; | check_atstart = 1; | ||||
unpron_ignore = 0; | unpron_ignore = 0; | ||||
match_type = RULE_PRE; | match_type = RULE_PRE; | ||||
break; | break; | ||||
case RULE_PRE: | case RULE_PRE: | ||||
match_type = RULE_PRE; | match_type = RULE_PRE; | ||||
if (word_flags & FLAG_UNPRON_TEST) { | if (word_flags & FLAG_UNPRON_TEST) { | ||||
failed = 1; | failed = 1; | ||||
} | } | ||||
break; | break; | ||||
case RULE_POST: | case RULE_POST: | ||||
match_type = RULE_POST; | match_type = RULE_POST; | ||||
break; | break; | ||||
} else | } else | ||||
failed = 1; | failed = 1; | ||||
break; | break; | ||||
case RULE_POST: | case RULE_POST: | ||||
/* continue moving fowards */ | /* continue moving fowards */ | ||||
distance_right += 6; | distance_right += 6; | ||||
} else | } else | ||||
failed = 1; | failed = 1; | ||||
break; | break; | ||||
case RULE_LETTERGP2: // match against a list of utf-8 strings | case RULE_LETTERGP2: // match against a list of utf-8 strings | ||||
letter_group = *rule++ - 'A'; | letter_group = *rule++ - 'A'; | ||||
if ((n_bytes = IsLetterGroup(tr, post_ptr-1, letter_group, 0)) > 0) { | if ((n_bytes = IsLetterGroup(tr, post_ptr-1, letter_group, 0)) > 0) { | ||||
} else | } else | ||||
failed = 1; | failed = 1; | ||||
break; | break; | ||||
case RULE_NOTVOWEL: | case RULE_NOTVOWEL: | ||||
if (IsLetter(tr, letter_w, 0) || ((letter_w == ' ') && (word_flags & FLAG_SUFFIX_VOWEL))) | if (IsLetter(tr, letter_w, 0) || ((letter_w == ' ') && (word_flags & FLAG_SUFFIX_VOWEL))) | ||||
failed = 1; | failed = 1; | ||||
post_ptr += letter_xbytes; | post_ptr += letter_xbytes; | ||||
} | } | ||||
break; | break; | ||||
case RULE_DIGIT: | case RULE_DIGIT: | ||||
if (IsDigit(letter_w)) { | if (IsDigit(letter_w)) { | ||||
add_points = (20-distance_right); | add_points = (20-distance_right); | ||||
} else | } else | ||||
failed = 1; | failed = 1; | ||||
break; | break; | ||||
case RULE_NONALPHA: | case RULE_NONALPHA: | ||||
if (!iswalpha2(letter_w)) { | if (!iswalpha2(letter_w)) { | ||||
add_points = (21-distance_right); | add_points = (21-distance_right); | ||||
} else | } else | ||||
failed = 1; | failed = 1; | ||||
break; | break; | ||||
case RULE_DOUBLE: | case RULE_DOUBLE: | ||||
if (letter == last_letter) | if (letter == last_letter) | ||||
add_points = (21-distance_right); | add_points = (21-distance_right); | ||||
else | else | ||||
failed = 1; | failed = 1; | ||||
break; | break; | ||||
case RULE_DOLLAR: | case RULE_DOLLAR: | ||||
command = *rule++; | command = *rule++; | ||||
if (command == DOLLAR_UNPR) | if (command == DOLLAR_UNPR) | ||||
failed = 1; | failed = 1; | ||||
} | } | ||||
break; | break; | ||||
case '-': | case '-': | ||||
if ((letter == '-') || ((letter == ' ') && (word_flags & FLAG_HYPHEN_AFTER))) | if ((letter == '-') || ((letter == ' ') && (word_flags & FLAG_HYPHEN_AFTER))) | ||||
add_points = (22-distance_right); // one point more than match against space | add_points = (22-distance_right); // one point more than match against space | ||||
else | else | ||||
failed = 1; | failed = 1; | ||||
break; | break; | ||||
case RULE_SYLLABLE: | case RULE_SYLLABLE: | ||||
{ | { | ||||
/* more than specified number of vowel letters to the right */ | /* more than specified number of vowel letters to the right */ | ||||
else | else | ||||
failed = 1; | failed = 1; | ||||
} | } | ||||
break; | |||||
break; | |||||
case RULE_NOVOWELS: | case RULE_NOVOWELS: | ||||
{ | { | ||||
char *p = post_ptr + letter_xbytes; | char *p = post_ptr + letter_xbytes; | ||||
if (!failed) | if (!failed) | ||||
add_points = (19-distance_right); | add_points = (19-distance_right); | ||||
} | } | ||||
break; | |||||
break; | |||||
case RULE_SKIPCHARS: | case RULE_SKIPCHARS: | ||||
{ | { | ||||
// Used for lang=Tamil, used to match on the next word after an unknown word ending | // Used for lang=Tamil, used to match on the next word after an unknown word ending | ||||
if (letter_w == rule_w) | if (letter_w == rule_w) | ||||
post_ptr = p2; | post_ptr = p2; | ||||
} | } | ||||
break; | |||||
break; | |||||
case RULE_INC_SCORE: | case RULE_INC_SCORE: | ||||
add_points = 20; // force an increase in points | add_points = 20; // force an increase in points | ||||
break; | break; | ||||
case RULE_DEL_FWD: | case RULE_DEL_FWD: | ||||
// find the next 'e' in the word and replace by 'E' | // find the next 'e' in the word and replace by 'E' | ||||
for (p = *word + group_length; p < post_ptr; p++) { | for (p = *word + group_length; p < post_ptr; p++) { | ||||
} | } | ||||
} | } | ||||
break; | break; | ||||
case RULE_ENDING: | case RULE_ENDING: | ||||
{ | { | ||||
int end_type; | int end_type; | ||||
rule += 3; | rule += 3; | ||||
} | } | ||||
} | } | ||||
break; | |||||
break; | |||||
case RULE_NO_SUFFIX: | case RULE_NO_SUFFIX: | ||||
if (word_flags & FLAG_SUFFIX_REMOVED) | if (word_flags & FLAG_SUFFIX_REMOVED) | ||||
failed = 1; // a suffix has been removed | failed = 1; // a suffix has been removed | ||||
else | else | ||||
add_points = 1; | add_points = 1; | ||||
break; | break; | ||||
default: | default: | ||||
if (letter == rb) { | if (letter == rb) { | ||||
if ((letter & 0xc0) != 0x80) { | if ((letter & 0xc0) != 0x80) { | ||||
break; | break; | ||||
} | } | ||||
break; | break; | ||||
case RULE_PRE: | case RULE_PRE: | ||||
/* match backwards from start of current group */ | /* match backwards from start of current group */ | ||||
distance_left += 2; | distance_left += 2; | ||||
} else | } else | ||||
failed = 1; | failed = 1; | ||||
break; | break; | ||||
case RULE_LETTERGP2: // match against a list of utf-8 strings | case RULE_LETTERGP2: // match against a list of utf-8 strings | ||||
letter_group = *rule++ - 'A'; | letter_group = *rule++ - 'A'; | ||||
if ((n_bytes = IsLetterGroup(tr, pre_ptr, letter_group, 1)) > 0) { | if ((n_bytes = IsLetterGroup(tr, pre_ptr, letter_group, 1)) > 0) { | ||||
} else | } else | ||||
failed = 1; | failed = 1; | ||||
break; | break; | ||||
case RULE_NOTVOWEL: | case RULE_NOTVOWEL: | ||||
if (!IsLetter(tr, letter_w, 0)) { | if (!IsLetter(tr, letter_w, 0)) { | ||||
add_points = (20-distance_left); | add_points = (20-distance_left); | ||||
} else | } else | ||||
failed = 1; | failed = 1; | ||||
break; | break; | ||||
case RULE_DOUBLE: | case RULE_DOUBLE: | ||||
if (letter == last_letter) | if (letter == last_letter) | ||||
add_points = (21-distance_left); | add_points = (21-distance_left); | ||||
else | else | ||||
failed = 1; | failed = 1; | ||||
break; | break; | ||||
case RULE_DIGIT: | case RULE_DIGIT: | ||||
if (IsDigit(letter_w)) { | if (IsDigit(letter_w)) { | ||||
add_points = (21-distance_left); | add_points = (21-distance_left); | ||||
} else | } else | ||||
failed = 1; | failed = 1; | ||||
break; | break; | ||||
case RULE_NONALPHA: | case RULE_NONALPHA: | ||||
if (!iswalpha2(letter_w)) { | if (!iswalpha2(letter_w)) { | ||||
add_points = (21-distance_right); | add_points = (21-distance_right); | ||||
} else | } else | ||||
failed = 1; | failed = 1; | ||||
break; | break; | ||||
case RULE_DOLLAR: | case RULE_DOLLAR: | ||||
command = *rule++; | command = *rule++; | ||||
if ((command == DOLLAR_LIST) || ((command & 0xf0) == 0x20)) { | if ((command == DOLLAR_LIST) || ((command & 0xf0) == 0x20)) { | ||||
failed = 1; | failed = 1; | ||||
} | } | ||||
break; | break; | ||||
case RULE_SYLLABLE: | case RULE_SYLLABLE: | ||||
/* more than specified number of vowels to the left */ | /* more than specified number of vowels to the left */ | ||||
syllable_count = 1; | syllable_count = 1; | ||||
else | else | ||||
failed = 1; | failed = 1; | ||||
break; | break; | ||||
case RULE_STRESSED: | case RULE_STRESSED: | ||||
if (tr->word_stressed_count > 0) | if (tr->word_stressed_count > 0) | ||||
add_points = 19; | add_points = 19; | ||||
else | else | ||||
failed = 1; | failed = 1; | ||||
break; | break; | ||||
case RULE_NOVOWELS: | case RULE_NOVOWELS: | ||||
{ | { | ||||
char *p = pre_ptr - letter_xbytes - 1; | char *p = pre_ptr - letter_xbytes - 1; | ||||
if (!failed) | if (!failed) | ||||
add_points = 3; | add_points = 3; | ||||
} | } | ||||
break; | |||||
break; | |||||
case RULE_IFVERB: | case RULE_IFVERB: | ||||
if (tr->expect_verb) | if (tr->expect_verb) | ||||
add_points = 1; | add_points = 1; | ||||
else | else | ||||
failed = 1; | failed = 1; | ||||
break; | break; | ||||
case RULE_CAPITAL: | case RULE_CAPITAL: | ||||
if (word_flags & FLAG_FIRST_UPPER) | if (word_flags & FLAG_FIRST_UPPER) | ||||
add_points = 1; | add_points = 1; | ||||
else | else | ||||
failed = 1; | failed = 1; | ||||
break; | break; | ||||
case '.': | case '.': | ||||
// dot in pre- section, match on any dot before this point in the word | // dot in pre- section, match on any dot before this point in the word | ||||
for (p = pre_ptr; *p != ' '; p--) { | for (p = pre_ptr; *p != ' '; p--) { | ||||
if (*p == ' ') | if (*p == ' ') | ||||
failed = 1; | failed = 1; | ||||
break; | break; | ||||
case '-': | case '-': | ||||
if ((letter == '-') || ((letter == ' ') && (word_flags & FLAG_HYPHEN))) | if ((letter == '-') || ((letter == ' ') && (word_flags & FLAG_HYPHEN))) | ||||
add_points = (22-distance_right); // one point more than match against space | add_points = (22-distance_right); // one point more than match against space | ||||
else | else | ||||
failed = 1; | failed = 1; | ||||
break; | break; | ||||
default: | default: | ||||
if (letter == rb) { | if (letter == rb) { | ||||
if (letter == RULE_SPACE) | if (letter == RULE_SPACE) | ||||
memcpy(match_out, &best, sizeof(MatchRecord)); | memcpy(match_out, &best, sizeof(MatchRecord)); | ||||
} | } | ||||
int TranslateRules(Translator *tr, char *p_start, char *phonemes, int ph_size, char *end_phonemes, int word_flags, unsigned int *dict_flags) | int TranslateRules(Translator *tr, char *p_start, char *phonemes, int ph_size, char *end_phonemes, int word_flags, unsigned int *dict_flags) | ||||
{ | { | ||||
/* Translate a word bounded by space characters | /* Translate a word bounded by space characters | ||||
} | } | ||||
word_copy[ix] = 0; | word_copy[ix] = 0; | ||||
if ((option_phonemes & espeakPHONEMES_TRACE) && ((word_flags & FLAG_NO_TRACE) == 0)) { | if ((option_phonemes & espeakPHONEMES_TRACE) && ((word_flags & FLAG_NO_TRACE) == 0)) { | ||||
char wordbuf[120]; | char wordbuf[120]; | ||||
unsigned int ix; | unsigned int ix; | ||||
return 0; | return 0; | ||||
} | } | ||||
void ApplySpecialAttribute2(Translator *tr, char *phonemes, int dict_flags) | void ApplySpecialAttribute2(Translator *tr, char *phonemes, int dict_flags) | ||||
{ | { | ||||
// apply after the translation is complete | // apply after the translation is complete | ||||
} | } | ||||
} | } | ||||
int TransposeAlphabet(Translator *tr, char *text) | int TransposeAlphabet(Translator *tr, char *text) | ||||
{ | { | ||||
// transpose cyrillic alphabet (for example) into ascii (single byte) character codes | // transpose cyrillic alphabet (for example) into ascii (single byte) character codes | ||||
int bufix; | int bufix; | ||||
char buf[N_WORD_BYTES+1]; | char buf[N_WORD_BYTES+1]; | ||||
offset = tr->transpose_min - 1; | offset = tr->transpose_min - 1; | ||||
min = tr->transpose_min; | min = tr->transpose_min; | ||||
max = tr->transpose_max; | max = tr->transpose_max; | ||||
return strlen(text); | return strlen(text); | ||||
} | } | ||||
/* Find an entry in the word_dict file for a specified word. | /* Find an entry in the word_dict file for a specified word. | ||||
Returns NULL if no match, else returns 'word_end' | Returns NULL if no match, else returns 'word_end' | ||||
return 0; | return 0; | ||||
} | } | ||||
/* Lookup a specified word in the word dictionary. | /* Lookup a specified word in the word dictionary. | ||||
Returns phonetic data in 'phonetic' and bits in 'flags' | Returns phonetic data in 'phonetic' and bits in 'flags' | ||||
found = LookupDict2(tr, word, word1, ph_out, flags, end_flags, wtab); | found = LookupDict2(tr, word, word1, ph_out, flags, end_flags, wtab); | ||||
if (flags[0] & FLAG_MAX3) { | if (flags[0] & FLAG_MAX3) { | ||||
if (strcmp(ph_out, tr->phonemes_repeat) == 0) { | if (strcmp(ph_out, tr->phonemes_repeat) == 0) { | ||||
tr->phonemes_repeat_count++; | tr->phonemes_repeat_count++; | ||||
} else | } else | ||||
tr->phonemes_repeat_count = 0; | tr->phonemes_repeat_count = 0; | ||||
if ((found == 0) && (flags[1] & FLAG_ACCENT)) { | if ((found == 0) && (flags[1] & FLAG_ACCENT)) { | ||||
int letter; | int letter; | ||||
word2 = word; | word2 = word; | ||||
return 0; | return 0; | ||||
} | } | ||||
extern char word_phonemes[N_WORD_PHONEMES]; // a word translated into phoneme codes | extern char word_phonemes[N_WORD_PHONEMES]; // a word translated into phoneme codes | ||||
int Lookup(Translator *tr, const char *word, char *ph_out) | int Lookup(Translator *tr, const char *word, char *ph_out) | ||||
return flags0; | return flags0; | ||||
} | } | ||||
int LookupFlags(Translator *tr, const char *word, unsigned int **flags_out) | int LookupFlags(Translator *tr, const char *word, unsigned int **flags_out) | ||||
{ | { | ||||
char buf[100]; | char buf[100]; | ||||
return flags[0]; | return flags[0]; | ||||
} | } | ||||
int RemoveEnding(Translator *tr, char *word, int end_type, char *word_copy) | int RemoveEnding(Translator *tr, char *word, int end_type, char *word_copy) | ||||
{ | { | ||||
/* Removes a standard suffix from a word, once it has been indicated by the dictionary rules. | /* Removes a standard suffix from a word, once it has been indicated by the dictionary rules. |
free(the_command->u.my_text.text); | free(the_command->u.my_text.text); | ||||
} | } | ||||
break; | break; | ||||
case ET_MARK: | case ET_MARK: | ||||
if (the_command->u.my_mark.text) | if (the_command->u.my_mark.text) | ||||
free(the_command->u.my_mark.text); | free(the_command->u.my_mark.text); | ||||
if (the_command->u.my_mark.index_mark) | if (the_command->u.my_mark.index_mark) | ||||
free((void *)(the_command->u.my_mark.index_mark)); | free((void *)(the_command->u.my_mark.index_mark)); | ||||
break; | break; | ||||
case ET_TERMINATED_MSG: | case ET_TERMINATED_MSG: | ||||
{ | { | ||||
// if the terminated msg is pending, | // if the terminated msg is pending, | ||||
sync_espeak_terminated_msg(data->unique_identifier, data->user_data); | sync_espeak_terminated_msg(data->unique_identifier, data->user_data); | ||||
} | } | ||||
} | } | ||||
break; | |||||
break; | |||||
case ET_KEY: | case ET_KEY: | ||||
if (the_command->u.my_key.key_name) | if (the_command->u.my_key.key_name) | ||||
free((void *)(the_command->u.my_key.key_name)); | free((void *)(the_command->u.my_key.key_name)); | ||||
break; | break; | ||||
case ET_CHAR: | case ET_CHAR: | ||||
case ET_PARAMETER: | case ET_PARAMETER: | ||||
// No allocation | // No allocation | ||||
break; | break; | ||||
case ET_PUNCTUATION_LIST: | case ET_PUNCTUATION_LIST: | ||||
if (the_command->u.my_punctuation_list) | if (the_command->u.my_punctuation_list) | ||||
free((void *)(the_command->u.my_punctuation_list)); | free((void *)(the_command->u.my_punctuation_list)); | ||||
break; | break; | ||||
case ET_VOICE_NAME: | case ET_VOICE_NAME: | ||||
if (the_command->u.my_voice_name) | if (the_command->u.my_voice_name) | ||||
free((void *)(the_command->u.my_voice_name)); | free((void *)(the_command->u.my_voice_name)); | ||||
break; | break; | ||||
case ET_VOICE_SPEC: | case ET_VOICE_SPEC: | ||||
{ | { | ||||
espeak_VOICE *data = &(the_command->u.my_voice_spec); | espeak_VOICE *data = &(the_command->u.my_voice_spec); | ||||
if (data->identifier) | if (data->identifier) | ||||
free((void *)data->identifier); | free((void *)data->identifier); | ||||
} | } | ||||
break; | |||||
break; | |||||
default: | default: | ||||
assert(0); | assert(0); | ||||
} | } | ||||
data->position, data->position_type, | data->position, data->position_type, | ||||
data->end_position, data->flags, data->user_data); | data->end_position, data->flags, data->user_data); | ||||
} | } | ||||
break; | |||||
break; | |||||
case ET_MARK: | case ET_MARK: | ||||
{ | { | ||||
t_espeak_mark *data = &(the_command->u.my_mark); | t_espeak_mark *data = &(the_command->u.my_mark); | ||||
data->index_mark, data->end_position, data->flags, | data->index_mark, data->end_position, data->flags, | ||||
data->user_data); | data->user_data); | ||||
} | } | ||||
break; | |||||
break; | |||||
case ET_TERMINATED_MSG: | case ET_TERMINATED_MSG: | ||||
{ | { | ||||
t_espeak_terminated_msg *data = &(the_command->u.my_terminated_msg); | t_espeak_terminated_msg *data = &(the_command->u.my_terminated_msg); | ||||
sync_espeak_terminated_msg(data->unique_identifier, data->user_data); | sync_espeak_terminated_msg(data->unique_identifier, data->user_data); | ||||
} | } | ||||
break; | |||||
break; | |||||
case ET_KEY: | case ET_KEY: | ||||
{ | { | ||||
const char *data = the_command->u.my_key.key_name; | const char *data = the_command->u.my_key.key_name; | ||||
sync_espeak_Key(data); | sync_espeak_Key(data); | ||||
} | } | ||||
break; | |||||
break; | |||||
case ET_CHAR: | case ET_CHAR: | ||||
{ | { | ||||
const wchar_t data = the_command->u.my_char.character; | const wchar_t data = the_command->u.my_char.character; | ||||
sync_espeak_Char(data); | sync_espeak_Char(data); | ||||
} | } | ||||
break; | |||||
break; | |||||
case ET_PARAMETER: | case ET_PARAMETER: | ||||
{ | { | ||||
t_espeak_parameter *data = &(the_command->u.my_param); | t_espeak_parameter *data = &(the_command->u.my_param); | ||||
SetParameter(data->parameter, data->value, data->relative); | SetParameter(data->parameter, data->value, data->relative); | ||||
} | } | ||||
break; | |||||
break; | |||||
case ET_PUNCTUATION_LIST: | case ET_PUNCTUATION_LIST: | ||||
{ | { | ||||
const wchar_t *data = the_command->u.my_punctuation_list; | const wchar_t *data = the_command->u.my_punctuation_list; | ||||
sync_espeak_SetPunctuationList(data); | sync_espeak_SetPunctuationList(data); | ||||
} | } | ||||
break; | |||||
break; | |||||
case ET_VOICE_NAME: | case ET_VOICE_NAME: | ||||
{ | { | ||||
const char *data = the_command->u.my_voice_name; | const char *data = the_command->u.my_voice_name; | ||||
SetVoiceByName(data); | SetVoiceByName(data); | ||||
} | } | ||||
break; | |||||
break; | |||||
case ET_VOICE_SPEC: | case ET_VOICE_SPEC: | ||||
{ | { | ||||
espeak_VOICE *data = &(the_command->u.my_voice_spec); | espeak_VOICE *data = &(the_command->u.my_voice_spec); | ||||
SetVoiceByProperties(data); | SetVoiceByProperties(data); | ||||
} | } | ||||
break; | |||||
break; | |||||
default: | default: | ||||
assert(0); | assert(0); | ||||
break; | break; | ||||
t_espeak_text *data = &(the_command->u.my_text); | t_espeak_text *data = &(the_command->u.my_text); | ||||
SHOW("display_espeak_command > (0x%x) uid=%d, TEXT=%s, user_data=0x%x\n", the_command, data->unique_identifier, (char *)data->text, (int)(data->user_data)); | SHOW("display_espeak_command > (0x%x) uid=%d, TEXT=%s, user_data=0x%x\n", the_command, data->unique_identifier, (char *)data->text, (int)(data->user_data)); | ||||
} | } | ||||
break; | |||||
break; | |||||
case ET_MARK: | case ET_MARK: | ||||
{ | { | ||||
t_espeak_mark *data = &(the_command->u.my_mark); | t_espeak_mark *data = &(the_command->u.my_mark); | ||||
SHOW("display_espeak_command > (0x%x) uid=%d, MARK=%s, user_data=0x%x\n", the_command, data->unique_identifier, (char *)data->text, (int)(data->user_data)); | SHOW("display_espeak_command > (0x%x) uid=%d, MARK=%s, user_data=0x%x\n", the_command, data->unique_identifier, (char *)data->text, (int)(data->user_data)); | ||||
} | } | ||||
break; | |||||
break; | |||||
case ET_KEY: | case ET_KEY: | ||||
{ | { | ||||
const char *data = the_command->u.my_key.key_name; | const char *data = the_command->u.my_key.key_name; | ||||
SHOW("display_espeak_command > (0x%x) KEY=%c\n", the_command, data); | SHOW("display_espeak_command > (0x%x) KEY=%c\n", the_command, data); | ||||
} | } | ||||
break; | |||||
break; | |||||
case ET_TERMINATED_MSG: | case ET_TERMINATED_MSG: | ||||
{ | { | ||||
t_espeak_terminated_msg *data = &(the_command->u.my_terminated_msg); | t_espeak_terminated_msg *data = &(the_command->u.my_terminated_msg); | ||||
the_command, data->unique_identifier, data->user_data, | the_command, data->unique_identifier, data->user_data, | ||||
the_command->state); | the_command->state); | ||||
} | } | ||||
break; | |||||
break; | |||||
case ET_CHAR: | case ET_CHAR: | ||||
{ | { | ||||
const wchar_t data = the_command->u.my_char.character; | const wchar_t data = the_command->u.my_char.character; | ||||
SHOW("display_espeak_command > (0x%x) CHAR=%c\n", the_command, (char)data); | SHOW("display_espeak_command > (0x%x) CHAR=%c\n", the_command, (char)data); | ||||
} | } | ||||
break; | |||||
break; | |||||
case ET_PARAMETER: | case ET_PARAMETER: | ||||
{ | { | ||||
t_espeak_parameter *data = &(the_command->u.my_param); | t_espeak_parameter *data = &(the_command->u.my_param); | ||||
SHOW("display_espeak_command > (0x%x) PARAMETER=%d, value=%d, relative=%d\n", | SHOW("display_espeak_command > (0x%x) PARAMETER=%d, value=%d, relative=%d\n", | ||||
the_command, data->parameter, data->value, data->relative); | the_command, data->parameter, data->value, data->relative); | ||||
} | } | ||||
break; | |||||
break; | |||||
case ET_PUNCTUATION_LIST: | case ET_PUNCTUATION_LIST: | ||||
{ | { | ||||
const wchar_t *data = the_command->u.my_punctuation_list; | const wchar_t *data = the_command->u.my_punctuation_list; | ||||
sync_espeak_SetPunctuationList(data); | sync_espeak_SetPunctuationList(data); | ||||
SHOW("display_espeak_command > (0x%x) PUNCTLIST=%s\n", the_command, (char *)data); | SHOW("display_espeak_command > (0x%x) PUNCTLIST=%s\n", the_command, (char *)data); | ||||
} | } | ||||
break; | |||||
break; | |||||
case ET_VOICE_NAME: | case ET_VOICE_NAME: | ||||
{ | { | ||||
const char *data = the_command->u.my_voice_name; | const char *data = the_command->u.my_voice_name; | ||||
SHOW("display_espeak_command > (0x%x) VOICE_NAME=%s\n", the_command, data); | SHOW("display_espeak_command > (0x%x) VOICE_NAME=%s\n", the_command, data); | ||||
} | } | ||||
break; | |||||
break; | |||||
case ET_VOICE_SPEC: | case ET_VOICE_SPEC: | ||||
{ | { | ||||
SHOW("display_espeak_command > (0x%x) VOICE_SPEC", the_command); | SHOW("display_espeak_command > (0x%x) VOICE_SPEC", the_command); | ||||
} | } | ||||
break; | |||||
break; | |||||
default: | default: | ||||
assert(0); | assert(0); | ||||
break; | break; |
ACTIVITY_TIMEOUT = 50, // in ms, check that the stream is active | ACTIVITY_TIMEOUT = 50, // in ms, check that the stream is active | ||||
MAX_ACTIVITY_CHECK = 6 }; | MAX_ACTIVITY_CHECK = 6 }; | ||||
typedef struct t_node { | typedef struct t_node { | ||||
void *data; | void *data; | ||||
struct t_node *next; | struct t_node *next; | ||||
my_callback(NULL, 0, events); | my_callback(NULL, 0, events); | ||||
a_old_uid = event->unique_identifier; | a_old_uid = event->unique_identifier; | ||||
break; | break; | ||||
case espeakEVENT_MSG_TERMINATED: | case espeakEVENT_MSG_TERMINATED: | ||||
case espeakEVENT_MARK: | case espeakEVENT_MARK: | ||||
case espeakEVENT_WORD: | case espeakEVENT_WORD: | ||||
my_callback(NULL, 0, events); | my_callback(NULL, 0, events); | ||||
a_old_uid = event->unique_identifier; | a_old_uid = event->unique_identifier; | ||||
} | } | ||||
break; | |||||
default: | |||||
break; | |||||
case espeakEVENT_LIST_TERMINATED: | case espeakEVENT_LIST_TERMINATED: | ||||
case espeakEVENT_PLAY: | case espeakEVENT_PLAY: | ||||
default: | |||||
break; | break; | ||||
} | } | ||||
} | } | ||||
case espeakEVENT_MSG_TERMINATED: | case espeakEVENT_MSG_TERMINATED: | ||||
event_notify(event); | event_notify(event); | ||||
break; | break; | ||||
case espeakEVENT_MARK: | case espeakEVENT_MARK: | ||||
case espeakEVENT_PLAY: | case espeakEVENT_PLAY: | ||||
if (event->id.name) | if (event->id.name) | ||||
free((void *)(event->id.name)); | free((void *)(event->id.name)); | ||||
break; | break; | ||||
default: | default: | ||||
break; | break; | ||||
} | } |
#include "wave.h" | #include "wave.h" | ||||
#include "debug.h" | #include "debug.h" | ||||
// my_mutex: protects my_thread_is_talking, | // my_mutex: protects my_thread_is_talking, | ||||
// my_stop_is_required, and the command fifo | // my_stop_is_required, and the command fifo | ||||
static pthread_mutex_t my_mutex; | static pthread_mutex_t my_mutex; |
#include "voice.h" | #include "voice.h" | ||||
#include "translate.h" | #include "translate.h" | ||||
/* Note this module is mostly old code that needs to be rewritten to | /* Note this module is mostly old code that needs to be rewritten to | ||||
provide a more flexible intonation system. | provide a more flexible intonation system. | ||||
*/ | */ | ||||
static SYLLABLE *syllable_tab; | static SYLLABLE *syllable_tab; | ||||
static int tone_pitch_env; /* used to return pitch envelope */ | static int tone_pitch_env; /* used to return pitch envelope */ | ||||
/* Pitch data for tone types */ | /* Pitch data for tone types */ | ||||
/*****************************/ | /*****************************/ | ||||
#define PITCHfall 0 | #define PITCHfall 0 | ||||
#define PITCHrise 2 | #define PITCHrise 2 | ||||
#define PITCHfrise 4 // and 3 must be for the variant preceded by 'r' | #define PITCHfrise 4 // and 3 must be for the variant preceded by 'r' | ||||
0x50, 0x5a, 0x64, 0x70, 0x7c, 0x83, 0x85, 0x88, 0x8a, 0x8c, 0x8e, 0x8f, 0x91, 0x92, 0x93, 0x93 | 0x50, 0x5a, 0x64, 0x70, 0x7c, 0x83, 0x85, 0x88, 0x8a, 0x8c, 0x8e, 0x8f, 0x91, 0x92, 0x93, 0x93 | ||||
}; | }; | ||||
unsigned char *envelope_data[N_ENVELOPE_DATA] = { | unsigned char *envelope_data[N_ENVELOPE_DATA] = { | ||||
env_fall, env_fall, | env_fall, env_fall, | ||||
env_rise, env_rise, | env_rise, env_rise, | ||||
env_risefallrise, env_risefallrise | env_risefallrise, env_risefallrise | ||||
}; | }; | ||||
/* indexed by stress */ | /* indexed by stress */ | ||||
static int min_drop[] = { 6, 7, 9, 9, 20, 20, 20, 25 }; | static int min_drop[] = { 6, 7, 9, 9, 20, 20, 20, 25 }; | ||||
static signed char oflow_emf[] = { 10, 52, 32, 20, 10 }; | static signed char oflow_emf[] = { 10, 52, 32, 20, 10 }; | ||||
static signed char oflow_less[] = { 6, 38, 24, 14, 4 }; | static signed char oflow_less[] = { 6, 38, 24, 14, 4 }; | ||||
#define N_TONE_HEAD_TABLE 13 | #define N_TONE_HEAD_TABLE 13 | ||||
#define N_TONE_NUCLEUS_TABLE 13 | #define N_TONE_NUCLEUS_TABLE 13 | ||||
typedef struct { | typedef struct { | ||||
unsigned char pre_start; | unsigned char pre_start; | ||||
unsigned char pre_end; | unsigned char pre_end; | ||||
signed char *overflow; | signed char *overflow; | ||||
} TONE_HEAD; | } TONE_HEAD; | ||||
typedef struct { | typedef struct { | ||||
unsigned char pitch_env0; /* pitch envelope, tonic syllable at end */ | unsigned char pitch_env0; /* pitch envelope, tonic syllable at end */ | ||||
unsigned char tonic_max0; | unsigned char tonic_max0; | ||||
{ PITCHfall, 70, 18, PITCHfall, 70, 24, NULL, 32, 20, 0 }, // 12 test | { PITCHfall, 70, 18, PITCHfall, 70, 24, NULL, 32, 20, 0 }, // 12 test | ||||
}; | }; | ||||
/* index by 0=. 1=, 2=?, 3=! 4=none, 5=emphasized */ | /* index by 0=. 1=, 2=?, 3=! 4=none, 5=emphasized */ | ||||
unsigned char punctuation_to_tone[INTONATION_TYPES][PUNCT_INTONATIONS] = { | unsigned char punctuation_to_tone[INTONATION_TYPES][PUNCT_INTONATIONS] = { | ||||
{ 0, 1, 2, 3, 0, 4 }, | { 0, 1, 2, 3, 0, 4 }, | ||||
{ 12, 12, 12, 12, 0, 0 } | { 12, 12, 12, 12, 0, 0 } | ||||
}; | }; | ||||
int n_tunes = 0; | int n_tunes = 0; | ||||
TUNE *tunes = NULL; | TUNE *tunes = NULL; | ||||
#define SECONDARY 3 | #define SECONDARY 3 | ||||
#define PRIMARY 4 | #define PRIMARY 4 | ||||
#define PRIMARY_STRESSED 6 | #define PRIMARY_STRESSED 6 | ||||
#define PRIMARY_LAST 7 | #define PRIMARY_LAST 7 | ||||
static int number_pre; | static int number_pre; | ||||
static int number_body; | static int number_body; | ||||
static int number_tail; | static int number_tail; | ||||
static int tone_posn2; | static int tone_posn2; | ||||
static int no_tonic; | static int no_tonic; | ||||
static void count_pitch_vowels(int start, int end, int clause_end) | static void count_pitch_vowels(int start, int end, int clause_end) | ||||
{ | { | ||||
int ix; | int ix; | ||||
last_primary = ix; | last_primary = ix; | ||||
} | } | ||||
} | } | ||||
if (number_pre < 0) | if (number_pre < 0) | ||||
} | } | ||||
} | } | ||||
/* Count number of primary stresses up to tonic syllable or body_reset */ | /* Count number of primary stresses up to tonic syllable or body_reset */ | ||||
static int count_increments(int ix, int end_ix, int min_stress) | static int count_increments(int ix, int end_ix, int min_stress) | ||||
{ | { | ||||
return count; | return count; | ||||
} | } | ||||
// 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) | ||||
{ | { | ||||
syl->flags |= flags; | syl->flags |= flags; | ||||
} | } | ||||
static int CountUnstressed(int start, int end, int limit) | static int CountUnstressed(int start, int end, int limit) | ||||
{ | { | ||||
int ix; | int ix; | ||||
increment = pitch_range / (n_steps -1); | increment = pitch_range / (n_steps -1); | ||||
else | else | ||||
increment = 0; | increment = 0; | ||||
} else if (syl_ix == head_final) { | } else if (syl_ix == head_final) { | ||||
// a pitch has been specified for the last primary stress before the nucleus | // a pitch has been specified for the last primary stress before the nucleus | ||||
pitch = tune->head_last << 8; | pitch = tune->head_last << 8; | ||||
syl_ix++; | syl_ix++; | ||||
} | } | ||||
return syl_ix; | return syl_ix; | ||||
} | } | ||||
/* Calculate pitches until next RESET or tonic syllable, or end. | /* Calculate pitches until next RESET or tonic syllable, or end. | ||||
Increment pitch if stress is >= min_stress. | Increment pitch if stress is >= min_stress. | ||||
Used for tonic segment */ | Used for tonic segment */ | ||||
return ix; | return ix; | ||||
} | } | ||||
static void SetPitchGradient(int start_ix, int end_ix, int start_pitch, int end_pitch) | static void SetPitchGradient(int start_ix, int end_ix, int start_pitch, int end_pitch) | ||||
{ | { | ||||
// Set a linear pitch change over a number of syllables. | // Set a linear pitch change over a number of syllables. | ||||
} | } | ||||
} | } | ||||
// 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) | ||||
{ | { | ||||
return tone_pitch_env; | return tone_pitch_env; | ||||
} | } | ||||
// 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) | ||||
{ | { | ||||
return tone_pitch_env; | return tone_pitch_env; | ||||
} | } | ||||
static void CalcPitches_Tone(Translator *tr, int clause_tone) | static void CalcPitches_Tone(Translator *tr, int clause_tone) | ||||
{ | { | ||||
// clause_tone: 0=. 1=, 2=?, 3=! 4=none | // clause_tone: 0=. 1=, 2=?, 3=! 4=none | ||||
p->tone_ph = PhonemeCode('7'); // change default tone (tone 1) to falling tone at end of clause | p->tone_ph = PhonemeCode('7'); // change default tone (tone 1) to falling tone at end of clause | ||||
} | } | ||||
pause = 1; | pause = 1; | ||||
tone_promoted = 0; | tone_promoted = 0; | ||||
p->tone_ph = tone_ph; | p->tone_ph = tone_ph; | ||||
tph = phoneme_tab[tone_ph]; | tph = phoneme_tab[tone_ph]; | ||||
} else | } else | ||||
tone_promoted = 0; | tone_promoted = 0; | ||||
p->pitch2 = pitch_adjust + phoneme_tab[tone_ph]->end_type; | p->pitch2 = pitch_adjust + phoneme_tab[tone_ph]->end_type; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
void CalcPitches(Translator *tr, int clause_type) | void CalcPitches(Translator *tr, int clause_type) | ||||
{ | { | ||||
// clause_type: 0=. 1=, 2=?, 3=! 4=none | // clause_type: 0=. 1=, 2=?, 3=! 4=none | ||||
if (n_st == 0) | if (n_st == 0) | ||||
return; // nothing to do | return; // nothing to do | ||||
if (tr->langopts.tone_language == 1) { | if (tr->langopts.tone_language == 1) { | ||||
CalcPitches_Tone(tr, clause_type); | CalcPitches_Tone(tr, clause_type); | ||||
return; | return; | ||||
} | } | ||||
option = tr->langopts.intonation_group; | option = tr->langopts.intonation_group; | ||||
if (option >= INTONATION_TYPES) | if (option >= INTONATION_TYPES) | ||||
option = 1; | option = 1; | ||||
calc_pitches(option, st_start, st_ix, group_tone); | calc_pitches(option, st_start, st_ix, group_tone); | ||||
} | } | ||||
// unpack pitch data | // unpack pitch data | ||||
st_ix = 0; | st_ix = 0; | ||||
for (ix = ph_start; ix < ph_end; ix++) { | for (ix = ph_start; ix < ph_end; ix++) { | ||||
st_ix++; | st_ix++; | ||||
} | } | ||||
} | } | ||||
} | } |
static int nsamples; | static int nsamples; | ||||
static int sample_count; | static int sample_count; | ||||
#ifdef _MSC_VER | #ifdef _MSC_VER | ||||
#define getrandom(min, max) ((rand()%(int)(((max)+1)-(min)))+(min)) | #define getrandom(min, max) ((rand()%(int)(((max)+1)-(min)))+(min)) | ||||
#else | #else | ||||
#define getrandom(min, max) ((rand()%(long)(((max)+1)-(min)))+(min)) | #define getrandom(min, max) ((rand()%(long)(((max)+1)-(min)))+(min)) | ||||
#endif | #endif | ||||
/* function prototypes for functions private to this file */ | /* function prototypes for functions private to this file */ | ||||
static void flutter(klatt_frame_ptr); | static void flutter(klatt_frame_ptr); | ||||
return (double)x; | return (double)x; | ||||
} | } | ||||
static double antiresonator2(resonator_ptr r, double input) | static double antiresonator2(resonator_ptr r, double input) | ||||
{ | { | ||||
register double x = (double)r->a * (double)input + (double)r->b * (double)r->p1 + (double)r->c * (double)r->p2; | register double x = (double)r->a * (double)input + (double)r->b * (double)r->p1 + (double)r->c * (double)r->p2; | ||||
return (double)x; | return (double)x; | ||||
} | } | ||||
/* | /* | ||||
function FLUTTER | function FLUTTER | ||||
time_count++; | time_count++; | ||||
} | } | ||||
/* | /* | ||||
function SAMPLED_SOURCE | function SAMPLED_SOURCE | ||||
return result; | return result; | ||||
} | } | ||||
/* | /* | ||||
function PARWAVE | function PARWAVE | ||||
Converts synthesis parameters to a waveform. | Converts synthesis parameters to a waveform. | ||||
*/ | */ | ||||
static int parwave(klatt_frame_ptr frame) | static int parwave(klatt_frame_ptr frame) | ||||
{ | { | ||||
double temp; | double temp; | ||||
return 0; | return 0; | ||||
} | } | ||||
void KlattReset(int control) | void KlattReset(int control) | ||||
{ | { | ||||
int r_ix; | int r_ix; | ||||
kt_globals.rsn[r_ix].p1 = 0; | kt_globals.rsn[r_ix].p1 = 0; | ||||
kt_globals.rsn[r_ix].p2 = 0; | kt_globals.rsn[r_ix].p2 = 0; | ||||
} | } | ||||
} | } | ||||
for (r_ix = 0; r_ix <= R6p; r_ix++) { | for (r_ix = 0; r_ix <= R6p; r_ix++) { | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
function FRAME_INIT | function FRAME_INIT | ||||
kt_globals.rsn[F_NZ].b_inc = (kt_globals.rsn_next[F_NZ].b - kt_globals.rsn[F_NZ].b) / 64.0; | kt_globals.rsn[F_NZ].b_inc = (kt_globals.rsn_next[F_NZ].b - kt_globals.rsn[F_NZ].b) / 64.0; | ||||
kt_globals.rsn[F_NZ].c_inc = (kt_globals.rsn_next[F_NZ].c - kt_globals.rsn[F_NZ].c) / 64.0; | kt_globals.rsn[F_NZ].c_inc = (kt_globals.rsn_next[F_NZ].c - kt_globals.rsn[F_NZ].c) / 64.0; | ||||
/* Set coefficients of parallel resonators, and amplitude of outputs */ | /* Set coefficients of parallel resonators, and amplitude of outputs */ | ||||
for (ix = 0; ix <= 6; ix++) { | for (ix = 0; ix <= 6; ix++) { | ||||
/* output low-pass filter */ | /* output low-pass filter */ | ||||
setabc((long)0.0, (long)(kt_globals.samrate/2), &(kt_globals.rsn[Rout])); | setabc((long)0.0, (long)(kt_globals.samrate/2), &(kt_globals.rsn[Rout])); | ||||
} | } | ||||
/* | /* | ||||
function IMPULSIVE_SOURCE | function IMPULSIVE_SOURCE | ||||
to Kopen. | to Kopen. | ||||
*/ | */ | ||||
static double impulsive_source() | static double impulsive_source() | ||||
{ | { | ||||
static double doublet[] = { 0.0, 13000000.0, -13000000.0 }; | static double doublet[] = { 0.0, 13000000.0, -13000000.0 }; | ||||
return resonator(&(kt_globals.rsn[RGL]), vwave); | return resonator(&(kt_globals.rsn[RGL]), vwave); | ||||
} | } | ||||
/* | /* | ||||
function NATURAL_SOURCE | function NATURAL_SOURCE | ||||
return 0.0; | return 0.0; | ||||
} | } | ||||
/* | /* | ||||
function PITCH_SYNC_PAR_RESET | function PITCH_SYNC_PAR_RESET | ||||
kt_globals.nopen = 40; | kt_globals.nopen = 40; | ||||
} | } | ||||
/* Reset a & b, which determine shape of "natural" glottal waveform */ | /* Reset a & b, which determine shape of "natural" glottal waveform */ | ||||
kt_globals.pulse_shape_b = B0[kt_globals.nopen-40]; | kt_globals.pulse_shape_b = B0[kt_globals.nopen-40]; | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
function SETABC | function SETABC | ||||
equation constants. | equation constants. | ||||
*/ | */ | ||||
static void setabc(long int f, long int bw, resonator_ptr rp) | static void setabc(long int f, long int bw, resonator_ptr rp) | ||||
{ | { | ||||
double r; | double r; | ||||
rp->a = 1.0 - rp->b - rp->c; | rp->a = 1.0 - rp->b - rp->c; | ||||
} | } | ||||
/* | /* | ||||
function SETZEROABC | function SETZEROABC | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
function GEN_NOISE | function GEN_NOISE | ||||
the origin in the z-plane, i.e. output = input + (0.75 * lastoutput) | the origin in the z-plane, i.e. output = input + (0.75 * lastoutput) | ||||
*/ | */ | ||||
static double gen_noise(double noise) | static double gen_noise(double noise) | ||||
{ | { | ||||
long temp; | long temp; | ||||
return noise; | return noise; | ||||
} | } | ||||
/* | /* | ||||
function DBTOLIN | function DBTOLIN | ||||
steps. | steps. | ||||
*/ | */ | ||||
static double DBtoLIN(long dB) | static double DBtoLIN(long dB) | ||||
{ | { | ||||
static short amptable[88] = { | static short amptable[88] = { | ||||
return (double)(amptable[dB]) * 0.001; | return (double)(amptable[dB]) * 0.001; | ||||
} | } | ||||
extern voice_t *wvoice; | extern voice_t *wvoice; | ||||
static klatt_peaks_t peaks[N_PEAKS]; | static klatt_peaks_t peaks[N_PEAKS]; | ||||
static int end_wave; | static int end_wave; | ||||
static double klattp1[N_KLATTP]; | static double klattp1[N_KLATTP]; | ||||
static double klattp_inc[N_KLATTP]; | static double klattp_inc[N_KLATTP]; | ||||
int Wavegen_Klatt(int resume) | int Wavegen_Klatt(int resume) | ||||
{ | { | ||||
int pk; | int pk; | ||||
return 0; | return 0; | ||||
} | } | ||||
void SetSynth_Klatt(int length, int modn, frame_t *fr1, frame_t *fr2, voice_t *v, int control) | void SetSynth_Klatt(int length, int modn, frame_t *fr1, frame_t *fr2, voice_t *v, int control) | ||||
{ | { | ||||
int ix; | int ix; | ||||
} | } | ||||
} | } | ||||
int Wavegen_Klatt2(int length, int modulation, int resume, frame_t *fr1, frame_t *fr2) | int Wavegen_Klatt2(int length, int modulation, int resume, frame_t *fr1, frame_t *fr2) | ||||
{ | { | ||||
if (resume == 0) | if (resume == 0) | ||||
return Wavegen_Klatt(resume); | return Wavegen_Klatt(resume); | ||||
} | } | ||||
void KlattInit() | void KlattInit() | ||||
{ | { | ||||
#include "mbrowrap.h" | #include "mbrowrap.h" | ||||
/* | /* | ||||
* mbrola instance parameters | * mbrola instance parameters | ||||
*/ | */ |
#include "voice.h" | #include "voice.h" | ||||
#include "translate.h" | #include "translate.h" | ||||
#define M_LIGATURE 0x8000 | #define M_LIGATURE 0x8000 | ||||
#define M_NAME 0 | #define M_NAME 0 | ||||
#define M_SMALLCAP 1 | #define M_SMALLCAP 1 | ||||
#define M_RETROFLEX 20 | #define M_RETROFLEX 20 | ||||
#define M_HOOK 21 | #define M_HOOK 21 | ||||
#define M_MIDDLE_DOT M_DOT_ABOVE // duplicate of M_DOT_ABOVE | #define M_MIDDLE_DOT M_DOT_ABOVE // duplicate of M_DOT_ABOVE | ||||
#define M_IMPLOSIVE M_HOOK | #define M_IMPLOSIVE M_HOOK | ||||
static int speak_missing_thousands; | static int speak_missing_thousands; | ||||
static int number_control; | static int number_control; | ||||
typedef struct { | typedef struct { | ||||
const char *name; | const char *name; | ||||
int accent_flags; // bit 0, say before the letter name | int accent_flags; // bit 0, say before the letter name | ||||
{ "_hok", 0 }, // hook | { "_hok", 0 }, // hook | ||||
}; | }; | ||||
#define CAPITAL 0 | #define CAPITAL 0 | ||||
#define LETTER(ch, mod1, mod2) (ch-59)+(mod1 << 6)+(mod2 << 11) | #define LETTER(ch, mod1, mod2) (ch-59)+(mod1 << 6)+(mod2 << 11) | ||||
#define LIGATURE(ch1, ch2, mod1) (ch1-59)+((ch2-59) << 6)+(mod1 << 12)+M_LIGATURE | #define LIGATURE(ch1, ch2, mod1) (ch1-59)+((ch2-59) << 6)+(mod1 << 12)+M_LIGATURE | ||||
#define L_RTAP 72 // U+27E | #define L_RTAP 72 // U+27E | ||||
#define L_RLONG 73 // U+27C | #define L_RLONG 73 // U+27C | ||||
static const short non_ascii_tab[] = { | static const short non_ascii_tab[] = { | ||||
0, 0x3b1, 0x259, 0x25b, 0x3b3, 0x3b9, 0x153, 0x3c9, | 0, 0x3b1, 0x259, 0x25b, 0x3b3, 0x3b9, 0x153, 0x3c9, | ||||
0x3c6, 0x283, 0x3c5, 0x292, 0x294, 0x27e, 0x27c | 0x3c6, 0x283, 0x3c5, 0x292, 0x294, 0x27e, 0x27c | ||||
}; | }; | ||||
// characters U+00e0 to U+017f | // characters U+00e0 to U+017f | ||||
static const unsigned short letter_accents_0e0[] = { | static const unsigned short letter_accents_0e0[] = { | ||||
LETTER('a', M_GRAVE, 0), // U+00e0 | LETTER('a', M_GRAVE, 0), // U+00e0 | ||||
CAPITAL, | CAPITAL, | ||||
LETTER('z', M_CARON, 0), | LETTER('z', M_CARON, 0), | ||||
LETTER('s', M_NAME, 0), // long-s // U+17f | LETTER('s', M_NAME, 0), // long-s // U+17f | ||||
}; | }; | ||||
// characters U+0250 to U+029F | // characters U+0250 to U+029F | ||||
static const unsigned short letter_accents_250[] = { | static const unsigned short letter_accents_250[] = { | ||||
LETTER('a', M_TURNED, 0), // U+250 | LETTER('a', M_TURNED, 0), // U+250 | ||||
return ph_buf[0]; | return ph_buf[0]; | ||||
} | } | ||||
void LookupAccentedLetter(Translator *tr, unsigned int letter, char *ph_buf) | void LookupAccentedLetter(Translator *tr, unsigned int letter, char *ph_buf) | ||||
{ | { | ||||
// lookup the character in the accents table | // lookup the character in the accents table | ||||
accent2 = (accent_data >> 11) & 0xf; | accent2 = (accent_data >> 11) & 0xf; | ||||
} | } | ||||
if ((accent1 == 0) && !(accent_data & M_LIGATURE)) { | if ((accent1 == 0) && !(accent_data & M_LIGATURE)) { | ||||
// just a letter name, not an accented character or ligature | // just a letter name, not an accented character or ligature | ||||
return; | return; | ||||
} | } | ||||
if ((flags1 = Lookup(tr, accents_tab[accent1].name, ph_accent1)) != 0) { | if ((flags1 = Lookup(tr, accents_tab[accent1].name, ph_accent1)) != 0) { | ||||
if (LookupLetter2(tr, basic_letter, ph_letter1) != 0) { | if (LookupLetter2(tr, basic_letter, ph_letter1) != 0) { | ||||
if (accent2 != 0) { | if (accent2 != 0) { | ||||
flags2 = Lookup(tr, accents_tab[accent2].name, ph_accent2); | flags2 = Lookup(tr, accents_tab[accent2].name, ph_accent2); | ||||
} | } | ||||
} | } | ||||
void LookupLetter(Translator *tr, unsigned int letter, int next_byte, char *ph_buf1, int control) | void LookupLetter(Translator *tr, unsigned int letter, int next_byte, char *ph_buf1, int control) | ||||
{ | { | ||||
// control, bit 0: not the first letter of a word | // control, bit 0: not the first letter of a word | ||||
dict_flags[0] = 0; | dict_flags[0] = 0; | ||||
dict_flags[1] = 0; | dict_flags[1] = 0; | ||||
SetWordStress(tr, ph_buf1, dict_flags, -1, control & 1); | SetWordStress(tr, ph_buf1, dict_flags, -1, control & 1); | ||||
} | } | ||||
// unicode ranges for non-ascii digits 0-9 | // unicode ranges for non-ascii digits 0-9 | ||||
static const int number_ranges[] = { | static const int number_ranges[] = { | ||||
0x660, 0x6f0, // arabic | 0x660, 0x6f0, // arabic | ||||
0 | 0 | ||||
}; // these must be in ascending order | }; // these must be in ascending order | ||||
int NonAsciiNumber(int letter) | int NonAsciiNumber(int letter) | ||||
{ | { | ||||
// Change non-ascii digit into ascii digit '0' to '9', (or -1 if not) | // Change non-ascii digit into ascii digit '0' to '9', (or -1 if not) | ||||
0, 0 | 0, 0 | ||||
}; | }; | ||||
static const char *hex_letters[] = { "'e:j", "b'i:", "s'i:", "d'i:", "'i:", "'ef" }; // names, using phonemes available to all languages | static const char *hex_letters[] = { "'e:j", "b'i:", "s'i:", "d'i:", "'i:", "'ef" }; // names, using phonemes available to all languages | ||||
int IsSuperscript(int letter) | int IsSuperscript(int letter) | ||||
{ | { | ||||
// is this a subscript or superscript letter ? | // is this a subscript or superscript letter ? | ||||
return 0; | return 0; | ||||
} | } | ||||
int TranslateLetter(Translator *tr, char *word, char *phonemes, int control) | int TranslateLetter(Translator *tr, char *word, char *phonemes, int control) | ||||
{ | { | ||||
// get pronunciation for an isolated letter | // get pronunciation for an isolated letter | ||||
} | } | ||||
} | } | ||||
// caution: SetWordStress() etc don't expect phonSWITCH + phoneme table number | // caution: SetWordStress() etc don't expect phonSWITCH + phoneme table number | ||||
if (ph_buf[0] == 0) { | if (ph_buf[0] == 0) { | ||||
return n_bytes; | return n_bytes; | ||||
} | } | ||||
void SetSpellingStress(Translator *tr, char *phonemes, int control, int n_chars) | void SetSpellingStress(Translator *tr, char *phonemes, int control, int n_chars) | ||||
{ | { | ||||
// Individual letter names, reduce the stress of some. | // Individual letter names, reduce the stress of some. | ||||
*phonemes = 0; | *phonemes = 0; | ||||
} | } | ||||
// Numbers | // Numbers | ||||
static char ph_ordinal2[12]; | static char ph_ordinal2[12]; | ||||
static char ph_ordinal2x[12]; | static char ph_ordinal2x[12]; | ||||
static int CheckDotOrdinal(Translator *tr, char *word, char *word_end, WORD_TAB *wtab, int roman) | static int CheckDotOrdinal(Translator *tr, char *word, char *word_end, WORD_TAB *wtab, int roman) | ||||
{ | { | ||||
int ordinal = 0; | int ordinal = 0; | ||||
int c2; | int c2; | ||||
int nextflags; | int nextflags; | ||||
return ordinal; | return ordinal; | ||||
} | } | ||||
static int hu_number_e(const char *word, int thousandplex, int value) | static int hu_number_e(const char *word, int thousandplex, int value) | ||||
{ | { | ||||
// lang-hu: variant form of numbers when followed by hyphen and a suffix starting with 'a' or 'e' (but not a, e, az, ez, azt, ezt, att. ett | // lang-hu: variant form of numbers when followed by hyphen and a suffix starting with 'a' or 'e' (but not a, e, az, ez, azt, ezt, att. ett | ||||
return 0; | return 0; | ||||
} | } | ||||
int TranslateRoman(Translator *tr, char *word, char *ph_out, WORD_TAB *wtab) | int TranslateRoman(Translator *tr, char *word, char *ph_out, WORD_TAB *wtab) | ||||
{ | { | ||||
int c; | int c; | ||||
if (acc > tr->langopts.max_roman) | if (acc > tr->langopts.max_roman) | ||||
return 0; | return 0; | ||||
Lookup(tr, "_roman", ph_roman); // precede by "roman" if _rom is defined in *_list | Lookup(tr, "_roman", ph_roman); // precede by "roman" if _rom is defined in *_list | ||||
p = &ph_out[0]; | p = &ph_out[0]; | ||||
return 1; | return 1; | ||||
} | } | ||||
static const char *M_Variant(int value) | static const char *M_Variant(int value) | ||||
{ | { | ||||
// returns M, or perhaps MA or MB for some cases | // returns M, or perhaps MA or MB for some cases | ||||
if ((teens == 0) && ((value % 10) == 1)) | if ((teens == 0) && ((value % 10) == 1)) | ||||
return "1M"; | return "1M"; | ||||
break; | break; | ||||
case 2: // lang=cs,sk | case 2: // lang=cs,sk | ||||
if ((value >= 2) && (value <= 4)) | if ((value >= 2) && (value <= 4)) | ||||
return "0MA"; | return "0MA"; | ||||
break; | break; | ||||
case 3: // lang=pl | case 3: // lang=pl | ||||
if ((teens == 0) && (((value % 10) >= 2) && ((value % 10) <= 4))) | if ((teens == 0) && (((value % 10) >= 2) && ((value % 10) <= 4))) | ||||
return "0MA"; | return "0MA"; | ||||
break; | break; | ||||
case 4: // lang=lt | case 4: // lang=lt | ||||
if ((teens == 1) || ((value % 10) == 0)) | if ((teens == 1) || ((value % 10) == 0)) | ||||
return "0MB"; | return "0MB"; | ||||
if ((value % 10) == 1) | if ((value % 10) == 1) | ||||
return "0MA"; | return "0MA"; | ||||
break; | break; | ||||
case 5: // lang=bs,hr,sr | case 5: // lang=bs,hr,sr | ||||
if (teens == 0) { | if (teens == 0) { | ||||
if ((value % 10) == 1) | if ((value % 10) == 1) | ||||
return "0M"; | return "0M"; | ||||
} | } | ||||
static int LookupThousands(Translator *tr, int value, int thousandplex, int thousands_exact, char *ph_out) | static int LookupThousands(Translator *tr, int value, int thousandplex, int thousands_exact, char *ph_out) | ||||
{ | { | ||||
// thousands_exact: bit 0 no hundreds,tens,or units, bit 1 ordinal numberr | // thousands_exact: bit 0 no hundreds,tens,or units, bit 1 ordinal numberr | ||||
return found_value; | return found_value; | ||||
} | } | ||||
static int LookupNum2(Translator *tr, int value, int thousandplex, const int control, char *ph_out) | static int LookupNum2(Translator *tr, int value, int thousandplex, const int control, char *ph_out) | ||||
{ | { | ||||
// Lookup a 2 digit number | // Lookup a 2 digit number | ||||
if (found) { | if (found) { | ||||
ph_tens[0] = 0; | ph_tens[0] = 0; | ||||
} else { | } else { | ||||
if (is_ordinal) { | if (is_ordinal) { | ||||
sprintf(string, "_%dX%c", tens, ord_type); | sprintf(string, "_%dX%c", tens, ord_type); | ||||
if (Lookup(tr, string, ph_tens) != 0) { | if (Lookup(tr, string, ph_tens) != 0) { | ||||
return used_and; | return used_and; | ||||
} | } | ||||
static int LookupNum3(Translator *tr, int value, char *ph_out, int suppress_null, int thousandplex, int control) | static int LookupNum3(Translator *tr, int value, char *ph_out, int suppress_null, int thousandplex, int control) | ||||
{ | { | ||||
// Translate a 3 digit number | // Translate a 3 digit number | ||||
} | } | ||||
} | } | ||||
buf2[0] = 0; | buf2[0] = 0; | ||||
if ((tensunits != 0) || (suppress_null == 0)) { | if ((tensunits != 0) || (suppress_null == 0)) { | ||||
return 0; | return 0; | ||||
} | } | ||||
bool CheckThousandsGroup(char *word, int group_len) | bool CheckThousandsGroup(char *word, int group_len) | ||||
{ | { | ||||
// Is this a group of 3 digits which looks like a thousands group? | // Is this a group of 3 digits which looks like a thousands group? | ||||
return true; | return true; | ||||
} | } | ||||
static int TranslateNumber_1(Translator *tr, char *word, char *ph_out, unsigned int *flags, WORD_TAB *wtab, int control) | static int TranslateNumber_1(Translator *tr, char *word, char *ph_out, unsigned int *flags, WORD_TAB *wtab, int control) | ||||
{ | { | ||||
// Number translation with various options | // Number translation with various options | ||||
ph_append[0] = 0; | ph_append[0] = 0; | ||||
ph_buf2[0] = 0; | ph_buf2[0] = 0; | ||||
if ((word[0] == '0') && (prev_thousands == 0) && (word[1] != ' ') && (word[1] != tr->langopts.decimal_sep)) { | if ((word[0] == '0') && (prev_thousands == 0) && (word[1] != ' ') && (word[1] != tr->langopts.decimal_sep)) { | ||||
if ((n_digits == 2) && (word[3] == ':') && IsDigit09(word[5]) && isspace(word[7])) { | if ((n_digits == 2) && (word[3] == ':') && IsDigit09(word[5]) && isspace(word[7])) { | ||||
// looks like a time 02:30, omit the leading zero | // looks like a time 02:30, omit the leading zero | ||||
{ | { | ||||
case NUM_DFRACTION_4: | case NUM_DFRACTION_4: | ||||
max_decimal_count = 5; | max_decimal_count = 5; | ||||
// fallthrough | |||||
case NUM_DFRACTION_2: | case NUM_DFRACTION_2: | ||||
// French/Polish decimal fraction | // French/Polish decimal fraction | ||||
while (word[n_digits] == '0') { | while (word[n_digits] == '0') { | ||||
n_digits += decimal_count; | n_digits += decimal_count; | ||||
} | } | ||||
break; | break; | ||||
case NUM_DFRACTION_1: // italian, say "hundredths" if leading zero | case NUM_DFRACTION_1: // italian, say "hundredths" if leading zero | ||||
case NUM_DFRACTION_5: // hungarian, always say "tenths" etc. | case NUM_DFRACTION_5: // hungarian, always say "tenths" etc. | ||||
case NUM_DFRACTION_6: // kazakh, always say "tenths" etc, before the decimal fraction | case NUM_DFRACTION_6: // kazakh, always say "tenths" etc, before the decimal fraction | ||||
strcat(ph_out, ph_buf); | strcat(ph_out, ph_buf); | ||||
n_digits += decimal_count; | n_digits += decimal_count; | ||||
break; | break; | ||||
case NUM_DFRACTION_3: | case NUM_DFRACTION_3: | ||||
// Romanian decimal fractions | // Romanian decimal fractions | ||||
if ((decimal_count <= 4) && (word[n_digits] != '0')) { | if ((decimal_count <= 4) && (word[n_digits] != '0')) { | ||||
n_digits += decimal_count; | n_digits += decimal_count; | ||||
} | } | ||||
break; | break; | ||||
case NUM_DFRACTION_7: | case NUM_DFRACTION_7: | ||||
// alternative form of decimal fraction digits, except the final digit | // alternative form of decimal fraction digits, except the final digit | ||||
while (decimal_count-- > 1) { | while (decimal_count-- > 1) { | ||||
return 1; | return 1; | ||||
} | } | ||||
int TranslateNumber(Translator *tr, char *word1, char *ph_out, unsigned int *flags, WORD_TAB *wtab, int control) | int TranslateNumber(Translator *tr, char *word1, char *ph_out, unsigned int *flags, WORD_TAB *wtab, int control) | ||||
{ | { | ||||
if ((option_sayas == SAYAS_DIGITS1) || (wtab[0].flags & FLAG_INDIVIDUAL_DIGITS)) | if ((option_sayas == SAYAS_DIGITS1) || (wtab[0].flags & FLAG_INDIVIDUAL_DIGITS)) |
#include "synthesize.h" | #include "synthesize.h" | ||||
#include "translate.h" | #include "translate.h" | ||||
const unsigned char pause_phonemes[8] = { 0, phonPAUSE_VSHORT, phonPAUSE_SHORT, phonPAUSE, phonPAUSE_LONG, phonGLOTTALSTOP, phonPAUSE_LONG, phonPAUSE_LONG }; | const unsigned char pause_phonemes[8] = { 0, phonPAUSE_VSHORT, phonPAUSE_SHORT, phonPAUSE, phonPAUSE_LONG, phonGLOTTALSTOP, phonPAUSE_LONG, phonPAUSE_LONG }; | ||||
extern int n_ph_list2; | extern int n_ph_list2; | ||||
extern PHONEME_LIST2 ph_list2[N_PHONEME_LIST]; // first stage of text->phonemes | extern PHONEME_LIST2 ph_list2[N_PHONEME_LIST]; // first stage of text->phonemes | ||||
static int SubstitutePhonemes(Translator *tr, PHONEME_LIST *plist_out) | static int SubstitutePhonemes(Translator *tr, PHONEME_LIST *plist_out) | ||||
{ | { | ||||
// 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 | ||||
return n_plist_out; | return n_plist_out; | ||||
} | } | ||||
void MakePhonemeList(Translator *tr, int post_pause, int start_sentence) | void MakePhonemeList(Translator *tr, int post_pause, int start_sentence) | ||||
{ | { | ||||
int ix = 0; | int ix = 0; | ||||
int j; | int j; | ||||
int insert_ph = 0; | int insert_ph = 0; |
#include <locale.h> | #include <locale.h> | ||||
#define N_XML_BUF 500 | #define N_XML_BUF 500 | ||||
static const char *xmlbase = ""; // base URL from <speak> | static const char *xmlbase = ""; // base URL from <speak> | ||||
static int namedata_ix = 0; | static int namedata_ix = 0; | ||||
static int n_namedata = 0; | static int n_namedata = 0; | ||||
char *namedata = NULL; | char *namedata = NULL; | ||||
static FILE *f_input = NULL; | static FILE *f_input = NULL; | ||||
static int ungot_char2 = 0; | static int ungot_char2 = 0; | ||||
unsigned char *p_textinput; | unsigned char *p_textinput; | ||||
0 }; | 0 }; | ||||
// indexed by (entry num. in punct_chars) + 1 | // indexed by (entry num. in punct_chars) + 1 | ||||
// bits 0-7 pause x 10mS, bits 12-14 intonation type, bit 15 don't need following space or bracket | // bits 0-7 pause x 10mS, bits 12-14 intonation type, bit 15 don't need following space or bracket | ||||
static const unsigned int punct_attributes[] = { 0, | static const unsigned int punct_attributes[] = { 0, | ||||
CLAUSE_SEMICOLON, // spare | CLAUSE_SEMICOLON, // spare | ||||
0 }; | 0 }; | ||||
// stack for language and voice properties | // stack for language and voice properties | ||||
// frame 0 is for the defaults, before any ssml tags. | // frame 0 is for the defaults, before any ssml tags. | ||||
typedef struct { | typedef struct { | ||||
static char base_voice_variant_name[40] = { 0 }; | static char base_voice_variant_name[40] = { 0 }; | ||||
static char current_voice_id[40] = { 0 }; | static char current_voice_id[40] = { 0 }; | ||||
#define N_PARAM_STACK 20 | #define N_PARAM_STACK 20 | ||||
static int n_param_stack; | static int n_param_stack; | ||||
PARAM_STACK param_stack[N_PARAM_STACK]; | PARAM_STACK param_stack[N_PARAM_STACK]; | ||||
0, // voice type | 0, // voice type | ||||
}; | }; | ||||
// additional Latin characters beyond the ascii character set | // additional Latin characters beyond the ascii character set | ||||
#define MAX_WALPHA 0x24f | #define MAX_WALPHA 0x24f | ||||
// indexed by character - 0x80 | // indexed by character - 0x80 | ||||
0, 0 | 0, 0 | ||||
}; | }; | ||||
#ifdef NEED_WCHAR_FUNCTIONS | #ifdef NEED_WCHAR_FUNCTIONS | ||||
// use ctype.h functions for Latin1 (character < 0x100) | // use ctype.h functions for Latin1 (character < 0x100) | ||||
} | } | ||||
#endif | #endif | ||||
// use internal data for iswalpha up to U+024F | // use internal data for iswalpha up to U+024F | ||||
// iswalpha() on Windows is unreliable (U+AA, U+BA). | // iswalpha() on Windows is unreliable (U+AA, U+BA). | ||||
int iswalpha2(int c) | int iswalpha2(int c) | ||||
return 0; | return 0; | ||||
} | } | ||||
static void GetC_unget(int c) | static void GetC_unget(int c) | ||||
{ | { | ||||
// This is only called with UTF8 input, not wchar input | // This is only called with UTF8 input, not wchar input | ||||
return end_of_input; | return end_of_input; | ||||
} | } | ||||
static int GetC_get(void) | static int GetC_get(void) | ||||
{ | { | ||||
unsigned int c; | unsigned int c; | ||||
return 0; | return 0; | ||||
} | } | ||||
static int GetC(void) | static int GetC(void) | ||||
{ | { | ||||
// Returns a unicode wide character | // Returns a unicode wide character | ||||
return c1; | return c1; | ||||
} | } | ||||
static void UngetC(int c) | static void UngetC(int c) | ||||
{ | { | ||||
ungot_char = c; | ungot_char = c; | ||||
} | } | ||||
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 | ||||
return buf; | return buf; | ||||
} | } | ||||
static const char *LookupSpecial(Translator *tr, const char *string, char *text_out) | static const char *LookupSpecial(Translator *tr, const char *string, char *text_out) | ||||
{ | { | ||||
unsigned int flags[2]; | unsigned int flags[2]; | ||||
return NULL; | return NULL; | ||||
} | } | ||||
static const char *LookupCharName(Translator *tr, int c, int only) | static const char *LookupCharName(Translator *tr, int c, int only) | ||||
{ | { | ||||
// 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 | ||||
return acc; | return acc; | ||||
} | } | ||||
static int LoadSoundFile(const char *fname, int index) | static int LoadSoundFile(const char *fname, int index) | ||||
{ | { | ||||
FILE *f; | FILE *f; | ||||
return 0; | return 0; | ||||
} | } | ||||
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 | ||||
return -1; | return -1; | ||||
} | } | ||||
static int LoadSoundFile2(const char *fname) | static int LoadSoundFile2(const char *fname) | ||||
{ | { | ||||
// 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 | ||||
return slot; | return slot; | ||||
} | } | ||||
static int AnnouncePunctuation(Translator *tr, int c1, int *c2_ptr, char *output, int *bufix, int end_clause) | static int AnnouncePunctuation(Translator *tr, int c1, int *c2_ptr, char *output, int *bufix, int end_clause) | ||||
{ | { | ||||
// announce punctuation names | // announce punctuation names | ||||
// these tags have no effect if they are self-closing, eg. <voice /> | // these tags have no effect if they are self-closing, eg. <voice /> | ||||
static char ignore_if_self_closing[] = { 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0 }; | static char ignore_if_self_closing[] = { 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0 }; | ||||
static MNEM_TAB ssmltags[] = { | static MNEM_TAB ssmltags[] = { | ||||
{ "speak", SSML_SPEAK }, | { "speak", SSML_SPEAK }, | ||||
{ "voice", SSML_VOICE }, | { "voice", SSML_VOICE }, | ||||
{ NULL, 0 } | { NULL, 0 } | ||||
}; | }; | ||||
static const char *VoiceFromStack() | static const char *VoiceFromStack() | ||||
{ | { | ||||
// 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 | ||||
return v_id; | return v_id; | ||||
} | } | ||||
static void ProcessParamStack(char *outbuf, int *outix) | static void ProcessParamStack(char *outbuf, int *outix) | ||||
{ | { | ||||
// Set the speech parameters from the parameter stack | // Set the speech parameters from the parameter stack | ||||
int new_parameters[N_SPEECH_PARAM]; | int new_parameters[N_SPEECH_PARAM]; | ||||
static char cmd_letter[N_SPEECH_PARAM] = { 0, 'S', 'A', 'P', 'R', 0, 'C', 0, 0, 0, 0, 0, 'F' }; // embedded command letters | static char cmd_letter[N_SPEECH_PARAM] = { 0, 'S', 'A', 'P', 'R', 0, 'C', 0, 0, 0, 0, 0, 'F' }; // embedded command letters | ||||
for (param = 0; param < N_SPEECH_PARAM; param++) | for (param = 0; param < N_SPEECH_PARAM; param++) | ||||
new_parameters[param] = -1; | new_parameters[param] = -1; | ||||
case espeakPUNCTUATION: | case espeakPUNCTUATION: | ||||
option_punctuation = value-1; | option_punctuation = value-1; | ||||
break; | break; | ||||
case espeakCAPITALS: | case espeakCAPITALS: | ||||
option_capitals = value; | option_capitals = value; | ||||
break; | break; | ||||
case espeakRATE: | case espeakRATE: | ||||
case espeakVOLUME: | case espeakVOLUME: | ||||
case espeakPITCH: | case espeakPITCH: | ||||
} | } | ||||
} | } | ||||
static PARAM_STACK *PushParamStack(int tag_type) | static PARAM_STACK *PushParamStack(int tag_type) | ||||
{ | { | ||||
int ix; | int ix; | ||||
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 | ||||
ProcessParamStack(outbuf, outix); | ProcessParamStack(outbuf, outix); | ||||
} | } | ||||
static wchar_t *GetSsmlAttribute(wchar_t *pw, const char *name) | static wchar_t *GetSsmlAttribute(wchar_t *pw, const char *name) | ||||
{ | { | ||||
// Gets the value string for an attribute. | // Gets the value string for an attribute. | ||||
return NULL; | return NULL; | ||||
} | } | ||||
static int attrcmp(const wchar_t *string1, const char *string2) | static int attrcmp(const wchar_t *string1, const char *string2) | ||||
{ | { | ||||
int ix; | int ix; | ||||
return 1; | return 1; | ||||
} | } | ||||
static int attrlookup(const wchar_t *string1, const MNEM_TAB *mtab) | static int attrlookup(const wchar_t *string1, const MNEM_TAB *mtab) | ||||
{ | { | ||||
int ix; | int ix; | ||||
return mtab[ix].value; | return mtab[ix].value; | ||||
} | } | ||||
static int attrnumber(const wchar_t *pw, int default_value, int type) | static int attrnumber(const wchar_t *pw, int default_value, int type) | ||||
{ | { | ||||
int value = 0; | int value = 0; | ||||
return value; | return value; | ||||
} | } | ||||
static int attrcopy_utf8(char *buf, const wchar_t *pw, int len) | static int attrcopy_utf8(char *buf, const wchar_t *pw, int len) | ||||
{ | { | ||||
// Convert attribute string into utf8, write to buf, and return its utf8 length | // Convert attribute string into utf8, write to buf, and return its utf8 length | ||||
return ix; | return ix; | ||||
} | } | ||||
static int attr_prosody_value(int param_type, const wchar_t *pw, int *value_out) | static int attr_prosody_value(int param_type, const wchar_t *pw, int *value_out) | ||||
{ | { | ||||
int sign = 0; | int sign = 0; | ||||
return sign; // -1, 0, or 1 | return sign; // -1, 0, or 1 | ||||
} | } | ||||
int AddNameData(const char *name, int wide) | int AddNameData(const char *name, int wide) | ||||
{ | { | ||||
// Add the name to the namedata and return its position | // Add the name to the namedata and return its position | ||||
return ix; | return ix; | ||||
} | } | ||||
void SetVoiceStack(espeak_VOICE *v, const char *variant_name) | void SetVoiceStack(espeak_VOICE *v, const char *variant_name) | ||||
{ | { | ||||
SSML_STACK *sp; | SSML_STACK *sp; | ||||
memcpy(&base_voice, ¤t_voice_selected, sizeof(base_voice)); | memcpy(&base_voice, ¤t_voice_selected, sizeof(base_voice)); | ||||
} | } | ||||
static int GetVoiceAttributes(wchar_t *pw, int tag_type) | static int GetVoiceAttributes(wchar_t *pw, int tag_type) | ||||
{ | { | ||||
// Determines whether voice attribute are specified in this tag, and if so, whether this means | // Determines whether voice attribute are specified in this tag, and if so, whether this means | ||||
return 0; | return 0; | ||||
} | } | ||||
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; | ||||
NULL, mnem_rate, mnem_volume, mnem_pitch, mnem_range | NULL, mnem_rate, mnem_volume, mnem_pitch, mnem_range | ||||
}; | }; | ||||
if ((value = attrlookup(attr1, mnem_tabs[param_type])) >= 0) { | if ((value = attrlookup(attr1, mnem_tabs[param_type])) >= 0) { | ||||
// 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; | ||||
} | } | ||||
} | } | ||||
static int ReplaceKeyName(char *outbuf, int index, int *outix) | static int ReplaceKeyName(char *outbuf, int index, int *outix) | ||||
{ | { | ||||
// Replace some key-names by single characters, so they can be pronounced in different languages | // Replace some key-names by single characters, so they can be pronounced in different languages | ||||
return 0; | return 0; | ||||
} | } | ||||
static int ProcessSsmlTag(wchar_t *xml_buf, char *outbuf, int *outix, int n_outbuf, int self_closing) | static int ProcessSsmlTag(wchar_t *xml_buf, char *outbuf, int *outix, int n_outbuf, int self_closing) | ||||
{ | { | ||||
// xml_buf is the tag and attributes with a zero terminator in place of the original '>' | // xml_buf is the tag and attributes with a zero terminator in place of the original '>' | ||||
return 0; | return 0; | ||||
} | } | ||||
voice_change_flag = 0; | voice_change_flag = 0; | ||||
terminator = CLAUSE_NONE; | terminator = CLAUSE_NONE; | ||||
ssml_sp = &ssml_stack[n_ssml_stack-1]; | ssml_sp = &ssml_stack[n_ssml_stack-1]; | ||||
} | } | ||||
ProcessParamStack(outbuf, outix); | ProcessParamStack(outbuf, outix); | ||||
break; | break; | ||||
case SSML_PROSODY: | case SSML_PROSODY: | ||||
sp = PushParamStack(tag_type); | sp = PushParamStack(tag_type); | ||||
ProcessParamStack(outbuf, outix); | ProcessParamStack(outbuf, outix); | ||||
break; | break; | ||||
case SSML_EMPHASIS: | case SSML_EMPHASIS: | ||||
sp = PushParamStack(tag_type); | sp = PushParamStack(tag_type); | ||||
value = 3; // default is "moderate" | value = 3; // default is "moderate" | ||||
} | } | ||||
ProcessParamStack(outbuf, outix); | ProcessParamStack(outbuf, outix); | ||||
break; | break; | ||||
case SSML_STYLE + SSML_CLOSE: | case SSML_STYLE + SSML_CLOSE: | ||||
case SSML_PROSODY + SSML_CLOSE: | case SSML_PROSODY + SSML_CLOSE: | ||||
case SSML_EMPHASIS + SSML_CLOSE: | case SSML_EMPHASIS + SSML_CLOSE: | ||||
PopParamStack(tag_type, outbuf, outix); | PopParamStack(tag_type, outbuf, outix); | ||||
break; | break; | ||||
case SSML_PHONEME: | case SSML_PHONEME: | ||||
attr1 = GetSsmlAttribute(px, "alphabet"); | attr1 = GetSsmlAttribute(px, "alphabet"); | ||||
attr2 = GetSsmlAttribute(px, "ph"); | attr2 = GetSsmlAttribute(px, "ph"); | ||||
outbuf[(*outix)++] = ']'; | outbuf[(*outix)++] = ']'; | ||||
} | } | ||||
break; | break; | ||||
case SSML_SAYAS: | case SSML_SAYAS: | ||||
attr1 = GetSsmlAttribute(px, "interpret-as"); | attr1 = GetSsmlAttribute(px, "interpret-as"); | ||||
attr2 = GetSsmlAttribute(px, "format"); | attr2 = GetSsmlAttribute(px, "format"); | ||||
sayas_start = *outix; | sayas_start = *outix; | ||||
sayas_mode = value; // punctuation doesn't end clause during SAY-AS | sayas_mode = value; // punctuation doesn't end clause during SAY-AS | ||||
break; | break; | ||||
case SSML_SAYAS + SSML_CLOSE: | case SSML_SAYAS + SSML_CLOSE: | ||||
if (sayas_mode == SAYAS_KEY) { | if (sayas_mode == SAYAS_KEY) { | ||||
outbuf[*outix] = 0; | outbuf[*outix] = 0; | ||||
outbuf[(*outix)++] = 'Y'; | outbuf[(*outix)++] = 'Y'; | ||||
sayas_mode = 0; | sayas_mode = 0; | ||||
break; | break; | ||||
case SSML_SUB: | case SSML_SUB: | ||||
if ((attr1 = GetSsmlAttribute(px, "alias")) != NULL) { | if ((attr1 = GetSsmlAttribute(px, "alias")) != NULL) { | ||||
// use the alias rather than the text | // use the alias rather than the text | ||||
*outix += attrcopy_utf8(&outbuf[*outix], attr1, n_outbuf-*outix); | *outix += attrcopy_utf8(&outbuf[*outix], attr1, n_outbuf-*outix); | ||||
} | } | ||||
break; | break; | ||||
case SSML_IGNORE_TEXT: | case SSML_IGNORE_TEXT: | ||||
ignore_text = 1; | ignore_text = 1; | ||||
break; | break; | ||||
case SSML_SUB + SSML_CLOSE: | case SSML_SUB + SSML_CLOSE: | ||||
case SSML_IGNORE_TEXT + SSML_CLOSE: | case SSML_IGNORE_TEXT + SSML_CLOSE: | ||||
ignore_text = 0; | ignore_text = 0; | ||||
break; | break; | ||||
case SSML_MARK: | case SSML_MARK: | ||||
if ((attr1 = GetSsmlAttribute(px, "name")) != NULL) { | if ((attr1 = GetSsmlAttribute(px, "name")) != NULL) { | ||||
// add name to circular buffer of marker names | // add name to circular buffer of marker names | ||||
} | } | ||||
} | } | ||||
break; | break; | ||||
case SSML_AUDIO: | case SSML_AUDIO: | ||||
sp = PushParamStack(tag_type); | sp = PushParamStack(tag_type); | ||||
else | else | ||||
audio_text = 1; | audio_text = 1; | ||||
return CLAUSE_NONE; | return CLAUSE_NONE; | ||||
case SSML_AUDIO + SSML_CLOSE: | case SSML_AUDIO + SSML_CLOSE: | ||||
PopParamStack(tag_type, outbuf, outix); | PopParamStack(tag_type, outbuf, outix); | ||||
audio_text = 0; | audio_text = 0; | ||||
return CLAUSE_NONE; | return CLAUSE_NONE; | ||||
case SSML_BREAK: | case SSML_BREAK: | ||||
value = 21; | value = 21; | ||||
terminator = CLAUSE_NONE; | terminator = CLAUSE_NONE; | ||||
return terminator + value; | return terminator + value; | ||||
} | } | ||||
break; | break; | ||||
case SSML_SPEAK: | case SSML_SPEAK: | ||||
if ((attr1 = GetSsmlAttribute(px, "xml:base")) != NULL) { | if ((attr1 = GetSsmlAttribute(px, "xml:base")) != NULL) { | ||||
attrcopy_utf8(buf, attr1, sizeof(buf)); | attrcopy_utf8(buf, attr1, sizeof(buf)); | ||||
if (GetVoiceAttributes(px, tag_type) == 0) | if (GetVoiceAttributes(px, tag_type) == 0) | ||||
return 0; // no voice change | return 0; // no voice change | ||||
return CLAUSE_VOICE; | return CLAUSE_VOICE; | ||||
case SSML_VOICE: | case SSML_VOICE: | ||||
if (GetVoiceAttributes(px, tag_type) == 0) | if (GetVoiceAttributes(px, tag_type) == 0) | ||||
return 0; // no voice change | return 0; // no voice change | ||||
return CLAUSE_VOICE; | return CLAUSE_VOICE; | ||||
case SSML_SPEAK + SSML_CLOSE: | case SSML_SPEAK + SSML_CLOSE: | ||||
// unwind stack until the previous <voice> or <speak> tag | // unwind stack until the previous <voice> or <speak> tag | ||||
while ((n_ssml_stack > 1) && (ssml_stack[n_ssml_stack-1].tag_type != SSML_SPEAK)) | while ((n_ssml_stack > 1) && (ssml_stack[n_ssml_stack-1].tag_type != SSML_SPEAK)) | ||||
n_ssml_stack--; | n_ssml_stack--; | ||||
return CLAUSE_PERIOD + GetVoiceAttributes(px, tag_type); | return CLAUSE_PERIOD + GetVoiceAttributes(px, tag_type); | ||||
case SSML_VOICE + SSML_CLOSE: | case SSML_VOICE + SSML_CLOSE: | ||||
// unwind stack until the previous <voice> or <speak> tag | // unwind stack until the previous <voice> or <speak> tag | ||||
while ((n_ssml_stack > 1) && (ssml_stack[n_ssml_stack-1].tag_type != SSML_VOICE)) | while ((n_ssml_stack > 1) && (ssml_stack[n_ssml_stack-1].tag_type != SSML_VOICE)) | ||||
terminator = 0; // ?? Sentence intonation, but no pause ?? | terminator = 0; // ?? Sentence intonation, but no pause ?? | ||||
return terminator + GetVoiceAttributes(px, tag_type); | return terminator + GetVoiceAttributes(px, tag_type); | ||||
case HTML_BREAK: | case HTML_BREAK: | ||||
case HTML_BREAK + SSML_CLOSE: | case HTML_BREAK + SSML_CLOSE: | ||||
return CLAUSE_COLON; | return CLAUSE_COLON; | ||||
case SSML_SENTENCE: | case SSML_SENTENCE: | ||||
if (ssml_sp->tag_type == SSML_SENTENCE) { | if (ssml_sp->tag_type == SSML_SENTENCE) { | ||||
// new sentence implies end-of-sentence | // new sentence implies end-of-sentence | ||||
} | } | ||||
voice_change_flag |= GetVoiceAttributes(px, tag_type); | voice_change_flag |= GetVoiceAttributes(px, tag_type); | ||||
return CLAUSE_PARAGRAPH + voice_change_flag; | return CLAUSE_PARAGRAPH + voice_change_flag; | ||||
case SSML_PARAGRAPH: | case SSML_PARAGRAPH: | ||||
if (ssml_sp->tag_type == SSML_SENTENCE) { | if (ssml_sp->tag_type == SSML_SENTENCE) { | ||||
// new paragraph implies end-of-sentence or end-of-paragraph | // new paragraph implies end-of-sentence or end-of-paragraph | ||||
} | } | ||||
voice_change_flag |= GetVoiceAttributes(px, tag_type); | voice_change_flag |= GetVoiceAttributes(px, tag_type); | ||||
return CLAUSE_PARAGRAPH + voice_change_flag; | return CLAUSE_PARAGRAPH + voice_change_flag; | ||||
case SSML_SENTENCE + SSML_CLOSE: | case SSML_SENTENCE + SSML_CLOSE: | ||||
if (ssml_sp->tag_type == SSML_SENTENCE) { | if (ssml_sp->tag_type == SSML_SENTENCE) { | ||||
// end of a sentence which specified a language | // end of a sentence which specified a language | ||||
voice_change_flag = GetVoiceAttributes(px, tag_type); | voice_change_flag = GetVoiceAttributes(px, tag_type); | ||||
} | } | ||||
return CLAUSE_PERIOD + voice_change_flag; | return CLAUSE_PERIOD + voice_change_flag; | ||||
case SSML_PARAGRAPH + SSML_CLOSE: | case SSML_PARAGRAPH + SSML_CLOSE: | ||||
if ((ssml_sp->tag_type == SSML_SENTENCE) || (ssml_sp->tag_type == SSML_PARAGRAPH)) { | if ((ssml_sp->tag_type == SSML_SENTENCE) || (ssml_sp->tag_type == SSML_PARAGRAPH)) { | ||||
// End of a paragraph which specified a language. | // End of a paragraph which specified a language. | ||||
return 0; | return 0; | ||||
} | } | ||||
static void RemoveChar(char *p) | static void RemoveChar(char *p) | ||||
{ | { | ||||
// Replace a UTF-8 character by spaces | // Replace a UTF-8 character by spaces | ||||
memset(p, ' ', utf8_in(&c, p)); | memset(p, ' ', utf8_in(&c, p)); | ||||
} | } | ||||
static MNEM_TAB xml_char_mnemonics[] = { | static MNEM_TAB xml_char_mnemonics[] = { | ||||
{ "gt", '>' }, | { "gt", '>' }, | ||||
{ "lt", 0xe000 + '<' }, // private usage area, to avoid confusion with XML tag | { "lt", 0xe000 + '<' }, // private usage area, to avoid confusion with XML tag | ||||
{ NULL, -1 } | { NULL, -1 } | ||||
}; | }; | ||||
int ReadClause(Translator *tr, FILE *f_in, char *buf, short *charix, int *charix_top, int n_buf, int *tone_type, char *voice_change) | int ReadClause(Translator *tr, FILE *f_in, char *buf, short *charix, int *charix_top, int n_buf, int *tone_type, char *voice_change) | ||||
{ | { | ||||
/* Find the end of the current clause. | /* Find the end of the current clause. | ||||
return CLAUSE_EOF; // end of file | return CLAUSE_EOF; // end of file | ||||
} | } | ||||
void InitNamedata(void) | void InitNamedata(void) | ||||
{ | { | ||||
namedata_ix = 0; | namedata_ix = 0; | ||||
} | } | ||||
} | } | ||||
void InitText2(void) | void InitText2(void) | ||||
{ | { | ||||
int param; | int param; |
extern void DoSonicSpeed(int value); | extern void DoSonicSpeed(int value); | ||||
extern int saved_parameters[]; | extern int saved_parameters[]; | ||||
// convert from words-per-minute to internal speed factor | // convert from words-per-minute to internal speed factor | ||||
// Use this to calibrate speed for wpm 80-350 | // Use this to calibrate speed for wpm 80-350 | ||||
static unsigned char speed_lookup[] = { | static unsigned char speed_lookup[] = { | ||||
9, 9, 8, 8, 8, // 355 | 9, 9, 8, 8, 8, // 355 | ||||
}; | }; | ||||
// speed_factor1 adjustments for speeds 350 to 374: pauses | // speed_factor1 adjustments for speeds 350 to 374: pauses | ||||
static unsigned char pause_factor_350[] = { | static unsigned char pause_factor_350[] = { | ||||
22, 22, 22, 22, 22, 22, 22, 21, 21, 21, // 350 | 22, 22, 22, 22, 22, 22, 22, 21, 21, 21, // 350 | ||||
static int speed2 = 121; | static int speed2 = 121; | ||||
static int speed3 = 118; | static int speed3 = 118; | ||||
#if HAVE_SONIC_H | #if HAVE_SONIC_H | ||||
void SetSpeed(int control) | void SetSpeed(int control) | ||||
embedded_value[EMBED_S2] = new_value; | embedded_value[EMBED_S2] = new_value; | ||||
SetSpeed(3); | SetSpeed(3); | ||||
break; | break; | ||||
case espeakVOLUME: | case espeakVOLUME: | ||||
embedded_value[EMBED_A] = new_value; | embedded_value[EMBED_A] = new_value; | ||||
GetAmplitude(); | GetAmplitude(); | ||||
break; | break; | ||||
case espeakPITCH: | case espeakPITCH: | ||||
if (new_value > 99) new_value = 99; | if (new_value > 99) new_value = 99; | ||||
if (new_value < 0) new_value = 0; | if (new_value < 0) new_value = 0; | ||||
embedded_value[EMBED_P] = new_value; | embedded_value[EMBED_P] = new_value; | ||||
break; | break; | ||||
case espeakRANGE: | case espeakRANGE: | ||||
if (new_value > 99) new_value = 99; | if (new_value > 99) new_value = 99; | ||||
embedded_value[EMBED_R] = new_value; | embedded_value[EMBED_R] = new_value; | ||||
break; | break; | ||||
case espeakLINELENGTH: | case espeakLINELENGTH: | ||||
option_linelength = new_value; | option_linelength = new_value; | ||||
break; | break; | ||||
case espeakWORDGAP: | case espeakWORDGAP: | ||||
option_wordgap = new_value; | option_wordgap = new_value; | ||||
break; | break; | ||||
case espeakINTONATION: | case espeakINTONATION: | ||||
if ((new_value & 0xff) != 0) | if ((new_value & 0xff) != 0) | ||||
translator->langopts.intonation_group = new_value & 0xff; | translator->langopts.intonation_group = new_value & 0xff; | ||||
option_tone_flags = new_value; | option_tone_flags = new_value; | ||||
break; | break; | ||||
default: | default: | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
static void DoEmbedded2(int *embix) | static void DoEmbedded2(int *embix) | ||||
{ | { | ||||
// There were embedded commands in the text at this point | // There were embedded commands in the text at this point | ||||
} while ((word & 0x80) == 0); | } while ((word & 0x80) == 0); | ||||
} | } | ||||
void CalcLengths(Translator *tr) | void CalcLengths(Translator *tr) | ||||
{ | { | ||||
int ix; | int ix; | ||||
case phPAUSE: | case phPAUSE: | ||||
last_pitch = 0; | last_pitch = 0; | ||||
break; | break; | ||||
case phSTOP: | case phSTOP: | ||||
last_pitch = 0; | last_pitch = 0; | ||||
if (prev->type == phFRICATIVE) | if (prev->type == phFRICATIVE) | ||||
if (p->synthflags & SFLAG_LENGTHEN) | if (p->synthflags & SFLAG_LENGTHEN) | ||||
p->prepause += tr->langopts.long_stop; | p->prepause += tr->langopts.long_stop; | ||||
break; | break; | ||||
case phVFRICATIVE: | case phVFRICATIVE: | ||||
case phFRICATIVE: | case phFRICATIVE: | ||||
if (p->newword) { | if (p->newword) { | ||||
p->length = (255 + prev->length)/2; | p->length = (255 + prev->length)/2; | ||||
} | } | ||||
break; | break; | ||||
case phVSTOP: | case phVSTOP: | ||||
if (prev->type == phVFRICATIVE || prev->type == phFRICATIVE || (prev->ph->phflags & phSIBILANT) || (prev->type == phLIQUID)) | if (prev->type == phVFRICATIVE || prev->type == phFRICATIVE || (prev->ph->phflags & phSIBILANT) || (prev->type == phLIQUID)) | ||||
p->prepause = 30; | p->prepause = 30; | ||||
} | } | ||||
if ((tr->langopts.word_gap & 0x10) && (p->newword) && (p->prepause < 20)) | if ((tr->langopts.word_gap & 0x10) && (p->newword) && (p->prepause < 20)) | ||||
p->prepause = 20; | p->prepause = 20; | ||||
break; | break; | ||||
case phLIQUID: | case phLIQUID: | ||||
case phNASAL: | case phNASAL: | ||||
p->amp = tr->stress_amps[0]; // unless changed later | p->amp = tr->stress_amps[0]; // unless changed later | ||||
pre_voiced = 0; | pre_voiced = 0; | ||||
} | } | ||||
break; | break; | ||||
case phVOWEL: | case phVOWEL: | ||||
min_drop = 0; | min_drop = 0; | ||||
next2 = &phoneme_list[ix+2]; | next2 = &phoneme_list[ix+2]; | ||||
} | } | ||||
} | } | ||||
if ((end_of_clause == 2) && !(tr->langopts.stress_flags & S_NO_EOC_LENGTHEN)) { | if ((end_of_clause == 2) && !(tr->langopts.stress_flags & S_NO_EOC_LENGTHEN)) { | ||||
// this is the last syllable in the clause, lengthen it - more for short vowels | // this is the last syllable in the clause, lengthen it - more for short vowels | ||||
len = (p->ph->std_length * 2); | len = (p->ph->std_length * 2); |
char path_home[N_PATH_HOME]; // this is the espeak-data directory | char path_home[N_PATH_HOME]; // this is the espeak-data directory | ||||
extern int saved_parameters[N_SPEECH_PARAM]; // Parameters saved on synthesis start | extern int saved_parameters[N_SPEECH_PARAM]; // Parameters saved on synthesis start | ||||
void WVoiceChanged(voice_t *wvoice) | void WVoiceChanged(voice_t *wvoice) | ||||
{ | { | ||||
// Voice change in wavegen | // Voice change in wavegen | ||||
voice_samplerate = wvoice->samplerate; | voice_samplerate = wvoice->samplerate; | ||||
} | } | ||||
#ifdef USE_ASYNC | #ifdef USE_ASYNC | ||||
static int dispatch_audio(short *outbuf, int length, espeak_EVENT *event) | static int dispatch_audio(short *outbuf, int length, espeak_EVENT *event) | ||||
a_wave_can_be_played = fifo_is_command_enabled(); | a_wave_can_be_played = fifo_is_command_enabled(); | ||||
} | } | ||||
} | } | ||||
break; | |||||
break; | |||||
case AUDIO_OUTPUT_RETRIEVAL: | case AUDIO_OUTPUT_RETRIEVAL: | ||||
if (synth_callback) | if (synth_callback) | ||||
synth_callback(outbuf, length, event); | synth_callback(outbuf, length, event); | ||||
break; | break; | ||||
case AUDIO_OUTPUT_SYNCHRONOUS: | case AUDIO_OUTPUT_SYNCHRONOUS: | ||||
case AUDIO_OUTPUT_SYNCH_PLAYBACK: | case AUDIO_OUTPUT_SYNCH_PLAYBACK: | ||||
break; | break; | ||||
return a_wave_can_be_played == 0; // 1 = stop synthesis, -1 = error | return a_wave_can_be_played == 0; // 1 = stop synthesis, -1 = error | ||||
} | } | ||||
static int create_events(short *outbuf, int length, espeak_EVENT *event, uint32_t the_write_pos) | static int create_events(short *outbuf, int length, espeak_EVENT *event, uint32_t the_write_pos) | ||||
{ | { | ||||
int finished; | int finished; | ||||
return finished; | return finished; | ||||
} | } | ||||
int sync_espeak_terminated_msg(uint32_t unique_identifier, void *user_data) | int sync_espeak_terminated_msg(uint32_t unique_identifier, void *user_data) | ||||
{ | { | ||||
ENTER("sync_espeak_terminated_msg"); | ENTER("sync_espeak_terminated_msg"); | ||||
#endif | #endif | ||||
static void select_output(espeak_AUDIO_OUTPUT output_type) | static void select_output(espeak_AUDIO_OUTPUT output_type) | ||||
{ | { | ||||
my_mode = output_type; | my_mode = output_type; | ||||
// wave_init() is now called just before the first wave_write() | // wave_init() is now called just before the first wave_write() | ||||
synchronous_mode = 0; | synchronous_mode = 0; | ||||
break; | break; | ||||
case AUDIO_OUTPUT_RETRIEVAL: | case AUDIO_OUTPUT_RETRIEVAL: | ||||
synchronous_mode = 0; | synchronous_mode = 0; | ||||
break; | break; | ||||
case AUDIO_OUTPUT_SYNCHRONOUS: | case AUDIO_OUTPUT_SYNCHRONOUS: | ||||
break; | break; | ||||
case AUDIO_OUTPUT_SYNCH_PLAYBACK: | case AUDIO_OUTPUT_SYNCH_PLAYBACK: | ||||
option_waveout = 0; | option_waveout = 0; | ||||
WavegenInitSound(); | WavegenInitSound(); | ||||
} | } | ||||
} | } | ||||
#pragma GCC visibility push(default) | #pragma GCC visibility push(default) | ||||
int GetFileLength(const char *filename) | int GetFileLength(const char *filename) | ||||
{ | { | ||||
} | } | ||||
#pragma GCC visibility pop | #pragma GCC visibility pop | ||||
char *Alloc(int size) | char *Alloc(int size) | ||||
{ | { | ||||
char *p; | char *p; | ||||
free(ptr); | free(ptr); | ||||
} | } | ||||
static void init_path(const char *path) | static void init_path(const char *path) | ||||
{ | { | ||||
#ifdef PLATFORM_WINDOWS | #ifdef PLATFORM_WINDOWS | ||||
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); | ||||
#else | #else | ||||
char *env; | char *env; | ||||
return 0; | return 0; | ||||
} | } | ||||
static espeak_ERROR Synthesize(unsigned int unique_identifier, const void *text, int flags) | static espeak_ERROR Synthesize(unsigned int unique_identifier, const void *text, int flags) | ||||
{ | { | ||||
// Fill the buffer with output sound | // Fill the buffer with output sound | ||||
}; | }; | ||||
#endif | #endif | ||||
void MarkerEvent(int type, unsigned int char_position, int value, int value2, unsigned char *out_ptr) | void MarkerEvent(int type, unsigned int char_position, int value, int value2, unsigned char *out_ptr) | ||||
{ | { | ||||
// 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 | ||||
ep->id.number = value; | ep->id.number = value; | ||||
} | } | ||||
espeak_ERROR sync_espeak_Synth(unsigned int unique_identifier, const void *text, size_t size, | espeak_ERROR sync_espeak_Synth(unsigned int unique_identifier, const void *text, size_t size, | ||||
unsigned int position, espeak_POSITION_TYPE position_type, | unsigned int position, espeak_POSITION_TYPE position_type, | ||||
unsigned int end_position, unsigned int flags, void *user_data) | unsigned int end_position, unsigned int flags, void *user_data) | ||||
{ | { | ||||
#ifdef DEBUG_ENABLED | #ifdef DEBUG_ENABLED | ||||
ENTER("sync_espeak_Synth"); | ENTER("sync_espeak_Synth"); | ||||
SHOW("sync_espeak_Synth > position=%d, position_type=%d, end_position=%d, flags=%d, user_data=0x%x, text=%s\n", position, position_type, end_position, flags, user_data, text); | SHOW("sync_espeak_Synth > position=%d, position_type=%d, end_position=%d, flags=%d, user_data=0x%x, text=%s\n", position, position_type, end_position, flags, user_data, text); | ||||
case POS_CHARACTER: | case POS_CHARACTER: | ||||
skip_characters = position; | skip_characters = position; | ||||
break; | break; | ||||
case POS_WORD: | case POS_WORD: | ||||
skip_words = position; | skip_words = position; | ||||
break; | break; | ||||
case POS_SENTENCE: | case POS_SENTENCE: | ||||
skip_sentences = position; | skip_sentences = position; | ||||
break; | break; | ||||
return aStatus; | return aStatus; | ||||
} | } | ||||
espeak_ERROR sync_espeak_Synth_Mark(unsigned int unique_identifier, const void *text, size_t size, | espeak_ERROR sync_espeak_Synth_Mark(unsigned int unique_identifier, const void *text, size_t size, | ||||
const char *index_mark, unsigned int end_position, | const char *index_mark, unsigned int end_position, | ||||
unsigned int flags, void *user_data) | unsigned int flags, void *user_data) | ||||
end_character_position = end_position; | end_character_position = end_position; | ||||
aStatus = Synthesize(unique_identifier, text, flags | espeakSSML); | aStatus = Synthesize(unique_identifier, text, flags | espeakSSML); | ||||
SHOW_TIME("LEAVE sync_espeak_Synth_Mark"); | SHOW_TIME("LEAVE sync_espeak_Synth_Mark"); | ||||
return aStatus; | return aStatus; | ||||
} | } | ||||
void sync_espeak_Key(const char *key) | void sync_espeak_Key(const char *key) | ||||
{ | { | ||||
// 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? | ||||
Synthesize(0, key, 0); // speak key as a text string | Synthesize(0, key, 0); // speak key as a text string | ||||
} | } | ||||
void sync_espeak_Char(wchar_t character) | void sync_espeak_Char(wchar_t character) | ||||
{ | { | ||||
// is there a system resource of character names per language? | // is there a system resource of character names per language? | ||||
Synthesize(0, buf, espeakSSML); | Synthesize(0, buf, espeakSSML); | ||||
} | } | ||||
void sync_espeak_SetPunctuationList(const wchar_t *punctlist) | void sync_espeak_SetPunctuationList(const wchar_t *punctlist) | ||||
{ | { | ||||
// Set the list of punctuation which are spoken for "some". | // Set the list of punctuation which are spoken for "some". | ||||
} | } | ||||
} | } | ||||
#pragma GCC visibility push(default) | #pragma GCC visibility push(default) | ||||
ESPEAK_API void espeak_SetSynthCallback(t_espeak_callback *SynthCallback) | ESPEAK_API void espeak_SetSynthCallback(t_espeak_callback *SynthCallback) | ||||
{ | { | ||||
ENTER("espeak_SetSynthCallback"); | ENTER("espeak_SetSynthCallback"); | ||||
uri_callback = UriCallback; | uri_callback = UriCallback; | ||||
} | } | ||||
ESPEAK_API void espeak_SetPhonemeCallback(int (*PhonemeCallback)(const char *)) | ESPEAK_API void espeak_SetPhonemeCallback(int (*PhonemeCallback)(const char *)) | ||||
{ | { | ||||
phoneme_callback = PhonemeCallback; | phoneme_callback = PhonemeCallback; | ||||
return samplerate; | return samplerate; | ||||
} | } | ||||
ESPEAK_API espeak_ERROR espeak_Synth(const void *text, size_t size, | ESPEAK_API espeak_ERROR espeak_Synth(const void *text, size_t size, | ||||
unsigned int position, | unsigned int position, | ||||
espeak_POSITION_TYPE position_type, | espeak_POSITION_TYPE position_type, | ||||
delete_espeak_command(c1); | delete_espeak_command(c1); | ||||
delete_espeak_command(c2); | delete_espeak_command(c2); | ||||
} | } | ||||
#endif | #endif | ||||
return a_error; | return a_error; | ||||
} | } | ||||
ESPEAK_API espeak_ERROR espeak_Synth_Mark(const void *text, size_t size, | ESPEAK_API espeak_ERROR espeak_Synth_Mark(const void *text, size_t size, | ||||
const char *index_mark, | const char *index_mark, | ||||
unsigned int end_position, | unsigned int end_position, | ||||
if (f_logespeak) | if (f_logespeak) | ||||
fprintf(f_logespeak, "\nSYNTH MARK %s posn %d flags 0x%x\n%s\n", index_mark, end_position, flags, (const char *)text); | fprintf(f_logespeak, "\nSYNTH MARK %s posn %d flags 0x%x\n%s\n", index_mark, end_position, flags, (const char *)text); | ||||
if (unique_identifier == NULL) | if (unique_identifier == NULL) | ||||
unique_identifier = &temp_identifier; | unique_identifier = &temp_identifier; | ||||
*unique_identifier = 0; | *unique_identifier = 0; | ||||
delete_espeak_command(c1); | delete_espeak_command(c1); | ||||
delete_espeak_command(c2); | delete_espeak_command(c2); | ||||
} | } | ||||
#endif | #endif | ||||
return a_error; | return a_error; | ||||
} | } | ||||
ESPEAK_API espeak_ERROR espeak_Key(const char *key) | ESPEAK_API espeak_ERROR espeak_Key(const char *key) | ||||
{ | { | ||||
ENTER("espeak_Key"); | ENTER("espeak_Key"); | ||||
a_error = fifo_add_command(c); | a_error = fifo_add_command(c); | ||||
if (a_error != EE_OK) | if (a_error != EE_OK) | ||||
delete_espeak_command(c); | delete_espeak_command(c); | ||||
#endif | #endif | ||||
return a_error; | return a_error; | ||||
} | } | ||||
ESPEAK_API espeak_ERROR espeak_Char(wchar_t character) | ESPEAK_API espeak_ERROR espeak_Char(wchar_t character) | ||||
{ | { | ||||
ENTER("espeak_Char"); | ENTER("espeak_Char"); | ||||
#endif | #endif | ||||
} | } | ||||
ESPEAK_API espeak_ERROR espeak_SetVoiceByName(const char *name) | ESPEAK_API espeak_ERROR espeak_SetVoiceByName(const char *name) | ||||
{ | { | ||||
ENTER("espeak_SetVoiceByName"); | ENTER("espeak_SetVoiceByName"); | ||||
return SetVoiceByName(name); | return SetVoiceByName(name); | ||||
} | } | ||||
ESPEAK_API espeak_ERROR espeak_SetVoiceByProperties(espeak_VOICE *voice_selector) | ESPEAK_API espeak_ERROR espeak_SetVoiceByProperties(espeak_VOICE *voice_selector) | ||||
{ | { | ||||
ENTER("espeak_SetVoiceByProperties"); | ENTER("espeak_SetVoiceByProperties"); | ||||
return SetVoiceByProperties(voice_selector); | return SetVoiceByProperties(voice_selector); | ||||
} | } | ||||
ESPEAK_API int espeak_GetParameter(espeak_PARAMETER parameter, int current) | ESPEAK_API int espeak_GetParameter(espeak_PARAMETER parameter, int current) | ||||
{ | { | ||||
ENTER("espeak_GetParameter"); | ENTER("espeak_GetParameter"); | ||||
return param_defaults[parameter]; | return param_defaults[parameter]; | ||||
} | } | ||||
ESPEAK_API espeak_ERROR espeak_SetParameter(espeak_PARAMETER parameter, int value, int relative) | ESPEAK_API espeak_ERROR espeak_SetParameter(espeak_PARAMETER parameter, int value, int relative) | ||||
{ | { | ||||
ENTER("espeak_SetParameter"); | ENTER("espeak_SetParameter"); | ||||
#endif | #endif | ||||
} | } | ||||
ESPEAK_API espeak_ERROR espeak_SetPunctuationList(const wchar_t *punctlist) | ESPEAK_API espeak_ERROR espeak_SetPunctuationList(const wchar_t *punctlist) | ||||
{ | { | ||||
ENTER("espeak_SetPunctuationList"); | ENTER("espeak_SetPunctuationList"); | ||||
#endif | #endif | ||||
} | } | ||||
ESPEAK_API void espeak_SetPhonemeTrace(int phonememode, FILE *stream) | ESPEAK_API void espeak_SetPhonemeTrace(int phonememode, FILE *stream) | ||||
{ | { | ||||
ENTER("espeak_SetPhonemes"); | ENTER("espeak_SetPhonemes"); | ||||
f_trans = stream; | f_trans = stream; | ||||
if (stream == NULL) | if (stream == NULL) | ||||
f_trans = stderr; | f_trans = stderr; | ||||
} | } | ||||
ESPEAK_API const char *espeak_TextToPhonemes(const void **textptr, int textmode, int phonememode) | ESPEAK_API const char *espeak_TextToPhonemes(const void **textptr, int textmode, int phonememode) | ||||
{ | { | ||||
/* phoneme_mode | /* phoneme_mode | ||||
return GetTranslatedPhonemeString(phonememode); | return GetTranslatedPhonemeString(phonememode); | ||||
} | } | ||||
ESPEAK_API void espeak_CompileDictionary(const char *path, FILE *log, int flags) | ESPEAK_API void espeak_CompileDictionary(const char *path, FILE *log, int flags) | ||||
{ | { | ||||
ENTER("espeak_CompileDictionary"); | ENTER("espeak_CompileDictionary"); | ||||
CompileDictionary(path, dictionary_name, log, NULL, flags); | CompileDictionary(path, dictionary_name, log, NULL, flags); | ||||
} | } | ||||
ESPEAK_API espeak_ERROR espeak_Cancel(void) | ESPEAK_API espeak_ERROR espeak_Cancel(void) | ||||
{ | { | ||||
#ifdef USE_ASYNC | #ifdef USE_ASYNC | ||||
return EE_OK; | return EE_OK; | ||||
} | } | ||||
ESPEAK_API int espeak_IsPlaying(void) | ESPEAK_API int espeak_IsPlaying(void) | ||||
{ | { | ||||
#ifdef USE_ASYNC | #ifdef USE_ASYNC | ||||
#endif | #endif | ||||
} | } | ||||
ESPEAK_API espeak_ERROR espeak_Synchronize(void) | ESPEAK_API espeak_ERROR espeak_Synchronize(void) | ||||
{ | { | ||||
espeak_ERROR berr = err; | espeak_ERROR berr = err; | ||||
return berr; | return berr; | ||||
} | } | ||||
extern void FreePhData(void); | extern void FreePhData(void); | ||||
extern void FreeVoiceList(void); | extern void FreeVoiceList(void); | ||||
wave_terminate(); | wave_terminate(); | ||||
out_samplerate = 0; | out_samplerate = 0; | ||||
} | } | ||||
#endif | #endif | ||||
Free(event_list); | Free(event_list); | ||||
event_list = NULL; | event_list = NULL; |
return y; | return y; | ||||
} | } | ||||
static SpectFrame *SpectFrameCreate() | static SpectFrame *SpectFrameCreate() | ||||
{ | { | ||||
int ix; | int ix; | ||||
free(frame); | free(frame); | ||||
} | } | ||||
int LoadFrame(SpectFrame *frame, FILE *stream, int file_format_type) | int LoadFrame(SpectFrame *frame, FILE *stream, int file_format_type) | ||||
{ | { | ||||
short ix; | short ix; | ||||
return 0; | return 0; | ||||
} | } | ||||
double GetFrameRms(SpectFrame *frame, int seq_amplitude) | double GetFrameRms(SpectFrame *frame, int seq_amplitude) | ||||
{ | { | ||||
int h; | int h; | ||||
return frame->rms; | return frame->rms; | ||||
} | } | ||||
SpectSeq *SpectSeqCreate() | SpectSeq *SpectSeqCreate() | ||||
{ | { | ||||
SpectSeq *spect = malloc(sizeof(SpectSeq)); | SpectSeq *spect = malloc(sizeof(SpectSeq)); | ||||
free(spect); | free(spect); | ||||
} | } | ||||
static float GetFrameLength(SpectSeq *spect, int frame) | static float GetFrameLength(SpectSeq *spect, int frame) | ||||
{ | { | ||||
int ix; | int ix; | ||||
return (spect->frames[ix]->time - spect->frames[frame]->time) * 1000.0 + adjust; | return (spect->frames[ix]->time - spect->frames[frame]->time) * 1000.0 + adjust; | ||||
} | } | ||||
int LoadSpectSeq(SpectSeq *spect, const char *filename) | int LoadSpectSeq(SpectSeq *spect, const char *filename) | ||||
{ | { | ||||
short n, temp; | short n, temp; | ||||
frame_width = (int)((FRAME_WIDTH*spect->max_x)/MAX_DISPLAY_FREQ); | frame_width = (int)((FRAME_WIDTH*spect->max_x)/MAX_DISPLAY_FREQ); | ||||
if (frame_width > FRAME_WIDTH) frame_width = FRAME_WIDTH; | if (frame_width > FRAME_WIDTH) frame_width = FRAME_WIDTH; | ||||
// start times from zero | // start times from zero | ||||
time_offset = spect->frames[0]->time; | time_offset = spect->frames[0]->time; | ||||
for (ix = 0; ix < spect->numframes; ix++) | for (ix = 0; ix < spect->numframes; ix++) |
#include "translate.h" | #include "translate.h" | ||||
#include "voice.h" | #include "voice.h" | ||||
#ifdef INCLUDE_MBROLA | #ifdef INCLUDE_MBROLA | ||||
extern int Read4Bytes(FILE *f); | extern int Read4Bytes(FILE *f); | ||||
PROCIV getFreq_MBR; | PROCIV getFreq_MBR; | ||||
PROCVF setVolumeRatio_MBR; | PROCVF setVolumeRatio_MBR; | ||||
HINSTANCE hinstDllMBR = NULL; | HINSTANCE hinstDllMBR = NULL; | ||||
BOOL load_MBR() | BOOL load_MBR() | ||||
{ | { | ||||
if (hinstDllMBR != NULL) | if (hinstDllMBR != NULL) | ||||
return TRUE; | return TRUE; | ||||
} | } | ||||
void unload_MBR() | void unload_MBR() | ||||
{ | { | ||||
if (hinstDllMBR) { | if (hinstDllMBR) { | ||||
#endif // windows | #endif // windows | ||||
static MBROLA_TAB *mbrola_tab = NULL; | static MBROLA_TAB *mbrola_tab = NULL; | ||||
static int mbrola_control = 0; | static int mbrola_control = 0; | ||||
static int mbr_name_prefix = 0; | static int mbr_name_prefix = 0; | ||||
return EE_OK; | return EE_OK; | ||||
} | } | ||||
static int GetMbrName(PHONEME_LIST *plist, PHONEME_TAB *ph, PHONEME_TAB *ph_prev, PHONEME_TAB *ph_next, int *name2, int *split, int *control) | static int GetMbrName(PHONEME_LIST *plist, PHONEME_TAB *ph, PHONEME_TAB *ph_prev, PHONEME_TAB *ph_next, int *name2, int *split, int *control) | ||||
{ | { | ||||
// Look up a phoneme in the mbrola phoneme name translation table | // Look up a phoneme in the mbrola phoneme name translation table | ||||
return mnem; | return mnem; | ||||
} | } | ||||
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. | ||||
output[0] = 0; | output[0] = 0; | ||||
pitch_env = envelope_data[env]; | pitch_env = envelope_data[env]; | ||||
SetPitch2(voice, pitch1, pitch2, &pitch_base, &pitch_range); | SetPitch2(voice, pitch1, pitch2, &pitch_base, &pitch_range); | ||||
env_split = (split * 128)/100; | env_split = (split * 128)/100; | ||||
if (env_split < 0) | if (env_split < 0) | ||||
env_split = 0-env_split; | env_split = 0-env_split; | ||||
p1 = ((pitch_env[0]*pitch_range)>>8) + pitch_base; // Hz << 12 | p1 = ((pitch_env[0]*pitch_range)>>8) + pitch_base; // Hz << 12 | ||||
p_end = ((pitch_env[127]*pitch_range)>>8) + pitch_base; | 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); | ||||
strcat(output, buf); | strcat(output, buf); | ||||
return output; | return output; | ||||
} | } | ||||
int MbrolaTranslate(PHONEME_LIST *plist, int n_phonemes, int resume, FILE *f_mbrola) | int MbrolaTranslate(PHONEME_LIST *plist, int n_phonemes, int resume, FILE *f_mbrola) | ||||
{ | { | ||||
// Generate a mbrola pho file | // Generate a mbrola pho file | ||||
} | } | ||||
done = 1; | done = 1; | ||||
break; | break; | ||||
case phSTOP: | case phSTOP: | ||||
released = 0; | released = 0; | ||||
if (next->type == phVOWEL) released = 1; | if (next->type == phVOWEL) released = 1; | ||||
len = (len * 1000)/samplerate; // convert to mS | len = (len * 1000)/samplerate; // convert to mS | ||||
len += PauseLength(p->prepause, 1); | len += PauseLength(p->prepause, 1); | ||||
break; | break; | ||||
case phVSTOP: | case phVSTOP: | ||||
len = (80 * speed.wav_factor)/256; | len = (80 * speed.wav_factor)/256; | ||||
break; | break; | ||||
case phFRICATIVE: | case phFRICATIVE: | ||||
len = 0; | len = 0; | ||||
InterpretPhoneme(NULL, 0, p, &phdata, NULL); | InterpretPhoneme(NULL, 0, p, &phdata, NULL); | ||||
len = (len * 1000)/samplerate; // convert to mS | len = (len * 1000)/samplerate; // convert to mS | ||||
break; | break; | ||||
case phNASAL: | case phNASAL: | ||||
if (next->type != phVOWEL) { | if (next->type != phVOWEL) { | ||||
memset(&fmtp, 0, sizeof(fmtp)); | memset(&fmtp, 0, sizeof(fmtp)); | ||||
final_pitch = WritePitch(p->env, p->pitch1, p->pitch2, 0, 1); | final_pitch = WritePitch(p->env, p->pitch1, p->pitch2, 0, 1); | ||||
} | } | ||||
break; | break; | ||||
case phLIQUID: | case phLIQUID: | ||||
if (next->type == phPAUSE) { | if (next->type == phPAUSE) { | ||||
len += 50; | len += 50; | ||||
return 0; | return 0; | ||||
} | } | ||||
int MbrolaGenerate(PHONEME_LIST *phoneme_list, int *n_ph, int resume) | int MbrolaGenerate(PHONEME_LIST *phoneme_list, int *n_ph, int resume) | ||||
{ | { | ||||
FILE *f_mbrola = NULL; | FILE *f_mbrola = NULL; | ||||
return again; | return again; | ||||
} | } | ||||
int MbrolaFill(int length, int resume, int amplitude) | int MbrolaFill(int length, int resume, int amplitude) | ||||
{ | { | ||||
// Read audio data from Mbrola (length is in millisecs) | // Read audio data from Mbrola (length is in millisecs) | ||||
return n_samples ? 1 : 0; | return n_samples ? 1 : 0; | ||||
} | } | ||||
void MbrolaReset(void) | void MbrolaReset(void) | ||||
{ | { | ||||
// Reset the Mbrola engine and flush the pending audio | // Reset the Mbrola engine and flush the pending audio | ||||
{ | { | ||||
} | } | ||||
#endif // INCLUDE_MBROLA | #endif // INCLUDE_MBROLA |
#include <stdint.h> | #include <stdint.h> | ||||
#endif | #endif | ||||
#include "speak_lib.h" | #include "speak_lib.h" | ||||
#include "speech.h" | #include "speech.h" | ||||
#include "phoneme.h" | #include "phoneme.h" | ||||
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); | ||||
static char *ReadPhFile(void *ptr, const char *fname, int *size) | static char *ReadPhFile(void *ptr, const char *fname, int *size) | ||||
{ | { | ||||
FILE *f_in; | FILE *f_in; | ||||
return p; | return p; | ||||
} | } | ||||
int LoadPhData(int *srate) | int LoadPhData(int *srate) | ||||
{ | { | ||||
int ix; | int ix; | ||||
return result; | return result; | ||||
} | } | ||||
void FreePhData(void) | void FreePhData(void) | ||||
{ | { | ||||
Free(phoneme_tab_data); | Free(phoneme_tab_data); | ||||
tunes = NULL; | tunes = NULL; | ||||
} | } | ||||
int PhonemeCode(unsigned int mnem) | int PhonemeCode(unsigned int mnem) | ||||
{ | { | ||||
int ix; | int ix; | ||||
return 0; | return 0; | ||||
} | } | ||||
int LookupPhonemeString(const char *string) | int LookupPhonemeString(const char *string) | ||||
{ | { | ||||
int ix; | int ix; | ||||
return PhonemeCode(mnem); | return PhonemeCode(mnem); | ||||
} | } | ||||
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; | ||||
seqk = (SPECT_SEQK *)seq; | seqk = (SPECT_SEQK *)seq; | ||||
nf = seq->n_frames; | nf = seq->n_frames; | ||||
if (nf >= N_SEQ_FRAMES) | if (nf >= N_SEQ_FRAMES) | ||||
nf = N_SEQ_FRAMES - 1; | nf = N_SEQ_FRAMES - 1; | ||||
return frames; | return frames; | ||||
} | } | ||||
unsigned char *GetEnvelope(int index) | unsigned char *GetEnvelope(int index) | ||||
{ | { | ||||
if (index == 0) { | if (index == 0) { | ||||
return (unsigned char *)&phondata_ptr[index]; | return (unsigned char *)&phondata_ptr[index]; | ||||
} | } | ||||
static void SetUpPhonemeTable(int number, int recursing) | static void SetUpPhonemeTable(int number, int recursing) | ||||
{ | { | ||||
int ix; | int ix; | ||||
} | } | ||||
} | } | ||||
void SelectPhonemeTable(int number) | void SelectPhonemeTable(int number) | ||||
{ | { | ||||
n_phoneme_tab = 0; | n_phoneme_tab = 0; | ||||
current_phoneme_table = number; | current_phoneme_table = number; | ||||
} | } | ||||
int LookupPhonemeTable(const char *name) | int LookupPhonemeTable(const char *name) | ||||
{ | { | ||||
int ix; | int ix; | ||||
return ix; | return ix; | ||||
} | } | ||||
int SelectPhonemeTableName(const char *name) | int SelectPhonemeTableName(const char *name) | ||||
{ | { | ||||
// Look up a phoneme set by name, and select it if it exists | // Look up a phoneme set by name, and select it if it exists | ||||
return ix; | return ix; | ||||
} | } | ||||
void LoadConfig(void) | void LoadConfig(void) | ||||
{ | { | ||||
// Load configuration file, if one exists | // Load configuration file, if one exists | ||||
fclose(f); | fclose(f); | ||||
} | } | ||||
PHONEME_DATA this_ph_data; | PHONEME_DATA this_ph_data; | ||||
static void InvalidInstn(PHONEME_TAB *ph, int instn) | static void InvalidInstn(PHONEME_TAB *ph, int instn) | ||||
{ | { | ||||
fprintf(stderr, "Invalid instruction %.4x for phoneme '%s'\n", instn, WordToString(ph->mnemonic)); | fprintf(stderr, "Invalid instruction %.4x for phoneme '%s'\n", instn, WordToString(ph->mnemonic)); | ||||
} | } | ||||
static bool StressCondition(Translator *tr, PHONEME_LIST *plist, int condition, int control) | static bool StressCondition(Translator *tr, PHONEME_LIST *plist, int condition, int control) | ||||
{ | { | ||||
// condition: | // condition: | ||||
} | } | ||||
static int CountVowelPosition(PHONEME_LIST *plist) | static int CountVowelPosition(PHONEME_LIST *plist) | ||||
{ | { | ||||
int count = 0; | int count = 0; | ||||
return count; | return count; | ||||
} | } | ||||
static bool InterpretCondition(Translator *tr, int control, PHONEME_LIST *plist, USHORT *p_prog, WORD_PH_DATA *worddata) | static bool InterpretCondition(Translator *tr, int control, PHONEME_LIST *plist, USHORT *p_prog, WORD_PH_DATA *worddata) | ||||
{ | { | ||||
int which; | int which; | ||||
return false; | return false; | ||||
} | } | ||||
switch (which) | switch (which) | ||||
{ | { | ||||
case 0: // prevPh | case 0: // prevPh | ||||
plist--; | plist--; | ||||
check_endtype = 1; | check_endtype = 1; | ||||
break; | break; | ||||
case 1: // thisPh | case 1: // thisPh | ||||
break; | break; | ||||
case 2: // nextPh | case 2: // nextPh | ||||
case 4: // nextPhW | case 4: // nextPhW | ||||
plist++; | plist++; | ||||
break; | break; | ||||
case 3: // next2Ph | case 3: // next2Ph | ||||
case 6: // next2PhW | case 6: // next2PhW | ||||
plist += 2; | plist += 2; | ||||
break; | break; | ||||
case 7: | case 7: | ||||
// nextVowel, not word boundary | // nextVowel, not word boundary | ||||
for (which = 1;; which++) { | for (which = 1;; which++) { | ||||
} | } | ||||
} | } | ||||
break; | break; | ||||
case 8: // prevVowel in this word | case 8: // prevVowel in this word | ||||
if ((worddata == NULL) || (worddata->prev_vowel.ph == NULL)) | if ((worddata == NULL) || (worddata->prev_vowel.ph == NULL)) | ||||
return false; // no previous vowel | return false; // no previous vowel | ||||
plist = &(worddata->prev_vowel); | plist = &(worddata->prev_vowel); | ||||
check_endtype = 1; | check_endtype = 1; | ||||
break; | break; | ||||
case 9: // next3PhW | case 9: // next3PhW | ||||
for (ix = 1; ix <= 3; ix++) { | for (ix = 1; ix <= 3; ix++) { | ||||
if (plist[ix].sourceix) | if (plist[ix].sourceix) | ||||
} | } | ||||
plist = &plist[3]; | plist = &plist[3]; | ||||
break; | break; | ||||
case 10: // prev2PhW | case 10: // prev2PhW | ||||
if ((plist[0].sourceix) || (plist[-1].sourceix)) | if ((plist[0].sourceix) || (plist[-1].sourceix)) | ||||
return false; | return false; | ||||
// phoneme type, vowel, nasal, fricative, etc | // phoneme type, vowel, nasal, fricative, etc | ||||
return ph->type == data; | return ph->type == data; | ||||
break; | break; | ||||
case 0x20: | case 0x20: | ||||
// place of articulation | // place of articulation | ||||
return ((ph->phflags >> 16) & 0xf) == data; | return ((ph->phflags >> 16) & 0xf) == data; | ||||
break; | break; | ||||
case 0x40: | case 0x40: | ||||
// is a bit set in phoneme flags | // is a bit set in phoneme flags | ||||
return (ph->phflags & (1 << data)) != 0; | return (ph->phflags & (1 << data)) != 0; | ||||
break; | break; | ||||
case 0x80: | case 0x80: | ||||
switch (data) | switch (data) | ||||
{ | { | ||||
case 3: | case 3: | ||||
case 4: | case 4: | ||||
return StressCondition(tr, plist, data, 0); | return StressCondition(tr, plist, data, 0); | ||||
case 5: // isBreak, Either pause phoneme, or (stop/vstop/vfric not followed by vowel or (liquid in same word)) | case 5: // isBreak, Either pause phoneme, or (stop/vstop/vfric not followed by vowel or (liquid in same word)) | ||||
return (ph->type == phPAUSE) || (plist_this->synthflags & SFLAG_NEXT_PAUSE); | return (ph->type == phPAUSE) || (plist_this->synthflags & SFLAG_NEXT_PAUSE); | ||||
case 6: // isWordStart | case 6: // isWordStart | ||||
return plist->sourceix != 0; | return plist->sourceix != 0; | ||||
case 7: // notWordStart | case 7: // notWordStart | ||||
return plist->sourceix == 0; | return plist->sourceix == 0; | ||||
case 8: // isWordEnd | case 8: // isWordEnd | ||||
return plist[1].sourceix || (plist[1].ph->type == phPAUSE); | return plist[1].sourceix || (plist[1].ph->type == phPAUSE); | ||||
break; | break; | ||||
case 9: // isAfterStress | case 9: // isAfterStress | ||||
if (plist->sourceix != 0) | if (plist->sourceix != 0) | ||||
return false; | return false; | ||||
} while (plist->sourceix == 0); | } while (plist->sourceix == 0); | ||||
break; | break; | ||||
case 10: // isNotVowel | case 10: // isNotVowel | ||||
return ph->type != phVOWEL; | return ph->type != phVOWEL; | ||||
case 11: // isFinalVowel | case 11: // isFinalVowel | ||||
for (;;) { | for (;;) { | ||||
plist++; | plist++; | ||||
return false; | return false; | ||||
} | } | ||||
break; | break; | ||||
case 12: // isVoiced | case 12: // isVoiced | ||||
return (ph->type == phVOWEL) || (ph->type == phLIQUID) || (ph->phflags & phVOICED); | return (ph->type == phVOWEL) || (ph->type == phLIQUID) || (ph->phflags & phVOICED); | ||||
case 13: // isFirstVowel | case 13: // isFirstVowel | ||||
return CountVowelPosition(plist) == 1; | return CountVowelPosition(plist) == 1; | ||||
case 14: // isSecondVowel | case 14: // isSecondVowel | ||||
return CountVowelPosition(plist) == 2; | return CountVowelPosition(plist) == 2; | ||||
case 15: // isSeqFlag1 | case 15: // isSeqFlag1 | ||||
// is this preceded by a sequence if 1 or more vowels which have 'flag1' ? (lang=hi) | // is this preceded by a sequence if 1 or more vowels which have 'flag1' ? (lang=hi) | ||||
if (plist->sourceix != 0) | if (plist->sourceix != 0) | ||||
break; | break; | ||||
} | } | ||||
return count > 0; | return count > 0; | ||||
case 0x10: // isTranslationGiven | case 0x10: // isTranslationGiven | ||||
return (plist->synthflags & SFLAG_DICTIONARY) != 0; | return (plist->synthflags & SFLAG_DICTIONARY) != 0; | ||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
static void SwitchOnVowelType(PHONEME_LIST *plist, PHONEME_DATA *phdata, USHORT **p_prog, int instn_type) | static void SwitchOnVowelType(PHONEME_LIST *plist, PHONEME_DATA *phdata, USHORT **p_prog, int instn_type) | ||||
{ | { | ||||
USHORT *prog; | USHORT *prog; | ||||
*p_prog += 12; | *p_prog += 12; | ||||
} | } | ||||
int NumInstnWords(USHORT *prog) | int NumInstnWords(USHORT *prog) | ||||
{ | { | ||||
int instn; | int instn; | ||||
return n+1; | return n+1; | ||||
} | } | ||||
return 1; | return 1; | ||||
case 6: | case 6: | ||||
type2 = (instn & 0xf00) >> 9; | type2 = (instn & 0xf00) >> 9; | ||||
if ((type2 == 5) || (type2 == 6)) | if ((type2 == 5) || (type2 == 6)) | ||||
return 12; // switch on vowel type | return 12; // switch on vowel type | ||||
return 1; | return 1; | ||||
case 2: | case 2: | ||||
case 3: | case 3: | ||||
// a condition, check for a 2-word instruction | // a condition, check for a 2-word instruction | ||||
if (((n = instn & 0x0f00) == 0x600) || (n == 0x0d00)) | if (((n = instn & 0x0f00) == 0x600) || (n == 0x0d00)) | ||||
return 2; | return 2; | ||||
return 1; | return 1; | ||||
default: | default: | ||||
// instn_type 11 to 15, 2 words | // instn_type 11 to 15, 2 words | ||||
instn2 = prog[2]; | instn2 = prog[2]; | ||||
} | } | ||||
} | } | ||||
void InterpretPhoneme(Translator *tr, int control, PHONEME_LIST *plist, PHONEME_DATA *phdata, WORD_PH_DATA *worddata) | void InterpretPhoneme(Translator *tr, int control, PHONEME_LIST *plist, PHONEME_DATA *phdata, WORD_PH_DATA *worddata) | ||||
{ | { | ||||
// control: | // control: | ||||
} else | } else | ||||
InvalidInstn(ph, instn); | InvalidInstn(ph, instn); | ||||
break; | break; | ||||
case 1: | case 1: | ||||
if (tr == NULL) | if (tr == NULL) | ||||
break; // ignore if in synthesis stage | break; // ignore if in synthesis stage | ||||
} | } | ||||
} | } | ||||
break; | break; | ||||
case 2: | case 2: | ||||
case 3: | case 3: | ||||
// conditions | // conditions | ||||
} | } | ||||
prog--; | prog--; | ||||
break; | break; | ||||
case 6: | case 6: | ||||
// JUMP | // JUMP | ||||
switch (instn2 >> 1) | switch (instn2 >> 1) | ||||
break; | break; | ||||
} | } | ||||
break; | break; | ||||
case 9: | case 9: | ||||
data = ((instn & 0xf) << 16) + prog[1]; | data = ((instn & 0xf) << 16) + prog[1]; | ||||
prog++; | prog++; | ||||
prog = &phoneme_index[data] - 1; | prog = &phoneme_index[data] - 1; | ||||
} | } | ||||
break; | break; | ||||
case 2: | case 2: | ||||
// pitch envelope | // pitch envelope | ||||
phdata->pitch_env = data; | phdata->pitch_env = data; | ||||
break; | break; | ||||
case 3: | case 3: | ||||
// amplitude envelope | // amplitude envelope | ||||
phdata->amp_env = data; | phdata->amp_env = data; | ||||
break; | break; | ||||
} | } | ||||
break; | break; | ||||
case 10: // Vowelin, Vowelout | case 10: // Vowelin, Vowelout | ||||
if (instn2 == 1) | if (instn2 == 1) | ||||
ix = 0; | ix = 0; | ||||
phdata->vowel_transition[ix+1] = (prog[2] << 16) + prog[3]; | phdata->vowel_transition[ix+1] = (prog[2] << 16) + prog[3]; | ||||
prog += 3; | prog += 3; | ||||
break; | break; | ||||
case 11: // FMT | case 11: // FMT | ||||
case 12: // WAV | case 12: // WAV | ||||
case 13: // VowelStart | case 13: // VowelStart | ||||
} | } | ||||
} | } | ||||
break; | break; | ||||
default: | default: | ||||
InvalidInstn(ph, instn); | InvalidInstn(ph, instn); | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
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 |
#include "voice.h" | #include "voice.h" | ||||
#include "translate.h" | #include "translate.h" | ||||
extern FILE *f_log; | extern FILE *f_log; | ||||
static void SmoothSpect(void); | static void SmoothSpect(void); | ||||
// list of phonemes in a clause | // list of phonemes in a clause | ||||
int n_phoneme_list = 0; | int n_phoneme_list = 0; | ||||
PHONEME_LIST phoneme_list[N_PHONEME_LIST+1]; | PHONEME_LIST phoneme_list[N_PHONEME_LIST+1]; | ||||
#define VOWEL_FRONT_LENGTH 50 | #define VOWEL_FRONT_LENGTH 50 | ||||
// a dummy phoneme_list entry which looks like a pause | // a dummy phoneme_list entry which looks like a pause | ||||
static PHONEME_LIST next_pause; | static PHONEME_LIST next_pause; | ||||
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 | ||||
return buf; | return buf; | ||||
} | } | ||||
void SynthesizeInit() | void SynthesizeInit() | ||||
{ | { | ||||
last_pitch_cmd = 0; | last_pitch_cmd = 0; | ||||
next_pause.newword = 0; | next_pause.newword = 0; | ||||
} | } | ||||
static void EndAmplitude(void) | static void EndAmplitude(void) | ||||
{ | { | ||||
if (amp_length > 0) { | if (amp_length > 0) { | ||||
} | } | ||||
} | } | ||||
static void EndPitch(int voice_break) | static void EndPitch(int voice_break) | ||||
{ | { | ||||
// posssible end of pitch envelope, fill in the length | // posssible end of pitch envelope, fill in the length | ||||
} | } | ||||
} | } | ||||
static void DoAmplitude(int amp, unsigned char *amp_env) | static void DoAmplitude(int amp, unsigned char *amp_env) | ||||
{ | { | ||||
intptr_t *q; | intptr_t *q; | ||||
WcmdqInc(); | WcmdqInc(); | ||||
} | } | ||||
static void DoPitch(unsigned char *env, int pitch1, int pitch2) | static void DoPitch(unsigned char *env, int pitch1, int pitch2) | ||||
{ | { | ||||
intptr_t *q; | intptr_t *q; | ||||
WcmdqInc(); | WcmdqInc(); | ||||
} | } | ||||
int PauseLength(int pause, int control) | int PauseLength(int pause, int control) | ||||
{ | { | ||||
unsigned int len; | unsigned int len; | ||||
return len; | return len; | ||||
} | } | ||||
static void DoPause(int length, int control) | static void DoPause(int length, int control) | ||||
{ | { | ||||
// length in nominal mS | // length in nominal mS | ||||
} | } | ||||
} | } | ||||
extern int seq_len_adjust; // temporary fix to advance the start point for playing the wav sample | extern int seq_len_adjust; // temporary fix to advance the start point for playing the wav sample | ||||
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 length; | ||||
q[3] = wav_scale + (amp << 8); | q[3] = wav_scale + (amp << 8); | ||||
WcmdqInc(); | WcmdqInc(); | ||||
while (length > len4*3) { | while (length > len4*3) { | ||||
x = len4; | x = len4; | ||||
if (wav_scale == 0) | if (wav_scale == 0) | ||||
return length; | return length; | ||||
} | } | ||||
int DoSample3(PHONEME_DATA *phdata, int length_mod, int amp) | int DoSample3(PHONEME_DATA *phdata, int length_mod, int amp) | ||||
{ | { | ||||
int amp2; | int amp2; | ||||
return len; | return len; | ||||
} | } | ||||
static frame_t *AllocFrame() | static frame_t *AllocFrame() | ||||
{ | { | ||||
// Allocate a temporary spectrum frame for the wavegen queue. Use a pool which is big | // Allocate a temporary spectrum frame for the wavegen queue. Use a pool which is big | ||||
return &frame_pool[ix]; | return &frame_pool[ix]; | ||||
} | } | ||||
static void set_frame_rms(frame_t *fr, int new_rms) | static void set_frame_rms(frame_t *fr, int new_rms) | ||||
{ | { | ||||
// Each frame includes its RMS amplitude value, so to set a new | // Each frame includes its RMS amplitude value, so to set a new | ||||
} | } | ||||
} | } | ||||
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 | ||||
} | } | ||||
} | } | ||||
static frame_t *CopyFrame(frame_t *frame1, int copy) | static frame_t *CopyFrame(frame_t *frame1, int copy) | ||||
{ | { | ||||
// create a copy of the specified frame in temporary buffer | // create a copy of the specified frame in temporary buffer | ||||
return frame2; | return frame2; | ||||
} | } | ||||
static frame_t *DuplicateLastFrame(frameref_t *seq, int n_frames, int length) | static frame_t *DuplicateLastFrame(frameref_t *seq, int n_frames, int length) | ||||
{ | { | ||||
frame_t *fr; | frame_t *fr; | ||||
return fr; | return fr; | ||||
} | } | ||||
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; | int x; | ||||
formants_reduce_hf(fr, hf_reduce); | formants_reduce_hf(fr, hf_reduce); | ||||
} | } | ||||
static int VowelCloseness(frame_t *fr) | static int VowelCloseness(frame_t *fr) | ||||
{ | { | ||||
// return a value 0-3 depending on the vowel's f1 | // return a value 0-3 depending on the vowel's f1 | ||||
return 0; | return 0; | ||||
} | } | ||||
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 ix; | ||||
return 0; | return 0; | ||||
} | } | ||||
static void SmoothSpect(void) | static void SmoothSpect(void) | ||||
{ | { | ||||
// Limit the rate of frequence change of formants, to reduce chirping | // Limit the rate of frequence change of formants, to reduce chirping | ||||
break; | break; | ||||
if (q[0] <= WCMD_SPECT2) { | if (q[0] <= WCMD_SPECT2) { | ||||
len = q[1] & 0xffff; | len = q[1] & 0xffff; | ||||
frame1 = (frame_t *)q[2]; | frame1 = (frame_t *)q[2]; | ||||
syllable_start = syllable_end; | syllable_start = syllable_end; | ||||
} | } | ||||
static void StartSyllable(void) | static void StartSyllable(void) | ||||
{ | { | ||||
// start of syllable, if not already started | // start of syllable, if not already started | ||||
syllable_end = wcmdq_tail; | syllable_end = wcmdq_tail; | ||||
} | } | ||||
int DoSpect2(PHONEME_TAB *this_ph, int which, FMT_PARAMS *fmt_params, PHONEME_LIST *plist, int modulation) | int DoSpect2(PHONEME_TAB *this_ph, int which, FMT_PARAMS *fmt_params, PHONEME_LIST *plist, int modulation) | ||||
{ | { | ||||
// which: 0 not a vowel, 1 start of vowel, 2 body and end of vowel | // which: 0 not a vowel, 1 start of vowel, 2 body and end of vowel | ||||
WcmdqInc(); | WcmdqInc(); | ||||
} | } | ||||
return total_len; | return total_len; | ||||
} | } | ||||
void DoMarker(int type, int char_posn, int length, int value) | void DoMarker(int type, int char_posn, int length, int value) | ||||
{ | { | ||||
// This could be used to return an index to the word currently being spoken | // This could be used to return an index to the word currently being spoken | ||||
} | } | ||||
} | } | ||||
void DoPhonemeMarker(int type, int char_posn, int length, char *name) | void DoPhonemeMarker(int type, int char_posn, int length, char *name) | ||||
{ | { | ||||
// This could be used to return an index to the word currently being spoken | // This could be used to return an index to the word currently being spoken | ||||
} | } | ||||
} | } | ||||
#if HAVE_SONIC_H | #if HAVE_SONIC_H | ||||
void DoSonicSpeed(int value) | void DoSonicSpeed(int value) | ||||
{ | { | ||||
} | } | ||||
#endif | #endif | ||||
void DoVoiceChange(voice_t *v) | void DoVoiceChange(voice_t *v) | ||||
{ | { | ||||
// allocate memory for a copy of the voice data, and free it in wavegenfill() | // allocate memory for a copy of the voice data, and free it in wavegenfill() | ||||
WcmdqInc(); | WcmdqInc(); | ||||
} | } | ||||
void DoEmbedded(int *embix, int sourceix) | void DoEmbedded(int *embix, int sourceix) | ||||
{ | { | ||||
// There were embedded commands in the text at this point | // There were embedded commands in the text at this point | ||||
SetEmbedded((command & 0x60) + EMBED_S2, value); // adjusts embedded_value[EMBED_S2] | SetEmbedded((command & 0x60) + EMBED_S2, value); // adjusts embedded_value[EMBED_S2] | ||||
SetSpeed(2); | SetSpeed(2); | ||||
break; | break; | ||||
case EMBED_I: // play dynamically loaded wav data (sound icon) | case EMBED_I: // play dynamically loaded wav data (sound icon) | ||||
if ((int)value < n_soundicon_tab) { | if ((int)value < n_soundicon_tab) { | ||||
if (soundicon_tab[value].length != 0) { | if (soundicon_tab[value].length != 0) { | ||||
} | } | ||||
} | } | ||||
break; | break; | ||||
case EMBED_M: // named marker | case EMBED_M: // named marker | ||||
DoMarker(espeakEVENT_MARK, (sourceix & 0x7ff) + clause_start_char, 0, value); | DoMarker(espeakEVENT_MARK, (sourceix & 0x7ff) + clause_start_char, 0, value); | ||||
break; | break; | ||||
case EMBED_U: // play sound | case EMBED_U: // play sound | ||||
DoMarker(espeakEVENT_PLAY, count_characters+1, 0, value); // always occurs at end of clause | DoMarker(espeakEVENT_PLAY, count_characters+1, 0, value); // always occurs at end of clause | ||||
break; | break; | ||||
default: | default: | ||||
DoPause(10, 0); // ensure a break in the speech | DoPause(10, 0); // ensure a break in the speech | ||||
wcmdq[wcmdq_tail][0] = WCMD_EMBEDDED; | wcmdq[wcmdq_tail][0] = WCMD_EMBEDDED; | ||||
} while ((word & 0x80) == 0); | } while ((word & 0x80) == 0); | ||||
} | } | ||||
int Generate(PHONEME_LIST *phoneme_list, int *n_ph, int resume) | int Generate(PHONEME_LIST *phoneme_list, int *n_ph, int resume) | ||||
{ | { | ||||
static int ix; | static int ix; | ||||
DoPause(p->length, 0); | DoPause(p->length, 0); | ||||
p->std_length = p->ph->std_length; | p->std_length = p->ph->std_length; | ||||
break; | break; | ||||
case phSTOP: | case phSTOP: | ||||
released = 0; | released = 0; | ||||
ph = p->ph; | ph = p->ph; | ||||
phdata.pd_control |= pd_DONTLENGTHEN; | phdata.pd_control |= pd_DONTLENGTHEN; | ||||
DoSample3(&phdata, 0, 0); | DoSample3(&phdata, 0, 0); | ||||
break; | break; | ||||
case phFRICATIVE: | case phFRICATIVE: | ||||
InterpretPhoneme(NULL, 0, p, &phdata, &worddata); | InterpretPhoneme(NULL, 0, p, &phdata, &worddata); | ||||
DoSample3(&phdata, p->length, 0); // play it twice for [s:] etc. | DoSample3(&phdata, p->length, 0); // play it twice for [s:] etc. | ||||
DoSample3(&phdata, p->length, 0); | DoSample3(&phdata, p->length, 0); | ||||
break; | break; | ||||
case phVSTOP: | case phVSTOP: | ||||
ph = p->ph; | ph = p->ph; | ||||
memset(&fmtp, 0, sizeof(fmtp)); | memset(&fmtp, 0, sizeof(fmtp)); | ||||
DoPause(12, 0); | DoPause(12, 0); | ||||
} | } | ||||
break; | break; | ||||
case phVFRICATIVE: | case phVFRICATIVE: | ||||
if (next->type == phVOWEL) { | if (next->type == phVOWEL) { | ||||
DoAmplitude(p->amp, NULL); | DoAmplitude(p->amp, NULL); | ||||
DoSpect2(p->ph, 0, &fmtp, p, 0); | DoSpect2(p->ph, 0, &fmtp, p, 0); | ||||
DoSpect2(p->ph, 0, &fmtp, p, 0); | DoSpect2(p->ph, 0, &fmtp, p, 0); | ||||
break; | break; | ||||
case phNASAL: | case phNASAL: | ||||
memset(&fmtp, 0, sizeof(fmtp)); | memset(&fmtp, 0, sizeof(fmtp)); | ||||
if (!(p->synthflags & SFLAG_SEQCONTINUE)) { | if (!(p->synthflags & SFLAG_SEQCONTINUE)) { | ||||
} | } | ||||
break; | break; | ||||
case phLIQUID: | case phLIQUID: | ||||
memset(&fmtp, 0, sizeof(fmtp)); | memset(&fmtp, 0, sizeof(fmtp)); | ||||
modulation = 0; | modulation = 0; | ||||
fmtp.wav_addr = phdata.sound_addr[pd_ADDWAV]; | fmtp.wav_addr = phdata.sound_addr[pd_ADDWAV]; | ||||
fmtp.wav_amp = phdata.sound_param[pd_ADDWAV]; | fmtp.wav_amp = phdata.sound_param[pd_ADDWAV]; | ||||
DoSpect2(p->ph, 0, &fmtp, p, modulation); | DoSpect2(p->ph, 0, &fmtp, p, modulation); | ||||
break; | break; | ||||
case phVOWEL: | case phVOWEL: | ||||
ph = p->ph; | ph = p->ph; | ||||
stress = p->stresslevel & 0xf; | stress = p->stresslevel & 0xf; | ||||
} | } | ||||
DoSpect2(ph, 2, &fmtp, p, modulation); | DoSpect2(ph, 2, &fmtp, p, modulation); | ||||
break; | break; | ||||
} | } | ||||
ix++; | ix++; | ||||
return 0; // finished the phoneme list | return 0; // finished the phoneme list | ||||
} | } | ||||
static int timer_on = 0; | static int timer_on = 0; | ||||
static int paused = 0; | static int paused = 0; | ||||
return 0; | return 0; | ||||
} | } | ||||
int SynthStatus() | int SynthStatus() | ||||
{ | { | ||||
return timer_on | paused; | return timer_on | paused; | ||||
} | } | ||||
int SpeakNextClause(FILE *f_in, const void *text_in, int control) | int SpeakNextClause(FILE *f_in, const void *text_in, int control) | ||||
{ | { | ||||
// Speak text from file (f_in) or memory (text_in) | // Speak text from file (f_in) or memory (text_in) |
#include "synthesize.h" | #include "synthesize.h" | ||||
#include "translate.h" | #include "translate.h" | ||||
#define L_qa 0x716100 | #define L_qa 0x716100 | ||||
#define L_grc 0x677263 // grc Ancient Greek | #define L_grc 0x677263 // grc Ancient Greek | ||||
#define L_jbo 0x6a626f // jbo Lojban | #define L_jbo 0x6a626f // jbo Lojban | ||||
#define OFFSET_KOREAN 0x1100 | #define OFFSET_KOREAN 0x1100 | ||||
#define OFFSET_ETHIOPIC 0x1200 | #define OFFSET_ETHIOPIC 0x1200 | ||||
// character ranges must be listed in ascending unicode order | // character ranges must be listed in ascending unicode order | ||||
ALPHABET alphabets[] = { | ALPHABET alphabets[] = { | ||||
{ "_el", OFFSET_GREEK, 0x380, 0x3ff, L('e', 'l'), AL_DONT_NAME | AL_NOT_LETTERS | AL_WORDS }, | { "_el", OFFSET_GREEK, 0x380, 0x3ff, L('e', 'l'), AL_DONT_NAME | AL_NOT_LETTERS | AL_WORDS }, | ||||
{ NULL, 0, 0, 0, 0, 0 } | { NULL, 0, 0, 0, 0, 0 } | ||||
}; | }; | ||||
ALPHABET *AlphabetFromName(const char *name) | ALPHABET *AlphabetFromName(const char *name) | ||||
{ | { | ||||
ALPHABET *alphabet; | ALPHABET *alphabet; | ||||
return NULL; | return NULL; | ||||
} | } | ||||
ALPHABET *AlphabetFromChar(int c) | ALPHABET *AlphabetFromChar(int c) | ||||
{ | { | ||||
// Find the alphabet from a character. | // Find the alphabet from a character. | ||||
return NULL; | return NULL; | ||||
} | } | ||||
static void Translator_Russian(Translator *tr); | static void Translator_Russian(Translator *tr); | ||||
static void SetLetterVowel(Translator *tr, int c) | static void SetLetterVowel(Translator *tr, int c) | ||||
{ | { | ||||
tr->letter_bits[c] = (tr->letter_bits[c] & 0x40) | 0x81; // keep value for group 6 (front vowels e,i,y) | tr->letter_bits[c] = (tr->letter_bits[c] & 0x40) | 0x81; // keep value for group 6 (front vowels e,i,y) | ||||
const char string_ordinal[] = { 0xc2, 0xba, 0 }; // masculine ordinal character, UTF-8 | const char string_ordinal[] = { 0xc2, 0xba, 0 }; // masculine ordinal character, UTF-8 | ||||
static Translator *NewTranslator(void) | static Translator *NewTranslator(void) | ||||
{ | { | ||||
Translator *tr; | Translator *tr; | ||||
SetLetterBits(tr, 6, "eiy"); // Letter group Y, front vowels | SetLetterBits(tr, 6, "eiy"); // Letter group Y, front vowels | ||||
SetLetterBits(tr, 7, "aeiouy"); // vowels, including y | SetLetterBits(tr, 7, "aeiouy"); // vowels, including y | ||||
tr->char_plus_apostrophe = empty_wstring; | tr->char_plus_apostrophe = empty_wstring; | ||||
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; | ||||
0x7fff | 0x7fff | ||||
}; | }; | ||||
static const unsigned int replace_cyrillic_latin[] = | static const unsigned int replace_cyrillic_latin[] = | ||||
{ 0x430, 'a', | { 0x430, 'a', | ||||
0x431, 'b', | 0x431, 'b', | ||||
0x45c, 0x107, | 0x45c, 0x107, | ||||
0 }; // ѓ ѕ ќ | 0 }; // ѓ ѕ ќ | ||||
static const unsigned char ru_vowels[] = { 0x10, 0x15, 0x31, 0x18, 0x1e, 0x23, 0x2b, 0x2d, 0x2e, 0x2f, 0xb9, 0xc9, 0x91, 0x8f, 0x36, 0 }; // also kazakh | static const unsigned char ru_vowels[] = { 0x10, 0x15, 0x31, 0x18, 0x1e, 0x23, 0x2b, 0x2d, 0x2e, 0x2f, 0xb9, 0xc9, 0x91, 0x8f, 0x36, 0 }; // also kazakh | ||||
static const unsigned char ru_consonants[] = { 0x11, 0x12, 0x13, 0x14, 0x16, 0x17, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1f, 0x20, 0x21, 0x22, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2c, 0x73, 0x7b, 0x83, 0x9b, 0 }; | static const unsigned char ru_consonants[] = { 0x11, 0x12, 0x13, 0x14, 0x16, 0x17, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1f, 0x20, 0x21, 0x22, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2c, 0x73, 0x7b, 0x83, 0x9b, 0 }; | ||||
SetLetterBits(tr, LETTERGP_VOWEL2, (char *)ru_vowels); | SetLetterBits(tr, LETTERGP_VOWEL2, (char *)ru_vowels); | ||||
} | } | ||||
void SetIndicLetters(Translator *tr) | void SetIndicLetters(Translator *tr) | ||||
{ | { | ||||
// Set letter types for Indic scripts, Devanagari, Tamill, etc | // Set letter types for Indic scripts, Devanagari, Tamill, etc | ||||
tr->langopts.suffix_add_e = tr->letter_bits_offset + 0x4d; // virama | tr->langopts.suffix_add_e = tr->letter_bits_offset + 0x4d; // virama | ||||
} | } | ||||
void SetupTranslator(Translator *tr, const short *lengths, const unsigned char *amps) | void SetupTranslator(Translator *tr, const short *lengths, const unsigned char *amps) | ||||
{ | { | ||||
if (lengths != NULL) | if (lengths != NULL) | ||||
memcpy(tr->stress_amps, amps, sizeof(tr->stress_amps)); | memcpy(tr->stress_amps, amps, sizeof(tr->stress_amps)); | ||||
} | } | ||||
Translator *SelectTranslator(const char *name) | Translator *SelectTranslator(const char *name) | ||||
{ | { | ||||
int name2 = 0; | int name2 = 0; | ||||
tr->langopts.numbers = NUM_SWAP_TENS | NUM_HUNDRED_AND | NUM_SINGLE_AND | NUM_ROMAN | NUM_1900; | tr->langopts.numbers = NUM_SWAP_TENS | NUM_HUNDRED_AND | NUM_SINGLE_AND | NUM_ROMAN | NUM_1900; | ||||
tr->langopts.accents = 1; | tr->langopts.accents = 1; | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('a', 'm'): // Amharic, Ethiopia | case L('a', 'm'): // Amharic, Ethiopia | ||||
{ | { | ||||
SetupTranslator(tr, stress_lengths_fr, stress_amps_fr); | SetupTranslator(tr, stress_lengths_fr, stress_amps_fr); | ||||
tr->langopts.param[LOPT_UNPRONOUNCABLE] = 1; // disable check for unpronouncable words | tr->langopts.param[LOPT_UNPRONOUNCABLE] = 1; // disable check for unpronouncable words | ||||
tr->langopts.numbers = NUM_OMIT_1_HUNDRED; | tr->langopts.numbers = NUM_OMIT_1_HUNDRED; | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('a', 'r'): // Arabic | case L('a', 'r'): // Arabic | ||||
tr->transpose_min = 0x620; // for ar_list, use 6-bit character codes | tr->transpose_min = 0x620; // for ar_list, use 6-bit character codes | ||||
tr->transpose_max = 0x65f; | tr->transpose_max = 0x65f; | ||||
tr->langopts.numbers = NUM_SWAP_TENS | NUM_AND_UNITS | NUM_HUNDRED_AND | NUM_OMIT_1_HUNDRED | NUM_AND_HUNDRED | NUM_THOUSAND_AND | NUM_OMIT_1_THOUSAND; | tr->langopts.numbers = NUM_SWAP_TENS | NUM_AND_UNITS | NUM_HUNDRED_AND | NUM_OMIT_1_HUNDRED | NUM_AND_HUNDRED | NUM_THOUSAND_AND | NUM_OMIT_1_THOUSAND; | ||||
tr->langopts.param[LOPT_UNPRONOUNCABLE] = 1; // disable check for unpronouncable words | tr->langopts.param[LOPT_UNPRONOUNCABLE] = 1; // disable check for unpronouncable words | ||||
break; | break; | ||||
case L('b', 'g'): // Bulgarian | case L('b', 'g'): // Bulgarian | ||||
{ | { | ||||
SetCyrillicLetters(tr); | SetCyrillicLetters(tr); | ||||
tr->langopts.numbers = NUM_DECIMAL_COMMA | NUM_ALLOW_SPACE | NUM_OMIT_1_HUNDRED | NUM_HUNDRED_AND | NUM_AND_UNITS | NUM_SINGLE_AND | NUM_ROMAN | NUM_ROMAN_ORDINAL | NUM_ROMAN_CAPITALS; | tr->langopts.numbers = NUM_DECIMAL_COMMA | NUM_ALLOW_SPACE | NUM_OMIT_1_HUNDRED | NUM_HUNDRED_AND | NUM_AND_UNITS | NUM_SINGLE_AND | NUM_ROMAN | NUM_ROMAN_ORDINAL | NUM_ROMAN_CAPITALS; | ||||
tr->langopts.thousands_sep = ' '; // don't allow dot as thousands separator | tr->langopts.thousands_sep = ' '; // don't allow dot as thousands separator | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('b', 'n'): // Bengali | case L('b', 'n'): // Bengali | ||||
case L('a', 's'): // Assamese | case L('a', 's'): // Assamese | ||||
case L_mni: // Manipuri (temporary placement - it's not indo-european) | case L_mni: // Manipuri (temporary placement - it's not indo-european) | ||||
} | } | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('b', 'o'): // Tibet | case L('b', 'o'): // Tibet | ||||
{ | { | ||||
tr->langopts.stress_rule = STRESSPOSN_1L; | tr->langopts.stress_rule = STRESSPOSN_1L; | ||||
tr->langopts.param[LOPT_UNPRONOUNCABLE] = 1; // disable check for unpronouncable words | tr->langopts.param[LOPT_UNPRONOUNCABLE] = 1; // disable check for unpronouncable words | ||||
tr->langopts.numbers = 1; | tr->langopts.numbers = 1; | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('c', 'y'): // Welsh | case L('c', 'y'): // Welsh | ||||
{ | { | ||||
static const short stress_lengths_cy[8] = { 170, 220, 180, 180, 0, 0, 250, 270 }; | static const short stress_lengths_cy[8] = { 170, 220, 180, 180, 0, 0, 250, 270 }; | ||||
SetLetterVowel(tr, 'w'); // add letter to vowels and remove from consonants | SetLetterVowel(tr, 'w'); // add letter to vowels and remove from consonants | ||||
SetLetterVowel(tr, 'y'); | SetLetterVowel(tr, 'y'); | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('d', 'a'): // Danish | case L('d', 'a'): // Danish | ||||
{ | { | ||||
static const short stress_lengths_da[8] = { 160, 140, 200, 200, 0, 0, 220, 230 }; | static const short stress_lengths_da[8] = { 160, 140, 200, 200, 0, 0, 220, 230 }; | ||||
SetLetterVowel(tr, 'y'); | SetLetterVowel(tr, 'y'); | ||||
tr->langopts.numbers = NUM_DECIMAL_COMMA | NUM_SWAP_TENS | NUM_HUNDRED_AND | NUM_OMIT_1_HUNDRED | NUM_ORDINAL_DOT | NUM_1900 | NUM_ROMAN | NUM_ROMAN_CAPITALS | NUM_ROMAN_ORDINAL; | tr->langopts.numbers = NUM_DECIMAL_COMMA | NUM_SWAP_TENS | NUM_HUNDRED_AND | NUM_OMIT_1_HUNDRED | NUM_ORDINAL_DOT | NUM_1900 | NUM_ROMAN | NUM_ROMAN_CAPITALS | NUM_ROMAN_ORDINAL; | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('d', 'e'): | case L('d', 'e'): | ||||
{ | { | ||||
static const short stress_lengths_de[8] = { 150, 130, 200, 200, 0, 0, 270, 270 }; | static const short stress_lengths_de[8] = { 150, 130, 200, 200, 0, 0, 270, 270 }; | ||||
SetLetterVowel(tr, 'y'); | SetLetterVowel(tr, 'y'); | ||||
tr->langopts.param[LOPT_UNPRONOUNCABLE] = 2; // use de_rules for unpronouncable rules | tr->langopts.param[LOPT_UNPRONOUNCABLE] = 2; // use de_rules for unpronouncable rules | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('d', 'v'): // Divehi (Maldives) | case L('d', 'v'): // Divehi (Maldives) | ||||
{ | { | ||||
SetupTranslator(tr, stress_lengths_ta, stress_amps_ta); | SetupTranslator(tr, stress_lengths_ta, stress_amps_ta); | ||||
tr->langopts.break_numbers = 0x14a8; // 1000, 100,000 10,000,000 | tr->langopts.break_numbers = 0x14a8; // 1000, 100,000 10,000,000 | ||||
tr->langopts.numbers = 1; | tr->langopts.numbers = 1; | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('e', 'n'): | case L('e', 'n'): | ||||
{ | { | ||||
static const short stress_lengths_en[8] = { 182, 140, 220, 220, 0, 0, 248, 275 }; | static const short stress_lengths_en[8] = { 182, 140, 220, 220, 0, 0, 248, 275 }; | ||||
tr->langopts.param[LOPT_UNPRONOUNCABLE] = 2; // use en_rules for unpronouncable rules | tr->langopts.param[LOPT_UNPRONOUNCABLE] = 2; // use en_rules for unpronouncable rules | ||||
SetLetterBits(tr, 6, "aeiouy"); // Group Y: vowels, including y | SetLetterBits(tr, 6, "aeiouy"); // Group Y: vowels, including y | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('e', 'l'): // Greek | case L('e', 'l'): // Greek | ||||
case L_grc: // Ancient Greek | case L_grc: // Ancient Greek | ||||
{ | { | ||||
tr->langopts.param[LOPT_UNPRONOUNCABLE] = 1; | tr->langopts.param[LOPT_UNPRONOUNCABLE] = 1; | ||||
} | } | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('e', 'o'): | case L('e', 'o'): | ||||
{ | { | ||||
static const short stress_lengths_eo[8] = { 150, 140, 180, 180, 0, 0, 200, 200 }; | static const short stress_lengths_eo[8] = { 150, 140, 180, 180, 0, 0, 200, 200 }; | ||||
tr->langopts.numbers = NUM_DECIMAL_COMMA | NUM_OMIT_1_HUNDRED | NUM_ALLOW_SPACE | NUM_ROMAN; | tr->langopts.numbers = NUM_DECIMAL_COMMA | NUM_OMIT_1_HUNDRED | NUM_ALLOW_SPACE | NUM_ROMAN; | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('e', 's'): // Spanish | case L('e', 's'): // Spanish | ||||
case L('a', 'n'): // Aragonese | case L('a', 'n'): // Aragonese | ||||
case L('c', 'a'): // Catalan | case L('c', 'a'): // Catalan | ||||
} else | } else | ||||
tr->langopts.param[LOPT_UNPRONOUNCABLE] = 2; // use es_rules for unpronouncable rules | tr->langopts.param[LOPT_UNPRONOUNCABLE] = 2; // use es_rules for unpronouncable rules | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('e', 'u'): // basque | case L('e', 'u'): // basque | ||||
{ | { | ||||
static const short stress_lengths_eu[8] = { 200, 200, 200, 200, 0, 0, 210, 230 }; // very weak stress | static const short stress_lengths_eu[8] = { 200, 200, 200, 200, 0, 0, 210, 230 }; // very weak stress | ||||
tr->langopts.param[LOPT_SUFFIX] = 1; | tr->langopts.param[LOPT_SUFFIX] = 1; | ||||
tr->langopts.numbers = NUM_SINGLE_STRESS | NUM_DECIMAL_COMMA | NUM_HUNDRED_AND | NUM_OMIT_1_HUNDRED | NUM_OMIT_1_THOUSAND | NUM_VIGESIMAL; | tr->langopts.numbers = NUM_SINGLE_STRESS | NUM_DECIMAL_COMMA | NUM_HUNDRED_AND | NUM_OMIT_1_HUNDRED | NUM_OMIT_1_THOUSAND | NUM_VIGESIMAL; | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('f', 'a'): // Farsi | case L('f', 'a'): // Farsi | ||||
{ | { | ||||
// Convert characters in the range 0x620 to 0x6cc to the range 1 to 63. | // Convert characters in the range 0x620 to 0x6cc to the range 1 to 63. | ||||
tr->chars_ignore = chars_ignore_zwnj_hyphen; // replace ZWNJ by hyphen | tr->chars_ignore = chars_ignore_zwnj_hyphen; // replace ZWNJ by hyphen | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('e', 't'): // Estonian | case L('e', 't'): // Estonian | ||||
tr->charset_a0 = charsets[4]; // ISO-8859-4 | tr->charset_a0 = charsets[4]; // ISO-8859-4 | ||||
// drop through to Finnish | |||||
// drop through to Finnish | |||||
case L('f', 'i'): // Finnish | case L('f', 'i'): // Finnish | ||||
{ | { | ||||
static const unsigned char stress_amps_fi[8] = { 18, 16, 22, 22, 20, 22, 22, 22 }; | static const unsigned char stress_amps_fi[8] = { 18, 16, 22, 22, 20, 22, 22, 22 }; | ||||
tr->langopts.spelling_stress = 1; | tr->langopts.spelling_stress = 1; | ||||
tr->langopts.intonation_group = 3; // less intonation, don't raise pitch at comma | tr->langopts.intonation_group = 3; // less intonation, don't raise pitch at comma | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('f', 'r'): // french | case L('f', 'r'): // french | ||||
{ | { | ||||
SetupTranslator(tr, stress_lengths_fr, stress_amps_fr); | SetupTranslator(tr, stress_lengths_fr, stress_amps_fr); | ||||
tr->langopts.numbers = NUM_SINGLE_STRESS | NUM_DECIMAL_COMMA | NUM_ALLOW_SPACE | NUM_OMIT_1_HUNDRED | NUM_NOPAUSE | NUM_ROMAN | NUM_ROMAN_CAPITALS | NUM_ROMAN_AFTER | NUM_VIGESIMAL | NUM_DFRACTION_4; | tr->langopts.numbers = NUM_SINGLE_STRESS | NUM_DECIMAL_COMMA | NUM_ALLOW_SPACE | NUM_OMIT_1_HUNDRED | NUM_NOPAUSE | NUM_ROMAN | NUM_ROMAN_CAPITALS | NUM_ROMAN_AFTER | NUM_VIGESIMAL | NUM_DFRACTION_4; | ||||
SetLetterVowel(tr, 'y'); | SetLetterVowel(tr, 'y'); | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('g', 'a'): // irish | case L('g', 'a'): // irish | ||||
case L('g', 'd'): // scots gaelic | case L('g', 'd'): // scots gaelic | ||||
{ | { | ||||
tr->langopts.param[LOPT_UNPRONOUNCABLE] = 3; // don't count apostrophe | tr->langopts.param[LOPT_UNPRONOUNCABLE] = 3; // don't count apostrophe | ||||
tr->langopts.param[LOPT_IT_LENGTHEN] = 1; // remove [:] phoneme from non-stressed syllables (Lang=gd) | tr->langopts.param[LOPT_IT_LENGTHEN] = 1; // remove [:] phoneme from non-stressed syllables (Lang=gd) | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('h', 'i'): // Hindi | case L('h', 'i'): // Hindi | ||||
case L('n', 'e'): // Nepali | case L('n', 'e'): // Nepali | ||||
case L('o', 'r'): // Oriya | case L('o', 'r'): // Oriya | ||||
tr->letter_bits_offset = OFFSET_ORIYA; | tr->letter_bits_offset = OFFSET_ORIYA; | ||||
SetIndicLetters(tr); | SetIndicLetters(tr); | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('h', 'r'): // Croatian | case L('h', 'r'): // Croatian | ||||
case L('b', 's'): // Bosnian | case L('b', 's'): // Bosnian | ||||
case L('s', 'r'): // Serbian | case L('s', 'r'): // Serbian | ||||
SetLetterVowel(tr, 'y'); | SetLetterVowel(tr, 'y'); | ||||
SetLetterVowel(tr, 'r'); | SetLetterVowel(tr, 'r'); | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('h', 't'): // Haitian Creole | case L('h', 't'): // Haitian Creole | ||||
tr->langopts.stress_rule = STRESSPOSN_1R; // stress on final syllable | tr->langopts.stress_rule = STRESSPOSN_1R; // stress on final syllable | ||||
tr->langopts.stress_flags = S_NO_AUTO_2 | S_FINAL_DIM; // don't use secondary stress | tr->langopts.stress_flags = S_NO_AUTO_2 | S_FINAL_DIM; // don't use secondary stress | ||||
tr->langopts.numbers = NUM_SINGLE_STRESS | NUM_OMIT_1_HUNDRED | NUM_NOPAUSE | NUM_ROMAN | NUM_VIGESIMAL | NUM_DFRACTION_4; | tr->langopts.numbers = NUM_SINGLE_STRESS | NUM_OMIT_1_HUNDRED | NUM_NOPAUSE | NUM_ROMAN | NUM_VIGESIMAL | NUM_DFRACTION_4; | ||||
break; | break; | ||||
case L('h', 'u'): // Hungarian | case L('h', 'u'): // Hungarian | ||||
{ | { | ||||
static const unsigned char stress_amps_hu[8] = { 17, 17, 19, 19, 20, 22, 22, 21 }; | static const unsigned char stress_amps_hu[8] = { 17, 17, 19, 19, 20, 22, 22, 21 }; | ||||
tr->langopts.spelling_stress = 1; | tr->langopts.spelling_stress = 1; | ||||
SetLengthMods(tr, 3); // all equal | SetLengthMods(tr, 3); // all equal | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('h', 'y'): // Armenian | case L('h', 'y'): // Armenian | ||||
{ | { | ||||
static const short stress_lengths_hy[8] = { 250, 200, 250, 250, 0, 0, 250, 250 }; | static const short stress_lengths_hy[8] = { 250, 200, 250, 250, 0, 0, 250, 250 }; | ||||
tr->langopts.max_initial_consonants = 6; | tr->langopts.max_initial_consonants = 6; | ||||
tr->langopts.numbers = NUM_DECIMAL_COMMA | NUM_ALLOW_SPACE | NUM_OMIT_1_HUNDRED; | tr->langopts.numbers = NUM_DECIMAL_COMMA | NUM_ALLOW_SPACE | NUM_OMIT_1_HUNDRED; | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('i', 'd'): // Indonesian | case L('i', 'd'): // Indonesian | ||||
case L('m', 's'): // Malay | case L('m', 's'): // Malay | ||||
{ | { | ||||
tr->langopts.stress_flags = S_FINAL_DIM_ONLY | S_FINAL_NO_2; | tr->langopts.stress_flags = S_FINAL_DIM_ONLY | S_FINAL_NO_2; | ||||
tr->langopts.accents = 2; // "capital" after letter name | tr->langopts.accents = 2; // "capital" after letter name | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('i', 's'): // Icelandic | case L('i', 's'): // Icelandic | ||||
{ | { | ||||
static const short stress_lengths_is[8] = { 180, 160, 200, 200, 0, 0, 240, 250 }; | static const short stress_lengths_is[8] = { 180, 160, 200, 200, 0, 0, 240, 250 }; | ||||
tr->langopts.numbers = NUM_DECIMAL_COMMA | NUM_SINGLE_AND | NUM_HUNDRED_AND | NUM_AND_UNITS | NUM_1900; | tr->langopts.numbers = NUM_DECIMAL_COMMA | NUM_SINGLE_AND | NUM_HUNDRED_AND | NUM_AND_UNITS | NUM_1900; | ||||
tr->langopts.numbers2 = 0x2; | tr->langopts.numbers2 = 0x2; | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('i', 't'): // Italian | case L('i', 't'): // Italian | ||||
{ | { | ||||
static const short stress_lengths_it[8] = | static const short stress_lengths_it[8] = | ||||
tr->langopts.accents = 2; // Say "Capital" after the letter. | tr->langopts.accents = 2; // Say "Capital" after the letter. | ||||
SetLetterVowel(tr, 'y'); | SetLetterVowel(tr, 'y'); | ||||
} | } | ||||
break; | |||||
break; | |||||
case L_jbo: // Lojban | case L_jbo: // Lojban | ||||
{ | { | ||||
static const short stress_lengths_jbo[8] = { 145, 145, 170, 160, 0, 0, 330, 350 }; | static const short stress_lengths_jbo[8] = { 145, 145, 170, 160, 0, 0, 330, 350 }; | ||||
SetLetterVowel(tr, 'y'); | SetLetterVowel(tr, 'y'); | ||||
tr->langopts.max_lengthmod = 368; | tr->langopts.max_lengthmod = 368; | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('k', 'a'): // Georgian | case L('k', 'a'): // Georgian | ||||
{ | { | ||||
// character codes offset by 0x1080 | // character codes offset by 0x1080 | ||||
tr->langopts.alt_alphabet = OFFSET_CYRILLIC; | tr->langopts.alt_alphabet = OFFSET_CYRILLIC; | ||||
tr->langopts.alt_alphabet_lang = L('r', 'u'); | tr->langopts.alt_alphabet_lang = L('r', 'u'); | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('k', 'k'): // Kazakh | case L('k', 'k'): // Kazakh | ||||
{ | { | ||||
static const unsigned char stress_amps_tr[8] = { 18, 16, 20, 21, 20, 21, 21, 20 }; | static const unsigned char stress_amps_tr[8] = { 18, 16, 20, 21, 20, 21, 21, 20 }; | ||||
tr->langopts.max_initial_consonants = 2; | tr->langopts.max_initial_consonants = 2; | ||||
SetLengthMods(tr, 3); // all equal | SetLengthMods(tr, 3); // all equal | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('k', 'l'): // Greenlandic | case L('k', 'l'): // Greenlandic | ||||
{ | { | ||||
SetupTranslator(tr, stress_lengths_equal, stress_amps_equal); | SetupTranslator(tr, stress_lengths_equal, stress_amps_equal); | ||||
tr->langopts.stress_flags = S_NO_AUTO_2; | tr->langopts.stress_flags = S_NO_AUTO_2; | ||||
tr->langopts.numbers = NUM_DECIMAL_COMMA | NUM_SWAP_TENS | NUM_HUNDRED_AND | NUM_OMIT_1_HUNDRED | NUM_ORDINAL_DOT | NUM_1900 | NUM_ROMAN | NUM_ROMAN_CAPITALS | NUM_ROMAN_ORDINAL; | tr->langopts.numbers = NUM_DECIMAL_COMMA | NUM_SWAP_TENS | NUM_HUNDRED_AND | NUM_OMIT_1_HUNDRED | NUM_ORDINAL_DOT | NUM_1900 | NUM_ROMAN | NUM_ROMAN_CAPITALS | NUM_ROMAN_ORDINAL; | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('k', 'o'): // Korean, TEST | case L('k', 'o'): // Korean, TEST | ||||
{ | { | ||||
static const char ko_ivowels[] = { 0x63, 0x64, 0x67, 0x68, 0x6d, 0x72, 0x74, 0x75, 0 }; // y and i vowels | static const char ko_ivowels[] = { 0x63, 0x64, 0x67, 0x68, 0x6d, 0x72, 0x74, 0x75, 0 }; // y and i vowels | ||||
tr->langopts.break_numbers = 0x1111110; | tr->langopts.break_numbers = 0x1111110; | ||||
tr->langopts.max_digits = 20; | tr->langopts.max_digits = 20; | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('k', 'u'): // Kurdish | case L('k', 'u'): // Kurdish | ||||
{ | { | ||||
static const unsigned char stress_amps_ku[8] = { 18, 18, 20, 20, 20, 22, 22, 21 }; | static const unsigned char stress_amps_ku[8] = { 18, 18, 20, 20, 20, 22, 22, 21 }; | ||||
tr->langopts.numbers = NUM_HUNDRED_AND | NUM_AND_UNITS | NUM_OMIT_1_HUNDRED | NUM_AND_HUNDRED; | tr->langopts.numbers = NUM_HUNDRED_AND | NUM_AND_UNITS | NUM_OMIT_1_HUNDRED | NUM_AND_HUNDRED; | ||||
tr->langopts.max_initial_consonants = 2; | tr->langopts.max_initial_consonants = 2; | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('l', 'a'): // Latin | case L('l', 'a'): // Latin | ||||
{ | { | ||||
tr->charset_a0 = charsets[4]; // ISO-8859-4, includes a,e,i,o,u-macron | tr->charset_a0 = charsets[4]; // ISO-8859-4, includes a,e,i,o,u-macron | ||||
tr->langopts.numbers = NUM_ROMAN; | tr->langopts.numbers = NUM_ROMAN; | ||||
tr->langopts.max_roman = 5000; | tr->langopts.max_roman = 5000; | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('l', 't'): // Lithuanian | case L('l', 't'): // Lithuanian | ||||
{ | { | ||||
tr->charset_a0 = charsets[4]; // ISO-8859-4 | tr->charset_a0 = charsets[4]; // ISO-8859-4 | ||||
tr->langopts.numbers2 = NUM2_THOUSANDS_VAR4; | tr->langopts.numbers2 = NUM2_THOUSANDS_VAR4; | ||||
tr->langopts.max_roman = 5000; | tr->langopts.max_roman = 5000; | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('l', 'v'): // latvian | case L('l', 'v'): // latvian | ||||
{ | { | ||||
static const unsigned char stress_amps_lv[8] = { 17, 13, 20, 20, 20, 22, 22, 21 }; | static const unsigned char stress_amps_lv[8] = { 17, 13, 20, 20, 20, 22, 22, 21 }; | ||||
tr->langopts.numbers = NUM_DECIMAL_COMMA | NUM_OMIT_1_HUNDRED | NUM_DFRACTION_4 | NUM_ORDINAL_DOT; | tr->langopts.numbers = NUM_DECIMAL_COMMA | NUM_OMIT_1_HUNDRED | NUM_DFRACTION_4 | NUM_ORDINAL_DOT; | ||||
tr->langopts.stress_flags = S_FINAL_DIM_ONLY | S_FINAL_NO_2 | S_EO_CLAUSE1; | tr->langopts.stress_flags = S_FINAL_DIM_ONLY | S_FINAL_NO_2 | S_EO_CLAUSE1; | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('m', 'k'): // Macedonian | case L('m', 'k'): // Macedonian | ||||
{ | { | ||||
static wchar_t vowels_cyrillic[] = { 0x440, // also include 'р' [R] | static wchar_t vowels_cyrillic[] = { 0x440, // also include 'р' [R] | ||||
tr->langopts.numbers = NUM_DECIMAL_COMMA | NUM_AND_UNITS | NUM_OMIT_1_HUNDRED | NUM_OMIT_1_THOUSAND | NUM_DFRACTION_2; | tr->langopts.numbers = NUM_DECIMAL_COMMA | NUM_AND_UNITS | NUM_OMIT_1_HUNDRED | NUM_OMIT_1_THOUSAND | NUM_DFRACTION_2; | ||||
tr->langopts.numbers2 = 0x8a; // variant numbers before thousands,milliards | tr->langopts.numbers2 = 0x8a; // variant numbers before thousands,milliards | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('m', 't'): // Maltese | case L('m', 't'): // Maltese | ||||
{ | { | ||||
tr->charset_a0 = charsets[3]; // ISO-8859-3 | tr->charset_a0 = charsets[3]; // ISO-8859-3 | ||||
tr->langopts.stress_rule = STRESSPOSN_2R; // penultimate | tr->langopts.stress_rule = STRESSPOSN_2R; // penultimate | ||||
tr->langopts.numbers = 1; | tr->langopts.numbers = 1; | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('n', 'l'): // Dutch | case L('n', 'l'): // Dutch | ||||
{ | { | ||||
static const short stress_lengths_nl[8] = { 160, 135, 210, 210, 0, 0, 260, 280 }; | static const short stress_lengths_nl[8] = { 160, 135, 210, 210, 0, 0, 260, 280 }; | ||||
tr->langopts.stress_flags = S_FIRST_PRIMARY; | tr->langopts.stress_flags = S_FIRST_PRIMARY; | ||||
memcpy(tr->stress_lengths, stress_lengths_nl, sizeof(tr->stress_lengths)); | memcpy(tr->stress_lengths, stress_lengths_nl, sizeof(tr->stress_lengths)); | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('n', 'o'): // Norwegian | case L('n', 'o'): // Norwegian | ||||
{ | { | ||||
static const short stress_lengths_no[8] = { 160, 140, 200, 200, 0, 0, 220, 230 }; | static const short stress_lengths_no[8] = { 160, 140, 200, 200, 0, 0, 220, 230 }; | ||||
SetLetterVowel(tr, 'y'); | SetLetterVowel(tr, 'y'); | ||||
tr->langopts.numbers = NUM_DECIMAL_COMMA | NUM_HUNDRED_AND | NUM_ALLOW_SPACE | NUM_1900 | NUM_ORDINAL_DOT; | tr->langopts.numbers = NUM_DECIMAL_COMMA | NUM_HUNDRED_AND | NUM_ALLOW_SPACE | NUM_1900 | NUM_ORDINAL_DOT; | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('o', 'm'): // Oromo | case L('o', 'm'): // Oromo | ||||
{ | { | ||||
static const unsigned char stress_amps_om[] = { 18, 15, 20, 20, 20, 22, 22, 22 }; | static const unsigned char stress_amps_om[] = { 18, 15, 20, 20, 20, 22, 22, 22 }; | ||||
tr->langopts.numbers = NUM_OMIT_1_HUNDRED | NUM_HUNDRED_AND; | tr->langopts.numbers = NUM_OMIT_1_HUNDRED | NUM_HUNDRED_AND; | ||||
tr->langopts.numbers2 = 0x200; // say "thousands" before its number | tr->langopts.numbers2 = 0x200; // say "thousands" before its number | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('p', 'l'): // Polish | case L('p', 'l'): // Polish | ||||
{ | { | ||||
static const short stress_lengths_pl[8] = { 160, 190, 175, 175, 0, 0, 200, 210 }; | static const short stress_lengths_pl[8] = { 160, 190, 175, 175, 0, 0, 200, 210 }; | ||||
tr->langopts.param[LOPT_COMBINE_WORDS] = 4 + 0x100; // combine 'nie' (marked with $alt2) with some 1-syllable (and 2-syllable) words (marked with $alt) | tr->langopts.param[LOPT_COMBINE_WORDS] = 4 + 0x100; // combine 'nie' (marked with $alt2) with some 1-syllable (and 2-syllable) words (marked with $alt) | ||||
SetLetterVowel(tr, 'y'); | SetLetterVowel(tr, 'y'); | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('p', 't'): // Portuguese | case L('p', 't'): // Portuguese | ||||
{ | { | ||||
static const short stress_lengths_pt[8] = { 170, 115, 210, 240, 0, 0, 260, 280 }; | static const short stress_lengths_pt[8] = { 170, 115, 210, 240, 0, 0, 260, 280 }; | ||||
tr->langopts.param[LOPT_ALT] = 2; // call ApplySpecialAttributes2() if a word has $alt or $alt2 | tr->langopts.param[LOPT_ALT] = 2; // call ApplySpecialAttributes2() if a word has $alt or $alt2 | ||||
tr->langopts.accents = 2; // 'capital' after letter name | tr->langopts.accents = 2; // 'capital' after letter name | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('r', 'o'): // Romanian | case L('r', 'o'): // Romanian | ||||
{ | { | ||||
static const short stress_lengths_ro[8] = { 170, 170, 180, 180, 0, 0, 240, 260 }; | static const short stress_lengths_ro[8] = { 170, 170, 180, 180, 0, 0, 240, 260 }; | ||||
tr->langopts.numbers = NUM_DECIMAL_COMMA | NUM_ALLOW_SPACE | NUM_DFRACTION_3 | NUM_AND_UNITS | NUM_ROMAN; | tr->langopts.numbers = NUM_DECIMAL_COMMA | NUM_ALLOW_SPACE | NUM_DFRACTION_3 | NUM_AND_UNITS | NUM_ROMAN; | ||||
tr->langopts.numbers2 = 0x1e; // variant numbers before all thousandplex | tr->langopts.numbers2 = 0x1e; // variant numbers before all thousandplex | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('r', 'u'): // Russian | case L('r', 'u'): // Russian | ||||
Translator_Russian(tr); | Translator_Russian(tr); | ||||
break; | break; | ||||
case L('r', 'w'): // Kiryarwanda | case L('r', 'w'): // Kiryarwanda | ||||
{ | { | ||||
tr->langopts.stress_rule = STRESSPOSN_2R; | tr->langopts.stress_rule = STRESSPOSN_2R; | ||||
tr->langopts.numbers = NUM_HUNDRED_AND | NUM_AND_UNITS | NUM_DFRACTION_2 | NUM_AND_HUNDRED; | tr->langopts.numbers = NUM_HUNDRED_AND | NUM_AND_UNITS | NUM_DFRACTION_2 | NUM_AND_HUNDRED; | ||||
tr->langopts.numbers2 = 0x200; // say "thousands" before its number | tr->langopts.numbers2 = 0x200; // say "thousands" before its number | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('s', 'k'): // Slovak | case L('s', 'k'): // Slovak | ||||
case L('c', 's'): // Czech | case L('c', 's'): // Czech | ||||
{ | { | ||||
ResetLetterBits(tr, 0x20); | ResetLetterBits(tr, 0x20); | ||||
SetLetterBits(tr, 5, sk_voiced); | SetLetterBits(tr, 5, sk_voiced); | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('s', 'i'): // Sinhala | case L('s', 'i'): // Sinhala | ||||
{ | { | ||||
SetupTranslator(tr, stress_lengths_ta, stress_amps_ta); | SetupTranslator(tr, stress_lengths_ta, stress_amps_ta); | ||||
tr->langopts.numbers2 = NUM2_PERCENT_BEFORE; | tr->langopts.numbers2 = NUM2_PERCENT_BEFORE; | ||||
tr->langopts.break_numbers = 0x14aa8; // for languages which have numbers for 100,000 and 100,00,000, eg Hindi | tr->langopts.break_numbers = 0x14aa8; // for languages which have numbers for 100,000 and 100,00,000, eg Hindi | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('s', 'l'): // Slovenian | case L('s', 'l'): // Slovenian | ||||
tr->charset_a0 = charsets[2]; // ISO-8859-2 | tr->charset_a0 = charsets[2]; // ISO-8859-2 | ||||
tr->langopts.stress_rule = STRESSPOSN_2R; // Temporary | tr->langopts.stress_rule = STRESSPOSN_2R; // Temporary | ||||
tr->langopts.thousands_sep = ' '; // don't allow dot as thousands separator | tr->langopts.thousands_sep = ' '; // don't allow dot as thousands separator | ||||
tr->langopts.replace_chars = replace_cyrillic_latin; | tr->langopts.replace_chars = replace_cyrillic_latin; | ||||
break; | break; | ||||
case L('s', 'q'): // Albanian | case L('s', 'q'): // Albanian | ||||
{ | { | ||||
static const short stress_lengths_sq[8] = { 150, 150, 180, 180, 0, 0, 300, 300 }; | static const short stress_lengths_sq[8] = { 150, 150, 180, 180, 0, 0, 300, 300 }; | ||||
tr->langopts.numbers = NUM_DECIMAL_COMMA | NUM_HUNDRED_AND | NUM_AND_UNITS | NUM_DFRACTION_4; | tr->langopts.numbers = NUM_DECIMAL_COMMA | NUM_HUNDRED_AND | NUM_AND_UNITS | NUM_DFRACTION_4; | ||||
tr->langopts.accents = 2; // "capital" after letter name | tr->langopts.accents = 2; // "capital" after letter name | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('s', 'v'): // Swedish | case L('s', 'v'): // Swedish | ||||
{ | { | ||||
static const unsigned char stress_amps_sv[] = { 16, 16, 20, 20, 20, 22, 22, 21 }; | static const unsigned char stress_amps_sv[] = { 16, 16, 20, 20, 20, 22, 22, 21 }; | ||||
tr->langopts.numbers = NUM_SINGLE_STRESS | NUM_DECIMAL_COMMA | NUM_ALLOW_SPACE | NUM_1900; | tr->langopts.numbers = NUM_SINGLE_STRESS | NUM_DECIMAL_COMMA | NUM_ALLOW_SPACE | NUM_1900; | ||||
tr->langopts.accents = 1; | tr->langopts.accents = 1; | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('s', 'w'): // Swahili | case L('s', 'w'): // Swahili | ||||
case L('t', 'n'): // Setswana | case L('t', 'n'): // Setswana | ||||
{ | { | ||||
tr->langopts.numbers = NUM_AND_UNITS | NUM_HUNDRED_AND | NUM_SINGLE_AND | NUM_OMIT_1_HUNDRED; | tr->langopts.numbers = NUM_AND_UNITS | NUM_HUNDRED_AND | NUM_SINGLE_AND | NUM_OMIT_1_HUNDRED; | ||||
tr->langopts.break_numbers = 0x49249268; // for languages which have numbers for 100,000 and 1,000,000 | tr->langopts.break_numbers = 0x49249268; // for languages which have numbers for 100,000 and 1,000,000 | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('t', 'a'): // Tamil | case L('t', 'a'): // Tamil | ||||
case L('k', 'n'): // Kannada | case L('k', 'n'): // Kannada | ||||
case L('m', 'l'): // Malayalam | case L('m', 'l'): // Malayalam | ||||
SetIndicLetters(tr); // call this after setting OFFSET_ | SetIndicLetters(tr); // call this after setting OFFSET_ | ||||
SetLetterBitsRange(tr, LETTERGP_B, 0x4e, 0x4e); // chillu-virama (unofficial) | SetLetterBitsRange(tr, LETTERGP_B, 0x4e, 0x4e); // chillu-virama (unofficial) | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('t', 'r'): // Turkish | case L('t', 'r'): // Turkish | ||||
case L('a', 'z'): // Azerbaijan | case L('a', 'z'): // Azerbaijan | ||||
{ | { | ||||
tr->langopts.numbers = NUM_SINGLE_STRESS | NUM_DECIMAL_COMMA | NUM_OMIT_1_HUNDRED | NUM_OMIT_1_THOUSAND | NUM_DFRACTION_2; | tr->langopts.numbers = NUM_SINGLE_STRESS | NUM_DECIMAL_COMMA | NUM_OMIT_1_HUNDRED | NUM_OMIT_1_THOUSAND | NUM_DFRACTION_2; | ||||
tr->langopts.max_initial_consonants = 2; | tr->langopts.max_initial_consonants = 2; | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('t', 't'): // Tatar | case L('t', 't'): // Tatar | ||||
{ | { | ||||
SetCyrillicLetters(tr); | SetCyrillicLetters(tr); | ||||
tr->langopts.stress_flags = S_NO_AUTO_2; // no automatic secondary stress | tr->langopts.stress_flags = S_NO_AUTO_2; // no automatic secondary stress | ||||
tr->langopts.numbers = NUM_SINGLE_STRESS | NUM_DECIMAL_COMMA | NUM_OMIT_1_HUNDRED | NUM_OMIT_1_THOUSAND | NUM_DFRACTION_4; | tr->langopts.numbers = NUM_SINGLE_STRESS | NUM_DECIMAL_COMMA | NUM_OMIT_1_HUNDRED | NUM_OMIT_1_THOUSAND | NUM_DFRACTION_4; | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('u', 'k'): // Ukrainian | case L('u', 'k'): // Ukrainian | ||||
{ | { | ||||
SetCyrillicLetters(tr); | SetCyrillicLetters(tr); | ||||
tr->langopts.param[LOPT_UNPRONOUNCABLE] = 0x432; // [v] don't count this character at start of word | tr->langopts.param[LOPT_UNPRONOUNCABLE] = 0x432; // [v] don't count this character at start of word | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('u', 'r'): // Urdu | case L('u', 'r'): // Urdu | ||||
case L('s', 'd'): // Sindhi | case L('s', 'd'): // Sindhi | ||||
{ | { | ||||
tr->langopts.numbers = NUM_SWAP_TENS; | tr->langopts.numbers = NUM_SWAP_TENS; | ||||
tr->langopts.break_numbers = 0x52a8; // for languages which have numbers for 100,000 and 100,00,000, eg Hindi | tr->langopts.break_numbers = 0x52a8; // for languages which have numbers for 100,000 and 100,00,000, eg Hindi | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('v', 'i'): // Vietnamese | case L('v', 'i'): // Vietnamese | ||||
{ | { | ||||
static const short stress_lengths_vi[8] = { 150, 150, 180, 180, 210, 230, 230, 240 }; | static const short stress_lengths_vi[8] = { 150, 150, 180, 180, 210, 230, 230, 240 }; | ||||
tr->langopts.numbers = NUM_DECIMAL_COMMA | NUM_HUNDRED_AND_DIGIT | NUM_DFRACTION_4 | NUM_ZERO_HUNDRED; | tr->langopts.numbers = NUM_DECIMAL_COMMA | NUM_HUNDRED_AND_DIGIT | NUM_DFRACTION_4 | NUM_ZERO_HUNDRED; | ||||
} | } | ||||
break; | |||||
break; | |||||
case L('w', 'o'): | case L('w', 'o'): | ||||
tr->langopts.stress_rule = STRESSPOSN_1L; | tr->langopts.stress_rule = STRESSPOSN_1L; | ||||
tr->langopts.numbers = NUM_AND_UNITS | NUM_HUNDRED_AND | NUM_OMIT_1_HUNDRED | NUM_OMIT_1_THOUSAND | NUM_SINGLE_STRESS; | tr->langopts.numbers = NUM_AND_UNITS | NUM_HUNDRED_AND | NUM_OMIT_1_HUNDRED | NUM_OMIT_1_THOUSAND | NUM_SINGLE_STRESS; | ||||
break; | break; | ||||
case L('z', 'h'): | case L('z', 'h'): | ||||
case L_zhy: | case L_zhy: | ||||
{ | { | ||||
tr->langopts.break_numbers = 0x00018; | tr->langopts.break_numbers = 0x00018; | ||||
} | } | ||||
} | } | ||||
break; | |||||
break; | |||||
default: | default: | ||||
tr->langopts.param[LOPT_UNPRONOUNCABLE] = 1; // disable check for unpronouncable words | tr->langopts.param[LOPT_UNPRONOUNCABLE] = 1; // disable check for unpronouncable words | ||||
break; | break; | ||||
return tr; | return tr; | ||||
} | } | ||||
void ProcessLanguageOptions(LANGUAGE_OPTIONS *langopts) | void ProcessLanguageOptions(LANGUAGE_OPTIONS *langopts) | ||||
{ | { | ||||
if (langopts->numbers & NUM_DECIMAL_COMMA) { | if (langopts->numbers & NUM_DECIMAL_COMMA) { | ||||
langopts->thousands_sep = 0; // don't allow thousands separator, except space | langopts->thousands_sep = 0; // don't allow thousands separator, except space | ||||
} | } | ||||
static void Translator_Russian(Translator *tr) | static void Translator_Russian(Translator *tr) | ||||
{ | { | ||||
static const unsigned char stress_amps_ru[] = { 16, 16, 18, 18, 20, 24, 24, 22 }; | static const unsigned char stress_amps_ru[] = { 16, 16, 18, 18, 20, 24, 24, 22 }; | ||||
tr->langopts.numbers2 = 0x2 + NUM2_THOUSANDS_VAR1; // variant numbers before thousands | tr->langopts.numbers2 = 0x2 + NUM2_THOUSANDS_VAR1; // variant numbers before thousands | ||||
tr->langopts.phoneme_change = 1; | tr->langopts.phoneme_change = 1; | ||||
tr->langopts.testing = 2; | tr->langopts.testing = 2; | ||||
} | } |
#define WORD_STRESS_CHAR '*' | #define WORD_STRESS_CHAR '*' | ||||
Translator *translator = NULL; // the main translator | Translator *translator = NULL; // the main translator | ||||
Translator *translator2 = NULL; // secondary translator for certain words | Translator *translator2 = NULL; // secondary translator for certain words | ||||
static char translator2_language[20] = { 0 }; | static char translator2_language[20] = { 0 }; | ||||
int pre_pause; | int pre_pause; | ||||
ALPHABET *current_alphabet; | ALPHABET *current_alphabet; | ||||
// these were previously in translator class | // these were previously in translator class | ||||
#ifdef PLATFORM_WINDOWS | #ifdef PLATFORM_WINDOWS | ||||
char word_phonemes[N_WORD_PHONEMES*2]; // longer, because snprint() is not available | char word_phonemes[N_WORD_PHONEMES*2]; // longer, because snprint() is not available | ||||
int n_ph_list2; | int n_ph_list2; | ||||
PHONEME_LIST2 ph_list2[N_PHONEME_LIST]; // first stage of text->phonemes | PHONEME_LIST2 ph_list2[N_PHONEME_LIST]; // first stage of text->phonemes | ||||
wchar_t option_punctlist[N_PUNCTLIST] = { 0 }; | wchar_t option_punctlist[N_PUNCTLIST] = { 0 }; | ||||
char ctrl_embedded = '\001'; // to allow an alternative CTRL for embedded commands | char ctrl_embedded = '\001'; // to allow an alternative CTRL for embedded commands | ||||
int option_multibyte = espeakCHARS_AUTO; // 0=auto, 1=utf8, 2=8bit, 3=wchar, 4=16bit | int option_multibyte = espeakCHARS_AUTO; // 0=auto, 1=utf8, 2=8bit, 3=wchar, 4=16bit | ||||
int n_replace_phonemes; | int n_replace_phonemes; | ||||
REPLACE_PHONEMES replace_phonemes[N_REPLACE_PHONEMES]; | REPLACE_PHONEMES replace_phonemes[N_REPLACE_PHONEMES]; | ||||
// brackets, also 0x2014 to 0x021f which don't need to be in this list | // brackets, also 0x2014 to 0x021f which don't need to be in this list | ||||
static const unsigned short brackets[] = { | static const unsigned short brackets[] = { | ||||
'(', ')', '[', ']', '{', '}', '<', '>', '"', '\'', '`', | '(', ')', '[', ']', '{', '}', '<', '>', '"', '\'', '`', | ||||
110, 120, 100, 110, 110, 110, 110, 110, 110, 110 | 110, 120, 100, 110, 110, 110, 110, 110, 110, 110 | ||||
}; | }; | ||||
static unsigned char *length_mod_tabs[6] = { | static unsigned char *length_mod_tabs[6] = { | ||||
length_mods_en, | length_mods_en, | ||||
length_mods_en, // 1 | length_mods_en, // 1 | ||||
length_mods_equal // 5 | length_mods_equal // 5 | ||||
}; | }; | ||||
void SetLengthMods(Translator *tr, int value) | void SetLengthMods(Translator *tr, int value) | ||||
{ | { | ||||
int value2; | int value2; | ||||
tr->langopts.length_mods0 = length_mod_tabs[value2]; | tr->langopts.length_mods0 = length_mod_tabs[value2]; | ||||
} | } | ||||
int IsAlpha(unsigned int c) | int IsAlpha(unsigned int c) | ||||
{ | { | ||||
// Replacement for iswalph() which also checks for some in-word symbols | // Replacement for iswalph() which also checks for some in-word symbols | ||||
return iswspace(c); | return iswspace(c); | ||||
} | } | ||||
void DeleteTranslator(Translator *tr) | void DeleteTranslator(Translator *tr) | ||||
{ | { | ||||
if (tr->data_dictlist != NULL) | if (tr->data_dictlist != NULL) | ||||
Free(tr); | Free(tr); | ||||
} | } | ||||
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 ? | ||||
return 0; | return 0; | ||||
} | } | ||||
int lookupwchar2(const unsigned short *list, int c) | int lookupwchar2(const unsigned short *list, int c) | ||||
{ | { | ||||
// Replace character c by another character. | // Replace character c by another character. | ||||
return 0; | return 0; | ||||
} | } | ||||
int IsBracket(int c) | int IsBracket(int c) | ||||
{ | { | ||||
if ((c >= 0x2014) && (c <= 0x201f)) | if ((c >= 0x2014) && (c <= 0x201f)) | ||||
return lookupwchar(brackets, c); | return lookupwchar(brackets, c); | ||||
} | } | ||||
int utf8_out(unsigned int c, char *buf) | int utf8_out(unsigned int c, char *buf) | ||||
{ | { | ||||
// write a unicode character into a buffer as utf8 | // write a unicode character into a buffer as utf8 | ||||
return n_bytes+1; | return n_bytes+1; | ||||
} | } | ||||
int utf8_nbytes(const char *buf) | int utf8_nbytes(const char *buf) | ||||
{ | { | ||||
// Returns the number of bytes for the first UTF-8 character in buf | // Returns the number of bytes for the first UTF-8 character in buf | ||||
return 4; | return 4; | ||||
} | } | ||||
int utf8_in2(int *c, const char *buf, int backwards) | int utf8_in2(int *c, const char *buf, int backwards) | ||||
{ | { | ||||
// Read a unicode characater from a UTF8 string | // Read a unicode characater from a UTF8 string | ||||
return n_bytes+1; | return n_bytes+1; | ||||
} | } | ||||
#pragma GCC visibility push(default) | #pragma GCC visibility push(default) | ||||
int utf8_in(int *c, const char *buf) | int utf8_in(int *c, const char *buf) | ||||
{ | { | ||||
} | } | ||||
#pragma GCC visibility pop | #pragma GCC visibility pop | ||||
char *strchr_w(const char *s, int c) | char *strchr_w(const char *s, int c) | ||||
{ | { | ||||
// return NULL for any non-ascii character | // return NULL for any non-ascii character | ||||
return strchr((char *)s, c); // (char *) is needed for Borland compiler | return strchr((char *)s, c); // (char *) is needed for Borland compiler | ||||
} | } | ||||
int IsAllUpper(const char *word) | int IsAllUpper(const char *word) | ||||
{ | { | ||||
int c; | int c; | ||||
return 1; | return 1; | ||||
} | } | ||||
static char *SpeakIndividualLetters(Translator *tr, char *word, char *phonemes, int spell_word) | static char *SpeakIndividualLetters(Translator *tr, char *word, char *phonemes, int spell_word) | ||||
{ | { | ||||
int posn = 0; | int posn = 0; | ||||
return word; | return word; | ||||
} | } | ||||
static int CheckDottedAbbrev(char *word1, WORD_TAB *wtab) | static int CheckDottedAbbrev(char *word1, WORD_TAB *wtab) | ||||
{ | { | ||||
int wc; | int wc; | ||||
return count; | return count; | ||||
} | } | ||||
extern char *phondata_ptr; | extern char *phondata_ptr; | ||||
int ChangeEquivalentPhonemes(Translator *tr, int lang2, char *phonemes) | int ChangeEquivalentPhonemes(Translator *tr, int lang2, char *phonemes) | ||||
return 1; | return 1; | ||||
} | } | ||||
int TranslateWord(Translator *tr, char *word_start, int next_pause, WORD_TAB *wtab, char *word_out) | int TranslateWord(Translator *tr, char *word_start, int next_pause, WORD_TAB *wtab, char *word_out) | ||||
{ | { | ||||
// word1 is terminated by space (0x20) character | // word1 is terminated by space (0x20) character | ||||
if (!found) | if (!found) | ||||
found = LookupDictList(tr, &word1, phonemes, dictionary_flags, FLAG_ALLOW_TEXTMODE, wtab); // the original word | found = LookupDictList(tr, &word1, phonemes, dictionary_flags, FLAG_ALLOW_TEXTMODE, wtab); // the original word | ||||
if ((dictionary_flags[0] & (FLAG_ALLOW_DOT | FLAG_NEEDS_DOT)) && (wordx[1] == '.')) | if ((dictionary_flags[0] & (FLAG_ALLOW_DOT | FLAG_NEEDS_DOT)) && (wordx[1] == '.')) | ||||
wordx[1] = ' '; // remove a Dot after this word | wordx[1] = ' '; // remove a Dot after this word | ||||
} | } | ||||
} | } | ||||
// if textmode, LookupDictList() replaces word1 by the new text and returns found=0 | // if textmode, LookupDictList() replaces word1 by the new text and returns found=0 | ||||
if (phonemes[0] == phonSWITCH) { | if (phonemes[0] == phonSWITCH) { | ||||
} | } | ||||
} | } | ||||
if ((end_type != 0) && !(end_type & SUFX_P)) { | if ((end_type != 0) && !(end_type & SUFX_P)) { | ||||
end_type1 = end_type; | end_type1 = end_type; | ||||
strcpy(phonemes2, phonemes); | strcpy(phonemes2, phonemes); | ||||
memcpy(wordx, word_copy, strlen(word_copy)); | memcpy(wordx, word_copy, strlen(word_copy)); | ||||
} | } | ||||
wordx[-1] = c_temp; | wordx[-1] = c_temp; | ||||
} | } | ||||
} | } | ||||
wflags |= emphasize_allcaps; | wflags |= emphasize_allcaps; | ||||
/* determine stress pattern for this word */ | /* determine stress pattern for this word */ | ||||
/******************************************/ | /******************************************/ | ||||
add_suffix_phonemes = 0; | add_suffix_phonemes = 0; | ||||
ChangeWordStress(tr, word_phonemes, 3); | ChangeWordStress(tr, word_phonemes, 3); | ||||
} | } | ||||
// dictionary flags for this word give a clue about which alternative pronunciations of | // dictionary flags for this word give a clue about which alternative pronunciations of | ||||
// following words to use. | // following words to use. | ||||
if (end_type1 & SUFX_F) { | if (end_type1 & SUFX_F) { | ||||
return dictionary_flags[0]; | return dictionary_flags[0]; | ||||
} | } | ||||
static void SetPlist2(PHONEME_LIST2 *p, unsigned char phcode) | static void SetPlist2(PHONEME_LIST2 *p, unsigned char phcode) | ||||
{ | { | ||||
p->phcode = phcode; | p->phcode = phcode; | ||||
return count; | return count; | ||||
} | } | ||||
void Word_EmbeddedCmd() | void Word_EmbeddedCmd() | ||||
{ | { | ||||
// Process embedded commands for emphasis, sayas, and break | // Process embedded commands for emphasis, sayas, and break | ||||
} while (((embedded_cmd & 0x80) == 0) && (embedded_read < embedded_ix)); | } while (((embedded_cmd & 0x80) == 0) && (embedded_read < embedded_ix)); | ||||
} | } | ||||
int SetTranslator2(const char *new_language) | int SetTranslator2(const char *new_language) | ||||
{ | { | ||||
// Set translator2 to a second language | // Set translator2 to a second language | ||||
return new_phoneme_tab; | return new_phoneme_tab; | ||||
} | } | ||||
static int TranslateWord2(Translator *tr, char *word, WORD_TAB *wtab, int pre_pause, int next_pause) | static int TranslateWord2(Translator *tr, char *word, WORD_TAB *wtab, int pre_pause, int next_pause) | ||||
{ | { | ||||
int flags = 0; | int flags = 0; | ||||
return flags; | return flags; | ||||
} | } | ||||
static int EmbeddedCommand(unsigned int *source_index_out) | static int EmbeddedCommand(unsigned int *source_index_out) | ||||
{ | { | ||||
// An embedded command to change the pitch, volume, etc. | // An embedded command to change the pitch, volume, etc. | ||||
return 1; | return 1; | ||||
} | } | ||||
static int SubstituteChar(Translator *tr, unsigned int c, unsigned int next_in, int *insert, int *wordflags) | static int SubstituteChar(Translator *tr, unsigned int c, unsigned int next_in, int *insert, int *wordflags) | ||||
{ | { | ||||
int ix; | int ix; | ||||
*wordflags |= FLAG_CHAR_REPLACED; | *wordflags |= FLAG_CHAR_REPLACED; | ||||
return new_c; | return new_c; | ||||
} | } | ||||
static int TranslateChar(Translator *tr, char *ptr, int prev_in, unsigned int c, unsigned int next_in, int *insert, int *wordflags) | static int TranslateChar(Translator *tr, char *ptr, int prev_in, unsigned int c, unsigned int next_in, int *insert, int *wordflags) | ||||
{ | { | ||||
// To allow language specific examination and replacement of characters | // To allow language specific examination and replacement of characters | ||||
case L('n', 'l'): | case L('n', 'l'): | ||||
// look for 'n and replace by a special character (unicode: schwa) | // look for 'n and replace by a special character (unicode: schwa) | ||||
if (!iswalpha2(prev_in)) { | if (!iswalpha2(prev_in)) { | ||||
utf8_in(&next2, &ptr[1]); | utf8_in(&next2, &ptr[1]); | ||||
return SubstituteChar(tr, c, next_in, insert, wordflags); | return SubstituteChar(tr, c, next_in, insert, wordflags); | ||||
} | } | ||||
static const char *UCase_ga[] = { "bp", "bhf", "dt", "gc", "hA", "mb", "nd", "ng", "ts", "tA", "nA", NULL }; | static const char *UCase_ga[] = { "bp", "bhf", "dt", "gc", "hA", "mb", "nd", "ng", "ts", "tA", "nA", NULL }; | ||||
int UpperCaseInWord(Translator *tr, char *word, int c) | int UpperCaseInWord(Translator *tr, char *word, int c) | ||||
return 0; | return 0; | ||||
} | } | ||||
void *TranslateClause(Translator *tr, FILE *f_text, const void *vp_input, int *tone_out, char **voice_change) | void *TranslateClause(Translator *tr, FILE *f_text, const void *vp_input, int *tone_out, char **voice_change) | ||||
{ | { | ||||
int ix; | int ix; | ||||
} | } | ||||
words[0].flags |= FLAG_FIRST_WORD; | words[0].flags |= FLAG_FIRST_WORD; | ||||
for (ix = 0; ix < word_count; ix++) { | for (ix = 0; ix < word_count; ix++) { | ||||
int nx; | int nx; | ||||
int c_temp; | int c_temp; | ||||
embedded_list[embedded_ix] = 0x80; | embedded_list[embedded_ix] = 0x80; | ||||
} | } | ||||
prev_clause_pause = clause_pause; | prev_clause_pause = clause_pause; | ||||
if (tone_out != NULL) | if (tone_out != NULL) | ||||
if (terminator & CLAUSE_BIT_SENTENCE) | if (terminator & CLAUSE_BIT_SENTENCE) | ||||
new_sentence = 1; // next clause is a new sentence | new_sentence = 1; // next clause is a new sentence | ||||
if (voice_change != NULL) { | if (voice_change != NULL) { | ||||
// return new voice name if an embedded voice change command terminated the clause | // return new voice name if an embedded voice change command terminated the clause | ||||
if (terminator & CLAUSE_BIT_VOICE) | if (terminator & CLAUSE_BIT_VOICE) | ||||
return (void *)p_textinput; | return (void *)p_textinput; | ||||
} | } | ||||
void InitText(int control) | void InitText(int control) | ||||
{ | { | ||||
count_sentences = 0; | count_sentences = 0; |
#include "voice.h" | #include "voice.h" | ||||
#include "translate.h" | #include "translate.h" | ||||
MNEM_TAB genders[] = { | MNEM_TAB genders[] = { | ||||
{ "unknown", 0 }, | { "unknown", 0 }, | ||||
{ "male", 1 }, | { "male", 1 }, | ||||
static int formant_rate_22050[9] = { 240, 170, 170, 170, 170, 170, 170, 170, 170 }; // values for 22kHz sample rate | static int formant_rate_22050[9] = { 240, 170, 170, 170, 170, 170, 170, 170, 170 }; // values for 22kHz sample rate | ||||
int formant_rate[9]; // values adjusted for actual sample rate | int formant_rate[9]; // values adjusted for actual sample rate | ||||
#define DEFAULT_LANGUAGE_PRIORITY 5 | #define DEFAULT_LANGUAGE_PRIORITY 5 | ||||
#define N_VOICES_LIST 250 | #define N_VOICES_LIST 250 | ||||
static int n_voices_list = 0; | static int n_voices_list = 0; | ||||
espeak_VOICE current_voice_selected; | espeak_VOICE current_voice_selected; | ||||
enum { | enum { | ||||
V_NAME = 1, | V_NAME = 1, | ||||
V_LANGUAGE, | V_LANGUAGE, | ||||
V_CONSONANTS | V_CONSONANTS | ||||
}; | }; | ||||
static MNEM_TAB options_tab[] = { | static MNEM_TAB options_tab[] = { | ||||
{ "reduce_t", LOPT_REDUCE_T }, | { "reduce_t", LOPT_REDUCE_T }, | ||||
{ "bracket", LOPT_BRACKET_PAUSE }, | { "bracket", LOPT_BRACKET_PAUSE }, | ||||
{ NULL, 0 } | { NULL, 0 } | ||||
}; | }; | ||||
#define N_VOICE_VARIANTS 12 | #define N_VOICE_VARIANTS 12 | ||||
const char variants_either[N_VOICE_VARIANTS] = { 1, 2, 12, 3, 13, 4, 14, 5, 11, 0 }; | const char variants_either[N_VOICE_VARIANTS] = { 1, 2, 12, 3, 13, 4, 14, 5, 11, 0 }; | ||||
const char variants_male[N_VOICE_VARIANTS] = { 1, 2, 3, 4, 5, 6, 0 }; | const char variants_male[N_VOICE_VARIANTS] = { 1, 2, 3, 4, 5, 6, 0 }; | ||||
static voice_t voicedata; | static voice_t voicedata; | ||||
voice_t *voice = &voicedata; | voice_t *voice = &voicedata; | ||||
static char *fgets_strip(char *buf, int size, FILE *f_in) | static char *fgets_strip(char *buf, int size, FILE *f_in) | ||||
{ | { | ||||
// strip trailing spaces, and truncate lines at // comment | // strip trailing spaces, and truncate lines at // comment | ||||
return buf; | return buf; | ||||
} | } | ||||
static int LookupTune(const char *name) | static int LookupTune(const char *name) | ||||
{ | { | ||||
int ix; | int ix; | ||||
return -1; | return -1; | ||||
} | } | ||||
static void SetToneAdjust(voice_t *voice, int *tone_pts) | static void SetToneAdjust(voice_t *voice, int *tone_pts) | ||||
{ | { | ||||
int ix; | int ix; | ||||
} | } | ||||
} | } | ||||
void ReadTonePoints(char *string, int *tone_pts) | void ReadTonePoints(char *string, int *tone_pts) | ||||
{ | { | ||||
// tone_pts[] is int[12] | // tone_pts[] is int[12] | ||||
&tone_pts[8], &tone_pts[9]); | &tone_pts[8], &tone_pts[9]); | ||||
} | } | ||||
static espeak_VOICE *ReadVoiceFile(FILE *f_in, const char *fname, const char *leafname) | static espeak_VOICE *ReadVoiceFile(FILE *f_in, const char *fname, const char *leafname) | ||||
{ | { | ||||
// Read a Voice file, allocate a VOICE_DATA and set data from the | // Read a Voice file, allocate a VOICE_DATA and set data from the | ||||
char vlanguage[80]; | char vlanguage[80]; | ||||
char languages[300]; // allow space for several alternate language names and priorities | char languages[300]; // allow space for several alternate language names and priorities | ||||
unsigned int len; | unsigned int len; | ||||
int langix = 0; | int langix = 0; | ||||
int n_languages = 0; | int n_languages = 0; | ||||
return voice_data; | return voice_data; | ||||
} | } | ||||
void VoiceReset(int tone_only) | void VoiceReset(int tone_only) | ||||
{ | { | ||||
// Set voice to the default values | // Set voice to the default values | ||||
} | } | ||||
} | } | ||||
static void VoiceFormant(char *p) | static void VoiceFormant(char *p) | ||||
{ | { | ||||
// Set parameters for a formant | // Set parameters for a formant | ||||
voice->freqadd[formant] = freqadd; | voice->freqadd[formant] = freqadd; | ||||
} | } | ||||
static void PhonemeReplacement(int type, char *p) | static void PhonemeReplacement(int type, char *p) | ||||
{ | { | ||||
int n; | int n; | ||||
replace_phonemes[n_replace_phonemes++].type = flags; | replace_phonemes[n_replace_phonemes++].type = flags; | ||||
} | } | ||||
static int Read8Numbers(char *data_in, int *data) | static int Read8Numbers(char *data_in, int *data) | ||||
{ | { | ||||
// Read 8 integer numbers | // Read 8 integer numbers | ||||
&data[0], &data[1], &data[2], &data[3], &data[4], &data[5], &data[6], &data[7]); | &data[0], &data[1], &data[2], &data[3], &data[4], &data[5], &data[6], &data[7]); | ||||
} | } | ||||
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') | ||||
return value; | return value; | ||||
} | } | ||||
voice_t *LoadVoice(const char *vname, int control) | voice_t *LoadVoice(const char *vname, int control) | ||||
{ | { | ||||
// control, bit 0 1= no_default | // control, bit 0 1= no_default | ||||
static const char *voices_europe = | static const char *voices_europe = | ||||
"an bg bs ca cs cy da de el en en-us es et eu fi fr fr-be ga hr hu is it lt lv mk nl no pl pt-pt ro ru sk sq sr sv "; | "an bg bs ca cs cy da de el en en-us es et eu fi fr fr-be ga hr hu is it lt lv mk nl no pl pt-pt ro ru sk sq sr sv "; | ||||
strncpy0(voicename, vname, sizeof(voicename)); | strncpy0(voicename, vname, sizeof(voicename)); | ||||
if (control & 0x10) { | if (control & 0x10) { | ||||
strcpy(buf, vname); | strcpy(buf, vname); | ||||
strcpy(new_dictionary, language_type); | strcpy(new_dictionary, language_type); | ||||
strcpy(phonemes_name, language_type); | strcpy(phonemes_name, language_type); | ||||
if (!tone_only) { | if (!tone_only) { | ||||
voice = &voicedata; | voice = &voicedata; | ||||
strncpy0(voice_identifier, vname, sizeof(voice_identifier)); | strncpy0(voice_identifier, vname, sizeof(voice_identifier)); | ||||
if (!tone_only) | if (!tone_only) | ||||
SelectPhonemeTableName(phonemes_name); // set up phoneme_tab | SelectPhonemeTableName(phonemes_name); // set up phoneme_tab | ||||
while ((f_voice != NULL) && (fgets_strip(buf, sizeof(buf), f_voice) != NULL)) { | while ((f_voice != NULL) && (fgets_strip(buf, sizeof(buf), f_voice) != NULL)) { | ||||
// isolate the attribute name | // isolate the attribute name | ||||
for (p = buf; (*p != 0) && !isspace(*p); p++) ; | for (p = buf; (*p != 0) && !isspace(*p); p++) ; | ||||
strncpy0(voice->language_name, language_name, sizeof(voice->language_name)); | strncpy0(voice->language_name, language_name, sizeof(voice->language_name)); | ||||
} | } | ||||
} | } | ||||
break; | |||||
break; | |||||
case V_NAME: | case V_NAME: | ||||
if (tone_only == 0) { | if (tone_only == 0) { | ||||
while (isspace(*p)) p++; | while (isspace(*p)) p++; | ||||
strncpy0(voice_name, p, sizeof(voice_name)); | strncpy0(voice_name, p, sizeof(voice_name)); | ||||
} | } | ||||
break; | break; | ||||
case V_GENDER: | case V_GENDER: | ||||
{ | { | ||||
int age = 0; | int age = 0; | ||||
current_voice_selected.gender = LookupMnem(genders, vgender); | current_voice_selected.gender = LookupMnem(genders, vgender); | ||||
current_voice_selected.age = age; | current_voice_selected.age = age; | ||||
} | } | ||||
break; | |||||
break; | |||||
case V_TRANSLATOR: | case V_TRANSLATOR: | ||||
if (tone_only) break; | if (tone_only) break; | ||||
new_translator = SelectTranslator(translator_name); | new_translator = SelectTranslator(translator_name); | ||||
langopts = &new_translator->langopts; | langopts = &new_translator->langopts; | ||||
break; | break; | ||||
case V_DICTIONARY: // dictionary | case V_DICTIONARY: // dictionary | ||||
sscanf(p, "%s", new_dictionary); | sscanf(p, "%s", new_dictionary); | ||||
break; | break; | ||||
case V_PHONEMES: // phoneme table | case V_PHONEMES: // phoneme table | ||||
sscanf(p, "%s", phonemes_name); | sscanf(p, "%s", phonemes_name); | ||||
break; | break; | ||||
case V_FORMANT: | case V_FORMANT: | ||||
VoiceFormant(p); | VoiceFormant(p); | ||||
break; | break; | ||||
case V_PITCH: | case V_PITCH: | ||||
{ | { | ||||
double factor; | double factor; | ||||
factor = (double)(pitch1 - 82)/82; | factor = (double)(pitch1 - 82)/82; | ||||
voice->formant_factor = (int)((1+factor/4) * 256); // nominal formant shift for a different voice pitch | voice->formant_factor = (int)((1+factor/4) * 256); // nominal formant shift for a different voice pitch | ||||
} | } | ||||
break; | |||||
break; | |||||
case V_STRESSLENGTH: // stressLength | case V_STRESSLENGTH: // stressLength | ||||
stress_lengths_set = Read8Numbers(p, stress_lengths); | stress_lengths_set = Read8Numbers(p, stress_lengths); | ||||
break; | break; | ||||
case V_STRESSAMP: // stressAmp | case V_STRESSAMP: // stressAmp | ||||
stress_amps_set = Read8Numbers(p, stress_amps); | stress_amps_set = Read8Numbers(p, stress_amps); | ||||
break; | break; | ||||
case V_STRESSADD: // stressAdd | case V_STRESSADD: // stressAdd | ||||
stress_add_set = Read8Numbers(p, stress_add); | stress_add_set = Read8Numbers(p, stress_add); | ||||
break; | break; | ||||
case V_INTONATION: // intonation | case V_INTONATION: // intonation | ||||
sscanf(p, "%d %d", &option_tone_flags, &option_tone2); | sscanf(p, "%d %d", &option_tone_flags, &option_tone2); | ||||
if ((option_tone_flags & 0xff) != 0) | if ((option_tone_flags & 0xff) != 0) | ||||
langopts->intonation_group = option_tone_flags & 0xff; | langopts->intonation_group = option_tone_flags & 0xff; | ||||
break; | break; | ||||
case V_TUNES: | case V_TUNES: | ||||
n = sscanf(p, "%s %s %s %s %s %s", names[0], names[1], names[2], names[3], names[4], names[5]); | n = sscanf(p, "%s %s %s %s %s %s", names[0], names[1], names[2], names[3], names[4], names[5]); | ||||
langopts->intonation_group = 0; | langopts->intonation_group = 0; | ||||
langopts->tunes[ix] = value; | langopts->tunes[ix] = value; | ||||
} | } | ||||
break; | break; | ||||
case V_DICTRULES: // conditional dictionary rules and list entries | case V_DICTRULES: // conditional dictionary rules and list entries | ||||
case V_NUMBERS: | case V_NUMBERS: | ||||
case V_STRESSOPT: | case V_STRESSOPT: | ||||
} | } | ||||
ProcessLanguageOptions(langopts); | ProcessLanguageOptions(langopts); | ||||
break; | break; | ||||
case V_REPLACE: | case V_REPLACE: | ||||
if (phonemes_set == 0) { | if (phonemes_set == 0) { | ||||
// must set up a phoneme table before we can lookup phoneme mnemonics | // must set up a phoneme table before we can lookup phoneme mnemonics | ||||
} | } | ||||
PhonemeReplacement(key, p); | PhonemeReplacement(key, p); | ||||
break; | break; | ||||
case V_WORDGAP: // words | case V_WORDGAP: // words | ||||
sscanf(p, "%d %d", &langopts->word_gap, &langopts->vowel_pause); | sscanf(p, "%d %d", &langopts->word_gap, &langopts->vowel_pause); | ||||
break; | break; | ||||
case V_STRESSRULE: | case V_STRESSRULE: | ||||
sscanf(p, "%d %d %d %d", &langopts->stress_rule, | sscanf(p, "%d %d %d %d", &langopts->stress_rule, | ||||
&langopts->stress_flags, | &langopts->stress_flags, | ||||
&langopts->unstressed_wd1, | &langopts->unstressed_wd1, | ||||
&langopts->unstressed_wd2); | &langopts->unstressed_wd2); | ||||
break; | break; | ||||
case V_CHARSET: | case V_CHARSET: | ||||
if ((sscanf(p, "%d", &value) == 1) && (value < N_CHARSETS)) | if ((sscanf(p, "%d", &value) == 1) && (value < N_CHARSETS)) | ||||
new_translator->charset_a0 = charsets[value]; | new_translator->charset_a0 = charsets[value]; | ||||
break; | break; | ||||
case V_OPTION: | case V_OPTION: | ||||
value2 = 0; | value2 = 0; | ||||
if (((sscanf(p, "%s %d %d", option_name, &value, &value2) >= 2) && ((ix = LookupMnem(options_tab, option_name)) >= 0)) || | if (((sscanf(p, "%s %d %d", option_name, &value, &value2) >= 2) && ((ix = LookupMnem(options_tab, option_name)) >= 0)) || | ||||
} else | } else | ||||
fprintf(stderr, "Bad voice option: %s %s\n", buf, p); | fprintf(stderr, "Bad voice option: %s %s\n", buf, p); | ||||
break; | break; | ||||
case V_ECHO: | case V_ECHO: | ||||
// echo. suggest: 135mS 11% | // echo. suggest: 135mS 11% | ||||
value = 0; | value = 0; | ||||
voice->echo_amp = 0; | voice->echo_amp = 0; | ||||
sscanf(p, "%d %d", &voice->echo_delay, &voice->echo_amp); | sscanf(p, "%d %d", &voice->echo_delay, &voice->echo_amp); | ||||
break; | break; | ||||
case V_FLUTTER: // flutter | case V_FLUTTER: // flutter | ||||
if (sscanf(p, "%d", &value) == 1) | if (sscanf(p, "%d", &value) == 1) | ||||
voice->flutter = value * 32; | voice->flutter = value * 32; | ||||
break; | break; | ||||
case V_ROUGHNESS: // roughness | case V_ROUGHNESS: // roughness | ||||
if (sscanf(p, "%d", &value) == 1) | if (sscanf(p, "%d", &value) == 1) | ||||
voice->roughness = value; | voice->roughness = value; | ||||
break; | break; | ||||
case V_CLARITY: // formantshape | case V_CLARITY: // formantshape | ||||
if (sscanf(p, "%d", &value) == 1) { | if (sscanf(p, "%d", &value) == 1) { | ||||
if (value > 4) { | if (value > 4) { | ||||
voice->n_harmonic_peaks = 1+value; | voice->n_harmonic_peaks = 1+value; | ||||
} | } | ||||
break; | break; | ||||
case V_TONE: | case V_TONE: | ||||
{ | { | ||||
int tone_data[12]; | int tone_data[12]; | ||||
ReadTonePoints(p, tone_data); | ReadTonePoints(p, tone_data); | ||||
SetToneAdjust(voice, tone_data); | SetToneAdjust(voice, tone_data); | ||||
} | } | ||||
break; | |||||
break; | |||||
case V_VOICING: | case V_VOICING: | ||||
if (sscanf(p, "%d", &value) == 1) | if (sscanf(p, "%d", &value) == 1) | ||||
voice->voicing = (value * 64)/100; | voice->voicing = (value * 64)/100; | ||||
break; | break; | ||||
case V_BREATH: | case V_BREATH: | ||||
voice->breath[0] = Read8Numbers(p, &voice->breath[1]); | voice->breath[0] = Read8Numbers(p, &voice->breath[1]); | ||||
for (ix = 1; ix < 8; ix++) { | for (ix = 1; ix < 8; ix++) { | ||||
voice->breath[ix] = -voice->breath[ix]; | voice->breath[ix] = -voice->breath[ix]; | ||||
} | } | ||||
break; | break; | ||||
case V_BREATHW: | case V_BREATHW: | ||||
voice->breathw[0] = Read8Numbers(p, &voice->breathw[1]); | voice->breathw[0] = Read8Numbers(p, &voice->breathw[1]); | ||||
break; | break; | ||||
case V_CONSONANTS: | case V_CONSONANTS: | ||||
value = sscanf(p, "%d %d", &voice->consonant_amp, &voice->consonant_ampv); | value = sscanf(p, "%d %d", &voice->consonant_amp, &voice->consonant_ampv); | ||||
break; | break; | ||||
case V_SPEED: | case V_SPEED: | ||||
sscanf(p, "%d", &voice->speed_percent); | sscanf(p, "%d", &voice->speed_percent); | ||||
break; | break; | ||||
case V_MBROLA: | case V_MBROLA: | ||||
{ | { | ||||
int srate = 16000; | int srate = 16000; | ||||
} | } | ||||
voice->samplerate = srate; | voice->samplerate = srate; | ||||
} | } | ||||
break; | |||||
break; | |||||
case V_KLATT: | case V_KLATT: | ||||
voice->klattv[0] = 1; // default source: IMPULSIVE | voice->klattv[0] = 1; // default source: IMPULSIVE | ||||
Read8Numbers(p, voice->klattv); | Read8Numbers(p, voice->klattv); | ||||
voice->klattv[KLATT_Kopen] -= 40; | voice->klattv[KLATT_Kopen] -= 40; | ||||
break; | break; | ||||
case V_FAST: | case V_FAST: | ||||
Read8Numbers(p, speed.fast_settings); | Read8Numbers(p, speed.fast_settings); | ||||
SetSpeed(3); | SetSpeed(3); | ||||
break; | break; | ||||
case V_DICTMIN: | case V_DICTMIN: | ||||
sscanf(p, "%d", &dict_min); | sscanf(p, "%d", &dict_min); | ||||
break; | break; | ||||
case V_ALPHABET2: | case V_ALPHABET2: | ||||
{ | { | ||||
ALPHABET *alphabet; | ALPHABET *alphabet; | ||||
} else | } else | ||||
fprintf(stderr, "alphabet name '%s' not found\n", name1); | fprintf(stderr, "alphabet name '%s' not found\n", name1); | ||||
} | } | ||||
break; | |||||
break; | |||||
case V_DICTDIALECT: | case V_DICTDIALECT: | ||||
// specify a dialect to use for foreign words, eg, en-us for _^_EN | // specify a dialect to use for foreign words, eg, en-us for _^_EN | ||||
if (sscanf(p, "%s", name1) == 1) { | if (sscanf(p, "%s", name1) == 1) { | ||||
fprintf(stderr, "dictdialect name '%s' not recognized\n", name1); | fprintf(stderr, "dictdialect name '%s' not recognized\n", name1); | ||||
} | } | ||||
break; | break; | ||||
default: | default: | ||||
if ((key & 0xff00) == 0x100) | if ((key & 0xff00) == 0x100) | ||||
sscanf(p, "%d", &langopts->param[key &0xff]); | sscanf(p, "%d", &langopts->param[key &0xff]); | ||||
return voice; | return voice; | ||||
} | } | ||||
static char *ExtractVoiceVariantName(char *vname, int variant_num, int add_dir) | static char *ExtractVoiceVariantName(char *vname, int variant_num, int add_dir) | ||||
{ | { | ||||
// Remove any voice variant suffix (name or number) from a voice name | // Remove any voice variant suffix (name or number) from a voice name | ||||
return variant_name; | return variant_name; | ||||
} | } | ||||
voice_t *LoadVoiceVariant(const char *vname, int variant_num) | voice_t *LoadVoiceVariant(const char *vname, int variant_num) | ||||
{ | { | ||||
// Load a voice file. | // Load a voice file. | ||||
return v; | return v; | ||||
} | } | ||||
static int __cdecl VoiceNameSorter(const void *p1, const void *p2) | static int __cdecl VoiceNameSorter(const void *p1, const void *p2) | ||||
{ | { | ||||
int ix; | int ix; | ||||
espeak_VOICE *v1 = *(espeak_VOICE **)p1; | espeak_VOICE *v1 = *(espeak_VOICE **)p1; | ||||
espeak_VOICE *v2 = *(espeak_VOICE **)p2; | espeak_VOICE *v2 = *(espeak_VOICE **)p2; | ||||
if ((ix = strcmp(&v1->languages[1], &v2->languages[1])) != 0) // primary language name | if ((ix = strcmp(&v1->languages[1], &v2->languages[1])) != 0) // primary language name | ||||
return ix; | return ix; | ||||
if ((ix = v1->languages[0] - v2->languages[0]) != 0) // priority number | if ((ix = v1->languages[0] - v2->languages[0]) != 0) // priority number | ||||
return strcmp(v1->name, v2->name); | return strcmp(v1->name, v2->name); | ||||
} | } | ||||
static int __cdecl VoiceScoreSorter(const void *p1, const void *p2) | static int __cdecl VoiceScoreSorter(const void *p1, const void *p2) | ||||
{ | { | ||||
int ix; | int ix; | ||||
return strcmp(v1->name, v2->name); | return strcmp(v1->name, v2->name); | ||||
} | } | ||||
static int ScoreVoice(espeak_VOICE *voice_spec, const char *spec_language, int spec_n_parts, int spec_lang_len, espeak_VOICE *voice) | static int ScoreVoice(espeak_VOICE *voice_spec, const char *spec_language, int spec_n_parts, int spec_lang_len, espeak_VOICE *voice) | ||||
{ | { | ||||
int ix; | int ix; | ||||
return score; | return score; | ||||
} | } | ||||
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 | ||||
language[lang_len] = 0; | language[lang_len] = 0; | ||||
n_parts = -1; | n_parts = -1; | ||||
} | } | ||||
} | } | ||||
// select those voices which match the specified language | // select those voices which match the specified language | ||||
return nv; | return nv; | ||||
} | } | ||||
espeak_VOICE *SelectVoiceByName(espeak_VOICE **voices, const char *name2) | espeak_VOICE *SelectVoiceByName(espeak_VOICE **voices, const char *name2) | ||||
{ | { | ||||
int ix; | int ix; | ||||
return voices[match_name]; | return voices[match_name]; | ||||
} | } | ||||
char const *SelectVoice(espeak_VOICE *voice_select, int *found) | char const *SelectVoice(espeak_VOICE *voice_select, int *found) | ||||
{ | { | ||||
// Returns a path within espeak-voices, with a possible +variant suffix | // Returns a path within espeak-voices, with a possible +variant suffix | ||||
return vp->identifier; | return vp->identifier; | ||||
} | } | ||||
static void GetVoices(const char *path) | static void GetVoices(const char *path) | ||||
{ | { | ||||
FILE *f_voice; | FILE *f_voice; | ||||
} | } | ||||
} while (FindNextFileA(hFind, &FindFileData) != 0); | } while (FindNextFileA(hFind, &FindFileData) != 0); | ||||
FindClose(hFind); | FindClose(hFind); | ||||
#else | #else | ||||
DIR *dir; | DIR *dir; | ||||
struct dirent *ent; | struct dirent *ent; | ||||
#endif | #endif | ||||
} | } | ||||
espeak_ERROR SetVoiceByName(const char *name) | espeak_ERROR SetVoiceByName(const char *name) | ||||
{ | { | ||||
espeak_VOICE *v; | espeak_VOICE *v; | ||||
return EE_INTERNAL_ERROR; // voice name not found | return EE_INTERNAL_ERROR; // voice name not found | ||||
} | } | ||||
espeak_ERROR SetVoiceByProperties(espeak_VOICE *voice_selector) | espeak_ERROR SetVoiceByProperties(espeak_VOICE *voice_selector) | ||||
{ | { | ||||
const char *voice_id; | const char *voice_id; | ||||
return EE_OK; | return EE_OK; | ||||
} | } | ||||
void FreeVoiceList() | void FreeVoiceList() | ||||
{ | { | ||||
int ix; | int ix; | ||||
n_voices_list = 0; | n_voices_list = 0; | ||||
} | } | ||||
#pragma GCC visibility push(default) | #pragma GCC visibility push(default) | ||||
ESPEAK_API const espeak_VOICE **espeak_ListVoices(espeak_VOICE *voice_spec) | ESPEAK_API const espeak_VOICE **espeak_ListVoices(espeak_VOICE *voice_spec) | ||||
{ | { | ||||
char path_voices[sizeof(path_home)+12]; | char path_voices[sizeof(path_home)+12]; | ||||
#ifdef PLATFORM_RISCOS | #ifdef PLATFORM_RISCOS | ||||
if (n_voices_list == 0) { | if (n_voices_list == 0) { | ||||
sprintf(path_voices, "%s%cvoices", path_home, PATHSEP); | sprintf(path_voices, "%s%cvoices", path_home, PATHSEP); | ||||
voices_list[n_voices_list] = NULL; // voices list terminator | voices_list[n_voices_list] = NULL; // voices list terminator | ||||
} | } | ||||
return (const espeak_VOICE **)voices_list; | return (const espeak_VOICE **)voices_list; | ||||
#else | #else | ||||
int ix; | int ix; | ||||
int j; | int j; | ||||
qsort(voices_list, n_voices_list, sizeof(espeak_VOICE *), | qsort(voices_list, n_voices_list, sizeof(espeak_VOICE *), | ||||
(int(__cdecl *)(const void *, const void *))VoiceNameSorter); | (int(__cdecl *)(const void *, const void *))VoiceNameSorter); | ||||
if (voice_spec) { | if (voice_spec) { | ||||
// select the voices which match the voice_spec, and sort them by preference | // select the voices which match the voice_spec, and sort them by preference | ||||
SetVoiceScores(voice_spec, voices, 1); | SetVoiceScores(voice_spec, voices, 1); | ||||
#endif | #endif | ||||
} | } | ||||
ESPEAK_API espeak_VOICE *espeak_GetCurrentVoice(void) | ESPEAK_API espeak_VOICE *espeak_GetCurrentVoice(void) | ||||
{ | { | ||||
return ¤t_voice_selected; | return ¤t_voice_selected; |
}; | }; | ||||
#endif /* HAVE_STRUCT_TIMESPEC */ | #endif /* HAVE_STRUCT_TIMESPEC */ | ||||
enum { ONE_BILLION = 1000000000 }; | enum { ONE_BILLION = 1000000000 }; | ||||
#ifdef USE_PORTAUDIO | #ifdef USE_PORTAUDIO | ||||
#define USE_PORTAUDIO 18 | #define USE_PORTAUDIO 18 | ||||
#endif | #endif | ||||
#ifdef USE_PULSEAUDIO | #ifdef USE_PULSEAUDIO | ||||
// create some wrappers for runtime detection | // create some wrappers for runtime detection | ||||
#endif // USE_PULSEAUDIO | #endif // USE_PULSEAUDIO | ||||
static t_wave_callback *my_callback_is_output_enabled = NULL; | static t_wave_callback *my_callback_is_output_enabled = NULL; | ||||
#define N_WAV_BUF 10 | #define N_WAV_BUF 10 | ||||
return aResult; | return aResult; | ||||
} | } | ||||
void wave_flush(void *theHandler) | void wave_flush(void *theHandler) | ||||
{ | { | ||||
ENTER("wave_flush"); | ENTER("wave_flush"); | ||||
out_channels = 1; | out_channels = 1; | ||||
#if USE_PORTAUDIO == 18 | #if USE_PORTAUDIO == 18 | ||||
PaDeviceID playbackDevice = Pa_GetDefaultOutputDeviceID(); | PaDeviceID playbackDevice = Pa_GetDefaultOutputDeviceID(); | ||||
PaError err = Pa_OpenStream(&pa_stream, | PaError err = Pa_OpenStream(&pa_stream, | ||||
SHOW("wave_is_busy: %d\n", active); | SHOW("wave_is_busy: %d\n", active); | ||||
return active == 1; | return active == 1; | ||||
} | } | ||||
ENTER("wave_terminate"); | ENTER("wave_terminate"); | ||||
Pa_Terminate(); | Pa_Terminate(); | ||||
} | } | ||||
uint32_t wave_get_read_position(void *theHandler) | uint32_t wave_get_read_position(void *theHandler) | ||||
return myWrite; | return myWrite; | ||||
} | } | ||||
#else | #else | ||||
int wave_init(int srate) { | int wave_init(int srate) { | ||||
return 1; | return 1; | ||||
} | } | ||||
ts->tv_nsec = (long int)t_ns; | ts->tv_nsec = (long int)t_ns; | ||||
} | } | ||||
#endif // USE_ASYNC | #endif // USE_ASYNC |
case PA_CONTEXT_FAILED: | case PA_CONTEXT_FAILED: | ||||
pa_threaded_mainloop_signal(mainloop, 0); | pa_threaded_mainloop_signal(mainloop, 0); | ||||
break; | break; | ||||
case PA_CONTEXT_UNCONNECTED: | case PA_CONTEXT_UNCONNECTED: | ||||
case PA_CONTEXT_CONNECTING: | case PA_CONTEXT_CONNECTING: | ||||
case PA_CONTEXT_AUTHORIZING: | case PA_CONTEXT_AUTHORIZING: | ||||
switch (pa_stream_get_state(s)) | switch (pa_stream_get_state(s)) | ||||
{ | { | ||||
case PA_STREAM_READY: | case PA_STREAM_READY: | ||||
case PA_STREAM_FAILED: | case PA_STREAM_FAILED: | ||||
case PA_STREAM_TERMINATED: | case PA_STREAM_TERMINATED: | ||||
pa_threaded_mainloop_signal(mainloop, 0); | pa_threaded_mainloop_signal(mainloop, 0); | ||||
break; | break; | ||||
case PA_STREAM_UNCONNECTED: | case PA_STREAM_UNCONNECTED: | ||||
case PA_STREAM_CREATING: | case PA_STREAM_CREATING: | ||||
break; | break; | ||||
static void pulse_write(void *ptr, int length) { | static void pulse_write(void *ptr, int length) { | ||||
ENTER(__FUNCTION__); | ENTER(__FUNCTION__); | ||||
SHOW("pulse_write > length=%d\n", length); | SHOW("pulse_write > length=%d\n", length); | ||||
CHECK_CONNECTED_NO_RETVAL(); | CHECK_CONNECTED_NO_RETVAL(); | ||||
do_trigger = 0; | do_trigger = 0; | ||||
written += length; | written += length; | ||||
fail: | fail: | ||||
pa_threaded_mainloop_unlock(mainloop); | pa_threaded_mainloop_unlock(mainloop); | ||||
} | } | ||||
SHOW("pa_stream_drain() failed: %s\n", pa_strerror(pa_context_errno(context))); | SHOW("pa_stream_drain() failed: %s\n", pa_strerror(pa_context_errno(context))); | ||||
else | else | ||||
ret = PULSE_OK; | ret = PULSE_OK; | ||||
fail: | fail: | ||||
SHOW_TIME("pa_operation_unref (call)"); | SHOW_TIME("pa_operation_unref (call)"); | ||||
if (o) | if (o) | ||||
return ret; | return ret; | ||||
} | } | ||||
static void pulse_close(void) { | static void pulse_close(void) { | ||||
ENTER(__FUNCTION__); | ENTER(__FUNCTION__); | ||||
} | } | ||||
static int pulse_open() | static int pulse_open() | ||||
{ | { | ||||
ENTER(__FUNCTION__); | ENTER(__FUNCTION__); | ||||
SHOW_TIME("pulse_open (ret true)"); | SHOW_TIME("pulse_open (ret true)"); | ||||
return PULSE_OK; | return PULSE_OK; | ||||
unlock_and_fail: | unlock_and_fail: | ||||
if (o) | if (o) | ||||
pa_operation_unref(o); | pa_operation_unref(o); | ||||
pa_threaded_mainloop_unlock(mainloop); | pa_threaded_mainloop_unlock(mainloop); | ||||
fail: | fail: | ||||
if (ret == PULSE_NO_CONNECTION) { | if (ret == PULSE_NO_CONNECTION) { | ||||
if (context) { | if (context) { | ||||
SHOW_TIME("pa_context_disconnect (call)"); | SHOW_TIME("pa_context_disconnect (call)"); | ||||
SHOW_TIME("pulse_open (ret false)"); | SHOW_TIME("pulse_open (ret false)"); | ||||
return ret; | return ret; | ||||
} | } | ||||
void wave_flush(void *theHandler) | void wave_flush(void *theHandler) | ||||
} | } | ||||
pulse_write(aBuffer, bytes_to_write); | pulse_write(aBuffer, bytes_to_write); | ||||
terminate: | terminate: | ||||
pthread_mutex_unlock(&pulse_mutex); | pthread_mutex_unlock(&pulse_mutex); | ||||
SHOW("wave_write: theSize=%d", theSize); | SHOW("wave_write: theSize=%d", theSize); | ||||
return NULL; | return NULL; | ||||
} | } | ||||
#else | #else | ||||
int wave_init(return 1; ) { | int wave_init(return 1; ) { | ||||
} | } | ||||
void *wave_open(const char *the_api) { | void *wave_open(const char *the_api) { | ||||
} | } | ||||
#endif // ifndef USE_PORTAUDIO | #endif // ifndef USE_PORTAUDIO | ||||
#endif // USE_ASYNC | #endif // USE_ASYNC |
#include <stdint.h> | #include <stdint.h> | ||||
#endif | #endif | ||||
#include "speak_lib.h" | #include "speak_lib.h" | ||||
#include "speech.h" | #include "speech.h" | ||||
#include "phoneme.h" | #include "phoneme.h" | ||||
#define N_SINTAB 2048 | #define N_SINTAB 2048 | ||||
#include "sintab.h" | #include "sintab.h" | ||||
#define PI 3.1415927 | #define PI 3.1415927 | ||||
#define PI2 6.283185307 | #define PI2 6.283185307 | ||||
#define N_WAV_BUF 10 | #define N_WAV_BUF 10 | ||||
static int harm_sqrt_n = 0; | static int harm_sqrt_n = 0; | ||||
#define N_LOWHARM 30 | #define N_LOWHARM 30 | ||||
static int harm_inc[N_LOWHARM]; // only for these harmonics do we interpolate amplitude between steps | static int harm_inc[N_LOWHARM]; // only for these harmonics do we interpolate amplitude between steps | ||||
static int *harmspect; | static int *harmspect; | ||||
static int glottal_flag = 0; | static int glottal_flag = 0; | ||||
static int glottal_reduce = 0; | static int glottal_reduce = 0; | ||||
WGEN_DATA wdata; | WGEN_DATA wdata; | ||||
static int amp_ix; | static int amp_ix; | ||||
static double minus_pi_t; | static double minus_pi_t; | ||||
static double two_pi_t; | static double two_pi_t; | ||||
unsigned char *out_ptr; | unsigned char *out_ptr; | ||||
unsigned char *out_start; | unsigned char *out_start; | ||||
unsigned char *out_end; | unsigned char *out_end; | ||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | ||||
}; | }; | ||||
// set from y = pow(2,x) * 128, x=-1 to 1 | // set from y = pow(2,x) * 128, x=-1 to 1 | ||||
unsigned char pitch_adjust_tab[MAX_PITCH_VALUE+1] = { | unsigned char pitch_adjust_tab[MAX_PITCH_VALUE+1] = { | ||||
64, 65, 66, 67, 68, 69, 70, 71, | 64, 65, 66, 67, 68, 69, 70, 71, | ||||
242, 246, 249, 252, 254, 255 | 242, 246, 249, 252, 254, 255 | ||||
}; | }; | ||||
void WcmdqStop() | void WcmdqStop() | ||||
{ | { | ||||
wcmdq_head = 0; | wcmdq_head = 0; | ||||
MbrolaReset(); | MbrolaReset(); | ||||
} | } | ||||
int WcmdqFree() | int WcmdqFree() | ||||
{ | { | ||||
int i; | int i; | ||||
return N_WCMDQ - WcmdqFree(); | return N_WCMDQ - WcmdqFree(); | ||||
} | } | ||||
void WcmdqInc() | void WcmdqInc() | ||||
{ | { | ||||
wcmdq_tail++; | wcmdq_tail++; | ||||
if (wcmdq_head >= N_WCMDQ) wcmdq_head = 0; | if (wcmdq_head >= N_WCMDQ) wcmdq_head = 0; | ||||
} | } | ||||
#define PEAKSHAPEW 256 | #define PEAKSHAPEW 256 | ||||
unsigned char pk_shape1[PEAKSHAPEW+1] = { | unsigned char pk_shape1[PEAKSHAPEW+1] = { | ||||
static unsigned char *pk_shape; | static unsigned char *pk_shape; | ||||
#ifdef USE_PORTAUDIO | #ifdef USE_PORTAUDIO | ||||
// PortAudio interface | // PortAudio interface | ||||
unsigned char *outbuffer = NULL; | unsigned char *outbuffer = NULL; | ||||
int outbuffer_size = 0; | int outbuffer_size = 0; | ||||
#if USE_PORTAUDIO == 18 | #if USE_PORTAUDIO == 18 | ||||
static int WaveCallback(void *inputBuffer, void *outputBuffer, | static int WaveCallback(void *inputBuffer, void *outputBuffer, | ||||
unsigned long framesPerBuffer, PaTimestamp outTime, void *userData) | unsigned long framesPerBuffer, PaTimestamp outTime, void *userData) | ||||
#else | #else | ||||
return result; | return result; | ||||
#endif | #endif | ||||
} | } | ||||
#if USE_PORTAUDIO == 19 | #if USE_PORTAUDIO == 19 | ||||
/* This is a fixed version of Pa_OpenDefaultStream() for use if the version in portaudio V19 | /* This is a fixed version of Pa_OpenDefaultStream() for use if the version in portaudio V19 | ||||
is broken */ | is broken */ | ||||
} | } | ||||
#endif | #endif | ||||
int WavegenOpenSound() | int WavegenOpenSound() | ||||
{ | { | ||||
PaError err, err2; | PaError err, err2; | ||||
return 0; | return 0; | ||||
} | } | ||||
int WavegenCloseSound() | int WavegenCloseSound() | ||||
{ | { | ||||
PaError active; | PaError active; | ||||
return 0; | return 0; | ||||
} | } | ||||
int WavegenInitSound() | int WavegenInitSound() | ||||
{ | { | ||||
PaError err; | PaError err; | ||||
} | } | ||||
#endif | #endif | ||||
void WavegenInit(int rate, int wavemult_fact) | void WavegenInit(int rate, int wavemult_fact) | ||||
{ | { | ||||
int ix; | int ix; | ||||
for (ix = 0; ix < N_EMBEDDED_VALUES; ix++) | for (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 | ||||
// single peak for HF peaks | // single peak for HF peaks | ||||
wavemult_max = (samplerate * wavemult_fact)/(256 * 50); | wavemult_max = (samplerate * wavemult_fact)/(256 * 50); | ||||
#endif | #endif | ||||
} | } | ||||
int GetAmplitude(void) | int GetAmplitude(void) | ||||
{ | { | ||||
int amp; | int amp; | ||||
return general_amplitude; | return general_amplitude; | ||||
} | } | ||||
static void WavegenSetEcho(void) | static void WavegenSetEcho(void) | ||||
{ | { | ||||
int delay; | int delay; | ||||
general_amplitude = ((general_amplitude * (500-amp))/500); | general_amplitude = ((general_amplitude * (500-amp))/500); | ||||
} | } | ||||
int PeaksToHarmspect(wavegen_peaks_t *peaks, int pitch, int *htab, int control) | int PeaksToHarmspect(wavegen_peaks_t *peaks, int pitch, int *htab, int control) | ||||
{ | { | ||||
// Calculate the amplitude of each harmonics from the formants | // Calculate the amplitude of each harmonics from the formants | ||||
return hmax; // highest harmonic number | return hmax; // highest harmonic number | ||||
} | } | ||||
static void AdvanceParameters() | static void AdvanceParameters() | ||||
{ | { | ||||
// Called every 64 samples to increment the formant freq, height, and widths | // Called every 64 samples to increment the formant freq, height, and widths | ||||
#endif | #endif | ||||
} | } | ||||
#ifndef PLATFORM_RISCOS | #ifndef PLATFORM_RISCOS | ||||
static double resonator(RESONATOR *r, double input) | static double resonator(RESONATOR *r, double input) | ||||
{ | { | ||||
return x; | return x; | ||||
} | } | ||||
static void setresonator(RESONATOR *rp, int freq, int bwidth, int init) | static void setresonator(RESONATOR *rp, int freq, int bwidth, int init) | ||||
{ | { | ||||
// freq Frequency of resonator in Hz | // freq Frequency of resonator in Hz | ||||
} | } | ||||
#endif | #endif | ||||
void InitBreath(void) | void InitBreath(void) | ||||
{ | { | ||||
#ifndef PLATFORM_RISCOS | #ifndef PLATFORM_RISCOS | ||||
#endif | #endif | ||||
} | } | ||||
static void SetBreath() | static void SetBreath() | ||||
{ | { | ||||
#ifndef PLATFORM_RISCOS | #ifndef PLATFORM_RISCOS | ||||
#endif | #endif | ||||
} | } | ||||
static int ApplyBreath(void) | static int ApplyBreath(void) | ||||
{ | { | ||||
int value = 0; | int value = 0; | ||||
return value; | return value; | ||||
} | } | ||||
int Wavegen() | int Wavegen() | ||||
{ | { | ||||
unsigned short waveph; | unsigned short waveph; | ||||
return 0; | return 0; | ||||
} | } | ||||
static int PlaySilence(int length, int resume) | static int PlaySilence(int length, int resume) | ||||
{ | { | ||||
static int n_samples; | static int n_samples; | ||||
return 0; | return 0; | ||||
} | } | ||||
static int PlayWave(int length, int resume, unsigned char *data, int scale, int amp) | static int PlayWave(int length, int resume, unsigned char *data, int scale, int amp) | ||||
{ | { | ||||
static int n_samples; | static int n_samples; | ||||
return 0; | return 0; | ||||
} | } | ||||
static int SetWithRange0(int value, int max) | static int SetWithRange0(int value, int max) | ||||
{ | { | ||||
if (value < 0) | if (value < 0) | ||||
return value; | return value; | ||||
} | } | ||||
static void SetPitchFormants() | static void SetPitchFormants() | ||||
{ | { | ||||
int ix; | int ix; | ||||
wvoice->height[1] = (wvoice->height2[1] * (256 - factor))/256; | wvoice->height[1] = (wvoice->height2[1] * (256 - factor))/256; | ||||
} | } | ||||
void SetEmbedded(int control, int value) | void SetEmbedded(int control, int value) | ||||
{ | { | ||||
// there was an embedded command in the text at this point | // there was an embedded command in the text at this point | ||||
case EMBED_P: | case EMBED_P: | ||||
SetPitchFormants(); | SetPitchFormants(); | ||||
break; | break; | ||||
case EMBED_A: // amplitude | case EMBED_A: // amplitude | ||||
general_amplitude = GetAmplitude(); | general_amplitude = GetAmplitude(); | ||||
break; | break; | ||||
case EMBED_F: // emphasis | case EMBED_F: // emphasis | ||||
general_amplitude = GetAmplitude(); | general_amplitude = GetAmplitude(); | ||||
break; | break; | ||||
case EMBED_H: | case EMBED_H: | ||||
WavegenSetEcho(); | WavegenSetEcho(); | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
void WavegenSetVoice(voice_t *v) | void WavegenSetVoice(voice_t *v) | ||||
{ | { | ||||
static voice_t v2; | static voice_t v2; | ||||
MarkerEvent(espeakEVENT_SAMPLERATE, 0, wvoice->samplerate, 0, out_ptr); | MarkerEvent(espeakEVENT_SAMPLERATE, 0, wvoice->samplerate, 0, out_ptr); | ||||
} | } | ||||
static void SetAmplitude(int length, unsigned char *amp_env, int value) | static void SetAmplitude(int length, unsigned char *amp_env, int value) | ||||
{ | { | ||||
amp_ix = 0; | amp_ix = 0; | ||||
amplitude_env = amp_env; | amplitude_env = amp_env; | ||||
} | } | ||||
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 x; | ||||
*pitch_range = base + (pitch2 * range)/2 - *pitch_base; | *pitch_range = base + (pitch2 * range)/2 - *pitch_base; | ||||
} | } | ||||
void SetPitch(int length, unsigned char *env, int pitch1, int pitch2) | void SetPitch(int length, unsigned char *env, int pitch1, int pitch2) | ||||
{ | { | ||||
// length in samples | // length in samples | ||||
wdata.pitch = ((wdata.pitch_env[0] * wdata.pitch_range) >>8) + wdata.pitch_base; // Hz << 12 | wdata.pitch = ((wdata.pitch_env[0] * wdata.pitch_range) >>8) + wdata.pitch_base; // Hz << 12 | ||||
flutter_amp = wvoice->flutter; | flutter_amp = wvoice->flutter; | ||||
} | } | ||||
void SetSynth(int length, int modn, frame_t *fr1, frame_t *fr2, voice_t *v) | void SetSynth(int length, int modn, frame_t *fr1, frame_t *fr2, voice_t *v) | ||||
{ | { | ||||
int ix; | int ix; | ||||
} | } | ||||
} | } | ||||
static int Wavegen2(int length, int modulation, int resume, frame_t *fr1, frame_t *fr2) | static int Wavegen2(int length, int modulation, int resume, frame_t *fr1, frame_t *fr2) | ||||
{ | { | ||||
if (resume == 0) | if (resume == 0) | ||||
} | } | ||||
} | } | ||||
int WavegenFill2(int fill_zeros) | int WavegenFill2(int fill_zeros) | ||||
{ | { | ||||
// Pick up next wavegen commands from the queue | // Pick up next wavegen commands from the queue | ||||
case WCMD_PITCH: | case WCMD_PITCH: | ||||
SetPitch(length, (unsigned char *)q[2], q[3] >> 16, q[3] & 0xffff); | SetPitch(length, (unsigned char *)q[2], q[3] >> 16, q[3] & 0xffff); | ||||
break; | break; | ||||
case WCMD_PAUSE: | case WCMD_PAUSE: | ||||
if (resume == 0) | if (resume == 0) | ||||
echo_complete -= length; | echo_complete -= length; | ||||
#endif | #endif | ||||
result = PlaySilence(length, resume); | result = PlaySilence(length, resume); | ||||
break; | break; | ||||
case WCMD_WAVE: | case WCMD_WAVE: | ||||
echo_complete = echo_length; | echo_complete = echo_length; | ||||
wdata.n_mix_wavefile = 0; | wdata.n_mix_wavefile = 0; | ||||
#endif | #endif | ||||
result = PlayWave(length, resume, (unsigned char *)q[2], q[3] & 0xff, q[3] >> 8); | result = PlayWave(length, resume, (unsigned char *)q[2], q[3] & 0xff, q[3] >> 8); | ||||
break; | break; | ||||
case WCMD_WAVE2: | case WCMD_WAVE2: | ||||
// wave file to be played at the same time as synthesis | // wave file to be played at the same time as synthesis | ||||
wdata.mix_wave_amp = q[3] >> 8; | wdata.mix_wave_amp = q[3] >> 8; | ||||
wdata.mix_wavefile_offset = 0; | wdata.mix_wavefile_offset = 0; | ||||
wdata.mix_wavefile = (unsigned char *)q[2]; | wdata.mix_wavefile = (unsigned char *)q[2]; | ||||
break; | break; | ||||
case WCMD_SPECT2: // as WCMD_SPECT but stop any concurrent wave file | case WCMD_SPECT2: // as WCMD_SPECT but stop any concurrent wave file | ||||
wdata.n_mix_wavefile = 0; // ... and drop through to WCMD_SPECT case | wdata.n_mix_wavefile = 0; // ... and drop through to WCMD_SPECT case | ||||
case WCMD_SPECT: | case WCMD_SPECT: | ||||
echo_complete = echo_length; | echo_complete = echo_length; | ||||
result = Wavegen2(length & 0xffff, q[1] >> 16, resume, (frame_t *)q[2], (frame_t *)q[3]); | result = Wavegen2(length & 0xffff, q[1] >> 16, resume, (frame_t *)q[2], (frame_t *)q[3]); | ||||
break; | break; | ||||
#ifdef INCLUDE_KLATT | #ifdef INCLUDE_KLATT | ||||
case WCMD_KLATT2: // as WCMD_SPECT but stop any concurrent wave file | case WCMD_KLATT2: // as WCMD_SPECT but stop any concurrent wave file | ||||
wdata.n_mix_wavefile = 0; // ... and drop through to WCMD_SPECT case | wdata.n_mix_wavefile = 0; // ... and drop through to WCMD_SPECT case | ||||
result = Wavegen_Klatt2(length & 0xffff, q[1] >> 16, resume, (frame_t *)q[2], (frame_t *)q[3]); | result = Wavegen_Klatt2(length & 0xffff, q[1] >> 16, resume, (frame_t *)q[2], (frame_t *)q[3]); | ||||
break; | break; | ||||
#endif | #endif | ||||
case WCMD_MARKER: | case WCMD_MARKER: | ||||
marker_type = q[0] >> 8; | marker_type = q[0] >> 8; | ||||
MarkerEvent(marker_type, q[1], q[2], q[3], out_ptr); | MarkerEvent(marker_type, q[1], q[2], q[3], out_ptr); | ||||
if (marker_type == 1) // word marker | if (marker_type == 1) // word marker | ||||
current_source_index = q[1] & 0xffffff; | current_source_index = q[1] & 0xffffff; | ||||
break; | break; | ||||
case WCMD_AMPLITUDE: | case WCMD_AMPLITUDE: | ||||
SetAmplitude(length, (unsigned char *)q[2], q[3]); | SetAmplitude(length, (unsigned char *)q[2], q[3]); | ||||
break; | break; | ||||
case WCMD_VOICE: | case WCMD_VOICE: | ||||
WavegenSetVoice((voice_t *)q[2]); | WavegenSetVoice((voice_t *)q[2]); | ||||
free((voice_t *)q[2]); | free((voice_t *)q[2]); | ||||
break; | break; | ||||
case WCMD_EMBEDDED: | case WCMD_EMBEDDED: | ||||
SetEmbedded(q[1], q[2]); | SetEmbedded(q[1], q[2]); | ||||
break; | break; | ||||
case WCMD_MBROLA_DATA: | case WCMD_MBROLA_DATA: | ||||
result = MbrolaFill(length, resume, (general_amplitude * wvoice->voicing)/64); | result = MbrolaFill(length, resume, (general_amplitude * wvoice->voicing)/64); | ||||
break; | break; | ||||
case WCMD_FMT_AMPLITUDE: | case WCMD_FMT_AMPLITUDE: | ||||
if ((wdata.amplitude_fmt = q[1]) == 0) | if ((wdata.amplitude_fmt = q[1]) == 0) | ||||
wdata.amplitude_fmt = 100; // percentage, but value=0 means 100% | wdata.amplitude_fmt = 100; // percentage, but value=0 means 100% | ||||
break; | break; | ||||
#if HAVE_SONIC_H | #if HAVE_SONIC_H | ||||
case WCMD_SONIC_SPEED: | case WCMD_SONIC_SPEED: | ||||
sonicSpeed = (double)q[1] / 1024; | sonicSpeed = (double)q[1] / 1024; | ||||
return 0; | return 0; | ||||
} | } | ||||
#if HAVE_SONIC_H | #if HAVE_SONIC_H | ||||
/* Speed up the audio samples with libsonic. */ | /* Speed up the audio samples with libsonic. */ | ||||
static int SpeedUp(short *outbuf, int length_in, int length_out, int end_of_text) | static int SpeedUp(short *outbuf, int length_in, int length_out, int end_of_text) | ||||
} | } | ||||
#endif | #endif | ||||
/* 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) | ||||
{ | { |
#include "voice.h" | #include "voice.h" | ||||
#include "translate.h" | #include "translate.h" | ||||
extern void Write4Bytes(FILE *f, int value); | extern void Write4Bytes(FILE *f, int value); | ||||
char path_home[N_PATH_HOME]; // this is the espeak-data directory | char path_home[N_PATH_HOME]; // this is the espeak-data directory | ||||
"\t List the available voices for the specified language.\n" | "\t List the available voices for the specified language.\n" | ||||
"\t If <language> is omitted, then list all voices.\n"; | "\t If <language> is omitted, then list all voices.\n"; | ||||
void DisplayVoices(FILE *f_out, char *language); | void DisplayVoices(FILE *f_out, char *language); | ||||
USHORT voice_pcnt[N_PEAKS+1][3]; | USHORT voice_pcnt[N_PEAKS+1][3]; | ||||
void DisplayVoices(FILE *f_out, char *language) | void DisplayVoices(FILE *f_out, char *language) | ||||
{ | { | ||||
int ix; | int ix; | ||||
} | } | ||||
} | } | ||||
static int OpenWaveFile(const char *path, int rate) | static int OpenWaveFile(const char *path, int rate) | ||||
{ | { | ||||
// Set the length of 0x7ffff000 for --stdout | // Set the length of 0x7ffff000 for --stdout | ||||
return 1; | return 1; | ||||
} | } | ||||
static void CloseWaveFile() | static void CloseWaveFile() | ||||
{ | { | ||||
unsigned int pos; | unsigned int pos; | ||||
fclose(f_wave); | fclose(f_wave); | ||||
f_wave = NULL; | f_wave = NULL; | ||||
} | } | ||||
static int WavegenFile(void) | static int WavegenFile(void) | ||||
{ | { | ||||
int finished; | int finished; | ||||
return finished; | return finished; | ||||
} | } | ||||
static void init_path(char *argv0, char *path_specified) | static void init_path(char *argv0, char *path_specified) | ||||
{ | { | ||||
if (path_specified) { | if (path_specified) { | ||||
sprintf(path_home, "%s/espeak-data", path_specified); | sprintf(path_home, "%s/espeak-data", path_specified); | ||||
return; | return; | ||||
#endif | #endif | ||||
} | } | ||||
static int initialise(void) | static int initialise(void) | ||||
{ | { | ||||
int param; | int param; | ||||
} | } | ||||
#endif | #endif | ||||
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"); | ||||
return 0; | return 0; | ||||
} | } | ||||
#ifdef NEED_GETOPT | #ifdef NEED_GETOPT | ||||
struct option { | struct option { | ||||
char *name; | char *name; | ||||
if ((sscanf(optarg2, "%d", &value) == 1) && (value <= 4)) | if ((sscanf(optarg2, "%d", &value) == 1) && (value <= 4)) | ||||
option_multibyte = value; | option_multibyte = value; | ||||
break; | break; | ||||
case 'h': | case 'h': | ||||
init_path(argv[0], data_path); | init_path(argv[0], data_path); | ||||
printf("\nspeak text-to-speech: %s Data at: %s\n%s", version_string, path_home, help_text); | printf("\nspeak text-to-speech: %s Data at: %s\n%s", version_string, path_home, help_text); | ||||
exit(0); | exit(0); | ||||
case 'k': | case 'k': | ||||
option_capitals = atoi(optarg2); | option_capitals = atoi(optarg2); | ||||
break; | break; | ||||
case 'x': | case 'x': | ||||
phoneme_options |= espeakPHONEMES_SHOW; | phoneme_options |= espeakPHONEMES_SHOW; | ||||
break; | break; | ||||
case 'X': | case 'X': | ||||
phoneme_options |= espeakPHONEMES_TRACE; | phoneme_options |= espeakPHONEMES_TRACE; | ||||
break; | break; | ||||
case 'm': | case 'm': | ||||
option_ssml = 1; | option_ssml = 1; | ||||
break; | break; | ||||
case 'p': | case 'p': | ||||
pitch_adjustment = atoi(optarg2); | pitch_adjustment = atoi(optarg2); | ||||
if (pitch_adjustment > 99) pitch_adjustment = 99; | if (pitch_adjustment > 99) pitch_adjustment = 99; | ||||
break; | break; | ||||
case 'q': | case 'q': | ||||
quiet = 1; | quiet = 1; | ||||
break; | break; | ||||
case 'f': | case 'f': | ||||
strncpy0(filename, optarg2, sizeof(filename)); | strncpy0(filename, optarg2, sizeof(filename)); | ||||
break; | break; | ||||
case 'l': | case 'l': | ||||
value = 0; | value = 0; | ||||
value = atoi(optarg2); | value = atoi(optarg2); | ||||
option_linelength = value; | option_linelength = value; | ||||
break; | break; | ||||
case 'a': | case 'a': | ||||
amp = atoi(optarg2); | amp = atoi(optarg2); | ||||
break; | break; | ||||
case 's': | case 's': | ||||
speed = atoi(optarg2); | speed = atoi(optarg2); | ||||
break; | break; | ||||
case 'g': | case 'g': | ||||
wordgap = atoi(optarg2); | wordgap = atoi(optarg2); | ||||
break; | break; | ||||
case 'v': | case 'v': | ||||
strncpy0(voicename, optarg2, sizeof(voicename)); | strncpy0(voicename, optarg2, sizeof(voicename)); | ||||
break; | break; | ||||
case 'w': | case 'w': | ||||
option_waveout = 1; | option_waveout = 1; | ||||
strncpy0(wavefile, optarg2, sizeof(wavefile)); | strncpy0(wavefile, optarg2, sizeof(wavefile)); | ||||
break; | break; | ||||
case 'z': | case 'z': | ||||
option_endpause = 0; | option_endpause = 0; | ||||
break; | break; | ||||
case 0x100: // --stdin | case 0x100: // --stdin | ||||
flag_stdin = 1; | flag_stdin = 1; | ||||
break; | break; | ||||
case 0x105: // --stdout | case 0x105: // --stdout | ||||
option_waveout = 1; | option_waveout = 1; | ||||
strcpy(wavefile, "stdout"); | strcpy(wavefile, "stdout"); | ||||
break; | break; | ||||
case 0x101: // --compile-debug | case 0x101: // --compile-debug | ||||
case 0x102: // --compile | case 0x102: // --compile | ||||
if (optarg2 != NULL) | if (optarg2 != NULL) | ||||
strncpy0(voicename, optarg2, sizeof(voicename)); | strncpy0(voicename, optarg2, sizeof(voicename)); | ||||
flag_compile = c; | flag_compile = c; | ||||
break; | break; | ||||
case 0x103: // --punct | case 0x103: // --punct | ||||
option_punctuation = 1; | option_punctuation = 1; | ||||
if (optarg2 != NULL) { | if (optarg2 != NULL) { | ||||
option_punctuation = 2; | option_punctuation = 2; | ||||
} | } | ||||
break; | break; | ||||
case 0x104: // --voices | case 0x104: // --voices | ||||
init_path(argv[0], data_path); | init_path(argv[0], data_path); | ||||
DisplayVoices(stdout, optarg2); | DisplayVoices(stdout, optarg2); | ||||
exit(0); | exit(0); | ||||
case 0x106: // -- split | case 0x106: // -- split | ||||
if (optarg2 == NULL) | if (optarg2 == NULL) | ||||
samples_split = 30; // default 30 minutes | samples_split = 30; // default 30 minutes | ||||
else | else | ||||
samples_split = atoi(optarg2); | samples_split = atoi(optarg2); | ||||
break; | break; | ||||
case 0x107: // --path | case 0x107: // --path | ||||
data_path = optarg2; | data_path = optarg2; | ||||
break; | break; | ||||
case 0x108: // --phonout | case 0x108: // --phonout | ||||
if ((f_trans = fopen(optarg2, "w")) == NULL) { | if ((f_trans = fopen(optarg2, "w")) == NULL) { | ||||
fprintf(stderr, "Can't write to: %s\n", optarg2); | fprintf(stderr, "Can't write to: %s\n", optarg2); | ||||
f_trans = stderr; | f_trans = stderr; | ||||
} | } | ||||
break; | break; | ||||
case 0x109: // --pho | case 0x109: // --pho | ||||
phoneme_options |= espeakPHONEMES_MBROLA; | phoneme_options |= espeakPHONEMES_MBROLA; | ||||
break; | break; | ||||
case 0x10a: // --ipa | case 0x10a: // --ipa | ||||
phoneme_options |= espeakPHONEMES_IPA; | phoneme_options |= espeakPHONEMES_IPA; | ||||
if (optarg2 != NULL) { | if (optarg2 != NULL) { | ||||
phoneme_options |= espeakPHONEMES_TIE; | phoneme_options |= espeakPHONEMES_TIE; | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
break; | break; | ||||
case 0x10b: // --version | case 0x10b: // --version | ||||
init_path(argv[0], data_path); | init_path(argv[0], data_path); | ||||
printf("speak text-to-speech: %s Data at: %s\n", version_string, path_home); | printf("speak text-to-speech: %s Data at: %s\n", version_string, path_home); | ||||
exit(0); | exit(0); | ||||
case 0x10c: // --sep | case 0x10c: // --sep | ||||
phoneme_options |= espeakPHONEMES_SHOW; | phoneme_options |= espeakPHONEMES_SHOW; | ||||
if (optarg2 == 0) | if (optarg2 == 0) | ||||
if (phonemes_separator == 'z') | if (phonemes_separator == 'z') | ||||
phonemes_separator = 0x200c; // ZWNJ | phonemes_separator = 0x200c; // ZWNJ | ||||
break; | break; | ||||
case 0x10d: // --tie | case 0x10d: // --tie | ||||
phoneme_options |= (espeakPHONEMES_SHOW | espeakPHONEMES_TIE); | phoneme_options |= (espeakPHONEMES_SHOW | espeakPHONEMES_TIE); | ||||
if (optarg2 == 0) | if (optarg2 == 0) | ||||
if (phonemes_separator == 'z') | if (phonemes_separator == 'z') | ||||
phonemes_separator = 0x200d; // ZWJ | phonemes_separator = 0x200d; // ZWJ | ||||
break; | break; | ||||
default: | default: | ||||
exit(0); | exit(0); | ||||
} | } | ||||
exit(0); | exit(0); | ||||
} | } | ||||
SetParameter(espeakRATE, speed, 0); | SetParameter(espeakRATE, speed, 0); | ||||
SetParameter(espeakVOLUME, amp, 0); | SetParameter(espeakVOLUME, amp, 0); | ||||
SetParameter(espeakCAPITALS, option_capitals, 0); | SetParameter(espeakCAPITALS, option_capitals, 0); |