#include "dusk/audio/DuskAudioSystem.h" #include #include #include #include #include #include #include "JSystem/JAudio2/JASAiCtrl.h" #include "JSystem/JAudio2/JASChannel.h" #include "JSystem/JAudio2/JASCriticalSection.h" #include "JSystem/JAudio2/JASDSPChannel.h" #include "JSystem/JAudio2/JASHeapCtrl.h" #include "DuskDsp.hpp" #include "JSystem/JAudio2/JASAudioThread.h" // #define DUSK_DUMP_AUDIO using namespace dusk::audio; static OutputSubframe OutBuffer; static std::array OutInterleaveBuffer; static SDL_AudioStream* PlaybackStream; /** * SDL audiostream callback to trigger rendering of new audio data. */ static void SDLCALL GetNewAudio( void*, SDL_AudioStream*, int needed, int); /** * Render an entire new frame of audio and output it to SDL3. * Note: "audio frames" are unrelated to video frames. * @return Amount of audio samples rendered. */ static int RenderNewAudioFrame(); /** * Render an audio subframe and output it to SDL3. */ static void RenderAudioSubframe(); static void InitSDL3Output() { SDL_Init(SDL_INIT_AUDIO); constexpr SDL_AudioSpec spec = { SDL_AUDIO_F32, 2, SampleRate, }; PlaybackStream = SDL_OpenAudioDeviceStream( SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &spec, &GetNewAudio, nullptr); } void dusk::audio::Initialize() { InitSDL3Output(); DspInit(); JASDsp::initBuffer(); JASDSPChannel::initAll(); JASPoolAllocObject_MultiThreaded::newMemPool(0x48); SDL_ResumeAudioStreamDevice(PlaybackStream); } void SDLCALL GetNewAudio( void*, SDL_AudioStream*, int needed, int) { while (needed > 0) { const int rendered = RenderNewAudioFrame(); needed -= rendered; } } #if defined(DUSK_DUMP_AUDIO) static std::ofstream outRaw("guh.raw", std::ios_base::out | std::ios_base::binary); #endif int RenderNewAudioFrame() { JASCriticalSection section; const u32 countSubframes = JASDriver::getSubFrames(); JASAudioThread::setDSPSyncCount(countSubframes); for (u32 i = 0; i < countSubframes; i++) { RenderAudioSubframe(); JASAudioThread::snIntCount -= 1; } #if defined(DUSK_DUMP_AUDIO) outRaw.flush(); #endif return static_cast(countSubframes) * DSP_SUBFRAME_SIZE; } static void InterleaveOutputData(const OutputSubframe& data, std::span target) { assert(target.size() >= data.channels[0].size() * OutputSubframe::NUM_CHANNELS); size_t outPos = 0; for (size_t inPos = 0; inPos < data.channels[0].size(); inPos++) { for (size_t channelIdx = 0; channelIdx < OutputSubframe::NUM_CHANNELS; channelIdx++) { target[outPos++] = data.channels[channelIdx][inPos]; } } } void RenderAudioSubframe() { OutBuffer = {}; JASDriver::updateDSP(); DspRender(OutBuffer); InterleaveOutputData(OutBuffer, OutInterleaveBuffer); #if defined(DUSK_DUMP_AUDIO) outRaw.write((const char*)OutInterleaveBuffer.data(), sizeof(OutInterleaveBuffer)); #endif SDL_PutAudioStreamData(PlaybackStream, &OutInterleaveBuffer, sizeof(OutInterleaveBuffer)); }