1 /* -*- c-basic-offset: 2 -*-
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>
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.
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.
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., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
32 #include <gst/audio/gstaudiofilter.h>
33 #include <gst/controller/gstcontroller.h>
35 /* FIXME: Remove this once we depend on gst-plugins-base 0.10.26 */
36 #ifndef GST_AUDIO_FILTER_CAST
37 #define GST_AUDIO_FILTER_CAST(obj) ((GstAudioFilter *) (obj))
40 #include "audiofxbasefirfilter.h"
42 #define GST_CAT_DEFAULT gst_audio_fx_base_fir_filter_debug
43 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
45 #define ALLOWED_CAPS \
46 "audio/x-raw-float, " \
47 " width = (int) { 32, 64 }, " \
48 " endianness = (int) BYTE_ORDER, " \
49 " rate = (int) [ 1, MAX ], " \
50 " channels = (int) [ 1, MAX ]"
52 #define DEBUG_INIT(bla) \
53 GST_DEBUG_CATEGORY_INIT (gst_audio_fx_base_fir_filter_debug, "audiofxbasefirfilter", 0, \
54 "FIR filter base class");
56 /* Switch from time-domain to FFT convolution for kernels >= this */
57 #define FFT_THRESHOLD 32
66 #define DEFAULT_LOW_LATENCY FALSE
67 #define DEFAULT_DRAIN_ON_CHANGES TRUE
69 GST_BOILERPLATE_FULL (GstAudioFXBaseFIRFilter, gst_audio_fx_base_fir_filter,
70 GstAudioFilter, GST_TYPE_AUDIO_FILTER, DEBUG_INIT);
72 static GstFlowReturn gst_audio_fx_base_fir_filter_transform (GstBaseTransform *
73 base, GstBuffer * inbuf, GstBuffer * outbuf);
74 static gboolean gst_audio_fx_base_fir_filter_start (GstBaseTransform * base);
75 static gboolean gst_audio_fx_base_fir_filter_stop (GstBaseTransform * base);
76 static gboolean gst_audio_fx_base_fir_filter_event (GstBaseTransform * base,
78 static gboolean gst_audio_fx_base_fir_filter_transform_size (GstBaseTransform *
79 base, GstPadDirection direction, GstCaps * caps, guint size,
80 GstCaps * othercaps, guint * othersize);
81 static gboolean gst_audio_fx_base_fir_filter_setup (GstAudioFilter * base,
82 GstRingBufferSpec * format);
84 static gboolean gst_audio_fx_base_fir_filter_query (GstPad * pad,
86 static const GstQueryType *gst_audio_fx_base_fir_filter_query_type (GstPad *
90 * The code below calculates the linear convolution:
92 * y[t] = \sum_{u=0}^{M-1} x[t - u] * h[u]
94 * where y is the output, x is the input, M is the length
95 * of the filter kernel and h is the filter kernel. For x
96 * holds: x[t] == 0 \forall t < 0.
98 * The runtime complexity of this is O (M) per sample.
101 #define DEFINE_PROCESS_FUNC(width,ctype) \
103 process_##width (GstAudioFXBaseFIRFilter * self, const g##ctype * src, g##ctype * dst, guint input_samples) \
105 gint channels = GST_AUDIO_FILTER_CAST (self)->format.channels; \
106 TIME_DOMAIN_CONVOLUTION_BODY (channels); \
109 #define DEFINE_PROCESS_FUNC_FIXED_CHANNELS(width,channels,ctype) \
111 process_##channels##_##width (GstAudioFXBaseFIRFilter * self, const g##ctype * src, g##ctype * dst, guint input_samples) \
113 TIME_DOMAIN_CONVOLUTION_BODY (channels); \
116 #define TIME_DOMAIN_CONVOLUTION_BODY(channels) G_STMT_START { \
117 gint kernel_length = self->kernel_length; \
122 gdouble *buffer = self->buffer; \
123 gdouble *kernel = self->kernel; \
124 guint buffer_length = self->buffer_length; \
127 self->buffer_length = buffer_length = kernel_length * channels; \
128 self->buffer = buffer = g_new0 (gdouble, self->buffer_length); \
132 for (i = 0; i < input_samples; i++) { \
136 from_input = MIN (l, kernel_length-1); \
137 off = l * channels + k; \
138 for (j = 0; j <= from_input; j++) { \
139 dst[i] += src[off] * kernel[j]; \
142 /* j == from_input && off == (l - j) * channels + k */ \
143 off += kernel_length * channels; \
144 for (; j < kernel_length; j++) { \
145 dst[i] += buffer[off] * kernel[j]; \
150 /* copy the tail of the current input buffer to the residue, while \
151 * keeping parts of the residue if the input buffer is smaller than \
152 * the kernel length */ \
153 /* from now on take kernel length as length over all channels */ \
154 kernel_length *= channels; \
155 if (input_samples < kernel_length) \
156 res_start = kernel_length - input_samples; \
160 for (i = 0; i < res_start; i++) \
161 buffer[i] = buffer[i + input_samples]; \
162 /* i == res_start */ \
163 for (; i < kernel_length; i++) \
164 buffer[i] = src[input_samples - kernel_length + i]; \
166 self->buffer_fill += kernel_length - res_start; \
167 if (self->buffer_fill > kernel_length) \
168 self->buffer_fill = kernel_length; \
170 return input_samples / channels; \
173 DEFINE_PROCESS_FUNC (32, float);
174 DEFINE_PROCESS_FUNC (64, double);
176 DEFINE_PROCESS_FUNC_FIXED_CHANNELS (32, 1, float);
177 DEFINE_PROCESS_FUNC_FIXED_CHANNELS (64, 1, double);
179 DEFINE_PROCESS_FUNC_FIXED_CHANNELS (32, 2, float);
180 DEFINE_PROCESS_FUNC_FIXED_CHANNELS (64, 2, double);
182 #undef TIME_DOMAIN_CONVOLUTION_BODY
183 #undef DEFINE_PROCESS_FUNC
184 #undef DEFINE_PROCESS_FUNC_FIXED_CHANNELS
186 /* This implements FFT convolution and uses the overlap-save algorithm.
187 * See http://cnx.org/content/m12022/latest/ or your favorite
188 * digital signal processing book for details.
190 * In every pass the following is calculated:
192 * y = IFFT (FFT(x) * FFT(h))
194 * where y is the output in the time domain, x the
195 * input and h the filter kernel. * is the multiplication
196 * of complex numbers.
198 * Due to the circular convolution theorem this
199 * gives in the time domain:
201 * y[t] = \sum_{u=0}^{M-1} x[t - u] * h[u]
203 * where y is the output, M is the kernel length,
204 * x the periodically extended[0] input and h the
207 * ([0] Periodically extended means: )
208 * ( x[t] = x[t+kN] \forall k \in Z )
209 * ( where N is the length of x )
212 * - Obviously x and h need to be of the same size for the FFT
213 * - The first M-1 output values are useless because they're
214 * built from 1 up to M-1 values from the end of the input
215 * (circular convolusion!).
216 * - The last M-1 input values are only used for 1 up to M-1
217 * output values, i.e. they need to be used again in the
218 * next pass for the first M-1 input values.
220 * => The first pass needs M-1 zeroes at the beginning of the
221 * input and the last M-1 input values of every pass need to
222 * be used as the first M-1 input values of the next pass.
224 * => x must be larger than h to give a useful number of output
225 * samples and h needs to be padded by zeroes at the end to give
226 * it virtually the same size as x (by M we denote the number of
227 * non-padding samples of h). If len(x)==len(h)==M only 1 output
228 * sample would be calculated per pass, len(x)==2*len(h) would
229 * give M+1 output samples, etc. Usually a factor between 4 and 8
230 * gives a low number of operations per output samples (see website
233 * Overall this gives a runtime complexity per sample of
236 * O ( --------- ) compared to O (M) for the direct calculation.
239 #define DEFINE_FFT_PROCESS_FUNC(width,ctype) \
241 process_fft_##width (GstAudioFXBaseFIRFilter * self, const g##ctype * src, \
242 g##ctype * dst, guint input_samples) \
244 gint channels = GST_AUDIO_FILTER_CAST (self)->format.channels; \
245 FFT_CONVOLUTION_BODY (channels); \
248 #define DEFINE_FFT_PROCESS_FUNC_FIXED_CHANNELS(width,channels,ctype) \
250 process_fft_##channels##_##width (GstAudioFXBaseFIRFilter * self, const g##ctype * src, \
251 g##ctype * dst, guint input_samples) \
253 FFT_CONVOLUTION_BODY (channels); \
256 #define FFT_CONVOLUTION_BODY(channels) G_STMT_START { \
259 guint kernel_length = self->kernel_length; \
260 guint block_length = self->block_length; \
261 guint buffer_length = self->buffer_length; \
262 guint real_buffer_length = buffer_length + kernel_length - 1; \
263 guint buffer_fill = self->buffer_fill; \
264 GstFFTF64 *fft = self->fft; \
265 GstFFTF64 *ifft = self->ifft; \
266 GstFFTF64Complex *frequency_response = self->frequency_response; \
267 GstFFTF64Complex *fft_buffer = self->fft_buffer; \
268 guint frequency_response_length = self->frequency_response_length; \
269 gdouble *buffer = self->buffer; \
270 guint generated = 0; \
274 self->fft_buffer = fft_buffer = \
275 g_new (GstFFTF64Complex, frequency_response_length); \
277 /* Buffer contains the time domain samples of input data for one chunk \
278 * plus some more space for the inverse FFT below. \
280 * The samples are put at offset kernel_length, the inverse FFT \
281 * overwrites everthing from offset 0 to length-kernel_length+1, keeping \
282 * the last kernel_length-1 samples for copying to the next processing \
286 self->buffer_length = buffer_length = block_length; \
287 real_buffer_length = buffer_length + kernel_length - 1; \
289 self->buffer = buffer = g_new0 (gdouble, real_buffer_length * channels); \
291 /* Beginning has kernel_length-1 zeroes at the beginning */ \
292 self->buffer_fill = buffer_fill = kernel_length - 1; \
295 g_assert (self->buffer_length == block_length); \
297 while (input_samples) { \
298 pass = MIN (buffer_length - buffer_fill, input_samples); \
300 /* Deinterleave channels */ \
301 for (i = 0; i < pass; i++) { \
302 for (j = 0; j < channels; j++) { \
303 buffer[real_buffer_length * j + buffer_fill + kernel_length - 1 + i] = \
304 src[i * channels + j]; \
307 buffer_fill += pass; \
308 src += channels * pass; \
309 input_samples -= pass; \
311 /* If we don't have a complete buffer go out */ \
312 if (buffer_fill < buffer_length) \
315 for (j = 0; j < channels; j++) { \
316 /* Calculate FFT of input block */ \
317 gst_fft_f64_fft (fft, \
318 buffer + real_buffer_length * j + kernel_length - 1, fft_buffer); \
320 /* Complex multiplication of input and filter spectrum */ \
321 for (i = 0; i < frequency_response_length; i++) { \
322 re = fft_buffer[i].r; \
323 im = fft_buffer[i].i; \
326 re * frequency_response[i].r - \
327 im * frequency_response[i].i; \
329 re * frequency_response[i].i + \
330 im * frequency_response[i].r; \
333 /* Calculate inverse FFT of the result */ \
334 gst_fft_f64_inverse_fft (ifft, fft_buffer, \
335 buffer + real_buffer_length * j); \
337 /* Copy all except the first kernel_length-1 samples to the output */ \
338 for (i = 0; i < buffer_length - kernel_length + 1; i++) { \
339 dst[i * channels + j] = \
340 buffer[real_buffer_length * j + kernel_length - 1 + i]; \
343 /* Copy the last kernel_length-1 samples to the beginning for the next block */ \
344 for (i = 0; i < kernel_length - 1; i++) { \
345 buffer[real_buffer_length * j + kernel_length - 1 + i] = \
346 buffer[real_buffer_length * j + buffer_length + i]; \
350 generated += buffer_length - kernel_length + 1; \
351 dst += channels * (buffer_length - kernel_length + 1); \
353 /* The the first kernel_length-1 samples are there already */ \
354 buffer_fill = kernel_length - 1; \
357 /* Write back cached buffer_fill value */ \
358 self->buffer_fill = buffer_fill; \
363 DEFINE_FFT_PROCESS_FUNC (32, float);
364 DEFINE_FFT_PROCESS_FUNC (64, double);
366 DEFINE_FFT_PROCESS_FUNC_FIXED_CHANNELS (32, 1, float);
367 DEFINE_FFT_PROCESS_FUNC_FIXED_CHANNELS (64, 1, double);
369 DEFINE_FFT_PROCESS_FUNC_FIXED_CHANNELS (32, 2, float);
370 DEFINE_FFT_PROCESS_FUNC_FIXED_CHANNELS (64, 2, double);
372 #undef FFT_CONVOLUTION_BODY
373 #undef DEFINE_FFT_PROCESS_FUNC
374 #undef DEFINE_FFT_PROCESS_FUNC_FIXED_CHANNELS
378 gst_audio_fx_base_fir_filter_calculate_frequency_response
379 (GstAudioFXBaseFIRFilter * self)
381 gst_fft_f64_free (self->fft);
383 gst_fft_f64_free (self->ifft);
385 g_free (self->frequency_response);
386 self->frequency_response_length = 0;
387 g_free (self->fft_buffer);
388 self->fft_buffer = NULL;
390 if (self->kernel && self->kernel_length >= FFT_THRESHOLD
391 && !self->low_latency) {
392 guint block_length, i;
393 gdouble *kernel_tmp, *kernel = self->kernel;
395 /* We process 4 * kernel_length samples per pass in FFT mode */
396 block_length = 4 * self->kernel_length;
397 block_length = gst_fft_next_fast_length (block_length);
398 self->block_length = block_length;
400 kernel_tmp = g_new0 (gdouble, block_length);
401 memcpy (kernel_tmp, kernel, self->kernel_length * sizeof (gdouble));
403 self->fft = gst_fft_f64_new (block_length, FALSE);
404 self->ifft = gst_fft_f64_new (block_length, TRUE);
405 self->frequency_response_length = block_length / 2 + 1;
406 self->frequency_response =
407 g_new (GstFFTF64Complex, self->frequency_response_length);
408 gst_fft_f64_fft (self->fft, kernel_tmp, self->frequency_response);
411 /* Normalize to make sure IFFT(FFT(x)) == x */
412 for (i = 0; i < self->frequency_response_length; i++) {
413 self->frequency_response[i].r /= block_length;
414 self->frequency_response[i].i /= block_length;
419 /* Must be called with base transform lock! */
421 gst_audio_fx_base_fir_filter_select_process_function (GstAudioFXBaseFIRFilter *
422 self, gint width, gint channels)
424 if (width == 32 && self->fft && !self->low_latency) {
426 self->process = (GstAudioFXBaseFIRFilterProcessFunc) process_fft_1_32;
427 else if (channels == 2)
428 self->process = (GstAudioFXBaseFIRFilterProcessFunc) process_fft_2_32;
430 self->process = (GstAudioFXBaseFIRFilterProcessFunc) process_fft_32;
431 } else if (width == 64 && self->fft && !self->low_latency) {
433 self->process = (GstAudioFXBaseFIRFilterProcessFunc) process_fft_1_64;
434 else if (channels == 2)
435 self->process = (GstAudioFXBaseFIRFilterProcessFunc) process_fft_2_64;
437 self->process = (GstAudioFXBaseFIRFilterProcessFunc) process_fft_64;
438 } else if (width == 32) {
440 self->process = (GstAudioFXBaseFIRFilterProcessFunc) process_1_32;
441 else if (channels == 2)
442 self->process = (GstAudioFXBaseFIRFilterProcessFunc) process_2_32;
444 self->process = (GstAudioFXBaseFIRFilterProcessFunc) process_32;
445 } else if (width == 64) {
447 self->process = (GstAudioFXBaseFIRFilterProcessFunc) process_1_64;
448 else if (channels == 2)
449 self->process = (GstAudioFXBaseFIRFilterProcessFunc) process_2_64;
451 self->process = (GstAudioFXBaseFIRFilterProcessFunc) process_64;
453 self->process = NULL;
458 gst_audio_fx_base_fir_filter_dispose (GObject * object)
460 GstAudioFXBaseFIRFilter *self = GST_AUDIO_FX_BASE_FIR_FILTER (object);
462 g_free (self->buffer);
464 self->buffer_length = 0;
466 g_free (self->kernel);
469 gst_fft_f64_free (self->fft);
471 gst_fft_f64_free (self->ifft);
474 g_free (self->frequency_response);
475 self->frequency_response = NULL;
477 g_free (self->fft_buffer);
478 self->fft_buffer = NULL;
480 G_OBJECT_CLASS (parent_class)->dispose (object);
484 gst_audio_fx_base_fir_filter_set_property (GObject * object, guint prop_id,
485 const GValue * value, GParamSpec * pspec)
487 GstAudioFXBaseFIRFilter *self = GST_AUDIO_FX_BASE_FIR_FILTER (object);
490 case PROP_LOW_LATENCY:{
491 gboolean low_latency;
493 if (GST_STATE (self) >= GST_STATE_PAUSED) {
494 g_warning ("Changing the \"low-latency\" property "
495 "is only allowed in states < PAUSED");
499 GST_BASE_TRANSFORM_LOCK (self);
500 low_latency = g_value_get_boolean (value);
502 if (self->low_latency != low_latency) {
503 self->low_latency = low_latency;
504 gst_audio_fx_base_fir_filter_calculate_frequency_response (self);
505 gst_audio_fx_base_fir_filter_select_process_function (self,
506 GST_AUDIO_FILTER_CAST (self)->format.width,
507 GST_AUDIO_FILTER_CAST (self)->format.channels);
509 GST_BASE_TRANSFORM_UNLOCK (self);
512 case PROP_DRAIN_ON_CHANGES:{
513 GST_BASE_TRANSFORM_LOCK (self);
514 self->drain_on_changes = g_value_get_boolean (value);
515 GST_BASE_TRANSFORM_UNLOCK (self);
519 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
525 gst_audio_fx_base_fir_filter_get_property (GObject * object, guint prop_id,
526 GValue * value, GParamSpec * pspec)
528 GstAudioFXBaseFIRFilter *self = GST_AUDIO_FX_BASE_FIR_FILTER (object);
531 case PROP_LOW_LATENCY:
532 g_value_set_boolean (value, self->low_latency);
534 case PROP_DRAIN_ON_CHANGES:
535 g_value_set_boolean (value, self->drain_on_changes);
538 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
544 gst_audio_fx_base_fir_filter_base_init (gpointer g_class)
548 caps = gst_caps_from_string (ALLOWED_CAPS);
549 gst_audio_filter_class_add_pad_templates (GST_AUDIO_FILTER_CLASS (g_class),
551 gst_caps_unref (caps);
555 gst_audio_fx_base_fir_filter_class_init (GstAudioFXBaseFIRFilterClass * klass)
557 GObjectClass *gobject_class = (GObjectClass *) klass;
558 GstBaseTransformClass *trans_class = (GstBaseTransformClass *) klass;
559 GstAudioFilterClass *filter_class = (GstAudioFilterClass *) klass;
561 gobject_class->dispose = gst_audio_fx_base_fir_filter_dispose;
562 gobject_class->set_property = gst_audio_fx_base_fir_filter_set_property;
563 gobject_class->get_property = gst_audio_fx_base_fir_filter_get_property;
566 * GstAudioFXBaseFIRFilter::low-latency:
568 * Work in low-latency mode. This mode is much slower for large filter sizes
569 * but the latency is always only the pre-latency of the filter.
573 g_object_class_install_property (gobject_class, PROP_LOW_LATENCY,
574 g_param_spec_boolean ("low-latency", "Low latency",
575 "Operate in low latency mode. This mode is slower but the "
576 "latency will only be the filter pre-latency. "
577 "Can only be changed in states < PAUSED!", DEFAULT_LOW_LATENCY,
578 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
581 * GstAudioFXBaseFIRFilter::drain-on-changes:
583 * Whether the filter should be drained when its coeficients change
585 * Note: Currently this only works if the kernel size is not changed!
586 * Support for drainless kernel size changes will be added in the future.
590 g_object_class_install_property (gobject_class, PROP_DRAIN_ON_CHANGES,
591 g_param_spec_boolean ("drain-on-changes", "Drain on changes",
592 "Drains the filter when its coeficients change",
593 DEFAULT_DRAIN_ON_CHANGES,
594 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
596 trans_class->transform =
597 GST_DEBUG_FUNCPTR (gst_audio_fx_base_fir_filter_transform);
598 trans_class->start = GST_DEBUG_FUNCPTR (gst_audio_fx_base_fir_filter_start);
599 trans_class->stop = GST_DEBUG_FUNCPTR (gst_audio_fx_base_fir_filter_stop);
600 trans_class->event = GST_DEBUG_FUNCPTR (gst_audio_fx_base_fir_filter_event);
601 trans_class->transform_size =
602 GST_DEBUG_FUNCPTR (gst_audio_fx_base_fir_filter_transform_size);
603 filter_class->setup = GST_DEBUG_FUNCPTR (gst_audio_fx_base_fir_filter_setup);
607 gst_audio_fx_base_fir_filter_init (GstAudioFXBaseFIRFilter * self,
608 GstAudioFXBaseFIRFilterClass * g_class)
612 self->buffer_length = 0;
614 self->start_ts = GST_CLOCK_TIME_NONE;
615 self->start_off = GST_BUFFER_OFFSET_NONE;
616 self->nsamples_out = 0;
617 self->nsamples_in = 0;
619 self->low_latency = DEFAULT_LOW_LATENCY;
620 self->drain_on_changes = DEFAULT_DRAIN_ON_CHANGES;
622 gst_pad_set_query_function (GST_BASE_TRANSFORM (self)->srcpad,
623 gst_audio_fx_base_fir_filter_query);
624 gst_pad_set_query_type_function (GST_BASE_TRANSFORM (self)->srcpad,
625 gst_audio_fx_base_fir_filter_query_type);
629 gst_audio_fx_base_fir_filter_push_residue (GstAudioFXBaseFIRFilter * self)
633 gint rate = GST_AUDIO_FILTER_CAST (self)->format.rate;
634 gint channels = GST_AUDIO_FILTER_CAST (self)->format.channels;
635 gint width = GST_AUDIO_FILTER_CAST (self)->format.width / 8;
636 gint outsize, outsamples;
639 if (channels == 0 || rate == 0 || self->nsamples_in == 0) {
640 self->buffer_fill = 0;
641 g_free (self->buffer);
646 /* Calculate the number of samples and their memory size that
647 * should be pushed from the residue */
648 outsamples = self->nsamples_in - (self->nsamples_out - self->latency);
649 if (outsamples <= 0) {
650 self->buffer_fill = 0;
651 g_free (self->buffer);
655 outsize = outsamples * channels * width;
657 if (!self->fft || self->low_latency) {
658 gint64 diffsize, diffsamples;
660 /* Process the difference between latency and residue length samples
661 * to start at the actual data instead of starting at the zeros before
662 * when we only got one buffer smaller than latency */
664 ((gint64) self->latency) - ((gint64) self->buffer_fill) / channels;
665 if (diffsamples > 0) {
666 diffsize = diffsamples * channels * width;
667 in = g_new0 (guint8, diffsize);
668 out = g_new0 (guint8, diffsize);
669 self->nsamples_out += self->process (self, in, out, diffsamples);
674 res = gst_pad_alloc_buffer (GST_BASE_TRANSFORM_CAST (self)->srcpad,
675 GST_BUFFER_OFFSET_NONE, outsize,
676 GST_PAD_CAPS (GST_BASE_TRANSFORM_CAST (self)->srcpad), &outbuf);
678 if (G_UNLIKELY (res != GST_FLOW_OK)) {
679 GST_WARNING_OBJECT (self, "failed allocating buffer of %d bytes",
681 self->buffer_fill = 0;
685 /* Convolve the residue with zeros to get the actual remaining data */
686 in = g_new0 (guint8, outsize);
687 self->nsamples_out +=
688 self->process (self, in, GST_BUFFER_DATA (outbuf), outsamples);
691 guint gensamples = 0;
694 outbuf = gst_buffer_new_and_alloc (outsize);
695 data = GST_BUFFER_DATA (outbuf);
697 while (gensamples < outsamples) {
698 guint step_insamples = self->block_length - self->buffer_fill;
699 guint8 *zeroes = g_new0 (guint8, step_insamples * channels * width);
700 guint8 *out = g_new (guint8, self->block_length * channels * width);
701 guint step_gensamples;
703 step_gensamples = self->process (self, zeroes, out, step_insamples);
706 memcpy (data + gensamples * width, out, MIN (step_gensamples,
707 outsamples - gensamples) * width);
708 gensamples += MIN (step_gensamples, outsamples - gensamples);
712 self->nsamples_out += gensamples;
715 /* Set timestamp, offset, etc from the values we
716 * saved when processing the regular buffers */
717 if (GST_CLOCK_TIME_IS_VALID (self->start_ts))
718 GST_BUFFER_TIMESTAMP (outbuf) = self->start_ts;
720 GST_BUFFER_TIMESTAMP (outbuf) = 0;
721 GST_BUFFER_TIMESTAMP (outbuf) +=
722 gst_util_uint64_scale_int (self->nsamples_out - outsamples -
723 self->latency, GST_SECOND, rate);
725 GST_BUFFER_DURATION (outbuf) =
726 gst_util_uint64_scale_int (outsamples, GST_SECOND, rate);
728 if (self->start_off != GST_BUFFER_OFFSET_NONE) {
729 GST_BUFFER_OFFSET (outbuf) =
730 self->start_off + self->nsamples_out - outsamples - self->latency;
731 GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET (outbuf) + outsamples;
734 GST_DEBUG_OBJECT (self, "Pushing residue buffer of size %d with timestamp: %"
735 GST_TIME_FORMAT ", duration: %" GST_TIME_FORMAT ", offset: %"
736 G_GUINT64_FORMAT ", offset_end: %" G_GUINT64_FORMAT ", nsamples_out: %d",
737 GST_BUFFER_SIZE (outbuf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
738 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf),
739 GST_BUFFER_OFFSET_END (outbuf), outsamples);
741 res = gst_pad_push (GST_BASE_TRANSFORM_CAST (self)->srcpad, outbuf);
743 if (G_UNLIKELY (res != GST_FLOW_OK)) {
744 GST_WARNING_OBJECT (self, "failed to push residue");
747 self->buffer_fill = 0;
750 /* GstAudioFilter vmethod implementations */
752 /* get notified of caps and plug in the correct process function */
754 gst_audio_fx_base_fir_filter_setup (GstAudioFilter * base,
755 GstRingBufferSpec * format)
757 GstAudioFXBaseFIRFilter *self = GST_AUDIO_FX_BASE_FIR_FILTER (base);
760 gst_audio_fx_base_fir_filter_push_residue (self);
761 g_free (self->buffer);
763 self->buffer_fill = 0;
764 self->buffer_length = 0;
765 self->start_ts = GST_CLOCK_TIME_NONE;
766 self->start_off = GST_BUFFER_OFFSET_NONE;
767 self->nsamples_out = 0;
768 self->nsamples_in = 0;
771 gst_audio_fx_base_fir_filter_select_process_function (self, format->width,
774 return (self->process != NULL);
777 /* GstBaseTransform vmethod implementations */
780 gst_audio_fx_base_fir_filter_transform_size (GstBaseTransform * base,
781 GstPadDirection direction, GstCaps * caps, guint size, GstCaps * othercaps,
784 GstAudioFXBaseFIRFilter *self = GST_AUDIO_FX_BASE_FIR_FILTER (base);
787 gint width, channels;
789 if (!self->fft || self->low_latency || direction == GST_PAD_SRC) {
794 s = gst_caps_get_structure (caps, 0);
795 if (!gst_structure_get_int (s, "width", &width) ||
796 !gst_structure_get_int (s, "channels", &channels))
801 size /= width * channels;
803 blocklen = self->block_length - self->kernel_length + 1;
804 *othersize = ((size + blocklen - 1) / blocklen) * blocklen;
806 *othersize *= width * channels;
812 gst_audio_fx_base_fir_filter_transform (GstBaseTransform * base,
813 GstBuffer * inbuf, GstBuffer * outbuf)
815 GstAudioFXBaseFIRFilter *self = GST_AUDIO_FX_BASE_FIR_FILTER (base);
816 GstClockTime timestamp, expected_timestamp;
817 gint channels = GST_AUDIO_FILTER_CAST (self)->format.channels;
818 gint rate = GST_AUDIO_FILTER_CAST (self)->format.rate;
819 gint width = GST_AUDIO_FILTER_CAST (self)->format.width / 8;
820 guint input_samples = (GST_BUFFER_SIZE (inbuf) / width) / channels;
821 guint output_samples = (GST_BUFFER_SIZE (outbuf) / width) / channels;
822 guint generated_samples;
823 guint64 output_offset;
825 GstClockTime stream_time;
827 timestamp = GST_BUFFER_TIMESTAMP (outbuf);
829 if (!GST_CLOCK_TIME_IS_VALID (timestamp)
830 && !GST_CLOCK_TIME_IS_VALID (self->start_ts)) {
831 GST_ERROR_OBJECT (self, "Invalid timestamp");
832 return GST_FLOW_ERROR;
836 gst_segment_to_stream_time (&base->segment, GST_FORMAT_TIME, timestamp);
838 GST_DEBUG_OBJECT (self, "sync to %" GST_TIME_FORMAT,
839 GST_TIME_ARGS (timestamp));
841 if (GST_CLOCK_TIME_IS_VALID (stream_time))
842 gst_object_sync_values (G_OBJECT (self), stream_time);
844 g_return_val_if_fail (self->kernel != NULL, GST_FLOW_ERROR);
845 g_return_val_if_fail (channels != 0, GST_FLOW_ERROR);
847 if (GST_CLOCK_TIME_IS_VALID (self->start_ts))
849 self->start_ts + gst_util_uint64_scale_int (self->nsamples_in,
852 expected_timestamp = GST_CLOCK_TIME_NONE;
854 /* Reset the residue if already existing on discont buffers */
855 if (GST_BUFFER_IS_DISCONT (inbuf)
856 || (GST_CLOCK_TIME_IS_VALID (expected_timestamp)
857 && (ABS (GST_CLOCK_DIFF (timestamp,
858 expected_timestamp) > 5 * GST_MSECOND)))) {
859 GST_DEBUG_OBJECT (self, "Discontinuity detected - flushing");
860 if (GST_CLOCK_TIME_IS_VALID (expected_timestamp))
861 gst_audio_fx_base_fir_filter_push_residue (self);
862 self->buffer_fill = 0;
863 g_free (self->buffer);
865 self->start_ts = timestamp;
866 self->start_off = GST_BUFFER_OFFSET (inbuf);
867 self->nsamples_out = 0;
868 self->nsamples_in = 0;
869 } else if (!GST_CLOCK_TIME_IS_VALID (self->start_ts)) {
870 self->start_ts = timestamp;
871 self->start_off = GST_BUFFER_OFFSET (inbuf);
874 self->nsamples_in += input_samples;
877 self->process (self, GST_BUFFER_DATA (inbuf), GST_BUFFER_DATA (outbuf),
880 g_assert (generated_samples <= output_samples);
881 self->nsamples_out += generated_samples;
882 if (generated_samples == 0)
883 return GST_BASE_TRANSFORM_FLOW_DROPPED;
885 /* Calculate the number of samples we can push out now without outputting
886 * latency zeros in the beginning */
887 diff = ((gint64) self->nsamples_out) - ((gint64) self->latency);
889 return GST_BASE_TRANSFORM_FLOW_DROPPED;
890 } else if (diff < generated_samples) {
892 diff = generated_samples - diff;
893 generated_samples = tmp;
894 GST_BUFFER_DATA (outbuf) += diff * width * channels;
896 GST_BUFFER_SIZE (outbuf) = generated_samples * width * channels;
898 output_offset = self->nsamples_out - self->latency - generated_samples;
899 GST_BUFFER_TIMESTAMP (outbuf) =
900 self->start_ts + gst_util_uint64_scale_int (output_offset, GST_SECOND,
902 GST_BUFFER_DURATION (outbuf) =
903 gst_util_uint64_scale_int (output_samples, GST_SECOND, rate);
904 if (self->start_off != GST_BUFFER_OFFSET_NONE) {
905 GST_BUFFER_OFFSET (outbuf) = self->start_off + output_offset;
906 GST_BUFFER_OFFSET_END (outbuf) =
907 GST_BUFFER_OFFSET (outbuf) + generated_samples;
909 GST_BUFFER_OFFSET (outbuf) = GST_BUFFER_OFFSET_NONE;
910 GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET_NONE;
913 GST_DEBUG_OBJECT (self, "Pushing buffer of size %d with timestamp: %"
914 GST_TIME_FORMAT ", duration: %" GST_TIME_FORMAT ", offset: %"
915 G_GUINT64_FORMAT ", offset_end: %" G_GUINT64_FORMAT ", nsamples_out: %d",
916 GST_BUFFER_SIZE (outbuf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
917 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf),
918 GST_BUFFER_OFFSET_END (outbuf), generated_samples);
924 gst_audio_fx_base_fir_filter_start (GstBaseTransform * base)
926 GstAudioFXBaseFIRFilter *self = GST_AUDIO_FX_BASE_FIR_FILTER (base);
928 self->buffer_fill = 0;
929 g_free (self->buffer);
931 self->start_ts = GST_CLOCK_TIME_NONE;
932 self->start_off = GST_BUFFER_OFFSET_NONE;
933 self->nsamples_out = 0;
934 self->nsamples_in = 0;
940 gst_audio_fx_base_fir_filter_stop (GstBaseTransform * base)
942 GstAudioFXBaseFIRFilter *self = GST_AUDIO_FX_BASE_FIR_FILTER (base);
944 g_free (self->buffer);
946 self->buffer_length = 0;
952 gst_audio_fx_base_fir_filter_query (GstPad * pad, GstQuery * query)
954 GstAudioFXBaseFIRFilter *self =
955 GST_AUDIO_FX_BASE_FIR_FILTER (gst_pad_get_parent (pad));
958 switch (GST_QUERY_TYPE (query)) {
959 case GST_QUERY_LATENCY:
961 GstClockTime min, max;
965 gint rate = GST_AUDIO_FILTER (self)->format.rate;
969 } else if ((peer = gst_pad_get_peer (GST_BASE_TRANSFORM (self)->sinkpad))) {
970 if ((res = gst_pad_query (peer, query))) {
971 gst_query_parse_latency (query, &live, &min, &max);
973 GST_DEBUG_OBJECT (self, "Peer latency: min %"
974 GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
975 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
977 if (self->fft && !self->low_latency)
978 latency = self->block_length - self->kernel_length + 1;
980 latency = self->latency;
982 /* add our own latency */
983 latency = gst_util_uint64_scale_round (latency, GST_SECOND, rate);
985 GST_DEBUG_OBJECT (self, "Our latency: %"
986 GST_TIME_FORMAT, GST_TIME_ARGS (latency));
989 if (max != GST_CLOCK_TIME_NONE)
992 GST_DEBUG_OBJECT (self, "Calculated total latency : min %"
993 GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
994 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
996 gst_query_set_latency (query, live, min, max);
998 gst_object_unref (peer);
1003 res = gst_pad_query_default (pad, query);
1006 gst_object_unref (self);
1010 static const GstQueryType *
1011 gst_audio_fx_base_fir_filter_query_type (GstPad * pad)
1013 static const GstQueryType types[] = {
1022 gst_audio_fx_base_fir_filter_event (GstBaseTransform * base, GstEvent * event)
1024 GstAudioFXBaseFIRFilter *self = GST_AUDIO_FX_BASE_FIR_FILTER (base);
1026 switch (GST_EVENT_TYPE (event)) {
1028 gst_audio_fx_base_fir_filter_push_residue (self);
1029 self->start_ts = GST_CLOCK_TIME_NONE;
1030 self->start_off = GST_BUFFER_OFFSET_NONE;
1031 self->nsamples_out = 0;
1032 self->nsamples_in = 0;
1038 return GST_BASE_TRANSFORM_CLASS (parent_class)->event (base, event);
1042 gst_audio_fx_base_fir_filter_set_kernel (GstAudioFXBaseFIRFilter * self,
1043 gdouble * kernel, guint kernel_length, guint64 latency)
1045 gboolean latency_changed;
1047 g_return_if_fail (kernel != NULL);
1048 g_return_if_fail (self != NULL);
1050 GST_BASE_TRANSFORM_LOCK (self);
1052 latency_changed = (self->latency != latency
1053 || (!self->low_latency && self->kernel_length < FFT_THRESHOLD
1054 && kernel_length >= FFT_THRESHOLD)
1055 || (!self->low_latency && self->kernel_length >= FFT_THRESHOLD
1056 && kernel_length < FFT_THRESHOLD));
1058 /* FIXME: If the latency changes, the buffer size changes too and we
1059 * have to drain in any case until this is fixed in the future */
1060 if (self->buffer && (!self->drain_on_changes || latency_changed)) {
1061 gst_audio_fx_base_fir_filter_push_residue (self);
1062 self->start_ts = GST_CLOCK_TIME_NONE;
1063 self->start_off = GST_BUFFER_OFFSET_NONE;
1064 self->nsamples_out = 0;
1065 self->nsamples_in = 0;
1066 self->buffer_fill = 0;
1069 g_free (self->kernel);
1070 if (!self->drain_on_changes || latency_changed) {
1071 g_free (self->buffer);
1072 self->buffer = NULL;
1073 self->buffer_fill = 0;
1074 self->buffer_length = 0;
1077 self->kernel = kernel;
1078 self->kernel_length = kernel_length;
1080 gst_audio_fx_base_fir_filter_calculate_frequency_response (self);
1081 gst_audio_fx_base_fir_filter_select_process_function (self,
1082 GST_AUDIO_FILTER_CAST (self)->format.width,
1083 GST_AUDIO_FILTER_CAST (self)->format.channels);
1085 if (latency_changed) {
1086 self->latency = latency;
1087 gst_element_post_message (GST_ELEMENT (self),
1088 gst_message_new_latency (GST_OBJECT (self)));
1091 GST_BASE_TRANSFORM_UNLOCK (self);