diff options
author | Michael Pavone <pavone@retrodev.com> | 2018-03-28 23:36:08 -0700 |
---|---|---|
committer | Michael Pavone <pavone@retrodev.com> | 2018-03-28 23:36:08 -0700 |
commit | 843f39ba736fc39c00275850ee2ec860093cd9a2 (patch) | |
tree | 732ee291762f8c3f897e01ceaccd6828bad802c6 | |
parent | e04a8ca03c0752a16e873a549961f9d739abd02e (diff) |
Small cleanup to audio interface between emulation code and renderer backend
-rw-r--r-- | genesis.c | 4 | ||||
-rw-r--r-- | psg.c | 12 | ||||
-rw-r--r-- | psg.h | 3 | ||||
-rw-r--r-- | render.h | 14 | ||||
-rwxr-xr-x | render_sdl.c | 166 | ||||
-rw-r--r-- | sms.c | 4 | ||||
-rw-r--r-- | ym2612.c | 12 | ||||
-rw-r--r-- | ym2612.h | 3 |
8 files changed, 130 insertions, 88 deletions
@@ -1052,6 +1052,8 @@ static void handle_reset_requests(genesis_context *gen) } } 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 @@ static void resume_genesis(system_header *system) 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); } @@ -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_init(psg_context * context, uint32_t sample_rate, uint32_t master_clock 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 @@ void psg_run(psg_context * context, uint32_t cycles) 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; } } } @@ -8,10 +8,11 @@ #include <stdint.h> #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; @@ -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 @@ typedef enum { #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_set_video_standard(vid_std std); 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_overscan_left(); 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 --git a/render_sdl.c b/render_sdl.c index db2e091..c69d4d2 100755 --- a/render_sdl.c +++ b/render_sdl.c @@ -44,73 +44,123 @@ static uint32_t missing_count; 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); - } - if (ym_enabled && !ym_buf) { - ym_buf = current_ym; - current_ym = NULL; - SDL_CondSignal(ym_cond); + num_populated = 0; + for (uint8_t i = 0; i < num_audio_sources; i++) + { + if (audio_sources[i]->front_populated) { + num_populated++; + } } - 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++) - { - *(stream++) = psg_buf[i] + *(ym_buf++); - *(stream++) = psg_buf[i] + *(ym_buf++); - } - } else { - 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]; - *(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); } } - } + SDL_UnlockMutex(audio_mutex); } -void render_disable_ym() +static void render_close_audio() { - ym_enabled = 0; + SDL_LockMutex(audio_mutex); + quitting = 1; + SDL_CondSignal(audio_ready); + SDL_UnlockMutex(audio_mutex); + SDL_CloseAudio(); } -void render_enable_ym() +audio_source *render_audio_source(uint8_t channels) { - ym_enabled = 1; + 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; } -static void render_close_audio() +void render_pause_source(audio_source *src) { SDL_LockMutex(audio_mutex); - quitting = 1; - SDL_CondSignal(audio_ready); + 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); - SDL_CloseAudio(); +} + +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]; @@ -480,8 +530,6 @@ void render_init(int width, int height, char * title, uint8_t fullscreen) 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 @@ void render_toggle_fullscreen() in_toggle = 0; } -void render_wait_psg(psg_context * context) +int16_t *render_audio_source_buffer(audio_source *src) { - SDL_LockMutex(audio_mutex); - while (current_psg != NULL) { - SDL_CondWait(psg_cond, audio_mutex); - } - current_psg = context->audio_buffer; - SDL_CondSignal(audio_ready); - - context->audio_buffer = context->back_buffer; - context->back_buffer = current_psg; - SDL_UnlockMutex(audio_mutex); - context->buffer_pos = 0; + return src->back; } -void render_wait_ym(ym2612_context * context) +int16_t *render_audio_ready(audio_source *src) { SDL_LockMutex(audio_mutex); - while (current_ym != NULL) { - SDL_CondWait(ym_cond, audio_mutex); + while (src->front_populated) { + SDL_CondWait(src->cond, audio_mutex); } - current_ym = 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_ym; SDL_UnlockMutex(audio_mutex); - context->buffer_pos = 0; + return src->back; } uint32_t render_audio_buffer() @@ -336,7 +336,6 @@ done: 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 @@ static void run_sms(system_header *system) } } 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); } @@ -168,8 +168,8 @@ void ym_init(ym2612_context * context, uint32_t sample_rate, uint32_t master_clo 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_init(ym2612_context * context, uint32_t sample_rate, uint32_t master_clo 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 @@ void ym_run(ym2612_context * context, uint32_t to_cycle) 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; } } } @@ -9,6 +9,7 @@ #include <stdint.h> #include <stdio.h> #include "serialize.h" +#include "render.h" #define NUM_PART_REGS (0xB7-0x30) #define NUM_CHANNELS 6 @@ -63,7 +64,7 @@ typedef struct { 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; |