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