3 * Copyright (C) 2007-2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
26 #include <gst/base/gstbasetransform.h>
27 #include <gst/audio/audio.h>
28 #include <gst/audio/gstaudiofilter.h>
29 #include <gst/controller/gstcontroller.h>
33 #include "audiofxbaseiirfilter.h"
35 #define GST_CAT_DEFAULT gst_audio_fx_base_iir_filter_debug
36 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
38 #define ALLOWED_CAPS \
39 "audio/x-raw-float," \
40 " width = (int) { 32, 64 }, " \
41 " endianness = (int) BYTE_ORDER," \
42 " rate = (int) [ 1, MAX ]," \
43 " channels = (int) [ 1, MAX ]"
45 #define DEBUG_INIT(bla) \
46 GST_DEBUG_CATEGORY_INIT (gst_audio_fx_base_iir_filter_debug, "audiofxbaseiirfilter", 0, "Audio IIR Filter Base Class");
48 GST_BOILERPLATE_FULL (GstAudioFXBaseIIRFilter,
49 gst_audio_fx_base_iir_filter, GstAudioFilter, GST_TYPE_AUDIO_FILTER,
52 static gboolean gst_audio_fx_base_iir_filter_setup (GstAudioFilter * filter,
53 GstRingBufferSpec * format);
55 gst_audio_fx_base_iir_filter_transform_ip (GstBaseTransform * base,
57 static gboolean gst_audio_fx_base_iir_filter_stop (GstBaseTransform * base);
59 static void process_64 (GstAudioFXBaseIIRFilter * filter,
60 gdouble * data, guint num_samples);
61 static void process_32 (GstAudioFXBaseIIRFilter * filter,
62 gfloat * data, guint num_samples);
64 /* GObject vmethod implementations */
67 gst_audio_fx_base_iir_filter_base_init (gpointer klass)
71 caps = gst_caps_from_string (ALLOWED_CAPS);
72 gst_audio_filter_class_add_pad_templates (GST_AUDIO_FILTER_CLASS (klass),
74 gst_caps_unref (caps);
78 gst_audio_fx_base_iir_filter_dispose (GObject * object)
80 GstAudioFXBaseIIRFilter *filter = GST_AUDIO_FX_BASE_IIR_FILTER (object);
92 if (filter->channels) {
93 GstAudioFXBaseIIRFilterChannelCtx *ctx;
96 for (i = 0; i < filter->nchannels; i++) {
97 ctx = &filter->channels[i];
102 g_free (filter->channels);
103 filter->channels = NULL;
106 G_OBJECT_CLASS (parent_class)->dispose (object);
110 gst_audio_fx_base_iir_filter_class_init (GstAudioFXBaseIIRFilterClass * klass)
112 GObjectClass *gobject_class = (GObjectClass *) klass;
113 GstBaseTransformClass *trans_class = (GstBaseTransformClass *) klass;
114 GstAudioFilterClass *filter_class = (GstAudioFilterClass *) klass;
116 gobject_class->dispose = gst_audio_fx_base_iir_filter_dispose;
118 filter_class->setup = GST_DEBUG_FUNCPTR (gst_audio_fx_base_iir_filter_setup);
120 trans_class->transform_ip =
121 GST_DEBUG_FUNCPTR (gst_audio_fx_base_iir_filter_transform_ip);
122 trans_class->stop = GST_DEBUG_FUNCPTR (gst_audio_fx_base_iir_filter_stop);
126 gst_audio_fx_base_iir_filter_init (GstAudioFXBaseIIRFilter * filter,
127 GstAudioFXBaseIIRFilterClass * klass)
129 gst_base_transform_set_in_place (GST_BASE_TRANSFORM (filter), TRUE);
135 filter->channels = NULL;
136 filter->nchannels = 0;
139 /* Evaluate the transfer function that corresponds to the IIR
140 * coefficients at zr + zi*I and return the magnitude */
142 gst_audio_fx_base_iir_filter_calculate_gain (gdouble * a, guint na, gdouble * b,
143 guint nb, gdouble zr, gdouble zi)
145 gdouble sum_ar, sum_ai;
146 gdouble sum_br, sum_bi;
147 gdouble gain_r, gain_i;
156 for (i = na - 1; i >= 0; i--) {
160 sum_ar = (sum_r_old * zr - sum_i_old * zi) + a[i];
161 sum_ai = (sum_r_old * zi + sum_i_old * zr) + 0.0;
166 for (i = nb - 1; i >= 0; i--) {
170 sum_br = (sum_r_old * zr - sum_i_old * zi) - b[i];
171 sum_bi = (sum_r_old * zi + sum_i_old * zr) - 0.0;
177 (sum_ar * sum_br + sum_ai * sum_bi) / (sum_br * sum_br + sum_bi * sum_bi);
179 (sum_ai * sum_br - sum_ar * sum_bi) / (sum_br * sum_br + sum_bi * sum_bi);
181 return (sqrt (gain_r * gain_r + gain_i * gain_i));
185 gst_audio_fx_base_iir_filter_set_coefficients (GstAudioFXBaseIIRFilter * filter,
186 gdouble * a, guint na, gdouble * b, guint nb)
190 g_return_if_fail (GST_IS_AUDIO_FX_BASE_IIR_FILTER (filter));
192 GST_BASE_TRANSFORM_LOCK (filter);
197 filter->a = filter->b = NULL;
199 if (filter->channels) {
200 GstAudioFXBaseIIRFilterChannelCtx *ctx;
201 gboolean free = (na != filter->na || nb != filter->nb);
203 for (i = 0; i < filter->nchannels; i++) {
204 ctx = &filter->channels[i];
209 memset (ctx->x, 0, filter->na * sizeof (gdouble));
214 memset (ctx->y, 0, filter->nb * sizeof (gdouble));
217 g_free (filter->channels);
218 filter->channels = NULL;
227 if (filter->nchannels && !filter->channels) {
228 GstAudioFXBaseIIRFilterChannelCtx *ctx;
231 g_new0 (GstAudioFXBaseIIRFilterChannelCtx, filter->nchannels);
232 for (i = 0; i < filter->nchannels; i++) {
233 ctx = &filter->channels[i];
235 ctx->x = g_new0 (gdouble, filter->na);
236 ctx->y = g_new0 (gdouble, filter->nb);
240 GST_BASE_TRANSFORM_UNLOCK (filter);
243 /* GstAudioFilter vmethod implementations */
246 gst_audio_fx_base_iir_filter_setup (GstAudioFilter * base,
247 GstRingBufferSpec * format)
249 GstAudioFXBaseIIRFilter *filter = GST_AUDIO_FX_BASE_IIR_FILTER (base);
252 if (format->width == 32)
253 filter->process = (GstAudioFXBaseIIRFilterProcessFunc)
255 else if (format->width == 64)
256 filter->process = (GstAudioFXBaseIIRFilterProcessFunc)
261 if (format->channels != filter->nchannels) {
263 GstAudioFXBaseIIRFilterChannelCtx *ctx;
265 if (filter->channels) {
267 for (i = 0; i < filter->nchannels; i++) {
268 ctx = &filter->channels[i];
274 g_free (filter->channels);
275 filter->channels = NULL;
278 filter->nchannels = format->channels;
281 g_new0 (GstAudioFXBaseIIRFilterChannelCtx, filter->nchannels);
282 for (i = 0; i < filter->nchannels; i++) {
283 ctx = &filter->channels[i];
285 ctx->x = g_new0 (gdouble, filter->na);
286 ctx->y = g_new0 (gdouble, filter->nb);
293 static inline gdouble
294 process (GstAudioFXBaseIIRFilter * filter,
295 GstAudioFXBaseIIRFilterChannelCtx * ctx, gdouble x0)
297 gdouble val = filter->a[0] * x0;
300 for (i = 1, j = ctx->x_pos; i < filter->na; i++) {
301 val += filter->a[i] * ctx->x[j];
307 for (i = 1, j = ctx->y_pos; i < filter->nb; i++) {
308 val += filter->b[i] * ctx->y[j];
316 if (ctx->x_pos >= filter->na)
318 ctx->x[ctx->x_pos] = x0;
322 if (ctx->y_pos >= filter->nb)
325 ctx->y[ctx->y_pos] = val;
331 #define DEFINE_PROCESS_FUNC(width,ctype) \
333 process_##width (GstAudioFXBaseIIRFilter * filter, \
334 g##ctype * data, guint num_samples) \
336 gint i, j, channels = GST_AUDIO_FILTER (filter)->format.channels; \
339 for (i = 0; i < num_samples / channels; i++) { \
340 for (j = 0; j < channels; j++) { \
341 val = process (filter, &filter->channels[j], *data); \
347 DEFINE_PROCESS_FUNC (32, float);
348 DEFINE_PROCESS_FUNC (64, double);
350 #undef DEFINE_PROCESS_FUNC
352 /* GstBaseTransform vmethod implementations */
354 gst_audio_fx_base_iir_filter_transform_ip (GstBaseTransform * base,
357 GstAudioFXBaseIIRFilter *filter = GST_AUDIO_FX_BASE_IIR_FILTER (base);
359 GstClockTime timestamp, stream_time;
361 timestamp = GST_BUFFER_TIMESTAMP (buf);
363 gst_segment_to_stream_time (&base->segment, GST_FORMAT_TIME, timestamp);
365 GST_DEBUG_OBJECT (filter, "sync to %" GST_TIME_FORMAT,
366 GST_TIME_ARGS (timestamp));
368 if (GST_CLOCK_TIME_IS_VALID (stream_time))
369 gst_object_sync_values (G_OBJECT (filter), stream_time);
372 GST_BUFFER_SIZE (buf) / (GST_AUDIO_FILTER (filter)->format.width / 8);
374 if (gst_base_transform_is_passthrough (base))
377 g_return_val_if_fail (filter->a != NULL, GST_FLOW_ERROR);
379 filter->process (filter, GST_BUFFER_DATA (buf), num_samples);
386 gst_audio_fx_base_iir_filter_stop (GstBaseTransform * base)
388 GstAudioFXBaseIIRFilter *filter = GST_AUDIO_FX_BASE_IIR_FILTER (base);
389 guint channels = GST_AUDIO_FILTER (filter)->format.channels;
390 GstAudioFXBaseIIRFilterChannelCtx *ctx;
393 /* Reset the history of input and output values if
394 * already existing */
395 if (channels && filter->channels) {
396 for (i = 0; i < channels; i++) {
397 ctx = &filter->channels[i];
401 g_free (filter->channels);
403 filter->channels = NULL;