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.
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 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
diff --git a/include/SDL_hints.h b/include/SDL_hints.h
index 4d445b3..600989e 100644
--- a/include/SDL_hints.h
+++ b/include/SDL_hints.h
@@ -278,10 +278,7 @@ extern "C" {
* If this hint isn't specified to a valid setting, or libsamplerate isn't
* available, SDL will use the default, internal resampling algorithm.
*
- * 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 default resampler (although this
- * might change for SDL 2.1).
+ * As of SDL 2.26, SDL_AudioCVT now respects this hint.
*
* This hint is currently only checked at audio subsystem initialization.
*
diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c
index 11700d4..0888878 100644
--- a/src/audio/SDL_audio.c
+++ b/src/audio/SDL_audio.c
@@ -144,6 +144,7 @@ int (*SRC_src_process)(SRC_STATE *state, SRC_DATA *data) = NULL;
int (*SRC_src_reset)(SRC_STATE *state) = NULL;
SRC_STATE* (*SRC_src_delete)(SRC_STATE *state) = 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
LoadLibSampleRate(void)
@@ -178,8 +179,9 @@ LoadLibSampleRate(void)
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_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);
SRC_lib = NULL;
return SDL_FALSE;
@@ -190,6 +192,7 @@ LoadLibSampleRate(void)
SRC_src_reset = src_reset;
SRC_src_delete = src_delete;
SRC_src_strerror = src_strerror;
+ SRC_src_simple = src_simple;
#endif
SRC_available = SDL_TRUE;
diff --git a/src/audio/SDL_audio_c.h b/src/audio/SDL_audio_c.h
index a516c55..a976dfd 100644
--- a/src/audio/SDL_audio_c.h
+++ b/src/audio/SDL_audio_c.h
@@ -45,6 +45,7 @@ extern int (*SRC_src_process)(SRC_STATE *state, SRC_DATA *data);
extern int (*SRC_src_reset)(SRC_STATE *state);
extern SRC_STATE* (*SRC_src_delete)(SRC_STATE *state);
extern const char* (*SRC_src_strerror)(int error);
+extern int (*SRC_src_simple)(SRC_DATA *data, int converter_type, int channels);
#endif
/* Functions to get a list of "close" audio formats */
diff --git a/src/audio/SDL_audiocvt.c b/src/audio/SDL_audiocvt.c
index 85faa4b..e79437e 100644
--- a/src/audio/SDL_audiocvt.c
+++ b/src/audio/SDL_audiocvt.c
@@ -418,6 +418,48 @@ SDL_BuildAudioTypeCVTFromFloat(SDL_AudioCVT *cvt, const SDL_AudioFormat dst_fmt)
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
SDL_ResampleCVT(SDL_AudioCVT *cvt, const int chans, const SDL_AudioFormat format)
{
@@ -478,9 +520,36 @@ RESAMPLER_FUNCS(6)
RESAMPLER_FUNCS(8)
#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
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) {
case 1: return SDL_ResampleCVT_c1;
case 2: return SDL_ResampleCVT_c2;