]> err.no Git - mapper/blob - src/speak.c
Parse directly but update informations in callbacks only if we got a sentence that...
[mapper] / src / speak.c
1 /*
2  * This file is part of mapper
3  *
4  * Copyright (C) 2007 Kaj-Michael Lang
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20
21 #include "config.h"
22
23 #include <string.h>
24 #include <glib.h>
25 #include <glib/gstdio.h>
26
27 #if defined (WITH_GST) && defined (WITH_ESPEAK)
28
29 #include <gst/gst.h>
30 #include <gst/app/gstappsrc.h>
31 #include <gst/app/gstappbuffer.h>
32 #include <gst/app/gstappsink.h>
33 #include <espeak/speak_lib.h>
34
35 #ifndef WITH_DEVICE_770
36 #define AUDIO_SINK "autoaudiosink"
37 #else
38 #define AUDIO_SINK "dsppcmsink"
39 #endif
40
41 #include "speak.h"
42
43 typedef struct _gst_espeak gst_espeak;
44 struct _gst_espeak {
45         GstCaps *srccaps;
46         GstElement *pipeline;
47         GstElement *src;
48         GstElement *queue;
49         GstElement *caps;
50         GstElement *sink;
51         gboolean done;
52         gshort  *buffer;
53         gint size;
54 };
55 static gst_espeak ge;
56
57 static gint erate;
58 static GstBus *bus;
59 static gboolean speaking=FALSE;
60 static gboolean speak_ok;
61 static gboolean espeak_ok;
62
63 static gboolean
64 bus_call (GstBus *bus, GstMessage *msg, gpointer data)
65 {
66 gchar *debug;
67 GError *err;
68
69 switch (GST_MESSAGE_TYPE (msg)) {
70         case GST_MESSAGE_EOS:
71         g_print ("EOS\n");
72                 speaking=FALSE;
73                 speak_ok=TRUE;
74                 speak_stop();
75         break;
76         case GST_MESSAGE_ERROR:
77                 gst_message_parse_error (msg, &err, &debug);
78                 g_free (debug);
79
80                 g_printf ("Error: %s\n", err->message);
81                 g_error_free (err);
82
83                 speak_stop();
84                 speaking=FALSE;
85                 speak_ok=FALSE;
86         break;
87         case GST_MESSAGE_STATE_CHANGED:
88         g_print ("GST: state changed\n");
89         break;
90     default:
91                 g_printf("GST: %s\n", gst_message_type_get_name(GST_MESSAGE_TYPE(msg)));
92         break;
93         }
94 return TRUE;
95 }
96
97 static gboolean
98 speak_create_pipeline(void)
99 {
100 ge.pipeline=gst_pipeline_new("pipeline");
101 ge.src=gst_element_factory_make("appsrc", "source");
102 ge.caps=gst_element_factory_make("capsfilter", "caps");
103 ge.srccaps=gst_caps_new_simple ("audio/x-raw-int",
104                         "depth", G_TYPE_INT, 16,
105                         "signed", G_TYPE_BOOLEAN, TRUE, 
106                         "width", G_TYPE_INT,  16,
107                         "rate", G_TYPE_INT, erate,
108                         "channels", G_TYPE_INT, 1,
109                         NULL);
110
111 ge.queue=gst_element_factory_make("queue", "queue");
112 ge.sink=gst_element_factory_make(AUDIO_SINK, "sink");
113
114 g_assert(ge.pipeline);
115 g_assert(ge.src);
116 g_assert(ge.caps);
117 g_assert(ge.srccaps);
118 g_assert(ge.queue);
119 g_assert(ge.sink);
120
121 g_object_set(ge.caps, "caps", ge.srccaps, NULL);
122
123 gst_bin_add_many (GST_BIN(ge.pipeline), ge.src, ge.queue, ge.sink, NULL);
124
125 if (!gst_element_link_filtered(ge.src, ge.queue, ge.srccaps)) {
126         g_warning ("Failed to link elements 1!");
127         return FALSE;
128 }
129
130 if (!gst_element_link_filtered(ge.queue, ge.sink, ge.srccaps)) {
131         g_warning ("Failed to link elements 2!");
132         return FALSE;
133 }
134
135 return TRUE;
136 }
137
138 static void
139 espeak_buffer_free(void *p)
140 {
141 g_free(p);
142 }
143
144 static int 
145 espeak_cb(short *wav, int numsamples, espeak_EVENT *events)
146 {
147 GstBuffer *buf;
148 gchar *data;
149
150 g_print("Adding buffer %d\n", numsamples);
151
152 if (wav==NULL) {
153         gst_app_src_end_of_stream (GST_APP_SRC (ge.src));
154         return 0;
155 } else if (numsamples>0) {
156         numsamples=numsamples*2;
157         data=g_memdup(wav, numsamples);
158         buf=gst_app_buffer_new (data, numsamples, espeak_buffer_free, data);
159         gst_buffer_set_caps(buf, ge.srccaps);
160         gst_app_src_push_buffer(GST_APP_SRC (ge.src), buf);
161 }
162
163 return 0;
164 }
165
166 void
167 speak_set_parameters(guint speed, guint pitch)
168 {
169 espeak_SetParameter(espeakRATE, speed, 0);
170 espeak_SetParameter(espeakPITCH, pitch, 0);
171 }
172
173 gboolean
174 speak_init(gchar *voice, guint speed, guint pitch)
175 {
176 espeak_ok=FALSE;
177 erate=espeak_Initialize(AUDIO_OUTPUT_RETRIEVAL, 100, NULL, 0);
178 if (erate==-1)
179         return FALSE;
180
181 espeak_SetSynthCallback(espeak_cb);
182 espeak_SetVoiceByName(voice);
183 speak_set_parameters(speed, pitch);
184 espeak_SetParameter(espeakVOLUME, 100, 0);
185 if (speak_create_pipeline()==FALSE)
186         return FALSE;
187
188 bus=gst_pipeline_get_bus(GST_PIPELINE (ge.pipeline));
189 g_assert(bus);
190 gst_bus_add_watch(bus, bus_call, NULL);
191 espeak_ok=TRUE;
192 return TRUE;
193 }
194
195 void
196 speak_deinit(void)
197 {
198 if (espeak_ok==FALSE)
199         return;
200
201 gst_element_set_state(ge.pipeline, GST_STATE_NULL);
202 gst_object_unref(ge.pipeline);
203 ge.pipeline=NULL;
204 speaking=FALSE;
205 espeak_Terminate();
206 }
207
208 gboolean
209 speak_text(gchar *text)
210 {
211 #if 0
212 if (speaking==TRUE)
213         return FALSE;
214 #endif
215
216 g_printf("Speaking: %s (%d)\n", text, strlen(text));
217 espeak_Synth(text, strlen(text)+1, 0, POS_CHARACTER, 0, espeakCHARS_UTF8, NULL, NULL);
218
219 if (speaking!=TRUE) {
220         if (gst_element_set_state (ge.pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
221                 g_print("Failed to play\n");
222                 speaking=FALSE;
223                 return FALSE;
224         }
225         speaking=TRUE;
226 }
227 g_print("Playing...\n");
228 return TRUE;
229 }
230
231 gboolean
232 speak_speaking(void)
233 {
234 return speaking;
235 }
236
237 gboolean
238 speak_stop(void)
239 {
240 if (gst_element_set_state(ge.pipeline, GST_STATE_NULL) == GST_STATE_CHANGE_FAILURE)
241     return FALSE;
242 return TRUE;
243 }
244
245 #else
246
247 gboolean speak_init(gchar voice, guint speed, guint pitch) {return TRUE;}
248 void speak_deinit(void) {}
249 gboolean speak_stop(void) {return TRUE;}
250 gboolean speak_speaking(void) {return FALSE;}
251 void speak_set_parameters(guint speed, guint pitch) {}
252
253 gboolean 
254 speak_text(gchar *text)
255 {
256 #ifdef WITH_ESPEAK
257 #define _voice_synth_path "/usr/bin/espeak"
258 #else
259 #define _voice_synth_path "/usr/bin/flite"
260 #endif
261
262 if (!fork()) {
263         /* We are the fork child.  Synthesize the voice. */
264         sound_noise();
265         sleep(1);
266         printf("%s %s\n", _voice_synth_path, text);
267 #ifdef WITH_ESPEAK
268         execl(_voice_synth_path, _voice_synth_path, "-t", text, (char *)NULL);
269 #else
270         execl(_voice_synth_path, _voice_synth_path, "-s", "150", text, (char *)NULL);
271 #endif
272         exit(0);
273 }
274
275 return TRUE;
276 }
277
278 #endif