Skip to content

Commit

Permalink
Add support for fractional speed (25%, 50%, etc.)
Browse files Browse the repository at this point in the history
  • Loading branch information
Arignir committed Mar 14, 2024
1 parent d98b0bc commit 8c77e5c
Show file tree
Hide file tree
Showing 12 changed files with 142 additions and 67 deletions.
11 changes: 7 additions & 4 deletions include/app/app.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
#include <GL/glew.h>
#include <SDL2/SDL.h>
#include <cimgui.h>
#include "hades.h"
#include "gba/gba.h"

#define GLSL(src) "#version 330 core\n" #src
Expand Down Expand Up @@ -87,6 +86,8 @@ enum bind_actions {
BIND_EMULATOR_PAUSE,
BIND_EMULATOR_STOP,
BIND_EMULATOR_RESET,
BIND_EMULATOR_SPEED_X0_25,
BIND_EMULATOR_SPEED_X0_50,
BIND_EMULATOR_SPEED_X1,
BIND_EMULATOR_SPEED_X2,
BIND_EMULATOR_SPEED_X3,
Expand Down Expand Up @@ -175,10 +176,12 @@ struct app {
// Current FPS
uint32_t fps;

// Speed
uint32_t speed;
// Fast forward
bool fast_forward;

// Speed
float speed;

// Skip BIOS
bool skip_bios;

Expand Down Expand Up @@ -457,7 +460,7 @@ void app_emulator_run(struct app *app);
void app_emulator_pause(struct app *app);
void app_emulator_exit(struct app *app);
void app_emulator_key(struct app *app, enum keys key, bool pressed);
void app_emulator_speed(struct app *app, uint32_t);
void app_emulator_speed(struct app *app, bool, float);
void app_emulator_update_backup(struct app *app);
void app_emulator_screenshot(struct app *app);
void app_emulator_screenshot_path(struct app *app, char const *);
Expand Down
4 changes: 2 additions & 2 deletions include/gba/event.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@

#pragma once

#include "hades.h"
#include "gba/gba.h"

/*
Expand Down Expand Up @@ -52,7 +51,8 @@ struct message_reset {

struct message_speed {
struct event_header header;
uint32_t speed;
bool fast_forward;
float speed;
};

struct message_key {
Expand Down
6 changes: 4 additions & 2 deletions include/gba/gba.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,10 @@ struct launch_config {
// True if the BIOS should be skipped
bool skip_bios;

// Speed. 0 = unlimited, 1 = 60fps, 2 = 120fps, etc.
uint32_t speed;
bool fast_forward; // Fast forward

float speed; // Speed. 0.5 = 30fps, 1 = 60fps, 2 = 120fps, etc.
// Can't be 0 unless `fast_forward` is true.

// Set to the frontend's audio frequency.
// Can be 0 if the frontend has no audio.
Expand Down
13 changes: 9 additions & 4 deletions include/gba/scheduler.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

#pragma once

#include "hades.h"

#define INVALID_EVENT_HANDLE ((size_t)(-1))

typedef size_t event_handler_t;
Expand Down Expand Up @@ -69,10 +71,13 @@ struct scheduler {
struct scheduler_event *events;
size_t events_size;

uint32_t speed; // Speed. 0 = unlimited, 1 = 60fps, 2 = 120fps, etc.
bool fast_forward; // Fast forward

float speed; // Speed. 0.5 = 30fps, 1 = 60fps, 2 = 120fps, etc.
// Can't be 0 unless `fast_forward` is true.

uint64_t time_per_frame;
uint64_t time_last_frame;
uint64_t time_per_frame; // In usec
uint64_t time_last_frame; // In usec
uint64_t accumulated_time;
};

Expand Down Expand Up @@ -133,4 +138,4 @@ void sched_process_events(struct gba *gba);
void sched_run_for(struct gba *gba, uint64_t cycles);
void sched_frame_limiter(struct gba *gba,struct event_args args);
void sched_reset_frame_limiter(struct gba *gba);
void sched_update_speed(struct gba *gba, uint32_t speed);
void sched_update_speed(struct gba *gba, bool fast_forward, float speed);
26 changes: 15 additions & 11 deletions source/app/bindings.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
#include <SDL2/SDL.h>
#include <cimgui.h>
#include <cimgui_impl.h>
#include "hades.h"
#include "app/app.h"

void
Expand Down Expand Up @@ -39,12 +38,6 @@ app_bindings_setup_default(
app->binds.keyboard[BIND_EMULATOR_MUTE] = SDL_GetKeyFromName("M");
app->binds.keyboard[BIND_EMULATOR_SCREENSHOT] = SDL_GetKeyFromName("F2");
app->binds.keyboard[BIND_EMULATOR_PAUSE] = SDL_GetKeyFromName("F3");
app->binds.keyboard[BIND_EMULATOR_SPEED_X1] = SDL_GetKeyFromName("1");
app->binds.keyboard[BIND_EMULATOR_SPEED_X2] = SDL_GetKeyFromName("2");
app->binds.keyboard[BIND_EMULATOR_SPEED_X3] = SDL_GetKeyFromName("3");
app->binds.keyboard[BIND_EMULATOR_SPEED_X4] = SDL_GetKeyFromName("4");
app->binds.keyboard[BIND_EMULATOR_SPEED_X5] = SDL_GetKeyFromName("5");
app->binds.keyboard[BIND_EMULATOR_FAST_FORWARD_TOGGLE] = SDL_GetKeyFromName("0");
app->binds.keyboard[BIND_EMULATOR_FAST_FORWARD_HOLD] = SDL_GetKeyFromName("Space");
app->binds.keyboard[BIND_EMULATOR_QUICKSAVE_1] = SDL_GetKeyFromName("F5");
app->binds.keyboard[BIND_EMULATOR_QUICKLOAD_1] = SDL_GetKeyFromName("F8");
Expand Down Expand Up @@ -139,7 +132,7 @@ app_bindings_handle(
case BIND_GBA_START: app_emulator_key(app, KEY_START, pressed); break;
case BIND_EMULATOR_FAST_FORWARD_HOLD: {
app->emulation.fast_forward = pressed;
app_emulator_speed(app, app->emulation.fast_forward ? 0 : app->emulation.speed);
app_emulator_speed(app, app->emulation.fast_forward, app->emulation.speed);
break;
};
default: break;
Expand All @@ -156,19 +149,30 @@ app_bindings_handle(
case BIND_EMULATOR_PAUSE: app->emulation.is_running ? app_emulator_pause(app) : app_emulator_run(app); break;
case BIND_EMULATOR_STOP: app_emulator_stop(app); break;
case BIND_EMULATOR_RESET: app_emulator_reset(app); break;
case BIND_EMULATOR_SPEED_X0_25:
case BIND_EMULATOR_SPEED_X0_50:
case BIND_EMULATOR_SPEED_X1:
case BIND_EMULATOR_SPEED_X2:
case BIND_EMULATOR_SPEED_X3:
case BIND_EMULATOR_SPEED_X4:
case BIND_EMULATOR_SPEED_X5: {
float speeds[] = {
0.25f,
0.50f,
1.00f,
2.00f,
3.00f,
4.00f,
5.00f,
};
app->emulation.fast_forward = false;
app->emulation.speed = 1 + (bind - BIND_EMULATOR_SPEED_X1);
app_emulator_speed(app, app->emulation.speed);
app->emulation.speed = speeds[bind - BIND_EMULATOR_SPEED_X0_25];
app_emulator_speed(app, app->emulation.fast_forward, app->emulation.speed);
break;
};
case BIND_EMULATOR_FAST_FORWARD_TOGGLE: {
app->emulation.fast_forward ^= true;
app_emulator_speed(app, app->emulation.fast_forward ? 0 : app->emulation.speed);
app_emulator_speed(app, app->emulation.fast_forward, app->emulation.speed);
break;
}
case BIND_EMULATOR_QUICKSAVE_1:
Expand Down
7 changes: 3 additions & 4 deletions source/app/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,7 @@ app_config_load(
double d;

if (mjson_get_number(data, data_len, "$.emulation.speed", &d)) {
app->emulation.speed = (int)d;
app->emulation.speed = max(0, min(app->emulation.speed, 5));
app->emulation.speed = max(0.0, min(d, 5.0));
}

if (mjson_get_bool(data, data_len, "$.emulation.fast_forward", &b)) {
Expand Down Expand Up @@ -250,7 +249,7 @@ app_config_save(
// Emulation
"emulation": {
"skip_bios": %B,
"speed": %d,
"speed": %g,
"fast_forward": %B,
"backup_storage": {
"autodetect": %B,
Expand Down Expand Up @@ -287,7 +286,7 @@ app_config_save(
app->file.recent_roms[3],
app->file.recent_roms[4],
(int)app->emulation.skip_bios,
(int)app->emulation.speed,
app->emulation.speed,
(int)app->emulation.fast_forward,
(int)app->emulation.backup_storage.autodetect,
(int)app->emulation.backup_storage.type,
Expand Down
13 changes: 10 additions & 3 deletions source/app/emulator.c
Original file line number Diff line number Diff line change
Expand Up @@ -559,7 +559,8 @@ app_emulator_configure_and_run(

app->emulation.game_path = strdup(rom_path);
app->emulation.launch_config->skip_bios = app->emulation.skip_bios;
app->emulation.launch_config->speed = app->emulation.fast_forward ? 0 : app->emulation.speed;
app->emulation.launch_config->fast_forward = app->emulation.fast_forward;
app->emulation.launch_config->speed = app->emulation.speed;
app->emulation.launch_config->audio_frequency = GBA_CYCLES_PER_SECOND / app->audio.resample_frequency;

if (app->emulation.backup_storage.autodetect) {
Expand All @@ -578,7 +579,11 @@ app_emulator_configure_and_run(
logln(HS_INFO, " Skip BIOS: %s", app->emulation.launch_config->skip_bios ? "true" : "false");
logln(HS_INFO, " Backup storage: %s", backup_storage_names[app->emulation.launch_config->backup_storage.type]);
logln(HS_INFO, " GPIO: %s", gpio_device_names[app->emulation.launch_config->gpio_device_type]);
logln(HS_INFO, " Speed: %i", app->emulation.speed);
if (app->emulation.launch_config->fast_forward) {
logln(HS_INFO, " Speed: Fast Forward");
} else {
logln(HS_INFO, " Speed: %.0f%%", app->emulation.launch_config->speed * 100.f);
}
logln(HS_INFO, " Audio Frequency: %iHz (%i cycles)", app->audio.resample_frequency, app->emulation.launch_config->audio_frequency);

event.header.kind = MESSAGE_RESET;
Expand Down Expand Up @@ -722,12 +727,14 @@ app_emulator_key(
void
app_emulator_speed(
struct app *app,
uint32_t speed
bool fast_forward,
float speed
) {
struct message_speed event;

event.header.kind = MESSAGE_SPEED;
event.header.size = sizeof(event);
event.fast_forward = fast_forward;
event.speed = speed;

channel_lock(&app->emulation.gba->channels.messages);
Expand Down
2 changes: 1 addition & 1 deletion source/app/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ main(
app.args.with_gui = true;
app.emulation.is_started = false;
app.emulation.is_running = false;
app.emulation.speed = 1;
app.emulation.speed = 1.0;
app.emulation.fast_forward = false;
app.emulation.backup_storage.autodetect = true;
app.emulation.backup_storage.type = BACKUP_NONE;
Expand Down
36 changes: 24 additions & 12 deletions source/app/windows/menubar.c
Original file line number Diff line number Diff line change
Expand Up @@ -103,28 +103,40 @@ app_win_menubar_emulation(
bind = SDL_GetKeyName(app->binds.keyboard[BIND_EMULATOR_FAST_FORWARD_TOGGLE]);
if (igMenuItem_Bool("Fast Forward", bind ?: "", app->emulation.fast_forward, true)) {
app->emulation.fast_forward ^= true;
app_emulator_speed(app, app->emulation.fast_forward ? 0 : app->emulation.speed);
app_emulator_speed(app, app->emulation.fast_forward, app->emulation.speed);
}

igSeparator();

char const *speed[] = {
"x1",
"x2",
"x3",
"x4",
"x5",
char const *speeds_str[] = {
"25% (15fps)",
"50% (30fps)",
"100% (60fps)",
"200% (120fps)",
"300% (180fps)",
"400% (240fps)",
"500% (300fps)",
};

float speeds[] = {
0.25f,
0.50f,
1.00f,
2.00f,
3.00f,
4.00f,
5.00f,
};

igBeginDisabled(app->emulation.fast_forward);
for (x = 0; x < 5; ++x) {
for (x = 0; x < array_length(speeds); ++x) {
char const *bind;

bind = SDL_GetKeyName(app->binds.keyboard[BIND_EMULATOR_SPEED_X1 + x]);
if (igMenuItem_Bool(speed[x], bind ?: "", app->emulation.speed == x + 1, true)) {
app->emulation.speed = x + 1;
bind = SDL_GetKeyName(app->binds.keyboard[BIND_EMULATOR_SPEED_X0_25 + x]);
if (igMenuItem_Bool(speeds_str[x], bind ?: "", app->emulation.speed >= speeds[x] - 0.01 && app->emulation.speed <= speeds[x] + 0.01, true)) {
app->emulation.speed = speeds[x];
app->emulation.fast_forward = false;
app_emulator_speed(app, app->emulation.speed);
app_emulator_speed(app, app->emulation.fast_forward, app->emulation.speed);
}
}
igEndDisabled();
Expand Down

0 comments on commit 8c77e5c

Please sign in to comment.