From e5a6c24c822e11c9a99f10adad49f904b8170562 Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Sat, 1 Apr 2023 22:29:30 -0400
Subject: [PATCH] audio: Redesigned audio conversion code for SDL3.
- SDL_AudioCVT is gone, even internally.
- libsamplerate is gone (I suspect our resampler is finally Good Enough).
- Cleanups and improvements to audio conversion interfaces.
- SDL_AudioStream can change its input/output format/rate/channels on the fly!
---
CMakeLists.txt | 3 -
build-scripts/gen_audio_channel_conversion.c | 80 +-
cmake/sdlchecks.cmake | 47 -
docs/README-linux.md | 8 +-
docs/README-migration.md | 3 +
include/SDL3/SDL_audio.h | 107 +-
include/SDL3/SDL_hints.h | 14 +-
include/build_config/SDL_build_config.h.cmake | 4 -
src/audio/SDL_audio.c | 95 -
src/audio/SDL_audio_c.h | 44 +-
src/audio/SDL_audio_channel_converters.h | 806 +++-----
src/audio/SDL_audiocvt.c | 1795 +++++++----------
src/audio/SDL_audiocvt_c.h | 69 -
src/audio/SDL_audiotypecvt.c | 465 ++---
src/audio/SDL_mixer.c | 3 +
src/dynapi/SDL_dynapi.sym | 2 +
src/dynapi/SDL_dynapi_overrides.h | 2 +
src/dynapi/SDL_dynapi_procs.h | 4 +-
test/CMakeLists.txt | 1 +
test/testaudiostreamdynamicresample.c | 123 ++
20 files changed, 1370 insertions(+), 2305 deletions(-)
delete mode 100644 src/audio/SDL_audiocvt_c.h
create mode 100644 test/testaudiostreamdynamicresample.c
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6cca05ba958e..407f7e46ab15 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -411,8 +411,6 @@ set_option(SDL_PULSEAUDIO "Use PulseAudio" ${UNIX_SYS})
dep_option(SDL_PULSEAUDIO_SHARED "Dynamically load PulseAudio support" ON "SDL_PULSEAUDIO" OFF)
set_option(SDL_SNDIO "Support the sndio audio API" ${UNIX_SYS})
dep_option(SDL_SNDIO_SHARED "Dynamically load the sndio audio API" ON "SDL_SNDIO" OFF)
-set_option(SDL_LIBSAMPLERATE "Use libsamplerate for audio rate conversion" ${UNIX_SYS})
-dep_option(SDL_LIBSAMPLERATE_SHARED "Dynamically load libsamplerate" ON "SDL_LIBSAMPLERATE" OFF)
set_option(SDL_RPATH "Use an rpath when linking SDL" ${UNIX_SYS})
set_option(SDL_CLOCK_GETTIME "Use clock_gettime() instead of gettimeofday()" ${SDL_CLOCK_GETTIME_ENABLED_BY_DEFAULT})
set_option(SDL_X11 "Use X11 video driver" ${UNIX_SYS})
@@ -2909,7 +2907,6 @@ if(HAVE_VULKAN AND NOT SDL_LOADSO)
endif()
# Platform-independent options
-CheckLibSampleRate()
if(SDL_VIDEO)
if(SDL_OFFSCREEN AND SDL_VIDEO_OPENGL_EGL)
diff --git a/build-scripts/gen_audio_channel_conversion.c b/build-scripts/gen_audio_channel_conversion.c
index 18304d51eb24..1056593b6d7b 100644
--- a/build-scripts/gen_audio_channel_conversion.c
+++ b/build-scripts/gen_audio_channel_conversion.c
@@ -261,27 +261,43 @@ static void write_converter(const int fromchans, const int tochans)
}
}
- printf("static void SDLCALL\n"
- "SDL_Convert%sTo%s(SDL_AudioCVT *cvt, SDL_AudioFormat format)\n"
- "{\n", remove_dots(fromstr), remove_dots(tostr));
-
- if (convert_backwards) { /* must convert backwards when growing the output in-place. */
- printf(" float *dst = ((float *) (cvt->buf + ((cvt->len_cvt / %d) * %d))) - %d;\n", fromchans, tochans, tochans);
- printf(" const float *src = ((const float *) (cvt->buf + cvt->len_cvt)) - %d;\n", fromchans);
- } else {
- printf(" float *dst = (float *) cvt->buf;\n");
- printf(" const float *src = dst;\n");
- }
+ printf("static void SDL_Convert%sTo%s(float *dst, const float *src, int num_frames)\n{\n", remove_dots(fromstr), remove_dots(tostr));
printf(" int i;\n"
"\n"
- " LOG_DEBUG_CONVERT(\"%s\", \"%s\");\n"
- " SDL_assert(format == AUDIO_F32SYS);\n"
+ " LOG_DEBUG_AUDIO_CONVERT(\"%s\", \"%s\");\n"
"\n", lowercase(fromstr), lowercase(tostr));
- if (convert_backwards) {
+ if (convert_backwards) { /* must convert backwards when growing the output in-place. */
printf(" /* convert backwards, since output is growing in-place. */\n");
- printf(" for (i = cvt->len_cvt / (sizeof (float) * %d); i; i--, src -= %d, dst -= %d) {\n", fromchans, fromchans, tochans);
+ printf(" src += (num_frames-1)");
+ if (fromchans != 1) {
+ printf(" * %d", fromchans);
+ }
+ printf(";\n");
+
+ printf(" dst += (num_frames-1)");
+ if (tochans != 1) {
+ printf(" * %d", tochans);
+ }
+ printf(";\n");
+ printf(" for (i = num_frames");
+ if (fromchans > 1) {
+ printf(" * %d", fromchans);
+ }
+ printf("; i; i--, ");
+ if (fromchans == 1) {
+ printf("src--");
+ } else {
+ printf("src -= %d", fromchans);
+ }
+ printf(", ");
+ if (tochans == 1) {
+ printf("dst--");
+ } else {
+ printf("dst -= %d", tochans);
+ }
+ printf(") {\n");
fptr = cvtmatrix;
for (i = 0; i < fromchans; i++) {
if (input_channel_used[i] > 1) { /* don't read it from src more than once. */
@@ -326,7 +342,19 @@ static void write_converter(const int fromchans, const int tochans)
printf(" }\n");
} else {
- printf(" for (i = cvt->len_cvt / (sizeof (float) * %d); i; i--, src += %d, dst += %d) {\n", fromchans, fromchans, tochans);
+ printf(" for (i = num_frames * %d; i; i--, ", fromchans);
+ if (fromchans == 1) {
+ printf("src++");
+ } else {
+ printf("src += %d", fromchans);
+ }
+ printf(", ");
+ if (tochans == 1) {
+ printf("dst++");
+ } else {
+ printf("dst += %d", tochans);
+ }
+ printf(") {\n");
fptr = cvtmatrix;
for (i = 0; i < fromchans; i++) {
@@ -372,20 +400,7 @@ static void write_converter(const int fromchans, const int tochans)
printf(" }\n");
}
- printf("\n");
-
- if ((fromchans > 1) && (tochans > 1)) {
- printf(" cvt->len_cvt = (cvt->len_cvt / %d) * %d;\n", fromchans, tochans);
- } else if (tochans == 1) {
- printf(" cvt->len_cvt = cvt->len_cvt / %d;\n", fromchans);
- } else /* if (fromchans == 1) */ {
- printf(" cvt->len_cvt = cvt->len_cvt * %d;\n", tochans);
- }
-
- printf(" if (cvt->filters[++cvt->filter_index]) {\n"
- " cvt->filters[cvt->filter_index] (cvt, format);\n"
- " }\n"
- "}\n\n");
+ printf("\n}\n\n");
}
int main(void)
@@ -416,6 +431,9 @@ int main(void)
"\n"
"/* DO NOT EDIT, THIS FILE WAS GENERATED BY build-scripts/gen_audio_channel_conversion.c */\n"
"\n"
+ "\n"
+ "typedef void (*SDL_AudioChannelConverter)(float *dst, const float *src, int num_frames);\n"
+ "\n"
);
for (ini = 1; ini <= NUM_CHANNELS; ini++) {
@@ -424,7 +442,7 @@ int main(void)
}
}
- printf("static const SDL_AudioFilter channel_converters[%d][%d] = { /* [from][to] */\n", NUM_CHANNELS, NUM_CHANNELS);
+ printf("static const SDL_AudioChannelConverter channel_converters[%d][%d] = { /* [from][to] */\n", NUM_CHANNELS, NUM_CHANNELS);
for (ini = 1; ini <= NUM_CHANNELS; ini++) {
const char *comma = "";
printf(" {");
diff --git a/cmake/sdlchecks.cmake b/cmake/sdlchecks.cmake
index 667221710a09..bab63865874b 100644
--- a/cmake/sdlchecks.cmake
+++ b/cmake/sdlchecks.cmake
@@ -240,53 +240,6 @@ macro(CheckSNDIO)
endif()
endmacro()
-# Requires:
-# - SDL_LIBSAMPLERATE
-# Optional:
-# - SDL_LIBSAMPLERATE_SHARED opt
-# - HAVE_SDL_LOADSO opt
-macro(CheckLibSampleRate)
- if(SDL_LIBSAMPLERATE)
- find_package(SampleRate QUIET)
- if(SampleRate_FOUND AND TARGET SampleRate::samplerate)
- set(HAVE_LIBSAMPLERATE TRUE)
- if(SDL_LIBSAMPLERATE_SHARED)
- target_include_directories(sdl-build-options INTERFACE $<TARGET_PROPERTY:SampleRate::samplerate,INTERFACE_INCLUDE_DIRECTORIES>)
- if(NOT HAVE_SDL_LOADSO)
- message_warn("You must have SDL_LoadObject() support for dynamic libsamplerate loading")
- else()
- get_property(_samplerate_type TARGET SampleRate::samplerate PROPERTY TYPE)
- if(_samplerate_type STREQUAL "SHARED_LIBRARY")
- set(HAVE_LIBSAMPLERATE_SHARED TRUE)
- if(WIN32)
- set(SDL_LIBSAMPLERATE_DYNAMIC "\"$<TARGET_FILE_NAME:SampleRate::samplerate>\"")
- else()
- set(SDL_LIBSAMPLERATE_DYNAMIC "\"$<TARGET_SONAME_FILE_NAME:SampleRate::samplerate>\"")
- endif()
- endif()
- endif()
- else()
- target_link_libraries(sdl-build-options INTERFACE SampleRate::samplerate)
- endif()
- else()
- check_include_file(samplerate.h HAVE_LIBSAMPLERATE_H)
- if(HAVE_LIBSAMPLERATE_H)
- set(HAVE_LIBSAMPLERATE TRUE)
- if(SDL_LIBSAMPLERATE_SHARED AND NOT HAVE_SDL_LOADSO)
- message_warn("You must have SDL_LoadObject() support for dynamic libsamplerate loading")
- endif()
- FindLibraryAndSONAME("samplerate")
- if(SDL_LIBSAMPLERATE_SHARED AND SAMPLERATE_LIB AND HAVE_SDL_LOADSO)
- set(SDL_LIBSAMPLERATE_DYNAMIC "\"${SAMPLERATE_LIB_SONAME}\"")
- set(HAVE_LIBSAMPLERATE_SHARED TRUE)
- else()
- list(APPEND SDL_EXTRA_LIBS samplerate)
- endif()
- endif()
- endif()
- endif()
-endmacro()
-
# Requires:
# - n/a
# Optional:
diff --git a/docs/README-linux.md b/docs/README-linux.md
index ea354e95f630..768a712525d9 100644
--- a/docs/README-linux.md
+++ b/docs/README-linux.md
@@ -16,7 +16,7 @@ Ubuntu 18.04, all available features enabled:
sudo apt-get install build-essential git make \
pkg-config cmake ninja-build gnome-desktop-testing libasound2-dev libpulse-dev \
- libaudio-dev libjack-dev libsndio-dev libsamplerate0-dev libx11-dev libxext-dev \
+ libaudio-dev libjack-dev libsndio-dev libx11-dev libxext-dev \
libxrandr-dev libxcursor-dev libxfixes-dev libxi-dev libxss-dev \
libxkbcommon-dev libdrm-dev libgbm-dev libgl1-mesa-dev libgles2-mesa-dev \
libegl1-mesa-dev libdbus-1-dev libibus-1.0-dev libudev-dev fcitx-libs-dev
@@ -32,15 +32,11 @@ Fedora 35, all available features enabled:
systemd-devel mesa-libGL-devel libxkbcommon-devel mesa-libGLES-devel \
mesa-libEGL-devel vulkan-devel wayland-devel wayland-protocols-devel \
libdrm-devel mesa-libgbm-devel libusb-devel libdecor-devel \
- libsamplerate-devel pipewire-jack-audio-connection-kit-devel \
+ pipewire-jack-audio-connection-kit-devel \
NOTES:
- The sndio audio target is unavailable on Fedora (but probably not what you
should want to use anyhow).
-- libsamplerate0-dev lets SDL optionally link to libresamplerate at runtime
- for higher-quality audio resampling. SDL will work without it if the library
- is missing, so it's safe to build in support even if the end user doesn't
- have this library installed.
Joystick does not work
diff --git a/docs/README-migration.md b/docs/README-migration.md
index 07824f1a0aa8..736869ff7add 100644
--- a/docs/README-migration.md
+++ b/docs/README-migration.md
@@ -103,6 +103,9 @@ If you need to convert U16 audio data to a still-supported format at runtime, th
}
+In SDL2, SDL_AudioStream would convert/resample audio data during input (via SDL_AudioStreamPut). In SDL3, it does this work when requesting audio (via SDL_GetAudioStreamData, which would have been SDL_AudioStreamPut in SDL2. The way you use an AudioStream is roughly the same, just be aware that the workload moved to a different phase.
+In SDL2, SDL_AudioStreamAvailable() returns 0 if passed a NULL stream. In SDL3, the equivalent SDL_GetAudioStreamAvailable() call returns -1 and sets an error string, which matches other audiostream APIs’ behavior.
+
The following functions have been renamed:
- SDL_AudioStreamAvailable() => SDL_GetAudioStreamAvailable()
diff --git a/include/SDL3/SDL_audio.h b/include/SDL3/SDL_audio.h
index 1596815bab1d…cad7afc2c0cb 100644
— a/include/SDL3/SDL_audio.h
+++ b/include/SDL3/SDL_audio.h
@@ -682,15 +682,15 @@ extern DECLSPEC SDL_AudioSpec *SDLCALL SDL_LoadWAV_RW(SDL_RWops * src,
SDL_LoadWAV_RW(SDL_RWFromFile(file, “rb”),1, spec,audio_buf,audio_len)
-/* SDL_AudioStream is a new audio conversion interface.
- The benefits vs SDL_AudioCVT:
-
- it can handle resampling data in chunks without generating
+/* SDL_AudioStream is an audio conversion interface.
- it can handle resampling data in chunks without generating
-
- It can handle resampling data in chunks without generating
artifacts, when it doesn’t have the complete buffer available.
- It can handle resampling data in chunks without generating
-
- it can handle incoming data in any variable size.
-
- It can handle incoming data in any variable size.
- You push data as you have it, and pull it when you need it
-
- It can also function as a basic audio data queue even if you
-
/just have sound that needs to pass from one place to another.
-/ this is opaque to the outside world. /
-struct SDL_AudioStream;
+struct SDL_AudioStream; / this is opaque to the outside world. */
typedef struct SDL_AudioStream SDL_AudioStream;
/**
@@ -704,6 +704,8 @@ typedef struct SDL_AudioStream SDL_AudioStream;
- \param dst_rate The sampling rate of the desired audio output
- \returns 0 on success, or -1 on error.
-
- \threadsafety It is safe to call this function from any thread.
-
- \since This function is available since SDL 3.0.0.
- \sa SDL_PutAudioStreamData
@@ -711,18 +713,87 @@ typedef struct SDL_AudioStream SDL_AudioStream; - \sa SDL_GetAudioStreamAvailable
- \sa SDL_FlushAudioStream
- \sa SDL_ClearAudioStream
-
- \sa SDL_ChangeAudioStreamOutput
- \sa SDL_DestroyAudioStream
*/
extern DECLSPEC SDL_AudioStream *SDLCALL SDL_CreateAudioStream(SDL_AudioFormat src_format,
-
Uint8 src_channels,
-
int src_channels, int src_rate, SDL_AudioFormat dst_format,
-
Uint8 dst_channels,
-
int dst_channels, int dst_rate);
+/**
-
- Query the current format of an audio stream.
-
-
- \param stream the SDL_AudioStream to query.
-
- \param src_format Where to store the input audio format; ignored if NULL.
-
- \param src_channels Where to store the input channel count; ignored if NULL.
-
- \param src_rate Where to store the input sample rate; ignored if NULL.
-
- \param dst_format Where to store the output audio format; ignored if NULL.
-
- \param dst_channels Where to store the output channel count; ignored if NULL.
-
- \param dst_rate Where to store the output sample rate; ignored if NULL.
-
- \returns 0 on success, or -1 on error.
-
-
- \threadsafety It is safe to call this function from any thread, as it
-
-
holds a stream-specific mutex while running.
-
-
-
- \since This function is available since SDL 3.0.0.
- */
+extern DECLSPEC int SDLCALL SDL_GetAudioStreamFormat(SDL_AudioStream *stream, -
SDL_AudioFormat *src_format,
-
int *src_channels,
-
int *src_rate,
-
SDL_AudioFormat *dst_format,
-
int *dst_channels,
-
int *dst_rate);
+/**
-
- Change the input and output formats of an audio stream.
-
-
- Future calls to and SDL_GetAudioStreamAvailable and SDL_GetAudioStreamData
-
- will reflect the new format, and future calls to SDL_PutAudioStreamData
-
- must provide data in the new input formats.
-
-
- \param src_format The format of the audio input
-
- \param src_channels The number of channels of the audio input
-
- \param src_rate The sampling rate of the audio input
-
- \param dst_format The format of the desired audio output
-
- \param dst_channels The number of channels of the desired audio output
-
- \param dst_rate The sampling rate of the desired audio output
-
- \returns 0 on success, or -1 on error.
-
-
- \threadsafety It is safe to call this function from any thread, as it
-
-
holds a stream-specific mutex while running.
-
-
-
- \since This function is available since SDL 3.0.0.
-
-
- \sa SDL_GetAudioStreamFormat
-
- \sa SDL_PutAudioStreamData
-
- \sa SDL_GetAudioStreamData
-
- \sa SDL_GetAudioStreamAvailable
- */
+extern DECLSPEC int SDLCALL SDL_SetAudioStreamFormat(SDL_AudioStream *stream, -
SDL_AudioFormat src_format,
-
int src_channels,
-
int src_rate,
-
SDL_AudioFormat dst_format,
-
int dst_channels,
-
int dst_rate);
/**
- Add data to be converted/resampled to the stream.
-
- This data must match the format/channels/samplerate specified in
-
- the latest call to SDL_SetAudioStreamFormat, or the format
-
- specified when creating the stream if it hasn’t been changed.
-
-
- Note that this call simply queues unconverted data for later.
-
- This is different than SDL2, where data was converted during the
-
- Put call and the Get call would just dequeue the
-
- previously-converted data.
-
- \param stream The stream the audio data is being added to
- \param buf A pointer to the audio data to add
- \param len The number of bytes to write to the stream
@@ -741,7 +812,17 @@ extern DECLSPEC SDL_AudioStream *SDLCALL SDL_CreateAudioStream(SDL_AudioFormat s
extern DECLSPEC int SDLCALL SDL_PutAudioStreamData(SDL_AudioStream *stream, const void *buf, int len);
/**
-
- Get converted/resampled data from the stream
-
- Get converted/resampled data from the stream.
-
-
- The input/output data format/channels/samplerate is specified when
-
- creating the stream, and can be changed after creation by calling
-
- SDL_SetAudioStreamFormat.
-
-
- Note that any conversion and resampling necessary is done during
-
- this call, and SDL_PutAudioStreamData simply queues unconverted
-
- data for later. This is different than SDL2, where that work was
-
- done while inputting new data to the stream and requesting the
-
- output just copied the converted data.
- \param stream The stream the audio is being requested from
- \param buf A buffer to fill with audio data
@@ -753,6 +834,7 @@ extern DECLSPEC int SDLCALL SDL_PutAudioStreamData(SDL_AudioStream *stream, cons - \sa SDL_CreateAudioStream
- \sa SDL_PutAudioStreamData
- \sa SDL_GetAudioStreamAvailable
-
- \sa SDL_SetAudioStreamFormat
- \sa SDL_FlushAudioStream
- \sa SDL_ClearAudioStream
- \sa SDL_DestroyAudioStream
@@ -766,6 +848,12 @@ extern DECLSPEC int SDLCALL SDL_GetAudioStreamData(SDL_AudioStream *stream, void - resample correctly, so this number might be lower than what you expect, or
- even be zero. Add more data or flush the stream if you need the data now.
-
- If the stream has so much data that it would overflow an int, the return
-
- value is clamped to a maximum value, but no queued data is lost; if there
-
- are gigabytes of data queued, the app might need to read some of it with
-
- SDL_GetAudioStreamData before this function’s return value is no longer
-
- clamped.
-
- \param stream The audio stream to query
- \returns the number of converted/resampled bytes available.
@@ -1133,6 +1221,7 @@ extern DECLSPEC void SDLCALL SDL_UnlockAudioDevice(SDL_AudioDeviceID dev);
*/
extern DECLSPEC void SDLCALL SDL_CloseAudioDevice(SDL_AudioDeviceID dev);
+/* !!! FIXME: maybe remove this before SDL3’s API is locked down. /
/*
- Convert some audio data of one format to another format.
diff --git a/include/SDL3/SDL_hints.h b/include/SDL3/SDL_hints.h
index 1d2bf9b53a9d…70f95957bed4 100644
— a/include/SDL3/SDL_hints.h
+++ b/include/SDL3/SDL_hints.h
@@ -271,21 +271,17 @@ extern “C” {
/**
- \brief A variable controlling speed/quality tradeoff of audio resampling.
-
- If available, SDL can use libsamplerate ( Secret Rabbit Code (aka libsamplerate) )
-
- to handle audio resampling. There are different resampling modes available
-
- that produce different levels of quality, using more CPU.
-
- SDL may be able to use different approaches to audio resampling, which
-
- produce different levels of quality, using more CPU.
-
- If this hint isn’t specified to a valid setting, or libsamplerate isn’t
-
- available, SDL will use the default, internal resampling algorithm.
-
-
- As of SDL 2.26, SDL_ConvertAudio() respects this hint when libsamplerate is available.
-
- If this hint isn’t specified to a valid setting SDL will use the default.
- This hint is currently only checked at audio subsystem initialization.
- This variable can be set to the following values:
-
- “0” or “default” - Use SDL’s internal resampling (Default when not set - low quality, fast)
-
- “1” or “fast” - Use fast, slightly higher quality resampling, if available
-
- “0” or “default” - SDL chooses default (probably “medium”).
-
- “1” or “fast” - Use fast, lower-quality resampling, if available
- “2” or “medium” - Use medium quality resampling, if available
- “3” or “best” - Use high quality resampling, if available
*/
diff --git a/include/build_config/SDL_build_config.h.cmake b/include/build_config/SDL_build_config.h.cmake
index c91c7a20e59e…29fdae642eec 100644
— a/include/build_config/SDL_build_config.h.cmake
+++ b/include/build_config/SDL_build_config.h.cmake
@@ -221,7 +221,6 @@
#cmakedefine HAVE_LINUX_INPUT_H 1
#cmakedefine HAVE_LIBUDEV_H 1
-#cmakedefine HAVE_LIBSAMPLERATE 1
#cmakedefine HAVE_LIBDECOR_H 1
#cmakedefine HAVE_D3D_H @HAVE_D3D_H@
@@ -543,9 +542,6 @@
/* Whether SDL_DYNAMIC_API needs dlopen */
#cmakedefine DYNAPI_NEEDS_DLOPEN @DYNAPI_NEEDS_DLOPEN@
-/* Enable dynamic libsamplerate support */
-#cmakedefine SDL_LIBSAMPLERATE_DYNAMIC @SDL_LIBSAMPLERATE_DYNAMIC@
/* Enable ime support */
#cmakedefine SDL_USE_IME @SDL_USE_IME@
diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c
index 1a306c675291…e38c4cea8263 100644
— a/src/audio/SDL_audio.c
+++ b/src/audio/SDL_audio.c
@@ -103,93 +103,6 @@ static const AudioBootStrap *const bootstrap[] = {
NULL
};
-#ifdef HAVE_LIBSAMPLERATE
-#ifdef SDL_LIBSAMPLERATE_DYNAMIC
-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;
-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)
-{
- const char *hint = SDL_GetHint(SDL_HINT_AUDIO_RESAMPLING_MODE);
- SRC_available = SDL_FALSE;
- SRC_converter = 0;
- if (!hint || *hint == ‘0’ || SDL_strcasecmp(hint, “default”) == 0) {
-
return SDL_FALSE; /* don't load anything. */
- } else if (*hint == ‘1’ || SDL_strcasecmp(hint, “fast”) == 0) {
-
SRC_converter = SRC_SINC_FASTEST;
- } else if (*hint == ‘2’ || SDL_strcasecmp(hint, “medium”) == 0) {
-
SRC_converter = SRC_SINC_MEDIUM_QUALITY;
- } else if (*hint == ‘3’ || SDL_strcasecmp(hint, “best”) == 0) {
-
SRC_converter = SRC_SINC_BEST_QUALITY;
- } else if (*hint == ‘4’ || SDL_strcasecmp(hint, “linear”) == 0) {
-
SRC_converter = SRC_LINEAR;
- } else {
-
return SDL_FALSE; /* treat it like "default", don't load anything. */
- }
-#ifdef SDL_LIBSAMPLERATE_DYNAMIC
- SDL_assert(SRC_lib == NULL);
- SRC_lib = SDL_LoadObject(SDL_LIBSAMPLERATE_DYNAMIC);
- if (!SRC_lib) {
-
SDL_ClearError();
-
return SDL_FALSE;
- }
- /* INDENT-OFF / / clang-format off */
- SRC_src_new = (SRC_STATE* (*)(int converter_type, int channels, int *error))SDL_LoadFunction(SRC_lib, “src_new”);
- SRC_src_process = (int (*)(SRC_STATE *state, SRC_DATA *data))SDL_LoadFunction(SRC_lib, “src_process”);
- 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”);
-/ INDENT-ON / / clang-format on */ - 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;
- }
-#else - SRC_src_new = src_new;
- SRC_src_process = src_process;
- 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;
- return SDL_TRUE;
-}
-static void UnloadLibSampleRate(void)
-{
-#ifdef SDL_LIBSAMPLERATE_DYNAMIC
- if (SRC_lib != NULL) {
-
SDL_UnloadObject(SRC_lib);
- }
- SRC_lib = NULL;
-#endif - SRC_available = SDL_FALSE;
- SRC_src_new = NULL;
- SRC_src_process = NULL;
- SRC_src_reset = NULL;
- SRC_src_delete = NULL;
- SRC_src_strerror = NULL;
-}
-#endif
static SDL_AudioDevice *get_audio_device(SDL_AudioDeviceID id)
{
id–;
@@ -978,10 +891,6 @@ int SDL_InitAudio(const char driver_name)
/ Make sure we have a list of devices available at startup. */
current_audio.impl.DetectDevices();
-#ifdef HAVE_LIBSAMPLERATE
- LoadLibSampleRate();
-#endif - return 0;
}
@@ -1608,10 +1517,6 @@ void SDL_QuitAudio(void)
SDL_zero(current_audio);
SDL_zeroa(open_devices);
-#ifdef HAVE_LIBSAMPLERATE
- UnloadLibSampleRate();
-#endif
}
#define NUM_FORMATS 8
diff --git a/src/audio/SDL_audio_c.h b/src/audio/SDL_audio_c.h
index d1c35b872ff7…a8a18adb3956 100644
— a/src/audio/SDL_audio_c.h
+++ b/src/audio/SDL_audio_c.h
@@ -24,30 +24,17 @@
#include “SDL_internal.h”
-#ifndef DEBUG_CONVERT
-#define DEBUG_CONVERT 0
-#endif
+#define DEBUG_AUDIOSTREAM 0
+#define DEBUG_AUDIO_CONVERT 0
-#if DEBUG_CONVERT
-#define LOG_DEBUG_CONVERT(from, to) SDL_Log(“SDL_AUDIO_CONVERT: Converting %s to %s.\n”, from, to);
+#if DEBUG_AUDIO_CONVERT
+#define LOG_DEBUG_AUDIO_CONVERT(from, to) SDL_Log(“SDL_AUDIO_CONVERT: Converting %s to %s.\n”, from, to);
#else
-#define LOG_DEBUG_CONVERT(from, to)
+#define LOG_DEBUG_AUDIO_CONVERT(from, to)
#endif
/* Functions and variables exported from SDL_audio.c for SDL_sysaudio.c */
-#ifdef HAVE_LIBSAMPLERATE
-#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);
-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 */
extern SDL_AudioFormat SDL_GetFirstAudioFormat(SDL_AudioFormat format);
extern SDL_AudioFormat SDL_GetNextAudioFormat(void);
@@ -56,21 +43,18 @@ extern SDL_AudioFormat SDL_GetNextAudioFormat(void);
extern Uint8 SDL_GetSilenceValueForFormat(const SDL_AudioFormat format);
extern void SDL_CalculateAudioSpec(SDL_AudioSpec *spec);
-/* Choose the audio filter functions below /
+/ Must be called at least once before using converters (SDL_CreateAudioStream will call it). */
extern void SDL_ChooseAudioConverters(void);
-struct SDL_AudioCVT;
-typedef void (SDLCALL * SDL_AudioFilter) (struct SDL_AudioCVT * cvt, SDL_AudioFormat format);
/* These pointers get set during SDL_ChooseAudioConverters() to various SIMD implementations. */
-extern SDL_AudioFilter SDL_Convert_S8_to_F32;
-extern SDL_AudioFilter SDL_Convert_U8_to_F32;
-extern SDL_AudioFilter SDL_Convert_S16_to_F32;
-extern SDL_AudioFilter SDL_Convert_S32_to_F32;
-extern SDL_AudioFilter SDL_Convert_F32_to_S8;
-extern SDL_AudioFilter SDL_Convert_F32_to_U8;
-extern SDL_AudioFilter SDL_Convert_F32_to_S16;
-extern SDL_AudioFilter SDL_Convert_F32_to_S32;
+extern void (*SDL_Convert_S8_to_F32)(float *dst, const Sint8 *src, int num_samples);
+extern void (*SDL_Convert_U8_to_F32)(float *dst, const Uint8 *src, int num_samples);
+extern void (*SDL_Convert_S16_to_F32)(float *dst, const Sint16 *src, int num_samples);
+extern void (*SDL_Convert_S32_to_F32)(float *dst, const Sint32 *src, int num_samples);
+extern void (*SDL_Convert_F32_to_S8)(Sint8 *dst, const float *src, int num_samples);
+extern void (*SDL_Convert_F32_to_U8)(Uint8 *dst, const float *src, int num_samples);
+extern void (*SDL_Convert_F32_to_S16)(Sint16 *dst, const float *src, int num_samples);
+extern void (*SDL_Convert_F32_to_S32)(Sint32 *dst, const float *src, int num_samples);
/**
- Use this function to initialize a particular audio driver.
diff --git a/src/audio/SDL_audio_channel_converters.h b/src/audio/SDL_audio_channel_converters.h
index afdafdbdf53c…7fa24f4e7bbb 100644
— a/src/audio/SDL_audio_channel_converters.h
+++ b/src/audio/SDL_audio_channel_converters.h
@@ -21,62 +21,54 @@
/* DO NOT EDIT, THIS FILE WAS GENERATED BY build-scripts/gen_audio_channel_conversion.c */
-static void SDLCALL SDL_ConvertMonoToStereo(SDL_AudioCVT *cvt, SDL_AudioFormat format)
+
+typedef void (*SDL_AudioChannelConverter)(float *dst, const float *src, int num_frames);
+
+static void SDL_ConvertMonoToStereo(float *dst, const float *src, int num_frames)
{
-
float *dst = ((float *)(cvt->buf + ((cvt->len_cvt / 1) * 2))) - 2;
-
const float *src = ((const float *)(cvt->buf + cvt->len_cvt)) - 1;
int i; -
LOG_DEBUG_CONVERT(“mono”, “stereo”);
-
SDL_assert(format == AUDIO_F32SYS);
-
LOG_DEBUG_AUDIO_CONVERT(“mono”, “stereo”);
/* convert backwards, since output is growing in-place. */
- for (i = cvt->len_cvt / (sizeof(float) * 1); i; i–, src -= 1, dst -= 2) {
- src += (num_frames-1);
- dst += (num_frames-1) * 2;
- for (i = num_frames; i; i–, src–, dst -= 2) {
const float srcFC = src[0];
dst[1] /* FR / = srcFC;
dst[0] / FL */ = srcFC;
}
- cvt->len_cvt = cvt->len_cvt * 2;
- if (cvt->filters[++cvt->filter_index]) {
-
cvt->filters[cvt->filt
(Patch may be truncated, please check the link at the top of this post.)