comparison 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
comparison
equal deleted inserted replaced
1554:87350caf6dab 1555:6ce36c3f250b
13 #include "genesis.h" 13 #include "genesis.h"
14 #include "io.h" 14 #include "io.h"
15 #include "util.h" 15 #include "util.h"
16 #include "ppm.h" 16 #include "ppm.h"
17 #include "png.h" 17 #include "png.h"
18 #include "config.h"
18 19
19 #ifndef DISABLE_OPENGL 20 #ifndef DISABLE_OPENGL
20 #include <GL/glew.h> 21 #include <GL/glew.h>
21 #endif 22 #endif
22 23
48 49
49 struct audio_source { 50 struct audio_source {
50 SDL_cond *cond; 51 SDL_cond *cond;
51 int16_t *front; 52 int16_t *front;
52 int16_t *back; 53 int16_t *back;
54 uint64_t buffer_fraction;
55 uint64_t buffer_inc;
56 uint32_t buffer_pos;
57 uint32_t lowpass_alpha;
58 int16_t last_left;
59 int16_t last_right;
53 uint8_t num_channels; 60 uint8_t num_channels;
54 uint8_t front_populated; 61 uint8_t front_populated;
55 }; 62 };
56 63
57 static audio_source *audio_sources[8]; 64 static audio_source *audio_sources[8];
159 SDL_CondSignal(audio_ready); 166 SDL_CondSignal(audio_ready);
160 SDL_UnlockMutex(audio_mutex); 167 SDL_UnlockMutex(audio_mutex);
161 SDL_CloseAudio(); 168 SDL_CloseAudio();
162 } 169 }
163 170
164 audio_source *render_audio_source(uint8_t channels) 171 #define BUFFER_INC_RES 0x40000000UL
172
173 void render_audio_adjust_clock(audio_source *src, uint64_t master_clock, uint64_t sample_divider)
174 {
175 src->buffer_inc = ((BUFFER_INC_RES * (uint64_t)sample_rate) / master_clock) * sample_divider;
176 }
177
178 audio_source *render_audio_source(uint64_t master_clock, uint64_t sample_divider, uint8_t channels)
165 { 179 {
166 audio_source *ret = NULL; 180 audio_source *ret = NULL;
167 SDL_LockMutex(audio_mutex); 181 SDL_LockMutex(audio_mutex);
168 if (num_audio_sources < 8) { 182 if (num_audio_sources < 8) {
169 ret = malloc(sizeof(audio_source)); 183 ret = malloc(sizeof(audio_source));
175 audio_sources[num_audio_sources++] = ret; 189 audio_sources[num_audio_sources++] = ret;
176 } 190 }
177 SDL_UnlockMutex(audio_mutex); 191 SDL_UnlockMutex(audio_mutex);
178 if (!ret) { 192 if (!ret) {
179 fatal_error("Too many audio sources!"); 193 fatal_error("Too many audio sources!");
194 } else {
195 render_audio_adjust_clock(ret, master_clock, sample_divider);
196 double lowpass_cutoff = get_lowpass_cutoff(config);
197 double rc = (1.0 / lowpass_cutoff) / (2.0 * M_PI);
198 double dt = 1.0 / ((double)master_clock / (double)(sample_divider));
199 double alpha = dt / (dt + rc);
200 ret->lowpass_alpha = (int32_t)(((double)0x10000) * alpha);
201 ret->buffer_pos = 0;
202 ret->buffer_fraction = 0;
203 ret->last_left = ret->last_right = 0;
180 } 204 }
181 return ret; 205 return ret;
182 } 206 }
183 207
184 void render_pause_source(audio_source *src) 208 void render_pause_source(audio_source *src)
210 234
211 free(src->front); 235 free(src->front);
212 free(src->back); 236 free(src->back);
213 SDL_DestroyCond(src->cond); 237 SDL_DestroyCond(src->cond);
214 free(src); 238 free(src);
239 }
240
241 static void do_audio_ready(audio_source *src)
242 {
243 SDL_LockMutex(audio_mutex);
244 while (src->front_populated) {
245 SDL_CondWait(src->cond, audio_mutex);
246 }
247 int16_t *tmp = src->front;
248 src->front = src->back;
249 src->back = tmp;
250 src->front_populated = 1;
251 src->buffer_pos = 0;
252 SDL_CondSignal(audio_ready);
253 SDL_UnlockMutex(audio_mutex);
254 }
255
256 static int16_t lowpass_sample(audio_source *src, int16_t last, int16_t current)
257 {
258 int32_t tmp = current * src->lowpass_alpha + last * (0x10000 - src->lowpass_alpha);
259 current = tmp >> 16;
260 return current;
261 }
262
263 static void interp_sample(audio_source *src, int16_t last, int16_t current)
264 {
265 int64_t tmp = last * ((src->buffer_fraction << 16) / src->buffer_inc);
266 tmp += current * (0x10000 - ((src->buffer_fraction << 16) / src->buffer_inc));
267 src->back[src->buffer_pos++] = tmp >> 16;
268 }
269
270 void render_put_mono_sample(audio_source *src, int16_t value)
271 {
272 value = lowpass_sample(src, src->last_left, value);
273 src->buffer_fraction += src->buffer_inc;
274 while (src->buffer_fraction > BUFFER_INC_RES)
275 {
276 src->buffer_fraction -= BUFFER_INC_RES;
277 interp_sample(src, src->last_left, value);
278
279 if (src->buffer_pos == buffer_samples) {
280 do_audio_ready(src);
281 }
282 }
283 src->last_left = value;
284 }
285
286 void render_put_stereo_sample(audio_source *src, int16_t left, int16_t right)
287 {
288 left = lowpass_sample(src, src->last_left, left);
289 right = lowpass_sample(src, src->last_right, right);
290 src->buffer_fraction += src->buffer_inc;
291 while (src->buffer_fraction > BUFFER_INC_RES)
292 {
293 src->buffer_fraction -= BUFFER_INC_RES;
294
295 interp_sample(src, src->last_left, left);
296 interp_sample(src, src->last_right, right);
297
298 if (src->buffer_pos == buffer_samples * 2) {
299 do_audio_ready(src);
300 }
301 }
302 src->last_left = left;
303 src->last_right = left;
215 } 304 }
216 305
217 static SDL_Joystick * joysticks[MAX_JOYSTICKS]; 306 static SDL_Joystick * joysticks[MAX_JOYSTICKS];
218 static int joystick_sdl_index[MAX_JOYSTICKS]; 307 static int joystick_sdl_index[MAX_JOYSTICKS];
219 308
1298 SDL_SetWindowSize(main_window, windowed_width, windowed_height); 1387 SDL_SetWindowSize(main_window, windowed_width, windowed_height);
1299 drain_events(); 1388 drain_events();
1300 in_toggle = 0; 1389 in_toggle = 0;
1301 } 1390 }
1302 1391
1303 int16_t *render_audio_source_buffer(audio_source *src)
1304 {
1305 return src->back;
1306 }
1307
1308 int16_t *render_audio_ready(audio_source *src)
1309 {
1310 SDL_LockMutex(audio_mutex);
1311 while (src->front_populated) {
1312 SDL_CondWait(src->cond, audio_mutex);
1313 }
1314 int16_t *tmp = src->front;
1315 src->front = src->back;
1316 src->back = tmp;
1317 src->front_populated = 1;
1318 SDL_CondSignal(audio_ready);
1319 SDL_UnlockMutex(audio_mutex);
1320 return src->back;
1321 }
1322
1323 uint32_t render_audio_buffer() 1392 uint32_t render_audio_buffer()
1324 { 1393 {
1325 return buffer_samples; 1394 return buffer_samples;
1326 } 1395 }
1327 1396