"Fossies" - the Fresh Open Source Software Archive 
Member "gst-plugins-good-1.20.3/gst/audiofx/audiofxbasefirfilter.c" (15 Jun 2022, 36035 Bytes) of package /linux/misc/gst-plugins-good-1.20.3.tar.xz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "audiofxbasefirfilter.c" see the
Fossies "Dox" file reference documentation.
1 /* -*- c-basic-offset: 2 -*-
2 *
3 * GStreamer
4 * Copyright (C) 1999-2001 Erik Walthinsen <omega@cse.ogi.edu>
5 * 2006 Dreamlab Technologies Ltd. <mathis.hofer@dreamlab.net>
6 * 2007-2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 *
23 */
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 #include <string.h>
30 #include <math.h>
31 #include <gst/gst.h>
32 #include <gst/audio/gstaudiofilter.h>
33
34 #include "audiofxbasefirfilter.h"
35
36 #define GST_CAT_DEFAULT gst_audio_fx_base_fir_filter_debug
37 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
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 /* Switch from time-domain to FFT convolution for kernels >= this */
47 #define FFT_THRESHOLD 32
48
49 enum
50 {
51 PROP_0 = 0,
52 PROP_LOW_LATENCY,
53 PROP_DRAIN_ON_CHANGES
54 };
55
56 #define DEFAULT_LOW_LATENCY FALSE
57 #define DEFAULT_DRAIN_ON_CHANGES TRUE
58
59 #define gst_audio_fx_base_fir_filter_parent_class parent_class
60 G_DEFINE_TYPE (GstAudioFXBaseFIRFilter, gst_audio_fx_base_fir_filter,
61 GST_TYPE_AUDIO_FILTER);
62
63 static GstFlowReturn gst_audio_fx_base_fir_filter_transform (GstBaseTransform *
64 base, GstBuffer * inbuf, GstBuffer * outbuf);
65 static gboolean gst_audio_fx_base_fir_filter_start (GstBaseTransform * base);
66 static gboolean gst_audio_fx_base_fir_filter_stop (GstBaseTransform * base);
67 static gboolean gst_audio_fx_base_fir_filter_sink_event (GstBaseTransform *
68 base, GstEvent * event);
69 static gboolean gst_audio_fx_base_fir_filter_transform_size (GstBaseTransform *
70 base, GstPadDirection direction, GstCaps * caps, gsize size,
71 GstCaps * othercaps, gsize * othersize);
72 static gboolean gst_audio_fx_base_fir_filter_setup (GstAudioFilter * base,
73 const GstAudioInfo * info);
74
75 static gboolean gst_audio_fx_base_fir_filter_query (GstBaseTransform * trans,
76 GstPadDirection direction, GstQuery * quer);
77
78 /*
79 * The code below calculates the linear convolution:
80 *
81 * y[t] = \sum_{u=0}^{M-1} x[t - u] * h[u]
82 *
83 * where y is the output, x is the input, M is the length
84 * of the filter kernel and h is the filter kernel. For x
85 * holds: x[t] == 0 \forall t < 0.
86 *
87 * The runtime complexity of this is O (M) per sample.
88 *
89 */
90 #define DEFINE_PROCESS_FUNC(width,ctype) \
91 static guint \
92 process_##width (GstAudioFXBaseFIRFilter * self, const g##ctype * src, g##ctype * dst, guint input_samples) \
93 { \
94 gint channels = GST_AUDIO_FILTER_CHANNELS (self); \
95 TIME_DOMAIN_CONVOLUTION_BODY (channels); \
96 }
97
98 #define DEFINE_PROCESS_FUNC_FIXED_CHANNELS(width,channels,ctype) \
99 static guint \
100 process_##channels##_##width (GstAudioFXBaseFIRFilter * self, const g##ctype * src, g##ctype * dst, guint input_samples) \
101 { \
102 TIME_DOMAIN_CONVOLUTION_BODY (channels); \
103 }
104
105 #define TIME_DOMAIN_CONVOLUTION_BODY(channels) G_STMT_START { \
106 gint kernel_length = self->kernel_length; \
107 gint i, j, k, l; \
108 gint res_start; \
109 gint from_input; \
110 gint off; \
111 gdouble *buffer = self->buffer; \
112 gdouble *kernel = self->kernel; \
113 \
114 if (!buffer) { \
115 self->buffer_length = kernel_length * channels; \
116 self->buffer = buffer = g_new0 (gdouble, self->buffer_length); \
117 } \
118 \
119 input_samples *= channels; \
120 /* convolution */ \
121 for (i = 0; i < input_samples; i++) { \
122 dst[i] = 0.0; \
123 k = i % channels; \
124 l = i / channels; \
125 from_input = MIN (l, kernel_length-1); \
126 off = l * channels + k; \
127 for (j = 0; j <= from_input; j++) { \
128 dst[i] += src[off] * kernel[j]; \
129 off -= channels; \
130 } \
131 /* j == from_input && off == (l - j) * channels + k */ \
132 off += kernel_length * channels; \
133 for (; j < kernel_length; j++) { \
134 dst[i] += buffer[off] * kernel[j]; \
135 off -= channels; \
136 } \
137 } \
138 \
139 /* copy the tail of the current input buffer to the residue, while \
140 * keeping parts of the residue if the input buffer is smaller than \
141 * the kernel length */ \
142 /* from now on take kernel length as length over all channels */ \
143 kernel_length *= channels; \
144 if (input_samples < kernel_length) \
145 res_start = kernel_length - input_samples; \
146 else \
147 res_start = 0; \
148 \
149 for (i = 0; i < res_start; i++) \
150 buffer[i] = buffer[i + input_samples]; \
151 /* i == res_start */ \
152 for (; i < kernel_length; i++) \
153 buffer[i] = src[input_samples - kernel_length + i]; \
154 \
155 self->buffer_fill += kernel_length - res_start; \
156 if (self->buffer_fill > kernel_length) \
157 self->buffer_fill = kernel_length; \
158 \
159 return input_samples / channels; \
160 } G_STMT_END
161
162 DEFINE_PROCESS_FUNC (32, float);
163 DEFINE_PROCESS_FUNC (64, double);
164
165 DEFINE_PROCESS_FUNC_FIXED_CHANNELS (32, 1, float);
166 DEFINE_PROCESS_FUNC_FIXED_CHANNELS (64, 1, double);
167
168 DEFINE_PROCESS_FUNC_FIXED_CHANNELS (32, 2, float);
169 DEFINE_PROCESS_FUNC_FIXED_CHANNELS (64, 2, double);
170
171 #undef TIME_DOMAIN_CONVOLUTION_BODY
172 #undef DEFINE_PROCESS_FUNC
173 #undef DEFINE_PROCESS_FUNC_FIXED_CHANNELS
174
175 /* This implements FFT convolution and uses the overlap-save algorithm.
176 * See http://cnx.org/content/m12022/latest/ or your favorite
177 * digital signal processing book for details.
178 *
179 * In every pass the following is calculated:
180 *
181 * y = IFFT (FFT(x) * FFT(h))
182 *
183 * where y is the output in the time domain, x the
184 * input and h the filter kernel. * is the multiplication
185 * of complex numbers.
186 *
187 * Due to the circular convolution theorem this
188 * gives in the time domain:
189 *
190 * y[t] = \sum_{u=0}^{M-1} x[t - u] * h[u]
191 *
192 * where y is the output, M is the kernel length,
193 * x the periodically extended[0] input and h the
194 * filter kernel.
195 *
196 * ([0] Periodically extended means: )
197 * ( x[t] = x[t+kN] \forall k \in Z )
198 * ( where N is the length of x )
199 *
200 * This means:
201 * - Obviously x and h need to be of the same size for the FFT
202 * - The first M-1 output values are useless because they're
203 * built from 1 up to M-1 values from the end of the input
204 * (circular convolusion!).
205 * - The last M-1 input values are only used for 1 up to M-1
206 * output values, i.e. they need to be used again in the
207 * next pass for the first M-1 input values.
208 *
209 * => The first pass needs M-1 zeroes at the beginning of the
210 * input and the last M-1 input values of every pass need to
211 * be used as the first M-1 input values of the next pass.
212 *
213 * => x must be larger than h to give a useful number of output
214 * samples and h needs to be padded by zeroes at the end to give
215 * it virtually the same size as x (by M we denote the number of
216 * non-padding samples of h). If len(x)==len(h)==M only 1 output
217 * sample would be calculated per pass, len(x)==2*len(h) would
218 * give M+1 output samples, etc. Usually a factor between 4 and 8
219 * gives a low number of operations per output samples (see website
220 * given above).
221 *
222 * Overall this gives a runtime complexity per sample of
223 *
224 * ( N log N )
225 * O ( --------- ) compared to O (M) for the direct calculation.
226 * ( N - M + 1 )
227 */
228 #define DEFINE_FFT_PROCESS_FUNC(width,ctype) \
229 static guint \
230 process_fft_##width (GstAudioFXBaseFIRFilter * self, const g##ctype * src, \
231 g##ctype * dst, guint input_samples) \
232 { \
233 gint channels = GST_AUDIO_FILTER_CHANNELS (self); \
234 FFT_CONVOLUTION_BODY (channels); \
235 }
236
237 #define DEFINE_FFT_PROCESS_FUNC_FIXED_CHANNELS(width,channels,ctype) \
238 static guint \
239 process_fft_##channels##_##width (GstAudioFXBaseFIRFilter * self, const g##ctype * src, \
240 g##ctype * dst, guint input_samples) \
241 { \
242 FFT_CONVOLUTION_BODY (channels); \
243 }
244
245 #define FFT_CONVOLUTION_BODY(channels) G_STMT_START { \
246 gint i, j; \
247 guint pass; \
248 guint kernel_length = self->kernel_length; \
249 guint block_length = self->block_length; \
250 guint buffer_length = self->buffer_length; \
251 guint real_buffer_length = buffer_length + kernel_length - 1; \
252 guint buffer_fill = self->buffer_fill; \
253 GstFFTF64 *fft = self->fft; \
254 GstFFTF64 *ifft = self->ifft; \
255 GstFFTF64Complex *frequency_response = self->frequency_response; \
256 GstFFTF64Complex *fft_buffer = self->fft_buffer; \
257 guint frequency_response_length = self->frequency_response_length; \
258 gdouble *buffer = self->buffer; \
259 guint generated = 0; \
260 gdouble re, im; \
261 \
262 if (!fft_buffer) \
263 self->fft_buffer = fft_buffer = \
264 g_new (GstFFTF64Complex, frequency_response_length); \
265 \
266 /* Buffer contains the time domain samples of input data for one chunk \
267 * plus some more space for the inverse FFT below. \
268 * \
269 * The samples are put at offset kernel_length, the inverse FFT \
270 * overwrites everything from offset 0 to length-kernel_length+1, keeping \
271 * the last kernel_length-1 samples for copying to the next processing \
272 * step. \
273 */ \
274 if (!buffer) { \
275 self->buffer_length = buffer_length = block_length; \
276 real_buffer_length = buffer_length + kernel_length - 1; \
277 \
278 self->buffer = buffer = g_new0 (gdouble, real_buffer_length * channels); \
279 \
280 /* Beginning has kernel_length-1 zeroes at the beginning */ \
281 self->buffer_fill = buffer_fill = kernel_length - 1; \
282 } \
283 \
284 g_assert (self->buffer_length == block_length); \
285 \
286 while (input_samples) { \
287 pass = MIN (buffer_length - buffer_fill, input_samples); \
288 \
289 /* Deinterleave channels */ \
290 for (i = 0; i < pass; i++) { \
291 for (j = 0; j < channels; j++) { \
292 buffer[real_buffer_length * j + buffer_fill + kernel_length - 1 + i] = \
293 src[i * channels + j]; \
294 } \
295 } \
296 buffer_fill += pass; \
297 src += channels * pass; \
298 input_samples -= pass; \
299 \
300 /* If we don't have a complete buffer go out */ \
301 if (buffer_fill < buffer_length) \
302 break; \
303 \
304 for (j = 0; j < channels; j++) { \
305 /* Calculate FFT of input block */ \
306 gst_fft_f64_fft (fft, \
307 buffer + real_buffer_length * j + kernel_length - 1, fft_buffer); \
308 \
309 /* Complex multiplication of input and filter spectrum */ \
310 for (i = 0; i < frequency_response_length; i++) { \
311 re = fft_buffer[i].r; \
312 im = fft_buffer[i].i; \
313 \
314 fft_buffer[i].r = \
315 re * frequency_response[i].r - \
316 im * frequency_response[i].i; \
317 fft_buffer[i].i = \
318 re * frequency_response[i].i + \
319 im * frequency_response[i].r; \
320 } \
321 \
322 /* Calculate inverse FFT of the result */ \
323 gst_fft_f64_inverse_fft (ifft, fft_buffer, \
324 buffer + real_buffer_length * j); \
325 \
326 /* Copy all except the first kernel_length-1 samples to the output */ \
327 for (i = 0; i < buffer_length - kernel_length + 1; i++) { \
328 dst[i * channels + j] = \
329 buffer[real_buffer_length * j + kernel_length - 1 + i]; \
330 } \
331 \
332 /* Copy the last kernel_length-1 samples to the beginning for the next block */ \
333 for (i = 0; i < kernel_length - 1; i++) { \
334 buffer[real_buffer_length * j + kernel_length - 1 + i] = \
335 buffer[real_buffer_length * j + buffer_length + i]; \
336 } \
337 } \
338 \
339 generated += buffer_length - kernel_length + 1; \
340 dst += channels * (buffer_length - kernel_length + 1); \
341 \
342 /* The the first kernel_length-1 samples are there already */ \
343 buffer_fill = kernel_length - 1; \
344 } \
345 \
346 /* Write back cached buffer_fill value */ \
347 self->buffer_fill = buffer_fill; \
348 \
349 return generated; \
350 } G_STMT_END
351
352 DEFINE_FFT_PROCESS_FUNC (32, float);
353 DEFINE_FFT_PROCESS_FUNC (64, double);
354
355 DEFINE_FFT_PROCESS_FUNC_FIXED_CHANNELS (32, 1, float);
356 DEFINE_FFT_PROCESS_FUNC_FIXED_CHANNELS (64, 1, double);
357
358 DEFINE_FFT_PROCESS_FUNC_FIXED_CHANNELS (32, 2, float);
359 DEFINE_FFT_PROCESS_FUNC_FIXED_CHANNELS (64, 2, double);
360
361 #undef FFT_CONVOLUTION_BODY
362 #undef DEFINE_FFT_PROCESS_FUNC
363 #undef DEFINE_FFT_PROCESS_FUNC_FIXED_CHANNELS
364
365 /* Element class */
366 static void
367 gst_audio_fx_base_fir_filter_calculate_frequency_response
368 (GstAudioFXBaseFIRFilter * self)
369 {
370 gst_fft_f64_free (self->fft);
371 self->fft = NULL;
372 gst_fft_f64_free (self->ifft);
373 self->ifft = NULL;
374 g_free (self->frequency_response);
375 self->frequency_response_length = 0;
376 g_free (self->fft_buffer);
377 self->fft_buffer = NULL;
378
379 if (self->kernel && self->kernel_length >= FFT_THRESHOLD
380 && !self->low_latency) {
381 guint block_length, i;
382 gdouble *kernel_tmp, *kernel = self->kernel;
383
384 /* We process 4 * kernel_length samples per pass in FFT mode */
385 block_length = 4 * self->kernel_length;
386 block_length = gst_fft_next_fast_length (block_length);
387 self->block_length = block_length;
388
389 kernel_tmp = g_new0 (gdouble, block_length);
390 memcpy (kernel_tmp, kernel, self->kernel_length * sizeof (gdouble));
391
392 self->fft = gst_fft_f64_new (block_length, FALSE);
393 self->ifft = gst_fft_f64_new (block_length, TRUE);
394 self->frequency_response_length = block_length / 2 + 1;
395 self->frequency_response =
396 g_new (GstFFTF64Complex, self->frequency_response_length);
397 gst_fft_f64_fft (self->fft, kernel_tmp, self->frequency_response);
398 g_free (kernel_tmp);
399
400 /* Normalize to make sure IFFT(FFT(x)) == x */
401 for (i = 0; i < self->frequency_response_length; i++) {
402 self->frequency_response[i].r /= block_length;
403 self->frequency_response[i].i /= block_length;
404 }
405 }
406 }
407
408 /* Must be called with base transform lock! */
409 static void
410 gst_audio_fx_base_fir_filter_select_process_function (GstAudioFXBaseFIRFilter *
411 self, GstAudioFormat format, gint channels)
412 {
413 switch (format) {
414 case GST_AUDIO_FORMAT_F32:
415 if (self->fft && !self->low_latency) {
416 if (channels == 1)
417 self->process = (GstAudioFXBaseFIRFilterProcessFunc) process_fft_1_32;
418 else if (channels == 2)
419 self->process = (GstAudioFXBaseFIRFilterProcessFunc) process_fft_2_32;
420 else
421 self->process = (GstAudioFXBaseFIRFilterProcessFunc) process_fft_32;
422 } else {
423 if (channels == 1)
424 self->process = (GstAudioFXBaseFIRFilterProcessFunc) process_1_32;
425 else if (channels == 2)
426 self->process = (GstAudioFXBaseFIRFilterProcessFunc) process_2_32;
427 else
428 self->process = (GstAudioFXBaseFIRFilterProcessFunc) process_32;
429 }
430 break;
431 case GST_AUDIO_FORMAT_F64:
432 if (self->fft && !self->low_latency) {
433 if (channels == 1)
434 self->process = (GstAudioFXBaseFIRFilterProcessFunc) process_fft_1_64;
435 else if (channels == 2)
436 self->process = (GstAudioFXBaseFIRFilterProcessFunc) process_fft_2_64;
437 else
438 self->process = (GstAudioFXBaseFIRFilterProcessFunc) process_fft_64;
439 } else {
440 if (channels == 1)
441 self->process = (GstAudioFXBaseFIRFilterProcessFunc) process_1_64;
442 else if (channels == 2)
443 self->process = (GstAudioFXBaseFIRFilterProcessFunc) process_2_64;
444 else
445 self->process = (GstAudioFXBaseFIRFilterProcessFunc) process_64;
446 }
447 break;
448 default:
449 self->process = NULL;
450 break;
451 }
452 }
453
454 static void
455 gst_audio_fx_base_fir_filter_finalize (GObject * object)
456 {
457 GstAudioFXBaseFIRFilter *self = GST_AUDIO_FX_BASE_FIR_FILTER (object);
458
459 g_free (self->buffer);
460 g_free (self->kernel);
461 gst_fft_f64_free (self->fft);
462 gst_fft_f64_free (self->ifft);
463 g_free (self->frequency_response);
464 g_free (self->fft_buffer);
465 g_mutex_clear (&self->lock);
466
467 G_OBJECT_CLASS (parent_class)->finalize (object);
468 }
469
470 static void
471 gst_audio_fx_base_fir_filter_set_property (GObject * object, guint prop_id,
472 const GValue * value, GParamSpec * pspec)
473 {
474 GstAudioFXBaseFIRFilter *self = GST_AUDIO_FX_BASE_FIR_FILTER (object);
475
476 switch (prop_id) {
477 case PROP_LOW_LATENCY:{
478 gboolean low_latency;
479
480 if (GST_STATE (self) >= GST_STATE_PAUSED) {
481 g_warning ("Changing the \"low-latency\" property "
482 "is only allowed in states < PAUSED");
483 return;
484 }
485
486
487 g_mutex_lock (&self->lock);
488 low_latency = g_value_get_boolean (value);
489
490 if (self->low_latency != low_latency) {
491 self->low_latency = low_latency;
492 gst_audio_fx_base_fir_filter_calculate_frequency_response (self);
493 gst_audio_fx_base_fir_filter_select_process_function (self,
494 GST_AUDIO_FILTER_FORMAT (self), GST_AUDIO_FILTER_CHANNELS (self));
495 }
496 g_mutex_unlock (&self->lock);
497 break;
498 }
499 case PROP_DRAIN_ON_CHANGES:{
500 g_mutex_lock (&self->lock);
501 self->drain_on_changes = g_value_get_boolean (value);
502 g_mutex_unlock (&self->lock);
503 break;
504 }
505 default:
506 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
507 break;
508 }
509 }
510
511 static void
512 gst_audio_fx_base_fir_filter_get_property (GObject * object, guint prop_id,
513 GValue * value, GParamSpec * pspec)
514 {
515 GstAudioFXBaseFIRFilter *self = GST_AUDIO_FX_BASE_FIR_FILTER (object);
516
517 switch (prop_id) {
518 case PROP_LOW_LATENCY:
519 g_value_set_boolean (value, self->low_latency);
520 break;
521 case PROP_DRAIN_ON_CHANGES:
522 g_value_set_boolean (value, self->drain_on_changes);
523 break;
524 default:
525 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
526 break;
527 }
528 }
529
530 static void
531 gst_audio_fx_base_fir_filter_class_init (GstAudioFXBaseFIRFilterClass * klass)
532 {
533 GObjectClass *gobject_class = (GObjectClass *) klass;
534 GstBaseTransformClass *trans_class = (GstBaseTransformClass *) klass;
535 GstAudioFilterClass *filter_class = (GstAudioFilterClass *) klass;
536 GstCaps *caps;
537
538 GST_DEBUG_CATEGORY_INIT (gst_audio_fx_base_fir_filter_debug,
539 "audiofxbasefirfilter", 0, "FIR filter base class");
540
541 gobject_class->finalize = gst_audio_fx_base_fir_filter_finalize;
542 gobject_class->set_property = gst_audio_fx_base_fir_filter_set_property;
543 gobject_class->get_property = gst_audio_fx_base_fir_filter_get_property;
544
545 /**
546 * GstAudioFXBaseFIRFilter:low-latency:
547 *
548 * Work in low-latency mode. This mode is much slower for large filter sizes
549 * but the latency is always only the pre-latency of the filter.
550 */
551 g_object_class_install_property (gobject_class, PROP_LOW_LATENCY,
552 g_param_spec_boolean ("low-latency", "Low latency",
553 "Operate in low latency mode. This mode is slower but the "
554 "latency will only be the filter pre-latency. "
555 "Can only be changed in states < PAUSED!", DEFAULT_LOW_LATENCY,
556 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
557
558 /**
559 * GstAudioFXBaseFIRFilter:drain-on-changes:
560 *
561 * Whether the filter should be drained when its coefficients change
562 *
563 * Note: Currently this only works if the kernel size is not changed!
564 * Support for drainless kernel size changes will be added in the future.
565 */
566 g_object_class_install_property (gobject_class, PROP_DRAIN_ON_CHANGES,
567 g_param_spec_boolean ("drain-on-changes", "Drain on changes",
568 "Drains the filter when its coefficients change",
569 DEFAULT_DRAIN_ON_CHANGES,
570 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
571
572 caps = gst_caps_from_string (ALLOWED_CAPS);
573 gst_audio_filter_class_add_pad_templates (GST_AUDIO_FILTER_CLASS (klass),
574 caps);
575 gst_caps_unref (caps);
576
577 trans_class->transform =
578 GST_DEBUG_FUNCPTR (gst_audio_fx_base_fir_filter_transform);
579 trans_class->start = GST_DEBUG_FUNCPTR (gst_audio_fx_base_fir_filter_start);
580 trans_class->stop = GST_DEBUG_FUNCPTR (gst_audio_fx_base_fir_filter_stop);
581 trans_class->sink_event =
582 GST_DEBUG_FUNCPTR (gst_audio_fx_base_fir_filter_sink_event);
583 trans_class->query = GST_DEBUG_FUNCPTR (gst_audio_fx_base_fir_filter_query);
584 trans_class->transform_size =
585 GST_DEBUG_FUNCPTR (gst_audio_fx_base_fir_filter_transform_size);
586 filter_class->setup = GST_DEBUG_FUNCPTR (gst_audio_fx_base_fir_filter_setup);
587
588 gst_type_mark_as_plugin_api (GST_TYPE_AUDIO_FX_BASE_FIR_FILTER, 0);
589 }
590
591 static void
592 gst_audio_fx_base_fir_filter_init (GstAudioFXBaseFIRFilter * self)
593 {
594 self->kernel = NULL;
595 self->buffer = NULL;
596 self->buffer_length = 0;
597
598 self->start_ts = GST_CLOCK_TIME_NONE;
599 self->start_off = GST_BUFFER_OFFSET_NONE;
600 self->nsamples_out = 0;
601 self->nsamples_in = 0;
602
603 self->low_latency = DEFAULT_LOW_LATENCY;
604 self->drain_on_changes = DEFAULT_DRAIN_ON_CHANGES;
605
606 g_mutex_init (&self->lock);
607 }
608
609 void
610 gst_audio_fx_base_fir_filter_push_residue (GstAudioFXBaseFIRFilter * self)
611 {
612 GstBuffer *outbuf;
613 GstFlowReturn res;
614 gint rate = GST_AUDIO_FILTER_RATE (self);
615 gint channels = GST_AUDIO_FILTER_CHANNELS (self);
616 gint bps = GST_AUDIO_FILTER_BPS (self);
617 gint outsize, outsamples;
618 GstMapInfo map;
619 guint8 *in, *out;
620
621 if (channels == 0 || rate == 0 || self->nsamples_in == 0) {
622 self->buffer_fill = 0;
623 g_free (self->buffer);
624 self->buffer = NULL;
625 return;
626 }
627
628 /* Calculate the number of samples and their memory size that
629 * should be pushed from the residue */
630 outsamples = self->nsamples_in - (self->nsamples_out - self->latency);
631 if (outsamples <= 0) {
632 self->buffer_fill = 0;
633 g_free (self->buffer);
634 self->buffer = NULL;
635 return;
636 }
637 outsize = outsamples * channels * bps;
638
639 if (!self->fft || self->low_latency) {
640 gint64 diffsize, diffsamples;
641
642 /* Process the difference between latency and residue length samples
643 * to start at the actual data instead of starting at the zeros before
644 * when we only got one buffer smaller than latency */
645 diffsamples =
646 ((gint64) self->latency) - ((gint64) self->buffer_fill) / channels;
647 if (diffsamples > 0) {
648 diffsize = diffsamples * channels * bps;
649 in = g_new0 (guint8, diffsize);
650 out = g_new0 (guint8, diffsize);
651 self->nsamples_out += self->process (self, in, out, diffsamples);
652 g_free (in);
653 g_free (out);
654 }
655
656 outbuf = gst_buffer_new_and_alloc (outsize);
657
658 /* Convolve the residue with zeros to get the actual remaining data */
659 in = g_new0 (guint8, outsize);
660 gst_buffer_map (outbuf, &map, GST_MAP_READWRITE);
661 self->nsamples_out += self->process (self, in, map.data, outsamples);
662 gst_buffer_unmap (outbuf, &map);
663
664 g_free (in);
665 } else {
666 guint gensamples = 0;
667
668 outbuf = gst_buffer_new_and_alloc (outsize);
669 gst_buffer_map (outbuf, &map, GST_MAP_READWRITE);
670
671 while (gensamples < outsamples) {
672 guint step_insamples = self->block_length - self->buffer_fill;
673 guint8 *zeroes = g_new0 (guint8, step_insamples * channels * bps);
674 guint8 *out = g_new (guint8, self->block_length * channels * bps);
675 guint step_gensamples;
676
677 step_gensamples = self->process (self, zeroes, out, step_insamples);
678 g_free (zeroes);
679
680 memcpy (map.data + gensamples * bps, out, MIN (step_gensamples,
681 outsamples - gensamples) * bps);
682 gensamples += MIN (step_gensamples, outsamples - gensamples);
683
684 g_free (out);
685 }
686 self->nsamples_out += gensamples;
687
688 gst_buffer_unmap (outbuf, &map);
689 }
690
691 /* Set timestamp, offset, etc from the values we
692 * saved when processing the regular buffers */
693 if (GST_CLOCK_TIME_IS_VALID (self->start_ts))
694 GST_BUFFER_TIMESTAMP (outbuf) = self->start_ts;
695 else
696 GST_BUFFER_TIMESTAMP (outbuf) = 0;
697 GST_BUFFER_TIMESTAMP (outbuf) +=
698 gst_util_uint64_scale_int (self->nsamples_out - outsamples -
699 self->latency, GST_SECOND, rate);
700
701 GST_BUFFER_DURATION (outbuf) =
702 gst_util_uint64_scale_int (outsamples, GST_SECOND, rate);
703
704 if (self->start_off != GST_BUFFER_OFFSET_NONE) {
705 GST_BUFFER_OFFSET (outbuf) =
706 self->start_off + self->nsamples_out - outsamples - self->latency;
707 GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET (outbuf) + outsamples;
708 }
709
710 GST_DEBUG_OBJECT (self,
711 "Pushing residue buffer of size %" G_GSIZE_FORMAT " with timestamp: %"
712 GST_TIME_FORMAT ", duration: %" GST_TIME_FORMAT ", offset: %"
713 G_GUINT64_FORMAT ", offset_end: %" G_GUINT64_FORMAT ", nsamples_out: %d",
714 gst_buffer_get_size (outbuf),
715 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
716 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf),
717 GST_BUFFER_OFFSET_END (outbuf), outsamples);
718
719 res = gst_pad_push (GST_BASE_TRANSFORM_CAST (self)->srcpad, outbuf);
720
721 if (G_UNLIKELY (res != GST_FLOW_OK)) {
722 GST_WARNING_OBJECT (self, "failed to push residue");
723 }
724
725 self->buffer_fill = 0;
726 }
727
728 /* GstAudioFilter vmethod implementations */
729
730 /* get notified of caps and plug in the correct process function */
731 static gboolean
732 gst_audio_fx_base_fir_filter_setup (GstAudioFilter * base,
733 const GstAudioInfo * info)
734 {
735 GstAudioFXBaseFIRFilter *self = GST_AUDIO_FX_BASE_FIR_FILTER (base);
736
737 g_mutex_lock (&self->lock);
738 if (self->buffer) {
739 gst_audio_fx_base_fir_filter_push_residue (self);
740 g_free (self->buffer);
741 self->buffer = NULL;
742 self->buffer_fill = 0;
743 self->buffer_length = 0;
744 self->start_ts = GST_CLOCK_TIME_NONE;
745 self->start_off = GST_BUFFER_OFFSET_NONE;
746 self->nsamples_out = 0;
747 self->nsamples_in = 0;
748 }
749
750 gst_audio_fx_base_fir_filter_select_process_function (self,
751 GST_AUDIO_INFO_FORMAT (info), GST_AUDIO_INFO_CHANNELS (info));
752 g_mutex_unlock (&self->lock);
753
754 return (self->process != NULL);
755 }
756
757 /* GstBaseTransform vmethod implementations */
758
759 static gboolean
760 gst_audio_fx_base_fir_filter_transform_size (GstBaseTransform * base,
761 GstPadDirection direction, GstCaps * caps, gsize size, GstCaps * othercaps,
762 gsize * othersize)
763 {
764 GstAudioFXBaseFIRFilter *self = GST_AUDIO_FX_BASE_FIR_FILTER (base);
765 guint blocklen;
766 GstAudioInfo info;
767 gint bpf;
768
769 if (!self->fft || self->low_latency || direction == GST_PAD_SRC) {
770 *othersize = size;
771 return TRUE;
772 }
773
774 if (!gst_audio_info_from_caps (&info, caps))
775 return FALSE;
776
777 bpf = GST_AUDIO_INFO_BPF (&info);
778
779 size /= bpf;
780 blocklen = self->block_length - self->kernel_length + 1;
781 *othersize = ((size + blocklen - 1) / blocklen) * blocklen;
782 *othersize *= bpf;
783
784 return TRUE;
785 }
786
787 static GstFlowReturn
788 gst_audio_fx_base_fir_filter_transform (GstBaseTransform * base,
789 GstBuffer * inbuf, GstBuffer * outbuf)
790 {
791 GstAudioFXBaseFIRFilter *self = GST_AUDIO_FX_BASE_FIR_FILTER (base);
792 GstClockTime timestamp, expected_timestamp;
793 gint channels = GST_AUDIO_FILTER_CHANNELS (self);
794 gint rate = GST_AUDIO_FILTER_RATE (self);
795 gint bps = GST_AUDIO_FILTER_BPS (self);
796 GstMapInfo inmap, outmap;
797 guint input_samples;
798 guint output_samples;
799 guint generated_samples;
800 guint64 output_offset;
801 gint64 diff = 0;
802 GstClockTime stream_time;
803
804 timestamp = GST_BUFFER_TIMESTAMP (outbuf);
805
806 if (!GST_CLOCK_TIME_IS_VALID (timestamp)
807 && !GST_CLOCK_TIME_IS_VALID (self->start_ts)) {
808 GST_ERROR_OBJECT (self, "Invalid timestamp");
809 return GST_FLOW_ERROR;
810 }
811
812 g_mutex_lock (&self->lock);
813 stream_time =
814 gst_segment_to_stream_time (&base->segment, GST_FORMAT_TIME, timestamp);
815
816 GST_DEBUG_OBJECT (self, "sync to %" GST_TIME_FORMAT,
817 GST_TIME_ARGS (timestamp));
818
819 if (GST_CLOCK_TIME_IS_VALID (stream_time))
820 gst_object_sync_values (GST_OBJECT (self), stream_time);
821
822 g_return_val_if_fail (self->kernel != NULL, GST_FLOW_ERROR);
823 g_return_val_if_fail (channels != 0, GST_FLOW_ERROR);
824
825 if (GST_CLOCK_TIME_IS_VALID (self->start_ts))
826 expected_timestamp =
827 self->start_ts + gst_util_uint64_scale_int (self->nsamples_in,
828 GST_SECOND, rate);
829 else
830 expected_timestamp = GST_CLOCK_TIME_NONE;
831
832 /* Reset the residue if already existing on discont buffers */
833 if (GST_BUFFER_IS_DISCONT (inbuf)
834 || (GST_CLOCK_TIME_IS_VALID (expected_timestamp)
835 && (ABS (GST_CLOCK_DIFF (timestamp,
836 expected_timestamp)) > 5 * GST_MSECOND))) {
837 GST_DEBUG_OBJECT (self, "Discontinuity detected - flushing");
838 if (GST_CLOCK_TIME_IS_VALID (expected_timestamp))
839 gst_audio_fx_base_fir_filter_push_residue (self);
840 self->buffer_fill = 0;
841 g_free (self->buffer);
842 self->buffer = NULL;
843 self->start_ts = timestamp;
844 self->start_off = GST_BUFFER_OFFSET (inbuf);
845 self->nsamples_out = 0;
846 self->nsamples_in = 0;
847 } else if (!GST_CLOCK_TIME_IS_VALID (self->start_ts)) {
848 self->start_ts = timestamp;
849 self->start_off = GST_BUFFER_OFFSET (inbuf);
850 }
851
852 gst_buffer_map (inbuf, &inmap, GST_MAP_READ);
853 gst_buffer_map (outbuf, &outmap, GST_MAP_WRITE);
854
855 input_samples = (inmap.size / bps) / channels;
856 output_samples = (outmap.size / bps) / channels;
857
858 self->nsamples_in += input_samples;
859
860 generated_samples =
861 self->process (self, inmap.data, outmap.data, input_samples);
862
863 gst_buffer_unmap (inbuf, &inmap);
864 gst_buffer_unmap (outbuf, &outmap);
865
866 g_assert (generated_samples <= output_samples);
867 self->nsamples_out += generated_samples;
868 if (generated_samples == 0)
869 goto no_samples;
870
871 /* Calculate the number of samples we can push out now without outputting
872 * latency zeros in the beginning */
873 diff = ((gint64) self->nsamples_out) - ((gint64) self->latency);
874 if (diff < 0)
875 goto no_samples;
876
877 if (diff < generated_samples) {
878 gint64 tmp = diff;
879 diff = generated_samples - diff;
880 generated_samples = tmp;
881 } else {
882 diff = 0;
883 }
884
885 gst_buffer_resize (outbuf, diff * bps * channels,
886 generated_samples * bps * channels);
887
888 output_offset = self->nsamples_out - self->latency - generated_samples;
889 GST_BUFFER_TIMESTAMP (outbuf) =
890 self->start_ts + gst_util_uint64_scale_int (output_offset, GST_SECOND,
891 rate);
892 GST_BUFFER_DURATION (outbuf) =
893 gst_util_uint64_scale_int (output_samples, GST_SECOND, rate);
894 if (self->start_off != GST_BUFFER_OFFSET_NONE) {
895 GST_BUFFER_OFFSET (outbuf) = self->start_off + output_offset;
896 GST_BUFFER_OFFSET_END (outbuf) =
897 GST_BUFFER_OFFSET (outbuf) + generated_samples;
898 } else {
899 GST_BUFFER_OFFSET (outbuf) = GST_BUFFER_OFFSET_NONE;
900 GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET_NONE;
901 }
902 g_mutex_unlock (&self->lock);
903
904 GST_DEBUG_OBJECT (self,
905 "Pushing buffer of size %" G_GSIZE_FORMAT " with timestamp: %"
906 GST_TIME_FORMAT ", duration: %" GST_TIME_FORMAT ", offset: %"
907 G_GUINT64_FORMAT ", offset_end: %" G_GUINT64_FORMAT ", nsamples_out: %d",
908 gst_buffer_get_size (outbuf),
909 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
910 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf),
911 GST_BUFFER_OFFSET_END (outbuf), generated_samples);
912
913 return GST_FLOW_OK;
914
915 no_samples:
916 {
917 g_mutex_unlock (&self->lock);
918 return GST_BASE_TRANSFORM_FLOW_DROPPED;
919 }
920 }
921
922 static gboolean
923 gst_audio_fx_base_fir_filter_start (GstBaseTransform * base)
924 {
925 GstAudioFXBaseFIRFilter *self = GST_AUDIO_FX_BASE_FIR_FILTER (base);
926
927 self->buffer_fill = 0;
928 g_free (self->buffer);
929 self->buffer = NULL;
930 self->start_ts = GST_CLOCK_TIME_NONE;
931 self->start_off = GST_BUFFER_OFFSET_NONE;
932 self->nsamples_out = 0;
933 self->nsamples_in = 0;
934
935 return TRUE;
936 }
937
938 static gboolean
939 gst_audio_fx_base_fir_filter_stop (GstBaseTransform * base)
940 {
941 GstAudioFXBaseFIRFilter *self = GST_AUDIO_FX_BASE_FIR_FILTER (base);
942
943 g_free (self->buffer);
944 self->buffer = NULL;
945 self->buffer_length = 0;
946
947 return TRUE;
948 }
949
950 static gboolean
951 gst_audio_fx_base_fir_filter_query (GstBaseTransform * trans,
952 GstPadDirection direction, GstQuery * query)
953 {
954 GstAudioFXBaseFIRFilter *self = GST_AUDIO_FX_BASE_FIR_FILTER (trans);
955 gboolean res = TRUE;
956
957 switch (GST_QUERY_TYPE (query)) {
958 case GST_QUERY_LATENCY:
959 {
960 GstClockTime min, max;
961 gboolean live;
962 guint64 latency;
963 gint rate = GST_AUDIO_FILTER_RATE (self);
964
965 if (rate == 0) {
966 res = FALSE;
967 } else if ((res =
968 gst_pad_peer_query (GST_BASE_TRANSFORM (self)->sinkpad, query))) {
969 gst_query_parse_latency (query, &live, &min, &max);
970
971 GST_DEBUG_OBJECT (self, "Peer latency: min %"
972 GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
973 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
974
975 if (self->fft && !self->low_latency)
976 latency = self->block_length - self->kernel_length + 1;
977 else
978 latency = self->latency;
979
980 /* add our own latency */
981 latency = gst_util_uint64_scale_round (latency, GST_SECOND, rate);
982
983 GST_DEBUG_OBJECT (self, "Our latency: %"
984 GST_TIME_FORMAT, GST_TIME_ARGS (latency));
985
986 min += latency;
987 if (max != GST_CLOCK_TIME_NONE)
988 max += latency;
989
990 GST_DEBUG_OBJECT (self, "Calculated total latency : min %"
991 GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
992 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
993
994 gst_query_set_latency (query, live, min, max);
995 }
996 break;
997 }
998 default:
999 res =
1000 GST_BASE_TRANSFORM_CLASS (parent_class)->query (trans, direction,
1001 query);
1002 break;
1003 }
1004 return res;
1005 }
1006
1007 static gboolean
1008 gst_audio_fx_base_fir_filter_sink_event (GstBaseTransform * base,
1009 GstEvent * event)
1010 {
1011 GstAudioFXBaseFIRFilter *self = GST_AUDIO_FX_BASE_FIR_FILTER (base);
1012
1013 switch (GST_EVENT_TYPE (event)) {
1014 case GST_EVENT_EOS:
1015 gst_audio_fx_base_fir_filter_push_residue (self);
1016 self->start_ts = GST_CLOCK_TIME_NONE;
1017 self->start_off = GST_BUFFER_OFFSET_NONE;
1018 self->nsamples_out = 0;
1019 self->nsamples_in = 0;
1020 break;
1021 default:
1022 break;
1023 }
1024
1025 return GST_BASE_TRANSFORM_CLASS (parent_class)->sink_event (base, event);
1026 }
1027
1028 void
1029 gst_audio_fx_base_fir_filter_set_kernel (GstAudioFXBaseFIRFilter * self,
1030 gdouble * kernel, guint kernel_length, guint64 latency,
1031 const GstAudioInfo * info)
1032 {
1033 gboolean latency_changed;
1034 GstAudioFormat format;
1035 gint channels;
1036
1037 g_return_if_fail (kernel != NULL);
1038 g_return_if_fail (self != NULL);
1039
1040 g_mutex_lock (&self->lock);
1041
1042 latency_changed = (self->latency != latency
1043 || (!self->low_latency && self->kernel_length < FFT_THRESHOLD
1044 && kernel_length >= FFT_THRESHOLD)
1045 || (!self->low_latency && self->kernel_length >= FFT_THRESHOLD
1046 && kernel_length < FFT_THRESHOLD));
1047
1048 /* FIXME: If the latency changes, the buffer size changes too and we
1049 * have to drain in any case until this is fixed in the future */
1050 if (self->buffer && (!self->drain_on_changes || latency_changed)) {
1051 gst_audio_fx_base_fir_filter_push_residue (self);
1052 self->start_ts = GST_CLOCK_TIME_NONE;
1053 self->start_off = GST_BUFFER_OFFSET_NONE;
1054 self->nsamples_out = 0;
1055 self->nsamples_in = 0;
1056 self->buffer_fill = 0;
1057 }
1058
1059 g_free (self->kernel);
1060 if (!self->drain_on_changes || latency_changed) {
1061 g_free (self->buffer);
1062 self->buffer = NULL;
1063 self->buffer_fill = 0;
1064 self->buffer_length = 0;
1065 }
1066
1067 self->kernel = kernel;
1068 self->kernel_length = kernel_length;
1069
1070 if (info) {
1071 format = GST_AUDIO_INFO_FORMAT (info);
1072 channels = GST_AUDIO_INFO_CHANNELS (info);
1073 } else {
1074 format = GST_AUDIO_FILTER_FORMAT (self);
1075 channels = GST_AUDIO_FILTER_CHANNELS (self);
1076 }
1077
1078 gst_audio_fx_base_fir_filter_calculate_frequency_response (self);
1079 gst_audio_fx_base_fir_filter_select_process_function (self, format, channels);
1080
1081 if (latency_changed) {
1082 self->latency = latency;
1083 gst_element_post_message (GST_ELEMENT (self),
1084 gst_message_new_latency (GST_OBJECT (self)));
1085 }
1086
1087 g_mutex_unlock (&self->lock);
1088 }