diff --git a/Makefile b/Makefile index 281c57c..c5cd20c 100644 --- a/Makefile +++ b/Makefile @@ -120,7 +120,13 @@ ifneq ($(findstring gtk3,$(MAKECMDGOALS)),) $(error The gtk3 target requires pkg-config) endif else -GTK3_CFLAGS := $(shell $(PKG_CONFIG) --cflags gio-2.0 gtk+-3.0 epoxy sdl2) -DGTK_DISABLE_DEPRECATED=1 -DG_DISABLE_DEPRECATED=1 -DG_LOG_DOMAIN=\"SameBoy\" -DRESOURCE_PREFIX=\"/io/github/sameboy/\" -DAPP_ID=\"io.github.sameboy\" +GTK_OPTIONS := -DGTK_DISABLE_DEPRECATED=1 -DG_DISABLE_DEPRECATED=1 -DG_LOG_DOMAIN=\"SameBoy\" -DRESOURCE_PREFIX=\"/io/github/sameboy/\" -DAPP_ID=\"io.github.sameboy\" + +ifeq ($(SDL_AUDIO_DRIVER),sdl) +GTK_OPTIONS += -DUSE_SDL_AUDIO +endif + +GTK3_CFLAGS := $(shell $(PKG_CONFIG) --cflags gio-2.0 gtk+-3.0 epoxy sdl2) $(GTK_OPTIONS) GTK3_LDFLAGS := $(shell $(PKG_CONFIG) --libs gio-2.0 gtk+-3.0 epoxy sdl2) # TODO: REMOVE DISABLE UNUSED WARNINGS @@ -198,7 +204,7 @@ all: cocoa sdl tester libretro CORE_SOURCES := $(shell ls Core/*.c) SDL_SOURCES := $(shell ls SDL/*.c) $(OPEN_DIALOG) SDL/audio/$(SDL_AUDIO_DRIVER).c -GTK3_SOURCES := $(shell ls gtk3/*.c) gtk3/sameboy-gtk3-resources.c +GTK3_SOURCES := $(shell ls gtk3/*.c) gtk3/sameboy-gtk3-resources.c SDL/audio/$(SDL_AUDIO_DRIVER).c TESTER_SOURCES := $(shell ls Tester/*.c) ifeq ($(PLATFORM),Darwin) diff --git a/SDL/audio/audio.h b/SDL/audio/audio.h index acaa011..3d50657 100644 --- a/SDL/audio/audio.h +++ b/SDL/audio/audio.h @@ -5,12 +5,14 @@ #include #include +unsigned GB_audio_default_sample_rate(void); bool GB_audio_is_playing(void); void GB_audio_set_paused(bool paused); void GB_audio_clear_queue(void); -unsigned GB_audio_get_frequency(void); +unsigned GB_audio_get_sample_rate(void); size_t GB_audio_get_queue_length(void); void GB_audio_queue_sample(GB_sample_t *sample); -void GB_audio_init(void); +void GB_audio_init(unsigned sample_rate); +void GB_audio_destroy(void); #endif /* sdl_audio_h */ diff --git a/SDL/audio/sdl.c b/SDL/audio/sdl.c index 12ee69a..cf5be00 100644 --- a/SDL/audio/sdl.c +++ b/SDL/audio/sdl.c @@ -29,6 +29,11 @@ static SDL_AudioSpec want_aspec, have_aspec; static unsigned buffer_pos = 0; static GB_sample_t audio_buffer[AUDIO_BUFFER_SIZE]; +unsigned GB_audio_default_sample_rate(void) +{ + return AUDIO_FREQUENCY; +} + bool GB_audio_is_playing(void) { return SDL_GetAudioDeviceStatus(device_id) == SDL_AUDIO_PLAYING; @@ -45,7 +50,7 @@ void GB_audio_clear_queue(void) SDL_ClearQueuedAudio(device_id); } -unsigned GB_audio_get_frequency(void) +unsigned GB_audio_get_sample_rate(void) { return have_aspec.freq; } @@ -65,11 +70,11 @@ void GB_audio_queue_sample(GB_sample_t *sample) } } -void GB_audio_init(void) +void GB_audio_init(unsigned sample_rate) { /* Configure Audio */ memset(&want_aspec, 0, sizeof(want_aspec)); - want_aspec.freq = AUDIO_FREQUENCY; + want_aspec.freq = sample_rate == 0 ? GB_audio_default_sample_rate() : sample_rate; want_aspec.format = AUDIO_S16SYS; want_aspec.channels = 2; want_aspec.samples = 512; @@ -94,3 +99,9 @@ void GB_audio_init(void) device_id = SDL_OpenAudioDevice(0, 0, &want_aspec, &have_aspec, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE | SDL_AUDIO_ALLOW_SAMPLES_CHANGE); } + +void GB_audio_destroy() { + GB_audio_set_paused(true); + + SDL_CloseAudioDevice(device_id); +} diff --git a/SDL/main.c b/SDL/main.c index c4a4d0f..81b2bdd 100644 --- a/SDL/main.c +++ b/SDL/main.c @@ -383,15 +383,15 @@ static void gb_audio_callback(GB_gameboy_t *gb, GB_sample_t *sample) if (turbo_down) { static unsigned skip = 0; skip++; - if (skip == GB_audio_get_frequency() / 8) { + if (skip == GB_audio_get_sample_rate() / 8) { skip = 0; } - if (skip > GB_audio_get_frequency() / 16) { + if (skip > GB_audio_get_sample_rate() / 16) { return; } } - if (GB_audio_get_queue_length() / sizeof(*sample) > GB_audio_get_frequency() / 4) { + if (GB_audio_get_queue_length() / sizeof(*sample) > GB_audio_get_sample_rate() / 4) { return; } @@ -488,7 +488,7 @@ restart: GB_set_vblank_callback(&gb, (GB_vblank_callback_t) vblank); GB_set_pixels_output(&gb, active_pixel_buffer); GB_set_rgb_encode_callback(&gb, rgb_encode); - GB_set_sample_rate(&gb, GB_audio_get_frequency()); + GB_set_sample_rate(&gb, GB_audio_get_sample_rate()); GB_set_color_correction_mode(&gb, configuration.color_correction_mode); update_palette(); if ((unsigned)configuration.border_mode <= GB_BORDER_ALWAYS) { @@ -649,7 +649,7 @@ int main(int argc, char **argv) pixel_format = SDL_AllocFormat(SDL_PIXELFORMAT_ABGR8888); } - GB_audio_init(); + GB_audio_init(GB_audio_default_sample_rate()); SDL_EventState(SDL_DROPFILE, SDL_ENABLE); diff --git a/gtk3/main.c b/gtk3/main.c index 8e4619f..e530cdd 100644 --- a/gtk3/main.c +++ b/gtk3/main.c @@ -1,27 +1,7 @@ #include "main.h" - -#ifndef _WIN32 -#define DEFAULT_AUDIO_SAMPLE_RATE 96000 -#else -/* Windows (well, at least my VM) can't handle 96KHz sound well :( */ - -/* felsqualle says: For SDL 2.0.6+ using the WASAPI driver, the highest freq. - we can get is 48000. 96000 also works, but always has some faint crackling in - the audio, no matter how high or low I set the buffer length... - Not quite satisfied with that solution, because acc. to SDL2 docs, - 96k + WASAPI *should* work. */ - -#define DEFAULT_AUDIO_SAMPLE_RATE 48000 -#endif - -/* Compatibility with older SDL versions */ -#ifndef SDL_AUDIO_ALLOW_SAMPLES_CHANGE -#define SDL_AUDIO_ALLOW_SAMPLES_CHANGE 0 -#endif +#include "../SDL/audio/audio.h" static SDL_GameController *controller = NULL; -static SDL_AudioSpec want_aspec, have_aspec; -static SDL_AudioDeviceID device_id; static const GThread *main_thread; @@ -324,49 +304,28 @@ static gboolean init_controllers() { return true; } +static bool audio_initialized = false; static gboolean init_audio() { - bool audio_playing = SDL_GetAudioDeviceStatus(device_id) == SDL_AUDIO_PLAYING; - SDL_PauseAudioDevice(device_id, 1); - SDL_ClearQueuedAudio(device_id); - SDL_QuitSubSystem(SDL_INIT_AUDIO); + bool audio_playing = GB_audio_is_playing(); + if (audio_initialized) { + GB_audio_destroy(); + } + +#ifdef USE_SDL_AUDIO if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) { g_warning("Failed to initialize audio: %s", SDL_GetError()); return false; } - - memset(&want_aspec, 0, sizeof(want_aspec)); - want_aspec.freq = gui_data.sample_rate; - want_aspec.format = AUDIO_S16SYS; - want_aspec.channels = 2; - want_aspec.samples = 512; - - SDL_version _sdl_version; - SDL_GetVersion(&_sdl_version); - unsigned sdl_version = _sdl_version.major * 1000 + _sdl_version.minor * 100 + _sdl_version.patch; - -#ifndef _WIN32 - /* SDL 2.0.5 on macOS and Linux introduced a bug where certain combinations of buffer lengths and frequencies - fail to produce audio correctly. */ - if (sdl_version >= 2005) { - want_aspec.samples = 2048; - } -#else - if (sdl_version < 2006) { - /* Since WASAPI audio was introduced in SDL 2.0.6, we have to lower the audio frequency - to 44100 because otherwise we would get garbled audio output.*/ - want_aspec.freq = 44100; - } #endif - device_id = SDL_OpenAudioDevice(0, 0, &want_aspec, &have_aspec, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE | SDL_AUDIO_ALLOW_SAMPLES_CHANGE); + 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); - g_debug("Requested Sample Rate: %d Hz\nUsed Sample Rate: %d Hz", want_aspec.freq, have_aspec.freq); - - SDL_PauseAudioDevice(device_id, audio_playing? 0 : 1); - GB_set_sample_rate(&gb, have_aspec.freq); - - return true; + return audio_initialized = true; } static GB_model_t get_model() { @@ -395,19 +354,21 @@ static void gb_audio_callback(GB_gameboy_t *gb, GB_sample_t *sample) { if (turbo_down) { static unsigned skip = 0; skip++; - if (skip == have_aspec.freq / 8) { + + if (skip == GB_audio_get_sample_rate() / 8) { skip = 0; } - if (skip > have_aspec.freq / 16) { + + if (skip > GB_audio_get_sample_rate() / 16) { return; } } - if (SDL_GetQueuedAudioSize(device_id) / sizeof(*sample) > have_aspec.freq / 4) { + if (GB_audio_get_queue_length() / sizeof(*sample) > GB_audio_get_sample_rate() / 4) { return; } - SDL_QueueAudio(device_id, sample, sizeof(*sample)); + GB_audio_queue_sample(sample); } // Console TODO: @@ -826,7 +787,7 @@ static void startup(GApplication *app, gpointer gui_data_gptr) { printer = GTK_WINDOW(get_object("printer")); if (config.sample_rate == -1) { - gui_data->sample_rate = DEFAULT_AUDIO_SAMPLE_RATE; + gui_data->sample_rate = GB_audio_default_sample_rate(); } else { gui_data->sample_rate = config.sample_rate; @@ -1058,7 +1019,7 @@ static gboolean on_key_press(GtkWidget *w, GdkEventKey *event, gpointer data) { case GDK_KEY_space: { turbo_down = event->type == GDK_KEY_PRESS; - SDL_ClearQueuedAudio(device_id); + GB_audio_clear_queue(); GB_set_turbo_mode(&gb, turbo_down, turbo_down && rewind_down); break; } @@ -1259,14 +1220,7 @@ static void on_model_changed(GSimpleAction *action, GVariant *value, gpointer us static void on_mute_changed(GSimpleAction *action, GVariant *value, gpointer user_data) { gboolean do_mute = g_variant_get_boolean(value); - if (do_mute) { - SDL_PauseAudioDevice(device_id, 1); - } - else { - SDL_ClearQueuedAudio(device_id); - SDL_PauseAudioDevice(device_id, 0); - } - + GB_audio_set_paused(do_mute); g_simple_action_set_state(action, value); } @@ -1705,7 +1659,7 @@ G_MODULE_EXPORT void on_sample_rate_changed(GtkWidget *w, gpointer user_data_gpt config.sample_rate = g_ascii_strtoll(gtk_combo_box_get_active_id(box), NULL, 10); if (config.sample_rate == -1) { - gui_data.sample_rate = DEFAULT_AUDIO_SAMPLE_RATE; + gui_data.sample_rate = GB_audio_default_sample_rate(); } else { gui_data.sample_rate = config.sample_rate; @@ -2198,7 +2152,7 @@ static void init(GuiData *gui_data) { GB_set_vblank_callback(&gb, vblank); GB_set_pixels_output(&gb, get_current_buffer()); GB_set_rgb_encode_callback(&gb, rgb_encode); - GB_set_sample_rate(&gb, gui_data->sample_rate); + GB_set_sample_rate(&gb, GB_audio_get_sample_rate()); GB_set_color_correction_mode(&gb, get_color_correction_mode()); GB_set_highpass_filter_mode(&gb, get_highpass_mode()); GB_set_rewind_length(&gb, config.rewind_duration); @@ -2280,7 +2234,7 @@ static void load_boot_rom(GB_gameboy_t *gb, GB_boot_rom_t type) { static void stop(GuiData *gui_data) { if (!running) return; - SDL_PauseAudioDevice(device_id, 1); + GB_audio_set_paused(true); GB_debugger_set_disabled(&gb, true); if (GB_debugger_is_stopped(&gb)) { @@ -2341,8 +2295,8 @@ static void start(GuiData *gui_data) { running = true; gui_data->stopped = false; - SDL_ClearQueuedAudio(device_id); - SDL_PauseAudioDevice(device_id, 0); + GB_audio_clear_queue(); + GB_audio_set_paused(false); /* Run emulation */ while (running) {