mirror of https://github.com/libsdl-org/SDL
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!
This commit is contained in:
parent
44bec9c01c
commit
e5a6c24c82
|
@ -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)
|
dep_option(SDL_PULSEAUDIO_SHARED "Dynamically load PulseAudio support" ON "SDL_PULSEAUDIO" OFF)
|
||||||
set_option(SDL_SNDIO "Support the sndio audio API" ${UNIX_SYS})
|
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)
|
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_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_CLOCK_GETTIME "Use clock_gettime() instead of gettimeofday()" ${SDL_CLOCK_GETTIME_ENABLED_BY_DEFAULT})
|
||||||
set_option(SDL_X11 "Use X11 video driver" ${UNIX_SYS})
|
set_option(SDL_X11 "Use X11 video driver" ${UNIX_SYS})
|
||||||
|
@ -2909,7 +2907,6 @@ if(HAVE_VULKAN AND NOT SDL_LOADSO)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Platform-independent options
|
# Platform-independent options
|
||||||
CheckLibSampleRate()
|
|
||||||
|
|
||||||
if(SDL_VIDEO)
|
if(SDL_VIDEO)
|
||||||
if(SDL_OFFSCREEN AND SDL_VIDEO_OPENGL_EGL)
|
if(SDL_OFFSCREEN AND SDL_VIDEO_OPENGL_EGL)
|
||||||
|
|
|
@ -261,27 +261,43 @@ static void write_converter(const int fromchans, const int tochans)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("static void SDLCALL\n"
|
printf("static void SDL_Convert%sTo%s(float *dst, const float *src, int num_frames)\n{\n", remove_dots(fromstr), remove_dots(tostr));
|
||||||
"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(" int i;\n"
|
printf(" int i;\n"
|
||||||
"\n"
|
"\n"
|
||||||
" LOG_DEBUG_CONVERT(\"%s\", \"%s\");\n"
|
" LOG_DEBUG_AUDIO_CONVERT(\"%s\", \"%s\");\n"
|
||||||
" SDL_assert(format == AUDIO_F32SYS);\n"
|
|
||||||
"\n", lowercase(fromstr), lowercase(tostr));
|
"\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(" /* 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;
|
fptr = cvtmatrix;
|
||||||
for (i = 0; i < fromchans; i++) {
|
for (i = 0; i < fromchans; i++) {
|
||||||
if (input_channel_used[i] > 1) { /* don't read it from src more than once. */
|
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");
|
printf(" }\n");
|
||||||
} else {
|
} 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;
|
fptr = cvtmatrix;
|
||||||
for (i = 0; i < fromchans; i++) {
|
for (i = 0; i < fromchans; i++) {
|
||||||
|
@ -372,20 +400,7 @@ static void write_converter(const int fromchans, const int tochans)
|
||||||
printf(" }\n");
|
printf(" }\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("\n");
|
printf("\n}\n\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");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
|
@ -416,6 +431,9 @@ int main(void)
|
||||||
"\n"
|
"\n"
|
||||||
"/* DO NOT EDIT, THIS FILE WAS GENERATED BY build-scripts/gen_audio_channel_conversion.c */\n"
|
"/* DO NOT EDIT, THIS FILE WAS GENERATED BY build-scripts/gen_audio_channel_conversion.c */\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
"\n"
|
||||||
|
"typedef void (*SDL_AudioChannelConverter)(float *dst, const float *src, int num_frames);\n"
|
||||||
|
"\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
for (ini = 1; ini <= NUM_CHANNELS; ini++) {
|
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++) {
|
for (ini = 1; ini <= NUM_CHANNELS; ini++) {
|
||||||
const char *comma = "";
|
const char *comma = "";
|
||||||
printf(" {");
|
printf(" {");
|
||||||
|
|
|
@ -240,53 +240,6 @@ macro(CheckSNDIO)
|
||||||
endif()
|
endif()
|
||||||
endmacro()
|
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:
|
# Requires:
|
||||||
# - n/a
|
# - n/a
|
||||||
# Optional:
|
# Optional:
|
||||||
|
|
|
@ -16,7 +16,7 @@ Ubuntu 18.04, all available features enabled:
|
||||||
|
|
||||||
sudo apt-get install build-essential git make \
|
sudo apt-get install build-essential git make \
|
||||||
pkg-config cmake ninja-build gnome-desktop-testing libasound2-dev libpulse-dev \
|
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 \
|
libxrandr-dev libxcursor-dev libxfixes-dev libxi-dev libxss-dev \
|
||||||
libxkbcommon-dev libdrm-dev libgbm-dev libgl1-mesa-dev libgles2-mesa-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
|
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 \
|
systemd-devel mesa-libGL-devel libxkbcommon-devel mesa-libGLES-devel \
|
||||||
mesa-libEGL-devel vulkan-devel wayland-devel wayland-protocols-devel \
|
mesa-libEGL-devel vulkan-devel wayland-devel wayland-protocols-devel \
|
||||||
libdrm-devel mesa-libgbm-devel libusb-devel libdecor-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:
|
NOTES:
|
||||||
- The sndio audio target is unavailable on Fedora (but probably not what you
|
- The sndio audio target is unavailable on Fedora (but probably not what you
|
||||||
should want to use anyhow).
|
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
|
Joystick does not work
|
||||||
|
|
|
@ -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:
|
The following functions have been renamed:
|
||||||
* SDL_AudioStreamAvailable() => SDL_GetAudioStreamAvailable()
|
* SDL_AudioStreamAvailable() => SDL_GetAudioStreamAvailable()
|
||||||
|
|
|
@ -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_LoadWAV_RW(SDL_RWFromFile(file, "rb"),1, spec,audio_buf,audio_len)
|
||||||
|
|
||||||
|
|
||||||
/* SDL_AudioStream is a new audio conversion interface.
|
/* SDL_AudioStream is an audio conversion interface.
|
||||||
The benefits vs SDL_AudioCVT:
|
- 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.
|
artifacts, when it doesn't have the complete buffer available.
|
||||||
- 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
|
- 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; /* this is opaque to the outside world. */
|
||||||
struct SDL_AudioStream;
|
|
||||||
typedef struct SDL_AudioStream SDL_AudioStream;
|
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
|
* \param dst_rate The sampling rate of the desired audio output
|
||||||
* \returns 0 on success, or -1 on error.
|
* \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.
|
* \since This function is available since SDL 3.0.0.
|
||||||
*
|
*
|
||||||
* \sa SDL_PutAudioStreamData
|
* \sa SDL_PutAudioStreamData
|
||||||
|
@ -711,18 +713,87 @@ typedef struct SDL_AudioStream SDL_AudioStream;
|
||||||
* \sa SDL_GetAudioStreamAvailable
|
* \sa SDL_GetAudioStreamAvailable
|
||||||
* \sa SDL_FlushAudioStream
|
* \sa SDL_FlushAudioStream
|
||||||
* \sa SDL_ClearAudioStream
|
* \sa SDL_ClearAudioStream
|
||||||
|
* \sa SDL_ChangeAudioStreamOutput
|
||||||
* \sa SDL_DestroyAudioStream
|
* \sa SDL_DestroyAudioStream
|
||||||
*/
|
*/
|
||||||
extern DECLSPEC SDL_AudioStream *SDLCALL SDL_CreateAudioStream(SDL_AudioFormat src_format,
|
extern DECLSPEC SDL_AudioStream *SDLCALL SDL_CreateAudioStream(SDL_AudioFormat src_format,
|
||||||
Uint8 src_channels,
|
int src_channels,
|
||||||
int src_rate,
|
int src_rate,
|
||||||
SDL_AudioFormat dst_format,
|
SDL_AudioFormat dst_format,
|
||||||
Uint8 dst_channels,
|
int dst_channels,
|
||||||
int dst_rate);
|
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.
|
* 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 stream The stream the audio data is being added to
|
||||||
* \param buf A pointer to the audio data to add
|
* \param buf A pointer to the audio data to add
|
||||||
* \param len The number of bytes to write to the stream
|
* \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);
|
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 stream The stream the audio is being requested from
|
||||||
* \param buf A buffer to fill with audio data
|
* \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_CreateAudioStream
|
||||||
* \sa SDL_PutAudioStreamData
|
* \sa SDL_PutAudioStreamData
|
||||||
* \sa SDL_GetAudioStreamAvailable
|
* \sa SDL_GetAudioStreamAvailable
|
||||||
|
* \sa SDL_SetAudioStreamFormat
|
||||||
* \sa SDL_FlushAudioStream
|
* \sa SDL_FlushAudioStream
|
||||||
* \sa SDL_ClearAudioStream
|
* \sa SDL_ClearAudioStream
|
||||||
* \sa SDL_DestroyAudioStream
|
* \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
|
* 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.
|
* 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
|
* \param stream The audio stream to query
|
||||||
* \returns the number of converted/resampled bytes available.
|
* \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);
|
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.
|
* Convert some audio data of one format to another format.
|
||||||
*
|
*
|
||||||
|
|
|
@ -271,21 +271,17 @@ extern "C" {
|
||||||
/**
|
/**
|
||||||
* \brief A variable controlling speed/quality tradeoff of audio resampling.
|
* \brief A variable controlling speed/quality tradeoff of audio resampling.
|
||||||
*
|
*
|
||||||
* If available, SDL can use libsamplerate ( http://www.mega-nerd.com/SRC/ )
|
* SDL may be able to use different approaches to audio resampling, which
|
||||||
* to handle audio resampling. There are different resampling modes available
|
* produce different levels of quality, using more CPU.
|
||||||
* that produce different levels of quality, using more CPU.
|
|
||||||
*
|
*
|
||||||
* If this hint isn't specified to a valid setting, or libsamplerate isn't
|
* If this hint isn't specified to a valid setting SDL will use the default.
|
||||||
* available, SDL will use the default, internal resampling algorithm.
|
|
||||||
*
|
|
||||||
* As of SDL 2.26, SDL_ConvertAudio() respects this hint when libsamplerate is available.
|
|
||||||
*
|
*
|
||||||
* This hint is currently only checked at audio subsystem initialization.
|
* This hint is currently only checked at audio subsystem initialization.
|
||||||
*
|
*
|
||||||
* This variable can be set to the following values:
|
* This variable can be set to the following values:
|
||||||
*
|
*
|
||||||
* "0" or "default" - Use SDL's internal resampling (Default when not set - low quality, fast)
|
* "0" or "default" - SDL chooses default (probably "medium").
|
||||||
* "1" or "fast" - Use fast, slightly higher quality resampling, if available
|
* "1" or "fast" - Use fast, lower-quality resampling, if available
|
||||||
* "2" or "medium" - Use medium quality resampling, if available
|
* "2" or "medium" - Use medium quality resampling, if available
|
||||||
* "3" or "best" - Use high quality resampling, if available
|
* "3" or "best" - Use high quality resampling, if available
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -221,7 +221,6 @@
|
||||||
|
|
||||||
#cmakedefine HAVE_LINUX_INPUT_H 1
|
#cmakedefine HAVE_LINUX_INPUT_H 1
|
||||||
#cmakedefine HAVE_LIBUDEV_H 1
|
#cmakedefine HAVE_LIBUDEV_H 1
|
||||||
#cmakedefine HAVE_LIBSAMPLERATE 1
|
|
||||||
#cmakedefine HAVE_LIBDECOR_H 1
|
#cmakedefine HAVE_LIBDECOR_H 1
|
||||||
|
|
||||||
#cmakedefine HAVE_D3D_H @HAVE_D3D_H@
|
#cmakedefine HAVE_D3D_H @HAVE_D3D_H@
|
||||||
|
@ -543,9 +542,6 @@
|
||||||
/* Whether SDL_DYNAMIC_API needs dlopen */
|
/* Whether SDL_DYNAMIC_API needs dlopen */
|
||||||
#cmakedefine DYNAPI_NEEDS_DLOPEN @DYNAPI_NEEDS_DLOPEN@
|
#cmakedefine DYNAPI_NEEDS_DLOPEN @DYNAPI_NEEDS_DLOPEN@
|
||||||
|
|
||||||
/* Enable dynamic libsamplerate support */
|
|
||||||
#cmakedefine SDL_LIBSAMPLERATE_DYNAMIC @SDL_LIBSAMPLERATE_DYNAMIC@
|
|
||||||
|
|
||||||
/* Enable ime support */
|
/* Enable ime support */
|
||||||
#cmakedefine SDL_USE_IME @SDL_USE_IME@
|
#cmakedefine SDL_USE_IME @SDL_USE_IME@
|
||||||
|
|
||||||
|
|
|
@ -103,93 +103,6 @@ static const AudioBootStrap *const bootstrap[] = {
|
||||||
NULL
|
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)
|
static SDL_AudioDevice *get_audio_device(SDL_AudioDeviceID id)
|
||||||
{
|
{
|
||||||
id--;
|
id--;
|
||||||
|
@ -978,10 +891,6 @@ int SDL_InitAudio(const char *driver_name)
|
||||||
/* Make sure we have a list of devices available at startup. */
|
/* Make sure we have a list of devices available at startup. */
|
||||||
current_audio.impl.DetectDevices();
|
current_audio.impl.DetectDevices();
|
||||||
|
|
||||||
#ifdef HAVE_LIBSAMPLERATE
|
|
||||||
LoadLibSampleRate();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1608,10 +1517,6 @@ void SDL_QuitAudio(void)
|
||||||
|
|
||||||
SDL_zero(current_audio);
|
SDL_zero(current_audio);
|
||||||
SDL_zeroa(open_devices);
|
SDL_zeroa(open_devices);
|
||||||
|
|
||||||
#ifdef HAVE_LIBSAMPLERATE
|
|
||||||
UnloadLibSampleRate();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define NUM_FORMATS 8
|
#define NUM_FORMATS 8
|
||||||
|
|
|
@ -24,30 +24,17 @@
|
||||||
|
|
||||||
#include "SDL_internal.h"
|
#include "SDL_internal.h"
|
||||||
|
|
||||||
#ifndef DEBUG_CONVERT
|
#define DEBUG_AUDIOSTREAM 0
|
||||||
#define DEBUG_CONVERT 0
|
#define DEBUG_AUDIO_CONVERT 0
|
||||||
#endif
|
|
||||||
|
|
||||||
#if DEBUG_CONVERT
|
#if DEBUG_AUDIO_CONVERT
|
||||||
#define LOG_DEBUG_CONVERT(from, to) SDL_Log("SDL_AUDIO_CONVERT: Converting %s to %s.\n", from, to);
|
#define LOG_DEBUG_AUDIO_CONVERT(from, to) SDL_Log("SDL_AUDIO_CONVERT: Converting %s to %s.\n", from, to);
|
||||||
#else
|
#else
|
||||||
#define LOG_DEBUG_CONVERT(from, to)
|
#define LOG_DEBUG_AUDIO_CONVERT(from, to)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Functions and variables exported from SDL_audio.c for SDL_sysaudio.c */
|
/* 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 */
|
/* Functions to get a list of "close" audio formats */
|
||||||
extern SDL_AudioFormat SDL_GetFirstAudioFormat(SDL_AudioFormat format);
|
extern SDL_AudioFormat SDL_GetFirstAudioFormat(SDL_AudioFormat format);
|
||||||
extern SDL_AudioFormat SDL_GetNextAudioFormat(void);
|
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 Uint8 SDL_GetSilenceValueForFormat(const SDL_AudioFormat format);
|
||||||
extern void SDL_CalculateAudioSpec(SDL_AudioSpec *spec);
|
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);
|
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. */
|
/* These pointers get set during SDL_ChooseAudioConverters() to various SIMD implementations. */
|
||||||
extern SDL_AudioFilter SDL_Convert_S8_to_F32;
|
extern void (*SDL_Convert_S8_to_F32)(float *dst, const Sint8 *src, int num_samples);
|
||||||
extern SDL_AudioFilter SDL_Convert_U8_to_F32;
|
extern void (*SDL_Convert_U8_to_F32)(float *dst, const Uint8 *src, int num_samples);
|
||||||
extern SDL_AudioFilter SDL_Convert_S16_to_F32;
|
extern void (*SDL_Convert_S16_to_F32)(float *dst, const Sint16 *src, int num_samples);
|
||||||
extern SDL_AudioFilter SDL_Convert_S32_to_F32;
|
extern void (*SDL_Convert_S32_to_F32)(float *dst, const Sint32 *src, int num_samples);
|
||||||
extern SDL_AudioFilter SDL_Convert_F32_to_S8;
|
extern void (*SDL_Convert_F32_to_S8)(Sint8 *dst, const float *src, int num_samples);
|
||||||
extern SDL_AudioFilter SDL_Convert_F32_to_U8;
|
extern void (*SDL_Convert_F32_to_U8)(Uint8 *dst, const float *src, int num_samples);
|
||||||
extern SDL_AudioFilter SDL_Convert_F32_to_S16;
|
extern void (*SDL_Convert_F32_to_S16)(Sint16 *dst, const float *src, int num_samples);
|
||||||
extern SDL_AudioFilter SDL_Convert_F32_to_S32;
|
extern void (*SDL_Convert_F32_to_S32)(Sint32 *dst, const float *src, int num_samples);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use this function to initialize a particular audio driver.
|
* Use this function to initialize a particular audio driver.
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,69 +0,0 @@
|
||||||
/*
|
|
||||||
Simple DirectMedia Layer
|
|
||||||
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
|
|
||||||
|
|
||||||
This software is provided 'as-is', without any express or implied
|
|
||||||
warranty. In no event will the authors be held liable for any damages
|
|
||||||
arising from the use of this software.
|
|
||||||
|
|
||||||
Permission is granted to anyone to use this software for any purpose,
|
|
||||||
including commercial applications, and to alter it and redistribute it
|
|
||||||
freely, subject to the following restrictions:
|
|
||||||
|
|
||||||
1. The origin of this software must not be misrepresented; you must not
|
|
||||||
claim that you wrote the original software. If you use this software
|
|
||||||
in a product, an acknowledgment in the product documentation would be
|
|
||||||
appreciated but is not required.
|
|
||||||
2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
misrepresented as being the original software.
|
|
||||||
3. This notice may not be removed or altered from any source distribution.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Upper limit of filters in SDL_AudioCVT
|
|
||||||
*
|
|
||||||
* The maximum number of SDL_AudioFilter functions in SDL_AudioCVT is
|
|
||||||
* currently limited to 9. The SDL_AudioCVT.filters array has 10 pointers,
|
|
||||||
* one of which is the terminating NULL pointer.
|
|
||||||
*/
|
|
||||||
#define SDL_AUDIOCVT_MAX_FILTERS 9
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \struct SDL_AudioCVT
|
|
||||||
* \brief A structure to hold a set of audio conversion filters and buffers.
|
|
||||||
*
|
|
||||||
* Note that various parts of the conversion pipeline can take advantage
|
|
||||||
* of SIMD operations (like SSE2, for example). SDL_AudioCVT doesn't require
|
|
||||||
* you to pass it aligned data, but can possibly run much faster if you
|
|
||||||
* set both its (buf) field to a pointer that is aligned to 16 bytes, and its
|
|
||||||
* (len) field to something that's a multiple of 16, if possible.
|
|
||||||
*/
|
|
||||||
#if defined(__GNUC__) && !defined(__CHERI_PURE_CAPABILITY__)
|
|
||||||
/* This structure is 84 bytes on 32-bit architectures, make sure GCC doesn't
|
|
||||||
pad it out to 88 bytes to guarantee ABI compatibility between compilers.
|
|
||||||
This is not a concern on CHERI architectures, where pointers must be stored
|
|
||||||
at aligned locations otherwise they will become invalid, and thus structs
|
|
||||||
containing pointers cannot be packed without giving a warning or error.
|
|
||||||
vvv
|
|
||||||
The next time we rev the ABI, make sure to size the ints and add padding.
|
|
||||||
*/
|
|
||||||
#define SDL_AUDIOCVT_PACKED __attribute__((packed))
|
|
||||||
#else
|
|
||||||
#define SDL_AUDIOCVT_PACKED
|
|
||||||
#endif
|
|
||||||
/* */
|
|
||||||
typedef struct SDL_AudioCVT
|
|
||||||
{
|
|
||||||
int needed; /**< Set to 1 if conversion possible */
|
|
||||||
SDL_AudioFormat src_format; /**< Source audio format */
|
|
||||||
SDL_AudioFormat dst_format; /**< Target audio format */
|
|
||||||
double rate_incr; /**< Rate conversion increment */
|
|
||||||
Uint8 *buf; /**< Buffer to hold entire audio data */
|
|
||||||
int len; /**< Length of original audio buffer */
|
|
||||||
int len_cvt; /**< Length of converted audio buffer */
|
|
||||||
int len_mult; /**< buffer must be len*len_mult big */
|
|
||||||
double len_ratio; /**< Given len, final size is len*len_ratio */
|
|
||||||
SDL_AudioFilter filters[SDL_AUDIOCVT_MAX_FILTERS + 1]; /**< NULL-terminated list of filter functions */
|
|
||||||
int filter_index; /**< Current audio conversion function */
|
|
||||||
} SDL_AUDIOCVT_PACKED SDL_AudioCVT;
|
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
#include "SDL_internal.h"
|
#include "SDL_internal.h"
|
||||||
|
|
||||||
#include "SDL_audio_c.h"
|
#include "SDL_audio_c.h"
|
||||||
#include "SDL_audiocvt_c.h"
|
|
||||||
|
|
||||||
#ifndef SDL_CPUINFO_DISABLED
|
#ifndef SDL_CPUINFO_DISABLED
|
||||||
#if defined(__x86_64__) && defined(SDL_SSE2_INTRINSICS)
|
#if defined(__x86_64__) && defined(SDL_SSE2_INTRINSICS)
|
||||||
|
@ -33,210 +32,72 @@
|
||||||
#elif defined(__APPLE__) && defined(__ARM_ARCH) && (__ARM_ARCH >= 7) && defined(SDL_NEON_INTRINSICS)
|
#elif defined(__APPLE__) && defined(__ARM_ARCH) && (__ARM_ARCH >= 7) && defined(SDL_NEON_INTRINSICS)
|
||||||
#define NEED_SCALAR_CONVERTER_FALLBACKS 0 /* All Apple ARMv7 chips promise NEON support. */
|
#define NEED_SCALAR_CONVERTER_FALLBACKS 0 /* All Apple ARMv7 chips promise NEON support. */
|
||||||
#endif
|
#endif
|
||||||
#endif /* !SDL_CPUINFO_DISABLED */
|
#endif
|
||||||
|
|
||||||
/* Set to zero if platform is guaranteed to use a SIMD codepath here. */
|
/* Set to zero if platform is guaranteed to use a SIMD codepath here. */
|
||||||
#if !defined(NEED_SCALAR_CONVERTER_FALLBACKS) || defined(SDL_CPUINFO_DISABLED)
|
#if !defined(NEED_SCALAR_CONVERTER_FALLBACKS) || defined(SDL_CPUINFO_DISABLED)
|
||||||
#define NEED_SCALAR_CONVERTER_FALLBACKS 1
|
#define NEED_SCALAR_CONVERTER_FALLBACKS 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Function pointers set to a CPU-specific implementation. */
|
|
||||||
SDL_AudioFilter SDL_Convert_S8_to_F32 = NULL;
|
|
||||||
SDL_AudioFilter SDL_Convert_U8_to_F32 = NULL;
|
|
||||||
SDL_AudioFilter SDL_Convert_S16_to_F32 = NULL;
|
|
||||||
SDL_AudioFilter SDL_Convert_S32_to_F32 = NULL;
|
|
||||||
SDL_AudioFilter SDL_Convert_F32_to_S8 = NULL;
|
|
||||||
SDL_AudioFilter SDL_Convert_F32_to_U8 = NULL;
|
|
||||||
SDL_AudioFilter SDL_Convert_F32_to_S16 = NULL;
|
|
||||||
SDL_AudioFilter SDL_Convert_F32_to_S32 = NULL;
|
|
||||||
|
|
||||||
#define DIVBY128 0.0078125f
|
#define DIVBY128 0.0078125f
|
||||||
#define DIVBY32768 0.000030517578125f
|
#define DIVBY32768 0.000030517578125f
|
||||||
#define DIVBY8388607 0.00000011920930376163766f
|
#define DIVBY8388607 0.00000011920930376163766f
|
||||||
|
|
||||||
#if NEED_SCALAR_CONVERTER_FALLBACKS
|
#if NEED_SCALAR_CONVERTER_FALLBACKS
|
||||||
static void SDLCALL SDL_Convert_S8_to_F32_Scalar(SDL_AudioCVT *cvt, SDL_AudioFormat format)
|
|
||||||
{
|
|
||||||
const Sint8 *src = ((const Sint8 *)(cvt->buf + cvt->len_cvt)) - 1;
|
|
||||||
float *dst = ((float *)(cvt->buf + cvt->len_cvt * 4)) - 1;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
LOG_DEBUG_CONVERT("AUDIO_S8", "AUDIO_F32");
|
/* these all convert backwards because (currently) float32 is >= to the size of anything it converts to, so it lets us safely convert in-place. */
|
||||||
|
#define AUDIOCVT_TOFLOAT_SCALAR(from, fromtype, equation) \
|
||||||
for (i = cvt->len_cvt; i; --i, --src, --dst) {
|
static void SDL_Convert_##from##_to_F32_Scalar(float *dst, const fromtype *src, int num_samples) { \
|
||||||
*dst = ((float)*src) * DIVBY128;
|
int i; \
|
||||||
|
LOG_DEBUG_AUDIO_CONVERT("AUDIO_" #from, "AUDIO_F32"); \
|
||||||
|
for (i = num_samples - 1; i >= 0; --i) { \
|
||||||
|
dst[i] = equation; \
|
||||||
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
cvt->len_cvt *= 4;
|
AUDIOCVT_TOFLOAT_SCALAR(S8, Sint8, ((float)src[i]) * DIVBY128)
|
||||||
if (cvt->filters[++cvt->filter_index]) {
|
AUDIOCVT_TOFLOAT_SCALAR(U8, Uint8, (((float)src[i]) * DIVBY128) - 1.0f)
|
||||||
cvt->filters[cvt->filter_index](cvt, AUDIO_F32SYS);
|
AUDIOCVT_TOFLOAT_SCALAR(S16, Sint16, ((float)src[i]) * DIVBY32768)
|
||||||
}
|
AUDIOCVT_TOFLOAT_SCALAR(S32, Sint32, ((float)(src[i] >> 8)) * DIVBY8388607)
|
||||||
}
|
#undef AUDIOCVT_FROMFLOAT_SCALAR
|
||||||
|
|
||||||
static void SDLCALL SDL_Convert_U8_to_F32_Scalar(SDL_AudioCVT *cvt, SDL_AudioFormat format)
|
/* these all convert forwards because (currently) float32 is >= to the size of anything it converts from, so it lets us safely convert in-place. */
|
||||||
{
|
#define AUDIOCVT_FROMFLOAT_SCALAR(to, totype, clampmin, clampmax, equation) \
|
||||||
const Uint8 *src = ((const Uint8 *)(cvt->buf + cvt->len_cvt)) - 1;
|
static void SDL_Convert_F32_to_##to##_Scalar(totype *dst, const float *src, int num_samples) { \
|
||||||
float *dst = ((float *)(cvt->buf + cvt->len_cvt * 4)) - 1;
|
int i; \
|
||||||
int i;
|
LOG_DEBUG_AUDIO_CONVERT("AUDIO_F32", "AUDIO_" #to); \
|
||||||
|
for (i = 0; i < num_samples; i++) { \
|
||||||
LOG_DEBUG_CONVERT("AUDIO_U8", "AUDIO_F32");
|
const float sample = src[i]; \
|
||||||
|
if (sample >= 1.0f) { \
|
||||||
for (i = cvt->len_cvt; i; --i, --src, --dst) {
|
dst[i] = (totype) (clampmax); \
|
||||||
*dst = (((float)*src) * DIVBY128) - 1.0f;
|
} else if (sample <= -1.0f) { \
|
||||||
|
dst[i] = (totype) (clampmin); \
|
||||||
|
} else { \
|
||||||
|
dst[i] = (totype) (equation); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
cvt->len_cvt *= 4;
|
AUDIOCVT_FROMFLOAT_SCALAR(S8, Sint8, -128, 127, sample * 127.0f);
|
||||||
if (cvt->filters[++cvt->filter_index]) {
|
AUDIOCVT_FROMFLOAT_SCALAR(U8, Uint8, 0, 255, (sample + 1.0f) * 127.0f);
|
||||||
cvt->filters[cvt->filter_index](cvt, AUDIO_F32SYS);
|
AUDIOCVT_FROMFLOAT_SCALAR(S16, Sint16, -32768, 32767, sample * 32767.0f);
|
||||||
}
|
AUDIOCVT_FROMFLOAT_SCALAR(S32, Sint32, -2147483648LL, 2147483647, ((Sint32)(sample * 8388607.0f)) << 8);
|
||||||
}
|
#undef AUDIOCVT_FROMFLOAT_SCALAR
|
||||||
|
|
||||||
static void SDLCALL SDL_Convert_S16_to_F32_Scalar(SDL_AudioCVT *cvt, SDL_AudioFormat format)
|
#endif /* NEED_SCALAR_CONVERTER_FALLBACKS */
|
||||||
{
|
|
||||||
const Sint16 *src = ((const Sint16 *)(cvt->buf + cvt->len_cvt)) - 1;
|
|
||||||
float *dst = ((float *)(cvt->buf + cvt->len_cvt * 2)) - 1;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
LOG_DEBUG_CONVERT("AUDIO_S16", "AUDIO_F32");
|
|
||||||
|
|
||||||
for (i = cvt->len_cvt / sizeof(Sint16); i; --i, --src, --dst) {
|
|
||||||
*dst = ((float)*src) * DIVBY32768;
|
|
||||||
}
|
|
||||||
|
|
||||||
cvt->len_cvt *= 2;
|
|
||||||
if (cvt->filters[++cvt->filter_index]) {
|
|
||||||
cvt->filters[cvt->filter_index](cvt, AUDIO_F32SYS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void SDLCALL SDL_Convert_S32_to_F32_Scalar(SDL_AudioCVT *cvt, SDL_AudioFormat format)
|
|
||||||
{
|
|
||||||
const Sint32 *src = (const Sint32 *)cvt->buf;
|
|
||||||
float *dst = (float *)cvt->buf;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
LOG_DEBUG_CONVERT("AUDIO_S32", "AUDIO_F32");
|
|
||||||
|
|
||||||
for (i = cvt->len_cvt / sizeof(Sint32); i; --i, ++src, ++dst) {
|
|
||||||
*dst = ((float)(*src >> 8)) * DIVBY8388607;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cvt->filters[++cvt->filter_index]) {
|
|
||||||
cvt->filters[cvt->filter_index](cvt, AUDIO_F32SYS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void SDLCALL SDL_Convert_F32_to_S8_Scalar(SDL_AudioCVT *cvt, SDL_AudioFormat format)
|
|
||||||
{
|
|
||||||
const float *src = (const float *)cvt->buf;
|
|
||||||
Sint8 *dst = (Sint8 *)cvt->buf;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
LOG_DEBUG_CONVERT("AUDIO_F32", "AUDIO_S8");
|
|
||||||
|
|
||||||
for (i = cvt->len_cvt / sizeof(float); i; --i, ++src, ++dst) {
|
|
||||||
const float sample = *src;
|
|
||||||
if (sample >= 1.0f) {
|
|
||||||
*dst = 127;
|
|
||||||
} else if (sample <= -1.0f) {
|
|
||||||
*dst = -128;
|
|
||||||
} else {
|
|
||||||
*dst = (Sint8)(sample * 127.0f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cvt->len_cvt /= 4;
|
|
||||||
if (cvt->filters[++cvt->filter_index]) {
|
|
||||||
cvt->filters[cvt->filter_index](cvt, AUDIO_S8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void SDLCALL SDL_Convert_F32_to_U8_Scalar(SDL_AudioCVT *cvt, SDL_AudioFormat format)
|
|
||||||
{
|
|
||||||
const float *src = (const float *)cvt->buf;
|
|
||||||
Uint8 *dst = (Uint8 *)cvt->buf;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
LOG_DEBUG_CONVERT("AUDIO_F32", "AUDIO_U8");
|
|
||||||
|
|
||||||
for (i = cvt->len_cvt / sizeof(float); i; --i, ++src, ++dst) {
|
|
||||||
const float sample = *src;
|
|
||||||
if (sample >= 1.0f) {
|
|
||||||
*dst = 255;
|
|
||||||
} else if (sample <= -1.0f) {
|
|
||||||
*dst = 0;
|
|
||||||
} else {
|
|
||||||
*dst = (Uint8)((sample + 1.0f) * 127.0f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cvt->len_cvt /= 4;
|
|
||||||
if (cvt->filters[++cvt->filter_index]) {
|
|
||||||
cvt->filters[cvt->filter_index](cvt, AUDIO_U8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void SDLCALL SDL_Convert_F32_to_S16_Scalar(SDL_AudioCVT *cvt, SDL_AudioFormat format)
|
|
||||||
{
|
|
||||||
const float *src = (const float *)cvt->buf;
|
|
||||||
Sint16 *dst = (Sint16 *)cvt->buf;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
LOG_DEBUG_CONVERT("AUDIO_F32", "AUDIO_S16");
|
|
||||||
|
|
||||||
for (i = cvt->len_cvt / sizeof(float); i; --i, ++src, ++dst) {
|
|
||||||
const float sample = *src;
|
|
||||||
if (sample >= 1.0f) {
|
|
||||||
*dst = 32767;
|
|
||||||
} else if (sample <= -1.0f) {
|
|
||||||
*dst = -32768;
|
|
||||||
} else {
|
|
||||||
*dst = (Sint16)(sample * 32767.0f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cvt->len_cvt /= 2;
|
|
||||||
if (cvt->filters[++cvt->filter_index]) {
|
|
||||||
cvt->filters[cvt->filter_index](cvt, AUDIO_S16SYS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void SDLCALL SDL_Convert_F32_to_S32_Scalar(SDL_AudioCVT *cvt, SDL_AudioFormat format)
|
|
||||||
{
|
|
||||||
const float *src = (const float *)cvt->buf;
|
|
||||||
Sint32 *dst = (Sint32 *)cvt->buf;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
LOG_DEBUG_CONVERT("AUDIO_F32", "AUDIO_S32");
|
|
||||||
|
|
||||||
for (i = cvt->len_cvt / sizeof(float); i; --i, ++src, ++dst) {
|
|
||||||
const float sample = *src;
|
|
||||||
if (sample >= 1.0f) {
|
|
||||||
*dst = 2147483647;
|
|
||||||
} else if (sample <= -1.0f) {
|
|
||||||
*dst = (Sint32)-2147483648LL;
|
|
||||||
} else {
|
|
||||||
*dst = ((Sint32)(sample * 8388607.0f)) << 8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cvt->filters[++cvt->filter_index]) {
|
|
||||||
cvt->filters[cvt->filter_index](cvt, AUDIO_S32SYS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef SDL_SSE2_INTRINSICS
|
#ifdef SDL_SSE2_INTRINSICS
|
||||||
static void SDLCALL SDL_TARGETING("sse2") SDL_Convert_S8_to_F32_SSE2(SDL_AudioCVT *cvt, SDL_AudioFormat format)
|
static void SDL_TARGETING("sse2") SDL_Convert_S8_to_F32_SSE2(float *dst, const Sint8 *src, int num_samples)
|
||||||
{
|
{
|
||||||
const Sint8 *src = ((const Sint8 *)(cvt->buf + cvt->len_cvt)) - 1;
|
|
||||||
float *dst = ((float *)(cvt->buf + cvt->len_cvt * 4)) - 1;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
LOG_DEBUG_CONVERT("AUDIO_S8", "AUDIO_F32 (using SSE2)");
|
LOG_DEBUG_AUDIO_CONVERT("AUDIO_S8", "AUDIO_F32 (using SSE2)");
|
||||||
|
|
||||||
|
src += num_samples - 1;
|
||||||
|
dst += num_samples - 1;
|
||||||
|
|
||||||
/* Get dst aligned to 16 bytes (since buffer is growing, we don't have to worry about overreading from src) */
|
/* Get dst aligned to 16 bytes (since buffer is growing, we don't have to worry about overreading from src) */
|
||||||
for (i = cvt->len_cvt; i && (((size_t)(dst - 15)) & 15); --i, --src, --dst) {
|
for (i = num_samples; i && (((size_t)(dst - 15)) & 15); --i, --src, --dst) {
|
||||||
*dst = ((float)*src) * DIVBY128;
|
*dst = ((float)*src) * DIVBY128;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -284,23 +145,19 @@ static void SDLCALL SDL_TARGETING("sse2") SDL_Convert_S8_to_F32_SSE2(SDL_AudioCV
|
||||||
src--;
|
src--;
|
||||||
dst--;
|
dst--;
|
||||||
}
|
}
|
||||||
|
|
||||||
cvt->len_cvt *= 4;
|
|
||||||
if (cvt->filters[++cvt->filter_index]) {
|
|
||||||
cvt->filters[cvt->filter_index](cvt, AUDIO_F32SYS);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SDLCALL SDL_TARGETING("sse2") SDL_Convert_U8_to_F32_SSE2(SDL_AudioCVT *cvt, SDL_AudioFormat format)
|
static void SDL_TARGETING("sse2") SDL_Convert_U8_to_F32_SSE2(float *dst, const Uint8 *src, int num_samples)
|
||||||
{
|
{
|
||||||
const Uint8 *src = ((const Uint8 *)(cvt->buf + cvt->len_cvt)) - 1;
|
|
||||||
float *dst = ((float *)(cvt->buf + cvt->len_cvt * 4)) - 1;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
LOG_DEBUG_CONVERT("AUDIO_U8", "AUDIO_F32 (using SSE2)");
|
LOG_DEBUG_AUDIO_CONVERT("AUDIO_U8", "AUDIO_F32 (using SSE2)");
|
||||||
|
|
||||||
|
src += num_samples - 1;
|
||||||
|
dst += num_samples - 1;
|
||||||
|
|
||||||
/* Get dst aligned to 16 bytes (since buffer is growing, we don't have to worry about overreading from src) */
|
/* Get dst aligned to 16 bytes (since buffer is growing, we don't have to worry about overreading from src) */
|
||||||
for (i = cvt->len_cvt; i && (((size_t)(dst - 15)) & 15); --i, --src, --dst) {
|
for (i = num_samples; i && (((size_t)(dst - 15)) & 15); --i, --src, --dst) {
|
||||||
*dst = (((float)*src) * DIVBY128) - 1.0f;
|
*dst = (((float)*src) * DIVBY128) - 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -350,23 +207,19 @@ static void SDLCALL SDL_TARGETING("sse2") SDL_Convert_U8_to_F32_SSE2(SDL_AudioCV
|
||||||
src--;
|
src--;
|
||||||
dst--;
|
dst--;
|
||||||
}
|
}
|
||||||
|
|
||||||
cvt->len_cvt *= 4;
|
|
||||||
if (cvt->filters[++cvt->filter_index]) {
|
|
||||||
cvt->filters[cvt->filter_index](cvt, AUDIO_F32SYS);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SDLCALL SDL_TARGETING("sse2") SDL_Convert_S16_to_F32_SSE2(SDL_AudioCVT *cvt, SDL_AudioFormat format)
|
static void SDL_TARGETING("sse2") SDL_Convert_S16_to_F32_SSE2(float *dst, const Sint16 *src, int num_samples)
|
||||||
{
|
{
|
||||||
const Sint16 *src = ((const Sint16 *)(cvt->buf + cvt->len_cvt)) - 1;
|
|
||||||
float *dst = ((float *)(cvt->buf + cvt->len_cvt * 2)) - 1;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
LOG_DEBUG_CONVERT("AUDIO_S16", "AUDIO_F32 (using SSE2)");
|
LOG_DEBUG_AUDIO_CONVERT("AUDIO_S16", "AUDIO_F32 (using SSE2)");
|
||||||
|
|
||||||
|
src += num_samples - 1;
|
||||||
|
dst += num_samples - 1;
|
||||||
|
|
||||||
/* Get dst aligned to 16 bytes (since buffer is growing, we don't have to worry about overreading from src) */
|
/* Get dst aligned to 16 bytes (since buffer is growing, we don't have to worry about overreading from src) */
|
||||||
for (i = cvt->len_cvt / sizeof(Sint16); i && (((size_t)(dst - 7)) & 15); --i, --src, --dst) {
|
for (i = num_samples; i && (((size_t)(dst - 7)) & 15); --i, --src, --dst) {
|
||||||
*dst = ((float)*src) * DIVBY32768;
|
*dst = ((float)*src) * DIVBY32768;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -403,23 +256,16 @@ static void SDLCALL SDL_TARGETING("sse2") SDL_Convert_S16_to_F32_SSE2(SDL_AudioC
|
||||||
src--;
|
src--;
|
||||||
dst--;
|
dst--;
|
||||||
}
|
}
|
||||||
|
|
||||||
cvt->len_cvt *= 2;
|
|
||||||
if (cvt->filters[++cvt->filter_index]) {
|
|
||||||
cvt->filters[cvt->filter_index](cvt, AUDIO_F32SYS);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SDLCALL SDL_TARGETING("sse2") SDL_Convert_S32_to_F32_SSE2(SDL_AudioCVT *cvt, SDL_AudioFormat format)
|
static void SDL_TARGETING("sse2") SDL_Convert_S32_to_F32_SSE2(float *dst, const Sint32 *src, int num_samples)
|
||||||
{
|
{
|
||||||
const Sint32 *src = (const Sint32 *)cvt->buf;
|
|
||||||
float *dst = (float *)cvt->buf;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
LOG_DEBUG_CONVERT("AUDIO_S32", "AUDIO_F32 (using SSE2)");
|
LOG_DEBUG_AUDIO_CONVERT("AUDIO_S32", "AUDIO_F32 (using SSE2)");
|
||||||
|
|
||||||
/* Get dst aligned to 16 bytes */
|
/* Get dst aligned to 16 bytes */
|
||||||
for (i = cvt->len_cvt / sizeof(Sint32); i && (((size_t)dst) & 15); --i, ++src, ++dst) {
|
for (i = num_samples; i && (((size_t)dst) & 15); --i, ++src, ++dst) {
|
||||||
*dst = ((float)(*src >> 8)) * DIVBY8388607;
|
*dst = ((float)(*src >> 8)) * DIVBY8388607;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -447,22 +293,16 @@ static void SDLCALL SDL_TARGETING("sse2") SDL_Convert_S32_to_F32_SSE2(SDL_AudioC
|
||||||
src++;
|
src++;
|
||||||
dst++;
|
dst++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cvt->filters[++cvt->filter_index]) {
|
|
||||||
cvt->filters[cvt->filter_index](cvt, AUDIO_F32SYS);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SDLCALL SDL_TARGETING("sse2") SDL_Convert_F32_to_S8_SSE2(SDL_AudioCVT *cvt, SDL_AudioFormat format)
|
static void SDL_TARGETING("sse2") SDL_Convert_F32_to_S8_SSE2(Sint8 *dst, const float *src, int num_samples)
|
||||||
{
|
{
|
||||||
const float *src = (const float *)cvt->buf;
|
|
||||||
Sint8 *dst = (Sint8 *)cvt->buf;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
LOG_DEBUG_CONVERT("AUDIO_F32", "AUDIO_S8 (using SSE2)");
|
LOG_DEBUG_AUDIO_CONVERT("AUDIO_F32", "AUDIO_S8 (using SSE2)");
|
||||||
|
|
||||||
/* Get dst aligned to 16 bytes */
|
/* Get dst aligned to 16 bytes */
|
||||||
for (i = cvt->len_cvt / sizeof(float); i && (((size_t)dst) & 15); --i, ++src, ++dst) {
|
for (i = num_samples; i && (((size_t)dst) & 15); --i, ++src, ++dst) {
|
||||||
const float sample = *src;
|
const float sample = *src;
|
||||||
if (sample >= 1.0f) {
|
if (sample >= 1.0f) {
|
||||||
*dst = 127;
|
*dst = 127;
|
||||||
|
@ -509,23 +349,16 @@ static void SDLCALL SDL_TARGETING("sse2") SDL_Convert_F32_to_S8_SSE2(SDL_AudioCV
|
||||||
src++;
|
src++;
|
||||||
dst++;
|
dst++;
|
||||||
}
|
}
|
||||||
|
|
||||||
cvt->len_cvt /= 4;
|
|
||||||
if (cvt->filters[++cvt->filter_index]) {
|
|
||||||
cvt->filters[cvt->filter_index](cvt, AUDIO_S8);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SDLCALL SDL_TARGETING("sse2") SDL_Convert_F32_to_U8_SSE2(SDL_AudioCVT *cvt, SDL_AudioFormat format)
|
static void SDL_TARGETING("sse2") SDL_Convert_F32_to_U8_SSE2(Uint8 *dst, const float *src, int num_samples)
|
||||||
{
|
{
|
||||||
const float *src = (const float *)cvt->buf;
|
|
||||||
Uint8 *dst = cvt->buf;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
LOG_DEBUG_CONVERT("AUDIO_F32", "AUDIO_U8 (using SSE2)");
|
LOG_DEBUG_AUDIO_CONVERT("AUDIO_F32", "AUDIO_U8 (using SSE2)");
|
||||||
|
|
||||||
/* Get dst aligned to 16 bytes */
|
/* Get dst aligned to 16 bytes */
|
||||||
for (i = cvt->len_cvt / sizeof(float); i && (((size_t)dst) & 15); --i, ++src, ++dst) {
|
for (i = num_samples; i && (((size_t)dst) & 15); --i, ++src, ++dst) {
|
||||||
const float sample = *src;
|
const float sample = *src;
|
||||||
if (sample >= 1.0f) {
|
if (sample >= 1.0f) {
|
||||||
*dst = 255;
|
*dst = 255;
|
||||||
|
@ -572,23 +405,16 @@ static void SDLCALL SDL_TARGETING("sse2") SDL_Convert_F32_to_U8_SSE2(SDL_AudioCV
|
||||||
src++;
|
src++;
|
||||||
dst++;
|
dst++;
|
||||||
}
|
}
|
||||||
|
|
||||||
cvt->len_cvt /= 4;
|
|
||||||
if (cvt->filters[++cvt->filter_index]) {
|
|
||||||
cvt->filters[cvt->filter_index](cvt, AUDIO_U8);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SDLCALL SDL_TARGETING("sse2") SDL_Convert_F32_to_S16_SSE2(SDL_AudioCVT *cvt, SDL_AudioFormat format)
|
static void SDL_TARGETING("sse2") SDL_Convert_F32_to_S16_SSE2(Sint16 *dst, const float *src, int num_samples)
|
||||||
{
|
{
|
||||||
const float *src = (const float *)cvt->buf;
|
|
||||||
Sint16 *dst = (Sint16 *)cvt->buf;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
LOG_DEBUG_CONVERT("AUDIO_F32", "AUDIO_S16 (using SSE2)");
|
LOG_DEBUG_AUDIO_CONVERT("AUDIO_F32", "AUDIO_S16 (using SSE2)");
|
||||||
|
|
||||||
/* Get dst aligned to 16 bytes */
|
/* Get dst aligned to 16 bytes */
|
||||||
for (i = cvt->len_cvt / sizeof(float); i && (((size_t)dst) & 15); --i, ++src, ++dst) {
|
for (i = num_samples; i && (((size_t)dst) & 15); --i, ++src, ++dst) {
|
||||||
const float sample = *src;
|
const float sample = *src;
|
||||||
if (sample >= 1.0f) {
|
if (sample >= 1.0f) {
|
||||||
*dst = 32767;
|
*dst = 32767;
|
||||||
|
@ -633,23 +459,16 @@ static void SDLCALL SDL_TARGETING("sse2") SDL_Convert_F32_to_S16_SSE2(SDL_AudioC
|
||||||
src++;
|
src++;
|
||||||
dst++;
|
dst++;
|
||||||
}
|
}
|
||||||
|
|
||||||
cvt->len_cvt /= 2;
|
|
||||||
if (cvt->filters[++cvt->filter_index]) {
|
|
||||||
cvt->filters[cvt->filter_index](cvt, AUDIO_S16SYS);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SDLCALL SDL_TARGETING("sse2") SDL_Convert_F32_to_S32_SSE2(SDL_AudioCVT *cvt, SDL_AudioFormat format)
|
static void SDL_TARGETING("sse2") SDL_Convert_F32_to_S32_SSE2(Sint32 *dst, const float *src, int num_samples)
|
||||||
{
|
{
|
||||||
const float *src = (const float *)cvt->buf;
|
|
||||||
Sint32 *dst = (Sint32 *)cvt->buf;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
LOG_DEBUG_CONVERT("AUDIO_F32", "AUDIO_S32 (using SSE2)");
|
LOG_DEBUG_AUDIO_CONVERT("AUDIO_F32", "AUDIO_S32 (using SSE2)");
|
||||||
|
|
||||||
/* Get dst aligned to 16 bytes */
|
/* Get dst aligned to 16 bytes */
|
||||||
for (i = cvt->len_cvt / sizeof(float); i && (((size_t)dst) & 15); --i, ++src, ++dst) {
|
for (i = num_samples; i && (((size_t)dst) & 15); --i, ++src, ++dst) {
|
||||||
const float sample = *src;
|
const float sample = *src;
|
||||||
if (sample >= 1.0f) {
|
if (sample >= 1.0f) {
|
||||||
*dst = 2147483647;
|
*dst = 2147483647;
|
||||||
|
@ -692,24 +511,21 @@ static void SDLCALL SDL_TARGETING("sse2") SDL_Convert_F32_to_S32_SSE2(SDL_AudioC
|
||||||
src++;
|
src++;
|
||||||
dst++;
|
dst++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cvt->filters[++cvt->filter_index]) {
|
|
||||||
cvt->filters[cvt->filter_index](cvt, AUDIO_S32SYS);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef SDL_NEON_INTRINSICS
|
#ifdef SDL_NEON_INTRINSICS
|
||||||
static void SDLCALL SDL_Convert_S8_to_F32_NEON(SDL_AudioCVT *cvt, SDL_AudioFormat format)
|
static void SDL_Convert_S8_to_F32_NEON(float *dst, const Sint8 *src, int num_samples)
|
||||||
{
|
{
|
||||||
const Sint8 *src = ((const Sint8 *)(cvt->buf + cvt->len_cvt)) - 1;
|
|
||||||
float *dst = ((float *)(cvt->buf + cvt->len_cvt * 4)) - 1;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
LOG_DEBUG_CONVERT("AUDIO_S8", "AUDIO_F32 (using NEON)");
|
LOG_DEBUG_AUDIO_CONVERT("AUDIO_S8", "AUDIO_F32 (using NEON)");
|
||||||
|
|
||||||
|
src += num_samples - 1;
|
||||||
|
dst += num_samples - 1;
|
||||||
|
|
||||||
/* Get dst aligned to 16 bytes (since buffer is growing, we don't have to worry about overreading from src) */
|
/* Get dst aligned to 16 bytes (since buffer is growing, we don't have to worry about overreading from src) */
|
||||||
for (i = cvt->len_cvt; i && (((size_t)(dst - 15)) & 15); --i, --src, --dst) {
|
for (i = num_samples; i && (((size_t)(dst - 15)) & 15); --i, --src, --dst) {
|
||||||
*dst = ((float)*src) * DIVBY128;
|
*dst = ((float)*src) * DIVBY128;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -749,23 +565,19 @@ static void SDLCALL SDL_Convert_S8_to_F32_NEON(SDL_AudioCVT *cvt, SDL_AudioForma
|
||||||
src--;
|
src--;
|
||||||
dst--;
|
dst--;
|
||||||
}
|
}
|
||||||
|
|
||||||
cvt->len_cvt *= 4;
|
|
||||||
if (cvt->filters[++cvt->filter_index]) {
|
|
||||||
cvt->filters[cvt->filter_index](cvt, AUDIO_F32SYS);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SDLCALL SDL_Convert_U8_to_F32_NEON(SDL_AudioCVT *cvt, SDL_AudioFormat format)
|
static void SDL_Convert_U8_to_F32_NEON(float *dst, const Uint8 *src, int num_samples)
|
||||||
{
|
{
|
||||||
const Uint8 *src = ((const Uint8 *)(cvt->buf + cvt->len_cvt)) - 1;
|
|
||||||
float *dst = ((float *)(cvt->buf + cvt->len_cvt * 4)) - 1;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
LOG_DEBUG_CONVERT("AUDIO_U8", "AUDIO_F32 (using NEON)");
|
LOG_DEBUG_AUDIO_CONVERT("AUDIO_U8", "AUDIO_F32 (using NEON)");
|
||||||
|
|
||||||
|
src += num_samples - 1;
|
||||||
|
dst += num_samples - 1;
|
||||||
|
|
||||||
/* Get dst aligned to 16 bytes (since buffer is growing, we don't have to worry about overreading from src) */
|
/* Get dst aligned to 16 bytes (since buffer is growing, we don't have to worry about overreading from src) */
|
||||||
for (i = cvt->len_cvt; i && (((size_t)(dst - 15)) & 15); --i, --src, --dst) {
|
for (i = num_samples; i && (((size_t)(dst - 15)) & 15); --i, --src, --dst) {
|
||||||
*dst = (((float)*src) * DIVBY128) - 1.0f;
|
*dst = (((float)*src) * DIVBY128) - 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -806,23 +618,19 @@ static void SDLCALL SDL_Convert_U8_to_F32_NEON(SDL_AudioCVT *cvt, SDL_AudioForma
|
||||||
src--;
|
src--;
|
||||||
dst--;
|
dst--;
|
||||||
}
|
}
|
||||||
|
|
||||||
cvt->len_cvt *= 4;
|
|
||||||
if (cvt->filters[++cvt->filter_index]) {
|
|
||||||
cvt->filters[cvt->filter_index](cvt, AUDIO_F32SYS);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SDLCALL SDL_Convert_S16_to_F32_NEON(SDL_AudioCVT *cvt, SDL_AudioFormat format)
|
static void SDL_Convert_S16_to_F32_NEON(float *dst, const Sint16 *src, int num_samples)
|
||||||
{
|
{
|
||||||
const Sint16 *src = ((const Sint16 *)(cvt->buf + cvt->len_cvt)) - 1;
|
|
||||||
float *dst = ((float *)(cvt->buf + cvt->len_cvt * 2)) - 1;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
LOG_DEBUG_CONVERT("AUDIO_S16", "AUDIO_F32 (using NEON)");
|
LOG_DEBUG_AUDIO_CONVERT("AUDIO_S16", "AUDIO_F32 (using NEON)");
|
||||||
|
|
||||||
|
src += num_samples - 1;
|
||||||
|
dst += num_samples - 1;
|
||||||
|
|
||||||
/* Get dst aligned to 16 bytes (since buffer is growing, we don't have to worry about overreading from src) */
|
/* Get dst aligned to 16 bytes (since buffer is growing, we don't have to worry about overreading from src) */
|
||||||
for (i = cvt->len_cvt / sizeof(Sint16); i && (((size_t)(dst - 7)) & 15); --i, --src, --dst) {
|
for (i = num_samples; i && (((size_t)(dst - 7)) & 15); --i, --src, --dst) {
|
||||||
*dst = ((float)*src) * DIVBY32768;
|
*dst = ((float)*src) * DIVBY32768;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -855,23 +663,16 @@ static void SDLCALL SDL_Convert_S16_to_F32_NEON(SDL_AudioCVT *cvt, SDL_AudioForm
|
||||||
src--;
|
src--;
|
||||||
dst--;
|
dst--;
|
||||||
}
|
}
|
||||||
|
|
||||||
cvt->len_cvt *= 2;
|
|
||||||
if (cvt->filters[++cvt->filter_index]) {
|
|
||||||
cvt->filters[cvt->filter_index](cvt, AUDIO_F32SYS);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SDLCALL SDL_Convert_S32_to_F32_NEON(SDL_AudioCVT *cvt, SDL_AudioFormat format)
|
static void SDL_Convert_S32_to_F32_NEON(float *dst, const Sint32 *src, int num_samples)
|
||||||
{
|
{
|
||||||
const Sint32 *src = (const Sint32 *)cvt->buf;
|
|
||||||
float *dst = (float *)cvt->buf;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
LOG_DEBUG_CONVERT("AUDIO_S32", "AUDIO_F32 (using NEON)");
|
LOG_DEBUG_AUDIO_CONVERT("AUDIO_S32", "AUDIO_F32 (using NEON)");
|
||||||
|
|
||||||
/* Get dst aligned to 16 bytes */
|
/* Get dst aligned to 16 bytes */
|
||||||
for (i = cvt->len_cvt / sizeof(Sint32); i && (((size_t)dst) & 15); --i, ++src, ++dst) {
|
for (i = num_samples; i && (((size_t)dst) & 15); --i, ++src, ++dst) {
|
||||||
*dst = ((float)(*src >> 8)) * DIVBY8388607;
|
*dst = ((float)(*src >> 8)) * DIVBY8388607;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -899,22 +700,16 @@ static void SDLCALL SDL_Convert_S32_to_F32_NEON(SDL_AudioCVT *cvt, SDL_AudioForm
|
||||||
src++;
|
src++;
|
||||||
dst++;
|
dst++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cvt->filters[++cvt->filter_index]) {
|
|
||||||
cvt->filters[cvt->filter_index](cvt, AUDIO_F32SYS);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SDLCALL SDL_Convert_F32_to_S8_NEON(SDL_AudioCVT *cvt, SDL_AudioFormat format)
|
static void SDL_Convert_F32_to_S8_NEON(Sint8 *dst, const float *src, int num_samples)
|
||||||
{
|
{
|
||||||
const float *src = (const float *)cvt->buf;
|
|
||||||
Sint8 *dst = (Sint8 *)cvt->buf;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
LOG_DEBUG_CONVERT("AUDIO_F32", "AUDIO_S8 (using NEON)");
|
LOG_DEBUG_AUDIO_CONVERT("AUDIO_F32", "AUDIO_S8 (using NEON)");
|
||||||
|
|
||||||
/* Get dst aligned to 16 bytes */
|
/* Get dst aligned to 16 bytes */
|
||||||
for (i = cvt->len_cvt / sizeof(float); i && (((size_t)dst) & 15); --i, ++src, ++dst) {
|
for (i = num_samples; i && (((size_t)dst) & 15); --i, ++src, ++dst) {
|
||||||
const float sample = *src;
|
const float sample = *src;
|
||||||
if (sample >= 1.0f) {
|
if (sample >= 1.0f) {
|
||||||
*dst = 127;
|
*dst = 127;
|
||||||
|
@ -963,23 +758,16 @@ static void SDLCALL SDL_Convert_F32_to_S8_NEON(SDL_AudioCVT *cvt, SDL_AudioForma
|
||||||
src++;
|
src++;
|
||||||
dst++;
|
dst++;
|
||||||
}
|
}
|
||||||
|
|
||||||
cvt->len_cvt /= 4;
|
|
||||||
if (cvt->filters[++cvt->filter_index]) {
|
|
||||||
cvt->filters[cvt->filter_index](cvt, AUDIO_S8);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SDLCALL SDL_Convert_F32_to_U8_NEON(SDL_AudioCVT *cvt, SDL_AudioFormat format)
|
static void SDL_Convert_F32_to_U8_NEON(Uint8 *dst, const float *src, int num_samples)
|
||||||
{
|
{
|
||||||
const float *src = (const float *)cvt->buf;
|
|
||||||
Uint8 *dst = cvt->buf;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
LOG_DEBUG_CONVERT("AUDIO_F32", "AUDIO_U8 (using NEON)");
|
LOG_DEBUG_AUDIO_CONVERT("AUDIO_F32", "AUDIO_U8 (using NEON)");
|
||||||
|
|
||||||
/* Get dst aligned to 16 bytes */
|
/* Get dst aligned to 16 bytes */
|
||||||
for (i = cvt->len_cvt / sizeof(float); i && (((size_t)dst) & 15); --i, ++src, ++dst) {
|
for (i = num_samples; i && (((size_t)dst) & 15); --i, ++src, ++dst) {
|
||||||
const float sample = *src;
|
const float sample = *src;
|
||||||
if (sample >= 1.0f) {
|
if (sample >= 1.0f) {
|
||||||
*dst = 255;
|
*dst = 255;
|
||||||
|
@ -1029,23 +817,16 @@ static void SDLCALL SDL_Convert_F32_to_U8_NEON(SDL_AudioCVT *cvt, SDL_AudioForma
|
||||||
src++;
|
src++;
|
||||||
dst++;
|
dst++;
|
||||||
}
|
}
|
||||||
|
|
||||||
cvt->len_cvt /= 4;
|
|
||||||
if (cvt->filters[++cvt->filter_index]) {
|
|
||||||
cvt->filters[cvt->filter_index](cvt, AUDIO_U8);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SDLCALL SDL_Convert_F32_to_S16_NEON(SDL_AudioCVT *cvt, SDL_AudioFormat format)
|
static void SDL_Convert_F32_to_S16_NEON(Sint16 *dst, const float *src, int num_samples)
|
||||||
{
|
{
|
||||||
const float *src = (const float *)cvt->buf;
|
|
||||||
Sint16 *dst = (Sint16 *)cvt->buf;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
LOG_DEBUG_CONVERT("AUDIO_F32", "AUDIO_S16 (using NEON)");
|
LOG_DEBUG_AUDIO_CONVERT("AUDIO_F32", "AUDIO_S16 (using NEON)");
|
||||||
|
|
||||||
/* Get dst aligned to 16 bytes */
|
/* Get dst aligned to 16 bytes */
|
||||||
for (i = cvt->len_cvt / sizeof(float); i && (((size_t)dst) & 15); --i, ++src, ++dst) {
|
for (i = num_samples; i && (((size_t)dst) & 15); --i, ++src, ++dst) {
|
||||||
const float sample = *src;
|
const float sample = *src;
|
||||||
if (sample >= 1.0f) {
|
if (sample >= 1.0f) {
|
||||||
*dst = 32767;
|
*dst = 32767;
|
||||||
|
@ -1090,23 +871,16 @@ static void SDLCALL SDL_Convert_F32_to_S16_NEON(SDL_AudioCVT *cvt, SDL_AudioForm
|
||||||
src++;
|
src++;
|
||||||
dst++;
|
dst++;
|
||||||
}
|
}
|
||||||
|
|
||||||
cvt->len_cvt /= 2;
|
|
||||||
if (cvt->filters[++cvt->filter_index]) {
|
|
||||||
cvt->filters[cvt->filter_index](cvt, AUDIO_S16SYS);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SDLCALL SDL_Convert_F32_to_S32_NEON(SDL_AudioCVT *cvt, SDL_AudioFormat format)
|
static void SDL_Convert_F32_to_S32_NEON(Sint32 *dst, const float *src, int num_samples)
|
||||||
{
|
{
|
||||||
const float *src = (const float *)cvt->buf;
|
|
||||||
Sint32 *dst = (Sint32 *)cvt->buf;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
LOG_DEBUG_CONVERT("AUDIO_F32", "AUDIO_S32 (using NEON)");
|
LOG_DEBUG_AUDIO_CONVERT("AUDIO_F32", "AUDIO_S32 (using NEON)");
|
||||||
|
|
||||||
/* Get dst aligned to 16 bytes */
|
/* Get dst aligned to 16 bytes */
|
||||||
for (i = cvt->len_cvt / sizeof(float); i && (((size_t)dst) & 15); --i, ++src, ++dst) {
|
for (i = num_samples; i && (((size_t)dst) & 15); --i, ++src, ++dst) {
|
||||||
const float sample = *src;
|
const float sample = *src;
|
||||||
if (sample >= 1.0f) {
|
if (sample >= 1.0f) {
|
||||||
*dst = 2147483647;
|
*dst = 2147483647;
|
||||||
|
@ -1149,28 +923,33 @@ static void SDLCALL SDL_Convert_F32_to_S32_NEON(SDL_AudioCVT *cvt, SDL_AudioForm
|
||||||
src++;
|
src++;
|
||||||
dst++;
|
dst++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cvt->filters[++cvt->filter_index]) {
|
|
||||||
cvt->filters[cvt->filter_index](cvt, AUDIO_S32SYS);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Function pointers set to a CPU-specific implementation. */
|
||||||
|
void (*SDL_Convert_S8_to_F32)(float *dst, const Sint8 *src, int num_samples) = NULL;
|
||||||
|
void (*SDL_Convert_U8_to_F32)(float *dst, const Uint8 *src, int num_samples) = NULL;
|
||||||
|
void (*SDL_Convert_S16_to_F32)(float *dst, const Sint16 *src, int num_samples) = NULL;
|
||||||
|
void (*SDL_Convert_S32_to_F32)(float *dst, const Sint32 *src, int num_samples) = NULL;
|
||||||
|
void (*SDL_Convert_F32_to_S8)(Sint8 *dst, const float *src, int num_samples) = NULL;
|
||||||
|
void (*SDL_Convert_F32_to_U8)(Uint8 *dst, const float *src, int num_samples) = NULL;
|
||||||
|
void (*SDL_Convert_F32_to_S16)(Sint16 *dst, const float *src, int num_samples) = NULL;
|
||||||
|
void (*SDL_Convert_F32_to_S32)(Sint32 *dst, const float *src, int num_samples) = NULL;
|
||||||
|
|
||||||
void SDL_ChooseAudioConverters(void)
|
void SDL_ChooseAudioConverters(void)
|
||||||
{
|
{
|
||||||
static SDL_bool converters_chosen = SDL_FALSE;
|
static SDL_bool converters_chosen = SDL_FALSE;
|
||||||
|
|
||||||
if (converters_chosen) {
|
if (converters_chosen) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SET_CONVERTER_FUNCS(fntype) \
|
#define SET_CONVERTER_FUNCS(fntype) \
|
||||||
SDL_Convert_S8_to_F32 = SDL_Convert_S8_to_F32_##fntype; \
|
SDL_Convert_S8_to_F32 = SDL_Convert_S8_to_F32_##fntype; \
|
||||||
SDL_Convert_U8_to_F32 = SDL_Convert_U8_to_F32_##fntype; \
|
SDL_Convert_U8_to_F32 = SDL_Convert_U8_to_F32_##fntype; \
|
||||||
SDL_Convert_S16_to_F32 = SDL_Convert_S16_to_F32_##fntype; \
|
SDL_Convert_S16_to_F32 = SDL_Convert_S16_to_F32_##fntype; \
|
||||||
SDL_Convert_S32_to_F32 = SDL_Convert_S32_to_F32_##fntype; \
|
SDL_Convert_S32_to_F32 = SDL_Convert_S32_to_F32_##fntype; \
|
||||||
SDL_Convert_F32_to_S8 = SDL_Convert_F32_to_S8_##fntype; \
|
SDL_Convert_F32_to_S8 = SDL_Convert_F32_to_S8_##fntype; \
|
||||||
SDL_Convert_F32_to_U8 = SDL_Convert_F32_to_U8_##fntype; \
|
SDL_Convert_F32_to_U8 = SDL_Convert_F32_to_U8_##fntype; \
|
||||||
SDL_Convert_F32_to_S16 = SDL_Convert_F32_to_S16_##fntype; \
|
SDL_Convert_F32_to_S16 = SDL_Convert_F32_to_S16_##fntype; \
|
||||||
SDL_Convert_F32_to_S32 = SDL_Convert_F32_to_S32_##fntype; \
|
SDL_Convert_F32_to_S32 = SDL_Convert_F32_to_S32_##fntype; \
|
||||||
converters_chosen = SDL_TRUE
|
converters_chosen = SDL_TRUE
|
||||||
|
|
|
@ -81,6 +81,9 @@ static const Uint8 mix8[] = {
|
||||||
#define ADJUST_VOLUME(type, s, v) ((s) = (type)(((s) * (v)) / SDL_MIX_MAXVOLUME))
|
#define ADJUST_VOLUME(type, s, v) ((s) = (type)(((s) * (v)) / SDL_MIX_MAXVOLUME))
|
||||||
#define ADJUST_VOLUME_U8(s, v) ((s) = (Uint8)(((((s) - 128) * (v)) / SDL_MIX_MAXVOLUME) + 128))
|
#define ADJUST_VOLUME_U8(s, v) ((s) = (Uint8)(((((s) - 128) * (v)) / SDL_MIX_MAXVOLUME) + 128))
|
||||||
|
|
||||||
|
|
||||||
|
/* !!! FIXME: this needs some SIMD magic. */
|
||||||
|
|
||||||
int SDL_MixAudioFormat(Uint8 *dst, const Uint8 *src, SDL_AudioFormat format,
|
int SDL_MixAudioFormat(Uint8 *dst, const Uint8 *src, SDL_AudioFormat format,
|
||||||
Uint32 len, int volume)
|
Uint32 len, int volume)
|
||||||
{
|
{
|
||||||
|
|
|
@ -842,6 +842,8 @@ SDL3_0.0.0 {
|
||||||
SDL_CreatePopupWindow;
|
SDL_CreatePopupWindow;
|
||||||
SDL_GetWindowParent;
|
SDL_GetWindowParent;
|
||||||
SDL_CreateWindowWithPosition;
|
SDL_CreateWindowWithPosition;
|
||||||
|
SDL_GetAudioStreamFormat;
|
||||||
|
SDL_SetAudioStreamFormat;
|
||||||
# extra symbols go here (don't modify this line)
|
# extra symbols go here (don't modify this line)
|
||||||
local: *;
|
local: *;
|
||||||
};
|
};
|
||||||
|
|
|
@ -868,3 +868,5 @@
|
||||||
#define SDL_CreatePopupWindow SDL_CreatePopupWindow_REAL
|
#define SDL_CreatePopupWindow SDL_CreatePopupWindow_REAL
|
||||||
#define SDL_GetWindowParent SDL_GetWindowParent_REAL
|
#define SDL_GetWindowParent SDL_GetWindowParent_REAL
|
||||||
#define SDL_CreateWindowWithPosition SDL_CreateWindowWithPosition_REAL
|
#define SDL_CreateWindowWithPosition SDL_CreateWindowWithPosition_REAL
|
||||||
|
#define SDL_GetAudioStreamFormat SDL_GetAudioStreamFormat_REAL
|
||||||
|
#define SDL_SetAudioStreamFormat SDL_SetAudioStreamFormat_REAL
|
||||||
|
|
|
@ -156,7 +156,7 @@ SDL_DYNAPI_PROC(int,SDL_CondWaitTimeout,(SDL_cond *a, SDL_mutex *b, Sint32 c),(a
|
||||||
SDL_DYNAPI_PROC(int,SDL_ConvertPixels,(int a, int b, Uint32 c, const void *d, int e, Uint32 f, void *g, int h),(a,b,c,d,e,f,g,h),return)
|
SDL_DYNAPI_PROC(int,SDL_ConvertPixels,(int a, int b, Uint32 c, const void *d, int e, Uint32 f, void *g, int h),(a,b,c,d,e,f,g,h),return)
|
||||||
SDL_DYNAPI_PROC(SDL_Surface*,SDL_ConvertSurface,(SDL_Surface *a, const SDL_PixelFormat *b),(a,b),return)
|
SDL_DYNAPI_PROC(SDL_Surface*,SDL_ConvertSurface,(SDL_Surface *a, const SDL_PixelFormat *b),(a,b),return)
|
||||||
SDL_DYNAPI_PROC(SDL_Surface*,SDL_ConvertSurfaceFormat,(SDL_Surface *a, Uint32 b),(a,b),return)
|
SDL_DYNAPI_PROC(SDL_Surface*,SDL_ConvertSurfaceFormat,(SDL_Surface *a, Uint32 b),(a,b),return)
|
||||||
SDL_DYNAPI_PROC(SDL_AudioStream*,SDL_CreateAudioStream,(SDL_AudioFormat a, Uint8 b, int c, SDL_AudioFormat d, Uint8 e, int f),(a,b,c,d,e,f),return)
|
SDL_DYNAPI_PROC(SDL_AudioStream*,SDL_CreateAudioStream,(SDL_AudioFormat a, int b, int c, SDL_AudioFormat d, int e, int f),(a,b,c,d,e,f),return)
|
||||||
SDL_DYNAPI_PROC(SDL_Cursor*,SDL_CreateColorCursor,(SDL_Surface *a, int b, int c),(a,b,c),return)
|
SDL_DYNAPI_PROC(SDL_Cursor*,SDL_CreateColorCursor,(SDL_Surface *a, int b, int c),(a,b,c),return)
|
||||||
SDL_DYNAPI_PROC(SDL_cond*,SDL_CreateCond,(void),(),return)
|
SDL_DYNAPI_PROC(SDL_cond*,SDL_CreateCond,(void),(),return)
|
||||||
SDL_DYNAPI_PROC(SDL_Cursor*,SDL_CreateCursor,(const Uint8 *a, const Uint8 *b, int c, int d, int e, int f),(a,b,c,d,e,f),return)
|
SDL_DYNAPI_PROC(SDL_Cursor*,SDL_CreateCursor,(const Uint8 *a, const Uint8 *b, int c, int d, int e, int f),(a,b,c,d,e,f),return)
|
||||||
|
@ -913,3 +913,5 @@ SDL_DYNAPI_PROC(SDL_SystemTheme,SDL_GetSystemTheme,(void),(),return)
|
||||||
SDL_DYNAPI_PROC(SDL_Window*,SDL_CreatePopupWindow,(SDL_Window *a, int b, int c, int d, int e, Uint32 f),(a,b,c,d,e,f),return)
|
SDL_DYNAPI_PROC(SDL_Window*,SDL_CreatePopupWindow,(SDL_Window *a, int b, int c, int d, int e, Uint32 f),(a,b,c,d,e,f),return)
|
||||||
SDL_DYNAPI_PROC(SDL_Window*,SDL_GetWindowParent,(SDL_Window *a),(a),return)
|
SDL_DYNAPI_PROC(SDL_Window*,SDL_GetWindowParent,(SDL_Window *a),(a),return)
|
||||||
SDL_DYNAPI_PROC(SDL_Window*,SDL_CreateWindowWithPosition,(const char *a, int b, int c, int d, int e, Uint32 f),(a,b,c,d,e,f),return)
|
SDL_DYNAPI_PROC(SDL_Window*,SDL_CreateWindowWithPosition,(const char *a, int b, int c, int d, int e, Uint32 f),(a,b,c,d,e,f),return)
|
||||||
|
SDL_DYNAPI_PROC(int,SDL_GetAudioStreamFormat,(SDL_AudioStream *a, SDL_AudioFormat *b, int *c, int *d, SDL_AudioFormat *e, int *f, int *g),(a,b,c,d,e,f,g),return)
|
||||||
|
SDL_DYNAPI_PROC(int,SDL_SetAudioStreamFormat,(SDL_AudioStream *a, SDL_AudioFormat b, int c, int d, SDL_AudioFormat e, int f, int g),(a,b,c,d,e,f,g),return)
|
||||||
|
|
|
@ -151,6 +151,7 @@ add_sdl_test_executable(loopwavequeue NEEDS_RESOURCES TESTUTILS SOURCES loopwave
|
||||||
add_sdl_test_executable(testsurround SOURCES testsurround.c)
|
add_sdl_test_executable(testsurround SOURCES testsurround.c)
|
||||||
add_sdl_test_executable(testresample NEEDS_RESOURCES SOURCES testresample.c)
|
add_sdl_test_executable(testresample NEEDS_RESOURCES SOURCES testresample.c)
|
||||||
add_sdl_test_executable(testaudioinfo SOURCES testaudioinfo.c)
|
add_sdl_test_executable(testaudioinfo SOURCES testaudioinfo.c)
|
||||||
|
add_sdl_test_executable(testaudiostreamdynamicresample SOURCES testaudiostreamdynamicresample.c)
|
||||||
|
|
||||||
file(GLOB TESTAUTOMATION_SOURCE_FILES testautomation*.c)
|
file(GLOB TESTAUTOMATION_SOURCE_FILES testautomation*.c)
|
||||||
add_sdl_test_executable(testautomation NEEDS_RESOURCES SOURCES ${TESTAUTOMATION_SOURCE_FILES})
|
add_sdl_test_executable(testautomation NEEDS_RESOURCES SOURCES ${TESTAUTOMATION_SOURCE_FILES})
|
||||||
|
|
|
@ -0,0 +1,123 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* !!! FIXME: this code is not up to standards for SDL3 test apps. Someone should improve this. */
|
||||||
|
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
#include <SDL3/SDL_main.h>
|
||||||
|
#include <SDL3/SDL_test.h>
|
||||||
|
|
||||||
|
static void SDLCALL audio_callback(void *userdata, Uint8 * stream, int len)
|
||||||
|
{
|
||||||
|
SDL_AudioStream *audiostream = (SDL_AudioStream *) userdata;
|
||||||
|
SDL_memset(stream, 0, len);
|
||||||
|
SDL_GetAudioStreamData(audiostream, stream, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
SDL_Window *window;
|
||||||
|
SDL_Renderer *renderer;
|
||||||
|
SDL_bool done = SDL_FALSE;
|
||||||
|
const SDL_FRect slider_area = { (640 - 500) / 2, (480 - 100) / 2, 500, 100 };
|
||||||
|
SDL_FRect slider_fill_area = slider_area;
|
||||||
|
int multiplier = 100;
|
||||||
|
SDL_AudioSpec spec;
|
||||||
|
Uint8 *audio_buf = NULL;
|
||||||
|
Uint32 audio_len = 0;
|
||||||
|
SDL_AudioStream *stream;
|
||||||
|
SDL_AudioDeviceID device;
|
||||||
|
|
||||||
|
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO);
|
||||||
|
window = SDL_CreateWindow("Drag the slider: Normal speed", 640, 480, 0);
|
||||||
|
renderer = SDL_CreateRenderer(window, NULL, 0);
|
||||||
|
|
||||||
|
SDL_LoadWAV("sample.wav", &spec, &audio_buf, &audio_len);
|
||||||
|
stream = SDL_CreateAudioStream(spec.format, spec.channels, spec.freq, spec.format, spec.channels, spec.freq);
|
||||||
|
SDL_PutAudioStreamData(stream, audio_buf, audio_len);
|
||||||
|
spec.callback = audio_callback;
|
||||||
|
spec.userdata = stream;
|
||||||
|
device = SDL_OpenAudioDevice(NULL, SDL_FALSE, &spec, NULL, 0);
|
||||||
|
SDL_PlayAudioDevice(device);
|
||||||
|
|
||||||
|
slider_fill_area.w /= 2;
|
||||||
|
|
||||||
|
while (!done) {
|
||||||
|
SDL_Event e;
|
||||||
|
int newmultiplier = multiplier;
|
||||||
|
while (SDL_PollEvent(&e)) {
|
||||||
|
if (e.type == SDL_EVENT_QUIT) {
|
||||||
|
done = 1;
|
||||||
|
} else if (e.type == SDL_EVENT_KEY_DOWN) {
|
||||||
|
if (e.key.keysym.sym == SDLK_ESCAPE) {
|
||||||
|
done = 1;
|
||||||
|
}
|
||||||
|
} else if (e.type == SDL_EVENT_MOUSE_MOTION) {
|
||||||
|
if (e.motion.state & SDL_BUTTON_LMASK) {
|
||||||
|
const SDL_FPoint p = { e.motion.x, e.motion.y };
|
||||||
|
if (SDL_PointInRectFloat(&p, &slider_area)) {
|
||||||
|
const float w = SDL_roundf(p.x - slider_area.x);
|
||||||
|
slider_fill_area.w = w;
|
||||||
|
newmultiplier = ((int) ((w / slider_area.w) * 800.0f)) - 400;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (multiplier != newmultiplier) {
|
||||||
|
char title[64];
|
||||||
|
int newfreq = spec.freq;
|
||||||
|
|
||||||
|
multiplier = newmultiplier;
|
||||||
|
if (multiplier == 0) {
|
||||||
|
SDL_snprintf(title, sizeof (title), "Drag the slider: Normal speed");
|
||||||
|
} else if (multiplier < 0) {
|
||||||
|
SDL_snprintf(title, sizeof (title), "Drag the slider: %.2fx slow", (-multiplier / 100.0f) + 1.0f);
|
||||||
|
} else {
|
||||||
|
SDL_snprintf(title, sizeof (title), "Drag the slider: %.2fx fast", (multiplier / 100.0f) + 1.0f);
|
||||||
|
}
|
||||||
|
SDL_SetWindowTitle(window, title);
|
||||||
|
|
||||||
|
// this math sucks, but whatever.
|
||||||
|
if (multiplier < 0) {
|
||||||
|
newfreq = spec.freq + (int) ((spec.freq * (multiplier / 400.0f)) * 0.75f);
|
||||||
|
} else if (multiplier > 0) {
|
||||||
|
newfreq = spec.freq + (int) (spec.freq * (multiplier / 100.0f));
|
||||||
|
}
|
||||||
|
//SDL_Log("newfreq=%d multiplier=%d\n", newfreq, multiplier);
|
||||||
|
SDL_LockAudioDevice(device);
|
||||||
|
SDL_SetAudioStreamFormat(stream, spec.format, spec.channels, newfreq, spec.format, spec.channels, spec.freq);
|
||||||
|
SDL_UnlockAudioDevice(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
// keep it looping.
|
||||||
|
if (SDL_GetAudioStreamAvailable(stream) < (1024 * 100)) {
|
||||||
|
SDL_PutAudioStreamData(stream, audio_buf, audio_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_SetRenderDrawColor(renderer, 0, 0, 255, 255);
|
||||||
|
SDL_RenderClear(renderer);
|
||||||
|
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
|
||||||
|
SDL_RenderFillRect(renderer, &slider_area);
|
||||||
|
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
|
||||||
|
SDL_RenderFillRect(renderer, &slider_fill_area);
|
||||||
|
SDL_RenderPresent(renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_DestroyRenderer(renderer);
|
||||||
|
SDL_DestroyWindow(window);
|
||||||
|
SDL_CloseAudioDevice(device);
|
||||||
|
SDL_free(audio_buf);
|
||||||
|
SDL_Quit();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue