Resampling using Soxr library instead of libsamplerate

Forums:

MOC version: 
2.6-alpha3

Hello,

As libsamplerate is using too much CPU at the best quality, I replaced it by Soxr. The developper of Soxr has written an implementation using the libsamplerate API (libsoxr-lsr), so first I just linked to libsoxr-lsr and it worked. CPU usage decreases, but you have to keep the libsamplerate options in the config file, which is weird if you say you use soxr. So I modified the code to use only the soxr API.

I post the modifications of the file here, I hope you will be able to read and understand it. You also have to replace #HAVE_SAMPLERATE by #HAVE_SOXR in every file needed.

As you will see, the algorithm to use soxr_process is much simpler than for libsamplerate, but it seems to work. The options are "VeryHighQuality" (best quality), "HighQuality", "MediumQuality", "LowQuality" and "QuickQubic" (lowest quality).

audio_conversion.h

#ifdef HAVE_SOXR # include <soxr.h> #endif (...) struct audio_conversion { struct sound_params from; struct sound_params to; #ifdef HAVE_SOXR soxr_t soxr_resampler; float *resample_buf; size_t resample_buf_nsamples; /* in samples ( sizeof(float) ) */ #endif };

audio_conversion.c

int audio_conv_new (struct audio_conversion *conv, const struct sound_params *from, const struct sound_params *to) { logit ("In AudioConvNew: creating audio_conversion structure"); assert (from->rate != to->rate || from->fmt != to->fmt || from->channels != to->channels); if (from->channels != to->channels) { /* the only conversion we can do */ if (!(from->channels == 1 && to->channels == 2)) { error ("Can't change number of channels (%d to %d)!", from->channels, to->channels); return 0; } } if (from->rate != to->rate) { #ifdef HAVE_SOXR soxr_error_t err; int resample_type = -1; char *method = options_get_symb ("ResampleMethod"); if (!strcasecmp(method, "VeryHighQuality")) resample_type = SOXR_VHQ; else if (!strcasecmp(method, "HighQuality")) resample_type = SOXR_HQ; else if (!strcasecmp(method, "MediumQuality")) resample_type = SOXR_MQ; else if (!strcasecmp(method, "LowQuality")) resample_type = SOXR_LQ; else if (!strcasecmp(method, "QuickQubic")) resample_type = SOXR_QQ; else fatal ("Bad ResampleMethod option: %s", method); soxr_quality_spec_t resampler_quality = soxr_quality_spec(resample_type, 0); conv->soxr_resampler = soxr_create(from->rate, to->rate, to->channels, &err,NULL, &resampler_quality, NULL); if (err) { logit ("Error couldn't create soxr resampler."); return 0; } #else error ("Resampling not supported!"); return 0; #endif } #ifdef HAVE_SOXR else conv->soxr_resampler = NULL; #endif conv->from = *from; conv->to = *to; return 1; }
static float *resample_sound (struct audio_conversion *conv, const float *buf, const size_t samples, const int nchannels, size_t *resampled_samples) { float *output; size_t odone; soxr_error_t err; size_t const osize = sizeof(float); float freq_ratio = conv->to.rate / (double)conv->from.rate; size_t osamples = (size_t) (samples * freq_ratio + 0.5); size_t olen = osamples / nchannels; size_t ilen = samples / nchannels; output = (float *)xmalloc (osize * osamples); if ((err = soxr_process(conv->soxr_resampler, buf, ilen, NULL, output, olen, &odone))) { error ("Soxr Can't resample : %s", soxr_error(conv->soxr_resampler) ); free (output); return NULL; } else if (odone == 0) { logit ("odone = 0, no resampled samples. Total samples number < 1024 ?"); *resampled_samples = 0; output = NULL; } *resampled_samples = odone * nchannels; return output; }
void audio_conv_destroy (struct audio_conversion *conv ASSERT_ONLY) { assert (conv != NULL); #ifdef HAVE_SOXR if (conv->soxr_resampler) soxr_delete (conv->soxr_resampler); #endif }

options.c

void options_init () { (...) add_symb ("ResampleMethod", "HighQuality", CHECK_SYMBOL(5), "VeryHighQuality", "HighQuality", "MediumQuality", "LowQuality", "QuickQubic"); (...) }

configure.in

dnl samplerate AC_ARG_WITH(samplerate, AS_HELP_STRING([--without-samplerate], [Compile without libsoxr])) COMPILE_SAMPLERATE="no" if test "x$with_samplerate" != "xno" then PKG_CHECK_MODULES([SOXR], [soxr >= 0.1], [ EXTRA_LIBS="$EXTRA_LIBS $SOXR_LIBS" CFLAGS="$CFLAGS $SOXR_CFLAGS" AC_DEFINE([HAVE_SOXR], 1, [Define if you have libsoxr]) COMPILE_SAMPLERATE="yes"], [true]) fi

In the code I sent, in audio_conversion.h, I forgot to remove

float *resample_buf;
size_t resample_buf_nsamples; /* in samples ( sizeof(float) ) */

I did it a few years ago, and you can compare your code with mine. You can find it at https://gitlab.com/tomaszg/mocp/tree/speex). It supports 3 additional resampling libraries: soxr, speex and zita.

PS. It would be better for people who would want to try your code to present it as a patch.

Ok, thank you,

The codes are nearly identical, but as your version has also opus support I might adopt it.