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