diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 16:03:18 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 16:03:18 +0000 |
commit | 2dd5bc6a074165ddfbd57c4bd52c2d2dac8f47a1 (patch) | |
tree | 465b29cb405d3af0b0ad50c78e1dccc636594fec /src/pulsecore/resampler/speex.c | |
parent | Initial commit. (diff) | |
download | pulseaudio-upstream.tar.xz pulseaudio-upstream.zip |
Adding upstream version 14.2.upstream/14.2upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/pulsecore/resampler/speex.c')
-rw-r--r-- | src/pulsecore/resampler/speex.c | 178 |
1 files changed, 178 insertions, 0 deletions
diff --git a/src/pulsecore/resampler/speex.c b/src/pulsecore/resampler/speex.c new file mode 100644 index 0000000..66387e5 --- /dev/null +++ b/src/pulsecore/resampler/speex.c @@ -0,0 +1,178 @@ +/*** + This file is part of PulseAudio. + + Copyright 2004-2006 Lennart Poettering + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. +***/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <speex/speex_resampler.h> +#include <math.h> + +#include <pulsecore/once.h> +#include <pulsecore/resampler.h> + +bool pa_speex_is_fixed_point(void) { + static bool result = false; + PA_ONCE_BEGIN { + float f_out = -1.0f, f_in = 1.0f; + spx_uint32_t in_len = 1, out_len = 1; + SpeexResamplerState *s; + + pa_assert_se(s = speex_resampler_init(1, 1, 1, + SPEEX_RESAMPLER_QUALITY_MIN, NULL)); + + /* feed one sample that is too soft for fixed-point speex */ + pa_assert_se(speex_resampler_process_float(s, 0, &f_in, &in_len, + &f_out, &out_len) == RESAMPLER_ERR_SUCCESS); + + /* expecting sample has been processed, one sample output */ + pa_assert_se(in_len == 1 && out_len == 1); + + /* speex compiled with --enable-fixed-point will output 0.0 due to insufficient precision */ + if (fabsf(f_out) < 0.00001f) + result = true; + + speex_resampler_destroy(s); + } PA_ONCE_END; + return result; +} + + +static unsigned 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; + SpeexResamplerState *state; + + pa_assert(r); + pa_assert(input); + pa_assert(output); + pa_assert(out_n_frames); + + state = r->impl.data; + + in = pa_memblock_acquire_chunk(input); + out = pa_memblock_acquire_chunk(output); + + /* Strictly speaking, speex resampler expects its input + * to be normalized to the [-32768.0 .. 32767.0] range. + * This matters if speex has been compiled with --enable-fixed-point, + * because such speex will round the samples to the nearest + * integer. speex with --enable-fixed-point is therefore incompatible + * with PulseAudio's floating-point sample range [-1 .. 1]. speex + * without --enable-fixed-point works fine with this range. + * Care has been taken to call speex_resample_float() only + * for speex compiled without --enable-fixed-point. + */ + pa_assert_se(speex_resampler_process_interleaved_float(state, in, &inf, out, &outf) == 0); + + pa_memblock_release(input->memblock); + pa_memblock_release(output->memblock); + + pa_assert(inf == in_n_frames); + *out_n_frames = outf; + + return 0; +} + +static unsigned speex_resample_int(pa_resampler *r, const pa_memchunk *input, unsigned in_n_frames, pa_memchunk *output, unsigned *out_n_frames) { + int16_t *in, *out; + uint32_t inf = in_n_frames, outf = *out_n_frames; + SpeexResamplerState *state; + + pa_assert(r); + pa_assert(input); + pa_assert(output); + pa_assert(out_n_frames); + + state = r->impl.data; + + in = pa_memblock_acquire_chunk(input); + out = pa_memblock_acquire_chunk(output); + + pa_assert_se(speex_resampler_process_interleaved_int(state, in, &inf, out, &outf) == 0); + + pa_memblock_release(input->memblock); + pa_memblock_release(output->memblock); + + pa_assert(inf == in_n_frames); + *out_n_frames = outf; + + return 0; +} + +static void speex_update_rates(pa_resampler *r) { + SpeexResamplerState *state; + pa_assert(r); + + state = r->impl.data; + + pa_assert_se(speex_resampler_set_rate(state, r->i_ss.rate, r->o_ss.rate) == 0); +} + +static void speex_reset(pa_resampler *r) { + SpeexResamplerState *state; + pa_assert(r); + + state = r->impl.data; + + pa_assert_se(speex_resampler_reset_mem(state) == 0); +} + +static void speex_free(pa_resampler *r) { + SpeexResamplerState *state; + pa_assert(r); + + state = r->impl.data; + if (!state) + return; + + speex_resampler_destroy(state); +} + +int pa_resampler_speex_init(pa_resampler *r) { + int q, err; + SpeexResamplerState *state; + + pa_assert(r); + + r->impl.free = speex_free; + r->impl.update_rates = speex_update_rates; + r->impl.reset = speex_reset; + + if (r->method >= PA_RESAMPLER_SPEEX_FIXED_BASE && r->method <= PA_RESAMPLER_SPEEX_FIXED_MAX) { + + q = r->method - PA_RESAMPLER_SPEEX_FIXED_BASE; + r->impl.resample = speex_resample_int; + + } else { + pa_assert(r->method >= PA_RESAMPLER_SPEEX_FLOAT_BASE && r->method <= PA_RESAMPLER_SPEEX_FLOAT_MAX); + + q = r->method - PA_RESAMPLER_SPEEX_FLOAT_BASE; + r->impl.resample = speex_resample_float; + } + + pa_log_info("Choosing speex quality setting %i.", q); + + if (!(state = speex_resampler_init(r->work_channels, r->i_ss.rate, r->o_ss.rate, q, &err))) + return -1; + + r->impl.data = state; + + return 0; +} |