summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Pavone <pavone@retrodev.com>2018-03-28 23:36:08 -0700
committerMichael Pavone <pavone@retrodev.com>2018-03-28 23:36:08 -0700
commit843f39ba736fc39c00275850ee2ec860093cd9a2 (patch)
tree732ee291762f8c3f897e01ceaccd6828bad802c6
parente04a8ca03c0752a16e873a549961f9d739abd02e (diff)
Small cleanup to audio interface between emulation code and renderer backend
-rw-r--r--genesis.c4
-rw-r--r--psg.c12
-rw-r--r--psg.h3
-rw-r--r--render.h14
-rwxr-xr-xrender_sdl.c166
-rw-r--r--sms.c4
-rw-r--r--ym2612.c12
-rw-r--r--ym2612.h3
8 files changed, 130 insertions, 88 deletions
diff --git a/genesis.c b/genesis.c
index e82b212..e4f4a8f 100644
--- a/genesis.c
+++ b/genesis.c
@@ -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);
}
diff --git a/psg.c b/psg.c
index 4713295..71c925a 100644
--- a/psg.c
+++ b/psg.c
@@ -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;
}
}
}
diff --git a/psg.h b/psg.h
index 0e11328..4e77f20 100644
--- a/psg.h
+++ b/psg.h
@@ -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;
diff --git a/render.h b/render.h
index 3dff089..ac4b62b 100644
--- a/render.h
+++ b/render.h
@@ -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()
diff --git a/sms.c b/sms.c
index 8e54619..c0fb1e3 100644
--- a/sms.c
+++ b/sms.c
@@ -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);
}
diff --git a/ym2612.c b/ym2612.c
index 7b45e67..11f4e19 100644
--- a/ym2612.c
+++ b/ym2612.c
@@ -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;
}
}
}
diff --git a/ym2612.h b/ym2612.h
index 9f2bd25..8bda299 100644
--- a/ym2612.h
+++ b/ym2612.h
@@ -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;