audio: Offer a hint for libsamplerate quality/speed tradeoff. This defaults to the internal SDL resampler, since that's the likely default without a system-wide install of libsamplerate, but those that need more can tweak this.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
diff --git a/include/SDL_hints.h b/include/SDL_hints.h
index a50bba3..ef68966 100644
--- a/include/SDL_hints.h
+++ b/include/SDL_hints.h
@@ -776,6 +776,42 @@ extern "C" {
#define SDL_HINT_OPENGL_ES_DRIVER "SDL_OPENGL_ES_DRIVER"
/**
+ * \brief A variable controlling speed/quality tradeoff of audio resampling.
+ *
+ * If available, SDL can use libsamplerate ( http://www.mega-nerd.com/SRC/ )
+ * to handle audio resampling. There are different resampling modes available
+ * that produce different levels of quality, possibly using more CPU.
+ *
+ * If this hint isn't specified to a valid setting, or libsamplerate isn't
+ * available, SDL will act as if this hint was set to "fast".
+ *
+ * Note that this is currently only applicable to resampling audio that is
+ * being written to a device for playback or audio being read from a device
+ * for capture. SDL_AudioCVT always uses the "fast" resampler (although this
+ * might change for SDL 2.1).
+ *
+ * Most things can probably live with the "fast" resampler, but if quality
+ * is important or you can spare some CPU cycles, the other options are
+ * worth exploring!
+ *
+ * libsamplerate's interpolators, that these hints map to, are explained here:
+ * http://www.mega-nerd.com/SRC/api_misc.html#Converters
+ *
+ * This hint is only checked at audio subsystem init time and changes to it
+ * at other times are ignored.
+ *
+ * This variable can be set to the following values:
+ *
+ * "default" - Use SDL's internal, resampler. (Default when not set. low quality, fast.)
+ * "linear" - Use libsamplerate's Linear interpolator (low quality, fast).
+ * "zero_order_hold" - Use libsamplerate's Zero Order Hold interpolator (low quality, fast).
+ * "sinc_fastest" - Use libsamplerate's fastest (lowest quality) sinc interpolator.
+ * "sinc_medium" - Use libsamplerate's medium quality sinc interpolator.
+ * "sinc_best" - Use libsamplerate's best quality sinc interpolator.
+ */
+#define SDL_HINT_AUDIO_RESAMPLER_MODE "SDL_AUDIO_RESAMPLER_MODE"
+
+/**
* \brief An enumeration of hint priorities
*/
typedef enum
diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c
index a62ef42..ec4c981 100644
--- a/src/audio/SDL_audio.c
+++ b/src/audio/SDL_audio.c
@@ -113,6 +113,7 @@ static const AudioBootStrap *const bootstrap[] = {
static void *SRC_lib = NULL;
#endif
SDL_bool SRC_available = SDL_FALSE;
+int SRC_converter = 0;
SRC_STATE* (*SRC_src_new)(int converter_type, int channels, int *error) = NULL;
int (*SRC_src_process)(SRC_STATE *state, SRC_DATA *data) = NULL;
int (*SRC_src_reset)(SRC_STATE *state) = NULL;
@@ -122,10 +123,25 @@ const char* (*SRC_src_strerror)(int error) = NULL;
static SDL_bool
LoadLibSampleRate(void)
{
- SRC_available = SDL_FALSE;
+ const char *hint = SDL_GetHint(SDL_HINT_AUDIO_RESAMPLER_MODE);
- if (!SDL_GetHintBoolean("SDL_AUDIO_ALLOW_LIBRESAMPLE", SDL_TRUE)) {
- return SDL_FALSE;
+ SRC_available = SDL_FALSE;
+ SRC_converter = 0;
+
+ if (!hint || (SDL_strcasecmp(hint, "default") == 0)) {
+ return SDL_FALSE; /* don't load anything. */
+ } else if (SDL_strcasecmp(hint, "linear") == 0) {
+ SRC_converter = SRC_LINEAR;
+ } else if (SDL_strcasecmp(hint, "zero_order_hold") == 0) {
+ SRC_converter = SRC_ZERO_ORDER_HOLD;
+ } else if (SDL_strcasecmp(hint, "sinc_fastest") == 0) {
+ SRC_converter = SRC_SINC_FASTEST;
+ } else if (SDL_strcasecmp(hint, "sinc_medium") == 0) {
+ SRC_converter = SRC_SINC_MEDIUM_QUALITY;
+ } else if (SDL_strcasecmp(hint, "sinc_best") == 0) {
+ SRC_converter = SRC_SINC_BEST_QUALITY;
+ } else {
+ return SDL_FALSE; /* treat it like "default", don't load anything. */
}
#ifdef SDL_LIBSAMPLERATE_DYNAMIC
diff --git a/src/audio/SDL_audio_c.h b/src/audio/SDL_audio_c.h
index 8a8af13..6358a08 100644
--- a/src/audio/SDL_audio_c.h
+++ b/src/audio/SDL_audio_c.h
@@ -39,6 +39,7 @@
#ifdef HAVE_LIBSAMPLERATE_H
#include "samplerate.h"
extern SDL_bool SRC_available;
+extern int SRC_converter;
extern SRC_STATE* (*SRC_src_new)(int converter_type, int channels, int *error);
extern int (*SRC_src_process)(SRC_STATE *state, SRC_DATA *data);
extern int (*SRC_src_reset)(SRC_STATE *state);
diff --git a/src/audio/SDL_audiocvt.c b/src/audio/SDL_audiocvt.c
index 4a33a83..73fb0c7 100644
--- a/src/audio/SDL_audiocvt.c
+++ b/src/audio/SDL_audiocvt.c
@@ -947,7 +947,7 @@ SetupLibSampleRateResampling(SDL_AudioStream *stream)
SRC_STATE *state = NULL;
if (SRC_available) {
- state = SRC_src_new(SRC_SINC_FASTEST, stream->pre_resample_channels, &result);
+ state = SRC_src_new(SRC_converter, stream->pre_resample_channels, &result);
if (!state) {
SDL_SetError("src_new() failed: %s", SRC_src_strerror(result));
}