Move the audio code to a different file

This commit is contained in:
Lior Halphon 2020-04-27 21:12:30 +03:00
parent 110cedeaac
commit 936a39f624
4 changed files with 119 additions and 68 deletions

View File

@ -37,6 +37,7 @@ endif
VERSION := 0.12.3 VERSION := 0.12.3
export VERSION export VERSION
CONF ?= debug CONF ?= debug
SDL_AUDIO_DRIVER ?= sdl
BIN := build/bin BIN := build/bin
OBJ := build/obj OBJ := build/obj
@ -172,7 +173,7 @@ all: cocoa sdl tester libretro
# Get a list of our source files and their respective object file targets # Get a list of our source files and their respective object file targets
CORE_SOURCES := $(shell ls Core/*.c) CORE_SOURCES := $(shell ls Core/*.c)
SDL_SOURCES := $(shell ls SDL/*.c) $(OPEN_DIALOG) SDL_SOURCES := $(shell ls SDL/*.c) $(OPEN_DIALOG) SDL/audio/$(SDL_AUDIO_DRIVER).c
TESTER_SOURCES := $(shell ls Tester/*.c) TESTER_SOURCES := $(shell ls Tester/*.c)
ifeq ($(PLATFORM),Darwin) ifeq ($(PLATFORM),Darwin)

16
SDL/audio/audio.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef sdl_audio_h
#define sdl_audio_h
#include <stdbool.h>
#include <stddef.h>
#include <Core/gb.h>
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);
size_t GB_audio_get_queue_length(void);
void GB_audio_queue_sample(GB_sample_t *sample);
void GB_audio_init(void);
#endif /* sdl_audio_h */

87
SDL/audio/sdl.c Normal file
View File

@ -0,0 +1,87 @@
#include "audio.h"
#include <SDL.h>
#ifndef _WIN32
#define AUDIO_FREQUENCY 96000
#include <unistd.h>
#else
#include <Windows.h>
/* 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 AUDIO_FREQUENCY 48000
#endif
/* Compatibility with older SDL versions */
#ifndef SDL_AUDIO_ALLOW_SAMPLES_CHANGE
#define SDL_AUDIO_ALLOW_SAMPLES_CHANGE 0
#endif
static SDL_AudioDeviceID device_id;
static SDL_AudioSpec want_aspec, have_aspec;
bool GB_audio_is_playing(void)
{
return SDL_GetAudioDeviceStatus(device_id) == SDL_AUDIO_PLAYING;
}
void GB_audio_set_paused(bool paused)
{
GB_audio_clear_queue();
SDL_PauseAudioDevice(device_id, paused);
}
void GB_audio_clear_queue(void)
{
SDL_ClearQueuedAudio(device_id);
}
unsigned GB_audio_get_frequency(void)
{
return have_aspec.freq;
}
size_t GB_audio_get_queue_length(void)
{
return SDL_GetQueuedAudioSize(device_id);
}
void GB_audio_queue_sample(GB_sample_t *sample)
{
SDL_QueueAudio(device_id, sample, sizeof(*sample));
}
void GB_audio_init(void)
{
/* Configure Audio */
memset(&want_aspec, 0, sizeof(want_aspec));
want_aspec.freq = AUDIO_FREQUENCY;
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);
}

View File

@ -8,27 +8,12 @@
#include "utils.h" #include "utils.h"
#include "gui.h" #include "gui.h"
#include "shader.h" #include "shader.h"
#include "audio/audio.h"
#ifndef _WIN32 #ifndef _WIN32
#define AUDIO_FREQUENCY 96000
#include <unistd.h> #include <unistd.h>
#else #else
#include <Windows.h> #include <Windows.h>
/* 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 AUDIO_FREQUENCY 48000
#endif
/* Compatibility with older SDL versions */
#ifndef SDL_AUDIO_ALLOW_SAMPLES_CHANGE
#define SDL_AUDIO_ALLOW_SAMPLES_CHANGE 0
#endif #endif
GB_gameboy_t gb; GB_gameboy_t gb;
@ -42,7 +27,6 @@ static char *filename = NULL;
static typeof(free) *free_function = NULL; static typeof(free) *free_function = NULL;
static char *battery_save_path_ptr; static char *battery_save_path_ptr;
SDL_AudioDeviceID device_id;
void set_filename(const char *new_filename, typeof(free) *new_free_function) void set_filename(const char *new_filename, typeof(free) *new_free_function)
{ {
@ -53,8 +37,6 @@ void set_filename(const char *new_filename, typeof(free) *new_free_function)
free_function = new_free_function; free_function = new_free_function;
} }
static SDL_AudioSpec want_aspec, have_aspec;
static char *captured_log = NULL; static char *captured_log = NULL;
static void log_capture_callback(GB_gameboy_t *gb, const char *string, GB_log_attributes attributes) static void log_capture_callback(GB_gameboy_t *gb, const char *string, GB_log_attributes attributes)
@ -127,16 +109,15 @@ static void screen_size_changed(void)
static void open_menu(void) static void open_menu(void)
{ {
bool audio_playing = SDL_GetAudioDeviceStatus(device_id) == SDL_AUDIO_PLAYING; bool audio_playing = GB_audio_is_playing();
if (audio_playing) { if (audio_playing) {
SDL_PauseAudioDevice(device_id, 1); GB_audio_set_paused(true);
} }
size_t previous_width = GB_get_screen_width(&gb); size_t previous_width = GB_get_screen_width(&gb);
run_gui(true); run_gui(true);
SDL_ShowCursor(SDL_DISABLE); SDL_ShowCursor(SDL_DISABLE);
if (audio_playing) { if (audio_playing) {
SDL_ClearQueuedAudio(device_id); GB_audio_set_paused(false);
SDL_PauseAudioDevice(device_id, 0);
} }
GB_set_color_correction_mode(&gb, configuration.color_correction_mode); GB_set_color_correction_mode(&gb, configuration.color_correction_mode);
GB_set_border_mode(&gb, configuration.border_mode); GB_set_border_mode(&gb, configuration.border_mode);
@ -176,7 +157,7 @@ static void handle_events(GB_gameboy_t *gb)
GB_set_key_state(gb, (GB_key_t) button, event.type == SDL_JOYBUTTONDOWN); GB_set_key_state(gb, (GB_key_t) button, event.type == SDL_JOYBUTTONDOWN);
} }
else if (button == JOYPAD_BUTTON_TURBO) { else if (button == JOYPAD_BUTTON_TURBO) {
SDL_ClearQueuedAudio(device_id); GB_audio_clear_queue();
turbo_down = event.type == SDL_JOYBUTTONDOWN; turbo_down = event.type == SDL_JOYBUTTONDOWN;
GB_set_turbo_mode(gb, turbo_down, turbo_down && rewind_down); GB_set_turbo_mode(gb, turbo_down, turbo_down && rewind_down);
} }
@ -294,14 +275,7 @@ static void handle_events(GB_gameboy_t *gb)
break; break;
} }
#endif #endif
bool audio_playing = SDL_GetAudioDeviceStatus(device_id) == SDL_AUDIO_PLAYING; GB_audio_set_paused(GB_audio_is_playing());
if (audio_playing) {
SDL_PauseAudioDevice(device_id, 1);
}
else if (!audio_playing) {
SDL_ClearQueuedAudio(device_id);
SDL_PauseAudioDevice(device_id, 0);
}
} }
break; break;
@ -336,7 +310,7 @@ static void handle_events(GB_gameboy_t *gb)
case SDL_KEYUP: // Fallthrough case SDL_KEYUP: // Fallthrough
if (event.key.keysym.scancode == configuration.keys[8]) { if (event.key.keysym.scancode == configuration.keys[8]) {
turbo_down = event.type == SDL_KEYDOWN; turbo_down = event.type == SDL_KEYDOWN;
SDL_ClearQueuedAudio(device_id); GB_audio_clear_queue();
GB_set_turbo_mode(gb, turbo_down, turbo_down && rewind_down); GB_set_turbo_mode(gb, turbo_down, turbo_down && rewind_down);
} }
else if (event.key.keysym.scancode == configuration.keys_2[0]) { else if (event.key.keysym.scancode == configuration.keys_2[0]) {
@ -409,15 +383,15 @@ static void gb_audio_callback(GB_gameboy_t *gb, GB_sample_t *sample)
if (turbo_down) { if (turbo_down) {
static unsigned skip = 0; static unsigned skip = 0;
skip++; skip++;
if (skip == have_aspec.freq / 8) { if (skip == GB_audio_get_frequency() / 8) {
skip = 0; skip = 0;
} }
if (skip > have_aspec.freq / 16) { if (skip > GB_audio_get_frequency() / 16) {
return; return;
} }
} }
if (SDL_GetQueuedAudioSize(device_id) / sizeof(*sample) > have_aspec.freq / 4) { if (GB_audio_get_queue_length() / sizeof(*sample) > GB_audio_get_frequency() / 4) {
return; return;
} }
@ -426,7 +400,7 @@ static void gb_audio_callback(GB_gameboy_t *gb, GB_sample_t *sample)
sample->right = sample->right * configuration.volume / 100; sample->right = sample->right * configuration.volume / 100;
} }
SDL_QueueAudio(device_id, sample, sizeof(*sample)); GB_audio_queue_sample(sample);
} }
@ -514,7 +488,7 @@ restart:
GB_set_vblank_callback(&gb, (GB_vblank_callback_t) vblank); GB_set_vblank_callback(&gb, (GB_vblank_callback_t) vblank);
GB_set_pixels_output(&gb, active_pixel_buffer); GB_set_pixels_output(&gb, active_pixel_buffer);
GB_set_rgb_encode_callback(&gb, rgb_encode); GB_set_rgb_encode_callback(&gb, rgb_encode);
GB_set_sample_rate(&gb, have_aspec.freq); GB_set_sample_rate(&gb, GB_audio_get_frequency());
GB_set_color_correction_mode(&gb, configuration.color_correction_mode); GB_set_color_correction_mode(&gb, configuration.color_correction_mode);
update_palette(); update_palette();
if ((unsigned)configuration.border_mode <= GB_BORDER_ALWAYS) { if ((unsigned)configuration.border_mode <= GB_BORDER_ALWAYS) {
@ -675,34 +649,7 @@ int main(int argc, char **argv)
pixel_format = SDL_AllocFormat(SDL_PIXELFORMAT_ABGR8888); pixel_format = SDL_AllocFormat(SDL_PIXELFORMAT_ABGR8888);
} }
GB_audio_init();
/* Configure Audio */
memset(&want_aspec, 0, sizeof(want_aspec));
want_aspec.freq = AUDIO_FREQUENCY;
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);
/* Start Audio */
SDL_EventState(SDL_DROPFILE, SDL_ENABLE); SDL_EventState(SDL_DROPFILE, SDL_ENABLE);
@ -735,7 +682,7 @@ int main(int argc, char **argv)
else { else {
connect_joypad(); connect_joypad();
} }
SDL_PauseAudioDevice(device_id, 0); GB_audio_set_paused(false);
run(); // Never returns run(); // Never returns
return 0; return 0;
} }