From 5eaec7360b85d2b3f053c2a78f142a9958f489c0 Mon Sep 17 00:00:00 2001 From: PJB3005 Date: Sat, 14 Mar 2026 15:50:39 +0100 Subject: [PATCH] Resample audio with SDL3 --- src/dusk/audio/DuskAudioSystem.cpp | 3 +- src/dusk/audio/DuskDsp.cpp | 90 +++++++++++++++++++++++------- src/dusk/audio/DuskDsp.hpp | 6 ++ 3 files changed, 78 insertions(+), 21 deletions(-) diff --git a/src/dusk/audio/DuskAudioSystem.cpp b/src/dusk/audio/DuskAudioSystem.cpp index 191df90686..9b089eb807 100644 --- a/src/dusk/audio/DuskAudioSystem.cpp +++ b/src/dusk/audio/DuskAudioSystem.cpp @@ -35,7 +35,7 @@ static void InitSDL3Output() { constexpr SDL_AudioSpec spec = { SDL_AUDIO_S16, 1, - 32000, + SampleRate, }; PlaybackStream = SDL_OpenAudioDeviceStream( SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, @@ -46,6 +46,7 @@ static void InitSDL3Output() { void dusk::audio::Initialize() { InitSDL3Output(); + DspInit(); JASDsp::initBuffer(); JASDSPChannel::initAll(); diff --git a/src/dusk/audio/DuskDsp.cpp b/src/dusk/audio/DuskDsp.cpp index cb2c01d1cb..5b4c5d0730 100644 --- a/src/dusk/audio/DuskDsp.cpp +++ b/src/dusk/audio/DuskDsp.cpp @@ -5,7 +5,6 @@ #include #include -#include #include "Adpcm.hpp" #include "global.h" @@ -58,9 +57,18 @@ static void RenderChannel( ChannelAuxData& channelAux, DspSubframe& subframe); -static void ResetChannel(JASDsp::TChannel& channel) { +static void ResetChannel(JASDsp::TChannel& channel, const ChannelAuxData& aux) { channel.mSamplesLeft = channel.mEndSample - channel.mSamplePosition; + const SDL_AudioSpec spec = { + SDL_AUDIO_S16, + 1, + static_cast(static_cast(SampleRate) * channel.mPitch / 4096) + }; + + SDL_ClearAudioStream(aux.resampleStream); + SDL_SetAudioStreamFormat(aux.resampleStream, &spec, nullptr); + channel.mResetFlag = false; } @@ -92,13 +100,21 @@ void dusk::audio::DspRender(DspSubframe& subframe) { } } -static void RenderChannel( - JASDsp::TChannel& channel, - ChannelAuxData& channelAux, - DspSubframe& subframe) { - if (channel.mResetFlag) { - ResetChannel(channel); - } +static void SDLCALL ReadChannelSamples( + void *userdata, + SDL_AudioStream *stream, + int additional_amount, + int) { + + const auto index = static_cast(reinterpret_cast(userdata)); + auto& channel = JASDsp::CH_BUF[index]; + auto& aux = ChannelAux[index]; + + additional_amount = ALIGN_NEXT(additional_amount, channel.mSamplesPerBlock); + + int requestedSize = static_cast(sizeof(s16) * additional_amount); + auto requested = static_cast(alloca(requestedSize)); + memset(requested, 0, requestedSize); auto aramBase = static_cast(ARGetStorageAddress()) + channel.mWaveAramAddress; @@ -107,15 +123,15 @@ static void RenderChannel( auto curSamplePosition = channel.mEndSample - channel.mSamplesLeft; auto dataPosition = ConvertSamplesToDataLength(channel, curSamplePosition); - u32 renderSamples = std::min(channel.mSamplesLeft, static_cast(DSP_SUBFRAME_SIZE)); + u32 renderSamples = std::min(channel.mSamplesLeft, static_cast(additional_amount)); Adpcm4ToPcm16( aramBase + dataPosition, ConvertSamplesToDataLength(channel, renderSamples), - subframe.data(), + requested, renderSamples, - channelAux.hist1, - channelAux.hist0); + aux.hist1, + aux.hist0); channel.mSamplesLeft -= renderSamples; channel.mSamplePosition += renderSamples; @@ -135,16 +151,50 @@ static void RenderChannel( Adpcm4ToPcm16( aramBase + dataPosition, - ConvertSamplesToDataLength(channel, DSP_SUBFRAME_SIZE - renderSamples), - subframe.data() + renderSamples, - subframe.size() - renderSamples, - channelAux.hist1, - channelAux.hist0); + ConvertSamplesToDataLength(channel, additional_amount - renderSamples), + requested + renderSamples, + additional_amount - renderSamples, + aux.hist1, + aux.hist0); - channel.mSamplesLeft -= (DSP_SUBFRAME_SIZE - renderSamples); - channel.mSamplePosition += (DSP_SUBFRAME_SIZE - renderSamples); + channel.mSamplesLeft -= (additional_amount - renderSamples); + channel.mSamplePosition += (additional_amount - renderSamples); } channel.mAramStreamPosition = channel.mWaveAramAddress + ConvertSamplesToDataLength(channel, channel.mSamplePosition); + + SDL_PutAudioStreamData(stream, requested, requestedSize); +} + +static void RenderChannel( + JASDsp::TChannel& channel, + ChannelAuxData& channelAux, + DspSubframe& subframe) { + if (channel.mResetFlag) { + ResetChannel(channel, channelAux); + } + + SDL_GetAudioStreamData( + channelAux.resampleStream, + subframe.data(), + static_cast(subframe.size() * sizeof(s16))); +} + +void dusk::audio::DspInit() { + constexpr SDL_AudioSpec spec = { + SDL_AUDIO_S16, + 1, + SampleRate + }; + + for (int i = 0; i < DSP_CHANNELS; i++) { + auto& aux = ChannelAux[i]; + aux.resampleStream = SDL_CreateAudioStream(&spec, &spec); + + SDL_SetAudioStreamGetCallback( + aux.resampleStream, + ReadChannelSamples, + reinterpret_cast(i)); + } } diff --git a/src/dusk/audio/DuskDsp.hpp b/src/dusk/audio/DuskDsp.hpp index a8013d6669..186f7de677 100644 --- a/src/dusk/audio/DuskDsp.hpp +++ b/src/dusk/audio/DuskDsp.hpp @@ -4,15 +4,21 @@ #include +#include "SDL3/SDL_audio.h" + namespace dusk::audio { + constexpr int SampleRate = 32000; + struct ChannelAuxData { s16 hist1; s16 hist0; + SDL_AudioStream* resampleStream; }; extern ChannelAuxData ChannelAux[DSP_CHANNELS]; using DspSubframe = std::array; + void DspInit(); void DspRender(DspSubframe& subframe); }