* src/gstpitch.c: (gst_pitch_class_init), (gst_pitch_init),
[tunertool] / src / gsttonesrc.c
1 /* Derived code of GStreamer - AudioTestSrc element
2  * Copyright (C) 2005 Stefan Kost <ensonic@users.sf.net>
3  * Copyright (C) 2008 Josep Torra <j.torra@telefonica.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., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <math.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <gst/controller/gstcontroller.h>
29
30 #include "gsttonesrc.h"
31
32 #ifndef M_PI
33 #define M_PI  3.14159265358979323846
34 #endif
35
36 #ifndef M_PI_2
37 #define M_PI_2  1.57079632679489661923
38 #endif
39
40 #define M_PI_M2 ( M_PI + M_PI )
41
42 GST_DEBUG_CATEGORY_STATIC (tone_src_debug);
43 #define GST_CAT_DEFAULT tone_src_debug
44
45 static const GstElementDetails gst_tone_src_details =
46 GST_ELEMENT_DETAILS ("Tone source",
47     "Source/Audio",
48     "Creates audio test signals of given frequency and volume",
49     "Stefan Kost <ensonic@users.sf.net>");
50
51
52 enum
53 {
54   PROP_0,
55   PROP_SAMPLES_PER_BUFFER,
56   PROP_FREQ,
57   PROP_VOLUME,
58 };
59
60
61 static GstStaticPadTemplate gst_tone_src_src_template =
62     GST_STATIC_PAD_TEMPLATE ("src",
63     GST_PAD_SRC,
64     GST_PAD_ALWAYS,
65     GST_STATIC_CAPS ("audio/x-raw-int, "
66         "endianness = (int) BYTE_ORDER, "
67         "signed = (boolean) true, "
68         "width = (int) 16, "
69         "depth = (int) 16, "
70         "rate = (int) [ 1, MAX ], "
71         "channels = (int) 1; "
72         "audio/x-raw-int, "
73         "endianness = (int) BYTE_ORDER, "
74         "signed = (boolean) true, "
75         "width = (int) 32, "
76         "depth = (int) 32,"
77         "rate = (int) [ 1, MAX ], "
78         "channels = (int) 1; "
79         "audio/x-raw-float, "
80         "endianness = (int) BYTE_ORDER, "
81         "width = (int) { 32, 64 }, "
82         "rate = (int) [ 1, MAX ], " "channels = (int) 1")
83     );
84
85
86 GST_BOILERPLATE (GstToneSrc, gst_tone_src, GstBaseSrc, GST_TYPE_BASE_SRC);
87
88 static void gst_tone_src_set_property (GObject * object,
89     guint prop_id, const GValue * value, GParamSpec * pspec);
90 static void gst_tone_src_get_property (GObject * object,
91     guint prop_id, GValue * value, GParamSpec * pspec);
92
93 static gboolean gst_tone_src_setcaps (GstBaseSrc * basesrc, GstCaps * caps);
94 static void gst_tone_src_src_fixate (GstPad * pad, GstCaps * caps);
95
96 static GstFlowReturn gst_tone_src_create (GstBaseSrc * basesrc,
97     guint64 offset, guint length, GstBuffer ** buffer);
98
99 #define DEFINE_OSCILATOR(type,scale) \
100 static void \
101 gst_tone_src_create_oscilator_##type (GstToneSrc * src, g##type * samples) \
102 { \
103   gint i; \
104   gdouble step, amp; \
105   \
106   step = M_PI_M2 * src->freq / src->samplerate; \
107   amp = src->volume * scale; \
108   \
109   for (i = 0; i < src->generate_samples_per_buffer; i++) { \
110     src->accumulator += step; \
111     if (src->accumulator >= M_PI_M2) \
112       src->accumulator -= M_PI_M2; \
113     \
114     samples[i] = (g##type) (sin (src->accumulator) * amp); \
115   } \
116 }
117
118 DEFINE_OSCILATOR (int16, 32767.0);
119 DEFINE_OSCILATOR (int32, 2147483647.0);
120 DEFINE_OSCILATOR (float, 1.0);
121 DEFINE_OSCILATOR (double, 1.0);
122
123 static ProcessFunc oscilator_funcs[] = {
124   (ProcessFunc) gst_tone_src_create_oscilator_int16,
125   (ProcessFunc) gst_tone_src_create_oscilator_int32,
126   (ProcessFunc) gst_tone_src_create_oscilator_float,
127   (ProcessFunc) gst_tone_src_create_oscilator_double
128 };
129
130 static void
131 gst_tone_src_base_init (gpointer g_class)
132 {
133   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
134
135   gst_element_class_add_pad_template (element_class,
136       gst_static_pad_template_get (&gst_tone_src_src_template));
137   gst_element_class_set_details (element_class, &gst_tone_src_details);
138 }
139
140 static void
141 gst_tone_src_class_init (GstToneSrcClass * klass)
142 {
143   GObjectClass *gobject_class;
144   GstBaseSrcClass *gstbasesrc_class;
145
146   gobject_class = (GObjectClass *) klass;
147   gstbasesrc_class = (GstBaseSrcClass *) klass;
148
149   gobject_class->set_property = gst_tone_src_set_property;
150   gobject_class->get_property = gst_tone_src_get_property;
151
152   g_object_class_install_property (gobject_class, PROP_SAMPLES_PER_BUFFER,
153       g_param_spec_int ("samplesperbuffer", "Samples per buffer",
154           "Number of samples in each outgoing buffer",
155           1, G_MAXINT, 1024, G_PARAM_READWRITE));
156   g_object_class_install_property (gobject_class, PROP_FREQ,
157       g_param_spec_double ("freq", "Frequency", "Frequency of test signal",
158           0.0, 20000.0, 440.0, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
159   g_object_class_install_property (gobject_class, PROP_VOLUME,
160       g_param_spec_double ("volume", "Volume", "Volume of test signal", 0.0,
161           1.0, 0.8, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
162
163   gstbasesrc_class->set_caps = GST_DEBUG_FUNCPTR (gst_tone_src_setcaps);
164   gstbasesrc_class->create = GST_DEBUG_FUNCPTR (gst_tone_src_create);
165 }
166
167 static void
168 gst_tone_src_init (GstToneSrc * src, GstToneSrcClass * g_class)
169 {
170   GstPad *pad = GST_BASE_SRC_PAD (src);
171
172   gst_pad_set_fixatecaps_function (pad, gst_tone_src_src_fixate);
173
174   src->samplerate = 44100;
175   src->format = GST_TONE_SRC_FORMAT_NONE;
176   src->volume = 0.8;
177   src->freq = 440.0;
178
179   /* we operate in time */
180   gst_base_src_set_format (GST_BASE_SRC (src), GST_FORMAT_TIME);
181   gst_base_src_set_live (GST_BASE_SRC (src), FALSE);
182
183   src->samples_per_buffer = 1024;
184   src->generate_samples_per_buffer = src->samples_per_buffer;
185 }
186
187 static void
188 gst_tone_src_src_fixate (GstPad * pad, GstCaps * caps)
189 {
190   GstToneSrc *src = GST_TONE_SRC (GST_PAD_PARENT (pad));
191   const gchar *name;
192   GstStructure *structure;
193
194   structure = gst_caps_get_structure (caps, 0);
195
196   gst_structure_fixate_field_nearest_int (structure, "rate", src->samplerate);
197
198   name = gst_structure_get_name (structure);
199   if (strcmp (name, "audio/x-raw-int") == 0)
200     gst_structure_fixate_field_nearest_int (structure, "width", 32);
201   else if (strcmp (name, "audio/x-raw-float") == 0)
202     gst_structure_fixate_field_nearest_int (structure, "width", 64);
203 }
204
205 static gboolean
206 gst_tone_src_setcaps (GstBaseSrc * basesrc, GstCaps * caps)
207 {
208   GstToneSrc *src = GST_TONE_SRC (basesrc);
209   const GstStructure *structure;
210   const gchar *name;
211   gint width;
212   gboolean ret;
213
214   structure = gst_caps_get_structure (caps, 0);
215   ret = gst_structure_get_int (structure, "rate", &src->samplerate);
216
217   name = gst_structure_get_name (structure);
218   if (strcmp (name, "audio/x-raw-int") == 0) {
219     ret &= gst_structure_get_int (structure, "width", &width);
220     src->format = (width == 32) ? GST_TONE_SRC_FORMAT_S32 :
221         GST_TONE_SRC_FORMAT_S16;
222   } else {
223     ret &= gst_structure_get_int (structure, "width", &width);
224     src->format = (width == 32) ? GST_TONE_SRC_FORMAT_F32 :
225         GST_TONE_SRC_FORMAT_F64;
226   }
227
228   src->process = oscilator_funcs[src->format];
229
230   return ret;
231 }
232
233
234
235 static GstFlowReturn
236 gst_tone_src_create (GstBaseSrc * basesrc, guint64 offset,
237     guint length, GstBuffer ** buffer)
238 {
239   GstFlowReturn res;
240   GstToneSrc *src;
241   GstBuffer *buf;
242   GstClockTime next_time;
243   gint64 n_samples;
244   gint sample_size;
245
246   src = GST_TONE_SRC (basesrc);
247
248   /* allocate a new buffer suitable for this pad */
249   switch (src->format) {
250     case GST_TONE_SRC_FORMAT_S16:
251       sample_size = sizeof (gint16);
252       break;
253     case GST_TONE_SRC_FORMAT_S32:
254       sample_size = sizeof (gint32);
255       break;
256     case GST_TONE_SRC_FORMAT_F32:
257       sample_size = sizeof (gfloat);
258       break;
259     case GST_TONE_SRC_FORMAT_F64:
260       sample_size = sizeof (gdouble);
261       break;
262     default:
263       sample_size = -1;
264       GST_ELEMENT_ERROR (src, CORE, NEGOTIATION, (NULL),
265           ("format wasn't negotiated before get function"));
266       return GST_FLOW_NOT_NEGOTIATED;
267       break;
268   }
269
270   n_samples = src->n_samples + src->samples_per_buffer;
271   next_time = gst_util_uint64_scale (n_samples, GST_SECOND,
272       (guint64) src->samplerate);
273
274   if ((res = gst_pad_alloc_buffer (basesrc->srcpad, src->n_samples,
275               src->generate_samples_per_buffer * sample_size,
276               GST_PAD_CAPS (basesrc->srcpad), &buf)) != GST_FLOW_OK) {
277     return res;
278   }
279
280   GST_BUFFER_TIMESTAMP (buf) = src->timestamp_offset + src->running_time;
281   GST_BUFFER_OFFSET_END (buf) = n_samples;
282   GST_BUFFER_DURATION (buf) = next_time - src->running_time;
283
284   gst_object_sync_values (G_OBJECT (src), src->running_time);
285
286   src->running_time = next_time;
287   src->n_samples = n_samples;
288
289   GST_LOG_OBJECT (src, "generating %u samples at ts %" GST_TIME_FORMAT,
290       length, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
291
292   src->process (src, GST_BUFFER_DATA (buf));
293
294   if (G_UNLIKELY ((src->volume == 0.0))) {
295     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_GAP);
296   }
297
298   *buffer = buf;
299
300   return GST_FLOW_OK;
301 }
302
303 static void
304 gst_tone_src_set_property (GObject * object, guint prop_id,
305     const GValue * value, GParamSpec * pspec)
306 {
307   GstToneSrc *src = GST_TONE_SRC (object);
308
309   switch (prop_id) {
310     case PROP_SAMPLES_PER_BUFFER:
311       src->samples_per_buffer = g_value_get_int (value);
312       break;
313     case PROP_FREQ:
314       src->freq = g_value_get_double (value);
315       break;
316     case PROP_VOLUME:
317       src->volume = g_value_get_double (value);
318       break;
319     default:
320       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
321       break;
322   }
323 }
324
325 static void
326 gst_tone_src_get_property (GObject * object, guint prop_id,
327     GValue * value, GParamSpec * pspec)
328 {
329   GstToneSrc *src = GST_TONE_SRC (object);
330
331   switch (prop_id) {
332     case PROP_SAMPLES_PER_BUFFER:
333       g_value_set_int (value, src->samples_per_buffer);
334       break;
335     case PROP_FREQ:
336       g_value_set_double (value, src->freq);
337       break;
338     case PROP_VOLUME:
339       g_value_set_double (value, src->volume);
340       break;
341     default:
342       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
343       break;
344   }
345 }
346
347 /*static*/ gboolean
348 plugin_tonesrc_init (GstPlugin * plugin)
349 {
350   /* initialize gst controller library */
351   gst_controller_init (NULL, NULL);
352
353   GST_DEBUG_CATEGORY_INIT (tone_src_debug, "tonesrc", 0, "Audio Test Source");
354
355   return gst_element_register (plugin, "tonesrc",
356       GST_RANK_NONE, GST_TYPE_TONE_SRC);
357 }
358
359 /*
360 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
361     GST_VERSION_MINOR,
362     "tonesrc",
363     "Creates audio test signals of given frequency and volume",
364     plugin_init, VERSION, "LGPL", NULL, NULL);
365 */