[PATCH] resampler: Support speex resampler compiled with FIXED_POINT

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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



[Index of Archives]     [Linux Audio Users]     [AMD Graphics]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux