speechd-discuss
[Top][All Lists]
Advanced

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

[PATCH 10/10] Native SSM output module for OS X


From: Boris Dušek
Subject: [PATCH 10/10] Native SSM output module for OS X
Date: Mon, 23 Jul 2012 15:24:21 +0200

From: Boris Dus?ek <address@hidden>
To: address@hidden

SSM is Speech Synthesis Manager, the API for speech synthesis on OS X.
---
 src/modules/Makefile.am |    6 ++
 src/modules/ssm.c       |  206 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 212 insertions(+), 0 deletions(-)
 create mode 100644 src/modules/ssm.c

diff --git a/src/modules/Makefile.am b/src/modules/Makefile.am
index 9012a4b..c241c90 100644
--- a/src/modules/Makefile.am
+++ b/src/modules/Makefile.am
@@ -82,3 +82,9 @@ sd_pico_LDADD = $(top_builddir)/src/common/libcommon.la \
        $(audio_dlopen_modules) -lttspico \
        $(common_LDADD)
 endif
+
+modulebin_PROGRAMS += sd_ssm
+sd_ssm_SOURCES = ssm.c $(audio_SOURCES) $(common_SOURCES)
+sd_ssm_LDADD = $(top_builddir)/src/common/libcommon.la \
+               $(audio_dlopen_modules) \
+               $(DOTCONF_LIBS) $(GLIB_LIBS) $(GTHREAD_LIBS)
diff --git a/src/modules/ssm.c b/src/modules/ssm.c
new file mode 100644
index 0000000..31d1a8b
--- /dev/null
+++ b/src/modules/ssm.c
@@ -0,0 +1,206 @@
+/*
+ * ssm.c - Speech Dispatcher SSM (Apple Speech Synthesis Manager) output module
+ *
+ * Copyright (C) 2011 Brailcom, o.p.s.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1, 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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 "module_utils.h"
+#include <ApplicationServices/ApplicationServices.h>
+
+#define MODULE_NAME     "ssm"
+#define MODULE_VERSION  "0.1"
+
+DECLARE_DEBUG();
+
+#define DOTRACE 1
+#ifdef DOTRACE
+#define TRACE(funcname) DBG("TRACE %s:%04d:%s\n", __FILE__, __LINE__, 
#funcname);
+#else
+#define TRACE(funcname)
+#endif
+
+#define REPORT_(err, funcname, final) do {\
+    DBG(MODULE_NAME ": failed at %s:%d:%s\n", __FILE__, __LINE__, funcname);\
+} while(0)
+#define REPORT(funcname) REPORT_(err, funcname, false)
+#define REPORT_FINAL(funcname) REPORT_(err, funcname, true)
+// CHECK(funcname, arg1, arg2, ...) { ... }
+#define CHECK_(err, funcname, final, ...)\
+    TRACE(funcname);\
+    if ((err = funcname(__VA_ARGS__)))\
+        REPORT_(err, #funcname, final);\
+    else
+#define CHECK(funcname, ...) CHECK_(err, funcname, false, __VA_ARGS__)
+#define CHECK_FINAL(funcname, ...) CHECK_(err, funcname, true, __VA_ARGS__)
+
+static SpeechChannel s_speech_channel;
+static char *s_spoken_string;
+static int s_first_word;
+
+int module_load(void) {
+       INIT_SETTINGS_TABLES();
+
+       MOD_OPTION_1_INT_REG(Debug, 0);
+
+       return 0;
+}
+
+static void SSMSpeechWordProc (SpeechChannel chan, SRefCon refCon, unsigned 
long wordPos, unsigned short wordLen) {
+       if (s_first_word) {
+               s_first_word = 0;
+               module_report_event_begin();
+       }
+}
+
+static void SSMSpeechDoneProc (SpeechChannel chan, long refCon) {
+       module_report_event_end();
+}
+
+int module_init(char **status_info) {
+       OSErr err = noErr;
+       int ret = -1;
+
+       s_spoken_string = 0;
+
+       TRACE(NewSpeechChannel);
+       if (noErr != (err = NewSpeechChannel(NULL, &s_speech_channel))) {
+               *status_info = g_strdup_printf(MODULE_NAME
+                       ": Cannot create speech channel: OSErr %d\n", err);
+               REPORT("NewSpeechChannel");
+       } else {
+               CHECK(SetSpeechInfo, s_speech_channel, soWordCallBack, 
SSMSpeechWordProc) {
+                       CHECK(SetSpeechInfo, s_speech_channel, 
soSpeechDoneCallBack, SSMSpeechDoneProc) {
+                               ret = 0;
+                       }
+               }
+       }
+
+       return ret;
+}
+
+static OSErr VoiceDescriptionToSPDVoice(VoiceDescription *voice_desc, SPDVoice 
**pVoice) {
+       OSErr err = noErr;
+       const char *const voice_name_buf = ((char *)voice_desc->name + 1);
+       const size_t voice_name_len = voice_name_buf[-1];
+       SPDVoice *voice = NULL;
+
+       voice = malloc(sizeof(SPDVoice));
+       voice->name = malloc(voice_name_buf[-1] + 1);
+       memcpy(voice->name, voice_name_buf, voice_name_len);
+       voice->name[voice_name_len] = '\0';
+       /*TODO*/
+       voice->language = g_strdup("en");
+       voice->variant = g_strdup("en-US");
+
+       *pVoice = voice;
+
+       return err;
+}
+
+SPDVoice **module_list_voices(void) {
+       OSErr err = noErr;
+       int i;
+
+       SInt16 nVoices;
+       VoiceSpec voice_spec;
+       VoiceDescription voice_desc;
+
+       SPDVoice **voices = 0;
+
+       CHECK(CountVoices, &nVoices) {
+               voices = malloc((nVoices + 1) * (sizeof (SPDVoice*)));
+               for (i = 0; i < nVoices + 1; ++i)
+                       voices[i] = NULL;
+               for (i = 0; (i < nVoices) && (noErr == err); ++i) {
+                       CHECK(GetIndVoice, i+1, &voice_spec) {
+                               CHECK(GetVoiceDescription, (&voice_spec), 
(&voice_desc), (sizeof(VoiceDescription))) {
+                                       CHECK(VoiceDescriptionToSPDVoice, 
&voice_desc, &voices[i]) {
+                                               /* voice with index i 
successfully converted to SPDVoice
+                                                * continue with next voice
+                                                */
+                                       }
+                               }
+                       }
+               }
+               if (noErr != err) {
+                       for (i = 0; i < nVoices; ++i) {
+                               if (voices[i]) {
+                                       free(voices[i]->name);
+                                       free(voices[i]->language);
+                                       free(voices[i]->variant);
+                                       free(voices);
+                               }
+                       }
+                       free(voices);
+                       voices = NULL;
+               }
+       }
+       return voices;
+}
+
+int module_speak(char * data, size_t bytes, SPDMessageType msgtype) {
+       OSErr err = noErr;
+       int ret = -1;
+       
+       free(s_spoken_string);
+       s_spoken_string = module_strip_ssml(data);
+
+       s_first_word = 1;
+
+       CHECK(SpeakText, s_speech_channel, s_spoken_string, 
strlen(s_spoken_string)) {
+               ret = bytes;
+       }
+
+       return ret;
+}
+
+int module_stop(void) {
+       int ret = -1;
+       OSErr err = noErr;
+
+       CHECK(StopSpeech, s_speech_channel) {
+               ret = 0;
+       }
+
+       return ret;
+}
+
+size_t module_pause(void) {
+       int ret = -1;
+       OSErr err = noErr;
+
+       /* this would lead to deadlock, and we have no other place to call
+        * the reporting function
+        */
+       /*module_report_event_pause();*/
+
+       CHECK(PauseSpeechAt, s_speech_channel, kImmediate) {
+               ret = 0;
+       }
+
+       return ret;
+}
+
+int module_close(void) {
+       DisposeSpeechChannel(s_speech_channel);
+       return 0;
+}
-- 
1.7.7.5 (Apple Git-26)




reply via email to

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