mirror of
https://github.com/Zelda64Recomp/Zelda64Recomp
synced 2026-09-05 11:07:22 -04:00
Build system & dependency refactoring
Switched to a makefile + clang build system Now builds as a library by default Removed SDL2 dependency Changed RT64 integration to use zilmar spec in order to pass a window handle Proper unaligned loads and stores implementation
This commit is contained in:
+39
-44
@@ -1,55 +1,39 @@
|
||||
#include "ultra64.h"
|
||||
#include "multilibultra.hpp"
|
||||
#include "SDL.h"
|
||||
#include "SDL_audio.h"
|
||||
#include <cassert>
|
||||
|
||||
static SDL_AudioDeviceID audio_device = 0;
|
||||
static uint32_t sample_rate = 48000;
|
||||
|
||||
static Multilibultra::audio_callbacks_t audio_callbacks;
|
||||
|
||||
void Multilibultra::set_audio_callbacks(const audio_callbacks_t* callbacks) {
|
||||
if (callbacks != nullptr) {
|
||||
audio_callbacks = *callbacks;
|
||||
}
|
||||
}
|
||||
|
||||
void Multilibultra::init_audio() {
|
||||
// Initialize SDL audio.
|
||||
SDL_InitSubSystem(SDL_INIT_AUDIO);
|
||||
// Pick an initial dummy sample rate; this will be set by the game later to the true sample rate.
|
||||
set_audio_frequency(48000);
|
||||
}
|
||||
|
||||
void Multilibultra::set_audio_frequency(uint32_t freq) {
|
||||
if (audio_device != 0) {
|
||||
SDL_CloseAudioDevice(audio_device);
|
||||
if (audio_callbacks.set_frequency) {
|
||||
audio_callbacks.set_frequency(freq);
|
||||
}
|
||||
SDL_AudioSpec spec_desired{
|
||||
.freq = (int)freq,
|
||||
.format = AUDIO_S16,
|
||||
.channels = 2,
|
||||
.silence = 0, // calculated
|
||||
.samples = 0x100, // Fairly small sample count to reduce the latency of internal buffering
|
||||
.padding = 0, // unused
|
||||
.size = 0, // calculated
|
||||
.callback = nullptr,//feed_audio, // Use a callback as QueueAudio causes popping
|
||||
.userdata = nullptr
|
||||
};
|
||||
|
||||
audio_device = SDL_OpenAudioDevice(nullptr, false, &spec_desired, nullptr, 0);
|
||||
if (audio_device == 0) {
|
||||
printf("SDL Error: %s\n", SDL_GetError());
|
||||
fflush(stdout);
|
||||
assert(false);
|
||||
}
|
||||
SDL_PauseAudioDevice(audio_device, 0);
|
||||
sample_rate = freq;
|
||||
}
|
||||
|
||||
void Multilibultra::queue_audio_buffer(RDRAM_ARG PTR(s16) audio_data_, uint32_t byte_count) {
|
||||
void Multilibultra::queue_audio_buffer(RDRAM_ARG PTR(int16_t) audio_data_, uint32_t byte_count) {
|
||||
// Buffer for holding the output of swapping the audio channels. This is reused across
|
||||
// calls to reduce runtime allocations.
|
||||
static std::vector<uint16_t> swap_buffer;
|
||||
static std::vector<int16_t> swap_buffer;
|
||||
|
||||
// Ensure that the byte count is an integer multiple of samples.
|
||||
assert((byte_count & 1) == 0);
|
||||
|
||||
// Calculate the number of samples from the number of bytes.
|
||||
uint32_t sample_count = byte_count / sizeof(s16);
|
||||
uint32_t sample_count = byte_count / sizeof(int16_t);
|
||||
|
||||
// Make sure the swap buffer is large enough to hold all the incoming audio data.
|
||||
if (sample_count > swap_buffer.size()) {
|
||||
@@ -57,34 +41,45 @@ void Multilibultra::queue_audio_buffer(RDRAM_ARG PTR(s16) audio_data_, uint32_t
|
||||
}
|
||||
|
||||
// Swap the audio channels into the swap buffer to correct for the address xor caused by endianness handling.
|
||||
s16* audio_data = TO_PTR(s16, audio_data_);
|
||||
int16_t* audio_data = TO_PTR(int16_t, audio_data_);
|
||||
for (size_t i = 0; i < sample_count; i += 2) {
|
||||
swap_buffer[i + 0] = audio_data[i + 1];
|
||||
swap_buffer[i + 1] = audio_data[i + 0];
|
||||
}
|
||||
|
||||
// Queue the swapped audio data.
|
||||
SDL_QueueAudio(audio_device, swap_buffer.data(), byte_count);
|
||||
if (audio_callbacks.queue_samples) {
|
||||
audio_callbacks.queue_samples(swap_buffer.data(), sample_count);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t buffer_offset_frames = 1;
|
||||
// For SDL2
|
||||
//uint32_t buffer_offset_frames = 1;
|
||||
// For Godot
|
||||
float buffer_offset_frames = 0.5f;
|
||||
|
||||
// If there's ever any audio popping, check here first. Some games are very sensitive to
|
||||
// the remaining sample count and reporting a number that's too high here can lead to issues.
|
||||
// Reporting a number that's too low can lead to audio lag in some games.
|
||||
uint32_t Multilibultra::get_remaining_audio_bytes() {
|
||||
// Get the number of remaining buffered audio bytes.
|
||||
uint32_t buffered_byte_count = SDL_GetQueuedAudioSize(audio_device);
|
||||
|
||||
// Adjust the reported count to be some number of refreshes in the future, which helps ensure that
|
||||
// there are enough samples even if the audio thread experiences a small amount of lag. This prevents
|
||||
// audio popping on games that use the buffered audio byte count to determine how many samples
|
||||
// to generate.
|
||||
uint32_t samples_per_vi = (sample_rate / 60);
|
||||
if (buffered_byte_count > (buffer_offset_frames * sizeof(int16_t) * samples_per_vi)) {
|
||||
buffered_byte_count -= (buffer_offset_frames * sizeof(int16_t) * samples_per_vi);
|
||||
} else {
|
||||
buffered_byte_count = 0;
|
||||
uint32_t buffered_byte_count;
|
||||
if (audio_callbacks.get_samples_remaining()) {
|
||||
buffered_byte_count = audio_callbacks.get_samples_remaining() * sizeof(int16_t);
|
||||
}
|
||||
return buffered_byte_count;
|
||||
else {
|
||||
buffered_byte_count = 100;
|
||||
}
|
||||
// Adjust the reported count to be some number of refreshes in the future, which helps ensure that
|
||||
// there are enough samples even if the audio thread experiences a small amount of lag. This prevents
|
||||
// audio popping on games that use the buffered audio byte count to determine how many samples
|
||||
// to generate.
|
||||
uint32_t samples_per_vi = (sample_rate / 60);
|
||||
if (buffered_byte_count > static_cast<uint32_t>(buffer_offset_frames * sizeof(int16_t) * samples_per_vi)) {
|
||||
buffered_byte_count -= static_cast<uint32_t>(buffer_offset_frames * sizeof(int16_t) * samples_per_vi);
|
||||
}
|
||||
else {
|
||||
buffered_byte_count = 0;
|
||||
}
|
||||
return buffered_byte_count;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user