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