[pulseaudio-discuss] [PATCH 2/3] resampler: Add optional soxr resampler

Peter Meerwald pmeerw at pmeerw.net
Mon Aug 4 05:40:13 PDT 2014


see http://sourceforge.net/p/soxr/wiki/Home/

Signed-off-by: Peter Meerwald <pmeerw at pmeerw.net>
Signed-off-by: poljar (Damir Jelić) <poljarinho at gmail.com>

--

rebased and leftover handling is external to _resample() now;
this fixes a bug in the leftover_length computation since soxr supports
s16 and float32, hence sizeof(float) is wrong
---
 configure.ac                   |  17 ++++++
 src/Makefile.am                |   6 ++
 src/pulsecore/resampler.c      |  14 ++++-
 src/pulsecore/resampler.h      |   2 +
 src/pulsecore/resampler/soxr.c | 124 +++++++++++++++++++++++++++++++++++++++++
 5 files changed, 162 insertions(+), 1 deletion(-)
 create mode 100644 src/pulsecore/resampler/soxr.c

diff --git a/configure.ac b/configure.ac
index 837e81e..cf63eca 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1109,6 +1109,21 @@ AS_IF([test "x$with_speex" = "xyes" && test "x$HAVE_SPEEX" = "x0"],
 AM_CONDITIONAL([HAVE_SPEEX], [test "x$HAVE_SPEEX" = "x1"])
 AS_IF([test "x$HAVE_SPEEX" = "x1"], AC_DEFINE([HAVE_SPEEX], 1, [Have speex]))
 
+#### sox resampler support (optional) ####
+
+AC_ARG_ENABLE([soxr],
+    AS_HELP_STRING([--disable-soxr],[Disable optional soxr support]))
+
+AS_IF([test "x$enable_soxr" != "xno"],
+    [PKG_CHECK_MODULES(SOXR, soxr, HAVE_SOXR=1, HAVE_SOXR=0)],
+    HAVE_SOXR=0)
+
+AS_IF([test "x$enable_soxr" = "xyes" && test "x$HAVE_SOXR" = "x0"],
+    [AC_MSG_ERROR([*** soxr not found])])
+
+AM_CONDITIONAL([HAVE_SOXR], [test "x$HAVE_SOXR" = x1])
+AS_IF([test "x$HAVE_SOXR" = "x1"], AC_DEFINE([HAVE_SOXR], 1, [Have soxr]))
+
 #### Xen support (optional) ####
 
 AC_ARG_ENABLE([xen],
@@ -1445,6 +1460,7 @@ AS_IF([test "x$HAVE_FFTW" = "x1"], ENABLE_FFTW=yes, ENABLE_FFTW=no)
 AS_IF([test "x$HAVE_ORC" = "xyes"], ENABLE_ORC=yes, ENABLE_ORC=no)
 AS_IF([test "x$HAVE_ADRIAN_EC" = "x1"], ENABLE_ADRIAN_EC=yes, ENABLE_ADRIAN_EC=no)
 AS_IF([test "x$HAVE_SPEEX" = "x1"], ENABLE_SPEEX=yes, ENABLE_SPEEX=no)
+AS_IF([test "x$HAVE_SOXR" = "x1"], ENABLE_SOXR=yes, ENABLE_SOXR=no)
 AS_IF([test "x$HAVE_WEBRTC" = "x1"], ENABLE_WEBRTC=yes, ENABLE_WEBRTC=no)
 AS_IF([test "x$HAVE_TDB" = "x1"], ENABLE_TDB=yes, ENABLE_TDB=no)
 AS_IF([test "x$HAVE_GDBM" = "x1"], ENABLE_GDBM=yes, ENABLE_GDBM=no)
@@ -1501,6 +1517,7 @@ echo "
     Enable orc:                    ${ENABLE_ORC}
     Enable Adrian echo canceller:  ${ENABLE_ADRIAN_EC}
     Enable speex (resampler, AEC): ${ENABLE_SPEEX}
+    Enable soxr:                   ${ENABLE_SOXR}
     Enable WebRTC echo canceller:  ${ENABLE_WEBRTC}
     Enable gcov coverage:          ${ENABLE_GCOV}
     Enable unit tests:             ${ENABLE_TESTS}
diff --git a/src/Makefile.am b/src/Makefile.am
index 21eb365..9df52df 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -992,6 +992,12 @@ libpulsecore_ at PA_MAJORMINOR@_la_CFLAGS += $(LIBSAMPLERATE_CFLAGS)
 libpulsecore_ at PA_MAJORMINOR@_la_LIBADD += $(LIBSAMPLERATE_LIBS)
 endif
 
+if HAVE_SOXR
+libpulsecore_ at PA_MAJORMINOR@_la_SOURCES += pulsecore/resampler/soxr.c
+libpulsecore_ at PA_MAJORMINOR@_la_CFLAGS += $(SOXR_CFLAGS)
+libpulsecore_ at PA_MAJORMINOR@_la_LIBADD += $(SOXR_LIBS)
+endif
+
 # We split the foreign code off to not be annoyed by warnings we don't care about
 noinst_LTLIBRARIES += libpulsecore-foreign.la
 
diff --git a/src/pulsecore/resampler.c b/src/pulsecore/resampler.c
index de58f3f..e366be6 100644
--- a/src/pulsecore/resampler.c
+++ b/src/pulsecore/resampler.c
@@ -117,6 +117,11 @@ static int (* const init_table[])(pa_resampler *r) = {
     [PA_RESAMPLER_AUTO]                    = NULL,
     [PA_RESAMPLER_COPY]                    = copy_init,
     [PA_RESAMPLER_PEAKS]                   = pa_resampler_peaks_init,
+#ifdef HAVE_SOXR
+    [PA_RESAMPLER_SOXR]                    = pa_resampler_soxr_init,
+#else
+    [PA_RESAMPLER_SOXR]                    = NULL,
+#endif
 };
 
 static bool speex_is_fixed_point(void);
@@ -163,6 +168,7 @@ static pa_resample_method_t fix_method(
                 break;
             }
                                      /* Else fall through */
+        case PA_RESAMPLER_SOXR:
         case PA_RESAMPLER_FFMPEG:
             if (flags & PA_RESAMPLER_VARIABLE_RATE) {
                 pa_log_info("Resampler '%s' cannot do variable rate, reverting to resampler 'auto'.", pa_resample_method_to_string(method));
@@ -606,7 +612,8 @@ static const char * const resample_methods[] = {
     "ffmpeg",
     "auto",
     "copy",
-    "peaks"
+    "peaks",
+    "soxr"
 };
 
 const char *pa_resample_method_to_string(pa_resample_method_t m) {
@@ -634,6 +641,11 @@ int pa_resample_method_supported(pa_resample_method_t m) {
         return 0;
 #endif
 
+#ifndef HAVE_SOXR
+    if (m == PA_RESAMPLER_SOXR)
+        return 0;
+#endif
+
     return 1;
 }
 
diff --git a/src/pulsecore/resampler.h b/src/pulsecore/resampler.h
index 13d8c35..1d248e2 100644
--- a/src/pulsecore/resampler.h
+++ b/src/pulsecore/resampler.h
@@ -61,6 +61,7 @@ typedef enum pa_resample_method {
     PA_RESAMPLER_AUTO, /* automatic select based on sample format */
     PA_RESAMPLER_COPY,
     PA_RESAMPLER_PEAKS,
+    PA_RESAMPLER_SOXR,
     PA_RESAMPLER_MAX
 } pa_resample_method_t;
 
@@ -164,6 +165,7 @@ int pa_resampler_ffmpeg_init(pa_resampler *r);
 int pa_resampler_libsamplerate_init(pa_resampler *r);
 int pa_resampler_peaks_init(pa_resampler *r);
 int pa_resampler_speex_init(pa_resampler *r);
+int pa_resampler_soxr_init(pa_resampler *r);
 int pa_resampler_trivial_init(pa_resampler*r);
 
 #endif
diff --git a/src/pulsecore/resampler/soxr.c b/src/pulsecore/resampler/soxr.c
new file mode 100644
index 0000000..4614a4f
--- /dev/null
+++ b/src/pulsecore/resampler/soxr.c
@@ -0,0 +1,124 @@
+/***
+  This file is part of PulseAudio.
+
+  Copyright 2013 Damir Jelić
+
+  PulseAudio is free software; you can redistribute it and/or modify
+  it under the terms of the GNU Lesser General Public License as published
+  by the Free Software Foundation; either version 2.1 of the License,
+  or (at your option) any later version.
+
+  PulseAudio 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
+  General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with PulseAudio; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <soxr.h>
+
+#include "pulsecore/resampler.h"
+
+static void soxr_free(pa_resampler *r);
+
+static unsigned soxr_resample(pa_resampler *r, const pa_memchunk *input,
+                          unsigned in_n_frames, pa_memchunk *output,
+                          unsigned *out_n_frames) {
+    soxr_t state;
+    soxr_error_t error;
+    uint8_t *out;
+    uint8_t *in;
+    size_t odone;
+    size_t consumed;
+
+    pa_assert(r);
+    pa_assert(input);
+    pa_assert(output);
+    pa_assert(out_n_frames);
+
+    state = r->impl.data;
+
+    in = pa_memblock_acquire_chunk(input);
+    out = pa_memblock_acquire_chunk(output);
+
+    error = soxr_process(state, in, in_n_frames, &consumed, out, *out_n_frames, &odone);
+    pa_assert(error == 0);
+
+    pa_memblock_release(input->memblock);
+    pa_memblock_release(output->memblock);
+
+    *out_n_frames = odone;
+
+    return in_n_frames - consumed;
+}
+
+static void soxr_udpate_rates(pa_resampler *r) {
+    pa_assert(r);
+
+    soxr_free(r);
+    pa_resampler_soxr_init(r);
+}
+
+static void soxr_reset(pa_resampler *r) {
+    pa_assert(r);
+
+    /* TODO use soxr_clear() since it is the documented way to reset the resamlper;
+     * for some reason soxr_process crashes after we use soxr_clear() here */
+    soxr_free(r);
+    pa_resampler_soxr_init(r);
+}
+
+static void soxr_free(pa_resampler *r) {
+    soxr_t state;
+    pa_assert(r);
+
+    state = r->impl.data;
+    soxr_delete(state);
+}
+
+int pa_resampler_soxr_init(pa_resampler *r) {
+    soxr_t state;
+    soxr_error_t error;
+    soxr_io_spec_t io_spec;
+    soxr_runtime_spec_t runtime_spec;
+    soxr_quality_spec_t quality_spec;
+    unsigned int format;
+
+    pa_assert(r);
+
+    switch (r->work_format) {
+        case PA_SAMPLE_S16NE:
+            format = SOXR_INT16;
+            break;
+        case PA_SAMPLE_FLOAT32NE:
+            format = SOXR_FLOAT32;
+            break;
+        default:
+            pa_assert_not_reached();
+    }
+
+    io_spec = soxr_io_spec(format, format);
+    runtime_spec = soxr_runtime_spec(0);
+    quality_spec = soxr_quality_spec(SOXR_QQ, 0);
+
+    state = soxr_create(r->i_ss.rate, r->o_ss.rate, r->work_channels, &error, &io_spec, &quality_spec, &runtime_spec);
+
+    if (error)
+        return -1;
+
+    r->impl.resample = soxr_resample;
+    r->impl.update_rates = soxr_udpate_rates;
+    r->impl.reset = soxr_reset;
+    r->impl.free = soxr_free;
+    r->impl.data = state;
+
+    return 0;
+}
-- 
1.9.1



More information about the pulseaudio-discuss mailing list