Some warnings, some globals hunting. Including fixes for asserts misuse (possible fatal for async in release builds).master
"-Wmissing-prototypes" | "-Wmissing-prototypes" | ||||
"-Wint-conversion" | "-Wint-conversion" | ||||
"-Wimplicit" | "-Wimplicit" | ||||
"-Wmisleading-indentation" | |||||
) | ) | ||||
endif() | endif() | ||||
target_compile_definitions(espeak-ng PRIVATE "LIBESPEAK_NG_EXPORT=1") | target_compile_definitions(espeak-ng PRIVATE "LIBESPEAK_NG_EXPORT=1") |
c2 = c2 >> 16; // sign extend | c2 = c2 >> 16; // sign extend | ||||
return (c1 & 0xff) + c2; | return (c1 & 0xff) + c2; | ||||
} | |||||
} |
} | } | ||||
c = ' '; | c = ' '; | ||||
} else if (rb == RULE_ENDING) { | } else if (rb == RULE_ENDING) { | ||||
static const char *flag_chars = "eipvdfq tba "; | |||||
static const char flag_chars[] = "eipvdfq tba "; | |||||
flags = ((rule[0] & 0x7f)<< 8) + (rule[1] & 0x7f); | flags = ((rule[0] & 0x7f)<< 8) + (rule[1] & 0x7f); | ||||
suffix_char = 'S'; | suffix_char = 'S'; | ||||
if (flags & (SUFX_P >> 8)) | if (flags & (SUFX_P >> 8)) |
#include "synthesize.h" // for STRESS_IS_PRIMARY, phoneme... | #include "synthesize.h" // for STRESS_IS_PRIMARY, phoneme... | ||||
#include "translate.h" // for Translator, utf8_in, LANGU... | #include "translate.h" // for Translator, utf8_in, LANGU... | ||||
static int LookupFlags(Translator *tr, const char *word, unsigned int **flags_out); | |||||
static void DollarRule(char *word[], char *word_start, int consumed, int group_length, char *word_buf, Translator *tr, unsigned int *flags, int command, int *failed, int *add_points); | |||||
static int LookupFlags(Translator *tr, const char *word, unsigned int flags_out[2]); | |||||
static void DollarRule(char *word[], char *word_start, int consumed, int group_length, char *word_buf, Translator *tr, int command, int *failed, int *add_points); | |||||
typedef struct { | typedef struct { | ||||
int points; | int points; | ||||
// convert characters to an approximate 7 bit ascii equivalent | // convert characters to an approximate 7 bit ascii equivalent | ||||
// used for checking for vowels (up to 0x259=schwa) | // used for checking for vowels (up to 0x259=schwa) | ||||
#define N_REMOVE_ACCENT 0x25e | #define N_REMOVE_ACCENT 0x25e | ||||
static unsigned char remove_accent[N_REMOVE_ACCENT] = { | |||||
static const unsigned char remove_accent[N_REMOVE_ACCENT] = { | |||||
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'c', 'e', 'e', 'e', 'e', 'i', 'i', 'i', 'i', // 0c0 | 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'c', 'e', 'e', 'e', 'e', 'i', 'i', 'i', 'i', // 0c0 | ||||
'd', 'n', 'o', 'o', 'o', 'o', 'o', 0, 'o', 'u', 'u', 'u', 'u', 'y', 't', 's', // 0d0 | 'd', 'n', 'o', 'o', 'o', 'o', 'o', 0, 'o', 'u', 'u', 'u', 'u', 'y', 't', 's', // 0d0 | ||||
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'c', 'e', 'e', 'e', 'e', 'i', 'i', 'i', 'i', // 0e0 | 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'c', 'e', 'e', 'e', 'e', 'i', 'i', 'i', 'i', // 0e0 | ||||
unsigned char c; | unsigned char c; | ||||
unsigned int mnem; | unsigned int mnem; | ||||
PHONEME_TAB *ph; | PHONEME_TAB *ph; | ||||
static const char *stress_chars = "==,,'* "; | |||||
static const char stress_chars[] = "==,,'* "; | |||||
sprintf(outptr, "* "); | sprintf(outptr, "* "); | ||||
while ((phcode = *inptr++) > 0) { | while ((phcode = *inptr++) > 0) { | ||||
char phon_buf2[30]; | char phon_buf2[30]; | ||||
PHONEME_LIST *plist; | PHONEME_LIST *plist; | ||||
static const char *stress_chars = "==,,''"; | |||||
static const char stress_chars[] = "==,,''"; | |||||
if (phon_out_buf == NULL) { | if (phon_out_buf == NULL) { | ||||
phon_out_size = N_PHON_OUT; | phon_out_size = N_PHON_OUT; | ||||
int n_bytes; | int n_bytes; | ||||
int add_points; | int add_points; | ||||
int command; | int command; | ||||
unsigned int *flags = NULL; | |||||
MatchRecord match; | MatchRecord match; | ||||
static MatchRecord best; | |||||
MatchRecord best; | |||||
int total_consumed; // letters consumed for best match | int total_consumed; // letters consumed for best match | ||||
else | else | ||||
failed = 1; | failed = 1; | ||||
} else if (((command & 0xf0) == 0x20) || (command == DOLLAR_LIST)) { | } else if (((command & 0xf0) == 0x20) || (command == DOLLAR_LIST)) { | ||||
DollarRule(word, word_start, consumed, group_length, word_buf, tr, flags, command, &failed, &add_points); | |||||
DollarRule(word, word_start, consumed, group_length, word_buf, tr, command, &failed, &add_points); | |||||
} | } | ||||
break; | break; | ||||
pre_ptr++; | pre_ptr++; | ||||
command = *rule++; | command = *rule++; | ||||
if ((command == DOLLAR_LIST) || ((command & 0xf0) == 0x20)) { | if ((command == DOLLAR_LIST) || ((command & 0xf0) == 0x20)) { | ||||
DollarRule(word, word_start, consumed, group_length, word_buf, tr, flags, command, &failed, &add_points); | |||||
DollarRule(word, word_start, consumed, group_length, word_buf, tr, command, &failed, &add_points); | |||||
} | } | ||||
break; | break; | ||||
case RULE_SYLLABLE: | case RULE_SYLLABLE: | ||||
return flags0; | return flags0; | ||||
} | } | ||||
static int LookupFlags(Translator *tr, const char *word, unsigned int **flags_out) | |||||
static int LookupFlags(Translator *tr, const char *word, unsigned int flags_out[2]) | |||||
{ | { | ||||
char buf[100]; | char buf[100]; | ||||
static unsigned int flags[2]; | static unsigned int flags[2]; | ||||
flags[0] = flags[1] = 0; | flags[0] = flags[1] = 0; | ||||
LookupDictList(tr, &word1, buf, flags, 0, NULL); | LookupDictList(tr, &word1, buf, flags, 0, NULL); | ||||
*flags_out = flags; | |||||
flags_out[0] = flags[0]; | |||||
flags_out[1] = flags[1]; | |||||
return flags[0]; | return flags[0]; | ||||
} | } | ||||
return end_flags; | return end_flags; | ||||
} | } | ||||
static void DollarRule(char *word[], char *word_start, int consumed, int group_length, char *word_buf, Translator *tr, unsigned int *flags, int command, int *failed, int *add_points) { | |||||
static void DollarRule(char *word[], char *word_start, int consumed, int group_length, char *word_buf, Translator *tr, int command, int *failed, int *add_points) { | |||||
// $list or $p_alt | // $list or $p_alt | ||||
// make a copy of the word up to the post-match characters | // make a copy of the word up to the post-match characters | ||||
int ix = *word - word_start + consumed + group_length + 1; | int ix = *word - word_start + consumed + group_length + 1; | ||||
memcpy(word_buf, word_start-1, ix); | memcpy(word_buf, word_start-1, ix); | ||||
word_buf[ix] = ' '; | word_buf[ix] = ' '; | ||||
word_buf[ix+1] = 0; | word_buf[ix+1] = 0; | ||||
LookupFlags(tr, &word_buf[1], &flags); | |||||
unsigned int flags[2]; | |||||
LookupFlags(tr, &word_buf[1], flags); | |||||
if ((command == DOLLAR_LIST) && (flags[0] & FLAG_FOUND) && !(flags[1] & FLAG_ONLY)) | if ((command == DOLLAR_LIST) && (flags[0] & FLAG_FOUND) && !(flags[1] & FLAG_ONLY)) | ||||
*add_points = 23; | *add_points = 23; | ||||
*add_points = 23; | *add_points = 23; | ||||
else | else | ||||
*failed = 1; | *failed = 1; | ||||
} | |||||
} |
pthread_mutex_init(&my_mutex, (const pthread_mutexattr_t *)NULL); | pthread_mutex_init(&my_mutex, (const pthread_mutexattr_t *)NULL); | ||||
init(); | init(); | ||||
assert(-1 != pthread_cond_init(&my_cond_start_is_required, NULL)); | |||||
assert(-1 != pthread_cond_init(&my_cond_stop_is_required, NULL)); | |||||
assert(-1 != pthread_cond_init(&my_cond_stop_is_acknowledged, NULL)); | |||||
int a_status; | |||||
a_status = pthread_cond_init(&my_cond_start_is_required, NULL); | |||||
assert(-1 != a_status); | |||||
a_status = pthread_cond_init(&my_cond_stop_is_required, NULL); | |||||
assert(-1 != a_status); | |||||
a_status = pthread_cond_init(&my_cond_stop_is_acknowledged, NULL); | |||||
assert(-1 != a_status); | |||||
(void)a_status; | |||||
pthread_attr_t a_attrib; | pthread_attr_t a_attrib; | ||||
return status; | return status; | ||||
} | } | ||||
espeak_ng_STATUS event_clear_all() | |||||
espeak_ng_STATUS event_clear_all(void) | |||||
{ | { | ||||
espeak_ng_STATUS status; | espeak_ng_STATUS status; | ||||
if ((status = pthread_mutex_lock(&my_mutex)) != ENS_OK) | if ((status = pthread_mutex_lock(&my_mutex)) != ENS_OK) | ||||
return ENS_OK; | return ENS_OK; | ||||
} | } | ||||
static void *pop() | |||||
static void *pop(void) | |||||
{ | { | ||||
void *the_data = NULL; | void *the_data = NULL; | ||||
} | } | ||||
static void init() | |||||
static void init(void) | |||||
{ | { | ||||
while (event_delete((espeak_EVENT *)pop())) | while (event_delete((espeak_EVENT *)pop())) | ||||
; | ; | ||||
node_counter = 0; | node_counter = 0; | ||||
} | } | ||||
void event_terminate() | |||||
void event_terminate(void) | |||||
{ | { | ||||
if (thread_inited) { | if (thread_inited) { | ||||
my_terminate_is_required = true; | my_terminate_is_required = true; | ||||
if (!ts) | if (!ts) | ||||
return; | return; | ||||
assert(gettimeofday(&tv, NULL) != -1); | |||||
int a_status = gettimeofday(&tv, NULL); | |||||
assert(a_status != -1); | |||||
(void)a_status; | |||||
ts->tv_sec = tv.tv_sec; | ts->tv_sec = tv.tv_sec; | ||||
ts->tv_nsec = tv.tv_usec*1000; | ts->tv_nsec = tv.tv_usec*1000; | ||||
} | } |
MAX_INACTIVITY_CHECK = 2 | MAX_INACTIVITY_CHECK = 2 | ||||
}; | }; | ||||
void fifo_init() | |||||
void fifo_init(void) | |||||
{ | { | ||||
// security | // security | ||||
pthread_mutex_init(&my_mutex, (const pthread_mutexattr_t *)NULL); | pthread_mutex_init(&my_mutex, (const pthread_mutexattr_t *)NULL); | ||||
init(0); | init(0); | ||||
assert(-1 != pthread_cond_init(&my_cond_command_is_running, NULL)); | |||||
assert(-1 != pthread_cond_init(&my_cond_start_is_required, NULL)); | |||||
assert(-1 != pthread_cond_init(&my_cond_stop_is_acknowledged, NULL)); | |||||
int a_status; | |||||
a_status = pthread_cond_init(&my_cond_command_is_running, NULL); | |||||
assert(-1 != a_status); | |||||
a_status = pthread_cond_init(&my_cond_start_is_required, NULL); | |||||
assert(-1 != a_status); | |||||
a_status = pthread_cond_init(&my_cond_stop_is_acknowledged, NULL); | |||||
assert(-1 != a_status); | |||||
pthread_attr_t a_attrib; | pthread_attr_t a_attrib; | ||||
if (pthread_attr_init(&a_attrib) | if (pthread_attr_init(&a_attrib) | ||||
pthread_attr_destroy(&a_attrib); | pthread_attr_destroy(&a_attrib); | ||||
// leave once the thread is actually started | // leave once the thread is actually started | ||||
assert(-1 != pthread_mutex_lock(&my_mutex)); | |||||
a_status = pthread_mutex_lock(&my_mutex); | |||||
assert(-1 != a_status); | |||||
(void)a_status; | |||||
while (my_stop_is_acknowledged == false) { | while (my_stop_is_acknowledged == false) { | ||||
while ((pthread_cond_wait(&my_cond_stop_is_acknowledged, &my_mutex) == -1) && errno == EINTR) | while ((pthread_cond_wait(&my_cond_stop_is_acknowledged, &my_mutex) == -1) && errno == EINTR) | ||||
; | ; | ||||
return ENS_OK; | return ENS_OK; | ||||
} | } | ||||
espeak_ng_STATUS fifo_stop() | |||||
espeak_ng_STATUS fifo_stop(void) | |||||
{ | { | ||||
if (!thread_inited) return ENS_OK; | if (!thread_inited) return ENS_OK; | ||||
espeak_ng_STATUS status; | espeak_ng_STATUS status; | ||||
return ENS_OK; | return ENS_OK; | ||||
} | } | ||||
int fifo_is_busy() | |||||
int fifo_is_busy(void) | |||||
{ | { | ||||
if (!thread_inited) return false; | if (!thread_inited) return false; | ||||
pthread_mutex_lock(&my_mutex); | pthread_mutex_lock(&my_mutex); | ||||
return running; | return running; | ||||
} | } | ||||
static int sleep_until_start_request_or_inactivity() | |||||
static int sleep_until_start_request_or_inactivity(void) | |||||
{ | { | ||||
int a_start_is_required = false; | int a_start_is_required = false; | ||||
i++; | i++; | ||||
struct timespec ts; | struct timespec ts; | ||||
struct timeval tv; | |||||
clock_gettime2(&ts); | clock_gettime2(&ts); | ||||
&& errno == EINTR) | && errno == EINTR) | ||||
continue; | continue; | ||||
assert(gettimeofday(&tv, NULL) != -1); | |||||
if (err == 0) | if (err == 0) | ||||
a_start_is_required = true; | a_start_is_required = true; | ||||
} | } | ||||
return a_start_is_required; | return a_start_is_required; | ||||
} | } | ||||
static espeak_ng_STATUS close_stream() | |||||
static espeak_ng_STATUS close_stream(void) | |||||
{ | { | ||||
espeak_ng_STATUS status = pthread_mutex_lock(&my_mutex); | espeak_ng_STATUS status = pthread_mutex_lock(&my_mutex); | ||||
if (status != ENS_OK) | if (status != ENS_OK) | ||||
{ | { | ||||
(void)p; // unused | (void)p; // unused | ||||
int a_status; | |||||
// announce that thread is started | // announce that thread is started | ||||
assert(-1 != pthread_mutex_lock(&my_mutex)); | |||||
a_status = pthread_mutex_lock(&my_mutex); | |||||
assert(-1 != a_status); | |||||
my_stop_is_acknowledged = true; | my_stop_is_acknowledged = true; | ||||
assert(-1 != pthread_cond_signal(&my_cond_stop_is_acknowledged)); | |||||
assert(-1 != pthread_mutex_unlock(&my_mutex)); | |||||
a_status = pthread_cond_signal(&my_cond_stop_is_acknowledged); | |||||
assert(-1 != a_status); | |||||
a_status = pthread_mutex_unlock(&my_mutex); | |||||
assert(-1 != a_status); | |||||
bool look_for_inactivity = false; | bool look_for_inactivity = false; | ||||
} | } | ||||
look_for_inactivity = true; | look_for_inactivity = true; | ||||
int a_status = pthread_mutex_lock(&my_mutex); | |||||
a_status = pthread_mutex_lock(&my_mutex); | |||||
assert(!a_status); | assert(!a_status); | ||||
if (!a_start_is_required) { | if (!a_start_is_required) { | ||||
my_command_is_running = true; | my_command_is_running = true; | ||||
assert(-1 != pthread_cond_broadcast(&my_cond_command_is_running)); | |||||
assert(-1 != pthread_mutex_unlock(&my_mutex)); | |||||
a_status = pthread_cond_broadcast(&my_cond_command_is_running); | |||||
assert(-1 != a_status); | |||||
a_status = pthread_mutex_unlock(&my_mutex); | |||||
assert(-1 != a_status); | |||||
while (my_command_is_running && !my_terminate_is_required) { | while (my_command_is_running && !my_terminate_is_required) { | ||||
int a_status = pthread_mutex_lock(&my_mutex); | |||||
a_status = pthread_mutex_lock(&my_mutex); | |||||
assert(!a_status); | assert(!a_status); | ||||
t_espeak_command *a_command = (t_espeak_command *)pop(); | t_espeak_command *a_command = (t_espeak_command *)pop(); | ||||
// and waiting for my_cond_stop_is_acknowledged | // and waiting for my_cond_stop_is_acknowledged | ||||
init(1); | init(1); | ||||
assert(-1 != pthread_mutex_lock(&my_mutex)); | |||||
a_status = pthread_mutex_lock(&my_mutex); | |||||
assert(-1 != a_status); | |||||
my_start_is_required = false; | my_start_is_required = false; | ||||
// acknowledge the stop request | // acknowledge the stop request | ||||
my_stop_is_acknowledged = true; | my_stop_is_acknowledged = true; | ||||
int a_status = pthread_cond_signal(&my_cond_stop_is_acknowledged); | |||||
a_status = pthread_cond_signal(&my_cond_stop_is_acknowledged); | |||||
assert(a_status != -1); | assert(a_status != -1); | ||||
pthread_mutex_unlock(&my_mutex); | pthread_mutex_unlock(&my_mutex); | ||||
} | } | ||||
// and wait for the next start | // and wait for the next start | ||||
} | } | ||||
(void)a_status; | |||||
return NULL; | return NULL; | ||||
} | } | ||||
int fifo_is_command_enabled() | |||||
int fifo_is_command_enabled(void) | |||||
{ | { | ||||
return 0 == my_stop_is_required; | return 0 == my_stop_is_required; | ||||
} | } | ||||
return ENS_OK; | return ENS_OK; | ||||
} | } | ||||
static t_espeak_command *pop() | |||||
static t_espeak_command *pop(void) | |||||
{ | { | ||||
t_espeak_command *the_command = NULL; | t_espeak_command *the_command = NULL; | ||||
node_counter = 0; | node_counter = 0; | ||||
} | } | ||||
void fifo_terminate() | |||||
void fifo_terminate(void) | |||||
{ | { | ||||
if (!thread_inited) return; | if (!thread_inited) return; | ||||
{ | { | ||||
PHONEME_LIST *p; | PHONEME_LIST *p; | ||||
int ix; | int ix; | ||||
int count_stressed = 0; | |||||
int final_stressed = 0; | int final_stressed = 0; | ||||
int tone_ph; | int tone_ph; | ||||
for (ix = 0; ix < n_phoneme_list; ix++, p++) { | for (ix = 0; ix < n_phoneme_list; ix++, p++) { | ||||
if ((p->type == phVOWEL) && (p->stresslevel >= 4)) { | if ((p->type == phVOWEL) && (p->stresslevel >= 4)) { | ||||
final_stressed = ix; | final_stressed = ix; | ||||
count_stressed++; | |||||
} | } | ||||
} | } | ||||
#define NUMBER_OF_SAMPLES 100 | #define NUMBER_OF_SAMPLES 100 | ||||
static int scale_wav_tab[] = { 45, 38, 45, 45, 55, 45 }; // scale output from different voicing sources | |||||
static const int scale_wav_tab[] = { 45, 38, 45, 45, 55, 45 }; // scale output from different voicing sources | |||||
// For testing, this can be overwritten in KlattInit() | // For testing, this can be overwritten in KlattInit() | ||||
static const short natural_samples2[256] = { | static const short natural_samples2[256] = { | ||||
to Kopen. | to Kopen. | ||||
*/ | */ | ||||
static double impulsive_source() | |||||
static double impulsive_source(void) | |||||
{ | { | ||||
static const double doublet[] = { 0.0, 13000000.0, -13000000.0 }; | static const double doublet[] = { 0.0, 13000000.0, -13000000.0 }; | ||||
static double vwave; | static double vwave; | ||||
spectral zero around 800 Hz, magic constants a,b reset pitch synchronously. | spectral zero around 800 Hz, magic constants a,b reset pitch synchronously. | ||||
*/ | */ | ||||
static double natural_source() | |||||
static double natural_source(void) | |||||
{ | { | ||||
double lgtemp; | double lgtemp; | ||||
static double vwave; | static double vwave; | ||||
} | } | ||||
} | } | ||||
void KlattInit() | |||||
void KlattInit(void) | |||||
{ | { | ||||
static const short formant_hz[10] = { 280, 688, 1064, 2806, 3260, 3700, 6500, 7000, 8000, 280 }; | static const short formant_hz[10] = { 280, 688, 1064, 2806, 3260, 3700, 6500, 7000, 8000, 280 }; |
static int CheckTranslator(Translator *tr, const MNEM_TAB *keyword_tab, int key); | static int CheckTranslator(Translator *tr, const MNEM_TAB *keyword_tab, int key); | ||||
static int LookupTune(const char *name); | static int LookupTune(const char *name); | ||||
extern const MNEM_TAB langopts_tab[]; | |||||
void LoadLanguageOptions(Translator *translator, int key, char *keyValue ) { | void LoadLanguageOptions(Translator *translator, int key, char *keyValue ) { | ||||
if (CheckTranslator(translator, langopts_tab, key) != 0) { | if (CheckTranslator(translator, langopts_tab, key) != 0) { | ||||
return; | return; | ||||
fprintf(stderr, "Cannot set %s: language not set, or is invalid.\n", LookupMnemName(keyword_tab, key)); | fprintf(stderr, "Cannot set %s: language not set, or is invalid.\n", LookupMnemName(keyword_tab, key)); | ||||
return 1; | return 1; | ||||
} | |||||
} |
// this list must be in ascending order | // this list must be in ascending order | ||||
static unsigned short derived_letters[] = { | |||||
static const unsigned short derived_letters[] = { | |||||
0x00aa, 'a'+L_SUP, | 0x00aa, 'a'+L_SUP, | ||||
0x00b2, '2'+L_SUP, | 0x00b2, '2'+L_SUP, | ||||
0x00b3, '3'+L_SUP, | 0x00b3, '3'+L_SUP, | ||||
int value; | int value; | ||||
int subtract; | int subtract; | ||||
int repeat = 0; | int repeat = 0; | ||||
int n_digits = 0; | |||||
char *word_start; | char *word_start; | ||||
int num_control = 0; | int num_control = 0; | ||||
unsigned int flags[2]; | unsigned int flags[2]; | ||||
char ph_roman[30]; | char ph_roman[30]; | ||||
char number_chars[N_WORD_BYTES]; | char number_chars[N_WORD_BYTES]; | ||||
static const char *roman_numbers = "ixcmvld"; | |||||
static const char roman_numbers[] = "ixcmvld"; | |||||
static const int roman_values[] = { 1, 10, 100, 1000, 5, 50, 500 }; | static const int roman_values[] = { 1, 10, 100, 1000, 5, 50, 500 }; | ||||
acc = 0; | acc = 0; | ||||
else | else | ||||
acc += prev; | acc += prev; | ||||
prev = value; | prev = value; | ||||
n_digits++; | |||||
} | } | ||||
if (IsDigit09(word[0])) | if (IsDigit09(word[0])) |
// re-interpret the changed phoneme | // re-interpret the changed phoneme | ||||
// But it doesn't obey a second ChangePhoneme() | // But it doesn't obey a second ChangePhoneme() | ||||
InterpretPhoneme(tr, 0x100, plist3, phdata, worddata); | InterpretPhoneme(tr, 0x100, plist3, phdata, worddata); | ||||
} | |||||
} |
} | } | ||||
} | } | ||||
static bool isKlattFrameFollowing() { | |||||
static bool isKlattFrameFollowing(void) { | |||||
// eSpeak implements its command queue with a circular buffer. | // eSpeak implements its command queue with a circular buffer. | ||||
// Thus to walk it, we start from the head, walking to the tail, which may wrap around to the beginning of the buffer as it is circular. | // Thus to walk it, we start from the head, walking to the tail, which may wrap around to the beginning of the buffer as it is circular. | ||||
for(int i=(wcmdq_head+1)%N_WCMDQ;i!=wcmdq_tail;i=(i+1)%N_WCMDQ) { | for(int i=(wcmdq_head+1)%N_WCMDQ;i!=wcmdq_tail;i=(i+1)%N_WCMDQ) { | ||||
spFrame->endVoicePitch=spFrame->voicePitch; | spFrame->endVoicePitch=spFrame->voicePitch; | ||||
} | } | ||||
void KlattInitSP() { | |||||
void KlattInitSP(void) { | |||||
speechPlayerHandle=speechPlayer_initialize(22050); | speechPlayerHandle=speechPlayer_initialize(22050); | ||||
} | } | ||||
void KlattFiniSP() { | |||||
void KlattFiniSP(void) { | |||||
if (speechPlayerHandle) | if (speechPlayerHandle) | ||||
speechPlayer_terminate(speechPlayerHandle); | speechPlayer_terminate(speechPlayerHandle); | ||||
speechPlayerHandle = NULL; | speechPlayerHandle = NULL; | ||||
} | } | ||||
void KlattResetSP() { | |||||
void KlattResetSP(void) { | |||||
KlattFiniSP(); | KlattFiniSP(); | ||||
KlattInitSP(); | KlattInitSP(); | ||||
} | } |
#include "synthesize.h" | #include "synthesize.h" | ||||
#include "translate.h" | #include "translate.h" | ||||
static void SetSpeedFactors(voice_t *voice, int x, int *speed1, int *speed2, int *speed3); | |||||
static void SetSpeedFactors(voice_t *voice, int x, int speeds[3]); | |||||
static void SetSpeedMods(SPEED_FACTORS *speed, int voiceSpeedF1, int wpm, int x); | static void SetSpeedMods(SPEED_FACTORS *speed, int voiceSpeedF1, int wpm, int x); | ||||
static void SetSpeedMultiplier(int *x, int *wpm); | static void SetSpeedMultiplier(int *x, int *wpm); | ||||
// convert from words-per-minute to internal speed factor | // convert from words-per-minute to internal speed factor | ||||
// Use this to calibrate speed for wpm 80-450 (espeakRATE_MINIMUM - espeakRATE_MAXIMUM) | // Use this to calibrate speed for wpm 80-450 (espeakRATE_MINIMUM - espeakRATE_MAXIMUM) | ||||
static unsigned char speed_lookup[] = { | |||||
static const unsigned char speed_lookup[] = { | |||||
255, 255, 255, 255, 255, // 80 | 255, 255, 255, 255, 255, // 80 | ||||
253, 249, 245, 242, 238, // 85 | 253, 249, 245, 242, 238, // 85 | ||||
235, 232, 228, 225, 222, // 90 | 235, 232, 228, 225, 222, // 90 | ||||
}; | }; | ||||
// speed_factor1 adjustments for speeds 350 to 374: pauses | // speed_factor1 adjustments for speeds 350 to 374: pauses | ||||
static unsigned char pause_factor_350[] = { | |||||
static const unsigned char pause_factor_350[] = { | |||||
22, 22, 22, 22, 22, 22, 22, 21, 21, 21, // 350 | 22, 22, 22, 22, 22, 22, 22, 21, 21, 21, // 350 | ||||
21, 20, 20, 19, 19, 18, 17, 16, 15, 15, // 360 | 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 | // wav_factor adjustments for speeds 350 to 450 | ||||
// Use this to calibrate speed for wpm 350-450 | // Use this to calibrate speed for wpm 350-450 | ||||
static unsigned char wav_factor_350[] = { | |||||
static const unsigned char wav_factor_350[] = { | |||||
120, 121, 120, 119, 119, // 350 | 120, 121, 120, 119, 119, // 350 | ||||
118, 118, 117, 116, 116, // 355 | 118, 118, 117, 116, 116, // 355 | ||||
115, 114, 113, 112, 112, // 360 | 115, 114, 113, 112, 112, // 360 | ||||
45 // 450 | 45 // 450 | ||||
}; | }; | ||||
static int speed1 = 130; | |||||
static int speed2 = 121; | |||||
static int speed3 = 118; | |||||
static int len_speeds[3] = { 130, 121, 118 }; | |||||
void SetSpeed(int control) | void SetSpeed(int control) | ||||
{ | { | ||||
// The eSpeak output will be speeded up by at least x2 | // The eSpeak output will be speeded up by at least x2 | ||||
x = 73; | x = 73; | ||||
if (control & 1) { | if (control & 1) { | ||||
speed1 = (x * voice->speedf1)/256; | |||||
speed2 = (x * voice->speedf2)/256; | |||||
speed3 = (x * voice->speedf3)/256; | |||||
len_speeds[0] = (x * voice->speedf1)/256; | |||||
len_speeds[1] = (x * voice->speedf2)/256; | |||||
len_speeds[2] = (x * voice->speedf3)/256; | |||||
} | } | ||||
if (control & 2) { | if (control & 2) { | ||||
double sonic; | double sonic; | ||||
SetSpeedMultiplier(&x, &wpm); | SetSpeedMultiplier(&x, &wpm); | ||||
if (control & 1) { | if (control & 1) { | ||||
SetSpeedFactors(voice, x, &speed1, &speed2, &speed3); | |||||
SetSpeedFactors(voice, x, len_speeds); | |||||
} | } | ||||
if (control & 2) { | if (control & 2) { | ||||
*x = 6; | *x = 6; | ||||
} | } | ||||
static void SetSpeedFactors(voice_t *voice, int x, int *speed1, int *speed2, int *speed3) { | |||||
static void SetSpeedFactors(voice_t *voice, int x, int speeds[3]) { | |||||
// set speed factors for different syllable positions within a word | // set speed factors for different syllable positions within a word | ||||
// these are used in CalcLengths() | // these are used in CalcLengths() | ||||
*speed1 = (x * voice->speedf1)/256; | |||||
*speed2 = (x * voice->speedf2)/256; | |||||
*speed3 = (x * voice->speedf3)/256; | |||||
speeds[0] = (x * voice->speedf1)/256; | |||||
speeds[1] = (x * voice->speedf2)/256; | |||||
speeds[2] = (x * voice->speedf3)/256; | |||||
if (x <= 7) { | if (x <= 7) { | ||||
*speed1 = x; | |||||
*speed2 = *speed3 = x - 1; | |||||
speeds[0] = x; | |||||
speeds[1] = speeds[2] = x - 1; | |||||
} | } | ||||
} | } | ||||
p->length = prev->length; | p->length = prev->length; | ||||
if (p->type == phLIQUID) | if (p->type == phLIQUID) | ||||
p->length = speed1; | |||||
p->length = len_speeds[0]; | |||||
if (next->type == phVSTOP) | if (next->type == phVSTOP) | ||||
p->length = (p->length * 160)/100; | p->length = (p->length * 160)/100; | ||||
} | } | ||||
if (more_syllables == 0) | if (more_syllables == 0) | ||||
length_mod *= speed1; | |||||
length_mod *= len_speeds[0]; | |||||
else if (more_syllables == 1) | else if (more_syllables == 1) | ||||
length_mod *= speed2; | |||||
length_mod *= len_speeds[1]; | |||||
else | else | ||||
length_mod *= speed3; | |||||
length_mod *= len_speeds[2]; | |||||
length_mod = length_mod / 128; | length_mod = length_mod / 128; | ||||
length_mod = length_mod * (256 + (280 - len)/3)/256; | length_mod = length_mod * (256 + (280 - len)/3)/256; | ||||
} | } | ||||
if (length_mod > tr->langopts.max_lengthmod*speed1) { | |||||
if (length_mod > tr->langopts.max_lengthmod*len_speeds[0]) { | |||||
// limit the vowel length adjustment for some languages | // limit the vowel length adjustment for some languages | ||||
length_mod = (tr->langopts.max_lengthmod*speed1); | |||||
length_mod = (tr->langopts.max_lengthmod*len_speeds[0]); | |||||
} | } | ||||
length_mod = length_mod / 128; | length_mod = length_mod / 128; |
#include "synthesize.h" // for KLATT_AV, KLATT_Kopen, N_KLATTP2 | #include "synthesize.h" // for KLATT_AV, KLATT_Kopen, N_KLATTP2 | ||||
#include "voice.h" // for N_PEAKS | #include "voice.h" // for N_PEAKS | ||||
static int frame_width; | |||||
static int default_freq[N_PEAKS] = | |||||
static const int default_freq[N_PEAKS] = | |||||
{ 200, 500, 1200, 3000, 3500, 4000, 6900, 7800, 9000 }; | { 200, 500, 1200, 3000, 3500, 4000, 6900, 7800, 9000 }; | ||||
static int default_width[N_PEAKS] = | |||||
static const int default_width[N_PEAKS] = | |||||
{ 750, 500, 550, 550, 600, 700, 700, 700, 700 }; | { 750, 500, 550, 550, 600, 700, 700, 700, 700 }; | ||||
static int default_klt_bw[N_PEAKS] = | |||||
static const int default_klt_bw[N_PEAKS] = | |||||
{ 89, 90, 140, 260, 260, 260, 500, 500, 500 }; | { 89, 90, 140, 260, 260, 260, 500, 500, 500 }; | ||||
static double read_double(FILE *stream) | static double read_double(FILE *stream) | ||||
return y; | return y; | ||||
} | } | ||||
static SpectFrame *SpectFrameCreate() | |||||
static SpectFrame *SpectFrameCreate(void) | |||||
{ | { | ||||
int ix; | int ix; | ||||
SpectFrame *frame; | SpectFrame *frame; | ||||
} | } | ||||
#pragma GCC visibility push(default) | #pragma GCC visibility push(default) | ||||
SpectSeq *SpectSeqCreate() | |||||
SpectSeq *SpectSeqCreate(void) | |||||
{ | { | ||||
SpectSeq *spect = malloc(sizeof(SpectSeq)); | SpectSeq *spect = malloc(sizeof(SpectSeq)); | ||||
if (!spect) | if (!spect) | ||||
} | } | ||||
spect->max_x = 9000; // disable auto-xscaling | spect->max_x = 9000; // disable auto-xscaling | ||||
frame_width = (int)((FRAME_WIDTH*spect->max_x)/MAX_DISPLAY_FREQ); | |||||
if (frame_width > FRAME_WIDTH) frame_width = FRAME_WIDTH; | |||||
// start times from zero | // start times from zero | ||||
time_offset = spect->frames[0]->time; | time_offset = spect->frames[0]->time; | ||||
for (ix = 0; ix < spect->numframes; ix++) | for (ix = 0; ix < spect->numframes; ix++) |
static espeak_ng_OUTPUT_MODE my_mode = ENOUTPUT_MODE_SYNCHRONOUS; | static espeak_ng_OUTPUT_MODE my_mode = ENOUTPUT_MODE_SYNCHRONOUS; | ||||
static int out_samplerate = 0; | static int out_samplerate = 0; | ||||
static int voice_samplerate = 22050; | static int voice_samplerate = 22050; | ||||
static int min_buffer_length = 60; // minimum buffer length in ms | |||||
static const int min_buffer_length = 60; // minimum buffer length in ms | |||||
static espeak_ng_STATUS err = ENS_OK; | static espeak_ng_STATUS err = ENS_OK; | ||||
static t_espeak_callback *synth_callback = NULL; | static t_espeak_callback *synth_callback = NULL; | ||||
// Fill the buffer with output sound | // Fill the buffer with output sound | ||||
int length; | int length; | ||||
int finished = 0; | int finished = 0; | ||||
int count_buffers = 0; | |||||
if ((outbuf == NULL) || (event_list == NULL)) | if ((outbuf == NULL) || (event_list == NULL)) | ||||
return ENS_NOT_INITIALIZED; | return ENS_NOT_INITIALIZED; | ||||
event_list[event_list_ix].unique_identifier = unique_identifier; | event_list[event_list_ix].unique_identifier = unique_identifier; | ||||
event_list[event_list_ix].user_data = my_user_data; | event_list[event_list_ix].user_data = my_user_data; | ||||
count_buffers++; | |||||
if ((my_mode & ENOUTPUT_MODE_SPEAK_AUDIO) == ENOUTPUT_MODE_SPEAK_AUDIO) { | if ((my_mode & ENOUTPUT_MODE_SPEAK_AUDIO) == ENOUTPUT_MODE_SPEAK_AUDIO) { | ||||
finished = create_events((short *)outbuf, length, event_list); | finished = create_events((short *)outbuf, length, event_list); | ||||
if (finished < 0) | if (finished < 0) | ||||
{ | { | ||||
(void)size; // unused in non-async modes | (void)size; // unused in non-async modes | ||||
static unsigned int temp_identifier; | |||||
unsigned int temp_identifier; | |||||
if (unique_identifier == NULL) | if (unique_identifier == NULL) | ||||
unique_identifier = &temp_identifier; | unique_identifier = &temp_identifier; | ||||
{ | { | ||||
(void)size; // unused in non-async modes | (void)size; // unused in non-async modes | ||||
static unsigned int temp_identifier; | |||||
unsigned int temp_identifier; | |||||
if (unique_identifier == NULL) | if (unique_identifier == NULL) | ||||
unique_identifier = &temp_identifier; | unique_identifier = &temp_identifier; |
return buf; | return buf; | ||||
} | } | ||||
void SynthesizeInit() | |||||
void SynthesizeInit(void) | |||||
{ | { | ||||
last_pitch_cmd = 0; | last_pitch_cmd = 0; | ||||
last_amp_cmd = 0; | last_amp_cmd = 0; | ||||
return len; | return len; | ||||
} | } | ||||
static frame_t *AllocFrame() | |||||
static frame_t *AllocFrame(void) | |||||
{ | { | ||||
// Allocate a temporary spectrum frame for the wavegen queue. Use a pool which is big | // Allocate a temporary spectrum frame for the wavegen queue. Use a pool which is big | ||||
// enough to use a round-robin without checks. | // enough to use a round-robin without checks. | ||||
if (WcmdqFree() <= free_min) | if (WcmdqFree() <= free_min) | ||||
return 1; // wait | return 1; // wait | ||||
PHONEME_LIST *prev; | |||||
PHONEME_LIST *next; | |||||
PHONEME_LIST *next2; | |||||
PHONEME_LIST *prev; | |||||
PHONEME_LIST *next; | |||||
PHONEME_LIST *next2; | |||||
prev = &phoneme_list[ix-1]; | prev = &phoneme_list[ix-1]; | ||||
next = &phoneme_list[ix+1]; | next = &phoneme_list[ix+1]; |
case L('s', 'k'): // Slovak | case L('s', 'k'): // Slovak | ||||
case L('c', 's'): // Czech | case L('c', 's'): // Czech | ||||
{ | { | ||||
static const char *sk_voiced = "bdgjlmnrvwzaeiouy"; | |||||
static const char sk_voiced[] = "bdgjlmnrvwzaeiouy"; | |||||
SetupTranslator(tr, stress_lengths_sk, stress_amps_sk); | SetupTranslator(tr, stress_lengths_sk, stress_amps_sk); | ||||
tr->encoding = ESPEAKNG_ENCODING_ISO_8859_2; | tr->encoding = ESPEAKNG_ENCODING_ISO_8859_2; |
return count; | return count; | ||||
} | } | ||||
static void Word_EmbeddedCmd() | |||||
static void Word_EmbeddedCmd(void) | |||||
{ | { | ||||
// Process embedded commands for emphasis, sayas, and break | // Process embedded commands for emphasis, sayas, and break | ||||
int embedded_cmd; | int embedded_cmd; |
int tone_points[12] = { 600, 170, 1200, 135, 2000, 110, 3000, 110, -1, 0 }; | int tone_points[12] = { 600, 170, 1200, 135, 2000, 110, 3000, 110, -1, 0 }; | ||||
// limit the rate of change for each formant number | // 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 | |||||
static const int formant_rate_22050[9] = { 240, 170, 170, 170, 170, 170, 170, 170, 170 }; // values for 22kHz sample rate | |||||
int formant_rate[9]; // values adjusted for actual sample rate | int formant_rate[9]; // values adjusted for actual sample rate | ||||
#define DEFAULT_LANGUAGE_PRIORITY 5 | #define DEFAULT_LANGUAGE_PRIORITY 5 | ||||
#pragma GCC visibility pop | #pragma GCC visibility pop | ||||
void FreeVoiceList() | |||||
void FreeVoiceList(void) | |||||
{ | { | ||||
int ix; | int ix; | ||||
for (ix = 0; ix < n_voices_list; ix++) { | for (ix = 0; ix < n_voices_list; ix++) { | ||||
if (voice_data != NULL) | if (voice_data != NULL) | ||||
voices_list[n_voices_list++] = voice_data; | voices_list[n_voices_list++] = voice_data; | ||||
return 0; | |||||
} | } | ||||
return 0; | return 0; | ||||
} | } |
// pitch,speed, | // pitch,speed, | ||||
const int embedded_default[N_EMBEDDED_VALUES] = { 0, 50, espeakRATE_NORMAL, 100, 50, 0, 0, 0, espeakRATE_NORMAL, 0, 0, 0, 0, 0, 0 }; | const int embedded_default[N_EMBEDDED_VALUES] = { 0, 50, espeakRATE_NORMAL, 100, 50, 0, 0, 0, espeakRATE_NORMAL, 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 }; | |||||
static const int embedded_max[N_EMBEDDED_VALUES] = { 0, 0x7fff, 750, 300, 99, 99, 99, 0, 750, 0, 0, 0, 0, 4, 0 }; | |||||
#if USE_LIBSONIC | #if USE_LIBSONIC | ||||
static sonicStream sonicSpeedupStream = NULL; | static sonicStream sonicSpeedupStream = NULL; | ||||
// 2nd index=modulation_type | // 2nd index=modulation_type | ||||
// value: bits 0-3 amplitude (16ths), bits 4-7 every n cycles | // value: bits 0-3 amplitude (16ths), bits 4-7 every n cycles | ||||
#define N_ROUGHNESS 8 | #define N_ROUGHNESS 8 | ||||
static unsigned char modulation_tab[N_ROUGHNESS][8] = { | |||||
static const unsigned char modulation_tab[N_ROUGHNESS][8] = { | |||||
{ 0, 0x00, 0x00, 0x00, 0, 0x46, 0xf2, 0x29 }, | { 0, 0x00, 0x00, 0x00, 0, 0x46, 0xf2, 0x29 }, | ||||
{ 0, 0x2f, 0x00, 0x2f, 0, 0x45, 0xf2, 0x29 }, | { 0, 0x2f, 0x00, 0x2f, 0, 0x45, 0xf2, 0x29 }, | ||||
{ 0, 0x2f, 0x00, 0x2e, 0, 0x45, 0xf2, 0x28 }, | { 0, 0x2f, 0x00, 0x2e, 0, 0x45, 0xf2, 0x28 }, | ||||
242, 246, 249, 252, 254, 255 | 242, 246, 249, 252, 254, 255 | ||||
}; | }; | ||||
void WcmdqStop() | |||||
void WcmdqStop(void) | |||||
{ | { | ||||
wcmdq_head = 0; | wcmdq_head = 0; | ||||
wcmdq_tail = 0; | wcmdq_tail = 0; | ||||
#endif | #endif | ||||
} | } | ||||
int WcmdqFree() | |||||
int WcmdqFree(void) | |||||
{ | { | ||||
int i; | int i; | ||||
i = wcmdq_head - wcmdq_tail; | i = wcmdq_head - wcmdq_tail; | ||||
return i; | return i; | ||||
} | } | ||||
int WcmdqUsed() | |||||
int WcmdqUsed(void) | |||||
{ | { | ||||
return N_WCMDQ - WcmdqFree(); | return N_WCMDQ - WcmdqFree(); | ||||
} | } | ||||
void WcmdqInc() | |||||
void WcmdqInc(void) | |||||
{ | { | ||||
wcmdq_tail++; | wcmdq_tail++; | ||||
if (wcmdq_tail >= N_WCMDQ) wcmdq_tail = 0; | if (wcmdq_tail >= N_WCMDQ) wcmdq_tail = 0; | ||||
} | } | ||||
static void WcmdqIncHead() | |||||
static void WcmdqIncHead(void) | |||||
{ | { | ||||
MAKE_MEM_UNDEFINED(&wcmdq[wcmdq_head], sizeof(wcmdq[wcmdq_head])); | MAKE_MEM_UNDEFINED(&wcmdq[wcmdq_head], sizeof(wcmdq[wcmdq_head])); | ||||
wcmdq_head++; | wcmdq_head++; | ||||
return hmax; // highest harmonic number | return hmax; // highest harmonic number | ||||
} | } | ||||
static void AdvanceParameters() | |||||
static void AdvanceParameters(void) | |||||
{ | { | ||||
// Called every 64 samples to increment the formant freq, height, and widths | // Called every 64 samples to increment the formant freq, height, and widths | ||||
if (wvoice == NULL) | if (wvoice == NULL) | ||||
setresonator(&rbreath[ix], 2000, 200, 1); | setresonator(&rbreath[ix], 2000, 200, 1); | ||||
} | } | ||||
static void SetBreath() | |||||
static void SetBreath(void) | |||||
{ | { | ||||
int pk; | int pk; | ||||
return value; | return value; | ||||
} | } | ||||
static void SetPitchFormants() | |||||
static void SetPitchFormants(void) | |||||
{ | { | ||||
if (wvoice == NULL) | if (wvoice == NULL) | ||||
return; | return; | ||||
} | } | ||||
} | } | ||||
static int WavegenFill2() | |||||
static int WavegenFill2(void) | |||||
{ | { | ||||
// Pick up next wavegen commands from the queue | // Pick up next wavegen commands from the queue | ||||
// return: 0 output buffer has been filled | // return: 0 output buffer has been filled |