Browse Source

Check and fix source code formatting.

master
Reece H. Dunn 9 years ago
parent
commit
3e99752d0c

+ 33
- 36
src/espeak-ng.c View File

@@ -173,7 +173,7 @@ void DisplayVoices(FILE *f_out, char *language)

static void Write4Bytes(FILE *f, int value)
{
// Write 4 bytes to a file, least significant first
// Write 4 bytes to a file, least significant first
int ix;

for (ix = 0; ix < 4; ix++) {
@@ -233,14 +233,13 @@ static void CloseWavFile()

fclose(f_wavfile);
f_wavfile = NULL;

}

static int SynthCallback(short *wav, int numsamples, espeak_EVENT *events)
{
char fname[210];

if (quiet) return 0; // -q quiet mode
if (quiet) return 0; // -q quiet mode

if (wav == NULL) {
CloseWavFile();
@@ -267,10 +266,8 @@ static int SynthCallback(short *wav, int numsamples, espeak_EVENT *events)
sprintf(fname, "%s_%.2d%s", wavefile, wavefile_count+1, filetype);
if (OpenWavFile(fname, samplerate) != 0)
return 1;
} else {
if (OpenWavFile(wavefile, samplerate) != 0)
return 1;
}
} else if (OpenWavFile(wavefile, samplerate) != 0)
return 1;
}

if (numsamples > 0) {
@@ -298,7 +295,7 @@ struct option {
};
int optind;
static int optional_argument;
static const char *arg_opts = "abfgklpsvw"; // which options have arguments
static const char *arg_opts = "abfgklpsvw"; // which options have arguments
static char *opt_string = "";
#define no_argument 0
#define required_argument 1
@@ -334,7 +331,7 @@ int main(int argc, char **argv)
FILE *f_text = NULL;
char *p_text = NULL;
FILE *f_phonemes_out = stdout;
char *data_path = NULL; // use default path for espeak-data
char *data_path = NULL; // use default path for espeak-data

int option_index = 0;
int c;
@@ -360,7 +357,7 @@ int main(int argc, char **argv)
espeak_VOICE voice_select;
char filename[200];
char voicename[40];
#define N_PUNCTLIST 100
#define N_PUNCTLIST 100
wchar_t option_punctlist[N_PUNCTLIST];

voicename[0] = 0;
@@ -389,7 +386,7 @@ int main(int argc, char **argv)

if (c == '-') {
if (p[0] == 0)
break; // -- means don't interpret further - as commands
break; // -- means don't interpret further - as commands

opt_string = "";
for (ix = 0;; ix++) {
@@ -417,7 +414,7 @@ int main(int argc, char **argv)
c = getopt_long(argc, argv, "a:b:f:g:hk:l:mp:qs:v:w:xXz",
long_options, &option_index);

/* Detect the end of the options. */
// Detect the end of the options.
if (c == -1)
break;
optarg2 = optarg;
@@ -478,23 +475,23 @@ int main(int argc, char **argv)
option_waveout = 1;
strncpy0(wavefile, optarg2, sizeof(filename));
break;
case 'z': // remove pause from the end of a sentence
case 'z': // remove pause from the end of a sentence
synth_flags &= ~espeakENDPAUSE;
break;
case 0x100: // --stdin
case 0x100: // --stdin
flag_stdin = 1;
break;
case 0x105: // --stdout
case 0x105: // --stdout
option_waveout = 1;
strcpy(wavefile, "stdout");
break;
case 0x101: // --compile-debug
case 0x102: // --compile
case 0x101: // --compile-debug
case 0x102: // --compile
strncpy0(voicename, optarg2, sizeof(voicename));
flag_compile = c;
quiet = 1;
break;
case 0x103: // --punct
case 0x103: // --punct
option_punctuation = 1;
if (optarg2 != NULL) {
ix = 0;
@@ -503,27 +500,27 @@ int main(int argc, char **argv)
option_punctuation = 2;
}
break;
case 0x104: // --voices
case 0x104: // --voices
espeak_Initialize(AUDIO_OUTPUT_SYNCHRONOUS, 0, data_path, 0);
DisplayVoices(stdout, optarg2);
exit(0);
case 0x106: // -- split
case 0x106: // -- split
if (optarg2 == NULL)
samples_split_seconds = 30 * 60; // default 30 minutes
samples_split_seconds = 30 * 60; // default 30 minutes
else
samples_split_seconds = atoi(optarg2) * 60;
break;
case 0x107: // --path
case 0x107: // --path
data_path = optarg2;
break;
case 0x108: // --phonout
case 0x108: // --phonout
if ((f_phonemes_out = fopen(optarg2, "w")) == NULL)
fprintf(stderr, "Can't write to: %s\n", optarg2);
break;
case 0x109: // --pho
case 0x109: // --pho
phoneme_options |= espeakPHONEMES_MBROLA;
break;
case 0x10a: // --ipa
case 0x10a: // --ipa
phoneme_options |= espeakPHONEMES_IPA;
if (optarg2 != NULL) {
// deprecated and obsolete
@@ -537,43 +534,43 @@ int main(int argc, char **argv)
phoneme_options |= espeakPHONEMES_TIE;
break;
case 3:
phonemes_separator = 0x200d; // ZWJ
phonemes_separator = 0x200d; // ZWJ
phoneme_options |= espeakPHONEMES_TIE;
break;
}

}
break;
case 0x10b: // --version
case 0x10b: // --version
PrintVersion();
exit(0);
case 0x10c: // --sep
case 0x10c: // --sep
phoneme_options |= espeakPHONEMES_SHOW;
if (optarg2 == 0)
phonemes_separator = ' ';
else
utf8_in(&phonemes_separator, optarg2);
if (phonemes_separator == 'z')
phonemes_separator = 0x200c; // ZWNJ
phonemes_separator = 0x200c; // ZWNJ
break;
case 0x10d: // --tie
case 0x10d: // --tie
phoneme_options |= (espeakPHONEMES_SHOW | espeakPHONEMES_TIE);
if (optarg2 == 0)
phonemes_separator = 0x0361; // default: combining-double-inverted-breve
phonemes_separator = 0x0361; // default: combining-double-inverted-breve
else
utf8_in(&phonemes_separator, optarg2);
if (phonemes_separator == 'z')
phonemes_separator = 0x200d; // ZWJ
phonemes_separator = 0x200d; // ZWJ
break;
case 0x10e: // --compile-mbrola
case 0x10e: // --compile-mbrola
samplerate = espeak_Initialize(AUDIO_OUTPUT_PLAYBACK, 0, data_path, 0);
espeak_ng_CompileMbrolaVoice(optarg2, stdout);
exit(0);
case 0x10f: // --compile-intonations
case 0x10f: // --compile-intonations
samplerate = espeak_Initialize(AUDIO_OUTPUT_PLAYBACK, 0, data_path, espeakINITIALIZE_PATH_ONLY);
espeak_ng_CompileIntonation(stdout);
exit(0);
case 0x110: // --compile-phonemes
case 0x110: // --compile-phonemes
samplerate = espeak_Initialize(AUDIO_OUTPUT_PLAYBACK, 0, data_path, espeakINITIALIZE_PATH_ONLY);
espeak_ng_CompilePhonemeData(22050, stdout);
exit(0);
@@ -707,6 +704,6 @@ int main(int argc, char **argv)
}

if (f_phonemes_out != stdout)
fclose(f_phonemes_out); // needed for WinCE
fclose(f_phonemes_out);
return 0;
}

+ 293
- 290
src/libespeak-ng/compiledata.c
File diff suppressed because it is too large
View File


+ 132
- 128
src/libespeak-ng/compiledict.c View File

@@ -54,9 +54,9 @@ static char *hash_chains[N_HASH_DICT];
static char letterGroupsDefined[N_LETTER_GROUPS];

MNEM_TAB mnem_rules[] = {
{ "unpr", DOLLAR_UNPR },
{ "unpr", DOLLAR_UNPR },
{ "noprefix", DOLLAR_NOPREFIX }, // rule fails if a prefix has been removed
{ "list", DOLLAR_LIST }, // a pronunciation is given in the *_list file
{ "list", DOLLAR_LIST }, // a pronunciation is given in the *_list file

{ "w_alt1", 0x11 },
{ "w_alt2", 0x12 },
@@ -64,7 +64,7 @@ MNEM_TAB mnem_rules[] = {
{ "w_alt4", 0x14 },
{ "w_alt5", 0x15 },
{ "w_alt6", 0x16 },
{ "w_alt", 0x11 }, // note: put longer names before their sub-strings
{ "w_alt", 0x11 }, // note: put longer names before their sub-strings

{ "p_alt1", 0x21 },
{ "p_alt2", 0x22 },
@@ -72,82 +72,84 @@ MNEM_TAB mnem_rules[] = {
{ "p_alt4", 0x24 },
{ "p_alt5", 0x25 },
{ "p_alt6", 0x26 },
{ "p_alt", 0x21 },
{ "p_alt", 0x21 },

{ NULL, -1 }
};

MNEM_TAB mnem_flags[] = {
// these in the first group put a value in bits0-3 of dictionary_flags
{ "$1", 0x41 }, // stress on 1st syllable
{ "$2", 0x42 }, // stress on 2nd syllable
{ "$3", 0x43 },
{ "$4", 0x44 },
{ "$5", 0x45 },
{ "$6", 0x46 },
{ "$7", 0x47 },
{ "$u", 0x48 }, // reduce to unstressed
{ "$u1", 0x49 },
{ "$u2", 0x4a },
{ "$u3", 0x4b },
{ "$u+", 0x4c }, // reduce to unstressed, but stress at end of clause
{ "$1", 0x41 }, // stress on 1st syllable
{ "$2", 0x42 }, // stress on 2nd syllable
{ "$3", 0x43 },
{ "$4", 0x44 },
{ "$5", 0x45 },
{ "$6", 0x46 },
{ "$7", 0x47 },
{ "$u", 0x48 }, // reduce to unstressed
{ "$u1", 0x49 },
{ "$u2", 0x4a },
{ "$u3", 0x4b },
{ "$u+", 0x4c }, // reduce to unstressed, but stress at end of clause
{ "$u1+", 0x4d },
{ "$u2+", 0x4e },
{ "$u3+", 0x4f },

// these set the corresponding numbered bit if dictionary_flags
{ "$pause", 8 }, // ensure pause before this word
{ "$strend", 9 }, // full stress if at end of clause
{ "$strend2", 10 }, // full stress if at end of clause, or only followed by unstressed
{ "$unstressend", 11 }, // reduce stress at end of clause
{ "$pause", 8 }, // ensure pause before this word
{ "$strend", 9 }, // full stress if at end of clause
{ "$strend2", 10 }, // full stress if at end of clause, or only followed by unstressed
{ "$unstressend", 11 }, // reduce stress at end of clause
{ "$accent_before", 12 }, // used with accent names, say this accent name before the letter name
{ "$abbrev", 13 }, // use this pronuciation rather than split into letters
// language specific
{ "$double", 14 }, // IT double the initial consonant of next word
{ "$alt", 15 }, // use alternative pronunciation
{ "$alt1", 15 }, // synonym for $alt
{ "$alt2", 16 },
{ "$alt3", 17 },
{ "$alt4", 18 },
{ "$alt5", 19 },
{ "$alt6", 20 },
{ "$alt7", 21 },
{ "$combine", 23 }, // Combine with the next word
{ "$dot", 24 }, // ignore '.' after this word (abbreviation)
{ "$hasdot", 25 }, // use this pronunciation if there is a dot after the word
{ "$max3", 27 }, // limit to 3 repetitions
{ "$brk", 28 }, // a shorter $pause
{ "$text", 29 }, // word translates to replcement text, not phonemes
// flags in dictionary word 2
{ "$verbf", 0x20 }, // verb follows
{ "$verbsf", 0x21 }, // verb follows, allow -s suffix
{ "$nounf", 0x22 }, // noun follows
{ "$pastf", 0x23 }, // past tense follows
{ "$verb", 0x24 }, // use this pronunciation when its a verb
{ "$noun", 0x25 }, // use this pronunciation when its a noun
{ "$past", 0x26 }, // use this pronunciation when its past tense
{ "$abbrev", 13 }, // use this pronuciation rather than split into letters
// language specific
{ "$double", 14 }, // IT double the initial consonant of next word
{ "$alt", 15 }, // use alternative pronunciation
{ "$alt1", 15 }, // synonym for $alt
{ "$alt2", 16 },
{ "$alt3", 17 },
{ "$alt4", 18 },
{ "$alt5", 19 },
{ "$alt6", 20 },
{ "$alt7", 21 },
{ "$combine", 23 }, // Combine with the next word
{ "$dot", 24 }, // ignore '.' after this word (abbreviation)
{ "$hasdot", 25 }, // use this pronunciation if there is a dot after the word
{ "$max3", 27 }, // limit to 3 repetitions
{ "$brk", 28 }, // a shorter $pause
{ "$text", 29 }, // word translates to replcement text, not phonemes
// flags in dictionary word 2
{ "$verbf", 0x20 }, // verb follows
{ "$verbsf", 0x21 }, // verb follows, allow -s suffix
{ "$nounf", 0x22 }, // noun follows
{ "$pastf", 0x23 }, // past tense follows
{ "$verb", 0x24 }, // use this pronunciation when its a verb
{ "$noun", 0x25 }, // use this pronunciation when its a noun
{ "$past", 0x26 }, // use this pronunciation when its past tense
{ "$verbextend", 0x28 }, // extend influence of 'verb follows'
{ "$capital", 0x29 }, // use this pronunciation if initial letter is upper case
{ "$allcaps", 0x2a }, // use this pronunciation if initial letter is upper case
{ "$accent", 0x2b }, // character name is base-character name + accent name
{ "$sentence", 0x2d }, // only if this clause is a sentence (i.e. terminator is {. ? !} not {, ; :}
{ "$only", 0x2e }, // only match on this word without suffix
{ "$onlys", 0x2f }, // only match with none, or with 's' suffix
{ "$stem", 0x30 }, // must have a suffix
{ "$atend", 0x31 }, // use this pronunciation if at end of clause
{ "$atstart", 0x32 }, // use this pronunciation at start of clause
{ "$native", 0x33 }, // not if we've switched translators
{ "$capital", 0x29 }, // use this pronunciation if initial letter is upper case
{ "$allcaps", 0x2a }, // use this pronunciation if initial letter is upper case
{ "$accent", 0x2b }, // character name is base-character name + accent name
{ "$sentence", 0x2d }, // only if this clause is a sentence (i.e. terminator is {. ? !} not {, ; :}
{ "$only", 0x2e }, // only match on this word without suffix
{ "$onlys", 0x2f }, // only match with none, or with 's' suffix
{ "$stem", 0x30 }, // must have a suffix
{ "$atend", 0x31 }, // use this pronunciation if at end of clause
{ "$atstart", 0x32 }, // use this pronunciation at start of clause
{ "$native", 0x33 }, // not if we've switched translators

// doesn't set dictionary_flags
{ "$?", 100 }, // conditional rule, followed by byte giving the condition number
{ "$?", 100 }, // conditional rule, followed by byte giving the condition number

{ "$textmode", 200 },
{ "$textmode", 200 },
{ "$phonememode", 201 },
{ NULL, -1 }

{ NULL, -1 }
};

#define LEN_GROUP_NAME 12
@@ -161,7 +163,7 @@ typedef struct {

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 !
int c2;

if (((c2 = (c & 0xff)) == 0) || (c > ' '))
@@ -171,7 +173,7 @@ int isspace2(unsigned int c)

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
FILE *f;

if ((f = fopen(fname, access)) == NULL) {
@@ -181,7 +183,7 @@ static FILE *fopen_log(const char *fname, const char *access)
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)
{
while (table->mnem != NULL) {
@@ -189,7 +191,7 @@ const char *LookupMnemName(MNEM_TAB *table, const int value)
return table->mnem;
table++;
}
return ""; /* not found */
return ""; // not found
}

void print_dictionary_flags(unsigned int *flags, char *buf, int buf_len)
@@ -222,7 +224,7 @@ void print_dictionary_flags(unsigned int *flags, char *buf, int buf_len)

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

unsigned char rb;
unsigned char c;
@@ -243,9 +245,12 @@ char *DecodeRule(const char *group_chars, int group_length, char *rule, int cont
char suffix[20];
static char output[80];

static char symbols[] =
{ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
'&', '%', '+', '#', 'S', 'D', 'Z', 'A', 'L', '!', ' ', '@', '?', 'J', 'N', 'K', 'V', '?', 'T', 'X', '?', 'W' };
static char symbols[] = {
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
'&', '%', '+', '#', 'S', 'D', 'Z', 'A', 'L', '!',
' ', '@', '?', 'J', 'N', 'K', 'V', '?', 'T', 'X',
'?', 'W'
};

static char symbols_lg[] = { 'A', 'B', 'C', 'H', 'F', 'G', 'Y' };

@@ -268,7 +273,8 @@ char *DecodeRule(const char *group_chars, int group_length, char *rule, int cont
finished = 1;
break;
case RULE_PRE_ATSTART:
at_start = 1; // drop through to next case
at_start = 1;
// fallthrough:
case RULE_PRE:
match_type = RULE_PRE;
*p = 0;
@@ -283,7 +289,7 @@ char *DecodeRule(const char *group_chars, int group_length, char *rule, int cont
case RULE_PH_COMMON:
break;
case RULE_CONDITION:
/* conditional rule, next byte gives condition number */
// conditional rule, next byte gives condition number
condition_num = *rule++;
break;
case RULE_LINENUM:
@@ -365,7 +371,7 @@ char *DecodeRule(const char *group_chars, int group_length, char *rule, int cont
}
*p = 0;

buf[p_end - p] = 0; // prevent overflow in output[]
buf[p_end - p] = 0; // prevent overflow in output[]
strcat(p, buf);
ix = strlen(output);
while (ix < 8)
@@ -376,7 +382,7 @@ char *DecodeRule(const char *group_chars, int group_length, char *rule, int cont

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
unsigned char c;
char *p;
char *word;
@@ -394,7 +400,7 @@ static int compile_line(char *linebuf, char *dict_line, int *hash)

int len_word;
int len_phonetic;
int text_not_phonemes; // this word specifies replacement text, not phonemes
int text_not_phonemes; // this word specifies replacement text, not phonemes
unsigned int wc;
int all_upper_case;

@@ -441,7 +447,7 @@ static int compile_line(char *linebuf, char *dict_line, int *hash)
}

if ((c == '$') && isalnum(p[1])) {
/* read keyword parameter */
// read keyword parameter
mnemptr = p;
while (!isspace2(c = *p)) p++;
*p = 0;
@@ -462,9 +468,8 @@ static int compile_line(char *linebuf, char *dict_line, int *hash)
}
}

if ((c == '/') && (p[1] == '/') && (multiple_words == 0)) {
c = '\n'; /* "//" treat comment as end of line */
}
if ((c == '/') && (p[1] == '/') && (multiple_words == 0))
c = '\n'; // "//" treat comment as end of line

switch (step)
{
@@ -486,7 +491,7 @@ static int compile_line(char *linebuf, char *dict_line, int *hash)
c = ' ';
}
if (isspace2(c)) {
p[0] = 0; /* terminate english word */
p[0] = 0; // terminate english word

if (multiple_words) {
multiple_string = multiple_string_end = p+1;
@@ -509,7 +514,7 @@ static int compile_line(char *linebuf, char *dict_line, int *hash)
if (isspace2(c))
multiple_words++;
else if (c == ')') {
p[0] = ' '; // terminate extra string
p[0] = ' '; // terminate extra string
multiple_string_end = p+1;
step = 3;
}
@@ -522,7 +527,7 @@ static int compile_line(char *linebuf, char *dict_line, int *hash)
break;
case 4:
if (isspace2(c)) {
p[0] = 0; /* terminate phonetic */
p[0] = 0; // terminate phonetic
step = 5;
}
break;
@@ -533,7 +538,7 @@ static int compile_line(char *linebuf, char *dict_line, int *hash)
}

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

if (text_mode)
text_not_phonemes = 1;
@@ -541,7 +546,7 @@ static int compile_line(char *linebuf, char *dict_line, int *hash)
if (text_not_phonemes) {
if (word[0] == '_') {
// This is a special word, used by eSpeak. Translate this into phonemes now
strcat(phonetic, " "); // need a space to indicate word-boundary
strcat(phonetic, " "); // need a space to indicate word-boundary

// PROBLEM vowel reductions are not applied to the translated phonemes
// condition rules are not applied
@@ -574,7 +579,6 @@ static int compile_line(char *linebuf, char *dict_line, int *hash)
if (text_not_phonemes != translator->langopts.textmode)
flag_codes[n_flag_codes++] = BITNUM_FLAG_TEXTMODE;


if (sscanf(word, "U+%x", &wc) == 1) {
// Character code
ix = utf8_out(wc, word);
@@ -609,7 +613,7 @@ static int compile_line(char *linebuf, char *dict_line, int *hash)
*hash = HashDictionary(word);
len_phonetic = strlen(encoded_ph);

dict_line[1] = len_word; // bit 6 indicates whether the word has been compressed
dict_line[1] = len_word; // bit 6 indicates whether the word has been compressed
len_word &= 0x3f;

memcpy(&dict_line[2], word, len_word);
@@ -647,7 +651,7 @@ static int compile_line(char *linebuf, char *dict_line, int *hash)

static void compile_dictlist_start(void)
{
// initialise dictionary list
// initialise dictionary list
int ix;
char *p;
char *p2;
@@ -666,7 +670,7 @@ static void compile_dictlist_start(void)

static void compile_dictlist_end(FILE *f_out)
{
// Write out the compiled dictionary list
// Write out the compiled dictionary list
int hash;
int length;
char *p;
@@ -725,7 +729,7 @@ static int compile_dictlist_file(const char *path, const char *filename)
linenum++;

length = compile_line(buf, dict_line, &hash);
if (length == 0) continue; /* blank line */
if (length == 0) continue; // blank line

hash_counts[hash]++;

@@ -758,7 +762,7 @@ static char rule_phonemes[80];
static char group_name[LEN_GROUP_NAME+1];
static int group3_ix;

#define N_RULES 3000 // max rules for each group
#define N_RULES 3000 // max rules for each group

int isHexDigit(int c)
{
@@ -773,7 +777,7 @@ int isHexDigit(int c)

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
static char *outbuf[5] = { rule_cond, rule_pre, rule_match, rule_post, rule_phonemes };
static int next_state[5] = { 2, 2, 4, 4, 4 };
char *output;
@@ -799,7 +803,7 @@ static void copy_rule_string(char *string, int *state_out)
rule_phonemes[len++] = ' ';
output = &rule_phonemes[len];
}
sxflags = 0x808000; // to ensure non-zero bytes
sxflags = 0x808000; // to ensure non-zero bytes

for (p = string, ix = 0;;) {
literal = 0;
@@ -810,7 +814,7 @@ static void copy_rule_string(char *string, int *state_out)
p += 2;
}
if (c == '\\') {
c = *p++; // treat next character literally
c = *p++; // treat next character literally
if ((c >= '0') && (c <= '3') && (p[0] >= '0') && (p[0] <= '7') && (p[1] >= '0') && (p[1] <= '7')) {
// character code given by 3 digit octal value;
c = (c-'0')*64 + (p[0]-'0')*8 + (p[1]-'0');
@@ -837,8 +841,9 @@ static void copy_rule_string(char *string, int *state_out)
break;

case 'Y':
c = 'I'; // drop through to next case
case 'A': // vowel
c = 'I';
// fallthrough:
case 'A': // vowel
case 'B':
case 'C':
case 'H':
@@ -947,10 +952,10 @@ static void copy_rule_string(char *string, int *state_out)
error_count++;
}
break;
case 'P':
sxflags |= SUFX_P; // Prefix, now drop through to Suffix
case 'P': // Prefix
sxflags |= SUFX_P;
// fallthrough
case 'S':
case 'S': // Suffix
output[ix++] = RULE_ENDING;
value = 0;
while (!isspace2(c = *p++) && (c != 0)) {
@@ -962,7 +967,7 @@ static void copy_rule_string(char *string, int *state_out)
case 'i':
sxflags |= SUFX_I;
break;
case 'p': // obsolete, replaced by 'P' above
case 'p': // obsolete, replaced by 'P' above
sxflags |= SUFX_P;
break;
case 'v':
@@ -1041,13 +1046,13 @@ static char *compile_rule(char *input)

switch (c = input[ix])
{
case ')': // end of prefix section
case ')': // end of prefix section
*p = 0;
state = 1;
copy_rule_string(buf, &state);
p = buf;
break;
case '(': // start of suffix section
case '(': // start of suffix section
*p = 0;
state = 2;
copy_rule_string(buf, &state);
@@ -1058,14 +1063,14 @@ static char *compile_rule(char *input)
error_count++;
}
break;
case '\n': // end of line
case '\n': // end of line
case '\r':
case 0: // end of line
case 0: // end of line
*p = 0;
copy_rule_string(buf, &state);
finish = 1;
break;
case '\t': // end of section section
case '\t': // end of section section
case ' ':
*p = 0;
copy_rule_string(buf, &state);
@@ -1180,7 +1185,7 @@ int __cdecl string_sorter(char **a, char **b)

static int __cdecl rgroup_sorter(RGROUP *a, RGROUP *b)
{
// Sort long names before short names
// Sort long names before short names
int ix;
ix = strlen(b->name) - strlen(a->name);
if (ix != 0) return ix;
@@ -1314,23 +1319,23 @@ static void output_rule_group(FILE *f_out, int n_rules, char **rules, char *name
qsort((void *)rules, n_rules, sizeof(char *), (int(__cdecl *)(const void *, const void *))string_sorter);

if (strcmp(name, "9") == 0)
len_name = 0; // don't remove characters from numeric match strings
len_name = 0; // don't remove characters from numeric match strings

for (ix = 0; ix < n_rules; ix++) {
p = rules[ix];
len1 = strlen(p) + 1; // phoneme string
len1 = strlen(p) + 1; // phoneme string
p3 = &p[len1];
p2 = p3 + len_name; // remove group name from start of match string
p2 = p3 + len_name; // remove group name from start of match string
len2 = strlen(p2);

nextchar_count[(unsigned char)(p2[0])]++; // the next byte after the group name
nextchar_count[(unsigned char)(p2[0])]++; // the next byte after the group name

if ((common[0] != 0) && (strcmp(p, common) == 0)) {
fwrite(p2, len2, 1, f_out);
fputc(0, f_out); // no phoneme string, it's the same as previous rule
fputc(0, f_out); // no phoneme string, it's the same as previous rule
} else {
if ((ix < n_rules-1) && (strcmp(p, rules[ix+1]) == 0)) {
common = rules[ix]; // phoneme string is same as next, set as common
common = rules[ix]; // phoneme string is same as next, set as common
fputc(RULE_PH_COMMON, f_out);
}

@@ -1358,7 +1363,7 @@ static int compile_lettergroup(char *input, FILE *f_out)
int length;
int max_length = 0;

#define N_LETTERGP_ITEMS 200
#define N_LETTERGP_ITEMS 200
char *items[N_LETTERGP_ITEMS];
char item_length[N_LETTERGP_ITEMS];

@@ -1395,7 +1400,7 @@ static int compile_lettergroup(char *input, FILE *f_out)

items[n_items] = p_start = p;
while ((*p & 0xff) > ' ') {
if (*p == '_') *p = ' '; // allow '_' for word break
if (*p == '_') *p = ' '; // allow '_' for word break
p++;
}
*p++ = 0;
@@ -1408,9 +1413,8 @@ static int compile_lettergroup(char *input, FILE *f_out)
// write out the items, longest first
while (max_length > 1) {
for (ix = 0; ix < n_items; ix++) {
if (item_length[ix] == max_length) {
if (item_length[ix] == max_length)
fwrite(items[ix], 1, max_length, f_out);
}
}
max_length--;
}
@@ -1457,7 +1461,7 @@ static int compile_dictrules(FILE *f_in, FILE *f_out, char *fname_temp)
if ((p = (unsigned char *)strstr(buf, "//")) != NULL)
*p = 0;

if (buf[0] == '\r') buf++; // ignore extra \r in \r\n
if (buf[0] == '\r') buf++; // ignore extra \r in \r\n
}

if ((buf == NULL) || (buf[0] == '.')) {
@@ -1478,11 +1482,11 @@ static int compile_dictrules(FILE *f_in, FILE *f_out, char *fname_temp)

if (compile_mode == 2) {
// end of the character replacements section
fwrite(&n_rules, 1, 4, f_out); // write a zero word to terminate the replacemenmt list
fwrite(&n_rules, 1, 4, f_out); // write a zero word to terminate the replacemenmt list
compile_mode = 0;
}

if (buf == NULL) break; // end of file
if (buf == NULL) break; // end of file

if (memcmp(buf, ".L", 2) == 0) {
compile_lettergroup(&buf[2], f_out);
@@ -1503,7 +1507,7 @@ static int compile_dictrules(FILE *f_in, FILE *f_out, char *fname_temp)
compile_mode = 1;

p = (unsigned char *)&buf[6];
while ((p[0] == ' ') || (p[0] == '\t')) p++; // Note: Windows isspace(0xe1) gives TRUE !
while ((p[0] == ' ') || (p[0] == '\t')) p++; // Note: Windows isspace(0xe1) gives TRUE !
ix = 0;
while ((*p > ' ') && (ix < LEN_GROUP_NAME))
group_name[ix++] = *p++;
@@ -1522,7 +1526,7 @@ static int compile_dictrules(FILE *f_in, FILE *f_out, char *fname_temp)
if (translator->letter_bits_offset > 0) {
utf8_in(&wc, group_name);
if (((ix = (wc - translator->letter_bits_offset)) >= 0) && (ix < 128))
group3_ix = ix+1; // not zero
group3_ix = ix+1; // not zero
}
}

@@ -1541,7 +1545,7 @@ static int compile_dictrules(FILE *f_in, FILE *f_out, char *fname_temp)

switch (compile_mode)
{
case 1: // .group
case 1: // .group
prule = compile_rule(buf);
if (prule != NULL) {
if (n_rules < N_RULES)
@@ -1556,7 +1560,7 @@ static int compile_dictrules(FILE *f_in, FILE *f_out, char *fname_temp)

}
break;
case 2: // .replace
case 2: // .replace
{
int replace1;
int replace2;
@@ -1580,11 +1584,11 @@ static int compile_dictrules(FILE *f_in, FILE *f_out, char *fname_temp)
ix += 16;
}
if (replace1 != 0) {
Write4Bytes(f_out, replace1); // write as little-endian
Write4Bytes(f_out, replace2); // if big-endian, reverse the bytes in LoadDictionary()
Write4Bytes(f_out, replace1); // write as little-endian
Write4Bytes(f_out, replace2); // if big-endian, reverse the bytes in LoadDictionary()
}
}
break;
break;
}
}
fclose(f_temp);
@@ -1631,8 +1635,8 @@ static int compile_dictrules(FILE *f_in, FILE *f_out, char *fname_temp)

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
// flags: bit 0: include source line number information, for debug purposes.
// fname: space to write the filename in case of error
// flags: bit 0: include source line number information, for debug purposes.

FILE *f_in;
FILE *f_out;

+ 3
- 3
src/libespeak-ng/compilembrola.c View File

@@ -78,7 +78,7 @@ espeak_ng_STATUS espeak_ng_CompileMbrolaVoice(const char *filepath, FILE *log)
char name2[40];
char mbrola_voice[40];
char buf[sizeof(path_home)+30];
int mbrola_ctrl = 20; // volume in 1/16 ths
int mbrola_ctrl = 20; // volume in 1/16 ths
MBROLA_TAB data[N_PHONEME_TAB];

strcpy(buf, filepath);
@@ -91,7 +91,7 @@ espeak_ng_STATUS espeak_ng_CompileMbrolaVoice(const char *filepath, FILE *log)
buf[sizeof(phoneme)-1] = 0;

if ((p = strstr(buf, "//")) != NULL)
*p = 0; // truncate line at comment
*p = 0; // truncate line at comment

if (memcmp(buf, "volume", 6) == 0) {
mbrola_ctrl = atoi(&buf[6]);
@@ -128,7 +128,7 @@ espeak_ng_STATUS espeak_ng_CompileMbrolaVoice(const char *filepath, FILE *log)
return ENE_WRITE_ERROR;
}

data[count].name = 0; // list terminator
data[count].name = 0; // list terminator
Write4Bytes(f_out, mbrola_ctrl);

pw_end = (int *)(&data[count+1]);

+ 225
- 228
src/libespeak-ng/dictionary.c
File diff suppressed because it is too large
View File


+ 2
- 2
src/libespeak-ng/espeak_command.h View File

@@ -89,8 +89,8 @@ typedef struct {

typedef enum {
CS_UNDEFINED, // The command has just been created
CS_PENDING, // stored in the fifo
CS_PROCESSED // processed
CS_PENDING, // stored in the fifo
CS_PROCESSED // processed
} t_command_state;

typedef struct {

+ 19
- 18
src/libespeak-ng/event.c View File

@@ -50,9 +50,11 @@ static bool thread_inited;
static t_espeak_callback *my_callback = NULL;
static int my_event_is_running = 0;

enum { MIN_TIMEOUT_IN_MS = 10,
ACTIVITY_TIMEOUT = 50, // in ms, check that the stream is active
MAX_ACTIVITY_CHECK = 6 };
enum {
MIN_TIMEOUT_IN_MS = 10,
ACTIVITY_TIMEOUT = 50, // in ms, check that the stream is active
MAX_ACTIVITY_CHECK = 6
};

typedef struct t_node {
void *data;
@@ -359,9 +361,9 @@ static int get_remaining_time(uint32_t sample, uint32_t *time_in_ms, int *stop_i
for (i = 0; i < MAX_ACTIVITY_CHECK && (*stop_is_required == 0); i++) {
err = wave_get_remaining_time(sample, time_in_ms);

if (err || wave_is_busy(NULL) || (*time_in_ms == 0)) { // if err, stream not available: quit
// if wave is busy, time_in_ms is known: quit
// if wave is not busy but remaining time == 0, event is reached: quit
if (err || // if err, stream not available: quit
wave_is_busy(NULL) || // if wave is busy, time_in_ms is known: quit
(*time_in_ms == 0)) { // if wave is not busy but remaining time == 0, event is reached: quit
break;
}

@@ -412,20 +414,19 @@ static void *polling_thread(void *p)
SHOW_TIME("polling_thread > unlocked\n");

a_stop_is_required = 0;
a_status = sem_getvalue(&my_sem_stop_is_required, &a_stop_is_required); // NOTE: may set a_stop_is_required to -1
a_status = sem_getvalue(&my_sem_stop_is_required, &a_stop_is_required); // NOTE: may set a_stop_is_required to -1
if ((a_status == 0) && (a_stop_is_required > 0)) {
SHOW("polling_thread > stop required (%d)\n", __LINE__);
while (0 == sem_trywait(&my_sem_stop_is_required)) {
}
;
while (0 == sem_trywait(&my_sem_stop_is_required))
;
} else
a_stop_is_required = 0;

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

espeak_EVENT *event = (espeak_EVENT *)(head->data);
assert(event);
@@ -465,8 +466,8 @@ static void *polling_thread(void *p)

if ((a_status == 0) && (a_stop_is_required > 0)) {
SHOW("polling_thread > stop required (%d)\n", __LINE__);
while (0 == sem_trywait(&my_sem_stop_is_required)) {
}
while (0 == sem_trywait(&my_sem_stop_is_required))
;
} else
a_stop_is_required = 0;
} else // The event will be notified soon: sleep until timeout or stop request
@@ -483,8 +484,8 @@ static void *polling_thread(void *p)
a_status = sem_getvalue(&my_sem_stop_is_required, &a_stop_is_required);
if ((a_status == 0) && (a_stop_is_required > 0)) {
SHOW("polling_thread > stop required (%d)\n", __LINE__);
while (0 == sem_trywait(&my_sem_stop_is_required)) {
}
while (0 == sem_trywait(&my_sem_stop_is_required))
;
} else
a_stop_is_required = 0;
}
@@ -573,8 +574,8 @@ static void init()
{
ENTER("event > init");

while (event_delete((espeak_EVENT *)pop())) {
}
while (event_delete((espeak_EVENT *)pop()))
;

node_counter = 0;
}

+ 10
- 9
src/libespeak-ng/fifo.c View File

@@ -43,8 +43,6 @@
static pthread_mutex_t my_mutex;
static int my_command_is_running = 0;
static int my_stop_is_required = 0;
// + fifo
//

// my_thread: reads commands from the fifo, and runs them.
static pthread_t my_thread;
@@ -57,9 +55,12 @@ static espeak_ERROR push(t_espeak_command *the_command);
static t_espeak_command *pop();
static void init(int process_parameters);
static int node_counter = 0;
enum { MAX_NODE_COUNTER = 400,
INACTIVITY_TIMEOUT = 50, // in ms, check that the stream is inactive
MAX_INACTIVITY_CHECK = 2 };

enum {
MAX_NODE_COUNTER = 400,
INACTIVITY_TIMEOUT = 50, // in ms, check that the stream is inactive
MAX_INACTIVITY_CHECK = 2
};

void fifo_init()
{
@@ -338,8 +339,8 @@ static void *say_thread(void *p)
display_espeak_command(a_command);
// purge start semaphore
SHOW_TIME("say_thread > purge my_sem_start_is_required\n");
while (0 == sem_trywait(&my_sem_start_is_required)) {
}
while (0 == sem_trywait(&my_sem_start_is_required))
;

if (my_stop_is_required) {
SHOW_TIME("say_thread > my_command_is_running = 0\n");
@@ -361,8 +362,8 @@ static void *say_thread(void *p)

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

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

+ 105
- 115
src/libespeak-ng/intonation.c View File

@@ -46,7 +46,7 @@
typedef struct {
char stress;
char env;
char flags; // bit 0=pitch rising, bit1=emnphasized, bit2=end of clause
char flags; // bit 0=pitch rising, bit1=emnphasized, bit2=end of clause
char nextph_type;
unsigned char pitch1;
unsigned char pitch2;
@@ -54,18 +54,17 @@ typedef struct {

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 */
/*****************************/

#define PITCHfall 0
#define PITCHrise 2
#define PITCHfrise 4 // and 3 must be for the variant preceded by 'r'
#define PITCHfrise2 6 // and 5 must be the 'r' variant
#define PITCHrisefall 8
#define PITCHfall 0
#define PITCHrise 2
#define PITCHfrise 4 // and 3 must be for the variant preceded by 'r'
#define PITCHfrise2 6 // and 5 must be the 'r' variant
#define PITCHrisefall 8

/* 0 fall */
unsigned char env_fall[128] = {
0xff, 0xfd, 0xfa, 0xf8, 0xf6, 0xf4, 0xf2, 0xf0, 0xee, 0xec, 0xea, 0xe8, 0xe6, 0xe4, 0xe2, 0xe0,
0xde, 0xdc, 0xda, 0xd8, 0xd6, 0xd4, 0xd2, 0xd0, 0xce, 0xcc, 0xca, 0xc8, 0xc6, 0xc4, 0xc2, 0xc0,
@@ -77,7 +76,6 @@ unsigned char env_fall[128] = {
0x1e, 0x1c, 0x1a, 0x18, 0x16, 0x14, 0x12, 0x10, 0x0e, 0x0c, 0x0a, 0x08, 0x06, 0x04, 0x02, 0x00
};

/* 1 rise */
unsigned char env_rise[128] = {
0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,
0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e,
@@ -213,7 +211,7 @@ unsigned char *envelope_data[N_ENVELOPE_DATA] = {
env_risefallrise, env_risefallrise
};

/* indexed by stress */
// indexed by stress
static int min_drop[] = { 6, 7, 9, 9, 20, 20, 20, 25 };

// pitch change during the main part of the clause
@@ -224,8 +222,8 @@ static signed char oflow[] = { 0, 40, 24, 8, 0 };
static signed char oflow_emf[] = { 10, 52, 32, 20, 10 };
static signed char oflow_less[] = { 6, 38, 24, 14, 4 };

#define N_TONE_HEAD_TABLE 13
#define N_TONE_NUCLEUS_TABLE 13
#define N_TONE_HEAD_TABLE 13
#define N_TONE_NUCLEUS_TABLE 13

typedef struct {
unsigned char pre_start;
@@ -243,11 +241,11 @@ typedef struct {
} TONE_HEAD;

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

unsigned char pitch_env1; /* followed by unstressed */
unsigned char pitch_env1; // followed by unstressed
unsigned char tonic_max1;
unsigned char tonic_min1;

@@ -261,57 +259,56 @@ typedef struct {
#define T_EMPH 1

static TONE_HEAD tone_head_table[N_TONE_HEAD_TABLE] = {
{ 46, 57, 78, 50, drops_0, 3, 7, 5, oflow }, // 0 statement
{ 46, 57, 78, 46, drops_0, 3, 7, 5, oflow }, // 1 comma
{ 46, 57, 78, 46, drops_0, 3, 7, 5, oflow }, // 2 question
{ 46, 57, 90, 50, drops_0, 3, 9, 5, oflow_emf }, // 3 exclamation
{ 46, 57, 78, 50, drops_0, 3, 7, 5, oflow }, // 4 statement, emphatic
{ 46, 57, 74, 55, drops_0, 4, 7, 5, oflow_less },// 5 statement, less intonation
{ 46, 57, 74, 55, drops_0, 4, 7, 5, oflow_less },// 6 comma, less intonation
{ 46, 57, 74, 55, drops_0, 4, 7, 5, oflow_less },// 7 comma, less intonation, less rise
{ 46, 57, 78, 50, drops_0, 3, 7, 5, oflow }, // 8 pitch raises at end of sentence
{ 46, 57, 78, 46, drops_0, 3, 7, 5, oflow }, // 9 comma
{ 46, 57, 78, 50, drops_0, 3, 7, 5, oflow }, // 10 question
{ 34, 41, 41, 32, drops_0, 3, 7, 5, oflow_less }, // 11 test
{ 46, 57, 55, 50, drops_0, 3, 7, 5, oflow_less }, // 12 test
{ 46, 57, 78, 50, drops_0, 3, 7, 5, oflow }, // 0 statement
{ 46, 57, 78, 46, drops_0, 3, 7, 5, oflow }, // 1 comma
{ 46, 57, 78, 46, drops_0, 3, 7, 5, oflow }, // 2 question
{ 46, 57, 90, 50, drops_0, 3, 9, 5, oflow_emf }, // 3 exclamation
{ 46, 57, 78, 50, drops_0, 3, 7, 5, oflow }, // 4 statement, emphatic
{ 46, 57, 74, 55, drops_0, 4, 7, 5, oflow_less }, // 5 statement, less intonation
{ 46, 57, 74, 55, drops_0, 4, 7, 5, oflow_less }, // 6 comma, less intonation
{ 46, 57, 74, 55, drops_0, 4, 7, 5, oflow_less }, // 7 comma, less intonation, less rise
{ 46, 57, 78, 50, drops_0, 3, 7, 5, oflow }, // 8 pitch raises at end of sentence
{ 46, 57, 78, 46, drops_0, 3, 7, 5, oflow }, // 9 comma
{ 46, 57, 78, 50, drops_0, 3, 7, 5, oflow }, // 10 question
{ 34, 41, 41, 32, drops_0, 3, 7, 5, oflow_less }, // 11 test
{ 46, 57, 55, 50, drops_0, 3, 7, 5, oflow_less }, // 12 test
};

static TONE_NUCLEUS tone_nucleus_table[N_TONE_NUCLEUS_TABLE] = {
{ PITCHfall, 64, 8, PITCHfall, 70, 18, NULL, 24, 12, 0 }, // 0 statement
{ PITCHfrise, 80, 18, PITCHfrise2, 78, 22, NULL, 34, 52, 0 }, // 1 comma
{ PITCHfrise, 88, 22, PITCHfrise2, 82, 22, NULL, 34, 64, 0 }, // 2 question
{ PITCHfall, 92, 8, PITCHfall, 92, 80, NULL, 76, 8, T_EMPH }, // 3 exclamation

{ PITCHfall, 86, 4, PITCHfall, 94, 66, NULL, 34, 10, 0 }, // 4 statement, emphatic
{ PITCHfall, 62, 10, PITCHfall, 62, 20, NULL, 28, 16, 0 }, // 5 statement, less intonation
{ PITCHfrise, 68, 18, PITCHfrise2, 68, 22, NULL, 30, 44, 0 }, // 6 comma, less intonation
{ PITCHfrise2, 64, 16, PITCHfall, 66, 32, NULL, 32, 18, 0 }, // 7 comma, less intonation, less rise
{ PITCHrise, 68, 46, PITCHfall, 42, 32, NULL, 46, 58, 0 }, // 8 pitch raises at end of sentence
{ PITCHfrise, 78, 24, PITCHfrise2, 72, 22, NULL, 42, 52, 0 }, // 9 comma
{ PITCHfrise, 88, 34, PITCHfall, 64, 32, NULL, 46, 82, 0 }, // 10 question
{ PITCHfall, 56, 12, PITCHfall, 56, 20, NULL, 24, 12, 0 }, // 11 test
{ PITCHfall, 70, 18, PITCHfall, 70, 24, NULL, 32, 20, 0 }, // 12 test
{ PITCHfall, 64, 8, PITCHfall, 70, 18, NULL, 24, 12, 0 }, // 0 statement
{ PITCHfrise, 80, 18, PITCHfrise2, 78, 22, NULL, 34, 52, 0 }, // 1 comma
{ PITCHfrise, 88, 22, PITCHfrise2, 82, 22, NULL, 34, 64, 0 }, // 2 question
{ PITCHfall, 92, 8, PITCHfall, 92, 80, NULL, 76, 8, T_EMPH }, // 3 exclamation
{ PITCHfall, 86, 4, PITCHfall, 94, 66, NULL, 34, 10, 0 }, // 4 statement, emphatic
{ PITCHfall, 62, 10, PITCHfall, 62, 20, NULL, 28, 16, 0 }, // 5 statement, less intonation
{ PITCHfrise, 68, 18, PITCHfrise2, 68, 22, NULL, 30, 44, 0 }, // 6 comma, less intonation
{ PITCHfrise2, 64, 16, PITCHfall, 66, 32, NULL, 32, 18, 0 }, // 7 comma, less intonation, less rise
{ PITCHrise, 68, 46, PITCHfall, 42, 32, NULL, 46, 58, 0 }, // 8 pitch raises at end of sentence
{ PITCHfrise, 78, 24, PITCHfrise2, 72, 22, NULL, 42, 52, 0 }, // 9 comma
{ PITCHfrise, 88, 34, PITCHfall, 64, 32, NULL, 46, 82, 0 }, // 10 question
{ PITCHfall, 56, 12, PITCHfall, 56, 20, NULL, 24, 12, 0 }, // 11 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] = {
{ 0, 1, 2, 3, 0, 4 },
{ 0, 1, 2, 3, 0, 4 },
{ 5, 6, 2, 3, 0, 4 },
{ 5, 7, 1, 3, 0, 4 },
{ 8, 9, 10, 3, 0, 0 },
{ 8, 8, 10, 3, 0, 0 },
{ 11, 11, 11, 11, 0, 0 }, // 6 test
{ 0, 1, 2, 3, 0, 4 },
{ 0, 1, 2, 3, 0, 4 },
{ 5, 6, 2, 3, 0, 4 },
{ 5, 7, 1, 3, 0, 4 },
{ 8, 9, 10, 3, 0, 0 },
{ 8, 8, 10, 3, 0, 0 },
{ 11, 11, 11, 11, 0, 0 }, // 6 test
{ 12, 12, 12, 12, 0, 0 }
};

int n_tunes = 0;
TUNE *tunes = NULL;

#define SECONDARY 3
#define PRIMARY 4
#define SECONDARY 3
#define PRIMARY 4
#define PRIMARY_STRESSED 6
#define PRIMARY_LAST 7
#define PRIMARY_LAST 7

static int number_pre;
static int number_body;
@@ -326,16 +323,16 @@ static void count_pitch_vowels(int start, int end, int clause_end)
int ix;
int stress;
int max_stress = 0;
int max_stress_posn = 0; // last syllable ot the highest stress
int max_stress_posn2 = 0; // penuntimate syllable of the highest stress
int max_stress_posn = 0; // last syllable ot the highest stress
int max_stress_posn2 = 0; // penuntimate syllable of the highest stress

number_pre = -1; /* number of vowels before 1st primary stress */
number_pre = -1; // number of vowels before 1st primary stress
number_body = 0;
number_tail = 0; /* number between tonic syllable and next primary */
number_tail = 0; // number between tonic syllable and next primary
last_primary = -1;

for (ix = start; ix < end; ix++) {
stress = syllable_tab[ix].stress; /* marked stress level */
stress = syllable_tab[ix].stress; // marked stress level

if (stress >= max_stress) {
if (stress > max_stress)
@@ -360,9 +357,9 @@ static void count_pitch_vowels(int start, int end, int clause_end)
tone_posn = max_stress_posn;
tone_posn2 = max_stress_posn2;

if (no_tonic) {
tone_posn = tone_posn2 = end; // next position after the end of the truncated clause
} else if (last_primary >= 0) {
if (no_tonic)
tone_posn = tone_posn2 = end; // next position after the end of the truncated clause
else if (last_primary >= 0) {
if (end == clause_end)
syllable_tab[last_primary].stress = PRIMARY_LAST;
} else {
@@ -371,7 +368,7 @@ static void count_pitch_vowels(int start, int end, int clause_end)
}
}

/* 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)
{
int count = 0;
@@ -434,7 +431,7 @@ static int SetHeadIntonation(TUNE *tune, int syl_ix, int end_ix, int control)
int pitch = 0;
int increment = 0;
int n_steps = 0;
int stage; // onset, head, last
int stage; // onset, head, last
int initial;
int overflow_ix = 0;
int pitch_range;
@@ -445,16 +442,16 @@ static int SetHeadIntonation(TUNE *tune, int syl_ix, int end_ix, int control)
int unstressed_inc;
int used_onset = 0;
int head_final = end_ix;
int secondary = 2; // 2
int secondary = 2;

pitch_range = (tune->head_end - tune->head_start) << 8;
pitch_range_abs = abs(pitch_range);
drops = drops_0; // this should be controled by tune->head_drops
drops = drops_0; // this should be controled by tune->head_drops
initial = 1;

stage = 0;
if (tune->onset == 255)
stage = 1; // no onset specified
stage = 1; // no onset specified

if (tune->head_last != 255) {
// find the last primary stress in the body
@@ -624,7 +621,7 @@ static int calc_pitch_segment(int ix, int end_ix, TONE_HEAD *th, TONE_NUCLEUS *t
} else if (stress >= SECONDARY)
set_pitch(syl, (pitch >> 8), drops[stress]);
else {
/* unstressed, drop pitch if preceded by PRIMARY */
// unstressed, drop pitch if preceded by PRIMARY
if ((syllable_tab[ix-1].stress & 0x3f) >= SECONDARY)
set_pitch(syl, (pitch >> 8) - th->body_lower_u, drops[stress]);
else
@@ -638,8 +635,8 @@ static int calc_pitch_segment(int ix, int end_ix, TONE_HEAD *th, TONE_NUCLEUS *t

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.
// Used for pre-head, unstressed syllables in the body, and the tail
// Set a linear pitch change over a number of syllables.
// Used for pre-head, unstressed syllables in the body, and the tail

int ix;
int stress;
@@ -691,24 +688,21 @@ static int calc_pitches2(int start, int end, int tune_number)
tune = &tunes[tune_number];
ix = start;

/* vowels before the first primary stress */
/******************************************/
// vowels before the first primary stress

SetPitchGradient(ix, ix+number_pre, tune->prehead_start, tune->prehead_end);
ix += number_pre;

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

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

if (no_tonic)
return 0;

/* tonic syllable */
/******************/
// tonic syllable

if (number_tail == 0) {
tone_pitch_env = tune->nucleus0_env;
@@ -724,8 +718,7 @@ static int calc_pitches2(int start, int end, int tune_number)
if (syllable_tab[tone_posn].stress == PRIMARY)
syllable_tab[tone_posn].stress = PRIMARY_STRESSED;

/* tail, after the tonic syllable */
/**********************************/
// tail, after the tonic syllable

SetPitchGradient(ix, end, tune->tail_start, tune->tail_end);

@@ -751,28 +744,24 @@ static int calc_pitches(int control, int start, int end, int tune_number)
tn = &tone_nucleus_table[tune_number];
ix = start;

/* vowels before the first primary stress */
/******************************************/
// vowels before the first primary stress

SetPitchGradient(ix, ix+number_pre, th->pre_start, th->pre_end);
ix += number_pre;

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

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

if (no_tonic)
return 0;

/* tonic syllable */
/******************/
// tonic syllable

if (tn->flags & T_EMPH) {
if (tn->flags & T_EMPH)
syllable_tab[ix].flags |= SYL_EMPHASIS;
}

if (number_tail == 0) {
tone_pitch_env = tn->pitch_env0;
@@ -788,8 +777,7 @@ static int calc_pitches(int control, int start, int end, int tune_number)
if (syllable_tab[tone_posn].stress == PRIMARY)
syllable_tab[tone_posn].stress = PRIMARY_STRESSED;

/* tail, after the tonic syllable */
/**********************************/
// tail, after the tonic syllable

SetPitchGradient(ix, end, tn->tail_start, tn->tail_end);

@@ -798,7 +786,8 @@ static int calc_pitches(int control, int start, int end, int tune_number)

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

PHONEME_LIST *p;
int ix;
int count_stressed = 0;
@@ -808,14 +797,14 @@ static void CalcPitches_Tone(Translator *tr, int clause_tone)
int pause;
int tone_promoted;
PHONEME_TAB *tph;
PHONEME_TAB *prev_tph; // forget across word boundary
PHONEME_TAB *prevw_tph; // remember across word boundary
PHONEME_TAB *prev_tph; // forget across word boundary
PHONEME_TAB *prevw_tph; // remember across word boundary
PHONEME_LIST *prev_p;

int pitch_adjust = 0; // pitch gradient through the clause - inital value
int pitch_decrement = 0; // decrease by this for each stressed syllable
int pitch_low = 0; // until it drops to this
int pitch_high = 0; // then reset to this
int pitch_adjust = 0; // pitch gradient through the clause - inital value
int pitch_decrement = 0; // decrease by this for each stressed syllable
int pitch_low = 0; // until it drops to this
int pitch_high = 0; // then reset to this

// count number of stressed syllables
p = &phoneme_list[0];
@@ -838,7 +827,7 @@ static void CalcPitches_Tone(Translator *tr, int clause_tone)
// LANG=vi
p = &phoneme_list[final_stressed];
if (p->tone_ph == 0)
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;
@@ -850,12 +839,12 @@ static void CalcPitches_Tone(Translator *tr, int clause_tone)
// perform tone sandhi
for (ix = 0; ix < n_phoneme_list; ix++, p++) {
if ((p->type == phPAUSE) && (p->ph->std_length > 50)) {
pause = 1; // there is a pause since the previous vowel
prevw_tph = phoneme_tab[phonPAUSE]; // forget previous tone
pause = 1; // there is a pause since the previous vowel
prevw_tph = phoneme_tab[phonPAUSE]; // forget previous tone
}

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

if (p->synthflags & SFLAG_SYLLABLE) {
tone_ph = p->tone_ph;
@@ -865,10 +854,10 @@ static void CalcPitches_Tone(Translator *tr, int clause_tone)
if (tr->translator_name == L('z', 'h')) {
if (tone_ph == 0) {
if (pause || tone_promoted) {
tone_ph = PhonemeCode2('5', '5'); // no previous vowel, use tone 1
tone_ph = PhonemeCode2('5', '5'); // no previous vowel, use tone 1
tone_promoted = 1;
} else
tone_ph = PhonemeCode2('1', '1'); // default tone 5
tone_ph = PhonemeCode2('1', '1'); // default tone 5

p->tone_ph = tone_ph;
tph = phoneme_tab[tone_ph];
@@ -883,12 +872,12 @@ static void CalcPitches_Tone(Translator *tr, int clause_tone)
}

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

if (tph->mnemonic == 0x3131) { // [11] Tone 5
@@ -901,7 +890,7 @@ static void CalcPitches_Tone(Translator *tr, int clause_tone)
p->tone_ph = PhonemeCode2('4', '4');

// tone 5 is unstressed (shorter)
p->stresslevel = 0; // diminished stress
p->stresslevel = 0; // diminished stress
}
}

@@ -929,7 +918,7 @@ static void CalcPitches_Tone(Translator *tr, int clause_tone)
}

if (tone_ph == 0) {
tone_ph = phonDEFAULTTONE; // no tone specified, use default tone 1
tone_ph = phonDEFAULTTONE; // no tone specified, use default tone 1
p->tone_ph = tone_ph;
}
p->pitch1 = pitch_adjust + phoneme_tab[tone_ph]->start_type;
@@ -940,7 +929,8 @@ static void CalcPitches_Tone(Translator *tr, int clause_tone)

void CalcPitches(Translator *tr, int clause_type)
{
// clause_type: 0=. 1=, 2=?, 3=! 4=none
// clause_type: 0=. 1=, 2=?, 3=! 4=none

PHONEME_LIST *p;
SYLLABLE *syl;
int ix;
@@ -961,7 +951,7 @@ void CalcPitches(Translator *tr, int clause_type)

SYLLABLE syllable_tab2[N_PHONEME_LIST];

syllable_tab = syllable_tab2; // don't use permanent storage. it's only needed during the call of CalcPitches()
syllable_tab = syllable_tab2; // don't use permanent storage. it's only needed during the call of CalcPitches()
n_st = 0;
n_primary = 0;
for (ix = 0; ix < (n_phoneme_list-1); ix++) {
@@ -977,10 +967,10 @@ void CalcPitches(Translator *tr, int clause_type)
} else if ((p->ph->code == phonPAUSE_CLAUSE) && (n_st > 0))
syllable_tab[n_st-1].flags |= SYL_END_CLAUSE;
}
syllable_tab[n_st].stress = 0; // extra 0 entry at the end
syllable_tab[n_st].stress = 0; // extra 0 entry at the end

if (n_st == 0)
return; // nothing to do
return; // nothing to do

if (tr->langopts.tone_language == 1) {
CalcPitches_Tone(tr, clause_type);
@@ -996,11 +986,11 @@ void CalcPitches(Translator *tr, int clause_type)
group_tone_comma = tr->langopts.tunes[1];
} else {
group_tone = tr->punct_to_tone[option][clause_type];
group_tone_comma = tr->punct_to_tone[option][1]; // emphatic form of statement
group_tone_comma = tr->punct_to_tone[option][1]; // emphatic form of statement
}

if (clause_type == 4)
no_tonic = 1; /* incomplete clause, used for abbreviations such as Mr. Dr. Mrs. */
no_tonic = 1; // incomplete clause, used for abbreviations such as Mr. Dr. Mrs.
else
no_tonic = 0;

@@ -1056,12 +1046,12 @@ void CalcPitches(Translator *tr, int clause_type)

count_pitch_vowels(st_start, ix, n_st);
if ((ix < n_st) || (clause_type == 0)) {
calc_pitches(option, st_start, ix, group_tone); // split into > 1 tone groups
calc_pitches(option, st_start, ix, group_tone); // split into > 1 tone groups

if ((clause_type == 1) || (clause_type == 2))
group_tone = tr->langopts.tunes[1]; // , or ? remainder has comma-tone
group_tone = tr->langopts.tunes[1]; // , or ? remainder has comma-tone
else
group_tone = tr->langopts.tunes[0]; // . or ! remainder has statement tone
group_tone = tr->langopts.tunes[0]; // . or ! remainder has statement tone
} else
calc_pitches(option, st_start, ix, group_tone);

@@ -1114,7 +1104,7 @@ void CalcPitches(Translator *tr, int clause_type)
}

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

st_ix++;
}

+ 151
- 174
src/libespeak-ng/klatt.c View File

@@ -53,7 +53,7 @@ static int sample_count;
#define getrandom(min, max) ((rand()%(long)(((max)+1)-(min)))+(min))
#endif

/* function prototypes for functions private to this file */
// function prototypes for functions private to this file

static void flutter(klatt_frame_ptr);
static double sampled_source(int);
@@ -71,50 +71,50 @@ static klatt_global_t kt_globals;

#define NUMBER_OF_SAMPLES 100

static int scale_wav_tab[] = { 45, 38, 45, 45, 55 }; // scale output from different voicing sources
static int scale_wav_tab[] = { 45, 38, 45, 45, 55 }; // scale output from different voicing sources

// For testing, this can be overwritten in KlattInit()
static short natural_samples2[256] = {
2583, 2516, 2450, 2384, 2319, 2254, 2191, 2127,
2067, 2005, 1946, 1890, 1832, 1779, 1726, 1675,
1626, 1579, 1533, 1491, 1449, 1409, 1372, 1336,
1302, 1271, 1239, 1211, 1184, 1158, 1134, 1111,
1089, 1069, 1049, 1031, 1013, 996, 980, 965,
950, 936, 921, 909, 895, 881, 869, 855,
843, 830, 818, 804, 792, 779, 766, 754,
740, 728, 715, 702, 689, 676, 663, 651,
637, 626, 612, 601, 588, 576, 564, 552,
540, 530, 517, 507, 496, 485, 475, 464,
454, 443, 434, 424, 414, 404, 394, 385,
375, 366, 355, 347, 336, 328, 317, 308,
299, 288, 280, 269, 260, 250, 240, 231,
220, 212, 200, 192, 181, 172, 161, 152,
142, 133, 123, 113, 105, 94, 86, 76,
67, 57, 49, 39, 30, 22, 11, 4,
-5, -14, -23, -32, -41, -50, -60, -69,
-78, -87, -96, -107, -115, -126, -134, -144,
-154, -164, -174, -183, -193, -203, -213, -222,
-233, -242, -252, -262, -271, -281, -291, -301,
-310, -320, -330, -339, -349, -357, -368, -377,
-387, -397, -406, -417, -426, -436, -446, -456,
-467, -477, -487, -499, -509, -521, -532, -543,
-555, -567, -579, -591, -603, -616, -628, -641,
-653, -666, -679, -692, -705, -717, -732, -743,
-758, -769, -783, -795, -808, -820, -834, -845,
-860, -872, -885, -898, -911, -926, -939, -955,
-968, -986, -999, -1018, -1034, -1054, -1072, -1094,
2583, 2516, 2450, 2384, 2319, 2254, 2191, 2127,
2067, 2005, 1946, 1890, 1832, 1779, 1726, 1675,
1626, 1579, 1533, 1491, 1449, 1409, 1372, 1336,
1302, 1271, 1239, 1211, 1184, 1158, 1134, 1111,
1089, 1069, 1049, 1031, 1013, 996, 980, 965,
950, 936, 921, 909, 895, 881, 869, 855,
843, 830, 818, 804, 792, 779, 766, 754,
740, 728, 715, 702, 689, 676, 663, 651,
637, 626, 612, 601, 588, 576, 564, 552,
540, 530, 517, 507, 496, 485, 475, 464,
454, 443, 434, 424, 414, 404, 394, 385,
375, 366, 355, 347, 336, 328, 317, 308,
299, 288, 280, 269, 260, 250, 240, 231,
220, 212, 200, 192, 181, 172, 161, 152,
142, 133, 123, 113, 105, 94, 86, 76,
67, 57, 49, 39, 30, 22, 11, 4,
-5, -14, -23, -32, -41, -50, -60, -69,
-78, -87, -96, -107, -115, -126, -134, -144,
-154, -164, -174, -183, -193, -203, -213, -222,
-233, -242, -252, -262, -271, -281, -291, -301,
-310, -320, -330, -339, -349, -357, -368, -377,
-387, -397, -406, -417, -426, -436, -446, -456,
-467, -477, -487, -499, -509, -521, -532, -543,
-555, -567, -579, -591, -603, -616, -628, -641,
-653, -666, -679, -692, -705, -717, -732, -743,
-758, -769, -783, -795, -808, -820, -834, -845,
-860, -872, -885, -898, -911, -926, -939, -955,
-968, -986, -999, -1018, -1034, -1054, -1072, -1094,
-1115, -1138, -1162, -1188, -1215, -1244, -1274, -1307,
-1340, -1377, -1415, -1453, -1496, -1538, -1584, -1631,
-1680, -1732, -1783, -1839, -1894, -1952, -2010, -2072,
-2133, -2196, -2260, -2325, -2390, -2456, -2522, -2589,
};
static short natural_samples[100] = {
-310, -400, 530, 356, 224, 89, 23, -10, -58, -16, 461, 599, 536, 701, 770,
605, 497, 461, 560, 404, 110, 224, 131, 104, -97, 155, 278, -154, -1165,
-598, 737, 125, -592, 41, 11, -247, -10, 65, 92, 80, -304, 71, 167, -1, 122,
233, 161, -43, 278, 479, 485, 407, 266, 650, 134, 80, 236, 68, 260, 269, 179,
53, 140, 275, 293, 296, 104, 257, 152, 311, 182, 263, 245, 125, 314, 140, 44,
203, 230, -235, -286, 23, 107, 92, -91, 38, 464, 443, 176, 98, -784, -2449,
-310, -400, 530, 356, 224, 89, 23, -10, -58, -16, 461, 599, 536, 701, 770,
605, 497, 461, 560, 404, 110, 224, 131, 104, -97, 155, 278, -154, -1165,
-598, 737, 125, -592, 41, 11, -247, -10, 65, 92, 80, -304, 71, 167, -1, 122,
233, 161, -43, 278, 479, 485, 407, 266, 650, 134, 80, 236, 68, 260, 269, 179,
53, 140, 275, 293, 296, 104, 257, 152, 311, 182, 263, 245, 125, 314, 140, 44,
203, 230, -235, -286, 23, 107, 92, -91, 38, 464, 443, 176, 98, -784, -2449,
-1891, -1045, -1600, -1462, -1384, -1261, -949, -730
};

@@ -182,7 +182,7 @@ static void flutter(klatt_frame_ptr frame)

fla = (double)kt_globals.f0_flutter / 50;
flb = (double)kt_globals.original_f0 / 100;
flc = sin(PI*12.7*time_count); // because we are calling flutter() more frequently, every 2.9mS
flc = sin(PI*12.7*time_count); // because we are calling flutter() more frequently, every 2.9mS
fld = sin(PI*7.1*time_count);
fle = sin(PI*4.7*time_count);
delta_f0 = fla * flb * (flc + fld + fle) * 10;
@@ -262,30 +262,26 @@ static int parwave(klatt_frame_ptr frame)
static double sourc;
int ix;

flutter(frame); /* add f0 flutter */
flutter(frame); // add f0 flutter

/* MAIN LOOP, for each output sample of current frame: */
// MAIN LOOP, for each output sample of current frame:

for (kt_globals.ns = 0; kt_globals.ns < kt_globals.nspfr; kt_globals.ns++) {
/* Get low-passed random number for aspiration and frication noise */
// Get low-passed random number for aspiration and frication noise
noise = gen_noise(noise);

/*
Amplitude modulate noise (reduce noise amplitude during
second half of glottal period) if voicing simultaneously present.
*/
// Amplitude modulate noise (reduce noise amplitude during
// second half of glottal period) if voicing simultaneously present.

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

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

/*
Compute voicing waveform. Run glottal source simulation at 4
times normal sample rate to minimize quantization noise in
period of female voice.
*/
// Compute voicing waveform. Run glottal source simulation at 4
// times normal sample rate to minimize quantization noise in
// period of female voice.

for (n4 = 0; n4 < 4; n4++) {
switch (kt_globals.glsource)
@@ -304,55 +300,46 @@ static int parwave(klatt_frame_ptr frame)
break;
}

/* Reset period when counter 'nper' reaches T0 */
// Reset period when counter 'nper' reaches T0
if (kt_globals.nper >= kt_globals.T0) {
kt_globals.nper = 0;
pitch_synch_par_reset(frame);
}

/*
Low-pass filter voicing waveform before downsampling from 4*samrate
to samrate samples/sec. Resonator f=.09*samrate, bw=.06*samrate
*/
// Low-pass filter voicing waveform before downsampling from 4*samrate
// to samrate samples/sec. Resonator f=.09*samrate, bw=.06*samrate

voice = resonator(&(kt_globals.rsn[RLP]), voice);

/* Increment counter that keeps track of 4*samrate samples per sec */
// Increment counter that keeps track of 4*samrate samples per sec
kt_globals.nper++;
}

/*
Tilt spectrum of voicing source down by soft low-pass filtering, amount
of tilt determined by TLTdb
*/
// Tilt spectrum of voicing source down by soft low-pass filtering, amount
// of tilt determined by TLTdb

voice = (voice * kt_globals.onemd) + (vlast * kt_globals.decay);
vlast = voice;

/*
Add breathiness during glottal open phase. Amount of breathiness
determined by parameter Aturb Use nrand rather than noise because
noise is low-passed.
*/

// Add breathiness during glottal open phase. Amount of breathiness
// determined by parameter Aturb Use nrand rather than noise because
// noise is low-passed.

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

/* Set amplitude of voicing */
// Set amplitude of voicing
glotout = kt_globals.amp_voice * voice;
par_glotout = kt_globals.par_amp_voice * voice;

/* Compute aspiration amplitude and add to voicing source */
// Compute aspiration amplitude and add to voicing source
aspiration = kt_globals.amp_aspir * noise;
glotout += aspiration;

par_glotout += aspiration;

/*
Cascade vocal tract, excited by laryngeal sources.
Nasal antiresonator, then formants FNP, F5, F4, F3, F2, F1
*/
// Cascade vocal tract, excited by laryngeal sources.
// Nasal antiresonator, then formants FNP, F5, F4, F3, F2, F1

out = 0;
if (kt_globals.synthesis_model != ALL_PARALLEL) {
@@ -368,15 +355,13 @@ static int parwave(klatt_frame_ptr frame)
out = resonator2(&(kt_globals.rsn[R1c]), casc_next_in);
}

/* Excite parallel F1 and FNP by voicing waveform */
sourc = par_glotout; /* Source is voicing plus aspiration */
// Excite parallel F1 and FNP by voicing waveform
sourc = par_glotout; // Source is voicing plus aspiration

/*
Standard parallel vocal tract Formants F6,F5,F4,F3,F2,
outputs added with alternating sign. Sound source for other
parallel resonators is frication plus first difference of
voicing waveform.
*/
// Standard parallel vocal tract Formants F6,F5,F4,F3,F2,
// outputs added with alternating sign. Sound source for other
// parallel resonators is frication plus first difference of
// voicing waveform.

out += resonator(&(kt_globals.rsn[R1p]), sourc);
out += resonator(&(kt_globals.rsn[Rnpp]), sourc);
@@ -392,30 +377,27 @@ static int parwave(klatt_frame_ptr frame)
out = outbypas - out;

out = resonator(&(kt_globals.rsn[Rout]), out);
temp = (int)(out * wdata.amplitude * kt_globals.amp_gain0); /* Convert back to integer */

temp = (int)(out * wdata.amplitude * kt_globals.amp_gain0); // Convert back to integer

// mix with a recorded WAV if required for this phoneme
{
int z2;
signed char c;
int sample;

z2 = 0;
if (wdata.mix_wavefile_ix < wdata.n_mix_wavefile) {
if (wdata.mix_wave_scale == 0) {
// a 16 bit sample
c = wdata.mix_wavefile[wdata.mix_wavefile_ix+1];
sample = wdata.mix_wavefile[wdata.mix_wavefile_ix] + (c * 256);
wdata.mix_wavefile_ix += 2;
} else {
// a 8 bit sample, scaled
sample = (signed char)wdata.mix_wavefile[wdata.mix_wavefile_ix++] * wdata.mix_wave_scale;
}
z2 = sample * wdata.amplitude_v / 1024;
z2 = (z2 * wdata.mix_wave_amp)/40;
temp += z2;
int z2;
signed char c;
int sample;

z2 = 0;
if (wdata.mix_wavefile_ix < wdata.n_mix_wavefile) {
if (wdata.mix_wave_scale == 0) {
// a 16 bit sample
c = wdata.mix_wavefile[wdata.mix_wavefile_ix+1];
sample = wdata.mix_wavefile[wdata.mix_wavefile_ix] + (c * 256);
wdata.mix_wavefile_ix += 2;
} else {
// a 8 bit sample, scaled
sample = (signed char)wdata.mix_wavefile[wdata.mix_wavefile_ix++] * wdata.mix_wave_scale;
}
z2 = sample * wdata.amplitude_v / 1024;
z2 = (z2 * wdata.mix_wave_amp)/40;
temp += z2;
}

// if fadeout is set, fade to zero over 64 samples, to avoid clicks at end of synthesis
@@ -459,7 +441,6 @@ void KlattReset(int control)
kt_globals.minus_pi_t = -PI / kt_globals.samrate;
kt_globals.two_pi_t = -2.0 * kt_globals.minus_pi_t;
setabc(kt_globals.FLPhz, kt_globals.BLPhz, &(kt_globals.rsn[RLP]));

}

if (control > 0) {
@@ -514,7 +495,7 @@ static void frame_init(klatt_frame_ptr frame)
Gain0_tmp = 57;
kt_globals.amp_gain0 = DBtoLIN(Gain0_tmp) / kt_globals.scale_wav;

/* Set coefficients of variable cascade resonators */
// Set coefficients of variable cascade resonators
for (ix = 1; ix <= 9; ix++) {
// formants 1 to 8, plus nasal pole
setabc(frame->Fhz[ix], frame->Bhz[ix], &(kt_globals.rsn[ix]));
@@ -535,14 +516,14 @@ static void frame_init(klatt_frame_ptr frame)
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;

/* Set coefficients of parallel resonators, and amplitude of outputs */
// Set coefficients of parallel resonators, and amplitude of outputs

for (ix = 0; ix <= 6; ix++) {
setabc(frame->Fhz[ix], frame->Bphz[ix], &(kt_globals.rsn[Rparallel+ix]));
kt_globals.rsn[Rparallel+ix].a *= amp_par[ix];
}

/* output low-pass filter */
// output low-pass filter

setabc((long)0.0, (long)(kt_globals.samrate/2), &(kt_globals.rsn[Rout]));
}
@@ -631,40 +612,39 @@ static void pitch_synch_par_reset(klatt_frame_ptr frame)
static long skew;
static short B0[224] = {
1200, 1142, 1088, 1038, 991, 948, 907, 869, 833, 799, 768, 738, 710, 683, 658,
634, 612, 590, 570, 551, 533, 515, 499, 483, 468, 454, 440, 427, 415, 403,
391, 380, 370, 360, 350, 341, 332, 323, 315, 307, 300, 292, 285, 278, 272,
265, 259, 253, 247, 242, 237, 231, 226, 221, 217, 212, 208, 204, 199, 195,
192, 188, 184, 180, 177, 174, 170, 167, 164, 161, 158, 155, 153, 150, 147,
145, 142, 140, 137, 135, 133, 131, 128, 126, 124, 122, 120, 119, 117, 115,
113, 111, 110, 108, 106, 105, 103, 102, 100, 99, 97, 96, 95, 93, 92, 91, 90,
88, 87, 86, 85, 84, 83, 82, 80, 79, 78, 77, 76, 75, 75, 74, 73, 72, 71,
70, 69, 68, 68, 67, 66, 65, 64, 64, 63, 62, 61, 61, 60, 59, 59, 58, 57,
57, 56, 56, 55, 55, 54, 54, 53, 53, 52, 52, 51, 51, 50, 50, 49, 49, 48, 48,
47, 47, 46, 46, 45, 45, 44, 44, 43, 43, 42, 42, 41, 41, 41, 41, 40, 40,
39, 39, 38, 38, 38, 38, 37, 37, 36, 36, 36, 36, 35, 35, 35, 35, 34, 34, 33,
33, 33, 33, 32, 32, 32, 32, 31, 31, 31, 31, 30, 30, 30, 30, 29, 29, 29, 29,
28, 28, 28, 28, 27, 27
634, 612, 590, 570, 551, 533, 515, 499, 483, 468, 454, 440, 427, 415, 403,
391, 380, 370, 360, 350, 341, 332, 323, 315, 307, 300, 292, 285, 278, 272,
265, 259, 253, 247, 242, 237, 231, 226, 221, 217, 212, 208, 204, 199, 195,
192, 188, 184, 180, 177, 174, 170, 167, 164, 161, 158, 155, 153, 150, 147,
145, 142, 140, 137, 135, 133, 131, 128, 126, 124, 122, 120, 119, 117, 115,
113, 111, 110, 108, 106, 105, 103, 102, 100, 99, 97, 96, 95, 93, 92, 91, 90,
88, 87, 86, 85, 84, 83, 82, 80, 79, 78, 77, 76, 75, 75, 74, 73, 72, 71,
70, 69, 68, 68, 67, 66, 65, 64, 64, 63, 62, 61, 61, 60, 59, 59, 58, 57,
57, 56, 56, 55, 55, 54, 54, 53, 53, 52, 52, 51, 51, 50, 50, 49, 49, 48, 48,
47, 47, 46, 46, 45, 45, 44, 44, 43, 43, 42, 42, 41, 41, 41, 41, 40, 40,
39, 39, 38, 38, 38, 38, 37, 37, 36, 36, 36, 36, 35, 35, 35, 35, 34, 34, 33,
33, 33, 33, 32, 32, 32, 32, 31, 31, 31, 31, 30, 30, 30, 30, 29, 29, 29, 29,
28, 28, 28, 28, 27, 27
};

if (frame->F0hz10 > 0) {
/* T0 is 4* the number of samples in one pitch period */
// T0 is 4* the number of samples in one pitch period

kt_globals.T0 = (40 * kt_globals.samrate) / frame->F0hz10;


kt_globals.amp_voice = DBtoLIN(frame->AVdb_tmp);

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

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

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

kt_globals.amp_breth = DBtoLIN(frame->Aturb) * 0.1;

/* Set open phase of glottal period where 40 <= open phase <= 263 */
// Set open phase of glottal period where 40 <= open phase <= 263

kt_globals.nopen = 4 * frame->Kopen;

@@ -675,31 +655,28 @@ static void pitch_synch_par_reset(klatt_frame_ptr frame)
kt_globals.nopen = kt_globals.T0 - 2;

if (kt_globals.nopen < 40) {
/* F0 max = 1000 Hz */
// F0 max = 1000 Hz
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_a = (kt_globals.pulse_shape_b * kt_globals.nopen) * 0.333;

/* Reset width of "impulsive" glottal pulse */
// Reset width of "impulsive" glottal pulse

temp = kt_globals.samrate / kt_globals.nopen;

setabc((long)0, temp, &(kt_globals.rsn[RGL]));

/* Make gain at F1 about constant */
// Make gain at F1 about constant

temp1 = kt_globals.nopen *.00833;
kt_globals.rsn[RGL].a *= temp1 * temp1;

/*
Truncate skewness so as not to exceed duration of closed phase
of glottal period.
*/

// Truncate skewness so as not to exceed duration of closed phase
// of glottal period.

temp = kt_globals.T0 - kt_globals.nopen;
if (frame->Kskew > temp)
@@ -709,11 +686,11 @@ static void pitch_synch_par_reset(klatt_frame_ptr frame)
else
skew = -frame->Kskew;

/* Add skewness to closed portion of voicing period */
// Add skewness to closed portion of voicing period
kt_globals.T0 = kt_globals.T0 + skew;
skew = -skew;
} else {
kt_globals.T0 = 4; /* Default for f0 undefined */
kt_globals.T0 = 4; // Default for f0 undefined
kt_globals.amp_voice = 0.0;
kt_globals.nmod = kt_globals.T0;
kt_globals.amp_breth = 0.0;
@@ -721,10 +698,10 @@ static void pitch_synch_par_reset(klatt_frame_ptr frame)
kt_globals.pulse_shape_b = 0.0;
}

/* Reset these pars pitch synchronously or at update rate if f0=0 */
// Reset these pars pitch synchronously or at update rate if f0=0

if ((kt_globals.T0 != 4) || (kt_globals.ns == 0)) {
/* Set one-pole low-pass filter that tilts glottal source */
// Set one-pole low-pass filter that tilts glottal source

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

@@ -747,18 +724,18 @@ static void setabc(long int f, long int bw, resonator_ptr rp)
double r;
double arg;

/* Let r = exp(-pi bw t) */
// Let r = exp(-pi bw t)
arg = kt_globals.minus_pi_t * bw;
r = exp(arg);

/* Let c = -r**2 */
// Let c = -r**2
rp->c = -(r * r);

/* Let b = r * 2*cos(2 pi f t) */
// Let b = r * 2*cos(2 pi f t)
arg = kt_globals.two_pi_t * f;
rp->b = r * cos(arg) * 2.0;

/* Let a = 1.0 - b - c */
// Let a = 1.0 - b - c
rp->a = 1.0 - rp->b - rp->c;
}

@@ -776,28 +753,28 @@ static void setzeroabc(long int f, long int bw, resonator_ptr rp)

f = -f;

/* First compute ordinary resonator coefficients */
/* Let r = exp(-pi bw t) */
// First compute ordinary resonator coefficients
// Let r = exp(-pi bw t)
arg = kt_globals.minus_pi_t * bw;
r = exp(arg);

/* Let c = -r**2 */
// Let c = -r**2
rp->c = -(r * r);

/* Let b = r * 2*cos(2 pi f t) */
// Let b = r * 2*cos(2 pi f t)
arg = kt_globals.two_pi_t * f;
rp->b = r * cos(arg) * 2.;

/* Let a = 1.0 - b - c */
// Let a = 1.0 - b - c
rp->a = 1.0 - rp->b - rp->c;

/* Now convert to antiresonator coefficients (a'=1/a, b'=b/a, c'=c/a) */
/* If f == 0 then rp->a gets set to 0 which makes a'=1/a set a', b' and c' to
* INF, causing an audible sound spike when triggered (e.g. apiration with the
* nasal register set to f=0, bw=0).
*/
// Now convert to antiresonator coefficients (a'=1/a, b'=b/a, c'=c/a)
// If f == 0 then rp->a gets set to 0 which makes a'=1/a set a', b' and c' to
// INF, causing an audible sound spike when triggered (e.g. apiration with the
// nasal register set to f=0, bw=0).
if (rp->a != 0) {
/* Now convert to antiresonator coefficients (a'=1/a, b'=b/a, c'=c/a) */
// Now convert to antiresonator coefficients (a'=1/a, b'=b/a, c'=c/a)
rp->a = 1.0 / rp->a;
rp->c *= -rp->a;
rp->b *= -rp->a;
@@ -847,15 +824,15 @@ static double gen_noise(double noise)
static double DBtoLIN(long dB)
{
static short amptable[88] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 7,
8, 9, 10, 11, 13, 14, 16, 18, 20, 22, 25, 28, 32,
35, 40, 45, 51, 57, 64, 71, 80, 90, 101, 114, 128,
142, 159, 179, 202, 227, 256, 284, 318, 359, 405,
455, 512, 568, 638, 719, 881, 911, 1024, 1137, 1276,
1438, 1622, 1823, 2048, 2273, 2552, 2875, 3244, 3645,
4096, 4547, 5104, 5751, 6488, 7291, 8192, 9093, 10207,
11502, 12976, 14582, 16384, 18350, 20644, 23429,
26214, 29491, 32767
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 7,
8, 9, 10, 11, 13, 14, 16, 18, 20, 22, 25, 28, 32,
35, 40, 45, 51, 57, 64, 71, 80, 90, 101, 114, 128,
142, 159, 179, 202, 227, 256, 284, 318, 359, 405,
455, 512, 568, 638, 719, 881, 911, 1024, 1137, 1276,
1438, 1622, 1823, 2048, 2273, 2552, 2875, 3244, 3645,
4096, 4547, 5104, 5751, 6488, 7291, 8192, 9093, 10207,
11502, 12976, 14582, 16384, 18350, 20644, 23429,
26214, 29491, 32767
};

if ((dB < 0) || (dB > 87))
@@ -939,14 +916,14 @@ int Wavegen_Klatt(int resume)
if (kt_globals.nspfr > STEPSIZE)
kt_globals.nspfr = STEPSIZE;

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

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

if (end_wave > 0) {
fade = 64; // not followd by formant synthesis
fade = 64; // not followed by formant synthesis

// fade out to avoid a click
kt_globals.fadeout = fade;
@@ -954,7 +931,7 @@ int Wavegen_Klatt(int resume)
sample_count -= fade;
kt_globals.nspfr = fade;
if (parwave(&kt_frame) == 1)
return 1; // output buffer is full
return 1; // output buffer is full
}

return 0;
@@ -979,7 +956,7 @@ void SetSynth_Klatt(int length, int modn, frame_t *fr1, frame_t *fr2, voice_t *v

end_wave = 0;
if (control & 2)
end_wave = 1; // fadeout at the end
end_wave = 1; // fadeout at the end
if (control & 1) {
end_wave = 1;
for (qix = wcmdq_head+1;; qix++) {
@@ -988,7 +965,7 @@ void SetSynth_Klatt(int length, int modn, frame_t *fr1, frame_t *fr2, voice_t *v

cmd = wcmdq[qix][0];
if (cmd == WCMD_KLATT) {
end_wave = 0; // next wave generation is from another spectrum
end_wave = 0; // next wave generation is from another spectrum

fr3 = (frame_t *)wcmdq[qix][2];
for (ix = 1; ix < 6; ix++) {
@@ -1001,7 +978,7 @@ void SetSynth_Klatt(int length, int modn, frame_t *fr1, frame_t *fr2, voice_t *v
break;
}
if ((cmd == WCMD_WAVE) || (cmd == WCMD_PAUSE))
break; // next is not from spectrum, so continue until end of wave cycle
break; // next is not from spectrum, so continue until end of wave cycle
}
}

@@ -1047,7 +1024,7 @@ void SetSynth_Klatt(int length, int modn, frame_t *fr1, frame_t *fr2, voice_t *v
// nasal zero frequency
peaks[0].freq1 = fr1->klattp[KLATT_FNZ] * 2;
if (peaks[0].freq1 == 0)
peaks[0].freq1 = kt_frame.Fhz[F_NP]; // if no nasal zero, set it to same freq as nasal pole
peaks[0].freq1 = kt_frame.Fhz[F_NP]; // if no nasal zero, set it to same freq as nasal pole

peaks[0].freq = (int)peaks[0].freq1;
next = fr2->klattp[KLATT_FNZ] * 2;
@@ -1063,12 +1040,12 @@ void SetSynth_Klatt(int length, int modn, frame_t *fr1, frame_t *fr2, voice_t *v
if (fr1->frflags & FRFLAG_KLATT) {
// the frame contains additional parameters for parallel resonators
for (ix = 1; ix < 7; ix++) {
peaks[ix].bp1 = fr1->klatt_bp[ix] * 4; // parallel bandwidth
peaks[ix].bp1 = fr1->klatt_bp[ix] * 4; // parallel bandwidth
peaks[ix].bp = (int)peaks[ix].bp1;
next = fr2->klatt_bp[ix] * 4;
peaks[ix].bp_inc = ((next - peaks[ix].bp1) * STEPSIZE) / length;

peaks[ix].ap1 = fr1->klatt_ap[ix]; // parallal amplitude
peaks[ix].ap1 = fr1->klatt_ap[ix]; // parallal amplitude
peaks[ix].ap = (int)peaks[ix].ap1;
next = fr2->klatt_ap[ix];
peaks[ix].ap_inc = ((next - peaks[ix].ap1) * STEPSIZE) / length;
@@ -1099,7 +1076,7 @@ void KlattInit()
kt_globals.synthesis_model = CASCADE_PARALLEL;
kt_globals.samrate = 22050;

kt_globals.glsource = IMPULSIVE; // IMPULSIVE, NATURAL, SAMPLED
kt_globals.glsource = IMPULSIVE;
kt_globals.scale_wav = scale_wav_tab[kt_globals.glsource];
kt_globals.natural_samples = natural_samples;
kt_globals.num_samples = NUMBER_OF_SAMPLES;
@@ -1120,14 +1097,14 @@ void KlattInit()
kt_frame.Bhz_next[F_NZ] = bandwidth[F_NZ];

kt_frame.F0hz10 = 1000;
kt_frame.AVdb = 59; // 59
kt_frame.AVdb = 59;
kt_frame.ASP = 0;
kt_frame.Kopen = 40; // 40
kt_frame.Kopen = 40;
kt_frame.Aturb = 0;
kt_frame.TLTdb = 0;
kt_frame.AF = 50;
kt_frame.Kskew = 0;
kt_frame.AB = 0;
kt_frame.AVpdb = 0;
kt_frame.Gain0 = 62; // 60
kt_frame.Gain0 = 62;
}

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

@@ -59,7 +59,7 @@ struct datablock {
struct datablock *next;
int done;
int size;
char buffer[1]; /* 1 or more, dynamically allocated */
char buffer[1]; // 1 or more, dynamically allocated
};

static struct datablock *mbr_pending_data_head, *mbr_pending_data_tail;
@@ -296,24 +296,24 @@ static int mbrola_has_errors(void)
}

if (result == 0) {
/* EOF on stderr, assume mbrola died. */
// EOF on stderr, assume mbrola died.
return mbrola_died();
}

buf_ptr[result] = 0;

for (; (lf = strchr(buf_ptr, '\n')); buf_ptr = lf + 1) {
/* inhibit the reset signal messages */
// inhibit the reset signal messages
if (strncmp(buf_ptr, "Got a reset signal", 18) == 0 ||
strncmp(buf_ptr, "Input Flush Signal", 18) == 0)
continue;
*lf = 0;
log("mbrola: %s", buf_ptr);
/* is this the last line? */
// is this the last line?
if (lf == &buf_ptr[result - 1]) {
snprintf(mbr_errorbuf, sizeof(mbr_errorbuf),
"%s", buf_ptr);
/* don't consider this fatal at this point */
// don't consider this fatal at this point
return 0;
}
}
@@ -369,9 +369,9 @@ static int send_to_mbrola(const char *cmd)
static int mbrola_is_idle(void)
{
char *p;
char buffer[20]; /* looking for "12345 (mbrola) S" so 20 is plenty*/
char buffer[20]; // looking for "12345 (mbrola) S" so 20 is plenty

/* look in /proc to determine if mbrola is still running or sleeping */
// look in /proc to determine if mbrola is still running or sleeping
if (lseek(mbr_proc_stat, 0, SEEK_SET) != 0)
return 0;
if (read(mbr_proc_stat, buffer, sizeof(buffer)) != sizeof(buffer))
@@ -494,7 +494,7 @@ int init_MBR(const char *voice_path)
return -1;
}

/* we should actually be getting only 44 bytes */
// we should actually be getting only 44 bytes
result = receive_from_mbrola(wavhdr, 45);
if (result != 44) {
if (result >= 0)
@@ -503,7 +503,7 @@ int init_MBR(const char *voice_path)
return -1;
}

/* parse wavhdr to get mbrola voice samplerate */
// parse wavhdr to get mbrola voice samplerate
if (memcmp(wavhdr, "RIFF", 4) != 0 ||
memcmp(wavhdr+8, "WAVEfmt ", 8) != 0) {
err("mbrola did not return a .wav header");
@@ -512,9 +512,8 @@ int init_MBR(const char *voice_path)
}
mbr_samplerate = wavhdr[24] + (wavhdr[25]<<8) +
(wavhdr[26]<<16) + (wavhdr[27]<<24);
// log("mbrowrap: voice samplerate = %d", mbr_samplerate);

/* remember the voice path for setVolumeRatio_MBR() */
// remember the voice path for setVolumeRatio_MBR()
if (mbr_voice_path != voice_path) {
free(mbr_voice_path);
mbr_voice_path = strdup(voice_path);

+ 163
- 157
src/libespeak-ng/numbers.c View File

@@ -64,7 +64,7 @@
#define M_RETROFLEX 20
#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

static int n_digit_lookup;
@@ -109,17 +109,16 @@ static ACCENTS accents_tab[] = {
#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 L_ALPHA 60 // U+3B1
#define L_SCHWA 61 // U+259
#define L_OPEN_E 62 // U+25B
#define L_GAMMA 63 // U+3B3
#define L_IOTA 64 // U+3B9
#define L_OE 65 // U+153
#define L_OMEGA 66 // U+3C9

#define L_ALPHA 60 // U+3B1
#define L_SCHWA 61 // U+259
#define L_OPEN_E 62 // U+25B
#define L_GAMMA 63 // U+3B3
#define L_IOTA 64 // U+3B9
#define L_OE 65 // U+153
#define L_OMEGA 66 // U+3C9

#define L_PHI 67 // U+3C6
#define L_ESH 68 // U+283
#define L_PHI 67 // U+3C6
#define L_ESH 68 // U+283
#define L_UPSILON 69 // U+3C5
#define L_EZH 70 // U+292
#define L_GLOTTAL 71 // U+294
@@ -127,13 +126,14 @@ static ACCENTS accents_tab[] = {
#define L_RLONG 73 // U+27C

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

// characters U+00e0 to U+017f
static const unsigned short letter_accents_0e0[] = {
LETTER('a', M_GRAVE, 0), // U+00e0
LETTER('a', M_GRAVE, 0), // U+00e0
LETTER('a', M_ACUTE, 0),
LETTER('a', M_CIRCUMFLEX, 0),
LETTER('a', M_TILDE, 0),
@@ -149,23 +149,23 @@ static const unsigned short letter_accents_0e0[] = {
LETTER('i', M_ACUTE, 0),
LETTER('i', M_CIRCUMFLEX, 0),
LETTER('i', M_DIAERESIS, 0),
LETTER('d', M_NAME, 0), // eth // U+00f0
LETTER('d', M_NAME, 0), // eth U+00f0
LETTER('n', M_TILDE, 0),
LETTER('o', M_GRAVE, 0),
LETTER('o', M_ACUTE, 0),
LETTER('o', M_CIRCUMFLEX, 0),
LETTER('o', M_TILDE, 0),
LETTER('o', M_DIAERESIS, 0),
0, // division sign
0, // division sign
LETTER('o', M_STROKE, 0),
LETTER('u', M_GRAVE, 0),
LETTER('u', M_ACUTE, 0),
LETTER('u', M_CIRCUMFLEX, 0),
LETTER('u', M_DIAERESIS, 0),
LETTER('y', M_ACUTE, 0),
LETTER('t', M_NAME, 0), // thorn
LETTER('t', M_NAME, 0), // thorn
LETTER('y', M_DIAERESIS, 0),
CAPITAL, // U+0100
CAPITAL, // U+0100
LETTER('a', M_MACRON, 0),
CAPITAL,
LETTER('a', M_BREVE, 0),
@@ -181,7 +181,7 @@ static const unsigned short letter_accents_0e0[] = {
LETTER('c', M_CARON, 0),
CAPITAL,
LETTER('d', M_CARON, 0),
CAPITAL, // U+0110
CAPITAL, // U+0110
LETTER('d', M_STROKE, 0),
CAPITAL,
LETTER('e', M_MACRON, 0),
@@ -197,7 +197,7 @@ static const unsigned short letter_accents_0e0[] = {
LETTER('g', M_CIRCUMFLEX, 0),
CAPITAL,
LETTER('g', M_BREVE, 0),
CAPITAL, // U+0120
CAPITAL, // U+0120
LETTER('g', M_DOT_ABOVE, 0),
CAPITAL,
LETTER('g', M_CEDILLA, 0),
@@ -213,7 +213,7 @@ static const unsigned short letter_accents_0e0[] = {
LETTER('i', M_BREVE, 0),
CAPITAL,
LETTER('i', M_OGONEK, 0),
CAPITAL, // U+0130
CAPITAL, // U+0130
LETTER('i', M_NAME, 0), // dotless i
CAPITAL,
LIGATURE('i', 'j', 0),
@@ -221,7 +221,7 @@ static const unsigned short letter_accents_0e0[] = {
LETTER('j', M_CIRCUMFLEX, 0),
CAPITAL,
LETTER('k', M_CEDILLA, 0),
LETTER('k', M_NAME, 0), // kra
LETTER('k', M_NAME, 0), // kra
CAPITAL,
LETTER('l', M_ACUTE, 0),
CAPITAL,
@@ -229,7 +229,7 @@ static const unsigned short letter_accents_0e0[] = {
CAPITAL,
LETTER('l', M_CARON, 0),
CAPITAL,
LETTER('l', M_MIDDLE_DOT, 0), // U+0140
LETTER('l', M_MIDDLE_DOT, 0), // U+0140
CAPITAL,
LETTER('l', M_STROKE, 0),
CAPITAL,
@@ -238,14 +238,14 @@ static const unsigned short letter_accents_0e0[] = {
LETTER('n', M_CEDILLA, 0),
CAPITAL,
LETTER('n', M_CARON, 0),
LETTER('n', M_NAME, 0), // apostrophe n
LETTER('n', M_NAME, 0), // apostrophe n
CAPITAL,
LETTER('n', M_NAME, 0), // eng
LETTER('n', M_NAME, 0), // eng
CAPITAL,
LETTER('o', M_MACRON, 0),
CAPITAL,
LETTER('o', M_BREVE, 0),
CAPITAL, // U+0150
CAPITAL, // U+0150
LETTER('o', M_DOUBLE_ACUTE, 0),
CAPITAL,
LIGATURE('o', 'e', 0),
@@ -261,7 +261,7 @@ static const unsigned short letter_accents_0e0[] = {
LETTER('s', M_CIRCUMFLEX, 0),
CAPITAL,
LETTER('s', M_CEDILLA, 0),
CAPITAL, // U+0160
CAPITAL, // U+0160
LETTER('s', M_CARON, 0),
CAPITAL,
LETTER('t', M_CEDILLA, 0),
@@ -277,7 +277,7 @@ static const unsigned short letter_accents_0e0[] = {
LETTER('u', M_BREVE, 0),
CAPITAL,
LETTER('u', M_RING, 0),
CAPITAL, // U+0170
CAPITAL, // U+0170
LETTER('u', M_DOUBLE_ACUTE, 0),
CAPITAL,
LETTER('u', M_OGONEK, 0),
@@ -285,43 +285,43 @@ static const unsigned short letter_accents_0e0[] = {
LETTER('w', M_CIRCUMFLEX, 0),
CAPITAL,
LETTER('y', M_CIRCUMFLEX, 0),
CAPITAL, // Y-DIAERESIS
CAPITAL, // Y-DIAERESIS
CAPITAL,
LETTER('z', M_ACUTE, 0),
CAPITAL,
LETTER('z', M_DOT_ABOVE, 0),
CAPITAL,
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
static const unsigned short letter_accents_250[] = {
LETTER('a', M_TURNED, 0), // U+250
LETTER('a', M_TURNED, 0), // U+250
LETTER(L_ALPHA, 0, 0),
LETTER(L_ALPHA, M_TURNED, 0),
LETTER('b', M_IMPLOSIVE, 0),
0, // open-o
0, // open-o
LETTER('c', M_CURL, 0),
LETTER('d', M_RETROFLEX, 0),
LETTER('d', M_IMPLOSIVE, 0),
LETTER('e', M_REVERSED, 0), // U+258
0, // schwa
LETTER('e', M_REVERSED, 0), // U+258
0, // schwa
LETTER(L_SCHWA, M_HOOK, 0),
0, // open-e
0, // open-e
LETTER(L_OPEN_E, M_REVERSED, 0),
LETTER(L_OPEN_E, M_HOOK, M_REVERSED),
0,
LETTER('j', M_BAR, 0),
LETTER('g', M_IMPLOSIVE, 0), // U+260
LETTER('g', M_IMPLOSIVE, 0), // U+260
LETTER('g', 0, 0),
LETTER('g', M_SMALLCAP, 0),
LETTER(L_GAMMA, 0, 0),
0, // ramshorn
0, // ramshorn
LETTER('h', M_TURNED, 0),
LETTER('h', M_HOOK, 0),
0,
LETTER('i', M_BAR, 0), // U+268
LETTER('i', M_BAR, 0), // U+268
LETTER(L_IOTA, 0, 0),
LETTER('i', M_SMALLCAP, 0),
LETTER('l', M_TILDE, 0),
@@ -337,23 +337,23 @@ static const unsigned short letter_accents_250[] = {
LETTER('o', M_BAR, 0),
LIGATURE('o', 'e', M_SMALLCAP),
0,
LETTER(L_PHI, 0, 0), // U+278
LETTER(L_PHI, 0, 0), // U+278
LETTER('r', M_TURNED, 0),
LETTER(L_RLONG, M_TURNED, 0),
LETTER('r', M_RETROFLEX, M_TURNED),
0,
LETTER('r', M_RETROFLEX, 0),
0, // r-tap
0, // r-tap
LETTER(L_RTAP, M_REVERSED, 0),
LETTER('r', M_SMALLCAP, 0), // U+280
LETTER('r', M_SMALLCAP, 0), // U+280
LETTER('r', M_TURNED, M_SMALLCAP),
LETTER('s', M_RETROFLEX, 0),
0, // esh
0, // esh
LETTER('j', M_HOOK, 0),
LETTER(L_ESH, M_REVERSED, 0),
LETTER(L_ESH, M_CURL, 0),
LETTER('t', M_TURNED, 0),
LETTER('t', M_RETROFLEX, 0), // U+288
LETTER('t', M_RETROFLEX, 0), // U+288
LETTER('u', M_BAR, 0),
LETTER(L_UPSILON, 0, 0),
LETTER('v', M_HOOK, 0),
@@ -361,15 +361,15 @@ static const unsigned short letter_accents_250[] = {
LETTER('w', M_TURNED, 0),
LETTER('y', M_TURNED, 0),
LETTER('y', M_SMALLCAP, 0),
LETTER('z', M_RETROFLEX, 0), // U+290
LETTER('z', M_RETROFLEX, 0), // U+290
LETTER('z', M_CURL, 0),
0, // ezh
0, // ezh
LETTER(L_EZH, M_CURL, 0),
0, // glottal stop
0, // glottal stop
LETTER(L_GLOTTAL, M_REVERSED, 0),
LETTER(L_GLOTTAL, M_TURNED, 0),
0,
0, // bilabial click // U+298
0, // bilabial click U+298
LETTER('b', M_SMALLCAP, 0),
0,
LETTER('g', M_IMPLOSIVE, M_SMALLCAP),
@@ -377,14 +377,14 @@ static const unsigned short letter_accents_250[] = {
LETTER('j', M_CURL, 0),
LETTER('k', M_TURNED, 0),
LETTER('l', M_SMALLCAP, 0),
LETTER('q', M_HOOK, 0), // U+2a0
LETTER('q', M_HOOK, 0), // U+2a0
LETTER(L_GLOTTAL, M_STROKE, 0),
LETTER(L_GLOTTAL, M_STROKE, M_REVERSED),
LIGATURE('d', 'z', 0),
0, // dezh
0, // dezh
LIGATURE('d', 'z', M_CURL),
LIGATURE('t', 's', 0),
0, // tesh
0, // tesh
LIGATURE('t', 's', M_CURL),
};

@@ -476,7 +476,7 @@ void LookupAccentedLetter(Translator *tr, unsigned int letter, char *ph_buf)

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

int len;
static char single_letter[10] = { 0, 0 };
@@ -494,18 +494,18 @@ void LookupLetter(Translator *tr, unsigned int letter, int next_byte, char *ph_b

single_letter[1] = '_';
if (Lookup(tr, &single_letter[1], ph_buf3) != 0)
return; // the character is specified as _* so ignore it when speaking normal text
return; // the character is specified as _* so ignore it when speaking normal text

// check whether this character is specified for English
if (tr->translator_name == L('e', 'n'))
return; // we are already using English
return; // we are already using English

SetTranslator2("en");
if (Lookup(translator2, &single_letter[2], ph_buf3) != 0) {
// yes, switch to English and re-translate the word
sprintf(ph_buf1, "%c", phonSWITCH);
}
SelectPhonemeTable(voice->phoneme_tab_ix); // revert to original phoneme table
SelectPhonemeTable(voice->phoneme_tab_ix); // revert to original phoneme table
return;
}

@@ -518,7 +518,7 @@ void LookupLetter(Translator *tr, unsigned int letter, int next_byte, char *ph_b

if (next_byte != ' ')
next_byte = RULE_SPELLING;
single_letter[3+len] = next_byte; // follow by space-space if the end of the word, or space-31
single_letter[3+len] = next_byte; // follow by space-space if the end of the word, or space-31

single_letter[1] = '_';

@@ -543,31 +543,31 @@ void LookupLetter(Translator *tr, unsigned int letter, int next_byte, char *ph_b
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 (these must be in ascending order)
static const int number_ranges[] = {
0x660, 0x6f0, // arabic
0x966, 0x9e6, 0xa66, 0xae6, 0xb66, 0xbe6, 0xc66, 0xce6, 0xd66, // indic
0x660, 0x6f0, // arabic
0x966, 0x9e6, 0xa66, 0xae6, 0xb66, 0xbe6, 0xc66, 0xce6, 0xd66, // indic
0xe50, 0xed0, 0xf20, 0x1040, 0x1090,
0
}; // these must be in ascending order
};

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)
const int *p;
int base;

for (p = number_ranges; (base = *p) != 0; p++) {
if (letter < base)
break; // not found
break; // not found
if (letter < (base+10))
return letter-base+'0';
}
return -1;
}

#define L_SUB 0x4000 // subscript
#define L_SUP 0x8000 // superscript
#define L_SUB 0x4000 // subscript
#define L_SUP 0x8000 // superscript

static const char *modifiers[] = { NULL, "_sub", "_sup", NULL };

@@ -638,11 +638,19 @@ static unsigned short derived_letters[] = {
0, 0
};

static const char *hex_letters[] = { "'e:j", "b'i:", "s'i:", "d'i:", "'i:", "'ef" }; // names, using phonemes available to all languages
// names, using phonemes available to all languages
static const char *hex_letters[] = {
"'e:j",
"b'i:",
"s'i:",
"d'i:",
"'i:",
"'ef"
};

int IsSuperscript(int letter)
{
// is this a subscript or superscript letter ?
// is this a subscript or superscript letter ?
int ix;
int c;

@@ -657,11 +665,11 @@ int IsSuperscript(int letter)

int TranslateLetter(Translator *tr, char *word, char *phonemes, int control)
{
// get pronunciation for an isolated letter
// return number of bytes used by the letter
// control bit 0: a non-initial letter in a word
// bit 1: say 'capital'
// bit 2: say character code for unknown letters
// get pronunciation for an isolated letter
// return number of bytes used by the letter
// control bit 0: a non-initial letter in a word
// bit 1: say 'capital'
// bit 2: say character code for unknown letters

int n_bytes;
int letter;
@@ -693,7 +701,7 @@ int TranslateLetter(Translator *tr, char *word, char *phonemes, int control)
n_bytes = utf8_in(&letter, word);

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

if (control & 2) {
// include CAPITAL information
@@ -711,7 +719,7 @@ int TranslateLetter(Translator *tr, char *word, char *phonemes, int control)
// don't say "superscript" during normal text reading
Lookup(tr, modifier, capital);
if (capital[0] == 0) {
capital[2] = SetTranslator2("en"); // overwrites previous contents of translator2
capital[2] = SetTranslator2("en"); // overwrites previous contents of translator2
Lookup(translator2, modifier, &capital[3]);
if (capital[3] != 0) {
capital[0] = phonPAUSE;
@@ -755,7 +763,7 @@ int TranslateLetter(Translator *tr, char *word, char *phonemes, int control)
ph_buf2[0] = 0;
if (Lookup(translator, alphabet->name, ph_alphabet) == 0) { // the original language for the current voice
// Can't find the local name for this alphabet, use the English name
ph_alphabet[2] = SetTranslator2("en"); // overwrites previous contents of translator2
ph_alphabet[2] = SetTranslator2("en"); // overwrites previous contents of translator2
Lookup(translator2, alphabet->name, ph_buf2);
} else if (translator != tr) {
phontab_1 = tr->phoneme_tab_ix;
@@ -777,7 +785,7 @@ int TranslateLetter(Translator *tr, char *word, char *phonemes, int control)
}
}

// 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 ((al_offset != 0) && (al_offset == translator->langopts.alt_alphabet))
@@ -805,8 +813,8 @@ int TranslateLetter(Translator *tr, char *word, char *phonemes, int control)
if ((initial = (code/28)/21) != 11) {
p3 += utf8_out(initial + 0x1100, p3);
}
utf8_out(((code/28) % 21) + 0x1161, p3); // medial
utf8_out((code % 28) + 0x11a7, &p3[3]); // final
utf8_out(((code/28) % 21) + 0x1161, p3); // medial
utf8_out((code % 28) + 0x11a7, &p3[3]); // final
p3[6] = ' ';
p3[7] = 0;
ph_buf[3] = 0;
@@ -821,13 +829,13 @@ int TranslateLetter(Translator *tr, char *word, char *phonemes, int control)
LookupLetter(translator2, letter, word[n_bytes], &ph_buf[3], control & 1);
}

SelectPhonemeTable(voice->phoneme_tab_ix); // revert to original phoneme table
SelectPhonemeTable(voice->phoneme_tab_ix); // revert to original phoneme table

if (ph_buf[3] != 0) {
ph_buf[0] = phonPAUSE;
ph_buf[1] = phonSWITCH;
len = strlen(&ph_buf[3]) + 3;
ph_buf[len] = phonSWITCH; // switch back
ph_buf[len] = phonSWITCH; // switch back
ph_buf[len+1] = tr->phoneme_tab_ix;
ph_buf[len+2] = 0;
}
@@ -890,16 +898,15 @@ int TranslateLetter(Translator *tr, char *word, char *phonemes, int control)
if (tr->langopts.accents & 2) // 'capital' before or after the word ?
sprintf(ph_buf2, "%c%s%s%s", 0xff, ph_alphabet, ph_buf, capital);
else
sprintf(ph_buf2, "%c%s%s%s", 0xff, ph_alphabet, capital, ph_buf); // the 0xff marker will be removed or replaced in SetSpellingStress()
if ((len + strlen(ph_buf2)) < N_WORD_PHONEMES) {
sprintf(ph_buf2, "%c%s%s%s", 0xff, ph_alphabet, capital, ph_buf); // the 0xff marker will be removed or replaced in SetSpellingStress()
if ((len + strlen(ph_buf2)) < N_WORD_PHONEMES)
strcpy(&phonemes[len], ph_buf2);
}
return n_bytes;
}

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.
int ix;
unsigned int c;
int n_stress = 0;
@@ -927,17 +934,17 @@ void SetSpellingStress(Translator *tr, char *phonemes, int control, int n_chars)
} else {
if (count != n_stress) {
if (((count % 3) != 0) || (count == n_stress-1))
c = phonSTRESS_3; // reduce to secondary stress
c = phonSTRESS_3; // reduce to secondary stress
}
}
} else if (c == 0xff) {
if ((control < 2) || (ix == 0))
continue; // don't insert pauses
continue; // don't insert pauses

if (control == 4)
c = phonPAUSE; // pause after each character
c = phonPAUSE; // pause after each character
if (((count % 3) == 0) || (control > 2))
c = phonPAUSE_NOLINK; // pause following a primary stress
c = phonPAUSE_NOLINK; // pause following a primary stress
else
c = phonPAUSE_VSHORT;
}
@@ -981,14 +988,14 @@ static int CheckDotOrdinal(Translator *tr, char *word, char *word_end, WORD_TAB
nextflags = TranslateWord(tr, &word_end[2], 0, NULL, NULL);

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

if (nextflags & FLAG_ALT_TRANS)
ordinal = 0;

if (nextflags & FLAG_ALT3_TRANS) {
if (word[-2] == '-')
ordinal = 0; // eg. december 2-5. között
ordinal = 0; // e.g. december 2-5. között

if (tr->prev_dict_flags[0] & (FLAG_ALT_TRANS | FLAG_ALT3_TRANS))
ordinal = 0x22;
@@ -1002,14 +1009,14 @@ static int CheckDotOrdinal(Translator *tr, char *word, char *word_end, WORD_TAB

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

if ((word[0] == 'a') || (word[0] == 'e')) {
if ((word[1] == ' ') || (word[1] == 'z') || ((word[1] == 't') && (word[2] == 't')))
return 0;

if (((thousandplex == 1) || ((value % 1000) == 0)) && (word[1] == 'l'))
return 0; // 1000-el
return 0; // 1000-el

return 1;
}
@@ -1044,13 +1051,13 @@ int TranslateRoman(Translator *tr, char *word, char *ph_out, WORD_TAB *wtab)
flags[1] = 0;

if (((tr->langopts.numbers & NUM_ROMAN_CAPITALS) && !(wtab[0].flags & FLAG_ALL_UPPER)) || IsDigit09(word[-2]))
return 0; // not '2xx'
return 0; // not '2xx'

if (word[1] == ' ') {
if ((tr->langopts.numbers & (NUM_ROMAN_CAPITALS | NUM_ROMAN_ORDINAL | NUM_ORDINAL_DOT)) && (wtab[0].flags & FLAG_HAS_DOT)) {
// allow single letter Roman ordinal followed by dot.
} else
return 0; // only one letter, don't speak as a Roman Number
return 0; // only one letter, don't speak as a Roman Number
}

word_start = word;
@@ -1084,7 +1091,7 @@ int TranslateRoman(Translator *tr, char *word, char *ph_out, WORD_TAB *wtab)
}

if (IsDigit09(word[0]))
return 0; // eg. 'xx2'
return 0; // e.g. 'xx2'

acc += prev;
if (acc < tr->langopts.min_roman)
@@ -1093,7 +1100,7 @@ int TranslateRoman(Translator *tr, char *word, char *ph_out, WORD_TAB *wtab)
if (acc > tr->langopts.max_roman)
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];

if ((tr->langopts.numbers & NUM_ROMAN_AFTER) == 0) {
@@ -1145,25 +1152,25 @@ static const char *M_Variant(int value)

switch ((translator->langopts.numbers2 >> 6) & 0x7)
{
case 1: // lang=ru use singular for xx1 except for x11
case 1: // lang=ru use singular for xx1 except for x11
if ((teens == 0) && ((value % 10) == 1))
return "1M";
break;
case 2: // lang=cs,sk
case 2: // lang=cs,sk
if ((value >= 2) && (value <= 4))
return "0MA";
break;
case 3: // lang=pl
case 3: // lang=pl
if ((teens == 0) && (((value % 10) >= 2) && ((value % 10) <= 4)))
return "0MA";
break;
case 4: // lang=lt
case 4: // lang=lt
if ((teens == 1) || ((value % 10) == 0))
return "0MB";
if ((value % 10) == 1)
return "0MA";
break;
case 5: // lang=bs,hr,sr
case 5: // lang=bs,hr,sr
if (teens == 0) {
if ((value % 10) == 1)
return "1M";
@@ -1177,7 +1184,7 @@ static const char *M_Variant(int value)

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
int found;
int found_value = 0;
char string[12];
@@ -1266,15 +1273,15 @@ static int LookupThousands(Translator *tr, int value, int thousandplex, int thou

static int LookupNum2(Translator *tr, int value, int thousandplex, const int control, char *ph_out)
{
// Lookup a 2 digit number
// control bit 0: ordinal number
// control bit 1: final tens and units (not number of thousands) (use special form of '1', LANG=de "eins")
// control bit 2: tens and units only, no higher digits
// control bit 3: use feminine form of '2' (for thousands
// control bit 4: speak zero tens
// control bit 5: variant of ordinal number (lang=hu)
// bit 8 followed by decimal fraction
// bit 9: use #f form for both tens and units (lang=ml)
// Lookup a 2 digit number
// control bit 0: ordinal number
// control bit 1: final tens and units (not number of thousands) (use special form of '1', LANG=de "eins")
// control bit 2: tens and units only, no higher digits
// control bit 3: use feminine form of '2' (for thousands
// control bit 4: speak zero tens
// control bit 5: variant of ordinal number (lang=hu)
// bit 8 followed by decimal fraction
// bit 9: use #f form for both tens and units (lang=ml)

int found;
int ix;
@@ -1285,7 +1292,7 @@ static int LookupNum2(Translator *tr, int value, int thousandplex, const int con
int found_ordinal = 0;
int next_phtype;
int ord_type = 'o';
char string[12]; // for looking up entries in *_list
char string[12]; // for looking up entries in *_list
char ph_ordinal[20];
char ph_tens[50];
char ph_digits[50];
@@ -1322,10 +1329,10 @@ static int LookupNum2(Translator *tr, int value, int thousandplex, const int con
strcpy(ph_ordinal, ph_ordinal2);

if (control & 4) {
sprintf(string, "_%d%cx", value, ord_type); // LANG=hu, special word for 1. 2. when there are no higher digits
sprintf(string, "_%d%cx", value, ord_type); // LANG=hu, special word for 1. 2. when there are no higher digits
if ((found = Lookup(tr, string, ph_digits)) != 0) {
if (ph_ordinal2x[0] != 0)
strcpy(ph_ordinal, ph_ordinal2x); // alternate pronunciation (lang=an)
strcpy(ph_ordinal, ph_ordinal2x); // alternate pronunciation (lang=an)
}
}
if (found == 0) {
@@ -1346,7 +1353,7 @@ static int LookupNum2(Translator *tr, int value, int thousandplex, const int con
} else {
// followed by hundreds or thousands etc
if ((tr->langopts.numbers2 & NUM2_ORDINAL_AND_THOUSANDS) && (thousandplex <= 1))
sprintf(string, "_%do", value); // LANG=TA
sprintf(string, "_%do", value); // LANG=TA
else
sprintf(string, "_%da", value);
found = Lookup(tr, string, ph_digits);
@@ -1369,9 +1376,9 @@ static int LookupNum2(Translator *tr, int value, int thousandplex, const int con
// speak leading zero
Lookup(tr, "_0", ph_tens);
} else {
if (found) {
if (found)
ph_tens[0] = 0;
} else {
else {
if (is_ordinal) {
sprintf(string, "_%dX%c", tens, ord_type);
if (Lookup(tr, string, ph_tens) != 0) {
@@ -1416,9 +1423,8 @@ static int LookupNum2(Translator *tr, int value, int thousandplex, const int con
if ((is_ordinal) && ((tr->langopts.numbers & NUM_SWAP_TENS) == 0)) {
// ordinal
sprintf(string, "_%d%c", units, ord_type);
if ((found = Lookup(tr, string, ph_digits)) != 0) {
if ((found = Lookup(tr, string, ph_digits)) != 0)
found_ordinal = 1;
}
}
if (found == 0) {
if ((number_control & 1) && (control & 2)) {
@@ -1511,11 +1517,12 @@ static int LookupNum2(Translator *tr, int value, int thousandplex, const int con

static int LookupNum3(Translator *tr, int value, char *ph_out, int suppress_null, int thousandplex, int control)
{
// Translate a 3 digit number
// control bit 0, previous thousands
// bit 1, ordinal number
// bit 5 variant form of ordinal number
// bit 8 followed by decimal fraction
// Translate a 3 digit number
// control bit 0, previous thousands
// bit 1, ordinal number
// bit 5 variant form of ordinal number
// bit 8 followed by decimal fraction

int found;
int hundreds;
int tensunits;
@@ -1526,7 +1533,7 @@ static int LookupNum3(Translator *tr, int value, char *ph_out, int suppress_null
int tplex;
int say_zero_hundred = 0;
int say_one_hundred;
char string[12]; // for looking up entries in **_list
char string[12]; // for looking up entries in **_list
char buf1[100];
char buf2[100];
char ph_100[20];
@@ -1544,9 +1551,8 @@ static int LookupNum3(Translator *tr, int value, char *ph_out, int suppress_null
ph_thousands[0] = 0;
ph_thousand_and[0] = 0;

if ((tr->langopts.numbers & NUM_ZERO_HUNDRED) && ((control & 1) || (hundreds >= 10))) {
say_zero_hundred = 1; // lang=vi
}
if ((tr->langopts.numbers & NUM_ZERO_HUNDRED) && ((control & 1) || (hundreds >= 10)))
say_zero_hundred = 1; // lang=vi

if ((hundreds > 0) || say_zero_hundred) {
found = 0;
@@ -1579,14 +1585,14 @@ static int LookupNum3(Translator *tr, int value, char *ph_out, int suppress_null
if (LookupThousands(tr, hundreds / 10, tplex, exact | ordinal, ph_10T) == 0) {
x = 0;
if (tr->langopts.numbers2 & (1 << tplex))
x = 8; // use variant (feminine) for before thousands and millions
x = 8; // use variant (feminine) for before thousands and millions
if (tr->translator_name == L('m', 'l'))
x = 0x208;
LookupNum2(tr, hundreds/10, thousandplex, x, ph_digits);
}

if (tr->langopts.numbers2 & 0x200)
sprintf(ph_thousands, "%s%c%s%c", ph_10T, phonEND_WORD, ph_digits, phonEND_WORD); // say "thousands" before its number, not after
sprintf(ph_thousands, "%s%c%s%c", ph_10T, phonEND_WORD, ph_digits, phonEND_WORD); // say "thousands" before its number, not after
else
sprintf(ph_thousands, "%s%c%s%c", ph_digits, phonEND_WORD, ph_10T, phonEND_WORD);

@@ -1674,18 +1680,18 @@ static int LookupNum3(Translator *tr, int value, char *ph_out, int suppress_null
if ((tensunits != 0) || (suppress_null == 0)) {
x = 0;
if (thousandplex == 0) {
x = 2; // allow "eins" for 1 rather than "ein"
x = 2; // allow "eins" for 1 rather than "ein"
if (ordinal)
x = 3; // ordinal number
x = 3; // ordinal number
if ((value < 100) && !(control & 1))
x |= 4; // tens and units only, no higher digits
x |= 4; // tens and units only, no higher digits
if (ordinal & 0x20)
x |= 0x20; // variant form of ordinal number
x |= 0x20; // variant form of ordinal number
} else if (tr->langopts.numbers2 & (1 << thousandplex))
x = 8; // use variant (feminine) for before thousands and millions
x = 8; // use variant (feminine) for before thousands and millions

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

if ((tr->langopts.numbers2 & NUM2_ZERO_TENS) && ((control & 1) || (hundreds > 0))) {
// LANG=zh,
@@ -1694,13 +1700,13 @@ static int LookupNum3(Translator *tr, int value, char *ph_out, int suppress_null

if (LookupNum2(tr, tensunits, thousandplex, x | (control & 0x100), buf2) != 0) {
if (tr->langopts.numbers & NUM_SINGLE_AND)
ph_hundred_and[0] = 0; // don't put 'and' after 'hundred' if there's 'and' between tens and units
ph_hundred_and[0] = 0; // don't put 'and' after 'hundred' if there's 'and' between tens and units
}
} else {
if (ph_ordinal2[0] != 0) {
ix = strlen(buf1);
if ((ix > 0) && (buf1[ix-1] == phonPAUSE_SHORT))
buf1[ix-1] = 0; // remove pause before addding ordinal suffix
buf1[ix-1] = 0; // remove pause before addding ordinal suffix
strcpy(buf2, ph_ordinal2);
}
}
@@ -1712,7 +1718,7 @@ static int LookupNum3(Translator *tr, int value, char *ph_out, int suppress_null

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?
int ix;

if (IsDigit09(word[group_len]) || IsDigit09(-1))
@@ -1727,9 +1733,9 @@ bool CheckThousandsGroup(char *word, int group_len)

static int TranslateNumber_1(Translator *tr, char *word, char *ph_out, unsigned int *flags, WORD_TAB *wtab, int control)
{
// Number translation with various options
// the "word" may be up to 4 digits
// "words" of 3 digits may be preceded by another number "word" for thousands or millions
// Number translation with various options
// the "word" may be up to 4 digits
// "words" of 3 digits may be preceded by another number "word" for thousands or millions

int n_digits;
int value;
@@ -1752,13 +1758,13 @@ static int TranslateNumber_1(Translator *tr, char *word, char *ph_out, unsigned
int group_len;
int len;
char *p;
char string[32]; // for looking up entries in **_list
char string[32]; // for looking up entries in **_list
char buf1[100];
char ph_append[50];
char ph_buf[200];
char ph_buf2[50];
char ph_zeros[50];
char suffix[30]; // string[] must be long enough for sizeof(suffix)+2
char suffix[30]; // string[] must be long enough for sizeof(suffix)+2
char buf_digit_lookup[50];

static const char str_pause[2] = { phonPAUSE_NOLINK, 0 };
@@ -1778,9 +1784,9 @@ static int TranslateNumber_1(Translator *tr, char *word, char *ph_out, unsigned
group_len = 4;

// is there a previous thousands part (as a previous "word") ?
if ((n_digits == group_len) && (word[-2] == tr->langopts.thousands_sep) && IsDigit09(word[-3])) {
if ((n_digits == group_len) && (word[-2] == tr->langopts.thousands_sep) && IsDigit09(word[-3]))
prev_thousands = 1;
} else if ((tr->langopts.thousands_sep == ' ') || (tr->langopts.numbers & NUM_ALLOW_SPACE)) {
else if ((tr->langopts.thousands_sep == ' ') || (tr->langopts.numbers & NUM_ALLOW_SPACE)) {
// thousands groups can be separated by spaces
if ((n_digits == 3) && !(wtab->flags & FLAG_MULTIPLE_SPACES) && IsDigit09(word[-2]))
prev_thousands = 1;
@@ -1802,7 +1808,7 @@ static int TranslateNumber_1(Translator *tr, char *word, char *ph_out, unsigned
}

if ((ordinal == 0) || (tr->translator_name == L('h', 'u'))) {
// NOTE lang=hu, allow both dot and ordinal suffix, eg. "december 21.-én"
// NOTE lang=hu, allow both dot and ordinal suffix, eg. "december 21.-én"
// look for an ordinal number suffix after the number
ix++;
p = suffix;
@@ -1817,7 +1823,7 @@ static int TranslateNumber_1(Translator *tr, char *word, char *ph_out, unsigned
if (suffix[0] != 0) {
if ((tr->langopts.ordinal_indicator != NULL) && (strcmp(suffix, tr->langopts.ordinal_indicator) == 0))
ordinal = 2;
else if (!IsDigit09(suffix[0])) { // not _#9 (tab)
else if (!IsDigit09(suffix[0])) { // not _#9 (tab)
sprintf(string, "_#%s", suffix);
if (Lookup(tr, string, ph_ordinal2)) {
// this is an ordinal suffix
@@ -1825,7 +1831,7 @@ static int TranslateNumber_1(Translator *tr, char *word, char *ph_out, unsigned
flags[0] |= FLAG_SKIPWORDS;
skipwords = 1;
sprintf(string, "_x#%s", suffix);
Lookup(tr, string, ph_ordinal2x); // is there an alternate pronunciation?
Lookup(tr, string, ph_ordinal2x); // is there an alternate pronunciation?
}
}
}
@@ -1843,7 +1849,7 @@ static int TranslateNumber_1(Translator *tr, char *word, char *ph_out, unsigned
} else {
if (n_digits > 3) {
flags[0] &= ~FLAG_SKIPWORDS;
return 0; // long number string with leading zero, speak as individual digits
return 0; // long number string with leading zero, speak as individual digits
}

// speak leading zeros
@@ -1887,7 +1893,7 @@ static int TranslateNumber_1(Translator *tr, char *word, char *ph_out, unsigned
if (tr->translator_name == L('h', 'u')) {
// variant form of numbers when followed by hyphen and a suffix starting with 'a' or 'e' (but not a, e, az, ez, azt, ezt
if ((wtab[thousandplex].flags & FLAG_HYPHEN_AFTER) && (thousands_exact == 1) && hu_number_e(&word[suffix_ix], thousandplex, value))
number_control |= 1; // use _1e variant of number
number_control |= 1; // use _1e variant of number
}

if ((word[n_digits] == tr->langopts.decimal_sep) && IsDigit09(word[n_digits+1])) {
@@ -1920,7 +1926,7 @@ static int TranslateNumber_1(Translator *tr, char *word, char *ph_out, unsigned
char *p2;
// look for combinations of the number with the next word
p = word;
while (IsDigit09(p[1])) p++; // just use the last digit
while (IsDigit09(p[1])) p++; // just use the last digit
if (IsDigit09(p[-1])) {
p2 = p - 1;
if (LookupDictList(tr, &p2, buf_digit_lookup, flags, FLAG_SUFX, wtab)) // lookup 2 digits
@@ -1959,7 +1965,7 @@ static int TranslateNumber_1(Translator *tr, char *word, char *ph_out, unsigned

LookupNum3(tr, value, ph_buf, suppress_null, thousandplex, prev_thousands | ordinal | decimal_point);
if ((thousandplex > 0) && (tr->langopts.numbers2 & 0x200))
sprintf(ph_out, "%s%s%c%s%s", ph_zeros, ph_append, phonEND_WORD, ph_buf2, ph_buf); // say "thousands" before its number
sprintf(ph_out, "%s%s%c%s%s", ph_zeros, ph_append, phonEND_WORD, ph_buf2, ph_buf); // say "thousands" before its number
else
sprintf(ph_out, "%s%s%s%c%s", ph_zeros, ph_buf2, ph_buf, phonEND_WORD, ph_append);

@@ -1976,7 +1982,7 @@ static int TranslateNumber_1(Translator *tr, char *word, char *ph_out, unsigned
{
case NUM_DFRACTION_4:
max_decimal_count = 5;
// fallthrough
// fallthrough:
case NUM_DFRACTION_2:
// French/Polish decimal fraction
while (word[n_digits] == '0') {
@@ -1991,15 +1997,15 @@ static int TranslateNumber_1(Translator *tr, char *word, char *ph_out, unsigned
n_digits += decimal_count;
}
break;
case NUM_DFRACTION_1: // italian, say "hundredths" if leading zero
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_1: // italian, say "hundredths" if leading zero
case NUM_DFRACTION_5: // hungarian, always say "tenths" etc.
case NUM_DFRACTION_6: // kazakh, always say "tenths" etc, before the decimal fraction
LookupNum3(tr, atoi(&word[n_digits]), ph_buf, 0, 0, 0);
if ((word[n_digits] == '0') || (decimal_mode != NUM_DFRACTION_1)) {
// decimal part has leading zeros, so add a "hundredths" or "thousandths" suffix
sprintf(string, "_0Z%d", decimal_count);
if (Lookup(tr, string, buf1) == 0)
break; // revert to speaking single digits
break; // revert to speaking single digits

if (decimal_mode == NUM_DFRACTION_6)
strcat(ph_out, buf1);
@@ -2056,7 +2062,7 @@ static int TranslateNumber_1(Translator *tr, char *word, char *ph_out, unsigned
utf8_in(&next_char, p);

if (!iswalpha2(next_char) && (thousands_exact == 0))
strcat(ph_out, str_pause); // don't add pause for 100s, 6th, etc.
strcat(ph_out, str_pause); // don't add pause for 100s, 6th, etc.
}

*flags |= FLAG_FOUND;
@@ -2070,7 +2076,7 @@ static int TranslateNumber_1(Translator *tr, char *word, char *ph_out, unsigned
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))
return 0; // speak digits individually
return 0; // speak digits individually

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

+ 0
- 10
src/libespeak-ng/phoneme.h View File

@@ -22,7 +22,6 @@ extern "C"
{
#endif


// phoneme types
#define phPAUSE 0
#define phSTRESS 1
@@ -37,7 +36,6 @@ extern "C"
#define phDELETED 14
#define phINVALID 15


// phoneme properties
// bits 16-19 give place of articulation
#define phARTICULATION 0xf0000
@@ -118,11 +116,8 @@ typedef struct {
unsigned char end_type;
unsigned char std_length; // for vowels, in mS/2; for phSTRESS phonemes, this is the stress/tone type
unsigned char length_mod; // a length_mod group number, used to access length_mod_tab

} PHONEME_TAB;



// Several phoneme tables may be loaded into memory. phoneme_tab points to
// one for the current voice
extern int n_phoneme_tab;
@@ -138,8 +133,6 @@ typedef struct {
int equivalence_tables; // lists of equivalent phonemes to match other languages, byte index into phondata
} PHONEME_TAB_LIST;



// table of phonemes to be replaced with different phonemes, for the current voice
#define N_REPLACE_PHONEMES 60
typedef struct {
@@ -151,15 +144,12 @@ typedef struct {
extern int n_replace_phonemes;
extern REPLACE_PHONEMES replace_phonemes[N_REPLACE_PHONEMES];


// Table of phoneme programs and lengths. Used by MakeVowelLists
typedef struct {
unsigned int addr;
unsigned int length;
} PHONEME_PROG_LOG;



#define PH(c1, c2) (c2<<8)+c1 // combine two characters into an integer for phoneme name
#define PH3(c1, c2, c3) (c3<<16)+(c2<<8)+c1
#define PhonemeCode2(c1, c2) PhonemeCode((c2<<8)+c1)

+ 33
- 32
src/libespeak-ng/phonemelist.c View File

@@ -32,15 +32,17 @@
#include "synthesize.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 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)
{
// Copy the phonemes list and perform any substitutions that are required for the
// current voice
// Copy the phonemes list and perform any substitutions that are required for the
// current voice
int ix;
int k;
int replace_flags;
@@ -67,24 +69,24 @@ static int SubstitutePhonemes(Translator *tr, PHONEME_LIST *plist_out)
replace_flags = replace_phonemes[k].type;

if ((replace_flags & 1) && (word_end == 0))
continue; // this replacement only occurs at the end of a word
continue; // this replacement only occurs at the end of a word

if ((replace_flags & 2) && ((plist2->stresslevel & 0x7) > 3))
continue; // this replacement doesn't occur in stressed syllables
continue; // this replacement doesn't occur in stressed syllables

if ((replace_flags & 4) && (plist2->sourceix == 0))
continue; // this replacement only occurs at the start of a word
continue; // this replacement only occurs at the start of a word

// substitute the replacement phoneme
plist2->phcode = replace_phonemes[k].new_ph;
if ((plist2->stresslevel > 1) && (phoneme_tab[plist2->phcode]->phflags & phUNSTRESSED))
plist2->stresslevel = 0; // the replacement must be unstressed
plist2->stresslevel = 0; // the replacement must be unstressed
break;
}
}

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

// copy phoneme into the output list
@@ -144,7 +146,7 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
// the last word is unstressed, look for a previous word that can be stressed
while (--j >= 0) {
if (plist2[j].synthflags & SFLAG_PROMOTE_STRESS) { // dictionary flags indicated that this stress can be promoted
plist2[j].stresslevel = 4; // promote to stressed
plist2[j].stresslevel = 4; // promote to stressed
break;
}
if (plist2[j].stresslevel >= 4) {
@@ -196,7 +198,7 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
stop_propagation = 0;
voicing = 0;
if (regression & 0x100)
voicing = 1; // word-end devoicing
voicing = 1; // word-end devoicing
continue;
}

@@ -215,12 +217,12 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
if ((voicing == 0) && (regression & 0xf))
voicing = 1;
else if ((voicing == 2) && (ph->end_type != 0)) // use end_type field for voicing_switch for consonants
plist2[j].phcode = ph->end_type; // change to voiced equivalent
plist2[j].phcode = ph->end_type; // change to voiced equivalent
} else if ((type == phVSTOP) || type == (phVFRICATIVE)) {
if ((voicing == 0) && (regression & 0xf))
voicing = 2;
else if ((voicing == 1) && (ph->end_type != 0))
plist2[j].phcode = ph->end_type; // change to unvoiced equivalent
plist2[j].phcode = ph->end_type; // change to unvoiced equivalent
} else {
if (regression & 0x8) {
// LANG=Polish, propagate through liquids and nasals
@@ -264,7 +266,7 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)

nextw++;
if (ph_list3[nextw].sourceix)
break; // start of the next word
break; // start of the next word
}
for (k = j; k < nextw; k++)
ph_list3[k].wordstress = word_stress;
@@ -307,7 +309,7 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
ph = phoneme_tab[insert_ph];
plist3->ph = ph;
insert_ph = 0;
inserted = 1; // don't insert the same phoneme repeatedly
inserted = 1; // don't insert the same phoneme repeatedly
} else {
// otherwise get the next phoneme from the list
if (plist3->sourceix != 0)
@@ -320,7 +322,7 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
// change phoneme table
SelectPhonemeTable(plist3->tone_ph);
}
next = phoneme_tab[plist3[1].phcode]; // the phoneme after this one
next = phoneme_tab[plist3[1].phcode]; // the phoneme after this one
plist3[1].ph = next;
}

@@ -348,7 +350,7 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
if (ph->type == phVOWEL) {
plist3->synthflags |= SFLAG_SYLLABLE;
if (ph2->type != phVOWEL)
plist3->stresslevel = 0; // change from non-vowel to vowel, make sure it's unstressed
plist3->stresslevel = 0; // change from non-vowel to vowel, make sure it's unstressed
} else
plist3->synthflags &= ~SFLAG_SYLLABLE;

@@ -365,12 +367,12 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
plist3->phcode = alternative;

if (alternative == 1)
deleted = 1; // NULL phoneme, discard
deleted = 1; // NULL phoneme, discard
else {
if (ph->type == phVOWEL) {
plist3->synthflags |= SFLAG_SYLLABLE;
if (ph2->type != phVOWEL)
plist3->stresslevel = 0; // change from non-vowel to vowel, make sure it's unstressed
plist3->stresslevel = 0; // change from non-vowel to vowel, make sure it's unstressed
} else
plist3->synthflags &= ~SFLAG_SYLLABLE;

@@ -408,14 +410,13 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
// stress. But not for the last phoneme of a stressed word
if ((tr->langopts.stress_flags & S_NO_DIM) || ((word_stress > 3) && ((plist3+1)->sourceix != 0))) {
// An unstressed final vowel of a stressed word
unstress_count = 1; // try again for next syllable
unstress_count = 1; // try again for next syllable
} else
plist3->stresslevel = 0; // change stress to 'diminished'
plist3->stresslevel = 0; // change stress to 'diminished'
}
}
} else {
} else
unstress_count = 0;
}
}

if ((plist3+1)->synthflags & SFLAG_LENGTHEN) {
@@ -483,7 +484,7 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
if (deleted == 0) {
phlist[ix].ph = ph;
phlist[ix].type = ph->type;
phlist[ix].env = PITCHfall; // default, can be changed in the "intonation" module
phlist[ix].env = PITCHfall; // default, can be changed in the "intonation" module
phlist[ix].synthflags = plist3->synthflags;
phlist[ix].stresslevel = plist3->stresslevel & 0xf;
phlist[ix].wordstress = plist3->wordstress;
@@ -493,10 +494,10 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)

if (plist3->sourceix != 0) {
phlist[ix].sourceix = plist3->sourceix;
phlist[ix].newword = 1; // this phoneme is the start of a word
phlist[ix].newword = 1; // this phoneme is the start of a word

if (start_sentence) {
phlist[ix].newword = 5; // start of sentence + start of word
phlist[ix].newword = 5; // start of sentence + start of word
start_sentence = 0;
}
} else
@@ -505,26 +506,26 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
phlist[ix].length = phdata.pd_param[i_SET_LENGTH]*2;
if ((ph->code == phonPAUSE_LONG) && (option_wordgap > 0) && (plist3[1].sourceix != 0)) {
phlist[ix].ph = phoneme_tab[phonPAUSE_SHORT];
phlist[ix].length = option_wordgap*14; // 10mS per unit at the default speed
phlist[ix].length = option_wordgap*14; // 10mS per unit at the default speed
}

if (ph->type == phVOWEL || ph->type == phLIQUID || ph->type == phNASAL || ph->type == phVSTOP || ph->type == phVFRICATIVE || (ph->phflags & phPREVOICE)) {
phlist[ix].length = 128; // length_mod
phlist[ix].length = 128; // length_mod
phlist[ix].env = PITCHfall;
}

phlist[ix].prepause = 0;
phlist[ix].amp = 20; // default, will be changed later
phlist[ix].amp = 20; // default, will be changed later
phlist[ix].pitch1 = 255;
phlist[ix].pitch2 = 255;
ix++;
}
}
phlist[ix].newword = 2; // end of clause
phlist[ix].newword = 2; // end of clause

phlist[ix].phcode = phonPAUSE;
phlist[ix].type = phPAUSE; // terminate with 2 Pause phonemes
phlist[ix].length = post_pause; // length of the pause, depends on the punctuation
phlist[ix].type = phPAUSE; // terminate with 2 Pause phonemes
phlist[ix].length = post_pause; // length of the pause, depends on the punctuation
phlist[ix].sourceix = end_sourceix;
phlist[ix].synthflags = 0;
phlist[ix++].ph = phoneme_tab[phonPAUSE];

+ 358
- 346
src/libespeak-ng/readclause.c
File diff suppressed because it is too large
View File


+ 84
- 85
src/libespeak-ng/setlengths.c View File

@@ -40,10 +40,10 @@ extern int saved_parameters[];
// convert from words-per-minute to internal speed factor
// Use this to calibrate speed for wpm 80-350
static unsigned char speed_lookup[] = {
255, 255, 255, 255, 255, // 80
253, 249, 245, 242, 238, // 85
235, 232, 228, 225, 222, // 90
218, 216, 213, 210, 207, // 95
255, 255, 255, 255, 255, // 80
253, 249, 245, 242, 238, // 85
235, 232, 228, 225, 222, // 90
218, 216, 213, 210, 207, // 95
204, 201, 198, 196, 193, // 100
191, 188, 186, 183, 181, // 105
179, 176, 174, 172, 169, // 110
@@ -56,54 +56,54 @@ static unsigned char speed_lookup[] = {
118, 117, 115, 114, 113, // 145
112, 111, 110, 109, 107, // 150
106, 105, 104, 103, 102, // 155
101, 100, 99, 98, 97,// 160
96, 95, 94, 93, 92, // 165
91, 90, 89, 89, 88, // 170
87, 86, 85, 84, 83, // 175
82, 82, 81, 80, 80, // 180
79, 78, 77, 76, 76, // 185
75, 75, 74, 73, 72, // 190
71, 71, 70, 69, 69, // 195
68, 67, 67, 66, 66, // 200
65, 64, 64, 63, 62, // 205
62, 61, 61, 60, 59, // 210
59, 58, 58, 57, 57, // 215
56, 56, 55, 54, 54, // 220
53, 53, 52, 52, 52, // 225
51, 50, 50, 49, 49, // 230
48, 48, 47, 47, 46, // 235
46, 46, 45, 45, 44, // 240
44, 44, 43, 43, 42, // 245
41, 40, 40, 40, 39, // 250
39, 39, 38, 38, 38, // 255
37, 37, 37, 36, 36, // 260
35, 35, 35, 35, 34, // 265
34, 34, 33, 33, 33, // 270
32, 32, 31, 31, 31, // 275
30, 30, 30, 29, 29, // 280
29, 29, 28, 28, 27, // 285
27, 27, 27, 26, 26, // 290
26, 26, 25, 25, 25, // 295
24, 24, 24, 24, 23, // 300
23, 23, 23, 22, 22, // 305
22, 21, 21, 21, 21, // 310
20, 20, 20, 20, 19, // 315
19, 19, 18, 18, 17, // 320
17, 17, 16, 16, 16, // 325
16, 16, 16, 15, 15, // 330
15, 15, 14, 14, 14, // 335
13, 13, 13, 12, 12, // 340
12, 12, 11, 11, 11, // 345
11, 10, 10, 10, 9, // 350
9, 9, 8, 8, 8, // 355
101, 100, 99, 98, 97, // 160
96, 95, 94, 93, 92, // 165
91, 90, 89, 89, 88, // 170
87, 86, 85, 84, 83, // 175
82, 82, 81, 80, 80, // 180
79, 78, 77, 76, 76, // 185
75, 75, 74, 73, 72, // 190
71, 71, 70, 69, 69, // 195
68, 67, 67, 66, 66, // 200
65, 64, 64, 63, 62, // 205
62, 61, 61, 60, 59, // 210
59, 58, 58, 57, 57, // 215
56, 56, 55, 54, 54, // 220
53, 53, 52, 52, 52, // 225
51, 50, 50, 49, 49, // 230
48, 48, 47, 47, 46, // 235
46, 46, 45, 45, 44, // 240
44, 44, 43, 43, 42, // 245
41, 40, 40, 40, 39, // 250
39, 39, 38, 38, 38, // 255
37, 37, 37, 36, 36, // 260
35, 35, 35, 35, 34, // 265
34, 34, 33, 33, 33, // 270
32, 32, 31, 31, 31, // 275
30, 30, 30, 29, 29, // 280
29, 29, 28, 28, 27, // 285
27, 27, 27, 26, 26, // 290
26, 26, 25, 25, 25, // 295
24, 24, 24, 24, 23, // 300
23, 23, 23, 22, 22, // 305
22, 21, 21, 21, 21, // 310
20, 20, 20, 20, 19, // 315
19, 19, 18, 18, 17, // 320
17, 17, 16, 16, 16, // 325
16, 16, 16, 15, 15, // 330
15, 15, 14, 14, 14, // 335
13, 13, 13, 12, 12, // 340
12, 12, 11, 11, 11, // 345
11, 10, 10, 10, 9, // 350
9, 9, 8, 8, 8, // 355
};

// speed_factor1 adjustments for speeds 350 to 374: pauses
static unsigned char pause_factor_350[] = {
22, 22, 22, 22, 22, 22, 22, 21, 21, 21, // 350
21, 20, 20, 19, 19, 18, 17, 16, 15, 15, // 360
15, 15, 15, 15, 15
}; // 370
15, 15, 15, 15, 15 // 370
};

// wav_factor adjustments for speeds 350 to 450
// Use this to calibrate speed for wpm 350-450
@@ -114,22 +114,22 @@ static unsigned char wav_factor_350[] = {
111, 111, 110, 109, 108, // 365
107, 106, 106, 104, 103, // 370
103, 102, 102, 102, 101, // 375
101, 99, 98, 98, 97,// 380
96, 96, 95, 94, 93, // 385
91, 90, 91, 90, 89, // 390
88, 86, 85, 86, 85, // 395
85, 84, 82, 81, 80, // 400
79, 77, 78, 78, 76, // 405
77, 75, 75, 74, 73, // 410
71, 72, 70, 69, 69, // 415
69, 67, 65, 64, 63, // 420
63, 63, 61, 61, 59, // 425
59, 59, 58, 56, 57, // 430
58, 56, 54, 53, 52, // 435
52, 53, 52, 52, 50, // 440
48, 47, 47, 45, 46, // 445
45
}; // 450
101, 99, 98, 98, 97, // 380
96, 96, 95, 94, 93, // 385
91, 90, 91, 90, 89, // 390
88, 86, 85, 86, 85, // 395
85, 84, 82, 81, 80, // 400
79, 77, 78, 78, 76, // 405
77, 75, 75, 74, 73, // 410
71, 72, 70, 69, 69, // 415
69, 67, 65, 64, 63, // 420
63, 63, 61, 61, 59, // 425
59, 59, 58, 56, 57, // 430
58, 56, 54, 53, 52, // 435
52, 53, 52, 52, 50, // 440
48, 47, 47, 45, 46, // 445
45 // 450
};

static int speed1 = 130;
static int speed2 = 121;
@@ -148,7 +148,7 @@ void SetSpeed(int control)

speed.loud_consonants = 0;
speed.min_sample_len = 450;
speed.lenmod_factor = 110; // controls the effect of FRFLAG_LEN_MOD reduce length change
speed.lenmod_factor = 110; // controls the effect of FRFLAG_LEN_MOD reduce length change
speed.lenmod2_factor = 100;
speed.min_pause = 5;

@@ -232,9 +232,9 @@ void SetSpeed(int control)
s1 = (x * voice->speedf1)/256;

if (wpm >= 170)
speed.wav_factor = 110 + (150*s1)/128; // reduced speed adjustment, used for playing recorded sounds
speed.wav_factor = 110 + (150*s1)/128; // reduced speed adjustment, used for playing recorded sounds
else
speed.wav_factor = 128 + (128*s1)/130; // = 215 at 170 wpm
speed.wav_factor = 128 + (128*s1)/130; // = 215 at 170 wpm

if (wpm >= 350)
speed.wav_factor = wav_factor_350[wpm-350];
@@ -245,10 +245,10 @@ void SetSpeed(int control)
speed.min_sample_len = 420 - (wpm - 440);
}

// adjust for different sample rates
// adjust for different sample rates
speed.min_sample_len = (speed.min_sample_len * samplerate_native) / 22050;

speed.pause_factor = (256 * s1)/115; // full speed adjustment, used for pause length
speed.pause_factor = (256 * s1)/115; // full speed adjustment, used for pause length
speed.clause_pause_factor = 0;

if (wpm > 430)
@@ -268,11 +268,11 @@ void SetSpeed(int control)
}
}

#else // not using sonic speed-up
#else

void SetSpeed(int control)
{
// This is the earlier version of SetSpeed() before sonic speed-up was added
// This is the earlier version of SetSpeed() before sonic speed-up was added
int x;
int s1;
int wpm;
@@ -280,7 +280,7 @@ void SetSpeed(int control)

speed.loud_consonants = 0;
speed.min_sample_len = 450;
speed.lenmod_factor = 110; // controls the effect of FRFLAG_LEN_MOD reduce length change
speed.lenmod_factor = 110; // controls the effect of FRFLAG_LEN_MOD reduce length change
speed.lenmod2_factor = 100;

wpm = embedded_value[EMBED_S];
@@ -332,9 +332,9 @@ void SetSpeed(int control)
s1 = (x * voice->speedf1)/256;

if (wpm >= 170)
speed.wav_factor = 110 + (150*s1)/128; // reduced speed adjustment, used for playing recorded sounds
speed.wav_factor = 110 + (150*s1)/128; // reduced speed adjustment, used for playing recorded sounds
else
speed.wav_factor = 128 + (128*s1)/130; // = 215 at 170 wpm
speed.wav_factor = 128 + (128*s1)/130; // = 215 at 170 wpm

if (wpm >= 350)
speed.wav_factor = wav_factor_350[wpm-350];
@@ -345,7 +345,7 @@ void SetSpeed(int control)
speed.min_sample_len = 420 - (wpm - 440);
}

speed.pause_factor = (256 * s1)/115; // full speed adjustment, used for pause length
speed.pause_factor = (256 * s1)/115; // full speed adjustment, used for pause length
speed.clause_pause_factor = 0;

if (wpm > 430)
@@ -367,11 +367,10 @@ void SetSpeed(int control)

#endif


void SetParameter(int parameter, int value, int relative)
{
// parameter: reset-all, amp, pitch, speed, linelength, expression, capitals, number grouping
// relative 0=absolute 1=relative
// parameter: reset-all, amp, pitch, speed, linelength, expression, capitals, number grouping
// relative 0=absolute 1=relative

int new_value = value;
int default_value;
@@ -432,7 +431,7 @@ static void DoEmbedded2(int *embix)

if ((word & 0x1f) == EMBED_S) {
// speed
SetEmbedded(word & 0x7f, word >> 8); // adjusts embedded_value[EMBED_S]
SetEmbedded(word & 0x7f, word >> 8); // adjusts embedded_value[EMBED_S]
SetSpeed(1);
}
} while ((word & 0x80) == 0);
@@ -529,7 +528,7 @@ void CalcLengths(Translator *tr)

if ((p->ph->phflags & phSIBILANT) && next->type == phSTOP && !next->newword) {
if (prev->type == phVOWEL)
p->length = 200; // ?? should do this if it's from a prefix
p->length = 200; // ?? should do this if it's from a prefix
else
p->length = 150;
} else
@@ -553,7 +552,7 @@ void CalcLengths(Translator *tr)
p->prepause = 40;

if (prev->type == phVOWEL) {
p->prepause = 0; // use murmur instead to link from the preceding vowel
p->prepause = 0; // use murmur instead to link from the preceding vowel
} else if (prev->type == phPAUSE) {
// reduce by the length of the preceding pause
if (prev->length < p->prepause)
@@ -575,8 +574,8 @@ void CalcLengths(Translator *tr)
break;
case phLIQUID:
case phNASAL:
p->amp = tr->stress_amps[0]; // unless changed later
p->length = 256; // TEMPORARY
p->amp = tr->stress_amps[0]; // unless changed later
p->length = 256; // TEMPORARY
min_drop = 0;

if (p->newword) {
@@ -698,7 +697,7 @@ void CalcLengths(Translator *tr)
length_mod = length_mod / 128;

if (length_mod < 8)
length_mod = 8; // restrict how much lengths can be reduced
length_mod = 8; // restrict how much lengths can be reduced

if (stress >= 7) {
// tonic syllable, include a constant component so it doesn't decrease directly with speed
@@ -724,7 +723,7 @@ void CalcLengths(Translator *tr)
// this is the last syllable in the clause, lengthen it - more for short vowels
len = (p->ph->std_length * 2);
if (tr->langopts.stress_flags & S_EO_CLAUSE1)
len = 200; // don't lengthen short vowels more than long vowels at end-of-clause
len = 200; // don't lengthen short vowels more than long vowels at end-of-clause
length_mod = length_mod * (256 + (280 - len)/3)/256;
}

@@ -748,7 +747,7 @@ void CalcLengths(Translator *tr)

// pre-vocalic part
// set last-pitch
env2 = p->env + 1; // version for use with preceding semi-vowel
env2 = p->env + 1; // version for use with preceding semi-vowel

if (p->tone_ph != 0) {
InterpretPhoneme2(p->tone_ph, &phdata_tone);
@@ -761,7 +760,7 @@ void CalcLengths(Translator *tr)
if (pre_sonorant || pre_voiced) {
// set pitch for pre-vocalic part
if (pitch_start == 255)
last_pitch = pitch_start; // pitch is not set
last_pitch = pitch_start; // pitch is not set

if (pitch_start - last_pitch > 16)
last_pitch = pitch_start - 16;

+ 29
- 28
src/libespeak-ng/speak_lib.c View File

@@ -76,12 +76,12 @@ t_espeak_callback *synth_callback = NULL;
int (*uri_callback)(int, const char *, const char *) = NULL;
int (*phoneme_callback)(const char *) = NULL;

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

void WVoiceChanged(voice_t *wvoice)
{
// Voice change in wavegen
// Voice change in wavegen
voice_samplerate = wvoice->samplerate;
}

@@ -235,7 +235,7 @@ static void select_output(espeak_AUDIO_OUTPUT output_type)
my_mode = output_type;
my_audio = NULL;
synchronous_mode = 1;
option_waveout = 1; // inhibit portaudio callback from wavegen.cpp
option_waveout = 1; // inhibit portaudio callback from wavegen.cpp
out_samplerate = 0;

switch (my_mode)
@@ -265,7 +265,7 @@ int GetFileLength(const char *filename)
return 0;

if (S_ISDIR(statbuf.st_mode))
return -2; // a directory
return -2; // a directory

return statbuf.st_size;
}
@@ -275,7 +275,7 @@ char *Alloc(int size)
{
char *p;
if ((p = (char *)malloc(size)) == NULL)
fprintf(stderr, "Can't allocate memory\n"); // I was told that size+1 fixes a crash on 64-bit systems
fprintf(stderr, "Can't allocate memory\n"); // I was told that size+1 fixes a crash on 64-bit systems
return p;
}

@@ -302,7 +302,7 @@ static void init_path(const char *path)
if ((env = getenv("ESPEAK_DATA_PATH")) != NULL) {
sprintf(path_home, "%s/espeak-data", env);
if (GetFileLength(path_home) == -2)
return; // an espeak-data directory exists
return; // an espeak-data directory exists
}

buf[0] = 0;
@@ -324,7 +324,7 @@ static void init_path(const char *path)
if ((env = getenv("ESPEAK_DATA_PATH")) != NULL) {
snprintf(path_home, sizeof(path_home), "%s/espeak-data", env);
if (GetFileLength(path_home) == -2)
return; // an espeak-data directory exists
return; // an espeak-data directory exists
}

snprintf(path_home, sizeof(path_home), "%s/espeak-data", getenv("HOME"));
@@ -337,7 +337,7 @@ static int initialise(int control)
{
int param;
int result;
int srate = 22050; // default sample rate 22050 Hz
int srate = 22050; // default sample rate 22050 Hz

err = EE_OK;
LoadConfig();
@@ -380,7 +380,7 @@ static espeak_ERROR Synthesize(unsigned int unique_identifier, const void *text,
#endif

if ((outbuf == NULL) || (event_list == NULL))
return EE_INTERNAL_ERROR; // espeak_Initialize() has not been called
return EE_INTERNAL_ERROR; // espeak_Initialize() has not been called

option_multibyte = flags & 7;
option_ssml = flags & espeakSSML;
@@ -402,13 +402,13 @@ static espeak_ERROR Synthesize(unsigned int unique_identifier, const void *text,
if (my_mode == AUDIO_OUTPUT_SYNCH_PLAYBACK) {
for (;;) {
#ifdef PLATFORM_WINDOWS
Sleep(300); // 0.3s
Sleep(300); // 0.3s
#else
#ifdef USE_NANOSLEEP
struct timespec period;
struct timespec remaining;
period.tv_sec = 0;
period.tv_nsec = 300000000; // 0.3 sec
period.tv_nsec = 300000000; // 0.3 sec
nanosleep(&period, &remaining);
#else
sleep(1);
@@ -446,7 +446,7 @@ static espeak_ERROR Synthesize(unsigned int unique_identifier, const void *text,
} else
finished = synth_callback((short *)outbuf, length, event_list);
if (finished) {
SpeakNextClause(NULL, 0, 2); // stop
SpeakNextClause(NULL, 0, 2); // stop
break;
}

@@ -465,9 +465,9 @@ static espeak_ERROR Synthesize(unsigned int unique_identifier, const void *text,
if (dispatch_audio(NULL, 0, NULL) < 0) // TBD: test case
return err = EE_INTERNAL_ERROR;
} else
synth_callback(NULL, 0, event_list); // NULL buffer ptr indicates end of data
synth_callback(NULL, 0, event_list); // NULL buffer ptr indicates end of data
#else
synth_callback(NULL, 0, event_list); // NULL buffer ptr indicates end of data
synth_callback(NULL, 0, event_list); // NULL buffer ptr indicates end of data
#endif
break;
}
@@ -615,7 +615,7 @@ void sync_espeak_Key(const char *key)

my_unique_identifier = 0;
my_user_data = NULL;
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)
@@ -959,18 +959,19 @@ ESPEAK_API espeak_ERROR espeak_SetPunctuationList(const wchar_t *punctlist)
ESPEAK_API void espeak_SetPhonemeTrace(int phonememode, FILE *stream)
{
ENTER("espeak_SetPhonemes");
/* phonememode: Controls the output of phoneme symbols for the text
bits 0-2:
value=0 No phoneme output (default)
value=1 Output the translated phoneme symbols for the text
value=2 as (1), but produces IPA phoneme names rather than ascii
bit 3: output a trace of how the translation was done (showing the matching rules and list entries)
bit 4: produce pho data for mbrola
bit 7: use (bits 8-23) as a tie within multi-letter phonemes names
bits 8-23: separator character, between phoneme names

stream output stream for the phoneme symbols (and trace). If stream=NULL then it uses stdout.
*/
/* phonememode: Controls the output of phoneme symbols for the text
bits 0-2:
value=0 No phoneme output (default)
value=1 Output the translated phoneme symbols for the text
value=2 as (1), but produces IPA phoneme names rather than ascii
bit 3: output a trace of how the translation was done (showing the matching rules and list entries)
bit 4: produce pho data for mbrola
bit 7: use (bits 8-23) as a tie within multi-letter phonemes names
bits 8-23: separator character, between phoneme names

stream output stream for the phoneme symbols (and trace). If stream=NULL then it uses stdout.
*/

option_phonemes = phonememode;
f_trans = stream;
if (stream == NULL)
@@ -1007,7 +1008,7 @@ ESPEAK_API espeak_ERROR espeak_Cancel(void)
wave_close(my_audio);
SHOW_TIME("espeak_Cancel > LEAVE");
#endif
embedded_value[EMBED_T] = 0; // reset echo for pronunciation announcements
embedded_value[EMBED_T] = 0; // reset echo for pronunciation announcements

for (int i = 0; i < N_SPEECH_PARAM; i++)
SetParameter(i, saved_parameters[i], 0);

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

@@ -63,10 +63,10 @@ static double read_double(FILE *stream)

float polint(float xa[], float ya[], int n, float x)
{
// General polinomial interpolation routine, xa[1...n] ya[1...n]
// General polinomial interpolation routine, xa[1...n] ya[1...n]
int i, m, ns = 1;
float den, dif, dift, ho, hp, w;
float y; // result
float y; // result
float c[9], d[9];

dif = fabs(x-xa[1]);
@@ -86,7 +86,7 @@ float polint(float xa[], float ya[], int n, float x)
hp = xa[i+m]-x;
w = c[i+1]-d[i];
if ((den = ho-hp) == 0.0)
return ya[2]; // two input xa are identical
return ya[2]; // two input xa are identical
den = w/den;
d[i] = hp*den;
c[i] = ho*den;
@@ -265,7 +265,8 @@ static float GetFrameLength(SpectSeq *spect, int frame)
if (frame >= spect->numframes-1) return 0;

for (ix = frame+1; ix < spect->numframes-1; ix++) {
if (spect->frames[ix]->keyframe) break; // reached next keyframe
if (spect->frames[ix]->keyframe)
break; // reached next keyframe
adjust += spect->frames[ix]->length_adjust;
}
return (spect->frames[ix]->time - spect->frames[frame]->time) * 1000.0 + adjust;
@@ -289,11 +290,11 @@ int LoadSpectSeq(SpectSeq *spect, const char *filename)
fread(&id2, sizeof(uint32_t), 1, stream);

if ((id1 == FILEID1_SPECTSEQ) && (id2 == FILEID2_SPECTSEQ))
spect->file_format = 0; // eSpeak formants
spect->file_format = 0; // eSpeak formants
else if ((id1 == FILEID1_SPECTSEQ) && (id2 == FILEID2_SPECTSEK))
spect->file_format = 1; // formants for Klatt synthesizer
spect->file_format = 1; // formants for Klatt synthesizer
else if ((id1 == FILEID1_SPECTSEQ) && (id2 == FILEID2_SPECTSQ2))
spect->file_format = 2; // formants for Klatt synthesizer
spect->file_format = 2; // formants for Klatt synthesizer
else {
fprintf(stderr, "Unsupported spectral file format.\n");
fclose(stream);

+ 4
- 8
src/libespeak-ng/spect.h View File

@@ -26,7 +26,6 @@ extern "C"
#define MAX_DISPLAY_FREQ 9500
#define FRAME_HEIGHT 240


#define T_ZOOMOUT 301
#define T_ZOOMIN 302
#define T_USEPITCHENV 303
@@ -50,7 +49,6 @@ extern "C"
#define T_KOPEN 320
#define T_FNZ 321


#define FILEID1_SPECTSEQ 0x43455053
#define FILEID2_SPECTSEQ 0x51455354 // for eSpeak sequence
#define FILEID2_SPECTSEK 0x4b455354 // for Klatt sequence
@@ -64,7 +62,6 @@ extern "C"
#define FILEID1_PRAATSEQ 0x41415250
#define FILEID2_PRAATSEQ 0x51455354


typedef struct {
unsigned short pitch1;
unsigned short pitch2;
@@ -74,7 +71,7 @@ typedef struct {
typedef struct {
short freq;
short bandw;
} formant_t;
} formant_t;

typedef struct {
short pkfreq;
@@ -84,8 +81,7 @@ typedef struct {
short klt_bw;
short klt_ap;
short klt_bp;
} peak_t;

} peak_t;

typedef struct {
int keyframe;
@@ -100,11 +96,11 @@ typedef struct {
unsigned short nx;
short markers;
int max_y;
USHORT *spect; // sqrt of harmonic amplitudes, 1-nx at 'pitch'
USHORT *spect; // sqrt of harmonic amplitudes, 1-nx at 'pitch'

short klatt_param[N_KLATTP2];

formant_t formants[N_PEAKS]; // this is just the estimate given by Praat
formant_t formants[N_PEAKS]; // this is just the estimate given by Praat
peak_t peaks[N_PEAKS];
} SpectFrame;


+ 0
- 2
src/libespeak-ng/speech.h View File

@@ -69,8 +69,6 @@ typedef signed __int32 intptr_t;
#endif
#endif



typedef struct {
const char *mnem;
int value;

+ 29
- 28
src/libespeak-ng/synth_mbrola.c View File

@@ -106,7 +106,7 @@ static int mbr_name_prefix = 0;

espeak_ERROR LoadMbrolaTable(const char *mbrola_voice, const char *phtrans, int *srate)
{
// Load a phoneme name translation table from espeak-data/mbrola
// Load a phoneme name translation table from espeak-data/mbrola

int size;
int ix;
@@ -141,16 +141,16 @@ espeak_ERROR LoadMbrolaTable(const char *mbrola_voice, const char *phtrans, int
close_MBR();
#endif
#ifdef PLATFORM_WINDOWS
if (load_MBR() == FALSE) { // load mbrola.dll
if (load_MBR() == FALSE) { // load mbrola.dll
fprintf(stderr, "Can't load mbrola.dll\n");
return EE_INTERNAL_ERROR;
}
#endif

if (init_MBR(path) != 0) // initialise the required mbrola voice
if (init_MBR(path) != 0) // initialise the required mbrola voice
return EE_NOT_FOUND;

setNoError_MBR(1); // don't stop on phoneme errors
setNoError_MBR(1); // don't stop on phoneme errors

// read eSpeak's mbrola phoneme translation data, eg. en1_phtrans
sprintf(path, "%s/mbrola_ph/%s", path_home, phtrans);
@@ -180,14 +180,15 @@ espeak_ERROR LoadMbrolaTable(const char *mbrola_voice, const char *phtrans, int
else
SetParameter(espeakVOICETYPE, 1, 0);
strcpy(mbrola_name, mbrola_voice);
mbrola_delay = 1000; // improve synchronization of events
mbrola_delay = 1000; // improve synchronization of events
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)
{
// Look up a phoneme in the mbrola phoneme name translation table
// It may give none, 1, or 2 mbrola phonemes
// Look up a phoneme in the mbrola phoneme name translation table
// It may give none, 1, or 2 mbrola phonemes

MBROLA_TAB *pr;
PHONEME_TAB *other_ph;
int found = 0;
@@ -218,7 +219,7 @@ static int GetMbrName(PHONEME_LIST *plist, PHONEME_TAB *ph, PHONEME_TAB *ph_prev
if (pr->control & 2)
other_ph = ph_prev;
else if ((pr->control & 8) && ((plist+1)->newword))
other_ph = phoneme_tab[phPAUSE]; // don't match the next phoneme over a word boundary
other_ph = phoneme_tab[phPAUSE]; // don't match the next phoneme over a word boundary
else
other_ph = ph_next;

@@ -228,14 +229,14 @@ static int GetMbrName(PHONEME_LIST *plist, PHONEME_TAB *ph, PHONEME_TAB *ph_prev
found = 1;
}

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

if ((pr->control & 0x40) && (plist[1].newword == 0)) // only at the end of a word
if ((pr->control & 0x40) && (plist[1].newword == 0)) // only at the end of a word
found = 0;

if ((pr->control & 0x20) && (plist->stresslevel < plist->wordstress))
found = 0; // only in stressed syllables
found = 0; // only in stressed syllables

if (found) {
*name2 = pr->mbr_name2;
@@ -262,7 +263,7 @@ static int GetMbrName(PHONEME_LIST *plist, PHONEME_TAB *ph, PHONEME_TAB *ph_prev

static char *WritePitch(int env, int pitch1, int pitch2, int split, int final)
{
// final=1: only give the final pitch value.
// final=1: only give the final pitch value.
int x;
int ix;
int pitch_base;
@@ -273,7 +274,7 @@ static char *WritePitch(int env, int pitch1, int pitch2, int split, int final)
int min = 999;
int y_max = 0;
int y_min = 0;
int env100 = 80; // apply the pitch change only over this proportion of the mbrola phoneme(s)
int env100 = 80; // apply the pitch change only over this proportion of the mbrola phoneme(s)
int y2;
int y[4];
int env_split;
@@ -311,7 +312,7 @@ static char *WritePitch(int env, int pitch1, int pitch2, int split, int final)
y[3] = y[2] + (127 - y[2])/2;

// set initial pitch
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;

if (split >= 0) {
@@ -355,7 +356,7 @@ static char *WritePitch(int env, int pitch1, int pitch2, int split, int final)

int MbrolaTranslate(PHONEME_LIST *plist, int n_phonemes, int resume, FILE *f_mbrola)
{
// Generate a mbrola pho file
// Generate a mbrola pho file
unsigned int name;
int len;
int len1;
@@ -412,7 +413,7 @@ int MbrolaTranslate(PHONEME_LIST *plist, int n_phonemes, int resume, FILE *f_mbr

if (name == 0) {
phix++;
continue; // ignore this phoneme
continue; // ignore this phoneme
}

if ((ph->type == phPAUSE) && (name == ph->mnemonic)) {
@@ -446,10 +447,10 @@ int MbrolaTranslate(PHONEME_LIST *plist, int n_phonemes, int resume, FILE *f_mbr
case phVOWEL:
len = ph->std_length;
if (p->synthflags & SFLAG_LENGTHEN)
len += phoneme_tab[phonLENGTHEN]->std_length; // phoneme was followed by an extra : symbol
len += phoneme_tab[phonLENGTHEN]->std_length; // phoneme was followed by an extra : symbol

if (ph_next->type == phPAUSE)
len += 50; // lengthen vowels before a pause
len += 50; // lengthen vowels before a pause
len = (len * p->length)/256;

if (name2 == 0) {
@@ -477,7 +478,7 @@ int MbrolaTranslate(PHONEME_LIST *plist, int n_phonemes, int resume, FILE *f_mbr
InterpretPhoneme(NULL, 0, p, &phdata, NULL);
len = DoSample3(&phdata, 0, -1);

len = (len * 1000)/samplerate; // convert to mS
len = (len * 1000)/samplerate; // convert to mS
len += PauseLength(p->prepause, 1);
break;
case phVSTOP:
@@ -487,10 +488,10 @@ int MbrolaTranslate(PHONEME_LIST *plist, int n_phonemes, int resume, FILE *f_mbr
len = 0;
InterpretPhoneme(NULL, 0, p, &phdata, NULL);
if (p->synthflags & SFLAG_LENGTHEN)
len = DoSample3(&phdata, p->length, -1); // play it twice for [s:] etc.
len = DoSample3(&phdata, p->length, -1); // play it twice for [s:] etc.
len += DoSample3(&phdata, p->length, -1);

len = (len * 1000)/samplerate; // convert to mS
len = (len * 1000)/samplerate; // convert to mS
break;
case phNASAL:
if (next->type != phVOWEL) {
@@ -528,11 +529,11 @@ int MbrolaTranslate(PHONEME_LIST *plist, int n_phonemes, int resume, FILE *f_mbr
}

if (f_mbrola)
fwrite(mbr_buf, 1, (ptr-mbr_buf), f_mbrola); // write .pho to a file
fwrite(mbr_buf, 1, (ptr-mbr_buf), f_mbrola); // write .pho to a file
else {
int res = write_MBR(mbr_buf);
if (res < 0)
return 0; /* don't get stuck on error */
return 0; // don't get stuck on error
if (res == 0)
return 1;
wcmdq[wcmdq_tail][0] = WCMD_MBROLA_DATA;
@@ -575,7 +576,7 @@ int MbrolaGenerate(PHONEME_LIST *phoneme_list, int *n_ph, int resume)

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)

static int n_samples;
int req_samples, result;
@@ -596,7 +597,7 @@ int MbrolaFill(int length, int resume, int amplitude)
for (ix = 0; ix < result; ix++) {
value16 = out_ptr[0] + (out_ptr[1] << 8);
value = value16 * amplitude;
value = value / 40; // adjust this constant to give a suitable amplitude for mbrola voices
value = value / 40; // adjust this constant to give a suitable amplitude for mbrola voices
if (value > 0x7fff)
value = 0x7fff;
if (value < -0x8000)
@@ -611,12 +612,12 @@ int MbrolaFill(int length, int resume, int amplitude)

void MbrolaReset(void)
{
// Reset the Mbrola engine and flush the pending audio
// Reset the Mbrola engine and flush the pending audio

reset_MBR();
}

#else // INCLUDE_MBROLA
#else

// mbrola interface is not compiled, provide dummy functions.

@@ -639,4 +640,4 @@ void MbrolaReset(void)
{
}

#endif // INCLUDE_MBROLA
#endif

+ 71
- 77
src/libespeak-ng/synthdata.c View File

@@ -59,7 +59,7 @@ int n_phoneme_tables;
PHONEME_TAB_LIST phoneme_tab_list[N_PHONEME_TABS];
int phoneme_tab_number = 0;

int wavefile_ix; // a wavefile to play along with the synthesis
int wavefile_ix; // a wavefile to play along with the synthesis
int wavefile_amp;
int wavefile_ix2;
int wavefile_amp2;
@@ -128,8 +128,8 @@ int LoadPhData(int *srate)
n_tunes = length / sizeof(TUNE);

// read the version number and sample rate from the first 8 bytes of phondata
version = 0; // bytes 0-3, version number
rate = 0; // bytes 4-7, sample rate
version = 0; // bytes 0-3, version number
rate = 0; // bytes 4-7, sample rate
for (ix = 0; ix < 4; ix++) {
version += (wavefile_data[ix] << (ix*8));
rate += (wavefile_data[ix+4] << (ix*8));
@@ -248,7 +248,7 @@ frameref_t *LookupSpect(PHONEME_TAB *this_ph, int which, FMT_PARAMS *fmt_params,
if (which == 1)
nf = seq_break + 1;
else {
frames = &frames_buf[seq_break]; // body of vowel, skip past initial frames
frames = &frames_buf[seq_break]; // body of vowel, skip past initial frames
nf -= seq_break;
}
}
@@ -289,16 +289,15 @@ frameref_t *LookupSpect(PHONEME_TAB *this_ph, int which, FMT_PARAMS *fmt_params,
if (length1 > 0) {
if (which == 2) {
// adjust the length of the main part to match the standard length specified for the vowel
// less the front part of the vowel and any added suffix
// less the front part of the vowel and any added suffix

length_std = fmt_params->std_length + seq_len_adjust - 45;
if (length_std < 10)
length_std = 10;
if (plist->synthflags & SFLAG_LENGTHEN)
length_std += (phoneme_tab[phonLENGTHEN]->std_length * 2); // phoneme was followed by an extra : symbol

// can adjust vowel length for stressed syllables here
length_std += (phoneme_tab[phonLENGTHEN]->std_length * 2); // phoneme was followed by an extra : symbol

// can adjust vowel length for stressed syllables here

length_factor = (length_std * 256)/ length1;

@@ -335,7 +334,7 @@ unsigned char *GetEnvelope(int index)
{
if (index == 0) {
fprintf(stderr, "espeak: No envelope\n");
return envelope_data[0]; // not found, use a default envelope
return envelope_data[0]; // not found, use a default envelope
}
return (unsigned char *)&phondata_ptr[index];
}
@@ -364,14 +363,14 @@ static void SetUpPhonemeTable(int number, int recursing)
n_phoneme_tab = ph_code;

if (recursing == 0)
phoneme_tab_flags[ph_code] |= 1; // not inherited
phoneme_tab_flags[ph_code] |= 1; // not inherited
}
}

void SelectPhonemeTable(int number)
{
n_phoneme_tab = 0;
SetUpPhonemeTable(number, 0); // recursively for included phoneme tables
SetUpPhonemeTable(number, 0); // recursively for included phoneme tables
n_phoneme_tab++;
current_phoneme_table = number;
}
@@ -394,8 +393,8 @@ int LookupPhonemeTable(const char *name)

int SelectPhonemeTableName(const char *name)
{
// Look up a phoneme set by name, and select it if it exists
// Returns the phoneme table number
// Look up a phoneme set by name, and select it if it exists
// Returns the phoneme table number
int ix;

if ((ix = LookupPhonemeTable(name)) == -1)
@@ -407,7 +406,7 @@ int SelectPhonemeTableName(const char *name)

void LoadConfig(void)
{
// Load configuration file, if one exists
// Load configuration file, if one exists
char buf[sizeof(path_home)+10];
FILE *f;
int ix;
@@ -462,8 +461,8 @@ static void InvalidInstn(PHONEME_TAB *ph, int instn)

static bool StressCondition(Translator *tr, PHONEME_LIST *plist, int condition, int control)
{
// condition:
// 0 if diminished, 1 if unstressed, 2 if not stressed, 3 if stressed, 4 if max stress
// condition:
// 0 if diminished, 1 if unstressed, 2 if not stressed, 3 if stressed, 4 if max stress

int stress_level;
PHONEME_LIST *pl;
@@ -476,7 +475,7 @@ static bool StressCondition(Translator *tr, PHONEME_LIST *plist, int condition,
if (phoneme_tab[plist[1].phcode]->type == phVOWEL)
pl = &plist[1];
else
return false; // no stress elevel for this consonant
return false; // no stress elevel for this consonant
}

stress_level = pl->stresslevel & 0xf;
@@ -574,19 +573,19 @@ static bool InterpretCondition(Translator *tr, int control, PHONEME_LIST *plist,

switch (which)
{
case 0: // prevPh
case 5: // prevPhW
case 0: // prevPh
case 5: // prevPhW
plist--;
check_endtype = 1;
break;
case 1: // thisPh
case 1: // thisPh
break;
case 2: // nextPh
case 4: // nextPhW
case 2: // nextPh
case 4: // nextPhW
plist++;
break;
case 3: // next2Ph
case 6: // next2PhW
case 3: // next2Ph
case 6: // next2PhW
plist += 2;
break;
case 7:
@@ -600,13 +599,13 @@ static bool InterpretCondition(Translator *tr, int control, PHONEME_LIST *plist,
}
}
break;
case 8: // prevVowel in this word
case 8: // prevVowel in this word
if ((worddata == NULL) || (worddata->prev_vowel.ph == NULL))
return false; // no previous vowel
return false; // no previous vowel
plist = &(worddata->prev_vowel);
check_endtype = 1;
break;
case 9: // next3PhW
case 9: // next3PhW
for (ix = 1; ix <= 3; ix++) {
if (plist[ix].sourceix)
return false;
@@ -641,8 +640,8 @@ static bool InterpretCondition(Translator *tr, int control, PHONEME_LIST *plist,

// not an exact match, check for a vowel type (eg. #i )
if ((check_endtype) && (ph->type == phVOWEL))
return data == ph->end_type; // prevPh() match on end_type
return data == ph->start_type; // thisPh() or nextPh(), match on start_type
return data == ph->end_type; // prevPh() match on end_type
return data == ph->start_type; // thisPh() or nextPh(), match on start_type
}

data = instn & 0x1f;
@@ -670,16 +669,16 @@ static bool InterpretCondition(Translator *tr, int control, PHONEME_LIST *plist,
case 3:
case 4:
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);
case 6: // isWordStart
case 6: // isWordStart
return plist->sourceix != 0;
case 7: // notWordStart
case 7: // notWordStart
return plist->sourceix == 0;
case 8: // isWordEnd
case 8: // isWordEnd
return plist[1].sourceix || (plist[1].ph->type == phPAUSE);
break;
case 9: // isAfterStress
case 9: // isAfterStress
if (plist->sourceix != 0)
return false;
do {
@@ -689,28 +688,27 @@ static bool InterpretCondition(Translator *tr, int control, PHONEME_LIST *plist,

} while (plist->sourceix == 0);
break;
case 10: // isNotVowel
case 10: // isNotVowel
return ph->type != phVOWEL;
case 11: // isFinalVowel
case 11: // isFinalVowel
for (;;) {
plist++;
// plist->ph = phoneme_tab[plist->phcode]; // Why was this line here?? It corrupts plist if we have language switching if phoneme_tab is wrong language
if (plist->sourceix != 0)
return true; // start of next word, without finding another vowel
return true; // start of next word, without finding another vowel
if (plist->ph->type == phVOWEL)
return false;
}
break;
case 12: // isVoiced
case 12: // isVoiced
return (ph->type == phVOWEL) || (ph->type == phLIQUID) || (ph->phflags & phVOICED);
case 13: // isFirstVowel
case 13: // isFirstVowel
return CountVowelPosition(plist) == 1;
case 14: // isSecondVowel
case 14: // isSecondVowel
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)
if (plist->sourceix != 0)
return false; // this is the first phoneme in the word, so no.
return false; // this is the first phoneme in the word, so no.

count = 0;
for (;;) {
@@ -719,13 +717,13 @@ static bool InterpretCondition(Translator *tr, int control, PHONEME_LIST *plist,
if (plist->ph->phflags & phFLAG1)
count++;
else
break; // stop when we find a vowel without flag1
break; // stop when we find a vowel without flag1
}
if (plist->sourceix != 0)
break;
}
return count > 0;
case 0x10: // isTranslationGiven
case 0x10: // isTranslationGiven
return (plist->synthflags & SFLAG_DICTIONARY) != 0;
}
break;
@@ -736,11 +734,11 @@ static bool InterpretCondition(Translator *tr, int control, PHONEME_LIST *plist,
// Other conditions
switch (data)
{
case 1: // PreVoicing
case 1: // PreVoicing
return control & 1;
case 2: // KlattSynth
case 2: // KlattSynth
return voice->klattv[0] != 0;
case 3: // MbrolaSynth
case 3: // MbrolaSynth
return mbrola_name[0] != 0;
}
}
@@ -755,16 +753,16 @@ static void SwitchOnVowelType(PHONEME_LIST *plist, PHONEME_DATA *phdata, USHORT

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

voweltype -= phonVOWELTYPES;
if ((voweltype >= 0) && (voweltype < 6)) {
prog = *p_prog + voweltype*2;
phdata->sound_addr[instn_type] = (((prog[1] & 0xf) << 16) + prog[2]) * 4;
x = (prog[1] >> 4) & 0xff;
phdata->sound_param[instn_type] = x; // sign extend
phdata->sound_param[instn_type] = x; // sign extend
}

*p_prog += 12;
@@ -795,7 +793,7 @@ int NumInstnWords(USHORT *prog)
case 6:
type2 = (instn & 0xf00) >> 9;
if ((type2 == 5) || (type2 == 6))
return 12; // switch on vowel type
return 12; // switch on vowel type
return 1;
case 2:
case 3:
@@ -818,9 +816,10 @@ int NumInstnWords(USHORT *prog)

void InterpretPhoneme(Translator *tr, int control, PHONEME_LIST *plist, PHONEME_DATA *phdata, WORD_PH_DATA *worddata)
{
// control:
// bit 0: PreVoicing
// bit 8: change phonemes
// control:
// bit 0: PreVoicing
// bit 8: change phonemes

PHONEME_TAB *ph;
USHORT *prog;
USHORT instn;
@@ -835,7 +834,7 @@ void InterpretPhoneme(Translator *tr, int control, PHONEME_LIST *plist, PHONEME_

#define N_RETURN 10
int n_return = 0;
USHORT *return_addr[N_RETURN]; // return address stack
USHORT *return_addr[N_RETURN]; // return address stack

ph = plist->ph;

@@ -860,7 +859,7 @@ void InterpretPhoneme(Translator *tr, int control, PHONEME_LIST *plist, PHONEME_

switch (instn >> 12)
{
case 0: // 0xxx
case 0: // 0xxx
data = instn & 0xff;

if (instn2 == 0) {
@@ -870,10 +869,8 @@ void InterpretPhoneme(Translator *tr, int control, PHONEME_LIST *plist, PHONEME_
case i_RETURN:
end_flag = 1;
break;

case i_CONTINUE:
break;

default:
InvalidInstn(ph, instn);
break;
@@ -897,7 +894,7 @@ void InterpretPhoneme(Translator *tr, int control, PHONEME_LIST *plist, PHONEME_
phdata->ipa_string[ix] = 0;
} else if (instn2 < N_PHONEME_DATA_PARAM) {
if (instn2 == i_CHANGE_PHONEME2)
phdata->pd_param[i_CHANGE_PHONEME] = data; // also set ChangePhoneme
phdata->pd_param[i_CHANGE_PHONEME] = data; // also set ChangePhoneme
phdata->pd_param[instn2] = data;
if ((instn2 == i_CHANGE_PHONEME) && (control & 0x100)) {
// found ChangePhoneme() in PhonemeList mode, exit
@@ -908,13 +905,13 @@ void InterpretPhoneme(Translator *tr, int control, PHONEME_LIST *plist, PHONEME_
break;
case 1:
if (tr == NULL)
break; // ignore if in synthesis stage
break; // ignore if in synthesis stage

if (instn2 < 8) {
// ChangeIf
if (StressCondition(tr, plist, instn2 & 7, 1) == true) {
phdata->pd_param[i_CHANGE_PHONEME] = instn & 0xff;
end_flag = 1; // change phoneme, exit
end_flag = 1; // change phoneme, exit
}
}
break;
@@ -947,7 +944,7 @@ void InterpretPhoneme(Translator *tr, int control, PHONEME_LIST *plist, PHONEME_
// instruction after a condition is not JUMP_FALSE, so skip the instruction.
prog += NumInstnWords(prog);
if ((prog[0] & 0xfe00) == 0x6000)
prog++; // and skip ELSE jump
prog++; // and skip ELSE jump
}
}
prog--;
@@ -959,16 +956,13 @@ void InterpretPhoneme(Translator *tr, int control, PHONEME_LIST *plist, PHONEME_
case 0:
prog += (instn & 0xff) - 1;
break;

case 4:
// conditional jumps should have been processed in the Condition section
break;

case 5: // NexttVowelStarts
case 5: // NexttVowelStarts
SwitchOnVowelType(plist, phdata, &prog, 2);
break;

case 6: // PrevVowelTypeEndings
case 6: // PrevVowelTypeEndings
SwitchOnVowelType(plist, phdata, &prog, 3);
break;
}
@@ -995,7 +989,7 @@ void InterpretPhoneme(Translator *tr, int control, PHONEME_LIST *plist, PHONEME_
break;
}
break;
case 10: // Vowelin, Vowelout
case 10: // Vowelin, Vowelout
if (instn2 == 1)
ix = 0;
else
@@ -1005,11 +999,11 @@ void InterpretPhoneme(Translator *tr, int control, PHONEME_LIST *plist, PHONEME_
phdata->vowel_transition[ix+1] = (prog[2] << 16) + prog[3];
prog += 3;
break;
case 11: // FMT
case 12: // WAV
case 13: // VowelStart
case 14: // VowelEnd
case 15: // addWav
case 11: // FMT
case 12: // WAV
case 13: // VowelStart
case 14: // VowelEnd
case 15: // addWav
instn2 = (instn >> 12) - 11;
phdata->sound_addr[instn2] = ((instn & 0xf) << 18) + (prog[1] << 2);
param_sc = phdata->sound_param[instn2] = (instn >> 4) & 0xff;
@@ -1054,17 +1048,17 @@ void InterpretPhoneme(Translator *tr, int control, PHONEME_LIST *plist, PHONEME_

plist->std_length = phdata->pd_param[i_SET_LENGTH];
if (phdata->sound_addr[0] != 0) {
plist->phontab_addr = phdata->sound_addr[0]; // FMT address
plist->phontab_addr = phdata->sound_addr[0]; // FMT address
plist->sound_param = phdata->sound_param[0];
} else {
plist->phontab_addr = phdata->sound_addr[1]; // WAV address
plist->phontab_addr = phdata->sound_addr[1]; // WAV address
plist->sound_param = phdata->sound_param[1];
}
}

void InterpretPhoneme2(int phcode, PHONEME_DATA *phdata)
{
// Examine the program of a single isolated phoneme
// Examine the program of a single isolated phoneme
int ix;
PHONEME_LIST plist[4];
memset(plist, 0, sizeof(plist));

+ 96
- 96
src/libespeak-ng/synthesize.c View File

@@ -76,7 +76,7 @@ static PHONEME_LIST next_pause;

const char *WordToString(unsigned int word)
{
// Convert a phoneme mnemonic word into a string
// Convert a phoneme mnemonic word into a string
int ix;
static char buf[5];

@@ -131,11 +131,11 @@ static void DoAmplitude(int amp, unsigned char *amp_env)
intptr_t *q;

last_amp_cmd = wcmdq_tail;
amp_length = 0; // total length of vowel with this amplitude envelope
amp_length = 0; // total length of vowel with this amplitude envelope

q = wcmdq[wcmdq_tail];
q[0] = WCMD_AMPLITUDE;
q[1] = 0; // fill in later from amp_length
q[1] = 0; // fill in later from amp_length
q[2] = (intptr_t)amp_env;
q[3] = amp;
WcmdqInc();
@@ -154,14 +154,14 @@ static void DoPitch(unsigned char *env, int pitch1, int pitch2)
env = envelope_data[PITCHfall];
}
last_pitch_cmd = wcmdq_tail;
pitch_length = 0; // total length of spect with this pitch envelope
pitch_length = 0; // total length of spect with this pitch envelope

if (pitch2 < 0)
pitch2 = 0;

q = wcmdq[wcmdq_tail];
q[0] = WCMD_PITCH;
q[1] = 0; // length, fill in later from pitch_length
q[1] = 0; // length, fill in later from pitch_length
q[2] = (intptr_t)env;
q[3] = (pitch1 << 16) + pitch2;
WcmdqInc();
@@ -179,16 +179,16 @@ int PauseLength(int pause, int control)
} else
len = (pause * speed.wav_factor)/256;

if (len < speed.min_pause) {
len = speed.min_pause; // mS, limit the amount to which pauses can be shortened
}
if (len < speed.min_pause)
len = speed.min_pause; // mS, limit the amount to which pauses can be shortened
return len;
}

static void DoPause(int length, int control)
{
// length in nominal mS
// control = 1, less shortening at fast speeds
// length in nominal mS
// control = 1, less shortening at fast speeds

unsigned int len;
int srate2;

@@ -198,9 +198,9 @@ static void DoPause(int length, int control)
len = PauseLength(length, control);

if (len < 90000)
len = (len * samplerate) / 1000; // convert from mS to number of samples
len = (len * samplerate) / 1000; // convert from mS to number of samples
else {
srate2 = samplerate / 25; // avoid overflow
srate2 = samplerate / 25; // avoid overflow
len = (len * srate2) / 40;
}
}
@@ -218,7 +218,7 @@ static void DoPause(int length, int control)
}
}

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)
{
@@ -235,7 +235,7 @@ static int DoSample2(int index, int which, int std_length, int control, int leng
p = &wavefile_data[index];
wav_scale = p[2];
wav_length = (p[1] * 256);
wav_length += p[0]; // length in bytes
wav_length += p[0]; // length in bytes

if (wav_length == 0)
return 0;
@@ -243,7 +243,7 @@ static int DoSample2(int index, int which, int std_length, int control, int leng
min_length = speed.min_sample_len;

if (wav_scale == 0)
min_length *= 2; // 16 bit samples
min_length *= 2; // 16 bit samples

if (std_length > 0) {
std_length = (std_length * samplerate)/1000;
@@ -294,7 +294,7 @@ static int DoSample2(int index, int which, int std_length, int control, int leng
last_wcmdq = wcmdq_tail;
q = wcmdq[wcmdq_tail];
q[0] = WCMD_WAVE2;
q[1] = length | (wav_length << 16); // length in samples
q[1] = length | (wav_length << 16); // length in samples
q[2] = (intptr_t)(&wavefile_data[index]);
q[3] = wav_scale + (amp << 8);
WcmdqInc();
@@ -312,7 +312,7 @@ static int DoSample2(int index, int which, int std_length, int control, int leng
last_wcmdq = wcmdq_tail;
q = wcmdq[wcmdq_tail];
q[0] = WCMD_WAVE;
q[1] = x; // length in samples
q[1] = x; // length in samples
q[2] = (intptr_t)(&wavefile_data[index]);
q[3] = wav_scale + (amp << 8);
WcmdqInc();
@@ -325,7 +325,7 @@ static int DoSample2(int index, int which, int std_length, int control, int leng
last_wcmdq = wcmdq_tail;
q = wcmdq[wcmdq_tail];
q[0] = WCMD_WAVE;
q[1] = len4*2; // length in samples
q[1] = len4*2; // length in samples
q[2] = (intptr_t)(&wavefile_data[index+x]);
q[3] = wav_scale + (amp << 8);
WcmdqInc();
@@ -340,7 +340,7 @@ static int DoSample2(int index, int which, int std_length, int control, int leng
last_wcmdq = wcmdq_tail;
q = wcmdq[wcmdq_tail];
q[0] = WCMD_WAVE;
q[1] = length; // length in samples
q[1] = length; // length in samples
q[2] = (intptr_t)(&wavefile_data[index+x]);
q[3] = wav_scale + (amp << 8);
WcmdqInc();
@@ -381,7 +381,7 @@ static frame_t *AllocFrame()
// enough to use a round-robin without checks.
// Only needed for modifying spectra for blending to consonants

#define N_FRAME_POOL N_WCMDQ
#define N_FRAME_POOL N_WCMDQ
static int ix = 0;
static frame_t frame_pool[N_FRAME_POOL];

@@ -393,15 +393,15 @@ static frame_t *AllocFrame()

static void set_frame_rms(frame_t *fr, int new_rms)
{
// Each frame includes its RMS amplitude value, so to set a new
// RMS just adjust the formant amplitudes by the appropriate ratio
// Each frame includes its RMS amplitude value, so to set a new
// RMS just adjust the formant amplitudes by the appropriate ratio

int x;
int h;
int ix;

static const short sqrt_tab[200] = {
0, 64, 90, 110, 128, 143, 156, 169, 181, 192, 202, 212, 221, 230, 239, 247,
0, 64, 90, 110, 128, 143, 156, 169, 181, 192, 202, 212, 221, 230, 239, 247,
256, 263, 271, 278, 286, 293, 300, 306, 313, 320, 326, 332, 338, 344, 350, 356,
362, 367, 373, 378, 384, 389, 394, 399, 404, 409, 414, 419, 424, 429, 434, 438,
443, 448, 452, 457, 461, 465, 470, 474, 478, 483, 487, 491, 495, 499, 503, 507,
@@ -422,11 +422,11 @@ static void set_frame_rms(frame_t *fr, int new_rms)
return;
}

if (fr->rms == 0) return; // check for divide by zero
if (fr->rms == 0) return; // check for divide by zero
x = (new_rms * 64)/fr->rms;
if (x >= 200) x = 199;

x = sqrt_tab[x]; // sqrt(new_rms/fr->rms)*0x200;
x = sqrt_tab[x]; // sqrt(new_rms/fr->rms)*0x200;

for (ix = 0; ix < 8; ix++) {
h = fr->fheight[ix] * x;
@@ -436,7 +436,7 @@ static void set_frame_rms(frame_t *fr, int new_rms)

static void formants_reduce_hf(frame_t *fr, int level)
{
// change height of peaks 2 to 8, percentage
// change height of peaks 2 to 8, percentage
int ix;
int x;

@@ -451,7 +451,8 @@ static void formants_reduce_hf(frame_t *fr, int level)

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

frame_t *frame2;

if ((copy == 0) && (frame1->frflags & FRFLAG_COPIED)) {
@@ -492,7 +493,7 @@ static void AdjustFormants(frame_t *fr, int target, int min, int max, int f1_adj
fr->ffreq[3] += f3_adj;

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

@@ -521,7 +522,7 @@ static void AdjustFormants(frame_t *fr, int target, int min, int max, int f1_adj

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
int f1;

if ((f1 = fr->ffreq[1]) < 300)
@@ -550,11 +551,11 @@ int FormantTransition2(frameref_t *seq, int *n_frames, unsigned int data1, unsig
int flags;
int vcolour;

#define N_VCOLOUR 2
// percentage change for each formant in 256ths
#define N_VCOLOUR 2
// percentage change for each formant in 256ths
static short vcolouring[N_VCOLOUR][5] = {
{ 243, 272, 256, 256, 256 }, // palatal consonant follows
{ 256, 256, 240, 240, 240 }, // retroflex
{ 243, 272, 256, 256, 256 }, // palatal consonant follows
{ 256, 256, 240, 240, 240 }, // retroflex
};

frame_t *fr = NULL;
@@ -578,13 +579,13 @@ int FormantTransition2(frameref_t *seq, int *n_frames, unsigned int data1, unsig
flags |= 8;

if (which == 1) {
/* entry to vowel */
// entry to vowel
fr = CopyFrame(seq[0].frame, 0);
seq[0].frame = fr;
seq[0].length = VOWEL_FRONT_LENGTH;
if (len > 0)
seq[0].length = len;
seq[0].frflags |= FRFLAG_LEN_MOD2; // reduce length modification
seq[0].frflags |= FRFLAG_LEN_MOD2; // reduce length modification
fr->frflags |= FRFLAG_LEN_MOD2;

next_rms = seq[1].frame->rms;
@@ -649,11 +650,11 @@ int FormantTransition2(frameref_t *seq, int *n_frames, unsigned int data1, unsig
if (flags & 4)
fr->frflags |= FRFLAG_FORMANT_RATE;
if (flags & 2)
fr->frflags |= FRFLAG_BREAK; // don't merge with next frame
fr->frflags |= FRFLAG_BREAK; // don't merge with next frame
}

if (flags & 0x40)
DoPause(20, 0); // add a short pause after the consonant
DoPause(20, 0); // add a short pause after the consonant

if (flags & 16)
return len;
@@ -705,7 +706,7 @@ static void SmoothSpect(void)
q[3] = (intptr_t)frame2;
frame1 = frame2;
} else
break; // doesn't follow on from previous frame
break; // doesn't follow on from previous frame

frame = frame2 = (frame_t *)q[2];
modified = 0;
@@ -714,7 +715,7 @@ static void SmoothSpect(void)
break;

if (frame->frflags & FRFLAG_FORMANT_RATE)
len = (len * 12)/10; // allow slightly greater rate of change for this frame (was 12/10)
len = (len * 12)/10; // allow slightly greater rate of change for this frame (was 12/10)

for (pk = 0; pk < 6; pk++) {
int f1, f2;
@@ -778,7 +779,7 @@ static void SmoothSpect(void)
q[2] = (intptr_t)frame2;
frame1 = frame2;
} else
break; // doesn't follow on from previous frame
break; // doesn't follow on from previous frame
}

frame = frame2 = (frame_t *)q[3];
@@ -788,7 +789,7 @@ static void SmoothSpect(void)
break;

if (frame1->frflags & FRFLAG_FORMANT_RATE)
len = (len *6)/5; // allow slightly greater rate of change for this frame
len = (len *6)/5; // allow slightly greater rate of change for this frame

for (pk = 0; pk < 6; pk++) {
int f1, f2;
@@ -868,10 +869,10 @@ int DoSpect2(PHONEME_TAB *this_ph, int which, FMT_PARAMS *fmt_params, PHONEME_L
length_mod = plist->length;
if (length_mod == 0) length_mod = 256;

length_min = (samplerate/70); // greater than one cycle at low pitch (Hz)
length_min = (samplerate/70); // greater than one cycle at low pitch (Hz)
if (which == 2) {
if ((translator->langopts.param[LOPT_LONG_VOWEL_THRESHOLD] > 0) && ((this_ph->std_length >= translator->langopts.param[LOPT_LONG_VOWEL_THRESHOLD]) || (plist->synthflags & SFLAG_LENGTHEN) || (this_ph->phflags & phLONG)))
length_min *= 2; // ensure long vowels are longer
length_min *= 2; // ensure long vowels are longer
}

if (which == 1) {
@@ -885,7 +886,7 @@ int DoSpect2(PHONEME_TAB *this_ph, int which, FMT_PARAMS *fmt_params, PHONEME_L
modn_flags = 0;
frames = LookupSpect(this_ph, which, fmt_params, &n_frames, plist);
if (frames == NULL)
return 0; // not found
return 0; // not found

if (fmt_params->fmt_amp != fmt_amplitude) {
// an amplitude adjustment is specified for this sequence
@@ -940,7 +941,7 @@ int DoSpect2(PHONEME_TAB *this_ph, int which, FMT_PARAMS *fmt_params, PHONEME_L
}

if ((this_ph->type == phVOWEL) && (which == 2)) {
SmoothSpect(); // process previous syllable
SmoothSpect(); // process previous syllable

// remember the point in the output queue of the centre of the vowel
syllable_centre = wcmdq_tail;
@@ -949,11 +950,10 @@ int DoSpect2(PHONEME_TAB *this_ph, int which, FMT_PARAMS *fmt_params, PHONEME_L
length_sum = 0;
for (frameix = 1; frameix < n_frames; frameix++) {
length_factor = length_mod;
if (frames[frameix-1].frflags & FRFLAG_LEN_MOD) { // reduce effect of length mod
if (frames[frameix-1].frflags & FRFLAG_LEN_MOD) // reduce effect of length mod
length_factor = (length_mod*(256-speed.lenmod_factor) + 256*speed.lenmod_factor)/256;
} else if (frames[frameix-1].frflags & FRFLAG_LEN_MOD2) { // reduce effect of length mod, used for the start of a vowel
else if (frames[frameix-1].frflags & FRFLAG_LEN_MOD2) // reduce effect of length mod, used for the start of a vowel
length_factor = (length_mod*(256-speed.lenmod2_factor) + 256*speed.lenmod2_factor)/256;
}

frame_length = frames[frameix-1].length;
len = (frame_length * samplerate)/1000;
@@ -984,7 +984,7 @@ int DoSpect2(PHONEME_TAB *this_ph, int which, FMT_PARAMS *fmt_params, PHONEME_L
if (frame1->frflags & FRFLAG_MODULATE)
modulation = 6;
if ((frameix == n_frames-1) && (modn_flags & 0xf00))
modulation |= modn_flags; // before or after a glottal stop
modulation |= modn_flags; // before or after a glottal stop
}

len = frame_lengths[frameix];
@@ -1023,8 +1023,9 @@ int DoSpect2(PHONEME_TAB *this_ph, int which, FMT_PARAMS *fmt_params, PHONEME_L

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
// Type 1=word, 2=sentence, 3=named marker, 4=play audio, 5=end
// This could be used to return an index to the word currently being spoken
// Type 1=word, 2=sentence, 3=named marker, 4=play audio, 5=end

if (WcmdqFree() > 5) {
wcmdq[wcmdq_tail][0] = WCMD_MARKER + (type << 8);
wcmdq[wcmdq_tail][1] = (char_posn & 0xffffff) | (length << 24);
@@ -1035,15 +1036,16 @@ void DoMarker(int type, int char_posn, int length, int value)

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
// Type 7=phoneme
// This could be used to return an index to the word currently being spoken
// Type 7=phoneme

int *p;

if (WcmdqFree() > 5) {
wcmdq[wcmdq_tail][0] = WCMD_MARKER + (type << 8);
wcmdq[wcmdq_tail][1] = (char_posn & 0xffffff) | (length << 24);
p = (int *)name;
wcmdq[wcmdq_tail][2] = p[0]; // up to 8 bytes of UTF8 characters
wcmdq[wcmdq_tail][2] = p[0]; // up to 8 bytes of UTF8 characters
wcmdq[wcmdq_tail][3] = p[1];
WcmdqInc();
}
@@ -1052,7 +1054,7 @@ void DoPhonemeMarker(int type, int char_posn, int length, char *name)
#if HAVE_SONIC_H
void DoSonicSpeed(int value)
{
// value, multiplier * 1024
// value, multiplier * 1024
wcmdq[wcmdq_tail][0] = WCMD_SONIC_SPEED;
wcmdq[wcmdq_tail][1] = value;
WcmdqInc();
@@ -1061,7 +1063,7 @@ void DoSonicSpeed(int value)

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()
voice_t *v2;

v2 = (voice_t *)malloc(sizeof(voice_t));
@@ -1074,7 +1076,7 @@ void DoVoiceChange(voice_t *v)
void DoEmbedded(int *embix, int sourceix)
{
// There were embedded commands in the text at this point
unsigned int word; // bit 7=last command for this word, bits 5,6 sign, bits 0-4 command
unsigned int word; // bit 7=last command for this word, bits 5,6 sign, bits 0-4 command
unsigned int value;
int command;

@@ -1084,36 +1086,36 @@ void DoEmbedded(int *embix, int sourceix)
command = word & 0x7f;

if (command == 0)
return; // error
return; // error

(*embix)++;

switch (command & 0x1f)
{
case EMBED_S: // speed
SetEmbedded((command & 0x60) + EMBED_S2, value); // adjusts embedded_value[EMBED_S2]
case EMBED_S: // speed
SetEmbedded((command & 0x60) + EMBED_S2, value); // adjusts embedded_value[EMBED_S2]
SetSpeed(2);
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 (soundicon_tab[value].length != 0) {
DoPause(10, 0); // ensure a break in the speech
DoPause(10, 0); // ensure a break in the speech
wcmdq[wcmdq_tail][0] = WCMD_WAVE;
wcmdq[wcmdq_tail][1] = soundicon_tab[value].length;
wcmdq[wcmdq_tail][2] = (intptr_t)soundicon_tab[value].data + 44; // skip WAV header
wcmdq[wcmdq_tail][3] = 0x1500; // 16 bit data, amp=21
wcmdq[wcmdq_tail][2] = (intptr_t)soundicon_tab[value].data + 44; // skip WAV header
wcmdq[wcmdq_tail][3] = 0x1500; // 16 bit data, amp=21
WcmdqInc();
}
}
break;
case EMBED_M: // named marker
case EMBED_M: // named marker
DoMarker(espeakEVENT_MARK, (sourceix & 0x7ff) + clause_start_char, 0, value);
break;
case EMBED_U: // play sound
DoMarker(espeakEVENT_PLAY, count_characters+1, 0, value); // always occurs at end of clause
case EMBED_U: // play sound
DoMarker(espeakEVENT_PLAY, count_characters+1, 0, value); // always occurs at end of clause
break;
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][1] = command;
wcmdq[wcmdq_tail][2] = value;
@@ -1177,7 +1179,7 @@ int Generate(PHONEME_LIST *phoneme_list, int *n_ph, int resume)
last_pitch_cmd = -1;
memset(vowel_transition, 0, sizeof(vowel_transition));
memset(&worddata, 0, sizeof(worddata));
DoPause(0, 0); // isolate from the previous clause
DoPause(0, 0); // isolate from the previous clause
}

while ((ix < (*n_ph)) && (ix < N_PHONEME_LIST-2)) {
@@ -1186,12 +1188,12 @@ int Generate(PHONEME_LIST *phoneme_list, int *n_ph, int resume)
if (p->type == phPAUSE)
free_min = 10;
else if (p->type != phVOWEL)
free_min = 15; // we need less Q space for non-vowels, and we need to generate phonemes after a vowel so that the pitch_length is filled in
free_min = 15; // we need less Q space for non-vowels, and we need to generate phonemes after a vowel so that the pitch_length is filled in
else
free_min = MIN_WCMDQ; // 25
free_min = MIN_WCMDQ;

if (WcmdqFree() <= free_min)
return 1; // wait
return 1; // wait

prev = &phoneme_list[ix-1];
next = &phoneme_list[ix+1];
@@ -1209,10 +1211,10 @@ int Generate(PHONEME_LIST *phoneme_list, int *n_ph, int resume)
sourceix = (p->sourceix & 0x7ff) + clause_start_char;

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

if (p->newword & 1)
DoMarker(espeakEVENT_WORD, sourceix, p->sourceix >> 11, clause_start_word + word_count++); // NOTE, this count doesn't include multiple-word pronunciations in *_list. eg (of a)
DoMarker(espeakEVENT_WORD, sourceix, p->sourceix >> 11, clause_start_word + word_count++); // NOTE, this count doesn't include multiple-word pronunciations in *_list. eg (of a)
}

EndAmplitude();
@@ -1271,7 +1273,7 @@ int Generate(PHONEME_LIST *phoneme_list, int *n_ph, int resume)
InterpretPhoneme(NULL, 0, p, &phdata, &worddata);

if (p->synthflags & SFLAG_LENGTHEN)
DoSample3(&phdata, p->length, 0); // play it twice for [s:] etc.
DoSample3(&phdata, p->length, 0); // play it twice for [s:] etc.
DoSample3(&phdata, p->length, 0);
break;
case phVSTOP:
@@ -1381,7 +1383,7 @@ int Generate(PHONEME_LIST *phoneme_list, int *n_ph, int resume)
} else if (prev->type == phVOWEL && (p->synthflags & SFLAG_SEQCONTINUE))
DoSpect2(p->ph, 0, &fmtp, p, 0);
else {
last_frame = NULL; // only for nasal ?
last_frame = NULL; // only for nasal ?
DoSpect2(p->ph, 0, &fmtp, p, 0);
last_frame = NULL;
}
@@ -1461,23 +1463,23 @@ int Generate(PHONEME_LIST *phoneme_list, int *n_ph, int resume)

modulation = 2;
if (stress <= 1)
modulation = 1; // 16ths
modulation = 1; // 16ths
else if (stress >= 7)
modulation = 3;

if (prev->type == phVSTOP || prev->type == phVFRICATIVE) {
DoAmplitude(p->amp, amp_env);
DoPitch(pitch_env, p->pitch1, p->pitch2); // don't use prevocalic rising tone
DoPitch(pitch_env, p->pitch1, p->pitch2); // don't use prevocalic rising tone
DoSpect2(ph, 1, &fmtp, p, modulation);
} else if (prev->type == phLIQUID || prev->type == phNASAL) {
DoAmplitude(p->amp, amp_env);
DoSpect2(ph, 1, &fmtp, p, modulation); // continue with pre-vocalic rising tone
DoSpect2(ph, 1, &fmtp, p, modulation); // continue with pre-vocalic rising tone
DoPitch(pitch_env, p->pitch1, p->pitch2);
} else if (vowelstart_prev) {
// VowelStart from the previous phoneme, but not phLIQUID or phNASAL
DoPitch(envelope_data[PITCHrise], p->pitch2 - 15, p->pitch2);
DoAmplitude(p->amp-1, amp_env);
DoSpect2(ph, 1, &fmtp, p, modulation); // continue with pre-vocalic rising tone
DoSpect2(ph, 1, &fmtp, p, modulation); // continue with pre-vocalic rising tone
DoPitch(pitch_env, p->pitch1, p->pitch2);
} else {
if (!(p->synthflags & SFLAG_SEQCONTINUE)) {
@@ -1505,12 +1507,11 @@ int Generate(PHONEME_LIST *phoneme_list, int *n_ph, int resume)
InterpretPhoneme(NULL, 0, next, &phdata_next, NULL);

fmtp.use_vowelin = 1;
fmtp.transition0 = phdata_next.vowel_transition[2]; // always do vowel_transition, even if ph_VWLEND ?? consider [N]
fmtp.transition0 = phdata_next.vowel_transition[2]; // always do vowel_transition, even if ph_VWLEND ?? consider [N]
fmtp.transition1 = phdata_next.vowel_transition[3];

if ((fmtp.fmt2_addr = phdata_next.sound_addr[pd_VWLEND]) != 0) {
if ((fmtp.fmt2_addr = phdata_next.sound_addr[pd_VWLEND]) != 0)
fmtp.fmt2_lenadj = phdata_next.sound_param[pd_VWLEND];
}
}

DoSpect2(ph, 2, &fmtp, p, modulation);
@@ -1520,11 +1521,11 @@ int Generate(PHONEME_LIST *phoneme_list, int *n_ph, int resume)
}
EndPitch(1);
if (*n_ph > 0) {
DoMarker(espeakEVENT_END, count_characters, 0, count_sentences); // end of clause
DoMarker(espeakEVENT_END, count_characters, 0, count_sentences); // end of clause
*n_ph = 0;
}

return 0; // finished the phoneme list
return 0; // finished the phoneme list
}

static int timer_on = 0;
@@ -1553,16 +1554,16 @@ int SynthStatus()

int SpeakNextClause(FILE *f_in, const void *text_in, int control)
{
// Speak text from file (f_in) or memory (text_in)
// control 0: start
// either f_in or text_in is set, the other must be NULL
// Speak text from file (f_in) or memory (text_in)
// control 0: start
// either f_in or text_in is set, the other must be NULL

// The other calls have f_in and text_in = NULL
// control 1: speak next text
// 2: stop
// 3: pause (toggle)
// 4: is file being read (0=no, 1=yes)
// 5: interrupt and flush current text.
// The other calls have f_in and text_in = NULL
// control 1: speak next text
// 2: stop
// 3: pause (toggle)
// 4: is file being read (0=no, 1=yes)
// 5: interrupt and flush current text.

int clause_tone;
char *voice_change;
@@ -1600,7 +1601,7 @@ int SpeakNextClause(FILE *f_in, const void *text_in, int control)
WavegenOpenSound();
timer_on = 1;
paused = 0;
Generate(phoneme_list, &n_phoneme_list, 0); // re-start from beginning of clause
Generate(phoneme_list, &n_phoneme_list, 0); // re-start from beginning of clause
}
return 0;
}
@@ -1650,7 +1651,6 @@ int SpeakNextClause(FILE *f_in, const void *text_in, int control)
phoneme_callback(phon_out);
}


if (skipping_text) {
n_phoneme_list = 0;
return 1;

+ 86
- 108
src/libespeak-ng/synthesize.h View File

@@ -22,69 +22,67 @@ extern "C"
{
#endif

#define espeakINITIALIZE_PHONEME_IPA 0x0002 // move this to speak_lib.h, after eSpeak version 1.46.02
#define espeakINITIALIZE_PHONEME_IPA 0x0002 // move this to speak_lib.h, after eSpeak version 1.46.02

#define N_PHONEME_LIST 1000 // enough for source[N_TR_SOURCE] full of text, else it will truncate

#define N_PHONEME_LIST 1000 // enough for source[N_TR_SOURCE] full of text, else it will truncate

#define MAX_HARMONIC 400 // 400 * 50Hz = 20 kHz, more than enough
#define N_SEQ_FRAMES 25 // max frames in a spectrum sequence (real max is ablut 8)
#define STEPSIZE 64 // 2.9mS at 22 kHz sample rate
#define MAX_HARMONIC 400 // 400 * 50Hz = 20 kHz, more than enough
#define N_SEQ_FRAMES 25 // max frames in a spectrum sequence (real max is ablut 8)
#define STEPSIZE 64 // 2.9mS at 22 kHz sample rate

// flags set for frames within a spectrum sequence
#define FRFLAG_KLATT 0x01 // this frame includes extra data for Klatt synthesizer
#define FRFLAG_VOWEL_CENTRE 0x02 // centre point of vowel
#define FRFLAG_LEN_MOD 0x04 // reduce effect of length adjustment
#define FRFLAG_BREAK_LF 0x08 // but keep f3 upwards
#define FRFLAG_BREAK 0x10 // don't merge with next frame
#define FRFLAG_BREAK_2 0x18 // FRFLAG_BREAK_LF or FRFLAG_BREAK
#define FRFLAG_FORMANT_RATE 0x20 // Flag5 allow increased rate of change of formant freq
#define FRFLAG_MODULATE 0x40 // Flag6 modulate amplitude of some cycles to give trill
#define FRFLAG_DEFER_WAV 0x80 // Flag7 defer mixing WAV until the next frame
#define FRFLAG_LEN_MOD2 0x4000 // reduce effect of length adjustment, used for the start of a vowel
#define FRFLAG_COPIED 0x8000 // This frame has been copied into temporary rw memory
#define SFLAG_SEQCONTINUE 0x01 // a liquid or nasal after a vowel, but not followed by a vowel
#define SFLAG_EMBEDDED 0x02 // there are embedded commands before this phoneme
#define SFLAG_SYLLABLE 0x04 // vowel or syllabic consonant
#define SFLAG_LENGTHEN 0x08 // lengthen symbol : included after this phoneme
#define SFLAG_DICTIONARY 0x10 // the pronunciation of this word was listed in the xx_list dictionary
#define SFLAG_SWITCHED_LANG 0x20 // this word uses phonemes from a different language
#define SFLAG_PROMOTE_STRESS 0x40 // this unstressed word can be promoted to stressed
#define SFLAG_PREV_PAUSE 0x1000 // consider previous phoneme as pause
#define SFLAG_NEXT_PAUSE 0x2000 // consider next phoneme as pause
#define FRFLAG_KLATT 0x01 // this frame includes extra data for Klatt synthesizer
#define FRFLAG_VOWEL_CENTRE 0x02 // centre point of vowel
#define FRFLAG_LEN_MOD 0x04 // reduce effect of length adjustment
#define FRFLAG_BREAK_LF 0x08 // but keep f3 upwards
#define FRFLAG_BREAK 0x10 // don't merge with next frame
#define FRFLAG_BREAK_2 0x18 // FRFLAG_BREAK_LF or FRFLAG_BREAK
#define FRFLAG_FORMANT_RATE 0x20 // Flag5 allow increased rate of change of formant freq
#define FRFLAG_MODULATE 0x40 // Flag6 modulate amplitude of some cycles to give trill
#define FRFLAG_DEFER_WAV 0x80 // Flag7 defer mixing WAV until the next frame
#define FRFLAG_LEN_MOD2 0x4000 // reduce effect of length adjustment, used for the start of a vowel
#define FRFLAG_COPIED 0x8000 // This frame has been copied into temporary rw memory
#define SFLAG_SEQCONTINUE 0x01 // a liquid or nasal after a vowel, but not followed by a vowel
#define SFLAG_EMBEDDED 0x02 // there are embedded commands before this phoneme
#define SFLAG_SYLLABLE 0x04 // vowel or syllabic consonant
#define SFLAG_LENGTHEN 0x08 // lengthen symbol : included after this phoneme
#define SFLAG_DICTIONARY 0x10 // the pronunciation of this word was listed in the xx_list dictionary
#define SFLAG_SWITCHED_LANG 0x20 // this word uses phonemes from a different language
#define SFLAG_PROMOTE_STRESS 0x40 // this unstressed word can be promoted to stressed
#define SFLAG_PREV_PAUSE 0x1000 // consider previous phoneme as pause
#define SFLAG_NEXT_PAUSE 0x2000 // consider next phoneme as pause

// embedded command numbers
#define EMBED_P 1 // pitch
#define EMBED_S 2 // speed (used in setlengths)
#define EMBED_A 3 // amplitude/volume
#define EMBED_R 4 // pitch range/expression
#define EMBED_H 5 // echo/reverberation
#define EMBED_T 6 // different tone for announcing punctuation (not used)
#define EMBED_I 7 // sound icon
#define EMBED_S2 8 // speed (used in synthesize)
#define EMBED_Y 9 // say-as commands
#define EMBED_M 10 // mark name
#define EMBED_U 11 // audio uri
#define EMBED_B 12 // break
#define EMBED_F 13 // emphasis
#define EMBED_C 14 // capital letter indication
#define EMBED_P 1 // pitch
#define EMBED_S 2 // speed (used in setlengths)
#define EMBED_A 3 // amplitude/volume
#define EMBED_R 4 // pitch range/expression
#define EMBED_H 5 // echo/reverberation
#define EMBED_T 6 // different tone for announcing punctuation (not used)
#define EMBED_I 7 // sound icon
#define EMBED_S2 8 // speed (used in synthesize)
#define EMBED_Y 9 // say-as commands
#define EMBED_M 10 // mark name
#define EMBED_U 11 // audio uri
#define EMBED_B 12 // break
#define EMBED_F 13 // emphasis
#define EMBED_C 14 // capital letter indication

#define N_EMBEDDED_VALUES 15
extern int embedded_value[N_EMBEDDED_VALUES];
extern int embedded_default[N_EMBEDDED_VALUES];


#define N_PEAKS 9
#define N_PEAKS2 9 // plus Notch and Fill (not yet implemented)
#define N_PEAKS2 9 // plus Notch and Fill (not yet implemented)
#define N_MARKERS 8

#define N_KLATTP 10 // this affects the phoneme data file format
#define N_KLATTP2 14 // used in vowel files, with extra parameters for future extensions
#define N_KLATTP 10 // this affects the phoneme data file format
#define N_KLATTP2 14 // used in vowel files, with extra parameters for future extensions

#define KLATT_AV 0
#define KLATT_FNZ 1 // nasal zero freq
#define KLATT_FNZ 1 // nasal zero freq
#define KLATT_Tilt 2
#define KLATT_Aspr 3
#define KLATT_Skew 4
@@ -95,38 +93,33 @@ extern int embedded_default[N_EMBEDDED_VALUES];
#define KLATT_FricBP 8
#define KLATT_Turb 9



typedef struct { // 64 bytes
typedef struct { // 64 bytes
short frflags;
short ffreq[7];
unsigned char length;
unsigned char rms;
unsigned char fheight[8];
unsigned char fwidth[6]; // width/4 f0-5
unsigned char fright[3]; // width/4 f0-2
unsigned char bw[4]; // Klatt bandwidth BNZ /2, f1,f2,f3
unsigned char klattp[5]; // AV, FNZ, Tilt, Aspr, Skew
unsigned char klattp2[5]; // continuation of klattp[], Avp, Fric, FricBP, Turb
unsigned char klatt_ap[7]; // Klatt parallel amplitude
unsigned char klatt_bp[7]; // Klatt parallel bandwidth /2
unsigned char spare; // pad to multiple of 4 bytes
} frame_t; // with extra Klatt parameters for parallel resonators


typedef struct { // 44 bytes
unsigned char fwidth[6]; // width/4 f0-5
unsigned char fright[3]; // width/4 f0-2
unsigned char bw[4]; // Klatt bandwidth BNZ /2, f1,f2,f3
unsigned char klattp[5]; // AV, FNZ, Tilt, Aspr, Skew
unsigned char klattp2[5]; // continuation of klattp[], Avp, Fric, FricBP, Turb
unsigned char klatt_ap[7]; // Klatt parallel amplitude
unsigned char klatt_bp[7]; // Klatt parallel bandwidth /2
unsigned char spare; // pad to multiple of 4 bytes
} frame_t; // with extra Klatt parameters for parallel resonators

typedef struct { // 44 bytes
short frflags;
short ffreq[7];
unsigned char length;
unsigned char rms;
unsigned char fheight[8];
unsigned char fwidth[6]; // width/4 f0-5
unsigned char fright[3]; // width/4 f0-2
unsigned char bw[4]; // Klatt bandwidth BNZ /2, f1,f2,f3
unsigned char klattp[5]; // AV, FNZ, Tilt, Aspr, Skew
} frame_t2; // without the extra Klatt parameters


unsigned char fwidth[6]; // width/4 f0-5
unsigned char fright[3]; // width/4 f0-2
unsigned char bw[4]; // Klatt bandwidth BNZ /2, f1,f2,f3
unsigned char klattp[5]; // AV, FNZ, Tilt, Aspr, Skew
} frame_t2; // without the extra Klatt parameters

// formant data used by wavegen
typedef struct {
@@ -138,11 +131,11 @@ typedef struct {
DOUBLEX height1;
DOUBLEX left1;
DOUBLEX right1;
DOUBLEX freq_inc; // increment by this every 64 samples
DOUBLEX freq_inc; // increment by this every 64 samples
DOUBLEX height_inc;
DOUBLEX left_inc;
DOUBLEX right_inc;
} wavegen_peaks_t;
} wavegen_peaks_t;

typedef struct {
unsigned char *pitch_env;
@@ -153,8 +146,8 @@ typedef struct {
int pitch_range; // Hz*256 range of envelope

unsigned char *mix_wavefile; // wave file to be added to synthesis
int n_mix_wavefile; // length in bytes
int mix_wave_scale; // 0=2 byte samples
int n_mix_wavefile; // length in bytes
int mix_wave_scale; // 0=2 byte samples
int mix_wave_amp;
int mix_wavefile_ix;
int mix_wavefile_max; // length of available WAV data (in bytes)
@@ -165,30 +158,27 @@ typedef struct {
int amplitude_fmt; // percentage amplitude adjustment for formant synthesis
} WGEN_DATA;


typedef struct {
double a;
double b;
double c;
double x1;
double x2;
} RESONATOR;

} RESONATOR;

typedef struct {
short length_total; // not used
unsigned char n_frames;
unsigned char sqflags;
frame_t2 frame[N_SEQ_FRAMES]; // max. frames in a spectrum sequence
} SPECT_SEQ; // sequence of espeak formant frames
frame_t2 frame[N_SEQ_FRAMES]; // max. frames in a spectrum sequence
} SPECT_SEQ; // sequence of espeak formant frames

typedef struct {
short length_total; // not used
unsigned char n_frames;
unsigned char sqflags;
frame_t frame[N_SEQ_FRAMES]; // max. frames in a spectrum sequence
} SPECT_SEQK; // sequence of klatt formants frames

frame_t frame[N_SEQ_FRAMES]; // max. frames in a spectrum sequence
} SPECT_SEQK; // sequence of klatt formants frames

typedef struct {
short length;
@@ -198,22 +188,21 @@ typedef struct {

// a clause translated into phoneme codes (first stage)
typedef struct {
unsigned short synthflags; // NOTE Put shorts on 32bit boundaries, because of RISC OS compiler bug?
unsigned short synthflags; // NOTE Put shorts on 32bit boundaries, because of RISC OS compiler bug?
unsigned char phcode;
unsigned char stresslevel;
unsigned short sourceix; // ix into the original source text string, only set at the start of a word
unsigned char wordstress; // the highest level stress in this word
unsigned char wordstress; // the highest level stress in this word
unsigned char tone_ph; // tone phoneme to use with this vowel
} PHONEME_LIST2;


typedef struct {
// The first section is a copy of PHONEME_LIST2
// The first section is a copy of PHONEME_LIST2
unsigned short synthflags;
unsigned char phcode;
unsigned char stresslevel;
unsigned short sourceix; // ix into the original source text string, only set at the start of a word
unsigned char wordstress; // the highest level stress in this word
unsigned char wordstress; // the highest level stress in this word
unsigned char tone_ph; // tone phoneme to use with this vowel

PHONEME_TAB *ph;
@@ -231,7 +220,6 @@ typedef struct {
int sound_param;
} PHONEME_LIST;


#define pd_FMT 0
#define pd_WAV 1
#define pd_VWLSTART 2
@@ -259,7 +247,6 @@ typedef struct {
char ipa_string[18];
} PHONEME_DATA;


typedef struct {
int fmt_control;
int use_vowelin;
@@ -304,7 +291,6 @@ typedef struct {

#define i_ADD_LENGTH 0x0c


// conditions and jumps
#define i_CONDITION 0x2000
#define i_OR 0x1000 // added to i_CONDITION
@@ -347,23 +333,20 @@ typedef struct {
#define i_isSeqFlag1 0x8f
#define i_IsTranslationGiven 0x90


// place of articulation
#define i_isVel 0x28

// phflags
#define i_isSibilant 0x45 // bit 5 in phflags
#define i_isPalatal 0x49 // bit 9 in phflags
#define i_isLong 0x55 // bit 21 in phflags
#define i_isRhotic 0x57 // bit 23 in phflags
#define i_isSibilant 0x45 // bit 5 in phflags
#define i_isPalatal 0x49 // bit 9 in phflags
#define i_isLong 0x55 // bit 21 in phflags
#define i_isRhotic 0x57 // bit 23 in phflags
#define i_isFlag1 0x5c
#define i_isFlag2 0x5d
#define i_isFlag3 0x5e

#define i_StressLevel 0x800



typedef struct {
int name;
int length;
@@ -376,7 +359,7 @@ typedef struct {
unsigned int next_phoneme;
int mbr_name;
int mbr_name2;
int percent; // percentage length of first component
int percent; // percentage length of first component
int control;
} MBROLA_TAB;

@@ -392,7 +375,6 @@ typedef struct {
int fast_settings[8];
} SPEED_FACTORS;


typedef struct {
char name[12];
unsigned char flags[4];
@@ -413,14 +395,14 @@ typedef struct {
unsigned char head_max_steps;
unsigned char n_head_extend;

signed char unstr_start[3]; // for: onset, head, last
signed char unstr_start[3]; // for: onset, head, last
signed char unstr_end[3];

unsigned char nucleus0_env; // pitch envelope, tonic syllable is at end, no tail
unsigned char nucleus0_env; // pitch envelope, tonic syllable is at end, no tail
unsigned char nucleus0_max;
unsigned char nucleus0_min;

unsigned char nucleus1_env; // when followed by a tail
unsigned char nucleus1_env; // when followed by a tail
unsigned char nucleus1_max;
unsigned char nucleus1_min;
unsigned char tail_start;
@@ -434,7 +416,7 @@ typedef struct {
unsigned char split_tune;

unsigned char spare[8];
int spare2; // the struct length should be a multiple of 4 bytes
int spare2; // the struct length should be a multiple of 4 bytes
} TUNE;

extern int n_tunes;
@@ -472,8 +454,6 @@ extern unsigned char pitch_adjust_tab[MAX_PITCH_VALUE+1];
#define WCMD_FMT_AMPLITUDE 14
#define WCMD_SONIC_SPEED 15



#define N_WCMDQ 170
#define MIN_WCMDQ 25 // need this many free entries before adding new phoneme

@@ -494,7 +474,6 @@ float polint(float xa[], float ya[], int n, float x);
int WavegenFill(int fill_zeros);
void MarkerEvent(int type, unsigned int char_position, int value, int value2, unsigned char *out_ptr);


extern unsigned char *wavefile_data;
extern int samplerate;
extern int samplerate_native;
@@ -538,10 +517,9 @@ int Read4Bytes(FILE *f);
int Reverse4Bytes(int word);
int CompileDictionary(const char *dsource, const char *dict_name, FILE *log, char *err_name, int flags);


#define ENV_LEN 128 // length of pitch envelopes
#define PITCHfall 0 // standard pitch envelopes
#define PITCHrise 2
#define PITCHfall 0 // standard pitch envelopes
#define PITCHrise 2
#define N_ENVELOPE_DATA 20
extern unsigned char *envelope_data[N_ENVELOPE_DATA];


+ 364
- 359
src/libespeak-ng/tr_languages.c
File diff suppressed because it is too large
View File


+ 202
- 201
src/libespeak-ng/translate.c
File diff suppressed because it is too large
View File


+ 156
- 178
src/libespeak-ng/translate.h View File

@@ -22,99 +22,96 @@ extern "C"
{
#endif

#define L(c1, c2) (c1<<8)+c2 // combine two characters into an integer for translator name
#define L(c1, c2) (c1<<8)+c2 // combine two characters into an integer for translator name

#define CTRL_EMBEDDED 0x01 // control character at the start of an embedded command
#define REPLACED_E 'E' // 'e' replaced by silent e
#define CTRL_EMBEDDED 0x01 // control character at the start of an embedded command
#define REPLACED_E 'E' // 'e' replaced by silent e

#define N_WORD_PHONEMES 200 // max phonemes in a word
#define N_WORD_BYTES 160 // max bytes for the UTF8 characters in a word
#define N_CLAUSE_WORDS 300 // max words in a clause
#define N_TR_SOURCE 800 // the source text of a single clause (UTF8 bytes)
#define N_WORD_PHONEMES 200 // max phonemes in a word
#define N_WORD_BYTES 160 // max bytes for the UTF8 characters in a word
#define N_CLAUSE_WORDS 300 // max words in a clause
#define N_TR_SOURCE 800 // the source text of a single clause (UTF8 bytes)


#define N_RULE_GROUP2 120 // max num of two-letter rule chains
#define N_RULE_GROUP2 120 // max num of two-letter rule chains
#define N_HASH_DICT 1024
#define N_CHARSETS 20
#define N_LETTER_GROUPS 95 // maximum is 127-32

#define N_LETTER_GROUPS 95 // maximum is 127-32

/* dictionary flags, word 1 */
// dictionary flags, word 1
// bits 0-3 stressed syllable, bit 6=unstressed
#define FLAG_SKIPWORDS 0x80
#define FLAG_PREPAUSE 0x100

#define FLAG_STRESS_END 0x200 // full stress if at end of clause
#define FLAG_STRESS_END2 0x400 // full stress if at end of clause, or only followed by unstressed
#define FLAG_UNSTRESS_END 0x800 // reduce stress at end of clause
#define FLAG_SPELLWORD 0x1000 // re-translate the word as individual letters, separated by spaces
#define FLAG_ACCENT_BEFORE 0x1000 // say this accent name before the letter name
#define FLAG_ABBREV 0x2000 // spell as letters, even with a vowel, OR use specified pronunciation rather than split into letters
#define FLAG_DOUBLING 0x4000 // doubles the following consonant
#define BITNUM_FLAG_ALT 14 // bit number of FLAG_ALT_TRANS - 1
#define FLAG_ALT_TRANS 0x8000 // language specific
#define FLAG_ALT2_TRANS 0x10000 // language specific
#define FLAG_ALT3_TRANS 0x20000 // language specific
#define FLAG_ALT4_TRANS 0x40000 // language specific
#define FLAG_ALT5_TRANS 0x80000 // language specific
#define FLAG_ALT6_TRANS 0x100000 // language specific
#define FLAG_ALT7_TRANS 0x200000 // language specific
#define FLAG_COMBINE 0x800000 // combine with the next word
#define FLAG_ALLOW_DOT 0x01000000 // ignore '.' after word (abbreviation)
#define FLAG_NEEDS_DOT 0x02000000 // only if the word is followed by a dot
#define FLAG_STRESS_END 0x200 // full stress if at end of clause
#define FLAG_STRESS_END2 0x400 // full stress if at end of clause, or only followed by unstressed
#define FLAG_UNSTRESS_END 0x800 // reduce stress at end of clause
#define FLAG_SPELLWORD 0x1000 // re-translate the word as individual letters, separated by spaces
#define FLAG_ACCENT_BEFORE 0x1000 // say this accent name before the letter name
#define FLAG_ABBREV 0x2000 // spell as letters, even with a vowel, OR use specified pronunciation rather than split into letters
#define FLAG_DOUBLING 0x4000 // doubles the following consonant
#define BITNUM_FLAG_ALT 14 // bit number of FLAG_ALT_TRANS - 1
#define FLAG_ALT_TRANS 0x8000 // language specific
#define FLAG_ALT2_TRANS 0x10000 // language specific
#define FLAG_ALT3_TRANS 0x20000 // language specific
#define FLAG_ALT4_TRANS 0x40000 // language specific
#define FLAG_ALT5_TRANS 0x80000 // language specific
#define FLAG_ALT6_TRANS 0x100000 // language specific
#define FLAG_ALT7_TRANS 0x200000 // language specific
#define FLAG_COMBINE 0x800000 // combine with the next word
#define FLAG_ALLOW_DOT 0x01000000 // ignore '.' after word (abbreviation)
#define FLAG_NEEDS_DOT 0x02000000 // only if the word is followed by a dot
#define FLAG_WAS_UNPRONOUNCABLE 0x04000000 // the unpronounceable routine was used
#define FLAG_MAX3 0x08000000 // limit to 3 repeats
#define FLAG_PAUSE1 0x10000000 // shorter prepause
#define FLAG_TEXTMODE 0x20000000 // word translates to replacement text, not phonemes
#define FLAG_MAX3 0x08000000 // limit to 3 repeats
#define FLAG_PAUSE1 0x10000000 // shorter prepause
#define FLAG_TEXTMODE 0x20000000 // word translates to replacement text, not phonemes
#define BITNUM_FLAG_TEXTMODE 29

#define FLAG_FOUND_ATTRIBUTES 0x40000000 // word was found in the dictionary list (has attributes)
#define FLAG_FOUND 0x80000000 // pronunciation was found in the dictionary list
#define FLAG_FOUND_ATTRIBUTES 0x40000000 // word was found in the dictionary list (has attributes)
#define FLAG_FOUND 0x80000000 // pronunciation was found in the dictionary list

// dictionary flags, word 2
#define FLAG_VERBF 0x1 /* verb follows */
#define FLAG_VERBSF 0x2 /* verb follows, may have -s suffix */
#define FLAG_NOUNF 0x4 /* noun follows */
#define FLAG_PASTF 0x8 /* past tense follows */
#define FLAG_VERB 0x10 /* pronunciation for verb */
#define FLAG_NOUN 0x20 /* pronunciation for noun */
#define FLAG_PAST 0x40 /* pronunciation for past tense */
#define FLAG_VERB_EXT 0x100 /* extend the 'verb follows' */
#define FLAG_CAPITAL 0x200 /* pronunciation if initial letter is upper case */
#define FLAG_ALLCAPS 0x400 // only if the word is all capitals
#define FLAG_ACCENT 0x800 // character name is base-character name + accent name
#define FLAG_HYPHENATED 0x1000 // multiple-words, but needs hyphen between parts 1 and 2
#define FLAG_SENTENCE 0x2000 // only if the clause is a sentence
#define FLAG_VERBF 0x1 // verb follows
#define FLAG_VERBSF 0x2 // verb follows, may have -s suffix
#define FLAG_NOUNF 0x4 // noun follows
#define FLAG_PASTF 0x8 // past tense follows
#define FLAG_VERB 0x10 // pronunciation for verb
#define FLAG_NOUN 0x20 // pronunciation for noun
#define FLAG_PAST 0x40 // pronunciation for past tense
#define FLAG_VERB_EXT 0x100 // extend the 'verb follows'
#define FLAG_CAPITAL 0x200 // pronunciation if initial letter is upper case
#define FLAG_ALLCAPS 0x400 // only if the word is all capitals
#define FLAG_ACCENT 0x800 // character name is base-character name + accent name
#define FLAG_HYPHENATED 0x1000 // multiple-words, but needs hyphen between parts 1 and 2
#define FLAG_SENTENCE 0x2000 // only if the clause is a sentence
#define FLAG_ONLY 0x4000
#define FLAG_ONLY_S 0x8000
#define FLAG_STEM 0x10000 // must have a suffix
#define FLAG_ATEND 0x20000 // use this pronunciation if at end of clause
#define FLAG_ATSTART 0x40000 // use this pronunciation if at start of clause
#define FLAG_NATIVE 0x80000 // not if we've switched translators
#define FLAG_LOOKUP_SYMBOL 0x40000000 // to indicate called from Lookup()

#define BITNUM_FLAG_ALLCAPS 0x2a
#define BITNUM_FLAG_HYPHENATED 0x2c
#define BITNUM_FLAG_ONLY 0x2e
#define BITNUM_FLAG_ONLY_S 0x2f
#define FLAG_STEM 0x10000 // must have a suffix
#define FLAG_ATEND 0x20000 // use this pronunciation if at end of clause
#define FLAG_ATSTART 0x40000 // use this pronunciation if at start of clause
#define FLAG_NATIVE 0x80000 // not if we've switched translators
#define FLAG_LOOKUP_SYMBOL 0x40000000 // to indicate called from Lookup()

#define BITNUM_FLAG_ALLCAPS 0x2a
#define BITNUM_FLAG_HYPHENATED 0x2c
#define BITNUM_FLAG_ONLY 0x2e
#define BITNUM_FLAG_ONLY_S 0x2f

// wordflags, flags in source word
#define FLAG_ALL_UPPER 0x1 /* no lower case letters in the word */
#define FLAG_FIRST_UPPER 0x2 /* first letter is upper case */
#define FLAG_UPPERS 0x3 // FLAG_ALL_UPPER | FLAG_FIRST_UPPER
#define FLAG_HAS_PLURAL 0x4 /* upper-case word with s or 's lower-case ending */
#define FLAG_PHONEMES 0x8 /* word is phonemes */
#define FLAG_LAST_WORD 0x10 /* last word in clause */
#define FLAG_EMBEDDED 0x40 /* word is preceded by embedded commands */
#define FLAG_ALL_UPPER 0x1 // no lower case letters in the word
#define FLAG_FIRST_UPPER 0x2 // first letter is upper case
#define FLAG_UPPERS 0x3 // FLAG_ALL_UPPER | FLAG_FIRST_UPPER
#define FLAG_HAS_PLURAL 0x4 // upper-case word with s or 's lower-case ending
#define FLAG_PHONEMES 0x8 // word is phonemes
#define FLAG_LAST_WORD 0x10 // last word in clause
#define FLAG_EMBEDDED 0x40 // word is preceded by embedded commands
#define FLAG_HYPHEN 0x80
#define FLAG_NOSPACE 0x100 // word is not seperated from previous word by a space
#define FLAG_FIRST_WORD 0x200 // first word in clause
#define FLAG_FOCUS 0x400 // the focus word of a clause
#define FLAG_NOSPACE 0x100 // word is not seperated from previous word by a space
#define FLAG_FIRST_WORD 0x200 // first word in clause
#define FLAG_FOCUS 0x400 // the focus word of a clause
#define FLAG_EMPHASIZED 0x800
#define FLAG_EMPHASIZED2 0xc00 // FLAG_FOCUS | FLAG_EMPHASIZED
#define FLAG_EMPHASIZED2 0xc00 // FLAG_FOCUS | FLAG_EMPHASIZED
#define FLAG_DONT_SWITCH_TRANSLATOR 0x1000
#define FLAG_SUFFIX_REMOVED 0x2000
#define FLAG_HYPHEN_AFTER 0x4000
@@ -128,11 +125,10 @@ extern "C"
#define FLAG_TRANSLATOR2 0x400000 // retranslating using a different language
#define FLAG_PREFIX_REMOVED 0x800000 // a prefix has been removed from this word

#define FLAG_SUFFIX_VOWEL 0x08000000 // remember an initial vowel from the suffix
#define FLAG_NO_TRACE 0x10000000 // passed to TranslateRules() to suppress dictionary lookup printout
#define FLAG_SUFFIX_VOWEL 0x08000000 // remember an initial vowel from the suffix
#define FLAG_NO_TRACE 0x10000000 // passed to TranslateRules() to suppress dictionary lookup printout
#define FLAG_NO_PREFIX 0x20000000
#define FLAG_UNPRON_TEST 0x80000000 // do unpronounability test on the beginning of the word

#define FLAG_UNPRON_TEST 0x80000000 // do unpronounability test on the beginning of the word

// prefix/suffix flags (bits 8 to 14, bits 16 to 22) don't use 0x8000, 0x800000
#define SUFX_E 0x0100 // e may have been added
@@ -149,60 +145,56 @@ extern "C"

#define SUFX_UNPRON 0x8000 // used to return $unpron flag from *_rules


#define FLAG_ALLOW_TEXTMODE 0x02 // allow dictionary to translate to text rather than phonemes
#define FLAG_SUFX 0x04
#define FLAG_SUFX_S 0x08
#define FLAG_SUFX_E_ADDED 0x10


// codes in dictionary rules
#define RULE_PRE 1
#define RULE_POST 2
#define RULE_PHONEMES 3
#define RULE_PH_COMMON 4 // At start of rule. Its phoneme string is used by subsequent rules
#define RULE_CONDITION 5 // followed by condition number (byte)
#define RULE_PRE 1
#define RULE_POST 2
#define RULE_PHONEMES 3
#define RULE_PH_COMMON 4 // At start of rule. Its phoneme string is used by subsequent rules
#define RULE_CONDITION 5 // followed by condition number (byte)
#define RULE_GROUP_START 6
#define RULE_GROUP_END 7
#define RULE_PRE_ATSTART 8 // as RULE_PRE but also match with 'start of word'
#define RULE_LINENUM 9 // next 2 bytes give a line number, for debugging purposes
#define RULE_SPACE 32 // ascii space
#define RULE_SYLLABLE 21 // @
#define RULE_STRESSED 10 // &
#define RULE_DOUBLE 11 // %
#define RULE_INC_SCORE 12 // +
#define RULE_DEL_FWD 13 // #
#define RULE_ENDING 14 // S
#define RULE_DIGIT 15 // D digit
#define RULE_NONALPHA 16 // Z non-alpha
#define RULE_LETTERGP 17 // A B C H F G Y letter group number
#define RULE_LETTERGP2 18 // L + letter group number
#define RULE_CAPITAL 19 // ! word starts with a capital letter
#define RULE_REPLACEMENTS 20 // section for character replacements
#define RULE_SKIPCHARS 23 // J
#define RULE_NO_SUFFIX 24 // N
#define RULE_NOTVOWEL 25 // K
#define RULE_IFVERB 26 // V
#define RULE_DOLLAR 28 // $ commands
#define RULE_NOVOWELS 29 // X no vowels up to word boundary
#define RULE_SPELLING 31 // W while spelling letter-by-letter
#define RULE_LAST_RULE 31
#define RULE_GROUP_END 7
#define RULE_PRE_ATSTART 8 // as RULE_PRE but also match with 'start of word'
#define RULE_LINENUM 9 // next 2 bytes give a line number, for debugging purposes
#define RULE_SPACE 32 // ascii space
#define RULE_SYLLABLE 21 // @
#define RULE_STRESSED 10 // &
#define RULE_DOUBLE 11 // %
#define RULE_INC_SCORE 12 // +
#define RULE_DEL_FWD 13 // #
#define RULE_ENDING 14 // S
#define RULE_DIGIT 15 // D digit
#define RULE_NONALPHA 16 // Z non-alpha
#define RULE_LETTERGP 17 // A B C H F G Y letter group number
#define RULE_LETTERGP2 18 // L + letter group number
#define RULE_CAPITAL 19 // ! word starts with a capital letter
#define RULE_REPLACEMENTS 20 // section for character replacements
#define RULE_SKIPCHARS 23 // J
#define RULE_NO_SUFFIX 24 // N
#define RULE_NOTVOWEL 25 // K
#define RULE_IFVERB 26 // V
#define RULE_DOLLAR 28 // $ commands
#define RULE_NOVOWELS 29 // X no vowels up to word boundary
#define RULE_SPELLING 31 // W while spelling letter-by-letter
#define RULE_LAST_RULE 31

#define DOLLAR_UNPR 0x01
#define DOLLAR_NOPREFIX 0x02
#define DOLLAR_LIST 0x03


#define LETTERGP_A 0
#define LETTERGP_B 1
#define LETTERGP_C 2
#define LETTERGP_H 3
#define LETTERGP_F 4
#define LETTERGP_G 5
#define LETTERGP_Y 6
#define LETTERGP_VOWEL2 7

#define LETTERGP_A 0
#define LETTERGP_B 1
#define LETTERGP_C 2
#define LETTERGP_H 3
#define LETTERGP_F 4
#define LETTERGP_G 5
#define LETTERGP_Y 6
#define LETTERGP_VOWEL2 7

// Punctuation types returned by ReadClause()
// bits 0-11 pause x 10mS
@@ -215,14 +207,14 @@ extern "C"
// bit 22= dot after the last word
// bit 23= pause is x 320mS (not x 10mS)

#define CLAUSE_BIT_SENTENCE 0x80000
#define CLAUSE_BIT_CLAUSE 0x40000
#define CLAUSE_BIT_VOICE 0x20000
#define CLAUSE_BITS_INTONATION 0x7000
#define PUNCT_IN_WORD 0x100000
#define PUNCT_SAY_NAME 0x200000
#define CLAUSE_DOT 0x400000
#define CLAUSE_PAUSE_LONG 0x800000
#define CLAUSE_BIT_SENTENCE 0x80000
#define CLAUSE_BIT_CLAUSE 0x40000
#define CLAUSE_BIT_VOICE 0x20000
#define CLAUSE_BITS_INTONATION 0x7000
#define PUNCT_IN_WORD 0x100000
#define PUNCT_SAY_NAME 0x200000
#define CLAUSE_DOT 0x400000
#define CLAUSE_PAUSE_LONG 0x800000

#define CLAUSE_NONE ( 0 + 0x04000)
#define CLAUSE_PARAGRAPH (70 + 0x80000)
@@ -237,15 +229,15 @@ extern "C"
#define CLAUSE_COLON (30 + 0x40000)
#define CLAUSE_SEMICOLON (30 + 0x41000)

#define SAYAS_CHARS 0x12
#define SAYAS_GLYPHS 0x13
#define SAYAS_CHARS 0x12
#define SAYAS_GLYPHS 0x13
#define SAYAS_SINGLE_CHARS 0x14
#define SAYAS_KEY 0x24
#define SAYAS_DIGITS 0x40 // + number of digits
#define SAYAS_DIGITS1 0xc1
#define SAYAS_KEY 0x24
#define SAYAS_DIGITS 0x40 // + number of digits
#define SAYAS_DIGITS1 0xc1

#define CHAR_EMPHASIS 0x0530 // this is an unused character code
#define CHAR_COMMA_BREAK 0x0557 // unused character code
#define CHAR_EMPHASIS 0x0530 // this is an unused character code
#define CHAR_COMMA_BREAK 0x0557 // unused character code

// Rule:
// [4] [match] [1 pre] [2 post] [3 phonemes] 0
@@ -261,7 +253,6 @@ typedef struct {
char *del_fwd;
} MatchRecord;


// used to mark words with the source[] buffer
typedef struct {
unsigned int flags;
@@ -272,7 +263,6 @@ typedef struct {
unsigned char length;
} WORD_TAB;


typedef struct {
int type;
int parameter[N_SPEECH_PARAM];
@@ -281,7 +271,6 @@ typedef struct {
extern PARAM_STACK param_stack[];
extern const int param_defaults[N_SPEECH_PARAM];


typedef struct {
const char *name;
int offset;
@@ -293,21 +282,20 @@ typedef struct {
extern ALPHABET alphabets[];
extern ALPHABET *current_alphabet;
// alphabet flags
#define AL_DONT_NAME 0x01 // don't speak the alphabet name
#define AL_NOT_LETTERS 0x02 // don't use the language for speaking letters
#define AL_WORDS 0x04 // use the language to speak words
#define AL_NOT_CODE 0x08 // don't speak the character code
#define AL_NO_SYMBOL 0x10 // don't repeat "symbol" or "character"


#define N_LOPTS 21
#define LOPT_DIERESES 1
#define AL_DONT_NAME 0x01 // don't speak the alphabet name
#define AL_NOT_LETTERS 0x02 // don't use the language for speaking letters
#define AL_WORDS 0x04 // use the language to speak words
#define AL_NOT_CODE 0x08 // don't speak the character code
#define AL_NO_SYMBOL 0x10 // don't repeat "symbol" or "character"

#define N_LOPTS 21
#define LOPT_DIERESES 1
// 1=remove [:] from unstressed syllables, 2= remove from unstressed or non-penultimate syllables
// bit 4=0, if stress < 4, bit 4=1, if not the highest stress in the word
#define LOPT_IT_LENGTHEN 2
#define LOPT_IT_LENGTHEN 2

// 1=german
#define LOPT_PREFIXES 3
#define LOPT_PREFIXES 3

// non-zero, change voiced/unoiced to match last consonant in a cluster
// bit 0=use regressive voicing
@@ -316,26 +304,26 @@ extern ALPHABET *current_alphabet;
// bit 3=LANG=pl, propagate over liquids and nasals
// bit 4=LANG=cz,sk don't progagate to [v]
// bit 8=devoice word-final consonants
#define LOPT_REGRESSIVE_VOICING 4
#define LOPT_REGRESSIVE_VOICING 4

// 0=default, 1=no check, other allow this character as an extra initial letter (default is 's')
#define LOPT_UNPRONOUNCABLE 5
#define LOPT_UNPRONOUNCABLE 5

// select length_mods tables, (length_mod_tab) + (length_mod_tab0 * 100)
#define LOPT_LENGTH_MODS 6
#define LOPT_LENGTH_MODS 6

// increase this to prevent sonorants being shortened before shortened (eg. unstressed) vowels
#define LOPT_SONORANT_MIN 7
#define LOPT_SONORANT_MIN 7

// bit 0: don't break vowels at word boundary
#define LOPT_WORD_MERGE 8
#define LOPT_WORD_MERGE 8

// max. amplitude for vowel at the end of a clause
#define LOPT_MAXAMP_EOC 9
#define LOPT_MAXAMP_EOC 9

// bit 0=reduce even if phonemes are specified in the **_list file
// bit 1=don't reduce the strongest vowel in a word which is marked 'unstressed'
#define LOPT_REDUCE 10
#define LOPT_REDUCE 10

// LANG=cs,sk combine some prepositions with the following word, if the combination has N or fewer syllables
// bits 0-3 N syllables
@@ -348,15 +336,15 @@ extern ALPHABET *current_alphabet;

// 1 = allow capitals inside a word
// 2 = stressed syllable is indicated by capitals
#define LOPT_CAPS_IN_WORD 13
#define LOPT_CAPS_IN_WORD 13

// bit 0=Italian "syntactic doubling" of consoants in the word after a word marked with $double attribute
// bit 1=also after a word which ends with a stressed vowel
#define LOPT_IT_DOUBLING 14
#define LOPT_IT_DOUBLING 14

// Call ApplySpecialAttributes() if $alt or $alt2 is set for a word
// bit 1: stressed syllable: $alt change [e],[o] to [E],[O], $alt2 change [E],[O] to [e],[o]
#define LOPT_ALT 15
#define LOPT_ALT 15

// pause for bracket (default=4), pause when annoucing bracket names (default=2)
#define LOPT_BRACKET_PAUSE 16
@@ -368,20 +356,18 @@ extern ALPHABET *current_alphabet;
#define LOPT_LONG_VOWEL_THRESHOLD 18

// bit 0: Don't allow suffices if there is no previous syllable
#define LOPT_SUFFIX 19
#define LOPT_SUFFIX 19

// bit 0 Apostrophe at start of word is part of the word
// bit 1 Apostrophe at end of word is part of the word
#define LOPT_APOSTROPHE 20

#define LOPT_APOSTROPHE 20

// stress_rule
#define STRESSPOSN_1L 0 // 1st syllable
#define STRESSPOSN_2L 1 // 2nd syllable
#define STRESSPOSN_2R 2 // penultimate
#define STRESSPOSN_1R 3 // final syllable
#define STRESSPOSN_3R 4 // antipenultimate

#define STRESSPOSN_1L 0 // 1st syllable
#define STRESSPOSN_2L 1 // 2nd syllable
#define STRESSPOSN_2R 2 // penultimate
#define STRESSPOSN_1R 3 // final syllable
#define STRESSPOSN_3R 4 // antipenultimate

typedef struct {
// bits0-2 separate words with (1=pause_vshort, 2=pause_short, 3=pause, 4=pause_long 5=[?] phonemme)
@@ -445,7 +431,6 @@ typedef struct {

// bit15= Give stress to the first unstressed syllable


int stress_flags;
int unstressed_wd1; // stress for $u word of 1 syllable
int unstressed_wd2; // stress for $u word of >1 syllable
@@ -531,7 +516,7 @@ typedef struct {
#define NUM2_PERCENT_BEFORE 0x10000
#define NUM2_OMIT_1_HUNDRED_ONLY 0x20000
#define NUM2_ORDINAL_AND_THOUSANDS 0x40000
#define NUM2_ORDINAL_DROP_VOWEL 0x80000 // currently only for tens and units
#define NUM2_ORDINAL_DROP_VOWEL 0x80000 // currently only for tens and units
#define NUM2_ZERO_TENS 0x100000
// bits 1-4 use variant form of numbers before thousands,millions,etc.
// bits 6-8 use different forms of thousand, million, etc (M MA MB)
@@ -588,7 +573,6 @@ typedef struct {
int dict_dialect; // bitmap, use a dialect for foreign words
} LANGUAGE_OPTIONS;


// a parameter of ChangePhonemes()
typedef struct {
int flags;
@@ -599,10 +583,7 @@ typedef struct {
unsigned char vowel_stressed; // syllable number of the highest stressed vowel
} CHANGEPH;



typedef struct {

LANGUAGE_OPTIONS langopts;
int translator_name;
int transpose_max;
@@ -630,8 +611,8 @@ typedef struct {
const wchar_t *letter_groups[8];

/* index1=option, index2 by 0=. 1=, 2=?, 3=! 4=none */
#define INTONATION_TYPES 8
#define PUNCT_INTONATIONS 6
#define INTONATION_TYPES 8
#define PUNCT_INTONATIONS 6
unsigned char punct_to_tone[INTONATION_TYPES][PUNCT_INTONATIONS];

char *data_dictrules; // language_1 translation rules file
@@ -671,7 +652,6 @@ typedef struct {
int clause_terminator;
} Translator;


extern int option_tone2;
#define OPTION_EMPHASIZE_ALLCAPS 0x100
#define OPTION_EMPHASIZE_PENULTIMATE 0x200
@@ -704,8 +684,6 @@ extern int clause_start_word;
extern char *namedata;
extern int pre_pause;



#define N_MARKER_LENGTH 50 // max.length of a mark name
extern char skip_marker[N_MARKER_LENGTH];

@@ -796,9 +774,9 @@ void InterpretPhoneme(Translator *tr, int control, PHONEME_LIST *plist, PHONEME_
void InterpretPhoneme2(int phcode, PHONEME_DATA *phdata);
char *WritePhMnemonic(char *phon_out, PHONEME_TAB *ph, PHONEME_LIST *plist, int use_ipa, int *flags);

extern FILE *f_trans; // for logging
extern FILE *f_trans; // for logging
extern FILE *f_logespeak;
extern int logging_type; // from config file
extern int logging_type; // from config file

#ifdef __cplusplus
}

+ 6
- 8
src/libespeak-ng/voice.h View File

@@ -22,15 +22,13 @@ extern "C"
{
#endif



typedef struct {
char v_name[40];
char language_name[20];

int phoneme_tab_ix; // phoneme table number
int pitch_base; // Hz<<12
int pitch_range; // standard = 0x1000
int phoneme_tab_ix; // phoneme table number
int pitch_base; // Hz<<12
int pitch_range; // standard = 0x1000

int speedf1;
int speedf2;
@@ -44,7 +42,7 @@ typedef struct {
int n_harmonic_peaks; // highest formant which is formed from adding harmonics
int peak_shape; // alternative shape for formant peaks (0=standard 1=squarer)
int voicing; // 100% = 64, level of formant-synthesized sound
int formant_factor; // adjust nominal formant frequencies by this because of the voice's pitch (256ths)
int formant_factor; // adjust nominal formant frequencies by this because of the voice's pitch (256ths)
int consonant_amp; // amplitude of unvoiced consonants
int consonant_ampv; // amplitude of the noise component of voiced consonants
int samplerate;
@@ -54,7 +52,7 @@ typedef struct {
short freq[N_PEAKS]; // 100% = 256
short height[N_PEAKS]; // 100% = 256
short width[N_PEAKS]; // 100% = 256
short freqadd[N_PEAKS]; // Hz
short freqadd[N_PEAKS]; // Hz

// copies without temporary adjustments from embedded commands
short freq2[N_PEAKS]; // 100% = 256
@@ -62,7 +60,7 @@ typedef struct {
short width2[N_PEAKS]; // 100% = 256

int breath[N_PEAKS]; // amount of breath for each formant. breath[0] indicates whether any are set.
int breathw[N_PEAKS]; // width of each breath formant
int breathw[N_PEAKS]; // width of each breath formant

// This table provides the opportunity for tone control.
// Adjustment of harmonic amplitudes, steps of 8Hz

+ 147
- 147
src/libespeak-ng/voices.c View File

@@ -56,8 +56,8 @@ MNEM_TAB genders[] = {
int tone_points[12] = { 600, 170, 1200, 135, 2000, 110, 3000, 110, -1, 0 };

// limit the rate of change for each formant number
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
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

#define DEFAULT_LANGUAGE_PRIORITY 5
#define N_VOICES_LIST 250
@@ -75,7 +75,7 @@ enum {
V_PHONEMES,
V_DICTIONARY,

// these affect voice quality, are independent of language
// these affect voice quality, are independent of language
V_FORMANT,
V_PITCH,
V_ECHO,
@@ -87,7 +87,7 @@ enum {
V_BREATH,
V_BREATHW,

// these override defaults set by the translator
// these override defaults set by the translator
V_WORDGAP,
V_INTONATION,
V_TUNES,
@@ -109,72 +109,74 @@ enum {
V_ALPHABET2,
V_DICTDIALECT,

// these need a phoneme table to have been specified
// these need a phoneme table to have been specified
V_REPLACE,
V_CONSONANTS
};

static MNEM_TAB options_tab[] = {
{ "reduce_t", LOPT_REDUCE_T },
{ "bracket", LOPT_BRACKET_PAUSE },
{ "reduce_t", LOPT_REDUCE_T },
{ "bracket", LOPT_BRACKET_PAUSE },
{ NULL, -1 }
};

static MNEM_TAB keyword_tab[] = {
{ "name", V_NAME },
{ "language", V_LANGUAGE },
{ "gender", V_GENDER },
{ "formant", V_FORMANT },
{ "pitch", V_PITCH },
{ "phonemes", V_PHONEMES },
{ "translator", V_TRANSLATOR },
{ "dictionary", V_DICTIONARY },
{ "name", V_NAME },
{ "language", V_LANGUAGE },
{ "gender", V_GENDER },
{ "formant", V_FORMANT },
{ "pitch", V_PITCH },
{ "phonemes", V_PHONEMES },
{ "translator", V_TRANSLATOR },
{ "dictionary", V_DICTIONARY },
{ "stressLength", V_STRESSLENGTH },
{ "stressAmp", V_STRESSAMP },
{ "stressAdd", V_STRESSADD },
{ "intonation", V_INTONATION },
{ "tunes", V_TUNES },
{ "dictrules", V_DICTRULES },
{ "stressrule", V_STRESSRULE },
{ "stressopt", V_STRESSOPT },
{ "charset", V_CHARSET },
{ "replace", V_REPLACE },
{ "words", V_WORDGAP },
{ "echo", V_ECHO },
{ "flutter", V_FLUTTER },
{ "roughness", V_ROUGHNESS },
{ "clarity", V_CLARITY },
{ "tone", V_TONE },
{ "voicing", V_VOICING },
{ "breath", V_BREATH },
{ "breathw", V_BREATHW },
{ "numbers", V_NUMBERS },
{ "option", V_OPTION },
{ "mbrola", V_MBROLA },
{ "consonants", V_CONSONANTS },
{ "klatt", V_KLATT },
{ "fast_test2", V_FAST },
{ "speed", V_SPEED },
{ "dict_min", V_DICTMIN },
{ "alphabet2", V_ALPHABET2 },
{ "dictdialect", V_DICTDIALECT },
{ "stressAmp", V_STRESSAMP },
{ "stressAdd", V_STRESSADD },
{ "intonation", V_INTONATION },
{ "tunes", V_TUNES },
{ "dictrules", V_DICTRULES },
{ "stressrule", V_STRESSRULE },
{ "stressopt", V_STRESSOPT },
{ "charset", V_CHARSET },
{ "replace", V_REPLACE },
{ "words", V_WORDGAP },
{ "echo", V_ECHO },
{ "flutter", V_FLUTTER },
{ "roughness", V_ROUGHNESS },
{ "clarity", V_CLARITY },
{ "tone", V_TONE },
{ "voicing", V_VOICING },
{ "breath", V_BREATH },
{ "breathw", V_BREATHW },
{ "numbers", V_NUMBERS },
{ "option", V_OPTION },
{ "mbrola", V_MBROLA },
{ "consonants", V_CONSONANTS },
{ "klatt", V_KLATT },
{ "fast_test2", V_FAST },
{ "speed", V_SPEED },
{ "dict_min", V_DICTMIN },
{ "alphabet2", V_ALPHABET2 },
{ "dictdialect", V_DICTDIALECT },

// these just set a value in langopts.param[]
{ "l_dieresis", 0x100+LOPT_DIERESES },
{ "l_prefix", 0x100+LOPT_PREFIXES },
{ "l_regressive_v", 0x100+LOPT_REGRESSIVE_VOICING },
{ "l_dieresis", 0x100+LOPT_DIERESES },
{ "l_prefix", 0x100+LOPT_PREFIXES },
{ "l_regressive_v", 0x100+LOPT_REGRESSIVE_VOICING },
{ "l_unpronouncable", 0x100+LOPT_UNPRONOUNCABLE },
{ "l_sonorant_min", 0x100+LOPT_SONORANT_MIN },
{ "l_length_mods", 0x100+LOPT_LENGTH_MODS },
{ "apostrophe", 0x100+LOPT_APOSTROPHE },
{ NULL, 0 }
{ "l_sonorant_min", 0x100+LOPT_SONORANT_MIN },
{ "l_length_mods", 0x100+LOPT_LENGTH_MODS },
{ "apostrophe", 0x100+LOPT_APOSTROPHE },

{ NULL, 0 }
};

static MNEM_TAB dict_dialects[] = {
{ "en-us", DICTDIALECT_EN_US },
{ "es-la", DICTDIALECT_ES_LA },
{ NULL, 0 }
{ "en-us", DICTDIALECT_EN_US },
{ "es-la", DICTDIALECT_ES_LA },

{ NULL, 0 }
};

#define N_VOICE_VARIANTS 12
@@ -188,7 +190,7 @@ voice_t *voice = &voicedata;

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
int len;
char *p;

@@ -238,7 +240,7 @@ static void SetToneAdjust(voice_t *voice, int *tone_pts)
if (pt > 0)
tone_pts[pt+1] = tone_pts[pt-1];
}
freq2 = tone_pts[pt] / 8; // 8Hz steps
freq2 = tone_pts[pt] / 8; // 8Hz steps
height2 = tone_pts[pt+1];
if ((freq2 - freq1) > 0) {
rate = (double)(height2-height1)/(freq2-freq1);
@@ -257,7 +259,7 @@ static void SetToneAdjust(voice_t *voice, int *tone_pts)

void ReadTonePoints(char *string, int *tone_pts)
{
// tone_pts[] is int[12]
// tone_pts[] is int[12]
int ix;

for (ix = 0; ix < 12; ix++)
@@ -271,14 +273,14 @@ void ReadTonePoints(char *string, int *tone_pts)

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
// file's language, gender, name lines
// Read a Voice file, allocate a VOICE_DATA and set data from the
// file's language, gender, name lines

char linebuf[120];
char vname[80];
char vgender[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;
int langix = 0;
@@ -287,7 +289,7 @@ static espeak_VOICE *ReadVoiceFile(FILE *f_in, const char *fname, const char *le
espeak_VOICE *voice_data;
int priority;
int age;
int n_variants = 4; // default, number of variants of this voice before using another voice
int n_variants = 4; // default, number of variants of this voice before using another voice
int gender;

#ifdef PLATFORM_WINDOWS
@@ -336,7 +338,7 @@ static espeak_VOICE *ReadVoiceFile(FILE *f_in, const char *fname, const char *le
gender = LookupMnem(genders, vgender);

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

p = (char *)calloc(sizeof(espeak_VOICE) + langix + strlen(fname) + strlen(vname) + 3, 1);
voice_data = (espeak_VOICE *)p;
@@ -364,10 +366,10 @@ static espeak_VOICE *ReadVoiceFile(FILE *f_in, const char *fname, const char *le

void VoiceReset(int tone_only)
{
// Set voice to the default values
// Set voice to the default values

int pk;
static unsigned char default_heights[N_PEAKS] = { 130, 128, 120, 116, 100, 100, 128, 128, 128 }; // changed for v.1.47
static unsigned char default_heights[N_PEAKS] = { 130, 128, 120, 116, 100, 100, 128, 128, 128 }; // changed for v.1.47
static unsigned char default_widths[N_PEAKS] = { 140, 128, 128, 160, 171, 171, 128, 128, 128 };

static int breath_widths[N_PEAKS] = { 0, 200, 200, 400, 400, 400, 600, 600, 600 };
@@ -385,7 +387,7 @@ void VoiceReset(int tone_only)
voice->n_harmonic_peaks = 5;
voice->peak_shape = 0;
voice->voicing = 64;
voice->consonant_amp = 90; // change from 100 to 90 for v.1.47
voice->consonant_amp = 90; // change from 100 to 90 for v.1.47
voice->consonant_ampv = 100;
voice->samplerate = samplerate_native;
memset(voice->klattv, 0, sizeof(voice->klattv));
@@ -406,7 +408,7 @@ void VoiceReset(int tone_only)
voice->height[pk] = default_heights[pk]*2;
voice->width[pk] = default_widths[pk]*2;
voice->breath[pk] = 0;
voice->breathw[pk] = breath_widths[pk]; // default breath formant woidths
voice->breathw[pk] = breath_widths[pk]; // default breath formant woidths
voice->freqadd[pk] = 0;

// adjust formant smoothing depending on sample rate
@@ -470,7 +472,7 @@ static void PhonemeReplacement(int type, char *p)
return;

if ((phon = LookupPhonemeString(phon_string1)) == 0)
return; // not recognised
return; // not recognised

replace_phonemes[n_replace_phonemes].old_ph = phon;
replace_phonemes[n_replace_phonemes].new_ph = LookupPhonemeString(phon_string2);
@@ -479,7 +481,7 @@ static void PhonemeReplacement(int type, char *p)

static int Read8Numbers(char *data_in, int *data)
{
// Read 8 integer numbers
// Read 8 integer numbers
memset(data, 0, 8+sizeof(int));
return sscanf(data_in, "%d %d %d %d %d %d %d %d",
&data[0], &data[1], &data[2], &data[3], &data[4], &data[5], &data[6], &data[7]);
@@ -487,7 +489,7 @@ static int Read8Numbers(char *data_in, int *data)

static unsigned int StringToWord2(const char *string)
{
// Convert a language name string to a word such as L('e','n')
// Convert a language name string to a word such as L('e','n')
int ix;
int c;
unsigned int value = 0;
@@ -499,10 +501,10 @@ static unsigned int StringToWord2(const char *string)

voice_t *LoadVoice(const char *vname, int control)
{
// control, bit 0 1= no_default
// bit 1 1 = change tone only, not language
// bit 2 1 = don't report error on LoadDictionary
// bit 4 1 = vname = full path
// control, bit 0 1= no_default
// bit 1 1 = change tone only, not language
// bit 2 1 = don't report error on LoadDictionary
// bit 4 1 = vname = full path

FILE *f_voice = NULL;
char *p;
@@ -545,9 +547,9 @@ voice_t *LoadVoice(const char *vname, int control)
int pitch1;
int pitch2;

static char voice_identifier[40]; // file name for current_voice_selected
static char voice_name[40]; // voice name for current_voice_selected
static char voice_languages[100]; // list of languages and priorities for current_voice_selected
static char voice_identifier[40]; // file name for current_voice_selected
static char voice_name[40]; // voice name for current_voice_selected
static char voice_languages[100]; // list of languages and priorities for current_voice_selected

// which directory to look for a named voice. List of voice names, must end in a space.
static const char *voices_asia =
@@ -565,12 +567,12 @@ voice_t *LoadVoice(const char *vname, int control)
strcpy(voicename, "default");

sprintf(path_voices, "%s%cvoices%c", path_home, PATHSEP, PATHSEP);
sprintf(buf, "%s%s", path_voices, voicename); // first, look in the main voices directory
sprintf(buf, "%s%s", path_voices, voicename); // first, look in the main voices directory

if (GetFileLength(buf) <= 0) {
// then look in the appropriate subdirectory
if ((voicename[0] == 'm') && (voicename[1] == 'b'))
voice_dir = "mb"; // mbrola voices
voice_dir = "mb"; // mbrola voices
else {
sprintf(name2, "%s ", voicename);
if (strstr(voices_europe, voicename) != NULL)
@@ -592,10 +594,10 @@ voice_t *LoadVoice(const char *vname, int control)

f_voice = fopen(buf, "r");

language_type = "en"; // default
language_type = "en"; // default
if (f_voice == NULL) {
if (control & 3)
return NULL; // can't open file
return NULL; // can't open file

if (SelectPhonemeTableName(voicename) >= 0)
language_type = voicename;
@@ -630,7 +632,7 @@ voice_t *LoadVoice(const char *vname, int control)
VoiceReset(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)) {
// isolate the attribute name
@@ -711,10 +713,10 @@ voice_t *LoadVoice(const char *vname, int control)
new_translator = SelectTranslator(translator_name);
langopts = &new_translator->langopts;
break;
case V_DICTIONARY: // dictionary
case V_DICTIONARY: // dictionary
sscanf(p, "%s", new_dictionary);
break;
case V_PHONEMES: // phoneme table
case V_PHONEMES: // phoneme table
sscanf(p, "%s", phonemes_name);
break;
case V_FORMANT:
@@ -728,19 +730,19 @@ voice_t *LoadVoice(const char *vname, int control)
voice->pitch_base = (pitch1 - 9) << 12;
voice->pitch_range = (pitch2 - pitch1) * 108;
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;
case V_STRESSLENGTH: // stressLength
case V_STRESSLENGTH: // stressLength
stress_lengths_set = Read8Numbers(p, stress_lengths);
break;
case V_STRESSAMP: // stressAmp
case V_STRESSAMP: // stressAmp
stress_amps_set = Read8Numbers(p, stress_amps);
break;
case V_STRESSADD: // stressAdd
case V_STRESSADD: // stressAdd
stress_add_set = Read8Numbers(p, stress_add);
break;
case V_INTONATION: // intonation
case V_INTONATION: // intonation
sscanf(p, "%d %d", &option_tone_flags, &option_tone2);
if ((option_tone_flags & 0xff) != 0)
langopts->intonation_group = option_tone_flags & 0xff;
@@ -758,7 +760,7 @@ voice_t *LoadVoice(const char *vname, int control)
langopts->tunes[ix] = value;
}
break;
case V_DICTRULES: // conditional dictionary rules and list entries
case V_DICTRULES: // conditional dictionary rules and list entries
case V_NUMBERS:
case V_STRESSOPT:
// expect a list of numbers
@@ -793,7 +795,7 @@ voice_t *LoadVoice(const char *vname, int control)
}
PhonemeReplacement(key, p);
break;
case V_WORDGAP: // words
case V_WORDGAP: // words
sscanf(p, "%d %d", &langopts->word_gap, &langopts->vowel_pause);
break;
case V_STRESSRULE:
@@ -821,18 +823,18 @@ voice_t *LoadVoice(const char *vname, int control)
voice->echo_amp = 0;
sscanf(p, "%d %d", &voice->echo_delay, &voice->echo_amp);
break;
case V_FLUTTER: // flutter
case V_FLUTTER: // flutter
if (sscanf(p, "%d", &value) == 1)
voice->flutter = value * 32;
break;
case V_ROUGHNESS: // roughness
case V_ROUGHNESS: // roughness
if (sscanf(p, "%d", &value) == 1)
voice->roughness = value;
break;
case V_CLARITY: // formantshape
case V_CLARITY: // formantshape
if (sscanf(p, "%d", &value) == 1) {
if (value > 4) {
voice->peak_shape = 1; // squarer formant peaks
voice->peak_shape = 1; // squarer formant peaks
value = 4;
}
voice->n_harmonic_peaks = 1+value;
@@ -871,14 +873,13 @@ voice_t *LoadVoice(const char *vname, int control)

name2[0] = 0;
sscanf(p, "%s %s %d", name1, name2, &srate);
if (LoadMbrolaTable(name1, name2, &srate) != EE_OK) {
if (LoadMbrolaTable(name1, name2, &srate) != EE_OK)
fprintf(stderr, "mbrola voice not found\n");
}
voice->samplerate = srate;
}
break;
case V_KLATT:
voice->klattv[0] = 1; // default source: IMPULSIVE
voice->klattv[0] = 1; // default source: IMPULSIVE
Read8Numbers(p, voice->klattv);
voice->klattv[KLATT_Kopen] -= 40;
break;
@@ -929,7 +930,7 @@ voice_t *LoadVoice(const char *vname, int control)
new_translator = SelectTranslator(translator_name);
}

SetSpeed(3); // for speed_percent
SetSpeed(3); // for speed_percent

for (ix = 0; ix < N_PEAKS; ix++) {
voice->freq2[ix] = voice->freq[ix];
@@ -950,7 +951,7 @@ voice_t *LoadVoice(const char *vname, int control)
LoadDictionary(new_translator, new_dictionary, control & 4);
if (dictionary_name[0] == 0) {
DeleteTranslator(new_translator);
return NULL; // no dictionary loaded
return NULL; // no dictionary loaded
}

new_translator->dict_condition = conditional_rules;
@@ -960,7 +961,6 @@ voice_t *LoadVoice(const char *vname, int control)

langopts = &new_translator->langopts;


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

@@ -969,7 +969,6 @@ voice_t *LoadVoice(const char *vname, int control)
if (!tone_only)
translator = new_translator;


// relative lengths of different stress syllables
for (ix = 0; ix < stress_lengths_set; ix++)
translator->stress_lengths[ix] = stress_lengths[ix];
@@ -985,8 +984,8 @@ voice_t *LoadVoice(const char *vname, int control)

static char *ExtractVoiceVariantName(char *vname, int variant_num, int add_dir)
{
// Remove any voice variant suffix (name or number) from a voice name
// Returns the voice variant name
// Remove any voice variant suffix (name or number) from a voice name
// Returns the voice variant name

char *p;
static char variant_name[40];
@@ -1001,9 +1000,9 @@ static char *ExtractVoiceVariantName(char *vname, int variant_num, int add_dir)
if ((p = strchr(vname, '+')) != NULL) {
// The voice name has a +variant suffix
variant_num = 0;
*p++ = 0; // delete the suffix from the voice name
*p++ = 0; // delete the suffix from the voice name
if (IsDigit09(*p))
variant_num = atoi(p); // variant number
variant_num = atoi(p); // variant number
else {
// voice variant name, not number
sprintf(variant_name, "%s%s", variant_prefix, p);
@@ -1013,9 +1012,9 @@ static char *ExtractVoiceVariantName(char *vname, int variant_num, int add_dir)

if (variant_num > 0) {
if (variant_num < 10)
sprintf(variant_name, "%sm%d", variant_prefix, variant_num); // male
sprintf(variant_name, "%sm%d", variant_prefix, variant_num); // male
else
sprintf(variant_name, "%sf%d", variant_prefix, variant_num-10); // female
sprintf(variant_name, "%sf%d", variant_prefix, variant_num-10); // female
}

return variant_name;
@@ -1023,8 +1022,8 @@ static char *ExtractVoiceVariantName(char *vname, int variant_num, int add_dir)

voice_t *LoadVoiceVariant(const char *vname, int variant_num)
{
// Load a voice file.
// Also apply a voice variant if specified by "variant", or by "+number" or "+name" in the "vname"
// Load a voice file.
// Also apply a voice variant if specified by "variant", or by "+number" or "+name" in the "vname"

voice_t *v;
char *variant_name;
@@ -1047,9 +1046,9 @@ static int __cdecl VoiceNameSorter(const void *p1, const void *p2)
espeak_VOICE *v1 = *(espeak_VOICE **)p1;
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;
if ((ix = v1->languages[0] - v2->languages[0]) != 0) // priority number
if ((ix = v1->languages[0] - v2->languages[0]) != 0) // priority number
return ix;
return strcmp(v1->name, v2->name);
}
@@ -1080,7 +1079,7 @@ static int ScoreVoice(espeak_VOICE *voice_spec, const char *spec_language, int s
int required_age;
int diff;

p = voice->languages; // list of languages+dialects for which this voice is suitable
p = voice->languages; // list of languages+dialects for which this voice is suitable

if (spec_n_parts < 0) {
// match on the subdirectory
@@ -1123,10 +1122,10 @@ static int ScoreVoice(espeak_VOICE *voice_spec, const char *spec_language, int s
break;
}
p += (ix+1);
matching_parts += matching; // number of parts which match
matching_parts += matching; // number of parts which match

if (matching_parts == 0)
continue; // no matching parts for this language
continue; // no matching parts for this language

x = 5;
// reduce the score if not all parts of the required language match
@@ -1163,7 +1162,7 @@ static int ScoreVoice(espeak_VOICE *voice_spec, const char *spec_language, int s
}

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

if (voice->age != 0) {
if (voice_spec->age == 0)
@@ -1174,14 +1173,14 @@ static int ScoreVoice(espeak_VOICE *voice_spec, const char *spec_language, int s
ratio = (required_age*100)/voice->age;
if (ratio < 100)
ratio = 10000/ratio;
ratio = (ratio - 100)/10; // 0=exact match, 10=out by factor of 2
ratio = (ratio - 100)/10; // 0=exact match, 10=out by factor of 2
x = 5 - ratio;
if (x > 0) x = 0;

score = score + x;

if (voice_spec->age > 0)
score += 10; // required age specified, favour voices with a specified age (near it)
score += 10; // required age specified, favour voices with a specified age (near it)
}
if (score < 1)
score = 1;
@@ -1190,10 +1189,10 @@ static int ScoreVoice(espeak_VOICE *voice_spec, const char *spec_language, int s

static int SetVoiceScores(espeak_VOICE *voice_select, espeak_VOICE **voices, int control)
{
// control: bit0=1 include mbrola voices
// control: bit0=1 include mbrola voices
int ix;
int score;
int nv; // number of candidates
int nv; // number of candidates
int n_parts = 0;
int lang_len = 0;
espeak_VOICE *vp;
@@ -1212,7 +1211,7 @@ static int SetVoiceScores(espeak_VOICE *voice_select, espeak_VOICE **voices, int

if ((n_parts == 1) && (control & 1)) {
if (strcmp(language, "mbrola") == 0) {
language[2] = 0; // truncate to "mb"
language[2] = 0; // truncate to "mb"
lang_len = 2;
}

@@ -1238,7 +1237,7 @@ static int SetVoiceScores(espeak_VOICE *voice_select, espeak_VOICE **voices, int
vp->score = score;
}
}
voices[nv] = NULL; // list terminator
voices[nv] = NULL; // list terminator

if (nv == 0)
return 0;
@@ -1255,7 +1254,7 @@ espeak_VOICE *SelectVoiceByName(espeak_VOICE **voices, const char *name2)
int match_fname = -1;
int match_fname2 = -1;
int match_name = -1;
const char *id; // this is the filename within espeak-data/voices
const char *id; // this is the filename within espeak-data/voices
char *variant_name;
int last_part_len;
char last_part[41];
@@ -1263,7 +1262,7 @@ espeak_VOICE *SelectVoiceByName(espeak_VOICE **voices, const char *name2)

if (voices == NULL) {
if (n_voices_list == 0)
espeak_ListVoices(NULL); // create the voices list
espeak_ListVoices(NULL); // create the voices list
voices = voices_list;
}

@@ -1278,21 +1277,21 @@ espeak_VOICE *SelectVoiceByName(espeak_VOICE **voices, const char *name2)

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

if (match_name < 0) {
match_name = match_fname; // no matching name, try matching filename
match_name = match_fname; // no matching name, try matching filename
if (match_name < 0)
match_name = match_fname2; // try matching just the last part of the filename
match_name = match_fname2; // try matching just the last part of the filename
}

if (match_name < 0)
@@ -1303,9 +1302,10 @@ espeak_VOICE *SelectVoiceByName(espeak_VOICE **voices, const char *name2)

char const *SelectVoice(espeak_VOICE *voice_select, int *found)
{
// Returns a path within espeak-voices, with a possible +variant suffix
// variant is an output-only parameter
int nv; // number of candidates
// Returns a path within espeak-voices, with a possible +variant suffix
// variant is an output-only parameter

int nv; // number of candidates
int ix, ix2;
int j;
int n_variants;
@@ -1327,7 +1327,7 @@ char const *SelectVoice(espeak_VOICE *voice_select, int *found)
memcpy(&voice_select2, voice_select, sizeof(voice_select2));

if (n_voices_list == 0)
espeak_ListVoices(NULL); // create the voices list
espeak_ListVoices(NULL); // create the voices list

if ((voice_select2.languages == NULL) || (voice_select2.languages[0] == 0)) {
// no language is specified. Get language from the named voice
@@ -1372,13 +1372,13 @@ char const *SelectVoice(espeak_VOICE *voice_select, int *found)
else if (voice_select2.gender == 1)
gender = 1;

#define AGE_OLD 60
#define AGE_OLD 60
if (voice_select2.age < AGE_OLD)
aged = 0;

p = p_start = variant_lists[gender];
if (aged == 0)
p++; // the first voice in the variants list is older
p++; // the first voice in the variants list is older

// add variants for the top voices
n_variants = 0;
@@ -1401,8 +1401,8 @@ char const *SelectVoice(espeak_VOICE *voice_select, int *found)
continue;
}

vp2 = &voice_variants[n_variants++]; // allocate space for voice variant
memcpy(vp2, vp, sizeof(espeak_VOICE)); // copy from the original voice
vp2 = &voice_variants[n_variants++]; // allocate space for voice variant
memcpy(vp2, vp, sizeof(espeak_VOICE)); // copy from the original voice
vp2->variant = variant_number;
voices2[ix2++] = vp2;
p++;
@@ -1411,8 +1411,8 @@ char const *SelectVoice(espeak_VOICE *voice_select, int *found)
}
// add any more variants to the end of the list
while ((vp != NULL) && ((variant_number = *p++) != 0) && (n_variants < N_VOICE_VARIANTS)) {
vp2 = &voice_variants[n_variants++]; // allocate space for voice variant
memcpy(vp2, vp, sizeof(espeak_VOICE)); // copy from the original voice
vp2 = &voice_variants[n_variants++]; // allocate space for voice variant
memcpy(vp2, vp, sizeof(espeak_VOICE)); // copy from the original voice
vp2->variant = variant_number;
voices2[ix2++] = vp2;
}
@@ -1456,7 +1456,7 @@ static void GetVoices(const char *path)
regs.r[6] = 0;

while (regs.r[3] > 0) {
error = _kernel_swi(0x0c+0x20000, &regs, &regs); /* OS_GBPB 10, read directory entries */
error = _kernel_swi(0x0c+0x20000, &regs, &regs); // OS_GBPB 10, read directory entries
if ((error != NULL) || (regs.r[3] == 0))
break;
type = (int *)(&buf[16]);
@@ -1484,7 +1484,7 @@ static void GetVoices(const char *path)
WIN32_FIND_DATAA FindFileData;
HANDLE hFind = INVALID_HANDLE_VALUE;

#undef UNICODE // we need FindFirstFileA() which takes an 8-bit c-string
#undef UNICODE // we need FindFirstFileA() which takes an 8-bit c-string
sprintf(fname, "%s\\*", path);
hFind = FindFirstFileA(fname, &FindFileData);
if (hFind == INVALID_HANDLE_VALUE)
@@ -1492,7 +1492,7 @@ static void GetVoices(const char *path)

do {
if (n_voices_list >= (N_VOICES_LIST-2))
break; // voices list is full
break; // voices list is full

if (FindFileData.cFileName[0] != '.') {
sprintf(fname, "%s%c%s", path, PATHSEP, FindFileData.cFileName);
@@ -1520,12 +1520,12 @@ static void GetVoices(const char *path)
DIR *dir;
struct dirent *ent;

if ((dir = opendir((char *)path)) == NULL) // note: (char *) is needed for WINCE
if ((dir = opendir((char *)path)) == NULL) // note: (char *) is needed for WINCE
return;

while ((ent = readdir(dir)) != NULL) {
if (n_voices_list >= (N_VOICES_LIST-2))
break; // voices list is full
break; // voices list is full

if (ent->d_name[0] == '.')
continue;
@@ -1574,7 +1574,7 @@ espeak_ERROR SetVoiceByName(const char *name)
}

memset(&voice_selector, 0, sizeof(voice_selector));
voice_selector.name = (char *)name; // include variant name in voice stack ??
voice_selector.name = (char *)name; // include variant name in voice stack ??

// first check for a voice with this filename
// This may avoid the need to call espeak_ListVoices().
@@ -1590,7 +1590,7 @@ espeak_ERROR SetVoiceByName(const char *name)
}

if (n_voices_list == 0)
espeak_ListVoices(NULL); // create the voices list
espeak_ListVoices(NULL); // create the voices list

if ((v = SelectVoiceByName(voices_list, buf)) != NULL) {
if (LoadVoice(v->identifier, 0) != NULL) {
@@ -1602,7 +1602,7 @@ espeak_ERROR SetVoiceByName(const char *name)
return EE_OK;
}
}
return EE_INTERNAL_ERROR; // voice name not found
return EE_INTERNAL_ERROR; // voice name not found
}

espeak_ERROR SetVoiceByProperties(espeak_VOICE *voice_selector)
@@ -1645,7 +1645,7 @@ ESPEAK_API const espeak_VOICE **espeak_ListVoices(espeak_VOICE *voice_spec)
sprintf(path_voices, "%s%cvoices", path_home, PATHSEP);
len_path_voices = strlen(path_voices)+1;
GetVoices(path_voices);
voices_list[n_voices_list] = NULL; // voices list terminator
voices_list[n_voices_list] = NULL; // voices list terminator
}
return (const espeak_VOICE **)voices_list;
#else
@@ -1661,7 +1661,7 @@ ESPEAK_API const espeak_VOICE **espeak_ListVoices(espeak_VOICE *voice_spec)
len_path_voices = strlen(path_voices)+1;

GetVoices(path_voices);
voices_list[n_voices_list] = NULL; // voices list terminator
voices_list[n_voices_list] = NULL; // voices list terminator
voices = (espeak_VOICE **)realloc(voices, sizeof(espeak_VOICE *)*(n_voices_list+1));

// sort the voices list

+ 92
- 66
src/libespeak-ng/wave.c View File

@@ -48,7 +48,7 @@ struct timespec {
long tv_sec;
long tv_nsec;
};
#endif /* HAVE_STRUCT_TIMESPEC */
#endif

enum { ONE_BILLION = 1000000000 };

@@ -99,7 +99,8 @@ void *wave_pulse_test_get_write_buffer();
int wave_pulse_get_remaining_time(uint32_t sample, uint32_t *time);

// wrappers
int wave_init(int srate) {
int wave_init(int srate)
{
pulse_running = is_pulse_running();

if (pulse_running)
@@ -108,70 +109,80 @@ int wave_init(int srate) {
return wave_port_init(srate);
}

void *wave_open(const char *the_api) {
void *wave_open(const char *the_api)
{
if (pulse_running)
return wave_pulse_open(the_api);
else
return wave_port_open(the_api);
}

size_t wave_write(void *theHandler, char *theMono16BitsWaveBuffer, size_t theSize) {
size_t wave_write(void *theHandler, char *theMono16BitsWaveBuffer, size_t theSize)
{
if (pulse_running)
return wave_pulse_write(theHandler, theMono16BitsWaveBuffer, theSize);
else
return wave_port_write(theHandler, theMono16BitsWaveBuffer, theSize);
}

int wave_close(void *theHandler) {
int wave_close(void *theHandler)
{
if (pulse_running)
return wave_pulse_close(theHandler);
else
return wave_port_close(theHandler);
}

int wave_is_busy(void *theHandler) {
int wave_is_busy(void *theHandler)
{
if (pulse_running)
return wave_pulse_is_busy(theHandler);
else
return wave_port_is_busy(theHandler);
}

void wave_terminate() {
void wave_terminate()
{
if (pulse_running)
wave_pulse_terminate();
else
wave_port_terminate();
}

uint32_t wave_get_read_position(void *theHandler) {
uint32_t wave_get_read_position(void *theHandler)
{
if (pulse_running)
return wave_pulse_get_read_position(theHandler);
else
return wave_port_get_read_position(theHandler);
}

uint32_t wave_get_write_position(void *theHandler) {
uint32_t wave_get_write_position(void *theHandler)
{
if (pulse_running)
return wave_pulse_get_write_position(theHandler);
else
return wave_port_get_write_position(theHandler);
}

void wave_flush(void *theHandler) {
void wave_flush(void *theHandler)
{
if (pulse_running)
wave_pulse_flush(theHandler);
else
wave_port_flush(theHandler);
}

void wave_set_callback_is_output_enabled(t_wave_callback *cb) {
void wave_set_callback_is_output_enabled(t_wave_callback *cb)
{
if (pulse_running)
wave_pulse_set_callback_is_output_enabled(cb);
else
wave_port_set_callback_is_output_enabled(cb);
}

void *wave_test_get_write_buffer() {
void *wave_test_get_write_buffer()
{
if (pulse_running)
return wave_pulse_test_get_write_buffer();
else
@@ -200,7 +211,7 @@ int wave_get_remaining_time(uint32_t sample, uint32_t *time)
#define wave_test_get_write_buffer wave_port_test_get_write_buffer
#define wave_get_remaining_time wave_port_get_remaining_time

#endif // USE_PULSEAUDIO
#endif

static t_wave_callback *my_callback_is_output_enabled = NULL;

@@ -320,9 +331,8 @@ static int pa_callback(const void *inputBuffer, void *outputBuffer,
mInCallbackFinishedState = true;
size_t aUsedMem = 0;
aUsedMem = (size_t)(aWrite - myRead);
if (aUsedMem) {
if (aUsedMem)
memcpy(outputBuffer, myRead, aUsedMem);
}
char *p = (char *)outputBuffer + aUsedMem;
memset(p, 0, n - aUsedMem);
myRead = aWrite;
@@ -418,17 +428,17 @@ static int wave_open_sound()
PaDeviceID playbackDevice = Pa_GetDefaultOutputDeviceID();

PaError err = Pa_OpenStream(&pa_stream,
/* capture parameters */
// capture parameters
paNoDevice,
0,
paInt16,
NULL,
/* playback parameters */
// playback parameters
playbackDevice,
out_channels,
paInt16,
NULL,
/* general parameters */
// general parameters
wave_samplerate, FRAMES_PER_BUFFER, 0,
paNoFlag,
pa_callback, (void *)userdata);
@@ -440,17 +450,17 @@ static int wave_open_sound()
// failed to open with mono, try stereo
out_channels = 2;
PaError err = Pa_OpenStream(&pa_stream,
/* capture parameters */
// capture parameters
paNoDevice,
0,
paInt16,
NULL,
/* playback parameters */
// playback parameters
playbackDevice,
out_channels,
paInt16,
NULL,
/* general parameters */
// general parameters
wave_samplerate, FRAMES_PER_BUFFER, 0,
paNoFlag,
pa_callback, (void *)userdata);
@@ -461,45 +471,40 @@ static int wave_open_sound()
#else
myOutputParameters.channelCount = out_channels;
unsigned long framesPerBuffer = paFramesPerBufferUnspecified;
err = Pa_OpenStream(
&pa_stream,
NULL, /* no input */
&myOutputParameters,
wave_samplerate,
framesPerBuffer,
paNoFlag,
pa_callback,
(void *)userdata);
err = Pa_OpenStream(&pa_stream,
NULL, // no input
&myOutputParameters,
wave_samplerate,
framesPerBuffer,
paNoFlag,
pa_callback,
(void *)userdata);
if ((err != paNoError)
&& (err != paInvalidChannelCount)) { // err==paUnanticipatedHostError
&& (err != paInvalidChannelCount)) {
fprintf(stderr, "wave_open_sound > Pa_OpenStream : err=%d (%s)\n", err, Pa_GetErrorText(err));
framesPerBuffer = FRAMES_PER_BUFFER;
err = Pa_OpenStream(
&pa_stream,
NULL, /* no input */
&myOutputParameters,
wave_samplerate,
framesPerBuffer,
paNoFlag,
// paClipOff | paDitherOff,
pa_callback,
(void *)userdata);
err = Pa_OpenStream(&pa_stream,
NULL, // no input
&myOutputParameters,
wave_samplerate,
framesPerBuffer,
paNoFlag,
pa_callback,
(void *)userdata);
}
if (err == paInvalidChannelCount) {
SHOW_TIME("wave_open_sound > try stereo");
// failed to open with mono, try stereo
out_channels = 2;
myOutputParameters.channelCount = out_channels;
err = Pa_OpenStream(
&pa_stream,
NULL, /* no input */
&myOutputParameters,
wave_samplerate,
framesPerBuffer,
paNoFlag,
// paClipOff | paDitherOff,
pa_callback,
(void *)userdata);
err = Pa_OpenStream(&pa_stream,
NULL, // no input
&myOutputParameters,
wave_samplerate,
framesPerBuffer,
paNoFlag,
pa_callback,
(void *)userdata);
}
mInCallbackFinishedState = false;
#endif
@@ -748,7 +753,7 @@ size_t wave_write(void *theHandler, char *theMono16BitsWaveBuffer, size_t theSiz
myWrite = myBuffer;
myWrite += copyBuffer(myWrite, theMono16BitsWaveBuffer+aFreeMem/2, theSize - aFreeMem/2);
} else { // 1 channel (mono)
// copy with wrap around at the end of ringbuffer
// copy with wrap around at the end of ringbuffer
copyBuffer(myWrite, theMono16BitsWaveBuffer, aFreeMem);
myWrite = myBuffer;
myWrite += copyBuffer(myWrite, theMono16BitsWaveBuffer+aFreeMem, theSize - aFreeMem);
@@ -832,7 +837,6 @@ int wave_close(void *theHandler)
// DMM: This doesn't seem to be true; it seems to be necessary to
// call StopStream if the callback brought us here, and AbortStream
// if the user brought us here.
//

#if (USE_PORTAUDIO == 19)
if (pa_stream) {
@@ -937,35 +941,57 @@ void *wave_test_get_write_buffer()

#else

int wave_init(int srate) {
int wave_init(int srate)
{
return 1;
}
void *wave_open(const char *the_api) {

void *wave_open(const char *the_api)
{
return (void *)1;
}
size_t wave_write(void *theHandler, char *theMono16BitsWaveBuffer, size_t theSize) {

size_t wave_write(void *theHandler, char *theMono16BitsWaveBuffer, size_t theSize)
{
return theSize;
}
int wave_close(void *theHandler) {

int wave_close(void *theHandler)
{
return 0;
}
int wave_is_busy(void *theHandler) {

int wave_is_busy(void *theHandler)
{
return 0;
}
void wave_terminate() {

void wave_terminate()
{
}
uint32_t wave_get_read_position(void *theHandler) {

uint32_t wave_get_read_position(void *theHandler)
{
return 0;
}
uint32_t wave_get_write_position(void *theHandler) {

uint32_t wave_get_write_position(void *theHandler)
{
return 0;
}
void wave_flush(void *theHandler) {

void wave_flush(void *theHandler)
{
}

typedef int (t_wave_callback)(void);
void wave_set_callback_is_output_enabled(t_wave_callback *cb) {

void wave_set_callback_is_output_enabled(t_wave_callback *cb)
{
}
extern void *wave_test_get_write_buffer() {

extern void *wave_test_get_write_buffer()
{
return NULL;
}

@@ -976,7 +1002,7 @@ int wave_get_remaining_time(uint32_t sample, uint32_t *time)
return 0;
}

#endif // of USE_PORTAUDIO
#endif

void clock_gettime2(struct timespec *ts)
{
@@ -1004,4 +1030,4 @@ void add_time_in_ms(struct timespec *ts, int time_in_ms)
ts->tv_nsec = (long int)t_ns;
}

#endif // USE_ASYNC
#endif

+ 0
- 1
src/libespeak-ng/wave.h View File

@@ -55,7 +55,6 @@ extern int wave_get_remaining_time(uint32_t sample, uint32_t *time);
typedef int (t_wave_callback)(void);
extern void wave_set_callback_is_output_enabled(t_wave_callback *cb);


// general functions
extern void clock_gettime2(struct timespec *ts);
extern void add_time_in_ms(struct timespec *ts, int time_in_ms);

+ 67
- 33
src/libespeak-ng/wave_pulse.c View File

@@ -102,7 +102,8 @@ int is_pulse_running()
} else
return 0;
}
#endif // USE_PORTAUDIO

#endif

static pthread_mutex_t pulse_mutex;

@@ -138,7 +139,8 @@ static int wave_samplerate;
if (!connected) { SHOW("CHECK_CONNECTED_NO_RETVAL: !pulse_connected\n", ""); return; } \
} while (0);

static void subscribe_cb(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata) {
static void subscribe_cb(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata)
{
ENTER(__FUNCTION__);

assert(c);
@@ -150,7 +152,8 @@ static void subscribe_cb(struct pa_context *c, enum pa_subscription_event_type t
return;
}

static void context_state_cb(pa_context *c, void *userdata) {
static void context_state_cb(pa_context *c, void *userdata)
{
ENTER(__FUNCTION__);
assert(c);

@@ -169,7 +172,8 @@ static void context_state_cb(pa_context *c, void *userdata) {
}
}

static void stream_state_cb(pa_stream *s, void *userdata) {
static void stream_state_cb(pa_stream *s, void *userdata)
{
ENTER(__FUNCTION__);
assert(s);

@@ -186,7 +190,8 @@ static void stream_state_cb(pa_stream *s, void *userdata) {
}
}

static void stream_success_cb(pa_stream *s, int success, void *userdata) {
static void stream_success_cb(pa_stream *s, int success, void *userdata)
{
ENTER(__FUNCTION__);
assert(s);

@@ -196,7 +201,8 @@ static void stream_success_cb(pa_stream *s, int success, void *userdata) {
pa_threaded_mainloop_signal(mainloop, 0);
}

static void context_success_cb(pa_context *c, int success, void *userdata) {
static void context_success_cb(pa_context *c, int success, void *userdata)
{
ENTER(__FUNCTION__);
assert(c);

@@ -206,20 +212,23 @@ static void context_success_cb(pa_context *c, int success, void *userdata) {
pa_threaded_mainloop_signal(mainloop, 0);
}

static void stream_request_cb(pa_stream *s, size_t length, void *userdata) {
static void stream_request_cb(pa_stream *s, size_t length, void *userdata)
{
ENTER(__FUNCTION__);
assert(s);

pa_threaded_mainloop_signal(mainloop, 0);
}

static void stream_latency_update_cb(pa_stream *s, void *userdata) {
static void stream_latency_update_cb(pa_stream *s, void *userdata)
{
assert(s);

pa_threaded_mainloop_signal(mainloop, 0);
}

static int pulse_free(void) {
static int pulse_free(void)
{
ENTER(__FUNCTION__);
size_t l = 0;
pa_operation *o = NULL;
@@ -273,7 +282,8 @@ fail:
return (int)l;
}

static int pulse_playing(const pa_timing_info *the_timing_info) {
static int pulse_playing(const pa_timing_info *the_timing_info)
{
ENTER(__FUNCTION__);
int r = 0;
const pa_timing_info *i;
@@ -306,7 +316,8 @@ fail:
return r;
}

static void pulse_write(void *ptr, int length) {
static void pulse_write(void *ptr, int length)
{
ENTER(__FUNCTION__);

SHOW("pulse_write > length=%d\n", length);
@@ -327,7 +338,8 @@ fail:
pa_threaded_mainloop_unlock(mainloop);
}

static int drain(void) {
static int drain(void)
{
pa_operation *o = NULL;
int success = 0;
int ret = PULSE_ERROR;
@@ -367,8 +379,8 @@ fail:
return ret;
}

static void pulse_close(void) {
static void pulse_close(void)
{
ENTER(__FUNCTION__);

drain();
@@ -448,7 +460,7 @@ static int pulse_open()
goto unlock_and_fail;
}

/* Wait until the context is ready */
// Wait until the context is ready
SHOW_TIME("pa_threaded_mainloop_wait");
pa_threaded_mainloop_wait(mainloop);

@@ -484,7 +496,7 @@ static int pulse_open()
goto unlock_and_fail;
}

/* Wait until the stream is ready */
// Wait until the stream is ready
SHOW_TIME("pa_threaded_mainloop_wait");
pa_threaded_mainloop_wait(mainloop);

@@ -493,7 +505,7 @@ static int pulse_open()
goto unlock_and_fail;
}

/* Now subscribe to events */
// Now subscribe to events
SHOW_TIME("pa_context_subscribe");
if (!(o = pa_context_subscribe(context, PA_SUBSCRIPTION_MASK_SINK_INPUT, context_success_cb, &success))) {
SHOW("pa_context_subscribe() failed: %s", pa_strerror(pa_context_errno(context)));
@@ -714,9 +726,8 @@ int wave_get_remaining_time(uint32_t sample, uint32_t *time)
// TBD: take in account time suplied by portaudio V18 API
a_time = sample - a_timing_info.read_index;
a_time = 0.5 + (a_time * 1000.0) / wave_samplerate;
} else {
} else
a_time = 0;
}

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

@@ -732,34 +743,57 @@ void *wave_test_get_write_buffer()

#else

int wave_init(return 1; ) {
int wave_init(int srate)
{
return 1;
}
void *wave_open(const char *the_api) {

void *wave_open(const char *the_api)
{
return (void *)1;
}
size_t wave_write(void *theHandler, char *theMono16BitsWaveBuffer, size_t theSize) {

size_t wave_write(void *theHandler, char *theMono16BitsWaveBuffer, size_t theSize)
{
return theSize;
}
int wave_close(void *theHandler) {

int wave_close(void *theHandler)
{
return 0;
}
int wave_is_busy(void *theHandler) {

int wave_is_busy(void *theHandler)
{
return 0;
}
void wave_terminate() {

void wave_terminate()
{
}
uint32_t wave_get_read_position(void *theHandler) {

uint32_t wave_get_read_position(void *theHandler)
{
return 0;
}
uint32_t wave_get_write_position(void *theHandler) {

uint32_t wave_get_write_position(void *theHandler)
{
return 0;
}
void wave_flush(void *theHandler) {

void wave_flush(void *theHandler)
{
}

typedef int (t_wave_callback)(void);
void wave_set_callback_is_output_enabled(t_wave_callback *cb) {

void wave_set_callback_is_output_enabled(t_wave_callback *cb)
{
}
extern void *wave_test_get_write_buffer() {

extern void *wave_test_get_write_buffer()
{
return NULL;
}

@@ -770,7 +804,7 @@ int wave_get_remaining_time(uint32_t sample, uint32_t *time)
return 0;
}

#endif // of USE_PULSEAUDIO
#endif

#ifndef USE_PORTAUDIO

@@ -799,6 +833,6 @@ void add_time_in_ms(struct timespec *ts, int time_in_ms)
}
ts->tv_nsec = (long int)t_ns;
}
#endif // ifndef USE_PORTAUDIO

#endif // USE_ASYNC
#endif
#endif

+ 39
- 16
src/libespeak-ng/wave_sada.c View File

@@ -75,7 +75,8 @@ static uint32_t wave_samplerate;
// sun_audio_fd: modified to hold the file descriptor of the opened
// audio device.
//
int wave_init(int srate) {
int wave_init(int srate)
{
ENTER("wave_init");

audio_info_t ainfo;
@@ -478,9 +479,9 @@ int wave_get_remaining_time(uint32_t sample, uint32_t *time)
//
actual_index = sample - total_samples_skipped;
if ((sample < total_samples_skipped) ||
(actual_index <= ainfo.play.samples)) {
(actual_index <= ainfo.play.samples))
*time = 0;
} else {
else {
a_time = ((actual_index - ainfo.play.samples) * 1000) / wave_samplerate;
*time = (uint32_t)a_time;
}
@@ -491,35 +492,57 @@ int wave_get_remaining_time(uint32_t sample, uint32_t *time)

#else

init wave_init() {
int wave_init(int srate)
{
return 1;
}
void *wave_open(const char *the_api) {

void *wave_open(const char *the_api)
{
return (void *)1;
}
size_t wave_write(void *theHandler, char *theMono16BitsWaveBuffer, size_t theSize) {

size_t wave_write(void *theHandler, char *theMono16BitsWaveBuffer, size_t theSize)
{
return theSize;
}
int wave_close(void *theHandler) {

int wave_close(void *theHandler)
{
return 0;
}
int wave_is_busy(void *theHandler) {

int wave_is_busy(void *theHandler)
{
return 0;
}
void wave_terminate() {

void wave_terminate()
{
}
uint32_t wave_get_read_position(void *theHandler) {

uint32_t wave_get_read_position(void *theHandler)
{
return 0;
}
uint32_t wave_get_write_position(void *theHandler) {

uint32_t wave_get_write_position(void *theHandler)
{
return 0;
}
void wave_flush(void *theHandler) {

void wave_flush(void *theHandler)
{
}

typedef int (t_wave_callback)(void);
void wave_set_callback_is_output_enabled(t_wave_callback *cb) {

void wave_set_callback_is_output_enabled(t_wave_callback *cb)
{
}
extern void *wave_test_get_write_buffer() {

extern void *wave_test_get_write_buffer()
{
return NULL;
}

@@ -530,7 +553,7 @@ int wave_get_remaining_time(uint32_t sample, uint32_t *time)
return 0;
}

#endif // of USE_PORTAUDIO
#endif

void clock_gettime2(struct timespec *ts)
{
@@ -558,4 +581,4 @@ void add_time_in_ms(struct timespec *ts, int time_in_ms)
ts->tv_nsec = (long int)t_ns;
}

#endif // USE_ASYNC
#endif

+ 126
- 127
src/libespeak-ng/wavegen.c View File

@@ -62,16 +62,16 @@ voice_t *wvoice;

FILE *f_log = NULL;
int option_waveout = 0;
static int option_harmonic1 = 10; // 10
static int option_harmonic1 = 10;
static int flutter_amp = 64;

static int general_amplitude = 60;
static int consonant_amp = 26; // 24
static int consonant_amp = 26;

int embedded_value[N_EMBEDDED_VALUES];

static int PHASE_INC_FACTOR;
int samplerate = 0; // this is set by Wavegeninit()
int samplerate = 0; // this is set by Wavegeninit()
int samplerate_native = 0;
extern int option_device_number;
extern int option_quiet;
@@ -84,7 +84,7 @@ int echo_head;
int echo_tail;
int echo_amp = 0;
short echo_buf[N_ECHO_BUF];
static int echo_length = 0; // period (in sample\) to ensure completion of echo at the end of speech, set in WavegenSetEcho()
static int echo_length = 0; // period (in sample\) to ensure completion of echo at the end of speech, set in WavegenSetEcho()

static int voicing;
static RESONATOR rbreath[N_PEAKS];
@@ -92,13 +92,13 @@ static RESONATOR rbreath[N_PEAKS];
static int harm_sqrt_n = 0;

#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 hswitch = 0;
static int hspect[2][MAX_HARMONIC]; // 2 copies, we interpolate between then
static int hspect[2][MAX_HARMONIC]; // 2 copies, we interpolate between then
static int max_hval = 0;

static int nsamples = 0; // number to do
static int nsamples = 0; // number to do
static int modulation_type = 0;
static int glottal_flag = 0;
static int glottal_reduce = 0;
@@ -109,12 +109,12 @@ static int amp_ix;
static int amp_inc;
static unsigned char *amplitude_env = NULL;

static int samplecount = 0; // number done
static int samplecount_start = 0; // count at start of this segment
static int end_wave = 0; // continue to end of wave cycle
static int samplecount = 0; // number done
static int samplecount_start = 0; // count at start of this segment
static int end_wave = 0; // continue to end of wave cycle
static int wavephase;
static int phaseinc;
static int cycle_samples; // number of samples in a cycle at current pitch
static int cycle_samples; // number of samples in a cycle at current pitch
static int cbytes;
static int hf_factor;

@@ -132,10 +132,10 @@ int wcmdq_head = 0;
int wcmdq_tail = 0;

// pitch,speed,
int embedded_default[N_EMBEDDED_VALUES] = { 0, 50, 175, 100, 50, 0, 0, 0, 175, 0, 0, 0, 0, 0, 0 };
static int embedded_max[N_EMBEDDED_VALUES] = { 0, 0x7fff, 750, 300, 99, 99, 99, 0, 750, 0, 0, 0, 0, 4, 0 };
int embedded_default[N_EMBEDDED_VALUES] = { 0, 50, 175, 100, 50, 0, 0, 0, 175, 0, 0, 0, 0, 0, 0 };
static int embedded_max[N_EMBEDDED_VALUES] = { 0, 0x7fff, 750, 300, 99, 99, 99, 0, 750, 0, 0, 0, 0, 4, 0 };

#define N_CALLBACK_IX N_WAV_BUF-2 // adjust this delay to match display with the currently spoken word
#define N_CALLBACK_IX N_WAV_BUF-2 // adjust this delay to match display with the currently spoken word
int current_source_index = 0;

extern FILE *f_wave;
@@ -232,22 +232,22 @@ static int wavemult_max = 0;
// the presets are for 22050 Hz sample rate.
// A different rate will need to recalculate the presets in WavegenInit()
static unsigned char wavemult[N_WAVEMULT] = {
0, 0, 0, 2, 3, 5, 8, 11, 14, 18, 22, 27, 32, 37, 43, 49,
55, 62, 69, 76, 83, 90, 98, 105, 113, 121, 128, 136, 144, 152, 159, 166,
0, 0, 0, 2, 3, 5, 8, 11, 14, 18, 22, 27, 32, 37, 43, 49,
55, 62, 69, 76, 83, 90, 98, 105, 113, 121, 128, 136, 144, 152, 159, 166,
174, 181, 188, 194, 201, 207, 213, 218, 224, 228, 233, 237, 240, 244, 246, 249,
251, 252, 253, 253, 253, 253, 252, 251, 249, 246, 244, 240, 237, 233, 228, 224,
218, 213, 207, 201, 194, 188, 181, 174, 166, 159, 152, 144, 136, 128, 121, 113,
105, 98, 90, 83, 76, 69, 62, 55, 49, 43, 37, 32, 27, 22, 18, 14,
11, 8, 5, 3, 2, 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
105, 98, 90, 83, 76, 69, 62, 55, 49, 43, 37, 32, 27, 22, 18, 14,
11, 8, 5, 3, 2, 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
unsigned char pitch_adjust_tab[MAX_PITCH_VALUE+1] = {
64, 65, 66, 67, 68, 69, 70, 71,
72, 73, 74, 75, 76, 77, 78, 79,
80, 81, 82, 83, 84, 86, 87, 88,
89, 91, 92, 93, 94, 96, 97, 98,
64, 65, 66, 67, 68, 69, 70, 71,
72, 73, 74, 75, 76, 77, 78, 79,
80, 81, 82, 83, 84, 86, 87, 88,
89, 91, 92, 93, 94, 96, 97, 98,
100, 101, 103, 104, 105, 107, 108, 110,
111, 113, 115, 116, 118, 119, 121, 123,
124, 126, 128, 130, 132, 133, 135, 137,
@@ -310,19 +310,19 @@ unsigned char pk_shape1[PEAKSHAPEW+1] = {
245, 244, 242, 241, 239, 238, 236, 234, 233, 231, 229, 227, 225, 223, 220, 218,
216, 213, 211, 209, 207, 205, 203, 201, 199, 197, 195, 193, 191, 189, 187, 185,
183, 180, 178, 176, 173, 171, 169, 166, 164, 161, 159, 156, 154, 151, 148, 146,
143, 140, 138, 135, 132, 129, 126, 123, 120, 118, 115, 112, 108, 105, 102, 99,
96, 95, 93, 91, 90, 88, 86, 85, 83, 82, 80, 79, 77, 76, 74, 73,
72, 70, 69, 68, 67, 66, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55,
55, 54, 53, 52, 52, 51, 50, 50, 49, 48, 48, 47, 47, 46, 46, 46,
45, 45, 45, 44, 44, 44, 44, 44, 44, 44, 43, 43, 43, 43, 44, 43,
42, 42, 41, 40, 40, 39, 38, 38, 37, 36, 36, 35, 35, 34, 33, 33,
32, 32, 31, 30, 30, 29, 29, 28, 28, 27, 26, 26, 25, 25, 24, 24,
23, 23, 22, 22, 21, 21, 20, 20, 19, 19, 18, 18, 18, 17, 17, 16,
16, 15, 15, 15, 14, 14, 13, 13, 13, 12, 12, 11, 11, 11, 10, 10,
10, 9, 9, 9, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 5, 5,
5, 5, 4, 4, 4, 4, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2,
2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0
143, 140, 138, 135, 132, 129, 126, 123, 120, 118, 115, 112, 108, 105, 102, 99,
96, 95, 93, 91, 90, 88, 86, 85, 83, 82, 80, 79, 77, 76, 74, 73,
72, 70, 69, 68, 67, 66, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55,
55, 54, 53, 52, 52, 51, 50, 50, 49, 48, 48, 47, 47, 46, 46, 46,
45, 45, 45, 44, 44, 44, 44, 44, 44, 44, 43, 43, 43, 43, 44, 43,
42, 42, 41, 40, 40, 39, 38, 38, 37, 36, 36, 35, 35, 34, 33, 33,
32, 32, 31, 30, 30, 29, 29, 28, 28, 27, 26, 26, 25, 25, 24, 24,
23, 23, 22, 22, 21, 21, 20, 20, 19, 19, 18, 18, 18, 17, 17, 16,
16, 15, 15, 15, 14, 14, 13, 13, 13, 12, 12, 11, 11, 11, 10, 10,
10, 9, 9, 9, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 5, 5,
5, 5, 4, 4, 4, 4, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2,
2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0
};

static unsigned char pk_shape2[PEAKSHAPEW+1] = {
@@ -331,18 +331,18 @@ static unsigned char pk_shape2[PEAKSHAPEW+1] = {
243, 243, 242, 241, 239, 237, 235, 233, 231, 229, 227, 225, 223, 221, 218, 216,
213, 211, 208, 205, 203, 200, 197, 194, 191, 187, 184, 181, 178, 174, 171, 167,
163, 160, 156, 152, 148, 144, 140, 136, 132, 127, 123, 119, 114, 110, 105, 100,
96, 94, 91, 88, 86, 83, 81, 78, 76, 74, 71, 69, 66, 64, 62, 60,
57, 55, 53, 51, 49, 47, 44, 42, 40, 38, 36, 34, 32, 30, 29, 27,
25, 23, 21, 19, 18, 16, 14, 12, 11, 9, 7, 6, 4, 3, 1, 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, 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, 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, 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, 0,
0
96, 94, 91, 88, 86, 83, 81, 78, 76, 74, 71, 69, 66, 64, 62, 60,
57, 55, 53, 51, 49, 47, 44, 42, 40, 38, 36, 34, 32, 30, 29, 27,
25, 23, 21, 19, 18, 16, 14, 12, 11, 9, 7, 6, 4, 3, 1, 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, 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, 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, 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, 0,
0
};

static unsigned char *pk_shape;
@@ -389,7 +389,7 @@ static int WaveCallback(const void *inputBuffer, void *outputBuffer,
out_ptr = out_start = outbuffer;
out_end = out_start + outbuffer_size;
}
out_end2 = &outbuffer[pa_size]; // top of data needed for the portaudio buffer
out_end2 = &outbuffer[pa_size]; // top of data needed for the portaudio buffer

#ifdef LIBRARY
event_list_ix = 0;
@@ -398,19 +398,17 @@ static int WaveCallback(const void *inputBuffer, void *outputBuffer,
result = WavegenFill(1);

// copy from the outbut buffer into the portaudio buffer
if (result && (out_ptr > out_end2)) {
result = 0; // don't end yet, there is more data in the buffer than can fit in portaudio
}
if (result && (out_ptr > out_end2))
result = 0; // don't end yet, there is more data in the buffer than can fit in portaudio

while (out_ptr < out_end2)
*out_ptr++ = 0; // fill with zeros up to the size of the portaudio buffer
*out_ptr++ = 0; // fill with zeros up to the size of the portaudio buffer

memcpy(outputBuffer, outbuffer, pa_size);

// move the remaining contents of the start of the output buffer
for (p = out_end2; p < out_end; p++) {
for (p = out_end2; p < out_end; p++)
p[-pa_size] = p[0];
}
out_ptr -= pa_size;

#ifdef LIBRARY
@@ -421,25 +419,23 @@ static int WaveCallback(const void *inputBuffer, void *outputBuffer,
event_list[event_list_ix].user_data = 0;

if (synth_callback(NULL, 0, event_list) == 1) {
SpeakNextClause(NULL, NULL, 2); // stop speaking
SpeakNextClause(NULL, NULL, 2); // stop speaking
result = 1;
}
}
#endif

#ifdef ARCH_BIG
{
// swap the order of bytes in each sound sample in the portaudio buffer
int c;
unsigned char *buf_end;
out_buf = (unsigned char *)outputBuffer;
buf_end = out_buf + framesPerBuffer*2;
while (out_buf < buf_end) {
c = out_buf[0];
out_buf[0] = out_buf[1];
out_buf[1] = c;
out_buf += 2;
}
// swap the order of bytes in each sound sample in the portaudio buffer
int c;
unsigned char *buf_end;
out_buf = (unsigned char *)outputBuffer;
buf_end = out_buf + framesPerBuffer*2;
while (out_buf < buf_end) {
c = out_buf[0];
out_buf[0] = out_buf[1];
out_buf[1] = c;
out_buf += 2;
}
#endif

@@ -591,7 +587,7 @@ int WavegenCloseSound()
return 1;
}
} else
WavegenOpenSound(); // still items in the queue, shouldn't be closed
WavegenOpenSound(); // still items in the queue, shouldn't be closed
}
return 0;
}
@@ -612,19 +608,24 @@ int WavegenInitSound()
}
return 0;
}

#else

int WavegenOpenSound()
{
return 0;
}

int WavegenCloseSound()
{
return 0;
}

int WavegenInitSound()
{
return 0;
}

#endif

void WavegenInit(int rate, int wavemult_fact)
@@ -633,11 +634,11 @@ void WavegenInit(int rate, int wavemult_fact)
double x;

if (wavemult_fact == 0)
wavemult_fact = 60; // default
wavemult_fact = 60; // default

wvoice = NULL;
samplerate = samplerate_native = rate;
PHASE_INC_FACTOR = 0x8000000 / samplerate; // assumes pitch is Hz*32
PHASE_INC_FACTOR = 0x8000000 / samplerate; // assumes pitch is Hz*32
Flutter_inc = (64 * samplerate)/rate;
samplecount = 0;
nsamples = 0;
@@ -666,7 +667,7 @@ void WavegenInit(int rate, int wavemult_fact)
}
}

pk_shape = pk_shape2; // pk_shape2
pk_shape = pk_shape2;

#ifdef INCLUDE_KLATT
KlattInit();
@@ -712,11 +713,11 @@ static void WavegenSetEcho(void)
amp = 0;

echo_head = (delay * samplerate)/1000;
echo_length = echo_head; // ensure completion of echo at the end of speech. Use 1 delay period?
echo_length = echo_head; // ensure completion of echo at the end of speech. Use 1 delay period?
if (amp == 0)
echo_length = 0;
if (amp > 20)
echo_length = echo_head * 2; // perhaps allow 2 echo periods if the echo is loud.
echo_length = echo_head * 2; // perhaps allow 2 echo periods if the echo is loud.

// echo_amp units are 1/256ths of the amplitude of the original sound.
echo_amp = amp;
@@ -727,21 +728,21 @@ static void WavegenSetEcho(void)

int PeaksToHarmspect(wavegen_peaks_t *peaks, int pitch, int *htab, int control)
{
// Calculate the amplitude of each harmonics from the formants
// Only for formants 0 to 5
// Calculate the amplitude of each harmonics from the formants
// Only for formants 0 to 5

// control 0=initial call, 1=every 64 cycles
// control 0=initial call, 1=every 64 cycles

// pitch and freqs are Hz<<16

int f;
wavegen_peaks_t *p;
int fp; // centre freq of peak
int fhi; // high freq of peak
int h; // harmonic number
int fp; // centre freq of peak
int fhi; // high freq of peak
int h; // harmonic number
int pk;
int hmax;
int hmax_samplerate; // highest harmonic allowed for the samplerate
int hmax_samplerate; // highest harmonic allowed for the samplerate
int x;
int ix;
int h1;
@@ -759,7 +760,7 @@ int PeaksToHarmspect(wavegen_peaks_t *peaks, int pitch, int *htab, int control)
hmax = MAX_HARMONIC-1;

// restrict highest harmonic to half the samplerate
hmax_samplerate = (((samplerate * 19)/40) << 16)/pitch; // only 95% of Nyquist freq
hmax_samplerate = (((samplerate * 19)/40) << 16)/pitch; // only 95% of Nyquist freq

if (hmax > hmax_samplerate)
hmax = hmax_samplerate;
@@ -787,7 +788,7 @@ int PeaksToHarmspect(wavegen_peaks_t *peaks, int pitch, int *htab, int control)
int h2;
// increase bass
y = peaks[1].height * 10; // addition as a multiple of 1/256s
h2 = (1000<<16)/pitch; // decrease until 1000Hz
h2 = (1000<<16)/pitch; // decrease until 1000Hz
if (h2 > 0) {
x = y/h2;
h = 1;
@@ -819,26 +820,25 @@ int PeaksToHarmspect(wavegen_peaks_t *peaks, int pitch, int *htab, int control)
htab[h] = (x * x) >> 8;

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

// adjust the amplitude of the first harmonic, affects tonal quality
h1 = htab[1] * option_harmonic1;
htab[1] = h1/8;


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

return hmax; // highest harmonic number
return hmax; // highest harmonic number
}

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

int x;
int ix;
@@ -859,7 +859,7 @@ static void AdvanceParameters()
Flutter_ix += Flutter_inc;
wdata.pitch += x;
if (wdata.pitch < 102400)
wdata.pitch = 102400; // min pitch, 25 Hz (25 << 12)
wdata.pitch = 102400; // min pitch, 25 Hz (25 << 12)

if (samplecount == samplecount_start)
return;
@@ -912,9 +912,9 @@ static double resonator(RESONATOR *r, double input)

static void setresonator(RESONATOR *rp, int freq, int bwidth, int init)
{
// freq Frequency of resonator in Hz
// bwidth Bandwidth of resonator in Hz
// init Initialize internal data
// freq Frequency of resonator in Hz
// bwidth Bandwidth of resonator in Hz
// init Initialize internal data

double x;
double arg;
@@ -1007,7 +1007,7 @@ int Wavegen()
static int agc = 256;
static int h_switch_sign = 0;
static int cycle_count = 0;
static int amplitude2 = 0; // adjusted for pitch
static int amplitude2 = 0; // adjusted for pitch

// continue until the output buffer is full, or
// the required number of samples have been produced
@@ -1033,7 +1033,7 @@ int Wavegen()

// pitch is Hz<<12
phaseinc = (wdata.pitch>>7) * PHASE_INC_FACTOR;
cycle_samples = samplerate/(wdata.pitch >> 12); // sr/(pitch*2)
cycle_samples = samplerate/(wdata.pitch >> 12); // sr/(pitch*2)
hf_factor = wdata.pitch >> 11;

maxh = maxh2;
@@ -1270,7 +1270,7 @@ static int PlayWave(int length, int resume, unsigned char *data, int scale, int
// 8 bit data, shift by the specified scale factor
value = (signed char)data[ix++] * scale;
}
value *= (consonant_amp * general_amplitude); // reduce strength of consonant
value *= (consonant_amp * general_amplitude); // reduce strength of consonant
value = value >> 10;
value = (value * amp)/32;

@@ -1353,14 +1353,14 @@ void SetEmbedded(int control, int value)
switch (command)
{
case EMBED_T:
WavegenSetEcho(); // and drop through to case P
WavegenSetEcho(); // and drop through to case P
case EMBED_P:
SetPitchFormants();
break;
case EMBED_A: // amplitude
case EMBED_A: // amplitude
general_amplitude = GetAmplitude();
break;
case EMBED_F: // emphasis
case EMBED_F: // emphasis
general_amplitude = GetAmplitude();
break;
case EMBED_H:
@@ -1383,7 +1383,7 @@ void WavegenSetVoice(voice_t *v)

consonant_amp = (v->consonant_amp * 26) /100;
if (samplerate <= 11000) {
consonant_amp = consonant_amp*2; // emphasize consonants at low sample rates
consonant_amp = consonant_amp*2; // emphasize consonants at low sample rates
option_harmonic1 = 6;
}
WavegenSetEcho();
@@ -1400,7 +1400,7 @@ static void SetAmplitude(int length, unsigned char *amp_env, int value)
amp_inc = (256 * ENV_LEN * STEPSIZE)/length;

wdata.amplitude = (value * general_amplitude)/16;
wdata.amplitude_v = (wdata.amplitude * wvoice->consonant_ampv * 15)/100; // for wave mixed with voiced sounds
wdata.amplitude_v = (wdata.amplitude * wvoice->consonant_ampv * 15)/100; // for wave mixed with voiced sounds

amplitude_env = amp_env;
}
@@ -1413,14 +1413,14 @@ void SetPitch2(voice_t *voice, int pitch1, int pitch2, int *pitch_base, int *pit
int pitch_value;

if (pitch1 > pitch2) {
x = pitch1; // swap values
x = pitch1; // swap values
pitch1 = pitch2;
pitch2 = x;
}

if ((pitch_value = embedded_value[EMBED_P]) > MAX_PITCH_VALUE)
pitch_value = MAX_PITCH_VALUE;
pitch_value -= embedded_value[EMBED_T]; // adjust tone for announcing punctuation
pitch_value -= embedded_value[EMBED_T]; // adjust tone for announcing punctuation
if (pitch_value < 0)
pitch_value = 0;

@@ -1436,10 +1436,10 @@ void SetPitch2(voice_t *voice, int pitch1, int pitch2, int *pitch_base, int *pit

void SetPitch(int length, unsigned char *env, int pitch1, int pitch2)
{
// length in samples
// length in samples

if ((wdata.pitch_env = env) == NULL)
wdata.pitch_env = env_fall; // default
wdata.pitch_env = env_fall; // default

wdata.pitch_ix = 0;
if (length == 0)
@@ -1449,7 +1449,7 @@ void SetPitch(int length, unsigned char *env, int pitch1, int pitch2)

SetPitch2(wvoice, pitch1, pitch2, &wdata.pitch_base, &wdata.pitch_range);
// set initial pitch
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;
}
@@ -1462,8 +1462,8 @@ void SetSynth(int length, int modn, frame_t *fr1, frame_t *fr2, voice_t *v)
int length4;
int qix;
int cmd;
static int glottal_reduce_tab1[4] = { 0x30, 0x30, 0x40, 0x50 }; // vowel before [?], amp * 1/256
static int glottal_reduce_tab2[4] = { 0x90, 0xa0, 0xb0, 0xc0 }; // vowel after [?], amp * 1/256
static int glottal_reduce_tab1[4] = { 0x30, 0x30, 0x40, 0x50 }; // vowel before [?], amp * 1/256
static int glottal_reduce_tab2[4] = { 0x90, 0xa0, 0xb0, 0xc0 }; // vowel after [?], amp * 1/256

harm_sqrt_n = 0;
end_wave = 1;
@@ -1473,11 +1473,11 @@ void SetSynth(int length, int modn, frame_t *fr1, frame_t *fr2, voice_t *v)

glottal_flag = 0;
if (modn & 0x400) {
glottal_flag = 3; // before a glottal stop
glottal_flag = 3; // before a glottal stop
glottal_reduce = glottal_reduce_tab1[(modn >> 8) & 3];
}
if (modn & 0x800) {
glottal_flag = 4; // after a glottal stop
glottal_flag = 4; // after a glottal stop
glottal_reduce = glottal_reduce_tab2[(modn >> 8) & 3];
}

@@ -1487,11 +1487,11 @@ void SetSynth(int length, int modn, frame_t *fr1, frame_t *fr2, voice_t *v)

cmd = wcmdq[qix][0];
if (cmd == WCMD_SPECT) {
end_wave = 0; // next wave generation is from another spectrum
end_wave = 0; // next wave generation is from another spectrum
break;
}
if ((cmd == WCMD_WAVE) || (cmd == WCMD_PAUSE))
break; // next is not from spectrum, so continue until end of wave cycle
break; // next is not from spectrum, so continue until end of wave cycle
}

// round the length to a multiple of the stepsize
@@ -1513,7 +1513,7 @@ void SetSynth(int length, int modn, frame_t *fr1, frame_t *fr2, voice_t *v)
peaks[ix].freq1 = (fr1->ffreq[ix] * v->freq[ix] + v->freqadd[ix]*256) << 8;
peaks[ix].freq = (int)peaks[ix].freq1;
next = (fr2->ffreq[ix] * v->freq[ix] + v->freqadd[ix]*256) << 8;
peaks[ix].freq_inc = ((next - peaks[ix].freq1) * (STEPSIZE/4)) / length4; // lower headroom for fixed point math
peaks[ix].freq_inc = ((next - peaks[ix].freq1) * (STEPSIZE/4)) / length4; // lower headroom for fixed point math
}

peaks[ix].height1 = (fr1->fheight[ix] * v->height[ix]) << 6;
@@ -1532,9 +1532,8 @@ void SetSynth(int length, int modn, frame_t *fr1, frame_t *fr2, voice_t *v)
peaks[ix].right = (int)peaks[ix].right1;
next = (fr2->fright[ix] * v->width[ix]) << 10;
peaks[ix].right_inc = ((next - peaks[ix].right1) * STEPSIZE) / length2;
} else {
} else
peaks[ix].right = peaks[ix].left;
}
}
}
}
@@ -1549,7 +1548,7 @@ static int Wavegen2(int length, int modulation, int resume, frame_t *fr1, frame_

void Write4Bytes(FILE *f, int value)
{
// Write 4 bytes to a file, least significant first
// Write 4 bytes to a file, least significant first
int ix;

for (ix = 0; ix < 4; ix++) {
@@ -1560,9 +1559,9 @@ void Write4Bytes(FILE *f, int value)

int WavegenFill2(int fill_zeros)
{
// Pick up next wavegen commands from the queue
// return: 0 output buffer has been filled
// return: 1 input command queue is now empty
// Pick up next wavegen commands from the queue
// return: 0 output buffer has been filled
// return: 1 input command queue is now empty

intptr_t *q;
int length;
@@ -1577,14 +1576,14 @@ int WavegenFill2(int fill_zeros)
// continue to play silence until echo is completed
resume = PlaySilence(echo_complete, resume);
if (resume == 1)
return 0; // not yet finished
return 0; // not yet finished
}

if (fill_zeros) {
while (out_ptr < out_end)
*out_ptr++ = 0;
}
return 1; // queue empty, close sound channel
return 1; // queue empty, close sound channel
}

result = 0;
@@ -1628,15 +1627,15 @@ int WavegenFill2(int fill_zeros)
wdata.mix_wavefile_offset = 0;
wdata.mix_wavefile = (unsigned char *)q[2];
break;
case WCMD_SPECT2: // as WCMD_SPECT but stop any concurrent wave file
wdata.n_mix_wavefile = 0; // ... and drop through to WCMD_SPECT case
case WCMD_SPECT2: // as WCMD_SPECT but stop any concurrent wave file
wdata.n_mix_wavefile = 0; // ... and drop through to WCMD_SPECT case
case WCMD_SPECT:
echo_complete = echo_length;
result = Wavegen2(length & 0xffff, q[1] >> 16, resume, (frame_t *)q[2], (frame_t *)q[3]);
break;
#ifdef INCLUDE_KLATT
case WCMD_KLATT2: // as WCMD_SPECT but stop any concurrent wave file
wdata.n_mix_wavefile = 0; // ... and drop through to WCMD_SPECT case
case WCMD_KLATT2: // as WCMD_SPECT but stop any concurrent wave file
wdata.n_mix_wavefile = 0; // ... and drop through to WCMD_SPECT case
case WCMD_KLATT:
echo_complete = echo_length;
result = Wavegen_Klatt2(length & 0xffff, q[1] >> 16, resume, (frame_t *)q[2], (frame_t *)q[3]);
@@ -1663,7 +1662,7 @@ int WavegenFill2(int fill_zeros)
break;
case WCMD_FMT_AMPLITUDE:
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;
#if HAVE_SONIC_H
case WCMD_SONIC_SPEED:
@@ -1683,7 +1682,7 @@ int WavegenFill2(int fill_zeros)
}

#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)
{
if (length_in > 0) {
@@ -1704,7 +1703,7 @@ static int SpeedUp(short *outbuf, int length_in, int length_out, int end_of_text
}
#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 finished;
@@ -1725,7 +1724,7 @@ int WavegenFill(int fill_zeros)
out_ptr = p_start + length;

if (length >= max_length)
finished = 0; // there may be more data to flush
finished = 0; // there may be more data to flush
}
#endif
return finished;

+ 39
- 40
src/speak-ng.c View File

@@ -53,7 +53,7 @@
#include "translate.h"

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

char filetype[5];
char wavefile[200];
@@ -204,7 +204,7 @@ static int OpenWaveFile(const char *path, int rate)
if (path[0] != 0) {
if (strcmp(path, "stdout") == 0) {
#ifdef PLATFORM_WINDOWS
// prevent Windows adding 0x0d before 0x0a bytes
// prevent Windows adding 0x0d before 0x0a bytes
_setmode(_fileno(stdout), _O_BINARY);
#endif
f_wave = stdout;
@@ -296,14 +296,14 @@ static void init_path(char *argv0, char *path_specified)
if (((env = getenv("ESPEAK_DATA_PATH")) != NULL) && ((strlen(env)+12) < sizeof(path_home))) {
sprintf(path_home, "%s\\espeak-data", env);
if (GetFileLength(path_home) == -2)
return; // an espeak-data directory exists in the directory specified by environment variable
return; // an espeak-data directory exists in the directory specified by environment variable
}

strcpy(path_home, argv0);
if ((p = strrchr(path_home, '\\')) != NULL) {
strcpy(&p[1], "espeak-data");
if (GetFileLength(path_home) == -2)
return; // an espeak-data directory exists in the same directory as the espeak program
return; // an espeak-data directory exists in the same directory as the espeak program
}

// otherwise, look in the Windows Registry
@@ -322,7 +322,7 @@ static void init_path(char *argv0, char *path_specified)
if ((env = getenv("ESPEAK_DATA_PATH")) != NULL) {
snprintf(path_home, sizeof(path_home), "%s/espeak-data", env);
if (GetFileLength(path_home) == -2)
return; // an espeak-data directory exists
return; // an espeak-data directory exists
}

snprintf(path_home, sizeof(path_home), "%s/espeak-data", getenv("HOME"));
@@ -336,7 +336,7 @@ static int initialise(void)
{
int param;
int result;
int srate = 22050; // default sample rate
int srate = 22050; // default sample rate

// It seems that the wctype functions don't work until the locale has been set
// to something other than the default "C". Then, not only Latin1 but also the
@@ -409,7 +409,7 @@ int main(int argc, char **argv)

FILE *f_text = NULL;
const char *p_text = NULL;
char *data_path = NULL; // use default path for espeak-data
char *data_path = NULL; // use default path for espeak-data

int option_index = 0;
int c;
@@ -417,7 +417,7 @@ int main(int argc, char **argv)
int speed = 175;
int ix;
char *optarg2;
int amp = 100; // default
int amp = 100; // default
int wordgap = 0;
int flag_stdin = 0;
int flag_compile = 0;
@@ -439,7 +439,7 @@ int main(int argc, char **argv)
option_wordgap = 0;
option_endpause = 1;
option_phoneme_input = 1;
option_multibyte = espeakCHARS_AUTO; // auto
option_multibyte = espeakCHARS_AUTO;
f_trans = stdout;

#ifdef NEED_GETOPT
@@ -463,7 +463,7 @@ int main(int argc, char **argv)

if (c == '-') {
if (p[0] == 0)
break; // -- means don't interpret further - as commands
break; // -- means don't interpret further - as commands

opt_string = "";
for (ix = 0;; ix++) {
@@ -488,10 +488,10 @@ int main(int argc, char **argv)
}
#else
while (true) {
c = getopt_long(argc, argv, "a:b:f:g:hk:l:p:qs:v:w:xXmz", // NOTE: also change arg_opts to indicate which commands have a numeric value
c = getopt_long(argc, argv, "a:b:f:g:hk:l:p:qs:v:w:xXmz", // NOTE: also change arg_opts to indicate which commands have a numeric value
long_options, &option_index);

/* Detect the end of the options. */
// Detect the end of the options.
if (c == -1)
break;
optarg2 = optarg;
@@ -555,20 +555,20 @@ int main(int argc, char **argv)
case 'z':
option_endpause = 0;
break;
case 0x100: // --stdin
case 0x100: // --stdin
flag_stdin = 1;
break;
case 0x105: // --stdout
case 0x105: // --stdout
option_waveout = 1;
strcpy(wavefile, "stdout");
break;
case 0x101: // --compile-debug
case 0x102: // --compile
case 0x101: // --compile-debug
case 0x102: // --compile
if (optarg2 != NULL)
strncpy0(voicename, optarg2, sizeof(voicename));
flag_compile = c;
break;
case 0x103: // --punct
case 0x103: // --punct
option_punctuation = 1;
if (optarg2 != NULL) {
ix = 0;
@@ -577,29 +577,29 @@ int main(int argc, char **argv)
option_punctuation = 2;
}
break;
case 0x104: // --voices
case 0x104: // --voices
init_path(argv[0], data_path);
DisplayVoices(stdout, optarg2);
exit(0);
case 0x106: // -- split
case 0x106: // -- split
if (optarg2 == NULL)
samples_split = 30; // default 30 minutes
samples_split = 30; // default 30 minutes
else
samples_split = atoi(optarg2);
break;
case 0x107: // --path
case 0x107: // --path
data_path = optarg2;
break;
case 0x108: // --phonout
case 0x108: // --phonout
if ((f_trans = fopen(optarg2, "w")) == NULL) {
fprintf(stderr, "Can't write to: %s\n", optarg2);
f_trans = stderr;
}
break;
case 0x109: // --pho
case 0x109: // --pho
phoneme_options |= espeakPHONEMES_MBROLA;
break;
case 0x10a: // --ipa
case 0x10a: // --ipa
phoneme_options |= espeakPHONEMES_IPA;
if (optarg2 != NULL) {
// deprecated and obsolete
@@ -613,33 +613,33 @@ int main(int argc, char **argv)
phoneme_options |= espeakPHONEMES_TIE;
break;
case 3:
phonemes_separator = 0x200d; // ZWJ
phonemes_separator = 0x200d; // ZWJ
phoneme_options |= espeakPHONEMES_TIE;
break;
}
}
break;
case 0x10b: // --version
case 0x10b: // --version
init_path(argv[0], data_path);
printf("speak text-to-speech: %s Data at: %s\n", version_string, path_home);
exit(0);
case 0x10c: // --sep
case 0x10c: // --sep
phoneme_options |= espeakPHONEMES_SHOW;
if (optarg2 == 0)
phonemes_separator = ' ';
else
utf8_in(&phonemes_separator, optarg2);
if (phonemes_separator == 'z')
phonemes_separator = 0x200c; // ZWNJ
phonemes_separator = 0x200c; // ZWNJ
break;
case 0x10d: // --tie
case 0x10d: // --tie
phoneme_options |= (espeakPHONEMES_SHOW | espeakPHONEMES_TIE);
if (optarg2 == 0)
phonemes_separator = 0x0361; // default: combining-double-inverted-breve
phonemes_separator = 0x0361; // default: combining-double-inverted-breve
else
utf8_in(&phonemes_separator, optarg2);
if (phonemes_separator == 'z')
phonemes_separator = 0x200d; // ZWJ
phonemes_separator = 0x200d; // ZWJ
break;
default:
exit(0);
@@ -665,14 +665,14 @@ int main(int argc, char **argv)
#ifdef PLATFORM_DOS
char path_dsource[sizeof(path_home)+20];
strcpy(path_dsource, path_home);
path_dsource[strlen(path_home)-11] = 0; // remove "espeak-data" from the end
path_dsource[strlen(path_home)-11] = 0; // remove "espeak-data" from the end
strcat(path_dsource, "dictsource\\");
CompileDictionary(path_dsource, dictionary_name, NULL, NULL, flag_compile & 0x1);
#else
#ifdef PLATFORM_WINDOWS
char path_dsource[sizeof(path_home)+20];
strcpy(path_dsource, path_home);
path_dsource[strlen(path_home)-11] = 0; // remove "espeak-data" from the end
path_dsource[strlen(path_home)-11] = 0; // remove "espeak-data" from the end
strcat(path_dsource, "dictsource\\");
CompileDictionary(path_dsource, dictionary_name, NULL, NULL, flag_compile & 0x1);
#else
@@ -690,9 +690,8 @@ int main(int argc, char **argv)

option_phonemes = phoneme_options | (phonemes_separator << 8);

if (pitch_adjustment != 50) {
if (pitch_adjustment != 50)
SetParameter(espeakPITCH, pitch_adjustment, 0);
}
DoVoiceChange(voice);

if (filename[0] == 0) {
@@ -703,7 +702,7 @@ int main(int argc, char **argv)
} else {
f_text = stdin;
if (flag_stdin == 0)
option_linelength = -1; // single input lines on stdin
option_linelength = -1; // single input lines on stdin
}
} else
f_text = fopen(filename, "r");
@@ -743,7 +742,7 @@ int main(int argc, char **argv)
for (;;) {
if (WavegenFile() != 0) {
if (ix == 0)
break; // finished, wavegen command queue is empty
break; // finished, wavegen command queue is empty
}

if (Generate(phoneme_list, &n_phoneme_list, 1) == 0)
@@ -767,13 +766,13 @@ int main(int argc, char **argv)
// NOTE: if nanosleep() isn't recognised on your system, try replacing
// this by sleep(1);
#ifdef PLATFORM_WINDOWS
Sleep(300); // 0.3s
Sleep(300); // 0.3s
#else
#ifdef USE_NANOSLEEP
struct timespec period;
struct timespec remaining;
period.tv_sec = 0;
period.tv_nsec = 300000000; // 0.3 sec
period.tv_nsec = 300000000; // 0.3 sec
nanosleep(&period, &remaining);
#else
sleep(1);
@@ -785,6 +784,6 @@ int main(int argc, char **argv)
}

if ((f_trans != stdout) && (f_trans != stderr))
fclose(f_trans); // needed for WinCe
fclose(f_trans);
return 0;
}

Loading…
Cancel
Save