mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 04:01:08 +00:00
audioresample: sinc filter performance improvements
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>
This commit is contained in:
parent
d8b42ae80c
commit
c41faa3d8e
5 changed files with 222 additions and 19 deletions
|
@ -25,6 +25,14 @@
|
|||
* 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");
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
@ -1391,6 +1423,12 @@ speex_resampler_get_filt_len (SpeexResamplerState * st)
|
|||
return st->filt_len;
|
||||
}
|
||||
|
||||
EXPORT int
|
||||
speex_resampler_get_sinc_filter_mode (SpeexResamplerState * st)
|
||||
{
|
||||
return st->use_full_sinc_table;
|
||||
}
|
||||
|
||||
EXPORT int
|
||||
speex_resampler_skip_zeros (SpeexResamplerState * st)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue