N64 Audio integration

This commit is contained in:
CocoSimone
2022-07-03 13:44:16 +02:00
parent 15746b8fb8
commit 80e9bf67e5
9 changed files with 104 additions and 8 deletions

83
src/core/Audio.cpp Normal file
View File

@@ -0,0 +1,83 @@
#include <Audio.hpp>
#include <SDL2/SDL.h>
#include <util.hpp>
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();
}
}

8
src/core/Audio.hpp Normal file
View File

@@ -0,0 +1,8 @@
#pragma once
#include <common.hpp>
namespace natsukashii::core {
void PushSample(s16, s16);
void InitAudio();
void AdjustSampleRate(int);
}

View File

@@ -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)

View File

@@ -1,6 +1,7 @@
#pragma once
#include <n64/core/mmio/VI.hpp>
#include <n64/core/mmio/MI.hpp>
#include <n64/core/mmio/AI.hpp>
#include <n64/core/RSP.hpp>
#include <n64/core/RDP.hpp>
@@ -12,6 +13,7 @@ struct MMIO {
MMIO() = default;
VI vi;
MI mi;
AI ai;
RSP rsp;
RDP rdp;

View File

@@ -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;

View File

@@ -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);

View File

@@ -2,6 +2,7 @@
#include <util.hpp>
#include <n64/core/Mem.hpp>
#include <n64/core/cpu/Registers.hpp>
#include <Audio.hpp>
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:

View File

@@ -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);
}
}
}

View File

@@ -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: {