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>
34 #include "audiofxbasefirfilter.h"
36 #define GST_CAT_DEFAULT gst_audio_fx_base_fir_filter_debug
37 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
39 #define ALLOWED_CAPS \
41 " format=(string){"GST_AUDIO_NE(F32)","GST_AUDIO_NE(F64)"}, " \
42 " rate = (int) [ 1, MAX ], " \
43 " channels = (int) [ 1, MAX ]"
45 /* Switch from time-domain to FFT convolution for kernels >= this */
46 #define FFT_THRESHOLD 32
55 #define DEFAULT_LOW_LATENCY FALSE
56 #define DEFAULT_DRAIN_ON_CHANGES TRUE
58 #define gst_audio_fx_base_fir_filter_parent_class parent_class
59 G_DEFINE_TYPE (GstAudioFXBaseFIRFilter, gst_audio_fx_base_fir_filter,
60 GST_TYPE_AUDIO_FILTER);
62 static GstFlowReturn gst_audio_fx_base_fir_filter_transform (GstBaseTransform *
63 base, GstBuffer * inbuf, GstBuffer * outbuf);
64 static gboolean gst_audio_fx_base_fir_filter_start (GstBaseTransform * base);
65 static gboolean gst_audio_fx_base_fir_filter_stop (GstBaseTransform * base);
66 static gboolean gst_audio_fx_base_fir_filter_sink_event (GstBaseTransform *
67 base, GstEvent * event);
68 static gboolean gst_audio_fx_base_fir_filter_transform_size (GstBaseTransform *
69 base, GstPadDirection direction, GstCaps * caps, gsize size,
70 GstCaps * othercaps, gsize * othersize);
71 static gboolean gst_audio_fx_base_fir_filter_setup (GstAudioFilter * base,
72 const GstAudioInfo * info);
74 static gboolean gst_audio_fx_base_fir_filter_query (GstPad * pad,
75 GstObject * parent, GstQuery * query);
78 * The code below calculates the linear convolution:
80 * y[t] = \sum_{u=0}^{M-1} x[t - u] * h[u]
82 * where y is the output, x is the input, M is the length
83 * of the filter kernel and h is the filter kernel. For x
84 * holds: x[t] == 0 \forall t < 0.
86 * The runtime complexity of this is O (M) per sample.
89 #define DEFINE_PROCESS_FUNC(width,ctype) \
91 process_##width (GstAudioFXBaseFIRFilter * self, const g##ctype * src, g##ctype * dst, guint input_samples) \
93 gint channels = GST_AUDIO_FILTER_CHANNELS (self); \
94 TIME_DOMAIN_CONVOLUTION_BODY (channels); \
97 #define DEFINE_PROCESS_FUNC_FIXED_CHANNELS(width,channels,ctype) \
99 process_##channels##_##width (GstAudioFXBaseFIRFilter * self, const g##ctype * src, g##ctype * dst, guint input_samples) \
101 TIME_DOMAIN_CONVOLUTION_BODY (channels); \
104 #define TIME_DOMAIN_CONVOLUTION_BODY(channels) G_STMT_START { \
105 gint kernel_length = self->kernel_length; \
110 gdouble *buffer = self->buffer; \
111 gdouble *kernel = self->kernel; \
112 guint buffer_length = self->buffer_length; \
115 self->buffer_length = buffer_length = kernel_length * channels; \
116 self->buffer = buffer = g_new0 (gdouble, self->buffer_length); \
120 for (i = 0; i < input_samples; i++) { \
124 from_input = MIN (l, kernel_length-1); \
125 off = l * channels + k; \
126 for (j = 0; j <= from_input; j++) { \
127 dst[i] += src[off] * kernel[j]; \
130 /* j == from_input && off == (l - j) * channels + k */ \
131 off += kernel_length * channels; \
132 for (; j < kernel_length; j++) { \
133 dst[i] += buffer[off] * kernel[j]; \
138 /* copy the tail of the current input buffer to the residue, while \
139 * keeping parts of the residue if the input buffer is smaller than \
140 * the kernel length */ \
141 /* from now on take kernel length as length over all channels */ \
142 kernel_length *= channels; \
143 if (input_samples < kernel_length) \
144 res_start = kernel_length - input_samples; \
148 for (i = 0; i < res_start; i++) \
149 buffer[i] = buffer[i + input_samples]; \
150 /* i == res_start */ \
151 for (; i < kernel_length; i++) \
152 buffer[i] = src[input_samples - kernel_length + i]; \
154 self->buffer_fill += kernel_length - res_start; \
155 if (self->buffer_fill > kernel_length) \
156 self->buffer_fill = kernel_length; \
158 return input_samples / channels; \
161 DEFINE_PROCESS_FUNC (32, float);
162 DEFINE_PROCESS_FUNC (64, double);
164 DEFINE_PROCESS_FUNC_FIXED_CHANNELS (32, 1, float);
165 DEFINE_PROCESS_FUNC_FIXED_CHANNELS (64, 1, double);
167 DEFINE_PROCESS_FUNC_FIXED_CHANNELS (32, 2, float);
168 DEFINE_PROCESS_FUNC_FIXED_CHANNELS (64, 2, double);
170 #undef TIME_DOMAIN_CONVOLUTION_BODY
171 #undef DEFINE_PROCESS_FUNC
172 #undef DEFINE_PROCESS_FUNC_FIXED_CHANNELS
174 /* This implements FFT convolution and uses the overlap-save algorithm.
175 * See http://cnx.org/content/m12022/latest/ or your favorite
176 * digital signal processing book for details.
178 * In every pass the following is calculated:
180 * y = IFFT (FFT(x) * FFT(h))
182 * where y is the output in the time domain, x the
183 * input and h the filter kernel. * is the multiplication
184 * of complex numbers.
186 * Due to the circular convolution theorem this
187 * gives in the time domain:
189 * y[t] = \sum_{u=0}^{M-1} x[t - u] * h[u]
191 * where y is the output, M is the kernel length,
192 * x the periodically extended[0] input and h the
195 * ([0] Periodically extended means: )
196 * ( x[t] = x[t+kN] \forall k \in Z )
197 * ( where N is the length of x )
200 * - Obviously x and h need to be of the same size for the FFT
201 * - The first M-1 output values are useless because they're
202 * built from 1 up to M-1 values from the end of the input
203 * (circular convolusion!).
204 * - The last M-1 input values are only used for 1 up to M-1
205 * output values, i.e. they need to be used again in the
206 * next pass for the first M-1 input values.
208 * => The first pass needs M-1 zeroes at the beginning of the
209 * input and the last M-1 input values of every pass need to
210 * be used as the first M-1 input values of the next pass.
212 * => x must be larger than h to give a useful number of output
213 * samples and h needs to be padded by zeroes at the end to give
214 * it virtually the same size as x (by M we denote the number of
215 * non-padding samples of h). If len(x)==len(h)==M only 1 output
216 * sample would be calculated per pass, len(x)==2*len(h) would
217 * give M+1 output samples, etc. Usually a factor between 4 and 8
218 * gives a low number of operations per output samples (see website
221 * Overall this gives a runtime complexity per sample of
224 * O ( --------- ) compared to O (M) for the direct calculation.
227 #define DEFINE_FFT_PROCESS_FUNC(width,ctype) \
229 process_fft_##width (GstAudioFXBaseFIRFilter * self, const g##ctype * src, \
230 g##ctype * dst, guint input_samples) \
232 gint channels = GST_AUDIO_FILTER_CHANNELS (self); \
233 FFT_CONVOLUTION_BODY (channels); \
236 #define DEFINE_FFT_PROCESS_FUNC_FIXED_CHANNELS(width,channels,ctype) \
238 process_fft_##channels##_##width (GstAudioFXBaseFIRFilter * self, const g##ctype * src, \
239 g##ctype * dst, guint input_samples) \
241 FFT_CONVOLUTION_BODY (channels); \
244 #define FFT_CONVOLUTION_BODY(channels) G_STMT_START { \
247 guint kernel_length = self->kernel_length; \
248 guint block_length = self->block_length; \
249 guint buffer_length = self->buffer_length; \
250 guint real_buffer_length = buffer_length + kernel_length - 1; \
251 guint buffer_fill = self->buffer_fill; \
252 GstFFTF64 *fft = self->fft; \
253 GstFFTF64 *ifft = self->ifft; \
254 GstFFTF64Complex *frequency_response = self->frequency_response; \
255 GstFFTF64Complex *fft_buffer = self->fft_buffer; \
256 guint frequency_response_length = self->frequency_response_length; \
257 gdouble *buffer = self->buffer; \
258 guint generated = 0; \
262 self->fft_buffer = fft_buffer = \
263 g_new (GstFFTF64Complex, frequency_response_length); \
265 /* Buffer contains the time domain samples of input data for one chunk \
266 * plus some more space for the inverse FFT below. \
268 * The samples are put at offset kernel_length, the inverse FFT \
269 * overwrites everthing from offset 0 to length-kernel_length+1, keeping \
270 * the last kernel_length-1 samples for copying to the next processing \
274 self->buffer_length = buffer_length = block_length; \
275 real_buffer_length = buffer_length + kernel_length - 1; \
277 self->buffer = buffer = g_new0 (gdouble, real_buffer_length * channels); \
279 /* Beginning has kernel_length-1 zeroes at the beginning */ \
280 self->buffer_fill = buffer_fill = kernel_length - 1; \
283 g_assert (self->buffer_length == block_length); \
285 while (input_samples) { \
286 pass = MIN (buffer_length - buffer_fill, input_samples); \
288 /* Deinterleave channels */ \
289 for (i = 0; i < pass; i++) { \
290 for (j = 0; j < channels; j++) { \
291 buffer[real_buffer_length * j + buffer_fill + kernel_length - 1 + i] = \
292 src[i * channels + j]; \
295 buffer_fill += pass; \
296 src += channels * pass; \
297 input_samples -= pass; \
299 /* If we don't have a complete buffer go out */ \
300 if (buffer_fill < buffer_length) \
303 for (j = 0; j < channels; j++) { \
304 /* Calculate FFT of input block */ \
305 gst_fft_f64_fft (fft, \
306 buffer + real_buffer_length * j + kernel_length - 1, fft_buffer); \
308 /* Complex multiplication of input and filter spectrum */ \
309 for (i = 0; i < frequency_response_length; i++) { \
310 re = fft_buffer[i].r; \
311 im = fft_buffer[i].i; \
314 re * frequency_response[i].r - \
315 im * frequency_response[i].i; \
317 re * frequency_response[i].i + \
318 im * frequency_response[i].r; \
321 /* Calculate inverse FFT of the result */ \
322 gst_fft_f64_inverse_fft (ifft, fft_buffer, \
323 buffer + real_buffer_length * j); \
325 /* Copy all except the first kernel_length-1 samples to the output */ \
326 for (i = 0; i < buffer_length - kernel_length + 1; i++) { \
327 dst[i * channels + j] = \
328 buffer[real_buffer_length * j + kernel_length - 1 + i]; \
331 /* Copy the last kernel_length-1 samples to the beginning for the next block */ \
332 for (i = 0; i < kernel_length - 1; i++) { \
333 buffer[real_buffer_length * j + kernel_length - 1 + i] = \
334 buffer[real_buffer_length * j + buffer_length + i]; \
338 generated += buffer_length - kernel_length + 1; \
339 dst += channels * (buffer_length - kernel_length + 1); \
341 /* The the first kernel_length-1 samples are there already */ \
342 buffer_fill = kernel_length - 1; \
345 /* Write back cached buffer_fill value */ \
346 self->buffer_fill = buffer_fill; \
351 DEFINE_FFT_PROCESS_FUNC (32, float);
352 DEFINE_FFT_PROCESS_FUNC (64, double);
354 DEFINE_FFT_PROCESS_FUNC_FIXED_CHANNELS (32, 1, float);
355 DEFINE_FFT_PROCESS_FUNC_FIXED_CHANNELS (64, 1, double);
357 DEFINE_FFT_PROCESS_FUNC_FIXED_CHANNELS (32, 2, float);
358 DEFINE_FFT_PROCESS_FUNC_FIXED_CHANNELS (64, 2, double);
360 #undef FFT_CONVOLUTION_BODY
361 #undef DEFINE_FFT_PROCESS_FUNC
362 #undef DEFINE_FFT_PROCESS_FUNC_FIXED_CHANNELS
366 gst_audio_fx_base_fir_filter_calculate_frequency_response
367 (GstAudioFXBaseFIRFilter * self)
369 gst_fft_f64_free (self->fft);
371 gst_fft_f64_free (self->ifft);
373 g_free (self->frequency_response);
374 self->frequency_response_length = 0;
375 g_free (self->fft_buffer);
376 self->fft_buffer = NULL;
378 if (self->kernel && self->kernel_length >= FFT_THRESHOLD
379 && !self->low_latency) {
380 guint block_length, i;
381 gdouble *kernel_tmp, *kernel = self->kernel;
383 /* We process 4 * kernel_length samples per pass in FFT mode */
384 block_length = 4 * self->kernel_length;
385 block_length = gst_fft_next_fast_length (block_length);
386 self->block_length = block_length;
388 kernel_tmp = g_new0 (gdouble, block_length);
389 memcpy (kernel_tmp, kernel, self->kernel_length * sizeof (gdouble));
391 self->fft = gst_fft_f64_new (block_length, FALSE);
392 self->ifft = gst_fft_f64_new (block_length, TRUE);
393 self->frequency_response_length = block_length / 2 + 1;
394 self->frequency_response =
395 g_new (GstFFTF64Complex, self->frequency_response_length);
396 gst_fft_f64_fft (self->fft, kernel_tmp, self->frequency_response);
399 /* Normalize to make sure IFFT(FFT(x)) == x */
400 for (i = 0; i < self->frequency_response_length; i++) {
401 self->frequency_response[i].r /= block_length;
402 self->frequency_response[i].i /= block_length;
407 /* Must be called with base transform lock! */
409 gst_audio_fx_base_fir_filter_select_process_function (GstAudioFXBaseFIRFilter *
410 self, GstAudioFormat format, gint channels)
413 case GST_AUDIO_FORMAT_F32:
414 if (self->fft && !self->low_latency) {
416 self->process = (GstAudioFXBaseFIRFilterProcessFunc) process_fft_1_32;
417 else if (channels == 2)
418 self->process = (GstAudioFXBaseFIRFilterProcessFunc) process_fft_2_32;
420 self->process = (GstAudioFXBaseFIRFilterProcessFunc) process_fft_32;
423 self->process = (GstAudioFXBaseFIRFilterProcessFunc) process_1_32;
424 else if (channels == 2)
425 self->process = (GstAudioFXBaseFIRFilterProcessFunc) process_2_32;
427 self->process = (GstAudioFXBaseFIRFilterProcessFunc) process_32;
430 case GST_AUDIO_FORMAT_F64:
431 if (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;
440 self->process = (GstAudioFXBaseFIRFilterProcessFunc) process_1_64;
441 else if (channels == 2)
442 self->process = (GstAudioFXBaseFIRFilterProcessFunc) process_2_64;
444 self->process = (GstAudioFXBaseFIRFilterProcessFunc) process_64;
448 self->process = NULL;
454 gst_audio_fx_base_fir_filter_dispose (GObject * object)
456 GstAudioFXBaseFIRFilter *self = GST_AUDIO_FX_BASE_FIR_FILTER (object);
458 g_free (self->buffer);
460 self->buffer_length = 0;
462 g_free (self->kernel);
465 gst_fft_f64_free (self->fft);
467 gst_fft_f64_free (self->ifft);
470 g_free (self->frequency_response);
471 self->frequency_response = NULL;
473 g_free (self->fft_buffer);
474 self->fft_buffer = NULL;
476 G_OBJECT_CLASS (parent_class)->dispose (object);
480 gst_audio_fx_base_fir_filter_set_property (GObject * object, guint prop_id,
481 const GValue * value, GParamSpec * pspec)
483 GstAudioFXBaseFIRFilter *self = GST_AUDIO_FX_BASE_FIR_FILTER (object);
486 case PROP_LOW_LATENCY:{
487 gboolean low_latency;
489 if (GST_STATE (self) >= GST_STATE_PAUSED) {
490 g_warning ("Changing the \"low-latency\" property "
491 "is only allowed in states < PAUSED");
495 GST_BASE_TRANSFORM_LOCK (self);
496 low_latency = g_value_get_boolean (value);
498 if (self->low_latency != low_latency) {
499 self->low_latency = low_latency;
500 gst_audio_fx_base_fir_filter_calculate_frequency_response (self);
501 gst_audio_fx_base_fir_filter_select_process_function (self,
502 GST_AUDIO_FILTER_FORMAT (self), GST_AUDIO_FILTER_CHANNELS (self));
504 GST_BASE_TRANSFORM_UNLOCK (self);
507 case PROP_DRAIN_ON_CHANGES:{
508 GST_BASE_TRANSFORM_LOCK (self);
509 self->drain_on_changes = g_value_get_boolean (value);
510 GST_BASE_TRANSFORM_UNLOCK (self);
514 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
520 gst_audio_fx_base_fir_filter_get_property (GObject * object, guint prop_id,
521 GValue * value, GParamSpec * pspec)
523 GstAudioFXBaseFIRFilter *self = GST_AUDIO_FX_BASE_FIR_FILTER (object);
526 case PROP_LOW_LATENCY:
527 g_value_set_boolean (value, self->low_latency);
529 case PROP_DRAIN_ON_CHANGES:
530 g_value_set_boolean (value, self->drain_on_changes);
533 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
539 gst_audio_fx_base_fir_filter_class_init (GstAudioFXBaseFIRFilterClass * klass)
541 GObjectClass *gobject_class = (GObjectClass *) klass;
542 GstBaseTransformClass *trans_class = (GstBaseTransformClass *) klass;
543 GstAudioFilterClass *filter_class = (GstAudioFilterClass *) klass;
546 GST_DEBUG_CATEGORY_INIT (gst_audio_fx_base_fir_filter_debug,
547 "audiofxbasefirfilter", 0, "FIR filter base class");
549 gobject_class->dispose = gst_audio_fx_base_fir_filter_dispose;
550 gobject_class->set_property = gst_audio_fx_base_fir_filter_set_property;
551 gobject_class->get_property = gst_audio_fx_base_fir_filter_get_property;
554 * GstAudioFXBaseFIRFilter::low-latency:
556 * Work in low-latency mode. This mode is much slower for large filter sizes
557 * but the latency is always only the pre-latency of the filter.
561 g_object_class_install_property (gobject_class, PROP_LOW_LATENCY,
562 g_param_spec_boolean ("low-latency", "Low latency",
563 "Operate in low latency mode. This mode is slower but the "
564 "latency will only be the filter pre-latency. "
565 "Can only be changed in states < PAUSED!", DEFAULT_LOW_LATENCY,
566 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
569 * GstAudioFXBaseFIRFilter::drain-on-changes:
571 * Whether the filter should be drained when its coeficients change
573 * Note: Currently this only works if the kernel size is not changed!
574 * Support for drainless kernel size changes will be added in the future.
578 g_object_class_install_property (gobject_class, PROP_DRAIN_ON_CHANGES,
579 g_param_spec_boolean ("drain-on-changes", "Drain on changes",
580 "Drains the filter when its coeficients change",
581 DEFAULT_DRAIN_ON_CHANGES,
582 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
584 caps = gst_caps_from_string (ALLOWED_CAPS);
585 gst_audio_filter_class_add_pad_templates (GST_AUDIO_FILTER_CLASS (klass),
587 gst_caps_unref (caps);
589 trans_class->transform =
590 GST_DEBUG_FUNCPTR (gst_audio_fx_base_fir_filter_transform);
591 trans_class->start = GST_DEBUG_FUNCPTR (gst_audio_fx_base_fir_filter_start);
592 trans_class->stop = GST_DEBUG_FUNCPTR (gst_audio_fx_base_fir_filter_stop);
593 trans_class->sink_event =
594 GST_DEBUG_FUNCPTR (gst_audio_fx_base_fir_filter_sink_event);
595 trans_class->transform_size =
596 GST_DEBUG_FUNCPTR (gst_audio_fx_base_fir_filter_transform_size);
597 filter_class->setup = GST_DEBUG_FUNCPTR (gst_audio_fx_base_fir_filter_setup);
601 gst_audio_fx_base_fir_filter_init (GstAudioFXBaseFIRFilter * self)
605 self->buffer_length = 0;
607 self->start_ts = GST_CLOCK_TIME_NONE;
608 self->start_off = GST_BUFFER_OFFSET_NONE;
609 self->nsamples_out = 0;
610 self->nsamples_in = 0;
612 self->low_latency = DEFAULT_LOW_LATENCY;
613 self->drain_on_changes = DEFAULT_DRAIN_ON_CHANGES;
615 gst_pad_set_query_function (GST_BASE_TRANSFORM (self)->srcpad,
616 gst_audio_fx_base_fir_filter_query);
620 gst_audio_fx_base_fir_filter_push_residue (GstAudioFXBaseFIRFilter * self)
624 gint rate = GST_AUDIO_FILTER_RATE (self);
625 gint channels = GST_AUDIO_FILTER_CHANNELS (self);
626 gint bps = GST_AUDIO_FILTER_BPS (self);
627 gint outsize, outsamples;
628 guint8 *in, *out, *data;
631 if (channels == 0 || rate == 0 || self->nsamples_in == 0) {
632 self->buffer_fill = 0;
633 g_free (self->buffer);
638 /* Calculate the number of samples and their memory size that
639 * should be pushed from the residue */
640 outsamples = self->nsamples_in - (self->nsamples_out - self->latency);
641 if (outsamples <= 0) {
642 self->buffer_fill = 0;
643 g_free (self->buffer);
647 outsize = outsamples * channels * bps;
649 if (!self->fft || self->low_latency) {
650 gint64 diffsize, diffsamples;
652 /* Process the difference between latency and residue length samples
653 * to start at the actual data instead of starting at the zeros before
654 * when we only got one buffer smaller than latency */
656 ((gint64) self->latency) - ((gint64) self->buffer_fill) / channels;
657 if (diffsamples > 0) {
658 diffsize = diffsamples * channels * bps;
659 in = g_new0 (guint8, diffsize);
660 out = g_new0 (guint8, diffsize);
661 self->nsamples_out += self->process (self, in, out, diffsamples);
666 outbuf = gst_buffer_new_and_alloc (outsize);
668 /* Convolve the residue with zeros to get the actual remaining data */
669 in = g_new0 (guint8, outsize);
670 data = gst_buffer_map (outbuf, &size, NULL, GST_MAP_READWRITE);
671 self->nsamples_out += self->process (self, in, data, outsamples);
672 gst_buffer_unmap (outbuf, data, size);
676 guint gensamples = 0;
678 outbuf = gst_buffer_new_and_alloc (outsize);
679 data = gst_buffer_map (outbuf, &size, NULL, GST_MAP_READWRITE);
681 while (gensamples < outsamples) {
682 guint step_insamples = self->block_length - self->buffer_fill;
683 guint8 *zeroes = g_new0 (guint8, step_insamples * channels * bps);
684 guint8 *out = g_new (guint8, self->block_length * channels * bps);
685 guint step_gensamples;
687 step_gensamples = self->process (self, zeroes, out, step_insamples);
690 memcpy (data + gensamples * bps, out, MIN (step_gensamples,
691 outsamples - gensamples) * bps);
692 gensamples += MIN (step_gensamples, outsamples - gensamples);
696 self->nsamples_out += gensamples;
698 gst_buffer_unmap (outbuf, data, size);
701 /* Set timestamp, offset, etc from the values we
702 * saved when processing the regular buffers */
703 if (GST_CLOCK_TIME_IS_VALID (self->start_ts))
704 GST_BUFFER_TIMESTAMP (outbuf) = self->start_ts;
706 GST_BUFFER_TIMESTAMP (outbuf) = 0;
707 GST_BUFFER_TIMESTAMP (outbuf) +=
708 gst_util_uint64_scale_int (self->nsamples_out - outsamples -
709 self->latency, GST_SECOND, rate);
711 GST_BUFFER_DURATION (outbuf) =
712 gst_util_uint64_scale_int (outsamples, GST_SECOND, rate);
714 if (self->start_off != GST_BUFFER_OFFSET_NONE) {
715 GST_BUFFER_OFFSET (outbuf) =
716 self->start_off + self->nsamples_out - outsamples - self->latency;
717 GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET (outbuf) + outsamples;
720 GST_DEBUG_OBJECT (self,
721 "Pushing residue buffer of size %" G_GSIZE_FORMAT " with timestamp: %"
722 GST_TIME_FORMAT ", duration: %" GST_TIME_FORMAT ", offset: %"
723 G_GUINT64_FORMAT ", offset_end: %" G_GUINT64_FORMAT ", nsamples_out: %d",
724 gst_buffer_get_size (outbuf),
725 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
726 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf),
727 GST_BUFFER_OFFSET_END (outbuf), outsamples);
729 res = gst_pad_push (GST_BASE_TRANSFORM_CAST (self)->srcpad, outbuf);
731 if (G_UNLIKELY (res != GST_FLOW_OK)) {
732 GST_WARNING_OBJECT (self, "failed to push residue");
735 self->buffer_fill = 0;
738 /* GstAudioFilter vmethod implementations */
740 /* get notified of caps and plug in the correct process function */
742 gst_audio_fx_base_fir_filter_setup (GstAudioFilter * base,
743 const GstAudioInfo * info)
745 GstAudioFXBaseFIRFilter *self = GST_AUDIO_FX_BASE_FIR_FILTER (base);
748 gst_audio_fx_base_fir_filter_push_residue (self);
749 g_free (self->buffer);
751 self->buffer_fill = 0;
752 self->buffer_length = 0;
753 self->start_ts = GST_CLOCK_TIME_NONE;
754 self->start_off = GST_BUFFER_OFFSET_NONE;
755 self->nsamples_out = 0;
756 self->nsamples_in = 0;
759 gst_audio_fx_base_fir_filter_select_process_function (self,
760 GST_AUDIO_INFO_FORMAT (info), GST_AUDIO_INFO_CHANNELS (info));
762 return (self->process != NULL);
765 /* GstBaseTransform vmethod implementations */
768 gst_audio_fx_base_fir_filter_transform_size (GstBaseTransform * base,
769 GstPadDirection direction, GstCaps * caps, gsize size, GstCaps * othercaps,
772 GstAudioFXBaseFIRFilter *self = GST_AUDIO_FX_BASE_FIR_FILTER (base);
777 if (!self->fft || self->low_latency || direction == GST_PAD_SRC) {
782 if (!gst_audio_info_from_caps (&info, caps))
785 bpf = GST_AUDIO_INFO_BPF (&info);
788 blocklen = self->block_length - self->kernel_length + 1;
789 *othersize = ((size + blocklen - 1) / blocklen) * blocklen;
796 gst_audio_fx_base_fir_filter_transform (GstBaseTransform * base,
797 GstBuffer * inbuf, GstBuffer * outbuf)
799 GstAudioFXBaseFIRFilter *self = GST_AUDIO_FX_BASE_FIR_FILTER (base);
800 GstClockTime timestamp, expected_timestamp;
801 gint channels = GST_AUDIO_FILTER_CHANNELS (self);
802 gint rate = GST_AUDIO_FILTER_RATE (self);
803 gint bps = GST_AUDIO_FILTER_BPS (self);
804 guint8 *indata, *outdata;
805 gsize insize, outsize;
807 guint output_samples;
808 guint generated_samples;
809 guint64 output_offset;
811 GstClockTime stream_time;
813 timestamp = GST_BUFFER_TIMESTAMP (outbuf);
815 if (!GST_CLOCK_TIME_IS_VALID (timestamp)
816 && !GST_CLOCK_TIME_IS_VALID (self->start_ts)) {
817 GST_ERROR_OBJECT (self, "Invalid timestamp");
818 return GST_FLOW_ERROR;
822 gst_segment_to_stream_time (&base->segment, GST_FORMAT_TIME, timestamp);
824 GST_DEBUG_OBJECT (self, "sync to %" GST_TIME_FORMAT,
825 GST_TIME_ARGS (timestamp));
827 if (GST_CLOCK_TIME_IS_VALID (stream_time))
828 gst_object_sync_values (GST_OBJECT (self), stream_time);
830 g_return_val_if_fail (self->kernel != NULL, GST_FLOW_ERROR);
831 g_return_val_if_fail (channels != 0, GST_FLOW_ERROR);
833 if (GST_CLOCK_TIME_IS_VALID (self->start_ts))
835 self->start_ts + gst_util_uint64_scale_int (self->nsamples_in,
838 expected_timestamp = GST_CLOCK_TIME_NONE;
840 /* Reset the residue if already existing on discont buffers */
841 if (GST_BUFFER_IS_DISCONT (inbuf)
842 || (GST_CLOCK_TIME_IS_VALID (expected_timestamp)
843 && (ABS (GST_CLOCK_DIFF (timestamp,
844 expected_timestamp) > 5 * GST_MSECOND)))) {
845 GST_DEBUG_OBJECT (self, "Discontinuity detected - flushing");
846 if (GST_CLOCK_TIME_IS_VALID (expected_timestamp))
847 gst_audio_fx_base_fir_filter_push_residue (self);
848 self->buffer_fill = 0;
849 g_free (self->buffer);
851 self->start_ts = timestamp;
852 self->start_off = GST_BUFFER_OFFSET (inbuf);
853 self->nsamples_out = 0;
854 self->nsamples_in = 0;
855 } else if (!GST_CLOCK_TIME_IS_VALID (self->start_ts)) {
856 self->start_ts = timestamp;
857 self->start_off = GST_BUFFER_OFFSET (inbuf);
860 indata = gst_buffer_map (inbuf, &insize, NULL, GST_MAP_READ);
861 outdata = gst_buffer_map (outbuf, &outsize, NULL, GST_MAP_WRITE);
863 input_samples = (insize / bps) / channels;
864 output_samples = (outsize / bps) / channels;
866 self->nsamples_in += input_samples;
868 generated_samples = self->process (self, indata, outdata, input_samples);
870 gst_buffer_unmap (inbuf, indata, insize);
871 gst_buffer_unmap (outbuf, outdata, outsize);
873 g_assert (generated_samples <= output_samples);
874 self->nsamples_out += generated_samples;
875 if (generated_samples == 0)
876 return GST_BASE_TRANSFORM_FLOW_DROPPED;
878 /* Calculate the number of samples we can push out now without outputting
879 * latency zeros in the beginning */
880 diff = ((gint64) self->nsamples_out) - ((gint64) self->latency);
882 return GST_BASE_TRANSFORM_FLOW_DROPPED;
883 } else if (diff < generated_samples) {
885 diff = generated_samples - diff;
886 generated_samples = tmp;
888 gst_buffer_resize (outbuf, diff * bps * channels,
889 generated_samples * bps * channels);
891 output_offset = self->nsamples_out - self->latency - generated_samples;
892 GST_BUFFER_TIMESTAMP (outbuf) =
893 self->start_ts + gst_util_uint64_scale_int (output_offset, GST_SECOND,
895 GST_BUFFER_DURATION (outbuf) =
896 gst_util_uint64_scale_int (output_samples, GST_SECOND, rate);
897 if (self->start_off != GST_BUFFER_OFFSET_NONE) {
898 GST_BUFFER_OFFSET (outbuf) = self->start_off + output_offset;
899 GST_BUFFER_OFFSET_END (outbuf) =
900 GST_BUFFER_OFFSET (outbuf) + generated_samples;
902 GST_BUFFER_OFFSET (outbuf) = GST_BUFFER_OFFSET_NONE;
903 GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET_NONE;
906 GST_DEBUG_OBJECT (self,
907 "Pushing buffer of size %" G_GSIZE_FORMAT " with timestamp: %"
908 GST_TIME_FORMAT ", duration: %" GST_TIME_FORMAT ", offset: %"
909 G_GUINT64_FORMAT ", offset_end: %" G_GUINT64_FORMAT ", nsamples_out: %d",
910 gst_buffer_get_size (outbuf),
911 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
912 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf),
913 GST_BUFFER_OFFSET_END (outbuf), generated_samples);
919 gst_audio_fx_base_fir_filter_start (GstBaseTransform * base)
921 GstAudioFXBaseFIRFilter *self = GST_AUDIO_FX_BASE_FIR_FILTER (base);
923 self->buffer_fill = 0;
924 g_free (self->buffer);
926 self->start_ts = GST_CLOCK_TIME_NONE;
927 self->start_off = GST_BUFFER_OFFSET_NONE;
928 self->nsamples_out = 0;
929 self->nsamples_in = 0;
935 gst_audio_fx_base_fir_filter_stop (GstBaseTransform * base)
937 GstAudioFXBaseFIRFilter *self = GST_AUDIO_FX_BASE_FIR_FILTER (base);
939 g_free (self->buffer);
941 self->buffer_length = 0;
947 gst_audio_fx_base_fir_filter_query (GstPad * pad, GstObject * parent,
950 GstAudioFXBaseFIRFilter *self = GST_AUDIO_FX_BASE_FIR_FILTER (parent);
953 switch (GST_QUERY_TYPE (query)) {
954 case GST_QUERY_LATENCY:
956 GstClockTime min, max;
959 gint rate = GST_AUDIO_FILTER_RATE (self);
964 gst_pad_peer_query (GST_BASE_TRANSFORM (self)->sinkpad, query))) {
965 gst_query_parse_latency (query, &live, &min, &max);
967 GST_DEBUG_OBJECT (self, "Peer latency: min %"
968 GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
969 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
971 if (self->fft && !self->low_latency)
972 latency = self->block_length - self->kernel_length + 1;
974 latency = self->latency;
976 /* add our own latency */
977 latency = gst_util_uint64_scale_round (latency, GST_SECOND, rate);
979 GST_DEBUG_OBJECT (self, "Our latency: %"
980 GST_TIME_FORMAT, GST_TIME_ARGS (latency));
983 if (max != GST_CLOCK_TIME_NONE)
986 GST_DEBUG_OBJECT (self, "Calculated total latency : min %"
987 GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
988 GST_TIME_ARGS (min), GST_TIME_ARGS (max));
990 gst_query_set_latency (query, live, min, max);
995 res = gst_pad_query_default (pad, parent, query);
1002 gst_audio_fx_base_fir_filter_sink_event (GstBaseTransform * base,
1005 GstAudioFXBaseFIRFilter *self = GST_AUDIO_FX_BASE_FIR_FILTER (base);
1007 switch (GST_EVENT_TYPE (event)) {
1009 gst_audio_fx_base_fir_filter_push_residue (self);
1010 self->start_ts = GST_CLOCK_TIME_NONE;
1011 self->start_off = GST_BUFFER_OFFSET_NONE;
1012 self->nsamples_out = 0;
1013 self->nsamples_in = 0;
1019 return GST_BASE_TRANSFORM_CLASS (parent_class)->sink_event (base, event);
1023 gst_audio_fx_base_fir_filter_set_kernel (GstAudioFXBaseFIRFilter * self,
1024 gdouble * kernel, guint kernel_length, guint64 latency)
1026 gboolean latency_changed;
1028 g_return_if_fail (kernel != NULL);
1029 g_return_if_fail (self != NULL);
1031 GST_BASE_TRANSFORM_LOCK (self);
1033 latency_changed = (self->latency != latency
1034 || (!self->low_latency && self->kernel_length < FFT_THRESHOLD
1035 && kernel_length >= FFT_THRESHOLD)
1036 || (!self->low_latency && self->kernel_length >= FFT_THRESHOLD
1037 && kernel_length < FFT_THRESHOLD));
1039 /* FIXME: If the latency changes, the buffer size changes too and we
1040 * have to drain in any case until this is fixed in the future */
1041 if (self->buffer && (!self->drain_on_changes || latency_changed)) {
1042 gst_audio_fx_base_fir_filter_push_residue (self);
1043 self->start_ts = GST_CLOCK_TIME_NONE;
1044 self->start_off = GST_BUFFER_OFFSET_NONE;
1045 self->nsamples_out = 0;
1046 self->nsamples_in = 0;
1047 self->buffer_fill = 0;
1050 g_free (self->kernel);
1051 if (!self->drain_on_changes || latency_changed) {
1052 g_free (self->buffer);
1053 self->buffer = NULL;
1054 self->buffer_fill = 0;
1055 self->buffer_length = 0;
1058 self->kernel = kernel;
1059 self->kernel_length = kernel_length;
1061 gst_audio_fx_base_fir_filter_calculate_frequency_response (self);
1062 gst_audio_fx_base_fir_filter_select_process_function (self,
1063 GST_AUDIO_FILTER_FORMAT (self), GST_AUDIO_FILTER_CHANNELS (self));
1065 if (latency_changed) {
1066 self->latency = latency;
1067 gst_element_post_message (GST_ELEMENT (self),
1068 gst_message_new_latency (GST_OBJECT (self)));
1071 GST_BASE_TRANSFORM_UNLOCK (self);