56#include <speex/speex_resampler.h>
63#define DEFAULT_SPEEX_RESAMPLE_QUALITY 10
64#define MOD_NAME "[audio_resampler] "
70 virtual std::tuple<bool, audio_frame2>
resample(
audio_frame2 &a, std::vector<audio_frame2::channel> &out,
int new_sample_rate_num,
int new_sample_rate_den) = 0;
79 LOG(
LOG_LEVEL_ERROR) <<
"Audio frame resampler: cannot resample, Soxr/SpeexDSP was not compiled in!\n";
82 return m_impl->resample(a, out, new_sample_rate_num, new_sample_rate_den);
96 tuple<bool, audio_frame2>
resample(
audio_frame2 &a, vector<audio_frame2::channel> &new_channels,
int new_sample_rate_num,
int new_sample_rate_den)
override;
98 static const int ret[] = { 2, 4, 0 };
103 soxr_delete(resampler);
108 bool check_reconfigure(uint32_t original_sample_rate, uint32_t new_sample_rate_num, uint32_t new_sample_rate_den,
size_t nb_channels,
unsigned bps);
110 soxr_t resampler{
nullptr};
126bool soxr_resampler::check_reconfigure(uint32_t original_sample_rate, uint32_t new_sample_rate_num, uint32_t new_sample_rate_den,
size_t nb_channels,
unsigned bps) {
127 if (resampler !=
nullptr && nb_channels == prop.ch_count &&
bps == prop.bps) {
128 if (original_sample_rate != prop.rate_from
129 || new_sample_rate_num != prop.rate_to_num
130 || new_sample_rate_den != prop.rate_to_den) {
132 prop.rate_from = original_sample_rate;
133 prop.rate_to_num = new_sample_rate_num;
134 prop.rate_to_den = new_sample_rate_den;
135 soxr_set_io_ratio(resampler, ((
double)prop.rate_from / ((
double)new_sample_rate_num / (
double)new_sample_rate_den)), 0);
140 if (this->resampler) {
141 soxr_delete((soxr_t)this->resampler);
143 this->resampler =
nullptr;
146 soxr_quality_spec_t q_spec = soxr_quality_spec(SOXR_HQ, SOXR_VR);
147 soxr_runtime_spec_t
const runtime_spec = soxr_runtime_spec(1);
148 soxr_io_spec_t io_spec;
150 io_spec = soxr_io_spec(SOXR_INT16_S, SOXR_INT16_S);
153 io_spec = soxr_io_spec(SOXR_INT32_S, SOXR_INT32_S);
164 this->resampler = soxr_create(2, 1, nb_channels, &error, &io_spec, &q_spec, &runtime_spec);
167 LOG(
LOG_LEVEL_ERROR) <<
"[audio_frame2_resampler] Cannot initialize resampler: " << soxr_strerror(error) <<
"\n";
171 soxr_set_io_ratio((soxr_t)this->resampler, ((
double)original_sample_rate / ((
double)new_sample_rate_num / (
double)new_sample_rate_den)), 0);
174 this->prop.rate_from = original_sample_rate;
175 this->prop.rate_to_num = new_sample_rate_num;
176 this->prop.rate_to_den = new_sample_rate_den;
177 this->prop.ch_count = nb_channels;
178 this->prop.bps =
bps;
183tuple<bool, audio_frame2> soxr_resampler::resample(
audio_frame2 &a, vector<audio_frame2::channel> &new_channels,
int new_sample_rate_num,
int new_sample_rate_den) {
184 std::chrono::high_resolution_clock::time_point funcBegin = std::chrono::high_resolution_clock::now();
192 void * *
const obuf_ptrs = (
void * *) malloc(
sizeof(
void *) * a.
get_channel_count());
195 for (
size_t i = 0; i < new_channels.size(); i++) {
197 obuf_ptrs[i] = new_channels[i].data.get();
202 size_t outlen = new_channels[0].len / a.
get_bps();
205 error = soxr_process(resampler, ibuf_ptrs, inlen, NULL, obuf_ptrs, outlen, &odone);
207 LOG(
LOG_LEVEL_ERROR) <<
"[audio_frame2_resampler] resampler failed: " << soxr_strerror(error) <<
"\n";
210 for (
unsigned int i = 0; i < new_channels.size(); i++) {
211 new_channels[i].len = odone * a.
get_bps();
214 free(obuf_ptrs); free(ibuf_ptrs);
216 std::chrono::high_resolution_clock::time_point funcEnd = std::chrono::high_resolution_clock::now();
217 long long resamplerDuration = std::chrono::duration_cast<std::chrono::milliseconds>(funcEnd - funcBegin).count();
218 LOG(
LOG_LEVEL_DEBUG) <<
"[audio_frame2_resampler] resampler_duration " << resamplerDuration <<
"\n";
222 return {
true, std::move(remainder)};
229 tuple<bool, audio_frame2>
resample(
audio_frame2 &a, vector<audio_frame2::channel> &new_channels,
int new_sample_rate_num,
int new_sample_rate_den)
override;
231 speex_resampler(
int q) : quality(q) {}
234 static const int ret[] = { 2, 4, 0 };
240 speex_resampler_destroy(
state);
244 bool check_reconfigure(
unsigned original_sample_rate,
unsigned new_sample_rate_num,
unsigned new_sample_rate_den,
unsigned channel_size,
unsigned bps);
247 SpeexResamplerState *
state{
nullptr};
251bool speex_resampler::check_reconfigure(
unsigned original_sample_rate,
unsigned new_sample_rate_num,
unsigned new_sample_rate_den,
unsigned nb_channels,
unsigned bps) {
252 if (
state !=
nullptr && original_sample_rate == prop.rate_from
253 && new_sample_rate_num == prop.rate_to_num
254 && new_sample_rate_den == prop.rate_to_den
255 && nb_channels == prop.ch_count
256 &&
bps == prop.bps) {
259 if (
bps != 2 &&
bps != 4) {
260 throw logic_error(
"Only 16 or 32 bits per sample are supported for resampling!");
264 speex_resampler_destroy(
state);
268 state = speex_resampler_init_frac(nb_channels, original_sample_rate * new_sample_rate_den,
269 new_sample_rate_num, original_sample_rate, new_sample_rate_num, quality, &err);
274 prop.rate_from = original_sample_rate;
275 prop.rate_to_num = new_sample_rate_num;
276 prop.rate_to_den = new_sample_rate_den;
277 prop.ch_count = nb_channels;
283struct speex_process_channel_data {
284 SpeexResamplerState *
state;
289 uint32_t in_frames_orig;
290 uint32_t write_frames;
293static void *speex_process_channel_short(
void *arg) {
294 auto *d = (speex_process_channel_data *) arg;
295 speex_resampler_process_int(d->state,
297 (spx_int16_t *) d->in, &d->in_frames,
298 (spx_int16_t *) d->out, &d->write_frames);
302static void *speex_process_channel_int(
void *arg) {
303 auto *d = (speex_process_channel_data *) arg;
304 int2float((
char *) d->in, (
char *) d->in,
sizeof(
float) * d->in_frames);
305 speex_resampler_process_float(d->state,
307 (
float *) d->in, &d->in_frames,
308 (
float *) d->out, &d->write_frames);
309 float2int((
char *) d->out, (
char *) d->out,
sizeof(
float) * d->write_frames);
313tuple<bool, audio_frame2> speex_resampler::resample(
audio_frame2 &a, vector<audio_frame2::channel> &new_channels,
int new_sample_rate_num,
int new_sample_rate_den) {
320 remainder.
init(new_channels.size(),
AC_PCM, prop.bps, prop.rate_from);
322 vector <speex_process_channel_data> speex_worker_data(new_channels.size());
323 for (
size_t i = 0; i < new_channels.size(); i++) {
324 speex_worker_data.at(i).state =
state;
325 speex_worker_data.at(i).channel_idx = i;
326 speex_worker_data.at(i).in = (
void *) a.
get_data(i);
327 speex_worker_data.at(i).out = (
void *) new_channels[i].data.get();
328 speex_worker_data.at(i).in_frames_orig =
330 speex_worker_data.at(i).write_frames = new_channels[i].len / a.
get_bps();
333 task_run_parallel(speex_process_channel_short, new_channels.size(), speex_worker_data.data(),
sizeof speex_worker_data[0], NULL);
335 task_run_parallel(speex_process_channel_int, new_channels.size(), speex_worker_data.data(),
sizeof speex_worker_data[0], NULL);
337 for (
size_t i = 0; i < new_channels.size(); i++) {
338 if (speex_worker_data.at(i).in_frames != speex_worker_data.at(i).in_frames_orig) {
340 speex_worker_data.at(i).in_frames_orig - speex_worker_data.at(i).in_frames);
342 new_channels[i].len = speex_worker_data.at(i).write_frames * a.
get_bps();
348 return {
true, std::move(remainder)};
352ADD_TO_PARAM(
"resampler",
"* resampler=[speex|soxr][[:]quality=[0-10]]\n"
357 enum { RESAMPLER_DEFAULT, RESAMPLER_SPEEX, RESAMPLER_SOXR } resampler_type = RESAMPLER_DEFAULT;
359 std::string_view sv = cfg_c ? cfg_c :
"";
361 while (!sv.empty()) {
362 const auto &tok =
tokenize(sv,
':');
363 if (tok ==
"speex") {
364 resampler_type = RESAMPLER_SPEEX;
365 }
else if (tok ==
"soxr") {
366 resampler_type = RESAMPLER_SOXR;
367 }
else if (tok.compare(0,
"quality="sv.length(),
"quality=") == 0) {
368 quality = stoi(
string(tok.substr(
"quality="sv.length())));
369 if (quality < 0 || quality > 10) {
370 throw ug_runtime_error(
"Quality " + to_string(quality) +
" out of range 0-10"s);
376 switch (resampler_type) {
377 case RESAMPLER_DEFAULT:
379 m_impl = unique_ptr<audio_frame2_resampler::impl>(
new speex_resampler(quality));
380#elif defined HAVE_SOXR
381 m_impl = unique_ptr<audio_frame2_resampler::impl>(
new soxr_resampler());
384 case RESAMPLER_SPEEX:
386 m_impl = unique_ptr<audio_frame2_resampler::impl>(
new speex_resampler(quality));
393 m_impl = unique_ptr<audio_frame2_resampler::impl>(
new soxr_resampler());
406 LOG(
LOG_LEVEL_ERROR) <<
"Audio frame resampler: cannot resample, Soxr/SpeexDSP was not compiled in!\n";
409 const int *sup =
m_impl->get_supported_bps();
This file contains definition of some common audio types.
virtual std::tuple< bool, audio_frame2 > resample(audio_frame2 &a, std::vector< audio_frame2::channel > &out, int new_sample_rate_num, int new_sample_rate_den)=0
virtual const int * get_supported_bps()=0
std::tuple< bool, audio_frame2 > resample(audio_frame2 &a, std::vector< audio_frame2::channel > &out, int new_sample_rate_num, int new_sample_rate_den)
std::unique_ptr< impl > m_impl
audio_frame2_resampler & operator=(audio_frame2_resampler &&)
~audio_frame2_resampler()
char * get_data(int channel)
void init(int nr_channels, audio_codec_t codec, int bps, int sample_rate)
Initializes audio_frame2 for use. If already initialized, data are dropped.
int get_channel_count() const
size_t get_data_len(int channel) const
int get_sample_rate() const
void append(audio_frame2 const &frame)
#define LOG_LEVEL_ERROR
general errors
#define LOG_LEVEL_VERBOSE
const char * get_commandline_param(const char *key)
#define ADD_TO_PARAM(param, doc)
#define DEFAULT_SPEEX_RESAMPLE_QUALITY
std::string_view tokenize(std::string_view &str, char delim, char quot)
Tokenizer for string_view.
void float2int(char *out, const char *in, int len)
void int2float(char *out, const char *in, int len)
void task_run_parallel(runnable_t task, int worker_count, void *data, size_t data_size, void **res)