See issue #8, https://github.com/espeak-ng/espeak-ng/issues/8 There might still be some ints that could be changed to boolean. Possible regressions in fifo.c: int fifo_is_busy() and int fifo_is_command_enabled() used to return an int. Now they return a boolean. This might cause problems on systems where stdbool true/false is something else than 1/0.master
| "-h, --help Show this help.\n"; | "-h, --help Show this help.\n"; | ||||
| int samplerate; | int samplerate; | ||||
| int quiet = 0; | |||||
| bool quiet = false; | |||||
| unsigned int samples_total = 0; | unsigned int samples_total = 0; | ||||
| unsigned int samples_split = 0; | unsigned int samples_split = 0; | ||||
| unsigned int samples_split_seconds = 0; | unsigned int samples_split_seconds = 0; | ||||
| pitch = atoi(optarg2); | pitch = atoi(optarg2); | ||||
| break; | break; | ||||
| case 'q': | case 'q': | ||||
| quiet = 1; | |||||
| quiet = true; | |||||
| break; | break; | ||||
| case 'f': | case 'f': | ||||
| strncpy0(filename, optarg2, sizeof(filename)); | strncpy0(filename, optarg2, sizeof(filename)); | ||||
| case 0x102: // --compile | case 0x102: // --compile | ||||
| strncpy0(voicename, optarg2, sizeof(voicename)); | strncpy0(voicename, optarg2, sizeof(voicename)); | ||||
| flag_compile = c; | flag_compile = c; | ||||
| quiet = 1; | |||||
| quiet = true; | |||||
| break; | break; | ||||
| case 0x103: // --punct | case 0x103: // --punct | ||||
| option_punctuation = 1; | option_punctuation = 1; |
| // my_mutex: protects my_thread_is_talking, | // my_mutex: protects my_thread_is_talking, | ||||
| static pthread_mutex_t my_mutex; | static pthread_mutex_t my_mutex; | ||||
| static pthread_cond_t my_cond_start_is_required; | static pthread_cond_t my_cond_start_is_required; | ||||
| static int my_start_is_required = 0; | |||||
| static bool my_start_is_required = false; | |||||
| static pthread_cond_t my_cond_stop_is_required; | static pthread_cond_t my_cond_stop_is_required; | ||||
| static int my_stop_is_required = 0; | |||||
| static bool my_stop_is_required = false; | |||||
| static pthread_cond_t my_cond_stop_is_acknowledged; | static pthread_cond_t my_cond_stop_is_acknowledged; | ||||
| static int my_stop_is_acknowledged = 0; | |||||
| static bool my_stop_is_acknowledged = false; | |||||
| // my_thread: polls the audio duration and compares it to the duration of the first event. | // my_thread: polls the audio duration and compares it to the duration of the first event. | ||||
| static pthread_t my_thread; | static pthread_t my_thread; | ||||
| static bool thread_inited; | static bool thread_inited; | ||||
| static t_espeak_callback *my_callback = NULL; | static t_espeak_callback *my_callback = NULL; | ||||
| static int my_event_is_running = 0; | |||||
| static bool my_event_is_running = false; | |||||
| enum { | enum { | ||||
| MIN_TIMEOUT_IN_MS = 10, | MIN_TIMEOUT_IN_MS = 10, | ||||
| void event_init(void) | void event_init(void) | ||||
| { | { | ||||
| my_event_is_running = 0; | |||||
| my_event_is_running = false; | |||||
| // security | // security | ||||
| pthread_mutex_init(&my_mutex, (const pthread_mutexattr_t *)NULL); | pthread_mutex_init(&my_mutex, (const pthread_mutexattr_t *)NULL); | ||||
| 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) { | ||||
| my_start_is_required = 1; | |||||
| my_start_is_required = true; | |||||
| return status; | return status; | ||||
| } | } | ||||
| event_delete(a_event); | event_delete(a_event); | ||||
| pthread_mutex_unlock(&my_mutex); | pthread_mutex_unlock(&my_mutex); | ||||
| } else { | } else { | ||||
| my_start_is_required = 1; | |||||
| my_start_is_required = true; | |||||
| pthread_cond_signal(&my_cond_start_is_required); | pthread_cond_signal(&my_cond_start_is_required); | ||||
| status = pthread_mutex_unlock(&my_mutex); | status = pthread_mutex_unlock(&my_mutex); | ||||
| } | } | ||||
| int a_event_is_running = 0; | int a_event_is_running = 0; | ||||
| if (my_event_is_running) { | if (my_event_is_running) { | ||||
| my_stop_is_required = 1; | |||||
| my_stop_is_required = true; | |||||
| pthread_cond_signal(&my_cond_stop_is_required); | pthread_cond_signal(&my_cond_stop_is_required); | ||||
| a_event_is_running = 1; | a_event_is_running = 1; | ||||
| } else | } else | ||||
| init(); // clear pending events | init(); // clear pending events | ||||
| if (a_event_is_running) { | if (a_event_is_running) { | ||||
| while (my_stop_is_acknowledged == 0) { | |||||
| 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) | ||||
| continue; // Restart when interrupted by handler | continue; // Restart when interrupted by handler | ||||
| } | } | ||||
| (void)p; // unused | (void)p; // unused | ||||
| while (1) { | while (1) { | ||||
| int a_stop_is_required = 0; | |||||
| bool a_stop_is_required = false; | |||||
| (void)pthread_mutex_lock(&my_mutex); | (void)pthread_mutex_lock(&my_mutex); | ||||
| my_event_is_running = 0; | |||||
| my_event_is_running = false; | |||||
| while (my_start_is_required == 0) { | |||||
| while (my_start_is_required == false) { | |||||
| while ((pthread_cond_wait(&my_cond_start_is_required, &my_mutex) == -1) && errno == EINTR) | while ((pthread_cond_wait(&my_cond_start_is_required, &my_mutex) == -1) && errno == EINTR) | ||||
| continue; // Restart when interrupted by handler | continue; // Restart when interrupted by handler | ||||
| } | } | ||||
| my_event_is_running = 1; | |||||
| a_stop_is_required = 0; | |||||
| my_start_is_required = 0; | |||||
| my_event_is_running = true; | |||||
| a_stop_is_required = false; | |||||
| my_start_is_required = false; | |||||
| pthread_mutex_unlock(&my_mutex); | pthread_mutex_unlock(&my_mutex); | ||||
| // In this loop, my_event_is_running = 1 | |||||
| while (head && (a_stop_is_required == 0)) { | |||||
| // In this loop, my_event_is_running = true | |||||
| while (head && (a_stop_is_required == false)) { | |||||
| espeak_EVENT *event = (espeak_EVENT *)(head->data); | espeak_EVENT *event = (espeak_EVENT *)(head->data); | ||||
| assert(event); | assert(event); | ||||
| (void)pthread_mutex_lock(&my_mutex); | (void)pthread_mutex_lock(&my_mutex); | ||||
| event_delete((espeak_EVENT *)pop()); | event_delete((espeak_EVENT *)pop()); | ||||
| a_stop_is_required = my_stop_is_required; | a_stop_is_required = my_stop_is_required; | ||||
| if (a_stop_is_required > 0) | |||||
| my_stop_is_required = 0; | |||||
| if (a_stop_is_required == true) | |||||
| my_stop_is_required = false; | |||||
| (void)pthread_mutex_unlock(&my_mutex); | (void)pthread_mutex_unlock(&my_mutex); | ||||
| } | } | ||||
| (void)pthread_mutex_lock(&my_mutex); | (void)pthread_mutex_lock(&my_mutex); | ||||
| my_event_is_running = 0; | |||||
| my_event_is_running = false; | |||||
| if (a_stop_is_required == 0) { | |||||
| if (a_stop_is_required == false) { | |||||
| a_stop_is_required = my_stop_is_required; | a_stop_is_required = my_stop_is_required; | ||||
| if (a_stop_is_required > 0) | |||||
| my_stop_is_required = 0; | |||||
| if (a_stop_is_required == true) | |||||
| my_stop_is_required = false; | |||||
| } | } | ||||
| (void)pthread_mutex_unlock(&my_mutex); | (void)pthread_mutex_unlock(&my_mutex); | ||||
| if (a_stop_is_required > 0) { | |||||
| if (a_stop_is_required == true) { | |||||
| // no mutex required since the stop command is synchronous | // no mutex required since the stop command is synchronous | ||||
| // and waiting for my_cond_stop_is_acknowledged | // and waiting for my_cond_stop_is_acknowledged | ||||
| init(); | init(); | ||||
| // acknowledge the stop request | // acknowledge the stop request | ||||
| (void)pthread_mutex_lock(&my_mutex); | (void)pthread_mutex_lock(&my_mutex); | ||||
| my_stop_is_acknowledged = 1; | |||||
| my_stop_is_acknowledged = true; | |||||
| (void)pthread_cond_signal(&my_cond_stop_is_acknowledged); | (void)pthread_cond_signal(&my_cond_stop_is_acknowledged); | ||||
| (void)pthread_mutex_unlock(&my_mutex); | (void)pthread_mutex_unlock(&my_mutex); | ||||
| } | } |
| #include <assert.h> | #include <assert.h> | ||||
| #include <errno.h> | #include <errno.h> | ||||
| #include <pthread.h> | #include <pthread.h> | ||||
| #include <stdbool.h> | |||||
| #include <stdint.h> | #include <stdint.h> | ||||
| #include <stdlib.h> | #include <stdlib.h> | ||||
| #include <string.h> | #include <string.h> | ||||
| // my_mutex: protects my_thread_is_talking, | // my_mutex: protects my_thread_is_talking, | ||||
| // my_stop_is_required, and the command fifo | // my_stop_is_required, and the command fifo | ||||
| static pthread_mutex_t my_mutex; | static pthread_mutex_t my_mutex; | ||||
| static int my_command_is_running = 0; | |||||
| static bool my_command_is_running = false; | |||||
| static pthread_cond_t my_cond_command_is_running; | static pthread_cond_t my_cond_command_is_running; | ||||
| static int my_stop_is_required = 0; | |||||
| static bool my_stop_is_required = false; | |||||
| // my_thread: reads commands from the fifo, and runs them. | // my_thread: reads commands from the fifo, and runs them. | ||||
| static pthread_t my_thread; | static pthread_t my_thread; | ||||
| static pthread_cond_t my_cond_start_is_required; | static pthread_cond_t my_cond_start_is_required; | ||||
| static int my_start_is_required = 0; | |||||
| static bool my_start_is_required = false; | |||||
| static pthread_cond_t my_cond_stop_is_acknowledged; | static pthread_cond_t my_cond_stop_is_acknowledged; | ||||
| static int my_stop_is_acknowledged = 0; | |||||
| static bool my_stop_is_acknowledged = false; | |||||
| static void *say_thread(void *); | static void *say_thread(void *); | ||||
| // leave once the thread is actually started | // leave once the thread is actually started | ||||
| assert(-1 != pthread_mutex_lock(&my_mutex)); | assert(-1 != pthread_mutex_lock(&my_mutex)); | ||||
| while (my_stop_is_acknowledged == 0) { | |||||
| 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) | ||||
| ; | ; | ||||
| } | } | ||||
| my_stop_is_acknowledged = 0; | |||||
| my_stop_is_acknowledged = false; | |||||
| pthread_mutex_unlock(&my_mutex); | pthread_mutex_unlock(&my_mutex); | ||||
| } | } | ||||
| return status; | return status; | ||||
| } | } | ||||
| my_start_is_required = 1; | |||||
| my_start_is_required = true; | |||||
| pthread_cond_signal(&my_cond_start_is_required); | pthread_cond_signal(&my_cond_start_is_required); | ||||
| while (my_start_is_required && !my_command_is_running) { | while (my_start_is_required && !my_command_is_running) { | ||||
| return status; | return status; | ||||
| } | } | ||||
| my_start_is_required = 1; | |||||
| my_start_is_required = true; | |||||
| pthread_cond_signal(&my_cond_start_is_required); | pthread_cond_signal(&my_cond_start_is_required); | ||||
| while (my_start_is_required && !my_command_is_running) { | while (my_start_is_required && !my_command_is_running) { | ||||
| if ((status = pthread_mutex_lock(&my_mutex)) != ENS_OK) | if ((status = pthread_mutex_lock(&my_mutex)) != ENS_OK) | ||||
| return status; | return status; | ||||
| int a_command_is_running = 0; | |||||
| bool a_command_is_running = false; | |||||
| if (my_command_is_running) { | if (my_command_is_running) { | ||||
| a_command_is_running = 1; | |||||
| my_stop_is_required = 1; | |||||
| my_stop_is_acknowledged = 0; | |||||
| a_command_is_running = true; | |||||
| my_stop_is_required = true; | |||||
| my_stop_is_acknowledged = false; | |||||
| } | } | ||||
| if (a_command_is_running) { | if (a_command_is_running) { | ||||
| while (my_stop_is_acknowledged == 0) { | |||||
| 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) | ||||
| continue; // Restart when interrupted by handler | continue; // Restart when interrupted by handler | ||||
| } | } | ||||
| } | } | ||||
| my_stop_is_required = 0; | |||||
| my_stop_is_required = false; | |||||
| if ((status = pthread_mutex_unlock(&my_mutex)) != ENS_OK) | if ((status = pthread_mutex_unlock(&my_mutex)) != ENS_OK) | ||||
| return status; | return status; | ||||
| static int sleep_until_start_request_or_inactivity() | static int sleep_until_start_request_or_inactivity() | ||||
| { | { | ||||
| int a_start_is_required = 0; | |||||
| int a_start_is_required = false; | |||||
| // Wait for the start request (my_cond_start_is_required). | // Wait for the start request (my_cond_start_is_required). | ||||
| // Besides this, if the audio stream is still busy, | // Besides this, if the audio stream is still busy, | ||||
| assert(gettimeofday(&tv, NULL) != -1); | assert(gettimeofday(&tv, NULL) != -1); | ||||
| if (err == 0) | if (err == 0) | ||||
| a_start_is_required = 1; | |||||
| a_start_is_required = true; | |||||
| } | } | ||||
| pthread_mutex_unlock(&my_mutex); | pthread_mutex_unlock(&my_mutex); | ||||
| return a_start_is_required; | return a_start_is_required; | ||||
| if (status != ENS_OK) | if (status != ENS_OK) | ||||
| return status; | return status; | ||||
| int a_stop_is_required = my_stop_is_required; | |||||
| bool a_stop_is_required = my_stop_is_required; | |||||
| if (!a_stop_is_required) | if (!a_stop_is_required) | ||||
| my_command_is_running = 1; | |||||
| my_command_is_running = true; | |||||
| status = pthread_mutex_unlock(&my_mutex); | status = pthread_mutex_unlock(&my_mutex); | ||||
| if (status == ENS_OK) | if (status == ENS_OK) | ||||
| status = a_status; | status = a_status; | ||||
| my_command_is_running = 0; | |||||
| my_command_is_running = false; | |||||
| a_stop_is_required = my_stop_is_required; | a_stop_is_required = my_stop_is_required; | ||||
| a_status = pthread_mutex_unlock(&my_mutex); | a_status = pthread_mutex_unlock(&my_mutex); | ||||
| if((a_status = pthread_mutex_lock(&my_mutex)) != ENS_OK) | if((a_status = pthread_mutex_lock(&my_mutex)) != ENS_OK) | ||||
| return a_status; | return a_status; | ||||
| my_stop_is_acknowledged = 1; | |||||
| my_stop_is_acknowledged = true; | |||||
| a_status = pthread_cond_signal(&my_cond_stop_is_acknowledged); | a_status = pthread_cond_signal(&my_cond_stop_is_acknowledged); | ||||
| if(a_status != ENS_OK) | if(a_status != ENS_OK) | ||||
| return a_status; | return a_status; | ||||
| // announce that thread is started | // announce that thread is started | ||||
| assert(-1 != pthread_mutex_lock(&my_mutex)); | assert(-1 != pthread_mutex_lock(&my_mutex)); | ||||
| my_stop_is_acknowledged = 1; | |||||
| my_stop_is_acknowledged = true; | |||||
| assert(-1 != pthread_cond_signal(&my_cond_stop_is_acknowledged)); | assert(-1 != pthread_cond_signal(&my_cond_stop_is_acknowledged)); | ||||
| assert(-1 != pthread_mutex_unlock(&my_mutex)); | assert(-1 != pthread_mutex_unlock(&my_mutex)); | ||||
| int look_for_inactivity = 0; | |||||
| bool look_for_inactivity = false; | |||||
| while (1) { | while (1) { | ||||
| int a_start_is_required = 0; | |||||
| bool a_start_is_required = false; | |||||
| if (look_for_inactivity) { | if (look_for_inactivity) { | ||||
| a_start_is_required = sleep_until_start_request_or_inactivity(); | a_start_is_required = sleep_until_start_request_or_inactivity(); | ||||
| if (!a_start_is_required) | if (!a_start_is_required) | ||||
| close_stream(); | close_stream(); | ||||
| } | } | ||||
| look_for_inactivity = 1; | |||||
| look_for_inactivity = true; | |||||
| int a_status = pthread_mutex_lock(&my_mutex); | int a_status = pthread_mutex_lock(&my_mutex); | ||||
| assert(!a_status); | assert(!a_status); | ||||
| if (!a_start_is_required) { | if (!a_start_is_required) { | ||||
| while (my_start_is_required == 0) { | |||||
| while (my_start_is_required == false) { | |||||
| while ((pthread_cond_wait(&my_cond_start_is_required, &my_mutex) == -1) && errno == EINTR) | while ((pthread_cond_wait(&my_cond_start_is_required, &my_mutex) == -1) && errno == EINTR) | ||||
| continue; // Restart when interrupted by handler | continue; // Restart when interrupted by handler | ||||
| } | } | ||||
| } | } | ||||
| my_command_is_running = 1; | |||||
| my_command_is_running = true; | |||||
| assert(-1 != pthread_cond_broadcast(&my_cond_command_is_running)); | assert(-1 != pthread_cond_broadcast(&my_cond_command_is_running)); | ||||
| assert(-1 != pthread_mutex_unlock(&my_mutex)); | assert(-1 != pthread_mutex_unlock(&my_mutex)); | ||||
| t_espeak_command *a_command = (t_espeak_command *)pop(); | t_espeak_command *a_command = (t_espeak_command *)pop(); | ||||
| if (a_command == NULL) { | if (a_command == NULL) { | ||||
| my_command_is_running = 0; | |||||
| my_command_is_running = false; | |||||
| a_status = pthread_mutex_unlock(&my_mutex); | a_status = pthread_mutex_unlock(&my_mutex); | ||||
| } else { | } else { | ||||
| my_start_is_required = 0; | |||||
| my_start_is_required = false; | |||||
| if (my_stop_is_required) | if (my_stop_is_required) | ||||
| my_command_is_running = 0; | |||||
| my_command_is_running = false; | |||||
| a_status = pthread_mutex_unlock(&my_mutex); | a_status = pthread_mutex_unlock(&my_mutex); | ||||
| if (my_command_is_running) | if (my_command_is_running) | ||||
| init(1); | init(1); | ||||
| assert(-1 != pthread_mutex_lock(&my_mutex)); | assert(-1 != pthread_mutex_lock(&my_mutex)); | ||||
| my_start_is_required = 0; | |||||
| my_start_is_required = false; | |||||
| // acknowledge the stop request | // acknowledge the stop request | ||||
| my_stop_is_acknowledged = 1; | |||||
| my_stop_is_acknowledged = true; | |||||
| int a_status = pthread_cond_signal(&my_cond_stop_is_acknowledged); | int 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); |
| #include "config.h" | #include "config.h" | ||||
| #include <stdbool.h> | |||||
| #include <stdint.h> | #include <stdint.h> | ||||
| #include <stdio.h> | #include <stdio.h> | ||||
| #include <stdlib.h> | #include <stdlib.h> | ||||
| int alternative; | int alternative; | ||||
| int delete_count; | int delete_count; | ||||
| int word_start; | int word_start; | ||||
| int inserted; | |||||
| int deleted; | |||||
| bool inserted; | |||||
| bool deleted; | |||||
| PHONEME_DATA phdata; | PHONEME_DATA phdata; | ||||
| int n_ph_list3; | int n_ph_list3; | ||||
| for (j = 0; insert_ph || ((j < n_ph_list3) && (ix < N_PHONEME_LIST-3)); j++) { | for (j = 0; insert_ph || ((j < n_ph_list3) && (ix < N_PHONEME_LIST-3)); j++) { | ||||
| plist3 = &ph_list3[j]; | plist3 = &ph_list3[j]; | ||||
| inserted = 0; | |||||
| deleted = 0; | |||||
| inserted = false; | |||||
| deleted = false; | |||||
| if (insert_ph != 0) { | if (insert_ph != 0) { | ||||
| // we have a (linking) phoneme which we need to insert here | // we have a (linking) phoneme which we need to insert here | ||||
| next = phoneme_tab[plist3->phcode]; // this phoneme, i.e. after the insert | next = phoneme_tab[plist3->phcode]; // this phoneme, i.e. after the insert | ||||
| ph = phoneme_tab[insert_ph]; | ph = phoneme_tab[insert_ph]; | ||||
| plist3->ph = ph; | plist3->ph = ph; | ||||
| insert_ph = 0; | insert_ph = 0; | ||||
| inserted = 1; // don't insert the same phoneme repeatedly | |||||
| inserted = true; // don't insert the same phoneme repeatedly | |||||
| } else { | } else { | ||||
| // otherwise get the next phoneme from the list | // otherwise get the next phoneme from the list | ||||
| if (plist3->sourceix != 0) | if (plist3->sourceix != 0) | ||||
| next = phoneme_tab[alternative]; | next = phoneme_tab[alternative]; | ||||
| } | } | ||||
| if (((alternative = phdata.pd_param[pd_INSERTPHONEME]) > 0) && (inserted == 0)) { | |||||
| if (((alternative = phdata.pd_param[pd_INSERTPHONEME]) > 0) && (inserted == false)) { | |||||
| // PROBLEM: if we insert a phoneme before a vowel then we loose the stress. | // PROBLEM: if we insert a phoneme before a vowel then we loose the stress. | ||||
| PHONEME_TAB *ph2; | PHONEME_TAB *ph2; | ||||
| ph2 = ph; | ph2 = ph; | ||||
| plist3->phcode = alternative; | plist3->phcode = alternative; | ||||
| if (alternative == 1) | if (alternative == 1) | ||||
| deleted = 1; // NULL phoneme, discard | |||||
| deleted = true; // NULL phoneme, discard | |||||
| else { | else { | ||||
| if (ph->type == phVOWEL) { | if (ph->type == phVOWEL) { | ||||
| plist3->synthflags |= SFLAG_SYLLABLE; | plist3->synthflags |= SFLAG_SYLLABLE; | ||||
| } | } | ||||
| } | } | ||||
| if ((ph->type == phVOWEL) && (deleted == 0)) { | |||||
| if ((ph->type == phVOWEL) && (deleted == false)) { | |||||
| PHONEME_LIST *p; | PHONEME_LIST *p; | ||||
| // Check for consecutive unstressed syllables, even across word boundaries. | // Check for consecutive unstressed syllables, even across word boundaries. | ||||
| if ((insert_ph == 0) && (phdata.pd_param[pd_APPENDPHONEME] != 0)) | if ((insert_ph == 0) && (phdata.pd_param[pd_APPENDPHONEME] != 0)) | ||||
| insert_ph = phdata.pd_param[pd_APPENDPHONEME]; | insert_ph = phdata.pd_param[pd_APPENDPHONEME]; | ||||
| if (deleted == 0) { | |||||
| if (deleted == false) { | |||||
| phlist[ix].ph = ph; | phlist[ix].ph = ph; | ||||
| phlist[ix].type = ph->type; | 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 |
| #include <ctype.h> | #include <ctype.h> | ||||
| #include <errno.h> | #include <errno.h> | ||||
| #include <math.h> | #include <math.h> | ||||
| #include <stdbool.h> | |||||
| #include <stdint.h> | #include <stdint.h> | ||||
| #include <stdio.h> | #include <stdio.h> | ||||
| #include <stdlib.h> | #include <stdlib.h> | ||||
| return output; | return output; | ||||
| } | } | ||||
| int MbrolaTranslate(PHONEME_LIST *plist, int n_phonemes, int resume, FILE *f_mbrola) | |||||
| int MbrolaTranslate(PHONEME_LIST *plist, int n_phonemes, bool resume, FILE *f_mbrola) | |||||
| { | { | ||||
| // Generate a mbrola pho file | // Generate a mbrola pho file | ||||
| unsigned int name; | unsigned int name; | ||||
| PHONEME_DATA phdata; | PHONEME_DATA phdata; | ||||
| FMT_PARAMS fmtp; | FMT_PARAMS fmtp; | ||||
| int pause = 0; | int pause = 0; | ||||
| int released; | |||||
| bool released; | |||||
| int name2; | int name2; | ||||
| int control; | int control; | ||||
| int done; | int done; | ||||
| done = 1; | done = 1; | ||||
| break; | break; | ||||
| case phSTOP: | case phSTOP: | ||||
| released = 0; | |||||
| if (next->type == phVOWEL) released = 1; | |||||
| if (next->type == phLIQUID && !next->newword) released = 1; | |||||
| released = false; | |||||
| if (next->type == phVOWEL) released = true; | |||||
| if (next->type == phLIQUID && !next->newword) released = true; | |||||
| if (released == 0) | |||||
| if (released == false) | |||||
| p->synthflags |= SFLAG_NEXT_PAUSE; | p->synthflags |= SFLAG_NEXT_PAUSE; | ||||
| InterpretPhoneme(NULL, 0, p, &phdata, NULL); | InterpretPhoneme(NULL, 0, p, &phdata, NULL); | ||||
| len = DoSample3(&phdata, 0, -1); | len = DoSample3(&phdata, 0, -1); | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| int MbrolaGenerate(PHONEME_LIST *phoneme_list, int *n_ph, int resume) | |||||
| int MbrolaGenerate(PHONEME_LIST *phoneme_list, int *n_ph, bool resume) | |||||
| { | { | ||||
| FILE *f_mbrola = NULL; | FILE *f_mbrola = NULL; | ||||
| f_mbrola = f_trans; | f_mbrola = f_trans; | ||||
| } | } | ||||
| int again = MbrolaTranslate(phoneme_list, *n_ph, resume, f_mbrola); | |||||
| int again = MbrolaTranslate(phoneme_list, *n_ph, resume, f_mbrola); | |||||
| if (!again) | if (!again) | ||||
| *n_ph = 0; | *n_ph = 0; | ||||
| return again; | return again; | ||||
| } | } | ||||
| int MbrolaFill(int length, int resume, int amplitude) | |||||
| int MbrolaFill(int length, bool resume, int amplitude) | |||||
| { | { | ||||
| // Read audio data from Mbrola (length is in millisecs) | // Read audio data from Mbrola (length is in millisecs) | ||||
| return ENS_NOT_SUPPORTED; | return ENS_NOT_SUPPORTED; | ||||
| } | } | ||||
| int MbrolaGenerate(PHONEME_LIST *phoneme_list, int *n_ph, int resume) | |||||
| int MbrolaGenerate(PHONEME_LIST *phoneme_list, int *n_ph, bool resume) | |||||
| { | { | ||||
| (void)phoneme_list; // unused parameter | (void)phoneme_list; // unused parameter | ||||
| (void)n_ph; // unused parameter | (void)n_ph; // unused parameter | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| int MbrolaFill(int length, int resume, int amplitude) | |||||
| int MbrolaFill(int length, bool resume, int amplitude) | |||||
| { | { | ||||
| (void)length; // unused parameter | (void)length; // unused parameter | ||||
| (void)resume; // unused parameter | (void)resume; // unused parameter |
| return (unsigned char *)&phondata_ptr[index]; | return (unsigned char *)&phondata_ptr[index]; | ||||
| } | } | ||||
| static void SetUpPhonemeTable(int number, int recursing) | |||||
| static void SetUpPhonemeTable(int number, bool recursing) | |||||
| { | { | ||||
| int ix; | int ix; | ||||
| int includes; | int includes; | ||||
| int ph_code; | int ph_code; | ||||
| PHONEME_TAB *phtab; | PHONEME_TAB *phtab; | ||||
| if (recursing == 0) | |||||
| if (recursing == false) | |||||
| memset(phoneme_tab_flags, 0, sizeof(phoneme_tab_flags)); | memset(phoneme_tab_flags, 0, sizeof(phoneme_tab_flags)); | ||||
| if ((includes = phoneme_tab_list[number].includes) > 0) { | if ((includes = phoneme_tab_list[number].includes) > 0) { | ||||
| // recursively include base phoneme tables | // recursively include base phoneme tables | ||||
| SetUpPhonemeTable(includes-1, 1); | |||||
| SetUpPhonemeTable(includes-1, true); | |||||
| } | } | ||||
| // now add the phonemes from this table | // now add the phonemes from this table | ||||
| void SelectPhonemeTable(int number) | void SelectPhonemeTable(int number) | ||||
| { | { | ||||
| n_phoneme_tab = 0; | n_phoneme_tab = 0; | ||||
| SetUpPhonemeTable(number, 0); // recursively for included phoneme tables | |||||
| SetUpPhonemeTable(number, false); // recursively for included phoneme tables | |||||
| n_phoneme_tab++; | n_phoneme_tab++; | ||||
| current_phoneme_table = number; | current_phoneme_table = number; | ||||
| } | } |
| #include <ctype.h> | #include <ctype.h> | ||||
| #include <errno.h> | #include <errno.h> | ||||
| #include <math.h> | #include <math.h> | ||||
| #include <stdbool.h> | |||||
| #include <stdint.h> | #include <stdint.h> | ||||
| #include <stdio.h> | #include <stdio.h> | ||||
| #include <stdlib.h> | #include <stdlib.h> | ||||
| } while ((word & 0x80) == 0); | } while ((word & 0x80) == 0); | ||||
| } | } | ||||
| int Generate(PHONEME_LIST *phoneme_list, int *n_ph, int resume) | |||||
| int Generate(PHONEME_LIST *phoneme_list, int *n_ph, bool resume) | |||||
| { | { | ||||
| static int ix; | static int ix; | ||||
| static int embedded_ix; | static int embedded_ix; | ||||
| PHONEME_LIST *next; | PHONEME_LIST *next; | ||||
| PHONEME_LIST *next2; | PHONEME_LIST *next2; | ||||
| PHONEME_LIST *p; | PHONEME_LIST *p; | ||||
| int released; | |||||
| bool released; | |||||
| int stress; | int stress; | ||||
| int modulation; | int modulation; | ||||
| int pre_voiced; | |||||
| bool pre_voiced; | |||||
| int free_min; | int free_min; | ||||
| int value; | int value; | ||||
| unsigned char *pitch_env = NULL; | unsigned char *pitch_env = NULL; | ||||
| if (mbrola_name[0] != 0) | if (mbrola_name[0] != 0) | ||||
| return MbrolaGenerate(phoneme_list, n_ph, resume); | return MbrolaGenerate(phoneme_list, n_ph, resume); | ||||
| if (resume == 0) { | |||||
| if (resume == false) { | |||||
| ix = 1; | ix = 1; | ||||
| embedded_ix = 0; | embedded_ix = 0; | ||||
| word_count = 0; | word_count = 0; | ||||
| p->std_length = p->ph->std_length; | p->std_length = p->ph->std_length; | ||||
| break; | break; | ||||
| case phSTOP: | case phSTOP: | ||||
| released = 0; | |||||
| released = false; | |||||
| ph = p->ph; | ph = p->ph; | ||||
| if (next->type == phVOWEL) | if (next->type == phVOWEL) | ||||
| released = 1; | |||||
| released = true; | |||||
| else if (!next->newword) { | else if (!next->newword) { | ||||
| if (next->type == phLIQUID) released = 1; | |||||
| if (next->type == phLIQUID) released = true; | |||||
| } | } | ||||
| if (released == 0) | |||||
| if (released == false) | |||||
| p->synthflags |= SFLAG_NEXT_PAUSE; | p->synthflags |= SFLAG_NEXT_PAUSE; | ||||
| if (ph->phflags & phPREVOICE) { | if (ph->phflags & phPREVOICE) { | ||||
| memset(&fmtp, 0, sizeof(fmtp)); | memset(&fmtp, 0, sizeof(fmtp)); | ||||
| fmtp.fmt_control = pd_DONTLENGTHEN; | fmtp.fmt_control = pd_DONTLENGTHEN; | ||||
| pre_voiced = 0; | |||||
| pre_voiced = false; | |||||
| if (next->type == phVOWEL) { | if (next->type == phVOWEL) { | ||||
| DoAmplitude(p->amp, NULL); | DoAmplitude(p->amp, NULL); | ||||
| DoPitch(envelope_data[p->env], p->pitch1, p->pitch2); | DoPitch(envelope_data[p->env], p->pitch1, p->pitch2); | ||||
| pre_voiced = 1; | |||||
| pre_voiced = true; | |||||
| } else if ((next->type == phLIQUID) && !next->newword) { | } else if ((next->type == phLIQUID) && !next->newword) { | ||||
| DoAmplitude(next->amp, NULL); | DoAmplitude(next->amp, NULL); | ||||
| DoPitch(envelope_data[next->env], next->pitch1, next->pitch2); | DoPitch(envelope_data[next->env], next->pitch1, next->pitch2); | ||||
| pre_voiced = 1; | |||||
| pre_voiced = true; | |||||
| } else { | } else { | ||||
| if (last_pitch_cmd < 0) { | if (last_pitch_cmd < 0) { | ||||
| DoAmplitude(next->amp, NULL); | DoAmplitude(next->amp, NULL); |
| * along with this program; if not, see: <http://www.gnu.org/licenses/>. | * along with this program; if not, see: <http://www.gnu.org/licenses/>. | ||||
| */ | */ | ||||
| #include <stdbool.h> | |||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||
| extern "C" | extern "C" | ||||
| { | { | ||||
| espeak_ng_STATUS LoadPhData(int *srate, espeak_ng_ERROR_CONTEXT *context); | espeak_ng_STATUS LoadPhData(int *srate, espeak_ng_ERROR_CONTEXT *context); | ||||
| void SynthesizeInit(void); | void SynthesizeInit(void); | ||||
| int Generate(PHONEME_LIST *phoneme_list, int *n_ph, int resume); | |||||
| int Generate(PHONEME_LIST *phoneme_list, int *n_ph, bool resume); | |||||
| void MakeWave2(PHONEME_LIST *p, int n_ph); | void MakeWave2(PHONEME_LIST *p, int n_ph); | ||||
| int SpeakNextClause(int control); | int SpeakNextClause(int control); | ||||
| void SetSpeed(int control); | void SetSpeed(int control); | ||||
| espeak_ng_STATUS LoadMbrolaTable(const char *mbrola_voice, const char *phtrans, int *srate); | espeak_ng_STATUS LoadMbrolaTable(const char *mbrola_voice, const char *phtrans, int *srate); | ||||
| espeak_ng_STATUS SetParameter(int parameter, int value, int relative); | espeak_ng_STATUS SetParameter(int parameter, int value, int relative); | ||||
| int MbrolaTranslate(PHONEME_LIST *plist, int n_phonemes, int resume, FILE *f_mbrola); | |||||
| int MbrolaGenerate(PHONEME_LIST *phoneme_list, int *n_ph, int resume); | |||||
| int MbrolaFill(int length, int resume, int amplitude); | |||||
| int MbrolaTranslate(PHONEME_LIST *plist, int n_phonemes, bool resume, FILE *f_mbrola); | |||||
| int MbrolaGenerate(PHONEME_LIST *phoneme_list, int *n_ph, bool resume); | |||||
| int MbrolaFill(int length, bool resume, int amplitude); | |||||
| void MbrolaReset(void); | void MbrolaReset(void); | ||||
| void DoEmbedded(int *embix, int sourceix); | void DoEmbedded(int *embix, int sourceix); | ||||
| void DoMarker(int type, int char_posn, int length, int value); | void DoMarker(int type, int char_posn, int length, int value); |
| #include "config.h" | #include "config.h" | ||||
| #include <ctype.h> | #include <ctype.h> | ||||
| #include <stdbool.h> | |||||
| #include <stdint.h> | #include <stdint.h> | ||||
| #include <stdio.h> | #include <stdio.h> | ||||
| #include <stdlib.h> | #include <stdlib.h> | ||||
| char word_copy2[N_WORD_BYTES]; | char word_copy2[N_WORD_BYTES]; | ||||
| int word_copy_length; | int word_copy_length; | ||||
| char prefix_chars[0x3f + 2]; | char prefix_chars[0x3f + 2]; | ||||
| int found = 0; | |||||
| bool found = false; | |||||
| int end_flags; | int end_flags; | ||||
| int c_temp; // save a character byte while we temporarily replace it with space | int c_temp; // save a character byte while we temporarily replace it with space | ||||
| int first_char; | int first_char; | ||||
| strcpy(word_out, word1); | strcpy(word_out, word1); | ||||
| return dictionary_flags[0]; | return dictionary_flags[0]; | ||||
| } else if ((found == 0) && (dictionary_flags[0] & FLAG_SKIPWORDS) && !(dictionary_flags[0] & FLAG_ABBREV)) { | |||||
| } else if ((found == false) && (dictionary_flags[0] & FLAG_SKIPWORDS) && !(dictionary_flags[0] & FLAG_ABBREV)) { | |||||
| // grouped words, but no translation. Join the words with hyphens. | // grouped words, but no translation. Join the words with hyphens. | ||||
| wordx = word1; | wordx = word1; | ||||
| ix = 0; | ix = 0; | ||||
| if (wflags & FLAG_TRANSLATOR2) | if (wflags & FLAG_TRANSLATOR2) | ||||
| return 0; | return 0; | ||||
| return dictionary_flags[0] & FLAG_SKIPWORDS; // for "b.c.d" | return dictionary_flags[0] & FLAG_SKIPWORDS; // for "b.c.d" | ||||
| } else if (found == 0) { | |||||
| } else if (found == false) { | |||||
| // word's pronunciation is not given in the dictionary list, although | // word's pronunciation is not given in the dictionary list, although | ||||
| // dictionary_flags may have ben set there | // dictionary_flags may have ben set there | ||||
| c_temp = wordx[-1]; | c_temp = wordx[-1]; | ||||
| found = 0; | |||||
| found = false; | |||||
| confirm_prefix = 1; | confirm_prefix = 1; | ||||
| for (loopcount = 0; (loopcount < 50) && (end_type & SUFX_P); loopcount++) { | for (loopcount = 0; (loopcount < 50) && (end_type & SUFX_P); loopcount++) { | ||||
| // Found a standard prefix, remove it and retranslate | // Found a standard prefix, remove it and retranslate | ||||
| dictionary_flags[1] = dictionary_flags2[1]; | dictionary_flags[1] = dictionary_flags2[1]; | ||||
| } else | } else | ||||
| prefix_flags = 1; | prefix_flags = 1; | ||||
| if (found == 0) { | |||||
| if (found == false) { | |||||
| end_type = TranslateRules(tr, wordx, phonemes, N_WORD_PHONEMES, end_phonemes, wflags & (FLAG_HYPHEN_AFTER | FLAG_PREFIX_REMOVED), dictionary_flags); | end_type = TranslateRules(tr, wordx, phonemes, N_WORD_PHONEMES, end_phonemes, wflags & (FLAG_HYPHEN_AFTER | FLAG_PREFIX_REMOVED), dictionary_flags); | ||||
| if (phonemes[0] == phonSWITCH) { | if (phonemes[0] == phonSWITCH) { | ||||
| if (found) | if (found) | ||||
| prefix_phonemes[0] = 0; // matched whole word, don't need prefix now | prefix_phonemes[0] = 0; // matched whole word, don't need prefix now | ||||
| if ((found == 0) && (dictionary_flags2[0] != 0)) | |||||
| if ((found == false) && (dictionary_flags2[0] != 0)) | |||||
| prefix_flags = 1; | prefix_flags = 1; | ||||
| } | } | ||||
| if (found == 0) { | |||||
| if (found == false) { | |||||
| found = LookupDictList(tr, &wordx, phonemes, dictionary_flags2, end_flags, wtab); // without prefix and suffix | found = LookupDictList(tr, &wordx, phonemes, dictionary_flags2, end_flags, wtab); // without prefix and suffix | ||||
| if (phonemes[0] == phonSWITCH) { | if (phonemes[0] == phonSWITCH) { | ||||
| // change to another language in order to translate this word | // change to another language in order to translate this word | ||||
| dictionary_flags[1] = dictionary_flags2[1]; | dictionary_flags[1] = dictionary_flags2[1]; | ||||
| } | } | ||||
| } | } | ||||
| if (found == 0) { | |||||
| if (found == false) { | |||||
| if (end_type & SUFX_Q) { | if (end_type & SUFX_Q) { | ||||
| // don't retranslate, use the original lookup result | // don't retranslate, use the original lookup result | ||||
| strcpy(phonemes, phonemes2); | strcpy(phonemes, phonemes2); |
| #include "config.h" | #include "config.h" | ||||
| #include <math.h> | #include <math.h> | ||||
| #include <stdbool.h> | |||||
| #include <stdint.h> | #include <stdint.h> | ||||
| #include <stdio.h> | #include <stdio.h> | ||||
| #include <stdlib.h> | #include <stdlib.h> | ||||
| } | } | ||||
| } | } | ||||
| static int PlaySilence(int length, int resume) | |||||
| static int PlaySilence(int length, bool resume) | |||||
| { | { | ||||
| static int n_samples; | static int n_samples; | ||||
| int value = 0; | int value = 0; | ||||
| if (length == 0) | if (length == 0) | ||||
| return 0; | return 0; | ||||
| if (resume == 0) | |||||
| if (resume == false) | |||||
| n_samples = length; | n_samples = length; | ||||
| while (n_samples-- > 0) { | while (n_samples-- > 0) { | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| static int PlayWave(int length, int resume, unsigned char *data, int scale, int amp) | |||||
| static int PlayWave(int length, bool resume, unsigned char *data, int scale, int amp) | |||||
| { | { | ||||
| static int n_samples; | static int n_samples; | ||||
| static int ix = 0; | static int ix = 0; | ||||
| int value; | int value; | ||||
| signed char c; | signed char c; | ||||
| if (resume == 0) { | |||||
| if (resume == false) { | |||||
| n_samples = length; | n_samples = length; | ||||
| ix = 0; | ix = 0; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| static int Wavegen2(int length, int modulation, int resume, frame_t *fr1, frame_t *fr2) | |||||
| static int Wavegen2(int length, int modulation, bool resume, frame_t *fr1, frame_t *fr2) | |||||
| { | { | ||||
| if (resume == 0) | |||||
| if (resume == false) | |||||
| SetSynth(length, modulation, fr1, fr2, wvoice); | SetSynth(length, modulation, fr1, fr2, wvoice); | ||||
| return Wavegen(); | return Wavegen(); | ||||
| int length; | int length; | ||||
| int result; | int result; | ||||
| int marker_type; | int marker_type; | ||||
| static int resume = 0; | |||||
| static bool resume = false; | |||||
| static int echo_complete = 0; | static int echo_complete = 0; | ||||
| while (out_ptr < out_end) { | while (out_ptr < out_end) { | ||||
| if (echo_complete > 0) { | if (echo_complete > 0) { | ||||
| // continue to play silence until echo is completed | // continue to play silence until echo is completed | ||||
| resume = PlaySilence(echo_complete, resume); | resume = PlaySilence(echo_complete, resume); | ||||
| if (resume == 1) | |||||
| if (resume == true) | |||||
| return 0; // not yet finished | return 0; // not yet finished | ||||
| } | } | ||||
| return 1; // queue empty, close sound channel | return 1; // queue empty, close sound channel | ||||
| SetPitch(length, (unsigned char *)q[2], q[3] >> 16, q[3] & 0xffff); | SetPitch(length, (unsigned char *)q[2], q[3] >> 16, q[3] & 0xffff); | ||||
| break; | break; | ||||
| case WCMD_PAUSE: | case WCMD_PAUSE: | ||||
| if (resume == 0) | |||||
| if (resume == false) | |||||
| echo_complete -= length; | echo_complete -= length; | ||||
| wdata.n_mix_wavefile = 0; | wdata.n_mix_wavefile = 0; | ||||
| wdata.amplitude_fmt = 100; | wdata.amplitude_fmt = 100; | ||||
| if (result == 0) { | if (result == 0) { | ||||
| WcmdqIncHead(); | WcmdqIncHead(); | ||||
| resume = 0; | |||||
| resume = false; | |||||
| } else | } else | ||||
| resume = 1; | |||||
| resume = true; | |||||
| } | } | ||||
| return 0; | return 0; |