Port sound mixer and input to SDL3

This commit is contained in:
Iliyas Jorio
2025-01-29 21:33:56 +01:00
parent 1acfd09704
commit ced44f27ee
3 changed files with 77 additions and 41 deletions

View File

@@ -120,16 +120,16 @@ endif()
add_library(${PROJECT_NAME} ${POMME_SOURCES}) add_library(${PROJECT_NAME} ${POMME_SOURCES})
find_package(SDL2 REQUIRED) # Input and SoundManager require SDL3.
# Linking with SDL3 will also expose its include directory to us.
if (NOT POMME_NO_INPUT OR NOT POMME_NO_SOUND_MIXER)
find_package(SDL3 REQUIRED)
target_link_libraries(${PROJECT_NAME} PUBLIC SDL3::SDL3)
endif()
add_compile_definitions( add_compile_definitions("$<$<CONFIG:DEBUG>:_DEBUG>")
"$<$<CONFIG:DEBUG>:_DEBUG>"
)
target_include_directories(${PROJECT_NAME} PRIVATE target_include_directories(${PROJECT_NAME} PRIVATE ${POMME_SRCDIR})
${SDL2_INCLUDE_DIRS}
${POMME_SRCDIR}
)
if(MSVC) if(MSVC)
# By default, MSVC may add /EHsc to CMAKE_CXX_FLAGS, which we don't want (we use /EHs below) # By default, MSVC may add /EHsc to CMAKE_CXX_FLAGS, which we don't want (we use /EHs below)

View File

@@ -3,8 +3,8 @@
#include "Pomme.h" #include "Pomme.h"
#include "PommeInput.h" #include "PommeInput.h"
#include <SDL_events.h> #include <SDL3/SDL_events.h>
#include <SDL_keyboard.h> #include <SDL3/SDL_keyboard.h>
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Input // Input
@@ -157,7 +157,7 @@ void GetKeys(KeyMap km)
SDL_PumpEvents(); SDL_PumpEvents();
int numkeys = 0; int numkeys = 0;
const UInt8* keystate = SDL_GetKeyboardState(&numkeys); const bool* keystate = SDL_GetKeyboardState(&numkeys);
numkeys = std::min((int) sizeof(scancodeLookupTable), numkeys); numkeys = std::min((int) sizeof(scancodeLookupTable), numkeys);
@@ -181,11 +181,11 @@ void GetKeys(KeyMap km)
void GetMouse(Point* mouseLoc) void GetMouse(Point* mouseLoc)
{ {
int x; float x;
int y; float y;
SDL_GetMouseState(&x, &y); SDL_GetMouseState(&x, &y);
mouseLoc->h = x; mouseLoc->h = (int) x;
mouseLoc->v = y; mouseLoc->v = (int) y;
} }
Boolean Button(void) Boolean Button(void)
@@ -198,17 +198,17 @@ Boolean Button(void)
void InitCursor() void InitCursor()
{ {
SDL_ShowCursor(1); SDL_ShowCursor();
} }
void HideCursor() void HideCursor()
{ {
SDL_ShowCursor(0); SDL_HideCursor();
} }
void ShowCursor() void ShowCursor()
{ {
SDL_ShowCursor(1); SDL_ShowCursor();
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------

View File

@@ -24,8 +24,9 @@
#include "cmixer.h" #include "cmixer.h"
#include "Utilities/structpack.h" #include "Utilities/structpack.h"
#include <SDL.h> #include <SDL3/SDL.h>
#include <cstring>
#include <vector> #include <vector>
#include <fstream> #include <fstream>
#include <list> #include <list>
@@ -50,16 +51,17 @@ using namespace cmixer;
static struct Mixer static struct Mixer
{ {
SDL_mutex* sdlAudioMutex; SDL_Mutex* sdlAudioMutex;
std::list<Source*> sources; // Linked list of active (playing) sources std::list<Source*> sources; // Linked list of active (playing) sources
int32_t pcmmixbuf[BUFFER_SIZE]; // Internal master buffer int32_t pcmmixbuf[BUFFER_SIZE]; // Internal master buffer
int16_t pcmclipbuf[BUFFER_SIZE]; // Internal clip buffer
int samplerate; // Master samplerate int samplerate; // Master samplerate
int gain; // Master gain (fixed point) int gain; // Master gain (fixed point)
void Init(int samplerate); void Init(int samplerate);
void Process(int16_t* dst, int len); void Process(SDL_AudioStream* stream, int len);
void Lock(); void Lock();
@@ -74,39 +76,71 @@ static struct Mixer
static bool sdlAudioSubSystemInited = false; static bool sdlAudioSubSystemInited = false;
static SDL_AudioDeviceID sdlDeviceID = 0; static SDL_AudioDeviceID sdlDeviceID = 0;
static void SDLCALL AudioCallback(void *userData, SDL_AudioStream *stream, int additionalAmount, int totalAmount)
{
(void) totalAmount;
(void) userData;
// Calculate a little more audio here, write it to `stream`
if (additionalAmount > 0)
{
gMixer.Process(stream, additionalAmount / 2);
}
}
// SDL2 used to offer SDL_AUDIO_ALLOW_FREQUENCY_CHANGE to avoid crackles and
// pops if the hardware doesn't work at the exact frequency we've asked for
// (typically we'd ask for 44100 and get back 48000).
// I couldn't find an equivalent to SDL_AUDIO_ALLOW_FREQUENCY_CHANGE in SDL3.
// So, use this function before opening the audio device to query the hardware
// for its preferred frequency (sample rate).
static int GetHardwareFrequency(void)
{
SDL_AudioStream* stream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, NULL, NULL, NULL);
if (!stream)
throw std::runtime_error(SDL_GetError());
SDL_AudioSpec spec;
bool success = SDL_GetAudioStreamFormat(stream, NULL, &spec);
if (!success)
throw std::runtime_error(SDL_GetError());
sdlDeviceID = SDL_GetAudioStreamDevice(stream);
if (!sdlDeviceID)
throw std::runtime_error("invalid audio stream device");
SDL_CloseAudioDevice(sdlDeviceID);
return spec.freq;
}
void cmixer::InitWithSDL() void cmixer::InitWithSDL()
{ {
if (sdlAudioSubSystemInited) if (sdlAudioSubSystemInited)
throw std::runtime_error("SDL audio subsystem already inited"); throw std::runtime_error("SDL audio subsystem already inited");
if (0 != SDL_InitSubSystem(SDL_INIT_AUDIO)) if (!SDL_InitSubSystem(SDL_INIT_AUDIO))
throw std::runtime_error("couldn't init SDL audio subsystem"); throw std::runtime_error("couldn't init SDL audio subsystem");
sdlAudioSubSystemInited = true; sdlAudioSubSystemInited = true;
// Init SDL audio // Init SDL audio
SDL_AudioSpec fmt = {}; SDL_AudioSpec spec = {.format=SDL_AUDIO_S16, .channels=2, .freq=GetHardwareFrequency()};
fmt.freq = 44100;
fmt.format = AUDIO_S16SYS;
fmt.channels = 2;
fmt.samples = 1024;
fmt.callback = [](void* udata, Uint8* stream, int size)
{
(void) udata;
gMixer.Process((int16_t*) stream, size / 2);
};
SDL_AudioSpec got; SDL_AudioStream* stream = SDL_OpenAudioDeviceStream(
sdlDeviceID = SDL_OpenAudioDevice(NULL, 0, &fmt, &got, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE); SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK,
if (!sdlDeviceID) &spec,
AudioCallback,
nullptr);
if (!stream)
throw std::runtime_error(SDL_GetError()); throw std::runtime_error(SDL_GetError());
sdlDeviceID = SDL_GetAudioStreamDevice(stream);
// Init library // Init library
gMixer.Init(got.freq); gMixer.Init(spec.freq);
gMixer.SetMasterGain(0.5); gMixer.SetMasterGain(0.5);
// Start audio // Start audio
SDL_PauseAudioDevice(sdlDeviceID, 0); SDL_ResumeAudioDevice(sdlDeviceID);
} }
void cmixer::ShutdownWithSDL() void cmixer::ShutdownWithSDL()
@@ -166,13 +200,12 @@ void Mixer::SetMasterGain(double newGain)
gain = (int) FX_FROM_FLOAT(newGain); gain = (int) FX_FROM_FLOAT(newGain);
} }
void Mixer::Process(int16_t* dst, int len) void Mixer::Process(SDL_AudioStream* stream, int len)
{ {
// Process in chunks of BUFFER_SIZE if `len` is larger than BUFFER_SIZE // Process in chunks of BUFFER_SIZE if `len` is larger than BUFFER_SIZE
while (len > BUFFER_SIZE) while (len > BUFFER_SIZE)
{ {
Process(dst, BUFFER_SIZE); Process(stream, BUFFER_SIZE);
dst += BUFFER_SIZE;
len -= BUFFER_SIZE; len -= BUFFER_SIZE;
} }
@@ -202,8 +235,11 @@ void Mixer::Process(int16_t* dst, int len)
for (int i = 0; i < len; i++) for (int i = 0; i < len; i++)
{ {
int x = (pcmmixbuf[i] * gain) >> FX_BITS; int x = (pcmmixbuf[i] * gain) >> FX_BITS;
dst[i] = CLAMP(x, -32768, 32767); pcmclipbuf[i] = CLAMP(x, -32768, 32767);
} }
// Feed SDL audio stream
SDL_PutAudioStreamData(stream, pcmclipbuf, len * 2);
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------