From b4335e593462cc2356e2c329d15aa702f98a1660 Mon Sep 17 00:00:00 2001 From: Lior Halphon Date: Tue, 28 Apr 2020 19:43:36 +0300 Subject: [PATCH] Make the portaudio frontend sync to audio --- SDL/audio/audio.h | 1 + SDL/audio/portaudio.c | 104 +++++++++++++----------------------------- SDL/audio/sdl.c | 6 +++ SDL/main.c | 21 +++++++-- 4 files changed, 55 insertions(+), 77 deletions(-) diff --git a/SDL/audio/audio.h b/SDL/audio/audio.h index acaa011..e575f53 100644 --- a/SDL/audio/audio.h +++ b/SDL/audio/audio.h @@ -12,5 +12,6 @@ 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); +bool GB_audio_set_sync_mode(bool sync_mode); #endif /* sdl_audio_h */ diff --git a/SDL/audio/portaudio.c b/SDL/audio/portaudio.c index 5ce0e24..4fab01d 100644 --- a/SDL/audio/portaudio.c +++ b/SDL/audio/portaudio.c @@ -1,20 +1,22 @@ #include "audio.h" #include -#include #define AUDIO_FREQUENCY 96000 static PaStream *stream; -static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; -static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; -static size_t buffer_position = 0, buffer_size = 0, buffer_needed = 0; -static GB_sample_t *buffer = NULL; -static bool playing = false; +static size_t buffer_position = 0; +static GB_sample_t buffer[4096]; +static bool blocking_mode = false; +bool GB_audio_set_sync_mode(bool sync_mode) +{ + blocking_mode = sync_mode; + return true; +} bool GB_audio_is_playing(void) { - return playing; + return stream && Pa_IsStreamActive(stream); } void GB_audio_set_paused(bool paused) @@ -22,17 +24,10 @@ void GB_audio_set_paused(bool paused) if (!stream) return; if (paused) { - Pa_Sleep(1000); - pthread_mutex_lock(&lock); - playing = false; - GB_audio_clear_queue(); - pthread_cond_signal(&cond); - pthread_mutex_unlock(&lock); Pa_StopStream(stream); } else { Pa_StartStream(stream); - playing = true; } } @@ -55,67 +50,32 @@ void GB_audio_queue_sample(GB_sample_t *sample) { if (!stream) return; - pthread_mutex_lock(&lock); - if (!GB_audio_is_playing()) { - pthread_mutex_unlock(&lock); - return; - } - - if (buffer_position == buffer_size) { - if (buffer_size >= 0x4000) { - buffer_position = 0; - pthread_mutex_unlock(&lock); + if (buffer_position < sizeof(buffer) / sizeof(buffer[0])) { + buffer[buffer_position++] = *sample; + if (blocking_mode) { return; } - - if (buffer_size == 0) { - buffer_size = 512; - } - else { - buffer_size += buffer_size >> 2; - } - buffer = realloc(buffer, sizeof(*sample) * buffer_size); - } - buffer[buffer_position++] = *sample; - if (buffer_position == buffer_needed) { - pthread_cond_signal(&cond); - buffer_needed = 0; - } - pthread_mutex_unlock(&lock); -} - -static int callback(const void *in, void *_out, - unsigned long frames, - const PaStreamCallbackTimeInfo *time_info, - PaStreamCallbackFlags status_flags, - void *unused) -{ - GB_sample_t *out = (GB_sample_t *)_out; - pthread_mutex_lock(&lock); - - if (buffer_position < frames) { - buffer_needed = frames; - pthread_cond_wait(&cond, &lock); - } - - if (!playing) { - memset(out, 0, frames * sizeof(*out)); - pthread_mutex_unlock(&lock); - return 0; - } - - if (buffer_position >= frames && buffer_position < frames + 4800) { - memcpy(out, buffer, frames * sizeof(*buffer)); - memmove(buffer, buffer + frames, (buffer_position - frames) * sizeof(*buffer)); - buffer_position -= frames; } else { - memcpy(out, buffer + (buffer_position - frames), frames * sizeof(*buffer)); - buffer_position = 0; + if (blocking_mode) { + Pa_WriteStream(stream, buffer, sizeof(buffer) / sizeof(buffer[0])); + buffer_position = 0; + return; + } + } + + + size_t write_legnth = Pa_GetStreamWriteAvailable(stream); + + if (write_legnth > buffer_position) { + write_legnth = buffer_position; + } + + if (write_legnth) { + Pa_WriteStream(stream, buffer, write_legnth); + memmove(buffer, buffer + write_legnth, sizeof(buffer[0]) * (buffer_position - write_legnth)); + buffer_position -= write_legnth; } - pthread_mutex_unlock(&lock); - - return 0; } void GB_audio_init(void) @@ -126,8 +86,8 @@ void GB_audio_init(void) 2, paInt16, AUDIO_FREQUENCY, - paFramesPerBufferUnspecified, - callback, + sizeof(buffer) / sizeof(buffer[0]), + NULL, NULL); } diff --git a/SDL/audio/sdl.c b/SDL/audio/sdl.c index 1f8a529..d997d83 100644 --- a/SDL/audio/sdl.c +++ b/SDL/audio/sdl.c @@ -25,6 +25,11 @@ static SDL_AudioDeviceID device_id; static SDL_AudioSpec want_aspec, have_aspec; +bool GB_audio_set_sync_mode(bool sync_mode) +{ + return false; +} + bool GB_audio_is_playing(void) { return SDL_GetAudioDeviceStatus(device_id) == SDL_AUDIO_PLAYING; @@ -58,6 +63,7 @@ void GB_audio_queue_sample(GB_sample_t *sample) void GB_audio_init(void) { + SDL_Init(SDL_INIT_AUDIO); /* Configure Audio */ memset(&want_aspec, 0, sizeof(want_aspec)); want_aspec.freq = AUDIO_FREQUENCY; diff --git a/SDL/main.c b/SDL/main.c index c4a4d0f..704011e 100644 --- a/SDL/main.c +++ b/SDL/main.c @@ -27,6 +27,16 @@ static char *filename = NULL; static typeof(free) *free_function = NULL; static char *battery_save_path_ptr; +static void update_turbo_mode(void) +{ + if (GB_audio_set_sync_mode(!turbo_down) && !turbo_down) { + GB_set_turbo_mode(&gb, true, true); + } + else { + // Sync mode is not supported + GB_set_turbo_mode(&gb, turbo_down, turbo_down && rewind_down); + } +} void set_filename(const char *new_filename, typeof(free) *new_free_function) { @@ -159,7 +169,7 @@ static void handle_events(GB_gameboy_t *gb) else if (button == JOYPAD_BUTTON_TURBO) { GB_audio_clear_queue(); turbo_down = event.type == SDL_JOYBUTTONDOWN; - GB_set_turbo_mode(gb, turbo_down, turbo_down && rewind_down); + update_turbo_mode(); } else if (button == JOYPAD_BUTTON_SLOW_MOTION) { underclock_down = event.type == SDL_JOYBUTTONDOWN; @@ -169,7 +179,7 @@ static void handle_events(GB_gameboy_t *gb) if (event.type == SDL_JOYBUTTONUP) { rewind_paused = false; } - GB_set_turbo_mode(gb, turbo_down, turbo_down && rewind_down); + update_turbo_mode(); } else if (button == JOYPAD_BUTTON_MENU && event.type == SDL_JOYBUTTONDOWN) { open_menu(); @@ -311,14 +321,14 @@ static void handle_events(GB_gameboy_t *gb) if (event.key.keysym.scancode == configuration.keys[8]) { turbo_down = event.type == SDL_KEYDOWN; GB_audio_clear_queue(); - GB_set_turbo_mode(gb, turbo_down, turbo_down && rewind_down); + update_turbo_mode(); } else if (event.key.keysym.scancode == configuration.keys_2[0]) { rewind_down = event.type == SDL_KEYDOWN; if (event.type == SDL_KEYUP) { rewind_paused = false; } - GB_set_turbo_mode(gb, turbo_down, turbo_down && rewind_down); + update_turbo_mode(); } else if (event.key.keysym.scancode == configuration.keys_2[1]) { underclock_down = event.type == SDL_KEYDOWN; @@ -615,7 +625,7 @@ int main(int argc, char **argv) signal(SIGINT, debugger_interrupt); - SDL_Init(SDL_INIT_EVERYTHING); + SDL_Init(SDL_INIT_EVERYTHING & ~SDL_INIT_AUDIO); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); @@ -683,6 +693,7 @@ int main(int argc, char **argv) connect_joypad(); } GB_audio_set_paused(false); + update_turbo_mode(); run(); // Never returns return 0; }