[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:22:35 +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)
- [PATCH 01/10] Remove references to TEMP_FAILURE_RETRY, Boris Dušek, 2012/07/23
- [PATCH 02/10] Do not exit on localization init fail, Boris Dušek, 2012/07/23
- [PATCH 03/10] Fix termination of threads in spd_close, Boris Dušek, 2012/07/23
- [PATCH 04/10] Cleanup execution of commands in dummy, Boris Dušek, 2012/07/23
- [PATCH 05/10] Fix audio module dynamic opening on OS X, Boris Dušek, 2012/07/23
- [PATCH 06/10] Use afplay and libao for playing sound on OS X in dummy, Boris Dušek, 2012/07/23
- [PATCH 07/10] Abstract unnamed semaphore interface and add OS X implementation, Boris Dušek, 2012/07/23
- [PATCH 08/10] Use launchd on OS X for launching the server, Boris Dušek, 2012/07/23
- [PATCH 09/10] Installation instructions for OS X, Boris Dušek, 2012/07/23
- [PATCH 10/10] Native SSM output module for OS X,
Boris Dušek <=
- [PATCH 01/10] Remove references to TEMP_FAILURE_RETRY, Boris Dušek, 2012/07/23
- [PATCH 02/10] Do not exit on localization init fail, Boris Dušek, 2012/07/23
- [PATCH 03/10] Fix termination of threads in spd_close, Boris Dušek, 2012/07/23
- [PATCH 04/10] Cleanup execution of commands in dummy, Boris Dušek, 2012/07/23
- [PATCH 05/10] Fix audio module dynamic opening on OS X, Boris Dušek, 2012/07/23
- [PATCH 06/10] Use afplay and libao for playing sound on OS X in dummy, Boris Dušek, 2012/07/23
- [PATCH 07/10] Abstract unnamed semaphore interface and add OS X implementation, Boris Dušek, 2012/07/23