# HG changeset patch # User Michael Pavone # Date 1522305368 25200 # Node ID ce1f93be0104560c2e2cd50dcb892dede53af866 # Parent b525491b4e5b319f88858d21c79448bfd9065e17 Small cleanup to audio interface between emulation code and renderer backend diff -r b525491b4e5b -r ce1f93be0104 genesis.c --- a/genesis.c Mon Mar 26 23:36:39 2018 -0700 +++ b/genesis.c Wed Mar 28 23:36:08 2018 -0700 @@ -1052,6 +1052,8 @@ } } vdp_release_framebuffer(gen->vdp); + render_pause_source(gen->ym->audio); + render_pause_source(gen->psg->audio); } static void start_genesis(system_header *system, char *statefile) @@ -1099,6 +1101,8 @@ map_all_bindings(&gen->io); render_set_video_standard((gen->version_reg & HZ50) ? VID_PAL : VID_NTSC); vdp_reacquire_framebuffer(gen->vdp); + render_resume_source(gen->ym->audio); + render_resume_source(gen->psg->audio); resume_68k(gen->m68k); handle_reset_requests(gen); } diff -r b525491b4e5b -r ce1f93be0104 psg.c --- a/psg.c Mon Mar 26 23:36:39 2018 -0700 +++ b/psg.c Wed Mar 28 23:36:08 2018 -0700 @@ -13,8 +13,8 @@ void psg_init(psg_context * context, uint32_t sample_rate, uint32_t master_clock, uint32_t clock_div, uint32_t samples_frame, uint32_t lowpass_cutoff) { memset(context, 0, sizeof(*context)); - context->audio_buffer = malloc(sizeof(*context->audio_buffer) * samples_frame); - context->back_buffer = malloc(sizeof(*context->audio_buffer) * samples_frame); + context->audio = render_audio_source(1); + context->audio_buffer = render_audio_source_buffer(context->audio); context->clock_inc = clock_div; context->sample_rate = sample_rate; context->samples_frame = samples_frame; @@ -30,10 +30,7 @@ void psg_free(psg_context *context) { - free(context->audio_buffer); - //TODO: Figure out how to make this 100% safe - //audio thread could still be using this - free(context->back_buffer); + render_free_source(context->audio); free(context); } @@ -143,7 +140,8 @@ if (context->buffer_pos == context->samples_frame) { if (!headless) { - render_wait_psg(context); + context->audio_buffer = render_audio_ready(context->audio); + context->buffer_pos = 0; } } } diff -r b525491b4e5b -r ce1f93be0104 psg.h --- a/psg.h Mon Mar 26 23:36:39 2018 -0700 +++ b/psg.h Wed Mar 28 23:36:08 2018 -0700 @@ -8,10 +8,11 @@ #include #include "serialize.h" +#include "render.h" typedef struct { int16_t *audio_buffer; - int16_t *back_buffer; + audio_source *audio; uint64_t buffer_fraction; uint64_t buffer_inc; uint32_t buffer_pos; diff -r b525491b4e5b -r ce1f93be0104 render.h --- a/render.h Mon Mar 26 23:36:39 2018 -0700 +++ b/render.h Wed Mar 28 23:36:08 2018 -0700 @@ -70,8 +70,6 @@ #define FRAMEBUFFER_EVEN 1 #include "vdp.h" -#include "psg.h" -#include "ym2612.h" typedef enum { VID_NTSC, @@ -85,6 +83,7 @@ #define RENDER_NOT_MAPPED -2 #define RENDER_NOT_PLUGGED_IN -3 +typedef struct audio_source audio_source; typedef void (*drop_handler)(const char *filename); uint32_t render_map_color(uint8_t r, uint8_t g, uint8_t b); @@ -96,10 +95,6 @@ void render_toggle_fullscreen(); void render_update_caption(char *title); void render_wait_quit(vdp_context * context); -void render_wait_psg(psg_context * context); -void render_wait_ym(ym2612_context * context); -void render_disable_ym(); -void render_enable_ym(); uint32_t render_audio_buffer(); uint32_t render_sample_rate(); void process_events(); @@ -122,6 +117,13 @@ uint32_t render_elapsed_ms(void); void render_sleep_ms(uint32_t delay); uint8_t render_has_gl(void); +audio_source *render_audio_source(uint8_t channels); +int16_t *render_audio_source_buffer(audio_source *src); +int16_t *render_audio_ready(audio_source *src); +void render_reset_sources(void); +void render_pause_source(audio_source *src); +void render_resume_source(audio_source *src); +void render_free_source(audio_source *src); #endif //RENDER_H_ diff -r b525491b4e5b -r ce1f93be0104 render_sdl.c --- a/render_sdl.c Mon Mar 26 23:36:39 2018 -0700 +++ b/render_sdl.c Wed Mar 28 23:36:08 2018 -0700 @@ -44,64 +44,61 @@ static SDL_mutex * audio_mutex; static SDL_cond * audio_ready; -static SDL_cond * psg_cond; -static SDL_cond * ym_cond; static uint8_t quitting = 0; -static uint8_t ym_enabled = 1; + +struct audio_source { + SDL_cond *cond; + int16_t *front; + int16_t *back; + uint8_t num_channels; + uint8_t front_populated; +}; + +static audio_source *audio_sources[8]; +static uint8_t num_audio_sources; static void audio_callback(void * userdata, uint8_t *byte_stream, int len) { - //puts("audio_callback"); int16_t * stream = (int16_t *)byte_stream; int samples = len/(sizeof(int16_t)*2); - int16_t * psg_buf, * ym_buf; - uint8_t local_quit; + uint8_t num_populated; + memset(stream, 0, len); SDL_LockMutex(audio_mutex); - psg_buf = NULL; - ym_buf = NULL; do { - if (!psg_buf) { - psg_buf = current_psg; - current_psg = NULL; - SDL_CondSignal(psg_cond); + num_populated = 0; + for (uint8_t i = 0; i < num_audio_sources; i++) + { + if (audio_sources[i]->front_populated) { + num_populated++; + } } - if (ym_enabled && !ym_buf) { - ym_buf = current_ym; - current_ym = NULL; - SDL_CondSignal(ym_cond); - } - if (!quitting && (!psg_buf || (ym_enabled && !ym_buf))) { + if (!quitting && num_populated < num_audio_sources) { SDL_CondWait(audio_ready, audio_mutex); } - } while(!quitting && (!psg_buf || (ym_enabled && !ym_buf))); - - local_quit = quitting; - SDL_UnlockMutex(audio_mutex); - if (!local_quit) { - if (ym_enabled) { - for (int i = 0; i < samples; i++) + } while(!quitting && num_populated < num_audio_sources); + if (!quitting) { + int16_t *end = stream + 2*samples; + for (uint8_t i = 0; i < num_audio_sources; i++) { - *(stream++) = psg_buf[i] + *(ym_buf++); - *(stream++) = psg_buf[i] + *(ym_buf++); - } - } else { - for (int i = 0; i < samples; i++) - { - *(stream++) = psg_buf[i]; - *(stream++) = psg_buf[i]; + int16_t *src = audio_sources[i]->front; + if (audio_sources[i]->num_channels == 1) { + for (int16_t *cur = stream; cur < end;) + { + *(cur++) += *src; + *(cur++) += *(src++); + } + } else { + for (int16_t *cur = stream; cur < end;) + { + *(cur++) += *(src++); + *(cur++) += *(src++); + } + } + audio_sources[i]->front_populated = 0; + SDL_CondSignal(audio_sources[i]->cond); } } - } -} - -void render_disable_ym() -{ - ym_enabled = 0; -} - -void render_enable_ym() -{ - ym_enabled = 1; + SDL_UnlockMutex(audio_mutex); } static void render_close_audio() @@ -113,6 +110,59 @@ SDL_CloseAudio(); } +audio_source *render_audio_source(uint8_t channels) +{ + audio_source *ret = NULL; + SDL_LockMutex(audio_mutex); + if (num_audio_sources < 8) { + ret = malloc(sizeof(audio_source)); + ret->front = malloc(channels * buffer_samples * sizeof(int16_t)); + ret->back = malloc(channels * buffer_samples * sizeof(int16_t)); + ret->front_populated = 0; + ret->cond = SDL_CreateCond(); + ret->num_channels = channels; + audio_sources[num_audio_sources++] = ret; + } + SDL_UnlockMutex(audio_mutex); + if (!ret) { + fatal_error("Too many audio sources!"); + } + return ret; +} + +void render_pause_source(audio_source *src) +{ + SDL_LockMutex(audio_mutex); + for (uint8_t i = 0; i < num_audio_sources; i++) + { + if (audio_sources[i] == src) { + audio_sources[i] = audio_sources[--num_audio_sources]; + SDL_CondSignal(audio_ready); + break; + } + } + SDL_UnlockMutex(audio_mutex); +} + +void render_resume_source(audio_source *src) +{ + SDL_LockMutex(audio_mutex); + if (num_audio_sources < 8) { + audio_sources[num_audio_sources++] = src; + } + SDL_UnlockMutex(audio_mutex); +} + +void render_free_source(audio_source *src) +{ + render_pause_source(src); + + free(src->front); + free(src->back); + SDL_DestroyCond(src->cond); + free(src); +} + static SDL_Joystick * joysticks[MAX_JOYSTICKS]; static int joystick_sdl_index[MAX_JOYSTICKS]; @@ -480,8 +530,6 @@ caption = title; audio_mutex = SDL_CreateMutex(); - psg_cond = SDL_CreateCond(); - ym_cond = SDL_CreateCond(); audio_ready = SDL_CreateCond(); SDL_AudioSpec desired, actual; @@ -1190,34 +1238,24 @@ in_toggle = 0; } -void render_wait_psg(psg_context * context) +int16_t *render_audio_source_buffer(audio_source *src) +{ + return src->back; +} + +int16_t *render_audio_ready(audio_source *src) { SDL_LockMutex(audio_mutex); - while (current_psg != NULL) { - SDL_CondWait(psg_cond, audio_mutex); + while (src->front_populated) { + SDL_CondWait(src->cond, audio_mutex); } - current_psg = context->audio_buffer; + int16_t *tmp = src->front; + src->front = src->back; + src->back = tmp; + src->front_populated = 1; SDL_CondSignal(audio_ready); - - context->audio_buffer = context->back_buffer; - context->back_buffer = current_psg; SDL_UnlockMutex(audio_mutex); - context->buffer_pos = 0; -} - -void render_wait_ym(ym2612_context * context) -{ - SDL_LockMutex(audio_mutex); - while (current_ym != NULL) { - SDL_CondWait(ym_cond, audio_mutex); - } - current_ym = context->audio_buffer; - SDL_CondSignal(audio_ready); - - context->audio_buffer = context->back_buffer; - context->back_buffer = current_ym; - SDL_UnlockMutex(audio_mutex); - context->buffer_pos = 0; + return src->back; } uint32_t render_audio_buffer() diff -r b525491b4e5b -r ce1f93be0104 sms.c --- a/sms.c Mon Mar 26 23:36:39 2018 -0700 +++ b/sms.c Wed Mar 28 23:36:08 2018 -0700 @@ -336,7 +336,6 @@ static void run_sms(system_header *system) { - render_disable_ym(); sms_context *sms = (sms_context *)system; uint32_t target_cycle = sms->z80->current_cycle + 3420*16; //TODO: PAL support @@ -387,14 +386,15 @@ } } vdp_release_framebuffer(sms->vdp); + render_pause_source(sms->psg->audio); sms->should_return = 0; - render_enable_ym(); } static void resume_sms(system_header *system) { sms_context *sms = (sms_context *)system; vdp_reacquire_framebuffer(sms->vdp); + render_resume_source(sms->psg->audio); run_sms(system); } diff -r b525491b4e5b -r ce1f93be0104 ym2612.c --- a/ym2612.c Mon Mar 26 23:36:39 2018 -0700 +++ b/ym2612.c Wed Mar 28 23:36:08 2018 -0700 @@ -168,8 +168,8 @@ static uint8_t registered_finalize; dfopen(debug_file, "ym_debug.txt", "w"); memset(context, 0, sizeof(*context)); - context->audio_buffer = malloc(sizeof(*context->audio_buffer) * sample_limit*2); - context->back_buffer = malloc(sizeof(*context->audio_buffer) * sample_limit*2); + context->audio = render_audio_source(2); + context->audio_buffer = render_audio_source_buffer(context->audio); context->sample_rate = sample_rate; context->clock_inc = clock_div * 6; ym_adjust_master_clock(context, master_clock); @@ -266,13 +266,10 @@ void ym_free(ym2612_context *context) { + render_free_source(context->audio); if (context == log_context) { ym_finalize_log(); } - free(context->audio_buffer); - //TODO: Figure out how to make this 100% safe - //audio thread could still be using this - free(context->back_buffer); free(context); } @@ -649,7 +646,8 @@ context->buffer_pos += 2; if (context->buffer_pos == context->sample_limit) { if (!headless) { - render_wait_ym(context); + context->audio_buffer = render_audio_ready(context->audio); + context->buffer_pos = 0; } } } diff -r b525491b4e5b -r ce1f93be0104 ym2612.h --- a/ym2612.h Mon Mar 26 23:36:39 2018 -0700 +++ b/ym2612.h Wed Mar 28 23:36:08 2018 -0700 @@ -9,6 +9,7 @@ #include #include #include "serialize.h" +#include "render.h" #define NUM_PART_REGS (0xB7-0x30) #define NUM_CHANNELS 6 @@ -63,7 +64,7 @@ typedef struct { int16_t *audio_buffer; - int16_t *back_buffer; + audio_source *audio; uint64_t buffer_fraction; uint64_t buffer_inc; uint32_t clock_inc;