More improvements to SameBoy audio interface for Super Game Boy.
Added a fix for a very rare crashing issue with SDL 2.0 joypad support.
This commit is contained in:
byuu 2019-10-06 10:14:30 +09:00
parent 1698533774
commit e22167cf82
8 changed files with 42 additions and 20 deletions

View File

@ -55,6 +55,7 @@ struct Filter {
struct Stream { struct Stream {
auto reset(uint channels, double inputFrequency, double outputFrequency) -> void; auto reset(uint channels, double inputFrequency, double outputFrequency) -> void;
auto reset() -> void;
auto frequency() const -> double; auto frequency() const -> double;
auto setFrequency(double inputFrequency, maybe<double> outputFrequency = nothing) -> void; auto setFrequency(double inputFrequency, maybe<double> outputFrequency = nothing) -> void;
@ -63,7 +64,7 @@ struct Stream {
auto addLowPassFilter(double cutoffFrequency, Filter::Order order, uint passes = 1) -> void; auto addLowPassFilter(double cutoffFrequency, Filter::Order order, uint passes = 1) -> void;
auto addHighPassFilter(double cutoffFrequency, Filter::Order order, uint passes = 1) -> void; auto addHighPassFilter(double cutoffFrequency, Filter::Order order, uint passes = 1) -> void;
auto pending() const -> bool; auto pending() const -> uint;
auto read(double samples[]) -> uint; auto read(double samples[]) -> uint;
auto write(const double samples[]) -> void; auto write(const double samples[]) -> void;

View File

@ -9,6 +9,12 @@ auto Stream::reset(uint channelCount, double inputFrequency, double outputFreque
setFrequency(inputFrequency, outputFrequency); setFrequency(inputFrequency, outputFrequency);
} }
auto Stream::reset() -> void {
for(auto& channel : channels) {
channel.resampler.reset(this->inputFrequency, this->outputFrequency);
}
}
auto Stream::frequency() const -> double { auto Stream::frequency() const -> double {
return inputFrequency; return inputFrequency;
} }
@ -81,8 +87,9 @@ auto Stream::addHighPassFilter(double cutoffFrequency, Filter::Order order, uint
} }
} }
auto Stream::pending() const -> bool { auto Stream::pending() const -> uint {
return channels && channels[0].resampler.pending(); if(!channels) return 0;
return channels[0].resampler.pending();
} }
auto Stream::read(double samples[]) -> uint { auto Stream::read(double samples[]) -> uint {

View File

@ -29,7 +29,7 @@ using namespace nall;
namespace Emulator { namespace Emulator {
static const string Name = "bsnes"; static const string Name = "bsnes";
static const string Version = "111"; static const string Version = "111.1";
static const string Author = "byuu"; static const string Author = "byuu";
static const string License = "GPLv3"; static const string License = "GPLv3";
static const string Website = "https://byuu.org"; static const string Website = "https://byuu.org";

View File

@ -40,6 +40,7 @@ namespace SameBoy {
float left = sample->left / 32768.0f; float left = sample->left / 32768.0f;
float right = sample->right / 32768.0f; float right = sample->right / 32768.0f;
icd.apuWrite(left, right); icd.apuWrite(left, right);
//print(dsp.stream->pending(), " ", icd.stream->pending(), "\n");
} }
static auto vblank(GB_gameboy_t*) -> void { static auto vblank(GB_gameboy_t*) -> void {
@ -63,7 +64,7 @@ auto ICD::main() -> void {
step(clocks >> 1); step(clocks >> 1);
} else { //DMG halted } else { //DMG halted
apuWrite(0.0, 0.0); apuWrite(0.0, 0.0);
step(256); step(128);
} }
synchronizeCPU(); synchronizeCPU();
} }
@ -75,16 +76,15 @@ auto ICD::step(uint clocks) -> void {
auto ICD::load() -> bool { auto ICD::load() -> bool {
information = {}; information = {};
//todo: connect to SFC random enable setting GB_random_set_enabled(configuration.hacks.entropy != "None");
//GB_random_set_enabled(false);
if(Frequency == 0) { if(Frequency == 0) {
GB_init(&sameboy, GB_MODEL_SGB_NO_SFC); GB_init(&sameboy, GB_MODEL_SGB_NO_SFC);
GB_load_boot_rom_from_buffer(&sameboy, (const unsigned char*)&SGB1BootROM[0], 256); GB_load_boot_rom_from_buffer(&sameboy, (const unsigned char*)&SGB1BootROM[0], 256);
GB_set_sample_rate(&sameboy, uint(system.cpuFrequency() / 5.0 / 128.0)); GB_set_sample_rate(&sameboy, 32768);
} else { } else {
GB_init(&sameboy, GB_MODEL_SGB2_NO_SFC); GB_init(&sameboy, GB_MODEL_SGB2_NO_SFC);
GB_load_boot_rom_from_buffer(&sameboy, (const unsigned char*)&SGB2BootROM[0], 256); GB_load_boot_rom_from_buffer(&sameboy, (const unsigned char*)&SGB2BootROM[0], 256);
GB_set_sample_rate(&sameboy, uint(Frequency / 5.0 / 128.0)); GB_set_sample_rate(&sameboy, 32000);
} }
GB_set_highpass_filter_mode(&sameboy, GB_HIGHPASS_ACCURATE); GB_set_highpass_filter_mode(&sameboy, GB_HIGHPASS_ACCURATE);
GB_set_icd_hreset_callback(&sameboy, &SameBoy::hreset); GB_set_icd_hreset_callback(&sameboy, &SameBoy::hreset);
@ -138,11 +138,12 @@ auto ICD::unload() -> void {
} }
auto ICD::power(bool reset) -> void { auto ICD::power(bool reset) -> void {
uint frequency = (Frequency ? Frequency : system.cpuFrequency()) / 5.0;
//SGB1 uses CPU oscillator; SGB2 uses dedicated oscillator //SGB1 uses CPU oscillator; SGB2 uses dedicated oscillator
create(ICD::Enter, (Frequency ? Frequency : system.cpuFrequency()) / 5.0); create(ICD::Enter, frequency);
if(!reset) { if(!reset) stream = Emulator::audio.createStream(2, frequency / 128);
stream = Emulator::audio.createStream(2, uint((Frequency ? Frequency : system.cpuFrequency()) / 5.0 / 128.0)); dsp.stream->reset();
} icd.stream->reset();
for(auto& packet : this->packet) packet = {}; for(auto& packet : this->packet) packet = {};
packetSize = 0; packetSize = 0;

View File

@ -19,7 +19,9 @@ auto DSP::main() -> void {
int count = spc_dsp.sample_count(); int count = spc_dsp.sample_count();
if(count > 0) { if(count > 0) {
for(uint n = 0; n < count; n += 2) { for(uint n = 0; n < count; n += 2) {
stream->sample(samplebuffer[n + 0] / 32768.0f, samplebuffer[n + 1] / 32768.0f); float left = samplebuffer[n + 0] / 32768.0f;
float right = samplebuffer[n + 1] / 32768.0f;
stream->sample(left, right);
} }
spc_dsp.set_output(samplebuffer, 8192); spc_dsp.set_output(samplebuffer, 8192);
} }

View File

@ -170,13 +170,23 @@ auto InputMapping::Binding::icon() -> image {
} }
auto InputMapping::Binding::name() -> string { auto InputMapping::Binding::name() -> string {
if(device && device->isKeyboard()) { //if ruby drivers cannot report accurate vendor/product IDs (eg SDL),
//and the user closes the emulator, changes gamepads, and restarts it,
//it is possible the wrong device will now be mapped to the input IDs.
//that could potentially make the group/input IDs go out of bounds.
if(!device) return {};
if(group >= device->size()) return {};
if(input >= device->group(group).size()) return {};
if(device->isKeyboard()) {
return device->group(group).input(input).name(); return device->group(group).input(input).name();
} }
if(device && device->isMouse()) {
if(device->isMouse()) {
return device->group(group).input(input).name(); return device->group(group).input(input).name();
} }
if(device && device->isJoypad()) {
if(device->isJoypad()) {
string name{Hash::CRC16(string{device->id()}).digest().upcase()}; string name{Hash::CRC16(string{device->id()}).digest().upcase()};
name.append(" ", device->group(group).name()); name.append(" ", device->group(group).name());
name.append(" ", device->group(group).input(input).name()); name.append(" ", device->group(group).input(input).name());
@ -185,6 +195,7 @@ auto InputMapping::Binding::name() -> string {
if(qualifier == Qualifier::Rumble) name.append(" Rumble"); if(qualifier == Qualifier::Rumble) name.append(" Rumble");
return name; return name;
} }
return {}; return {};
} }

View File

@ -8,7 +8,7 @@ namespace nall::DSP::Resampler {
struct Cubic { struct Cubic {
inline auto reset(double inputFrequency, double outputFrequency = 0, uint queueSize = 0) -> void; inline auto reset(double inputFrequency, double outputFrequency = 0, uint queueSize = 0) -> void;
inline auto setInputFrequency(double inputFrequency) -> void; inline auto setInputFrequency(double inputFrequency) -> void;
inline auto pending() const -> bool; inline auto pending() const -> uint;
inline auto read() -> double; inline auto read() -> double;
inline auto write(double sample) -> void; inline auto write(double sample) -> void;
@ -37,7 +37,7 @@ auto Cubic::setInputFrequency(double inputFrequency) -> void {
ratio = inputFrequency / outputFrequency; ratio = inputFrequency / outputFrequency;
} }
auto Cubic::pending() const -> bool { auto Cubic::pending() const -> uint {
return samples.pending(); return samples.pending();
} }

View File

@ -41,7 +41,7 @@ struct queue {
template<typename U = T> auto capacity() const -> uint { return _capacity * sizeof(T) / sizeof(U); } template<typename U = T> auto capacity() const -> uint { return _capacity * sizeof(T) / sizeof(U); }
template<typename U = T> auto size() const -> uint { return _size * sizeof(T) / sizeof(U); } template<typename U = T> auto size() const -> uint { return _size * sizeof(T) / sizeof(U); }
auto empty() const -> bool { return _size == 0; } auto empty() const -> bool { return _size == 0; }
auto pending() const -> bool { return _size > 0; } auto pending() const -> uint { return _size; }
auto full() const -> bool { return _size >= (int)_capacity; } auto full() const -> bool { return _size >= (int)_capacity; }
auto underflow() const -> bool { return _size < 0; } auto underflow() const -> bool { return _size < 0; }
auto overflow() const -> bool { return _size > (int)_capacity; } auto overflow() const -> bool { return _size > (int)_capacity; }