diff --git a/src/backend/core/mmio/AI.cpp b/src/backend/core/mmio/AI.cpp index 1e64dd52..b26fd80d 100644 --- a/src/backend/core/mmio/AI.cpp +++ b/src/backend/core/mmio/AI.cpp @@ -2,7 +2,6 @@ #include #include #include -#include namespace n64 { void AI::Reset() { @@ -56,12 +55,12 @@ void AI::Write(Mem& mem, Registers& regs, u32 addr, u32 val) { InterruptLower(mem.mmio.mi, regs, Interrupt::AI); break; case 0x04500010: { - u32 old_dac_freq = dac.freq; + u32 oldDacFreq = dac.freq; dacRate = val & 0x3FFF; dac.freq = std::max(1u, GetVideoFrequency(mem.IsROMPAL()) / (dacRate + 1)); dac.period = N64_CPU_FREQ / dac.freq; - if(old_dac_freq != dac.freq) { - AdjustSampleRate(dac.freq); + if(oldDacFreq != dac.freq) { + device.AdjustSampleRate(dac.freq); } } break; case 0x04500014: @@ -87,7 +86,7 @@ void AI::Step(Mem& mem, Registers& regs, u32 cpuCycles, float volumeL, float vol s16 r = s16(data); if(volumeR > 0 && volumeL > 0) { - PushSample((float) l / INT16_MAX, volumeL, (float) r / INT16_MAX, volumeR); + device.PushSample((float) l / INT16_MAX, volumeL, (float) r / INT16_MAX, volumeR); } u32 addrLo = (dmaAddr[0] + 4) & 0x1FFF; diff --git a/src/backend/core/mmio/AI.hpp b/src/backend/core/mmio/AI.hpp index bd9dc4d8..f7d5ed0a 100644 --- a/src/backend/core/mmio/AI.hpp +++ b/src/backend/core/mmio/AI.hpp @@ -1,6 +1,7 @@ #pragma once #include #include +#include "Audio.hpp" namespace n64 { struct Mem; @@ -20,6 +21,7 @@ struct AI { u32 dmaAddr[2]{}; bool dmaAddrCarry{}; u32 cycles{}; + AudioDevice device; struct { u32 freq{44100}; diff --git a/src/backend/core/mmio/Audio.cpp b/src/backend/core/mmio/Audio.cpp index 16f2af16..40bcaa5d 100644 --- a/src/backend/core/mmio/Audio.cpp +++ b/src/backend/core/mmio/Audio.cpp @@ -1,6 +1,5 @@ #include #include -#include namespace n64 { #define AUDIO_SAMPLE_RATE 44100 @@ -8,56 +7,47 @@ namespace n64 { #define SYSTEM_SAMPLE_SIZE 4 #define BYTES_PER_HALF_SECOND (((float)AUDIO_SAMPLE_RATE / 2) * SYSTEM_SAMPLE_SIZE) -static SDL_AudioStream* audioStream = nullptr; -SDL_mutex* audioStreamMutex; -SDL_AudioSpec audioSpec; -SDL_AudioSpec request; -SDL_AudioDeviceID audioDev{}; - -#define LockAudioMutex() SDL_LockMutex(audioStreamMutex) -#define UnlockAudioMutex() SDL_UnlockMutex(audioStreamMutex) - -void audioCallback(void*, Uint8* stream, int length) { +void audioCallback(void* user, Uint8* stream, int length) { + auto audioDevice = (AudioDevice*)user; int gotten = 0; - LockAudioMutex(); - int available = SDL_AudioStreamAvailable(audioStream); + audioDevice->LockMutex(); + int available = SDL_AudioStreamAvailable(audioDevice->GetStream()); if (available > 0) { - gotten = SDL_AudioStreamGet(audioStream, stream, length); + gotten = SDL_AudioStreamGet(audioDevice->GetStream(), stream, length); } - UnlockAudioMutex(); + audioDevice->UnlockMutex(); - int gotten_samples = (int)(gotten / sizeof(float)); + int gottenSamples = (int)(gotten / sizeof(float)); auto* out = (float*)stream; - out += gotten_samples; + out += gottenSamples; - for (int i = gotten_samples; i < length / sizeof(float); i++) { + for (int i = gottenSamples; i < length / sizeof(float); i++) { float sample = 0; *out++ = sample; } } -void InitAudio() { +AudioDevice::AudioDevice() { SDL_InitSubSystem(SDL_INIT_AUDIO); AdjustSampleRate(AUDIO_SAMPLE_RATE); - memset(&request, 0, sizeof(request)); request.freq = AUDIO_SAMPLE_RATE; request.format = SYSTEM_SAMPLE_FORMAT; request.channels = 2; request.samples = 1024; request.callback = audioCallback; - request.userdata = nullptr; + request.userdata = (void*)this; - if(!audioDev) { - audioDev = SDL_OpenAudioDevice(nullptr, 0, &request, &audioSpec, 0); + if(!handle) { + handle = SDL_OpenAudioDevice(nullptr, 0, &request, &audioSpec, 0); } - if(!audioDev) { + if(!handle) { Util::panic("Failed to initialize SDL Audio: {}", SDL_GetError()); } - SDL_PauseAudioDevice(audioDev, false); + SDL_PauseAudioDevice(handle, false); audioStreamMutex = SDL_CreateMutex(); @@ -66,7 +56,7 @@ void InitAudio() { } } -void PushSample(float left, float volumeL, float right, float volumeR) { +void AudioDevice::PushSample(float left, float volumeL, float right, float volumeR) { float adjustedL = left * volumeL; float adjustedR = right * volumeR; float samples[2]{ adjustedL, adjustedR }; @@ -77,12 +67,11 @@ void PushSample(float left, float volumeL, float right, float volumeR) { } } -void AdjustSampleRate(int sampleRate) { - LockAudioMutex(); +void AudioDevice::AdjustSampleRate(int sampleRate) { + LockMutex(); if(audioStream) SDL_FreeAudioStream(audioStream); audioStream = SDL_NewAudioStream(AUDIO_F32SYS, 2, sampleRate, SYSTEM_SAMPLE_FORMAT, 2, AUDIO_SAMPLE_RATE); - UnlockAudioMutex(); + UnlockMutex(); } - } \ No newline at end of file diff --git a/src/backend/core/mmio/Audio.hpp b/src/backend/core/mmio/Audio.hpp index 70b466b1..177ab7cc 100644 --- a/src/backend/core/mmio/Audio.hpp +++ b/src/backend/core/mmio/Audio.hpp @@ -1,8 +1,31 @@ #pragma once #include +#include namespace n64 { -void PushSample(float, float, float, float); -void InitAudio(); -void AdjustSampleRate(int); +struct AudioDevice { + AudioDevice(); + ~AudioDevice() { + SDL_FreeAudioStream(audioStream); + SDL_DestroyMutex(audioStreamMutex); + } + + void PushSample(float, float, float, float); + void AdjustSampleRate(int); + void LockMutex() { + SDL_LockMutex(audioStreamMutex); + } + void UnlockMutex() { + SDL_UnlockMutex(audioStreamMutex); + } + + SDL_AudioStream* GetStream() { return audioStream; } +private: + SDL_AudioStream* audioStream = nullptr; + SDL_mutex* audioStreamMutex = nullptr; + SDL_AudioSpec audioSpec{}; + SDL_AudioSpec request{}; + SDL_AudioDeviceID handle{}; +}; + } \ No newline at end of file diff --git a/src/frontend/EmuThread.cpp b/src/frontend/EmuThread.cpp index 2d439b50..6b03cb54 100644 --- a/src/frontend/EmuThread.cpp +++ b/src/frontend/EmuThread.cpp @@ -9,7 +9,7 @@ EmuThread::EmuThread(std::unique_ptr&& instance, std::unique_ [[noreturn]] void EmuThread::run() noexcept { LoadWSIPlatform(instance.get(), std::move(wsiPlatform), std::move(windowInfo)); LoadParallelRDP(core->cpu->mem.GetRDRAM()); - n64::InitAudio(); + while (true) { if (!core->pause) { core->Run(settings->getVolumeL(), settings->getVolumeR());