diff --git a/gtk3/config.c b/gtk3/config.c index 016221c..f9f1b43 100644 --- a/gtk3/config.c +++ b/gtk3/config.c @@ -172,7 +172,7 @@ void save_config(GtkWindow *main_window, GDateTime *saved_modification_date) { GError *error = NULL; g_message("Trying to save config to %s", config_file_path); - + g_autoptr(GFile) file = g_file_new_for_path(config_file_path); g_autoptr(GFileInfo) file_info = g_file_query_info(file, "time::*", G_FILE_QUERY_INFO_NONE, NULL, NULL); @@ -429,7 +429,7 @@ const GB_rumble_mode_t config_get_rumble_mode(void) { } // This should not happen - g_warning("Unknown highpass mode: %s\nFalling back to “Never”", config.controls.rumble_mode); + g_warning("Unknown rumble mode: %s\nFalling back to “Never”", config.controls.rumble_mode); default_value: return GB_RUMBLE_DISABLED; } diff --git a/gtk3/config.h b/gtk3/config.h index c7c158b..850e0b0 100644 --- a/gtk3/config.h +++ b/gtk3/config.h @@ -47,11 +47,12 @@ EXPAND_GROUP(audio, \ EXPAND_GROUP_MEMBER(high_pass_filter_id, string, "emulate_hardware") \ EXPAND_GROUP_MEMBER(sample_rate, integer, -1) \ + EXPAND_GROUP_MEMBER(interference_volume, integer, 0) \ EXPAND_GROUP_MEMBER(muted, boolean, false) \ ) \ EXPAND_GROUP(controls, \ EXPAND_GROUP_MEMBER(analog_speed_controls, boolean, false) \ - EXPAND_GROUP_MEMBER(rumble_mode, string, "Never") \ + EXPAND_GROUP_MEMBER(rumble_mode, string, "never") \ ) \ EXPAND_GROUP(window, \ \ diff --git a/gtk3/main.c b/gtk3/main.c index 9186cbe..6325e35 100644 --- a/gtk3/main.c +++ b/gtk3/main.c @@ -87,7 +87,7 @@ static const GActionEntry file_entries[] = { }; static const GActionEntry edit_entries[] = { - + }; static const GActionEntry emulation_entries[] = { @@ -252,7 +252,7 @@ static gboolean init_controllers(void) { if (s->haptic == NULL) { g_warning("%s", SDL_GetError()); } - + SDL_HapticClose(s->haptic); s->haptic = NULL; } @@ -298,7 +298,7 @@ static gboolean init_audio(void) { GB_audio_init(gui_data.sample_rate); GB_set_sample_rate(&gb, GB_audio_get_sample_rate()); - + // restore playing state GB_audio_set_paused(!audio_playing); @@ -583,12 +583,12 @@ static void handle_events(GB_gameboy_t *gb) { gui_data.last_used_controller = s; controller_state |= BUTTON_MASK_A; } - + if (SDL_GameControllerGetButton(s->controller, SDL_CONTROLLER_BUTTON_B)) { gui_data.last_used_controller = s; controller_state |= BUTTON_MASK_B; } - + if (SDL_GameControllerGetButton(s->controller, SDL_CONTROLLER_BUTTON_BACK)) { gui_data.last_used_controller = s; controller_state |= BUTTON_MASK_SELECT; @@ -698,9 +698,10 @@ static void init(void) { } GB_apu_set_sample_callback(&gb, gb_audio_callback); - + GB_set_sample_rate(&gb, GB_audio_get_sample_rate()); GB_set_highpass_filter_mode(&gb, config_get_highpass_mode()); + GB_set_interference_volume(&gb, (double) config.audio.interference_volume / 255.0); GB_set_log_callback(&gb, wrapped_console_log); GB_set_input_callback(&gb, wrapped_console_get_sync_input); @@ -837,7 +838,7 @@ static gpointer run_thread(gpointer null_ptr) { char *path = g_file_get_path(gui_data.file); size_t path_length = strlen(path); - + /* At the worst case, size is strlen(path) + 4 bytes for .sav + NULL */ char battery_save_path[path_length + 5]; char cheats_save_path[path_length + 5]; @@ -915,14 +916,14 @@ static void create_action_groups(GApplication *app) { static gboolean on_key_press(GtkWidget *w, GdkEventKey *event, gpointer data) { uint8_t mask; - if (event->keyval == key_map[INPUT_UP]) mask = BUTTON_MASK_UP; - if (event->keyval == key_map[INPUT_DOWN]) mask = BUTTON_MASK_DOWN; - if (event->keyval == key_map[INPUT_LEFT]) mask = BUTTON_MASK_LEFT; - if (event->keyval == key_map[INPUT_RIGHT]) mask = BUTTON_MASK_RIGHT; - if (event->keyval == key_map[INPUT_START]) mask = BUTTON_MASK_START; - if (event->keyval == key_map[INPUT_SELECT]) mask = BUTTON_MASK_SELECT; - if (event->keyval == key_map[INPUT_A]) mask = BUTTON_MASK_A; - if (event->keyval == key_map[INPUT_B]) mask = BUTTON_MASK_B; + if (event->keyval == key_map[INPUT_UP]) mask = BUTTON_MASK_UP; + if (event->keyval == key_map[INPUT_DOWN]) mask = BUTTON_MASK_DOWN; + if (event->keyval == key_map[INPUT_LEFT]) mask = BUTTON_MASK_LEFT; + if (event->keyval == key_map[INPUT_RIGHT]) mask = BUTTON_MASK_RIGHT; + if (event->keyval == key_map[INPUT_START]) mask = BUTTON_MASK_START; + if (event->keyval == key_map[INPUT_SELECT]) mask = BUTTON_MASK_SELECT; + if (event->keyval == key_map[INPUT_A]) mask = BUTTON_MASK_A; + if (event->keyval == key_map[INPUT_B]) mask = BUTTON_MASK_B; if (event->keyval == key_map[INPUT_REWIND]) { gui_data.rewind_down = event->type == GDK_KEY_PRESS; @@ -956,7 +957,7 @@ static gboolean on_key_press(GtkWidget *w, GdkEventKey *event, gpointer data) { } } } - + if (event->type == GDK_KEY_PRESS) { gui_data.pressed_buttons |= mask; } @@ -1120,6 +1121,12 @@ void on_preferences_notify_sample_rate(PreferencesWindow *pref, const guint *sam init_audio(); } +void on_preferences_notify_interference_volume(PreferencesWindow *pref, const guint *interference_volume) { + if (GB_is_inited(&gb)) { + GB_set_interference_volume(&gb, (double) *interference_volume / 255.0); + } +} + static void connect_signal_handlers(GApplication *app) { // Connect signal handlers gtk_widget_add_events(GTK_WIDGET(gui_data.main_window), GDK_KEY_PRESS_MASK); @@ -1140,6 +1147,7 @@ static void connect_signal_handlers(GApplication *app) { g_signal_connect(gui_data.preferences, "pref-update::video-display-border-mode", G_CALLBACK(on_preferences_notify_border), NULL); g_signal_connect(gui_data.preferences, "pref-update::video-shader", G_CALLBACK(on_preferences_notify_shader), NULL); g_signal_connect(gui_data.preferences, "pref-update::audio-sample-rate", G_CALLBACK(on_preferences_notify_sample_rate), NULL); + g_signal_connect(gui_data.preferences, "pref-update::audio-interference-volume", G_CALLBACK(on_preferences_notify_interference_volume), NULL); } // This function gets called when the GApplication gets activated, i.e. it is ready to show widgets. @@ -1167,7 +1175,7 @@ static void shutdown(GApplication *app, GFile **files, gint n_files, const gchar stop(); SDL_Quit(); GB_free(&gb); - + g_object_unref(gui_data.builder); } @@ -1193,7 +1201,6 @@ static void activate_about(GSimpleAction *action, GVariant *parameter, gpointer gtk_widget_hide(GTK_WIDGET(dialog)); } - // app.preferences GAction // Opens the preferences window static void activate_preferences(GSimpleAction *action, GVariant *parameter, gpointer app) { @@ -1234,7 +1241,7 @@ static void activate_clear_console(GSimpleAction *action, GVariant *parameter, g static void close_rom(void) { stop(); GB_free(&gb); - + gb_screen_clear(gui_data.screen); gb_screen_queue_render(gui_data.screen); @@ -1244,7 +1251,7 @@ static void close_rom(void) { // Update menu action states action_set_enabled(gui_data.main_application, "close", false); action_entries_set_enabled(emulation_entries, G_N_ELEMENTS(emulation_entries), false); - + // Try force the queued redraws while (g_main_context_pending(NULL)) { g_main_context_iteration(NULL, FALSE); diff --git a/gtk3/preferences_window.c b/gtk3/preferences_window.c index 72c2725..aa73526 100644 --- a/gtk3/preferences_window.c +++ b/gtk3/preferences_window.c @@ -19,6 +19,7 @@ struct _PreferencesWindow { GtkCheckButton *aspect_ratio_toggle; GtkComboBoxText *highpass_filter_selector; GtkComboBoxText *sample_rate_selector; + GtkScale *interference_volume_slider; GtkCheckButton *analog_speed_controls_toggle; GtkComboBoxText *rumble_mode_selector; GtkButton *configure_joypad_skip; @@ -206,6 +207,18 @@ static void on_sample_rate_changed(GtkWidget *w, PreferencesWindow *self) { ); } +static void on_interference_volume_changed(GtkWidget *w, PreferencesWindow *self) { + GtkRange *range = GTK_RANGE(w); + gdouble value = gtk_range_get_value(range); + config.audio.interference_volume = (guint32) clamp_double(0, 255, value); + + g_signal_emit( + self, + preferences_signals[PREF_UPDATE], + g_quark_from_static_string("audio-interference-volume"), + &config.audio.interference_volume + ); +} static void preferences_window_realize(GtkWidget *widget) { PreferencesWindow *self = (PreferencesWindow *)widget; @@ -225,6 +238,7 @@ static void preferences_window_realize(GtkWidget *widget) { gtk_combo_box_set_active_id(GTK_COMBO_BOX(self->highpass_filter_selector), config.audio.high_pass_filter_id); gtk_combo_box_set_active_id(GTK_COMBO_BOX(self->sample_rate_selector), g_strdup_printf("%i", config.audio.sample_rate)); + gtk_range_set_value(GTK_RANGE(self->interference_volume_slider), (double) config.audio.interference_volume); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(self->analog_speed_controls_toggle), config.controls.analog_speed_controls); gtk_combo_box_set_active_id(GTK_COMBO_BOX(self->rumble_mode_selector), config.controls.rumble_mode); @@ -251,6 +265,7 @@ static void preferences_window_class_init(PreferencesWindowClass *class) { gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS(class), PreferencesWindow, aspect_ratio_toggle); gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS(class), PreferencesWindow, highpass_filter_selector); gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS(class), PreferencesWindow, sample_rate_selector); + gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS(class), PreferencesWindow, interference_volume_slider); gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS(class), PreferencesWindow, analog_speed_controls_toggle); gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS(class), PreferencesWindow, rumble_mode_selector); gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS(class), PreferencesWindow, configure_joypad_skip); @@ -269,6 +284,7 @@ static void preferences_window_class_init(PreferencesWindowClass *class) { gtk_widget_class_bind_template_callback(GTK_WIDGET_CLASS(class), on_keep_aspect_ratio_changed); gtk_widget_class_bind_template_callback(GTK_WIDGET_CLASS(class), on_highpass_filter_changed); gtk_widget_class_bind_template_callback(GTK_WIDGET_CLASS(class), on_sample_rate_changed); + gtk_widget_class_bind_template_callback(GTK_WIDGET_CLASS(class), on_interference_volume_changed); gtk_widget_class_bind_template_callback(GTK_WIDGET_CLASS(class), on_analog_speed_controls_changed); gtk_widget_class_bind_template_callback(GTK_WIDGET_CLASS(class), on_rumble_mode_changed); diff --git a/gtk3/resources/ui/preferences_window.ui b/gtk3/resources/ui/preferences_window.ui index 9c44bff..c6ed5b6 100644 --- a/gtk3/resources/ui/preferences_window.ui +++ b/gtk3/resources/ui/preferences_window.ui @@ -573,6 +573,8 @@ Author: Maximilian Mader + 5 + 10 True False @@ -590,6 +592,35 @@ Author: Maximilian Mader 3 + + + True + False + Interference volume: + + + False + True + 4 + + + + + True + False + byteAdjustment + 0 + 0 + left + + + + + False + True + 5 + + 2 @@ -976,4 +1007,10 @@ Author: Maximilian Mader + + + 255 + 1 + 8 + diff --git a/gtk3/resources/ui/window.ui b/gtk3/resources/ui/window.ui index 23d2d9c..aae98ff 100644 --- a/gtk3/resources/ui/window.ui +++ b/gtk3/resources/ui/window.ui @@ -37,7 +37,7 @@ Author: Maximilian Mader False normal SameBoy - Copyright © 2015-2019 Lior Halphon + Copyright © 2015-2021 Lior Halphon https://sameboy.github.io sameboy.github.io Lior Halphon https://github.com/LIJI32 diff --git a/gtk3/util.c b/gtk3/util.c index 00b1b56..76f75e7 100644 --- a/gtk3/util.c +++ b/gtk3/util.c @@ -103,7 +103,7 @@ GB_model_t config_get_model_type(GuiData *gui_data) { GtkWidget *menubar_to_menu(GtkMenuBar *menubar) { GtkWidget *menu = gtk_menu_new(); g_autoptr(GList) iter = gtk_container_get_children(GTK_CONTAINER(menubar)); - + while (iter) { GtkWidget *item = GTK_WIDGET(iter->data); gtk_widget_reparent(item, menu); @@ -157,3 +157,12 @@ gboolean scroll_to_bottom(GtkTextView *textview, GtkTextMark *mark) { return true; } + +gchar* format_scale_value_pct(GtkScale *scale, gdouble value) { + GtkAdjustment *adj = gtk_range_get_adjustment(GTK_RANGE(scale)); + gdouble lower = gtk_adjustment_get_lower(adj); + gdouble upper = gtk_adjustment_get_upper(adj); + gdouble range = fabs(upper - lower); + gdouble pct = (value / range) * 100.0; + return g_strdup_printf ("%.1f%% ", pct); +} diff --git a/gtk3/util.h b/gtk3/util.h index 40f3d64..9050160 100644 --- a/gtk3/util.h +++ b/gtk3/util.h @@ -27,4 +27,6 @@ void set_combo_box_row_separator_func(GtkContainer *container); gboolean scroll_to_bottom(GtkTextView *textview, GtkTextMark *mark); +gchar* format_scale_value_pct(GtkScale *scale, gdouble value); + #endif \ No newline at end of file