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