Merge branch 'dtmf-moved-from-bad'
[platform/upstream/gstreamer.git] / gst / equalizer / gstiirequalizer.c
1 /* GStreamer
2  * Copyright (C) <2004> Benjamin Otte <otte@gnome.org>
3  *               <2007> Stefan Kost <ensonic@users.sf.net>
4  *               <2007> Sebastian Dröge <slomo@circular-chaos.org>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <math.h>
27 #include <stdio.h>
28 #include <string.h>
29
30 #include "gstiirequalizer.h"
31 #include "gstiirequalizernbands.h"
32 #include "gstiirequalizer3bands.h"
33 #include "gstiirequalizer10bands.h"
34
35 #include "gst/glib-compat-private.h"
36
37 GST_DEBUG_CATEGORY (equalizer_debug);
38 #define GST_CAT_DEFAULT equalizer_debug
39
40 #define BANDS_LOCK(equ) g_mutex_lock(&equ->bands_lock)
41 #define BANDS_UNLOCK(equ) g_mutex_unlock(&equ->bands_lock)
42
43 static void gst_iir_equalizer_child_proxy_interface_init (gpointer g_iface,
44     gpointer iface_data);
45
46 static void gst_iir_equalizer_finalize (GObject * object);
47
48 static gboolean gst_iir_equalizer_setup (GstAudioFilter * filter,
49     const GstAudioInfo * info);
50 static GstFlowReturn gst_iir_equalizer_transform_ip (GstBaseTransform * btrans,
51     GstBuffer * buf);
52
53 #define ALLOWED_CAPS \
54     "audio/x-raw,"                                                \
55     " format=(string) {"GST_AUDIO_NE(S16)","GST_AUDIO_NE(F32)","  \
56                         GST_AUDIO_NE(F64)" }, "                   \
57     " rate=(int)[1000,MAX],"                                      \
58     " channels=(int)[1,MAX],"                                     \
59     " layout=(string)interleaved"
60
61 #define gst_iir_equalizer_parent_class parent_class
62 G_DEFINE_TYPE_WITH_CODE (GstIirEqualizer, gst_iir_equalizer,
63     GST_TYPE_AUDIO_FILTER,
64     G_IMPLEMENT_INTERFACE (GST_TYPE_CHILD_PROXY,
65         gst_iir_equalizer_child_proxy_interface_init)
66     G_IMPLEMENT_INTERFACE (GST_TYPE_PRESET, NULL));
67
68
69 /* child object */
70
71 enum
72 {
73   PROP_GAIN = 1,
74   PROP_FREQ,
75   PROP_BANDWIDTH,
76   PROP_TYPE
77 };
78
79 typedef enum
80 {
81   BAND_TYPE_PEAK = 0,
82   BAND_TYPE_LOW_SHELF,
83   BAND_TYPE_HIGH_SHELF
84 } GstIirEqualizerBandType;
85
86 #define GST_TYPE_IIR_EQUALIZER_BAND_TYPE (gst_iir_equalizer_band_type_get_type ())
87 static GType
88 gst_iir_equalizer_band_type_get_type (void)
89 {
90   static GType gtype = 0;
91
92   if (gtype == 0) {
93     static const GEnumValue values[] = {
94       {BAND_TYPE_PEAK, "Peak filter (default for inner bands)", "peak"},
95       {BAND_TYPE_LOW_SHELF, "Low shelf filter (default for first band)",
96           "low-shelf"},
97       {BAND_TYPE_HIGH_SHELF, "High shelf filter (default for last band)",
98           "high-shelf"},
99       {0, NULL, NULL}
100     };
101
102     gtype = g_enum_register_static ("GstIirEqualizerBandType", values);
103   }
104   return gtype;
105 }
106
107
108 typedef struct _GstIirEqualizerBandClass GstIirEqualizerBandClass;
109
110 #define GST_TYPE_IIR_EQUALIZER_BAND \
111   (gst_iir_equalizer_band_get_type())
112 #define GST_IIR_EQUALIZER_BAND(obj) \
113   (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_IIR_EQUALIZER_BAND,GstIirEqualizerBand))
114 #define GST_IIR_EQUALIZER_BAND_CLASS(klass) \
115   (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_IIR_EQUALIZER_BAND,GstIirEqualizerBandClass))
116 #define GST_IS_IIR_EQUALIZER_BAND(obj) \
117   (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_IIR_EQUALIZER_BAND))
118 #define GST_IS_IIR_EQUALIZER_BAND_CLASS(klass) \
119   (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_IIR_EQUALIZER_BAND))
120
121 struct _GstIirEqualizerBand
122 {
123   GstObject object;
124
125   /*< private > */
126   /* center frequency and gain */
127   gdouble freq;
128   gdouble gain;
129   gdouble width;
130   GstIirEqualizerBandType type;
131
132   /* second order iir filter */
133   gdouble b1, b2;               /* IIR coefficients for outputs */
134   gdouble a0, a1, a2;           /* IIR coefficients for inputs */
135 };
136
137 struct _GstIirEqualizerBandClass
138 {
139   GstObjectClass parent_class;
140 };
141
142 static GType gst_iir_equalizer_band_get_type (void);
143
144 static void
145 gst_iir_equalizer_band_set_property (GObject * object, guint prop_id,
146     const GValue * value, GParamSpec * pspec)
147 {
148   GstIirEqualizerBand *band = GST_IIR_EQUALIZER_BAND (object);
149   GstIirEqualizer *equ =
150       GST_IIR_EQUALIZER (gst_object_get_parent (GST_OBJECT (band)));
151
152   switch (prop_id) {
153     case PROP_GAIN:{
154       gdouble gain;
155
156       gain = g_value_get_double (value);
157       GST_DEBUG_OBJECT (band, "gain = %lf -> %lf", band->gain, gain);
158       if (gain != band->gain) {
159         BANDS_LOCK (equ);
160         equ->need_new_coefficients = TRUE;
161         band->gain = gain;
162         BANDS_UNLOCK (equ);
163         GST_DEBUG_OBJECT (band, "changed gain = %lf ", band->gain);
164       }
165       break;
166     }
167     case PROP_FREQ:{
168       gdouble freq;
169
170       freq = g_value_get_double (value);
171       GST_DEBUG_OBJECT (band, "freq = %lf -> %lf", band->freq, freq);
172       if (freq != band->freq) {
173         BANDS_LOCK (equ);
174         equ->need_new_coefficients = TRUE;
175         band->freq = freq;
176         BANDS_UNLOCK (equ);
177         GST_DEBUG_OBJECT (band, "changed freq = %lf ", band->freq);
178       }
179       break;
180     }
181     case PROP_BANDWIDTH:{
182       gdouble width;
183
184       width = g_value_get_double (value);
185       GST_DEBUG_OBJECT (band, "width = %lf -> %lf", band->width, width);
186       if (width != band->width) {
187         BANDS_LOCK (equ);
188         equ->need_new_coefficients = TRUE;
189         band->width = width;
190         BANDS_UNLOCK (equ);
191         GST_DEBUG_OBJECT (band, "changed width = %lf ", band->width);
192       }
193       break;
194     }
195     case PROP_TYPE:{
196       GstIirEqualizerBandType type;
197
198       type = g_value_get_enum (value);
199       GST_DEBUG_OBJECT (band, "type = %d -> %d", band->type, type);
200       if (type != band->type) {
201         BANDS_LOCK (equ);
202         equ->need_new_coefficients = TRUE;
203         band->type = type;
204         BANDS_UNLOCK (equ);
205         GST_DEBUG_OBJECT (band, "changed type = %d ", band->type);
206       }
207       break;
208     }
209     default:
210       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
211       break;
212   }
213
214   gst_object_unref (equ);
215 }
216
217 static void
218 gst_iir_equalizer_band_get_property (GObject * object, guint prop_id,
219     GValue * value, GParamSpec * pspec)
220 {
221   GstIirEqualizerBand *band = GST_IIR_EQUALIZER_BAND (object);
222
223   switch (prop_id) {
224     case PROP_GAIN:
225       g_value_set_double (value, band->gain);
226       break;
227     case PROP_FREQ:
228       g_value_set_double (value, band->freq);
229       break;
230     case PROP_BANDWIDTH:
231       g_value_set_double (value, band->width);
232       break;
233     case PROP_TYPE:
234       g_value_set_enum (value, band->type);
235       break;
236     default:
237       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
238       break;
239   }
240 }
241
242 static void
243 gst_iir_equalizer_band_class_init (GstIirEqualizerBandClass * klass)
244 {
245   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
246
247   gobject_class->set_property = gst_iir_equalizer_band_set_property;
248   gobject_class->get_property = gst_iir_equalizer_band_get_property;
249
250   g_object_class_install_property (gobject_class, PROP_GAIN,
251       g_param_spec_double ("gain", "gain",
252           "gain for the frequency band ranging from -24.0 dB to +12.0 dB",
253           -24.0, 12.0, 0.0,
254           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
255
256   g_object_class_install_property (gobject_class, PROP_FREQ,
257       g_param_spec_double ("freq", "freq",
258           "center frequency of the band",
259           0.0, 100000.0, 0.0,
260           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
261
262   g_object_class_install_property (gobject_class, PROP_BANDWIDTH,
263       g_param_spec_double ("bandwidth", "bandwidth",
264           "difference between bandedges in Hz",
265           0.0, 100000.0, 1.0,
266           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
267
268   g_object_class_install_property (gobject_class, PROP_TYPE,
269       g_param_spec_enum ("type", "Type",
270           "Filter type", GST_TYPE_IIR_EQUALIZER_BAND_TYPE,
271           BAND_TYPE_PEAK,
272           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
273 }
274
275 static void
276 gst_iir_equalizer_band_init (GstIirEqualizerBand * band,
277     GstIirEqualizerBandClass * klass)
278 {
279   band->freq = 0.0;
280   band->gain = 0.0;
281   band->width = 1.0;
282   band->type = BAND_TYPE_PEAK;
283 }
284
285 static GType
286 gst_iir_equalizer_band_get_type (void)
287 {
288   static GType type = 0;
289
290   if (G_UNLIKELY (!type)) {
291     const GTypeInfo type_info = {
292       sizeof (GstIirEqualizerBandClass),
293       NULL,
294       NULL,
295       (GClassInitFunc) gst_iir_equalizer_band_class_init,
296       NULL,
297       NULL,
298       sizeof (GstIirEqualizerBand),
299       0,
300       (GInstanceInitFunc) gst_iir_equalizer_band_init,
301     };
302     type =
303         g_type_register_static (GST_TYPE_OBJECT, "GstIirEqualizerBand",
304         &type_info, 0);
305   }
306   return (type);
307 }
308
309
310 /* child proxy iface */
311 static GObject *
312 gst_iir_equalizer_child_proxy_get_child_by_index (GstChildProxy * child_proxy,
313     guint index)
314 {
315   GstIirEqualizer *equ = GST_IIR_EQUALIZER (child_proxy);
316   GObject *ret;
317
318   BANDS_LOCK (equ);
319   if (G_UNLIKELY (index >= equ->freq_band_count)) {
320     BANDS_UNLOCK (equ);
321     g_return_val_if_fail (index < equ->freq_band_count, NULL);
322   }
323
324   ret = g_object_ref (equ->bands[index]);
325   BANDS_UNLOCK (equ);
326
327   GST_LOG_OBJECT (equ, "return child[%d] %" GST_PTR_FORMAT, index, ret);
328   return ret;
329 }
330
331 static guint
332 gst_iir_equalizer_child_proxy_get_children_count (GstChildProxy * child_proxy)
333 {
334   GstIirEqualizer *equ = GST_IIR_EQUALIZER (child_proxy);
335
336   GST_LOG ("we have %d children", equ->freq_band_count);
337   return equ->freq_band_count;
338 }
339
340 static void
341 gst_iir_equalizer_child_proxy_interface_init (gpointer g_iface,
342     gpointer iface_data)
343 {
344   GstChildProxyInterface *iface = g_iface;
345
346   GST_DEBUG ("initializing iface");
347
348   iface->get_child_by_index = gst_iir_equalizer_child_proxy_get_child_by_index;
349   iface->get_children_count = gst_iir_equalizer_child_proxy_get_children_count;
350 }
351
352 /* equalizer implementation */
353
354 static void
355 gst_iir_equalizer_class_init (GstIirEqualizerClass * klass)
356 {
357   GstAudioFilterClass *audio_filter_class = (GstAudioFilterClass *) klass;
358   GstBaseTransformClass *btrans_class = (GstBaseTransformClass *) klass;
359   GObjectClass *gobject_class = (GObjectClass *) klass;
360   GstCaps *caps;
361
362   gobject_class->finalize = gst_iir_equalizer_finalize;
363   audio_filter_class->setup = gst_iir_equalizer_setup;
364   btrans_class->transform_ip = gst_iir_equalizer_transform_ip;
365
366   caps = gst_caps_from_string (ALLOWED_CAPS);
367   gst_audio_filter_class_add_pad_templates (audio_filter_class, caps);
368   gst_caps_unref (caps);
369 }
370
371 static void
372 gst_iir_equalizer_init (GstIirEqualizer * eq)
373 {
374   g_mutex_init (&eq->bands_lock);
375   eq->need_new_coefficients = TRUE;
376 }
377
378 static void
379 gst_iir_equalizer_finalize (GObject * object)
380 {
381   GstIirEqualizer *equ = GST_IIR_EQUALIZER (object);
382   gint i;
383
384   for (i = 0; i < equ->freq_band_count; i++) {
385     if (equ->bands[i])
386       gst_object_unparent (GST_OBJECT (equ->bands[i]));
387     equ->bands[i] = NULL;
388   }
389   equ->freq_band_count = 0;
390
391   g_free (equ->bands);
392   g_free (equ->history);
393
394   g_mutex_clear (&equ->bands_lock);
395
396   G_OBJECT_CLASS (parent_class)->finalize (object);
397 }
398
399 /* Filter taken from
400  *
401  * The Equivalence of Various Methods of Computing
402  * Biquad Coefficients for Audio Parametric Equalizers
403  *
404  * by Robert Bristow-Johnson
405  *
406  * http://www.aes.org/e-lib/browse.cfm?elib=6326
407  * http://www.musicdsp.org/files/EQ-Coefficients.pdf
408  * http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt
409  *
410  * The bandwidth method that we use here is the preferred
411  * one from this article transformed from octaves to frequency
412  * in Hz.
413  */
414 static inline gdouble
415 arg_to_scale (gdouble arg)
416 {
417   return (pow (10.0, arg / 40.0));
418 }
419
420 static gdouble
421 calculate_omega (gdouble freq, gint rate)
422 {
423   gdouble omega;
424
425   if (freq / rate >= 0.5)
426     omega = G_PI;
427   else if (freq <= 0.0)
428     omega = 0.0;
429   else
430     omega = 2.0 * G_PI * (freq / rate);
431
432   return omega;
433 }
434
435 static gdouble
436 calculate_bw (GstIirEqualizerBand * band, gint rate)
437 {
438   gdouble bw = 0.0;
439
440   if (band->width / rate >= 0.5) {
441     /* If bandwidth == 0.5 the calculation below fails as tan(G_PI/2)
442      * is undefined. So set the bandwidth to a slightly smaller value.
443      */
444     bw = G_PI - 0.00000001;
445   } else if (band->width <= 0.0) {
446     /* If bandwidth == 0 this band won't change anything so set
447      * the coefficients accordingly. The coefficient calculation
448      * below would create coefficients that for some reason amplify
449      * the band.
450      */
451     band->a0 = 1.0;
452     band->a1 = 0.0;
453     band->a2 = 0.0;
454     band->b1 = 0.0;
455     band->b2 = 0.0;
456   } else {
457     bw = 2.0 * G_PI * (band->width / rate);
458   }
459   return bw;
460 }
461
462 static void
463 setup_peak_filter (GstIirEqualizer * equ, GstIirEqualizerBand * band)
464 {
465   gint rate = GST_AUDIO_FILTER_RATE (equ);
466
467   g_return_if_fail (rate);
468
469   {
470     gdouble gain, omega, bw;
471     gdouble alpha, alpha1, alpha2, b0;
472
473     gain = arg_to_scale (band->gain);
474     omega = calculate_omega (band->freq, rate);
475     bw = calculate_bw (band, rate);
476     if (bw == 0.0)
477       goto out;
478
479     alpha = tan (bw / 2.0);
480
481     alpha1 = alpha * gain;
482     alpha2 = alpha / gain;
483
484     b0 = (1.0 + alpha2);
485
486     band->a0 = (1.0 + alpha1) / b0;
487     band->a1 = (-2.0 * cos (omega)) / b0;
488     band->a2 = (1.0 - alpha1) / b0;
489     band->b1 = (2.0 * cos (omega)) / b0;
490     band->b2 = -(1.0 - alpha2) / b0;
491
492   out:
493     GST_INFO
494         ("gain = %5.1f, width= %7.2f, freq = %7.2f, a0 = %7.5g, a1 = %7.5g, a2=%7.5g b1 = %7.5g, b2 = %7.5g",
495         band->gain, band->width, band->freq, band->a0, band->a1, band->a2,
496         band->b1, band->b2);
497   }
498 }
499
500 static void
501 setup_low_shelf_filter (GstIirEqualizer * equ, GstIirEqualizerBand * band)
502 {
503   gint rate = GST_AUDIO_FILTER_RATE (equ);
504
505   g_return_if_fail (rate);
506
507   {
508     gdouble gain, omega, bw;
509     gdouble alpha, delta, b0;
510     gdouble egp, egm;
511
512     gain = arg_to_scale (band->gain);
513     omega = calculate_omega (band->freq, rate);
514     bw = calculate_bw (band, rate);
515     if (bw == 0.0)
516       goto out;
517
518     egm = gain - 1.0;
519     egp = gain + 1.0;
520     alpha = tan (bw / 2.0);
521
522     delta = 2.0 * sqrt (gain) * alpha;
523     b0 = egp + egm * cos (omega) + delta;
524
525     band->a0 = ((egp - egm * cos (omega) + delta) * gain) / b0;
526     band->a1 = ((egm - egp * cos (omega)) * 2.0 * gain) / b0;
527     band->a2 = ((egp - egm * cos (omega) - delta) * gain) / b0;
528     band->b1 = ((egm + egp * cos (omega)) * 2.0) / b0;
529     band->b2 = -((egp + egm * cos (omega) - delta)) / b0;
530
531
532   out:
533     GST_INFO
534         ("gain = %5.1f, width= %7.2f, freq = %7.2f, a0 = %7.5g, a1 = %7.5g, a2=%7.5g b1 = %7.5g, b2 = %7.5g",
535         band->gain, band->width, band->freq, band->a0, band->a1, band->a2,
536         band->b1, band->b2);
537   }
538 }
539
540 static void
541 setup_high_shelf_filter (GstIirEqualizer * equ, GstIirEqualizerBand * band)
542 {
543   gint rate = GST_AUDIO_FILTER_RATE (equ);
544
545   g_return_if_fail (rate);
546
547   {
548     gdouble gain, omega, bw;
549     gdouble alpha, delta, b0;
550     gdouble egp, egm;
551
552     gain = arg_to_scale (band->gain);
553     omega = calculate_omega (band->freq, rate);
554     bw = calculate_bw (band, rate);
555     if (bw == 0.0)
556       goto out;
557
558     egm = gain - 1.0;
559     egp = gain + 1.0;
560     alpha = tan (bw / 2.0);
561
562     delta = 2.0 * sqrt (gain) * alpha;
563     b0 = egp - egm * cos (omega) + delta;
564
565     band->a0 = ((egp + egm * cos (omega) + delta) * gain) / b0;
566     band->a1 = ((egm + egp * cos (omega)) * -2.0 * gain) / b0;
567     band->a2 = ((egp + egm * cos (omega) - delta) * gain) / b0;
568     band->b1 = ((egm - egp * cos (omega)) * -2.0) / b0;
569     band->b2 = -((egp - egm * cos (omega) - delta)) / b0;
570
571
572   out:
573     GST_INFO
574         ("gain = %5.1f, width= %7.2f, freq = %7.2f, a0 = %7.5g, a1 = %7.5g, a2=%7.5g b1 = %7.5g, b2 = %7.5g",
575         band->gain, band->width, band->freq, band->a0, band->a1, band->a2,
576         band->b1, band->b2);
577   }
578 }
579
580 /* Must be called with bands_lock and transform lock! */
581 static void
582 set_passthrough (GstIirEqualizer * equ)
583 {
584   gint i;
585   gboolean passthrough = TRUE;
586
587   for (i = 0; i < equ->freq_band_count; i++) {
588     passthrough = passthrough && (equ->bands[i]->gain == 0.0);
589   }
590
591   gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (equ), passthrough);
592   GST_DEBUG ("Passthrough mode: %d\n", passthrough);
593 }
594
595 /* Must be called with bands_lock and transform lock! */
596 static void
597 update_coefficients (GstIirEqualizer * equ)
598 {
599   gint i, n = equ->freq_band_count;
600
601   for (i = 0; i < n; i++) {
602     if (equ->bands[i]->type == BAND_TYPE_PEAK)
603       setup_peak_filter (equ, equ->bands[i]);
604     else if (equ->bands[i]->type == BAND_TYPE_LOW_SHELF)
605       setup_low_shelf_filter (equ, equ->bands[i]);
606     else
607       setup_high_shelf_filter (equ, equ->bands[i]);
608   }
609
610   equ->need_new_coefficients = FALSE;
611 }
612
613 /* Must be called with transform lock! */
614 static void
615 alloc_history (GstIirEqualizer * equ, const GstAudioInfo * info)
616 {
617   /* free + alloc = no memcpy */
618   g_free (equ->history);
619   equ->history =
620       g_malloc0 (equ->history_size * GST_AUDIO_INFO_CHANNELS (info) *
621       equ->freq_band_count);
622 }
623
624 void
625 gst_iir_equalizer_compute_frequencies (GstIirEqualizer * equ, guint new_count)
626 {
627   guint old_count, i;
628   gdouble freq0, freq1, step;
629   gchar name[20];
630
631   if (equ->freq_band_count == new_count)
632     return;
633
634   BANDS_LOCK (equ);
635
636   if (G_UNLIKELY (equ->freq_band_count == new_count)) {
637     BANDS_UNLOCK (equ);
638     return;
639   }
640
641   old_count = equ->freq_band_count;
642   equ->freq_band_count = new_count;
643   GST_DEBUG ("bands %u -> %u", old_count, new_count);
644
645   if (old_count < new_count) {
646     /* add new bands */
647     equ->bands = g_realloc (equ->bands, sizeof (GstObject *) * new_count);
648     for (i = old_count; i < new_count; i++) {
649       /* otherwise they get names like 'iirequalizerband5' */
650       sprintf (name, "band%u", i);
651       equ->bands[i] = g_object_new (GST_TYPE_IIR_EQUALIZER_BAND,
652           "name", name, NULL);
653       GST_DEBUG ("adding band[%d]=%p", i, equ->bands[i]);
654
655       gst_object_set_parent (GST_OBJECT (equ->bands[i]), GST_OBJECT (equ));
656       gst_child_proxy_child_added (GST_CHILD_PROXY (equ),
657           G_OBJECT (equ->bands[i]), name);
658     }
659   } else {
660     /* free unused bands */
661     for (i = new_count; i < old_count; i++) {
662       GST_DEBUG ("removing band[%d]=%p", i, equ->bands[i]);
663       gst_child_proxy_child_removed (GST_CHILD_PROXY (equ),
664           G_OBJECT (equ->bands[i]), GST_OBJECT_NAME (equ->bands[i]));
665       gst_object_unparent (GST_OBJECT (equ->bands[i]));
666       equ->bands[i] = NULL;
667     }
668   }
669
670   alloc_history (equ, GST_AUDIO_FILTER_INFO (equ));
671
672   /* set center frequencies and name band objects
673    * FIXME: arg! we can't change the name of parented objects :(
674    *   application should read band->freq to get the name
675    */
676
677   step = pow (HIGHEST_FREQ / LOWEST_FREQ, 1.0 / new_count);
678   freq0 = LOWEST_FREQ;
679   for (i = 0; i < new_count; i++) {
680     freq1 = freq0 * step;
681
682     if (i == 0)
683       equ->bands[i]->type = BAND_TYPE_LOW_SHELF;
684     else if (i == new_count - 1)
685       equ->bands[i]->type = BAND_TYPE_HIGH_SHELF;
686     else
687       equ->bands[i]->type = BAND_TYPE_PEAK;
688
689     equ->bands[i]->freq = freq0 + ((freq1 - freq0) / 2.0);
690     equ->bands[i]->width = freq1 - freq0;
691     GST_DEBUG ("band[%2d] = '%lf'", i, equ->bands[i]->freq);
692
693     g_object_notify (G_OBJECT (equ->bands[i]), "bandwidth");
694     g_object_notify (G_OBJECT (equ->bands[i]), "freq");
695     g_object_notify (G_OBJECT (equ->bands[i]), "type");
696
697     /*
698        if(equ->bands[i]->freq<10000.0)
699        sprintf (name,"%dHz",(gint)equ->bands[i]->freq);
700        else
701        sprintf (name,"%dkHz",(gint)(equ->bands[i]->freq/1000.0));
702        gst_object_set_name( GST_OBJECT (equ->bands[i]), name);
703        GST_DEBUG ("band[%2d] = '%s'",i,name);
704      */
705     freq0 = freq1;
706   }
707
708   equ->need_new_coefficients = TRUE;
709   BANDS_UNLOCK (equ);
710 }
711
712 /* start of code that is type specific */
713
714 #define CREATE_OPTIMIZED_FUNCTIONS_INT(TYPE,BIG_TYPE,MIN_VAL,MAX_VAL)   \
715 typedef struct {                                                        \
716   BIG_TYPE x1, x2;          /* history of input values for a filter */  \
717   BIG_TYPE y1, y2;          /* history of output values for a filter */ \
718 } SecondOrderHistory ## TYPE;                                           \
719                                                                         \
720 static inline BIG_TYPE                                                  \
721 one_step_ ## TYPE (GstIirEqualizerBand *filter,                         \
722     SecondOrderHistory ## TYPE *history, BIG_TYPE input)                \
723 {                                                                       \
724   /* calculate output */                                                \
725   BIG_TYPE output = filter->a0 * input +                                \
726       filter->a1 * history->x1 + filter->a2 * history->x2 +             \
727       filter->b1 * history->y1 + filter->b2 * history->y2;              \
728   /* update history */                                                  \
729   history->y2 = history->y1;                                            \
730   history->y1 = output;                                                 \
731   history->x2 = history->x1;                                            \
732   history->x1 = input;                                                  \
733                                                                         \
734   return output;                                                        \
735 }                                                                       \
736                                                                         \
737 static const guint                                                      \
738 history_size_ ## TYPE = sizeof (SecondOrderHistory ## TYPE);            \
739                                                                         \
740 static void                                                             \
741 gst_iir_equ_process_ ## TYPE (GstIirEqualizer *equ, guint8 *data,       \
742 guint size, guint channels)                                             \
743 {                                                                       \
744   guint frames = size / channels / sizeof (TYPE);                       \
745   guint i, c, f, nf = equ->freq_band_count;                             \
746   BIG_TYPE cur;                                                         \
747   GstIirEqualizerBand **filters = equ->bands;                           \
748                                                                         \
749   for (i = 0; i < frames; i++) {                                        \
750     SecondOrderHistory ## TYPE *history = equ->history;                 \
751     for (c = 0; c < channels; c++) {                                    \
752       cur = *((TYPE *) data);                                           \
753       for (f = 0; f < nf; f++) {                                        \
754         cur = one_step_ ## TYPE (filters[f], history, cur);             \
755         history++;                                                      \
756       }                                                                 \
757       cur = CLAMP (cur, MIN_VAL, MAX_VAL);                              \
758       *((TYPE *) data) = (TYPE) floor (cur);                            \
759       data += sizeof (TYPE);                                            \
760     }                                                                   \
761   }                                                                     \
762 }
763
764 #define CREATE_OPTIMIZED_FUNCTIONS(TYPE)                                \
765 typedef struct {                                                        \
766   TYPE x1, x2;          /* history of input values for a filter */  \
767   TYPE y1, y2;          /* history of output values for a filter */ \
768 } SecondOrderHistory ## TYPE;                                           \
769                                                                         \
770 static inline TYPE                                                      \
771 one_step_ ## TYPE (GstIirEqualizerBand *filter,                         \
772     SecondOrderHistory ## TYPE *history, TYPE input)                    \
773 {                                                                       \
774   /* calculate output */                                                \
775   TYPE output = filter->a0 * input + filter->a1 * history->x1 +         \
776       filter->a2 * history->x2 + filter->b1 * history->y1 +             \
777       filter->b2 * history->y2;                                         \
778   /* update history */                                                  \
779   history->y2 = history->y1;                                            \
780   history->y1 = output;                                                 \
781   history->x2 = history->x1;                                            \
782   history->x1 = input;                                                  \
783                                                                         \
784   return output;                                                        \
785 }                                                                       \
786                                                                         \
787 static const guint                                                      \
788 history_size_ ## TYPE = sizeof (SecondOrderHistory ## TYPE);            \
789                                                                         \
790 static void                                                             \
791 gst_iir_equ_process_ ## TYPE (GstIirEqualizer *equ, guint8 *data,       \
792 guint size, guint channels)                                             \
793 {                                                                       \
794   guint frames = size / channels / sizeof (TYPE);                       \
795   guint i, c, f, nf = equ->freq_band_count;                             \
796   TYPE cur;                                                             \
797   GstIirEqualizerBand **filters = equ->bands;                           \
798                                                                         \
799   for (i = 0; i < frames; i++) {                                        \
800     SecondOrderHistory ## TYPE *history = equ->history;                 \
801     for (c = 0; c < channels; c++) {                                    \
802       cur = *((TYPE *) data);                                           \
803       for (f = 0; f < nf; f++) {                                        \
804         cur = one_step_ ## TYPE (filters[f], history, cur);             \
805         history++;                                                      \
806       }                                                                 \
807       *((TYPE *) data) = (TYPE) cur;                                    \
808       data += sizeof (TYPE);                                            \
809     }                                                                   \
810   }                                                                     \
811 }
812
813 CREATE_OPTIMIZED_FUNCTIONS_INT (gint16, gfloat, -32768.0, 32767.0);
814 CREATE_OPTIMIZED_FUNCTIONS (gfloat);
815 CREATE_OPTIMIZED_FUNCTIONS (gdouble);
816
817 static GstFlowReturn
818 gst_iir_equalizer_transform_ip (GstBaseTransform * btrans, GstBuffer * buf)
819 {
820   GstAudioFilter *filter = GST_AUDIO_FILTER (btrans);
821   GstIirEqualizer *equ = GST_IIR_EQUALIZER (btrans);
822   GstClockTime timestamp;
823   GstMapInfo map;
824   gint channels = GST_AUDIO_FILTER_CHANNELS (filter);
825   gboolean need_new_coefficients;
826
827   if (G_UNLIKELY (channels < 1 || equ->process == NULL))
828     return GST_FLOW_NOT_NEGOTIATED;
829
830   BANDS_LOCK (equ);
831   need_new_coefficients = equ->need_new_coefficients;
832   BANDS_UNLOCK (equ);
833
834   if (!need_new_coefficients && gst_base_transform_is_passthrough (btrans))
835     return GST_FLOW_OK;
836
837   timestamp = GST_BUFFER_TIMESTAMP (buf);
838   timestamp =
839       gst_segment_to_stream_time (&btrans->segment, GST_FORMAT_TIME, timestamp);
840
841   if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
842     GstIirEqualizerBand **filters = equ->bands;
843     guint f, nf = equ->freq_band_count;
844
845     gst_object_sync_values (GST_OBJECT (equ), timestamp);
846
847     /* sync values for bands too */
848     /* FIXME: iterating equ->bands is not thread-safe here */
849     for (f = 0; f < nf; f++) {
850       gst_object_sync_values (GST_OBJECT (filters[f]), timestamp);
851     }
852   }
853
854   BANDS_LOCK (equ);
855   if (need_new_coefficients) {
856     update_coefficients (equ);
857     set_passthrough (equ);
858   }
859   BANDS_UNLOCK (equ);
860
861   gst_buffer_map (buf, &map, GST_MAP_READWRITE);
862   equ->process (equ, map.data, map.size, channels);
863   gst_buffer_unmap (buf, &map);
864
865   return GST_FLOW_OK;
866 }
867
868 static gboolean
869 gst_iir_equalizer_setup (GstAudioFilter * audio, const GstAudioInfo * info)
870 {
871   GstIirEqualizer *equ = GST_IIR_EQUALIZER (audio);
872
873   switch (GST_AUDIO_INFO_FORMAT (info)) {
874     case GST_AUDIO_FORMAT_S16:
875       equ->history_size = history_size_gint16;
876       equ->process = gst_iir_equ_process_gint16;
877       break;
878     case GST_AUDIO_FORMAT_F32:
879       equ->history_size = history_size_gfloat;
880       equ->process = gst_iir_equ_process_gfloat;
881       break;
882     case GST_AUDIO_FORMAT_F64:
883       equ->history_size = history_size_gdouble;
884       equ->process = gst_iir_equ_process_gdouble;
885       break;
886     default:
887       return FALSE;
888   }
889
890   alloc_history (equ, info);
891   return TRUE;
892 }
893
894
895 static gboolean
896 plugin_init (GstPlugin * plugin)
897 {
898   GST_DEBUG_CATEGORY_INIT (equalizer_debug, "equalizer", 0, "equalizer");
899
900   if (!(gst_element_register (plugin, "equalizer-nbands", GST_RANK_NONE,
901               GST_TYPE_IIR_EQUALIZER_NBANDS)))
902     return FALSE;
903
904   if (!(gst_element_register (plugin, "equalizer-3bands", GST_RANK_NONE,
905               GST_TYPE_IIR_EQUALIZER_3BANDS)))
906     return FALSE;
907
908   if (!(gst_element_register (plugin, "equalizer-10bands", GST_RANK_NONE,
909               GST_TYPE_IIR_EQUALIZER_10BANDS)))
910     return FALSE;
911
912   return TRUE;
913 }
914
915 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
916     GST_VERSION_MINOR,
917     equalizer,
918     "GStreamer audio equalizers",
919     plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)