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