Mercurial > repos > blastem
diff render_sdl.c @ 1555:6ce36c3f250b
More audio refactoring in preparation for allowing proper sync to video with dynamic audio rate control
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Fri, 30 Mar 2018 00:37:08 -0700 |
parents | 13a82adb185b |
children | d7b0d0ce8ed1 |
line wrap: on
line diff
--- a/render_sdl.c Thu Mar 29 00:40:41 2018 -0700 +++ b/render_sdl.c Fri Mar 30 00:37:08 2018 -0700 @@ -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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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;