diff --git a/src/event.cpp b/src/event.cpp index 53948ec6..d2cc3695 100644 --- a/src/event.cpp +++ b/src/event.cpp @@ -108,34 +108,34 @@ void event_init(t_espeak_callback* SynthCallback) // event=%s\n","NULL"); - } - else - { - static const char* label[] = { - "LIST_TERMINATED", - "WORD", - "SENTENCE", - "MARK", - "PLAY", - "END", - "MSG_TERMINATED" - }; + if (event==NULL) + { + SHOW("event_display > event=%s\n","NULL"); + } + else + { + static const char* label[] = { + "LIST_TERMINATED", + "WORD", + "SENTENCE", + "MARK", + "PLAY", + "END", + "MSG_TERMINATED" + }; - SHOW("event_display > event=0x%x\n",event); - SHOW("event_display > type=%s\n",label[event->type]); - SHOW("event_display > uid=%d\n",event->unique_identifier); - SHOW("event_display > text_position=%d\n",event->text_position); - SHOW("event_display > length=%d\n",event->length); - SHOW("event_display > audio_position=%d\n",event->audio_position); - SHOW("event_display > sample=%d\n",event->sample); - SHOW("event_display > user_data=0x%x\n",event->user_data); - } + SHOW("event_display > event=0x%x\n",event); + SHOW("event_display > type=%s\n",label[event->type]); + SHOW("event_display > uid=%d\n",event->unique_identifier); + SHOW("event_display > text_position=%d\n",event->text_position); + SHOW("event_display > length=%d\n",event->length); + SHOW("event_display > audio_position=%d\n",event->audio_position); + SHOW("event_display > sample=%d\n",event->sample); + SHOW("event_display > user_data=0x%x\n",event->user_data); + } #endif } //> @@ -143,36 +143,36 @@ void event_display(espeak_EVENT* event) static espeak_EVENT* event_copy (espeak_EVENT* event) { - ENTER("event_copy"); - - if (event==NULL) - { - return NULL; - } - - espeak_EVENT* a_event=(espeak_EVENT*)malloc(sizeof(espeak_EVENT)); - if (a_event) - { - memcpy(a_event, event, sizeof(espeak_EVENT)); - - switch(event->type) + ENTER("event_copy"); + + if (event==NULL) { - case espeakEVENT_MARK: - case espeakEVENT_PLAY: - if (event->id.name) - { - a_event->id.name = strdup(event->id.name); - } - break; - - default: - break; + return NULL; } - } - - event_display(a_event); - - return a_event; + + espeak_EVENT* a_event=(espeak_EVENT*)malloc(sizeof(espeak_EVENT)); + if (a_event) + { + memcpy(a_event, event, sizeof(espeak_EVENT)); + + switch(event->type) + { + case espeakEVENT_MARK: + case espeakEVENT_PLAY: + if (event->id.name) + { + a_event->id.name = strdup(event->id.name); + } + break; + + default: + break; + } + } + + event_display(a_event); + + return a_event; } //> @@ -189,81 +189,80 @@ static espeak_EVENT* event_copy (espeak_EVENT* event) static void event_notify(espeak_EVENT* event) { - ENTER("event_notify"); +ENTER("event_notify"); - static unsigned int a_old_uid = 0; + static unsigned int a_old_uid = 0; - if (event && my_callback) - { - event_display(event); - - switch(event->type) + if (event && my_callback) { - case espeakEVENT_SENTENCE: - my_callback(NULL, 0, event); - a_old_uid = event->unique_identifier; - break; + event_display(event); - case espeakEVENT_WORD: - case espeakEVENT_MSG_TERMINATED: - { - if (a_old_uid != event->unique_identifier) - { - espeak_EVENT_TYPE a_new_type = event->type; - event->type = espeakEVENT_SENTENCE; - my_callback(NULL, 0, event); - event->type = a_new_type; - usleep(50000); - } - my_callback(NULL, 0, event); - a_old_uid = event->unique_identifier; - } - break; - - default: - case espeakEVENT_LIST_TERMINATED: - case espeakEVENT_MARK: - case espeakEVENT_PLAY: - case espeakEVENT_END: - break; + switch(event->type) + { + case espeakEVENT_SENTENCE: + my_callback(NULL, 0, event); + a_old_uid = event->unique_identifier; + break; + + case espeakEVENT_WORD: + case espeakEVENT_MSG_TERMINATED: + { + if (a_old_uid != event->unique_identifier) + { + espeak_EVENT_TYPE a_new_type = event->type; + event->type = espeakEVENT_SENTENCE; + my_callback(NULL, 0, event); + event->type = a_new_type; + usleep(50000); + } + my_callback(NULL, 0, event); + a_old_uid = event->unique_identifier; + } + break; + + default: + case espeakEVENT_LIST_TERMINATED: + case espeakEVENT_MARK: + case espeakEVENT_PLAY: + case espeakEVENT_END: + break; + } } - } } //> //type) - { - case espeakEVENT_MSG_TERMINATED: - event_notify(event); - break; - - case espeakEVENT_MARK: - case espeakEVENT_PLAY: - if(event->id.name) + if(event==NULL) { - free((void*)(event->id.name)); + return 0; } - break; + switch(event->type) + { + case espeakEVENT_MSG_TERMINATED: + event_notify(event); + break; - default: - break; - } + case espeakEVENT_MARK: + case espeakEVENT_PLAY: + if(event->id.name) + { + free((void*)(event->id.name)); + } + break; - free(event); - return 1; + default: + break; + } + + free(event); + return 1; } //> @@ -271,41 +270,41 @@ static int event_delete(espeak_EVENT* event) espeak_ERROR event_declare (espeak_EVENT* event) { - ENTER("event_declare"); +ENTER("event_declare"); - event_display(event); + event_display(event); - if (!event) - { - return EE_INTERNAL_ERROR; - } - - int a_status = pthread_mutex_lock(&my_mutex); - espeak_ERROR a_error = EE_OK; - - if (!a_status) - { - SHOW_TIME("event_declare > locked\n"); - espeak_EVENT* a_event = event_copy(event); - a_error = push(a_event); - if (a_error != EE_OK) + if (!event) { - event_delete(a_event); + return EE_INTERNAL_ERROR; + } + + int a_status = pthread_mutex_lock(&my_mutex); + espeak_ERROR a_error = EE_OK; + + if (!a_status) + { + SHOW_TIME("event_declare > locked\n"); + espeak_EVENT* a_event = event_copy(event); + a_error = push(a_event); + if (a_error != EE_OK) + { + event_delete(a_event); + } + SHOW_TIME("event_declare > unlocking\n"); + a_status = pthread_mutex_unlock(&my_mutex); } - SHOW_TIME("event_declare > unlocking\n"); - a_status = pthread_mutex_unlock(&my_mutex); - } // TBD: remove the comment // reminder: code in comment. // This wait can lead to an underrun // // if (!a_status && !my_event_is_running && (a_error == EE_OK)) -// { +// { // // quit when command is actually started // // (for possible forthcoming 'end of command' checks) - SHOW_TIME("event_declare > post my_sem_start_is_required\n"); - sem_post(&my_sem_start_is_required); + SHOW_TIME("event_declare > post my_sem_start_is_required\n"); + sem_post(&my_sem_start_is_required); // int val=1; // while (val) // { @@ -314,12 +313,12 @@ espeak_ERROR event_declare (espeak_EVENT* event) // } // } - if (a_status != 0) - { - a_error = EE_INTERNAL_ERROR; - } + if (a_status != 0) + { + a_error = EE_INTERNAL_ERROR; + } - return a_error; + return a_error; } //> @@ -327,47 +326,47 @@ espeak_ERROR event_declare (espeak_EVENT* event) espeak_ERROR event_clear_all () { - ENTER("event_clear_all"); + ENTER("event_clear_all"); - int a_status = pthread_mutex_lock(&my_mutex); - int a_event_is_running = 0; + int a_status = pthread_mutex_lock(&my_mutex); + int a_event_is_running = 0; - SHOW_TIME("event_stop > locked\n"); - if (a_status != 0) - { - return EE_INTERNAL_ERROR; - } - - if (my_event_is_running) - { - SHOW_TIME("event_stop > post my_sem_stop_is_required\n"); - sem_post(&my_sem_stop_is_required); - a_event_is_running = 1; - } - else - { - init(); // clear pending events - } - SHOW_TIME("event_stop > unlocking\n"); - a_status = pthread_mutex_unlock(&my_mutex); - if (a_status != 0) - { - return EE_INTERNAL_ERROR; - } - - if (a_event_is_running) - { - SHOW_TIME("event_stop > wait for my_sem_stop_is_acknowledged\n"); - while ((sem_wait(&my_sem_stop_is_acknowledged) == -1) && errno == EINTR) + SHOW_TIME("event_stop > locked\n"); + if (a_status != 0) { - continue; // Restart when interrupted by handler + return EE_INTERNAL_ERROR; } - SHOW_TIME("event_stop > get my_sem_stop_is_acknowledged\n"); - } - SHOW_TIME("LEAVE event_stop\n"); + if (my_event_is_running) + { + SHOW_TIME("event_stop > post my_sem_stop_is_required\n"); + sem_post(&my_sem_stop_is_required); + a_event_is_running = 1; + } + else + { + init(); // clear pending events + } + SHOW_TIME("event_stop > unlocking\n"); + a_status = pthread_mutex_unlock(&my_mutex); + if (a_status != 0) + { + return EE_INTERNAL_ERROR; + } - return EE_OK; + if (a_event_is_running) + { + SHOW_TIME("event_stop > wait for my_sem_stop_is_acknowledged\n"); + while ((sem_wait(&my_sem_stop_is_acknowledged) == -1) && errno == EINTR) + { + continue; // Restart when interrupted by handler + } + SHOW_TIME("event_stop > get my_sem_stop_is_acknowledged\n"); + } + + SHOW_TIME("LEAVE event_stop\n"); + + return EE_OK; } //> @@ -375,39 +374,39 @@ espeak_ERROR event_clear_all () static int sleep_until_timeout_or_stop_request(uint32_t time_in_ms) { - ENTER("sleep_until_timeout_or_stop_request"); +ENTER("sleep_until_timeout_or_stop_request"); - int a_stop_is_required=0; - struct timespec ts, to; - struct timeval tv; - int err=0; + int a_stop_is_required=0; + struct timespec ts, to; + struct timeval tv; + int err=0; - clock_gettime2( &ts); - to.tv_sec = ts.tv_sec; - to.tv_nsec = ts.tv_nsec; - - add_time_in_ms( &ts, time_in_ms); - - SHOW("polling_thread > sleep_until_timeout_or_stop_request > start sem_timedwait from %d.%09lu to %d.%09lu \n", + clock_gettime2( &ts); + to.tv_sec = ts.tv_sec; + to.tv_nsec = ts.tv_nsec; + + add_time_in_ms( &ts, time_in_ms); + + SHOW("polling_thread > sleep_until_timeout_or_stop_request > start sem_timedwait from %d.%09lu to %d.%09lu \n", to.tv_sec, to.tv_nsec, ts.tv_sec, ts.tv_nsec); - while ((err = sem_timedwait(&my_sem_stop_is_required, &ts)) == -1 - && errno == EINTR) - { - continue; // Restart when interrupted by handler - } + while ((err = sem_timedwait(&my_sem_stop_is_required, &ts)) == -1 + && errno == EINTR) + { + continue; // Restart when interrupted by handler + } - assert (gettimeofday(&tv, NULL) != -1); - SHOW("polling_thread > sleep_until_timeout_or_stop_request > stop sem_timedwait %d.%09lu \n", + assert (gettimeofday(&tv, NULL) != -1); + SHOW("polling_thread > sleep_until_timeout_or_stop_request > stop sem_timedwait %d.%09lu \n", tv.tv_sec, tv.tv_usec*1000); - if (err == 0) - { - SHOW("polling_thread > sleep_until_timeout_or_stop_request > %s\n","stop required!"); - a_stop_is_required=1; // stop required - } - return a_stop_is_required; + if (err == 0) + { + SHOW("polling_thread > sleep_until_timeout_or_stop_request > %s\n","stop required!"); + a_stop_is_required=1; // stop required + } + return a_stop_is_required; } //> @@ -418,21 +417,21 @@ static int sleep_until_timeout_or_stop_request(uint32_t time_in_ms) static int get_remaining_time(uint32_t sample, uint32_t* time_in_ms, int* stop_is_required) { - ENTER("get_remaining_time"); +ENTER("get_remaining_time"); - int err = 0; - *stop_is_required = 0; - int i=0; + int err = 0; + *stop_is_required = 0; + int i=0; - for (i=0; i < MAX_ACTIVITY_CHECK && (*stop_is_required == 0); i++) - { - err = wave_get_remaining_time( sample, time_in_ms); + 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 (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 - break; + break; } // stream opened but not active @@ -448,10 +447,10 @@ static int get_remaining_time(uint32_t sample, uint32_t* time_in_ms, int* stop_i // // wait for the close of stream - *stop_is_required = sleep_until_timeout_or_stop_request( ACTIVITY_TIMEOUT); - } + *stop_is_required = sleep_until_timeout_or_stop_request( ACTIVITY_TIMEOUT); + } - return err; + return err; } //> @@ -459,154 +458,155 @@ static int get_remaining_time(uint32_t sample, uint32_t* time_in_ms, int* stop_i static void* polling_thread(void*) { - ENTER("polling_thread"); +ENTER("polling_thread"); - while(1) - { - int a_stop_is_required=0; - - SHOW_TIME("polling_thread > locking\n"); - int a_status = pthread_mutex_lock(&my_mutex); - SHOW_TIME("polling_thread > locked (my_event_is_running = 0)\n"); - my_event_is_running = 0; - pthread_mutex_unlock(&my_mutex); - SHOW_TIME("polling_thread > unlocked\n"); - - SHOW_TIME("polling_thread > wait for my_sem_start_is_required\n"); - - while ((sem_wait(&my_sem_start_is_required) == -1) && errno == EINTR) + while(1) { - continue; // Restart when interrupted by handler - } + int a_stop_is_required=0; - SHOW_TIME("polling_thread > get my_sem_start_is_required\n"); + SHOW_TIME("polling_thread > locking\n"); + int a_status = pthread_mutex_lock(&my_mutex); + SHOW_TIME("polling_thread > locked (my_event_is_running = 0)\n"); + my_event_is_running = 0; + pthread_mutex_unlock(&my_mutex); + SHOW_TIME("polling_thread > unlocked\n"); - a_status = pthread_mutex_lock(&my_mutex); - SHOW_TIME("polling_thread > locked (my_event_is_running = 1)\n"); - my_event_is_running = 1; - pthread_mutex_unlock(&my_mutex); - SHOW_TIME("polling_thread > unlocked\n"); + SHOW_TIME("polling_thread > wait for my_sem_start_is_required\n"); - a_stop_is_required=0; - a_status = sem_getvalue(&my_sem_stop_is_required, &a_stop_is_required); - if ((a_status==0) && a_stop_is_required) - { - SHOW("polling_thread > stop required (%d)\n", __LINE__); - 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) - { - SHOW_TIME("polling_thread > check head\n"); - while(0 == sem_trywait(&my_sem_start_is_required)) - { - }; - - espeak_EVENT* event = (espeak_EVENT*)(head->data); - assert(event); - - uint32_t time_in_ms = 0; - - int err = get_remaining_time((uint32_t)event->sample, - &time_in_ms, - &a_stop_is_required); - if (a_stop_is_required) - { - break; - } - else if (err != 0) - { - // No available time: the event is deleted. - SHOW("polling_thread > %s\n","audio device down"); - a_status = pthread_mutex_lock(&my_mutex); - SHOW_TIME("polling_thread > locked\n"); - event_delete( (espeak_EVENT*)pop()); - a_status = pthread_mutex_unlock(&my_mutex); - SHOW_TIME("polling_thread > unlocked\n"); - } - else if (time_in_ms==0) - { // the event is already reached. - if (my_callback) + while ((sem_wait(&my_sem_start_is_required) == -1) && errno == EINTR) { - event_notify(event); - // the user_data (and the type) are cleaned to be sure - // that MSG_TERMINATED is called twice (at delete time too). - event->type=espeakEVENT_LIST_TERMINATED; - event->user_data=NULL; + continue; // Restart when interrupted by handler } - a_status = pthread_mutex_lock(&my_mutex); - SHOW_TIME("polling_thread > locked\n"); - event_delete( (espeak_EVENT*)pop()); - a_status = pthread_mutex_unlock(&my_mutex); - SHOW_TIME("polling_thread > unlocked\n"); - a_stop_is_required=0; - a_status = sem_getvalue(&my_sem_stop_is_required, &a_stop_is_required); - if ((a_status==0) && a_stop_is_required) + SHOW_TIME("polling_thread > get my_sem_start_is_required\n"); + + a_status = pthread_mutex_lock(&my_mutex); + SHOW_TIME("polling_thread > locked (my_event_is_running = 1)\n"); + my_event_is_running = 1; + pthread_mutex_unlock(&my_mutex); + SHOW_TIME("polling_thread > unlocked\n"); + + a_stop_is_required=0; + a_status = sem_getvalue(&my_sem_stop_is_required, &a_stop_is_required); + if ((a_status==0) && a_stop_is_required) { - SHOW("polling_thread > stop required (%d)\n", __LINE__); - while(0 == sem_trywait(&my_sem_stop_is_required)) - { - }; + SHOW("polling_thread > stop required (%d)\n", __LINE__); + while(0 == sem_trywait(&my_sem_stop_is_required)) + { + }; } - else + else { - a_stop_is_required=0; + a_stop_is_required=0; } - } - else - { // The event will be notified soon: sleep until timeout or stop request - a_stop_is_required = sleep_until_timeout_or_stop_request(time_in_ms); - } - } - a_status = pthread_mutex_lock(&my_mutex); - SHOW_TIME("polling_thread > locked\n"); - - SHOW_TIME("polling_thread > my_event_is_running = 0\n"); - my_event_is_running = 0; - - if(!a_stop_is_required) - { - a_status = sem_getvalue(&my_sem_stop_is_required, &a_stop_is_required); - if ((a_status==0) && a_stop_is_required) - { - SHOW("polling_thread > stop required (%d)\n", __LINE__); - while(0 == sem_trywait(&my_sem_stop_is_required)) + // In this loop, my_event_is_running = 1 + while (head && !a_stop_is_required) { - }; - } - else - { - a_stop_is_required=0; - } + SHOW_TIME("polling_thread > check head\n"); + while(0 == sem_trywait(&my_sem_start_is_required)) + { + }; + + espeak_EVENT* event = (espeak_EVENT*)(head->data); + assert(event); + + uint32_t time_in_ms = 0; + + int err = get_remaining_time((uint32_t)event->sample, + &time_in_ms, + &a_stop_is_required); + if (a_stop_is_required) + { + break; + } + else if (err != 0) + { + // No available time: the event is deleted. + SHOW("polling_thread > %s\n","audio device down"); + a_status = pthread_mutex_lock(&my_mutex); + SHOW_TIME("polling_thread > locked\n"); + event_delete( (espeak_EVENT*)pop()); + a_status = pthread_mutex_unlock(&my_mutex); + SHOW_TIME("polling_thread > unlocked\n"); + } + else if (time_in_ms==0) + { // the event is already reached. + if (my_callback) + { + event_notify(event); + // the user_data (and the type) are cleaned to be sure + // that MSG_TERMINATED is called twice (at delete time too). + event->type=espeakEVENT_LIST_TERMINATED; + event->user_data=NULL; + } + + a_status = pthread_mutex_lock(&my_mutex); + SHOW_TIME("polling_thread > locked\n"); + event_delete( (espeak_EVENT*)pop()); + a_status = pthread_mutex_unlock(&my_mutex); + SHOW_TIME("polling_thread > unlocked\n"); + + a_stop_is_required=0; + a_status = sem_getvalue(&my_sem_stop_is_required, &a_stop_is_required); + + if ((a_status==0) && a_stop_is_required) + { + SHOW("polling_thread > stop required (%d)\n", __LINE__); + 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 + a_stop_is_required = sleep_until_timeout_or_stop_request(time_in_ms); + } + } + + a_status = pthread_mutex_lock(&my_mutex); + SHOW_TIME("polling_thread > locked\n"); + + SHOW_TIME("polling_thread > my_event_is_running = 0\n"); + my_event_is_running = 0; + + if(!a_stop_is_required) + { + a_status = sem_getvalue(&my_sem_stop_is_required, &a_stop_is_required); + if ((a_status==0) && a_stop_is_required) + { + SHOW("polling_thread > stop required (%d)\n", __LINE__); + while(0 == sem_trywait(&my_sem_stop_is_required)) + { + }; + } + else + { + a_stop_is_required=0; + } + } + + a_status = pthread_mutex_unlock(&my_mutex); + SHOW_TIME("polling_thread > unlocked\n"); + + if (a_stop_is_required) + { + SHOW("polling_thread > %s\n","stop required!"); + // no mutex required since the stop command is synchronous + // and waiting for my_sem_stop_is_acknowledged + init(); + + // acknowledge the stop request + SHOW_TIME("polling_thread > post my_sem_stop_is_acknowledged\n"); + a_status = sem_post(&my_sem_stop_is_acknowledged); + } } - a_status = pthread_mutex_unlock(&my_mutex); - SHOW_TIME("polling_thread > unlocked\n"); - - if (a_stop_is_required) - { - SHOW("polling_thread > %s\n","stop required!"); - // no mutex required since the stop command is synchronous - // and waiting for my_sem_stop_is_acknowledged - init(); - - // acknowledge the stop request - SHOW_TIME("polling_thread > post my_sem_stop_is_acknowledged\n"); - a_status = sem_post(&my_sem_stop_is_acknowledged); - } - - } - - return NULL; + return NULL; } //> @@ -615,100 +615,100 @@ enum {MAX_NODE_COUNTER=1000}; // return 1 if ok, 0 otherwise static espeak_ERROR push(void* the_data) { - ENTER("event > push"); + ENTER("event > push"); - assert((!head && !tail) || (head && tail)); + assert((!head && !tail) || (head && tail)); - if (the_data == NULL) - { - SHOW("event > push > event=0x%x\n", NULL); - return EE_INTERNAL_ERROR; - } + if (the_data == NULL) + { + SHOW("event > push > event=0x%x\n", NULL); + return EE_INTERNAL_ERROR; + } - if (node_counter >= MAX_NODE_COUNTER) - { - SHOW("event > push > %s\n", "EE_BUFFER_FULL"); - return EE_BUFFER_FULL; - } - - node *n = (node *)malloc(sizeof(node)); - if (n == NULL) - { - return EE_INTERNAL_ERROR; - } - - if (head == NULL) - { - head = n; - tail = n; - } - else - { - tail->next = n; - tail = n; - } - - tail->next = NULL; - tail->data = the_data; - - node_counter++; - SHOW("event > push > counter=%d (uid=%d)\n",node_counter,((espeak_EVENT*)the_data)->unique_identifier); - - return EE_OK; + if (node_counter >= MAX_NODE_COUNTER) + { + SHOW("event > push > %s\n", "EE_BUFFER_FULL"); + return EE_BUFFER_FULL; + } + + node *n = (node *)malloc(sizeof(node)); + if (n == NULL) + { + return EE_INTERNAL_ERROR; + } + + if (head == NULL) + { + head = n; + tail = n; + } + else + { + tail->next = n; + tail = n; + } + + tail->next = NULL; + tail->data = the_data; + + node_counter++; + SHOW("event > push > counter=%d (uid=%d)\n",node_counter,((espeak_EVENT*)the_data)->unique_identifier); + + return EE_OK; } static void* pop() { - ENTER("event > pop"); - void* the_data = NULL; - - assert((!head && !tail) || (head && tail)); - - if (head != NULL) - { - node* n = head; - the_data = n->data; - head = n->next; - free(n); - node_counter--; - SHOW("event > pop > event=0x%x (counter=%d, uid=%d)\n",the_data, node_counter,((espeak_EVENT*)the_data)->unique_identifier); - } - - if(head == NULL) - { - tail = NULL; - } - - return the_data; + ENTER("event > pop"); + void* the_data = NULL; + + assert((!head && !tail) || (head && tail)); + + if (head != NULL) + { + node* n = head; + the_data = n->data; + head = n->next; + free(n); + node_counter--; + SHOW("event > pop > event=0x%x (counter=%d, uid=%d)\n",the_data, node_counter,((espeak_EVENT*)the_data)->unique_identifier); + } + + if(head == NULL) + { + tail = NULL; + } + + return the_data; } static void init() { - ENTER("event > init"); - - while (event_delete( (espeak_EVENT*)pop() )) - {} - - node_counter = 0; + ENTER("event > init"); + + while (event_delete( (espeak_EVENT*)pop() )) + {} + + node_counter = 0; } //> //type) != 0) { - fprintf(f_events,"%4d %4d (%2d): %d ",events->audio_position,events->text_position,events->length,type); + fprintf(f_events,"%5d %4d (%2d) %d ",events->audio_position,events->text_position,events->length,type); if((type==3) || (type==4)) fprintf(f_events,"'%s'\n",events->id.name); else @@ -904,8 +903,8 @@ int x; char* text1[]= { - "eSpeak.", - " normally would, " + "Hello World. This is the second sentence", + "Testing" }; void TestTest(int control) @@ -947,8 +946,9 @@ if(control==2) OpenWaveFile3("/home/jsd1/speechdata/text/test.wav",samplerate); f_events = fopen("/home/jsd1/speechdata/text/events","w"); + fprintf(f_events,"Audio Text Length Type Id\n"); - espeak_Initialize(AUDIO_OUTPUT_SYNCHRONOUS,100,NULL); + espeak_Initialize(AUDIO_OUTPUT_SYNCH_PLAYBACK,0,NULL); espeak_SetSynthCallback(TestSynthCallback); unsigned int unique_identifier=0; diff --git a/src/speak_lib.cpp b/src/speak_lib.cpp index de56a535..b3dc8db1 100644 --- a/src/speak_lib.cpp +++ b/src/speak_lib.cpp @@ -73,13 +73,13 @@ voice_t *voice = &voicedata; static int dispatch_audio(short* outbuf, int length, espeak_EVENT* event) {//====================================================================== ENTER("dispatch_audio"); - + int a_wave_can_be_played = fifo_is_command_enabled(); - + SHOW("*** dispatch_audio > uid=%d, [write=%p (%d bytes)], sample=%d, a_wave_can_be_played = %d\n", - (event) ? event->unique_identifier : 0, wave_test_get_write_buffer(), 2*length, - (event) ? event->sample : 0, - a_wave_can_be_played); + (event) ? event->unique_identifier : 0, wave_test_get_write_buffer(), 2*length, + (event) ? event->sample : 0, + a_wave_can_be_played); switch(my_mode) @@ -248,31 +248,31 @@ static void select_output(espeak_AUDIO_OUTPUT output_type) int GetFileLength(const char *filename) {//==================================== - struct stat statbuf; - - if(stat(filename,&statbuf) != 0) - return(0); - - if((statbuf.st_mode & S_IFMT) == S_IFDIR) - // if(S_ISDIR(statbuf.st_mode)) - return(-2); // a directory - - return(statbuf.st_size); + struct stat statbuf; + + if(stat(filename,&statbuf) != 0) + return(0); + + if((statbuf.st_mode & S_IFMT) == S_IFDIR) + // if(S_ISDIR(statbuf.st_mode)) + return(-2); // a directory + + return(statbuf.st_size); } // end of GetFileLength char *Alloc(int size) {//================== - char *p; - if((p = (char *)malloc(size)) == NULL) - fprintf(stderr,"Can't allocate memory\n"); - return(p); + char *p; + if((p = (char *)malloc(size)) == NULL) + fprintf(stderr,"Can't allocate memory\n"); + return(p); } void Free(void *ptr) {//================= - if(ptr != NULL) - free(ptr); + if(ptr != NULL) + free(ptr); } @@ -475,34 +475,34 @@ static const char* label[] = { void MarkerEvent(int type, unsigned int char_position, int value, unsigned char *out_ptr) {//====================================================================================== - // type: 1=word, 2=sentence, 3=named mark, 4=play audio, 5=end - ENTER("MarkerEvent"); - espeak_EVENT *ep; - double time; - - if((event_list == NULL) || (event_list_ix >= (n_event_list-2))) - return; - - ep = &event_list[event_list_ix++]; - ep->type = (espeak_EVENT_TYPE)type; - ep->unique_identifier = my_unique_identifier; - ep->user_data = my_user_data; - ep->text_position = char_position & 0xffff; - ep->length = char_position >> 24; - - time = (double(count_samples + (out_ptr - out_start)/2)*1000.0)/samplerate; - ep->audio_position = int(time); - ep->sample = (count_samples + (out_ptr - out_start)/2); - - SHOW("MarkerEvent > count_samples=%d, out_ptr=%x, out_start=0x%x\n",count_samples, out_ptr, out_start); - SHOW("*** MarkerEvent > type=%s, uid=%d, text_pos=%d, length=%d, audio_position=%d, sample=%d\n", - label[ep->type], ep->unique_identifier, ep->text_position, ep->length, - ep->audio_position, ep->sample); - - if((type == espeakEVENT_MARK) || (type == espeakEVENT_PLAY)) - ep->id.name = &namedata[value]; - else - ep->id.number = value; + // type: 1=word, 2=sentence, 3=named mark, 4=play audio, 5=end + ENTER("MarkerEvent"); + espeak_EVENT *ep; + double time; + + if((event_list == NULL) || (event_list_ix >= (n_event_list-2))) + return; + + ep = &event_list[event_list_ix++]; + ep->type = (espeak_EVENT_TYPE)type; + ep->unique_identifier = my_unique_identifier; + ep->user_data = my_user_data; + ep->text_position = char_position & 0xffff; + ep->length = char_position >> 24; + + time = (double(count_samples + (out_ptr - out_start)/2)*1000.0)/samplerate; + ep->audio_position = int(time); + ep->sample = (count_samples + (out_ptr - out_start)/2); + + SHOW("MarkerEvent > count_samples=%d, out_ptr=%x, out_start=0x%x\n",count_samples, out_ptr, out_start); + SHOW("*** MarkerEvent > type=%s, uid=%d, text_pos=%d, length=%d, audio_position=%d, sample=%d\n", + label[ep->type], ep->unique_identifier, ep->text_position, ep->length, + ep->audio_position, ep->sample); + + if((type == espeakEVENT_MARK) || (type == espeakEVENT_PLAY)) + ep->id.name = &namedata[value]; + else + ep->id.number = value; } // end of MarkerEvent @@ -512,43 +512,43 @@ espeak_ERROR sync_espeak_Synth(unsigned int unique_identifier, const void *text, unsigned int position, espeak_POSITION_TYPE position_type, unsigned int end_position, unsigned int flags, void* user_data) {//=========================================================================== - ENTER("sync_espeak_Synth"); - - SHOW("sync_espeak_Synth > position=%d, position_type=%d, end_position=%d, flags=%d, user_data=0x%x, text=%s\n", position, position_type, end_position, flags, user_data, text); - - espeak_ERROR aStatus; - - InitText(flags); - my_unique_identifier = unique_identifier; - my_user_data = user_data; - - switch(position_type) - { - case POS_CHARACTER: - skip_characters = position; - break; - - case POS_WORD: - skip_words = position; - break; - - case POS_SENTENCE: - skip_sentences = position; - break; - - } - if(skip_characters || skip_words || skip_sentences) - skipping_text = 1; - - end_character_position = end_position; - - aStatus = Synthesize(unique_identifier, text, flags); -#ifdef USE_ASYNC - wave_flush(my_audio); -#endif - - SHOW_TIME("LEAVE sync_espeak_Synth"); - return aStatus; + ENTER("sync_espeak_Synth"); + + SHOW("sync_espeak_Synth > position=%d, position_type=%d, end_position=%d, flags=%d, user_data=0x%x, text=%s\n", position, position_type, end_position, flags, user_data, text); + + espeak_ERROR aStatus; + + InitText(flags); + my_unique_identifier = unique_identifier; + my_user_data = user_data; + + switch(position_type) + { + case POS_CHARACTER: + skip_characters = position; + break; + + case POS_WORD: + skip_words = position; + break; + + case POS_SENTENCE: + skip_sentences = position; + break; + + } + if(skip_characters || skip_words || skip_sentences) + skipping_text = 1; + + end_character_position = end_position; + + aStatus = Synthesize(unique_identifier, text, flags); + #ifdef USE_ASYNC + wave_flush(my_audio); + #endif + + SHOW_TIME("LEAVE sync_espeak_Synth"); + return aStatus; } // end of sync_espeak_Synth @@ -559,59 +559,59 @@ espeak_ERROR sync_espeak_Synth_Mark(unsigned int unique_identifier, const void * unsigned int flags, void* user_data) {//========================================================================= espeak_ERROR aStatus; - - InitText(flags); - - my_unique_identifier = unique_identifier; - my_user_data = user_data; - - if(index_mark != NULL) - { - strncpy0(skip_marker, index_mark, sizeof(skip_marker)); - skipping_text = 1; - } - - end_character_position = end_position; - - - aStatus = Synthesize(unique_identifier, text, flags | espeakSSML); - SHOW_TIME("LEAVE sync_espeak_Synth_Mark"); - - return (aStatus); + + InitText(flags); + + my_unique_identifier = unique_identifier; + my_user_data = user_data; + + if(index_mark != NULL) + { + strncpy0(skip_marker, index_mark, sizeof(skip_marker)); + skipping_text = 1; + } + + end_character_position = end_position; + + + aStatus = Synthesize(unique_identifier, text, flags | espeakSSML); + SHOW_TIME("LEAVE sync_espeak_Synth_Mark"); + + return (aStatus); } // end of sync_espeak_Synth_Mark void sync_espeak_Key(const char *key) {//================================== - // symbolic name, symbolicname_character - is there a system resource of symbolic names per language? - my_unique_identifier = 0; - my_user_data = NULL; - Synthesize(0, key,0); // for now, just say the key name as passed + // symbolic name, symbolicname_character - is there a system resource of symbolic names per language? + my_unique_identifier = 0; + my_user_data = NULL; + Synthesize(0, key,0); // for now, just say the key name as passed } void sync_espeak_Char(wchar_t character) {//===================================== - // is there a system resource of character names per language? - char buf[80]; - my_unique_identifier = 0; - my_user_data = NULL; + // is there a system resource of character names per language? + char buf[80]; + my_unique_identifier = 0; + my_user_data = NULL; - sprintf(buf,"&#%d;",character); - Synthesize(0, buf,espeakSSML); + sprintf(buf,"&#%d;",character); + Synthesize(0, buf,espeakSSML); } void sync_espeak_SetPunctuationList(const wchar_t *punctlist) {//========================================================== - // Set the list of punctuation which are spoken for "some". - my_unique_identifier = 0; - my_user_data = NULL; - - wcsncpy(option_punctlist, punctlist, N_PUNCTLIST); - option_punctlist[N_PUNCTLIST-1] = 0; + // Set the list of punctuation which are spoken for "some". + my_unique_identifier = 0; + my_user_data = NULL; + + wcsncpy(option_punctlist, punctlist, N_PUNCTLIST); + option_punctlist[N_PUNCTLIST-1] = 0; } // end of sync_espeak_SetPunctuationList @@ -622,24 +622,24 @@ void sync_espeak_SetPunctuationList(const wchar_t *punctlist) ESPEAK_API void espeak_SetSynthCallback(t_espeak_callback* SynthCallback) {//====================================================================== - ENTER("espeak_SetSynthCallback"); - synth_callback = SynthCallback; + ENTER("espeak_SetSynthCallback"); + synth_callback = SynthCallback; } ESPEAK_API void espeak_SetUriCallback(int (* UriCallback)(int, const char*, const char *)) {//======================================================================================= - ENTER("espeak_SetUriCallback"); - uri_callback = UriCallback; + ENTER("espeak_SetUriCallback"); + uri_callback = UriCallback; } ESPEAK_API int espeak_Initialize(espeak_AUDIO_OUTPUT output_type, int buf_length, const char *path) {//================================================================================================ - ENTER("espeak_Initialize"); - int param; +ENTER("espeak_Initialize"); + int param; - // 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 - // other characters give the correct results with iswalpha() etc. + // 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 + // other characters give the correct results with iswalpha() etc. #ifdef PLATFORM_RISCOS setlocale(LC_CTYPE,"ISO8859-1"); #else @@ -649,39 +649,39 @@ ESPEAK_API int espeak_Initialize(espeak_AUDIO_OUTPUT output_type, int buf_length setlocale(LC_CTYPE,""); } #endif - - init_path(path); - initialise(); - select_output(output_type); - - // buflength is in mS, allocate 2 bytes per sample - if(buf_length == 0) - buf_length = 200; - outbuf_size = (buf_length * samplerate)/500; - outbuf = (unsigned char*)realloc(outbuf,outbuf_size); - if((out_start = outbuf) == NULL) + + init_path(path); + initialise(); + select_output(output_type); + + // buflength is in mS, allocate 2 bytes per sample + if(buf_length == 0) + buf_length = 200; + outbuf_size = (buf_length * samplerate)/500; + outbuf = (unsigned char*)realloc(outbuf,outbuf_size); + if((out_start = outbuf) == NULL) return(EE_INTERNAL_ERROR); - - // allocate space for event list. Allow 500 events per minute - n_event_list = (buf_length*500)/1000; - if((event_list = (espeak_EVENT *)realloc(event_list,sizeof(espeak_EVENT) * n_event_list)) == NULL) + + // allocate space for event list. Allow 500 events per minute + n_event_list = (buf_length*500)/1000; + if((event_list = (espeak_EVENT *)realloc(event_list,sizeof(espeak_EVENT) * n_event_list)) == NULL) return(EE_INTERNAL_ERROR); - - option_phonemes = 0; - - SetVoiceByName("default"); - - for(param=0; paramu.my_mark.unique_identifier; - - // Create the "terminated msg" command (same uid) - t_espeak_command* c2 = create_espeak_terminated_msg(*unique_identifier, user_data); - - // Try to add these 2 commands (single transaction) - if (c1 && c2) - { - a_error = fifo_add_commands(c1, c2); - if (a_error != EE_OK) + // Create the mark command + t_espeak_command* c1 = create_espeak_mark(text, size, index_mark, end_position, + flags, user_data); + + // Retrieve the unique identifier + *unique_identifier = c1->u.my_mark.unique_identifier; + + // Create the "terminated msg" command (same uid) + t_espeak_command* c2 = create_espeak_terminated_msg(*unique_identifier, user_data); + + // Try to add these 2 commands (single transaction) + if (c1 && c2) { - delete_espeak_command(c1); - delete_espeak_command(c2); - c1=c2=NULL; + a_error = fifo_add_commands(c1, c2); + if (a_error != EE_OK) + { + delete_espeak_command(c1); + delete_espeak_command(c2); + c1=c2=NULL; + } + } + else + { + delete_espeak_command(c1); + delete_espeak_command(c2); } - } - else - { - delete_espeak_command(c1); - delete_espeak_command(c2); - } #endif - return a_error; + return a_error; } // end of espeak_Synth_Mark @@ -981,24 +981,24 @@ ESPEAK_API espeak_ERROR espeak_SetPunctuationList(const wchar_t *punctlist) ESPEAK_API void espeak_SetPhonemeTrace(int value, FILE *stream) {//============================================================ - ENTER("espeak_SetPhonemes"); - /* Controls the output of phoneme symbols for the text - value=0 No phoneme output (default) - value=1 Output the translated phoneme symbols for the text - value=2 as (1), but also output a trace of how the translation was done (matching rules and list entries) - */ - option_phonemes = value; - f_trans = stream; - if(stream == NULL) - f_trans = stdout; - + ENTER("espeak_SetPhonemes"); + /* Controls the output of phoneme symbols for the text + value=0 No phoneme output (default) + value=1 Output the translated phoneme symbols for the text + value=2 as (1), but also output a trace of how the translation was done (matching rules and list entries) + */ + option_phonemes = value; + f_trans = stream; + if(stream == NULL) + f_trans = stdout; + } // end of espeak_SetPhonemes ESPEAK_API void espeak_CompileDictionary(const char *path, FILE *log) {//================================================================== - ENTER("espeak_CompileDictionary"); - CompileDictionary(path,dictionary_name,log,NULL); + ENTER("espeak_CompileDictionary"); + CompileDictionary(path,dictionary_name,log,NULL); } // end of espeak_CompileDirectory