Refactor Audio
This commit is contained in:
@@ -2,7 +2,6 @@
|
|||||||
#include <log.hpp>
|
#include <log.hpp>
|
||||||
#include <core/Mem.hpp>
|
#include <core/Mem.hpp>
|
||||||
#include <core/registers/Registers.hpp>
|
#include <core/registers/Registers.hpp>
|
||||||
#include <Audio.hpp>
|
|
||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
void AI::Reset() {
|
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);
|
InterruptLower(mem.mmio.mi, regs, Interrupt::AI);
|
||||||
break;
|
break;
|
||||||
case 0x04500010: {
|
case 0x04500010: {
|
||||||
u32 old_dac_freq = dac.freq;
|
u32 oldDacFreq = dac.freq;
|
||||||
dacRate = val & 0x3FFF;
|
dacRate = val & 0x3FFF;
|
||||||
dac.freq = std::max(1u, GetVideoFrequency(mem.IsROMPAL()) / (dacRate + 1));
|
dac.freq = std::max(1u, GetVideoFrequency(mem.IsROMPAL()) / (dacRate + 1));
|
||||||
dac.period = N64_CPU_FREQ / dac.freq;
|
dac.period = N64_CPU_FREQ / dac.freq;
|
||||||
if(old_dac_freq != dac.freq) {
|
if(oldDacFreq != dac.freq) {
|
||||||
AdjustSampleRate(dac.freq);
|
device.AdjustSampleRate(dac.freq);
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case 0x04500014:
|
case 0x04500014:
|
||||||
@@ -87,7 +86,7 @@ void AI::Step(Mem& mem, Registers& regs, u32 cpuCycles, float volumeL, float vol
|
|||||||
s16 r = s16(data);
|
s16 r = s16(data);
|
||||||
|
|
||||||
if(volumeR > 0 && volumeL > 0) {
|
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;
|
u32 addrLo = (dmaAddr[0] + 4) & 0x1FFF;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <common.hpp>
|
#include <common.hpp>
|
||||||
#include <core/mmio/Interrupt.hpp>
|
#include <core/mmio/Interrupt.hpp>
|
||||||
|
#include "Audio.hpp"
|
||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
struct Mem;
|
struct Mem;
|
||||||
@@ -20,6 +21,7 @@ struct AI {
|
|||||||
u32 dmaAddr[2]{};
|
u32 dmaAddr[2]{};
|
||||||
bool dmaAddrCarry{};
|
bool dmaAddrCarry{};
|
||||||
u32 cycles{};
|
u32 cycles{};
|
||||||
|
AudioDevice device;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
u32 freq{44100};
|
u32 freq{44100};
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#include <Audio.hpp>
|
#include <Audio.hpp>
|
||||||
#include <log.hpp>
|
#include <log.hpp>
|
||||||
#include <SDL2/SDL.h>
|
|
||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
#define AUDIO_SAMPLE_RATE 44100
|
#define AUDIO_SAMPLE_RATE 44100
|
||||||
@@ -8,56 +7,47 @@ namespace n64 {
|
|||||||
#define SYSTEM_SAMPLE_SIZE 4
|
#define SYSTEM_SAMPLE_SIZE 4
|
||||||
#define BYTES_PER_HALF_SECOND (((float)AUDIO_SAMPLE_RATE / 2) * SYSTEM_SAMPLE_SIZE)
|
#define BYTES_PER_HALF_SECOND (((float)AUDIO_SAMPLE_RATE / 2) * SYSTEM_SAMPLE_SIZE)
|
||||||
|
|
||||||
static SDL_AudioStream* audioStream = nullptr;
|
void audioCallback(void* user, Uint8* stream, int length) {
|
||||||
SDL_mutex* audioStreamMutex;
|
auto audioDevice = (AudioDevice*)user;
|
||||||
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) {
|
|
||||||
int gotten = 0;
|
int gotten = 0;
|
||||||
LockAudioMutex();
|
audioDevice->LockMutex();
|
||||||
int available = SDL_AudioStreamAvailable(audioStream);
|
int available = SDL_AudioStreamAvailable(audioDevice->GetStream());
|
||||||
|
|
||||||
if (available > 0) {
|
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;
|
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;
|
float sample = 0;
|
||||||
*out++ = sample;
|
*out++ = sample;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitAudio() {
|
AudioDevice::AudioDevice() {
|
||||||
SDL_InitSubSystem(SDL_INIT_AUDIO);
|
SDL_InitSubSystem(SDL_INIT_AUDIO);
|
||||||
AdjustSampleRate(AUDIO_SAMPLE_RATE);
|
AdjustSampleRate(AUDIO_SAMPLE_RATE);
|
||||||
memset(&request, 0, sizeof(request));
|
|
||||||
|
|
||||||
request.freq = AUDIO_SAMPLE_RATE;
|
request.freq = AUDIO_SAMPLE_RATE;
|
||||||
request.format = SYSTEM_SAMPLE_FORMAT;
|
request.format = SYSTEM_SAMPLE_FORMAT;
|
||||||
request.channels = 2;
|
request.channels = 2;
|
||||||
request.samples = 1024;
|
request.samples = 1024;
|
||||||
request.callback = audioCallback;
|
request.callback = audioCallback;
|
||||||
request.userdata = nullptr;
|
request.userdata = (void*)this;
|
||||||
|
|
||||||
if(!audioDev) {
|
if(!handle) {
|
||||||
audioDev = SDL_OpenAudioDevice(nullptr, 0, &request, &audioSpec, 0);
|
handle = SDL_OpenAudioDevice(nullptr, 0, &request, &audioSpec, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!audioDev) {
|
if(!handle) {
|
||||||
Util::panic("Failed to initialize SDL Audio: {}", SDL_GetError());
|
Util::panic("Failed to initialize SDL Audio: {}", SDL_GetError());
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_PauseAudioDevice(audioDev, false);
|
SDL_PauseAudioDevice(handle, false);
|
||||||
|
|
||||||
audioStreamMutex = SDL_CreateMutex();
|
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 adjustedL = left * volumeL;
|
||||||
float adjustedR = right * volumeR;
|
float adjustedR = right * volumeR;
|
||||||
float samples[2]{ adjustedL, adjustedR };
|
float samples[2]{ adjustedL, adjustedR };
|
||||||
@@ -77,12 +67,11 @@ void PushSample(float left, float volumeL, float right, float volumeR) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdjustSampleRate(int sampleRate) {
|
void AudioDevice::AdjustSampleRate(int sampleRate) {
|
||||||
LockAudioMutex();
|
LockMutex();
|
||||||
if(audioStream) SDL_FreeAudioStream(audioStream);
|
if(audioStream) SDL_FreeAudioStream(audioStream);
|
||||||
|
|
||||||
audioStream = SDL_NewAudioStream(AUDIO_F32SYS, 2, sampleRate, SYSTEM_SAMPLE_FORMAT, 2, AUDIO_SAMPLE_RATE);
|
audioStream = SDL_NewAudioStream(AUDIO_F32SYS, 2, sampleRate, SYSTEM_SAMPLE_FORMAT, 2, AUDIO_SAMPLE_RATE);
|
||||||
UnlockAudioMutex();
|
UnlockMutex();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,31 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <common.hpp>
|
#include <common.hpp>
|
||||||
|
#include <SDL2/SDL.h>
|
||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
void PushSample(float, float, float, float);
|
struct AudioDevice {
|
||||||
void InitAudio();
|
AudioDevice();
|
||||||
void AdjustSampleRate(int);
|
~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{};
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -9,7 +9,7 @@ EmuThread::EmuThread(std::unique_ptr<QtInstanceFactory>&& instance, std::unique_
|
|||||||
[[noreturn]] void EmuThread::run() noexcept {
|
[[noreturn]] void EmuThread::run() noexcept {
|
||||||
LoadWSIPlatform(instance.get(), std::move(wsiPlatform), std::move(windowInfo));
|
LoadWSIPlatform(instance.get(), std::move(wsiPlatform), std::move(windowInfo));
|
||||||
LoadParallelRDP(core->cpu->mem.GetRDRAM());
|
LoadParallelRDP(core->cpu->mem.GetRDRAM());
|
||||||
n64::InitAudio();
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (!core->pause) {
|
if (!core->pause) {
|
||||||
core->Run(settings->getVolumeL(), settings->getVolumeR());
|
core->Run(settings->getVolumeL(), settings->getVolumeR());
|
||||||
|
|||||||
Reference in New Issue
Block a user