3 * Copyright (C) 2007,2010 Sebastian Dröge <sebastian.droege@collabora.co.uk>
5 * gstlfocontrolsource.c: Control source that provides some periodic waveforms
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.
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.
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.
25 * SECTION:gstlfocontrolsource
26 * @short_description: LFO control source
28 * #GstLFOControlSource is a #GstControlSource, that provides several periodic waveforms
29 * as control values. It supports all fundamental, numeric GValue types as property.
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.
35 * All functions are MT-safe.
39 #include <glib-object.h>
41 #include <gst/gstcontrolsource.h>
43 #include "gstlfocontrolsource.h"
45 #include "gst/glib-compat-private.h"
47 #include <gst/math-compat.h>
49 #define GST_CAT_DEFAULT controller_debug
50 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
52 struct _GstLFOControlSourcePrivate
54 GstLFOWaveform waveform;
57 GstClockTime timeshift;
62 /* FIXME: as % in C is not the modulo operator we need here for
63 * negative numbers implement our own. Are there better ways? */
64 static inline GstClockTime
65 _calculate_pos (GstClockTime timestamp, GstClockTime timeshift,
68 while (timestamp < timeshift)
71 timestamp -= timeshift;
73 return timestamp % period;
77 _sine_get (GstLFOControlSource * self, gdouble amp, gdouble off,
78 GstClockTime timeshift, GstClockTime period, gdouble frequency,
79 GstClockTime timestamp)
81 GstClockTime pos = _calculate_pos (timestamp, timeshift, period);
85 sin (2.0 * M_PI * (frequency / GST_SECOND) *
86 gst_guint64_to_gdouble (pos));
94 waveform_sine_get (GstLFOControlSource * self, GstClockTime timestamp,
97 GstLFOControlSourcePrivate *priv = self->priv;
98 gdouble amp, off, frequency;
99 GstClockTime timeshift, period;
101 g_mutex_lock (self->lock);
102 amp = priv->amplitude;
104 timeshift = priv->timeshift;
105 period = priv->period;
106 frequency = priv->frequency;
108 *value = _sine_get (self, amp, off, timeshift, period, frequency, timestamp);
109 g_mutex_unlock (self->lock);
114 waveform_sine_get_value_array (GstLFOControlSource * self,
115 GstClockTime timestamp, GstClockTime interval, guint n_values,
118 GstLFOControlSourcePrivate *priv = self->priv;
120 GstClockTime ts = timestamp;
121 gdouble amp, off, frequency;
122 GstClockTime timeshift, period;
124 g_mutex_lock (self->lock);
125 amp = priv->amplitude;
127 timeshift = priv->timeshift;
128 period = priv->period;
129 frequency = priv->frequency;
131 for (i = 0; i < n_values; i++) {
132 *values = _sine_get (self, amp, off, timeshift, period, frequency, ts);
136 g_mutex_unlock (self->lock);
141 static inline gdouble
142 _square_get (GstLFOControlSource * self, gdouble amp, gdouble off,
143 GstClockTime timeshift, GstClockTime period, gdouble frequency,
144 GstClockTime timestamp)
146 GstClockTime pos = _calculate_pos (timestamp, timeshift, period);
149 if (pos >= period / 2)
159 waveform_square_get (GstLFOControlSource * self, GstClockTime timestamp,
162 GstLFOControlSourcePrivate *priv = self->priv;
163 gdouble amp, off, frequency;
164 GstClockTime timeshift, period;
166 g_mutex_lock (self->lock);
167 amp = priv->amplitude;
169 timeshift = priv->timeshift;
170 period = priv->period;
171 frequency = priv->frequency;
174 _square_get (self, amp, off, timeshift, period, frequency, timestamp);
175 g_mutex_unlock (self->lock);
180 waveform_square_get_value_array (GstLFOControlSource * self,
181 GstClockTime timestamp, GstClockTime interval, guint n_values,
184 GstLFOControlSourcePrivate *priv = self->priv;
186 GstClockTime ts = timestamp;
187 gdouble amp, off, frequency;
188 GstClockTime timeshift, period;
190 g_mutex_lock (self->lock);
191 amp = priv->amplitude;
193 timeshift = priv->timeshift;
194 period = priv->period;
195 frequency = priv->frequency;
197 for (i = 0; i < n_values; i++) {
198 *values = _square_get (self, amp, off, timeshift, period, frequency, ts);
202 g_mutex_unlock (self->lock);
206 static inline gdouble
207 _saw_get (GstLFOControlSource * self, gdouble amp, gdouble off,
208 GstClockTime timeshift, GstClockTime period, gdouble frequency,
209 GstClockTime timestamp)
211 GstClockTime pos = _calculate_pos (timestamp, timeshift, period);
215 -((gst_guint64_to_gdouble (pos) -
216 gst_guint64_to_gdouble (period) / 2.0) * ((2.0 * amp) /
217 gst_guint64_to_gdouble (period)));
224 waveform_saw_get (GstLFOControlSource * self, GstClockTime timestamp,
227 GstLFOControlSourcePrivate *priv = self->priv;
228 gdouble amp, off, frequency;
229 GstClockTime timeshift, period;
231 g_mutex_lock (self->lock);
232 amp = priv->amplitude;
234 timeshift = priv->timeshift;
235 period = priv->period;
236 frequency = priv->frequency;
238 *value = _saw_get (self, amp, off, timeshift, period, frequency, timestamp);
239 g_mutex_unlock (self->lock);
244 waveform_saw_get_value_array (GstLFOControlSource * self,
245 GstClockTime timestamp, GstClockTime interval, guint n_values,
248 GstLFOControlSourcePrivate *priv = self->priv;
250 GstClockTime ts = timestamp;
251 gdouble amp, off, frequency;
252 GstClockTime timeshift, period;
254 g_mutex_lock (self->lock);
255 amp = priv->amplitude;
257 timeshift = priv->timeshift;
258 period = priv->period;
259 frequency = priv->frequency;
261 for (i = 0; i < n_values; i++) {
262 *values = _saw_get (self, amp, off, timeshift, period, frequency, ts);
266 g_mutex_unlock (self->lock);
270 static inline gdouble
271 _rsaw_get (GstLFOControlSource * self, gdouble amp, gdouble off,
272 GstClockTime timeshift, GstClockTime period, gdouble frequency,
273 GstClockTime timestamp)
275 GstClockTime pos = _calculate_pos (timestamp, timeshift, period);
279 ((gst_guint64_to_gdouble (pos) -
280 gst_guint64_to_gdouble (period) / 2.0) * ((2.0 * amp) /
281 gst_guint64_to_gdouble (period)));
288 waveform_rsaw_get (GstLFOControlSource * self, GstClockTime timestamp,
291 GstLFOControlSourcePrivate *priv = self->priv;
292 gdouble amp, off, frequency;
293 GstClockTime timeshift, period;
295 g_mutex_lock (self->lock);
296 amp = priv->amplitude;
298 timeshift = priv->timeshift;
299 period = priv->period;
300 frequency = priv->frequency;
302 *value = _rsaw_get (self, amp, off, timeshift, period, frequency, timestamp);
303 g_mutex_unlock (self->lock);
308 waveform_rsaw_get_value_array (GstLFOControlSource * self,
309 GstClockTime timestamp, GstClockTime interval, guint n_values,
312 GstLFOControlSourcePrivate *priv = self->priv;
314 GstClockTime ts = timestamp;
315 gdouble amp, off, frequency;
316 GstClockTime timeshift, period;
318 g_mutex_lock (self->lock);
319 amp = priv->amplitude;
321 timeshift = priv->timeshift;
322 period = priv->period;
323 frequency = priv->frequency;
325 for (i = 0; i < n_values; i++) {
326 *values = _rsaw_get (self, amp, off, timeshift, period, frequency, ts);
330 g_mutex_unlock (self->lock);
335 static inline gdouble
336 _triangle_get (GstLFOControlSource * self, gdouble amp, gdouble off,
337 GstClockTime timeshift, GstClockTime period, gdouble frequency,
338 GstClockTime timestamp)
340 GstClockTime pos = _calculate_pos (timestamp, timeshift, period);
343 if (gst_guint64_to_gdouble (pos) <= gst_guint64_to_gdouble (period) / 4.0)
345 gst_guint64_to_gdouble (pos) * ((4.0 * amp) /
346 gst_guint64_to_gdouble (period));
347 else if (gst_guint64_to_gdouble (pos) <=
348 (3.0 * gst_guint64_to_gdouble (period)) / 4.0)
350 -(gst_guint64_to_gdouble (pos) -
351 gst_guint64_to_gdouble (period) / 2.0) * ((4.0 * amp) /
352 gst_guint64_to_gdouble (period));
355 gst_guint64_to_gdouble (period) -
356 gst_guint64_to_gdouble (pos) * ((4.0 * amp) /
357 gst_guint64_to_gdouble (period));
365 waveform_triangle_get (GstLFOControlSource * self, GstClockTime timestamp,
368 GstLFOControlSourcePrivate *priv = self->priv;
369 gdouble amp, off, frequency;
370 GstClockTime timeshift, period;
372 g_mutex_lock (self->lock);
373 amp = priv->amplitude;
375 timeshift = priv->timeshift;
376 period = priv->period;
377 frequency = priv->frequency;
380 _triangle_get (self, amp, off, timeshift, period, frequency, timestamp);
381 g_mutex_unlock (self->lock);
386 waveform_triangle_get_value_array (GstLFOControlSource * self,
387 GstClockTime timestamp, GstClockTime interval, guint n_values,
390 GstLFOControlSourcePrivate *priv = self->priv;
392 GstClockTime ts = timestamp;
393 gdouble amp, off, frequency;
394 GstClockTime timeshift, period;
396 g_mutex_lock (self->lock);
397 amp = priv->amplitude;
399 timeshift = priv->timeshift;
400 period = priv->period;
401 frequency = priv->frequency;
403 for (i = 0; i < n_values; i++) {
404 *values = _triangle_get (self, amp, off, timeshift, period, frequency, ts);
408 g_mutex_unlock (self->lock);
414 GstControlSourceGetValue get;
415 GstControlSourceGetValueArray get_value_array;
418 (GstControlSourceGetValue) waveform_sine_get,
419 (GstControlSourceGetValueArray) waveform_sine_get_value_array}, {
420 (GstControlSourceGetValue) waveform_square_get,
421 (GstControlSourceGetValueArray) waveform_square_get_value_array}, {
422 (GstControlSourceGetValue) waveform_saw_get,
423 (GstControlSourceGetValueArray) waveform_saw_get_value_array}, {
424 (GstControlSourceGetValue) waveform_rsaw_get,
425 (GstControlSourceGetValueArray) waveform_rsaw_get_value_array}, {
426 (GstControlSourceGetValue) waveform_triangle_get,
427 (GstControlSourceGetValueArray) waveform_triangle_get_value_array}
430 static const guint num_waveforms = G_N_ELEMENTS (waveforms);
442 gst_lfo_waveform_get_type (void)
444 static gsize gtype = 0;
445 static const GEnumValue values[] = {
446 {GST_LFO_WAVEFORM_SINE, "GST_LFO_WAVEFORM_SINE",
448 {GST_LFO_WAVEFORM_SQUARE, "GST_LFO_WAVEFORM_SQUARE",
450 {GST_LFO_WAVEFORM_SAW, "GST_LFO_WAVEFORM_SAW",
452 {GST_LFO_WAVEFORM_REVERSE_SAW, "GST_LFO_WAVEFORM_REVERSE_SAW",
454 {GST_LFO_WAVEFORM_TRIANGLE, "GST_LFO_WAVEFORM_TRIANGLE",
459 if (g_once_init_enter (>ype)) {
460 GType tmp = g_enum_register_static ("GstLFOWaveform", values);
461 g_once_init_leave (>ype, tmp);
464 return (GType) gtype;
468 GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "lfo control source", 0, "low frequency oscillator control source")
470 G_DEFINE_TYPE_WITH_CODE (GstLFOControlSource, gst_lfo_control_source,
471 GST_TYPE_CONTROL_SOURCE, _do_init);
474 gst_lfo_control_source_reset (GstLFOControlSource * self)
476 GstControlSource *csource = GST_CONTROL_SOURCE (self);
478 csource->get_value = NULL;
479 csource->get_value_array = NULL;
483 * gst_lfo_control_source_new:
485 * This returns a new, unbound #GstLFOControlSource.
487 * Returns: a new, unbound #GstLFOControlSource.
489 GstLFOControlSource *
490 gst_lfo_control_source_new (void)
492 return g_object_newv (GST_TYPE_LFO_CONTROL_SOURCE, 0, NULL);
496 gst_lfo_control_source_set_waveform (GstLFOControlSource * self,
497 GstLFOWaveform waveform)
499 GstControlSource *csource = GST_CONTROL_SOURCE (self);
501 if (waveform >= num_waveforms || (int) waveform < 0) {
502 GST_WARNING ("waveform %d invalid or not implemented yet", waveform);
506 csource->get_value = waveforms[waveform].get;
507 csource->get_value_array = waveforms[waveform].get_value_array;
509 self->priv->waveform = waveform;
515 gst_lfo_control_source_init (GstLFOControlSource * self)
518 G_TYPE_INSTANCE_GET_PRIVATE (self, GST_TYPE_LFO_CONTROL_SOURCE,
519 GstLFOControlSourcePrivate);
520 self->priv->waveform = gst_lfo_control_source_set_waveform (self,
521 GST_LFO_WAVEFORM_SINE);
522 self->priv->frequency = 1.0;
523 self->priv->period = GST_SECOND / self->priv->frequency;
524 self->priv->timeshift = 0;
526 self->lock = g_mutex_new ();
530 gst_lfo_control_source_finalize (GObject * obj)
532 GstLFOControlSource *self = GST_LFO_CONTROL_SOURCE (obj);
534 gst_lfo_control_source_reset (self);
535 g_mutex_free (self->lock);
537 G_OBJECT_CLASS (gst_lfo_control_source_parent_class)->finalize (obj);
541 gst_lfo_control_source_set_property (GObject * object, guint prop_id,
542 const GValue * value, GParamSpec * pspec)
544 GstLFOControlSource *self = GST_LFO_CONTROL_SOURCE (object);
548 g_mutex_lock (self->lock);
549 gst_lfo_control_source_set_waveform (self,
550 (GstLFOWaveform) g_value_get_enum (value));
551 g_mutex_unlock (self->lock);
553 case PROP_FREQUENCY:{
554 gdouble frequency = g_value_get_double (value);
556 g_return_if_fail (frequency > 0
557 || ((GstClockTime) (GST_SECOND / frequency)) != 0);
559 g_mutex_lock (self->lock);
560 self->priv->frequency = frequency;
561 self->priv->period = GST_SECOND / frequency;
562 g_mutex_unlock (self->lock);
566 g_mutex_lock (self->lock);
567 self->priv->timeshift = g_value_get_uint64 (value);
568 g_mutex_unlock (self->lock);
571 g_mutex_lock (self->lock);
572 self->priv->amplitude = g_value_get_double (value);
573 g_mutex_unlock (self->lock);
576 g_mutex_lock (self->lock);
577 self->priv->offset = g_value_get_double (value);
578 g_mutex_unlock (self->lock);
581 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
587 gst_lfo_control_source_get_property (GObject * object, guint prop_id,
588 GValue * value, GParamSpec * pspec)
590 GstLFOControlSource *self = GST_LFO_CONTROL_SOURCE (object);
594 g_value_set_enum (value, self->priv->waveform);
597 g_value_set_double (value, self->priv->frequency);
600 g_value_set_uint64 (value, self->priv->timeshift);
603 g_value_set_double (value, self->priv->amplitude);
606 g_value_set_double (value, self->priv->offset);
609 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
615 gst_lfo_control_source_class_init (GstLFOControlSourceClass * klass)
617 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
619 g_type_class_add_private (klass, sizeof (GstLFOControlSourcePrivate));
621 gobject_class->finalize = gst_lfo_control_source_finalize;
622 gobject_class->set_property = gst_lfo_control_source_set_property;
623 gobject_class->get_property = gst_lfo_control_source_get_property;
626 * GstLFOControlSource:waveform
628 * Specifies the waveform that should be used for this #GstLFOControlSource.
630 g_object_class_install_property (gobject_class, PROP_WAVEFORM,
631 g_param_spec_enum ("waveform", "Waveform", "Waveform",
632 GST_TYPE_LFO_WAVEFORM, GST_LFO_WAVEFORM_SINE,
633 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
636 * GstLFOControlSource:frequency
638 * Specifies the frequency that should be used for the waveform
639 * of this #GstLFOControlSource. It should be large enough
640 * so that the period is longer than one nanosecond.
642 g_object_class_install_property (gobject_class, PROP_FREQUENCY,
643 g_param_spec_double ("frequency", "Frequency",
644 "Frequency of the waveform", 0.0, G_MAXDOUBLE, 1.0,
645 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
648 * GstLFOControlSource:timeshift
650 * Specifies the timeshift to the right that should be used for the waveform
651 * of this #GstLFOControlSource in nanoseconds.
653 * To get a n nanosecond shift to the left use
654 * "(GST_SECOND / frequency) - n".
657 g_object_class_install_property (gobject_class, PROP_TIMESHIFT,
658 g_param_spec_uint64 ("timeshift", "Timeshift",
659 "Timeshift of the waveform to the right", 0, G_MAXUINT64, 0,
660 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
663 * GstLFOControlSource:amplitude
665 * Specifies the amplitude for the waveform of this #GstLFOControlSource.
667 g_object_class_install_property (gobject_class, PROP_AMPLITUDE,
668 g_param_spec_double ("amplitude", "Amplitude",
669 "Amplitude of the waveform", 0.0, G_MAXDOUBLE, 1.0,
670 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
673 * GstLFOControlSource:offset
675 * Specifies the value offset for the waveform of this #GstLFOControlSource.
677 g_object_class_install_property (gobject_class, PROP_OFFSET,
678 g_param_spec_double ("offset", "Offset", "Offset of the waveform",
679 0.0, G_MAXDOUBLE, 1.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));