"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 }