mirror of https://github.com/encounter/SDL.git
SDL_audiocvt: Respct the SDL_HINT_AUDIO_RESAMPLING_MODE hint
This implements using libsamplerate for the SDL_AudioCVT API. This library was already being used for audio streams when this hint is set.
This commit is contained in:
parent
e8fdb861ef
commit
22461383c6
|
@ -278,10 +278,7 @@ extern "C" {
|
||||||
* If this hint isn't specified to a valid setting, or libsamplerate isn't
|
* If this hint isn't specified to a valid setting, or libsamplerate isn't
|
||||||
* available, SDL will use the default, internal resampling algorithm.
|
* available, SDL will use the default, internal resampling algorithm.
|
||||||
*
|
*
|
||||||
* Note that this is currently only applicable to resampling audio that is
|
* As of SDL 2.26, SDL_AudioCVT now respects this hint.
|
||||||
* being written to a device for playback or audio being read from a device
|
|
||||||
* for capture. SDL_AudioCVT always uses the default resampler (although this
|
|
||||||
* might change for SDL 2.1).
|
|
||||||
*
|
*
|
||||||
* This hint is currently only checked at audio subsystem initialization.
|
* This hint is currently only checked at audio subsystem initialization.
|
||||||
*
|
*
|
||||||
|
|
|
@ -144,6 +144,7 @@ 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;
|
||||||
SRC_STATE* (*SRC_src_delete)(SRC_STATE *state) = NULL;
|
SRC_STATE* (*SRC_src_delete)(SRC_STATE *state) = NULL;
|
||||||
const char* (*SRC_src_strerror)(int error) = NULL;
|
const char* (*SRC_src_strerror)(int error) = NULL;
|
||||||
|
int (*SRC_src_simple)(SRC_DATA *data, int converter_type, int channels) = NULL;
|
||||||
|
|
||||||
static SDL_bool
|
static SDL_bool
|
||||||
LoadLibSampleRate(void)
|
LoadLibSampleRate(void)
|
||||||
|
@ -178,8 +179,9 @@ LoadLibSampleRate(void)
|
||||||
SRC_src_reset = (int(*)(SRC_STATE *state))SDL_LoadFunction(SRC_lib, "src_reset");
|
SRC_src_reset = (int(*)(SRC_STATE *state))SDL_LoadFunction(SRC_lib, "src_reset");
|
||||||
SRC_src_delete = (SRC_STATE* (*)(SRC_STATE *state))SDL_LoadFunction(SRC_lib, "src_delete");
|
SRC_src_delete = (SRC_STATE* (*)(SRC_STATE *state))SDL_LoadFunction(SRC_lib, "src_delete");
|
||||||
SRC_src_strerror = (const char* (*)(int error))SDL_LoadFunction(SRC_lib, "src_strerror");
|
SRC_src_strerror = (const char* (*)(int error))SDL_LoadFunction(SRC_lib, "src_strerror");
|
||||||
|
SRC_src_simple = (int(*)(SRC_DATA *data, int converter_type, int channels))SDL_LoadFunction(SRC_lib, "src_simple");
|
||||||
|
|
||||||
if (!SRC_src_new || !SRC_src_process || !SRC_src_reset || !SRC_src_delete || !SRC_src_strerror) {
|
if (!SRC_src_new || !SRC_src_process || !SRC_src_reset || !SRC_src_delete || !SRC_src_strerror || !SRC_src_simple) {
|
||||||
SDL_UnloadObject(SRC_lib);
|
SDL_UnloadObject(SRC_lib);
|
||||||
SRC_lib = NULL;
|
SRC_lib = NULL;
|
||||||
return SDL_FALSE;
|
return SDL_FALSE;
|
||||||
|
@ -190,6 +192,7 @@ LoadLibSampleRate(void)
|
||||||
SRC_src_reset = src_reset;
|
SRC_src_reset = src_reset;
|
||||||
SRC_src_delete = src_delete;
|
SRC_src_delete = src_delete;
|
||||||
SRC_src_strerror = src_strerror;
|
SRC_src_strerror = src_strerror;
|
||||||
|
SRC_src_simple = src_simple;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
SRC_available = SDL_TRUE;
|
SRC_available = SDL_TRUE;
|
||||||
|
|
|
@ -45,6 +45,7 @@ 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);
|
||||||
extern SRC_STATE* (*SRC_src_delete)(SRC_STATE *state);
|
extern SRC_STATE* (*SRC_src_delete)(SRC_STATE *state);
|
||||||
extern const char* (*SRC_src_strerror)(int error);
|
extern const char* (*SRC_src_strerror)(int error);
|
||||||
|
extern int (*SRC_src_simple)(SRC_DATA *data, int converter_type, int channels);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Functions to get a list of "close" audio formats */
|
/* Functions to get a list of "close" audio formats */
|
||||||
|
|
|
@ -418,6 +418,48 @@ SDL_BuildAudioTypeCVTFromFloat(SDL_AudioCVT *cvt, const SDL_AudioFormat dst_fmt)
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBSAMPLERATE_H
|
||||||
|
|
||||||
|
static void
|
||||||
|
SDL_ResampleCVT_SRC(SDL_AudioCVT *cvt, const int chans, const SDL_AudioFormat format)
|
||||||
|
{
|
||||||
|
const float *src = (const float *) cvt->buf;
|
||||||
|
const int srclen = cvt->len_cvt;
|
||||||
|
float *dst = (float *) (cvt->buf + srclen);
|
||||||
|
const int dstlen = (cvt->len * cvt->len_mult) - srclen;
|
||||||
|
const int framelen = sizeof(float) * chans;
|
||||||
|
int result = 0;
|
||||||
|
SRC_DATA data;
|
||||||
|
|
||||||
|
SDL_zero(data);
|
||||||
|
|
||||||
|
data.data_in = (float *)src; /* Older versions of libsamplerate had a non-const pointer, but didn't write to it */
|
||||||
|
data.input_frames = srclen / framelen;
|
||||||
|
|
||||||
|
data.data_out = dst;
|
||||||
|
data.output_frames = dstlen / framelen;
|
||||||
|
|
||||||
|
data.src_ratio = cvt->rate_incr;
|
||||||
|
|
||||||
|
result = SRC_src_simple(&data, SRC_converter, chans); /* Simple API converts the whole buffer at once. No need for initialization. */
|
||||||
|
/* !!! FIXME: Handle library failures? */
|
||||||
|
#ifdef DEBUG_CONVERT
|
||||||
|
if (result != 0) {
|
||||||
|
SDL_Log("src_simple() failed: %s", SRC_src_strerror(result));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
cvt->len_cvt = data.output_frames_gen * framelen;
|
||||||
|
|
||||||
|
SDL_memmove(cvt->buf, dst, cvt->len_cvt);
|
||||||
|
|
||||||
|
if (cvt->filters[++cvt->filter_index]) {
|
||||||
|
cvt->filters[cvt->filter_index](cvt, format);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* HAVE_LIBSAMPLERATE_H */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
SDL_ResampleCVT(SDL_AudioCVT *cvt, const int chans, const SDL_AudioFormat format)
|
SDL_ResampleCVT(SDL_AudioCVT *cvt, const int chans, const SDL_AudioFormat format)
|
||||||
{
|
{
|
||||||
|
@ -478,9 +520,36 @@ RESAMPLER_FUNCS(6)
|
||||||
RESAMPLER_FUNCS(8)
|
RESAMPLER_FUNCS(8)
|
||||||
#undef RESAMPLER_FUNCS
|
#undef RESAMPLER_FUNCS
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBSAMPLERATE_H
|
||||||
|
#define RESAMPLER_FUNCS(chans) \
|
||||||
|
static void SDLCALL \
|
||||||
|
SDL_ResampleCVT_SRC_c##chans(SDL_AudioCVT *cvt, SDL_AudioFormat format) { \
|
||||||
|
SDL_ResampleCVT_SRC(cvt, chans, format); \
|
||||||
|
}
|
||||||
|
RESAMPLER_FUNCS(1)
|
||||||
|
RESAMPLER_FUNCS(2)
|
||||||
|
RESAMPLER_FUNCS(4)
|
||||||
|
RESAMPLER_FUNCS(6)
|
||||||
|
RESAMPLER_FUNCS(8)
|
||||||
|
#undef RESAMPLER_FUNCS
|
||||||
|
#endif /* HAVE_LIBSAMPLERATE_H */
|
||||||
|
|
||||||
static SDL_AudioFilter
|
static SDL_AudioFilter
|
||||||
ChooseCVTResampler(const int dst_channels)
|
ChooseCVTResampler(const int dst_channels)
|
||||||
{
|
{
|
||||||
|
#ifdef HAVE_LIBSAMPLERATE_H
|
||||||
|
if (SRC_available) {
|
||||||
|
switch (dst_channels) {
|
||||||
|
case 1: return SDL_ResampleCVT_SRC_c1;
|
||||||
|
case 2: return SDL_ResampleCVT_SRC_c2;
|
||||||
|
case 4: return SDL_ResampleCVT_SRC_c4;
|
||||||
|
case 6: return SDL_ResampleCVT_SRC_c6;
|
||||||
|
case 8: return SDL_ResampleCVT_SRC_c8;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* HAVE_LIBSAMPLERATE_H */
|
||||||
|
|
||||||
switch (dst_channels) {
|
switch (dst_channels) {
|
||||||
case 1: return SDL_ResampleCVT_c1;
|
case 1: return SDL_ResampleCVT_c1;
|
||||||
case 2: return SDL_ResampleCVT_c2;
|
case 2: return SDL_ResampleCVT_c2;
|
||||||
|
|
Loading…
Reference in New Issue