• 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 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