Make the portaudio frontend sync to audio
This commit is contained in:
parent
1abb6e62f4
commit
b4335e5934
@ -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 */
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
|
21
SDL/main.c
21
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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user