Skip to content
Permalink
Browse files

GB: Reduce input lag by 1 frame, video and audio timing updates...

Similar update to GBA which does the following:
- reduces input lag by 1 frame by reading user input at beginning of cpu loop
- audio and video timing update, which sends audio and video at every frame possible
- add missing sound state variable, soundTicks for gb and gba
  • Loading branch information
retro-wertz
retro-wertz committed Jul 22, 2019
1 parent bdd4386 commit 1532f555fe1805663cbf79c1ac9385d0d3957cb3
Showing with 93 additions and 115 deletions.
  1. +48 −67 src/gb/GB.cpp
  2. +38 −41 src/gb/gbSound.cpp
  3. +3 −3 src/gb/gbSound.h
  4. +4 −4 src/gba/Sound.cpp
@@ -1232,7 +1232,7 @@ void gbWriteMemory(uint16_t address, uint8_t value)
case 0x3e:
case 0x3f:
// Sound registers handled by blargg
gbSoundEvent(address, value);
gbSoundEvent(soundTicks, address, value);
//gbMemory[address] = value;
return;

@@ -1967,7 +1967,7 @@ uint8_t gbReadMemory(uint16_t address)
case 0x3e:
case 0x3f:
// Sound registers read
return gbSoundRead(address);
return gbSoundRead(soundTicks, address);
case 0x40:
return register_LCDC;
case 0x41:
@@ -4535,12 +4535,37 @@ void gbDrawLine()
}
}

static void gbUpdateJoypads(bool readSensors)
{
if (systemReadJoypads()) {
// read joystick
if (gbSgbMode && gbSgbMultiplayer) {
if (gbSgbFourPlayers) {
gbJoymask[0] = systemReadJoypad(0);
gbJoymask[1] = systemReadJoypad(1);
gbJoymask[2] = systemReadJoypad(2);
gbJoymask[3] = systemReadJoypad(3);
} else {
gbJoymask[0] = systemReadJoypad(0);
gbJoymask[1] = systemReadJoypad(1);
}
} else {
gbJoymask[0] = systemReadJoypad(-1);
}
}

if (readSensors && gbRomType == 0x22) {
systemUpdateMotionSensor();
}
}

void gbEmulate(int ticksToStop)
{
gbRegister tempRegister;
uint8_t tempValue;
int8_t offset;


clockTicks = 0;
gbDmaTicks = 0;

@@ -4549,6 +4574,9 @@ void gbEmulate(int ticksToStop)
int opcode1 = 0;
int opcode2 = 0;
bool execute = false;
bool frameDone = false;

gbUpdateJoypads(true);

while (1) {
uint16_t oldPCW = PC.W;
@@ -4661,6 +4689,8 @@ void gbEmulate(int ticksToStop)
}

ticksToStop -= clockTicks;
soundTicks += clockTicks;
if (!gbSpeed) soundTicks += clockTicks;

// DIV register emulation
gbDivTicks -= clockTicks;
@@ -4930,6 +4960,7 @@ void gbEmulate(int ticksToStop)

gbFrameCount++;
systemFrame();
gbSoundTick(soundTicks);

if ((gbFrameCount % 10) == 0)
system10Frames(60);
@@ -4944,28 +4975,8 @@ void gbEmulate(int ticksToStop)
gbFrameCount = 0;
}

if (systemReadJoypads()) {
// read joystick
if (gbSgbMode && gbSgbMultiplayer) {
if (gbSgbFourPlayers) {
gbJoymask[0] = systemReadJoypad(0);
gbJoymask[1] = systemReadJoypad(1);
gbJoymask[2] = systemReadJoypad(2);
gbJoymask[3] = systemReadJoypad(3);
} else {
gbJoymask[0] = systemReadJoypad(0);
gbJoymask[1] = systemReadJoypad(1);
}
} else {
gbJoymask[0] = systemReadJoypad(-1);
}
}
int newmask = gbJoymask[0] & 255;

if (gbRomType == 0x22) {
systemUpdateMotionSensor();
}

if (newmask) {
gbMemory[0xff0f] = register_IF |= 16;
}
@@ -5003,6 +5014,8 @@ void gbEmulate(int ticksToStop)
} else
gbFrameSkipCount++;

frameDone = true;

} else {
// go the the OAM being accessed mode
gbLcdTicksDelayed += GBLCD_MODE_2_CLOCK_TICKS;
@@ -5151,25 +5164,11 @@ void gbEmulate(int ticksToStop)
ticksToStop = 0;
}
}
if (systemReadJoypads()) {
// read joystick
if (gbSgbMode && gbSgbMultiplayer) {
if (gbSgbFourPlayers) {
gbJoymask[0] = systemReadJoypad(0);
gbJoymask[1] = systemReadJoypad(1);
gbJoymask[2] = systemReadJoypad(2);
gbJoymask[3] = systemReadJoypad(3);
} else {
gbJoymask[0] = systemReadJoypad(0);
gbJoymask[1] = systemReadJoypad(1);
}
} else {
gbJoymask[0] = systemReadJoypad(-1);
}
}

gbFrameCount++;

systemFrame();
gbSoundTick(soundTicks);

if ((gbFrameCount % 10) == 0)
system10Frames(60);
@@ -5183,6 +5182,7 @@ void gbEmulate(int ticksToStop)
gbLastTime = currentTime;
gbFrameCount = 0;
}
frameDone = true;
}
}
}
@@ -5279,15 +5279,14 @@ void gbEmulate(int ticksToStop)
#endif
}
#endif

soundTicks -= clockTicks;
if (!gbSpeed)
soundTicks -= clockTicks;

while (soundTicks < 0) {
soundTicks += SOUND_CLOCK_TICKS;

gbSoundTick();
// TODO: evaluate and fix this
// On VBA-M (gb core running twice as fast?), each vblank is uses 35112 cycles.
// on some cases no vblank is generated causing sound ticks to keep accumulating causing core to crash.
// This forces core to flush sound buffers when expected sound ticks has passed and no frame is done yet.which then ends cpuloop
if ((soundTicks > SOUND_CLOCK_TICKS) && !frameDone) {
int last_st = soundTicks;
gbSoundTick(soundTicks);
soundTicks = (last_st - SOUND_CLOCK_TICKS);
}

// timer emulation
@@ -5413,25 +5412,7 @@ void gbEmulate(int ticksToStop)

gbBlackScreen = false;

if ((ticksToStop <= 0)) {
if (!(register_LCDC & 0x80)) {
if (systemReadJoypads()) {
// read joystick
if (gbSgbMode && gbSgbMultiplayer) {
if (gbSgbFourPlayers) {
gbJoymask[0] = systemReadJoypad(0);
gbJoymask[1] = systemReadJoypad(1);
gbJoymask[2] = systemReadJoypad(2);
gbJoymask[3] = systemReadJoypad(3);
} else {
gbJoymask[0] = systemReadJoypad(0);
gbJoymask[1] = systemReadJoypad(1);
}
} else {
gbJoymask[0] = systemReadJoypad(-1);
}
}
}
if (ticksToStop <= 0 || frameDone) { // Stop loop
return;
}
}
@@ -5821,7 +5802,7 @@ struct EmulatedSystem GBSystem = {
false,
// emuCount
#ifdef FINAL_VERSION
70000 / 4,
72000,
#else
1000,
#endif
@@ -24,25 +24,20 @@ static bool declicking = false;
int const chan_count = 4;
int const ticks_to_time = 2 * GB_APU_OVERCLOCK;

static inline blip_time_t blip_time()
{
return (SOUND_CLOCK_TICKS - soundTicks) * ticks_to_time;
}

uint8_t gbSoundRead(uint16_t address)
uint8_t gbSoundRead(int st, uint16_t address)
{
if (gb_apu && address >= NR10 && address <= 0xFF3F)
return gb_apu->read_register(blip_time(), address);
return gb_apu->read_register((blip_time_t)(st * ticks_to_time), address);

return gbMemory[address];
}

void gbSoundEvent(uint16_t address, int data)
void gbSoundEvent(int st, uint16_t address, int data)
{
gbMemory[address] = data;

if (gb_apu && address >= NR10 && address <= 0xFF3F)
gb_apu->write_register(blip_time(), address, data);
gb_apu->write_register((blip_time_t)(st * ticks_to_time), address, data);
}

static void end_frame(blip_time_t time)
@@ -83,11 +78,11 @@ static void apply_volume()
gb_apu->volume(soundVolume_);
}

void gbSoundTick()
void gbSoundTick(int st)
{
if (gb_apu && stereo_buffer) {
// Run sound hardware to present
end_frame(SOUND_CLOCK_TICKS * ticks_to_time);
end_frame((blip_time_t)(st * ticks_to_time));

flush_samples(stereo_buffer);

@@ -100,6 +95,8 @@ void gbSoundTick()
if (soundVolume_ != soundGetVolume())
apply_volume();
}

soundTicks = 0;
}

static void reset_apu()
@@ -115,7 +112,7 @@ static void reset_apu()
if (stereo_buffer)
stereo_buffer->clear();

soundTicks = SOUND_CLOCK_TICKS;
soundTicks = 0;
}

static void remake_stereo_buffer()
@@ -171,42 +168,42 @@ bool gbSoundGetDeclicking()

void gbSoundReset()
{
SOUND_CLOCK_TICKS = 20000; // 1/100 second
SOUND_CLOCK_TICKS = 35112;

remake_stereo_buffer();
reset_apu();

soundPaused = 1;

gbSoundEvent(0xff10, 0x80);
gbSoundEvent(0xff11, 0xbf);
gbSoundEvent(0xff12, 0xf3);
gbSoundEvent(0xff14, 0xbf);
gbSoundEvent(0xff16, 0x3f);
gbSoundEvent(0xff17, 0x00);
gbSoundEvent(0xff19, 0xbf);

gbSoundEvent(0xff1a, 0x7f);
gbSoundEvent(0xff1b, 0xff);
gbSoundEvent(0xff1c, 0xbf);
gbSoundEvent(0xff1e, 0xbf);

gbSoundEvent(0xff20, 0xff);
gbSoundEvent(0xff21, 0x00);
gbSoundEvent(0xff22, 0x00);
gbSoundEvent(0xff23, 0xbf);
gbSoundEvent(0xff24, 0x77);
gbSoundEvent(0xff25, 0xf3);
gbSoundEvent(0, 0xff10, 0x80);
gbSoundEvent(0, 0xff11, 0xbf);
gbSoundEvent(0, 0xff12, 0xf3);
gbSoundEvent(0, 0xff14, 0xbf);
gbSoundEvent(0, 0xff16, 0x3f);
gbSoundEvent(0, 0xff17, 0x00);
gbSoundEvent(0, 0xff19, 0xbf);

gbSoundEvent(0, 0xff1a, 0x7f);
gbSoundEvent(0, 0xff1b, 0xff);
gbSoundEvent(0, 0xff1c, 0xbf);
gbSoundEvent(0, 0xff1e, 0xbf);

gbSoundEvent(0, 0xff20, 0xff);
gbSoundEvent(0, 0xff21, 0x00);
gbSoundEvent(0, 0xff22, 0x00);
gbSoundEvent(0, 0xff23, 0xbf);
gbSoundEvent(0, 0xff24, 0x77);
gbSoundEvent(0, 0xff25, 0xf3);

if (gbHardware & 0x4)
gbSoundEvent(0xff26, 0xf0);
gbSoundEvent(0, 0xff26, 0xf0);
else
gbSoundEvent(0xff26, 0xf1);
gbSoundEvent(0, 0xff26, 0xf1);

/* workaround for game Beetlejuice */
if (gbHardware & 0x1) {
gbSoundEvent(0xff24, 0x77);
gbSoundEvent(0xff25, 0xf3);
gbSoundEvent(0, 0xff24, 0x77);
gbSoundEvent(0, 0xff25, 0xf3);
}

int addr = 0xff30;
@@ -399,7 +396,6 @@ static void gbSoundReadGameOld(int version, gzFile gzFile)
#endif

// New state format

static variable_desc gb_state[] = {
LOAD(int, state.version), // room_for_expansion will be used by later versions

@@ -427,7 +423,8 @@ static variable_desc gb_state[] = {
SKIP(int[13], room_for_expansion),

// Emulator
SKIP(int[16], room_for_expansion),
LOAD(int, soundTicks),
SKIP(int[15], room_for_expansion),

{ NULL, 0 }
};
@@ -445,7 +442,7 @@ void gbSoundSaveGame(gzFile out)

state.version = 1;
#ifdef __LIBRETRO__
utilWriteDataMem(out, gb_state);
utilWriteDataMem(out, gb_state);
#else
utilWriteData(out, gb_state);
#endif
@@ -461,10 +458,10 @@ void gbSoundReadGame(int version, gzFile in)
reset_apu();
gb_apu->save_state(&state.apu);

if (version > 11)
#ifdef __LIBRETRO__
utilReadDataMem(in, gb_state);
utilReadDataMem(in, gb_state);
#else
if (version > 11)
utilReadData(in, gb_state);
else
gbSoundReadGameOld(version, in);

0 comments on commit 1532f55

Please sign in to comment.
You can’t perform that action at this time.