mirror of https://github.com/bsnes-emu/bsnes.git
v111.1
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:
parent
1698533774
commit
e22167cf82
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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";
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
Loading…
Reference in New Issue