Make the portaudio frontend sync to audio

This commit is contained in:
Lior Halphon 2020-04-28 19:43:36 +03:00
parent 1abb6e62f4
commit b4335e5934
4 changed files with 55 additions and 77 deletions

View File

@ -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 */

View File

@ -1,20 +1,22 @@
#include "audio.h"
#include <portaudio.h>
#include <pthread.h>
#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;
}
}
pthread_mutex_unlock(&lock);
return 0;
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;
}
}
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);
}

View File

@ -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;

View File

@ -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;
}