1/*** 2 This file is part of PulseAudio. 3 4 Copyright 2014, 2015 Andrey Semashev 5 6 PulseAudio is free software; you can redistribute it and/or modify 7 it under the terms of the GNU Lesser General Public License as published 8 by the Free Software Foundation; either version 2.1 of the License, 9 or (at your option) any later version. 10 11 PulseAudio is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 General Public License for more details. 15 16 You should have received a copy of the GNU Lesser General Public License 17 along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 18***/ 19 20#ifdef HAVE_CONFIG_H 21#include <config.h> 22#endif 23 24#include <stddef.h> 25#include <soxr.h> 26 27#include <pulsecore/resampler.h> 28 29static unsigned resampler_soxr_resample(pa_resampler *r, const pa_memchunk *input, unsigned in_n_frames, 30 pa_memchunk *output, unsigned *out_n_frames) { 31 soxr_t state; 32 void *in, *out; 33 size_t consumed = 0, produced = 0; 34 35 pa_assert(r); 36 pa_assert(input); 37 pa_assert(output); 38 pa_assert(out_n_frames); 39 40 state = r->impl.data; 41 pa_assert(state); 42 43 in = pa_memblock_acquire_chunk(input); 44 out = pa_memblock_acquire_chunk(output); 45 46 pa_assert_se(soxr_process(state, in, in_n_frames, &consumed, out, *out_n_frames, &produced) == 0); 47 48 pa_memblock_release(input->memblock); 49 pa_memblock_release(output->memblock); 50 51 *out_n_frames = produced; 52 53 return in_n_frames - consumed; 54} 55 56static void resampler_soxr_free(pa_resampler *r) { 57 pa_assert(r); 58 59 if (!r->impl.data) 60 return; 61 62 soxr_delete(r->impl.data); 63 r->impl.data = NULL; 64} 65 66static void resampler_soxr_reset(pa_resampler *r) { 67#if SOXR_THIS_VERSION >= SOXR_VERSION(0, 1, 2) 68 double ratio; 69 70 pa_assert(r); 71 72 soxr_clear(r->impl.data); 73 74 ratio = (double)r->i_ss.rate / (double)r->o_ss.rate; 75 soxr_set_io_ratio(r->impl.data, ratio, 0); 76#else 77 /* With libsoxr prior to 0.1.2 soxr_clear() makes soxr_process() crash afterwards, 78 * so don't use this function and re-create the context instead. */ 79 soxr_t old_state; 80 81 pa_assert(r); 82 83 old_state = r->impl.data; 84 r->impl.data = NULL; 85 86 if (pa_resampler_soxr_init(r) == 0) { 87 if (old_state) 88 soxr_delete(old_state); 89 } else { 90 r->impl.data = old_state; 91 pa_log_error("Failed to reset libsoxr context"); 92 } 93#endif 94} 95 96static void resampler_soxr_update_rates(pa_resampler *r) { 97 double ratio; 98 99 pa_assert(r); 100 101 ratio = (double)r->i_ss.rate / (double)r->o_ss.rate; 102 soxr_set_io_ratio(r->impl.data, ratio, 0); 103} 104 105int pa_resampler_soxr_init(pa_resampler *r) { 106 soxr_t state; 107 soxr_datatype_t io_format; 108 soxr_io_spec_t io_spec; 109 soxr_runtime_spec_t runtime_spec; 110 unsigned long quality_recipe; 111 soxr_quality_spec_t quality; 112 soxr_error_t err = NULL; 113 double ratio; 114 115 pa_assert(r); 116 117 switch (r->work_format) { 118 case PA_SAMPLE_S16NE: 119 io_format = SOXR_INT16_I; 120 break; 121 case PA_SAMPLE_FLOAT32NE: 122 io_format = SOXR_FLOAT32_I; 123 break; 124 default: 125 pa_assert_not_reached(); 126 } 127 128 io_spec = soxr_io_spec(io_format, io_format); 129 130 /* Resample in one thread. Multithreading makes 131 * performance worse with small chunks of audio. */ 132 runtime_spec = soxr_runtime_spec(1); 133 134 switch (r->method) { 135 case PA_RESAMPLER_SOXR_MQ: 136 quality_recipe = SOXR_MQ | SOXR_LINEAR_PHASE; 137 break; 138 case PA_RESAMPLER_SOXR_HQ: 139 quality_recipe = SOXR_HQ | SOXR_LINEAR_PHASE; 140 break; 141 case PA_RESAMPLER_SOXR_VHQ: 142 quality_recipe = SOXR_VHQ | SOXR_LINEAR_PHASE; 143 break; 144 default: 145 pa_assert_not_reached(); 146 } 147 148 quality = soxr_quality_spec(quality_recipe, SOXR_VR); 149 150 /* Maximum resample ratio is 100:1 */ 151 state = soxr_create(100, 1, r->work_channels, &err, &io_spec, &quality, &runtime_spec); 152 if (!state) { 153 pa_log_error("Failed to create libsoxr resampler context: %s.", (err ? err : "[unknown error]")); 154 return -1; 155 } 156 157 ratio = (double)r->i_ss.rate / (double)r->o_ss.rate; 158 soxr_set_io_ratio(state, ratio, 0); 159 160 r->impl.free = resampler_soxr_free; 161 r->impl.reset = resampler_soxr_reset; 162 r->impl.update_rates = resampler_soxr_update_rates; 163 r->impl.resample = resampler_soxr_resample; 164 r->impl.data = state; 165 166 return 0; 167} 168