diff --git a/src/core/Audio.cpp b/src/core/Audio.cpp new file mode 100644 index 00000000..e9266c5c --- /dev/null +++ b/src/core/Audio.cpp @@ -0,0 +1,83 @@ +#include +#include +#include + +namespace natsukashii::core { +#define AUDIO_SAMPLE_RATE 48000 +#define SYSTEM_SAMPLE_FORMAT AUDIO_F32SYS +#define SYSTEM_SAMPLE_SIZE 4 +#define BYTES_PER_HALF_SECOND ((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* userdata, Uint8* stream, int length) { + int gotten = 0; + LockAudioMutex(); + int available = SDL_AudioStreamAvailable(audioStream); + + if (available > 0) { + gotten = SDL_AudioStreamGet(audioStream, stream, length); + } + UnlockAudioMutex(); + + int gotten_samples = (int)(gotten / sizeof(float)); + auto* out = (float*)stream; + out += gotten_samples; + + for (int i = gotten_samples; i < length / sizeof(float); i++) { + float sample = 0; + *out++ = sample; + } +} + +void InitAudio() { + 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; + + audioDev = SDL_OpenAudioDevice(nullptr, 0, &request, &audioSpec, 0); + + if(!audioDev) { + util::panic("Failed to initialize SDL Audio: {}", SDL_GetError()); + } + + SDL_PauseAudioDevice(audioDev, false); + + audioStreamMutex = SDL_CreateMutex(); + + if(!audioStreamMutex) { + util::panic("Unable to initialize audio mutex: {}", SDL_GetError()); + } +} + +void PushSample(s16 left, s16 right) { + s16 samples[2]{ left, right }; + + int availableBytes = SDL_AudioStreamAvailable(audioStream); + if(availableBytes < BYTES_PER_HALF_SECOND) { + SDL_AudioStreamPut(audioStream, samples, 2 * sizeof(16)); + } +} + +void AdjustSampleRate(int sampleRate) { + LockAudioMutex(); + if(audioStream) SDL_FreeAudioStream(audioStream); + + audioStream = SDL_NewAudioStream(AUDIO_S16SYS, 2, sampleRate, SYSTEM_SAMPLE_FORMAT, 2, AUDIO_SAMPLE_RATE); + UnlockAudioMutex(); +} + +} \ No newline at end of file diff --git a/src/core/Audio.hpp b/src/core/Audio.hpp new file mode 100644 index 00000000..38acd696 --- /dev/null +++ b/src/core/Audio.hpp @@ -0,0 +1,8 @@ +#pragma once +#include + +namespace natsukashii::core { +void PushSample(s16, s16); +void InitAudio(); +void AdjustSampleRate(int); +} \ No newline at end of file diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 6ab671a2..15833c4e 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -10,6 +10,6 @@ add_library(cores Scheduler.cpp Scheduler.hpp common.hpp - util.hpp) + util.hpp Audio.hpp Audio.cpp) target_include_directories(cores PUBLIC . ../../external) target_link_libraries(cores PUBLIC gb n64) diff --git a/src/core/n64/core/MMIO.hpp b/src/core/n64/core/MMIO.hpp index fad4eec4..38a7de86 100644 --- a/src/core/n64/core/MMIO.hpp +++ b/src/core/n64/core/MMIO.hpp @@ -1,6 +1,7 @@ #pragma once #include #include +#include #include #include @@ -12,6 +13,7 @@ struct MMIO { MMIO() = default; VI vi; MI mi; + AI ai; RSP rsp; RDP rdp; diff --git a/src/core/n64/core/RDP.cpp b/src/core/n64/core/RDP.cpp index 517c0b15..fe3805d8 100644 --- a/src/core/n64/core/RDP.cpp +++ b/src/core/n64/core/RDP.cpp @@ -92,7 +92,7 @@ void RDP::RunCommand(MI& mi, Registers& regs, RSP& rsp) { if (cmd == 0x29) { OnFullSync(); - InterruptRaise(mi, regs, InterruptType::DP); + InterruptRaise(mi, regs, Interrupt::DP); } buf_index += cmd_len; diff --git a/src/core/n64/core/RSP.cpp b/src/core/n64/core/RSP.cpp index 2888f85e..63354243 100644 --- a/src/core/n64/core/RSP.cpp +++ b/src/core/n64/core/RSP.cpp @@ -78,8 +78,8 @@ void RSP::Write(Mem& mem, Registers& regs, u32 addr, u32 value) { write.raw = value; CLEAR_SET(spStatus.halt, write.clearHalt, write.setHalt); CLEAR_SET(spStatus.broke, write.clearBroke, false); - if(write.clearIntr) InterruptLower(mi, regs, InterruptType::SP); - if(write.setIntr) InterruptRaise(mi, regs, InterruptType::SP); + if(write.clearIntr) InterruptLower(mi, regs, Interrupt::SP); + if(write.setIntr) InterruptRaise(mi, regs, Interrupt::SP); CLEAR_SET(spStatus.singleStep, write.clearSstep, write.setSstep); CLEAR_SET(spStatus.interruptOnBreak, write.clearIntrOnBreak, write.setIntrOnBreak); CLEAR_SET(spStatus.signal0Set, write.clearSignal0, write.setSignal0); diff --git a/src/core/n64/core/mmio/AI.cpp b/src/core/n64/core/mmio/AI.cpp index 1f312ac2..c31a22a7 100644 --- a/src/core/n64/core/mmio/AI.cpp +++ b/src/core/n64/core/mmio/AI.cpp @@ -2,6 +2,7 @@ #include #include #include +#include namespace natsukashii::n64::core { auto AI::Read(u32 addr) const -> u32 { @@ -23,6 +24,8 @@ auto AI::Read(u32 addr) const -> u32 { #define max(x, y) ((x) > (y) ? (x) : (y)) +using namespace natsukashii::core; + void AI::Write(Mem& mem, Registers& regs, u32 addr, u32 val) { switch(addr) { case 0x04500000: diff --git a/src/core/n64/core/mmio/MI.cpp b/src/core/n64/core/mmio/MI.cpp index 1b6af136..4e3b2363 100644 --- a/src/core/n64/core/mmio/MI.cpp +++ b/src/core/n64/core/mmio/MI.cpp @@ -18,7 +18,7 @@ auto MI::Read(u32 paddr) const -> u32 { case 0x4: return MI_VERSION_REG; case 0x8: return miIntr.raw & 0x3F; case 0xC: return miIntrMask.raw & 0x3F; - default: util::panic("Unhandled MI[%08X] read\n", paddr); + default: util::panic("Unhandled MI[{:08X}] read\n", paddr); } return 0; } @@ -45,7 +45,7 @@ void MI::Write(Registers& regs, u32 paddr, u32 val) { } if (val & (1 << 11)) { - InterruptLower(*this, regs, InterruptType::DP); + InterruptLower(*this, regs, Interrupt::DP); } if (val & (1 << 12)) { @@ -74,7 +74,7 @@ void MI::Write(Registers& regs, u32 paddr, u32 val) { UpdateInterrupt(*this, regs); break; default: - util::panic("Unhandled MI[%08X] write (%08X)\n", val, paddr); + util::panic("Unhandled MI[{:08X}] write ({:08X})\n", val, paddr); } } } \ No newline at end of file diff --git a/src/core/n64/core/mmio/VI.cpp b/src/core/n64/core/mmio/VI.cpp index 1e01da24..a7afa0b1 100644 --- a/src/core/n64/core/mmio/VI.cpp +++ b/src/core/n64/core/mmio/VI.cpp @@ -60,7 +60,7 @@ void VI::Write(MI& mi, Registers& regs, u32 paddr, u32 val) { intr = val & 0x3FF; } break; case 0x04400010: - InterruptLower(mi, regs, InterruptType::VI); + InterruptLower(mi, regs, Interrupt::VI); break; case 0x04400014: burst.raw = val; break; case 0x04400018: {