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);
|
size_t GB_audio_get_queue_length(void);
|
||||||
void GB_audio_queue_sample(GB_sample_t *sample);
|
void GB_audio_queue_sample(GB_sample_t *sample);
|
||||||
void GB_audio_init(void);
|
void GB_audio_init(void);
|
||||||
|
bool GB_audio_set_sync_mode(bool sync_mode);
|
||||||
|
|
||||||
#endif /* sdl_audio_h */
|
#endif /* sdl_audio_h */
|
||||||
|
@ -1,20 +1,22 @@
|
|||||||
#include "audio.h"
|
#include "audio.h"
|
||||||
#include <portaudio.h>
|
#include <portaudio.h>
|
||||||
#include <pthread.h>
|
|
||||||
|
|
||||||
|
|
||||||
#define AUDIO_FREQUENCY 96000
|
#define AUDIO_FREQUENCY 96000
|
||||||
static PaStream *stream;
|
static PaStream *stream;
|
||||||
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
|
static size_t buffer_position = 0;
|
||||||
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
|
static GB_sample_t buffer[4096];
|
||||||
static size_t buffer_position = 0, buffer_size = 0, buffer_needed = 0;
|
static bool blocking_mode = false;
|
||||||
static GB_sample_t *buffer = NULL;
|
|
||||||
static bool playing = false;
|
|
||||||
|
|
||||||
|
bool GB_audio_set_sync_mode(bool sync_mode)
|
||||||
|
{
|
||||||
|
blocking_mode = sync_mode;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool GB_audio_is_playing(void)
|
bool GB_audio_is_playing(void)
|
||||||
{
|
{
|
||||||
return playing;
|
return stream && Pa_IsStreamActive(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GB_audio_set_paused(bool paused)
|
void GB_audio_set_paused(bool paused)
|
||||||
@ -22,17 +24,10 @@ void GB_audio_set_paused(bool paused)
|
|||||||
if (!stream) return;
|
if (!stream) return;
|
||||||
|
|
||||||
if (paused) {
|
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);
|
Pa_StopStream(stream);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Pa_StartStream(stream);
|
Pa_StartStream(stream);
|
||||||
playing = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,67 +50,32 @@ void GB_audio_queue_sample(GB_sample_t *sample)
|
|||||||
{
|
{
|
||||||
if (!stream) return;
|
if (!stream) return;
|
||||||
|
|
||||||
pthread_mutex_lock(&lock);
|
if (buffer_position < sizeof(buffer) / sizeof(buffer[0])) {
|
||||||
if (!GB_audio_is_playing()) {
|
buffer[buffer_position++] = *sample;
|
||||||
pthread_mutex_unlock(&lock);
|
if (blocking_mode) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buffer_position == buffer_size) {
|
|
||||||
if (buffer_size >= 0x4000) {
|
|
||||||
buffer_position = 0;
|
|
||||||
pthread_mutex_unlock(&lock);
|
|
||||||
return;
|
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 {
|
else {
|
||||||
memcpy(out, buffer + (buffer_position - frames), frames * sizeof(*buffer));
|
if (blocking_mode) {
|
||||||
buffer_position = 0;
|
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)
|
void GB_audio_init(void)
|
||||||
@ -126,8 +86,8 @@ void GB_audio_init(void)
|
|||||||
2,
|
2,
|
||||||
paInt16,
|
paInt16,
|
||||||
AUDIO_FREQUENCY,
|
AUDIO_FREQUENCY,
|
||||||
paFramesPerBufferUnspecified,
|
sizeof(buffer) / sizeof(buffer[0]),
|
||||||
callback,
|
NULL,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,11 @@
|
|||||||
static SDL_AudioDeviceID device_id;
|
static SDL_AudioDeviceID device_id;
|
||||||
static SDL_AudioSpec want_aspec, have_aspec;
|
static SDL_AudioSpec want_aspec, have_aspec;
|
||||||
|
|
||||||
|
bool GB_audio_set_sync_mode(bool sync_mode)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool GB_audio_is_playing(void)
|
bool GB_audio_is_playing(void)
|
||||||
{
|
{
|
||||||
return SDL_GetAudioDeviceStatus(device_id) == SDL_AUDIO_PLAYING;
|
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)
|
void GB_audio_init(void)
|
||||||
{
|
{
|
||||||
|
SDL_Init(SDL_INIT_AUDIO);
|
||||||
/* Configure Audio */
|
/* Configure Audio */
|
||||||
memset(&want_aspec, 0, sizeof(want_aspec));
|
memset(&want_aspec, 0, sizeof(want_aspec));
|
||||||
want_aspec.freq = AUDIO_FREQUENCY;
|
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 typeof(free) *free_function = NULL;
|
||||||
static char *battery_save_path_ptr;
|
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)
|
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) {
|
else if (button == JOYPAD_BUTTON_TURBO) {
|
||||||
GB_audio_clear_queue();
|
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);
|
update_turbo_mode();
|
||||||
}
|
}
|
||||||
else if (button == JOYPAD_BUTTON_SLOW_MOTION) {
|
else if (button == JOYPAD_BUTTON_SLOW_MOTION) {
|
||||||
underclock_down = event.type == SDL_JOYBUTTONDOWN;
|
underclock_down = event.type == SDL_JOYBUTTONDOWN;
|
||||||
@ -169,7 +179,7 @@ static void handle_events(GB_gameboy_t *gb)
|
|||||||
if (event.type == SDL_JOYBUTTONUP) {
|
if (event.type == SDL_JOYBUTTONUP) {
|
||||||
rewind_paused = false;
|
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) {
|
else if (button == JOYPAD_BUTTON_MENU && event.type == SDL_JOYBUTTONDOWN) {
|
||||||
open_menu();
|
open_menu();
|
||||||
@ -311,14 +321,14 @@ static void handle_events(GB_gameboy_t *gb)
|
|||||||
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;
|
||||||
GB_audio_clear_queue();
|
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]) {
|
else if (event.key.keysym.scancode == configuration.keys_2[0]) {
|
||||||
rewind_down = event.type == SDL_KEYDOWN;
|
rewind_down = event.type == SDL_KEYDOWN;
|
||||||
if (event.type == SDL_KEYUP) {
|
if (event.type == SDL_KEYUP) {
|
||||||
rewind_paused = false;
|
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]) {
|
else if (event.key.keysym.scancode == configuration.keys_2[1]) {
|
||||||
underclock_down = event.type == SDL_KEYDOWN;
|
underclock_down = event.type == SDL_KEYDOWN;
|
||||||
@ -615,7 +625,7 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
signal(SIGINT, debugger_interrupt);
|
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_MAJOR_VERSION, 3);
|
||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
|
||||||
@ -683,6 +693,7 @@ int main(int argc, char **argv)
|
|||||||
connect_joypad();
|
connect_joypad();
|
||||||
}
|
}
|
||||||
GB_audio_set_paused(false);
|
GB_audio_set_paused(false);
|
||||||
|
update_turbo_mode();
|
||||||
run(); // Never returns
|
run(); // Never returns
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user