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