diff --git a/config.def.h b/config.def.h index 8d92f3a815..9bd17f9bc3 100644 --- a/config.def.h +++ b/config.def.h @@ -252,6 +252,7 @@ static const struct snes_keybind snes_keybinds_1[] = { { SSNES_REWIND, SK_r, NO_BTN, AXIS_NONE }, { SSNES_MOVIE_RECORD_TOGGLE, SK_o, NO_BTN, AXIS_NONE }, { SSNES_PAUSE_TOGGLE, SK_p, NO_BTN, AXIS_NONE }, + { SSNES_FRAMEADVANCE, SK_k, NO_BTN, AXIS_NONE }, { SSNES_RESET, SK_h, NO_BTN, AXIS_NONE }, { SSNES_SHADER_NEXT, SK_m, NO_BTN, AXIS_NONE }, { SSNES_SHADER_PREV, SK_n, NO_BTN, AXIS_NONE }, diff --git a/driver.h b/driver.h index 929433df6e..701fc55e00 100644 --- a/driver.h +++ b/driver.h @@ -41,6 +41,7 @@ enum SSNES_REWIND, SSNES_MOVIE_RECORD_TOGGLE, SSNES_PAUSE_TOGGLE, + SSNES_FRAMEADVANCE, SSNES_RESET, SSNES_SHADER_NEXT, SSNES_SHADER_PREV, diff --git a/general.h b/general.h index 2364e4caf6..58d45a287d 100644 --- a/general.h +++ b/general.h @@ -260,6 +260,7 @@ struct global // Pausing support bool is_paused; + bool is_oneshot; // Autosave support. autosave_t *autosave[2]; diff --git a/settings.c b/settings.c index d3066cca60..d24da50d54 100644 --- a/settings.c +++ b/settings.c @@ -479,6 +479,7 @@ static const struct bind_map bind_maps[MAX_PLAYERS][MAX_BINDS - 1] = { DECLARE_BIND(rewind, SSNES_REWIND) DECLARE_BIND(movie_record_toggle, SSNES_MOVIE_RECORD_TOGGLE) DECLARE_BIND(pause_toggle, SSNES_PAUSE_TOGGLE) + DECLARE_BIND(frame_advance, SSNES_FRAMEADVANCE) DECLARE_BIND(reset, SSNES_RESET) DECLARE_BIND(shader_next, SSNES_SHADER_NEXT) DECLARE_BIND(shader_prev, SSNES_SHADER_PREV) @@ -514,6 +515,7 @@ static const struct bind_map bind_maps[MAX_PLAYERS][MAX_BINDS - 1] = { DECLARE_BIND(rewind, SSNES_REWIND) DECLARE_BIND(movie_record_toggle, SSNES_MOVIE_RECORD_TOGGLE) DECLARE_BIND(pause_toggle, SSNES_PAUSE_TOGGLE) + DECLARE_BIND(frame_advance, SSNES_FRAMEADVANCE) DECLARE_BIND(reset, SSNES_RESET) DECLARE_BIND(shader_next, SSNES_SHADER_NEXT) DECLARE_BIND(shader_prev, SSNES_SHADER_PREV) @@ -549,6 +551,7 @@ static const struct bind_map bind_maps[MAX_PLAYERS][MAX_BINDS - 1] = { DECLARE_BIND(rewind, SSNES_REWIND) DECLARE_BIND(movie_record_toggle, SSNES_MOVIE_RECORD_TOGGLE) DECLARE_BIND(pause_toggle, SSNES_PAUSE_TOGGLE) + DECLARE_BIND(frame_advance, SSNES_FRAMEADVANCE) DECLARE_BIND(reset, SSNES_RESET) DECLARE_BIND(shader_next, SSNES_SHADER_NEXT) DECLARE_BIND(shader_prev, SSNES_SHADER_PREV) @@ -584,6 +587,7 @@ static const struct bind_map bind_maps[MAX_PLAYERS][MAX_BINDS - 1] = { DECLARE_BIND(rewind, SSNES_REWIND) DECLARE_BIND(movie_record_toggle, SSNES_MOVIE_RECORD_TOGGLE) DECLARE_BIND(pause_toggle, SSNES_PAUSE_TOGGLE) + DECLARE_BIND(frame_advance, SSNES_FRAMEADVANCE) DECLARE_BIND(reset, SSNES_RESET) DECLARE_BIND(shader_next, SSNES_SHADER_NEXT) DECLARE_BIND(shader_prev, SSNES_SHADER_PREV) @@ -619,6 +623,7 @@ static const struct bind_map bind_maps[MAX_PLAYERS][MAX_BINDS - 1] = { DECLARE_BIND(rewind, SSNES_REWIND) DECLARE_BIND(movie_record_toggle, SSNES_MOVIE_RECORD_TOGGLE) DECLARE_BIND(pause_toggle, SSNES_PAUSE_TOGGLE) + DECLARE_BIND(frame_advance, SSNES_FRAMEADVANCE) DECLARE_BIND(reset, SSNES_RESET) DECLARE_BIND(shader_next, SSNES_SHADER_NEXT) DECLARE_BIND(shader_prev, SSNES_SHADER_PREV) diff --git a/ssnes.c b/ssnes.c index c6c88d6262..319a7abb15 100644 --- a/ssnes.c +++ b/ssnes.c @@ -185,11 +185,6 @@ static void video_frame(const uint16_t *data, unsigned width, unsigned height) static bool audio_flush(const int16_t *data, unsigned samples) { - audio_convert_s16_to_float(g_extern.audio_data.data, data, samples); - - const float *output_data = NULL; - unsigned output_frames = 0; - #ifdef HAVE_FFMPEG if (g_extern.recording) { @@ -201,6 +196,14 @@ static bool audio_flush(const int16_t *data, unsigned samples) } #endif + if (g_extern.is_paused) + return true; + + const float *output_data = NULL; + unsigned output_frames = 0; + + audio_convert_s16_to_float(g_extern.audio_data.data, data, samples); + ssnes_dsp_input_t dsp_input = { .samples = g_extern.audio_data.data, .frames = samples / 2 @@ -1506,6 +1509,15 @@ static void check_pause(void) old_state = new_state; } +static void check_oneshot(void) +{ + static bool old_state = false; + bool new_state = driver.input->key_pressed(driver.input_data, SSNES_FRAMEADVANCE); + + g_extern.is_oneshot = new_state && !old_state; + old_state = new_state; +} + static void check_reset(void) { if (driver.input->key_pressed(driver.input_data, SSNES_RESET)) @@ -1623,7 +1635,8 @@ static void do_state_checks(void) check_cheats(); #endif check_pause(); - if (g_extern.is_paused) + check_oneshot(); + if (g_extern.is_paused && !g_extern.is_oneshot) return; set_fast_forward_button( @@ -1751,7 +1764,7 @@ int main(int argc, char *argv[]) do_state_checks(); // Run libsnes for one frame. - if (!g_extern.is_paused) + if (!g_extern.is_paused || g_extern.is_oneshot) { lock_autosave(); diff --git a/ssnes.cfg b/ssnes.cfg index 3b209d728b..d3dcb67695 100644 --- a/ssnes.cfg +++ b/ssnes.cfg @@ -276,6 +276,9 @@ # Toggle between paused and non-paused state # input_pause_toggle = p +# Frame advance when game is paused +# input_frame_advance = k + # Reset the emulated SNES. # input_reset = h diff --git a/tools/ssnes-joyconfig.c b/tools/ssnes-joyconfig.c index 1b6c1b98ee..bd30de64cf 100644 --- a/tools/ssnes-joyconfig.c +++ b/tools/ssnes-joyconfig.c @@ -92,6 +92,7 @@ static struct bind binds[] = { MISC_BIND("Rewind", rewind) MISC_BIND("Movie recording toggle", movie_record_toggle) MISC_BIND("Pause", pause_toggle) + MISC_BIND("Frame advance", frame_advance) MISC_BIND("Reset", reset) MISC_BIND("Next shader", shader_next) MISC_BIND("Previous shader", shader_prev)