controller: move GValue handling from control-sources to -binding
[platform/upstream/gstreamer.git] / libs / gst / controller / gstlfocontrolsource.c
1 /* GStreamer
2  *
3  * Copyright (C) 2007,2010 Sebastian Dröge <sebastian.droege@collabora.co.uk>
4  *
5  * gstlfocontrolsource.c: Control source that provides some periodic waveforms
6  *                        as control values.
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 /**
25  * SECTION:gstlfocontrolsource
26  * @short_description: LFO control source
27  *
28  * #GstLFOControlSource is a #GstControlSource, that provides several periodic waveforms
29  * as control values. It supports all fundamental, numeric GValue types as property.
30  *
31  * To use #GstLFOControlSource get a new instance by calling gst_lfo_control_source_new(),
32  * bind it to a #GParamSpec and set the relevant properties or use
33  * gst_lfo_control_source_set_waveform.
34  *
35  * All functions are MT-safe.
36  *
37  */
38
39 #include <glib-object.h>
40 #include <gst/gst.h>
41 #include <gst/gstcontrolsource.h>
42
43 #include "gstlfocontrolsource.h"
44
45 #include "gst/glib-compat-private.h"
46
47 #include <gst/math-compat.h>
48
49 #define GST_CAT_DEFAULT controller_debug
50 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
51
52 struct _GstLFOControlSourcePrivate
53 {
54   GstLFOWaveform waveform;
55   gdouble frequency;
56   GstClockTime period;
57   GstClockTime timeshift;
58   gdouble amplitude;
59   gdouble offset;
60 };
61
62 /* FIXME: as % in C is not the modulo operator we need here for
63  * negative numbers implement our own. Are there better ways? */
64 static inline GstClockTime
65 _calculate_pos (GstClockTime timestamp, GstClockTime timeshift,
66     GstClockTime period)
67 {
68   while (timestamp < timeshift)
69     timestamp += period;
70
71   timestamp -= timeshift;
72
73   return timestamp % period;
74 }
75
76 static inline gdouble
77 _sine_get (GstLFOControlSource * self, gdouble amp, gdouble off,
78     GstClockTime timeshift, GstClockTime period, gdouble frequency,
79     GstClockTime timestamp)
80 {
81   GstClockTime pos = _calculate_pos (timestamp, timeshift, period);
82   gdouble ret;
83
84   ret =
85       sin (2.0 * M_PI * (frequency / GST_SECOND) *
86       gst_guint64_to_gdouble (pos));
87   ret *= amp;
88   ret += off;
89
90   return ret;
91 }
92
93 static gboolean
94 waveform_sine_get (GstLFOControlSource * self, GstClockTime timestamp,
95     gdouble * value)
96 {
97   GstLFOControlSourcePrivate *priv = self->priv;
98   gdouble amp, off, frequency;
99   GstClockTime timeshift, period;
100
101   g_mutex_lock (self->lock);
102   amp = priv->amplitude;
103   off = priv->offset;
104   timeshift = priv->timeshift;
105   period = priv->period;
106   frequency = priv->frequency;
107
108   *value = _sine_get (self, amp, off, timeshift, period, frequency, timestamp);
109   g_mutex_unlock (self->lock);
110   return TRUE;
111 }
112
113 static gboolean
114 waveform_sine_get_value_array (GstLFOControlSource * self,
115     GstClockTime timestamp, GstClockTime interval, guint n_values,
116     gdouble * values)
117 {
118   GstLFOControlSourcePrivate *priv = self->priv;
119   guint i;
120   GstClockTime ts = timestamp;
121   gdouble amp, off, frequency;
122   GstClockTime timeshift, period;
123
124   g_mutex_lock (self->lock);
125   amp = priv->amplitude;
126   off = priv->offset;
127   timeshift = priv->timeshift;
128   period = priv->period;
129   frequency = priv->frequency;
130
131   for (i = 0; i < n_values; i++) {
132     *values = _sine_get (self, amp, off, timeshift, period, frequency, ts);
133     ts += interval;
134     values++;
135   }
136   g_mutex_unlock (self->lock);
137   return TRUE;
138 }
139
140
141 static inline gdouble
142 _square_get (GstLFOControlSource * self, gdouble amp, gdouble off,
143     GstClockTime timeshift, GstClockTime period, gdouble frequency,
144     GstClockTime timestamp)
145 {
146   GstClockTime pos = _calculate_pos (timestamp, timeshift, period);
147   gdouble ret;
148
149   if (pos >= period / 2)
150     ret = amp;
151   else
152     ret = -amp;
153   ret += off;
154
155   return ret;
156 }
157
158 static gboolean
159 waveform_square_get (GstLFOControlSource * self, GstClockTime timestamp,
160     gdouble * value)
161 {
162   GstLFOControlSourcePrivate *priv = self->priv;
163   gdouble amp, off, frequency;
164   GstClockTime timeshift, period;
165
166   g_mutex_lock (self->lock);
167   amp = priv->amplitude;
168   off = priv->offset;
169   timeshift = priv->timeshift;
170   period = priv->period;
171   frequency = priv->frequency;
172
173   *value =
174       _square_get (self, amp, off, timeshift, period, frequency, timestamp);
175   g_mutex_unlock (self->lock);
176   return TRUE;
177 }
178
179 static gboolean
180 waveform_square_get_value_array (GstLFOControlSource * self,
181     GstClockTime timestamp, GstClockTime interval, guint n_values,
182     gdouble * values)
183 {
184   GstLFOControlSourcePrivate *priv = self->priv;
185   guint i;
186   GstClockTime ts = timestamp;
187   gdouble amp, off, frequency;
188   GstClockTime timeshift, period;
189
190   g_mutex_lock (self->lock);
191   amp = priv->amplitude;
192   off = priv->offset;
193   timeshift = priv->timeshift;
194   period = priv->period;
195   frequency = priv->frequency;
196
197   for (i = 0; i < n_values; i++) {
198     *values = _square_get (self, amp, off, timeshift, period, frequency, ts);
199     ts += interval;
200     values++;
201   }
202   g_mutex_unlock (self->lock);
203   return TRUE;
204 }
205
206 static inline gdouble
207 _saw_get (GstLFOControlSource * self, gdouble amp, gdouble off,
208     GstClockTime timeshift, GstClockTime period, gdouble frequency,
209     GstClockTime timestamp)
210 {
211   GstClockTime pos = _calculate_pos (timestamp, timeshift, period);
212   gdouble ret;
213
214   ret =
215       -((gst_guint64_to_gdouble (pos) -
216           gst_guint64_to_gdouble (period) / 2.0) * ((2.0 * amp) /
217           gst_guint64_to_gdouble (period)));
218   ret += off;
219
220   return ret;
221 }
222
223 static gboolean
224 waveform_saw_get (GstLFOControlSource * self, GstClockTime timestamp,
225     gdouble * value)
226 {
227   GstLFOControlSourcePrivate *priv = self->priv;
228   gdouble amp, off, frequency;
229   GstClockTime timeshift, period;
230
231   g_mutex_lock (self->lock);
232   amp = priv->amplitude;
233   off = priv->offset;
234   timeshift = priv->timeshift;
235   period = priv->period;
236   frequency = priv->frequency;
237
238   *value = _saw_get (self, amp, off, timeshift, period, frequency, timestamp);
239   g_mutex_unlock (self->lock);
240   return TRUE;
241 }
242
243 static gboolean
244 waveform_saw_get_value_array (GstLFOControlSource * self,
245     GstClockTime timestamp, GstClockTime interval, guint n_values,
246     gdouble * values)
247 {
248   GstLFOControlSourcePrivate *priv = self->priv;
249   guint i;
250   GstClockTime ts = timestamp;
251   gdouble amp, off, frequency;
252   GstClockTime timeshift, period;
253
254   g_mutex_lock (self->lock);
255   amp = priv->amplitude;
256   off = priv->offset;
257   timeshift = priv->timeshift;
258   period = priv->period;
259   frequency = priv->frequency;
260
261   for (i = 0; i < n_values; i++) {
262     *values = _saw_get (self, amp, off, timeshift, period, frequency, ts);
263     ts += interval;
264     values++;
265   }
266   g_mutex_unlock (self->lock);
267   return TRUE;
268 }
269
270 static inline gdouble
271 _rsaw_get (GstLFOControlSource * self, gdouble amp, gdouble off,
272     GstClockTime timeshift, GstClockTime period, gdouble frequency,
273     GstClockTime timestamp)
274 {
275   GstClockTime pos = _calculate_pos (timestamp, timeshift, period);
276   gdouble ret;
277
278   ret =
279       ((gst_guint64_to_gdouble (pos) -
280           gst_guint64_to_gdouble (period) / 2.0) * ((2.0 * amp) /
281           gst_guint64_to_gdouble (period)));
282   ret += off;
283
284   return ret;
285 }
286
287 static gboolean
288 waveform_rsaw_get (GstLFOControlSource * self, GstClockTime timestamp,
289     gdouble * value)
290 {
291   GstLFOControlSourcePrivate *priv = self->priv;
292   gdouble amp, off, frequency;
293   GstClockTime timeshift, period;
294
295   g_mutex_lock (self->lock);
296   amp = priv->amplitude;
297   off = priv->offset;
298   timeshift = priv->timeshift;
299   period = priv->period;
300   frequency = priv->frequency;
301
302   *value = _rsaw_get (self, amp, off, timeshift, period, frequency, timestamp);
303   g_mutex_unlock (self->lock);
304   return TRUE;
305 }
306
307 static gboolean
308 waveform_rsaw_get_value_array (GstLFOControlSource * self,
309     GstClockTime timestamp, GstClockTime interval, guint n_values,
310     gdouble * values)
311 {
312   GstLFOControlSourcePrivate *priv = self->priv;
313   guint i;
314   GstClockTime ts = timestamp;
315   gdouble amp, off, frequency;
316   GstClockTime timeshift, period;
317
318   g_mutex_lock (self->lock);
319   amp = priv->amplitude;
320   off = priv->offset;
321   timeshift = priv->timeshift;
322   period = priv->period;
323   frequency = priv->frequency;
324
325   for (i = 0; i < n_values; i++) {
326     *values = _rsaw_get (self, amp, off, timeshift, period, frequency, ts);
327     ts += interval;
328     values++;
329   }
330   g_mutex_unlock (self->lock);
331   return TRUE;
332 }
333
334
335 static inline gdouble
336 _triangle_get (GstLFOControlSource * self, gdouble amp, gdouble off,
337     GstClockTime timeshift, GstClockTime period, gdouble frequency,
338     GstClockTime timestamp)
339 {
340   GstClockTime pos = _calculate_pos (timestamp, timeshift, period);
341   gdouble ret;
342
343   if (gst_guint64_to_gdouble (pos) <= gst_guint64_to_gdouble (period) / 4.0)
344     ret =
345         gst_guint64_to_gdouble (pos) * ((4.0 * amp) /
346         gst_guint64_to_gdouble (period));
347   else if (gst_guint64_to_gdouble (pos) <=
348       (3.0 * gst_guint64_to_gdouble (period)) / 4.0)
349     ret =
350         -(gst_guint64_to_gdouble (pos) -
351         gst_guint64_to_gdouble (period) / 2.0) * ((4.0 * amp) /
352         gst_guint64_to_gdouble (period));
353   else
354     ret =
355         gst_guint64_to_gdouble (period) -
356         gst_guint64_to_gdouble (pos) * ((4.0 * amp) /
357         gst_guint64_to_gdouble (period));
358
359   ret += off;
360
361   return ret;
362 }
363
364 static gboolean
365 waveform_triangle_get (GstLFOControlSource * self, GstClockTime timestamp,
366     gdouble * value)
367 {
368   GstLFOControlSourcePrivate *priv = self->priv;
369   gdouble amp, off, frequency;
370   GstClockTime timeshift, period;
371
372   g_mutex_lock (self->lock);
373   amp = priv->amplitude;
374   off = priv->offset;
375   timeshift = priv->timeshift;
376   period = priv->period;
377   frequency = priv->frequency;
378
379   *value =
380       _triangle_get (self, amp, off, timeshift, period, frequency, timestamp);
381   g_mutex_unlock (self->lock);
382   return TRUE;
383 }
384
385 static gboolean
386 waveform_triangle_get_value_array (GstLFOControlSource * self,
387     GstClockTime timestamp, GstClockTime interval, guint n_values,
388     gdouble * values)
389 {
390   GstLFOControlSourcePrivate *priv = self->priv;
391   guint i;
392   GstClockTime ts = timestamp;
393   gdouble amp, off, frequency;
394   GstClockTime timeshift, period;
395
396   g_mutex_lock (self->lock);
397   amp = priv->amplitude;
398   off = priv->offset;
399   timeshift = priv->timeshift;
400   period = priv->period;
401   frequency = priv->frequency;
402
403   for (i = 0; i < n_values; i++) {
404     *values = _triangle_get (self, amp, off, timeshift, period, frequency, ts);
405     ts += interval;
406     values++;
407   }
408   g_mutex_unlock (self->lock);
409   return TRUE;
410 }
411
412 static struct
413 {
414   GstControlSourceGetValue get;
415   GstControlSourceGetValueArray get_value_array;
416 } waveforms[] = {
417   {
418   (GstControlSourceGetValue) waveform_sine_get,
419         (GstControlSourceGetValueArray) waveform_sine_get_value_array}, {
420   (GstControlSourceGetValue) waveform_square_get,
421         (GstControlSourceGetValueArray) waveform_square_get_value_array}, {
422   (GstControlSourceGetValue) waveform_saw_get,
423         (GstControlSourceGetValueArray) waveform_saw_get_value_array}, {
424   (GstControlSourceGetValue) waveform_rsaw_get,
425         (GstControlSourceGetValueArray) waveform_rsaw_get_value_array}, {
426   (GstControlSourceGetValue) waveform_triangle_get,
427         (GstControlSourceGetValueArray) waveform_triangle_get_value_array}
428 };
429
430 static const guint num_waveforms = G_N_ELEMENTS (waveforms);
431
432 enum
433 {
434   PROP_WAVEFORM = 1,
435   PROP_FREQUENCY,
436   PROP_TIMESHIFT,
437   PROP_AMPLITUDE,
438   PROP_OFFSET
439 };
440
441 GType
442 gst_lfo_waveform_get_type (void)
443 {
444   static gsize gtype = 0;
445   static const GEnumValue values[] = {
446     {GST_LFO_WAVEFORM_SINE, "GST_LFO_WAVEFORM_SINE",
447         "sine"},
448     {GST_LFO_WAVEFORM_SQUARE, "GST_LFO_WAVEFORM_SQUARE",
449         "square"},
450     {GST_LFO_WAVEFORM_SAW, "GST_LFO_WAVEFORM_SAW",
451         "saw"},
452     {GST_LFO_WAVEFORM_REVERSE_SAW, "GST_LFO_WAVEFORM_REVERSE_SAW",
453         "reverse-saw"},
454     {GST_LFO_WAVEFORM_TRIANGLE, "GST_LFO_WAVEFORM_TRIANGLE",
455         "triangle"},
456     {0, NULL, NULL}
457   };
458
459   if (g_once_init_enter (&gtype)) {
460     GType tmp = g_enum_register_static ("GstLFOWaveform", values);
461     g_once_init_leave (&gtype, tmp);
462   }
463
464   return (GType) gtype;
465 }
466
467 #define _do_init \
468   GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "lfo control source", 0, "low frequency oscillator control source")
469
470 G_DEFINE_TYPE_WITH_CODE (GstLFOControlSource, gst_lfo_control_source,
471     GST_TYPE_CONTROL_SOURCE, _do_init);
472
473 static void
474 gst_lfo_control_source_reset (GstLFOControlSource * self)
475 {
476   GstControlSource *csource = GST_CONTROL_SOURCE (self);
477
478   csource->get_value = NULL;
479   csource->get_value_array = NULL;
480 }
481
482 /**
483  * gst_lfo_control_source_new:
484  *
485  * This returns a new, unbound #GstLFOControlSource.
486  *
487  * Returns: a new, unbound #GstLFOControlSource.
488  */
489 GstLFOControlSource *
490 gst_lfo_control_source_new (void)
491 {
492   return g_object_newv (GST_TYPE_LFO_CONTROL_SOURCE, 0, NULL);
493 }
494
495 static gboolean
496 gst_lfo_control_source_set_waveform (GstLFOControlSource * self,
497     GstLFOWaveform waveform)
498 {
499   GstControlSource *csource = GST_CONTROL_SOURCE (self);
500
501   if (waveform >= num_waveforms || (int) waveform < 0) {
502     GST_WARNING ("waveform %d invalid or not implemented yet", waveform);
503     return FALSE;
504   }
505
506   csource->get_value = waveforms[waveform].get;
507   csource->get_value_array = waveforms[waveform].get_value_array;
508
509   self->priv->waveform = waveform;
510
511   return TRUE;
512 }
513
514 static void
515 gst_lfo_control_source_init (GstLFOControlSource * self)
516 {
517   self->priv =
518       G_TYPE_INSTANCE_GET_PRIVATE (self, GST_TYPE_LFO_CONTROL_SOURCE,
519       GstLFOControlSourcePrivate);
520   self->priv->waveform = gst_lfo_control_source_set_waveform (self,
521       GST_LFO_WAVEFORM_SINE);
522   self->priv->frequency = 1.0;
523   self->priv->period = GST_SECOND / self->priv->frequency;
524   self->priv->timeshift = 0;
525
526   self->lock = g_mutex_new ();
527 }
528
529 static void
530 gst_lfo_control_source_finalize (GObject * obj)
531 {
532   GstLFOControlSource *self = GST_LFO_CONTROL_SOURCE (obj);
533
534   gst_lfo_control_source_reset (self);
535   g_mutex_free (self->lock);
536
537   G_OBJECT_CLASS (gst_lfo_control_source_parent_class)->finalize (obj);
538 }
539
540 static void
541 gst_lfo_control_source_set_property (GObject * object, guint prop_id,
542     const GValue * value, GParamSpec * pspec)
543 {
544   GstLFOControlSource *self = GST_LFO_CONTROL_SOURCE (object);
545
546   switch (prop_id) {
547     case PROP_WAVEFORM:
548       g_mutex_lock (self->lock);
549       gst_lfo_control_source_set_waveform (self,
550           (GstLFOWaveform) g_value_get_enum (value));
551       g_mutex_unlock (self->lock);
552       break;
553     case PROP_FREQUENCY:{
554       gdouble frequency = g_value_get_double (value);
555
556       g_return_if_fail (frequency > 0
557           || ((GstClockTime) (GST_SECOND / frequency)) != 0);
558
559       g_mutex_lock (self->lock);
560       self->priv->frequency = frequency;
561       self->priv->period = GST_SECOND / frequency;
562       g_mutex_unlock (self->lock);
563       break;
564     }
565     case PROP_TIMESHIFT:
566       g_mutex_lock (self->lock);
567       self->priv->timeshift = g_value_get_uint64 (value);
568       g_mutex_unlock (self->lock);
569       break;
570     case PROP_AMPLITUDE:
571       g_mutex_lock (self->lock);
572       self->priv->amplitude = g_value_get_double (value);
573       g_mutex_unlock (self->lock);
574       break;
575     case PROP_OFFSET:
576       g_mutex_lock (self->lock);
577       self->priv->offset = g_value_get_double (value);
578       g_mutex_unlock (self->lock);
579       break;
580     default:
581       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
582       break;
583   }
584 }
585
586 static void
587 gst_lfo_control_source_get_property (GObject * object, guint prop_id,
588     GValue * value, GParamSpec * pspec)
589 {
590   GstLFOControlSource *self = GST_LFO_CONTROL_SOURCE (object);
591
592   switch (prop_id) {
593     case PROP_WAVEFORM:
594       g_value_set_enum (value, self->priv->waveform);
595       break;
596     case PROP_FREQUENCY:
597       g_value_set_double (value, self->priv->frequency);
598       break;
599     case PROP_TIMESHIFT:
600       g_value_set_uint64 (value, self->priv->timeshift);
601       break;
602     case PROP_AMPLITUDE:
603       g_value_set_double (value, self->priv->amplitude);
604       break;
605     case PROP_OFFSET:
606       g_value_set_double (value, self->priv->offset);
607       break;
608     default:
609       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
610       break;
611   }
612 }
613
614 static void
615 gst_lfo_control_source_class_init (GstLFOControlSourceClass * klass)
616 {
617   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
618
619   g_type_class_add_private (klass, sizeof (GstLFOControlSourcePrivate));
620
621   gobject_class->finalize = gst_lfo_control_source_finalize;
622   gobject_class->set_property = gst_lfo_control_source_set_property;
623   gobject_class->get_property = gst_lfo_control_source_get_property;
624
625   /**
626    * GstLFOControlSource:waveform
627    *
628    * Specifies the waveform that should be used for this #GstLFOControlSource.
629    */
630   g_object_class_install_property (gobject_class, PROP_WAVEFORM,
631       g_param_spec_enum ("waveform", "Waveform", "Waveform",
632           GST_TYPE_LFO_WAVEFORM, GST_LFO_WAVEFORM_SINE,
633           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
634
635   /**
636    * GstLFOControlSource:frequency
637    *
638    * Specifies the frequency that should be used for the waveform
639    * of this #GstLFOControlSource. It should be large enough
640    * so that the period is longer than one nanosecond.
641    */
642   g_object_class_install_property (gobject_class, PROP_FREQUENCY,
643       g_param_spec_double ("frequency", "Frequency",
644           "Frequency of the waveform", 0.0, G_MAXDOUBLE, 1.0,
645           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
646
647   /**
648    * GstLFOControlSource:timeshift
649    *
650    * Specifies the timeshift to the right that should be used for the waveform
651    * of this #GstLFOControlSource in nanoseconds.
652    *
653    * To get a n nanosecond shift to the left use
654    * "(GST_SECOND / frequency) - n".
655    *
656    */
657   g_object_class_install_property (gobject_class, PROP_TIMESHIFT,
658       g_param_spec_uint64 ("timeshift", "Timeshift",
659           "Timeshift of the waveform to the right", 0, G_MAXUINT64, 0,
660           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
661
662   /**
663    * GstLFOControlSource:amplitude
664    *
665    * Specifies the amplitude for the waveform of this #GstLFOControlSource.
666    */
667   g_object_class_install_property (gobject_class, PROP_AMPLITUDE,
668       g_param_spec_double ("amplitude", "Amplitude",
669           "Amplitude of the waveform", 0.0, G_MAXDOUBLE, 1.0,
670           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
671
672   /**
673    * GstLFOControlSource:offset
674    *
675    * Specifies the value offset for the waveform of this #GstLFOControlSource.
676    */
677   g_object_class_install_property (gobject_class, PROP_OFFSET,
678       g_param_spec_double ("offset", "Offset", "Offset of the waveform",
679           0.0, G_MAXDOUBLE, 1.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
680 }