speechd-discuss
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] Add an output module for RHVoice.


From: Anatol
Subject: [PATCH] Add an output module for RHVoice.
Date: Fri, 3 Feb 2012 15:38:41 +0400

RHVoice is a free and open source speech synthesizer developed
by Olga Yakovleva. At the moment, the engine has two Russian voices (male
and female). Currently, RHVoice is the only freeware speech synthesizer
for Russian language which has high speech quality.
In the future, support for other languages (such as Ukrainian, Belarusian
and Kazakh) will be added. However, the creating new  voices mostly depends
on the activity of the community.
More:  https://github.com/olga-yakovleva/rhvoice
---
 config/modules/Makefile.am  |    5 +
 config/modules/rhvoice.conf |   17 ++
 configure.ac                |   14 +
 src/modules/Makefile.am     |    8 +
 src/modules/rhvoice.c       |  633 +++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 677 insertions(+), 0 deletions(-)
 create mode 100644 config/modules/rhvoice.conf
 create mode 100644 src/modules/rhvoice.c

diff --git a/config/modules/Makefile.am b/config/modules/Makefile.am
index 8632db8..8499eeb 100644
--- a/config/modules/Makefile.am
+++ b/config/modules/Makefile.am
@@ -16,3 +16,8 @@ if pico_support
 dist_moduleconf_DATA += pico.conf
 dist_moduleconforig_DATA += pico.conf
 endif
+
+if rhvoice_support
+dist_moduleconf_DATA += rhvoice.conf
+dist_moduleconforig_DATA += rhvoice.conf
+endif
diff --git a/config/modules/rhvoice.conf b/config/modules/rhvoice.conf
new file mode 100644
index 0000000..69dd022
--- /dev/null
+++ b/config/modules/rhvoice.conf
@@ -0,0 +1,17 @@
+
+# Data
+RHVoiceDataPath "/usr/local/share/RHVoice"
+RHVoiceConfigPath "/usr/local/etc/RHVoice"
+
+# Punctuation
+
+RHVoicePunctuationMode 0
+#RHVoicePunctuationList "@+_"
+
+# Default Voice
+RHVoiceDefaultVoice "Aleksandr"
+RHVoiceDefaultVariant "Pseudo-English"
+
+
+# Debugging
+Debug 0
diff --git a/configure.ac b/configure.ac
index 4ef8f70..a423882 100644
--- a/configure.ac
+++ b/configure.ac
@@ -202,6 +202,20 @@ AS_IF([test $with_pico != "no"],
 AM_CONDITIONAL([pico_support], [test $with_pico = "yes"])
 AS_IF([test $with_pico = "yes"], [output_modules="${output_modules} pico"])
 
+# check for RHVoice support
+AC_ARG_WITH([rhvoice],
+       [AS_HELP_STRING([--with-rhvoice], [include RHVoice support])],
+       [],
+       [with_rhvoice=check])
+AS_IF([test $with_rhvoice != "no"],
+       [AC_CHECK_LIB([RHVoice], [RHVoice_initialize],
+               [with_rhvoice=yes],
+               [AS_IF([test $with_rhvoice = "yes"],
+                       [AC_MSG_FAILURE([RHVoice is not available])])])])
+AM_CONDITIONAL([rhvoice_support], [test $with_rhvoice = "yes"])
+AS_IF([test $with_rhvoice = "yes"], [output_modules="${output_modules} 
rhvoice"])
+
+
 audio_dlopen_modules='-dlopen force'
 
 # clear default audio method
diff --git a/src/modules/Makefile.am b/src/modules/Makefile.am
index 9012a4b..38cee5d 100644
--- a/src/modules/Makefile.am
+++ b/src/modules/Makefile.am
@@ -82,3 +82,11 @@ sd_pico_LDADD = $(top_builddir)/src/common/libcommon.la \
        $(audio_dlopen_modules) -lttspico \
        $(common_LDADD)
 endif
+
+if rhvoice_support
+modulebin_PROGRAMS += sd_rhvoice
+sd_rhvoice_SOURCES = rhvoice.c $(audio_SOURCES) $(common_SOURCES)
+sd_rhvoice_LDADD = $(top_builddir)/src/common/libcommon.la \
+       $(audio_dlopen_modules) -lRHVoice \
+       $(common_LDADD)
+endif
diff --git a/src/modules/rhvoice.c b/src/modules/rhvoice.c
new file mode 100644
index 0000000..6ca7339
--- /dev/null
+++ b/src/modules/rhvoice.c
@@ -0,0 +1,633 @@
+
+/*
+ * rhvoice.c - Speech Dispatcher backend for RHVoice *
+ * Copyright (C) 2011, 2012 Anatol Kamynin
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this package; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+ #ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <stdio.h>
+
+/* RHVoice header file */
+#include <RHVoice.h>
+
+/* Speech Dispatcher includes. */
+#include "spd_audio.h"
+#include <speechd_types.h>
+
+#include "module_utils.h"
+
+#define MODULE_NAME     "rhvoice"
+#define MODULE_VERSION  "0.1"
+
+#define RHV_NUM_CHANNELS       1
+#define RHV_BITS_PER_SAMPLE    16
+
+typedef enum
+{
+               RHV_STATE_UNKNOWN = 0,
+               RHV_STATE_IDLE,
+               RHV_STATE_SPEAK,
+               RHV_STATE_STOP,
+               RHV_STATE_CLOSE
+} RHV_STATE;
+
+typedef enum
+{
+       RHV_CANCEL = 0,
+       RHV_CONTINUE =1
+} RHV_CALLBACK_RETVAL;
+
+typedef struct _tRHVMsgEntry
+{
+       RHVoice_message msg;
+       SPDMsgSettings  settings;
+}      RHVMsgEntry;
+
+const char *RHV_DEFAULT_DATAPATH = "/usr/local/sharead/RHVoice";
+const char *RHV_SOUND_ICON_FOLDER = "/usr/local/share/RHVoice/icons";
+const char *RHV_DEFAULT_CONFIGPATH = "/usr/local/etc/Rhvoice";
+
+#define DEBUG_MODULE 1
+DECLARE_DEBUG();
+
+/* callback function prototype */
+int rhv_callback(const short *samples,int num_samples,const RHVoice_event 
*events,int num_events,RHVoice_message msg);
+static void rhv_handle_events(const RHVoice_event *events,int num_events);
+
+/* Internal functions prototypes */
+static void rhv_set_rate(signed int rate);
+static void rhv_set_pitch(signed int pitch);
+static void rhv_set_volume(signed int volume);
+static void rhv_set_voice(SPDVoiceType voice);
+static void rhv_set_synthesis_voice(const char *name);
+static void rhv_set_language(const char *lang);
+static void rhv_set_punctuation_mode(SPDPunctuation pm);
+static void rhv_set_cap_let_recogn(SPDCapitalLetters cl);
+
+/* thread function */
+static void* _rhv_speak(void*);
+
+/* control list of voices */
+static SPDVoice ** rhv_list_voices_new(void);
+static void rhv_list_voices_free(SPDVoice **list);
+
+/*  control the queue of the messages */
+static void rhv_msgqueue_pop(void);
+static void rhv_msgqueue_push(RHVoice_message msg);
+static void rhv_msgqueue_free(void);
+
+/* players */
+static int rhv_play_raw(const short *samples, size_t num_samples);
+
+/* message to tts*/
+GSList *rhv_msg_queue = NULL;
+
+/* Thread and process control */
+volatile gint rhv_state= RHV_STATE_UNKNOWN;
+
+static pthread_t rhv_speak_thread;
+static GCond *rhv_msg_queueNotEmpty = NULL;
+static GMutex *rhv_msg_queue_mutex = NULL;
+static int rhv_samplerate = 0;
+
+/* list of voices */
+static SPDVoice **rhv_list_voices= NULL;
+
+/* Module configuration options*/
+MOD_OPTION_1_INT(RHVoicePunctuationMode);
+MOD_OPTION_1_STR(RHVoicePunctuationList);
+MOD_OPTION_1_STR(RHVoiceDataPath);
+MOD_OPTION_1_STR(RHVoiceConfigPath);
+MOD_OPTION_1_STR(RHVoiceDefaultVoice);
+MOD_OPTION_1_STR(RHVoiceDefaultVariant);
+MOD_OPTION_1_STR(RHVoiceSoundIconFolder);
+
+/* Public functions */
+
+int
+module_load(void)
+{
+       INIT_SETTINGS_TABLES();
+       REGISTER_DEBUG();
+       module_audio_id = NULL;
+
+       MOD_OPTION_1_INT_REG(RHVoicePunctuationMode,
+                       RHVoice_get_punctuation_mode());
+       MOD_OPTION_1_STR_REG(RHVoicePunctuationList,"");
+       MOD_OPTION_1_STR_REG(RHVoiceDataPath, RHV_DEFAULT_DATAPATH);
+       MOD_OPTION_1_STR_REG(RHVoiceConfigPath, RHV_DEFAULT_CONFIGPATH);
+       MOD_OPTION_1_STR_REG(RHVoiceDefaultVoice,
+                       RHVoice_get_voice_name(RHVoice_get_voice()));
+       MOD_OPTION_1_STR_REG(RHVoiceDefaultVariant,
+                       RHVoice_get_variant_name(RHVoice_get_variant()));
+       MOD_OPTION_1_STR_REG(RHVoiceSoundIconFolder, RHV_SOUND_ICON_FOLDER);
+
+       return 0;
+}
+
+#define ABORT(msg) g_string_append(info, msg); \
+        DBG("FATAL ERROR:", info->str); \
+       *status_info = info->str; \
+       g_string_free(info, 0); \
+       return -1;
+
+int
+module_init(char **status_info)
+{
+       int ret;
+       GString *info;
+
+       INIT_INDEX_MARKING();
+
+       *status_info = NULL;
+       info = g_string_new("");
+
+       /* Init RHVoice */
+       rhv_samplerate = RHVoice_initialize(
+                       RHVoiceDataPath, rhv_callback,
+                       RHVoiceConfigPath,0);
+       if(rhv_samplerate  <= 0) {
+               DBG(MODULE_NAME ": couldn't initialize tts-engine.");
+               *status_info = strdup("Can't initialize tts-engine.");
+               return -1;
+       }
+
+       if(RHVoiceDefaultVariant!=NULL && *RHVoiceDefaultVariant) {
+               int variant=RHVoice_find_variant(RHVoiceDefaultVariant);
+               if(variant>0)
+                       RHVoice_set_variant(variant);
+       }
+
+       if(RHVoiceDefaultVoice !=NULL && *RHVoiceDefaultVoice ) {
+               int voice=RHVoice_find_voice(RHVoiceDefaultVoice );
+               if(voice>0) RHVoice_set_voice(voice);
+       }
+
+       RHVoice_set_punctuation_mode(RHVoicePunctuationMode);
+       if      (RHVoicePunctuationList!=NULL && *RHVoicePunctuationList) {
+               RHVoice_set_punctuation_list(RHVoicePunctuationList);
+       }
+
+       g_thread_init(NULL);
+       rhv_msg_queueNotEmpty= g_cond_new();
+       if (NULL == rhv_msg_queueNotEmpty) {
+               DBG(MODULE_NAME ": unable to create glib cond.");
+               return -1;
+       }
+
+       rhv_msg_queue_mutex = g_mutex_new();
+       if (NULL == rhv_msg_queue_mutex)
+       {
+               DBG(MODULE_NAME ": unable to create the queue mutex");
+               return -1;
+       }
+
+       rhv_list_voices = rhv_list_voices_new();
+       if (NULL == rhv_list_voices) {
+               DBG(MODULE_NAME": unable to create list of voices.");
+               return -1;
+       }
+
+       ret = pthread_create(&rhv_speak_thread, NULL, _rhv_speak, NULL);
+       if(ret != 0) {
+               DBG(MODULE_NAME": couldn't initialize threads.");
+               *status_info = strdup("Couldn't initialize threads "
+                       "This could be either an internal problem or an "
+                       "architecture problem. If you are sure your 
architecture "
+                       "supports threads, please report a bug.");
+               return -1;
+       }
+
+       *status_info = g_strdup_printf(MODULE_NAME ": engine version = %s, "
+               "voices: %d.",
+               RHVoice_get_version(),
+               RHVoice_get_voice_count());
+
+               g_atomic_int_set(&rhv_state, RHV_STATE_IDLE);
+
+       return 0;
+}
+#undef ABORT
+
+SPDVoice **
+module_list_voices(void)
+{
+  return rhv_list_voices;
+}
+
+int
+module_speak(gchar *data, size_t bytes, SPDMessageType msgtype)
+{
+       int isSSML = 1;
+       char *xdata = NULL;
+
+       DBG(MODULE_NAME ": requested data: |%s|\n", data);
+       switch (msgtype) {
+               case SPD_MSGTYPE_TEXT : break;
+               case SPD_MSGTYPE_SOUND_ICON :
+                       xdata = g_strdup_printf(
+                               "<audio src=\"%s%s\">%s</audio>",
+                               RHVoiceSoundIconFolder, data, data);
+                       bytes = strlen(xdata);
+                       break;
+               case SPD_MSGTYPE_CHAR :  isSSML  = 0; break;
+               case SPD_MSGTYPE_KEY : isSSML  = 0; break;
+               case SPD_MSGTYPE_SPELL : break;
+       }
+
+       if (data != NULL && bytes != 0) {
+               RHVoice_message msg =RHVoice_new_message_utf8(
+                               (const uint8_t*)(xdata ? xdata:data),
+                               bytes, isSSML);
+               g_free(xdata);
+               if(NULL == msg) {
+                       DBG(MODULE_NAME ": unable to create msg.");
+                       return -1;
+               }
+
+               g_mutex_lock(rhv_msg_queue_mutex);
+               rhv_msgqueue_push(msg);
+               g_mutex_unlock(rhv_msg_queue_mutex);
+               g_cond_signal(rhv_msg_queueNotEmpty);
+       }       /* if data */
+
+       DBG(MODULE_NAME ": leaving module_speak() normally.");
+       return bytes;
+}
+
+int
+module_stop(void)
+{
+       DBG(MODULE_NAME ": stop");
+       if (g_atomic_int_get(&rhv_state) != RHV_STATE_SPEAK) {
+               DBG(MODULE_NAME ": STOP called when not in speaking.");
+               return -1;
+       }
+
+       g_atomic_int_set(&rhv_state, RHV_STATE_STOP);
+       return 0;
+}
+
+size_t
+module_pause(void)
+{
+       DBG(MODULE_NAME ": pause requested");
+       if(g_atomic_int_get(&rhv_state) == RHV_STATE_SPEAK) {
+               DBG(MODULE_NAME " doesn't support pause, stopping");
+               module_stop();
+               return -1;
+       }
+
+       return 0;
+}
+
+int
+module_close(void)
+{
+       DBG(MODULE_NAME ": close");
+       if (rhv_samplerate <= 0) {
+               DBG(MODULE_NAME ": tts engine was not properly initialized");
+               return 0;
+       }
+
+       if(g_atomic_int_get(&rhv_state) == RHV_STATE_SPEAK) {
+               module_stop();
+       }
+
+       DBG(MODULE_NAME ": terminating thread");
+
+       g_atomic_int_set(&rhv_state, RHV_STATE_CLOSE);
+       g_cond_signal(rhv_msg_queueNotEmpty);
+
+       if (module_terminate_thread(rhv_speak_thread) != 0) {
+               DBG(MODULE_NAME ": unable to terminate thread.");
+               return -1;
+       }
+
+       rhv_list_voices_free(rhv_list_voices);
+       RHVoice_terminate();
+
+       DBG(MODULE_NAME ": closing audio output");
+       spd_audio_close(module_audio_id);
+
+       g_cond_free(rhv_msg_queueNotEmpty);
+       rhv_msg_queueNotEmpty= NULL;
+       g_mutex_free(rhv_msg_queue_mutex);
+       rhv_msg_queue_mutex = NULL;
+       return 0;
+}
+
+/* Internal functions */
+
+void*
+_rhv_speak(void* nothing)
+{
+       GMutex *mx = g_mutex_new();
+
+       set_speaking_thread_parameters();
+
+       while(g_atomic_int_get(&rhv_state) != RHV_STATE_CLOSE) {
+               g_atomic_int_set(&rhv_state, RHV_STATE_IDLE);
+               g_cond_wait(rhv_msg_queueNotEmpty, mx);
+               while(rhv_msg_queue  != NULL )  {
+                       g_atomic_int_set(&rhv_state, RHV_STATE_SPEAK);
+                       module_report_event_begin();
+
+                       if (rhv_msg_queue->data != NULL) {
+                               g_mutex_lock(rhv_msg_queue_mutex);
+                               /* Setting voice */
+                               msg_settings = ((RHVMsgEntry*) 
rhv_msg_queue->data)->settings;
+                               UPDATE_PARAMETER(voice_type, rhv_set_voice);
+                               UPDATE_STRING_PARAMETER(voice.language, 
rhv_set_language);
+                               UPDATE_STRING_PARAMETER(voice.name, 
rhv_set_synthesis_voice);
+                               UPDATE_PARAMETER(rate, rhv_set_rate);
+                               UPDATE_PARAMETER(volume, rhv_set_volume);
+                               UPDATE_PARAMETER(pitch, rhv_set_pitch);
+                               UPDATE_PARAMETER(punctuation_mode, 
rhv_set_punctuation_mode);
+                               UPDATE_PARAMETER(cap_let_recogn, 
rhv_set_cap_let_recogn);
+                               /* UPDATE_PARAMETER(spelling_mode, 
rhv_set_spelling_mode); */
+
+                               g_mutex_unlock(rhv_msg_queue_mutex);
+                               if (((RHVMsgEntry*) rhv_msg_queue->data)->msg 
!= NULL) {
+                                       
RHVoice_speak(((RHVMsgEntry*)rhv_msg_queue->data)->msg);
+                               }
+                       }       /* if data */
+
+                       if (g_atomic_int_get(&rhv_state) == RHV_STATE_STOP) {
+                               g_mutex_lock(rhv_msg_queue_mutex);
+                               rhv_msgqueue_free();
+                               g_mutex_unlock(rhv_msg_queue_mutex);
+                               module_report_event_stop();
+                       } else {
+                               g_mutex_lock(rhv_msg_queue_mutex);
+                               rhv_msgqueue_pop();
+                               g_mutex_unlock(rhv_msg_queue_mutex);
+                               module_report_event_end();
+                       }
+               } /* while queue*/
+       } /* while */
+
+       g_mutex_free(mx);
+       mx = NULL;
+       DBG(MODULE_NAME ": speaking thread ended.");
+       pthread_exit(NULL);
+}
+
+static float
+rhv_convert_prosody_value(float v, float min, float max, float norm)
+{
+float ret = 0;
+       ret=((v<0) ? (norm+ (norm- min) * v/ 100.0) :
+               (norm+ (max- norm) * v/ 100.0));
+return ret;
+}
+
+void
+rhv_set_rate(signed int rate)
+{
+       assert(rate >= -100 && rate <= +100);
+       RHVoice_set_rate(rhv_convert_prosody_value(
+               rate,RHVoice_get_min_rate(),
+               RHVoice_get_max_rate(),RHVoice_get_default_rate()));
+}
+
+void
+rhv_set_volume(signed  int volume)
+{
+       assert(volume >= -100 && volume <= +100);
+       RHVoice_set_volume(rhv_convert_prosody_value(
+               
volume,0,RHVoice_get_max_volume(),RHVoice_get_default_volume()));
+}
+
+void
+rhv_set_pitch(signed int pitch)
+{
+       assert(pitch >= -100 && pitch <= +100);
+       RHVoice_set_pitch(rhv_convert_prosody_value(
+               pitch,RHVoice_get_min_pitch(),
+               RHVoice_get_max_pitch(),RHVoice_get_default_pitch()));
+}
+
+void
+rhv_set_voice(SPDVoiceType voice)
+{
+       return;
+}
+
+void
+rhv_set_synthesis_voice(const char *name)
+{
+       if (name!=NULL && *name)
+       {
+               int id=  RHVoice_find_voice(name);
+               if (id <= 0)
+               {
+                       char* real_name = g_strdup(name);
+                       *real_name -= 32;
+                       id=  RHVoice_find_voice(real_name);
+                       g_free(real_name);
+               }
+               DBG("set voice: [%s], id=%d", name, id);
+               if (id>0)
+                       RHVoice_set_voice(id);
+       } /* if name */
+}
+
+void
+rhv_set_language(const char *lang)
+{
+       return;
+} /* rhv_set_language */
+
+void
+rhv_set_punctuation_mode(SPDPunctuation pm)
+{
+       RHVoice_punctuation_mode  mode = RHVoice_get_punctuation_mode();
+       switch (pm)  {
+               case SPD_PUNCT_ALL :
+                       mode= RHVoice_punctuation_all;
+                       break;
+               case SPD_PUNCT_SOME :
+                       mode = RHVoice_punctuation_some;
+                       break;
+               case SPD_PUNCT_NONE :
+                       mode = RHVoice_punctuation_none;
+                       break;
+       }
+       RHVoice_set_punctuation_mode(mode);
+} /* rhv_set_punctuation_mode */
+
+void
+rhv_set_cap_let_recogn(SPDCapitalLetters cl)
+{
+
+} /* rhv_set_cap_let_recogn */
+
+int
+rhv_callback(
+                               const short *samples,
+                               int num_samples,
+                               const RHVoice_event *events,
+                               int num_events,
+                               RHVoice_message msg)
+{
+
+       rhv_handle_events(events, num_events);
+
+       if (g_atomic_int_get(&rhv_state) == RHV_STATE_STOP) {
+               DBG("Stop in callback, terminating");
+                       if (module_audio_id) {
+               int ret = spd_audio_stop(module_audio_id);
+               if (ret != 0)
+                               DBG("WARNING: Non 0 value from spd_audio_stop: 
%d", ret);
+       }
+
+               return RHV_CANCEL;
+       }
+
+       if (samples != NULL && num_samples != 0) {
+               rhv_play_raw(samples, num_samples);
+       }
+       return RHV_CONTINUE;
+}              /* rhv_callback */
+
+void
+rhv_handle_events(const RHVoice_event *events,int count)
+{
+       int i;
+       if (NULL == events || !count) return;
+
+       for(i=0; i<count && (events+i) != NULL; ++i) {
+               switch (events[i].type) {
+                       case     RHVoice_event_mark:
+                               DBG(MODULE_NAME ": index mark |%s|.", 
events[i].id.name);
+                               
module_report_index_mark((char*)(events[i].id.name));
+                               break;
+
+                       case RHVoice_event_play:
+                               if (0 >  module_play_file(events[i].id.name)) {
+                                       DBG(MODULE_NAME ": Unable to play |%s|",
+                                               events[i].id.name);
+                               }
+                               break;
+
+                       case RHVoice_event_word_start: break;
+                       case RHVoice_event_word_end: break;
+                       case RHVoice_event_sentence_start: break;
+                       case RHVoice_event_sentence_end: break;
+               }       /* switch */
+       } /* for events */
+} /* rhv_handle_events */
+
+SPDVoice **
+rhv_list_voices_new(void)
+{
+       int numVoices = 0, i=0;
+       SPDVoice **voices = NULL;
+
+       numVoices = RHVoice_get_voice_count();
+       if (numVoices <= 0) return NULL;
+       voices = g_try_malloc(sizeof(SPDVoice *)*(numVoices+1));
+       if (NULL == voices) return NULL;
+       for (i=0; i<numVoices;++i) {
+               voices[i] = g_try_malloc(sizeof(SPDVoice));
+               voices[i]->name = g_strdup(RHVoice_get_voice_name(i+1));
+               voices[i]->language = g_strdup("ru");
+               voices[i]->variant= g_strdup("");
+       } /* for */
+
+       /* last pointer must be NULL */
+       voices[i] = NULL;
+       return voices;
+} /* rhv_list_voices_new */
+
+void
+rhv_list_voices_free(SPDVoice **voices)
+{
+       if (voices != NULL) {
+               int i = 0;
+               for (i=0; voices[i] != NULL;++i) {
+                       if (voices[i]->name) g_free(voices[i]->name);
+                       if (voices[i]->language) g_free(voices[i]->language);
+                       if (voices[i]->variant) g_free(voices[i]->variant);
+                       g_free(voices[i]);
+               } /* for */
+               g_free(voices);
+       } /* if not null */
+} /* rhv_list_voices_free*/
+
+void
+rhv_msgqueue_free(void)
+{
+       while(rhv_msg_queue != NULL) {
+               rhv_msgqueue_pop();
+       }
+} /* rhv_msgqueue_free */
+
+void
+rhv_msgqueue_pop(void)
+{
+       if (rhv_msg_queue != NULL) {
+               if (rhv_msg_queue->data != NULL) {
+                       if (((RHVMsgEntry*) rhv_msg_queue->data)->msg != NULL)  
{
+                       RHVoice_delete_message(
+                               ((RHVMsgEntry*) rhv_msg_queue->data)->msg);
+                       }
+                       g_free(rhv_msg_queue->data);
+               } /* if data */
+               rhv_msg_queue = g_slist_remove_link(rhv_msg_queue, 
rhv_msg_queue);
+       } /* if queue */
+}
+
+void
+rhv_msgqueue_push(RHVoice_message msg)
+{
+       assert(msg != NULL);
+       RHVMsgEntry *entry = g_try_malloc(sizeof(RHVMsgEntry));
+       if (NULL == entry) {
+               DBG(MODULE_NAME ": unable to create the queue entry.");
+               return;
+       }
+
+       entry->msg = msg;
+       entry->settings = msg_settings;
+       rhv_msg_queue = g_slist_append(rhv_msg_queue, entry);
+} /* rhv_msgqueue_push */
+
+int
+rhv_play_raw(const short* samples, size_t num_samples)
+{
+       AudioTrack track;
+#if defined(BYTE_ORDER) && (BYTE_ORDER == BIG_ENDIAN)
+       AudioFormat format = SPD_AUDIO_BE;
+#else
+       AudioFormat format = SPD_AUDIO_LE;
+#endif
+
+               track.num_samples = num_samples;
+               track.num_channels = RHV_NUM_CHANNELS;
+               track.sample_rate = rhv_samplerate;
+               track.bits = RHV_BITS_PER_SAMPLE;
+               track.samples = (short*)samples;
+
+               return spd_audio_play(module_audio_id, track, format);
+} /* rhv_play_raw */
-- 
1.7.4.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]