diff options
author | Lennart Poettering <lennart@poettering.net> | 2007-08-23 22:35:40 +0000 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2007-08-23 22:35:40 +0000 |
commit | ed4dc16b95ce73862540a9669c273b9d0b888100 (patch) | |
tree | 882490ec7c118c77fc29d96c1c93e40253985faa | |
parent | 4eb9bb074653a6ebbb925c701c69d2b101098142 (diff) |
big resampler rework: support integer-only resampling, support speex resampler
git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/lennart@1712 fefdeb5f-60dc-0310-8127-8f9354f1896f
-rw-r--r-- | src/pulsecore/resampler.c | 764 | ||||
-rw-r--r-- | src/pulsecore/resampler.h | 5 | ||||
-rw-r--r-- | src/pulsecore/sconv-s16be.c | 3 | ||||
-rw-r--r-- | src/pulsecore/sconv-s16be.h | 15 | ||||
-rw-r--r-- | src/pulsecore/sconv-s16le.c | 68 | ||||
-rw-r--r-- | src/pulsecore/sconv-s16le.h | 15 | ||||
-rw-r--r-- | src/pulsecore/sconv.c | 261 | ||||
-rw-r--r-- | src/pulsecore/sconv.h | 10 |
8 files changed, 711 insertions, 430 deletions
diff --git a/src/pulsecore/resampler.c b/src/pulsecore/resampler.c index 1405d7e1..57de0d15 100644 --- a/src/pulsecore/resampler.c +++ b/src/pulsecore/resampler.c @@ -28,6 +28,7 @@ #include <string.h> #include <samplerate.h> + #include <liboil/liboilfuncs.h> #include <liboil/liboil.h> @@ -36,41 +37,93 @@ #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; } diff --git a/src/pulsecore/resampler.h b/src/pulsecore/resampler.h index ada293e5..35f53db3 100644 --- a/src/pulsecore/resampler.h +++ b/src/pulsecore/resampler.h @@ -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; diff --git a/src/pulsecore/sconv-s16be.c b/src/pulsecore/sconv-s16be.c index c530e79b..658b3f5c 100644 --- a/src/pulsecore/sconv-s16be.c +++ b/src/pulsecore/sconv-s16be.c @@ -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 diff --git a/src/pulsecore/sconv-s16be.h b/src/pulsecore/sconv-s16be.h index 6b736f69..ad034489 100644 --- a/src/pulsecore/sconv-s16be.h +++ b/src/pulsecore/sconv-s16be.h @@ -24,7 +24,18 @@ 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 diff --git a/src/pulsecore/sconv-s16le.c b/src/pulsecore/sconv-s16le.c index 5f45ef66..c82708ca 100644 --- a/src/pulsecore/sconv-s16le.c +++ b/src/pulsecore/sconv-s16le.c @@ -25,12 +25,12 @@ #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" @@ -53,32 +53,28 @@ #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 } diff --git a/src/pulsecore/sconv-s16le.h b/src/pulsecore/sconv-s16le.h index c4e4911a..4203315a 100644 --- a/src/pulsecore/sconv-s16le.h +++ b/src/pulsecore/sconv-s16le.h @@ -24,7 +24,18 @@ 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 diff --git a/src/pulsecore/sconv.c b/src/pulsecore/sconv.c index d15cec84..4986ba7c 100644 --- a/src/pulsecore/sconv.c +++ b/src/pulsecore/sconv.c @@ -28,12 +28,12 @@ #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" @@ -41,71 +41,92 @@ #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]; } diff --git a/src/pulsecore/sconv.h b/src/pulsecore/sconv.h index 1e97aad9..5e8fa684 100644 --- a/src/pulsecore/sconv.h +++ b/src/pulsecore/sconv.h @@ -27,10 +27,12 @@ #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 |