[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH 2/2] add pico
From: |
Andrei Kholodnyi |
Subject: |
[PATCH 2/2] add pico |
Date: |
Tue, 28 Sep 2010 00:22:52 +0200 |
Speech Dispatcher output module for SVOX pico synth
---
config/modules/Makefile.am | 5 +
config/modules/pico.conf | 2 +
config/speechd.conf | 1 +
configure.ac | 15 +
src/modules/Makefile.am | 8 +
src/modules/pico.c | 609 ++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 640 insertions(+), 0 deletions(-)
create mode 100644 config/modules/pico.conf
create mode 100644 src/modules/pico.c
diff --git a/config/modules/Makefile.am b/config/modules/Makefile.am
index 50e853a..8632db8 100644
--- a/config/modules/Makefile.am
+++ b/config/modules/Makefile.am
@@ -11,3 +11,8 @@ dist_moduleconforig_DATA = cicero.conf espeak.conf
festival.conf flite.conf \
epos-generic.conf espeak-generic.conf \
espeak-mbrola-generic.conf llia_phon-generic.conf \
swift-generic.conf
+
+if pico_support
+dist_moduleconf_DATA += pico.conf
+dist_moduleconforig_DATA += pico.conf
+endif
diff --git a/config/modules/pico.conf b/config/modules/pico.conf
new file mode 100644
index 0000000..b73e218
--- /dev/null
+++ b/config/modules/pico.conf
@@ -0,0 +1,2 @@
+#PicoLingwarePath "/usr/share/pico/lang/"
+
diff --git a/config/speechd.conf b/config/speechd.conf
index 6eec028..c4eff67 100644
--- a/config/speechd.conf
+++ b/config/speechd.conf
@@ -210,6 +210,7 @@ AddModule "espeak" "sd_espeak" "espeak.conf"
AddModule "festival" "sd_festival" "festival.conf"
#AddModule "flite" "sd_flite" "flite.conf"
#AddModule "ivona" "sd_ivona" "ivona.conf"
+AddModule "pico" "sd_pico" "pico.conf"
#AddModule "espeak-generic" "sd_generic" "espeak-generic.conf"
#AddModule "espeak-mbrola-generic" "sd_generic" "espeak-mbrola-generic.conf"
#AddModule "swift-generic" "sd_generic" "swift-generic.conf"
diff --git a/configure.ac b/configure.ac
index 814d944..296205c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -225,6 +225,21 @@ AC_ARG_WITH(ivona, AS_HELP_STRING(--with-ivona, Compile
with ivona support),
AM_CONDITIONAL(ivona_support, test $ivona_ok = "true")
+AC_ARG_WITH([pico],
+ [AS_HELP_STRING([--with-pico], [include pico SVOX support])],
+ [],
+ [with_pico=check])
+
+# check for pico SVOX support
+AS_IF([test $with_pico != "no"],
+ [AC_CHECK_LIB([ttspico],
+ [pico_initialize],
+ [with_pico=yes],
+ [AS_IF([test $with_pico = "yes"],
+ [AC_MSG_FAILURE([pico SVOX is not available])])])])
+
+AM_CONDITIONAL(pico_support, test $with_pico = "yes")
+
STATIC_AUDIO_PLUGINS_LIST=""
SPD_AUDIO_LIBS=
diff --git a/src/modules/Makefile.am b/src/modules/Makefile.am
index b01b0e0..4359b3a 100644
--- a/src/modules/Makefile.am
+++ b/src/modules/Makefile.am
@@ -70,3 +70,11 @@ sd_ivona_LDADD = $(top_builddir)/src/common/libcommon.la
-lsdaudio \
-ldumbtts -lpthread $(SNDFILE_LIBS) $(DOTCONF_LIBS) $(GLIB_LIBS) \
$(GTHREAD_LIBS)
endif
+
+if pico_support
+modulebin_PROGRAMS += sd_pico
+sd_pico_SOURCES = pico.c $(common_SOURCES)
+sd_pico_LDFLAGS = $(RPATH) '$(spdlibdir)' $(lib_audio)
+sd_pico_LDADD = $(top_builddir)/src/common/libcommon.la -lsdaudio -lttspico \
+ $(DOTCONF_LIBS) $(GLIB_LIBS) $(GTHREAD_LIBS)
+endif
diff --git a/src/modules/pico.c b/src/modules/pico.c
new file mode 100644
index 0000000..32c6850
--- /dev/null
+++ b/src/modules/pico.c
@@ -0,0 +1,609 @@
+/*
+ * pico.c - Speech Dispatcher pico SVOX output module
+ *
+ * A pico SVOX output module
+ *
+ * Copyright (C) 2010 Andrei Kholodnyi <andrei.kholodnyi at gmail.com>
+ *
+ * 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 <stdio.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <string.h>
+
+#include <glib.h>
+#include <semaphore.h>
+
+#include <picoapi.h>
+
+#include "spd_audio.h"
+#include <speechd_types.h>
+#include "module_utils.h"
+
+#define MODULE_NAME "pico"
+#define MODULE_VERSION "0.1"
+
+#define MAX_OUTBUF_SIZE (128)
+#define PICO_MEM_SIZE (10000000)
+
+#define PICO_VOICE_SPEED_MIN (20)
+#define PICO_VOICE_SPEED_MAX (500)
+#define PICO_VOICE_SPEED_DEFAULT (100)
+
+#define PICO_VOICE_PITCH_MIN (50)
+#define PICO_VOICE_PITCH_MAX (200)
+#define PICO_VOICE_PITCH_DEFAULT (100)
+
+#define PICO_VOICE_VOLUME_MIN (0)
+#define PICO_VOICE_VOLUME_MAX (500)
+#define PICO_VOICE_VOLUME_DEFAULT (100)
+
+static pico_System picoSystem;
+static pico_Resource picoTaResource;
+static pico_Resource picoSgResource;
+static pico_Engine picoEngine;
+static pico_Char *picoInp;
+
+static const char * PICO_LINGWARE_PATH = "/usr/share/pico/lang/";
+static const int PICO_SAMPLE_RATE = 16000;
+static const char * picoInternalTaLingware[] = {
+ "en-US_ta.bin",
+ "en-GB_ta.bin",
+ "de-DE_ta.bin",
+ "es-ES_ta.bin",
+ "fr-FR_ta.bin",
+ "it-IT_ta.bin" };
+static const char * picoInternalSgLingware[] = {
+ "en-US_lh0_sg.bin",
+ "en-GB_kh0_sg.bin",
+ "de-DE_gl0_sg.bin",
+ "es-ES_zl0_sg.bin",
+ "fr-FR_nk0_sg.bin",
+ "it-IT_cm0_sg.bin" };
+
+static const VoiceDescription pico_voices[] = {
+ {"samantha", "en", "en-US"},
+ {"serena", "en", "en-GB"},
+ {"sabrina", "de", "de-DE"},
+ {"isabel", "es", "es-ES"},
+ {"virginie", "fr", "fr-FR"},
+ {"silvia", "it", "it-IT"}
+};
+
+static const VoiceDescription *pico_voices_list[] = {
+ &pico_voices[0],
+ &pico_voices[1],
+ &pico_voices[2],
+ &pico_voices[3],
+ &pico_voices[4],
+ &pico_voices[5],
+ NULL
+};
+
+static GThread *pico_play_thread;
+static sem_t *pico_play_semaphore;
+
+enum states {STATE_IDLE, STATE_PLAY, STATE_PAUSE, STATE_STOP, STATE_CLOSE};
+static enum states pico_state;
+
+/* Module configuration options */
+MOD_OPTION_1_STR(PicoLingwarePath)
+
+static int pico_set_rate(signed int value)
+{
+ int speed;
+
+ if (value < 0)
+ speed = PICO_VOICE_SPEED_MIN + (value - (-100))
+ * (PICO_VOICE_SPEED_DEFAULT - PICO_VOICE_SPEED_MIN)
+ / (0 - (-100));
+ else
+ speed = PICO_VOICE_SPEED_DEFAULT + (value - 0)
+ * (PICO_VOICE_SPEED_MAX - PICO_VOICE_SPEED_DEFAULT)
+ / (100 - 0);
+
+ return speed;
+}
+
+static int pico_set_volume(signed int value)
+{
+ int volume;
+
+ if (value < 0)
+ volume = PICO_VOICE_VOLUME_MIN + (value - (-100))
+ * (PICO_VOICE_VOLUME_DEFAULT - PICO_VOICE_VOLUME_MIN)
+ / (0 - (-100));
+ else
+ volume = PICO_VOICE_VOLUME_DEFAULT + (value - 0)
+ * (PICO_VOICE_VOLUME_MAX - PICO_VOICE_VOLUME_DEFAULT)
+ / (100 - 0);
+
+ return volume;
+}
+
+static int pico_set_pitch(signed int value)
+{
+ int pitch;
+
+ if (value < 0)
+ pitch = PICO_VOICE_PITCH_MIN + (value - (-100))
+ * (PICO_VOICE_PITCH_DEFAULT - PICO_VOICE_PITCH_MIN)
+ / (0 - (-100));
+ else
+ pitch = PICO_VOICE_PITCH_DEFAULT + (value - 0)
+ * (PICO_VOICE_PITCH_MAX - PICO_VOICE_PITCH_DEFAULT)
+ / (100 - 0);
+
+ return pitch;
+}
+
+static int pico_process_tts(void)
+{
+ pico_Int16 bytes_sent, bytes_recv, text_remaining, out_data_type;
+ int ret, getstatus;
+ short outbuf[MAX_OUTBUF_SIZE];
+ pico_Retstring outMessage;
+ AudioTrack track;
+ pico_Char *buf = picoInp;
+
+ text_remaining = strlen((const char *) buf) + 1;
+
+ DBG(MODULE_NAME " Text: %s\n", picoInp);
+
+ /* synthesis loop */
+ while (text_remaining) {
+ /* Feed the text into the engine. */
+ if((ret = pico_putTextUtf8(picoEngine, buf, text_remaining,
+ &bytes_sent))) {
+ pico_getSystemStatusMessage(picoSystem, ret,
outMessage);
+ DBG(MODULE_NAME
+ "Cannot put Text (%i): %s\n", ret, outMessage);
+ return -1;
+ }
+
+ text_remaining -= bytes_sent;
+ buf += bytes_sent;
+
+ do {
+ /* Retrieve the samples and add them to the buffer.
+ SVOX pico TTS sample rate is 16K */
+ getstatus = pico_getData(picoEngine, (void *) outbuf,
+ MAX_OUTBUF_SIZE, &bytes_recv, &out_data_type );
+ if((getstatus != PICO_STEP_BUSY)
+ && (getstatus != PICO_STEP_IDLE)){
+ pico_getSystemStatusMessage(picoSystem,
getstatus, outMessage);
+ DBG(MODULE_NAME
+ "Cannot get Data (%i): %s\n", getstatus,
+ outMessage);
+ return -1;
+ }
+
+ if (bytes_recv) {
+ track.num_samples = bytes_recv / 2;
+ track.samples = (short *)
g_memdup((gconstpointer) outbuf, bytes_recv);
+ track.num_channels = 1;
+ track.sample_rate = PICO_SAMPLE_RATE;
+ track.bits = 16;
+ DBG(MODULE_NAME
+ ": Sending %i samples to audio.",
track.num_samples);
+
+ spd_audio_set_volume(module_audio_id, 85);
+ if (spd_audio_play(module_audio_id, track,
+ module_audio_id->format)
< 0) {
+ DBG(MODULE_NAME
+ "Can't play track for unknown
reason.");
+ return -1;
+ }
+ }
+ } while (PICO_STEP_BUSY == getstatus
+ && g_atomic_int_get(&pico_state) == STATE_PLAY);
+
+ }
+
+ g_free(picoInp);
+ picoInp = NULL;
+ return 0;
+}
+
+/* Playback thread. */
+static gpointer
+pico_play_func(gpointer nothing)
+{
+ DBG(MODULE_NAME ": Playback thread starting");
+
+ set_speaking_thread_parameters();
+
+ while (g_atomic_int_get(&pico_state) != STATE_CLOSE) {
+
+ sem_wait(pico_play_semaphore);
+ if (g_atomic_int_get(&pico_state) != STATE_PLAY)
+ continue;
+
+ DBG(MODULE_NAME ": Sending to TTS engine");
+ module_report_event_begin();
+
+ if (0 != pico_process_tts()) {
+ DBG(MODULE_NAME ": ERROR in TTS");
+ }
+
+
+ if (g_atomic_int_get(&pico_state) == STATE_PLAY) {
+ module_report_event_end();
+ g_atomic_int_set(&pico_state, STATE_IDLE);
+ }
+
+ if (g_atomic_int_get(&pico_state) == STATE_STOP) {
+ module_report_event_stop();
+ g_atomic_int_set(&pico_state, STATE_IDLE);
+ }
+
+ if (g_atomic_int_get(&pico_state) == STATE_PAUSE) {
+ module_report_event_pause();
+ g_atomic_int_set(&pico_state, STATE_IDLE);
+ }
+
+ DBG(MODULE_NAME ": state %d", pico_state);
+
+ }
+ return 0;
+}
+
+/* Public functions */
+int module_load(void)
+{
+ INIT_SETTINGS_TABLES();
+
+ MOD_OPTION_1_STR_REG(PicoLingwarePath,PICO_LINGWARE_PATH);
+
+ module_audio_id = NULL;
+
+ return 0;
+}
+
+int pico_init_voice (int voice_index) {
+ int ret;
+ pico_Retstring outMessage;
+ pico_Char picoTaFileName[PICO_MAX_DATAPATH_NAME_SIZE +
PICO_MAX_FILE_NAME_SIZE];
+ pico_Char picoSgFileName[PICO_MAX_DATAPATH_NAME_SIZE +
PICO_MAX_FILE_NAME_SIZE];
+ pico_Char picoTaResourceName[PICO_MAX_RESOURCE_NAME_SIZE];
+ pico_Char picoSgResourceName[PICO_MAX_RESOURCE_NAME_SIZE];
+
+ /* Load the text analysis Lingware resource file. */
+ strcpy((char *) picoTaFileName, PicoLingwarePath);
+ strcat((char *) picoTaFileName,
+ (const char *) picoInternalTaLingware[voice_index]);
+ if((ret = pico_loadResource(picoSystem, picoTaFileName,
&picoTaResource))) {
+ pico_getSystemStatusMessage(picoSystem, ret, outMessage);
+ DBG(MODULE_NAME
+ "Cannot load TA Lingware resource file (%i): %s\n", ret,
+ outMessage);
+ return -1;
+ }
+
+ /* Load the signal generation Lingware resource file. */
+ strcpy((char *) picoSgFileName, PicoLingwarePath);
+ strcat((char *) picoSgFileName,
+ (const char *) picoInternalSgLingware[voice_index]);
+ if((ret = pico_loadResource(picoSystem, picoSgFileName,
&picoSgResource))) {
+ pico_getSystemStatusMessage(picoSystem, ret, outMessage);
+ DBG(MODULE_NAME
+ "Cannot load SG Lingware resource file (%i): %s\n", ret,
+ outMessage);
+ return -1;
+ }
+
+ /* Get the text analysis resource name. */
+ if((ret = pico_getResourceName(picoSystem, picoTaResource,
+ (char *) picoTaResourceName))) {
+ pico_getSystemStatusMessage(picoSystem, ret, outMessage);
+ DBG(MODULE_NAME
+ "Cannot get TA resource name (%i): %s\n", ret,
+ outMessage);
+ return -1;
+ }
+
+ /* Get the signal generation resource name. */
+ if((ret = pico_getResourceName(picoSystem, picoSgResource,
+ (char *) picoSgResourceName))) {
+ pico_getSystemStatusMessage(picoSystem, ret, outMessage);
+ DBG(MODULE_NAME
+ "Cannot get SG resource name (%i): %s\n", ret,
+ outMessage);
+ return -1;
+ }
+
+ /* Create a voice definition. */
+ if((ret = pico_createVoiceDefinition(picoSystem,
+ (const pico_Char *) pico_voices[voice_index].name))) {
+ pico_getSystemStatusMessage(picoSystem, ret, outMessage);
+ DBG(MODULE_NAME
+ "Cannot create voice definition (%i): %s\n", ret,
+ outMessage);
+ return -1;
+ }
+
+ /* Add the text analysis resource to the voice. */
+ if((ret = pico_addResourceToVoiceDefinition(picoSystem,
+ (const pico_Char *)pico_voices[voice_index].name,
+ picoTaResourceName))) {
+ pico_getSystemStatusMessage(picoSystem, ret, outMessage);
+ DBG(MODULE_NAME
+ "Cannot add TA resource to the voice (%i): %s\n",
+ ret, outMessage);
+ return -1;
+ }
+
+ /* Add the signal generation resource to the voice. */
+ if((ret = pico_addResourceToVoiceDefinition(picoSystem,
+ (const pico_Char *)pico_voices[voice_index].name,
+ picoSgResourceName))) {
+ pico_getSystemStatusMessage(picoSystem, ret, outMessage);
+ DBG(MODULE_NAME
+ "Cannot add SG resource to the voice (%i): %s\n",
+ ret, outMessage);
+ return -1;
+ }
+
+ return 0;
+}
+
+int module_init(char **status_info)
+{
+ int ret, i;
+ pico_Retstring outMessage;
+ void * pmem;
+ GError *error = NULL;
+
+ if (!g_thread_supported())
+ g_thread_init(NULL);
+
+ pico_play_semaphore = module_semaphore_init();
+ if (pico_play_semaphore == NULL) {
+ *status_info = g_strdup_printf(MODULE_NAME
+ "Failed to initialize play thread semaphore!");
+ DBG(MODULE_NAME": %s", *status_info);
+ return -1;
+ }
+
+ if ((pico_play_thread = g_thread_create((GThreadFunc)pico_play_func,
+ NULL, TRUE, &error)) == NULL) {
+ *status_info = g_strdup_printf(MODULE_NAME
+ "Failed to create a play thread : %s\n",
+ error->message );
+ DBG(MODULE_NAME": %s", *status_info);
+ g_error_free(error);
+ return -1;
+ }
+
+ pmem = g_malloc(PICO_MEM_SIZE);
+ if((ret = pico_initialize(pmem, PICO_MEM_SIZE, &picoSystem))) {
+ pico_getSystemStatusMessage(picoSystem, ret, outMessage);
+ *status_info = g_strdup_printf(MODULE_NAME
+ ": Cannot initialize (%i): %s\n", ret, outMessage);
+ g_free(pmem);
+ return -1;
+ }
+
+ /* load resource for all language, probably need only one */
+ for (i = 0; i < sizeof(pico_voices)/sizeof(VoiceDescription); i++) {
+ if (0 != pico_init_voice(i)) {
+ g_free(pmem);
+ *status_info = g_strdup_printf(MODULE_NAME
+ ": fail init voice (%s)\n",
pico_voices[i].name);
+ return -1;
+ }
+ }
+
+ /* Create a new Pico engine, english default */
+ if((ret = pico_newEngine(picoSystem,
+ (const pico_Char *)pico_voices[0].name,
+ &picoEngine))) {
+ pico_getSystemStatusMessage(picoSystem, ret, outMessage);
+ DBG(MODULE_NAME
+ "Cannot create a new pico engine (%i): %s\n", ret,
+ outMessage);
+ return -1;
+ }
+
+ *status_info = g_strdup(MODULE_NAME ": Initialized successfully.");
+
+ g_atomic_int_set(&pico_state, STATE_IDLE);
+ return 0;
+}
+
+int module_audio_init(char **status_info)
+{
+ return module_audio_init_spd(status_info);
+}
+
+VoiceDescription **module_list_voices(void)
+{
+ return pico_voices_list;
+}
+
+void pico_set_synthesis_voice(char *voice_name)
+{
+ int ret;
+ pico_Retstring outMessage;
+
+ /* Create a new Pico engine, english default */
+ if((ret = pico_disposeEngine(picoSystem, &picoEngine))) {
+ pico_getSystemStatusMessage(picoSystem, ret, outMessage);
+ DBG(MODULE_NAME
+ "Cannot dispose pico engine (%i): %s\n", ret,
+ outMessage);
+ return;
+ }
+
+ /* Create a new Pico engine, english default */
+ if((ret = pico_newEngine(picoSystem, (const pico_Char *)voice_name,
+ &picoEngine))) {
+ pico_getSystemStatusMessage(picoSystem, ret, outMessage);
+ DBG(MODULE_NAME
+ "Cannot create a new pico engine (%i): %s\n", ret,
+ outMessage);
+ return;
+ }
+
+ return;
+}
+
+static void pico_set_language(char *lang)
+{
+ int i;
+
+ /* get voice name based on language */
+ for (i = 0; i < sizeof(pico_voices)/sizeof(VoiceDescription); i++) {
+ if (!strcmp(pico_voices[i].language,lang)) {
+ pico_set_synthesis_voice(pico_voices[i].name);
+ return;
+ }
+ }
+ return;
+}
+
+int module_speak(char * data, size_t bytes, EMessageType msgtype)
+{
+ int value;
+ static pico_Char *tmp;
+
+ if (g_atomic_int_get(&pico_state) != STATE_IDLE){
+ DBG(MODULE_NAME
+ ": module still speaking state = %d", pico_state);
+ return 0;
+ }
+
+ /* Setting speech parameters. */
+
+ UPDATE_STRING_PARAMETER(synthesis_voice, pico_set_synthesis_voice);
+/* UPDATE_PARAMETER(voice_type, pico_set_voice);*/
+ UPDATE_STRING_PARAMETER(language, pico_set_language);
+
+ picoInp = (pico_Char *) module_strip_ssml(data);
+
+ value = pico_set_rate(msg_settings.rate);
+ if (PICO_VOICE_SPEED_DEFAULT != value) {
+ tmp = picoInp;
+ picoInp = (pico_Char *) g_strdup_printf(
+ "<speed level='%d'>%s</speed>", value, tmp);
+ g_free(tmp);
+ }
+
+ value = pico_set_volume(msg_settings.volume);
+ if (PICO_VOICE_VOLUME_DEFAULT != value) {
+ tmp = picoInp;
+ picoInp = (pico_Char *) g_strdup_printf(
+ "<volume level='%d'>%s</volume>", value, tmp);
+ g_free(tmp);
+ }
+
+ value = pico_set_pitch(msg_settings.pitch);
+ if (PICO_VOICE_PITCH_DEFAULT != value) {
+ tmp = picoInp;
+ picoInp = (pico_Char *) g_strdup_printf(
+ "<pitch level='%d'>%s</pitch>", value, tmp);
+ g_free(tmp);
+ }
+
+/* switch (msgtype) {
+ case SPD_MSGTYPE_CHAR:
+ case SPD_MSGTYPE_KEY:
+ case SPD_MSGTYPE_TEXT:
+ case SPD_MSGTYPE_SOUND_ICON:
+ default:
+ DBG(MODULE_NAME
+ ": msgtype = %d", msgtype);
+ break;
+ }
+*/
+ g_atomic_int_set(&pico_state, STATE_PLAY);
+ sem_post(pico_play_semaphore);
+ return bytes;
+}
+
+int module_stop(void)
+{
+ pico_Status ret;
+ pico_Retstring outMessage;
+
+ if (g_atomic_int_get(&pico_state) != STATE_PLAY){
+ DBG(MODULE_NAME
+ ": STOP called when not in PLAY state");
+ return -1;
+ }
+
+ g_atomic_int_set(&pico_state, STATE_STOP);
+
+ /* reset Pico engine. */
+ if((ret = pico_resetEngine(picoEngine, PICO_RESET_SOFT))) {
+ pico_getSystemStatusMessage(picoSystem, ret, outMessage);
+ DBG(MODULE_NAME
+ "Cannot reset pico engine (%i): %s\n", ret, outMessage);
+ return -1;
+ }
+
+ return 0;
+}
+
+size_t module_pause(void)
+{
+ pico_Status ret;
+ pico_Retstring outMessage;
+
+ if (g_atomic_int_get(&pico_state) != STATE_PLAY){
+ DBG(MODULE_NAME
+ ": PAUSE called when not in PLAY state");
+ return -1;
+ }
+
+ g_atomic_int_set(&pico_state, STATE_PAUSE);
+
+ /* reset Pico engine. */
+ if((ret = pico_resetEngine(picoEngine, PICO_RESET_SOFT))) {
+ pico_getSystemStatusMessage(picoSystem, ret, outMessage);
+ DBG(MODULE_NAME
+ "Cannot reset pico engine (%i): %s\n", ret, outMessage);
+ return -1;
+ }
+
+ return 0;
+}
+
+void module_close(int status)
+{
+ if (module_audio_id) {
+ spd_audio_close(module_audio_id);
+ }
+
+ g_atomic_int_set(&pico_state, STATE_CLOSE);
+ sem_post(pico_play_semaphore);
+
+ g_thread_join(pico_play_thread);
+
+ if (picoSystem) {
+ pico_terminate(&picoSystem);
+ picoSystem = NULL;
+ }
+
+ g_free(pico_play_semaphore);
+}
--
1.6.0.4