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