[pulseaudio-discuss] [PATCH] resampler: Support speex resampler compiled with FIXED_POINT
Peter Meerwald
pmeerw at pmeerw.net
Wed Apr 2 15:27:23 PDT 2014
When Speex is compiled with FIXED_POINT defined, it scales float input
to +/-32768 instead of +/-1. In order to make floating point resampler
work with speex compiled with FIXED_POINT, we need to rescale the input
to speex.
Unfortunately, there is no easy way to tell how speex has been built,
so we probe at runtime.
A patch to fix speex was rejected saying that speex API is stable.
Further discussion is here
http://lists.openembedded.org/pipermail/openembedded-core/2014-January/087886.html
Signed-off-by: Peter Meerwald <pmeerw at pmeerw.net>
Reported-by: Fahad Arslan <fahad_arslan at mentor.com>
Cc: Damir Jelić <poljarinho at gmail.com>
---
src/pulsecore/resampler.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 80 insertions(+), 1 deletion(-)
diff --git a/src/pulsecore/resampler.c b/src/pulsecore/resampler.c
index 38389f3..4a9c1f5 100644
--- a/src/pulsecore/resampler.c
+++ b/src/pulsecore/resampler.c
@@ -39,6 +39,7 @@
#include <pulsecore/macro.h>
#include <pulsecore/strbuf.h>
#include <pulsecore/remap.h>
+#include <pulsecore/once.h>
#include <pulsecore/core-util.h>
#include "ffmpeg/avcodec.h"
@@ -1490,6 +1491,82 @@ static unsigned speex_resample_float(pa_resampler *r, const pa_memchunk *input,
return 0;
}
+/* float resampler when speexdsp is built with FIXED_POINT */
+static unsigned speex_resample_float_fixed(pa_resampler *r, const pa_memchunk *input, unsigned in_n_frames, pa_memchunk *output, unsigned *out_n_frames) {
+ pa_memblock *b;
+ float *in, *out, *t;
+ uint32_t inf = in_n_frames, outf = *out_n_frames, i;
+ unsigned nsamples = r->work_channels * in_n_frames;
+ SpeexResamplerState *state;
+
+ pa_assert(r);
+ pa_assert(input);
+ pa_assert(output);
+ pa_assert(out_n_frames);
+
+ state = r->impl.data;
+
+ b = pa_memblock_new(r->mempool, nsamples * sizeof(float));
+ t = pa_memblock_acquire(b);
+ in = pa_memblock_acquire_chunk(input);
+
+ /* speexdsp float API sample range is [-32768,32768] instead of [-1,1]
+ * when compiled with FIXED_POINT, rescale input before passing to speex. */
+ for (i = 0; i < nsamples; i++)
+ t[i] = 32768.0f * in[i];
+
+ pa_memblock_release(input->memblock);
+
+ out = pa_memblock_acquire_chunk(output);
+
+ pa_assert_se(speex_resampler_process_interleaved_float(state, t, &inf, out, &outf) == 0);
+
+ pa_memblock_release(b);
+ pa_memblock_unref(b);
+
+ pa_memblock_release(output->memblock);
+
+ pa_assert(inf == in_n_frames);
+ *out_n_frames = outf;
+
+ return 0;
+}
+
+/* speexdsp has a nasty issue: when built with FIXED_POINT, the float resampler
+ * expects samples in [-32768,32768] instead of [-1,1]; there is no easy way
+ * to figure out how speexdsp has been compiled. */
+
+static unsigned (*speex_resampler_float)(pa_resampler *r, const pa_memchunk *input, unsigned in_n_frames, pa_memchunk *output, unsigned *out_n_frames) = speex_resample_float;
+
+static void speex_probe_fixed_point() {
+ PA_ONCE_BEGIN {
+ float f_out = -1.0f, f_in = 1.0f;
+ spx_uint32_t in_len = 1, out_len = 1;
+
+ SpeexResamplerState *s = speex_resampler_init(1, 1, 1,
+ SPEEX_RESAMPLER_QUALITY_MIN, NULL);
+ if (!s)
+ goto done;
+
+ /* feed one sample */
+ if (speex_resampler_process_float(s, 0, &f_in, &in_len,
+ &f_out, &out_len) != RESAMPLER_ERR_SUCCESS)
+ goto done;
+
+ /* expecting sample has been processed, one sample output */
+ if (in_len != 1 && out_len != 1)
+ goto done;
+
+ /* FIXED_POINT implementation will output 0.0 */
+ if (fabsf(f_out) < 0.00001f)
+ speex_resampler_float = speex_resample_float_fixed;
+
+done:
+ if (s)
+ speex_resampler_destroy(s);
+ } PA_ONCE_END;
+}
+
static unsigned speex_resample_int(pa_resampler *r, const pa_memchunk *input, unsigned in_n_frames, pa_memchunk *output, unsigned *out_n_frames) {
int16_t *in, *out;
uint32_t inf = in_n_frames, outf = *out_n_frames;
@@ -1563,8 +1640,10 @@ static int speex_init(pa_resampler *r) {
} else {
pa_assert(r->method >= PA_RESAMPLER_SPEEX_FLOAT_BASE && r->method <= PA_RESAMPLER_SPEEX_FLOAT_MAX);
+ speex_probe_fixed_point();
+
q = r->method - PA_RESAMPLER_SPEEX_FLOAT_BASE;
- r->impl.resample = speex_resample_float;
+ r->impl.resample = speex_resampler_float;
}
pa_log_info("Choosing speex quality setting %i.", q);
--
1.9.1
More information about the pulseaudio-discuss
mailing list