Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAleksey Lim <alsroot@sugarlabs.org>2012-08-19 17:35:53 (GMT)
committer Aleksey Lim <alsroot@sugarlabs.org>2012-08-19 17:36:08 (GMT)
commit92644184c286ba7aacec7a3c8382cc279eb474c6 (patch)
treea9e3f65603ebcb74f334f12451242b8ff7640a04
parent8ecc6d10a7f88577362ff486a95d393a2fc44fdf (diff)
First shotsimplify
-rw-r--r--src/espeak.c398
1 files changed, 164 insertions, 234 deletions
diff --git a/src/espeak.c b/src/espeak.c
index 60bdd1b..ef1481f 100644
--- a/src/espeak.c
+++ b/src/espeak.c
@@ -24,53 +24,22 @@
#define SYNC_BUFFER_SIZE_MS 200
#define BYTES_PER_SAMPLE 2
-#define SPIN_QUEUE_SIZE 2
#define SPIN_FRAME_SIZE 255
#include "espeak.h"
-typedef enum {
- IN = 1,
- OUT = 2,
- PLAY = 4
-} SpinState;
-
-typedef enum {
- INPROCESS = 1,
- CLOSE = 2
-} ContextState;
-
-typedef struct {
- Econtext *context;
-
- volatile SpinState state;
+struct _Econtext {
+ gchar *text;
+ gchar *next_mark;
- GByteArray *sound;
+ GList *first_buffer;
+ GList *last_buffer;
gsize sound_offset;
GstClockTime audio_position;
GArray *events;
gsize events_pos;
- int last_word;
- int mark_offset;
- const gchar *mark_name;
-} Espin;
-
-struct _Econtext {
- volatile ContextState state;
-
- gchar *text;
- gsize text_offset;
- gsize text_len;
- gchar *next_mark;
-
- Espin queue[SPIN_QUEUE_SIZE];
- Espin *in;
- Espin *out;
-
- GSList *process_chunk;
-
volatile gint rate;
volatile gint pitch;
volatile const gchar *voice;
@@ -81,11 +50,6 @@ struct _Econtext {
GstBus *bus;
};
-static inline void spinning (Espin * base, Espin ** i) {
- if (++(*i) == base + SPIN_QUEUE_SIZE)
- *i = base;
-}
-
static void post_message (Econtext * self, GstStructure * data) {
if (!self->bus)
self->bus = gst_element_get_bus (self->emitter);
@@ -116,10 +80,9 @@ static void init ();
static void process_push (Econtext *, gboolean);
static void process_pop (Econtext *);
-static GThread *process_tid = NULL;
-static GMutex *process_lock = NULL;
-static GCond *process_cond = NULL;
-static GSList *process_queue = NULL;
+static GCond *synth_cond = NULL;
+static GMutex *synth_lock = NULL;
+static GSList *synth_queue = NULL;
static gint espeak_sample_rate = 0;
static gint espeak_buffer_size = 0;
@@ -131,22 +94,6 @@ Econtext *espeak_new (GstElement * emitter) {
init ();
Econtext *self = g_new0 (Econtext, 1);
- gint i;
-
- for (i = SPIN_QUEUE_SIZE; i--;) {
- Espin *spin = &self->queue[i];
-
- spin->context = self;
- spin->state = IN;
- spin->sound = g_byte_array_new ();
- spin->events = g_array_new (FALSE, FALSE, sizeof (espeak_EVENT));
- }
-
- self->in = self->queue;
- self->out = self->queue;
-
- self->process_chunk = g_slist_alloc ();
- self->process_chunk->data = self;
self->pitch = 50;
self->rate = 170;
@@ -154,6 +101,7 @@ Econtext *espeak_new (GstElement * emitter) {
self->gap = 0;
self->track = ESPEAK_TRACK_NONE;
+ spin->events = g_array_new (FALSE, FALSE, sizeof (espeak_EVENT));
self->emitter = emitter;
gst_object_ref (self->emitter);
self->bus = NULL;
@@ -163,20 +111,29 @@ Econtext *espeak_new (GstElement * emitter) {
return self;
}
-void espeak_unref (Econtext * self) {
- GST_DEBUG ("[%p]", self);
-
- espeak_reset (self);
+void espeak_reset (Econtext * self) {
+ g_mutex_lock (synth_lock);
- gint i;
+ g_list_free_full (self->last_buffer, g_free);
+ self->first_buffer = NULL;
+ self->last_buffer = NULL;
- for (i = SPIN_QUEUE_SIZE; i--;) {
- g_byte_array_free (self->queue[i].sound, TRUE);
- g_array_free (self->queue[i].events, TRUE);
+ if (self->text) {
+ g_free (self->text);
+ self->text = NULL;
}
- g_slist_free (self->process_chunk);
+ self->next_mark = NULL;
+
+ g_mutex_unlock (synth_lock);
+}
+
+void espeak_unref (Econtext * self) {
+ GST_DEBUG ("[%p]", self);
+
+ espeak_reset (self);
+ g_array_free (self->events, TRUE);
gst_object_unref (self->bus);
gst_object_unref (self->emitter);
@@ -193,13 +150,16 @@ void espeak_in (Econtext * self, const gchar * text) {
return;
self->text = g_strdup (text);
- self->text_offset = 0;
- self->text_len = strlen (text);
+ g_array_set_size (self->events, 0);
+ self->sound_offset = 0;
+ self->audio_position = 0;
+ self->events_pos = 0;
process_push (self, TRUE);
}
GstBuffer *play (Econtext * self, Espin * spin, gsize size_to_play) {
+
inline gsize whole (Espin * spin, gsize size_to_play) {
for (;; ++spin->events_pos) {
espeak_EVENT *i = &g_array_index (spin->events, espeak_EVENT,
@@ -244,8 +204,6 @@ GstBuffer *play (Econtext * self, Espin * spin, gsize size_to_play) {
return sample_offset - spin->sound_offset;
}
- g_atomic_int_set (&spin->state, PLAY);
-
switch (g_atomic_int_get (&self->track)) {
case ESPEAK_TRACK_WORD:
case ESPEAK_TRACK_MARK:
@@ -287,7 +245,7 @@ GstBuffer *espeak_out (Econtext * self, gsize size_to_play) {
GST_DEBUG ("[%p] size_to_play=%d", self, size_to_play);
for (;;) {
- g_mutex_lock (process_lock);
+ g_mutex_lock (synth_lock);
for (;;) {
if (g_atomic_int_get (&self->out->state) & (PLAY | OUT))
break;
@@ -296,13 +254,13 @@ GstBuffer *espeak_out (Econtext * self, gsize size_to_play) {
GST_DEBUG ("[%p] sesseion is closed", self);
else
GST_DEBUG ("[%p] nothing to play", self);
- g_mutex_unlock (process_lock);
+ g_mutex_unlock (synth_lock);
return NULL;
}
GST_DEBUG ("[%p] wait for processed data", self);
- g_cond_wait (process_cond, process_lock);
+ g_cond_wait (synth_cond, synth_lock);
}
- g_mutex_unlock (process_lock);
+ g_mutex_unlock (synth_lock);
Espin *spin = self->out;
gsize spin_size = spin->sound->len;
@@ -327,110 +285,8 @@ GstBuffer *espeak_out (Econtext * self, gsize size_to_play) {
return NULL;
}
-void espeak_reset (Econtext * self) {
- process_pop (self);
-
- GstBuffer *buf;
- while ((buf = espeak_out (self, espeak_buffer_size)) != NULL)
- gst_buffer_unref (buf);
-
- int i;
- for (i = SPIN_QUEUE_SIZE; i--;)
- g_atomic_int_set (&self->queue[i].state, IN);
-
- if (self->text) {
- g_free (self->text);
- self->text = NULL;
- }
-
- self->next_mark = NULL;
-}
-
// espeak ----------------------------------------------------------------------
-static gint synth_cb (short *data, int numsamples, espeak_EVENT * events) {
- if (data == NULL)
- return 0;
-
- Espin *spin = events->user_data;
- Econtext *self = spin->context;
-
- if (numsamples > 0) {
- g_byte_array_append (spin->sound, (const guint8 *) data,
- numsamples * BYTES_PER_SAMPLE);
-
- espeak_EVENT *i;
-
- for (i = events; i->type != espeakEVENT_LIST_TERMINATED; ++i) {
- GST_DEBUG ("type=%d text_position=%d length=%d "
- "audio_position=%d sample=%d",
- i->type, i->text_position, i->length,
- i->audio_position, i->sample * BYTES_PER_SAMPLE);
-
- // convert to 0-based position
- --i->text_position;
-
- if (i->type == espeakEVENT_MARK) {
- // point mark name to our text substring instead of
- // one which was temporally allocated by espeak
- if (self->next_mark == NULL)
- self->next_mark = self->text;
- int mark_len = strlen (i->id.name);
- strncpy (self->next_mark, i->id.name, mark_len);
- i->id.name = self->next_mark;
- self->next_mark[mark_len] = '\0';
- self->next_mark += mark_len + 1;
- }
-
- GST_DEBUG ("text_position=%d length=%d",
- i->text_position, i->length);
-
- g_array_append_val (spin->events, *i);
- }
- }
-
- GST_DEBUG ("numsamples=%d", numsamples * BYTES_PER_SAMPLE);
-
- return 0;
-}
-
-static void synth (Econtext * self, Espin * spin) {
- g_byte_array_set_size (spin->sound, 0);
- g_array_set_size (spin->events, 0);
- spin->sound_offset = 0;
- spin->audio_position = 0;
- spin->events_pos = 0;
- spin->mark_offset = 0;
- spin->mark_name = NULL;
- spin->last_word = -1;
-
- espeak_SetParameter (espeakPITCH, g_atomic_int_get (&self->pitch), 0);
- espeak_SetParameter (espeakRATE, g_atomic_int_get (&self->rate), 0);
- espeak_SetVoiceByName ((gchar *) g_atomic_pointer_get (&self->voice));
- espeak_SetParameter (espeakWORDGAP, g_atomic_int_get (&self->gap), 0);
-
- gint track = g_atomic_int_get (&self->track);
-
- gint flags = espeakCHARS_UTF8;
- if (track == ESPEAK_TRACK_MARK)
- flags |= espeakSSML;
-
- GST_DEBUG ("[%p] text_offset=%zd", self, self->text_offset);
-
- espeak_Synth (self->text, self->text_len + 1, 0, POS_CHARACTER, 0, flags,
- NULL, spin);
-
- if (spin->events->len) {
- int text_offset = g_array_index (spin->events, espeak_EVENT,
- spin->events->len - 1).text_position + 1;
- self->text_offset = g_utf8_offset_to_pointer (self->text, text_offset)
- - self->text;
- }
-
- espeak_EVENT last_event = { espeakEVENT_LIST_TERMINATED };
- last_event.sample = spin->sound->len / BYTES_PER_SAMPLE;
- g_array_append_val (spin->events, last_event);
-}
gint espeak_get_sample_rate () {
return espeak_sample_rate;
@@ -477,81 +333,155 @@ void espeak_set_track (Econtext * self, guint value) {
g_atomic_int_set (&self->track, value);
}
-// process ----------------------------------------------------------------------
-static gpointer process (gpointer data) {
- g_mutex_lock (process_lock);
+
+
+static gpointer synth_thread (gpointer data) {
for (;;) {
- while (process_queue == NULL)
- g_cond_wait (process_cond, process_lock);
+ g_mutex_lock (synth_lock);
- while (process_queue) {
- Econtext *context = (Econtext *) process_queue->data;
- Espin *spin = context->in;
+ while (synth_queue == NULL)
+ g_cond_wait (synth_cond, synth_lock);
+ Econtext *context = (Econtext *) synth_queue->data;
+ synth_queue = g_slist_remove_link (synth_queue, synth_queue);
+
+ espeak_SetParameter (espeakPITCH, context->pitch, 0);
+ espeak_SetParameter (espeakRATE, context->rate, 0);
+ espeak_SetVoiceByName ((gchar *) context->voice);
+ espeak_SetParameter (espeakWORDGAP, context->gap, 0);
+ gchar *text = context->text;
+ context->text = NULL;
+ gint track = context->track;
+
+ g_mutex_unlock (synth_lock);
+
+
+
+
+
+
+
+
+
+
+
+
+
+ gint flags = espeakCHARS_UTF8;
+ if (track == ESPEAK_TRACK_MARK)
+ flags |= espeakSSML;
+
+ gint text_len = strlen (text);
+ espeak_Synth (text, text_len + 1, 0, POS_CHARACTER, 0, flags,
+ NULL, spin);
+
+ espeak_EVENT last_event = { espeakEVENT_LIST_TERMINATED };
+ last_event.sample = spin->sound->len / BYTES_PER_SAMPLE;
+ g_array_append_val (spin->events, last_event);
+
+ g_free(text);
- process_queue = g_slist_remove_link (process_queue, process_queue);
- if (context->state == CLOSE) {
- GST_DEBUG ("[%p] session is closed", context);
- continue;
- }
- GST_DEBUG ("[%p] context->text_offset=%d context->text_len=%d",
- context, context->text_offset, context->text_len);
-
- if (context->text_offset >= context->text_len) {
- GST_DEBUG ("[%p] end of text to process", context);
- context->state &= ~INPROCESS;
- } else {
- synth (context, spin);
- g_atomic_int_set (&spin->state, OUT);
- spinning (context->queue, &context->in);
-
- if (g_atomic_int_get (&context->in->state) == IN) {
- GST_DEBUG ("[%p] continue to process data", context);
- process_queue = g_slist_concat (process_queue,
- context->process_chunk);
- } else {
- GST_DEBUG ("[%p] pause to process data", context);
- context->state &= ~INPROCESS;
- }
- }
- }
- g_cond_broadcast (process_cond);
+
+
+
+
+
+
+
+ g_cond_broadcast (synth_cond);
}
- g_mutex_unlock (process_lock);
+ g_mutex_unlock (synth_lock);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
return NULL;
}
+static gint synth_cb (short *data, int numsamples, espeak_EVENT * events) {
+ if (data == NULL)
+ return 0;
+
+ Espin *spin = events->user_data;
+ Econtext *self = spin->context;
+
+ if (numsamples > 0) {
+ g_byte_array_append (spin->sound, (const guint8 *) data,
+ numsamples * BYTES_PER_SAMPLE);
+
+ espeak_EVENT *i;
+
+ for (i = events; i->type != espeakEVENT_LIST_TERMINATED; ++i) {
+ GST_DEBUG ("type=%d text_position=%d length=%d "
+ "audio_position=%d sample=%d",
+ i->type, i->text_position, i->length,
+ i->audio_position, i->sample * BYTES_PER_SAMPLE);
+
+ // convert to 0-based position
+ --i->text_position;
+
+ if (i->type == espeakEVENT_MARK) {
+ // point mark name to our text substring instead of
+ // one which was temporally allocated by espeak
+ if (self->next_mark == NULL)
+ self->next_mark = self->text;
+ int mark_len = strlen (i->id.name);
+ strncpy (self->next_mark, i->id.name, mark_len);
+ i->id.name = self->next_mark;
+ self->next_mark[mark_len] = '\0';
+ self->next_mark += mark_len + 1;
+ }
+
+ GST_DEBUG ("text_position=%d length=%d",
+ i->text_position, i->length);
+
+ g_array_append_val (spin->events, *i);
+ }
+ }
+
+ GST_DEBUG ("numsamples=%d", numsamples * BYTES_PER_SAMPLE);
+
+ return 0;
+}
+
+
+
static void process_push (Econtext * context, gboolean force_in) {
GST_DEBUG ("[%p] lock", context);
- g_mutex_lock (process_lock);
-
- if (context->state == CLOSE && !force_in)
- GST_DEBUG ("[%p] state=%d", context, context->state);
- else if (context->state != INPROCESS) {
- context->state = INPROCESS;
- process_queue = g_slist_concat (process_queue, context->process_chunk);
- g_cond_broadcast (process_cond);
- }
+ g_mutex_lock (synth_lock);
+
+ synth_queue = g_slist_concat (synth_queue, context);
+ g_cond_broadcast (synth_cond);
- g_mutex_unlock (process_lock);
+ g_mutex_unlock (synth_lock);
GST_DEBUG ("[%p] unlock", context);
}
static void process_pop (Econtext * context) {
GST_DEBUG ("[%p] lock", context);
- g_mutex_lock (process_lock);
+ g_mutex_lock (synth_lock);
- process_queue = g_slist_remove_link (process_queue, context->process_chunk);
- context->state = CLOSE;
- g_cond_broadcast (process_cond);
+ synth_queue = g_slist_remove_link (synth_queue, context->process_chunk);
+ g_cond_broadcast (synth_cond);
- g_mutex_unlock (process_lock);
+ g_mutex_unlock (synth_lock);
GST_DEBUG ("[%p] unlock", context);
}
@@ -563,9 +493,9 @@ static void init () {
if (initialized == 0) {
++initialized;
- process_lock = g_mutex_new ();
- process_cond = g_cond_new ();
- process_tid = g_thread_create (process, NULL, FALSE, NULL);
+ synth_lock = g_mutex_new ();
+ synth_cond = g_cond_new ();
+ g_thread_create (synth_thread, NULL, FALSE, NULL);
espeak_sample_rate = espeak_Initialize (AUDIO_OUTPUT_SYNCHRONOUS,
SYNC_BUFFER_SIZE_MS, NULL, 0);