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