From 12766882b5d6ffcb8c48f2fa0a1f19ab17c05077 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 30 Oct 2008 12:43:44 +0000 Subject: [PATCH] Add support for double samples as input and refactor the usage of the different compilation flavors of the speex resa... Original commit message from CVS: * gst/speexresample/Makefile.am: * gst/speexresample/arch.h: * gst/speexresample/gstspeexresample.c: (gst_speex_resample_stop), (gst_speex_resample_get_unit_size), (gst_speex_resample_get_funcs), (gst_speex_resample_init_state), (gst_speex_resample_update_state), (gst_speex_resample_reset_state), (gst_speex_resample_parse_caps), (_gcd), (gst_speex_resample_transform_size), (gst_speex_resample_set_caps), (gst_speex_resample_push_drain), (gst_speex_resample_process), (gst_speex_resample_transform), (gst_speex_resample_query), (gst_speex_resample_set_property): * gst/speexresample/gstspeexresample.h: * gst/speexresample/resample.c: * gst/speexresample/speex_resampler.h: * gst/speexresample/speex_resampler_double.c: * gst/speexresample/speex_resampler_wrapper.h: * tests/check/elements/speexresample.c: (setup_speexresample), (test_perfect_stream_instance), (GST_START_TEST), (test_discont_stream_instance): Add support for double samples as input and refactor the usage of the different compilation flavors of the speex resampler. --- ChangeLog | 23 ++ gst/speexresample/Makefile.am | 3 +- gst/speexresample/arch.h | 23 ++ gst/speexresample/gstspeexresample.c | 263 +++++++++----------- gst/speexresample/gstspeexresample.h | 5 +- gst/speexresample/resample.c | 58 ++++- gst/speexresample/speex_resampler.h | 13 + gst/speexresample/speex_resampler_double.c | 25 ++ gst/speexresample/speex_resampler_wrapper.h | 125 ++++++++-- tests/check/elements/speexresample.c | 43 +++- 10 files changed, 393 insertions(+), 188 deletions(-) create mode 100644 gst/speexresample/speex_resampler_double.c diff --git a/ChangeLog b/ChangeLog index 8377763e06..e68f686538 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,26 @@ +2008-10-30 Sebastian Dröge + + * gst/speexresample/Makefile.am: + * gst/speexresample/arch.h: + * gst/speexresample/gstspeexresample.c: (gst_speex_resample_stop), + (gst_speex_resample_get_unit_size), (gst_speex_resample_get_funcs), + (gst_speex_resample_init_state), (gst_speex_resample_update_state), + (gst_speex_resample_reset_state), (gst_speex_resample_parse_caps), + (_gcd), (gst_speex_resample_transform_size), + (gst_speex_resample_set_caps), (gst_speex_resample_push_drain), + (gst_speex_resample_process), (gst_speex_resample_transform), + (gst_speex_resample_query), (gst_speex_resample_set_property): + * gst/speexresample/gstspeexresample.h: + * gst/speexresample/resample.c: + * gst/speexresample/speex_resampler.h: + * gst/speexresample/speex_resampler_double.c: + * gst/speexresample/speex_resampler_wrapper.h: + * tests/check/elements/speexresample.c: (setup_speexresample), + (test_perfect_stream_instance), (GST_START_TEST), + (test_discont_stream_instance): + Add support for double samples as input and refactor the usage + of the different compilation flavors of the speex resampler. + 2008-10-30 Stefan Kost * gst/scaletempo/gstscaletempo.c: diff --git a/gst/speexresample/Makefile.am b/gst/speexresample/Makefile.am index 3e0c4924ac..f4d1534d57 100644 --- a/gst/speexresample/Makefile.am +++ b/gst/speexresample/Makefile.am @@ -3,7 +3,8 @@ plugin_LTLIBRARIES = libgstspeexresample.la libgstspeexresample_la_SOURCES = \ gstspeexresample.c \ speex_resampler_int.c \ - speex_resampler_float.c + speex_resampler_float.c \ + speex_resampler_double.c libgstspeexresample_la_CFLAGS = \ $(GST_PLUGINS_BASE_CFLAGS) \ diff --git a/gst/speexresample/arch.h b/gst/speexresample/arch.h index 168f28bdf2..86c9b351e2 100644 --- a/gst/speexresample/arch.h +++ b/gst/speexresample/arch.h @@ -137,6 +137,28 @@ typedef spx_word32_t spx_sig_t; #else +#ifdef DOUBLE_PRECISION +typedef double spx_mem_t; +typedef double spx_coef_t; +typedef double spx_lsp_t; +typedef double spx_sig_t; +typedef double spx_word16_t; +typedef double spx_word32_t; + +#define Q15ONE 1.0 +#define LPC_SCALING 1. +#define SIG_SCALING 1. +#define LSP_SCALING 1. +#define GAMMA_SCALING 1. +#define GAIN_SCALING 1. +#define GAIN_SCALING_1 1. + + +#define VERY_SMALL 1e-20 +#define VERY_LARGE32 1e20 +#define VERY_LARGE16 1e20 +#define Q15_ONE ((spx_word16_t)1.) +#else /* !DOUBLE_PRECISION */ typedef float spx_mem_t; typedef float spx_coef_t; typedef float spx_lsp_t; @@ -157,6 +179,7 @@ typedef float spx_word32_t; #define VERY_LARGE32 1e15f #define VERY_LARGE16 1e15f #define Q15_ONE ((spx_word16_t)1.f) +#endif /* DOUBLE_PRECISION */ #define QCONST16(x,bits) (x) #define QCONST32(x,bits) (x) diff --git a/gst/speexresample/gstspeexresample.c b/gst/speexresample/gstspeexresample.c index f9b5b0e365..e0dee7dbdc 100644 --- a/gst/speexresample/gstspeexresample.c +++ b/gst/speexresample/gstspeexresample.c @@ -60,7 +60,7 @@ GST_STATIC_CAPS ( \ "rate = (int) [ 1, MAX ], " \ "channels = (int) [ 1, MAX ], " \ "endianness = (int) BYTE_ORDER, " \ - "width = (int) 32; " \ + "width = (int) { 32, 64 }; " \ "audio/x-raw-int, " \ "rate = (int) [ 1, MAX ], " \ "channels = (int) [ 1, MAX ], " \ @@ -196,10 +196,12 @@ gst_speex_resample_stop (GstBaseTransform * base) GstSpeexResample *resample = GST_SPEEX_RESAMPLE (base); if (resample->state) { - resample_resampler_destroy (resample->state); + resample->funcs->destroy (resample->state); resample->state = NULL; } + resample->funcs = NULL; + gst_caps_replace (&resample->sinkcaps, NULL); gst_caps_replace (&resample->srccaps, NULL); @@ -224,7 +226,7 @@ gst_speex_resample_get_unit_size (GstBaseTransform * base, GstCaps * caps, if (G_UNLIKELY (!ret)) return FALSE; - *size = gst_util_uint64_scale (width, channels, 8); + *size = (width / 8) * channels; return TRUE; } @@ -261,38 +263,47 @@ gst_speex_resample_fixate_caps (GstBaseTransform * base, gst_structure_fixate_field_nearest_int (s, "rate", rate); } +static const SpeexResampleFuncs * +gst_speex_resample_get_funcs (gint width, gboolean fp) +{ + const SpeexResampleFuncs *funcs = NULL; + + if (width == 16 && !fp) + funcs = &int_funcs; + else if (width == 32 && fp) + funcs = &float_funcs; + else if (width == 64 && fp) + funcs = &double_funcs; + else + g_assert_not_reached (); + + return funcs; +} + static SpeexResamplerState * -gst_speex_resample_init_state (gint channels, gint inrate, gint outrate, - gint quality, gboolean fp) +gst_speex_resample_init_state (GstSpeexResample * resample, gint width, + gint channels, gint inrate, gint outrate, gint quality, gboolean fp) { SpeexResamplerState *ret = NULL; gint err = RESAMPLER_ERR_SUCCESS; + const SpeexResampleFuncs *funcs = gst_speex_resample_get_funcs (width, fp); - if (fp) - ret = - resample_float_resampler_init (channels, inrate, outrate, quality, - &err); - else - ret = - resample_int_resampler_init (channels, inrate, outrate, quality, &err); + ret = funcs->init (channels, inrate, outrate, quality, &err); if (G_UNLIKELY (err != RESAMPLER_ERR_SUCCESS)) { - GST_ERROR ("Failed to create resampler state: %s", - resample_resampler_strerror (err)); + GST_ERROR_OBJECT (resample, "Failed to create resampler state: %s", + funcs->strerror (err)); return NULL; } - if (fp) - resample_float_resampler_skip_zeros (ret); - else - resample_int_resampler_skip_zeros (ret); + funcs->skip_zeros (ret); return ret; } static gboolean -gst_speex_resample_update_state (GstSpeexResample * resample, gint channels, - gint inrate, gint outrate, gint quality, gboolean fp) +gst_speex_resample_update_state (GstSpeexResample * resample, gint width, + gint channels, gint inrate, gint outrate, gint quality, gboolean fp) { gboolean ret = TRUE; gboolean updated_latency = FALSE; @@ -302,41 +313,38 @@ gst_speex_resample_update_state (GstSpeexResample * resample, gint channels, if (resample->state == NULL) { ret = TRUE; - } else if (resample->channels != channels || fp != resample->fp) { - resample_resampler_destroy (resample->state); + } else if (resample->channels != channels || fp != resample->fp + || width != resample->width) { + resample->funcs->destroy (resample->state); resample->state = - gst_speex_resample_init_state (channels, inrate, outrate, quality, fp); + gst_speex_resample_init_state (resample, width, channels, inrate, + outrate, quality, fp); + resample->funcs = gst_speex_resample_get_funcs (width, fp); ret = (resample->state != NULL); } else if (resample->inrate != inrate || resample->outrate != outrate) { gint err = RESAMPLER_ERR_SUCCESS; - if (fp) - err = - resample_float_resampler_set_rate (resample->state, inrate, outrate); - else - err = resample_int_resampler_set_rate (resample->state, inrate, outrate); + err = resample->funcs->set_rate (resample->state, inrate, outrate); if (G_UNLIKELY (err != RESAMPLER_ERR_SUCCESS)) GST_ERROR_OBJECT (resample, "Failed to update rate: %s", - resample_resampler_strerror (err)); + resample->funcs->strerror (err)); ret = (err == RESAMPLER_ERR_SUCCESS); } else if (quality != resample->quality) { gint err = RESAMPLER_ERR_SUCCESS; - if (fp) - err = resample_float_resampler_set_quality (resample->state, quality); - else - err = resample_int_resampler_set_quality (resample->state, quality); + err = resample->funcs->set_quality (resample->state, quality); if (G_UNLIKELY (err != RESAMPLER_ERR_SUCCESS)) GST_ERROR_OBJECT (resample, "Failed to update quality: %s", - resample_resampler_strerror (err)); + resample->funcs->strerror (err)); ret = (err == RESAMPLER_ERR_SUCCESS); } + resample->width = width; resample->channels = channels; resample->fp = fp; resample->quality = quality; @@ -353,20 +361,18 @@ gst_speex_resample_update_state (GstSpeexResample * resample, gint channels, static void gst_speex_resample_reset_state (GstSpeexResample * resample) { - if (resample->state && resample->fp) - resample_float_resampler_reset_mem (resample->state); - else if (resample->state && !resample->fp) - resample_int_resampler_reset_mem (resample->state); + if (resample->state) + resample->funcs->reset_mem (resample->state); } static gboolean gst_speex_resample_parse_caps (GstCaps * incaps, - GstCaps * outcaps, gint * channels, gint * inrate, gint * outrate, - gboolean * fp) + GstCaps * outcaps, gint * width, gint * channels, gint * inrate, + gint * outrate, gboolean * fp) { GstStructure *structure; gboolean ret; - gint myinrate, myoutrate, mychannels; + gint mywidth, myinrate, myoutrate, mychannels; gboolean myfp; GST_DEBUG ("incaps %" GST_PTR_FORMAT ", outcaps %" @@ -381,6 +387,7 @@ gst_speex_resample_parse_caps (GstCaps * incaps, ret = gst_structure_get_int (structure, "rate", &myinrate); ret &= gst_structure_get_int (structure, "channels", &mychannels); + ret &= gst_structure_get_int (structure, "width", &mywidth); if (G_UNLIKELY (!ret)) goto no_in_rate_channels; @@ -395,7 +402,8 @@ gst_speex_resample_parse_caps (GstCaps * incaps, *inrate = myinrate; if (outrate) *outrate = myoutrate; - + if (width) + *width = mywidth; if (fp) *fp = myfp; @@ -414,18 +422,30 @@ no_out_rate: } } +static gint +_gcd (gint a, gint b) +{ + while (b != 0) { + int temp = a; + + a = b; + b = temp % b; + } + + return ABS (a); +} + static gboolean gst_speex_resample_transform_size (GstBaseTransform * base, GstPadDirection direction, GstCaps * caps, guint size, GstCaps * othercaps, guint * othersize) { GstSpeexResample *resample = GST_SPEEX_RESAMPLE (base); - SpeexResamplerState *state; GstCaps *srccaps, *sinkcaps; - gboolean use_internal = FALSE; /* whether we use the internal state */ gboolean ret = TRUE; guint32 ratio_den, ratio_num; - gboolean fp; + gint inrate, outrate, gcd; + gint width; GST_LOG_OBJECT (resample, "asked to transform size %d in direction %s", size, direction == GST_PAD_SINK ? "SINK" : "SRC"); @@ -437,60 +457,40 @@ gst_speex_resample_transform_size (GstBaseTransform * base, srccaps = caps; } - /* if the caps are the ones that _set_caps got called with; we can use - * our own state; otherwise we'll have to create a state */ - if (resample->state && gst_caps_is_equal (sinkcaps, resample->sinkcaps) && - gst_caps_is_equal (srccaps, resample->srccaps)) { - use_internal = TRUE; - state = resample->state; - fp = resample->fp; - } else { - gint inrate, outrate, channels; - - GST_DEBUG_OBJECT (resample, "Can't use internal state, creating state"); - - ret = - gst_speex_resample_parse_caps (caps, othercaps, &channels, &inrate, - &outrate, &fp); - - if (G_UNLIKELY (!ret)) { - GST_ERROR_OBJECT (resample, "Wrong caps"); - return FALSE; - } - - state = gst_speex_resample_init_state (channels, inrate, outrate, 0, TRUE); - if (G_UNLIKELY (!state)) - return FALSE; + ret = + gst_speex_resample_parse_caps (caps, othercaps, &width, NULL, &inrate, + &outrate, NULL); + if (G_UNLIKELY (!ret)) { + GST_ERROR_OBJECT (resample, "Wrong caps"); + return FALSE; } - if (resample->fp || use_internal) - resample_float_resampler_get_ratio (state, &ratio_num, &ratio_den); - else - resample_int_resampler_get_ratio (state, &ratio_num, &ratio_den); + gcd = _gcd (inrate, outrate); + ratio_num = inrate / gcd; + ratio_den = outrate / gcd; if (direction == GST_PAD_SINK) { - gint fac = (fp) ? 4 : 2; + gint fac = width / 8; /* asked to convert size of an incoming buffer */ size /= fac; - *othersize = (size * ratio_den + (ratio_num >> 1)) / ratio_num; + //*othersize = (size * ratio_den + (ratio_num >> 1)) / ratio_num; + *othersize = (size * ratio_den + ratio_num - 1) / ratio_num; *othersize *= fac; size *= fac; } else { - gint fac = (fp) ? 4 : 2; + gint fac = width / 8; /* asked to convert size of an outgoing buffer */ size /= fac; - *othersize = (size * ratio_num + (ratio_den >> 1)) / ratio_den; + //*othersize = (size * ratio_num + (ratio_den >> 1)) / ratio_den; + *othersize = (size * ratio_num + ratio_den - 1) / ratio_den; *othersize *= fac; size *= fac; } GST_LOG_OBJECT (resample, "transformed size %d to %d", size, *othersize); - if (!use_internal) - resample_resampler_destroy (state); - return ret; } @@ -499,22 +499,22 @@ gst_speex_resample_set_caps (GstBaseTransform * base, GstCaps * incaps, GstCaps * outcaps) { gboolean ret; - gint inrate = 0, outrate = 0, channels = 0; - gboolean fp = FALSE; + gint width = 0, inrate = 0, outrate = 0, channels = 0; + gboolean fp; GstSpeexResample *resample = GST_SPEEX_RESAMPLE (base); GST_LOG ("incaps %" GST_PTR_FORMAT ", outcaps %" GST_PTR_FORMAT, incaps, outcaps); ret = gst_speex_resample_parse_caps (incaps, outcaps, - &channels, &inrate, &outrate, &fp); + &width, &channels, &inrate, &outrate, &fp); if (G_UNLIKELY (!ret)) return FALSE; ret = - gst_speex_resample_update_state (resample, channels, inrate, outrate, - resample->quality, fp); + gst_speex_resample_update_state (resample, width, channels, inrate, + outrate, resample->quality, fp); if (G_UNLIKELY (!ret)) return FALSE; @@ -536,27 +536,16 @@ gst_speex_resample_push_drain (GstSpeexResample * resample) gint outsize; guint out_len, out_processed; gint err; + guint num, den, len; if (!resample->state) return; - if (resample->fp) { - guint num, den; + resample->funcs->get_ratio (resample->state, &num, &den); - resample_float_resampler_get_ratio (resample->state, &num, &den); - - out_len = resample_float_resampler_get_input_latency (resample->state); - out_len = out_processed = (out_len * den + (num >> 1)) / num; - outsize = 4 * out_len * resample->channels; - } else { - guint num, den; - - resample_int_resampler_get_ratio (resample->state, &num, &den); - - out_len = resample_int_resampler_get_input_latency (resample->state); - out_len = out_processed = (out_len * den + (num >> 1)) / num; - outsize = 2 * out_len * resample->channels; - } + out_len = resample->funcs->get_input_latency (resample->state); + out_len = out_processed = (out_len * den + (num >> 1)) / num; + outsize = (resample->width / 8) * out_len * resample->channels; res = gst_pad_alloc_buffer_and_set_caps (trans->srcpad, GST_BUFFER_OFFSET_NONE, @@ -568,23 +557,15 @@ gst_speex_resample_push_drain (GstSpeexResample * resample) return; } - if (resample->fp) { - guint len = resample_float_resampler_get_input_latency (resample->state); + len = resample->funcs->get_input_latency (resample->state); - err = - resample_float_resampler_process_interleaved_float (resample->state, - NULL, &len, (gfloat *) GST_BUFFER_DATA (buf), &out_processed); - } else { - guint len = resample_int_resampler_get_input_latency (resample->state); - - err = - resample_int_resampler_process_interleaved_int (resample->state, NULL, - &len, (gint16 *) GST_BUFFER_DATA (buf), &out_processed); - } + err = + resample->funcs->process (resample->state, + NULL, &len, (guint8 *) GST_BUFFER_DATA (buf), &out_processed); if (G_UNLIKELY (err != RESAMPLER_ERR_SUCCESS)) { GST_WARNING_OBJECT (resample, "Failed to process drain: %s", - resample_resampler_strerror (err)); + resample->funcs->strerror (err)); gst_buffer_unref (buf); return; } @@ -598,7 +579,7 @@ gst_speex_resample_push_drain (GstSpeexResample * resample) GST_BUFFER_DURATION (buf) = GST_FRAMES_TO_CLOCK_TIME (out_processed, resample->outrate); GST_BUFFER_SIZE (buf) = - out_processed * resample->channels * ((resample->fp) ? 4 : 2); + out_processed * resample->channels * (resample->width / 8); if (GST_CLOCK_TIME_IS_VALID (resample->next_ts)) { GST_BUFFER_OFFSET (buf) = resample->next_offset; @@ -693,25 +674,15 @@ gst_speex_resample_process (GstSpeexResample * resample, GstBuffer * inbuf, in_len = GST_BUFFER_SIZE (inbuf) / resample->channels; out_len = GST_BUFFER_SIZE (outbuf) / resample->channels; - if (resample->fp) { - in_len /= 4; - out_len /= 4; - } else { - in_len /= 2; - out_len /= 2; - } + in_len /= (resample->width / 8); + out_len /= (resample->width / 8); in_processed = in_len; out_processed = out_len; - if (resample->fp) - err = resample_float_resampler_process_interleaved_float (resample->state, - (const gfloat *) GST_BUFFER_DATA (inbuf), &in_processed, - (gfloat *) GST_BUFFER_DATA (outbuf), &out_processed); - else - err = resample_int_resampler_process_interleaved_int (resample->state, - (const gint16 *) GST_BUFFER_DATA (inbuf), &in_processed, - (gint16 *) GST_BUFFER_DATA (outbuf), &out_processed); + err = resample->funcs->process (resample->state, + (const guint8 *) GST_BUFFER_DATA (inbuf), &in_processed, + (guint8 *) GST_BUFFER_DATA (outbuf), &out_processed); if (G_UNLIKELY (in_len != in_processed)) GST_WARNING_OBJECT (resample, "Converted %d of %d input samples", @@ -738,13 +709,13 @@ gst_speex_resample_process (GstSpeexResample * resample, GstBuffer * inbuf, if (G_UNLIKELY (err != RESAMPLER_ERR_SUCCESS)) { GST_ERROR_OBJECT (resample, "Failed to convert data: %s", - resample_resampler_strerror (err)); + resample->funcs->strerror (err)); return GST_FLOW_ERROR; } else { GST_BUFFER_DURATION (outbuf) = GST_FRAMES_TO_CLOCK_TIME (out_processed, resample->outrate); GST_BUFFER_SIZE (outbuf) = - out_processed * resample->channels * ((resample->fp) ? 4 : 2); + out_processed * resample->channels * (resample->width / 8); if (GST_CLOCK_TIME_IS_VALID (resample->next_ts)) { GST_BUFFER_TIMESTAMP (outbuf) = resample->next_ts; @@ -778,13 +749,17 @@ gst_speex_resample_transform (GstBaseTransform * base, GstBuffer * inbuf, guint outsamples, insamples; GstFlowReturn ret; - if (resample->state == NULL) + if (resample->state == NULL) { if (G_UNLIKELY (!(resample->state = - gst_speex_resample_init_state (resample->channels, - resample->inrate, resample->outrate, resample->quality, - resample->fp)))) + gst_speex_resample_init_state (resample, resample->width, + resample->channels, resample->inrate, resample->outrate, + resample->quality, resample->fp)))) return GST_FLOW_ERROR; + resample->funcs = + gst_speex_resample_get_funcs (resample->width, resample->fp); + } + data = GST_BUFFER_DATA (inbuf); size = GST_BUFFER_SIZE (inbuf); timestamp = GST_BUFFER_TIMESTAMP (inbuf); @@ -810,10 +785,10 @@ gst_speex_resample_transform (GstBaseTransform * base, GstBuffer * inbuf, } insamples = GST_BUFFER_SIZE (inbuf) / resample->channels; - insamples /= (resample->fp) ? 4 : 2; + insamples /= (resample->width / 8); outsamples = GST_BUFFER_SIZE (outbuf) / resample->channels; - outsamples /= (resample->fp) ? 4 : 2; + outsamples /= (resample->width / 8); if (GST_CLOCK_TIME_IS_VALID (timestamp) && !GST_CLOCK_TIME_IS_VALID (resample->next_ts)) { @@ -860,12 +835,9 @@ gst_speex_resample_query (GstPad * pad, GstQuery * query) gint rate = resample->inrate; gint resampler_latency; - if (resample->state && resample->fp) + if (resample->state) resampler_latency = - resample_float_resampler_get_input_latency (resample->state); - else if (resample->state && !resample->fp) - resampler_latency = - resample_int_resampler_get_input_latency (resample->state); + resample->funcs->get_input_latency (resample->state); else resampler_latency = 0; @@ -936,8 +908,9 @@ gst_speex_resample_set_property (GObject * object, guint prop_id, resample->quality = g_value_get_int (value); GST_DEBUG_OBJECT (resample, "new quality %d", resample->quality); - gst_speex_resample_update_state (resample, resample->channels, - resample->inrate, resample->outrate, resample->quality, resample->fp); + gst_speex_resample_update_state (resample, resample->width, + resample->channels, resample->inrate, resample->outrate, + resample->quality, resample->fp); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); diff --git a/gst/speexresample/gstspeexresample.h b/gst/speexresample/gstspeexresample.h index 7e7a68f652..25be5ca991 100644 --- a/gst/speexresample/gstspeexresample.h +++ b/gst/speexresample/gstspeexresample.h @@ -24,6 +24,7 @@ #include #include +#include #include "speex_resampler_wrapper.h" @@ -61,13 +62,15 @@ struct _GstSpeexResample { GstClockTime next_ts; GstClockTime next_upstream_ts; - gboolean fp; gint channels; gint inrate; gint outrate; gint quality; + gint width; + gboolean fp; SpeexResamplerState *state; + const SpeexResampleFuncs *funcs; }; struct _GstSpeexResampleClass { diff --git a/gst/speexresample/resample.c b/gst/speexresample/resample.c index ec127aa191..6f172509e7 100644 --- a/gst/speexresample/resample.c +++ b/gst/speexresample/resample.c @@ -267,10 +267,17 @@ static const struct QualityMapping quality_map[11] = { }; /*8,24,40,56,80,104,128,160,200,256,320*/ +#ifdef DOUBLE_PRECISION +static double +compute_func (double x, struct FuncDef *func) +{ + double y, frac; +#else static double compute_func (float x, struct FuncDef *func) { float y, frac; +#endif double interp[4]; int ind; y = x * func->oversample; @@ -321,11 +328,19 @@ sinc (float cutoff, float x, int N, struct FuncDef *window_func) } #else /* The slow way of computing a sinc for the table. Should improve that some day */ +#ifdef DOUBLE_PRECISION +static spx_word16_t +sinc (double cutoff, double x, int N, struct FuncDef *window_func) +{ + /*fprintf (stderr, "%f ", x); */ + double xx = x * cutoff; +#else static spx_word16_t sinc (float cutoff, float x, int N, struct FuncDef *window_func) { /*fprintf (stderr, "%f ", x); */ float xx = x * cutoff; +#endif if (fabs (x) < 1e-6) return cutoff; else if (fabs (x) > .5 * N) @@ -376,6 +391,7 @@ cubic_coef (spx_word16_t frac, spx_word16_t interp[4]) } #endif +#ifndef DOUBLE_PRECISION static int resampler_basic_direct_single (SpeexResamplerState * st, spx_uint32_t channel_index, const spx_word16_t * in, spx_uint32_t * in_len, @@ -425,6 +441,7 @@ resampler_basic_direct_single (SpeexResamplerState * st, st->samp_frac_num[channel_index] = samp_frac_num; return out_sample; } +#endif #ifdef FIXED_POINT #else @@ -480,6 +497,7 @@ resampler_basic_direct_double (SpeexResamplerState * st, } #endif +#ifndef DOUBLE_PRECISION static int resampler_basic_interpolate_single (SpeexResamplerState * st, spx_uint32_t channel_index, const spx_word16_t * in, spx_uint32_t * in_len, @@ -558,6 +576,7 @@ resampler_basic_interpolate_single (SpeexResamplerState * st, st->samp_frac_num[channel_index] = samp_frac_num; return out_sample; } +#endif #ifdef FIXED_POINT #else @@ -587,10 +606,16 @@ resampler_basic_interpolate_double (SpeexResamplerState * st, const spx_word16_t frac = PDIV32 (SHL32 ((samp_frac_num * st->oversample) % st->den_rate, 15), st->den_rate); +#else +#ifdef DOUBLE_PRECISION + const spx_word16_t frac = + ((double) ((samp_frac_num * st->oversample) % st->den_rate)) / + st->den_rate; #else const spx_word16_t frac = ((float) ((samp_frac_num * st->oversample) % st->den_rate)) / st->den_rate; +#endif #endif spx_word16_t interp[4]; @@ -692,19 +717,26 @@ update_filter (SpeexResamplerState * st) spx_int32_t j; for (j = 0; j < st->filt_len; j++) { st->sinc_table[i * st->filt_len + j] = - sinc (st->cutoff, - ((j - (spx_int32_t) st->filt_len / 2 + 1) - + sinc (st->cutoff, ((j - (spx_int32_t) st->filt_len / 2 + 1) - +#ifdef DOUBLE_PRECISION + ((double) i) / st->den_rate), st->filt_len, +#else ((float) i) / st->den_rate), st->filt_len, +#endif quality_map[st->quality].window_func); } } #ifdef FIXED_POINT st->resampler_ptr = resampler_basic_direct_single; +#else +#ifdef DOUBLE_PRECISION + st->resampler_ptr = resampler_basic_direct_double; #else if (st->quality > 8) st->resampler_ptr = resampler_basic_direct_double; else st->resampler_ptr = resampler_basic_direct_single; +#endif #endif /*fprintf (stderr, "resampler uses direct sinc table and normalised cutoff %f\n", cutoff); */ } else { @@ -721,15 +753,23 @@ update_filter (SpeexResamplerState * st) } for (i = -4; i < (spx_int32_t) (st->oversample * st->filt_len + 4); i++) st->sinc_table[i + 4] = +#ifdef DOUBLE_PRECISION + sinc (st->cutoff, (i / (double) st->oversample - st->filt_len / 2), +#else sinc (st->cutoff, (i / (float) st->oversample - st->filt_len / 2), +#endif st->filt_len, quality_map[st->quality].window_func); #ifdef FIXED_POINT st->resampler_ptr = resampler_basic_interpolate_single; +#else +#ifdef DOUBLE_PRECISION + st->resampler_ptr = resampler_basic_interpolate_double; #else if (st->quality > 8) st->resampler_ptr = resampler_basic_interpolate_double; else st->resampler_ptr = resampler_basic_interpolate_single; +#endif #endif /*fprintf (stderr, "resampler uses interpolated sinc table and normalised cutoff %f\n", cutoff); */ } @@ -960,11 +1000,18 @@ speex_resampler_process_int (SpeexResamplerState * st, spx_uint32_t channel_index, const spx_int16_t * in, spx_uint32_t * in_len, spx_int16_t * out, spx_uint32_t * out_len) #else +#ifdef DOUBLE_PRECISION +EXPORT int +speex_resampler_process_float (SpeexResamplerState * st, + spx_uint32_t channel_index, const double *in, spx_uint32_t * in_len, + double *out, spx_uint32_t * out_len) +#else EXPORT int speex_resampler_process_float (SpeexResamplerState * st, spx_uint32_t channel_index, const float *in, spx_uint32_t * in_len, float *out, spx_uint32_t * out_len) #endif +#endif { int j; spx_uint32_t ilen = *in_len; @@ -1082,9 +1129,16 @@ speex_resampler_process_int (SpeexResamplerState * st, return RESAMPLER_ERR_SUCCESS; } +#ifdef DOUBLE_PRECISION +EXPORT int +speex_resampler_process_interleaved_float (SpeexResamplerState * st, + const double *in, spx_uint32_t * in_len, double *out, + spx_uint32_t * out_len) +#else EXPORT int speex_resampler_process_interleaved_float (SpeexResamplerState * st, const float *in, spx_uint32_t * in_len, float *out, spx_uint32_t * out_len) +#endif { spx_uint32_t i; int istride_save, ostride_save; diff --git a/gst/speexresample/speex_resampler.h b/gst/speexresample/speex_resampler.h index a00c37c88d..4e4a44fff9 100644 --- a/gst/speexresample/speex_resampler.h +++ b/gst/speexresample/speex_resampler.h @@ -162,10 +162,17 @@ extern "C" * @param out Output buffer * @param out_len Size of the output buffer. Returns the number of samples written */ +#ifdef DOUBLE_PRECISION + int speex_resampler_process_float (SpeexResamplerState * st, + spx_uint32_t channel_index, + const double *in, + spx_uint32_t * in_len, double *out, spx_uint32_t * out_len); +#else int speex_resampler_process_float (SpeexResamplerState * st, spx_uint32_t channel_index, const float *in, spx_uint32_t * in_len, float *out, spx_uint32_t * out_len); +#endif /** Resample an int array. The input and output buffers must *not* overlap. * @param st Resampler state @@ -191,9 +198,15 @@ extern "C" * @param out_len Size of the output buffer. Returns the number of samples written. * This is all per-channel. */ +#ifdef DOUBLE_PRECISION + int speex_resampler_process_interleaved_float (SpeexResamplerState * st, + const double *in, + spx_uint32_t * in_len, double *out, spx_uint32_t * out_len); +#else int speex_resampler_process_interleaved_float (SpeexResamplerState * st, const float *in, spx_uint32_t * in_len, float *out, spx_uint32_t * out_len); +#endif /** Resample an interleaved int array. The input and output buffers must *not* overlap. * @param st Resampler state diff --git a/gst/speexresample/speex_resampler_double.c b/gst/speexresample/speex_resampler_double.c new file mode 100644 index 0000000000..39e242d81c --- /dev/null +++ b/gst/speexresample/speex_resampler_double.c @@ -0,0 +1,25 @@ +/* GStreamer + * Copyright (C) 2007 Sebastian Dröge + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#define FLOATING_POINT +#define DOUBLE_PRECISION +#define OUTSIDE_SPEEX +#define RANDOM_PREFIX resample_double + +#include "resample.c" diff --git a/gst/speexresample/speex_resampler_wrapper.h b/gst/speexresample/speex_resampler_wrapper.h index 6d7c17d036..6f3fba9b80 100644 --- a/gst/speexresample/speex_resampler_wrapper.h +++ b/gst/speexresample/speex_resampler_wrapper.h @@ -39,48 +39,119 @@ enum typedef struct SpeexResamplerState_ SpeexResamplerState; +typedef struct { + SpeexResamplerState *(*init) (guint32 nb_channels, + guint32 in_rate, guint32 out_rate, gint quality, gint * err); + void (*destroy) (SpeexResamplerState * st); + int (*process) (SpeexResamplerState * + st, const guint8 * in, guint32 * in_len, guint8 * out, guint32 * out_len); + int (*set_rate) (SpeexResamplerState * st, + guint32 in_rate, guint32 out_rate); + void (*get_rate) (SpeexResamplerState * st, + guint32 * in_rate, guint32 * out_rate); + void (*get_ratio) (SpeexResamplerState * st, + guint32 * ratio_num, guint32 * ratio_den); + int (*get_input_latency) (SpeexResamplerState * st); + int (*set_quality) (SpeexResamplerState * st, gint quality); + int (*reset_mem) (SpeexResamplerState * st); + int (*skip_zeros) (SpeexResamplerState * st); + const char * (*strerror) (gint err); +} SpeexResampleFuncs; + SpeexResamplerState *resample_float_resampler_init (guint32 nb_channels, guint32 in_rate, guint32 out_rate, gint quality, gint * err); -SpeexResamplerState *resample_int_resampler_init (guint32 nb_channels, - guint32 in_rate, guint32 out_rate, gint quality, gint * err); - -#define resample_resampler_destroy resample_int_resampler_destroy -void resample_resampler_destroy (SpeexResamplerState * st); - +void resample_float_resampler_destroy (SpeexResamplerState * st); int resample_float_resampler_process_interleaved_float (SpeexResamplerState * - st, const gfloat * in, guint32 * in_len, gfloat * out, guint32 * out_len); -int resample_int_resampler_process_interleaved_int (SpeexResamplerState * st, - const gint16 * in, guint32 * in_len, gint16 * out, guint32 * out_len); - + st, const guint8 * in, guint32 * in_len, guint8 * out, guint32 * out_len); int resample_float_resampler_set_rate (SpeexResamplerState * st, guint32 in_rate, guint32 out_rate); -int resample_int_resampler_set_rate (SpeexResamplerState * st, - guint32 in_rate, guint32 out_rate); - void resample_float_resampler_get_rate (SpeexResamplerState * st, guint32 * in_rate, guint32 * out_rate); -void resample_int_resampler_get_rate (SpeexResamplerState * st, - guint32 * in_rate, guint32 * out_rate); - 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_set_quality (SpeexResamplerState * st, gint quality); +int resample_float_resampler_reset_mem (SpeexResamplerState * st); +int resample_float_resampler_skip_zeros (SpeexResamplerState * st); +const char * resample_float_resampler_strerror (gint err); + +static const SpeexResampleFuncs float_funcs = +{ + resample_float_resampler_init, + resample_float_resampler_destroy, + resample_float_resampler_process_interleaved_float, + resample_float_resampler_set_rate, + resample_float_resampler_get_rate, + resample_float_resampler_get_ratio, + resample_float_resampler_get_input_latency, + resample_float_resampler_set_quality, + resample_float_resampler_reset_mem, + resample_float_resampler_skip_zeros, + resample_float_resampler_strerror +}; + +SpeexResamplerState *resample_double_resampler_init (guint32 nb_channels, + guint32 in_rate, guint32 out_rate, gint quality, 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); +int resample_double_resampler_set_rate (SpeexResamplerState * st, + guint32 in_rate, guint32 out_rate); +void resample_double_resampler_get_rate (SpeexResamplerState * st, + guint32 * in_rate, guint32 * out_rate); +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_set_quality (SpeexResamplerState * st, gint quality); +int resample_double_resampler_reset_mem (SpeexResamplerState * st); +int resample_double_resampler_skip_zeros (SpeexResamplerState * st); +const char * resample_double_resampler_strerror (gint err); + +static const SpeexResampleFuncs double_funcs = +{ + resample_double_resampler_init, + resample_double_resampler_destroy, + resample_double_resampler_process_interleaved_float, + resample_double_resampler_set_rate, + resample_double_resampler_get_rate, + resample_double_resampler_get_ratio, + resample_double_resampler_get_input_latency, + resample_double_resampler_set_quality, + resample_double_resampler_reset_mem, + resample_double_resampler_skip_zeros, + resample_double_resampler_strerror +}; + +SpeexResamplerState *resample_int_resampler_init (guint32 nb_channels, + guint32 in_rate, guint32 out_rate, gint quality, 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); +int resample_int_resampler_set_rate (SpeexResamplerState * st, + guint32 in_rate, guint32 out_rate); +void resample_int_resampler_get_rate (SpeexResamplerState * st, + guint32 * in_rate, guint32 * out_rate); void resample_int_resampler_get_ratio (SpeexResamplerState * st, guint32 * ratio_num, guint32 * ratio_den); - -int resample_float_resampler_get_input_latency (SpeexResamplerState * st); int resample_int_resampler_get_input_latency (SpeexResamplerState * st); - -int resample_float_resampler_set_quality (SpeexResamplerState * st, - gint quality); int resample_int_resampler_set_quality (SpeexResamplerState * st, gint quality); - -int resample_float_resampler_reset_mem (SpeexResamplerState * st); int resample_int_resampler_reset_mem (SpeexResamplerState * st); - -int resample_float_resampler_skip_zeros (SpeexResamplerState * st); int resample_int_resampler_skip_zeros (SpeexResamplerState * st); +const char * resample_int_resampler_strerror (gint err); -#define resample_resampler_strerror resample_int_resampler_strerror -const char *resample_resampler_strerror (gint err); +static const SpeexResampleFuncs int_funcs = +{ + resample_int_resampler_init, + resample_int_resampler_destroy, + resample_int_resampler_process_interleaved_int, + resample_int_resampler_set_rate, + resample_int_resampler_get_rate, + resample_int_resampler_get_ratio, + resample_int_resampler_get_input_latency, + resample_int_resampler_set_quality, + resample_int_resampler_reset_mem, + resample_int_resampler_skip_zeros, + resample_int_resampler_strerror +}; #endif /* __SPEEX_RESAMPLER_WRAPPER_H__ */ diff --git a/tests/check/elements/speexresample.c b/tests/check/elements/speexresample.c index a78ada6d1f..e070a2d96d 100644 --- a/tests/check/elements/speexresample.c +++ b/tests/check/elements/speexresample.c @@ -32,8 +32,14 @@ * get_peer, and then remove references in every test function */ static GstPad *mysrcpad, *mysinkpad; +#define RESAMPLE_CAPS_FLOAT \ + "audio/x-raw-float, " \ + "channels = (int) [ 1, MAX ], " \ + "rate = (int) [ 1, MAX ], " \ + "endianness = (int) BYTE_ORDER, " \ + "width = (int) { 32, 64 }" -#define RESAMPLE_CAPS_TEMPLATE_STRING \ +#define RESAMPLE_CAPS_INT \ "audio/x-raw-int, " \ "channels = (int) [ 1, MAX ], " \ "rate = (int) [ 1, MAX ], " \ @@ -42,6 +48,10 @@ static GstPad *mysrcpad, *mysinkpad; "depth = (int) 16, " \ "signed = (bool) TRUE" +#define RESAMPLE_CAPS_TEMPLATE_STRING \ + RESAMPLE_CAPS_FLOAT " ; " \ + RESAMPLE_CAPS_INT + static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, @@ -54,7 +64,8 @@ static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", ); static GstElement * -setup_speexresample (int channels, int inrate, int outrate) +setup_speexresample (int channels, int inrate, int outrate, int width, + gboolean fp) { GstElement *speexresample; GstCaps *caps; @@ -63,10 +74,15 @@ setup_speexresample (int channels, int inrate, int outrate) GST_DEBUG ("setup_speexresample"); speexresample = gst_check_setup_element ("speexresample"); - caps = gst_caps_from_string (RESAMPLE_CAPS_TEMPLATE_STRING); + if (fp) + caps = gst_caps_from_string (RESAMPLE_CAPS_FLOAT); + else + caps = gst_caps_from_string (RESAMPLE_CAPS_INT); structure = gst_caps_get_structure (caps, 0); gst_structure_set (structure, "channels", G_TYPE_INT, channels, - "rate", G_TYPE_INT, inrate, NULL); + "rate", G_TYPE_INT, inrate, "width", G_TYPE_INT, width, NULL); + if (!fp) + gst_structure_set (structure, "depth", G_TYPE_INT, width, NULL); fail_unless (gst_caps_is_fixed (caps)); fail_unless (gst_element_set_state (speexresample, @@ -77,10 +93,15 @@ setup_speexresample (int channels, int inrate, int outrate) gst_pad_set_caps (mysrcpad, caps); gst_caps_unref (caps); - caps = gst_caps_from_string (RESAMPLE_CAPS_TEMPLATE_STRING); + if (fp) + caps = gst_caps_from_string (RESAMPLE_CAPS_FLOAT); + else + caps = gst_caps_from_string (RESAMPLE_CAPS_INT); structure = gst_caps_get_structure (caps, 0); gst_structure_set (structure, "channels", G_TYPE_INT, channels, - "rate", G_TYPE_INT, outrate, NULL); + "rate", G_TYPE_INT, outrate, "width", G_TYPE_INT, width, NULL); + if (!fp) + gst_structure_set (structure, "depth", G_TYPE_INT, width, NULL); fail_unless (gst_caps_is_fixed (caps)); mysinkpad = gst_check_setup_sink_pad (speexresample, &sinktemplate, caps); @@ -157,7 +178,7 @@ test_perfect_stream_instance (int inrate, int outrate, int samples, int i, j; gint16 *p; - speexresample = setup_speexresample (2, inrate, outrate); + speexresample = setup_speexresample (2, inrate, outrate, 16, FALSE); caps = gst_pad_get_negotiated_caps (mysrcpad); fail_unless (gst_caps_is_fixed (caps)); @@ -212,7 +233,6 @@ GST_START_TEST (test_perfect_stream) { /* integral scalings */ test_perfect_stream_instance (48000, 24000, 500, 20); -#if 0 test_perfect_stream_instance (48000, 12000, 500, 20); test_perfect_stream_instance (12000, 24000, 500, 20); test_perfect_stream_instance (12000, 48000, 500, 20); @@ -224,7 +244,6 @@ GST_START_TEST (test_perfect_stream) /* wacky scalings */ test_perfect_stream_instance (12345, 54321, 500, 20); test_perfect_stream_instance (101, 99, 500, 20); -#endif } GST_END_TEST; @@ -246,7 +265,7 @@ test_discont_stream_instance (int inrate, int outrate, int samples, GST_DEBUG ("inrate:%d outrate:%d samples:%d numbuffers:%d", inrate, outrate, samples, numbuffers); - speexresample = setup_speexresample (2, inrate, outrate); + speexresample = setup_speexresample (2, inrate, outrate, 16, FALSE); caps = gst_pad_get_negotiated_caps (mysrcpad); fail_unless (gst_caps_is_fixed (caps)); @@ -332,7 +351,7 @@ GST_START_TEST (test_reuse) GstBuffer *inbuffer; GstCaps *caps; - speexresample = setup_speexresample (1, 9343, 48000); + speexresample = setup_speexresample (1, 9343, 48000, 16, FALSE); caps = gst_pad_get_negotiated_caps (mysrcpad); fail_unless (gst_caps_is_fixed (caps)); @@ -525,7 +544,7 @@ GST_START_TEST (test_live_switch) GstEvent *newseg; GstCaps *caps; - speexresample = setup_speexresample (4, 48000, 48000); + speexresample = setup_speexresample (4, 48000, 48000, 16, FALSE); /* Let the sinkpad act like something that can only handle things of * rate 48000- and can only allocate buffers for that rate, but if someone