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