diff --git a/AUTHORS b/AUTHORS index e8a1b8eb..1957c685 100644 --- a/AUTHORS +++ b/AUTHORS @@ -40,3 +40,5 @@ lexander Yashin https://github.com/yashin-alexander Nils Duval https://github.com/nlsdvl JackRedstonia jackredstonia64@gmail.com David Bullock https://github.com/dwbullock +Sam Gubernick https://github.com/samgubernick +Vincent Hamm https://github.com/yaz0r diff --git a/build/genie.lua b/build/genie.lua index 572187a9..0cd4e10a 100644 --- a/build/genie.lua +++ b/build/genie.lua @@ -1,7 +1,9 @@ local WITH_SDL = 0 local WITH_SDL2 = 0 +local WITH_SDL3 = 0 local WITH_SDL_STATIC = 0 local WITH_SDL2_STATIC = 0 +local WITH_SDL3_STATIC = 0 local WITH_PORTAUDIO = 0 local WITH_OPENAL = 0 local WITH_XAUDIO2 = 0 @@ -30,6 +32,7 @@ end local sdl_root = "/libraries/sdl" local sdl2_root = "/libraries/sdl2" +local sdl3_root = "/libraries/sdl3" local dxsdk_root = os.getenv("DXSDK_DIR") and os.getenv("DXSDK_DIR") or "C:/Program Files (x86)/Microsoft DirectX SDK (June 2010)" local portaudio_root = "/libraries/portaudio" local openal_root = "/libraries/openal" @@ -40,6 +43,9 @@ local sdl_include = sdl_root .. "/include" local sdl2_include = sdl2_root .. "/include" local sdl2_lib_x86 = sdl2_root .. "/lib/x86" local sdl2_lib_x64 = sdl2_root .. "/lib/x64" +local sdl3_include = sdl3_root .. "/include" +local sdl3_lib_x86 = sdl3_root .. "/lib/x86" +local sdl3_lib_x64 = sdl3_root .. "/lib/x64" local dxsdk_include = dxsdk_root .. "/include" local portaudio_include = portaudio_root .. "/include" local openal_include = openal_root .. "/include" @@ -69,6 +75,11 @@ newoption { description = "Include SDL2 backend in build" } +newoption { + trigger = "with-sdl3", + description = "Include SDL3 backend in build" +} + newoption { trigger = "with-portaudio", description = "Include PortAudio backend in build" @@ -109,6 +120,16 @@ newoption { description = "Only include sdl2 that doesn't use dyndll in build" } +newoption { + trigger = "with-sdl3static-only", + description = "Only include sdl3 that doesn't use dyndll in build" +} + +newoption { + trigger = "with-sdl3-only", + description = "Only include sdl3 in build" +} + newoption { trigger = "with-coreaudio", description = "Include OS X CoreAudio backend in build" @@ -157,6 +178,7 @@ newoption { if _OPTIONS["soloud-devel"] then WITH_SDL = 0 WITH_SDL2 = 1 + WITH_SDL3 = 0 WITH_SDL_STATIC = 0 WITH_SDL2_STATIC = 0 WITH_PORTAUDIO = 1 @@ -178,6 +200,7 @@ end if _OPTIONS["with-common-backends"] then WITH_SDL = 1 + WITH_SDL3 = 0 WITH_SDL_STATIC = 0 WITH_SDL2_STATIC = 0 WITH_PORTAUDIO = 1 @@ -221,6 +244,10 @@ if _OPTIONS["with-sdl2"] then WITH_SDL2 = 1 end +if _OPTIONS["with-sdl3"] then + WITH_SDL3 = 1 +end + if _OPTIONS["with-wasapi"] then WITH_WASAPI = 1 end @@ -232,8 +259,10 @@ end if _OPTIONS["with-sdl-only"] then WITH_SDL = 1 WITH_SDL2 = 0 + WITH_SDL3 = 0 WITH_SDL_STATIC = 0 WITH_SDL2_STATIC = 0 + WITH_SDL3_STATIC = 0 WITH_PORTAUDIO = 0 WITH_OPENAL = 0 WITH_XAUDIO2 = 0 @@ -247,8 +276,27 @@ end if _OPTIONS["with-sdl2-only"] then WITH_SDL = 0 WITH_SDL2 = 1 + WITH_SDL3 = 0 + WITH_SDL_STATIC = 0 + WITH_SDL2_STATIC = 0 + WITH_SDL3_STATIC = 0 + WITH_PORTAUDIO = 0 + WITH_OPENAL = 0 + WITH_XAUDIO2 = 0 + WITH_WINMM = 0 + WITH_WASAPI = 0 + WITH_OSS = 0 + WITH_NOSOUND = 0 + WITH_MINIAUDIO = 0 +end + +if _OPTIONS["with-sdl3-only"] then + WITH_SDL = 0 + WITH_SDL2 = 0 + WITH_SDL3 = 1 WITH_SDL_STATIC = 0 WITH_SDL2_STATIC = 0 + WITH_SDL3_STATIC = 0 WITH_PORTAUDIO = 0 WITH_OPENAL = 0 WITH_XAUDIO2 = 0 @@ -262,7 +310,10 @@ end if _OPTIONS["with-sdlstatic-only"] then WITH_SDL = 0 WITH_SDL2 = 0 + WITH_SDL3 = 0 WITH_SDL_STATIC = 1 + WITH_SDL2_STATIC = 0 + WITH_SDL3_STATIC = 0 WITH_PORTAUDIO = 0 WITH_OPENAL = 0 WITH_XAUDIO2 = 0 @@ -276,8 +327,10 @@ end if _OPTIONS["with-sdl2static-only"] then WITH_SDL = 0 WITH_SDL2 = 0 + WITH_SDL3 = 0 WITH_SDL_STATIC = 0 WITH_SDL2_STATIC = 1 + WITH_SDL3_STATIC = 0 WITH_PORTAUDIO = 0 WITH_OPENAL = 0 WITH_XAUDIO2 = 0 @@ -288,11 +341,13 @@ if _OPTIONS["with-sdl2static-only"] then WITH_MINIAUDIO = 0 end -if _OPTIONS["with-sdl2static-only"] then +if _OPTIONS["with-sdl3static-only"] then WITH_SDL = 0 WITH_SDL2 = 0 + WITH_SDL3 = 0 WITH_SDL_STATIC = 0 - WITH_SDL2_STATIC = 1 + WITH_SDL2_STATIC = 0 + WITH_SDL3_STATIC = 1 WITH_PORTAUDIO = 0 WITH_OPENAL = 0 WITH_XAUDIO2 = 0 @@ -306,8 +361,10 @@ end if _OPTIONS["with-vita-homebrew-only"] then WITH_SDL = 0 WITH_SDL2 = 0 + WITH_SDL3 = 0 WITH_SDL_STATIC = 0 WITH_SDL2_STATIC = 0 + WITH_SDL3_STATIC = 0 WITH_PORTAUDIO = 0 WITH_OPENAL = 0 WITH_XAUDIO2 = 0 @@ -331,8 +388,10 @@ end if _OPTIONS["with-jack-only"] then WITH_SDL = 0 WITH_SDL2 = 0 + WITH_SDL3 = 0 WITH_SDL_STATIC = 0 WITH_SDL2_STATIC = 0 + WITH_SDL3_STATIC = 0 WITH_PORTAUDIO = 0 WITH_OPENAL = 0 WITH_XAUDIO2 = 0 @@ -354,8 +413,10 @@ end if _OPTIONS["with-miniaudio-only"] then WITH_SDL = 0 WITH_SDL2 = 0 + WITH_SDL3 = 0 WITH_SDL_STATIC = 0 WITH_SDL2_STATIC = 0 + WITH_SDL3_STATIC = 0 WITH_PORTAUDIO = 0 WITH_OPENAL = 0 WITH_XAUDIO2 = 0 @@ -373,8 +434,10 @@ end if _OPTIONS["with-native-only"] then WITH_SDL = 0 WITH_SDL2 = 0 + WITH_SDL3 = 0 WITH_SDL_STATIC = 0 WITH_SDL2_STATIC = 0 + WITH_SDL3_STATIC = 0 WITH_PORTAUDIO = 0 WITH_OPENAL = 0 WITH_XAUDIO2 = 0 @@ -400,6 +463,7 @@ print ("") print ("Active options:") print ("WITH_SDL = ", WITH_SDL) print ("WITH_SDL2 = ", WITH_SDL2) +print ("WITH_SDL3 = ", WITH_SDL3) print ("WITH_PORTAUDIO = ", WITH_PORTAUDIO) print ("WITH_OPENAL = ", WITH_OPENAL) print ("WITH_XAUDIO2 = ", WITH_XAUDIO2) @@ -601,6 +665,31 @@ if (WITH_SDL2 == 1 or WITH_SDL2STATIC) then targetname "solouddemocommon" end +-- 8< -- 8< -- 8< -- 8< -- 8< -- 8< -- 8< -- 8< -- 8< -- 8< -- + +if (WITH_SDL3 == 1 or WITH_SDL3STATIC) then + + project "SoloudDemoCommon" + kind "StaticLib" + targetdir "../lib" + language "C++" + + files { + "../demos/common/**.c*", + "../demos/common/imgui/**.c*", + "../demos/common/glew/GL/**.c*" + } + includedirs { + "../include", + "../demos/common", + "../demos/common/imgui", + "../demos/common/glew", + sdl3_include + } + defines { "GLEW_STATIC" } + + targetname "solouddemocommon" +end -- 8< -- 8< -- 8< -- 8< -- 8< -- 8< -- 8< -- 8< -- 8< -- 8< -- project "SoloudStatic" @@ -715,6 +804,17 @@ if (WITH_SDL2 == 1) then } end +if (WITH_SDL3 == 1) then + defines { "WITH_SDL3" } + files { + "../src/backend/sdl/**.c*" + } + includedirs { + "../include", + sdl3_include + } +end + if (WITH_SDL_STATIC == 1) then defines { "WITH_SDL_STATIC" } files { @@ -737,6 +837,17 @@ if (WITH_SDL2_STATIC == 1) then } end +if (WITH_SDL3_STATIC == 1) then + defines { "WITH_SDL3_STATIC" } + files { + "../src/backend/sdl3_static/**.c*" + } + includedirs { + "../include", + sdl3_include + } +end + if (WITH_WASAPI == 1) then defines { "WITH_WASAPI" } files { diff --git a/include/soloud.h b/include/soloud.h index e3b47d8e..ff58b172 100644 --- a/include/soloud.h +++ b/include/soloud.h @@ -48,10 +48,12 @@ freely, subject to the following restrictions: #endif #ifdef WITH_SDL +#undef WITH_SDL3 #undef WITH_SDL2 #undef WITH_SDL1 #define WITH_SDL1 #define WITH_SDL2 +#define WITH_SDL3 #endif #ifdef WITH_SDL_STATIC @@ -194,6 +196,7 @@ namespace SoLoud MINIAUDIO, NOSOUND, NULLDRIVER, + SDL3, BACKEND_MAX, }; @@ -227,7 +230,7 @@ namespace SoLoud }; // Initialize SoLoud. Must be called before SoLoud can be used. - result init(unsigned int aFlags = Soloud::CLIP_ROUNDOFF, unsigned int aBackend = Soloud::AUTO, unsigned int aSamplerate = Soloud::AUTO, unsigned int aBufferSize = Soloud::AUTO, unsigned int aChannels = 2); + result init(unsigned int aFlags = Soloud::CLIP_ROUNDOFF, unsigned int aBackend = Soloud::AUTO, unsigned int aSamplerate = Soloud::AUTO, unsigned int aBufferSize = Soloud::AUTO, unsigned int aChannels = 2, void const * clientData = NULL); result pause(); result resume(); diff --git a/include/soloud_backend_data_sdl3.h b/include/soloud_backend_data_sdl3.h new file mode 100644 index 00000000..c713e059 --- /dev/null +++ b/include/soloud_backend_data_sdl3.h @@ -0,0 +1,55 @@ +/* +SoLoud audio engine +Copyright (c) 2013-2015 Jari Komppa + +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. +*/ + +#ifndef SOLOUD_BACKEND_DATA_SDL3_H +#define SOLOUD_BACKEND_DATA_SDL3_H + +#if defined(WITH_SDL3) || defined(WITH_SDL3_STATIC) +#include "SDL3/SDL.h" + +namespace SoLoud +{ + struct SoLoudBackendDataSdl3 + { + SoLoudBackendDataSdl3() + : audioStream{NULL} + , audioDeviceId{0} + , activeAudioSpec{} + {} + SDL_AudioStream * audioStream; + SDL_AudioDeviceID audioDeviceId; + SDL_AudioSpec activeAudioSpec; + }; + + struct SoLoudClientDataSdl3 + { + SoLoudClientDataSdl3(unsigned int deviceId) + : deviceId(deviceId) + {} + unsigned int deviceId; + }; +} +#endif + +#endif diff --git a/include/soloud_internal.h b/include/soloud_internal.h index c0589abd..7fe738ea 100644 --- a/include/soloud_internal.h +++ b/include/soloud_internal.h @@ -35,12 +35,18 @@ namespace SoLoud // SDL2 back-end initialization call result sdl2_init(SoLoud::Soloud *aSoloud, unsigned int aFlags = Soloud::CLIP_ROUNDOFF, unsigned int aSamplerate = 44100, unsigned int aBuffer = 2048, unsigned int aChannels = 2); + // SDL3 back-end initialization call + result sdl3_init(SoLoud::Soloud *aSoloud, unsigned int aFlags = Soloud::CLIP_ROUNDOFF, unsigned int aSamplerate = 44100, unsigned int aBuffer = 2048, unsigned int aChannels = 2, void const * clientData = NULL); + // SDL1 "non-dynamic" back-end initialization call result sdl1static_init(SoLoud::Soloud *aSoloud, unsigned int aFlags = Soloud::CLIP_ROUNDOFF, unsigned int aSamplerate = 44100, unsigned int aBuffer = 2048, unsigned int aChannels = 2); // SDL2 "non-dynamic" back-end initialization call result sdl2static_init(SoLoud::Soloud *aSoloud, unsigned int aFlags = Soloud::CLIP_ROUNDOFF, unsigned int aSamplerate = 44100, unsigned int aBuffer = 2048, unsigned int aChannels = 2); + // SDL3 "non-dynamic" back-end initialization call + result sdl3static_init(SoLoud::Soloud* aSoloud, unsigned int aFlags = Soloud::CLIP_ROUNDOFF, unsigned int aSamplerate = 44100, unsigned int aBuffer = 2048, unsigned int aChannels = 2, void const* clientData = NULL); + // OpenAL back-end initialization call result openal_init(SoLoud::Soloud *aSoloud, unsigned int aFlags = Soloud::CLIP_ROUNDOFF, unsigned int aSamplerate = 44100, unsigned int aBuffer = 2048, unsigned int aChannels = 2); diff --git a/src/backend/sdl/soloud_sdl3.cpp b/src/backend/sdl/soloud_sdl3.cpp new file mode 100644 index 00000000..0f341f02 --- /dev/null +++ b/src/backend/sdl/soloud_sdl3.cpp @@ -0,0 +1,196 @@ +/* +SoLoud audio engine +Copyright (c) 2013-2018 Jari Komppa + +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. +*/ +#include + +#include "soloud.h" +#include "soloud_backend_data_sdl3.h" + +#if !defined(WITH_SDL3) + +namespace SoLoud +{ + result sdl3_init( + SoLoud::Soloud * aSoloud, + unsigned int aFlags, + unsigned int aSamplerate, + unsigned int aBuffer, + unsigned int aChannels, + void const * backendData + ) + { + return NOT_IMPLEMENTED; + } +} + +#else + +#include "SDL3/SDL.h" +#include + +extern "C" +{ + int dll_SDL3_found(); + + Uint32 dll_SDL3_WasInit(Uint32 flags); + int dll_SDL3_InitSubSystem(Uint32 flags); + SDL_AudioStream * dll_SDL3_OpenAudioDeviceStream( + SDL_AudioDeviceID device, + SDL_AudioSpec const * spec, + SDL_AudioStreamCallback callback, + void * userdata + ); + void dll_SDL3_CloseAudioDevice(SDL_AudioDeviceID dev); + bool dll_SDL3_PauseAudioStreamDevice(SDL_AudioStream * dev); +}; + +namespace SoLoud +{ + static SoLoudBackendDataSdl3 gBackendData{}; + + void soloud_sdl2_audiomixer(Uint8 * stream, void * userdata, int len) + { + SoLoud::Soloud *soloud = (SoLoud::Soloud *)userdata; + if (gBackendData.activeAudioSpec.format == SDL_AUDIO_F32) + { + int samples = len / (gBackendData.activeAudioSpec.channels * sizeof(float)); + soloud->mix((float *)stream, samples); + } + else // assume s16 if not float + { + int samples = len / (gBackendData.activeAudioSpec.channels * sizeof(short)); + soloud->mixSigned16((short *)stream, samples); + } + } + + void soloud_sdl3_audiomixer(void *userdata, SDL_AudioStream *stream, int additionalAmount, int totalAmount) + { + SoLoud::Soloud *soloud = (SoLoud::Soloud *)userdata; + + if (additionalAmount > 0) + { + Uint8 * data = SDL_stack_alloc(Uint8, additionalAmount); + if (data) + { + soloud_sdl2_audiomixer( + data, + userdata, + additionalAmount + ); + SDL_PutAudioStreamData(stream, data, additionalAmount); + SDL_stack_free(data); + } + } + } + + static void soloud_sdl3_deinit(SoLoud::Soloud * /*aSoloud*/) + { + dll_SDL3_CloseAudioDevice(gBackendData.audioDeviceId); + } + + result sdl3_init( + SoLoud::Soloud *aSoloud, + unsigned int aFlags, + unsigned int aSamplerate, + unsigned int aBuffer, + unsigned int aChannels, + void const * clientData + ) + { + if (!dll_SDL3_found()) + return DLL_NOT_FOUND; + + if (!dll_SDL3_WasInit(SDL_INIT_AUDIO)) + { + if (dll_SDL3_InitSubSystem(SDL_INIT_AUDIO) < 0) + { + return UNKNOWN_ERROR; + } + } + + SoLoudClientDataSdl3 const * data = NULL; + if (clientData != NULL) + { + data = static_cast(clientData); + gBackendData.audioDeviceId = data->deviceId; + } + else + { + gBackendData.audioDeviceId = 0; + } + + SDL_AudioDeviceID const deviceId = gBackendData.audioDeviceId; + SDL_AudioSpec as{}; + as.freq = aSamplerate; + as.format = SDL_AUDIO_F32; + as.channels = (Uint8)aChannels; + + gBackendData.audioStream = dll_SDL3_OpenAudioDeviceStream( + gBackendData.audioDeviceId, + &as, + soloud_sdl3_audiomixer, + static_cast(aSoloud) + ); + + gBackendData.audioDeviceId = SDL_GetAudioStreamDevice(gBackendData.audioStream); + + if (gBackendData.audioDeviceId == NULL) + { + as.format = SDL_AUDIO_S16; + gBackendData.audioStream = dll_SDL3_OpenAudioDeviceStream( + deviceId, + NULL, + soloud_sdl3_audiomixer, + static_cast(aSoloud) + ); + + gBackendData.audioDeviceId = SDL_GetAudioStreamDevice(gBackendData.audioStream); + + if (gBackendData.audioDeviceId == NULL) + { + return UNKNOWN_ERROR; + } + } + + SDL_GetAudioDeviceFormat( + gBackendData.audioDeviceId, + &gBackendData.activeAudioSpec, + NULL + ); + + aSoloud->postinit_internal( + gBackendData.activeAudioSpec.freq, + aBuffer, + aFlags, + gBackendData.activeAudioSpec.channels + ); + + aSoloud->mBackendCleanupFunc = soloud_sdl3_deinit; + + dll_SDL3_PauseAudioStreamDevice(gBackendData.audioStream); + aSoloud->mBackendData = &gBackendData; + aSoloud->mBackendString = "SDL3 (dynamic)"; + return 0; + } +}; +#endif diff --git a/src/backend/sdl/soloud_sdl3_dll.c b/src/backend/sdl/soloud_sdl3_dll.c new file mode 100644 index 00000000..e4185d96 --- /dev/null +++ b/src/backend/sdl/soloud_sdl3_dll.c @@ -0,0 +1,172 @@ +/* +SoLoud audio engine +Copyright (c) 2013-2018 Jari Komppa + +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. +*/ +#ifdef WITH_SDL3 + +#include +#if defined(_MSC_VER) +#define WINDOWS_VERSION +#endif +#include "SDL3/SDL.h" +#include + + +typedef Uint32 (*SDL3_WasInit_t)(Uint32 flags); +typedef int (*SDL3_InitSubSystem_t)(Uint32 flags); +typedef SDL_AudioStream * (*SDL3_OpenAudioDeviceStream_t)( + SDL_AudioDeviceID deviceId, + SDL_AudioSpec const * spec, + SDL_AudioStreamCallback callback, + void * userdata +); + +typedef void (*SDL3_CloseAudioDevice_t)(SDL_AudioDeviceID dev); +typedef bool (*SDL3_PauseAudioStreamDevice_t)(SDL_AudioStream * dev); + +static SDL3_WasInit_t SDL3_WasInit = NULL; +static SDL3_InitSubSystem_t SDL3_InitSubSystem = NULL; +static SDL3_OpenAudioDeviceStream_t SDL3_OpenAudioDeviceStream = NULL; +static SDL3_CloseAudioDevice_t SDL3_CloseAudioDevice = NULL; +static SDL3_PauseAudioStreamDevice_t SDL3_PauseAudioStreamDevice = NULL; + +#ifdef WINDOWS_VERSION +#include + +static HMODULE sdl3_openDll() +{ + HMODULE res = LoadLibraryA("SDL3.dll"); + return res; +} + +static void* sdl3_getDllProc(HMODULE aDllHandle, const char *aProcName) +{ + return (void*)GetProcAddress(aDllHandle, (LPCSTR)aProcName); +} + +#else +#include // dll functions + +static void * sdl3_openDll() +{ + void * res; + res = dlopen("/Library/Frameworks/SDL3.framework/SDL3", RTLD_LAZY); + if (!res) res = dlopen("SDL3.so", RTLD_LAZY); + if (!res) res = dlopen("libSDL3.so", RTLD_LAZY); + return res; +} + +static void* sdl3_getDllProc(void * aLibrary, const char *aProcName) +{ + return dlsym(aLibrary, aProcName); +} + +#endif + +static int sdl3_load_dll() +{ +#ifdef WINDOWS_VERSION + HMODULE dll = NULL; +#else + void * dll = NULL; +#endif + + if (SDL3_OpenAudioDeviceStream != NULL) + { + return 1; + } + + dll = sdl3_openDll(); + + if (dll) + { + SDL3_WasInit = (SDL3_WasInit_t)sdl3_getDllProc(dll, "SDL_WasInit"); + SDL3_InitSubSystem = (SDL3_InitSubSystem_t)sdl3_getDllProc(dll, "SDL_InitSubSystem"); + SDL3_OpenAudioDeviceStream = (SDL3_OpenAudioDeviceStream_t)sdl3_getDllProc(dll, "SDL_OpenAudioDeviceStream"); + SDL3_CloseAudioDevice = (SDL3_CloseAudioDevice_t)sdl3_getDllProc(dll, "SDL_CloseAudioDevice"); + SDL3_PauseAudioStreamDevice = (SDL3_PauseAudioStreamDevice_t)sdl3_getDllProc(dll, "SDL_PauseAudioStreamDevice"); + + if (SDL3_WasInit && + SDL3_InitSubSystem && + SDL3_OpenAudioDeviceStream && + SDL3_CloseAudioDevice && + SDL3_PauseAudioStreamDevice) + { + return 1; + } + } + SDL3_OpenAudioDeviceStream = NULL; + return 0; +} + +int dll_SDL3_found() +{ + return sdl3_load_dll(); +} + +Uint32 dll_SDL3_WasInit(Uint32 flags) +{ + if (SDL3_WasInit) + return SDL3_WasInit(flags); + return 0; +} + +int dll_SDL3_InitSubSystem(Uint32 flags) +{ + if (SDL3_InitSubSystem) + return SDL3_InitSubSystem(flags); + return -1; +} + +SDL_AudioStream * dll_SDL3_OpenAudioDeviceStream( + SDL_AudioDeviceID deviceId, + SDL_AudioSpec const * spec, + SDL_AudioStreamCallback callback, + void * userdata +) +{ + if (SDL3_OpenAudioDeviceStream) + { + return SDL3_OpenAudioDeviceStream( + deviceId, + spec, + callback, + userdata + ); + } + return 0; +} + +void dll_SDL3_CloseAudioDevice (SDL_AudioDeviceID dev) +{ + if (SDL3_CloseAudioDevice) + SDL3_CloseAudioDevice(dev); +} + +bool dll_SDL3_PauseAudioStreamDevice(SDL_AudioStream * dev) +{ + if (SDL3_PauseAudioStreamDevice) + return SDL3_PauseAudioStreamDevice(dev); + return false; +} + +#endif diff --git a/src/backend/sdl3_static/soloud_sdl3_static.cpp b/src/backend/sdl3_static/soloud_sdl3_static.cpp new file mode 100644 index 00000000..2d6a3867 --- /dev/null +++ b/src/backend/sdl3_static/soloud_sdl3_static.cpp @@ -0,0 +1,166 @@ +/* +SoLoud audio engine +Copyright (c) 2013-2015 Jari Komppa + +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. +*/ +#include + +#include "soloud.h" + +#if !defined(WITH_SDL3_STATIC) + +namespace SoLoud +{ + result sdl3static_init(SoLoud::Soloud *aSoloud, unsigned int aFlags, unsigned int aSamplerate, unsigned int aBuffer, void const* clientData) + { + return NOT_IMPLEMENTED; + } +} + +#else + +#include "soloud_backend_data_sdl3.h" +#include "SDL.h" +#include + +namespace SoLoud +{ + static SoLoudBackendDataSdl3 gBackendData{}; + + void soloud_sdl2static_audiomixer(Uint8* stream, void* userdata, int len) + { + SoLoud::Soloud* soloud = (SoLoud::Soloud*)userdata; + if (gBackendData.activeAudioSpec.format == SDL_AUDIO_F32) + { + int samples = len / (gBackendData.activeAudioSpec.channels * sizeof(float)); + soloud->mix((float*)stream, samples); + } + else // assume s16 if not float + { + int samples = len / (gBackendData.activeAudioSpec.channels * sizeof(short)); + soloud->mixSigned16((short*)stream, samples); + } + } + + void soloud_sdl3static_audiomixer(void* userdata, SDL_AudioStream* stream, int additionalAmount, int totalAmount) + { + SoLoud::Soloud* soloud = (SoLoud::Soloud*)userdata; + + if (additionalAmount > 0) + { + Uint8* data = SDL_stack_alloc(Uint8, additionalAmount); + if (data) + { + soloud_sdl2static_audiomixer( + data, + userdata, + additionalAmount + ); + SDL_PutAudioStreamData(stream, data, additionalAmount); + SDL_stack_free(data); + } + } + } + + static void soloud_sdl3static_deinit(SoLoud::Soloud *aSoloud) + { + SDL_CloseAudioDevice(gBackendData.audioDeviceId); + } + + result sdl3static_init(SoLoud::Soloud *aSoloud, unsigned int aFlags, unsigned int aSamplerate, unsigned int aBuffer, unsigned int aChannels, void const* clientData) + { + if (!SDL_WasInit(SDL_INIT_AUDIO)) + { + if (!SDL_InitSubSystem(SDL_INIT_AUDIO)) + { + return UNKNOWN_ERROR; + } + } + + SoLoudClientDataSdl3 const* data = NULL; + if (clientData != NULL) + { + data = static_cast(clientData); + gBackendData.audioDeviceId = data->deviceId; + } + else + { + gBackendData.audioDeviceId = SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK; + } + + SDL_AudioDeviceID const deviceId = gBackendData.audioDeviceId; + SDL_AudioSpec as{}; + as.freq = aSamplerate; + as.format = SDL_AUDIO_F32; + as.channels = (Uint8)aChannels; + + gBackendData.audioStream = SDL_OpenAudioDeviceStream( + gBackendData.audioDeviceId, + &as, + soloud_sdl3static_audiomixer, + static_cast(aSoloud) + ); + + gBackendData.audioDeviceId = SDL_GetAudioStreamDevice(gBackendData.audioStream); + + if (gBackendData.audioDeviceId == 0) + { + as.format = SDL_AUDIO_S16; + gBackendData.audioStream = SDL_OpenAudioDeviceStream( + deviceId, + NULL, + soloud_sdl3static_audiomixer, + static_cast(aSoloud) + ); + + gBackendData.audioDeviceId = SDL_GetAudioStreamDevice(gBackendData.audioStream); + + if (gBackendData.audioDeviceId == 0) + { + return UNKNOWN_ERROR; + } + } + + SDL_GetAudioDeviceFormat( + gBackendData.audioDeviceId, + &gBackendData.activeAudioSpec, + NULL + ); + + aSoloud->postinit_internal( + gBackendData.activeAudioSpec.freq, + aBuffer, + aFlags, + gBackendData.activeAudioSpec.channels + ); + + aSoloud->mBackendCleanupFunc = soloud_sdl3static_deinit; + + //SDL_PauseAudioStreamDevice(gBackendData.audioStream); + aSoloud->mBackendData = &gBackendData; + aSoloud->mBackendString = "SDL3 (dynamic)"; + + SDL_ResumeAudioDevice(SDL_GetAudioStreamDevice(gBackendData.audioStream)); + + return 0; + } +}; +#endif \ No newline at end of file diff --git a/src/core/soloud.cpp b/src/core/soloud.cpp index e2544572..a9b19380 100644 --- a/src/core/soloud.cpp +++ b/src/core/soloud.cpp @@ -41,10 +41,11 @@ freely, subject to the following restrictions: //#define FLOATING_POINT_DEBUG -#if !defined(WITH_SDL2) && !defined(WITH_SDL1) && !defined(WITH_PORTAUDIO) && \ +#if !defined(WITH_SDL3) && !defined(WITH_SDL2) && !defined(WITH_SDL1) && !defined(WITH_PORTAUDIO) && \ !defined(WITH_OPENAL) && !defined(WITH_XAUDIO2) && !defined(WITH_WINMM) && \ !defined(WITH_WASAPI) && !defined(WITH_OSS) && !defined(WITH_SDL1_STATIC) && \ !defined(WITH_SDL2_STATIC) && !defined(WITH_ALSA) && !defined(WITH_OPENSLES) && \ + !defined(WITH_SDL3_STATIC) && \ !defined(WITH_NULL) && !defined(WITH_COREAUDIO) && !defined(WITH_VITA_HOMEBREW) &&\ !defined(WITH_JACK) && !defined(WITH_NOSOUND) && !defined(WITH_MINIAUDIO) #error It appears you haven't enabled any of the back-ends. Please #define one or more of the WITH_ defines (or use premake) ' @@ -204,8 +205,8 @@ namespace SoLoud mAudioThreadMutex = NULL; } - result Soloud::init(unsigned int aFlags, unsigned int aBackend, unsigned int aSamplerate, unsigned int aBufferSize, unsigned int aChannels) - { + result Soloud::init(unsigned int aFlags, unsigned int aBackend, unsigned int aSamplerate, unsigned int aBufferSize, unsigned int aChannels, void const * clientData) + { if (aBackend >= BACKEND_MAX || aChannels == 3 || aChannels == 5 || aChannels == 7 || aChannels > MAX_CHANNELS) return INVALID_PARAMETER; @@ -261,6 +262,52 @@ namespace SoLoud } #endif +#if defined(WITH_SDL3_STATIC) + if (!inited && + (aBackend == Soloud::SDL3 || + aBackend == Soloud::AUTO)) + { + if (aBufferSize == Soloud::AUTO) buffersize = 2048; + + int ret = sdl3static_init(this, aFlags, samplerate, buffersize, aChannels); + if (ret == 0) + { + inited = 1; + mBackendID = Soloud::SDL3; + } + + if (ret != 0 && aBackend != Soloud::AUTO) + return ret; + } +#endif + +#if defined(WITH_SDL3) + if (!inited && + (aBackend == Soloud::SDL3 || + aBackend == Soloud::AUTO)) + { + if (aBufferSize == Soloud::AUTO) buffersize = 2048; + + int ret = sdl3_init( + this, + aFlags, + samplerate, + buffersize, + aChannels, + clientData + ); + + if (ret == 0) + { + inited = 1; + mBackendID = Soloud::SDL3; + } + + if (ret != 0 && aBackend != Soloud::AUTO) + return ret; + } +#endif + #if defined(WITH_SDL2) if (!inited && (aBackend == Soloud::SDL2 || @@ -587,7 +634,6 @@ namespace SoLoud return NOT_IMPLEMENTED; } - void Soloud::postinit_internal(unsigned int aSamplerate, unsigned int aBufferSize, unsigned int aFlags, unsigned int aChannels) { mGlobalVolume = 1; @@ -602,7 +648,7 @@ namespace SoLoud mResampleData = new float*[mMaxActiveVoices * 2]; mResampleDataOwner = new AudioSourceInstance*[mMaxActiveVoices]; mResampleDataBuffer.init(mMaxActiveVoices * 2 * SAMPLE_GRANULARITY * MAX_CHANNELS); - unsigned int i; + unsigned int i; for (i = 0; i < mMaxActiveVoices * 2; i++) mResampleData[i] = mResampleDataBuffer.mData + (SAMPLE_GRANULARITY * MAX_CHANNELS * i); for (i = 0; i < mMaxActiveVoices; i++) @@ -1171,7 +1217,7 @@ namespace SoLoud c += 4; } } - + // If buffer size or samples to read are not divisible by 4, handle leftovers for (j = c; j < aSamplesToRead; j++) { @@ -2192,7 +2238,7 @@ namespace SoLoud if (mActiveVoiceDirty) calcActiveVoices_internal(); - + mixBus_internal(mOutputScratch.mData, aSamples, aStride, mScratch.mData, 0, (float)mSamplerate, mChannels, mResampler); for (i = 0; i < FILTERS_PER_STREAM; i++) @@ -2204,7 +2250,7 @@ namespace SoLoud } unlockAudioMutex_internal(); - + // Note: clipping channels*aStride, not channels*aSamples, so we're possibly clipping some unused data. // The buffers should be large enough for it, we just may do a few bytes of unneccessary work. clip_internal(mOutputScratch, mScratch, aStride, globalVolume[0], globalVolume[1]); @@ -2316,5 +2362,4 @@ namespace SoLoud Thread::unlockMutex(mAudioThreadMutex); } } - }; diff --git a/src/core/soloud_core_setters.cpp b/src/core/soloud_core_setters.cpp index 718ff8ec..7f491580 100644 --- a/src/core/soloud_core_setters.cpp +++ b/src/core/soloud_core_setters.cpp @@ -124,7 +124,7 @@ namespace SoLoud } void Soloud::setChannelVolume(handle aVoiceHandle, unsigned int aChannel, float aVolume) - { + { FOR_ALL_VOICES_PRE if (mVoice[ch]->mChannels > aChannel) { @@ -249,5 +249,4 @@ namespace SoLoud m3dSpeakerPosition[3 * aChannel + 2] = aZ; return SO_NO_ERROR; } - }