Merging gstreamer-sharp
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-bad / ext / flite / gstflitetestsrc.c
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
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
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
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 *
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
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
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
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 *
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
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
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
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 }