Mercurial > repos > blastem
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 |