1 /* GStreamer
2 * Copyright (C) 2010 David Schleef <ds@schleef.org>
3 * Copyright (C) 2005 Stefan Kost <ensonic@users.sf.net>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <gst/gst.h>
26 #include <gst/base/gstbasesrc.h>
27 #include <gst/base/gstadapter.h>
28 #include <gst/audio/audio.h>
29
30 #include <flite/flite.h>
31
32 #define GST_TYPE_FLITE_TEST_SRC \
33 (gst_flite_test_src_get_type())
34 #define GST_FLITE_TEST_SRC(obj) \
35 (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FLITE_TEST_SRC,GstFliteTestSrc))
36 #define GST_FLITE_TEST_SRC_CLASS(klass) \
37 (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FLITE_TEST_SRC,GstFliteTestSrcClass))
38 #define GST_IS_FLITE_TEST_SRC(obj) \
39 (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FLITE_TEST_SRC))
40 #define GST_IS_FLITE_TEST_SRC_CLASS(klass) \
41 (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FLITE_TEST_SRC))
42
43 typedef struct _GstFliteTestSrc GstFliteTestSrc;
44 typedef struct _GstFliteTestSrcClass GstFliteTestSrcClass;
45
46 struct _GstFliteTestSrc
47 {
48 GstBaseSrc parent;
49
50 GstAdapter *adapter;
51
52 GstAudioInfo info;
53
54 int samples_per_buffer;
55
56 int channel;
57
58 cst_voice *voice;
59 };
60
61 struct _GstFliteTestSrcClass
62 {
63 GstBaseSrcClass parent_class;
64 };
65
66 GType gst_flite_test_src_get_type (void);
67
68
69
70 GST_DEBUG_CATEGORY_STATIC (flite_test_src_debug);
71 #define GST_CAT_DEFAULT flite_test_src_debug
72
73 #define DEFAULT_SAMPLES_PER_BUFFER 1024
74
75 enum
76 {
77 PROP_0,
78 PROP_SAMPLES_PER_BUFFER,
79 PROP_LAST
80 };
81
82
83 static GstStaticPadTemplate gst_flite_test_src_src_template =
84 GST_STATIC_PAD_TEMPLATE ("src",
85 GST_PAD_SRC,
86 GST_PAD_ALWAYS,
87 GST_STATIC_CAPS ("audio/x-raw, "
88 "format = (string) " GST_AUDIO_NE (S16) ", "
89 "layout = (string) interleaved, "
90 "rate = (int) 48000, " "channels = (int) [1, 8]")
91 );
92
93 #define gst_flite_test_src_parent_class parent_class
94 G_DEFINE_TYPE (GstFliteTestSrc, gst_flite_test_src, GST_TYPE_BASE_SRC);
95
96 static void gst_flite_test_src_set_property (GObject * object,
97 guint prop_id, const GValue * value, GParamSpec * pspec);
98 static void gst_flite_test_src_get_property (GObject * object,
99 guint prop_id, GValue * value, GParamSpec * pspec);
100
101 static gboolean gst_flite_test_src_start (GstBaseSrc * basesrc);
102 static gboolean gst_flite_test_src_stop (GstBaseSrc * basesrc);
103 static GstFlowReturn gst_flite_test_src_create (GstBaseSrc * basesrc,
104 guint64 offset, guint length, GstBuffer ** buffer);
105 static gboolean
106 gst_flite_test_src_set_caps (GstBaseSrc * basesrc, GstCaps * caps);
107 static GstCaps *gst_flite_test_src_fixate (GstBaseSrc * bsrc, GstCaps * caps);
108
109 static void
gst_flite_test_src_class_init(GstFliteTestSrcClass * klass)110 gst_flite_test_src_class_init (GstFliteTestSrcClass * klass)
111 {
112 GObjectClass *gobject_class;
113 GstElementClass *gstelement_class;
114 GstBaseSrcClass *gstbasesrc_class;
115
116 gobject_class = (GObjectClass *) klass;
117 gstelement_class = (GstElementClass *) klass;
118 gstbasesrc_class = (GstBaseSrcClass *) klass;
119
120 gobject_class->set_property = gst_flite_test_src_set_property;
121 gobject_class->get_property = gst_flite_test_src_get_property;
122
123 g_object_class_install_property (gobject_class, PROP_SAMPLES_PER_BUFFER,
124 g_param_spec_int ("samplesperbuffer", "Samples per buffer",
125 "Number of samples in each outgoing buffer",
126 1, G_MAXINT, DEFAULT_SAMPLES_PER_BUFFER,
127 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
128
129 gst_element_class_add_static_pad_template (gstelement_class,
130 &gst_flite_test_src_src_template);
131
132 gst_element_class_set_static_metadata (gstelement_class,
133 "Flite speech test source", "Source/Audio",
134 "Creates audio test signals identifying channels",
135 "David Schleef <ds@schleef.org>");
136
137 gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_flite_test_src_start);
138 gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_flite_test_src_stop);
139 gstbasesrc_class->create = GST_DEBUG_FUNCPTR (gst_flite_test_src_create);
140 gstbasesrc_class->set_caps = GST_DEBUG_FUNCPTR (gst_flite_test_src_set_caps);
141 gstbasesrc_class->fixate = GST_DEBUG_FUNCPTR (gst_flite_test_src_fixate);
142
143 GST_DEBUG_CATEGORY_INIT (flite_test_src_debug, "flitetestsrc", 0,
144 "Flite Audio Test Source");
145 }
146
147 static void
gst_flite_test_src_init(GstFliteTestSrc * src)148 gst_flite_test_src_init (GstFliteTestSrc * src)
149 {
150 src->samples_per_buffer = DEFAULT_SAMPLES_PER_BUFFER;
151
152 /* we operate in time */
153 gst_base_src_set_format (GST_BASE_SRC (src), GST_FORMAT_TIME);
154
155 gst_base_src_set_blocksize (GST_BASE_SRC (src), -1);
156 }
157
158 static gint
n_bits_set(guint64 x)159 n_bits_set (guint64 x)
160 {
161 gint i;
162 gint c = 0;
163 guint64 y = 1;
164
165 for (i = 0; i < 64; i++) {
166 if (x & y)
167 c++;
168 y <<= 1;
169 }
170
171 return c;
172 }
173
174 static GstCaps *
gst_flite_test_src_fixate(GstBaseSrc * bsrc,GstCaps * caps)175 gst_flite_test_src_fixate (GstBaseSrc * bsrc, GstCaps * caps)
176 {
177 GstStructure *structure;
178 gint channels;
179
180 caps = gst_caps_truncate (caps);
181 caps = gst_caps_make_writable (caps);
182
183 structure = gst_caps_get_structure (caps, 0);
184
185 gst_structure_fixate_field_nearest_int (structure, "channels", 2);
186 gst_structure_get_int (structure, "channels", &channels);
187
188 if (channels == 1) {
189 gst_structure_remove_field (structure, "channel-mask");
190 } else {
191 guint64 channel_mask = 0;
192 gint x = 63;
193
194 if (!gst_structure_get (structure, "channel-mask", GST_TYPE_BITMASK,
195 &channel_mask, NULL)) {
196 switch (channels) {
197 case 8:
198 channel_mask =
199 GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_LEFT) |
200 GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_RIGHT) |
201 GST_AUDIO_CHANNEL_POSITION_MASK (REAR_LEFT) |
202 GST_AUDIO_CHANNEL_POSITION_MASK (REAR_RIGHT) |
203 GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_CENTER) |
204 GST_AUDIO_CHANNEL_POSITION_MASK (LFE1) |
205 GST_AUDIO_CHANNEL_POSITION_MASK (SIDE_LEFT) |
206 GST_AUDIO_CHANNEL_POSITION_MASK (SIDE_RIGHT);
207 break;
208 case 7:
209 channel_mask =
210 GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_LEFT) |
211 GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_RIGHT) |
212 GST_AUDIO_CHANNEL_POSITION_MASK (REAR_LEFT) |
213 GST_AUDIO_CHANNEL_POSITION_MASK (REAR_RIGHT) |
214 GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_CENTER) |
215 GST_AUDIO_CHANNEL_POSITION_MASK (LFE1) |
216 GST_AUDIO_CHANNEL_POSITION_MASK (REAR_CENTER);
217 break;
218 case 6:
219 channel_mask =
220 GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_LEFT) |
221 GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_RIGHT) |
222 GST_AUDIO_CHANNEL_POSITION_MASK (REAR_LEFT) |
223 GST_AUDIO_CHANNEL_POSITION_MASK (REAR_RIGHT) |
224 GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_CENTER) |
225 GST_AUDIO_CHANNEL_POSITION_MASK (LFE1);
226 break;
227 case 5:
228 channel_mask =
229 GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_LEFT) |
230 GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_RIGHT) |
231 GST_AUDIO_CHANNEL_POSITION_MASK (REAR_LEFT) |
232 GST_AUDIO_CHANNEL_POSITION_MASK (REAR_RIGHT) |
233 GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_CENTER);
234 break;
235 case 4:
236 channel_mask =
237 GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_LEFT) |
238 GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_RIGHT) |
239 GST_AUDIO_CHANNEL_POSITION_MASK (REAR_LEFT) |
240 GST_AUDIO_CHANNEL_POSITION_MASK (REAR_RIGHT);
241 break;
242 case 3:
243 channel_mask =
244 GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_LEFT) |
245 GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_RIGHT) |
246 GST_AUDIO_CHANNEL_POSITION_MASK (LFE1);
247 break;
248 case 2:
249 channel_mask =
250 GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_LEFT) |
251 GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_RIGHT);
252 break;
253 default:
254 channel_mask = 0;
255 break;
256 }
257 }
258
259 while (n_bits_set (channel_mask) > channels) {
260 channel_mask &= ~(G_GUINT64_CONSTANT (1) << x);
261 x--;
262 }
263
264 gst_structure_set (structure, "channel-mask", GST_TYPE_BITMASK,
265 channel_mask, NULL);
266 }
267
268 return GST_BASE_SRC_CLASS (parent_class)->fixate (bsrc, caps);
269 }
270
271 static gboolean
gst_flite_test_src_set_caps(GstBaseSrc * basesrc,GstCaps * caps)272 gst_flite_test_src_set_caps (GstBaseSrc * basesrc, GstCaps * caps)
273 {
274 GstFliteTestSrc *src = GST_FLITE_TEST_SRC (basesrc);
275
276 gst_audio_info_init (&src->info);
277 if (!gst_audio_info_from_caps (&src->info, caps)) {
278 GST_ERROR_OBJECT (src, "Invalid caps");
279 return FALSE;
280 }
281
282 return TRUE;
283 }
284
285 #if 0
286 static gboolean
287 gst_flite_test_src_query (GstBaseSrc * basesrc, GstQuery * query)
288 {
289 GstFliteTestSrc *src = GST_FLITE_TEST_SRC (basesrc);
290 gboolean res = FALSE;
291
292 switch (GST_QUERY_TYPE (query)) {
293 case GST_QUERY_CONVERT:
294 {
295 GstFormat src_fmt, dest_fmt;
296 gint64 src_val, dest_val;
297
298 gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
299 if (src_fmt == dest_fmt) {
300 dest_val = src_val;
301 goto done;
302 }
303
304 switch (src_fmt) {
305 case GST_FORMAT_DEFAULT:
306 switch (dest_fmt) {
307 case GST_FORMAT_TIME:
308 /* samples to time */
309 dest_val =
310 gst_util_uint64_scale_int (src_val, GST_SECOND,
311 src->samplerate);
312 break;
313 default:
314 goto error;
315 }
316 break;
317 case GST_FORMAT_TIME:
318 switch (dest_fmt) {
319 case GST_FORMAT_DEFAULT:
320 /* time to samples */
321 dest_val =
322 gst_util_uint64_scale_int (src_val, src->samplerate,
323 GST_SECOND);
324 break;
325 default:
326 goto error;
327 }
328 break;
329 default:
330 goto error;
331 }
332 done:
333 gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
334 res = TRUE;
335 break;
336 }
337 default:
338 res = GST_BASE_SRC_CLASS (parent_class)->query (basesrc, query);
339 break;
340 }
341
342 return res;
343 /* ERROR */
344 error:
345 {
346 GST_DEBUG_OBJECT (src, "query failed");
347 return FALSE;
348 }
349 }
350 #endif
351
352
353 #if 0
354 static void
355 gst_flite_test_src_get_times (GstBaseSrc * basesrc, GstBuffer * buffer,
356 GstClockTime * start, GstClockTime * end)
357 {
358 /* for live sources, sync on the timestamp of the buffer */
359 if (gst_base_src_is_live (basesrc)) {
360 GstClockTime timestamp = GST_BUFFER_TIMESTAMP (buffer);
361
362 if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
363 /* get duration to calculate end time */
364 GstClockTime duration = GST_BUFFER_DURATION (buffer);
365
366 if (GST_CLOCK_TIME_IS_VALID (duration)) {
367 *end = timestamp + duration;
368 }
369 *start = timestamp;
370 }
371 } else {
372 *start = -1;
373 *end = -1;
374 }
375 }
376 #endif
377
378 /* there is no header for libflite_cmu_us_kal */
379 cst_voice *register_cmu_us_kal ();
380
381 static gboolean
gst_flite_test_src_start(GstBaseSrc * basesrc)382 gst_flite_test_src_start (GstBaseSrc * basesrc)
383 {
384 GstFliteTestSrc *src = GST_FLITE_TEST_SRC (basesrc);
385
386 src->adapter = gst_adapter_new ();
387
388 src->voice = register_cmu_us_kal ();
389
390 return TRUE;
391 }
392
393 static gboolean
gst_flite_test_src_stop(GstBaseSrc * basesrc)394 gst_flite_test_src_stop (GstBaseSrc * basesrc)
395 {
396 GstFliteTestSrc *src = GST_FLITE_TEST_SRC (basesrc);
397
398 g_object_unref (src->adapter);
399
400 return TRUE;
401 }
402
403 static char *
get_channel_name(GstFliteTestSrc * src,int channel)404 get_channel_name (GstFliteTestSrc * src, int channel)
405 {
406 static const char *numbers[10] = {
407 "zero", "one", "two", "three", "four", "five", "six", "seven", "eight",
408 "nine"
409 };
410 static const char *names[64] = {
411 "front left", "front right", "front center", "lfe 1", "rear left",
412 "rear right", "front left of center", "front right of center",
413 "rear center", "lfe 2", "side left", "side right", "top front left",
414 "top front right", "top front center", "top center", "top rear left",
415 "top rear right", "top side left", "top side right", "top rear center",
416 "bottom front center", "bottom front left", "bottom front right",
417 "wide left", "wide right", "surround left", "surround right"
418 };
419 const char *name;
420
421 if (src->info.position[channel] == GST_AUDIO_CHANNEL_POSITION_INVALID) {
422 name = "invalid";
423 } else if (src->info.position[channel] == GST_AUDIO_CHANNEL_POSITION_NONE) {
424 name = "none";
425 } else if (src->info.position[channel] == GST_AUDIO_CHANNEL_POSITION_MONO) {
426 name = "mono";
427 } else {
428 name = names[src->info.position[channel]];
429 }
430
431 return g_strdup_printf ("%s, %s", numbers[channel], name);
432 }
433
434 static GstFlowReturn
gst_flite_test_src_create(GstBaseSrc * basesrc,guint64 offset,guint length,GstBuffer ** buffer)435 gst_flite_test_src_create (GstBaseSrc * basesrc, guint64 offset,
436 guint length, GstBuffer ** buffer)
437 {
438 GstFliteTestSrc *src;
439 int n_bytes;
440
441 src = GST_FLITE_TEST_SRC (basesrc);
442
443 n_bytes = src->info.channels * sizeof (gint16) * src->samples_per_buffer;
444
445 while (gst_adapter_available (src->adapter) < n_bytes) {
446 GstBuffer *buf;
447 char *text;
448 int i;
449 GstMapInfo map;
450 gint16 *data;
451 cst_wave *wave;
452 gsize size;
453
454 text = get_channel_name (src, src->channel);
455
456 wave = flite_text_to_wave (text, src->voice);
457 g_free (text);
458 cst_wave_resample (wave, src->info.rate);
459
460 GST_DEBUG ("type %s, sample_rate %d, num_samples %d, num_channels %d",
461 wave->type, wave->sample_rate, wave->num_samples, wave->num_channels);
462
463 size = src->info.channels * sizeof (gint16) * wave->num_samples;
464 buf = gst_buffer_new_and_alloc (size);
465
466 gst_buffer_map (buf, &map, GST_MAP_WRITE);
467 data = (gint16 *) map.data;
468 memset (data, 0, size);
469 for (i = 0; i < wave->num_samples; i++) {
470 data[i * src->info.channels + src->channel] = wave->samples[i];
471 }
472 gst_buffer_unmap (buf, &map);
473
474 src->channel++;
475 if (src->channel == src->info.channels) {
476 src->channel = 0;
477 }
478
479 gst_adapter_push (src->adapter, buf);
480 }
481
482 *buffer = gst_adapter_take_buffer (src->adapter, n_bytes);
483
484 return GST_FLOW_OK;
485 }
486
487 static void
gst_flite_test_src_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)488 gst_flite_test_src_set_property (GObject * object, guint prop_id,
489 const GValue * value, GParamSpec * pspec)
490 {
491 GstFliteTestSrc *src = GST_FLITE_TEST_SRC (object);
492
493 switch (prop_id) {
494 case PROP_SAMPLES_PER_BUFFER:
495 src->samples_per_buffer = g_value_get_int (value);
496 break;
497 default:
498 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
499 break;
500 }
501 }
502
503 static void
gst_flite_test_src_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)504 gst_flite_test_src_get_property (GObject * object, guint prop_id,
505 GValue * value, GParamSpec * pspec)
506 {
507 GstFliteTestSrc *src = GST_FLITE_TEST_SRC (object);
508
509 switch (prop_id) {
510 case PROP_SAMPLES_PER_BUFFER:
511 g_value_set_int (value, src->samples_per_buffer);
512 break;
513 default:
514 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
515 break;
516 }
517 }
518