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/soxr.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/soxr.c')
-rw-r--r-- | src/pulsecore/resampler/soxr.c | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/src/pulsecore/resampler/soxr.c b/src/pulsecore/resampler/soxr.c new file mode 100644 index 0000000..b1b2e19 --- /dev/null +++ b/src/pulsecore/resampler/soxr.c @@ -0,0 +1,168 @@ +/*** + This file is part of PulseAudio. + + Copyright 2014, 2015 Andrey Semashev + + 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 <stddef.h> +#include <soxr.h> + +#include <pulsecore/resampler.h> + +static unsigned resampler_soxr_resample(pa_resampler *r, const pa_memchunk *input, unsigned in_n_frames, + pa_memchunk *output, unsigned *out_n_frames) { + soxr_t state; + void *in, *out; + size_t consumed = 0, produced = 0; + + pa_assert(r); + pa_assert(input); + pa_assert(output); + pa_assert(out_n_frames); + + state = r->impl.data; + pa_assert(state); + + in = pa_memblock_acquire_chunk(input); + out = pa_memblock_acquire_chunk(output); + + pa_assert_se(soxr_process(state, in, in_n_frames, &consumed, out, *out_n_frames, &produced) == 0); + + pa_memblock_release(input->memblock); + pa_memblock_release(output->memblock); + + *out_n_frames = produced; + + return in_n_frames - consumed; +} + +static void resampler_soxr_free(pa_resampler *r) { + pa_assert(r); + + if (!r->impl.data) + return; + + soxr_delete(r->impl.data); + r->impl.data = NULL; +} + +static void resampler_soxr_reset(pa_resampler *r) { +#if SOXR_THIS_VERSION >= SOXR_VERSION(0, 1, 2) + pa_assert(r); + + soxr_clear(r->impl.data); +#else + /* With libsoxr prior to 0.1.2 soxr_clear() makes soxr_process() crash afterwards, + * so don't use this function and re-create the context instead. */ + soxr_t old_state; + + pa_assert(r); + + old_state = r->impl.data; + r->impl.data = NULL; + + if (pa_resampler_soxr_init(r) == 0) { + if (old_state) + soxr_delete(old_state); + } else { + r->impl.data = old_state; + pa_log_error("Failed to reset libsoxr context"); + } +#endif +} + +static void resampler_soxr_update_rates(pa_resampler *r) { + soxr_t old_state; + + pa_assert(r); + + /* There is no update method in libsoxr, + * so just re-create the resampler context */ + + old_state = r->impl.data; + r->impl.data = NULL; + + if (pa_resampler_soxr_init(r) == 0) { + if (old_state) + soxr_delete(old_state); + } else { + r->impl.data = old_state; + pa_log_error("Failed to update libsoxr sample rates"); + } +} + +int pa_resampler_soxr_init(pa_resampler *r) { + soxr_t state; + soxr_datatype_t io_format; + soxr_io_spec_t io_spec; + soxr_runtime_spec_t runtime_spec; + unsigned long quality_recipe; + soxr_quality_spec_t quality; + soxr_error_t err = NULL; + + pa_assert(r); + + switch (r->work_format) { + case PA_SAMPLE_S16NE: + io_format = SOXR_INT16_I; + break; + case PA_SAMPLE_FLOAT32NE: + io_format = SOXR_FLOAT32_I; + break; + default: + pa_assert_not_reached(); + } + + io_spec = soxr_io_spec(io_format, io_format); + + /* Resample in one thread. Multithreading makes + * performance worse with small chunks of audio. */ + runtime_spec = soxr_runtime_spec(1); + + switch (r->method) { + case PA_RESAMPLER_SOXR_MQ: + quality_recipe = SOXR_MQ | SOXR_LINEAR_PHASE; + break; + case PA_RESAMPLER_SOXR_HQ: + quality_recipe = SOXR_HQ | SOXR_LINEAR_PHASE; + break; + case PA_RESAMPLER_SOXR_VHQ: + quality_recipe = SOXR_VHQ | SOXR_LINEAR_PHASE; + break; + default: + pa_assert_not_reached(); + } + + quality = soxr_quality_spec(quality_recipe, 0); + + state = soxr_create(r->i_ss.rate, r->o_ss.rate, r->work_channels, &err, &io_spec, &quality, &runtime_spec); + if (!state) { + pa_log_error("Failed to create libsoxr resampler context: %s.", (err ? err : "[unknown error]")); + return -1; + } + + r->impl.free = resampler_soxr_free; + r->impl.reset = resampler_soxr_reset; + r->impl.update_rates = resampler_soxr_update_rates; + r->impl.resample = resampler_soxr_resample; + r->impl.data = state; + + return 0; +} |