mirror of https://github.com/bsnes-emu/bsnes.git
Update to v105 release.
byuu says: This release provides several major improvements to Mega Drive emulation which enhances compatibility a good deal. It also includes important Super Famicom mosaic emulation improvements, plus a much-needed SuperFX save state issue fix. Changelog (since v104): - higan: many improvements to Emulator::Interface to support forks/frontends - higan: refreshed program icon - icarus: new program icon - Game Boy Advance: slight emulation speedup over v104 - Game Boy Advance: synchronize APU FIFO updates better - Mega Drive: added automatic region detection [hex_usr] - Mega Drive: support 8-bit SRAM - Game Boy Advance: fixed bug when changing to THUMB mode via MSR [MerryMage] - Master System: fix bug in backdrop color and background 0 priority [hex_usr] - Mega Drive: backgrounds always update output priority bit [Cydrak] - Mega Drive: emulated interlaced video output - Mega Drive: emulated shadow/highlight mode [Cydrak] - Super Famicom: auto joypad polling clears the shift register when starting - Super Famicom: added new low-entropy RAM initialization mode to more closely match hardware - Game Boy Advance: rumble will now time out after being left on for 500ms - ruby: improved rumble support in udev input driver [ma_rysia] - M68K: `move.b (a7)[+/-]` adjust a7 by two - M68K: illegal/lineA/lineF opcodes do not modify the stack register - Mega Drive: emulate VIP status bit - uPD7725: improved emulation of OV1/S1 flags [byuu, AWJ, Lord Nightmare] - uPD7725: improved handling of DP, RP updates [Jonas Quinn] - Super Famicom: improved emulation of mosaic effects in hires, interlace, and offset-per-tile modes [byuu, Cydrak] - ruby: improved Direct3D exclusive mode monitor selection [Cydrak] - Super Famicom: fixed save state bug affecting SuperFX games [Cydrak] - Mega Drive: added workaround for Clang compiler bug; allowing this core to work on macOS [Cydrak, Sintendo] - higan: hotkeys now also trigger when the main window lacks focus yet higan is set to allow input on focus loss - higan: fixed an edge case where `int16_t` ↔ `double` audio conversion could possibly result in overflows - higan: fixed a crash on macOS when choosing quit from the application menu [ncbncb] Changelog (since the previous WIP): - higan: restored `make console=true` - tomoko: if you allow input when main window focus is lost, hotkeys can now be triggered without focus as well - hiro/cocoa: fix crash on exit from menu [ncbncb] - ruby: smarter `double` → `int16_t` conversion to prevent underflow/overflow
This commit is contained in:
parent
9a13863adb
commit
f8e71b50d0
|
@ -8,7 +8,7 @@ objects := libco emulator audio video resource
|
||||||
flags += -I. -I..
|
flags += -I. -I..
|
||||||
|
|
||||||
ifeq ($(platform),windows)
|
ifeq ($(platform),windows)
|
||||||
link += -mwindows
|
link += $(if $(call streq,$(console),true),-mconsole,-mwindows)
|
||||||
ifeq ($(binary),application)
|
ifeq ($(binary),application)
|
||||||
link += -mthreads -lpthread -luuid -lkernel32 -luser32 -lgdi32 -lcomctl32 -lcomdlg32 -lshell32
|
link += -mthreads -lpthread -luuid -lkernel32 -luser32 -lgdi32 -lcomctl32 -lcomdlg32 -lshell32
|
||||||
link += -Wl,-enable-auto-import
|
link += -Wl,-enable-auto-import
|
||||||
|
|
|
@ -12,7 +12,7 @@ using namespace nall;
|
||||||
|
|
||||||
namespace Emulator {
|
namespace Emulator {
|
||||||
static const string Name = "higan";
|
static const string Name = "higan";
|
||||||
static const string Version = "104.17";
|
static const string Version = "105";
|
||||||
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/";
|
||||||
|
|
|
@ -96,7 +96,7 @@ auto InputManager::appendHotkeys() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto InputManager::pollHotkeys() -> void {
|
auto InputManager::pollHotkeys() -> void {
|
||||||
if(!program->focused()) return;
|
if(!program->focused() && !settings["Input/FocusLoss/AllowInput"].boolean()) return;
|
||||||
|
|
||||||
for(auto& hotkey : hotkeys) {
|
for(auto& hotkey : hotkeys) {
|
||||||
int16 state = hotkey->poll();
|
int16 state = hotkey->poll();
|
||||||
|
|
|
@ -33,17 +33,18 @@
|
||||||
@end
|
@end
|
||||||
|
|
||||||
CocoaDelegate* cocoaDelegate = nullptr;
|
CocoaDelegate* cocoaDelegate = nullptr;
|
||||||
|
NSTimer* applicationTimer = nullptr;
|
||||||
|
|
||||||
namespace hiro {
|
namespace hiro {
|
||||||
|
|
||||||
auto pApplication::run() -> void {
|
auto pApplication::run() -> void {
|
||||||
//NSTimer* timer = [NSTimer scheduledTimerWithTimeInterval:0.1667 target:cocoaDelegate selector:@selector(updateInDock:) userInfo:nil repeats:YES];
|
//applicationTimer = [NSTimer scheduledTimerWithTimeInterval:0.1667 target:cocoaDelegate selector:@selector(updateInDock:) userInfo:nil repeats:YES];
|
||||||
|
|
||||||
if(Application::state.onMain) {
|
if(Application::state.onMain) {
|
||||||
NSTimer* timer = [NSTimer scheduledTimerWithTimeInterval:0.0 target:cocoaDelegate selector:@selector(run:) userInfo:nil repeats:YES];
|
applicationTimer = [NSTimer scheduledTimerWithTimeInterval:0.0 target:cocoaDelegate selector:@selector(run:) userInfo:nil repeats:YES];
|
||||||
|
|
||||||
//below line is needed to run application during window resize; however it has a large performance penalty on the resize smoothness
|
//below line is needed to run application during window resize; however it has a large performance penalty on the resize smoothness
|
||||||
//[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSEventTrackingRunLoopMode];
|
//[[NSRunLoop currentRunLoop] addTimer:applicationTimer forMode:NSEventTrackingRunLoopMode];
|
||||||
}
|
}
|
||||||
|
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
|
@ -74,6 +75,7 @@ auto pApplication::processEvents() -> void {
|
||||||
|
|
||||||
auto pApplication::quit() -> void {
|
auto pApplication::quit() -> void {
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
|
[applicationTimer invalidate];
|
||||||
[NSApp stop:nil];
|
[NSApp stop:nil];
|
||||||
NSEvent* event = [NSEvent otherEventWithType:NSApplicationDefined location:NSMakePoint(0, 0) modifierFlags:0 timestamp:0.0 windowNumber:0 context:nil subtype:0 data1:0 data2:0];
|
NSEvent* event = [NSEvent otherEventWithType:NSApplicationDefined location:NSMakePoint(0, 0) modifierFlags:0 timestamp:0.0 windowNumber:0 context:nil subtype:0 data1:0 data2:0];
|
||||||
[NSApp postEvent:event atStart:true];
|
[NSApp postEvent:event atStart:true];
|
||||||
|
|
|
@ -54,8 +54,9 @@ struct AudioALSA : Audio {
|
||||||
auto output(const double samples[]) -> void {
|
auto output(const double samples[]) -> void {
|
||||||
if(!ready()) return;
|
if(!ready()) return;
|
||||||
|
|
||||||
_buffer[_offset++] = uint16_t(samples[0] * 32768.0) << 0 | uint16_t(samples[1] * 32768.0) << 16;
|
_buffer[_offset] = (uint16_t)sclamp<16>(samples[0] * 32767.0) << 0;
|
||||||
if(_offset < _periodSize) return;
|
_buffer[_offset] |= (uint16_t)sclamp<16>(samples[1] * 32767.0) << 16;
|
||||||
|
if(++_offset < _periodSize) return;
|
||||||
|
|
||||||
snd_pcm_sframes_t available;
|
snd_pcm_sframes_t available;
|
||||||
do {
|
do {
|
||||||
|
|
|
@ -33,7 +33,9 @@ struct AudioAO : Audio {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto output(const double samples[]) -> void {
|
auto output(const double samples[]) -> void {
|
||||||
uint32_t sample = uint16_t(samples[0] * 32768.0) << 0 | uint16_t(samples[1] * 32768.0) << 16;
|
uint32_t sample = 0;
|
||||||
|
sample |= (uint16_t)sclamp<16>(samples[0] * 32767.0) << 0;
|
||||||
|
sample |= (uint16_t)sclamp<16>(samples[1] * 32767.0) << 16;
|
||||||
ao_play(_interface, (char*)&sample, 4);
|
ao_play(_interface, (char*)&sample, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -208,30 +208,30 @@ private:
|
||||||
|
|
||||||
switch(_sampleFormat) {
|
switch(_sampleFormat) {
|
||||||
case ASIOSTInt16LSB: {
|
case ASIOSTInt16LSB: {
|
||||||
*(int16_t*)buffer = samples[n] * double(1 << 15);
|
*(uint16_t*)buffer = (uint16_t)sclamp<16>(samples[n] * (32768.0 - 1.0));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case ASIOSTInt24LSB: {
|
case ASIOSTInt24LSB: {
|
||||||
int value = samples[n] * double(1 << 23);
|
auto value = (uint32_t)sclamp<24>(samples[n] * (256.0 * 32768.0 - 1.0));
|
||||||
buffer[0] = value >> 0;
|
buffer[0] = value >> 0;
|
||||||
buffer[1] = value >> 8;
|
buffer[1] = value >> 8;
|
||||||
buffer[2] = value >> 16;
|
buffer[2] = value >> 16;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case ASIOSTInt32LSB: {
|
case ASIOSTInt32LSB: {
|
||||||
*(int32_t*)buffer = samples[n] * double(1 << 31);
|
*(uint32_t*)buffer = (uint32_t)sclamp<32>(samples[n] * (65536.0 * 32768.0 - 1.0));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case ASIOSTFloat32LSB: {
|
case ASIOSTFloat32LSB: {
|
||||||
*(float*)buffer = samples[n];
|
*(float*)buffer = max(-1.0, min(+1.0, samples[n]));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case ASIOSTFloat64LSB: {
|
case ASIOSTFloat64LSB: {
|
||||||
*(double*)buffer = samples[n];
|
*(double*)buffer = max(-1.0, min(+1.0, samples[n]));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,8 +70,9 @@ struct AudioDirectSound : Audio {
|
||||||
auto output(const double samples[]) -> void {
|
auto output(const double samples[]) -> void {
|
||||||
if(!ready()) return;
|
if(!ready()) return;
|
||||||
|
|
||||||
_buffer[_offset++] = uint16_t(samples[0] * 32768.0) << 0 | uint16_t(samples[1] * 32768.0) << 16;
|
_buffer[_offset] = (uint16_t)sclamp<16>(samples[0] * 32767.0) << 0;
|
||||||
if(_offset < _period) return;
|
_buffer[_offset] |= (uint16_t)sclamp<16>(samples[1] * 32767.0) << 16;
|
||||||
|
if(++_offset < _period) return;
|
||||||
_offset = 0;
|
_offset = 0;
|
||||||
|
|
||||||
if(_blocking) {
|
if(_blocking) {
|
||||||
|
|
|
@ -61,8 +61,8 @@ struct AudioOpenAL : Audio {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto output(const double samples[]) -> void {
|
auto output(const double samples[]) -> void {
|
||||||
_buffer[_bufferLength] = int16_t(samples[0] * 32768.0) << 0;
|
_buffer[_bufferLength] = (uint16_t)sclamp<16>(samples[0] * 32767.0) << 0;
|
||||||
_buffer[_bufferLength] |= int16_t(samples[1] * 32768.0) << 16;
|
_buffer[_bufferLength] |= (uint16_t)sclamp<16>(samples[1] * 32767.0) << 16;
|
||||||
if(++_bufferLength < _bufferSize) return;
|
if(++_bufferLength < _bufferSize) return;
|
||||||
|
|
||||||
ALuint alBuffer = 0;
|
ALuint alBuffer = 0;
|
||||||
|
|
|
@ -77,7 +77,7 @@ struct AudioOSS : Audio {
|
||||||
auto output(const double samples[]) -> void {
|
auto output(const double samples[]) -> void {
|
||||||
if(!ready()) return;
|
if(!ready()) return;
|
||||||
for(auto n : range(_channels)) {
|
for(auto n : range(_channels)) {
|
||||||
int16_t sample = samples[n] * 32768.0;
|
auto sample = (uint16_t)sclamp<16>(samples[n] * 32767.0);
|
||||||
auto unused = write(_fd, &sample, 2);
|
auto unused = write(_fd, &sample, 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,8 +46,9 @@ struct AudioPulseAudio : Audio {
|
||||||
|
|
||||||
auto output(const double samples[]) -> void {
|
auto output(const double samples[]) -> void {
|
||||||
pa_stream_begin_write(_stream, (void**)&_buffer, &_period);
|
pa_stream_begin_write(_stream, (void**)&_buffer, &_period);
|
||||||
_buffer[_offset++] = uint16_t(samples[0] * 32768.0) << 0 | uint16_t(samples[1] * 32768.0) << 16;
|
_buffer[_offset] = (uint16_t)sclamp<16>(samples[0] * 32767.0) << 0;
|
||||||
if((_offset + 1) * pa_frame_size(&_specification) <= _period) return;
|
_buffer[_offset] |= (uint16_t)sclamp<16>(samples[1] * 32767.0) << 16;
|
||||||
|
if((++_offset + 1) * pa_frame_size(&_specification) <= _period) return;
|
||||||
|
|
||||||
while(true) {
|
while(true) {
|
||||||
if(_first) {
|
if(_first) {
|
||||||
|
|
|
@ -36,8 +36,9 @@ struct AudioPulseAudioSimple : Audio {
|
||||||
auto output(const double samples[]) -> void {
|
auto output(const double samples[]) -> void {
|
||||||
if(!ready()) return;
|
if(!ready()) return;
|
||||||
|
|
||||||
_buffer[_offset++] = uint16_t(samples[0] * 32768.0) << 0 | uint16_t(samples[1] * 32768.0) << 16;
|
_buffer[_offset] = (uint16_t)sclamp<16>(samples[0] * 32767.0) << 0;
|
||||||
if(_offset >= 64) {
|
_buffer[_offset] |= (uint16_t)sclamp<16>(samples[1] * 32767.0) << 16;
|
||||||
|
if(++_offset >= 64) {
|
||||||
int error;
|
int error;
|
||||||
pa_simple_write(_interface, (const void*)_buffer, _offset * sizeof(uint32_t), &error);
|
pa_simple_write(_interface, (const void*)_buffer, _offset * sizeof(uint32_t), &error);
|
||||||
_offset = 0;
|
_offset = 0;
|
||||||
|
|
|
@ -205,16 +205,16 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_mode == 1 && _precision == 16) {
|
if(_mode == 1 && _precision == 16) {
|
||||||
auto output = (int16_t*)buffer;
|
auto output = (uint16_t*)buffer;
|
||||||
for(uint n : range(_channels)) *output++ = int16_t(samples[n] * 32768.0);
|
for(uint n : range(_channels)) *output++ = (uint16_t)sclamp<16>(samples[n] * (32768.0 - 1.0));
|
||||||
buffer = (uint8_t*)output;
|
buffer = (uint8_t*)output;
|
||||||
} else if(_mode == 1 && _precision == 32) {
|
} else if(_mode == 1 && _precision == 32) {
|
||||||
auto output = (int32_t*)buffer;
|
auto output = (uint32_t*)buffer;
|
||||||
for(uint n : range(_channels)) *output++ = int32_t(samples[n] * 65536.0 * 32768.0);
|
for(uint n : range(_channels)) *output++ = (uint32_t)sclamp<32>(samples[n] * (65536.0 * 32768.0 - 1.0));
|
||||||
buffer = (uint8_t*)output;
|
buffer = (uint8_t*)output;
|
||||||
} else if(_mode == 3 && _precision == 32) {
|
} else if(_mode == 3 && _precision == 32) {
|
||||||
auto output = (float*)buffer;
|
auto output = (float*)buffer;
|
||||||
for(uint n : range(_channels)) *output++ = float(samples[n]);
|
for(uint n : range(_channels)) *output++ = float(max(-1.0, min(+1.0, samples[n])));
|
||||||
buffer = (uint8_t*)output;
|
buffer = (uint8_t*)output;
|
||||||
} else {
|
} else {
|
||||||
//output silence for unsupported sample formats
|
//output silence for unsupported sample formats
|
||||||
|
|
|
@ -59,8 +59,9 @@ struct AudioXAudio2 : Audio, public IXAudio2VoiceCallback {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto output(const double samples[]) -> void {
|
auto output(const double samples[]) -> void {
|
||||||
_buffer[_bufferIndex * _period + _bufferOffset++] = uint16_t(samples[0] * 32768.0) << 0 | uint16_t(samples[1] * 32768.0) << 16;
|
_buffer[_bufferIndex * _period + _bufferOffset] = (uint16_t)sclamp<16>(samples[0] * 32767.0) << 0;
|
||||||
if(_bufferOffset < _period) return;
|
_buffer[_bufferIndex * _period + _bufferOffset] |= (uint16_t)sclamp<16>(samples[1] * 32767.0) << 16;
|
||||||
|
if(++_bufferOffset < _period) return;
|
||||||
_bufferOffset = 0;
|
_bufferOffset = 0;
|
||||||
|
|
||||||
if(_bufferQueue == _bufferCount - 1) {
|
if(_bufferQueue == _bufferCount - 1) {
|
||||||
|
|
|
@ -55,10 +55,10 @@ struct InputJoypadDirectInput {
|
||||||
int16_t yaxis = 0;
|
int16_t yaxis = 0;
|
||||||
|
|
||||||
if(pov < 36000) {
|
if(pov < 36000) {
|
||||||
if(pov >= 31500 || pov <= 4500) yaxis = -32768;
|
if(pov >= 31500 || pov <= 4500) yaxis = -32767;
|
||||||
if(pov >= 4500 && pov <= 13500) xaxis = +32767;
|
if(pov >= 4500 && pov <= 13500) xaxis = +32767;
|
||||||
if(pov >= 13500 && pov <= 22500) yaxis = +32767;
|
if(pov >= 13500 && pov <= 22500) yaxis = +32767;
|
||||||
if(pov >= 22500 && pov <= 31500) xaxis = -32768;
|
if(pov >= 22500 && pov <= 31500) xaxis = -32767;
|
||||||
}
|
}
|
||||||
|
|
||||||
assign(jp.hid, HID::Joypad::GroupID::Hat, n * 2 + 0, xaxis);
|
assign(jp.hid, HID::Joypad::GroupID::Hat, n * 2 + 0, xaxis);
|
||||||
|
|
|
@ -30,8 +30,8 @@ struct InputJoypadSDL {
|
||||||
|
|
||||||
for(signed n = 0; n < (signed)jp.hid->hats().size() - 1; n += 2) {
|
for(signed n = 0; n < (signed)jp.hid->hats().size() - 1; n += 2) {
|
||||||
uint8_t state = SDL_JoystickGetHat(jp.handle, n >> 1);
|
uint8_t state = SDL_JoystickGetHat(jp.handle, n >> 1);
|
||||||
assign(jp.hid, HID::Joypad::GroupID::Hat, n + 0, state & SDL_HAT_LEFT ? -32768 : state & SDL_HAT_RIGHT ? +32767 : 0);
|
assign(jp.hid, HID::Joypad::GroupID::Hat, n + 0, state & SDL_HAT_LEFT ? -32767 : state & SDL_HAT_RIGHT ? +32767 : 0);
|
||||||
assign(jp.hid, HID::Joypad::GroupID::Hat, n + 1, state & SDL_HAT_UP ? -32768 : state & SDL_HAT_DOWN ? +32767 : 0);
|
assign(jp.hid, HID::Joypad::GroupID::Hat, n + 1, state & SDL_HAT_UP ? -32767 : state & SDL_HAT_DOWN ? +32767 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(auto n : range(jp.hid->buttons())) {
|
for(auto n : range(jp.hid->buttons())) {
|
||||||
|
|
Loading…
Reference in New Issue