• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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