2cea4f80d5d27ec4e2a2650daf115746f1bd57c9
[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 #define _do_init \
376   GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "lfo control source", 0, "low frequency oscillator control source")
377
378 #define gst_lfo_control_source_parent_class parent_class
379 G_DEFINE_TYPE_WITH_CODE (GstLFOControlSource, gst_lfo_control_source,
380     GST_TYPE_CONTROL_SOURCE, G_ADD_PRIVATE (GstLFOControlSource) _do_init);
381
382 static void
383 gst_lfo_control_source_reset (GstLFOControlSource * self)
384 {
385   GstControlSource *csource = GST_CONTROL_SOURCE (self);
386
387   csource->get_value = NULL;
388   csource->get_value_array = NULL;
389 }
390
391 /**
392  * gst_lfo_control_source_new:
393  *
394  * This returns a new, unbound #GstLFOControlSource.
395  *
396  * Returns: (transfer full): a new, unbound #GstLFOControlSource.
397  */
398 GstControlSource *
399 gst_lfo_control_source_new (void)
400 {
401   GstControlSource *csource = g_object_new (GST_TYPE_LFO_CONTROL_SOURCE, NULL);
402
403   /* Clear floating flag */
404   gst_object_ref_sink (csource);
405
406   return csource;
407 }
408
409 static gboolean
410 gst_lfo_control_source_set_waveform (GstLFOControlSource * self,
411     GstLFOWaveform waveform)
412 {
413   GstControlSource *csource = GST_CONTROL_SOURCE (self);
414
415   if (waveform >= num_waveforms || (int) waveform < 0) {
416     GST_WARNING ("waveform %d invalid or not implemented yet", waveform);
417     return FALSE;
418   }
419
420   csource->get_value = waveforms[waveform].get;
421   csource->get_value_array = waveforms[waveform].get_value_array;
422
423   self->priv->waveform = waveform;
424
425   return TRUE;
426 }
427
428 static void
429 gst_lfo_control_source_init (GstLFOControlSource * self)
430 {
431   self->priv = gst_lfo_control_source_get_instance_private (self);
432   self->priv->waveform = gst_lfo_control_source_set_waveform (self,
433       GST_LFO_WAVEFORM_SINE);
434   self->priv->frequency = 1.0;
435   self->priv->amplitude = 1.0;
436   self->priv->period = GST_SECOND / self->priv->frequency;
437   self->priv->timeshift = 0;
438
439   g_mutex_init (&self->lock);
440 }
441
442 static void
443 gst_lfo_control_source_finalize (GObject * obj)
444 {
445   GstLFOControlSource *self = GST_LFO_CONTROL_SOURCE (obj);
446
447   gst_lfo_control_source_reset (self);
448   g_mutex_clear (&self->lock);
449
450   G_OBJECT_CLASS (parent_class)->finalize (obj);
451 }
452
453 static void
454 gst_lfo_control_source_set_property (GObject * object, guint prop_id,
455     const GValue * value, GParamSpec * pspec)
456 {
457   GstLFOControlSource *self = GST_LFO_CONTROL_SOURCE (object);
458
459   switch (prop_id) {
460     case PROP_WAVEFORM:
461       g_mutex_lock (&self->lock);
462       gst_lfo_control_source_set_waveform (self,
463           (GstLFOWaveform) g_value_get_enum (value));
464       g_mutex_unlock (&self->lock);
465       break;
466     case PROP_FREQUENCY:{
467       gdouble frequency = g_value_get_double (value);
468
469       g_return_if_fail (((GstClockTime) (GST_SECOND / frequency)) != 0);
470
471       g_mutex_lock (&self->lock);
472       self->priv->frequency = frequency;
473       self->priv->period = GST_SECOND / frequency;
474       g_mutex_unlock (&self->lock);
475       break;
476     }
477     case PROP_TIMESHIFT:
478       g_mutex_lock (&self->lock);
479       self->priv->timeshift = g_value_get_uint64 (value);
480       g_mutex_unlock (&self->lock);
481       break;
482     case PROP_AMPLITUDE:
483       g_mutex_lock (&self->lock);
484       self->priv->amplitude = g_value_get_double (value);
485       g_mutex_unlock (&self->lock);
486       break;
487     case PROP_OFFSET:
488       g_mutex_lock (&self->lock);
489       self->priv->offset = g_value_get_double (value);
490       g_mutex_unlock (&self->lock);
491       break;
492     default:
493       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
494       break;
495   }
496 }
497
498 static void
499 gst_lfo_control_source_get_property (GObject * object, guint prop_id,
500     GValue * value, GParamSpec * pspec)
501 {
502   GstLFOControlSource *self = GST_LFO_CONTROL_SOURCE (object);
503
504   switch (prop_id) {
505     case PROP_WAVEFORM:
506       g_value_set_enum (value, self->priv->waveform);
507       break;
508     case PROP_FREQUENCY:
509       g_value_set_double (value, self->priv->frequency);
510       break;
511     case PROP_TIMESHIFT:
512       g_value_set_uint64 (value, self->priv->timeshift);
513       break;
514     case PROP_AMPLITUDE:
515       g_value_set_double (value, self->priv->amplitude);
516       break;
517     case PROP_OFFSET:
518       g_value_set_double (value, self->priv->offset);
519       break;
520     default:
521       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
522       break;
523   }
524 }
525
526 static void
527 gst_lfo_control_source_class_init (GstLFOControlSourceClass * klass)
528 {
529   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
530
531   gobject_class->finalize = gst_lfo_control_source_finalize;
532   gobject_class->set_property = gst_lfo_control_source_set_property;
533   gobject_class->get_property = gst_lfo_control_source_get_property;
534
535   /**
536    * GstLFOControlSource:waveform:
537    *
538    * Specifies the waveform that should be used for this #GstLFOControlSource.
539    */
540   g_object_class_install_property (gobject_class, PROP_WAVEFORM,
541       g_param_spec_enum ("waveform", "Waveform", "Waveform",
542           GST_TYPE_LFO_WAVEFORM, GST_LFO_WAVEFORM_SINE,
543           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
544
545   /**
546    * GstLFOControlSource:frequency:
547    *
548    * Specifies the frequency that should be used for the waveform
549    * of this #GstLFOControlSource. It should be large enough
550    * so that the period is longer than one nanosecond.
551    */
552   g_object_class_install_property (gobject_class, PROP_FREQUENCY,
553       g_param_spec_double ("frequency", "Frequency",
554           "Frequency of the waveform", DBL_MIN, G_MAXDOUBLE, 1.0,
555           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
556
557   /**
558    * GstLFOControlSource:timeshift:
559    *
560    * Specifies the timeshift to the right that should be used for the waveform
561    * of this #GstLFOControlSource in nanoseconds.
562    *
563    * To get a n nanosecond shift to the left use
564    * "(GST_SECOND / frequency) - n".
565    *
566    */
567   g_object_class_install_property (gobject_class, PROP_TIMESHIFT,
568       g_param_spec_uint64 ("timeshift", "Timeshift",
569           "Timeshift of the waveform to the right", 0, G_MAXUINT64, 0,
570           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
571
572   /**
573    * GstLFOControlSource:amplitude:
574    *
575    * Specifies the amplitude for the waveform of this #GstLFOControlSource.
576    */
577   g_object_class_install_property (gobject_class, PROP_AMPLITUDE,
578       g_param_spec_double ("amplitude", "Amplitude",
579           "Amplitude of the waveform", 0.0, 1.0, 1.0,
580           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
581
582   /**
583    * GstLFOControlSource:offset:
584    *
585    * Specifies the value offset for the waveform of this #GstLFOControlSource.
586    */
587   g_object_class_install_property (gobject_class, PROP_OFFSET,
588       g_param_spec_double ("offset", "Offset", "Offset of the waveform",
589           0.0, 1.0, 1.0,
590           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
591 }