2 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3 * 2000 Wim Taymans <wtay@chello.be>
4 * 2001 Steve Baker <stevebaker_org@yahoo.co.uk>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
30 #include <gst/control/control.h>
32 #include <gstsinesrc.h>
34 /* elementfactory information */
35 GstElementDetails gst_sinesrc_details = {
38 "Create a sine wave of a given frequency and volume",
39 "Erik Walthinsen <omega@cse.ogi.edu>"
43 /* SineSrc signals and args */
52 ARG_SAMPLES_PER_BUFFER,
57 static GstStaticPadTemplate gst_sinesrc_src_template =
58 GST_STATIC_PAD_TEMPLATE (
62 GST_STATIC_CAPS ("audio/x-raw-int, "
63 "endianness = (int) BYTE_ORDER, "
64 "signed = (boolean) true, "
67 "rate = (int) [ 8000, 48000 ], "
72 static void gst_sinesrc_class_init (GstSineSrcClass *klass);
73 static void gst_sinesrc_base_init (GstSineSrcClass *klass);
74 static void gst_sinesrc_init (GstSineSrc *src);
75 static void gst_sinesrc_set_property (GObject *object,
79 static void gst_sinesrc_get_property (GObject *object,
83 static GstPadLinkReturn
84 gst_sinesrc_link (GstPad *pad,
86 static GstElementStateReturn
87 gst_sinesrc_change_state (GstElement *element);
89 static void gst_sinesrc_update_freq (const GValue *value,
91 static void gst_sinesrc_populate_sinetable (GstSineSrc *src);
92 static inline void gst_sinesrc_update_table_inc (GstSineSrc *src);
94 static const GstQueryType *
95 gst_sinesrc_get_query_types (GstPad *pad);
96 static gboolean gst_sinesrc_src_query (GstPad *pad,
101 static GstData* gst_sinesrc_get (GstPad *pad);
102 static GstCaps * gst_sinesrc_src_fixate (GstPad *pad, const GstCaps *caps);
104 static GstElementClass *parent_class = NULL;
105 /*static guint gst_sinesrc_signals[LAST_SIGNAL] = { 0 }; */
108 gst_sinesrc_get_type (void)
110 static GType sinesrc_type = 0;
113 static const GTypeInfo sinesrc_info = {
114 sizeof (GstSineSrcClass),
115 (GBaseInitFunc) gst_sinesrc_base_init, NULL,
116 (GClassInitFunc) gst_sinesrc_class_init, NULL, NULL,
117 sizeof (GstSineSrc), 0,
118 (GInstanceInitFunc) gst_sinesrc_init,
120 sinesrc_type = g_type_register_static (GST_TYPE_ELEMENT, "GstSineSrc",
127 gst_sinesrc_base_init (GstSineSrcClass *klass)
129 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
131 gst_element_class_add_pad_template (element_class,
132 gst_static_pad_template_get (&gst_sinesrc_src_template));
133 gst_element_class_set_details (element_class, &gst_sinesrc_details);
137 gst_sinesrc_class_init (GstSineSrcClass *klass)
139 GObjectClass *gobject_class;
140 GstElementClass *gstelement_class;
142 gobject_class = (GObjectClass *) klass;
143 gstelement_class = (GstElementClass *) klass;
145 parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
147 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_TABLESIZE,
148 g_param_spec_int ("tablesize", "tablesize", "tablesize",
149 1, G_MAXINT, 1024, G_PARAM_READWRITE));
150 g_object_class_install_property (G_OBJECT_CLASS (klass),
151 ARG_SAMPLES_PER_BUFFER,
152 g_param_spec_int ("samplesperbuffer", "Samples per buffer",
153 "Number of samples in each outgoing buffer",
154 1, G_MAXINT, 1024, G_PARAM_READWRITE));
155 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_FREQ,
156 g_param_spec_double ("freq", "Frequency", "Frequency of sine source",
157 0.0, 20000.0, 440.0, G_PARAM_READWRITE));
158 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_VOLUME,
159 g_param_spec_double ("volume", "Volume", "Volume",
160 0.0, 1.0, 0.8, G_PARAM_READWRITE));
162 gobject_class->set_property = gst_sinesrc_set_property;
163 gobject_class->get_property = gst_sinesrc_get_property;
165 gstelement_class->change_state = gst_sinesrc_change_state;
169 gst_sinesrc_init (GstSineSrc *src)
171 src->srcpad = gst_pad_new_from_template (
172 gst_static_pad_template_get (&gst_sinesrc_src_template), "src");
173 gst_pad_set_link_function (src->srcpad, gst_sinesrc_link);
174 gst_pad_set_fixate_function (src->srcpad, gst_sinesrc_src_fixate);
175 gst_pad_set_get_function (src->srcpad, gst_sinesrc_get);
176 gst_pad_set_query_function (src->srcpad, gst_sinesrc_src_query);
177 gst_pad_set_query_type_function (src->srcpad, gst_sinesrc_get_query_types);
178 gst_element_add_pad (GST_ELEMENT(src), src->srcpad);
180 src->samplerate = 44100;
184 src->table_pos = 0.0;
185 src->table_size = 1024;
186 src->samples_per_buffer=1024;
192 src->dpman = gst_dpman_new ("sinesrc_dpman", GST_ELEMENT(src));
194 gst_dpman_add_required_dparam_callback (
196 g_param_spec_double("freq","Frequency (Hz)","Frequency of the tone",
197 10.0, 10000.0, 350.0, G_PARAM_READWRITE),
199 gst_sinesrc_update_freq,
203 gst_dpman_add_required_dparam_direct (
205 g_param_spec_double("volume","Volume","Volume of the tone",
206 0.0, 1.0, 0.8, G_PARAM_READWRITE),
211 gst_dpman_set_rate(src->dpman, src->samplerate);
213 gst_sinesrc_populate_sinetable(src);
214 gst_sinesrc_update_table_inc(src);
219 gst_sinesrc_src_fixate (GstPad *pad, const GstCaps *caps)
221 GstStructure *structure;
224 if (gst_caps_get_size (caps) > 1) return NULL;
226 newcaps = gst_caps_copy (caps);
227 structure = gst_caps_get_structure (newcaps, 0);
229 if (gst_caps_structure_fixate_field_nearest_int (structure, "rate", 44100)) {
233 gst_caps_free (newcaps);
237 static GstPadLinkReturn
238 gst_sinesrc_link (GstPad *pad, const GstCaps *caps)
241 const GstStructure *structure;
244 GST_DEBUG ("gst_sinesrc_src_link");
245 sinesrc = GST_SINESRC (gst_pad_get_parent (pad));
247 structure = gst_caps_get_structure (caps, 0);
249 ret = gst_structure_get_int (structure, "rate", &sinesrc->samplerate);
251 if (!ret) return GST_PAD_LINK_REFUSED;
253 return GST_PAD_LINK_OK;
256 static const GstQueryType *
257 gst_sinesrc_get_query_types (GstPad *pad)
259 static const GstQueryType query_types[] = {
268 gst_sinesrc_src_query (GstPad *pad,
273 gboolean res = FALSE;
276 src = GST_SINESRC (gst_pad_get_parent (pad));
279 case GST_QUERY_POSITION:
281 case GST_FORMAT_TIME:
282 *value = src->timestamp;
285 case GST_FORMAT_DEFAULT: /* samples */
286 *value = src->offset / 2; /* 16bpp audio */
289 case GST_FORMAT_BYTES:
290 *value = src->offset;
305 gst_sinesrc_get (GstPad *pad)
314 g_return_val_if_fail (pad != NULL, NULL);
315 src = GST_SINESRC (gst_pad_get_parent (pad));
317 if (!src->tags_pushed) {
320 taglist = gst_tag_list_new ();
322 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
323 GST_TAG_DESCRIPTION, "sine wave", NULL);
325 gst_element_found_tags_for_pad (GST_ELEMENT (src), pad, 0, taglist);
326 src->tags_pushed = TRUE;
329 tdiff = src->samples_per_buffer * GST_SECOND / src->samplerate;
331 /* note: the 2 is because of the format we use */
332 buf = gst_buffer_new_and_alloc (src->samples_per_buffer * 2);
334 GST_BUFFER_TIMESTAMP(buf) = src->timestamp;
335 GST_BUFFER_OFFSET (buf) = src->offset;
336 GST_BUFFER_DURATION (buf) = tdiff;
338 samples = (gint16 *) GST_BUFFER_DATA(buf);
340 GST_DPMAN_PREPROCESS(src->dpman, src->samples_per_buffer, src->timestamp);
342 src->timestamp += tdiff;
343 src->offset += GST_BUFFER_SIZE (buf);
345 while(GST_DPMAN_PROCESS(src->dpman, i)) {
347 src->table_lookup = (gint)(src->table_pos);
348 src->table_lookup_next = src->table_lookup + 1;
349 src->table_interp = src->table_pos - src->table_lookup;
351 /* wrap the array lookups if we're out of bounds */
352 if (src->table_lookup_next >= src->table_size){
353 src->table_lookup_next -= src->table_size;
354 if (src->table_lookup >= src->table_size){
355 src->table_lookup -= src->table_size;
356 src->table_pos -= src->table_size;
360 src->table_pos += src->table_inc;
362 /*no interpolation */
363 /*samples[i] = src->table_data[src->table_lookup] */
364 /* * src->volume * 32767.0; */
366 /*linear interpolation */
367 samples[i] = ((src->table_interp
368 *(src->table_data[src->table_lookup_next]
369 -src->table_data[src->table_lookup]
371 )+src->table_data[src->table_lookup]
372 )* src->volume * 32767.0;
374 src->accumulator += 2*M_PI*src->freq / src->samplerate;
375 if(src->accumulator >= 2*M_PI){
376 src->accumulator -= 2*M_PI;
378 samples[i] = sin(src->accumulator) * src->volume * 32767.0;
383 if (!GST_PAD_CAPS (src->srcpad)) {
384 if (gst_sinesrc_link (src->srcpad,
385 gst_pad_get_allowed_caps (src->srcpad)) <= 0) {
386 GST_ELEMENT_ERROR (src, CORE, NEGOTIATION, (NULL), (NULL));
391 return GST_DATA (buf);
395 gst_sinesrc_set_property (GObject *object, guint prop_id,
396 const GValue *value, GParamSpec *pspec)
400 g_return_if_fail (GST_IS_SINESRC (object));
401 src = GST_SINESRC (object);
405 src->table_size = g_value_get_int (value);
406 gst_sinesrc_populate_sinetable (src);
407 gst_sinesrc_update_table_inc (src);
409 case ARG_SAMPLES_PER_BUFFER:
410 src->samples_per_buffer = g_value_get_int (value);
413 gst_dpman_bypass_dparam (src->dpman, "freq");
414 gst_sinesrc_update_freq (value, src);
417 gst_dpman_bypass_dparam (src->dpman, "volume");
418 src->volume = g_value_get_double (value);
426 gst_sinesrc_get_property (GObject *object, guint prop_id,
427 GValue *value, GParamSpec *pspec)
431 /* it's not null if we got it, but it might not be ours */
432 g_return_if_fail(GST_IS_SINESRC(object));
433 src = GST_SINESRC(object);
437 g_value_set_int (value, src->table_size);
439 case ARG_SAMPLES_PER_BUFFER:
440 g_value_set_int (value, src->samples_per_buffer);
443 g_value_set_double (value, src->freq);
446 g_value_set_double (value, src->volume);
449 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
454 static GstElementStateReturn
455 gst_sinesrc_change_state (GstElement *element)
457 GstSineSrc *src = GST_SINESRC (element);
459 switch (GST_STATE_TRANSITION (element)) {
460 case GST_STATE_PAUSED_TO_READY:
461 src->timestamp = 0LLU;
468 if (GST_ELEMENT_CLASS(parent_class)->change_state)
469 return GST_ELEMENT_CLASS(parent_class)->change_state (element);
471 return GST_STATE_SUCCESS;
475 gst_sinesrc_populate_sinetable (GstSineSrc *src)
478 gdouble pi2scaled = M_PI * 2 / src->table_size;
479 gdouble *table = g_new (gdouble, src->table_size);
481 for(i=0 ; i < src->table_size ; i++){
482 table[i] = (gdouble) sin(i * pi2scaled);
485 g_free (src->table_data);
486 src->table_data = table;
490 gst_sinesrc_update_freq (const GValue *value, gpointer data)
492 GstSineSrc *src = (GstSineSrc *) data;
493 g_return_if_fail (GST_IS_SINESRC (src));
495 src->freq = g_value_get_double (value);
496 src->table_inc = src->table_size * src->freq / src->samplerate;
498 /*GST_DEBUG ("freq %f", src->freq); */
502 gst_sinesrc_update_table_inc (GstSineSrc *src)
504 src->table_inc = src->table_size * src->freq / src->samplerate;
509 gst_sinesrc_force_caps (GstSineSrc *src)
511 static GstStaticCaps static_caps = GST_STATIC_CAPS ("audio/x-raw-int, "
512 "endianness = (int) BYTE_ORDER, "
513 "signed = (boolean) true, "
516 "rate = (int) [ 8000, 48000 ], "
520 GstStructure *structure;
525 caps = gst_caps_copy (gst_static_caps_get (&static_caps));
527 structure = gst_caps_get_structure (caps, 0);
529 gst_structure_set (structure, "rate", G_TYPE_INT, src->samplerate, NULL);
531 src->newcaps = gst_pad_try_set_caps (src->srcpad, caps) < GST_PAD_LINK_OK;
533 return !src->newcaps;
538 plugin_init (GstPlugin *plugin)
540 /* initialize dparam support library */
541 gst_control_init(NULL,NULL);
543 return gst_element_register (plugin, "sinesrc",
544 GST_RANK_NONE, GST_TYPE_SINESRC);
551 "Sine audio wave generator",