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