gst_plugins_good/gst/audiofx/audiofxbaseiirfilter.c
changeset 26 69c7080681bf
parent 24 bc39b352897e
child 28 4ed5253bb6ba
equal deleted inserted replaced
24:bc39b352897e 26:69c7080681bf
     1 /* 
       
     2  * GStreamer
       
     3  * Copyright (C) 2007-2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
       
     4  *
       
     5  * This library is free software; you can redistribute it and/or
       
     6  * modify it under the terms of the GNU Library General Public
       
     7  * License as published by the Free Software Foundation; either
       
     8  * version 2 of the License, or (at your option) any later version.
       
     9  *
       
    10  * This library is distributed in the hope that it will be useful,
       
    11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    13  * Library General Public License for more details.
       
    14  *
       
    15  * You should have received a copy of the GNU Library General Public
       
    16  * License along with this library; if not, write to the
       
    17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
       
    18  * Boston, MA 02111-1307, USA.
       
    19  */
       
    20 
       
    21 #ifdef HAVE_CONFIG_H
       
    22 #include "config.h"
       
    23 #endif
       
    24 
       
    25 #include <gst/gst.h>
       
    26 #include <gst/base/gstbasetransform.h>
       
    27 #include <gst/audio/audio.h>
       
    28 #include <gst/audio/gstaudiofilter.h>
       
    29 #include <gst/controller/gstcontroller.h>
       
    30 
       
    31 #include <math.h>
       
    32 
       
    33 #include "audiofxbaseiirfilter.h"
       
    34 
       
    35 #define GST_CAT_DEFAULT gst_audio_fx_base_iir_filter_debug
       
    36 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
       
    37 
       
    38 #define ALLOWED_CAPS \
       
    39     "audio/x-raw-float,"                                              \
       
    40     " width = (int) { 32, 64 }, "                                     \
       
    41     " endianness = (int) BYTE_ORDER,"                                 \
       
    42     " rate = (int) [ 1, MAX ],"                                       \
       
    43     " channels = (int) [ 1, MAX ]"
       
    44 
       
    45 #define DEBUG_INIT(bla) \
       
    46   GST_DEBUG_CATEGORY_INIT (gst_audio_fx_base_iir_filter_debug, "audiofxbaseiirfilter", 0, "Audio IIR Filter Base Class");
       
    47 
       
    48 GST_BOILERPLATE_FULL (GstAudioFXBaseIIRFilter,
       
    49     gst_audio_fx_base_iir_filter, GstAudioFilter, GST_TYPE_AUDIO_FILTER,
       
    50     DEBUG_INIT);
       
    51 
       
    52 static gboolean gst_audio_fx_base_iir_filter_setup (GstAudioFilter * filter,
       
    53     GstRingBufferSpec * format);
       
    54 static GstFlowReturn
       
    55 gst_audio_fx_base_iir_filter_transform_ip (GstBaseTransform * base,
       
    56     GstBuffer * buf);
       
    57 static gboolean gst_audio_fx_base_iir_filter_stop (GstBaseTransform * base);
       
    58 
       
    59 static void process_64 (GstAudioFXBaseIIRFilter * filter,
       
    60     gdouble * data, guint num_samples);
       
    61 static void process_32 (GstAudioFXBaseIIRFilter * filter,
       
    62     gfloat * data, guint num_samples);
       
    63 
       
    64 /* GObject vmethod implementations */
       
    65 
       
    66 static void
       
    67 gst_audio_fx_base_iir_filter_base_init (gpointer klass)
       
    68 {
       
    69   GstCaps *caps;
       
    70 
       
    71   caps = gst_caps_from_string (ALLOWED_CAPS);
       
    72   gst_audio_filter_class_add_pad_templates (GST_AUDIO_FILTER_CLASS (klass),
       
    73       caps);
       
    74   gst_caps_unref (caps);
       
    75 }
       
    76 
       
    77 static void
       
    78 gst_audio_fx_base_iir_filter_dispose (GObject * object)
       
    79 {
       
    80   GstAudioFXBaseIIRFilter *filter = GST_AUDIO_FX_BASE_IIR_FILTER (object);
       
    81 
       
    82   if (filter->a) {
       
    83     g_free (filter->a);
       
    84     filter->a = NULL;
       
    85   }
       
    86 
       
    87   if (filter->b) {
       
    88     g_free (filter->b);
       
    89     filter->b = NULL;
       
    90   }
       
    91 
       
    92   if (filter->channels) {
       
    93     GstAudioFXBaseIIRFilterChannelCtx *ctx;
       
    94     guint i;
       
    95 
       
    96     for (i = 0; i < filter->nchannels; i++) {
       
    97       ctx = &filter->channels[i];
       
    98       g_free (ctx->x);
       
    99       g_free (ctx->y);
       
   100     }
       
   101 
       
   102     g_free (filter->channels);
       
   103     filter->channels = NULL;
       
   104   }
       
   105 
       
   106   G_OBJECT_CLASS (parent_class)->dispose (object);
       
   107 }
       
   108 
       
   109 static void
       
   110 gst_audio_fx_base_iir_filter_class_init (GstAudioFXBaseIIRFilterClass * klass)
       
   111 {
       
   112   GObjectClass *gobject_class = (GObjectClass *) klass;
       
   113   GstBaseTransformClass *trans_class = (GstBaseTransformClass *) klass;
       
   114   GstAudioFilterClass *filter_class = (GstAudioFilterClass *) klass;
       
   115 
       
   116   gobject_class->dispose = gst_audio_fx_base_iir_filter_dispose;
       
   117 
       
   118   filter_class->setup = GST_DEBUG_FUNCPTR (gst_audio_fx_base_iir_filter_setup);
       
   119 
       
   120   trans_class->transform_ip =
       
   121       GST_DEBUG_FUNCPTR (gst_audio_fx_base_iir_filter_transform_ip);
       
   122   trans_class->stop = GST_DEBUG_FUNCPTR (gst_audio_fx_base_iir_filter_stop);
       
   123 }
       
   124 
       
   125 static void
       
   126 gst_audio_fx_base_iir_filter_init (GstAudioFXBaseIIRFilter * filter,
       
   127     GstAudioFXBaseIIRFilterClass * klass)
       
   128 {
       
   129   gst_base_transform_set_in_place (GST_BASE_TRANSFORM (filter), TRUE);
       
   130 
       
   131   filter->a = NULL;
       
   132   filter->na = 0;
       
   133   filter->b = NULL;
       
   134   filter->nb = 0;
       
   135   filter->channels = NULL;
       
   136   filter->nchannels = 0;
       
   137 }
       
   138 
       
   139 /* Evaluate the transfer function that corresponds to the IIR
       
   140  * coefficients at zr + zi*I and return the magnitude */
       
   141 gdouble
       
   142 gst_audio_fx_base_iir_filter_calculate_gain (gdouble * a, guint na, gdouble * b,
       
   143     guint nb, gdouble zr, gdouble zi)
       
   144 {
       
   145   gdouble sum_ar, sum_ai;
       
   146   gdouble sum_br, sum_bi;
       
   147   gdouble gain_r, gain_i;
       
   148 
       
   149   gdouble sum_r_old;
       
   150   gdouble sum_i_old;
       
   151 
       
   152   gint i;
       
   153 
       
   154   sum_ar = 0.0;
       
   155   sum_ai = 0.0;
       
   156   for (i = na - 1; i >= 0; i--) {
       
   157     sum_r_old = sum_ar;
       
   158     sum_i_old = sum_ai;
       
   159 
       
   160     sum_ar = (sum_r_old * zr - sum_i_old * zi) + a[i];
       
   161     sum_ai = (sum_r_old * zi + sum_i_old * zr) + 0.0;
       
   162   }
       
   163 
       
   164   sum_br = 0.0;
       
   165   sum_bi = 0.0;
       
   166   for (i = nb - 1; i >= 0; i--) {
       
   167     sum_r_old = sum_br;
       
   168     sum_i_old = sum_bi;
       
   169 
       
   170     sum_br = (sum_r_old * zr - sum_i_old * zi) - b[i];
       
   171     sum_bi = (sum_r_old * zi + sum_i_old * zr) - 0.0;
       
   172   }
       
   173   sum_br += 1.0;
       
   174   sum_bi += 0.0;
       
   175 
       
   176   gain_r =
       
   177       (sum_ar * sum_br + sum_ai * sum_bi) / (sum_br * sum_br + sum_bi * sum_bi);
       
   178   gain_i =
       
   179       (sum_ai * sum_br - sum_ar * sum_bi) / (sum_br * sum_br + sum_bi * sum_bi);
       
   180 
       
   181   return (sqrt (gain_r * gain_r + gain_i * gain_i));
       
   182 }
       
   183 
       
   184 void
       
   185 gst_audio_fx_base_iir_filter_set_coefficients (GstAudioFXBaseIIRFilter * filter,
       
   186     gdouble * a, guint na, gdouble * b, guint nb)
       
   187 {
       
   188   guint i;
       
   189 
       
   190   g_return_if_fail (GST_IS_AUDIO_FX_BASE_IIR_FILTER (filter));
       
   191 
       
   192   GST_BASE_TRANSFORM_LOCK (filter);
       
   193 
       
   194   g_free (filter->a);
       
   195   g_free (filter->b);
       
   196 
       
   197   filter->a = filter->b = NULL;
       
   198 
       
   199   if (filter->channels) {
       
   200     GstAudioFXBaseIIRFilterChannelCtx *ctx;
       
   201     gboolean free = (na != filter->na || nb != filter->nb);
       
   202 
       
   203     for (i = 0; i < filter->nchannels; i++) {
       
   204       ctx = &filter->channels[i];
       
   205 
       
   206       if (free)
       
   207         g_free (ctx->x);
       
   208       else
       
   209         memset (ctx->x, 0, filter->na * sizeof (gdouble));
       
   210 
       
   211       if (free)
       
   212         g_free (ctx->y);
       
   213       else
       
   214         memset (ctx->y, 0, filter->nb * sizeof (gdouble));
       
   215     }
       
   216 
       
   217     g_free (filter->channels);
       
   218     filter->channels = NULL;
       
   219   }
       
   220 
       
   221   filter->na = na;
       
   222   filter->nb = nb;
       
   223 
       
   224   filter->a = a;
       
   225   filter->b = b;
       
   226 
       
   227   if (filter->nchannels && !filter->channels) {
       
   228     GstAudioFXBaseIIRFilterChannelCtx *ctx;
       
   229 
       
   230     filter->channels =
       
   231         g_new0 (GstAudioFXBaseIIRFilterChannelCtx, filter->nchannels);
       
   232     for (i = 0; i < filter->nchannels; i++) {
       
   233       ctx = &filter->channels[i];
       
   234 
       
   235       ctx->x = g_new0 (gdouble, filter->na);
       
   236       ctx->y = g_new0 (gdouble, filter->nb);
       
   237     }
       
   238   }
       
   239 
       
   240   GST_BASE_TRANSFORM_UNLOCK (filter);
       
   241 }
       
   242 
       
   243 /* GstAudioFilter vmethod implementations */
       
   244 
       
   245 static gboolean
       
   246 gst_audio_fx_base_iir_filter_setup (GstAudioFilter * base,
       
   247     GstRingBufferSpec * format)
       
   248 {
       
   249   GstAudioFXBaseIIRFilter *filter = GST_AUDIO_FX_BASE_IIR_FILTER (base);
       
   250   gboolean ret = TRUE;
       
   251 
       
   252   if (format->width == 32)
       
   253     filter->process = (GstAudioFXBaseIIRFilterProcessFunc)
       
   254         process_32;
       
   255   else if (format->width == 64)
       
   256     filter->process = (GstAudioFXBaseIIRFilterProcessFunc)
       
   257         process_64;
       
   258   else
       
   259     ret = FALSE;
       
   260 
       
   261   if (format->channels != filter->nchannels) {
       
   262     guint i;
       
   263     GstAudioFXBaseIIRFilterChannelCtx *ctx;
       
   264 
       
   265     if (filter->channels) {
       
   266 
       
   267       for (i = 0; i < filter->nchannels; i++) {
       
   268         ctx = &filter->channels[i];
       
   269 
       
   270         g_free (ctx->x);
       
   271         g_free (ctx->y);
       
   272       }
       
   273 
       
   274       g_free (filter->channels);
       
   275       filter->channels = NULL;
       
   276     }
       
   277 
       
   278     filter->nchannels = format->channels;
       
   279 
       
   280     filter->channels =
       
   281         g_new0 (GstAudioFXBaseIIRFilterChannelCtx, filter->nchannels);
       
   282     for (i = 0; i < filter->nchannels; i++) {
       
   283       ctx = &filter->channels[i];
       
   284 
       
   285       ctx->x = g_new0 (gdouble, filter->na);
       
   286       ctx->y = g_new0 (gdouble, filter->nb);
       
   287     }
       
   288   }
       
   289 
       
   290   return ret;
       
   291 }
       
   292 
       
   293 static inline gdouble
       
   294 process (GstAudioFXBaseIIRFilter * filter,
       
   295     GstAudioFXBaseIIRFilterChannelCtx * ctx, gdouble x0)
       
   296 {
       
   297   gdouble val = filter->a[0] * x0;
       
   298   gint i, j;
       
   299 
       
   300   for (i = 1, j = ctx->x_pos; i < filter->na; i++) {
       
   301     val += filter->a[i] * ctx->x[j];
       
   302     j--;
       
   303     if (j < 0)
       
   304       j = filter->na - 1;
       
   305   }
       
   306 
       
   307   for (i = 1, j = ctx->y_pos; i < filter->nb; i++) {
       
   308     val += filter->b[i] * ctx->y[j];
       
   309     j--;
       
   310     if (j < 0)
       
   311       j = filter->nb - 1;
       
   312   }
       
   313 
       
   314   if (ctx->x) {
       
   315     ctx->x_pos++;
       
   316     if (ctx->x_pos >= filter->na)
       
   317       ctx->x_pos = 0;
       
   318     ctx->x[ctx->x_pos] = x0;
       
   319   }
       
   320   if (ctx->y) {
       
   321     ctx->y_pos++;
       
   322     if (ctx->y_pos >= filter->nb)
       
   323       ctx->y_pos = 0;
       
   324 
       
   325     ctx->y[ctx->y_pos] = val;
       
   326   }
       
   327 
       
   328   return val;
       
   329 }
       
   330 
       
   331 #define DEFINE_PROCESS_FUNC(width,ctype) \
       
   332 static void \
       
   333 process_##width (GstAudioFXBaseIIRFilter * filter, \
       
   334     g##ctype * data, guint num_samples) \
       
   335 { \
       
   336   gint i, j, channels = GST_AUDIO_FILTER (filter)->format.channels; \
       
   337   gdouble val; \
       
   338   \
       
   339   for (i = 0; i < num_samples / channels; i++) { \
       
   340     for (j = 0; j < channels; j++) { \
       
   341       val = process (filter, &filter->channels[j], *data); \
       
   342       *data++ = val; \
       
   343     } \
       
   344   } \
       
   345 }
       
   346 
       
   347 DEFINE_PROCESS_FUNC (32, float);
       
   348 DEFINE_PROCESS_FUNC (64, double);
       
   349 
       
   350 #undef DEFINE_PROCESS_FUNC
       
   351 
       
   352 /* GstBaseTransform vmethod implementations */
       
   353 static GstFlowReturn
       
   354 gst_audio_fx_base_iir_filter_transform_ip (GstBaseTransform * base,
       
   355     GstBuffer * buf)
       
   356 {
       
   357   GstAudioFXBaseIIRFilter *filter = GST_AUDIO_FX_BASE_IIR_FILTER (base);
       
   358   guint num_samples =
       
   359       GST_BUFFER_SIZE (buf) / (GST_AUDIO_FILTER (filter)->format.width / 8);
       
   360 
       
   361   if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buf)))
       
   362     gst_object_sync_values (G_OBJECT (filter), GST_BUFFER_TIMESTAMP (buf));
       
   363 
       
   364   if (gst_base_transform_is_passthrough (base))
       
   365     return GST_FLOW_OK;
       
   366 
       
   367   g_return_val_if_fail (filter->a != NULL, GST_FLOW_ERROR);
       
   368 
       
   369   filter->process (filter, GST_BUFFER_DATA (buf), num_samples);
       
   370 
       
   371   return GST_FLOW_OK;
       
   372 }
       
   373 
       
   374 
       
   375 static gboolean
       
   376 gst_audio_fx_base_iir_filter_stop (GstBaseTransform * base)
       
   377 {
       
   378   GstAudioFXBaseIIRFilter *filter = GST_AUDIO_FX_BASE_IIR_FILTER (base);
       
   379   guint channels = GST_AUDIO_FILTER (filter)->format.channels;
       
   380   GstAudioFXBaseIIRFilterChannelCtx *ctx;
       
   381   guint i;
       
   382 
       
   383   /* Reset the history of input and output values if
       
   384    * already existing */
       
   385   if (channels && filter->channels) {
       
   386     for (i = 0; i < channels; i++) {
       
   387       ctx = &filter->channels[i];
       
   388       g_free (ctx->x);
       
   389       g_free (ctx->y);
       
   390     }
       
   391     g_free (filter->channels);
       
   392   }
       
   393   filter->channels = NULL;
       
   394 
       
   395   return TRUE;
       
   396 }