]> err.no Git - mapper/blob - src/speak.c
Call espeak terminate on deinit. Add helper to set pitch and speed.
[mapper] / src / speak.c
1 #include "config.h"
2
3 #include <string.h>
4 #include <glib.h>
5 #include <glib/gstdio.h>
6
7 #if defined (WITH_GST) && defined (WITH_ESPEAK)
8
9 #include <gst/gst.h>
10 #include <gst/app/gstappsrc.h>
11 #include <gst/app/gstappbuffer.h>
12 #include <gst/app/gstappsink.h>
13 #include <espeak/speak_lib.h>
14
15 #ifndef WITH_DEVICE_770
16 #define AUDIO_SINK "autoaudiosink"
17 #else
18 #define AUDIO_SINK "dsppcmsink"
19 #endif
20
21 #include "speak.h"
22
23 typedef struct _gst_espeak gst_espeak;
24 struct _gst_espeak {
25         GstCaps *srccaps;
26         GstElement *pipeline;
27         GstElement *src;
28         GstElement *queue;
29         GstElement *caps;
30         GstElement *sink;
31         gboolean done;
32         gshort  *buffer;
33         gint size;
34 };
35 static gst_espeak ge;
36
37 static gint erate;
38 static GstBus *bus;
39 static gboolean speaking=FALSE;
40 static gboolean speak_ok;
41
42 static gboolean
43 bus_call (GstBus *bus, GstMessage *msg, gpointer data)
44 {
45 gchar *debug;
46 GError *err;
47
48 switch (GST_MESSAGE_TYPE (msg)) {
49         case GST_MESSAGE_EOS:
50         g_print ("EOS\n");
51                 speaking=FALSE;
52                 speak_ok=TRUE;
53                 speak_stop();
54         break;
55         case GST_MESSAGE_ERROR:
56                 gst_message_parse_error (msg, &err, &debug);
57                 g_free (debug);
58
59                 g_printf ("Error: %s\n", err->message);
60                 g_error_free (err);
61
62                 speak_stop();
63                 speaking=FALSE;
64                 speak_ok=FALSE;
65         break;
66         case GST_MESSAGE_STATE_CHANGED:
67
68         break;
69     default:
70                 g_printf("GST: %s\n", gst_message_type_get_name(GST_MESSAGE_TYPE(msg)));
71         break;
72         }
73 return TRUE;
74 }
75
76 static gboolean
77 speak_create_pipeline(void)
78 {
79 ge.pipeline=gst_pipeline_new("pipeline");
80 ge.src=gst_element_factory_make("appsrc", "source");
81 ge.caps=gst_element_factory_make("capsfilter", "caps");
82 ge.srccaps=gst_caps_new_simple ("audio/x-raw-int",
83                         "depth", G_TYPE_INT, 16,
84                         "signed", G_TYPE_BOOLEAN, TRUE, 
85                         "width", G_TYPE_INT,  16,
86                         "rate", G_TYPE_INT, erate,
87                         "channels", G_TYPE_INT, 1,
88                         NULL);
89
90 ge.queue=gst_element_factory_make("queue", "queue");
91 ge.sink=gst_element_factory_make(AUDIO_SINK, "sink");
92
93 g_assert(ge.pipeline);
94 g_assert(ge.src);
95 g_assert(ge.caps);
96 g_assert(ge.srccaps);
97 g_assert(ge.queue);
98 g_assert(ge.sink);
99
100 g_object_set(ge.caps, "caps", ge.srccaps, NULL);
101
102 gst_bin_add_many (GST_BIN(ge.pipeline), ge.src, ge.queue, ge.sink, NULL);
103
104 if (!gst_element_link_filtered(ge.src, ge.queue, ge.srccaps)) {
105         g_warning ("Failed to link elements 1!");
106         return FALSE;
107 }
108
109 if (!gst_element_link_filtered(ge.queue, ge.sink, ge.srccaps)) {
110         g_warning ("Failed to link elements 2!");
111         return FALSE;
112 }
113
114 return TRUE;
115 }
116
117 static void
118 espeak_buffer_free(void *p)
119 {
120 g_free(p);
121 }
122
123 static int 
124 espeak_cb(short *wav, int numsamples, espeak_EVENT *events)
125 {
126 GstBuffer *buf;
127 gchar *data;
128
129 g_print("Adding buffer %d\n", numsamples);
130
131 if (wav==NULL) {
132         gst_app_src_end_of_stream (GST_APP_SRC (ge.src));
133         return 0;
134 } else if (numsamples>0) {
135         numsamples=numsamples*2;
136         data=g_memdup(wav, numsamples);
137         buf=gst_app_buffer_new (data, numsamples, espeak_buffer_free, data);
138         gst_buffer_set_caps(buf, ge.srccaps);
139         gst_app_src_push_buffer(GST_APP_SRC (ge.src), buf);
140 }
141
142 return 0;
143 }
144
145 void
146 speak_set_parameters(guint speed, guint pitch)
147 {
148 espeak_SetParameter(espeakRATE, speed, 0);
149 espeak_SetParameter(espeakPITCH, pitch, 0);
150 }
151
152 gboolean
153 speak_init(gchar *voice, guint speed, guint pitch)
154 {
155 erate=espeak_Initialize(AUDIO_OUTPUT_RETRIEVAL, 100, NULL, 0);
156 if (erate==-1)
157         return FALSE;
158
159 espeak_SetSynthCallback(espeak_cb);
160 espeak_SetVoiceByName(voice);
161 speak_set_parameters(speed, pitch);
162 espeak_SetParameter(espeakVOLUME, 100, 0);
163 if (speak_create_pipeline()==FALSE)
164         return FALSE;
165
166 bus=gst_pipeline_get_bus(GST_PIPELINE (ge.pipeline));
167 g_assert(bus);
168 gst_bus_add_watch(bus, bus_call, NULL);
169
170 return TRUE;
171 }
172
173 void
174 speak_deinit(void)
175 {
176 gst_element_set_state(ge.pipeline, GST_STATE_NULL);
177 gst_object_unref(ge.pipeline);
178 ge.pipeline=NULL;
179 speaking=FALSE;
180 espeak_Terminate();
181 }
182
183 gboolean
184 speak_text(gchar *text)
185 {
186 if (speaking==TRUE)
187         return FALSE;
188
189 g_printf("Speaking: %s (%d)\n", text, strlen(text));
190 espeak_Synth(text, strlen(text)+1, 0, POS_CHARACTER, 0, espeakCHARS_UTF8, NULL, NULL);
191
192 if (gst_element_set_state (ge.pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
193         g_print("Failed to play\n");
194         speaking=FALSE;
195         return FALSE;
196 }
197 speaking=TRUE;
198 g_print("Playing...\n");
199 return TRUE;
200 }
201
202 gboolean
203 speak_speaking(void)
204 {
205 return speaking;
206 }
207
208 gboolean
209 speak_stop(void)
210 {
211 if (gst_element_set_state(ge.pipeline, GST_STATE_NULL) == GST_STATE_CHANGE_FAILURE)
212     return FALSE;
213 return TRUE;
214 }
215
216 #else
217
218 gboolean speak_init(gchar voice, guint speed, guint pitch) {return TRUE;}
219 void speak_deinit(void) {}
220 gboolean speak_stop(void) {return TRUE;}
221 gboolean speak_speaking(void) {return FALSE;}
222 void speak_set_parameters(guint speed, guint pitch) {}
223
224 gboolean 
225 speak_text(gchar *text)
226 {
227 #ifdef WITH_ESPEAK
228 #define _voice_synth_path "/usr/bin/espeak"
229 #else
230 #define _voice_synth_path "/usr/bin/flite"
231 #endif
232
233 if (!fork()) {
234         /* We are the fork child.  Synthesize the voice. */
235         sound_noise();
236         sleep(1);
237         printf("%s %s\n", _voice_synth_path, text);
238 #ifdef WITH_ESPEAK
239         execl(_voice_synth_path, _voice_synth_path, "-t", text, (char *)NULL);
240 #else
241         execl(_voice_synth_path, _voice_synth_path, "-s", "150", text, (char *)NULL);
242 #endif
243         exit(0);
244 }
245
246 return TRUE;
247 }
248
249 #endif