libs/gst/controller/: Use gst_guint64_to_gdouble() when converting from a uint64 or
[platform/upstream/gstreamer.git] / libs / gst / controller / gstlfocontrolsource.c
1 /* GStreamer
2  *
3  * Copyright (C) 2007 Sebastian Dröge <slomo@circular-chaos.org>
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
42 #include "gstcontrolsource.h"
43 #include "gstlfocontrolsource.h"
44 #include "gstlfocontrolsourceprivate.h"
45
46 #include "math.h"
47
48 #define EMPTY(x) (x)
49
50 /* FIXME: as % in C is not the modulo operator we need here for
51  * negative numbers implement our own. Are there better ways? */
52 static inline GstClockTime
53 _calculate_pos (GstClockTime timestamp, GstClockTime timeshift,
54     GstClockTime period)
55 {
56   while (timestamp < timeshift)
57     timestamp += period;
58
59   timestamp -= timeshift;
60
61   return timestamp % period;
62 }
63
64 #define DEFINE_SINE(type,round,convert) \
65 \
66 static inline g##type \
67 _sine_get_##type (GstLFOControlSource *self, GstClockTime timestamp) \
68 { \
69   gdouble ret; \
70   g##type max = g_value_get_##type (&self->priv->maximum_value); \
71   g##type min = g_value_get_##type (&self->priv->minimum_value); \
72   gdouble amp = convert (g_value_get_##type (&self->priv->amplitude)); \
73   gdouble off = convert (g_value_get_##type (&self->priv->offset)); \
74   GstClockTime pos = _calculate_pos (timestamp, self->priv->timeshift, self->priv->period); \
75   \
76   ret = sin (2.0 * M_PI * (self->priv->frequency / GST_SECOND) * gst_util_guint64_to_gdouble (pos)); \
77   ret *= amp; \
78   ret += off; \
79   \
80   if (round) \
81     ret += 0.5; \
82   \
83   return (g##type) CLAMP (ret, convert (min), convert (max)); \
84 } \
85 \
86 static gboolean \
87 waveform_sine_get_##type (GstLFOControlSource *self, GstClockTime timestamp, \
88     GValue *value) \
89 { \
90   g##type ret; \
91   g_mutex_lock (self->lock); \
92   ret = _sine_get_##type (self, timestamp); \
93   g_value_set_##type (value, ret); \
94   g_mutex_unlock (self->lock); \
95   return TRUE; \
96 } \
97 \
98 static gboolean \
99 waveform_sine_get_##type##_value_array (GstLFOControlSource *self, \
100    GstClockTime timestamp, GstValueArray * value_array) \
101 { \
102   gint i; \
103   GstClockTime ts = timestamp; \
104   g##type *values = (g##type *) value_array->values; \
105   \
106   g_mutex_lock (self->lock); \
107   for(i = 0; i < value_array->nbsamples; i++) { \
108     *values = _sine_get_##type (self, ts); \
109     ts += value_array->sample_interval; \
110     values++; \
111   } \
112   g_mutex_unlock (self->lock); \
113   return TRUE; \
114 }
115
116 DEFINE_SINE (int, TRUE, EMPTY);
117 DEFINE_SINE (uint, TRUE, EMPTY);
118 DEFINE_SINE (long, TRUE, EMPTY);
119
120 DEFINE_SINE (ulong, TRUE, EMPTY);
121 DEFINE_SINE (int64, TRUE, EMPTY);
122 DEFINE_SINE (uint64, TRUE, gst_util_guint64_to_gdouble);
123 DEFINE_SINE (float, FALSE, EMPTY);
124 DEFINE_SINE (double, FALSE, EMPTY);
125
126 static GstWaveformImplementation waveform_sine = {
127   (GstControlSourceGetValue) waveform_sine_get_int,
128   (GstControlSourceGetValueArray) waveform_sine_get_int_value_array,
129   (GstControlSourceGetValue) waveform_sine_get_uint,
130   (GstControlSourceGetValueArray) waveform_sine_get_uint_value_array,
131   (GstControlSourceGetValue) waveform_sine_get_long,
132   (GstControlSourceGetValueArray) waveform_sine_get_long_value_array,
133   (GstControlSourceGetValue) waveform_sine_get_ulong,
134   (GstControlSourceGetValueArray) waveform_sine_get_ulong_value_array,
135   (GstControlSourceGetValue) waveform_sine_get_int64,
136   (GstControlSourceGetValueArray) waveform_sine_get_int64_value_array,
137   (GstControlSourceGetValue) waveform_sine_get_uint64,
138   (GstControlSourceGetValueArray) waveform_sine_get_uint64_value_array,
139   (GstControlSourceGetValue) waveform_sine_get_float,
140   (GstControlSourceGetValueArray) waveform_sine_get_float_value_array,
141   (GstControlSourceGetValue) waveform_sine_get_double,
142   (GstControlSourceGetValueArray) waveform_sine_get_double_value_array
143 };
144
145 #define DEFINE_SQUARE(type,round, convert) \
146 \
147 static inline g##type \
148 _square_get_##type (GstLFOControlSource *self, GstClockTime timestamp) \
149 { \
150   g##type max = g_value_get_##type (&self->priv->maximum_value); \
151   g##type min = g_value_get_##type (&self->priv->minimum_value); \
152   gdouble amp = convert (g_value_get_##type (&self->priv->amplitude)); \
153   gdouble off = convert (g_value_get_##type (&self->priv->offset)); \
154   GstClockTime period = self->priv->period; \
155   GstClockTime pos = _calculate_pos (timestamp, self->priv->timeshift, period); \
156   gdouble ret; \
157   \
158   if (pos >= period / 2) \
159     ret = amp; \
160   else \
161     ret = - amp; \
162   \
163   ret += off; \
164   \
165   if (round) \
166     ret += 0.5; \
167   \
168   return (g##type) CLAMP (ret, convert (min), convert (max)); \
169 } \
170 \
171 static gboolean \
172 waveform_square_get_##type (GstLFOControlSource *self, GstClockTime timestamp, \
173     GValue *value) \
174 { \
175   g##type ret; \
176   g_mutex_lock (self->lock); \
177   ret = _square_get_##type (self, timestamp); \
178   g_value_set_##type (value, ret); \
179   g_mutex_unlock (self->lock); \
180   return TRUE; \
181 } \
182 \
183 static gboolean \
184 waveform_square_get_##type##_value_array (GstLFOControlSource *self, \
185    GstClockTime timestamp, GstValueArray * value_array) \
186 { \
187   gint i; \
188   GstClockTime ts = timestamp; \
189   g##type *values = (g##type *) value_array->values; \
190   \
191   g_mutex_lock (self->lock); \
192   for(i = 0; i < value_array->nbsamples; i++) { \
193     *values = _square_get_##type (self, ts); \
194     ts += value_array->sample_interval; \
195     values++; \
196   } \
197   g_mutex_unlock (self->lock); \
198   return TRUE; \
199 }
200
201 DEFINE_SQUARE (int, TRUE, EMPTY);
202
203 DEFINE_SQUARE (uint, TRUE, EMPTY);
204 DEFINE_SQUARE (long, TRUE, EMPTY);
205
206 DEFINE_SQUARE (ulong, TRUE, EMPTY);
207 DEFINE_SQUARE (int64, TRUE, EMPTY);
208 DEFINE_SQUARE (uint64, TRUE, gst_util_guint64_to_gdouble);
209 DEFINE_SQUARE (float, FALSE, EMPTY);
210 DEFINE_SQUARE (double, FALSE, EMPTY);
211
212 static GstWaveformImplementation waveform_square = {
213   (GstControlSourceGetValue) waveform_square_get_int,
214   (GstControlSourceGetValueArray) waveform_square_get_int_value_array,
215   (GstControlSourceGetValue) waveform_square_get_uint,
216   (GstControlSourceGetValueArray) waveform_square_get_uint_value_array,
217   (GstControlSourceGetValue) waveform_square_get_long,
218   (GstControlSourceGetValueArray) waveform_square_get_long_value_array,
219   (GstControlSourceGetValue) waveform_square_get_ulong,
220   (GstControlSourceGetValueArray) waveform_square_get_ulong_value_array,
221   (GstControlSourceGetValue) waveform_square_get_int64,
222   (GstControlSourceGetValueArray) waveform_square_get_int64_value_array,
223   (GstControlSourceGetValue) waveform_square_get_uint64,
224   (GstControlSourceGetValueArray) waveform_square_get_uint64_value_array,
225   (GstControlSourceGetValue) waveform_square_get_float,
226   (GstControlSourceGetValueArray) waveform_square_get_float_value_array,
227   (GstControlSourceGetValue) waveform_square_get_double,
228   (GstControlSourceGetValueArray) waveform_square_get_double_value_array
229 };
230
231 #define DEFINE_SAW(type,round,convert) \
232 \
233 static inline g##type \
234 _saw_get_##type (GstLFOControlSource *self, GstClockTime timestamp) \
235 { \
236   g##type max = g_value_get_##type (&self->priv->maximum_value); \
237   g##type min = g_value_get_##type (&self->priv->minimum_value); \
238   gdouble amp = convert (g_value_get_##type (&self->priv->amplitude)); \
239   gdouble off = convert (g_value_get_##type (&self->priv->offset)); \
240   GstClockTime period = self->priv->period; \
241   GstClockTime pos = _calculate_pos (timestamp, self->priv->timeshift, period); \
242   gdouble ret; \
243   \
244   ret = - ((gst_util_guint64_to_gdouble (pos) - gst_util_guint64_to_gdouble (period) / 2.0) * ((2.0 * amp) / gst_util_guint64_to_gdouble (period)));\
245   \
246   ret += off; \
247   \
248   if (round) \
249     ret += 0.5; \
250   \
251   return (g##type) CLAMP (ret, convert (min), convert (max)); \
252 } \
253 \
254 static gboolean \
255 waveform_saw_get_##type (GstLFOControlSource *self, GstClockTime timestamp, \
256     GValue *value) \
257 { \
258   g##type ret; \
259   g_mutex_lock (self->lock); \
260   ret = _saw_get_##type (self, timestamp); \
261   g_value_set_##type (value, ret); \
262   g_mutex_unlock (self->lock); \
263   return TRUE; \
264 } \
265 \
266 static gboolean \
267 waveform_saw_get_##type##_value_array (GstLFOControlSource *self, \
268    GstClockTime timestamp, GstValueArray * value_array) \
269 { \
270   gint i; \
271   GstClockTime ts = timestamp; \
272   g##type *values = (g##type *) value_array->values; \
273   \
274   g_mutex_lock (self->lock); \
275   for(i = 0; i < value_array->nbsamples; i++) { \
276     *values = _saw_get_##type (self, ts); \
277     ts += value_array->sample_interval; \
278     values++; \
279   } \
280   g_mutex_unlock (self->lock); \
281   return TRUE; \
282 }
283
284 DEFINE_SAW (int, TRUE, EMPTY);
285
286 DEFINE_SAW (uint, TRUE, EMPTY);
287 DEFINE_SAW (long, TRUE, EMPTY);
288
289 DEFINE_SAW (ulong, TRUE, EMPTY);
290 DEFINE_SAW (int64, TRUE, EMPTY);
291 DEFINE_SAW (uint64, TRUE, gst_util_guint64_to_gdouble);
292 DEFINE_SAW (float, FALSE, EMPTY);
293 DEFINE_SAW (double, FALSE, EMPTY);
294
295 static GstWaveformImplementation waveform_saw = {
296   (GstControlSourceGetValue) waveform_saw_get_int,
297   (GstControlSourceGetValueArray) waveform_saw_get_int_value_array,
298   (GstControlSourceGetValue) waveform_saw_get_uint,
299   (GstControlSourceGetValueArray) waveform_saw_get_uint_value_array,
300   (GstControlSourceGetValue) waveform_saw_get_long,
301   (GstControlSourceGetValueArray) waveform_saw_get_long_value_array,
302   (GstControlSourceGetValue) waveform_saw_get_ulong,
303   (GstControlSourceGetValueArray) waveform_saw_get_ulong_value_array,
304   (GstControlSourceGetValue) waveform_saw_get_int64,
305   (GstControlSourceGetValueArray) waveform_saw_get_int64_value_array,
306   (GstControlSourceGetValue) waveform_saw_get_uint64,
307   (GstControlSourceGetValueArray) waveform_saw_get_uint64_value_array,
308   (GstControlSourceGetValue) waveform_saw_get_float,
309   (GstControlSourceGetValueArray) waveform_saw_get_float_value_array,
310   (GstControlSourceGetValue) waveform_saw_get_double,
311   (GstControlSourceGetValueArray) waveform_saw_get_double_value_array
312 };
313
314 #define DEFINE_RSAW(type,round,convert) \
315 \
316 static inline g##type \
317 _rsaw_get_##type (GstLFOControlSource *self, GstClockTime timestamp) \
318 { \
319   g##type max = g_value_get_##type (&self->priv->maximum_value); \
320   g##type min = g_value_get_##type (&self->priv->minimum_value); \
321   gdouble amp = convert (g_value_get_##type (&self->priv->amplitude)); \
322   gdouble off = convert (g_value_get_##type (&self->priv->offset)); \
323   GstClockTime period = self->priv->period; \
324   GstClockTime pos = _calculate_pos (timestamp, self->priv->timeshift, period); \
325   gdouble ret; \
326   \
327   ret = ((gst_util_guint64_to_gdouble (pos) - gst_util_guint64_to_gdouble (period) / 2.0) * ((2.0 * amp) / gst_util_guint64_to_gdouble (period)));\
328   \
329   ret += off; \
330   \
331   if (round) \
332     ret += 0.5; \
333   \
334   return (g##type) CLAMP (ret, convert (min), convert (max)); \
335 } \
336 \
337 static gboolean \
338 waveform_rsaw_get_##type (GstLFOControlSource *self, GstClockTime timestamp, \
339     GValue *value) \
340 { \
341   g##type ret; \
342   g_mutex_lock (self->lock); \
343   ret = _rsaw_get_##type (self, timestamp); \
344   g_value_set_##type (value, ret); \
345   g_mutex_unlock (self->lock); \
346   return TRUE; \
347 } \
348 \
349 static gboolean \
350 waveform_rsaw_get_##type##_value_array (GstLFOControlSource *self, \
351    GstClockTime timestamp, GstValueArray * value_array) \
352 { \
353   gint i; \
354   GstClockTime ts = timestamp; \
355   g##type *values = (g##type *) value_array->values; \
356   \
357   g_mutex_lock (self->lock); \
358   for(i = 0; i < value_array->nbsamples; i++) { \
359     *values = _rsaw_get_##type (self, ts); \
360     ts += value_array->sample_interval; \
361     values++; \
362   } \
363   g_mutex_unlock (self->lock); \
364   return TRUE; \
365 }
366
367 DEFINE_RSAW (int, TRUE, EMPTY);
368
369 DEFINE_RSAW (uint, TRUE, EMPTY);
370 DEFINE_RSAW (long, TRUE, EMPTY);
371
372 DEFINE_RSAW (ulong, TRUE, EMPTY);
373 DEFINE_RSAW (int64, TRUE, EMPTY);
374 DEFINE_RSAW (uint64, TRUE, gst_util_guint64_to_gdouble);
375 DEFINE_RSAW (float, FALSE, EMPTY);
376 DEFINE_RSAW (double, FALSE, EMPTY);
377
378 static GstWaveformImplementation waveform_rsaw = {
379   (GstControlSourceGetValue) waveform_rsaw_get_int,
380   (GstControlSourceGetValueArray) waveform_rsaw_get_int_value_array,
381   (GstControlSourceGetValue) waveform_rsaw_get_uint,
382   (GstControlSourceGetValueArray) waveform_rsaw_get_uint_value_array,
383   (GstControlSourceGetValue) waveform_rsaw_get_long,
384   (GstControlSourceGetValueArray) waveform_rsaw_get_long_value_array,
385   (GstControlSourceGetValue) waveform_rsaw_get_ulong,
386   (GstControlSourceGetValueArray) waveform_rsaw_get_ulong_value_array,
387   (GstControlSourceGetValue) waveform_rsaw_get_int64,
388   (GstControlSourceGetValueArray) waveform_rsaw_get_int64_value_array,
389   (GstControlSourceGetValue) waveform_rsaw_get_uint64,
390   (GstControlSourceGetValueArray) waveform_rsaw_get_uint64_value_array,
391   (GstControlSourceGetValue) waveform_rsaw_get_float,
392   (GstControlSourceGetValueArray) waveform_rsaw_get_float_value_array,
393   (GstControlSourceGetValue) waveform_rsaw_get_double,
394   (GstControlSourceGetValueArray) waveform_rsaw_get_double_value_array
395 };
396
397 #define DEFINE_TRIANGLE(type,round,convert) \
398 \
399 static inline g##type \
400 _triangle_get_##type (GstLFOControlSource *self, GstClockTime timestamp) \
401 { \
402   g##type max = g_value_get_##type (&self->priv->maximum_value); \
403   g##type min = g_value_get_##type (&self->priv->minimum_value); \
404   gdouble amp = convert (g_value_get_##type (&self->priv->amplitude)); \
405   gdouble off = convert (g_value_get_##type (&self->priv->offset)); \
406   GstClockTime period = self->priv->period; \
407   GstClockTime pos = _calculate_pos (timestamp, self->priv->timeshift, period); \
408   gdouble ret; \
409   \
410   if (gst_util_guint64_to_gdouble (pos) <= gst_util_guint64_to_gdouble (period) / 4.0) \
411     ret = gst_util_guint64_to_gdouble (pos) * ((4.0 * amp) / gst_util_guint64_to_gdouble (period)); \
412   else if (gst_util_guint64_to_gdouble (pos) <= (3.0 * gst_util_guint64_to_gdouble (period)) / 4.0) \
413     ret = -(gst_util_guint64_to_gdouble (pos) - gst_util_guint64_to_gdouble (period) / 2.0) * ((4.0 * amp) / gst_util_guint64_to_gdouble (period)); \
414   else \
415     ret = gst_util_guint64_to_gdouble (period) - gst_util_guint64_to_gdouble (pos) * ((4.0 * amp) / gst_util_guint64_to_gdouble (period)); \
416   \
417   ret += off; \
418   \
419   if (round) \
420     ret += 0.5; \
421   \
422   return (g##type) CLAMP (ret, convert (min), convert (max)); \
423 } \
424 \
425 static gboolean \
426 waveform_triangle_get_##type (GstLFOControlSource *self, GstClockTime timestamp, \
427     GValue *value) \
428 { \
429   g##type ret; \
430   g_mutex_lock (self->lock); \
431   ret = _triangle_get_##type (self, timestamp); \
432   g_value_set_##type (value, ret); \
433   g_mutex_unlock (self->lock); \
434   return TRUE; \
435 } \
436 \
437 static gboolean \
438 waveform_triangle_get_##type##_value_array (GstLFOControlSource *self, \
439    GstClockTime timestamp, GstValueArray * value_array) \
440 { \
441   gint i; \
442   GstClockTime ts = timestamp; \
443   g##type *values = (g##type *) value_array->values; \
444   \
445   g_mutex_lock (self->lock); \
446   for(i = 0; i < value_array->nbsamples; i++) { \
447     *values = _triangle_get_##type (self, ts); \
448     ts += value_array->sample_interval; \
449     values++; \
450   } \
451   g_mutex_unlock (self->lock); \
452   return TRUE; \
453 }
454
455 DEFINE_TRIANGLE (int, TRUE, EMPTY);
456
457 DEFINE_TRIANGLE (uint, TRUE, EMPTY);
458 DEFINE_TRIANGLE (long, TRUE, EMPTY);
459
460 DEFINE_TRIANGLE (ulong, TRUE, EMPTY);
461 DEFINE_TRIANGLE (int64, TRUE, EMPTY);
462 DEFINE_TRIANGLE (uint64, TRUE, gst_util_guint64_to_gdouble);
463 DEFINE_TRIANGLE (float, FALSE, EMPTY);
464 DEFINE_TRIANGLE (double, FALSE, EMPTY);
465
466 static GstWaveformImplementation waveform_triangle = {
467   (GstControlSourceGetValue) waveform_triangle_get_int,
468   (GstControlSourceGetValueArray) waveform_triangle_get_int_value_array,
469   (GstControlSourceGetValue) waveform_triangle_get_uint,
470   (GstControlSourceGetValueArray) waveform_triangle_get_uint_value_array,
471   (GstControlSourceGetValue) waveform_triangle_get_long,
472   (GstControlSourceGetValueArray) waveform_triangle_get_long_value_array,
473   (GstControlSourceGetValue) waveform_triangle_get_ulong,
474   (GstControlSourceGetValueArray) waveform_triangle_get_ulong_value_array,
475   (GstControlSourceGetValue) waveform_triangle_get_int64,
476   (GstControlSourceGetValueArray) waveform_triangle_get_int64_value_array,
477   (GstControlSourceGetValue) waveform_triangle_get_uint64,
478   (GstControlSourceGetValueArray) waveform_triangle_get_uint64_value_array,
479   (GstControlSourceGetValue) waveform_triangle_get_float,
480   (GstControlSourceGetValueArray) waveform_triangle_get_float_value_array,
481   (GstControlSourceGetValue) waveform_triangle_get_double,
482   (GstControlSourceGetValueArray) waveform_triangle_get_double_value_array
483 };
484
485 static GstWaveformImplementation *waveforms[] = {
486   &waveform_sine,
487   &waveform_square,
488   &waveform_saw,
489   &waveform_rsaw,
490   &waveform_triangle
491 };
492
493 static guint num_waveforms = G_N_ELEMENTS (waveforms);
494
495 enum
496 {
497   PROP_WAVEFORM = 1,
498   PROP_FREQUENCY,
499   PROP_TIMESHIFT,
500   PROP_AMPLITUDE,
501   PROP_OFFSET
502 };
503
504 GType
505 gst_lfo_waveform_get_type (void)
506 {
507   static GType gtype = 0;
508
509   if (gtype == 0) {
510     static const GEnumValue values[] = {
511       {GST_LFO_WAVEFORM_SINE, "Sine waveform (default)",
512           "sine"},
513       {GST_LFO_WAVEFORM_SQUARE, "Square waveform",
514           "square"},
515       {GST_LFO_WAVEFORM_SAW, "Saw waveform",
516           "saw"},
517       {GST_LFO_WAVEFORM_REVERSE_SAW, "Reverse saw waveform",
518           "reverse-saw"},
519       {GST_LFO_WAVEFORM_TRIANGLE, "Triangle waveform",
520           "triangle"},
521       {0, NULL, NULL}
522     };
523
524     gtype = g_enum_register_static ("GstLFOWaveform", values);
525   }
526   return gtype;
527 }
528
529 static void gst_lfo_control_source_init (GstLFOControlSource * self);
530 static void
531 gst_lfo_control_source_class_init (GstLFOControlSourceClass * klass);
532
533 G_DEFINE_TYPE (GstLFOControlSource, gst_lfo_control_source,
534     GST_TYPE_CONTROL_SOURCE);
535
536 static GObjectClass *parent_class = NULL;
537
538 static void
539 gst_lfo_control_source_reset (GstLFOControlSource * self)
540 {
541   GstControlSource *csource = GST_CONTROL_SOURCE (self);
542
543   csource->get_value = NULL;
544   csource->get_value_array = NULL;
545
546   self->priv->type = self->priv->base = G_TYPE_INVALID;
547
548   if (G_IS_VALUE (&self->priv->minimum_value))
549     g_value_unset (&self->priv->minimum_value);
550   if (G_IS_VALUE (&self->priv->maximum_value))
551     g_value_unset (&self->priv->maximum_value);
552
553   if (G_IS_VALUE (&self->priv->amplitude))
554     g_value_unset (&self->priv->amplitude);
555   if (G_IS_VALUE (&self->priv->offset))
556     g_value_unset (&self->priv->offset);
557 }
558
559 /**
560  * gst_lfo_control_source_new:
561  *
562  * This returns a new, unbound #GstLFOControlSource.
563  *
564  * Returns: a new, unbound #GstLFOControlSource.
565  */
566 GstLFOControlSource *
567 gst_lfo_control_source_new ()
568 {
569   return g_object_new (GST_TYPE_LFO_CONTROL_SOURCE, NULL);
570 }
571
572 static gboolean
573 gst_lfo_control_source_set_waveform (GstLFOControlSource * self,
574     GstLFOWaveform waveform)
575 {
576   GstControlSource *csource = GST_CONTROL_SOURCE (self);
577   gboolean ret = TRUE;
578
579   if (waveform >= num_waveforms || waveform < 0) {
580     GST_WARNING ("waveform %d invalid or not implemented yet", waveform);
581     return FALSE;
582   }
583
584   if (self->priv->base == G_TYPE_INVALID) {
585     GST_WARNING ("not bound to a property yet");
586     return FALSE;
587   }
588
589   switch (self->priv->base) {
590     case G_TYPE_INT:
591       csource->get_value = waveforms[waveform]->get_int;
592       csource->get_value_array = waveforms[waveform]->get_int_value_array;
593       break;
594     case G_TYPE_UINT:{
595       csource->get_value = waveforms[waveform]->get_uint;
596       csource->get_value_array = waveforms[waveform]->get_uint_value_array;
597       break;
598     }
599     case G_TYPE_LONG:{
600       csource->get_value = waveforms[waveform]->get_long;
601       csource->get_value_array = waveforms[waveform]->get_long_value_array;
602       break;
603     }
604     case G_TYPE_ULONG:{
605       csource->get_value = waveforms[waveform]->get_ulong;
606       csource->get_value_array = waveforms[waveform]->get_ulong_value_array;
607       break;
608     }
609     case G_TYPE_INT64:{
610       csource->get_value = waveforms[waveform]->get_int64;
611       csource->get_value_array = waveforms[waveform]->get_int64_value_array;
612       break;
613     }
614     case G_TYPE_UINT64:{
615       csource->get_value = waveforms[waveform]->get_uint64;
616       csource->get_value_array = waveforms[waveform]->get_uint64_value_array;
617       break;
618     }
619     case G_TYPE_FLOAT:{
620       csource->get_value = waveforms[waveform]->get_float;
621       csource->get_value_array = waveforms[waveform]->get_float_value_array;
622       break;
623     }
624     case G_TYPE_DOUBLE:{
625       csource->get_value = waveforms[waveform]->get_double;
626       csource->get_value_array = waveforms[waveform]->get_double_value_array;
627       break;
628     }
629     default:
630       ret = FALSE;
631       break;
632   }
633
634   if (ret)
635     self->priv->waveform = waveform;
636   else
637     GST_WARNING ("incomplete implementation for type '%s'",
638         GST_STR_NULL (g_type_name (self->priv->type)));
639
640   return ret;
641 }
642
643 static gboolean
644 gst_lfo_control_source_bind (GstControlSource * source, GParamSpec * pspec)
645 {
646   GType type, base;
647   GstLFOControlSource *self = GST_LFO_CONTROL_SOURCE (source);
648   gboolean ret = TRUE;
649
650   /* get the fundamental base type */
651   self->priv->type = base = type = G_PARAM_SPEC_VALUE_TYPE (pspec);
652   while ((type = g_type_parent (type)))
653     base = type;
654
655   self->priv->base = base;
656   /* restore type */
657   type = self->priv->type;
658
659   switch (base) {
660     case G_TYPE_INT:{
661       GParamSpecInt *tpspec = G_PARAM_SPEC_INT (pspec);
662
663       g_value_init (&self->priv->minimum_value, type);
664       g_value_set_int (&self->priv->minimum_value, tpspec->minimum);
665       g_value_init (&self->priv->maximum_value, type);
666       g_value_set_int (&self->priv->maximum_value, tpspec->maximum);
667
668       if (!G_IS_VALUE (&self->priv->amplitude)) {
669         g_value_init (&self->priv->amplitude, type);
670         g_value_set_int (&self->priv->amplitude, 0);
671       }
672
673       if (!G_IS_VALUE (&self->priv->offset)) {
674         g_value_init (&self->priv->offset, type);
675         g_value_set_int (&self->priv->offset, tpspec->default_value);
676       }
677       break;
678     }
679     case G_TYPE_UINT:{
680       GParamSpecUInt *tpspec = G_PARAM_SPEC_UINT (pspec);
681
682       g_value_init (&self->priv->minimum_value, type);
683       g_value_set_uint (&self->priv->minimum_value, tpspec->minimum);
684       g_value_init (&self->priv->maximum_value, type);
685       g_value_set_uint (&self->priv->maximum_value, tpspec->maximum);
686
687       if (!G_IS_VALUE (&self->priv->amplitude)) {
688         g_value_init (&self->priv->amplitude, type);
689         g_value_set_uint (&self->priv->amplitude, 0);
690       }
691
692       if (!G_IS_VALUE (&self->priv->offset)) {
693         g_value_init (&self->priv->offset, type);
694         g_value_set_uint (&self->priv->offset, tpspec->default_value);
695       }
696       break;
697     }
698     case G_TYPE_LONG:{
699       GParamSpecLong *tpspec = G_PARAM_SPEC_LONG (pspec);
700
701       g_value_init (&self->priv->minimum_value, type);
702       g_value_set_long (&self->priv->minimum_value, tpspec->minimum);
703       g_value_init (&self->priv->maximum_value, type);
704       g_value_set_long (&self->priv->maximum_value, tpspec->maximum);
705       if (!G_IS_VALUE (&self->priv->amplitude)) {
706         g_value_init (&self->priv->amplitude, type);
707         g_value_set_long (&self->priv->amplitude, 0);
708       }
709
710       if (!G_IS_VALUE (&self->priv->offset)) {
711         g_value_init (&self->priv->offset, type);
712         g_value_set_long (&self->priv->offset, tpspec->default_value);
713       }
714       break;
715     }
716     case G_TYPE_ULONG:{
717       GParamSpecULong *tpspec = G_PARAM_SPEC_ULONG (pspec);
718
719       g_value_init (&self->priv->minimum_value, type);
720       g_value_set_ulong (&self->priv->minimum_value, tpspec->minimum);
721       g_value_init (&self->priv->maximum_value, type);
722       g_value_set_ulong (&self->priv->maximum_value, tpspec->maximum);
723       if (!G_IS_VALUE (&self->priv->amplitude)) {
724         g_value_init (&self->priv->amplitude, type);
725         g_value_set_ulong (&self->priv->amplitude, 0);
726       }
727
728       if (!G_IS_VALUE (&self->priv->offset)) {
729         g_value_init (&self->priv->offset, type);
730         g_value_set_ulong (&self->priv->offset, tpspec->default_value);
731       }
732       break;
733     }
734     case G_TYPE_INT64:{
735       GParamSpecInt64 *tpspec = G_PARAM_SPEC_INT64 (pspec);
736
737       g_value_init (&self->priv->minimum_value, type);
738       g_value_set_int64 (&self->priv->minimum_value, tpspec->minimum);
739       g_value_init (&self->priv->maximum_value, type);
740       g_value_set_int64 (&self->priv->maximum_value, tpspec->maximum);
741       if (!G_IS_VALUE (&self->priv->amplitude)) {
742         g_value_init (&self->priv->amplitude, type);
743         g_value_set_int64 (&self->priv->amplitude, 0);
744       }
745
746       if (!G_IS_VALUE (&self->priv->offset)) {
747         g_value_init (&self->priv->offset, type);
748         g_value_set_int64 (&self->priv->offset, tpspec->default_value);
749       }
750       break;
751     }
752     case G_TYPE_UINT64:{
753       GParamSpecUInt64 *tpspec = G_PARAM_SPEC_UINT64 (pspec);
754
755       g_value_init (&self->priv->minimum_value, type);
756       g_value_set_uint64 (&self->priv->minimum_value, tpspec->minimum);
757       g_value_init (&self->priv->maximum_value, type);
758       g_value_set_uint64 (&self->priv->maximum_value, tpspec->maximum);
759       if (!G_IS_VALUE (&self->priv->amplitude)) {
760         g_value_init (&self->priv->amplitude, type);
761         g_value_set_uint64 (&self->priv->amplitude, 0);
762       }
763
764       if (!G_IS_VALUE (&self->priv->offset)) {
765         g_value_init (&self->priv->offset, type);
766         g_value_set_uint64 (&self->priv->offset, tpspec->default_value);
767       }
768       break;
769     }
770     case G_TYPE_FLOAT:{
771       GParamSpecFloat *tpspec = G_PARAM_SPEC_FLOAT (pspec);
772
773       g_value_init (&self->priv->minimum_value, type);
774       g_value_set_float (&self->priv->minimum_value, tpspec->minimum);
775       g_value_init (&self->priv->maximum_value, type);
776       g_value_set_float (&self->priv->maximum_value, tpspec->maximum);
777       if (!G_IS_VALUE (&self->priv->amplitude)) {
778         g_value_init (&self->priv->amplitude, type);
779         g_value_set_float (&self->priv->amplitude, 0.0);
780       }
781
782       if (!G_IS_VALUE (&self->priv->offset)) {
783         g_value_init (&self->priv->offset, type);
784         g_value_set_float (&self->priv->offset, tpspec->default_value);
785       }
786       break;
787     }
788     case G_TYPE_DOUBLE:{
789       GParamSpecDouble *tpspec = G_PARAM_SPEC_DOUBLE (pspec);
790
791       g_value_init (&self->priv->minimum_value, type);
792       g_value_set_double (&self->priv->minimum_value, tpspec->minimum);
793       g_value_init (&self->priv->maximum_value, type);
794       g_value_set_double (&self->priv->maximum_value, tpspec->maximum);
795       if (!G_IS_VALUE (&self->priv->amplitude)) {
796         g_value_init (&self->priv->amplitude, type);
797         g_value_set_float (&self->priv->amplitude, 0.0);
798       }
799
800       if (!G_IS_VALUE (&self->priv->offset)) {
801         g_value_init (&self->priv->offset, type);
802         g_value_set_float (&self->priv->offset, tpspec->default_value);
803       }
804       break;
805     }
806     default:
807       GST_WARNING ("incomplete implementation for paramspec type '%s'",
808           G_PARAM_SPEC_TYPE_NAME (pspec));
809       ret = FALSE;
810       break;
811   }
812
813   if (ret) {
814     GValue amp = { 0, }
815     , off = {
816     0,};
817
818     /* This should never fail unless the user already set amplitude or offset
819      * with an incompatible type before _bind () */
820     if (!g_value_type_transformable (G_VALUE_TYPE (&self->priv->amplitude),
821             base)
822         || !g_value_type_transformable (G_VALUE_TYPE (&self->priv->offset),
823             base)) {
824       GST_WARNING ("incompatible types for amplitude or offset");
825       gst_lfo_control_source_reset (self);
826       return FALSE;
827     }
828
829     /* Generate copies and transform to the correct type */
830     g_value_init (&amp, base);
831     g_value_transform (&self->priv->amplitude, &amp);
832     g_value_init (&off, base);
833     g_value_transform (&self->priv->offset, &off);
834
835     ret = gst_lfo_control_source_set_waveform (self, self->priv->waveform);
836
837     g_value_unset (&self->priv->amplitude);
838     g_value_init (&self->priv->amplitude, self->priv->base);
839     g_value_transform (&amp, &self->priv->amplitude);
840
841     g_value_unset (&self->priv->offset);
842     g_value_init (&self->priv->offset, self->priv->base);
843     g_value_transform (&off, &self->priv->offset);
844
845     g_value_unset (&amp);
846     g_value_unset (&off);
847   }
848
849   if (!ret)
850     gst_lfo_control_source_reset (self);
851
852   return ret;
853 }
854
855 static void
856 gst_lfo_control_source_init (GstLFOControlSource * self)
857 {
858   self->priv =
859       G_TYPE_INSTANCE_GET_PRIVATE (self, GST_TYPE_LFO_CONTROL_SOURCE,
860       GstLFOControlSourcePrivate);
861   self->priv->waveform = GST_LFO_WAVEFORM_SINE;
862   self->priv->frequency = 1.0;
863   self->priv->period = GST_SECOND / self->priv->frequency;
864   self->priv->timeshift = 0;
865
866   self->lock = g_mutex_new ();
867 }
868
869 static void
870 gst_lfo_control_source_finalize (GObject * obj)
871 {
872   GstLFOControlSource *self = GST_LFO_CONTROL_SOURCE (obj);
873
874   gst_lfo_control_source_reset (self);
875
876   if (self->lock) {
877     g_mutex_free (self->lock);
878     self->lock = NULL;
879   }
880
881   G_OBJECT_CLASS (parent_class)->finalize (obj);
882 }
883
884 static void
885 gst_lfo_control_source_dispose (GObject * obj)
886 {
887   G_OBJECT_CLASS (parent_class)->dispose (obj);
888 }
889
890 static void
891 gst_lfo_control_source_set_property (GObject * object, guint prop_id,
892     const GValue * value, GParamSpec * pspec)
893 {
894   GstLFOControlSource *self = GST_LFO_CONTROL_SOURCE (object);
895
896   switch (prop_id) {
897     case PROP_WAVEFORM:
898       g_mutex_lock (self->lock);
899       gst_lfo_control_source_set_waveform (self, g_value_get_enum (value));
900       g_mutex_unlock (self->lock);
901       break;
902     case PROP_FREQUENCY:{
903       gdouble frequency = g_value_get_double (value);
904
905       g_return_if_fail (frequency > 0
906           || ((GstClockTime) (GST_SECOND / frequency)) != 0);
907
908       g_mutex_lock (self->lock);
909       self->priv->frequency = frequency;
910       self->priv->period = GST_SECOND / frequency;
911       g_mutex_unlock (self->lock);
912       break;
913     }
914     case PROP_TIMESHIFT:
915       g_mutex_lock (self->lock);
916       self->priv->timeshift = g_value_get_uint64 (value);
917       g_mutex_unlock (self->lock);
918       break;
919     case PROP_AMPLITUDE:{
920       GValue *val = g_value_get_boxed (value);
921
922       if (self->priv->type != G_TYPE_INVALID) {
923         g_return_if_fail (g_value_type_transformable (self->priv->type,
924                 G_VALUE_TYPE (val)));
925
926         g_mutex_lock (self->lock);
927         if (G_IS_VALUE (&self->priv->amplitude))
928           g_value_unset (&self->priv->amplitude);
929
930         g_value_init (&self->priv->amplitude, self->priv->type);
931         g_value_transform (val, &self->priv->amplitude);
932         g_mutex_unlock (self->lock);
933       } else {
934         g_mutex_lock (self->lock);
935         if (G_IS_VALUE (&self->priv->amplitude))
936           g_value_unset (&self->priv->amplitude);
937
938         g_value_init (&self->priv->amplitude, G_VALUE_TYPE (val));
939         g_value_copy (val, &self->priv->amplitude);
940         g_mutex_unlock (self->lock);
941       }
942
943       break;
944     }
945     case PROP_OFFSET:{
946       GValue *val = g_value_get_boxed (value);
947
948       if (self->priv->type != G_TYPE_INVALID) {
949         g_return_if_fail (g_value_type_transformable (self->priv->type,
950                 G_VALUE_TYPE (val)));
951
952         g_mutex_lock (self->lock);
953         if (G_IS_VALUE (&self->priv->offset))
954           g_value_unset (&self->priv->offset);
955
956         g_value_init (&self->priv->offset, self->priv->type);
957         g_value_transform (val, &self->priv->offset);
958         g_mutex_unlock (self->lock);
959       } else {
960         g_mutex_lock (self->lock);
961         if (G_IS_VALUE (&self->priv->offset))
962           g_value_unset (&self->priv->offset);
963
964         g_value_init (&self->priv->offset, G_VALUE_TYPE (val));
965         g_value_copy (val, &self->priv->offset);
966         g_mutex_unlock (self->lock);
967       }
968
969       break;
970     }
971     default:
972       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
973       break;
974   }
975 }
976
977 static void
978 gst_lfo_control_source_get_property (GObject * object, guint prop_id,
979     GValue * value, GParamSpec * pspec)
980 {
981   GstLFOControlSource *self = GST_LFO_CONTROL_SOURCE (object);
982
983   switch (prop_id) {
984     case PROP_WAVEFORM:
985       g_value_set_enum (value, self->priv->waveform);
986       break;
987     case PROP_FREQUENCY:
988       g_value_set_double (value, self->priv->frequency);
989       break;
990     case PROP_TIMESHIFT:
991       g_value_set_uint64 (value, self->priv->timeshift);
992       break;
993     case PROP_AMPLITUDE:
994       g_value_set_boxed (value, &self->priv->amplitude);
995       break;
996     case PROP_OFFSET:
997       g_value_set_boxed (value, &self->priv->offset);
998       break;
999     default:
1000       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1001       break;
1002   }
1003 }
1004
1005 static void
1006 gst_lfo_control_source_class_init (GstLFOControlSourceClass * klass)
1007 {
1008   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1009   GstControlSourceClass *csource_class = GST_CONTROL_SOURCE_CLASS (klass);
1010
1011   parent_class = g_type_class_peek_parent (klass);
1012   g_type_class_add_private (klass, sizeof (GstLFOControlSourcePrivate));
1013
1014   gobject_class->finalize = gst_lfo_control_source_finalize;
1015   gobject_class->dispose = gst_lfo_control_source_dispose;
1016   gobject_class->set_property = gst_lfo_control_source_set_property;
1017   gobject_class->get_property = gst_lfo_control_source_get_property;
1018
1019   csource_class->bind = gst_lfo_control_source_bind;
1020
1021   /**
1022    * GstLFOControlSource:waveform
1023    *
1024    * Specifies the waveform that should be used for this #GstLFOControlSource.
1025    * 
1026    **/
1027   g_object_class_install_property (gobject_class, PROP_WAVEFORM,
1028       g_param_spec_enum ("waveform", "Waveform", "Waveform",
1029           GST_TYPE_LFO_WAVEFORM, GST_LFO_WAVEFORM_SINE, G_PARAM_READWRITE));
1030
1031   /**
1032    * GstLFOControlSource:frequency
1033    *
1034    * Specifies the frequency that should be used for the waveform
1035    * of this #GstLFOControlSource. It should be large enough
1036    * so that the period is longer than one nanosecond.
1037    * 
1038    **/
1039   g_object_class_install_property (gobject_class, PROP_FREQUENCY,
1040       g_param_spec_double ("frequency", "Frequency",
1041           "Frequency of the waveform", 0.0, G_MAXDOUBLE, 1.0,
1042           G_PARAM_READWRITE));
1043
1044   /**
1045    * GstLFOControlSource:timeshift
1046    *
1047    * Specifies the timeshift to the right that should be used for the waveform
1048    * of this #GstLFOControlSource in nanoseconds.
1049    *
1050    * To get a n nanosecond shift to the left use
1051    * "(GST_SECOND / frequency) - n".
1052    *
1053    **/
1054   g_object_class_install_property (gobject_class, PROP_TIMESHIFT,
1055       g_param_spec_uint64 ("timeshift", "Timeshift",
1056           "Timeshift of the waveform to the right", 0, G_MAXUINT64, 0,
1057           G_PARAM_READWRITE));
1058
1059   /**
1060    * GstLFOControlSource:amplitude
1061    *
1062    * Specifies the amplitude for the waveform of this #GstLFOControlSource.
1063    *
1064    * It should be given as a #GValue with a type that can be transformed
1065    * to the type of the bound property.
1066    **/
1067   g_object_class_install_property (gobject_class, PROP_AMPLITUDE,
1068       g_param_spec_boxed ("amplitude", "Amplitude", "Amplitude of the waveform",
1069           G_TYPE_VALUE, G_PARAM_READWRITE));
1070
1071   /**
1072    * GstLFOControlSource:offset
1073    *
1074    * Specifies the offset for the waveform of this #GstLFOControlSource.
1075    *
1076    * It should be given as a #GValue with a type that can be transformed
1077    * to the type of the bound property.
1078    **/
1079   g_object_class_install_property (gobject_class, PROP_OFFSET,
1080       g_param_spec_boxed ("offset", "Offset", "Offset of the waveform",
1081           G_TYPE_VALUE, G_PARAM_READWRITE));
1082 }