mirror of
https://github.com/jorio/Pomme.git
synced 2025-08-07 05:26:45 +00:00
Port sound mixer and input to SDL3
This commit is contained in:
@@ -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)
|
||||||
|
@@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
Reference in New Issue
Block a user