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