summaryrefslogtreecommitdiff
path: root/render_sdl.c
diff options
context:
space:
mode:
authorMichael Pavone <pavone@retrodev.com>2018-03-30 00:37:08 -0700
committerMichael Pavone <pavone@retrodev.com>2018-03-30 00:37:08 -0700
commit6409b9654c78328d03c4ced4f4b651a303497873 (patch)
tree205d01d6118297ffa1570f3cacb4306b7ee7cdf8 /render_sdl.c
parent431054f4686cd2a9fffa6f64751f81cdf0b39a89 (diff)
More audio refactoring in preparation for allowing proper sync to video with dynamic audio rate control
Diffstat (limited to 'render_sdl.c')
-rwxr-xr-xrender_sdl.c111
1 files changed, 90 insertions, 21 deletions
diff --git a/render_sdl.c b/render_sdl.c
index 0f3fb76..f9001d7 100755
--- a/render_sdl.c
+++ b/render_sdl.c
@@ -15,6 +15,7 @@
#include "util.h"
#include "ppm.h"
#include "png.h"
+#include "config.h"
#ifndef DISABLE_OPENGL
#include <GL/glew.h>
@@ -50,6 +51,12 @@ struct audio_source {
SDL_cond *cond;
int16_t *front;
int16_t *back;
+ uint64_t buffer_fraction;
+ uint64_t buffer_inc;
+ uint32_t buffer_pos;
+ uint32_t lowpass_alpha;
+ int16_t last_left;
+ int16_t last_right;
uint8_t num_channels;
uint8_t front_populated;
};
@@ -161,7 +168,14 @@ static void render_close_audio()
SDL_CloseAudio();
}
-audio_source *render_audio_source(uint8_t channels)
+#define BUFFER_INC_RES 0x40000000UL
+
+void render_audio_adjust_clock(audio_source *src, uint64_t master_clock, uint64_t sample_divider)
+{
+ src->buffer_inc = ((BUFFER_INC_RES * (uint64_t)sample_rate) / master_clock) * sample_divider;
+}
+
+audio_source *render_audio_source(uint64_t master_clock, uint64_t sample_divider, uint8_t channels)
{
audio_source *ret = NULL;
SDL_LockMutex(audio_mutex);
@@ -177,6 +191,16 @@ audio_source *render_audio_source(uint8_t channels)
SDL_UnlockMutex(audio_mutex);
if (!ret) {
fatal_error("Too many audio sources!");
+ } else {
+ render_audio_adjust_clock(ret, master_clock, sample_divider);
+ double lowpass_cutoff = get_lowpass_cutoff(config);
+ double rc = (1.0 / lowpass_cutoff) / (2.0 * M_PI);
+ double dt = 1.0 / ((double)master_clock / (double)(sample_divider));
+ double alpha = dt / (dt + rc);
+ ret->lowpass_alpha = (int32_t)(((double)0x10000) * alpha);
+ ret->buffer_pos = 0;
+ ret->buffer_fraction = 0;
+ ret->last_left = ret->last_right = 0;
}
return ret;
}
@@ -214,6 +238,71 @@ void render_free_source(audio_source *src)
free(src);
}
+static void do_audio_ready(audio_source *src)
+{
+ SDL_LockMutex(audio_mutex);
+ while (src->front_populated) {
+ SDL_CondWait(src->cond, audio_mutex);
+ }
+ int16_t *tmp = src->front;
+ src->front = src->back;
+ src->back = tmp;
+ src->front_populated = 1;
+ src->buffer_pos = 0;
+ SDL_CondSignal(audio_ready);
+ SDL_UnlockMutex(audio_mutex);
+}
+
+static int16_t lowpass_sample(audio_source *src, int16_t last, int16_t current)
+{
+ int32_t tmp = current * src->lowpass_alpha + last * (0x10000 - src->lowpass_alpha);
+ current = tmp >> 16;
+ return current;
+}
+
+static void interp_sample(audio_source *src, int16_t last, int16_t current)
+{
+ int64_t tmp = last * ((src->buffer_fraction << 16) / src->buffer_inc);
+ tmp += current * (0x10000 - ((src->buffer_fraction << 16) / src->buffer_inc));
+ src->back[src->buffer_pos++] = tmp >> 16;
+}
+
+void render_put_mono_sample(audio_source *src, int16_t value)
+{
+ value = lowpass_sample(src, src->last_left, value);
+ src->buffer_fraction += src->buffer_inc;
+ while (src->buffer_fraction > BUFFER_INC_RES)
+ {
+ src->buffer_fraction -= BUFFER_INC_RES;
+ interp_sample(src, src->last_left, value);
+
+ if (src->buffer_pos == buffer_samples) {
+ do_audio_ready(src);
+ }
+ }
+ src->last_left = value;
+}
+
+void render_put_stereo_sample(audio_source *src, int16_t left, int16_t right)
+{
+ left = lowpass_sample(src, src->last_left, left);
+ right = lowpass_sample(src, src->last_right, right);
+ src->buffer_fraction += src->buffer_inc;
+ while (src->buffer_fraction > BUFFER_INC_RES)
+ {
+ src->buffer_fraction -= BUFFER_INC_RES;
+
+ interp_sample(src, src->last_left, left);
+ interp_sample(src, src->last_right, right);
+
+ if (src->buffer_pos == buffer_samples * 2) {
+ do_audio_ready(src);
+ }
+ }
+ src->last_left = left;
+ src->last_right = left;
+}
+
static SDL_Joystick * joysticks[MAX_JOYSTICKS];
static int joystick_sdl_index[MAX_JOYSTICKS];
@@ -1300,26 +1389,6 @@ void render_toggle_fullscreen()
in_toggle = 0;
}
-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 (src->front_populated) {
- SDL_CondWait(src->cond, audio_mutex);
- }
- int16_t *tmp = src->front;
- src->front = src->back;
- src->back = tmp;
- src->front_populated = 1;
- SDL_CondSignal(audio_ready);
- SDL_UnlockMutex(audio_mutex);
- return src->back;
-}
-
uint32_t render_audio_buffer()
{
return buffer_samples;