gst_plugins_good/gst/audiofx/audiofirfilter.c
changeset 27 d43ce56a1534
parent 23 29ecd5cb86b3
child 31 aec498aab1d3
equal deleted inserted replaced
23:29ecd5cb86b3 27:d43ce56a1534
     1 /* 
       
     2  * GStreamer
       
     3  * Copyright (C) 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 
       
    22 /**
       
    23  * SECTION:element-audiofirfilter
       
    24  *
       
    25  * audiofirfilter implements a generic audio <ulink url="http://en.wikipedia.org/wiki/Finite_impulse_response">FIR filter</ulink>. Before usage the
       
    26  * "kernel" property has to be set to the filter kernel that should be
       
    27  * used and the "latency" property has to be set to the latency (in samples)
       
    28  * that is introduced by the filter kernel. Setting a latency of n samples
       
    29  * will lead to the first n samples being dropped from the output and
       
    30  * n samples added to the end.
       
    31  *
       
    32  * The filter kernel describes the impulse response of the filter. To
       
    33  * calculate the frequency response of the filter you have to calculate
       
    34  * the Fourier Transform of the impulse response.
       
    35  *
       
    36  * To change the filter kernel whenever the sampling rate changes the
       
    37  * "rate-changed" signal can be used. This should be done for most
       
    38  * FIR filters as they're depending on the sampling rate.
       
    39  *
       
    40  * <refsect2>
       
    41  * <title>Example application</title>
       
    42  * |[
       
    43  * <xi:include xmlns:xi="http://www.w3.org/2003/XInclude" parse="text" href="../../../../tests/examples/audiofx/firfilter-example.c" />
       
    44  * ]|
       
    45  * </refsect2>
       
    46  */
       
    47 
       
    48 #ifdef HAVE_CONFIG_H
       
    49 #include "config.h"
       
    50 #endif
       
    51 
       
    52 #include <string.h>
       
    53 #include <math.h>
       
    54 #include <gst/gst.h>
       
    55 #include <gst/audio/gstaudiofilter.h>
       
    56 #include <gst/controller/gstcontroller.h>
       
    57 
       
    58 #include "audiofirfilter.h"
       
    59 
       
    60 #define GST_CAT_DEFAULT gst_audio_fir_filter_debug
       
    61 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
       
    62 
       
    63 enum
       
    64 {
       
    65   SIGNAL_RATE_CHANGED,
       
    66   LAST_SIGNAL
       
    67 };
       
    68 
       
    69 enum
       
    70 {
       
    71   PROP_0,
       
    72   PROP_KERNEL,
       
    73   PROP_LATENCY
       
    74 };
       
    75 
       
    76 static guint gst_audio_fir_filter_signals[LAST_SIGNAL] = { 0, };
       
    77 
       
    78 #define DEBUG_INIT(bla) \
       
    79   GST_DEBUG_CATEGORY_INIT (gst_audio_fir_filter_debug, "audiofirfilter", 0, \
       
    80       "Generic audio FIR filter plugin");
       
    81 
       
    82 GST_BOILERPLATE_FULL (GstAudioFIRFilter, gst_audio_fir_filter, GstAudioFilter,
       
    83     GST_TYPE_AUDIO_FX_BASE_FIR_FILTER, DEBUG_INIT);
       
    84 
       
    85 static void gst_audio_fir_filter_set_property (GObject * object, guint prop_id,
       
    86     const GValue * value, GParamSpec * pspec);
       
    87 static void gst_audio_fir_filter_get_property (GObject * object, guint prop_id,
       
    88     GValue * value, GParamSpec * pspec);
       
    89 static void gst_audio_fir_filter_finalize (GObject * object);
       
    90 
       
    91 static gboolean gst_audio_fir_filter_setup (GstAudioFilter * base,
       
    92     GstRingBufferSpec * format);
       
    93 
       
    94 /* Element class */
       
    95 static void
       
    96 gst_audio_fir_filter_base_init (gpointer g_class)
       
    97 {
       
    98   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
       
    99 
       
   100   gst_element_class_set_details_simple (element_class,
       
   101       "Audio FIR filter", "Filter/Effect/Audio",
       
   102       "Generic audio FIR filter with custom filter kernel",
       
   103       "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
       
   104 }
       
   105 
       
   106 static void
       
   107 gst_audio_fir_filter_class_init (GstAudioFIRFilterClass * klass)
       
   108 {
       
   109   GObjectClass *gobject_class = (GObjectClass *) klass;
       
   110   GstAudioFilterClass *filter_class = (GstAudioFilterClass *) klass;
       
   111 
       
   112   gobject_class->set_property = gst_audio_fir_filter_set_property;
       
   113   gobject_class->get_property = gst_audio_fir_filter_get_property;
       
   114   gobject_class->finalize = gst_audio_fir_filter_finalize;
       
   115 
       
   116   g_object_class_install_property (gobject_class, PROP_KERNEL,
       
   117       g_param_spec_value_array ("kernel", "Filter Kernel",
       
   118           "Filter kernel for the FIR filter",
       
   119           g_param_spec_double ("Element", "Filter Kernel Element",
       
   120               "Element of the filter kernel", -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
       
   121               G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS),
       
   122           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
       
   123   g_object_class_install_property (gobject_class, PROP_LATENCY,
       
   124       g_param_spec_uint64 ("latency", "Latecy",
       
   125           "Filter latency in samples",
       
   126           0, G_MAXUINT64, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
       
   127 
       
   128   filter_class->setup = GST_DEBUG_FUNCPTR (gst_audio_fir_filter_setup);
       
   129 
       
   130   /**
       
   131    * GstAudioFIRFilter::rate-changed:
       
   132    * @filter: the filter on which the signal is emitted
       
   133    * @rate: the new sampling rate
       
   134    *
       
   135    * Will be emitted when the sampling rate changes. The callbacks
       
   136    * will be called from the streaming thread and processing will
       
   137    * stop until the event is handled.
       
   138    */
       
   139   gst_audio_fir_filter_signals[SIGNAL_RATE_CHANGED] =
       
   140       g_signal_new ("rate-changed", G_TYPE_FROM_CLASS (klass),
       
   141       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstAudioFIRFilterClass, rate_changed),
       
   142       NULL, NULL, gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
       
   143 }
       
   144 
       
   145 static void
       
   146 gst_audio_fir_filter_update_kernel (GstAudioFIRFilter * self, GValueArray * va)
       
   147 {
       
   148   gdouble *kernel;
       
   149   guint i;
       
   150 
       
   151   gst_audio_fx_base_fir_filter_push_residue (GST_AUDIO_FX_BASE_FIR_FILTER
       
   152       (self));
       
   153 
       
   154   if (va) {
       
   155     if (self->kernel)
       
   156       g_value_array_free (self->kernel);
       
   157 
       
   158     self->kernel = va;
       
   159   }
       
   160 
       
   161   kernel = g_new (gdouble, self->kernel->n_values);
       
   162 
       
   163   for (i = 0; i < self->kernel->n_values; i++) {
       
   164     GValue *v = g_value_array_get_nth (self->kernel, i);
       
   165     kernel[i] = g_value_get_double (v);
       
   166   }
       
   167 
       
   168   gst_audio_fx_base_fir_filter_set_kernel (GST_AUDIO_FX_BASE_FIR_FILTER (self),
       
   169       kernel, self->kernel->n_values, self->latency);
       
   170 }
       
   171 
       
   172 static void
       
   173 gst_audio_fir_filter_init (GstAudioFIRFilter * self,
       
   174     GstAudioFIRFilterClass * g_class)
       
   175 {
       
   176   GValue v = { 0, };
       
   177   GValueArray *va;
       
   178 
       
   179   self->latency = 0;
       
   180   va = g_value_array_new (1);
       
   181 
       
   182   g_value_init (&v, G_TYPE_DOUBLE);
       
   183   g_value_set_double (&v, 1.0);
       
   184   g_value_array_append (va, &v);
       
   185   g_value_unset (&v);
       
   186   gst_audio_fir_filter_update_kernel (self, va);
       
   187 
       
   188   self->lock = g_mutex_new ();
       
   189 }
       
   190 
       
   191 /* GstAudioFilter vmethod implementations */
       
   192 
       
   193 /* get notified of caps and plug in the correct process function */
       
   194 static gboolean
       
   195 gst_audio_fir_filter_setup (GstAudioFilter * base, GstRingBufferSpec * format)
       
   196 {
       
   197   GstAudioFIRFilter *self = GST_AUDIO_FIR_FILTER (base);
       
   198 
       
   199   if (self->rate != format->rate) {
       
   200     g_signal_emit (G_OBJECT (self),
       
   201         gst_audio_fir_filter_signals[SIGNAL_RATE_CHANGED], 0, format->rate);
       
   202     self->rate = format->rate;
       
   203   }
       
   204 
       
   205   return GST_AUDIO_FILTER_CLASS (parent_class)->setup (base, format);
       
   206 }
       
   207 
       
   208 static void
       
   209 gst_audio_fir_filter_finalize (GObject * object)
       
   210 {
       
   211   GstAudioFIRFilter *self = GST_AUDIO_FIR_FILTER (object);
       
   212 
       
   213   g_mutex_free (self->lock);
       
   214   self->lock = NULL;
       
   215 
       
   216   if (self->kernel)
       
   217     g_value_array_free (self->kernel);
       
   218   self->kernel = NULL;
       
   219 
       
   220   G_OBJECT_CLASS (parent_class)->finalize (object);
       
   221 }
       
   222 
       
   223 static void
       
   224 gst_audio_fir_filter_set_property (GObject * object, guint prop_id,
       
   225     const GValue * value, GParamSpec * pspec)
       
   226 {
       
   227   GstAudioFIRFilter *self = GST_AUDIO_FIR_FILTER (object);
       
   228 
       
   229   g_return_if_fail (GST_IS_AUDIO_FIR_FILTER (self));
       
   230 
       
   231   switch (prop_id) {
       
   232     case PROP_KERNEL:
       
   233       g_mutex_lock (self->lock);
       
   234       gst_audio_fx_base_fir_filter_push_residue (GST_AUDIO_FX_BASE_FIR_FILTER
       
   235           (self));
       
   236 
       
   237       gst_audio_fir_filter_update_kernel (self, g_value_dup_boxed (value));
       
   238       g_mutex_unlock (self->lock);
       
   239       break;
       
   240     case PROP_LATENCY:
       
   241       g_mutex_lock (self->lock);
       
   242       self->latency = g_value_get_uint64 (value);
       
   243       gst_audio_fir_filter_update_kernel (self, NULL);
       
   244       g_mutex_unlock (self->lock);
       
   245       break;
       
   246     default:
       
   247       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       
   248       break;
       
   249   }
       
   250 }
       
   251 
       
   252 static void
       
   253 gst_audio_fir_filter_get_property (GObject * object, guint prop_id,
       
   254     GValue * value, GParamSpec * pspec)
       
   255 {
       
   256   GstAudioFIRFilter *self = GST_AUDIO_FIR_FILTER (object);
       
   257 
       
   258   switch (prop_id) {
       
   259     case PROP_KERNEL:
       
   260       g_value_set_boxed (value, self->kernel);
       
   261       break;
       
   262     case PROP_LATENCY:
       
   263       g_value_set_uint64 (value, self->latency);
       
   264       break;
       
   265     default:
       
   266       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       
   267       break;
       
   268   }
       
   269 }