audioresample: sinc filter performance improvements
authorCarlos Rafael Giani <dv@pseudoterminal.org>
Sun, 7 Oct 2012 01:00:52 +0000 (03:00 +0200)
committerSebastian Dröge <sebastian.droege@collabora.co.uk>
Thu, 25 Oct 2012 12:03:52 +0000 (14:03 +0200)
Original idea comes from Jyri Sarha
( http://lists.xiph.org/pipermail/speex-dev/2011-September/008243.html ).
Patch was discovered by Branislav Katreniak
( branislav.katreniak@streamunlimited.com ) for StreamUnlimited
( http://streamunlimited.com/ ). Tests showed up to 5x speed increase in
the resampler in the 44.1<->48kHz case.
I added the sinc-filter-mode and sinc-filter-auto-threshold properties
and the auto mode threshold tests, and adapted the code to GStreamer 1.0.

Signed-off-by: Carlos Rafael Giani <dv@pseudoterminal.org>
gst/audioresample/gstaudioresample.c
gst/audioresample/gstaudioresample.h
gst/audioresample/resample.c
gst/audioresample/speex_resampler.h
gst/audioresample/speex_resampler_wrapper.h

index fa73ec1..0a1bdb0 100644 (file)
  * audioresample resamples raw audio buffers to different sample rates using
  * a configurable windowing function to enhance quality.
  *
+ * By default, the resampler uses a reduced sinc table, with cubic interpolation filling in
+ * the gaps. This ensures that the table does not become too big. However, the interpolation
+ * increases the CPU usage considerably. As an alternative, a full sinc table can be used.
+ * Doing so can drastically reduce CPU usage (4x faster with 44.1 -> 48 kHz conversions for
+ * example), at the cost of increased memory consumption, plus the sinc table takes longer
+ * to initialize when the element is created. A third mode exists, which uses the full table
+ * unless said table would become too large, in which case the interpolated one is used instead.
+ *
  * <refsect2>
  * <title>Example launch line</title>
  * |[
@@ -62,10 +70,14 @@ GST_DEBUG_CATEGORY (audio_resample_debug);
 GST_DEBUG_CATEGORY_STATIC (GST_CAT_PERFORMANCE);
 #endif
 
+#define GST_TYPE_SPEEX_RESAMPLER_SINC_FILTER_MODE (speex_resampler_sinc_filter_mode_get_type ())
+
 enum
 {
   PROP_0,
-  PROP_QUALITY
+  PROP_QUALITY,
+  PROP_SINC_FILTER_MODE,
+  PROP_SINC_FILTER_AUTO_THRESHOLD
 };
 
 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
@@ -104,6 +116,9 @@ static void gst_audio_resample_set_property (GObject * object,
 static void gst_audio_resample_get_property (GObject * object,
     guint prop_id, GValue * value, GParamSpec * pspec);
 
+static GType
+speex_resampler_sinc_filter_mode_get_type (void);
+
 /* vmethods */
 static gboolean gst_audio_resample_get_unit_size (GstBaseTransform * base,
     GstCaps * caps, gsize * size);
@@ -144,6 +159,20 @@ gst_audio_resample_class_init (GstAudioResampleClass * klass)
           SPEEX_RESAMPLER_QUALITY_DEFAULT,
           G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
 
+  g_object_class_install_property (gobject_class, PROP_SINC_FILTER_MODE,
+      g_param_spec_enum ("sinc-filter-mode", "Sinc filter table mode",
+          "What sinc filter table mode to use",
+          GST_TYPE_SPEEX_RESAMPLER_SINC_FILTER_MODE,
+          SPEEX_RESAMPLER_SINC_FILTER_DEFAULT,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_SINC_FILTER_AUTO_THRESHOLD,
+      g_param_spec_uint ("sinc-filter-auto-threshold", "Sinc filter auto mode threshold",
+          "Memory usage threshold to use if sinc filter mode is AUTO, given in bytes",
+          0, G_MAXUINT,
+          SPEEX_RESAMPLER_SINC_FILTER_AUTO_THRESHOLD_DEFAULT,
+           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
   gst_element_class_add_pad_template (gstelement_class,
       gst_static_pad_template_get (&gst_audio_resample_src_template));
   gst_element_class_add_pad_template (gstelement_class,
@@ -181,6 +210,8 @@ gst_audio_resample_init (GstAudioResample * resample)
   GstBaseTransform *trans = GST_BASE_TRANSFORM (resample);
 
   resample->quality = SPEEX_RESAMPLER_QUALITY_DEFAULT;
+  resample->sinc_filter_mode = SPEEX_RESAMPLER_SINC_FILTER_DEFAULT;
+  resample->sinc_filter_auto_threshold = SPEEX_RESAMPLER_SINC_FILTER_AUTO_THRESHOLD_DEFAULT;
 
   gst_base_transform_set_gap_aware (trans, TRUE);
   gst_pad_set_query_function (trans->srcpad, gst_audio_resample_query);
@@ -349,13 +380,16 @@ gst_audio_resample_get_funcs (gint width, gboolean fp)
 
 static SpeexResamplerState *
 gst_audio_resample_init_state (GstAudioResample * resample, gint width,
-    gint channels, gint inrate, gint outrate, gint quality, gboolean fp)
+    gint channels, gint inrate, gint outrate, gint quality, gboolean fp,
+    SpeexResamplerSincFilterMode sinc_filter_mode,
+    guint32 sinc_filter_auto_threshold)
 {
   SpeexResamplerState *ret = NULL;
   gint err = RESAMPLER_ERR_SUCCESS;
   const SpeexResampleFuncs *funcs = gst_audio_resample_get_funcs (width, fp);
 
-  ret = funcs->init (channels, inrate, outrate, quality, &err);
+  ret = funcs->init (channels, inrate, outrate, quality,
+        sinc_filter_mode, sinc_filter_auto_threshold, &err);
 
   if (G_UNLIKELY (err != RESAMPLER_ERR_SUCCESS)) {
     GST_ERROR_OBJECT (resample, "Failed to create resampler state: %s",
@@ -363,6 +397,11 @@ gst_audio_resample_init_state (GstAudioResample * resample, gint width,
     return NULL;
   }
 
+  if (sinc_filter_mode == SPEEX_RESAMPLER_SINC_FILTER_AUTO) {
+    GST_INFO_OBJECT (resample, "Using the %s sinc filter table",
+        funcs->get_sinc_filter_mode(ret) ? "full" : "interpolated");
+  }
+
   funcs->skip_zeros (ret);
 
   return ret;
@@ -370,7 +409,9 @@ gst_audio_resample_init_state (GstAudioResample * resample, gint width,
 
 static gboolean
 gst_audio_resample_update_state (GstAudioResample * resample, gint width,
-    gint channels, gint inrate, gint outrate, gint quality, gboolean fp)
+    gint channels, gint inrate, gint outrate, gint quality, gboolean fp,
+    SpeexResamplerSincFilterMode sinc_filter_mode,
+    guint32 sinc_filter_auto_threshold)
 {
   gboolean ret = TRUE;
   gboolean updated_latency = FALSE;
@@ -381,11 +422,12 @@ gst_audio_resample_update_state (GstAudioResample * resample, gint width,
   if (resample->state == NULL) {
     ret = TRUE;
   } else if (resample->channels != channels || fp != resample->fp
-      || width != resample->width) {
+      || width != resample->width || sinc_filter_mode != resample->sinc_filter_mode
+      || sinc_filter_auto_threshold != resample->sinc_filter_auto_threshold) {
     resample->funcs->destroy (resample->state);
     resample->state =
         gst_audio_resample_init_state (resample, width, channels, inrate,
-        outrate, quality, fp);
+        outrate, quality, fp, sinc_filter_mode, sinc_filter_auto_threshold);
 
     resample->funcs = gst_audio_resample_get_funcs (width, fp);
     ret = (resample->state != NULL);
@@ -417,6 +459,8 @@ gst_audio_resample_update_state (GstAudioResample * resample, gint width,
   resample->quality = quality;
   resample->inrate = inrate;
   resample->outrate = outrate;
+  resample->sinc_filter_mode = sinc_filter_mode;
+  resample->sinc_filter_auto_threshold = sinc_filter_auto_threshold;
 
   if (updated_latency)
     gst_element_post_message (GST_ELEMENT (resample),
@@ -526,7 +570,8 @@ gst_audio_resample_set_caps (GstBaseTransform * base, GstCaps * incaps,
 
   ret =
       gst_audio_resample_update_state (resample, width, channels, inrate,
-      outrate, resample->quality, fp);
+      outrate, resample->quality, fp, resample->sinc_filter_mode,
+      resample->sinc_filter_auto_threshold);
 
   if (G_UNLIKELY (!ret))
     return FALSE;
@@ -1126,7 +1171,8 @@ gst_audio_resample_transform (GstBaseTransform * base, GstBuffer * inbuf,
     if (G_UNLIKELY (!(resample->state =
                 gst_audio_resample_init_state (resample, resample->width,
                     resample->channels, resample->inrate, resample->outrate,
-                    resample->quality, resample->fp))))
+                    resample->quality, resample->fp, resample->sinc_filter_mode,
+                    resample->sinc_filter_auto_threshold))))
       return GST_FLOW_ERROR;
 
     resample->funcs =
@@ -1279,8 +1325,31 @@ gst_audio_resample_set_property (GObject * object, guint prop_id,
 
       gst_audio_resample_update_state (resample, resample->width,
           resample->channels, resample->inrate, resample->outrate,
-          quality, resample->fp);
+          quality, resample->fp, resample->sinc_filter_mode,
+          resample->sinc_filter_auto_threshold);
+      break;
+    case PROP_SINC_FILTER_MODE: {
+      /* FIXME locking! */
+      SpeexResamplerSincFilterMode sinc_filter_mode = g_value_get_enum (value);
+
+      gst_audio_resample_update_state (resample, resample->width,
+          resample->channels, resample->inrate, resample->outrate,
+          resample->quality, resample->fp, sinc_filter_mode,
+          resample->sinc_filter_auto_threshold);
+
+      break;
+    }
+    case PROP_SINC_FILTER_AUTO_THRESHOLD: {
+      /* FIXME locking! */
+      guint32 sinc_filter_auto_threshold = g_value_get_uint (value);
+
+      gst_audio_resample_update_state (resample, resample->width,
+          resample->channels, resample->inrate, resample->outrate,
+          resample->quality, resample->fp, resample->sinc_filter_mode,
+          sinc_filter_auto_threshold);
+
       break;
+    }
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -1299,12 +1368,39 @@ gst_audio_resample_get_property (GObject * object, guint prop_id,
     case PROP_QUALITY:
       g_value_set_int (value, resample->quality);
       break;
+    case PROP_SINC_FILTER_MODE:
+      g_value_set_enum(value, resample->sinc_filter_mode);
+      break;
+    case PROP_SINC_FILTER_AUTO_THRESHOLD:
+      g_value_set_uint(value, resample->sinc_filter_auto_threshold);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
   }
 }
 
+static GType
+speex_resampler_sinc_filter_mode_get_type (void)
+{
+  static GType speex_resampler_sinc_filter_mode_type = 0;
+
+  if (!speex_resampler_sinc_filter_mode_type) {
+    static GEnumValue sinc_filter_modes[] = {
+      { SPEEX_RESAMPLER_SINC_FILTER_INTERPOLATED, "Use interpolated sinc table",                  "interpolated" },
+      { SPEEX_RESAMPLER_SINC_FILTER_FULL,         "Use full sinc table",                          "full"         },
+      { SPEEX_RESAMPLER_SINC_FILTER_AUTO,         "Use full table if table size below threshold", "auto"         },
+      { 0, NULL, NULL },
+    };
+
+    speex_resampler_sinc_filter_mode_type = g_enum_register_static (
+                                            "SpeexResamplerSincFilterMode",
+                                            sinc_filter_modes);
+  }
+
+  return speex_resampler_sinc_filter_mode_type;
+}
+
 /* FIXME: should have a benchmark fallback for the case where orc is disabled */
 #if defined(AUDIORESAMPLE_FORMAT_AUTO) && !defined(DISABLE_ORC)
 
@@ -1367,13 +1463,19 @@ _benchmark_integer_resampling (void)
   orc_profile_init (&a);
   orc_profile_init (&b);
 
-  sta = resample_float_resampler_init (1, 48000, 24000, 4, NULL);
+  sta = resample_float_resampler_init (1, 48000, 24000, 4,
+        SPEEX_RESAMPLER_SINC_FILTER_INTERPOLATED,
+        SPEEX_RESAMPLER_SINC_FILTER_AUTO_THRESHOLD_DEFAULT,
+        NULL);
   if (sta == NULL) {
     GST_ERROR ("Failed to create float resampler state");
     return FALSE;
   }
 
-  stb = resample_int_resampler_init (1, 48000, 24000, 4, NULL);
+  stb = resample_int_resampler_init (1, 48000, 24000, 4,
+        SPEEX_RESAMPLER_SINC_FILTER_INTERPOLATED,
+        SPEEX_RESAMPLER_SINC_FILTER_AUTO_THRESHOLD_DEFAULT,
+        NULL);
   if (stb == NULL) {
     resample_float_resampler_destroy (sta);
     GST_ERROR ("Failed to create int resampler state");
index da75b64..df2d2f1 100644 (file)
@@ -77,6 +77,9 @@ struct _GstAudioResample {
   gint inrate;
   gint outrate;
 
+  SpeexResamplerSincFilterMode sinc_filter_mode;
+  guint32 sinc_filter_auto_threshold;
+
   guint8 *tmp_in;
   guint tmp_in_size;
 
index fefa0c5..bd36bfa 100644 (file)
@@ -184,6 +184,7 @@ struct SpeexResamplerState_
   spx_uint32_t oversample;
   int initialised;
   int started;
+  int use_full_sinc_table;
 
   /* These are per-channel */
   spx_int32_t *last_sample;
@@ -754,7 +755,8 @@ update_filter (SpeexResamplerState * st)
   }
 
   /* Choose the resampling type that requires the least amount of memory */
-  if (st->den_rate <= st->oversample) {
+  /* Or if the full sinc table is explicitely requested, use that */
+  if (st->use_full_sinc_table || (st->den_rate <= st->oversample)) {
     spx_uint32_t i;
     if (!st->sinc_table)
       st->sinc_table =
@@ -918,10 +920,11 @@ update_filter (SpeexResamplerState * st)
 
 EXPORT SpeexResamplerState *
 speex_resampler_init (spx_uint32_t nb_channels, spx_uint32_t in_rate,
-    spx_uint32_t out_rate, int quality, int *err)
+    spx_uint32_t out_rate, int quality, SpeexResamplerSincFilterMode sinc_filter_mode,
+    spx_uint32_t sinc_filter_auto_threshold, int *err)
 {
   return speex_resampler_init_frac (nb_channels, in_rate, out_rate, in_rate,
-      out_rate, quality, err);
+      out_rate, quality, sinc_filter_mode, sinc_filter_auto_threshold, err);
 }
 
 #if defined HAVE_ORC && !defined DISABLE_ORC
@@ -940,15 +943,33 @@ check_insn_set (SpeexResamplerState * st, const char *name)
 EXPORT SpeexResamplerState *
 speex_resampler_init_frac (spx_uint32_t nb_channels, spx_uint32_t ratio_num,
     spx_uint32_t ratio_den, spx_uint32_t in_rate, spx_uint32_t out_rate,
-    int quality, int *err)
+    int quality, SpeexResamplerSincFilterMode sinc_filter_mode,
+    spx_uint32_t sinc_filter_auto_threshold, int *err)
 {
   spx_uint32_t i;
   SpeexResamplerState *st;
+  int use_full_sinc_table = 0;
   if (quality > 10 || quality < 0) {
     if (err)
       *err = RESAMPLER_ERR_INVALID_ARG;
     return NULL;
   }
+  switch (sinc_filter_mode) {
+    case RESAMPLER_SINC_FILTER_INTERPOLATED:
+      use_full_sinc_table = 0;
+      break;
+    case RESAMPLER_SINC_FILTER_FULL:
+      use_full_sinc_table = 1;
+      break;
+    case RESAMPLER_SINC_FILTER_AUTO:
+      /* Handled below */
+      break;
+    default:
+      if (err)
+        *err = RESAMPLER_ERR_INVALID_ARG;
+      return NULL;
+  }
+
   st = (SpeexResamplerState *) speex_alloc (sizeof (SpeexResamplerState));
   st->initialised = 0;
   st->started = 0;
@@ -962,6 +983,7 @@ speex_resampler_init_frac (spx_uint32_t nb_channels, spx_uint32_t ratio_num,
   st->filt_len = 0;
   st->mem = 0;
   st->resampler_ptr = 0;
+  st->use_full_sinc_table = use_full_sinc_table;
 
   st->cutoff = 1.f;
   st->nb_channels = nb_channels;
@@ -1004,6 +1026,16 @@ speex_resampler_init_frac (spx_uint32_t nb_channels, spx_uint32_t ratio_num,
   speex_resampler_set_quality (st, quality);
   speex_resampler_set_rate_frac (st, ratio_num, ratio_den, in_rate, out_rate);
 
+  if (sinc_filter_mode == RESAMPLER_SINC_FILTER_AUTO) {
+    /*
+    Estimate how big the filter table would become if the full mode were to be used
+    calculations used correspond to the ones in update_filter()
+    if the size is bigger than the threshold, use interpolated sinc instead
+    */
+    spx_uint32_t base_filter_length = st->filt_len = quality_map[st->quality].base_length;
+    spx_uint32_t filter_table_size = base_filter_length * st->den_rate * sizeof(spx_uint16_t);
+    st->use_full_sinc_table = (filter_table_size > sinc_filter_auto_threshold) ? 0 : 1;
+  }
 
   update_filter (st);
 
@@ -1392,6 +1424,12 @@ speex_resampler_get_filt_len (SpeexResamplerState * st)
 }
 
 EXPORT int
+speex_resampler_get_sinc_filter_mode (SpeexResamplerState * st)
+{
+  return st->use_full_sinc_table;
+}
+
+EXPORT int
 speex_resampler_skip_zeros (SpeexResamplerState * st)
 {
   spx_uint32_t i;
index 894b380..b9aaa2c 100644 (file)
@@ -74,6 +74,7 @@
 #define speex_resampler_get_input_latency CAT_PREFIX(RANDOM_PREFIX,_resampler_get_input_latency)
 #define speex_resampler_get_output_latency CAT_PREFIX(RANDOM_PREFIX,_resampler_get_output_latency)
 #define speex_resampler_get_filt_len CAT_PREFIX(RANDOM_PREFIX,_resampler_get_filt_len)
+#define speex_resampler_get_sinc_filter_mode CAT_PREFIX(RANDOM_PREFIX,_resampler_get_sinc_filter_mode)
 #define speex_resampler_skip_zeros CAT_PREFIX(RANDOM_PREFIX,_resampler_skip_zeros)
 #define speex_resampler_reset_mem CAT_PREFIX(RANDOM_PREFIX,_resampler_reset_mem)
 #define speex_resampler_strerror CAT_PREFIX(RANDOM_PREFIX,_resampler_strerror)
@@ -113,6 +114,15 @@ enum {
    RESAMPLER_ERR_MAX_ERROR
 };
 
+typedef enum {
+   RESAMPLER_SINC_FILTER_INTERPOLATED   = 0,
+   RESAMPLER_SINC_FILTER_FULL           = 1,
+   RESAMPLER_SINC_FILTER_AUTO           = 2
+} SpeexResamplerSincFilterMode;
+
+#define RESAMPLER_SINC_FILTER_DEFAULT RESAMPLER_SINC_FILTER_INTERPOLATED
+#define RESAMPLER_SINC_FILTER_AUTO_THRESHOLD_DEFAULT (1 * 1048576)
+
 struct SpeexResamplerState_;
 typedef struct SpeexResamplerState_ SpeexResamplerState;
 
@@ -122,13 +132,23 @@ typedef struct SpeexResamplerState_ SpeexResamplerState;
  * @param out_rate Output sampling rate (integer number of Hz).
  * @param quality Resampling quality between 0 and 10, where 0 has poor quality
  * and 10 has very high quality.
+ * @param sinc_filter_mode Sinc filter table mode to use
+ * @param sinc_filter_auto_threshold Threshold to use if sinc filter mode is auto, in bytes
  * @return Newly created resampler state
  * @retval NULL Error: not enough memory
+ *
+ * If a full filter table would be larger than the auto threshold, and sinc_filter_mode is AUTO,
+ * the resample uses the interpolated mode instead
+ *
+ * @note A full sinc table can significantly improve the resampler's performance, but calculating the table
+ * takes longer, as opposed to the interpolated variant
  */
 SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels, 
                                           spx_uint32_t in_rate, 
                                           spx_uint32_t out_rate, 
                                           int quality,
+                                          SpeexResamplerSincFilterMode sinc_filter_mode,
+                                          spx_uint32_t sinc_filter_auto_threshold,
                                           int *err);
 
 /** Create a new resampler with fractional input/output rates. The sampling 
@@ -141,8 +161,16 @@ SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels,
  * @param out_rate Output sampling rate rounded to the nearest integer (in Hz).
  * @param quality Resampling quality between 0 and 10, where 0 has poor quality
  * and 10 has very high quality.
+ * @param sinc_filter_mode Sinc filter table mode to use
+ * @param sinc_filter_auto_threshold Threshold to use if sinc filter mode is auto, in bytes
  * @return Newly created resampler state
  * @retval NULL Error: not enough memory
+ *
+ * If a full filter table would be larger than the auto threshold, and sinc_filter_mode is AUTO,
+ * the resample uses the interpolated mode instead
+ *
+ * @note A full sinc table can significantly improve the resampler's performance, but calculating the table
+ * takes longer, as opposed to the interpolated variant
  */
 SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels, 
                                                spx_uint32_t ratio_num, 
@@ -150,6 +178,8 @@ SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels,
                                                spx_uint32_t in_rate, 
                                                spx_uint32_t out_rate, 
                                                int quality,
+                                               SpeexResamplerSincFilterMode sinc_filter_mode,
+                                               spx_uint32_t sinc_filter_auto_threshold,
                                                int *err);
 
 /** Destroy a resampler state.
@@ -339,6 +369,12 @@ int speex_resampler_get_output_latency(SpeexResamplerState *st);
  */
 int speex_resampler_get_filt_len(SpeexResamplerState *st);
 
+/** Returns 1 if the full sinc filter table is used, 0 if the interpolated one is used
+ * @param st Resampler state
+ * @return Sinc filter mode
+ */
+int speex_resampler_get_sinc_filter_mode(SpeexResamplerState *st);
+
 /** Make sure that the first samples to go out of the resamplers don't have 
  * leading zeros. This is only useful before starting to use a newly created 
  * resampler. It is recommended to use that when resampling an audio file, as
index 08a82bc..5a13dee 100644 (file)
@@ -26,6 +26,9 @@
 #define SPEEX_RESAMPLER_QUALITY_VOIP 3
 #define SPEEX_RESAMPLER_QUALITY_DESKTOP 5
 
+#define SPEEX_RESAMPLER_SINC_FILTER_DEFAULT SPEEX_RESAMPLER_SINC_FILTER_INTERPOLATED
+#define SPEEX_RESAMPLER_SINC_FILTER_AUTO_THRESHOLD_DEFAULT (1 * 1048576)
+
 enum
 {
   RESAMPLER_ERR_SUCCESS = 0,
@@ -37,11 +40,19 @@ enum
   RESAMPLER_ERR_MAX_ERROR
 };
 
+typedef enum {
+  SPEEX_RESAMPLER_SINC_FILTER_INTERPOLATED   = 0,
+  SPEEX_RESAMPLER_SINC_FILTER_FULL           = 1,
+  SPEEX_RESAMPLER_SINC_FILTER_AUTO           = 2
+} SpeexResamplerSincFilterMode;
+
 typedef struct SpeexResamplerState_ SpeexResamplerState;
 
 typedef struct {
   SpeexResamplerState *(*init) (guint32 nb_channels,
-    guint32 in_rate, guint32 out_rate, gint quality, gint * err);
+    guint32 in_rate, guint32 out_rate, gint quality,
+    SpeexResamplerSincFilterMode sinc_filter_mode,
+    guint32 sinc_filter_auto_threshold, gint * err);
   void (*destroy) (SpeexResamplerState * st);
   int (*process) (SpeexResamplerState *
     st, const guint8 * in, guint32 * in_len, guint8 * out, guint32 * out_len);
@@ -53,6 +64,7 @@ typedef struct {
     guint32 * ratio_num, guint32 * ratio_den);
   int (*get_input_latency) (SpeexResamplerState * st);
   int (*get_filt_len) (SpeexResamplerState * st);
+  int (*get_sinc_filter_mode) (SpeexResamplerState * st);
   int (*set_quality) (SpeexResamplerState * st, gint quality);
   int (*reset_mem) (SpeexResamplerState * st);
   int (*skip_zeros) (SpeexResamplerState * st);
@@ -61,7 +73,9 @@ typedef struct {
 } SpeexResampleFuncs;
 
 SpeexResamplerState *resample_float_resampler_init (guint32 nb_channels,
-    guint32 in_rate, guint32 out_rate, gint quality, gint * err);
+    guint32 in_rate, guint32 out_rate, gint quality,
+    SpeexResamplerSincFilterMode sinc_filter_mode,
+    guint32 sinc_filter_auto_threshold, gint * err);
 void resample_float_resampler_destroy (SpeexResamplerState * st);
 int resample_float_resampler_process_interleaved_float (SpeexResamplerState *
     st, const guint8 * in, guint32 * in_len, guint8 * out, guint32 * out_len);
@@ -73,6 +87,7 @@ void resample_float_resampler_get_ratio (SpeexResamplerState * st,
     guint32 * ratio_num, guint32 * ratio_den);
 int resample_float_resampler_get_input_latency (SpeexResamplerState * st);
 int resample_float_resampler_get_filt_len (SpeexResamplerState * st);
+int resample_float_resampler_get_sinc_filter_mode (SpeexResamplerState * st);
 int resample_float_resampler_set_quality (SpeexResamplerState * st, gint quality);
 int resample_float_resampler_reset_mem (SpeexResamplerState * st);
 int resample_float_resampler_skip_zeros (SpeexResamplerState * st);
@@ -88,6 +103,7 @@ static const SpeexResampleFuncs float_funcs =
   resample_float_resampler_get_ratio,
   resample_float_resampler_get_input_latency,
   resample_float_resampler_get_filt_len,
+  resample_float_resampler_get_sinc_filter_mode,
   resample_float_resampler_set_quality,
   resample_float_resampler_reset_mem,
   resample_float_resampler_skip_zeros,
@@ -96,7 +112,9 @@ static const SpeexResampleFuncs float_funcs =
 };
 
 SpeexResamplerState *resample_double_resampler_init (guint32 nb_channels,
-    guint32 in_rate, guint32 out_rate, gint quality, gint * err);
+    guint32 in_rate, guint32 out_rate, gint quality,
+    SpeexResamplerSincFilterMode sinc_filter_mode,
+    guint32 sinc_filter_auto_threshold, gint * err);
 void resample_double_resampler_destroy (SpeexResamplerState * st);
 int resample_double_resampler_process_interleaved_float (SpeexResamplerState *
     st, const guint8 * in, guint32 * in_len, guint8 * out, guint32 * out_len);
@@ -108,6 +126,7 @@ void resample_double_resampler_get_ratio (SpeexResamplerState * st,
     guint32 * ratio_num, guint32 * ratio_den);
 int resample_double_resampler_get_input_latency (SpeexResamplerState * st);
 int resample_double_resampler_get_filt_len (SpeexResamplerState * st);
+int resample_double_resampler_get_sinc_filter_mode (SpeexResamplerState * st);
 int resample_double_resampler_set_quality (SpeexResamplerState * st, gint quality);
 int resample_double_resampler_reset_mem (SpeexResamplerState * st);
 int resample_double_resampler_skip_zeros (SpeexResamplerState * st);
@@ -123,6 +142,7 @@ static const SpeexResampleFuncs double_funcs =
   resample_double_resampler_get_ratio,
   resample_double_resampler_get_input_latency,
   resample_double_resampler_get_filt_len,
+  resample_double_resampler_get_sinc_filter_mode,
   resample_double_resampler_set_quality,
   resample_double_resampler_reset_mem,
   resample_double_resampler_skip_zeros,
@@ -131,7 +151,9 @@ static const SpeexResampleFuncs double_funcs =
 };
 
 SpeexResamplerState *resample_int_resampler_init (guint32 nb_channels,
-    guint32 in_rate, guint32 out_rate, gint quality, gint * err);
+    guint32 in_rate, guint32 out_rate, gint quality,
+    SpeexResamplerSincFilterMode sinc_filter_mode,
+    guint32 sinc_filter_auto_threshold, gint * err);
 void resample_int_resampler_destroy (SpeexResamplerState * st);
 int resample_int_resampler_process_interleaved_int (SpeexResamplerState *
     st, const guint8 * in, guint32 * in_len, guint8 * out, guint32 * out_len);
@@ -143,6 +165,7 @@ void resample_int_resampler_get_ratio (SpeexResamplerState * st,
     guint32 * ratio_num, guint32 * ratio_den);
 int resample_int_resampler_get_input_latency (SpeexResamplerState * st);
 int resample_int_resampler_get_filt_len (SpeexResamplerState * st);
+int resample_int_resampler_get_sinc_filter_mode (SpeexResamplerState * st);
 int resample_int_resampler_set_quality (SpeexResamplerState * st, gint quality);
 int resample_int_resampler_reset_mem (SpeexResamplerState * st);
 int resample_int_resampler_skip_zeros (SpeexResamplerState * st);
@@ -158,6 +181,7 @@ static const SpeexResampleFuncs int_funcs =
   resample_int_resampler_get_ratio,
   resample_int_resampler_get_input_latency,
   resample_int_resampler_get_filt_len,
+  resample_int_resampler_get_sinc_filter_mode,
   resample_int_resampler_set_quality,
   resample_int_resampler_reset_mem,
   resample_int_resampler_skip_zeros,