• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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   gst_type_mark_as_plugin_api (GST_TYPE_IIR_EQUALIZER, 0);
277 }
278 
279 static void
gst_iir_equalizer_band_init(GstIirEqualizerBand * band,GstIirEqualizerBandClass * klass)280 gst_iir_equalizer_band_init (GstIirEqualizerBand * band,
281     GstIirEqualizerBandClass * klass)
282 {
283   band->freq = 0.0;
284   band->gain = 0.0;
285   band->width = 1.0;
286   band->type = BAND_TYPE_PEAK;
287 }
288 
289 static GType
gst_iir_equalizer_band_get_type(void)290 gst_iir_equalizer_band_get_type (void)
291 {
292   static GType type = 0;
293 
294   if (G_UNLIKELY (!type)) {
295     const GTypeInfo type_info = {
296       sizeof (GstIirEqualizerBandClass),
297       NULL,
298       NULL,
299       (GClassInitFunc) gst_iir_equalizer_band_class_init,
300       NULL,
301       NULL,
302       sizeof (GstIirEqualizerBand),
303       0,
304       (GInstanceInitFunc) gst_iir_equalizer_band_init,
305     };
306     type =
307         g_type_register_static (GST_TYPE_OBJECT, "GstIirEqualizerBand",
308         &type_info, 0);
309   }
310   return (type);
311 }
312 
313 
314 /* child proxy iface */
315 static GObject *
gst_iir_equalizer_child_proxy_get_child_by_index(GstChildProxy * child_proxy,guint index)316 gst_iir_equalizer_child_proxy_get_child_by_index (GstChildProxy * child_proxy,
317     guint index)
318 {
319   GstIirEqualizer *equ = GST_IIR_EQUALIZER (child_proxy);
320   GObject *ret;
321 
322   BANDS_LOCK (equ);
323   if (G_UNLIKELY (index >= equ->freq_band_count)) {
324     BANDS_UNLOCK (equ);
325     g_return_val_if_fail (index < equ->freq_band_count, NULL);
326   }
327 
328   ret = g_object_ref (G_OBJECT (equ->bands[index]));
329   BANDS_UNLOCK (equ);
330 
331   GST_LOG_OBJECT (equ, "return child[%d] %" GST_PTR_FORMAT, index, ret);
332   return ret;
333 }
334 
335 static guint
gst_iir_equalizer_child_proxy_get_children_count(GstChildProxy * child_proxy)336 gst_iir_equalizer_child_proxy_get_children_count (GstChildProxy * child_proxy)
337 {
338   GstIirEqualizer *equ = GST_IIR_EQUALIZER (child_proxy);
339 
340   GST_LOG ("we have %d children", equ->freq_band_count);
341   return equ->freq_band_count;
342 }
343 
344 static void
gst_iir_equalizer_child_proxy_interface_init(gpointer g_iface,gpointer iface_data)345 gst_iir_equalizer_child_proxy_interface_init (gpointer g_iface,
346     gpointer iface_data)
347 {
348   GstChildProxyInterface *iface = g_iface;
349 
350   GST_DEBUG ("initializing iface");
351 
352   iface->get_child_by_index = gst_iir_equalizer_child_proxy_get_child_by_index;
353   iface->get_children_count = gst_iir_equalizer_child_proxy_get_children_count;
354 }
355 
356 /* equalizer implementation */
357 
358 static void
gst_iir_equalizer_class_init(GstIirEqualizerClass * klass)359 gst_iir_equalizer_class_init (GstIirEqualizerClass * klass)
360 {
361   GstAudioFilterClass *audio_filter_class = (GstAudioFilterClass *) klass;
362   GstBaseTransformClass *btrans_class = (GstBaseTransformClass *) klass;
363   GObjectClass *gobject_class = (GObjectClass *) klass;
364   GstCaps *caps;
365 
366   gobject_class->finalize = gst_iir_equalizer_finalize;
367   audio_filter_class->setup = gst_iir_equalizer_setup;
368   btrans_class->transform_ip = gst_iir_equalizer_transform_ip;
369   btrans_class->transform_ip_on_passthrough = FALSE;
370 
371   caps = gst_caps_from_string (ALLOWED_CAPS);
372   gst_audio_filter_class_add_pad_templates (audio_filter_class, caps);
373   gst_caps_unref (caps);
374 }
375 
376 static void
gst_iir_equalizer_init(GstIirEqualizer * eq)377 gst_iir_equalizer_init (GstIirEqualizer * eq)
378 {
379   g_mutex_init (&eq->bands_lock);
380   /* Band gains are 0 by default, passthrough until they are changed */
381   gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (eq), TRUE);
382 }
383 
384 static void
gst_iir_equalizer_finalize(GObject * object)385 gst_iir_equalizer_finalize (GObject * object)
386 {
387   GstIirEqualizer *equ = GST_IIR_EQUALIZER (object);
388   gint i;
389 
390   for (i = 0; i < equ->freq_band_count; i++) {
391     if (equ->bands[i])
392       gst_object_unparent (GST_OBJECT (equ->bands[i]));
393     equ->bands[i] = NULL;
394   }
395   equ->freq_band_count = 0;
396 
397   g_free (equ->bands);
398   g_free (equ->history);
399 
400   g_mutex_clear (&equ->bands_lock);
401 
402   G_OBJECT_CLASS (parent_class)->finalize (object);
403 }
404 
405 /* Filter taken from
406  *
407  * The Equivalence of Various Methods of Computing
408  * Biquad Coefficients for Audio Parametric Equalizers
409  *
410  * by Robert Bristow-Johnson
411  *
412  * http://www.aes.org/e-lib/browse.cfm?elib=6326
413  * http://www.musicdsp.org/files/EQ-Coefficients.pdf
414  * http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt
415  *
416  * The bandwidth method that we use here is the preferred
417  * one from this article transformed from octaves to frequency
418  * in Hz.
419  */
420 static inline gdouble
arg_to_scale(gdouble arg)421 arg_to_scale (gdouble arg)
422 {
423   return (pow (10.0, arg / 40.0));
424 }
425 
426 static gdouble
calculate_omega(gdouble freq,gint rate)427 calculate_omega (gdouble freq, gint rate)
428 {
429   gdouble omega;
430 
431   if (freq / rate >= 0.5)
432     omega = G_PI;
433   else if (freq <= 0.0)
434     omega = 0.0;
435   else
436     omega = 2.0 * G_PI * (freq / rate);
437 
438   return omega;
439 }
440 
441 static gdouble
calculate_bw(GstIirEqualizerBand * band,gint rate)442 calculate_bw (GstIirEqualizerBand * band, gint rate)
443 {
444   gdouble bw = 0.0;
445 
446   if (band->width / rate >= 0.5) {
447     /* If bandwidth == 0.5 the calculation below fails as tan(G_PI/2)
448      * is undefined. So set the bandwidth to a slightly smaller value.
449      */
450     bw = G_PI - 0.00000001;
451   } else if (band->width <= 0.0) {
452     /* If bandwidth == 0 this band won't change anything so set
453      * the coefficients accordingly. The coefficient calculation
454      * below would create coefficients that for some reason amplify
455      * the band.
456      */
457     band->a0 = 1.0;
458     band->a1 = 0.0;
459     band->a2 = 0.0;
460     band->b1 = 0.0;
461     band->b2 = 0.0;
462   } else {
463     bw = 2.0 * G_PI * (band->width / rate);
464   }
465   return bw;
466 }
467 
468 static void
setup_peak_filter(GstIirEqualizer * equ,GstIirEqualizerBand * band)469 setup_peak_filter (GstIirEqualizer * equ, GstIirEqualizerBand * band)
470 {
471   gint rate = GST_AUDIO_FILTER_RATE (equ);
472 
473   g_return_if_fail (rate);
474 
475   {
476     gdouble gain, omega, bw;
477     gdouble alpha, alpha1, alpha2, b0;
478 
479     gain = arg_to_scale (band->gain);
480     omega = calculate_omega (band->freq, rate);
481     bw = calculate_bw (band, rate);
482     if (bw == 0.0)
483       goto out;
484 
485     alpha = tan (bw / 2.0);
486 
487     alpha1 = alpha * gain;
488     alpha2 = alpha / gain;
489 
490     b0 = (1.0 + alpha2);
491 
492     band->a0 = (1.0 + alpha1) / b0;
493     band->a1 = (-2.0 * cos (omega)) / b0;
494     band->a2 = (1.0 - alpha1) / b0;
495     band->b1 = (2.0 * cos (omega)) / b0;
496     band->b2 = -(1.0 - alpha2) / b0;
497 
498   out:
499     GST_INFO
500         ("gain = %5.1f, width= %7.2f, freq = %7.2f, a0 = %7.5g, a1 = %7.5g, a2=%7.5g b1 = %7.5g, b2 = %7.5g",
501         band->gain, band->width, band->freq, band->a0, band->a1, band->a2,
502         band->b1, band->b2);
503   }
504 }
505 
506 static void
setup_low_shelf_filter(GstIirEqualizer * equ,GstIirEqualizerBand * band)507 setup_low_shelf_filter (GstIirEqualizer * equ, GstIirEqualizerBand * band)
508 {
509   gint rate = GST_AUDIO_FILTER_RATE (equ);
510 
511   g_return_if_fail (rate);
512 
513   {
514     gdouble gain, omega, bw;
515     gdouble alpha, delta, b0;
516     gdouble egp, egm;
517 
518     gain = arg_to_scale (band->gain);
519     omega = calculate_omega (band->freq, rate);
520     bw = calculate_bw (band, rate);
521     if (bw == 0.0)
522       goto out;
523 
524     egm = gain - 1.0;
525     egp = gain + 1.0;
526     alpha = tan (bw / 2.0);
527 
528     delta = 2.0 * sqrt (gain) * alpha;
529     b0 = egp + egm * cos (omega) + delta;
530 
531     band->a0 = ((egp - egm * cos (omega) + delta) * gain) / b0;
532     band->a1 = ((egm - egp * cos (omega)) * 2.0 * gain) / b0;
533     band->a2 = ((egp - egm * cos (omega) - delta) * gain) / b0;
534     band->b1 = ((egm + egp * cos (omega)) * 2.0) / b0;
535     band->b2 = -((egp + egm * cos (omega) - delta)) / b0;
536 
537 
538   out:
539     GST_INFO
540         ("gain = %5.1f, width= %7.2f, freq = %7.2f, a0 = %7.5g, a1 = %7.5g, a2=%7.5g b1 = %7.5g, b2 = %7.5g",
541         band->gain, band->width, band->freq, band->a0, band->a1, band->a2,
542         band->b1, band->b2);
543   }
544 }
545 
546 static void
setup_high_shelf_filter(GstIirEqualizer * equ,GstIirEqualizerBand * band)547 setup_high_shelf_filter (GstIirEqualizer * equ, GstIirEqualizerBand * band)
548 {
549   gint rate = GST_AUDIO_FILTER_RATE (equ);
550 
551   g_return_if_fail (rate);
552 
553   {
554     gdouble gain, omega, bw;
555     gdouble alpha, delta, b0;
556     gdouble egp, egm;
557 
558     gain = arg_to_scale (band->gain);
559     omega = calculate_omega (band->freq, rate);
560     bw = calculate_bw (band, rate);
561     if (bw == 0.0)
562       goto out;
563 
564     egm = gain - 1.0;
565     egp = gain + 1.0;
566     alpha = tan (bw / 2.0);
567 
568     delta = 2.0 * sqrt (gain) * alpha;
569     b0 = egp - egm * cos (omega) + delta;
570 
571     band->a0 = ((egp + egm * cos (omega) + delta) * gain) / b0;
572     band->a1 = ((egm + egp * cos (omega)) * -2.0 * gain) / b0;
573     band->a2 = ((egp + egm * cos (omega) - delta) * gain) / b0;
574     band->b1 = ((egm - egp * cos (omega)) * -2.0) / b0;
575     band->b2 = -((egp - egm * cos (omega) - delta)) / b0;
576 
577 
578   out:
579     GST_INFO
580         ("gain = %5.1f, width= %7.2f, freq = %7.2f, a0 = %7.5g, a1 = %7.5g, a2=%7.5g b1 = %7.5g, b2 = %7.5g",
581         band->gain, band->width, band->freq, band->a0, band->a1, band->a2,
582         band->b1, band->b2);
583   }
584 }
585 
586 /* Must be called with bands_lock and transform lock! */
587 static void
set_passthrough(GstIirEqualizer * equ)588 set_passthrough (GstIirEqualizer * equ)
589 {
590   gint i;
591   gboolean passthrough = TRUE;
592 
593   for (i = 0; i < equ->freq_band_count; i++) {
594     passthrough = passthrough && (equ->bands[i]->gain == 0.0);
595   }
596 
597   gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (equ), passthrough);
598   GST_DEBUG ("Passthrough mode: %d\n", passthrough);
599 }
600 
601 /* Must be called with bands_lock and transform lock! */
602 static void
update_coefficients(GstIirEqualizer * equ)603 update_coefficients (GstIirEqualizer * equ)
604 {
605   gint i, n = equ->freq_band_count;
606 
607   for (i = 0; i < n; i++) {
608     if (equ->bands[i]->type == BAND_TYPE_PEAK)
609       setup_peak_filter (equ, equ->bands[i]);
610     else if (equ->bands[i]->type == BAND_TYPE_LOW_SHELF)
611       setup_low_shelf_filter (equ, equ->bands[i]);
612     else
613       setup_high_shelf_filter (equ, equ->bands[i]);
614   }
615 
616   equ->need_new_coefficients = FALSE;
617 }
618 
619 /* Must be called with transform lock! */
620 static void
alloc_history(GstIirEqualizer * equ,const GstAudioInfo * info)621 alloc_history (GstIirEqualizer * equ, const GstAudioInfo * info)
622 {
623   /* free + alloc = no memcpy */
624   g_free (equ->history);
625   equ->history =
626       g_malloc0 (equ->history_size * GST_AUDIO_INFO_CHANNELS (info) *
627       equ->freq_band_count);
628 }
629 
630 void
gst_iir_equalizer_compute_frequencies(GstIirEqualizer * equ,guint new_count)631 gst_iir_equalizer_compute_frequencies (GstIirEqualizer * equ, guint new_count)
632 {
633   guint old_count, i;
634   gdouble freq0, freq1, step;
635   gchar name[20];
636 
637   if (equ->freq_band_count == new_count)
638     return;
639 
640   BANDS_LOCK (equ);
641 
642   if (G_UNLIKELY (equ->freq_band_count == new_count)) {
643     BANDS_UNLOCK (equ);
644     return;
645   }
646 
647   old_count = equ->freq_band_count;
648   equ->freq_band_count = new_count;
649   GST_DEBUG ("bands %u -> %u", old_count, new_count);
650 
651   if (old_count < new_count) {
652     /* add new bands */
653     equ->bands = g_realloc (equ->bands, sizeof (GstObject *) * new_count);
654     for (i = old_count; i < new_count; i++) {
655       /* otherwise they get names like 'iirequalizerband5' */
656       sprintf (name, "band%u", i);
657       equ->bands[i] = g_object_new (GST_TYPE_IIR_EQUALIZER_BAND,
658           "name", name, NULL);
659       GST_DEBUG ("adding band[%d]=%p", i, equ->bands[i]);
660 
661       gst_object_set_parent (GST_OBJECT (equ->bands[i]), GST_OBJECT (equ));
662       gst_child_proxy_child_added (GST_CHILD_PROXY (equ),
663           G_OBJECT (equ->bands[i]), name);
664     }
665   } else {
666     /* free unused bands */
667     for (i = new_count; i < old_count; i++) {
668       GST_DEBUG ("removing band[%d]=%p", i, equ->bands[i]);
669       gst_child_proxy_child_removed (GST_CHILD_PROXY (equ),
670           G_OBJECT (equ->bands[i]), GST_OBJECT_NAME (equ->bands[i]));
671       gst_object_unparent (GST_OBJECT (equ->bands[i]));
672       equ->bands[i] = NULL;
673     }
674   }
675 
676   alloc_history (equ, GST_AUDIO_FILTER_INFO (equ));
677 
678   /* set center frequencies and name band objects
679    * FIXME: arg! we can't change the name of parented objects :(
680    *   application should read band->freq to get the name
681    */
682 
683   step = pow (HIGHEST_FREQ / LOWEST_FREQ, 1.0 / new_count);
684   freq0 = LOWEST_FREQ;
685   for (i = 0; i < new_count; i++) {
686     freq1 = freq0 * step;
687 
688     if (i == 0)
689       equ->bands[i]->type = BAND_TYPE_LOW_SHELF;
690     else if (i == new_count - 1)
691       equ->bands[i]->type = BAND_TYPE_HIGH_SHELF;
692     else
693       equ->bands[i]->type = BAND_TYPE_PEAK;
694 
695     equ->bands[i]->freq = freq0 + ((freq1 - freq0) / 2.0);
696     equ->bands[i]->width = freq1 - freq0;
697     GST_DEBUG ("band[%2d] = '%lf'", i, equ->bands[i]->freq);
698 
699     g_object_notify (G_OBJECT (equ->bands[i]), "bandwidth");
700     g_object_notify (G_OBJECT (equ->bands[i]), "freq");
701     g_object_notify (G_OBJECT (equ->bands[i]), "type");
702 
703     /*
704        if(equ->bands[i]->freq<10000.0)
705        sprintf (name,"%dHz",(gint)equ->bands[i]->freq);
706        else
707        sprintf (name,"%dkHz",(gint)(equ->bands[i]->freq/1000.0));
708        gst_object_set_name( GST_OBJECT (equ->bands[i]), name);
709        GST_DEBUG ("band[%2d] = '%s'",i,name);
710      */
711     freq0 = freq1;
712   }
713 
714   equ->need_new_coefficients = TRUE;
715   BANDS_UNLOCK (equ);
716 }
717 
718 /* start of code that is type specific */
719 
720 #define CREATE_OPTIMIZED_FUNCTIONS_INT(TYPE,BIG_TYPE,MIN_VAL,MAX_VAL)   \
721 typedef struct {                                                        \
722   BIG_TYPE x1, x2;          /* history of input values for a filter */  \
723   BIG_TYPE y1, y2;          /* history of output values for a filter */ \
724 } SecondOrderHistory ## TYPE;                                           \
725                                                                         \
726 static inline BIG_TYPE                                                  \
727 one_step_ ## TYPE (GstIirEqualizerBand *filter,                         \
728     SecondOrderHistory ## TYPE *history, BIG_TYPE input)                \
729 {                                                                       \
730   /* calculate output */                                                \
731   BIG_TYPE output = filter->a0 * input +                                \
732       filter->a1 * history->x1 + filter->a2 * history->x2 +             \
733       filter->b1 * history->y1 + filter->b2 * history->y2;              \
734   /* update history */                                                  \
735   history->y2 = history->y1;                                            \
736   history->y1 = output;                                                 \
737   history->x2 = history->x1;                                            \
738   history->x1 = input;                                                  \
739                                                                         \
740   return output;                                                        \
741 }                                                                       \
742                                                                         \
743 static const guint                                                      \
744 history_size_ ## TYPE = sizeof (SecondOrderHistory ## TYPE);            \
745                                                                         \
746 static void                                                             \
747 gst_iir_equ_process_ ## TYPE (GstIirEqualizer *equ, guint8 *data,       \
748 guint size, guint channels)                                             \
749 {                                                                       \
750   guint frames = size / channels / sizeof (TYPE);                       \
751   guint i, c, f, nf = equ->freq_band_count;                             \
752   BIG_TYPE cur;                                                         \
753   GstIirEqualizerBand **filters = equ->bands;                           \
754                                                                         \
755   for (i = 0; i < frames; i++) {                                        \
756     SecondOrderHistory ## TYPE *history = equ->history;                 \
757     for (c = 0; c < channels; c++) {                                    \
758       cur = *((TYPE *) data);                                           \
759       for (f = 0; f < nf; f++) {                                        \
760         cur = one_step_ ## TYPE (filters[f], history, cur);             \
761         history++;                                                      \
762       }                                                                 \
763       cur = CLAMP (cur, MIN_VAL, MAX_VAL);                              \
764       *((TYPE *) data) = (TYPE) floor (cur);                            \
765       data += sizeof (TYPE);                                            \
766     }                                                                   \
767   }                                                                     \
768 }
769 
770 #define CREATE_OPTIMIZED_FUNCTIONS(TYPE)                                \
771 typedef struct {                                                        \
772   TYPE x1, x2;          /* history of input values for a filter */  \
773   TYPE y1, y2;          /* history of output values for a filter */ \
774 } SecondOrderHistory ## TYPE;                                           \
775                                                                         \
776 static inline TYPE                                                      \
777 one_step_ ## TYPE (GstIirEqualizerBand *filter,                         \
778     SecondOrderHistory ## TYPE *history, TYPE input)                    \
779 {                                                                       \
780   /* calculate output */                                                \
781   TYPE output = filter->a0 * input + filter->a1 * history->x1 +         \
782       filter->a2 * history->x2 + filter->b1 * history->y1 +             \
783       filter->b2 * history->y2;                                         \
784   /* update history */                                                  \
785   history->y2 = history->y1;                                            \
786   history->y1 = output;                                                 \
787   history->x2 = history->x1;                                            \
788   history->x1 = input;                                                  \
789                                                                         \
790   return output;                                                        \
791 }                                                                       \
792                                                                         \
793 static const guint                                                      \
794 history_size_ ## TYPE = sizeof (SecondOrderHistory ## TYPE);            \
795                                                                         \
796 static void                                                             \
797 gst_iir_equ_process_ ## TYPE (GstIirEqualizer *equ, guint8 *data,       \
798 guint size, guint channels)                                             \
799 {                                                                       \
800   guint frames = size / channels / sizeof (TYPE);                       \
801   guint i, c, f, nf = equ->freq_band_count;                             \
802   TYPE cur;                                                             \
803   GstIirEqualizerBand **filters = equ->bands;                           \
804                                                                         \
805   for (i = 0; i < frames; i++) {                                        \
806     SecondOrderHistory ## TYPE *history = equ->history;                 \
807     for (c = 0; c < channels; c++) {                                    \
808       cur = *((TYPE *) data);                                           \
809       for (f = 0; f < nf; f++) {                                        \
810         cur = one_step_ ## TYPE (filters[f], history, cur);             \
811         history++;                                                      \
812       }                                                                 \
813       *((TYPE *) data) = (TYPE) cur;                                    \
814       data += sizeof (TYPE);                                            \
815     }                                                                   \
816   }                                                                     \
817 }
818 
819 CREATE_OPTIMIZED_FUNCTIONS_INT (gint16, gfloat, -32768.0, 32767.0);
820 CREATE_OPTIMIZED_FUNCTIONS (gfloat);
821 CREATE_OPTIMIZED_FUNCTIONS (gdouble);
822 
823 static GstFlowReturn
gst_iir_equalizer_transform_ip(GstBaseTransform * btrans,GstBuffer * buf)824 gst_iir_equalizer_transform_ip (GstBaseTransform * btrans, GstBuffer * buf)
825 {
826   GstAudioFilter *filter = GST_AUDIO_FILTER (btrans);
827   GstIirEqualizer *equ = GST_IIR_EQUALIZER (btrans);
828   GstClockTime timestamp;
829   GstMapInfo map;
830   gint channels = GST_AUDIO_FILTER_CHANNELS (filter);
831   gboolean need_new_coefficients;
832 
833   if (G_UNLIKELY (channels < 1 || equ->process == NULL))
834     return GST_FLOW_NOT_NEGOTIATED;
835 
836   BANDS_LOCK (equ);
837   need_new_coefficients = equ->need_new_coefficients;
838   BANDS_UNLOCK (equ);
839 
840   timestamp = GST_BUFFER_TIMESTAMP (buf);
841   timestamp =
842       gst_segment_to_stream_time (&btrans->segment, GST_FORMAT_TIME, timestamp);
843 
844   if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
845     GstIirEqualizerBand **filters = equ->bands;
846     guint f, nf = equ->freq_band_count;
847 
848     gst_object_sync_values (GST_OBJECT (equ), timestamp);
849 
850     /* sync values for bands too */
851     /* FIXME: iterating equ->bands is not thread-safe here */
852     for (f = 0; f < nf; f++) {
853       gst_object_sync_values (GST_OBJECT (filters[f]), timestamp);
854     }
855   }
856 
857   BANDS_LOCK (equ);
858   if (need_new_coefficients) {
859     update_coefficients (equ);
860   }
861   BANDS_UNLOCK (equ);
862 
863   gst_buffer_map (buf, &map, GST_MAP_READWRITE);
864   equ->process (equ, map.data, map.size, channels);
865   gst_buffer_unmap (buf, &map);
866 
867   return GST_FLOW_OK;
868 }
869 
870 static gboolean
gst_iir_equalizer_setup(GstAudioFilter * audio,const GstAudioInfo * info)871 gst_iir_equalizer_setup (GstAudioFilter * audio, const GstAudioInfo * info)
872 {
873   GstIirEqualizer *equ = GST_IIR_EQUALIZER (audio);
874 
875   switch (GST_AUDIO_INFO_FORMAT (info)) {
876     case GST_AUDIO_FORMAT_S16:
877       equ->history_size = history_size_gint16;
878       equ->process = gst_iir_equ_process_gint16;
879       break;
880     case GST_AUDIO_FORMAT_F32:
881       equ->history_size = history_size_gfloat;
882       equ->process = gst_iir_equ_process_gfloat;
883       break;
884     case GST_AUDIO_FORMAT_F64:
885       equ->history_size = history_size_gdouble;
886       equ->process = gst_iir_equ_process_gdouble;
887       break;
888     default:
889       return FALSE;
890   }
891 
892   alloc_history (equ, info);
893   return TRUE;
894 }
895 
896 void
equalizer_element_init(GstPlugin * plugin)897 equalizer_element_init (GstPlugin * plugin)
898 {
899   static gsize res = FALSE;
900   if (g_once_init_enter (&res)) {
901     GST_DEBUG_CATEGORY_INIT (equalizer_debug, "equalizer", 0, "equalizer");
902     g_once_init_leave (&res, TRUE);
903   }
904 }
905