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 GST_ELEMENT_REGISTER_DECLARE (flitetestsrc);
94 #define gst_flite_test_src_parent_class parent_class
95 G_DEFINE_TYPE (GstFliteTestSrc, gst_flite_test_src, GST_TYPE_BASE_SRC);
96 GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (flitetestsrc, "flitetestsrc",
97 GST_RANK_NONE, gst_flite_test_src_get_type (), flite_init ());
98
99 static void gst_flite_test_src_set_property (GObject * object,
100 guint prop_id, const GValue * value, GParamSpec * pspec);
101 static void gst_flite_test_src_get_property (GObject * object,
102 guint prop_id, GValue * value, GParamSpec * pspec);
103
104 static gboolean gst_flite_test_src_start (GstBaseSrc * basesrc);
105 static gboolean gst_flite_test_src_stop (GstBaseSrc * basesrc);
106 static GstFlowReturn gst_flite_test_src_create (GstBaseSrc * basesrc,
107 guint64 offset, guint length, GstBuffer ** buffer);
108 static gboolean
109 gst_flite_test_src_set_caps (GstBaseSrc * basesrc, GstCaps * caps);
110 static GstCaps *gst_flite_test_src_fixate (GstBaseSrc * bsrc, GstCaps * caps);
111
112 static void
gst_flite_test_src_class_init(GstFliteTestSrcClass * klass)113 gst_flite_test_src_class_init (GstFliteTestSrcClass * klass)
114 {
115 GObjectClass *gobject_class;
116 GstElementClass *gstelement_class;
117 GstBaseSrcClass *gstbasesrc_class;
118
119 gobject_class = (GObjectClass *) klass;
120 gstelement_class = (GstElementClass *) klass;
121 gstbasesrc_class = (GstBaseSrcClass *) klass;
122
123 gobject_class->set_property = gst_flite_test_src_set_property;
124 gobject_class->get_property = gst_flite_test_src_get_property;
125
126 g_object_class_install_property (gobject_class, PROP_SAMPLES_PER_BUFFER,
127 g_param_spec_int ("samplesperbuffer", "Samples per buffer",
128 "Number of samples in each outgoing buffer",
129 1, G_MAXINT, DEFAULT_SAMPLES_PER_BUFFER,
130 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
131
132 gst_element_class_add_static_pad_template (gstelement_class,
133 &gst_flite_test_src_src_template);
134
135 gst_element_class_set_static_metadata (gstelement_class,
136 "Flite speech test source", "Source/Audio",
137 "Creates audio test signals identifying channels",
138 "David Schleef <ds@schleef.org>");
139
140 gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_flite_test_src_start);
141 gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_flite_test_src_stop);
142 gstbasesrc_class->create = GST_DEBUG_FUNCPTR (gst_flite_test_src_create);
143 gstbasesrc_class->set_caps = GST_DEBUG_FUNCPTR (gst_flite_test_src_set_caps);
144 gstbasesrc_class->fixate = GST_DEBUG_FUNCPTR (gst_flite_test_src_fixate);
145
146 GST_DEBUG_CATEGORY_INIT (flite_test_src_debug, "flitetestsrc", 0,
147 "Flite Audio Test Source");
148 }
149
150 static void
gst_flite_test_src_init(GstFliteTestSrc * src)151 gst_flite_test_src_init (GstFliteTestSrc * src)
152 {
153 src->samples_per_buffer = DEFAULT_SAMPLES_PER_BUFFER;
154
155 /* we operate in time */
156 gst_base_src_set_format (GST_BASE_SRC (src), GST_FORMAT_TIME);
157
158 gst_base_src_set_blocksize (GST_BASE_SRC (src), -1);
159 }
160
161 static gint
n_bits_set(guint64 x)162 n_bits_set (guint64 x)
163 {
164 gint i;
165 gint c = 0;
166 guint64 y = 1;
167
168 for (i = 0; i < 64; i++) {
169 if (x & y)
170 c++;
171 y <<= 1;
172 }
173
174 return c;
175 }
176
177 static GstCaps *
gst_flite_test_src_fixate(GstBaseSrc * bsrc,GstCaps * caps)178 gst_flite_test_src_fixate (GstBaseSrc * bsrc, GstCaps * caps)
179 {
180 GstStructure *structure;
181 gint channels;
182
183 caps = gst_caps_truncate (caps);
184 caps = gst_caps_make_writable (caps);
185
186 structure = gst_caps_get_structure (caps, 0);
187
188 gst_structure_fixate_field_nearest_int (structure, "channels", 2);
189 gst_structure_get_int (structure, "channels", &channels);
190
191 if (channels == 1) {
192 gst_structure_remove_field (structure, "channel-mask");
193 } else {
194 guint64 channel_mask = 0;
195 gint x = 63;
196
197 if (!gst_structure_get (structure, "channel-mask", GST_TYPE_BITMASK,
198 &channel_mask, NULL)) {
199 switch (channels) {
200 case 8:
201 channel_mask =
202 GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_LEFT) |
203 GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_RIGHT) |
204 GST_AUDIO_CHANNEL_POSITION_MASK (REAR_LEFT) |
205 GST_AUDIO_CHANNEL_POSITION_MASK (REAR_RIGHT) |
206 GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_CENTER) |
207 GST_AUDIO_CHANNEL_POSITION_MASK (LFE1) |
208 GST_AUDIO_CHANNEL_POSITION_MASK (SIDE_LEFT) |
209 GST_AUDIO_CHANNEL_POSITION_MASK (SIDE_RIGHT);
210 break;
211 case 7:
212 channel_mask =
213 GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_LEFT) |
214 GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_RIGHT) |
215 GST_AUDIO_CHANNEL_POSITION_MASK (REAR_LEFT) |
216 GST_AUDIO_CHANNEL_POSITION_MASK (REAR_RIGHT) |
217 GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_CENTER) |
218 GST_AUDIO_CHANNEL_POSITION_MASK (LFE1) |
219 GST_AUDIO_CHANNEL_POSITION_MASK (REAR_CENTER);
220 break;
221 case 6:
222 channel_mask =
223 GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_LEFT) |
224 GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_RIGHT) |
225 GST_AUDIO_CHANNEL_POSITION_MASK (REAR_LEFT) |
226 GST_AUDIO_CHANNEL_POSITION_MASK (REAR_RIGHT) |
227 GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_CENTER) |
228 GST_AUDIO_CHANNEL_POSITION_MASK (LFE1);
229 break;
230 case 5:
231 channel_mask =
232 GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_LEFT) |
233 GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_RIGHT) |
234 GST_AUDIO_CHANNEL_POSITION_MASK (REAR_LEFT) |
235 GST_AUDIO_CHANNEL_POSITION_MASK (REAR_RIGHT) |
236 GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_CENTER);
237 break;
238 case 4:
239 channel_mask =
240 GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_LEFT) |
241 GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_RIGHT) |
242 GST_AUDIO_CHANNEL_POSITION_MASK (REAR_LEFT) |
243 GST_AUDIO_CHANNEL_POSITION_MASK (REAR_RIGHT);
244 break;
245 case 3:
246 channel_mask =
247 GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_LEFT) |
248 GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_RIGHT) |
249 GST_AUDIO_CHANNEL_POSITION_MASK (LFE1);
250 break;
251 case 2:
252 channel_mask =
253 GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_LEFT) |
254 GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_RIGHT);
255 break;
256 default:
257 channel_mask = 0;
258 break;
259 }
260 }
261
262 while (n_bits_set (channel_mask) > channels) {
263 channel_mask &= ~(G_GUINT64_CONSTANT (1) << x);
264 x--;
265 }
266
267 gst_structure_set (structure, "channel-mask", GST_TYPE_BITMASK,
268 channel_mask, NULL);
269 }
270
271 return GST_BASE_SRC_CLASS (parent_class)->fixate (bsrc, caps);
272 }
273
274 static gboolean
gst_flite_test_src_set_caps(GstBaseSrc * basesrc,GstCaps * caps)275 gst_flite_test_src_set_caps (GstBaseSrc * basesrc, GstCaps * caps)
276 {
277 GstFliteTestSrc *src = GST_FLITE_TEST_SRC (basesrc);
278
279 gst_audio_info_init (&src->info);
280 if (!gst_audio_info_from_caps (&src->info, caps)) {
281 GST_ERROR_OBJECT (src, "Invalid caps");
282 return FALSE;
283 }
284
285 return TRUE;
286 }
287
288 #if 0
289 static gboolean
290 gst_flite_test_src_query (GstBaseSrc * basesrc, GstQuery * query)
291 {
292 GstFliteTestSrc *src = GST_FLITE_TEST_SRC (basesrc);
293 gboolean res = FALSE;
294
295 switch (GST_QUERY_TYPE (query)) {
296 case GST_QUERY_CONVERT:
297 {
298 GstFormat src_fmt, dest_fmt;
299 gint64 src_val, dest_val;
300
301 gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
302 if (src_fmt == dest_fmt) {
303 dest_val = src_val;
304 goto done;
305 }
306
307 switch (src_fmt) {
308 case GST_FORMAT_DEFAULT:
309 switch (dest_fmt) {
310 case GST_FORMAT_TIME:
311 /* samples to time */
312 dest_val =
313 gst_util_uint64_scale_int (src_val, GST_SECOND,
314 src->samplerate);
315 break;
316 default:
317 goto error;
318 }
319 break;
320 case GST_FORMAT_TIME:
321 switch (dest_fmt) {
322 case GST_FORMAT_DEFAULT:
323 /* time to samples */
324 dest_val =
325 gst_util_uint64_scale_int (src_val, src->samplerate,
326 GST_SECOND);
327 break;
328 default:
329 goto error;
330 }
331 break;
332 default:
333 goto error;
334 }
335 done:
336 gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
337 res = TRUE;
338 break;
339 }
340 default:
341 res = GST_BASE_SRC_CLASS (parent_class)->query (basesrc, query);
342 break;
343 }
344
345 return res;
346 /* ERROR */
347 error:
348 {
349 GST_DEBUG_OBJECT (src, "query failed");
350 return FALSE;
351 }
352 }
353 #endif
354
355
356 #if 0
357 static void
358 gst_flite_test_src_get_times (GstBaseSrc * basesrc, GstBuffer * buffer,
359 GstClockTime * start, GstClockTime * end)
360 {
361 /* for live sources, sync on the timestamp of the buffer */
362 if (gst_base_src_is_live (basesrc)) {
363 GstClockTime timestamp = GST_BUFFER_TIMESTAMP (buffer);
364
365 if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
366 /* get duration to calculate end time */
367 GstClockTime duration = GST_BUFFER_DURATION (buffer);
368
369 if (GST_CLOCK_TIME_IS_VALID (duration)) {
370 *end = timestamp + duration;
371 }
372 *start = timestamp;
373 }
374 } else {
375 *start = -1;
376 *end = -1;
377 }
378 }
379 #endif
380
381 /* there is no header for libflite_cmu_us_kal */
382 cst_voice *register_cmu_us_kal ();
383
384 static gboolean
gst_flite_test_src_start(GstBaseSrc * basesrc)385 gst_flite_test_src_start (GstBaseSrc * basesrc)
386 {
387 GstFliteTestSrc *src = GST_FLITE_TEST_SRC (basesrc);
388
389 src->adapter = gst_adapter_new ();
390
391 src->voice = register_cmu_us_kal ();
392
393 return TRUE;
394 }
395
396 static gboolean
gst_flite_test_src_stop(GstBaseSrc * basesrc)397 gst_flite_test_src_stop (GstBaseSrc * basesrc)
398 {
399 GstFliteTestSrc *src = GST_FLITE_TEST_SRC (basesrc);
400
401 g_object_unref (src->adapter);
402
403 return TRUE;
404 }
405
406 static char *
get_channel_name(GstFliteTestSrc * src,int channel)407 get_channel_name (GstFliteTestSrc * src, int channel)
408 {
409 static const char *numbers[10] = {
410 "zero", "one", "two", "three", "four", "five", "six", "seven", "eight",
411 "nine"
412 };
413 static const char *names[64] = {
414 "front left", "front right", "front center", "lfe 1", "rear left",
415 "rear right", "front left of center", "front right of center",
416 "rear center", "lfe 2", "side left", "side right", "top front left",
417 "top front right", "top front center", "top center", "top rear left",
418 "top rear right", "top side left", "top side right", "top rear center",
419 "bottom front center", "bottom front left", "bottom front right",
420 "wide left", "wide right", "surround left", "surround right"
421 };
422 const char *name;
423
424 if (src->info.position[channel] == GST_AUDIO_CHANNEL_POSITION_INVALID) {
425 name = "invalid";
426 } else if (src->info.position[channel] == GST_AUDIO_CHANNEL_POSITION_NONE) {
427 name = "none";
428 } else if (src->info.position[channel] == GST_AUDIO_CHANNEL_POSITION_MONO) {
429 name = "mono";
430 } else {
431 name = names[src->info.position[channel]];
432 }
433
434 return g_strdup_printf ("%s, %s", numbers[channel], name);
435 }
436
437 static GstFlowReturn
gst_flite_test_src_create(GstBaseSrc * basesrc,guint64 offset,guint length,GstBuffer ** buffer)438 gst_flite_test_src_create (GstBaseSrc * basesrc, guint64 offset,
439 guint length, GstBuffer ** buffer)
440 {
441 GstFliteTestSrc *src;
442 int n_bytes;
443
444 src = GST_FLITE_TEST_SRC (basesrc);
445
446 n_bytes = src->info.channels * sizeof (gint16) * src->samples_per_buffer;
447
448 while (gst_adapter_available (src->adapter) < n_bytes) {
449 GstBuffer *buf;
450 char *text;
451 int i;
452 GstMapInfo map;
453 gint16 *data;
454 cst_wave *wave;
455 gsize size;
456
457 text = get_channel_name (src, src->channel);
458
459 wave = flite_text_to_wave (text, src->voice);
460 g_free (text);
461 cst_wave_resample (wave, src->info.rate);
462
463 GST_DEBUG ("type %s, sample_rate %d, num_samples %d, num_channels %d",
464 wave->type, wave->sample_rate, wave->num_samples, wave->num_channels);
465
466 size = src->info.channels * sizeof (gint16) * wave->num_samples;
467 buf = gst_buffer_new_and_alloc (size);
468
469 gst_buffer_map (buf, &map, GST_MAP_WRITE);
470 data = (gint16 *) map.data;
471 memset (data, 0, size);
472 for (i = 0; i < wave->num_samples; i++) {
473 data[i * src->info.channels + src->channel] = wave->samples[i];
474 }
475 gst_buffer_unmap (buf, &map);
476
477 src->channel++;
478 if (src->channel == src->info.channels) {
479 src->channel = 0;
480 }
481
482 gst_adapter_push (src->adapter, buf);
483 }
484
485 *buffer = gst_adapter_take_buffer (src->adapter, n_bytes);
486
487 return GST_FLOW_OK;
488 }
489
490 static void
gst_flite_test_src_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)491 gst_flite_test_src_set_property (GObject * object, guint prop_id,
492 const GValue * value, GParamSpec * pspec)
493 {
494 GstFliteTestSrc *src = GST_FLITE_TEST_SRC (object);
495
496 switch (prop_id) {
497 case PROP_SAMPLES_PER_BUFFER:
498 src->samples_per_buffer = g_value_get_int (value);
499 break;
500 default:
501 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
502 break;
503 }
504 }
505
506 static void
gst_flite_test_src_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)507 gst_flite_test_src_get_property (GObject * object, guint prop_id,
508 GValue * value, GParamSpec * pspec)
509 {
510 GstFliteTestSrc *src = GST_FLITE_TEST_SRC (object);
511
512 switch (prop_id) {
513 case PROP_SAMPLES_PER_BUFFER:
514 g_value_set_int (value, src->samples_per_buffer);
515 break;
516 default:
517 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
518 break;
519 }
520 }
521