gst-plugins-good  1.20.3
About: GStreamer (Good Plugins) is a library for constructing of graphs of media-handling components. A set of good-quality plug-ins (under LGPL license).
  Fossies Dox: gst-plugins-good-1.20.3.tar.xz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

audiofxbaseiirfilter.c
Go to the documentation of this file.
1/*
2 * GStreamer
3 * Copyright (C) 2007-2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
4 *
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.
9 *
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.
14 *
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., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21#ifdef HAVE_CONFIG_H
22#include "config.h"
23#endif
24
25#include <string.h>
26
27#include <gst/gst.h>
28#include <gst/base/gstbasetransform.h>
29#include <gst/audio/audio.h>
30#include <gst/audio/gstaudiofilter.h>
31
32#include <math.h>
33
35
36#define GST_CAT_DEFAULT gst_audio_fx_base_iir_filter_debug
38
39#define ALLOWED_CAPS \
40 "audio/x-raw," \
41 " format=(string){"GST_AUDIO_NE(F32)","GST_AUDIO_NE(F64)"}," \
42 " rate = (int) [ 1, MAX ]," \
43 " channels = (int) [ 1, MAX ]," \
44 " layout=(string) interleaved"
45
46#define gst_audio_fx_base_iir_filter_parent_class parent_class
48 gst_audio_fx_base_iir_filter, GST_TYPE_AUDIO_FILTER);
49
50static gboolean gst_audio_fx_base_iir_filter_setup (GstAudioFilter * filter,
51 const GstAudioInfo * info);
52static GstFlowReturn
53gst_audio_fx_base_iir_filter_transform_ip (GstBaseTransform * base,
54 GstBuffer * buf);
55static gboolean gst_audio_fx_base_iir_filter_stop (GstBaseTransform * base);
56
57static void process_64 (GstAudioFXBaseIIRFilter * filter,
58 gdouble * data, guint num_samples);
59static void process_32 (GstAudioFXBaseIIRFilter * filter,
60 gfloat * data, guint num_samples);
61
62/* GObject vmethod implementations */
63
64static void
66{
68
69 if (filter->a) {
70 g_free (filter->a);
71 filter->a = NULL;
72 }
73
74 if (filter->b) {
75 g_free (filter->b);
76 filter->b = NULL;
77 }
78
79 if (filter->channels) {
81 guint i;
82
83 for (i = 0; i < filter->nchannels; i++) {
84 ctx = &filter->channels[i];
85 g_free (ctx->x);
86 g_free (ctx->y);
87 }
88
89 g_free (filter->channels);
90 filter->channels = NULL;
91 }
92 g_mutex_clear (&filter->lock);
93
94 G_OBJECT_CLASS (parent_class)->finalize (object);
95}
96
97static void
99{
100 GObjectClass *gobject_class = (GObjectClass *) klass;
101 GstBaseTransformClass *trans_class = (GstBaseTransformClass *) klass;
102 GstAudioFilterClass *filter_class = (GstAudioFilterClass *) klass;
103 GstCaps *caps;
104
105 GST_DEBUG_CATEGORY_INIT (gst_audio_fx_base_iir_filter_debug,
106 "audiofxbaseiirfilter", 0, "Audio IIR Filter Base Class");
107
108 gobject_class->finalize = gst_audio_fx_base_iir_filter_finalize;
109
110 caps = gst_caps_from_string (ALLOWED_CAPS);
111 gst_audio_filter_class_add_pad_templates (GST_AUDIO_FILTER_CLASS (klass),
112 caps);
113 gst_caps_unref (caps);
114
115 filter_class->setup = GST_DEBUG_FUNCPTR (gst_audio_fx_base_iir_filter_setup);
116
117 trans_class->transform_ip =
119 trans_class->transform_ip_on_passthrough = FALSE;
120 trans_class->stop = GST_DEBUG_FUNCPTR (gst_audio_fx_base_iir_filter_stop);
121
122 gst_type_mark_as_plugin_api (GST_TYPE_AUDIO_FX_BASE_IIR_FILTER, 0);
123}
124
125static void
127{
128 gst_base_transform_set_in_place (GST_BASE_TRANSFORM (filter), TRUE);
129
130 filter->a = NULL;
131 filter->na = 0;
132 filter->b = NULL;
133 filter->nb = 0;
134 filter->channels = NULL;
135 filter->nchannels = 0;
136
137 g_mutex_init (&filter->lock);
138}
139
140/* Evaluate the transfer function that corresponds to the IIR
141 * coefficients at (zr + zi*I)^-1 and return the magnitude */
142gdouble
143gst_audio_fx_base_iir_filter_calculate_gain (gdouble * a, guint na, gdouble * b,
144 guint nb, gdouble zr, gdouble zi)
145{
146 gdouble sum_ar, sum_ai;
147 gdouble sum_br, sum_bi;
148 gdouble gain_r, gain_i;
149
150 gdouble sum_r_old;
151 gdouble sum_i_old;
152
153 gint i;
154
155 sum_ar = a[na - 1];
156 sum_ai = 0.0;
157 for (i = na - 2; i >= 0; i--) {
158 sum_r_old = sum_ar;
159 sum_i_old = sum_ai;
160
161 sum_ar = (sum_r_old * zr - sum_i_old * zi) + a[i];
162 sum_ai = (sum_r_old * zi + sum_i_old * zr) + 0.0;
163 }
164
165 sum_br = b[nb - 1];
166 sum_bi = 0.0;
167 for (i = nb - 2; i >= 0; i--) {
168 sum_r_old = sum_br;
169 sum_i_old = sum_bi;
170
171 sum_br = (sum_r_old * zr - sum_i_old * zi) + b[i];
172 sum_bi = (sum_r_old * zi + sum_i_old * zr) + 0.0;
173 }
174
175 gain_r =
176 (sum_br * sum_ar + sum_bi * sum_ai) / (sum_ar * sum_ar + sum_ai * sum_ai);
177 gain_i =
178 (sum_bi * sum_ar - sum_br * sum_ai) / (sum_ar * sum_ar + sum_ai * sum_ai);
179
180 return (sqrt (gain_r * gain_r + gain_i * gain_i));
181}
182
183void
185 gdouble * a, guint na, gdouble * b, guint nb)
186{
187 guint i;
188
189 g_return_if_fail (GST_IS_AUDIO_FX_BASE_IIR_FILTER (filter));
190
191 g_mutex_lock (&filter->lock);
192
193 g_free (filter->a);
194 g_free (filter->b);
195
196 filter->a = filter->b = NULL;
197
198 if (filter->channels) {
200 gboolean free = (na != filter->na || nb != filter->nb);
201
202 for (i = 0; i < filter->nchannels; i++) {
203 ctx = &filter->channels[i];
204
205 if (free)
206 g_free (ctx->x);
207 else
208 memset (ctx->x, 0, filter->nb * sizeof (gdouble));
209
210 if (free)
211 g_free (ctx->y);
212 else
213 memset (ctx->y, 0, filter->na * sizeof (gdouble));
214 }
215
216 g_free (filter->channels);
217 filter->channels = NULL;
218 }
219
220 filter->na = na;
221 filter->nb = nb;
222
223 filter->a = a;
224 filter->b = b;
225
226 if (filter->nchannels && !filter->channels) {
228
229 filter->channels =
231 for (i = 0; i < filter->nchannels; i++) {
232 ctx = &filter->channels[i];
233
234 ctx->x = g_new0 (gdouble, filter->nb);
235 ctx->y = g_new0 (gdouble, filter->na);
236 }
237 }
238
239 g_mutex_unlock (&filter->lock);
240}
241
242/* GstAudioFilter vmethod implementations */
243
244static gboolean
246 const GstAudioInfo * info)
247{
249 gboolean ret = TRUE;
250 gint channels;
251
252 g_mutex_lock (&filter->lock);
253 switch (GST_AUDIO_INFO_FORMAT (info)) {
254 case GST_AUDIO_FORMAT_F32:
257 break;
258 case GST_AUDIO_FORMAT_F64:
261 break;
262 default:
263 ret = FALSE;
264 break;
265 }
266
267 channels = GST_AUDIO_INFO_CHANNELS (info);
268
269 if (channels != filter->nchannels) {
270 guint i;
272
273 if (filter->channels) {
274 for (i = 0; i < filter->nchannels; i++) {
275 ctx = &filter->channels[i];
276
277 g_free (ctx->x);
278 g_free (ctx->y);
279 }
280 g_free (filter->channels);
281 }
282
283 filter->channels = g_new0 (GstAudioFXBaseIIRFilterChannelCtx, channels);
284 for (i = 0; i < channels; i++) {
285 ctx = &filter->channels[i];
286
287 ctx->x = g_new0 (gdouble, filter->nb);
288 ctx->y = g_new0 (gdouble, filter->na);
289 }
290 filter->nchannels = channels;
291 }
292 g_mutex_unlock (&filter->lock);
293
294 return ret;
295}
296
297static inline gdouble
299 GstAudioFXBaseIIRFilterChannelCtx * ctx, gdouble x0)
300{
301 gdouble val = filter->b[0] * x0;
302 gint i, j;
303
304 for (i = 1, j = ctx->x_pos; i < filter->nb; i++) {
305 val += filter->b[i] * ctx->x[j];
306 j--;
307 if (j < 0)
308 j = filter->nb - 1;
309 }
310
311 for (i = 1, j = ctx->y_pos; i < filter->na; i++) {
312 val -= filter->a[i] * ctx->y[j];
313 j--;
314 if (j < 0)
315 j = filter->na - 1;
316 }
317 val /= filter->a[0];
318
319 if (ctx->x) {
320 ctx->x_pos++;
321 if (ctx->x_pos >= filter->nb)
322 ctx->x_pos = 0;
323 ctx->x[ctx->x_pos] = x0;
324 }
325 if (ctx->y) {
326 ctx->y_pos++;
327 if (ctx->y_pos >= filter->na)
328 ctx->y_pos = 0;
329
330 ctx->y[ctx->y_pos] = val;
331 }
332
333 return val;
334}
335
336#define DEFINE_PROCESS_FUNC(width,ctype) \
337static void \
338process_##width (GstAudioFXBaseIIRFilter * filter, \
339 g##ctype * data, guint num_samples) \
340{ \
341 gint i, j, channels = filter->nchannels; \
342 gdouble val; \
343 \
344 for (i = 0; i < num_samples / channels; i++) { \
345 for (j = 0; j < channels; j++) { \
346 val = process (filter, &filter->channels[j], *data); \
347 *data++ = val; \
348 } \
349 } \
350}
351
354
355#undef DEFINE_PROCESS_FUNC
356
357/* GstBaseTransform vmethod implementations */
358static GstFlowReturn
360 GstBuffer * buf)
361{
363 guint num_samples;
364 GstClockTime timestamp, stream_time;
365 GstMapInfo map;
366
367 timestamp = GST_BUFFER_TIMESTAMP (buf);
368 stream_time =
369 gst_segment_to_stream_time (&base->segment, GST_FORMAT_TIME, timestamp);
370
371 GST_DEBUG_OBJECT (filter, "sync to %" GST_TIME_FORMAT,
372 GST_TIME_ARGS (timestamp));
373
374 if (GST_CLOCK_TIME_IS_VALID (stream_time))
375 gst_object_sync_values (GST_OBJECT (filter), stream_time);
376
377 gst_buffer_map (buf, &map, GST_MAP_READWRITE);
378 num_samples = map.size / GST_AUDIO_FILTER_BPS (filter);
379
380 g_mutex_lock (&filter->lock);
381 if (filter->a == NULL || filter->b == NULL) {
382 g_warn_if_fail (filter->a != NULL && filter->b != NULL);
383 gst_buffer_unmap (buf, &map);
384 g_mutex_unlock (&filter->lock);
385 return GST_FLOW_ERROR;
386 }
387 filter->process (filter, map.data, num_samples);
388 g_mutex_unlock (&filter->lock);
389
390 gst_buffer_unmap (buf, &map);
391
392 return GST_FLOW_OK;
393}
394
395
396static gboolean
397gst_audio_fx_base_iir_filter_stop (GstBaseTransform * base)
398{
400 guint channels = filter->nchannels;
402 guint i;
403
404 /* Reset the history of input and output values if
405 * already existing */
406 if (channels && filter->channels) {
407 for (i = 0; i < channels; i++) {
408 ctx = &filter->channels[i];
409 g_free (ctx->x);
410 g_free (ctx->y);
411 }
412 g_free (filter->channels);
413 }
414 filter->channels = NULL;
415 filter->nchannels = 0;
416
417 return TRUE;
418}
static gboolean gst_audio_fx_base_iir_filter_setup(GstAudioFilter *filter, const GstAudioInfo *info)
static void process_32(GstAudioFXBaseIIRFilter *filter, gfloat *data, guint num_samples)
static gboolean gst_audio_fx_base_iir_filter_stop(GstBaseTransform *base)
gdouble gst_audio_fx_base_iir_filter_calculate_gain(gdouble *a, guint na, gdouble *b, guint nb, gdouble zr, gdouble zi)
static GstFlowReturn gst_audio_fx_base_iir_filter_transform_ip(GstBaseTransform *base, GstBuffer *buf)
static void gst_audio_fx_base_iir_filter_init(GstAudioFXBaseIIRFilter *filter)
static void gst_audio_fx_base_iir_filter_class_init(GstAudioFXBaseIIRFilterClass *klass)
void gst_audio_fx_base_iir_filter_set_coefficients(GstAudioFXBaseIIRFilter *filter, gdouble *a, guint na, gdouble *b, guint nb)
#define DEFINE_PROCESS_FUNC(width, ctype)
G_DEFINE_TYPE(GstAudioFXBaseIIRFilter, gst_audio_fx_base_iir_filter, GST_TYPE_AUDIO_FILTER)
static void gst_audio_fx_base_iir_filter_finalize(GObject *object)
static void process_64(GstAudioFXBaseIIRFilter *filter, gdouble *data, guint num_samples)
#define ALLOWED_CAPS
static gdouble process(GstAudioFXBaseIIRFilter *filter, GstAudioFXBaseIIRFilterChannelCtx *ctx, gdouble x0)
#define GST_CAT_DEFAULT
GST_DEBUG_CATEGORY_STATIC(gst_audio_fx_base_iir_filter_debug)
void(* GstAudioFXBaseIIRFilterProcessFunc)(GstAudioFXBaseIIRFilter *, guint8 *, guint)
#define GST_AUDIO_FX_BASE_IIR_FILTER(obj)
#define GST_TYPE_AUDIO_FX_BASE_IIR_FILTER
#define GST_IS_AUDIO_FX_BASE_IIR_FILTER(obj)
#define parent_class
Definition: gstsbcparse.c:83
GstAudioFXBaseIIRFilterProcessFunc process
GstAudioFXBaseIIRFilterChannelCtx * channels