change NULL to (NULL) for GST_ELEMENT_ERROR
[platform/upstream/gst-plugins-base.git] / gst / sine / gstsinesrc.c
1 /* GStreamer
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>
5  *
6  * gstsinesrc.c: 
7  *
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.
12  *
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.
17  *
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.
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27 #include <math.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <gst/control/control.h>
31
32 #include <gstsinesrc.h>
33
34 /* elementfactory information */
35 GstElementDetails gst_sinesrc_details = {
36   "Sine-wave src",
37   "Source/Audio",
38   "Create a sine wave of a given frequency and volume",
39   "Erik Walthinsen <omega@cse.ogi.edu>"
40 };
41
42
43 /* SineSrc signals and args */
44 enum {
45   /* FILL ME */
46   LAST_SIGNAL
47 };
48
49 enum {
50   ARG_0,
51   ARG_TABLESIZE,
52   ARG_SAMPLES_PER_BUFFER,
53   ARG_FREQ,
54   ARG_VOLUME,
55 };
56
57 static GstStaticPadTemplate gst_sinesrc_src_template =
58 GST_STATIC_PAD_TEMPLATE (
59   "src",
60   GST_PAD_SRC,
61   GST_PAD_ALWAYS,
62   GST_STATIC_CAPS ("audio/x-raw-int, "
63       "endianness = (int) BYTE_ORDER, "
64       "signed = (boolean) true, "
65       "width = (int) 16, "
66       "depth = (int) 16, "
67       "rate = (int) [ 8000, 48000 ], "
68       "channels = (int) 1"
69   )
70 );
71
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, 
76                                                      guint prop_id, 
77                                                      const GValue *value, 
78                                                      GParamSpec *pspec);
79 static void         gst_sinesrc_get_property        (GObject *object, 
80                                                      guint prop_id, 
81                                                      GValue *value, 
82                                                      GParamSpec *pspec);
83 static GstPadLinkReturn
84                     gst_sinesrc_link                (GstPad  *pad,
85                                                      const GstCaps *caps);
86 static GstElementStateReturn
87                     gst_sinesrc_change_state        (GstElement *element);
88
89 static void         gst_sinesrc_update_freq         (const GValue *value, 
90                                                      gpointer data);
91 static void         gst_sinesrc_populate_sinetable  (GstSineSrc *src);
92 static inline void  gst_sinesrc_update_table_inc    (GstSineSrc *src);
93
94 static const GstQueryType *
95                     gst_sinesrc_get_query_types     (GstPad      *pad);
96 static gboolean     gst_sinesrc_src_query           (GstPad      *pad,
97                                                      GstQueryType type,
98                                                      GstFormat   *format,
99                                                      gint64      *value);
100
101 static GstData*   gst_sinesrc_get                   (GstPad *pad);
102 static GstCaps * gst_sinesrc_src_fixate (GstPad *pad, const GstCaps *caps);
103
104 static GstElementClass *parent_class = NULL;
105 /*static guint gst_sinesrc_signals[LAST_SIGNAL] = { 0 }; */
106
107 GType
108 gst_sinesrc_get_type (void)
109 {
110   static GType sinesrc_type = 0;
111
112   if (!sinesrc_type) {
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,
119     };
120     sinesrc_type = g_type_register_static (GST_TYPE_ELEMENT, "GstSineSrc", 
121                                            &sinesrc_info, 0);
122   }
123   return sinesrc_type;
124 }
125
126 static void
127 gst_sinesrc_base_init (GstSineSrcClass *klass)
128 {
129   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
130
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);
134 }
135
136 static void
137 gst_sinesrc_class_init (GstSineSrcClass *klass) 
138 {
139   GObjectClass *gobject_class;
140   GstElementClass *gstelement_class;
141
142   gobject_class = (GObjectClass *) klass;
143   gstelement_class = (GstElementClass *) klass;
144
145   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
146
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)); 
161                                      
162   gobject_class->set_property = gst_sinesrc_set_property;
163   gobject_class->get_property = gst_sinesrc_get_property;
164
165   gstelement_class->change_state = gst_sinesrc_change_state;
166 }
167
168 static void 
169 gst_sinesrc_init (GstSineSrc *src) 
170 {
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);
179   
180   src->samplerate = 44100;
181   src->volume = 1.0;
182   src->freq = 440.0;
183   
184   src->table_pos = 0.0;
185   src->table_size = 1024;
186   src->samples_per_buffer=1024;
187   src->timestamp=0LLU;
188   src->offset=0LLU;
189   
190   src->seq = 0;
191
192   src->dpman = gst_dpman_new ("sinesrc_dpman", GST_ELEMENT(src));
193
194   gst_dpman_add_required_dparam_callback (
195     src->dpman, 
196     g_param_spec_double("freq","Frequency (Hz)","Frequency of the tone",
197                        10.0, 10000.0, 350.0, G_PARAM_READWRITE),
198     "hertz",
199     gst_sinesrc_update_freq, 
200     src
201   );
202   
203   gst_dpman_add_required_dparam_direct (
204     src->dpman, 
205     g_param_spec_double("volume","Volume","Volume of the tone",
206                        0.0, 1.0, 0.8, G_PARAM_READWRITE),
207     "scalar",
208     &(src->volume)
209   );
210   
211   gst_dpman_set_rate(src->dpman, src->samplerate);
212
213   gst_sinesrc_populate_sinetable(src);
214   gst_sinesrc_update_table_inc(src);
215
216 }
217
218 static GstCaps *
219 gst_sinesrc_src_fixate (GstPad *pad, const GstCaps *caps)
220 {
221   GstStructure *structure;
222   GstCaps *newcaps;
223
224   if (gst_caps_get_size (caps) > 1) return NULL;
225
226   newcaps = gst_caps_copy (caps);
227   structure = gst_caps_get_structure (newcaps, 0);
228
229   if (gst_caps_structure_fixate_field_nearest_int (structure, "rate", 44100)) {
230     return newcaps;
231   }
232
233   gst_caps_free (newcaps);
234   return NULL;
235 }
236
237 static GstPadLinkReturn
238 gst_sinesrc_link (GstPad *pad, const GstCaps *caps)
239 {
240   GstSineSrc *sinesrc;
241   const GstStructure *structure;
242   gboolean ret;
243
244   GST_DEBUG ("gst_sinesrc_src_link");
245   sinesrc = GST_SINESRC (gst_pad_get_parent (pad));
246
247   structure = gst_caps_get_structure (caps, 0);
248
249   ret = gst_structure_get_int (structure, "rate", &sinesrc->samplerate);
250
251   if (!ret) return GST_PAD_LINK_REFUSED;
252
253   return GST_PAD_LINK_OK;
254 }
255
256 static const GstQueryType *
257 gst_sinesrc_get_query_types (GstPad *pad)
258 {
259   static const GstQueryType query_types[] = {
260     GST_QUERY_POSITION,
261     0,
262   };
263
264   return query_types;
265
266
267 static gboolean
268 gst_sinesrc_src_query (GstPad      *pad,
269                        GstQueryType type,
270                        GstFormat   *format,
271                        gint64      *value)
272 {
273   gboolean res = FALSE;
274   GstSineSrc *src;
275               
276   src = GST_SINESRC (gst_pad_get_parent (pad));
277                 
278   switch (type) {
279     case GST_QUERY_POSITION:
280       switch (*format) {
281         case GST_FORMAT_TIME:
282           *value = src->timestamp;
283           res = TRUE;
284           break;
285         case GST_FORMAT_DEFAULT: /* samples */
286           *value = src->offset / 2; /* 16bpp audio */
287           res = TRUE;
288           break;
289         case GST_FORMAT_BYTES:
290           *value = src->offset;
291           res = TRUE;
292           break;
293         default:
294           break;
295       }
296       break;
297     default:
298       break;
299   }
300
301   return res;
302 }
303
304 static GstData *
305 gst_sinesrc_get (GstPad *pad)
306 {
307   GstSineSrc *src;
308   GstBuffer *buf;
309   guint tdiff;
310   
311   gint16 *samples;
312   gint i=0;
313   
314   g_return_val_if_fail (pad != NULL, NULL);
315   src = GST_SINESRC (gst_pad_get_parent (pad));
316
317   if (!src->tags_pushed) {
318     GstTagList *taglist;
319
320     taglist = gst_tag_list_new ();
321
322     gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
323         GST_TAG_DESCRIPTION, "sine wave", NULL);
324
325     gst_element_found_tags_for_pad (GST_ELEMENT (src), pad, 0, taglist);
326     src->tags_pushed = TRUE;
327   }
328
329   tdiff = src->samples_per_buffer * GST_SECOND / src->samplerate;
330
331   /* note: the 2 is because of the format we use */
332   buf = gst_buffer_new_and_alloc (src->samples_per_buffer * 2);
333
334   GST_BUFFER_TIMESTAMP(buf) = src->timestamp;
335   GST_BUFFER_OFFSET (buf) = src->offset;
336   GST_BUFFER_DURATION (buf) = tdiff;
337
338   samples = (gint16 *) GST_BUFFER_DATA(buf);
339
340   GST_DPMAN_PREPROCESS(src->dpman, src->samples_per_buffer, src->timestamp);
341   
342   src->timestamp += tdiff;
343   src->offset += GST_BUFFER_SIZE (buf);
344    
345   while(GST_DPMAN_PROCESS(src->dpman, i)) {
346 #if 0
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;
350
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;
357       }
358     }
359     
360     src->table_pos += src->table_inc;
361
362     /*no interpolation */
363     /*samples[i] = src->table_data[src->table_lookup] */
364     /*               * src->volume * 32767.0; */
365
366     /*linear interpolation */
367     samples[i] = ((src->table_interp
368                    *(src->table_data[src->table_lookup_next]
369                     -src->table_data[src->table_lookup]
370                     )
371                   )+src->table_data[src->table_lookup]
372                  )* src->volume * 32767.0;
373 #endif
374     src->accumulator += 2*M_PI*src->freq / src->samplerate;
375     if(src->accumulator >= 2*M_PI){
376       src->accumulator -= 2*M_PI;
377     }
378     samples[i] = sin(src->accumulator) * src->volume * 32767.0;
379
380     i++;
381   }
382
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));
387       return NULL;
388     }
389   }
390
391   return GST_DATA (buf);
392 }
393
394 static void 
395 gst_sinesrc_set_property (GObject *object, guint prop_id, 
396                           const GValue *value, GParamSpec *pspec) 
397 {
398   GstSineSrc *src;
399
400   g_return_if_fail (GST_IS_SINESRC (object));
401   src = GST_SINESRC (object);
402
403   switch (prop_id) {
404     case ARG_TABLESIZE:
405       src->table_size = g_value_get_int (value);
406       gst_sinesrc_populate_sinetable (src);
407       gst_sinesrc_update_table_inc (src);
408       break;
409     case ARG_SAMPLES_PER_BUFFER:
410       src->samples_per_buffer = g_value_get_int (value);
411       break;
412     case ARG_FREQ:
413       gst_dpman_bypass_dparam (src->dpman, "freq");
414       gst_sinesrc_update_freq (value, src);      
415       break;
416     case ARG_VOLUME:
417       gst_dpman_bypass_dparam (src->dpman, "volume");
418       src->volume = g_value_get_double (value);
419       break;
420     default:
421       break;
422   }
423 }
424
425 static void 
426 gst_sinesrc_get_property (GObject *object, guint prop_id, 
427                           GValue *value, GParamSpec *pspec) 
428 {
429   GstSineSrc *src;
430
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);
434
435   switch (prop_id) {
436     case ARG_TABLESIZE:
437       g_value_set_int (value, src->table_size);
438       break;
439     case ARG_SAMPLES_PER_BUFFER:
440       g_value_set_int (value, src->samples_per_buffer);
441       break;
442     case ARG_FREQ:
443       g_value_set_double (value, src->freq);
444       break;
445     case ARG_VOLUME:
446       g_value_set_double (value, src->volume);
447       break;      
448     default:
449       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
450       break;
451   }
452 }
453
454 static GstElementStateReturn
455 gst_sinesrc_change_state (GstElement *element)
456 {
457   GstSineSrc *src = GST_SINESRC (element);
458
459   switch (GST_STATE_TRANSITION (element)) {
460     case GST_STATE_PAUSED_TO_READY:
461       src->timestamp = 0LLU;
462       src->offset = 0LLU;
463       break;
464     default:
465       break;
466   }
467
468   if (GST_ELEMENT_CLASS(parent_class)->change_state)
469     return GST_ELEMENT_CLASS(parent_class)->change_state (element);
470
471   return GST_STATE_SUCCESS;
472 }
473
474 static void 
475 gst_sinesrc_populate_sinetable (GstSineSrc *src)
476 {
477   gint i;
478   gdouble pi2scaled = M_PI * 2 / src->table_size;
479   gdouble *table = g_new (gdouble, src->table_size);
480
481   for(i=0 ; i < src->table_size ; i++){
482     table[i] = (gdouble) sin(i * pi2scaled);
483   }
484   
485   g_free (src->table_data);
486   src->table_data = table;
487 }
488
489 static void
490 gst_sinesrc_update_freq (const GValue *value, gpointer data)
491 {
492   GstSineSrc *src = (GstSineSrc *) data;
493   g_return_if_fail (GST_IS_SINESRC (src));
494
495   src->freq = g_value_get_double (value);
496   src->table_inc = src->table_size * src->freq / src->samplerate;
497   
498   /*GST_DEBUG ("freq %f", src->freq); */
499 }
500
501 static inline void 
502 gst_sinesrc_update_table_inc (GstSineSrc *src)
503 {
504   src->table_inc = src->table_size * src->freq / src->samplerate;
505 }
506
507 #if 0
508 static gboolean 
509 gst_sinesrc_force_caps (GstSineSrc *src)
510 {
511   static GstStaticCaps static_caps = GST_STATIC_CAPS ("audio/x-raw-int, "
512       "endianness = (int) BYTE_ORDER, "
513       "signed = (boolean) true, "
514       "width = (int) 16, "
515       "depth = (int) 16, "
516       "rate = (int) [ 8000, 48000 ], "
517       "channels = (int) 1"
518   );
519   GstCaps *caps;
520   GstStructure *structure;
521
522   if (!src->newcaps)
523     return TRUE;
524   
525   caps = gst_caps_copy (gst_static_caps_get (&static_caps));
526
527   structure = gst_caps_get_structure (caps, 0);
528
529   gst_structure_set (structure, "rate", G_TYPE_INT, src->samplerate, NULL);
530   
531   src->newcaps = gst_pad_try_set_caps (src->srcpad, caps) < GST_PAD_LINK_OK;
532
533   return !src->newcaps;
534 }
535 #endif
536
537 static gboolean
538 plugin_init (GstPlugin *plugin)
539 {
540   /* initialize dparam support library */
541   gst_control_init(NULL,NULL);
542
543   return gst_element_register (plugin, "sinesrc",
544                                GST_RANK_NONE, GST_TYPE_SINESRC);
545 }
546
547 GST_PLUGIN_DEFINE (
548   GST_VERSION_MAJOR,
549   GST_VERSION_MINOR,
550   "sine",
551   "Sine audio wave generator",
552   plugin_init,
553   VERSION,
554   "LGPL",
555   GST_PACKAGE,
556   GST_ORIGIN
557 )