mirror of https://github.com/encounter/SDL.git
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.
This commit is contained in:
parent
5ea0c893cd
commit
c7f9dcb6fc
|
@ -775,6 +775,42 @@ extern "C" {
|
||||||
*/
|
*/
|
||||||
#define SDL_HINT_OPENGL_ES_DRIVER "SDL_OPENGL_ES_DRIVER"
|
#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
|
* \brief An enumeration of hint priorities
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -113,6 +113,7 @@ static const AudioBootStrap *const bootstrap[] = {
|
||||||
static void *SRC_lib = NULL;
|
static void *SRC_lib = NULL;
|
||||||
#endif
|
#endif
|
||||||
SDL_bool SRC_available = SDL_FALSE;
|
SDL_bool SRC_available = SDL_FALSE;
|
||||||
|
int SRC_converter = 0;
|
||||||
SRC_STATE* (*SRC_src_new)(int converter_type, int channels, int *error) = NULL;
|
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_process)(SRC_STATE *state, SRC_DATA *data) = NULL;
|
||||||
int (*SRC_src_reset)(SRC_STATE *state) = NULL;
|
int (*SRC_src_reset)(SRC_STATE *state) = NULL;
|
||||||
|
@ -122,10 +123,25 @@ const char* (*SRC_src_strerror)(int error) = NULL;
|
||||||
static SDL_bool
|
static SDL_bool
|
||||||
LoadLibSampleRate(void)
|
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)) {
|
SRC_available = SDL_FALSE;
|
||||||
return 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
|
#ifdef SDL_LIBSAMPLERATE_DYNAMIC
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
#ifdef HAVE_LIBSAMPLERATE_H
|
#ifdef HAVE_LIBSAMPLERATE_H
|
||||||
#include "samplerate.h"
|
#include "samplerate.h"
|
||||||
extern SDL_bool SRC_available;
|
extern SDL_bool SRC_available;
|
||||||
|
extern int SRC_converter;
|
||||||
extern SRC_STATE* (*SRC_src_new)(int converter_type, int channels, int *error);
|
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_process)(SRC_STATE *state, SRC_DATA *data);
|
||||||
extern int (*SRC_src_reset)(SRC_STATE *state);
|
extern int (*SRC_src_reset)(SRC_STATE *state);
|
||||||
|
|
|
@ -947,7 +947,7 @@ SetupLibSampleRateResampling(SDL_AudioStream *stream)
|
||||||
SRC_STATE *state = NULL;
|
SRC_STATE *state = NULL;
|
||||||
|
|
||||||
if (SRC_available) {
|
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) {
|
if (!state) {
|
||||||
SDL_SetError("src_new() failed: %s", SRC_src_strerror(result));
|
SDL_SetError("src_new() failed: %s", SRC_src_strerror(result));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue