big resampler rework: support integer-only resampling, support speex resampler
authorLennart Poettering <lennart@poettering.net>
Thu, 23 Aug 2007 22:35:40 +0000 (22:35 +0000)
committerLennart Poettering <lennart@poettering.net>
Thu, 23 Aug 2007 22:35:40 +0000 (22:35 +0000)
git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/lennart@1712 fefdeb5f-60dc-0310-8127-8f9354f1896f

src/pulsecore/resampler.c
src/pulsecore/resampler.h
src/pulsecore/sconv-s16be.c
src/pulsecore/sconv-s16be.h
src/pulsecore/sconv-s16le.c
src/pulsecore/sconv-s16le.h
src/pulsecore/sconv.c
src/pulsecore/sconv.h

index 1405d7e..57de0d1 100644 (file)
@@ -28,6 +28,7 @@
 #include <string.h>
 
 #include <samplerate.h>
+
 #include <liboil/liboilfuncs.h>
 #include <liboil/liboil.h>
 
 #include <pulsecore/log.h>
 #include <pulsecore/macro.h>
 
+#include "speexwrap.h"
+
 #include "resampler.h"
 
 struct pa_resampler {
     pa_resample_method_t resample_method;
     pa_sample_spec i_ss, o_ss;
     pa_channel_map i_cm, o_cm;
-    size_t i_fz, o_fz;
+    size_t i_fz, o_fz, w_sz;
     pa_mempool *mempool;
 
-    void (*impl_free)(pa_resampler *r);
-    void (*impl_update_input_rate)(pa_resampler *r, uint32_t rate);
-    void (*impl_update_output_rate)(pa_resampler *r, uint32_t rate);
-    void (*impl_run)(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out);
-    void *impl_data;
-};
-
-struct impl_libsamplerate {
     pa_memchunk buf1, buf2, buf3, buf4;
     unsigned buf1_samples, buf2_samples, buf3_samples, buf4_samples;
 
-    pa_convert_to_float32ne_func_t to_float32ne_func;
-    pa_convert_from_float32ne_func_t from_float32ne_func;
-    SRC_STATE *src_state;
+    pa_sample_format_t work_format;
+    
+    pa_convert_func_t to_work_format_func;
+    pa_convert_func_t from_work_format_func;
 
     int map_table[PA_CHANNELS_MAX][PA_CHANNELS_MAX];
     int map_required;
-};
 
-struct impl_trivial {
-    unsigned o_counter;
-    unsigned i_counter;
+    void (*impl_free)(pa_resampler *r);
+    void (*impl_update_rates)(pa_resampler *r);
+    void (*impl_resample)(pa_resampler *r, const pa_memchunk *in, unsigned in_samples, pa_memchunk *out, unsigned *out_samples);
+    
+    struct { /* data specific to the trivial resampler */
+        unsigned o_counter;
+        unsigned i_counter;
+    } trivial;
+
+    struct { /* data specific to libsamplerate */
+        SRC_STATE *state;
+    } src;
+
+    struct { /* data specific to speex */
+        SpeexResamplerState* state;
+    } speex;
 };
 
 static int libsamplerate_init(pa_resampler*r);
 static int trivial_init(pa_resampler*r);
+static int speex_init(pa_resampler*r);
+
+static void calc_map_table(pa_resampler *r);
+
+static int (* const init_table[])(pa_resampler*r) = {
+    [PA_RESAMPLER_SRC_SINC_BEST_QUALITY]   = libsamplerate_init,
+    [PA_RESAMPLER_SRC_SINC_MEDIUM_QUALITY] = libsamplerate_init,
+    [PA_RESAMPLER_SRC_SINC_FASTEST]        = libsamplerate_init,
+    [PA_RESAMPLER_SRC_ZERO_ORDER_HOLD]     = libsamplerate_init,
+    [PA_RESAMPLER_SRC_LINEAR]              = libsamplerate_init,
+    [PA_RESAMPLER_TRIVIAL]                 = trivial_init,
+    [PA_RESAMPLER_SPEEX_FLOAT_BASE+0]      = speex_init,
+    [PA_RESAMPLER_SPEEX_FLOAT_BASE+1]      = speex_init,
+    [PA_RESAMPLER_SPEEX_FLOAT_BASE+2]      = speex_init,
+    [PA_RESAMPLER_SPEEX_FLOAT_BASE+3]      = speex_init,
+    [PA_RESAMPLER_SPEEX_FLOAT_BASE+4]      = speex_init,
+    [PA_RESAMPLER_SPEEX_FLOAT_BASE+5]      = speex_init,
+    [PA_RESAMPLER_SPEEX_FLOAT_BASE+6]      = speex_init,
+    [PA_RESAMPLER_SPEEX_FLOAT_BASE+7]      = speex_init,
+    [PA_RESAMPLER_SPEEX_FLOAT_BASE+8]      = speex_init,
+    [PA_RESAMPLER_SPEEX_FLOAT_BASE+9]      = speex_init,
+    [PA_RESAMPLER_SPEEX_FLOAT_BASE+10]     = speex_init,
+    [PA_RESAMPLER_SPEEX_FIXED_BASE+0]      = speex_init,
+    [PA_RESAMPLER_SPEEX_FIXED_BASE+1]      = speex_init,
+    [PA_RESAMPLER_SPEEX_FIXED_BASE+2]      = speex_init,
+    [PA_RESAMPLER_SPEEX_FIXED_BASE+3]      = speex_init,
+    [PA_RESAMPLER_SPEEX_FIXED_BASE+4]      = speex_init,
+    [PA_RESAMPLER_SPEEX_FIXED_BASE+5]      = speex_init,
+    [PA_RESAMPLER_SPEEX_FIXED_BASE+6]      = speex_init,
+    [PA_RESAMPLER_SPEEX_FIXED_BASE+7]      = speex_init,
+    [PA_RESAMPLER_SPEEX_FIXED_BASE+8]      = speex_init,
+    [PA_RESAMPLER_SPEEX_FIXED_BASE+9]      = speex_init,
+    [PA_RESAMPLER_SPEEX_FIXED_BASE+10]     = speex_init,
+    [PA_RESAMPLER_AUTO]                    = NULL,
+};
+
+static inline size_t sample_size(pa_sample_format_t f) {
+    pa_sample_spec ss = {
+        .format = f,
+        .rate = 0,
+        .channels = 1
+    };
+
+    return pa_sample_size(&ss);
+}
 
 pa_resampler* pa_resampler_new(
         pa_mempool *pool,
@@ -87,16 +140,25 @@ pa_resampler* pa_resampler_new(
     pa_assert(b);
     pa_assert(pa_sample_spec_valid(a));
     pa_assert(pa_sample_spec_valid(b));
-    pa_assert(resample_method != PA_RESAMPLER_INVALID);
-
+    pa_assert(resample_method >= 0);
+    pa_assert(resample_method < PA_RESAMPLER_MAX);
+
+    /* Fix method */
+    if (resample_method == PA_RESAMPLER_AUTO) {
+        if (a->format == PA_SAMPLE_FLOAT32LE || a->format == PA_SAMPLE_FLOAT32BE ||
+            b->format == PA_SAMPLE_FLOAT32LE || b->format == PA_SAMPLE_FLOAT32BE)
+            resample_method = PA_RESAMPLER_SPEEX_FLOAT_BASE + 0;
+        else
+            resample_method = PA_RESAMPLER_SPEEX_FIXED_BASE + 0;
+    }
+    
     r = pa_xnew(pa_resampler, 1);
-    r->impl_data = NULL;
     r->mempool = pool;
     r->resample_method = resample_method;
 
     r->impl_free = NULL;
-    r->impl_update_input_rate = NULL;
-    r->impl_run = NULL;
+    r->impl_update_rates = NULL;
+    r->impl_resample = NULL;
 
     /* Fill sample specs */
     r->i_ss = *a;
@@ -115,25 +177,62 @@ pa_resampler* pa_resampler_new(
     r->i_fz = pa_frame_size(a);
     r->o_fz = pa_frame_size(b);
 
-    /* Choose implementation */
-    if (a->channels != b->channels ||
-        a->format != b->format ||
-        !pa_channel_map_equal(&r->i_cm, &r->o_cm) ||
-        resample_method != PA_RESAMPLER_TRIVIAL) {
+    pa_memchunk_reset(&r->buf1);
+    pa_memchunk_reset(&r->buf2);
+    pa_memchunk_reset(&r->buf3);
+    pa_memchunk_reset(&r->buf4);
+
+    r->buf1_samples = r->buf2_samples = r->buf3_samples = r->buf4_samples = 0;
 
-        /* Use the libsamplerate based resampler for the complicated cases */
-        if (resample_method == PA_RESAMPLER_TRIVIAL)
-            r->resample_method = PA_RESAMPLER_SRC_ZERO_ORDER_HOLD;
+    calc_map_table(r);
 
-        if (libsamplerate_init(r) < 0)
+    pa_log_info("Using resampler '%s'", pa_resample_method_to_string(resample_method));
+    
+    if (resample_method >= PA_RESAMPLER_SPEEX_FIXED_BASE && resample_method <= PA_RESAMPLER_SPEEX_FIXED_MAX)
+        r->work_format = PA_SAMPLE_S16NE;
+    else if (resample_method == PA_RESAMPLER_TRIVIAL) {
+
+        if (r->map_required || a->format != b->format) {
+
+            if (a->format == PA_SAMPLE_FLOAT32NE || a->format == PA_SAMPLE_FLOAT32RE)
+                r->work_format = PA_SAMPLE_FLOAT32NE;
+            else
+                r->work_format = PA_SAMPLE_S16NE;
+            
+        } else
+            r->work_format = a->format;
+        
+    } else
+        r->work_format = PA_SAMPLE_FLOAT32NE;
+
+    r->w_sz = sample_size(r->work_format);
+        
+    if (r->i_ss.format == r->work_format)
+        r->to_work_format_func = NULL;
+    else if (r->work_format == PA_SAMPLE_FLOAT32NE) {
+        if (!(r->to_work_format_func = pa_get_convert_to_float32ne_function(r->i_ss.format)))
             goto fail;
+    } else {
+        pa_assert(r->work_format == PA_SAMPLE_S16NE);
+        if (!(r->to_work_format_func = pa_get_convert_to_s16ne_function(r->i_ss.format)))
+            goto fail;
+    }
 
+    if (r->o_ss.format == r->work_format)
+        r->from_work_format_func = NULL;
+    else if (r->work_format == PA_SAMPLE_FLOAT32NE) {
+        if (!(r->from_work_format_func = pa_get_convert_from_float32ne_function(r->o_ss.format)))
+            goto fail;
     } else {
-        /* Use our own simple non-fp resampler for the trivial cases and when the user selects it */
-        if (trivial_init(r) < 0)
+        pa_assert(r->work_format == PA_SAMPLE_S16NE);
+        if (!(r->from_work_format_func = pa_get_convert_from_s16ne_function(r->o_ss.format)))
             goto fail;
     }
 
+    /* initialize implementation */
+    if (init_table[resample_method](r) < 0)
+        goto fail;
+
     return r;
 
 fail:
@@ -149,6 +248,15 @@ void pa_resampler_free(pa_resampler *r) {
     if (r->impl_free)
         r->impl_free(r);
 
+    if (r->buf1.memblock)
+        pa_memblock_unref(r->buf1.memblock);
+    if (r->buf2.memblock)
+        pa_memblock_unref(r->buf2.memblock);
+    if (r->buf3.memblock)
+        pa_memblock_unref(r->buf3.memblock);
+    if (r->buf4.memblock)
+        pa_memblock_unref(r->buf4.memblock);
+    
     pa_xfree(r);
 }
 
@@ -160,9 +268,7 @@ void pa_resampler_set_input_rate(pa_resampler *r, uint32_t rate) {
         return;
 
     r->i_ss.rate = rate;
-
-    if (r->impl_update_input_rate)
-        r->impl_update_input_rate(r, rate);
+    r->impl_update_rates(r);
 }
 
 void pa_resampler_set_output_rate(pa_resampler *r, uint32_t rate) {
@@ -173,15 +279,7 @@ void pa_resampler_set_output_rate(pa_resampler *r, uint32_t rate) {
         return;
 
     r->o_ss.rate = rate;
-
-    if (r->impl_update_output_rate)
-        r->impl_update_output_rate(r, rate);
-}
-
-void pa_resampler_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out) {
-    pa_assert(r && in && out && r->impl_run);
-
-    r->impl_run(r, in, out);
+    r->impl_update_rates(r);
 }
 
 size_t pa_resampler_request(pa_resampler *r, size_t out_length) {
@@ -192,6 +290,7 @@ size_t pa_resampler_request(pa_resampler *r, size_t out_length) {
 
 pa_resample_method_t pa_resampler_get_method(pa_resampler *r) {
     pa_assert(r);
+    
     return r->resample_method;
 }
 
@@ -201,7 +300,30 @@ static const char * const resample_methods[] = {
     "src-sinc-fastest",
     "src-zero-order-hold",
     "src-linear",
-    "trivial"
+    "trivial",
+    "speex-float-0",
+    "speex-float-1",
+    "speex-float-2",
+    "speex-float-3",
+    "speex-float-4",
+    "speex-float-5",
+    "speex-float-6",
+    "speex-float-7",
+    "speex-float-8",
+    "speex-float-9",
+    "speex-float-10",
+    "speex-fixed-0",
+    "speex-fixed-1",
+    "speex-fixed-2",
+    "speex-fixed-3",
+    "speex-fixed-4",
+    "speex-fixed-5",
+    "speex-fixed-6",
+    "speex-fixed-7",
+    "speex-fixed-8",
+    "speex-fixed-9",
+    "speex-fixed-10",
+    "auto"
 };
 
 const char *pa_resample_method_to_string(pa_resample_method_t m) {
@@ -221,44 +343,21 @@ pa_resample_method_t pa_parse_resample_method(const char *string) {
         if (!strcmp(string, resample_methods[m]))
             return m;
 
-    return PA_RESAMPLER_INVALID;
-}
-
+    if (!strcmp(string, "speex-fixed"))
+        return PA_RESAMPLER_SPEEX_FIXED_BASE + 0;
 
-/*** libsamplerate based implementation ***/
+    if (!strcmp(string, "speex-float"))
+        return PA_RESAMPLER_SPEEX_FLOAT_BASE + 0;
 
-static void libsamplerate_free(pa_resampler *r) {
-    struct impl_libsamplerate *u;
-
-    pa_assert(r);
-    pa_assert(r->impl_data);
-
-    u = r->impl_data;
-
-    if (u->src_state)
-        src_delete(u->src_state);
-
-    if (u->buf1.memblock)
-        pa_memblock_unref(u->buf1.memblock);
-    if (u->buf2.memblock)
-        pa_memblock_unref(u->buf2.memblock);
-    if (u->buf3.memblock)
-        pa_memblock_unref(u->buf3.memblock);
-    if (u->buf4.memblock)
-        pa_memblock_unref(u->buf4.memblock);
-    pa_xfree(u);
+    return PA_RESAMPLER_INVALID;
 }
 
 static void calc_map_table(pa_resampler *r) {
-    struct impl_libsamplerate *u;
     unsigned oc;
     
     pa_assert(r);
-    pa_assert(r->impl_data);
-
-    u = r->impl_data;
 
-    if (!(u->map_required = (r->i_ss.channels != r->o_ss.channels || !pa_channel_map_equal(&r->i_cm, &r->o_cm))))
+    if (!(r->map_required = (r->i_ss.channels != r->o_ss.channels || !pa_channel_map_equal(&r->i_cm, &r->o_cm))))
         return;
 
     for (oc = 0; oc < r->o_ss.channels; oc++) {
@@ -276,17 +375,16 @@ static void calc_map_table(pa_resampler *r) {
                 (a == PA_CHANNEL_POSITION_LEFT && b == PA_CHANNEL_POSITION_MONO) ||
                 (a == PA_CHANNEL_POSITION_RIGHT && b == PA_CHANNEL_POSITION_MONO))
 
-                u->map_table[oc][i++] = ic;
+                r->map_table[oc][i++] = ic;
         }
 
         /* Add an end marker */
         if (i < PA_CHANNELS_MAX)
-            u->map_table[oc][i] = -1;
+            r->map_table[oc][i] = -1;
     }
 }
 
-static pa_memchunk* convert_to_float(pa_resampler *r, pa_memchunk *input) {
-    struct impl_libsamplerate *u;
+static pa_memchunk* convert_to_work_format(pa_resampler *r, pa_memchunk *input) {
     unsigned n_samples;
     void *src, *dst;
 
@@ -294,192 +392,193 @@ static pa_memchunk* convert_to_float(pa_resampler *r, pa_memchunk *input) {
     pa_assert(input);
     pa_assert(input->memblock);
 
-    pa_assert(r->impl_data);
-    u = r->impl_data;
-
-    /* Convert the incoming sample into floats and place them in buf1 */
+    /* Convert the incoming sample into the work sample format and place them in buf1 */
 
-    if (!u->to_float32ne_func || !input->length)
+    if (!r->to_work_format_func || !input->length)
         return input;
 
     n_samples = (input->length / r->i_fz) * r->i_ss.channels;
 
-    if (!u->buf1.memblock || u->buf1_samples < n_samples) {
-        if (u->buf1.memblock)
-            pa_memblock_unref(u->buf1.memblock);
+    r->buf1.index = 0;
+    r->buf1.length = r->w_sz * n_samples;
+    
+    if (!r->buf1.memblock || r->buf1_samples < n_samples) {
+        if (r->buf1.memblock)
+            pa_memblock_unref(r->buf1.memblock);
 
-        u->buf1_samples = n_samples;
-        u->buf1.memblock = pa_memblock_new(r->mempool, u->buf1.length = sizeof(float) * n_samples);
-        u->buf1.index = 0;
+        r->buf1_samples = n_samples;
+        r->buf1.memblock = pa_memblock_new(r->mempool, r->buf1.length);
     }
 
     src = (uint8_t*) pa_memblock_acquire(input->memblock) + input->index;
-    dst = (uint8_t*) pa_memblock_acquire(u->buf1.memblock);
+    dst = (uint8_t*) pa_memblock_acquire(r->buf1.memblock);
 
-    u->to_float32ne_func(n_samples, src, dst);
+    r->to_work_format_func(n_samples, src, dst);
 
     pa_memblock_release(input->memblock);
-    pa_memblock_release(u->buf1.memblock);
-
-    u->buf1.length = sizeof(float) * n_samples;
+    pa_memblock_release(r->buf1.memblock);
 
-    return &u->buf1;
+    return &r->buf1;
 }
 
 static pa_memchunk *remap_channels(pa_resampler *r, pa_memchunk *input) {
-    struct impl_libsamplerate *u;
     unsigned in_n_samples, out_n_samples, n_frames;
     int i_skip, o_skip;
     unsigned oc;
-    float *src, *dst;
+    void *src, *dst;
 
     pa_assert(r);
     pa_assert(input);
     pa_assert(input->memblock);
 
-    pa_assert(r->impl_data);
-    u = r->impl_data;
-
     /* Remap channels and place the result int buf2 */
 
-    if (!u->map_required || !input->length)
+    if (!r->map_required || !input->length)
         return input;
 
-    in_n_samples = input->length / sizeof(float);
+    in_n_samples = input->length / r->w_sz;
     n_frames = in_n_samples / r->i_ss.channels;
     out_n_samples = n_frames * r->o_ss.channels;
 
-    if (!u->buf2.memblock || u->buf2_samples < out_n_samples) {
-        if (u->buf2.memblock)
-            pa_memblock_unref(u->buf2.memblock);
+    r->buf2.index = 0;
+    r->buf2.length = r->w_sz * out_n_samples;
+    
+    if (!r->buf2.memblock || r->buf2_samples < out_n_samples) {
+        if (r->buf2.memblock)
+            pa_memblock_unref(r->buf2.memblock);
 
-        u->buf2_samples = out_n_samples;
-        u->buf2.memblock = pa_memblock_new(r->mempool, u->buf2.length = sizeof(float) * out_n_samples);
-        u->buf2.index = 0;
+        r->buf2_samples = out_n_samples;
+        r->buf2.memblock = pa_memblock_new(r->mempool, r->buf2.length);
     }
 
-    src = (float*) ((uint8_t*) pa_memblock_acquire(input->memblock) + input->index);
-    dst = (float*) pa_memblock_acquire(u->buf2.memblock);
-
-    memset(dst, 0, u->buf2.length);
-
-    o_skip = sizeof(float) * r->o_ss.channels;
-    i_skip = sizeof(float) * r->i_ss.channels;
-
-    for (oc = 0; oc < r->o_ss.channels; oc++) {
-        unsigned i;
-        static const float one = 1.0;
-
-        for (i = 0; i < PA_CHANNELS_MAX && u->map_table[oc][i] >= 0; i++)
-            oil_vectoradd_f32(
-                dst + oc, o_skip,
-                dst + oc, o_skip,
-                src + u->map_table[oc][i], i_skip,
-                n_frames,
-                &one, &one);
+    src = ((uint8_t*) pa_memblock_acquire(input->memblock) + input->index);
+    dst = pa_memblock_acquire(r->buf2.memblock);
+
+    memset(dst, 0, r->buf2.length);
+
+    o_skip = r->w_sz * r->o_ss.channels;
+    i_skip = r->w_sz * r->i_ss.channels;
+
+    switch (r->work_format) {
+        case PA_SAMPLE_FLOAT32NE:
+            
+            for (oc = 0; oc < r->o_ss.channels; oc++) {
+                unsigned i;
+                static const float one = 1.0;
+                
+                for (i = 0; i < PA_CHANNELS_MAX && r->map_table[oc][i] >= 0; i++)
+                    oil_vectoradd_f32(
+                            (float*) dst + oc, o_skip,
+                            (float*) dst + oc, o_skip,
+                            (float*) src + r->map_table[oc][i], i_skip,
+                            n_frames,
+                            &one, &one);
+            }
+
+            break;
+
+        case PA_SAMPLE_S16NE:
+
+            for (oc = 0; oc < r->o_ss.channels; oc++) {
+                unsigned i;
+                static const int16_t one = 1;
+                
+                for (i = 0; i < PA_CHANNELS_MAX && r->map_table[oc][i] >= 0; i++)
+                    oil_vectoradd_s16(
+                            (int16_t*) dst + oc, o_skip,
+                            (int16_t*) dst + oc, o_skip,
+                            (int16_t*) src + r->map_table[oc][i], i_skip,
+                            n_frames,
+                            &one, &one);
+            }
+
+            break;
+
+        default:
+            pa_assert_not_reached();
     }
 
     pa_memblock_release(input->memblock);
-    pa_memblock_release(u->buf2.memblock);
+    pa_memblock_release(r->buf2.memblock);
 
-    u->buf2.length = out_n_samples * sizeof(float);
+    r->buf2.length = out_n_samples * r->w_sz;
 
-    return &u->buf2;
+    return &r->buf2;
 }
 
 static pa_memchunk *resample(pa_resampler *r, pa_memchunk *input) {
-    struct impl_libsamplerate *u;
-    SRC_DATA data;
     unsigned in_n_frames, in_n_samples;
     unsigned out_n_frames, out_n_samples;
-    int ret;
 
     pa_assert(r);
     pa_assert(input);
-    pa_assert(r->impl_data);
-    u = r->impl_data;
 
     /* Resample the data and place the result in buf3 */
 
-    if (!u->src_state || !input->length)
+    if (!r->impl_resample || !input->length)
         return input;
 
-    in_n_samples = input->length / sizeof(float);
+    in_n_samples = input->length / r->w_sz;
     in_n_frames = in_n_samples / r->o_ss.channels;
 
     out_n_frames = ((in_n_frames*r->o_ss.rate)/r->i_ss.rate)+1024;
     out_n_samples = out_n_frames * r->o_ss.channels;
 
-    if (!u->buf3.memblock || u->buf3_samples < out_n_samples) {
-        if (u->buf3.memblock)
-            pa_memblock_unref(u->buf3.memblock);
+    r->buf3.index = 0;
+    r->buf3.length = r->w_sz * out_n_samples;
+    
+    if (!r->buf3.memblock || r->buf3_samples < out_n_samples) {
+        if (r->buf3.memblock)
+            pa_memblock_unref(r->buf3.memblock);
 
-        u->buf3_samples = out_n_samples;
-        u->buf3.memblock = pa_memblock_new(r->mempool, u->buf3.length = sizeof(float) * out_n_samples);
-        u->buf3.index = 0;
+        r->buf3_samples = out_n_samples;
+        r->buf3.memblock = pa_memblock_new(r->mempool, r->buf3.length);
     }
 
-    data.data_in = (float*) ((uint8_t*) pa_memblock_acquire(input->memblock) + input->index);
-    data.input_frames = in_n_frames;
-
-    data.data_out = (float*) pa_memblock_acquire(u->buf3.memblock);
-    data.output_frames = out_n_frames;
-
-    data.src_ratio = (double) r->o_ss.rate / r->i_ss.rate;
-    data.end_of_input = 0;
-
-    ret = src_process(u->src_state, &data);
-    pa_assert(ret == 0);
-    pa_assert((unsigned) data.input_frames_used == in_n_frames);
-
-    pa_memblock_release(input->memblock);
-    pa_memblock_release(u->buf3.memblock);
-
-    u->buf3.length = data.output_frames_gen * sizeof(float) * r->o_ss.channels;
-
-    return &u->buf3;
+    r->impl_resample(r, input, in_n_frames, &r->buf3, &out_n_frames);
+    r->buf3.length = out_n_frames * r->w_sz * r->o_ss.channels;
+    
+    return &r->buf3;
 }
 
-static pa_memchunk *convert_from_float(pa_resampler *r, pa_memchunk *input) {
-    struct impl_libsamplerate *u;
+static pa_memchunk *convert_from_work_format(pa_resampler *r, pa_memchunk *input) {
     unsigned n_samples, n_frames;
     void *src, *dst;
 
     pa_assert(r);
     pa_assert(input);
-    pa_assert(r->impl_data);
-    u = r->impl_data;
 
     /* Convert the data into the correct sample type and place the result in buf4 */
 
-    if (!u->from_float32ne_func || !input->length)
+    if (!r->from_work_format_func || !input->length)
         return input;
 
-    n_frames = input->length / sizeof(float) / r->o_ss.channels;
-    n_samples = n_frames * r->o_ss.channels;
+    n_samples = input->length / r->w_sz;
+    n_frames =  n_samples / r->o_ss.channels;
 
-    if (!u->buf4.memblock || u->buf4_samples < n_samples) {
-        if (u->buf4.memblock)
-            pa_memblock_unref(u->buf4.memblock);
+    r->buf4.index = 0;
+    r->buf4.length = r->o_fz * n_frames;
+        
+    if (!r->buf4.memblock || r->buf4_samples < n_samples) {
+        if (r->buf4.memblock)
+            pa_memblock_unref(r->buf4.memblock);
 
-        u->buf4_samples = n_samples;
-        u->buf4.memblock = pa_memblock_new(r->mempool, u->buf4.length = r->o_fz * n_frames);
-        u->buf4.index = 0;
+        r->buf4_samples = n_samples;
+        r->buf4.memblock = pa_memblock_new(r->mempool, r->buf4.length);
     }
 
     src = (uint8_t*) pa_memblock_acquire(input->memblock) + input->index;
-    dst = pa_memblock_acquire(u->buf4.memblock);
-    u->from_float32ne_func(n_samples, src, dst);
+    dst = pa_memblock_acquire(r->buf4.memblock);
+    r->from_work_format_func(n_samples, src, dst);
     pa_memblock_release(input->memblock);
-    pa_memblock_release(u->buf4.memblock);
+    pa_memblock_release(r->buf4.memblock);
 
-    u->buf4.length = r->o_fz * n_frames;
+    r->buf4.length = r->o_fz * n_frames;
 
-    return &u->buf4;
+    return &r->buf4;
 }
 
-static void libsamplerate_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out) {
-    struct impl_libsamplerate *u;
+void pa_resampler_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out) {
     pa_memchunk *buf;
 
     pa_assert(r);
@@ -488,19 +587,16 @@ static void libsamplerate_run(pa_resampler *r, const pa_memchunk *in, pa_memchun
     pa_assert(in->length);
     pa_assert(in->memblock);
     pa_assert(in->length % r->i_fz == 0);
-    pa_assert(r->impl_data);
-
-    u = r->impl_data;
 
     buf = (pa_memchunk*) in;
-    buf = convert_to_float(r, buf);
+    buf = convert_to_work_format(r, buf);
     buf = remap_channels(r, buf);
     buf = resample(r, buf);
 
     if (buf->length) {
-        buf = convert_from_float(r, buf);
+        buf = convert_from_work_format(r, buf);
         *out = *buf;
-
+        
         if (buf == in)
             pa_memblock_ref(buf->memblock);
         else
@@ -509,188 +605,222 @@ static void libsamplerate_run(pa_resampler *r, const pa_memchunk *in, pa_memchun
         pa_memchunk_reset(out);
 }
 
-static void libsamplerate_update_input_rate(pa_resampler *r, uint32_t rate) {
-    struct impl_libsamplerate *u;
+/*** libsamplerate based implementation ***/
 
+static void libsamplerate_resample(pa_resampler *r, const pa_memchunk *input, unsigned in_n_frames, pa_memchunk *output, unsigned *out_n_frames) {
+    SRC_DATA data;
+    
     pa_assert(r);
-    pa_assert(rate > 0);
-    pa_assert(r->impl_data);
-    u = r->impl_data;
+    pa_assert(input);
+    pa_assert(output);
+    pa_assert(out_n_frames);
+    
+    memset(&data, 0, sizeof(data));
+    
+    data.data_in = (float*) ((uint8_t*) pa_memblock_acquire(input->memblock) + input->index);
+    data.input_frames = in_n_frames;
 
-    if (!u->src_state) {
-        int err;
-        u->src_state = src_new(r->resample_method, r->o_ss.channels, &err);
-        pa_assert(u->src_state);
-    } else {
-        int ret = src_set_ratio(u->src_state, (double) r->o_ss.rate / rate);
-        pa_assert(ret == 0);
-    }
-}
+    data.data_out = (float*) ((uint8_t*) pa_memblock_acquire(output->memblock) + output->index);
+    data.output_frames = *out_n_frames;
 
-static void libsamplerate_update_output_rate(pa_resampler *r, uint32_t rate) {
-    struct impl_libsamplerate *u;
+    data.src_ratio = (double) r->o_ss.rate / r->i_ss.rate;
+    data.end_of_input = 0;
+
+    pa_assert_se(src_process(r->src.state, &data) == 0);
+    pa_assert((unsigned) data.input_frames_used == in_n_frames);
+
+    pa_memblock_release(input->memblock);
+    pa_memblock_release(output->memblock);
 
+    *out_n_frames = data.output_frames_gen;
+}
+
+static void libsamplerate_update_rates(pa_resampler *r) {
     pa_assert(r);
-    pa_assert(rate > 0);
-    pa_assert(r->impl_data);
-    u = r->impl_data;
 
-    if (!u->src_state) {
-        int err;
-        u->src_state = src_new(r->resample_method, r->o_ss.channels, &err);
-        pa_assert(u->src_state);
-    } else {
-        int ret = src_set_ratio(u->src_state, (double) rate / r->i_ss.rate);
-        pa_assert(ret == 0);
-    }
+    pa_assert_se(src_set_ratio(r->src.state, (double) r->o_ss.rate / r->i_ss.rate) == 0);
+}
+
+static void libsamplerate_free(pa_resampler *r) {
+    pa_assert(r);
+    
+    if (r->src.state)
+        src_delete(r->src.state);
 }
 
 static int libsamplerate_init(pa_resampler *r) {
-    struct impl_libsamplerate *u = NULL;
     int err;
+    
+    pa_assert(r);
+    
+    if (!(r->src.state = src_new(r->resample_method, r->o_ss.channels, &err)))
+        return -1;
 
-    r->impl_data = u = pa_xnew(struct impl_libsamplerate, 1);
-
-    pa_memchunk_reset(&u->buf1);
-    pa_memchunk_reset(&u->buf2);
-    pa_memchunk_reset(&u->buf3);
-    pa_memchunk_reset(&u->buf4);
-    u->buf1_samples = u->buf2_samples = u->buf3_samples = u->buf4_samples = 0;
+    r->impl_free = libsamplerate_free;
+    r->impl_update_rates = libsamplerate_update_rates;
+    r->impl_resample = libsamplerate_resample;
 
-    if (r->i_ss.format == PA_SAMPLE_FLOAT32NE)
-        u->to_float32ne_func = NULL;
-    else if (!(u->to_float32ne_func = pa_get_convert_to_float32ne_function(r->i_ss.format)))
-        goto fail;
+    return 0;
+}
 
-    if (r->o_ss.format == PA_SAMPLE_FLOAT32NE)
-        u->from_float32ne_func = NULL;
-    else if (!(u->from_float32ne_func = pa_get_convert_from_float32ne_function(r->o_ss.format)))
-        goto fail;
+/*** speex based implementation ***/
 
-    if (r->o_ss.rate == r->i_ss.rate)
-        u->src_state = NULL;
-    else if (!(u->src_state = src_new(r->resample_method, r->o_ss.channels, &err)))
-        goto fail;
+static void speex_resample_float(pa_resampler *r, const pa_memchunk *input, unsigned in_n_frames, pa_memchunk *output, unsigned *out_n_frames) {
+    float *in, *out;
+    uint32_t inf = in_n_frames, outf = *out_n_frames;
 
-    r->impl_free = libsamplerate_free;
-    r->impl_update_input_rate = libsamplerate_update_input_rate;
-    r->impl_update_output_rate = libsamplerate_update_output_rate;
-    r->impl_run = libsamplerate_run;
+    pa_assert(r);
+    pa_assert(input);
+    pa_assert(output);
+    pa_assert(out_n_frames);
+    
+    in = (float*) ((uint8_t*) pa_memblock_acquire(input->memblock) + input->index);
+    out = (float*) ((uint8_t*) pa_memblock_acquire(output->memblock) + output->index);
 
-    calc_map_table(r);
+    pa_assert_se(paspfl_resampler_process_interleaved_float(r->speex.state, in, &inf, out, &outf) == 0);
 
-    return 0;
+    pa_memblock_release(input->memblock);
+    pa_memblock_release(output->memblock);
 
-fail:
-    pa_xfree(u);
-    return -1;
+    pa_assert(inf == in_n_frames);
+    *out_n_frames = outf;
 }
 
-/* Trivial implementation */
-
-static void trivial_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out) {
-    size_t fz;
-    unsigned  n_frames;
-    struct impl_trivial *u;
+static void 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;
 
     pa_assert(r);
-    pa_assert(in);
-    pa_assert(out);
-    pa_assert(r->impl_data);
-
-    u = r->impl_data;
-
-    fz = r->i_fz;
-    pa_assert(fz == r->o_fz);
+    pa_assert(input);
+    pa_assert(output);
+    pa_assert(out_n_frames);
+    
+    in = (int16_t*) ((uint8_t*) pa_memblock_acquire(input->memblock) + input->index);
+    out = (int16_t*) ((uint8_t*) pa_memblock_acquire(output->memblock) + output->index);
 
-    n_frames = in->length/fz;
+    pa_assert_se(paspfx_resampler_process_interleaved_int(r->speex.state, in, &inf, out, &outf) == 0);
 
-    if (r->i_ss.rate == r->o_ss.rate) {
+    pa_memblock_release(input->memblock);
+    pa_memblock_release(output->memblock);
 
-        /* In case there's no diefference in sample types, do nothing */
-        *out = *in;
-        pa_memblock_ref(out->memblock);
+    pa_assert(inf == in_n_frames);
+    *out_n_frames = outf;
+}
 
-        u->o_counter += n_frames;
-    } else {
-        /* Do real resampling */
-        size_t l;
-        unsigned o_index;
-        void *src, *dst;
+static void speex_update_rates(pa_resampler *r) {
+    pa_assert(r);
 
-        /* The length of the new memory block rounded up */
-        l = ((((n_frames+1) * r->o_ss.rate) / r->i_ss.rate) + 1) * fz;
+    if (r->resample_method >= PA_RESAMPLER_SPEEX_FIXED_BASE && r->resample_method <= PA_RESAMPLER_SPEEX_FIXED_MAX) 
+        pa_assert_se(paspfx_resampler_set_rate(r->speex.state, r->i_ss.rate, r->o_ss.rate) == 0);
+    else {
+        pa_assert(r->resample_method >= PA_RESAMPLER_SPEEX_FLOAT_BASE && r->resample_method <= PA_RESAMPLER_SPEEX_FLOAT_MAX);
+        pa_assert_se(paspfl_resampler_set_rate(r->speex.state, r->i_ss.rate, r->o_ss.rate) == 0);
+    }
+}
 
-        out->index = 0;
-        out->memblock = pa_memblock_new(r->mempool, l);
+static void speex_free(pa_resampler *r) {
+    pa_assert(r);
+    
+    if (r->speex.state) {
+        if (r->resample_method >= PA_RESAMPLER_SPEEX_FIXED_BASE && r->resample_method <= PA_RESAMPLER_SPEEX_FIXED_MAX) 
+            paspfx_resampler_destroy(r->speex.state);
+        else {
+            pa_assert(r->resample_method >= PA_RESAMPLER_SPEEX_FLOAT_BASE && r->resample_method <= PA_RESAMPLER_SPEEX_FLOAT_MAX);
+            paspfl_resampler_destroy(r->speex.state);
+        }
+    }
+}
 
-        src = (uint8_t*) pa_memblock_acquire(in->memblock) + in->index;
-        dst = pa_memblock_acquire(out->memblock);
+static int speex_init(pa_resampler *r) {
+    int q, err;
+    
+    pa_assert(r);
 
-        for (o_index = 0;; o_index++, u->o_counter++) {
-            unsigned j;
+    r->impl_free = speex_free;
+    r->impl_update_rates = speex_update_rates;
+    
+    if (r->resample_method >= PA_RESAMPLER_SPEEX_FIXED_BASE && r->resample_method <= PA_RESAMPLER_SPEEX_FIXED_MAX) {
+        q = r->resample_method - PA_RESAMPLER_SPEEX_FIXED_BASE;
+        r->impl_resample = speex_resample_int;
 
-            j = (u->o_counter * r->i_ss.rate / r->o_ss.rate);
-            j = j > u->i_counter ? j - u->i_counter : 0;
+        if (!(r->speex.state = paspfx_resampler_init(r->o_ss.channels, r->i_ss.rate, r->o_ss.rate, q, &err)))
+            return -1;
 
-            if (j >= n_frames)
-                break;
+    } else {
+        pa_assert(r->resample_method >= PA_RESAMPLER_SPEEX_FLOAT_BASE && r->resample_method <= PA_RESAMPLER_SPEEX_FLOAT_MAX);
+        q = r->resample_method - PA_RESAMPLER_SPEEX_FLOAT_BASE;
+        r->impl_resample = speex_resample_float;
 
-            pa_assert(o_index*fz < pa_memblock_get_length(out->memblock));
+        if (!(r->speex.state = paspfl_resampler_init(r->o_ss.channels, r->i_ss.rate, r->o_ss.rate, q, &err)))
+            return -1;
+    }
+    
 
-            memcpy((uint8_t*) dst + fz*o_index,
-                   (uint8_t*) src + fz*j, fz);
+    return 0;
+}
 
-        }
+/* Trivial implementation */
 
-        pa_memblock_release(in->memblock);
-        pa_memblock_release(out->memblock);
+static void trivial_resample(pa_resampler *r, const pa_memchunk *input, unsigned in_n_frames, pa_memchunk *output, unsigned *out_n_frames) {
+    size_t fz;
+    unsigned o_index;
+    void *src, *dst;
+    
+    pa_assert(r);
+    pa_assert(input);
+    pa_assert(output);
+    pa_assert(out_n_frames);
 
-        out->length = o_index*fz;
+    fz = r->w_sz * r->o_ss.channels;
+    
+    src = (uint8_t*) pa_memblock_acquire(input->memblock) + input->index;
+    dst = (uint8_t*) pa_memblock_acquire(output->memblock) + output->index;
+    
+    for (o_index = 0;; o_index++, r->trivial.o_counter++) {
+        unsigned j;
+        
+        j = ((r->trivial.o_counter * r->i_ss.rate) / r->o_ss.rate);
+        j = j > r->trivial.i_counter ? j - r->trivial.i_counter : 0;
+        
+        if (j >= in_n_frames)
+            break;
+
+        pa_assert(o_index * fz < pa_memblock_get_length(output->memblock));
+        
+        oil_memcpy((uint8_t*) dst + fz * o_index,
+                   (uint8_t*) src + fz * j, fz);   
     }
+    
+    pa_memblock_release(input->memblock);
+    pa_memblock_release(output->memblock);
+    
+    *out_n_frames = o_index;
 
-    u->i_counter += n_frames;
+    r->trivial.i_counter += in_n_frames;
 
     /* Normalize counters */
-    while (u->i_counter >= r->i_ss.rate) {
-        u->i_counter -= r->i_ss.rate;
-        pa_assert(u->o_counter >= r->o_ss.rate);
-        u->o_counter -= r->o_ss.rate;
-    }
-}
-
-static void trivial_free(pa_resampler *r) {
-    pa_assert(r);
+    while (r->trivial.i_counter >= r->i_ss.rate) {
+        pa_assert(r->trivial.o_counter >= r->o_ss.rate);
 
-    pa_xfree(r->impl_data);
+        r->trivial.i_counter -= r->i_ss.rate;
+        r->trivial.o_counter -= r->o_ss.rate;
+    }
 }
 
-static void trivial_update_rate(pa_resampler *r, uint32_t rate) {
-    struct impl_trivial *u;
-
+static void trivial_update_rates(pa_resampler *r) {
     pa_assert(r);
-    pa_assert(rate > 0);
-    pa_assert(r->impl_data);
 
-    u = r->impl_data;
-    u->i_counter = 0;
-    u->o_counter = 0;
+    r->trivial.i_counter = 0;
+    r->trivial.o_counter = 0;
 }
 
 static int trivial_init(pa_resampler*r) {
-    struct impl_trivial *u;
-
     pa_assert(r);
-    pa_assert(r->i_ss.format == r->o_ss.format);
-    pa_assert(r->i_ss.channels == r->o_ss.channels);
 
-    r->impl_data = u = pa_xnew(struct impl_trivial, 1);
-    u->o_counter = u->i_counter = 0;
+    r->trivial.o_counter = r->trivial.i_counter = 0;
 
-    r->impl_run = trivial_run;
-    r->impl_free = trivial_free;
-    r->impl_update_input_rate = trivial_update_rate;
-    r->impl_update_output_rate = trivial_update_rate;
+    r->impl_resample = trivial_resample;
+    r->impl_update_rates = trivial_update_rates;
 
     return 0;
 }
index ada293e..35f53db 100644 (file)
@@ -41,6 +41,11 @@ typedef enum pa_resample_method {
     PA_RESAMPLER_SRC_ZERO_ORDER_HOLD     = SRC_ZERO_ORDER_HOLD,
     PA_RESAMPLER_SRC_LINEAR              = SRC_LINEAR,
     PA_RESAMPLER_TRIVIAL,
+    PA_RESAMPLER_SPEEX_FLOAT_BASE,
+    PA_RESAMPLER_SPEEX_FLOAT_MAX = PA_RESAMPLER_SPEEX_FLOAT_BASE + 10,
+    PA_RESAMPLER_SPEEX_FIXED_BASE,
+    PA_RESAMPLER_SPEEX_FIXED_MAX = PA_RESAMPLER_SPEEX_FIXED_BASE + 10,
+    PA_RESAMPLER_AUTO, /* automatic select based on sample format */
     PA_RESAMPLER_MAX
 } pa_resample_method_t;
 
index c530e79..658b3f5 100644 (file)
@@ -33,6 +33,9 @@
 #define pa_sconv_s16le_to_float32ne pa_sconv_s16be_to_float32ne
 #define pa_sconv_s16le_from_float32ne pa_sconv_s16be_from_float32ne
 
+#define pa_sconv_s16le_to_float32re pa_sconv_s16be_to_float32re
+#define pa_sconv_s16le_from_float32re pa_sconv_s16be_from_float32re
+
 #ifdef WORDS_BIGENDIAN
 #define SWAP_WORDS 0
 #else
index 6b736f6..ad03448 100644 (file)
   USA.
 ***/
 
-void pa_sconv_s16be_to_float32ne(unsigned n, const void *a, float *b);
-void pa_sconv_s16be_from_float32ne(unsigned n, const float *a, void *b);
+#include <inttypes.h>
+
+void pa_sconv_s16be_to_float32ne(unsigned n, const int16_t *a, float *b);
+void pa_sconv_s16be_from_float32ne(unsigned n, const float *a, int16_t *b);
+void pa_sconv_s16be_to_float32re(unsigned n, const int16_t *a, float *b);
+void pa_sconv_s16be_from_float32re(unsigned n, const float *a, int16_t *b);
+
+#ifdef WORDS_BIGENDIAN
+#define pa_sconv_float32be_to_s16ne pa_sconv_s16be_from_float32ne
+#define pa_sconv_float32be_from_s16ne pa_sconv_s16be_to_float32ne
+#define pa_sconv_float32le_to_s16ne pa_sconv_s16be_from_float32re
+#define pa_sconv_float32le_from_s16ne pa_sconv_s16be_to_float32re
+#endif
 
 #endif
index 5f45ef6..c82708c 100644 (file)
 #include <config.h>
 #endif
 
-#include <assert.h>
 #include <inttypes.h>
 
 #include <liboil/liboilfuncs.h>
 
 #include <pulsecore/sconv.h>
+#include <pulsecore/macro.h>
 #include <pulsecore/log.h>
 
 #include "endianmacros.h"
 #endif
 #endif
 
-void pa_sconv_s16le_to_float32ne(unsigned n, const void *a, float *b) {
-    const int16_t *ca = a;
-
-    assert(a);
-    assert(b);
+void pa_sconv_s16le_to_float32ne(unsigned n, const int16_t *a, float *b) {
+    pa_assert(a);
+    pa_assert(b);
 
 #if SWAP_WORDS == 1
 
     for (; n > 0; n--) {
-        int16_t s = *(ca++);
+        int16_t s = *(a++);
         *(b++) = ((float) INT16_FROM(s))/0x7FFF;
     }
 
 #else
 {
     static const double add = 0, factor = 1.0/0x7FFF;
-    oil_scaleconv_f32_s16(b, ca, n, &add, &factor);
+    oil_scaleconv_f32_s16(b, a, n, &add, &factor);
 }
 #endif
 }
 
-void pa_sconv_s16le_from_float32ne(unsigned n, const float *a, void *b) {
-    int16_t *cb = b;
-
-    assert(a);
-    assert(b);
+void pa_sconv_s16le_from_float32ne(unsigned n, const float *a, int16_t *b) {
+    pa_assert(a);
+    pa_assert(b);
 
 #if SWAP_WORDS == 1
 
@@ -93,13 +89,55 @@ void pa_sconv_s16le_from_float32ne(unsigned n, const float *a, void *b) {
             v = -1;
 
         s = (int16_t) (v * 0x7FFF);
-        *(cb++) = INT16_TO(s);
+        *(b++) = INT16_TO(s);
     }
 
 #else
 {
     static const double add = 0, factor = 0x7FFF;
-    oil_scaleconv_s16_f32(cb, a, n, &add, &factor);
+    oil_scaleconv_s16_f32(b, a, n, &add, &factor);
+}
+#endif
 }
+
+void pa_sconv_s16le_to_float32re(unsigned n, const int16_t *a, float *b) {
+    pa_assert(a);
+    pa_assert(b);
+
+#if SWAP_WORDS == 1
+
+    for (; n > 0; n--) {
+        int16_t s = *(a++);
+        float k = ((float) INT16_FROM(s))/0x7FFF;
+        uint32_t *j = (uint32_t*) &k;
+        *j = UINT32_SWAP(*j);
+        *(b++) = k;
+    }
+
+#endif
+}
+
+void pa_sconv_s16le_from_float32re(unsigned n, const float *a, int16_t *b) {
+    pa_assert(a);
+    pa_assert(b);
+
+#if SWAP_WORDS == 1
+
+    for (; n > 0; n--) {
+        int16_t s;
+        float v = *(a++);
+        uint32_t *j = (uint32_t*) &v;
+        *j = UINT32_SWAP(*j);
+
+        if (v > 1)
+            v = 1;
+
+        if (v < -1)
+            v = -1;
+
+        s = (int16_t) (v * 0x7FFF);
+        *(b++) = INT16_TO(s);
+    }
+
 #endif
 }
index c4e4911..4203315 100644 (file)
   USA.
 ***/
 
-void pa_sconv_s16le_to_float32ne(unsigned n, const void *a, float *b);
-void pa_sconv_s16le_from_float32ne(unsigned n, const float *a, void *b);
+#include <inttypes.h>
+
+void pa_sconv_s16le_to_float32ne(unsigned n, const int16_t *a, float *b);
+void pa_sconv_s16le_from_float32ne(unsigned n, const float *a, int16_t *b);
+void pa_sconv_s16le_to_float32re(unsigned n, const int16_t *a, float *b);
+void pa_sconv_s16le_from_float32re(unsigned n, const float *a, int16_t *b);
+
+#ifndef WORDS_BIGENDIAN
+#define pa_sconv_float32be_to_s16ne pa_sconv_s16le_from_float32re
+#define pa_sconv_float32be_from_s16ne pa_sconv_s16le_to_float32re
+#define pa_sconv_float32le_to_s16ne pa_sconv_s16le_from_float32ne
+#define pa_sconv_float32le_from_s16ne pa_sconv_s16le_to_float32ne
+#endif
 
 #endif
index d15cec8..4986ba7 100644 (file)
 
 #include <stdio.h>
 #include <stdlib.h>
-#include <assert.h>
 
 #include <liboil/liboilfuncs.h>
 #include <liboil/liboil.h>
 
 #include <pulsecore/g711.h>
+#include <pulsecore/macro.h>
 
 #include "endianmacros.h"
 #include "sconv-s16le.h"
 
 #include "sconv.h"
 
-static void u8_to_float32ne(unsigned n, const void *a, float *b) {
-    const uint8_t *ca = a;
+/* u8 */
+static void u8_to_float32ne(unsigned n, const uint8_t *a, float *b) {
     static const double add = -128.0/127.0, factor = 1.0/127.0;
 
-    assert(a);
-    assert(b);
+    pa_assert(a);
+    pa_assert(b);
 
-    oil_scaleconv_f32_u8(b, ca, n, &add, &factor);
+    oil_scaleconv_f32_u8(b, a, n, &add, &factor);
 }
 
-static void u8_from_float32ne(unsigned n, const float *a, void *b) {
-    uint8_t *cb = b;
+static void u8_from_float32ne(unsigned n, const float *a, uint8_t *b) {
     static const double add = 128.0, factor = 127.0;
 
-    assert(a);
-    assert(b);
+    pa_assert(a);
+    pa_assert(b);
 
-    oil_scaleconv_u8_f32(cb, a, n, &add, &factor);
+    oil_scaleconv_u8_f32(b, a, n, &add, &factor);
 }
 
-static void float32ne_to_float32ne(unsigned n, const void *a, float *b) {
-    assert(a);
-    assert(b);
+static void u8_to_s16ne(unsigned n, const uint8_t *a, int16_t *b) {
+    static const int16_t add = -128, factor = 0x100;
 
-    oil_memcpy(b, a, sizeof(float) * n);
+    pa_assert(a);
+    pa_assert(b);
+
+    oil_conv_s16_u8(b, 2, a, 1, n);
+    oil_scalaradd_s16(b, 2, b, 2, &add, n);
+    oil_scalarmult_s16(b, 2, b, 2, &factor, n);
+}
+
+static void u8_from_s16ne(unsigned n, const int16_t *a, uint8_t *b) {
+
+    pa_assert(a);
+    pa_assert(b);
+    
+    for (; n > 0; n--, a ++, a++)
+        *b = (uint8_t) (*a / 0x100 + 0x80);
 }
 
-static void float32ne_from_float32ne(unsigned n, const float *a, void *b) {
-    assert(a);
-    assert(b);
+/* float32 */
+
+static void float32ne_to_float32ne(unsigned n, const float *a, float *b) {
+    pa_assert(a);
+    pa_assert(b);
 
     oil_memcpy(b, a, sizeof(float) * n);
 }
 
-static void float32re_to_float32ne(unsigned n, const void *a, float *b) {
-    assert(a);
-    assert(b);
+static void float32re_to_float32ne(unsigned n, const float *a, float *b) {
+    pa_assert(a);
+    pa_assert(b);
 
-    while (n-- > 0)
-        ((uint32_t *)b)[n] = UINT32_SWAP (((uint32_t *)a)[n]);
+    for (; n > 0; n--, a++, b++)
+        *((uint32_t *) b) = UINT32_SWAP(*((uint32_t *) a));
 }
 
-static void float32re_from_float32ne(unsigned n, const float *a, void *b) {
-    assert(a);
-    assert(b);
+/* s16 */
 
-    while (n-- > 0)
-        ((uint32_t *)b)[n] = UINT32_SWAP (((uint32_t *)a)[n]);
+static void s16ne_to_s16ne(unsigned n, const int16_t *a, int16_t *b) {
+    pa_assert(a);
+    pa_assert(b);
+
+    oil_memcpy(b, a, sizeof(int16_t) * n);
 }
 
-static void ulaw_to_float32ne(unsigned n, const void *a, float *b) {
-    const uint8_t *ca = a;
+static void s16re_to_s16ne(unsigned n, const int16_t *a, int16_t *b) {
+    pa_assert(a);
+    pa_assert(b);
+
+    for (; n > 0; n--, a++, b++)
+        *b = UINT16_SWAP(*a);
+}
 
-    assert(a);
-    assert(b);
+/* ulaw */
+
+static void ulaw_to_float32ne(unsigned n, const uint8_t *a, float *b) {
+    pa_assert(a);
+    pa_assert(b);
 
     for (; n > 0; n--)
-        *(b++) = st_ulaw2linear16(*(ca++)) * 1.0F / 0x7FFF;
+        *(b++) = st_ulaw2linear16(*(a++)) * 1.0F / 0x7FFF;
 }
 
-static void ulaw_from_float32ne(unsigned n, const float *a, void *b) {
-    uint8_t *cb = b;
-
-    assert(a);
-    assert(b);
+static void ulaw_from_float32ne(unsigned n, const float *a, uint8_t *b) {
+    pa_assert(a);
+    pa_assert(b);
 
     for (; n > 0; n--) {
         float v = *(a++);
@@ -116,28 +137,42 @@ static void ulaw_from_float32ne(unsigned n, const float *a, void *b) {
         if (v < -1)
             v = -1;
 
-        *(cb++) = st_14linear2ulaw((int16_t) (v * 0x1FFF));
+        *(b++) = st_14linear2ulaw((int16_t) (v * 0x1FFF));
     }
 }
 
-static void alaw_to_float32ne(unsigned n, const void *a, float *b) {
-    const uint8_t *ca = a;
+static void ulaw_to_s16ne(unsigned n, const uint8_t *a, int16_t *b) {
+    pa_assert(a);
+    pa_assert(b);
 
-    assert(a);
-    assert(b);
+    for (; n > 0; n--, a++, b++)
+        *b = st_ulaw2linear16(*a);
+}
 
-    for (; n > 0; n--)
-        *(b++) = st_alaw2linear16(*(ca++)) * 1.0F / 0x7FFF;
+static void ulaw_from_s16ne(unsigned n, const int16_t *a, uint8_t *b) {
+    pa_assert(a);
+    pa_assert(b);
+
+    for (; n > 0; n--, a++, b++)
+        *b = st_14linear2ulaw(*a >> 2);
 }
 
-static void alaw_from_float32ne(unsigned n, const float *a, void *b) {
-    uint8_t *cb = b;
+/* alaw */
 
-    assert(a);
-    assert(b);
+static void alaw_to_float32ne(unsigned n, const uint8_t *a, float *b) {
+    pa_assert(a);
+    pa_assert(b);
 
-    for (; n > 0; n--) {
-        float v = *(a++);
+    for (; n > 0; n--, a++, b++)
+        *b = st_alaw2linear16(*a) * 1.0F / 0x7FFF;
+}
+
+static void alaw_from_float32ne(unsigned n, const float *a, uint8_t *b) {
+    pa_assert(a);
+    pa_assert(b);
+
+    for (; n > 0; n--, a++, b++) {
+        float v = *a;
 
         if (v > 1)
             v = 1;
@@ -145,48 +180,94 @@ static void alaw_from_float32ne(unsigned n, const float *a, void *b) {
         if (v < -1)
             v = -1;
 
-        *(cb++) = st_13linear2alaw((int16_t) (v * 0xFFF));
+        *b = st_13linear2alaw((int16_t) (v * 0xFFF));
     }
 }
 
-pa_convert_to_float32ne_func_t pa_get_convert_to_float32ne_function(pa_sample_format_t f) {
-    switch(f) {
-        case PA_SAMPLE_U8:
-            return u8_to_float32ne;
-        case PA_SAMPLE_S16LE:
-            return pa_sconv_s16le_to_float32ne;
-        case PA_SAMPLE_S16BE:
-            return pa_sconv_s16be_to_float32ne;
-        case PA_SAMPLE_FLOAT32NE:
-            return float32ne_to_float32ne;
-        case PA_SAMPLE_FLOAT32RE:
-            return float32re_to_float32ne;
-        case PA_SAMPLE_ALAW:
-            return alaw_to_float32ne;
-        case PA_SAMPLE_ULAW:
-            return ulaw_to_float32ne;
-        default:
-            return NULL;
-    }
+static void alaw_to_s16ne(unsigned n, const int8_t *a, int16_t *b) {
+    pa_assert(a);
+    pa_assert(b);
+
+    for (; n > 0; n--, a++, b++)
+        *b = st_alaw2linear16(*a);
 }
 
-pa_convert_from_float32ne_func_t pa_get_convert_from_float32ne_function(pa_sample_format_t f) {
-    switch(f) {
-        case PA_SAMPLE_U8:
-            return u8_from_float32ne;
-        case PA_SAMPLE_S16LE:
-            return pa_sconv_s16le_from_float32ne;
-        case PA_SAMPLE_S16BE:
-            return pa_sconv_s16be_from_float32ne;
-        case PA_SAMPLE_FLOAT32NE:
-            return float32ne_from_float32ne;
-        case PA_SAMPLE_FLOAT32RE:
-            return float32re_from_float32ne;
-        case PA_SAMPLE_ALAW:
-            return alaw_from_float32ne;
-        case PA_SAMPLE_ULAW:
-            return ulaw_from_float32ne;
-        default:
-            return NULL;
-    }
+static void alaw_from_s16ne(unsigned n, const int16_t *a, uint8_t *b) {
+    pa_assert(a);
+    pa_assert(b);
+
+    for (; n > 0; n--)
+        *b = st_13linear2alaw(*a >> 3);
+}
+
+pa_convert_func_t pa_get_convert_to_float32ne_function(pa_sample_format_t f) {
+
+    static const pa_convert_func_t table[] = {
+        [PA_SAMPLE_U8]        = (pa_convert_func_t) u8_to_float32ne,
+        [PA_SAMPLE_ALAW]      = (pa_convert_func_t) alaw_to_float32ne,
+        [PA_SAMPLE_ULAW]      = (pa_convert_func_t) ulaw_to_float32ne,
+        [PA_SAMPLE_S16LE]     = (pa_convert_func_t) pa_sconv_s16le_to_float32ne,
+        [PA_SAMPLE_S16BE]     = (pa_convert_func_t) pa_sconv_s16be_to_float32ne,
+        [PA_SAMPLE_FLOAT32NE] = (pa_convert_func_t) float32ne_to_float32ne,
+        [PA_SAMPLE_FLOAT32RE] = (pa_convert_func_t) float32re_to_float32ne,
+    };
+
+    pa_assert(f >= 0);
+    pa_assert(f < PA_SAMPLE_MAX);
+
+    return table[f];
+}
+
+pa_convert_func_t pa_get_convert_from_float32ne_function(pa_sample_format_t f) {
+
+    static const pa_convert_func_t table[] = {
+        [PA_SAMPLE_U8]        = (pa_convert_func_t) u8_from_float32ne,
+        [PA_SAMPLE_S16LE]     = (pa_convert_func_t) pa_sconv_s16le_from_float32ne,
+        [PA_SAMPLE_S16BE]     = (pa_convert_func_t) pa_sconv_s16be_from_float32ne,
+        [PA_SAMPLE_FLOAT32NE] = (pa_convert_func_t) float32ne_to_float32ne,
+        [PA_SAMPLE_FLOAT32RE] = (pa_convert_func_t) float32re_to_float32ne,
+        [PA_SAMPLE_ALAW]      = (pa_convert_func_t) alaw_from_float32ne,
+        [PA_SAMPLE_ULAW]      = (pa_convert_func_t) ulaw_from_float32ne
+    };
+
+    pa_assert(f >= 0);
+    pa_assert(f < PA_SAMPLE_MAX);
+
+    return table[f];
+}
+
+pa_convert_func_t pa_get_convert_to_s16ne_function(pa_sample_format_t f) {
+
+    static const pa_convert_func_t table[] = {
+        [PA_SAMPLE_U8]        = (pa_convert_func_t) u8_to_s16ne,
+        [PA_SAMPLE_S16NE]     = (pa_convert_func_t) s16ne_to_s16ne,
+        [PA_SAMPLE_S16RE]     = (pa_convert_func_t) s16re_to_s16ne,
+        [PA_SAMPLE_FLOAT32BE] = (pa_convert_func_t) pa_sconv_float32be_to_s16ne,
+        [PA_SAMPLE_FLOAT32LE] = (pa_convert_func_t) pa_sconv_float32le_to_s16ne,
+        [PA_SAMPLE_ALAW]      = (pa_convert_func_t) alaw_to_s16ne,
+        [PA_SAMPLE_ULAW]      = (pa_convert_func_t) ulaw_to_s16ne
+    };
+
+    pa_assert(f >= 0);
+    pa_assert(f < PA_SAMPLE_MAX);
+
+    return table[f];
+}
+
+pa_convert_func_t pa_get_convert_from_s16ne_function(pa_sample_format_t f) {
+
+    static const pa_convert_func_t table[] = {
+        [PA_SAMPLE_U8]        = (pa_convert_func_t) u8_from_s16ne,
+        [PA_SAMPLE_S16NE]     = (pa_convert_func_t) s16ne_to_s16ne,
+        [PA_SAMPLE_S16RE]     = (pa_convert_func_t) s16re_to_s16ne,
+        [PA_SAMPLE_FLOAT32BE] = (pa_convert_func_t) pa_sconv_float32be_from_s16ne,
+        [PA_SAMPLE_FLOAT32LE] = (pa_convert_func_t) pa_sconv_float32le_from_s16ne,
+        [PA_SAMPLE_ALAW]      = (pa_convert_func_t) alaw_from_s16ne,
+        [PA_SAMPLE_ULAW]      = (pa_convert_func_t) ulaw_from_s16ne,
+    };
+
+    pa_assert(f >= 0);
+    pa_assert(f < PA_SAMPLE_MAX);
+
+    return table[f];
 }
index 1e97aad..5e8fa68 100644 (file)
 
 #include <pulse/sample.h>
 
-typedef void (*pa_convert_to_float32ne_func_t)(unsigned n, const void *a, float *b);
-typedef void (*pa_convert_from_float32ne_func_t)(unsigned n, const float *a, void *b);
+typedef void (*pa_convert_func_t)(unsigned n, const void *a, void *b);
 
-pa_convert_to_float32ne_func_t pa_get_convert_to_float32ne_function(pa_sample_format_t f);
-pa_convert_from_float32ne_func_t pa_get_convert_from_float32ne_function(pa_sample_format_t f);
+pa_convert_func_t pa_get_convert_to_float32ne_function(pa_sample_format_t f);
+pa_convert_func_t pa_get_convert_from_float32ne_function(pa_sample_format_t f);
+
+pa_convert_func_t pa_get_convert_to_s16ne_function(pa_sample_format_t f);
+pa_convert_func_t pa_get_convert_from_s16ne_function(pa_sample_format_t f);
 
 #endif