comparison render_sdl.c @ 1865:4c322abd9fa5

Split generic part of audio code into a separate file so it can be used in other targets besides SDL
author Michael Pavone <pavone@retrodev.com>
date Fri, 17 May 2019 08:43:30 -0700
parents e07fc3d473b2
children 55198fc9cc1f
comparison
equal deleted inserted replaced
1863:d60f2d7c02a5 1865:4c322abd9fa5
44 static uint8_t render_gl = 1; 44 static uint8_t render_gl = 1;
45 static uint8_t scanlines = 0; 45 static uint8_t scanlines = 0;
46 46
47 static uint32_t last_frame = 0; 47 static uint32_t last_frame = 0;
48 48
49 static uint8_t output_channels;
50 static uint32_t buffer_samples, sample_rate;
51 static uint32_t missing_count;
52
53 static SDL_mutex * audio_mutex; 49 static SDL_mutex * audio_mutex;
54 static SDL_cond * audio_ready; 50 static SDL_cond * audio_ready;
55 static uint8_t quitting = 0; 51 static uint8_t quitting = 0;
56 52
57 struct audio_source {
58 SDL_cond *cond;
59 int16_t *front;
60 int16_t *back;
61 double dt;
62 uint64_t buffer_fraction;
63 uint64_t buffer_inc;
64 float gain_mult;
65 uint32_t buffer_pos;
66 uint32_t read_start;
67 uint32_t read_end;
68 uint32_t lowpass_alpha;
69 uint32_t mask;
70 int16_t last_left;
71 int16_t last_right;
72 uint8_t num_channels;
73 uint8_t front_populated;
74 };
75
76 static audio_source *audio_sources[8];
77 static audio_source *inactive_audio_sources[8];
78 static uint8_t num_audio_sources;
79 static uint8_t num_inactive_audio_sources;
80 static uint8_t sync_to_audio; 53 static uint8_t sync_to_audio;
81 static uint32_t min_buffered; 54 static uint32_t min_buffered;
82 static float overall_gain_mult, *mix_buf; 55
83 static int sample_size; 56 uint32_t render_min_buffered(void)
84 57 {
85 typedef void (*conv_func)(float *samples, void *vstream, int sample_count); 58 return min_buffered;
86 59 }
87 static void convert_null(float *samples, void *vstream, int sample_count) 60
88 { 61 uint8_t render_is_audio_sync(void)
89 memset(vstream, 0, sample_count * sample_size); 62 {
90 } 63 return sync_to_audio;
91 64 }
92 static void convert_s16(float *samples, void *vstream, int sample_count) 65
93 { 66 void render_buffer_consumed(audio_source *src)
94 int16_t *stream = vstream; 67 {
95 for (int16_t *end = stream + sample_count; stream < end; stream++, samples++) 68 SDL_CondSignal(src->opaque);
96 { 69 }
97 float sample = *samples;
98 int16_t out_sample;
99 if (sample >= 1.0f) {
100 out_sample = 0x7FFF;
101 } else if (sample <= -1.0f) {
102 out_sample = -0x8000;
103 } else {
104 out_sample = sample * 0x7FFF;
105 }
106 *stream = out_sample;
107 }
108 }
109
110 static void clamp_f32(float *samples, void *vstream, int sample_count)
111 {
112 for (; sample_count > 0; sample_count--, samples++)
113 {
114 float sample = *samples;
115 if (sample > 1.0f) {
116 sample = 1.0f;
117 } else if (sample < -1.0f) {
118 sample = -1.0f;
119 }
120 *samples = sample;
121 }
122 }
123
124 static int32_t mix_f32(audio_source *audio, float *stream, int samples)
125 {
126 float *end = stream + samples;
127 int16_t *src = audio->front;
128 uint32_t i = audio->read_start;
129 uint32_t i_end = audio->read_end;
130 float *cur = stream;
131 float gain_mult = audio->gain_mult * overall_gain_mult;
132 size_t first_add = output_channels > 1 ? 1 : 0, second_add = output_channels > 1 ? output_channels - 1 : 1;
133 if (audio->num_channels == 1) {
134 while (cur < end && i != i_end)
135 {
136 *cur += gain_mult * ((float)src[i]) / 0x7FFF;
137 cur += first_add;
138 *cur += gain_mult * ((float)src[i++]) / 0x7FFF;
139 cur += second_add;
140 i &= audio->mask;
141 }
142 } else {
143 while(cur < end && i != i_end)
144 {
145 *cur += gain_mult * ((float)src[i++]) / 0x7FFF;
146 cur += first_add;
147 *cur += gain_mult * ((float)src[i++]) / 0x7FFF;
148 cur += second_add;
149 i &= audio->mask;
150 }
151 }
152 if (!sync_to_audio) {
153 audio->read_start = i;
154 }
155 if (cur != end) {
156 debug_message("Underflow of %d samples, read_start: %d, read_end: %d, mask: %X\n", (int)(end-cur)/2, audio->read_start, audio->read_end, audio->mask);
157 return (cur-end)/2;
158 } else {
159 return ((i_end - i) & audio->mask) / audio->num_channels;
160 }
161 }
162
163 static conv_func convert;
164 70
165 static void audio_callback(void * userdata, uint8_t *byte_stream, int len) 71 static void audio_callback(void * userdata, uint8_t *byte_stream, int len)
166 { 72 {
167 uint8_t num_populated;
168 SDL_LockMutex(audio_mutex); 73 SDL_LockMutex(audio_mutex);
74 uint8_t all_ready;
169 do { 75 do {
170 num_populated = 0; 76 all_ready = all_sources_ready();
171 for (uint8_t i = 0; i < num_audio_sources; i++) 77 if (!quitting && !all_ready) {
172 {
173 if (audio_sources[i]->front_populated) {
174 num_populated++;
175 }
176 }
177 if (!quitting && num_populated < num_audio_sources) {
178 fflush(stdout);
179 SDL_CondWait(audio_ready, audio_mutex); 78 SDL_CondWait(audio_ready, audio_mutex);
180 } 79 }
181 } while(!quitting && num_populated < num_audio_sources); 80 } while(!quitting && !all_ready);
182 int samples = len / sample_size;
183 float *mix_dest = mix_buf ? mix_buf : (float *)byte_stream;
184 memset(mix_dest, 0, samples * sizeof(float));
185 if (!quitting) { 81 if (!quitting) {
186 for (uint8_t i = 0; i < num_audio_sources; i++) 82 mix_and_convert(byte_stream, len, NULL);
187 { 83 }
188 mix_f32(audio_sources[i], mix_dest, samples);
189 audio_sources[i]->front_populated = 0;
190 SDL_CondSignal(audio_sources[i]->cond);
191 }
192 }
193 convert(mix_dest, byte_stream, samples);
194 SDL_UnlockMutex(audio_mutex); 84 SDL_UnlockMutex(audio_mutex);
195 } 85 }
196 86
197 #define NO_LAST_BUFFERED -2000000000 87 #define NO_LAST_BUFFERED -2000000000
198 static int32_t last_buffered = NO_LAST_BUFFERED; 88 static int32_t last_buffered = NO_LAST_BUFFERED;
206 { 96 {
207 if (cur_min_buffered < 0) { 97 if (cur_min_buffered < 0) {
208 //underflow last frame, but main thread hasn't gotten a chance to call SDL_PauseAudio yet 98 //underflow last frame, but main thread hasn't gotten a chance to call SDL_PauseAudio yet
209 return; 99 return;
210 } 100 }
211 cur_min_buffered = 0x7FFFFFFF; 101 cur_min_buffered = mix_and_convert(byte_stream, len, &min_remaining_buffer);
212 min_remaining_buffer = 0xFFFFFFFF; 102 }
213 float *mix_dest = mix_buf ? mix_buf : (float *)byte_stream; 103
214 int samples = len / sample_size; 104 void render_lock_audio()
215 memset(mix_dest, 0, samples * sizeof(float));
216 for (uint8_t i = 0; i < num_audio_sources; i++)
217 {
218
219 int32_t buffered = mix_f32(audio_sources[i], mix_dest, samples);
220 cur_min_buffered = buffered < cur_min_buffered ? buffered : cur_min_buffered;
221 uint32_t remaining = (audio_sources[i]->mask + 1)/audio_sources[i]->num_channels - buffered;
222 min_remaining_buffer = remaining < min_remaining_buffer ? remaining : min_remaining_buffer;
223 }
224 convert(mix_dest, byte_stream, samples);
225 }
226
227 static void lock_audio()
228 { 105 {
229 if (sync_to_audio) { 106 if (sync_to_audio) {
230 SDL_LockMutex(audio_mutex); 107 SDL_LockMutex(audio_mutex);
231 } else { 108 } else {
232 SDL_LockAudio(); 109 SDL_LockAudio();
233 } 110 }
234 } 111 }
235 112
236 static void unlock_audio() 113 void render_unlock_audio()
237 { 114 {
238 if (sync_to_audio) { 115 if (sync_to_audio) {
239 SDL_UnlockMutex(audio_mutex); 116 SDL_UnlockMutex(audio_mutex);
240 } else { 117 } else {
241 SDL_UnlockAudio(); 118 SDL_UnlockAudio();
247 SDL_LockMutex(audio_mutex); 124 SDL_LockMutex(audio_mutex);
248 quitting = 1; 125 quitting = 1;
249 SDL_CondSignal(audio_ready); 126 SDL_CondSignal(audio_ready);
250 SDL_UnlockMutex(audio_mutex); 127 SDL_UnlockMutex(audio_mutex);
251 SDL_CloseAudio(); 128 SDL_CloseAudio();
129 /*
130 FIXME: move this to render_audio.c
252 if (mix_buf) { 131 if (mix_buf) {
253 free(mix_buf); 132 free(mix_buf);
254 mix_buf = NULL; 133 mix_buf = NULL;
255 } 134 }
256 } 135 */
257 136 }
258 #define BUFFER_INC_RES 0x40000000UL 137
259 138 void *render_new_audio_opaque(void)
260 void render_audio_adjust_clock(audio_source *src, uint64_t master_clock, uint64_t sample_divider) 139 {
261 { 140 return SDL_CreateCond();
262 src->buffer_inc = ((BUFFER_INC_RES * (uint64_t)sample_rate) / master_clock) * sample_divider; 141 }
263 } 142
264 143 void render_free_audio_opaque(void *opaque)
265 audio_source *render_audio_source(uint64_t master_clock, uint64_t sample_divider, uint8_t channels) 144 {
266 { 145 SDL_DestroyCond(opaque);
267 audio_source *ret = NULL; 146 }
268 uint32_t alloc_size = sync_to_audio ? channels * buffer_samples : nearest_pow2(min_buffered * 4 * channels); 147
269 lock_audio(); 148 void render_audio_created(audio_source *source)
270 if (num_audio_sources < 8) { 149 {
271 ret = malloc(sizeof(audio_source));
272 ret->back = malloc(alloc_size * sizeof(int16_t));
273 ret->front = sync_to_audio ? malloc(alloc_size * sizeof(int16_t)) : ret->back;
274 ret->front_populated = 0;
275 ret->cond = SDL_CreateCond();
276 ret->num_channels = channels;
277 audio_sources[num_audio_sources++] = ret;
278 }
279 unlock_audio();
280 if (!ret) {
281 fatal_error("Too many audio sources!");
282 } else {
283 render_audio_adjust_clock(ret, master_clock, sample_divider);
284 double lowpass_cutoff = get_lowpass_cutoff(config);
285 double rc = (1.0 / lowpass_cutoff) / (2.0 * M_PI);
286 ret->dt = 1.0 / ((double)master_clock / (double)(sample_divider));
287 double alpha = ret->dt / (ret->dt + rc);
288 ret->lowpass_alpha = (int32_t)(((double)0x10000) * alpha);
289 ret->buffer_pos = 0;
290 ret->buffer_fraction = 0;
291 ret->last_left = ret->last_right = 0;
292 ret->read_start = 0;
293 ret->read_end = sync_to_audio ? buffer_samples * channels : 0;
294 ret->mask = sync_to_audio ? 0xFFFFFFFF : alloc_size-1;
295 ret->gain_mult = 1.0f;
296 }
297 if (sync_to_audio && SDL_GetAudioStatus() == SDL_AUDIO_PAUSED) { 150 if (sync_to_audio && SDL_GetAudioStatus() == SDL_AUDIO_PAUSED) {
298 SDL_PauseAudio(0); 151 SDL_PauseAudio(0);
299 } 152 }
300 return ret; 153 }
301 } 154
302 155 void render_source_paused(audio_source *src, uint8_t remaining_sources)
303 static float db_to_mult(float gain) 156 {
304 { 157 if (sync_to_audio) {
305 return powf(10.0f, gain/20.0f); 158 SDL_CondSignal(audio_ready);
306 } 159 }
307 160 if (!remaining_sources) {
308 void render_audio_source_gaindb(audio_source *src, float gain) 161 SDL_PauseAudio(0);
309 { 162 }
310 src->gain_mult = db_to_mult(gain); 163 }
311 } 164
312 165 void render_source_resumed(audio_source *src)
313 void render_pause_source(audio_source *src) 166 {
314 {
315 uint8_t need_pause = 0;
316 lock_audio();
317 for (uint8_t i = 0; i < num_audio_sources; i++)
318 {
319 if (audio_sources[i] == src) {
320 audio_sources[i] = audio_sources[--num_audio_sources];
321 if (sync_to_audio) {
322 SDL_CondSignal(audio_ready);
323 }
324 break;
325 }
326 }
327 if (!num_audio_sources) {
328 need_pause = 1;
329 }
330 unlock_audio();
331 if (need_pause) {
332 SDL_PauseAudio(1);
333 }
334 inactive_audio_sources[num_inactive_audio_sources++] = src;
335 }
336
337 void render_resume_source(audio_source *src)
338 {
339 lock_audio();
340 if (num_audio_sources < 8) {
341 audio_sources[num_audio_sources++] = src;
342 }
343 unlock_audio();
344 for (uint8_t i = 0; i < num_inactive_audio_sources; i++)
345 {
346 if (inactive_audio_sources[i] == src) {
347 inactive_audio_sources[i] = inactive_audio_sources[--num_inactive_audio_sources];
348 }
349 }
350 if (sync_to_audio) { 167 if (sync_to_audio) {
351 SDL_PauseAudio(0); 168 SDL_PauseAudio(0);
352 } 169 }
353 } 170 }
354 171
355 void render_free_source(audio_source *src) 172 void render_do_audio_ready(audio_source *src)
356 {
357 render_pause_source(src);
358
359 free(src->front);
360 if (sync_to_audio) {
361 free(src->back);
362 SDL_DestroyCond(src->cond);
363 }
364 free(src);
365 }
366 static uint32_t sync_samples;
367 static void do_audio_ready(audio_source *src)
368 { 173 {
369 if (sync_to_audio) { 174 if (sync_to_audio) {
370 SDL_LockMutex(audio_mutex); 175 SDL_LockMutex(audio_mutex);
371 while (src->front_populated) { 176 while (src->front_populated) {
372 SDL_CondWait(src->cond, audio_mutex); 177 SDL_CondWait(src->opaque, audio_mutex);
373 } 178 }
374 int16_t *tmp = src->front; 179 int16_t *tmp = src->front;
375 src->front = src->back; 180 src->front = src->back;
376 src->back = tmp; 181 src->back = tmp;
377 src->front_populated = 1; 182 src->front_populated = 1;
386 SDL_UnlockAudio(); 191 SDL_UnlockAudio();
387 if (num_buffered >= min_buffered && SDL_GetAudioStatus() == SDL_AUDIO_PAUSED) { 192 if (num_buffered >= min_buffered && SDL_GetAudioStatus() == SDL_AUDIO_PAUSED) {
388 SDL_PauseAudio(0); 193 SDL_PauseAudio(0);
389 } 194 }
390 } 195 }
391 }
392
393 static int16_t lowpass_sample(audio_source *src, int16_t last, int16_t current)
394 {
395 int32_t tmp = current * src->lowpass_alpha + last * (0x10000 - src->lowpass_alpha);
396 current = tmp >> 16;
397 return current;
398 }
399
400 static void interp_sample(audio_source *src, int16_t last, int16_t current)
401 {
402 int64_t tmp = last * ((src->buffer_fraction << 16) / src->buffer_inc);
403 tmp += current * (0x10000 - ((src->buffer_fraction << 16) / src->buffer_inc));
404 src->back[src->buffer_pos++] = tmp >> 16;
405 }
406
407 void render_put_mono_sample(audio_source *src, int16_t value)
408 {
409 value = lowpass_sample(src, src->last_left, value);
410 src->buffer_fraction += src->buffer_inc;
411 uint32_t base = sync_to_audio ? 0 : src->read_end;
412 while (src->buffer_fraction > BUFFER_INC_RES)
413 {
414 src->buffer_fraction -= BUFFER_INC_RES;
415 interp_sample(src, src->last_left, value);
416
417 if (((src->buffer_pos - base) & src->mask) >= sync_samples) {
418 do_audio_ready(src);
419 }
420 src->buffer_pos &= src->mask;
421 }
422 src->last_left = value;
423 }
424
425 void render_put_stereo_sample(audio_source *src, int16_t left, int16_t right)
426 {
427 left = lowpass_sample(src, src->last_left, left);
428 right = lowpass_sample(src, src->last_right, right);
429 src->buffer_fraction += src->buffer_inc;
430 uint32_t base = sync_to_audio ? 0 : src->read_end;
431 while (src->buffer_fraction > BUFFER_INC_RES)
432 {
433 src->buffer_fraction -= BUFFER_INC_RES;
434
435 interp_sample(src, src->last_left, left);
436 interp_sample(src, src->last_right, right);
437
438 if (((src->buffer_pos - base) & src->mask)/2 >= sync_samples) {
439 do_audio_ready(src);
440 }
441 src->buffer_pos &= src->mask;
442 }
443 src->last_left = left;
444 src->last_right = right;
445 } 196 }
446 197
447 static SDL_Joystick * joysticks[MAX_JOYSTICKS]; 198 static SDL_Joystick * joysticks[MAX_JOYSTICKS];
448 static int joystick_sdl_index[MAX_JOYSTICKS]; 199 static int joystick_sdl_index[MAX_JOYSTICKS];
449 static uint8_t joystick_index_locked[MAX_JOYSTICKS]; 200 static uint8_t joystick_index_locked[MAX_JOYSTICKS];
1111 static int source_hz; 862 static int source_hz;
1112 static int source_frame; 863 static int source_frame;
1113 static int source_frame_count; 864 static int source_frame_count;
1114 static int frame_repeat[60]; 865 static int frame_repeat[60];
1115 866
867 static uint32_t sample_rate;
1116 static void init_audio() 868 static void init_audio()
1117 { 869 {
1118 SDL_AudioSpec desired, actual; 870 SDL_AudioSpec desired, actual;
1119 char * rate_str = tern_find_path(config, "audio\0rate\0", TVAL_PTR).ptrval; 871 char * rate_str = tern_find_path(config, "audio\0rate\0", TVAL_PTR).ptrval;
1120 int rate = rate_str ? atoi(rate_str) : 0; 872 int rate = rate_str ? atoi(rate_str) : 0;
1135 desired.userdata = NULL; 887 desired.userdata = NULL;
1136 888
1137 if (SDL_OpenAudio(&desired, &actual) < 0) { 889 if (SDL_OpenAudio(&desired, &actual) < 0) {
1138 fatal_error("Unable to open SDL audio: %s\n", SDL_GetError()); 890 fatal_error("Unable to open SDL audio: %s\n", SDL_GetError());
1139 } 891 }
1140 buffer_samples = actual.samples;
1141 sample_rate = actual.freq; 892 sample_rate = actual.freq;
1142 output_channels = actual.channels;
1143 debug_message("Initialized audio at frequency %d with a %d sample buffer, ", actual.freq, actual.samples); 893 debug_message("Initialized audio at frequency %d with a %d sample buffer, ", actual.freq, actual.samples);
1144 sample_size = SDL_AUDIO_BITSIZE(actual.format) / 8; 894 render_audio_format format = RENDER_AUDIO_UNKNOWN;
1145 if (actual.format == AUDIO_S16SYS) { 895 if (actual.format == AUDIO_S16SYS) {
1146 debug_message("signed 16-bit int format\n"); 896 debug_message("signed 16-bit int format\n");
1147 convert = convert_s16; 897 format = RENDER_AUDIO_S16;
1148 mix_buf = calloc(output_channels * buffer_samples, sizeof(float));
1149 } else if (actual.format == AUDIO_F32SYS) { 898 } else if (actual.format == AUDIO_F32SYS) {
1150 debug_message("32-bit float format\n"); 899 debug_message("32-bit float format\n");
1151 convert = clamp_f32; 900 format = RENDER_AUDIO_FLOAT;
1152 mix_buf = NULL;
1153 } else { 901 } else {
1154 debug_message("unsupported format %X\n", actual.format); 902 debug_message("unsupported format %X\n", actual.format);
1155 warning("Unsupported audio sample format: %X\n", actual.format); 903 warning("Unsupported audio sample format: %X\n", actual.format);
1156 convert = convert_null; 904 }
1157 mix_buf = calloc(output_channels * buffer_samples, sizeof(float)); 905 render_audio_initialized(format, actual.freq, actual.channels, actual.samples, SDL_AUDIO_BITSIZE(actual.format) / 8);
1158 }
1159 char * gain_str = tern_find_path(config, "audio\0gain\0", TVAL_PTR).ptrval;
1160 overall_gain_mult = db_to_mult(gain_str ? atof(gain_str) : 0.0f);
1161 } 906 }
1162 907
1163 void window_setup(void) 908 void window_setup(void)
1164 { 909 {
1165 uint32_t flags = SDL_WINDOW_RESIZABLE; 910 uint32_t flags = SDL_WINDOW_RESIZABLE;
1350 1095
1351 atexit(render_quit); 1096 atexit(render_quit);
1352 } 1097 }
1353 #include<unistd.h> 1098 #include<unistd.h>
1354 static int in_toggle; 1099 static int in_toggle;
1355 static void update_source(audio_source *src, double rc, uint8_t sync_changed)
1356 {
1357 double alpha = src->dt / (src->dt + rc);
1358 int32_t lowpass_alpha = (int32_t)(((double)0x10000) * alpha);
1359 src->lowpass_alpha = lowpass_alpha;
1360 if (sync_changed) {
1361 uint32_t alloc_size = sync_to_audio ? src->num_channels * buffer_samples : nearest_pow2(min_buffered * 4 * src->num_channels);
1362 src->back = realloc(src->back, alloc_size * sizeof(int16_t));
1363 if (sync_to_audio) {
1364 src->front = malloc(alloc_size * sizeof(int16_t));
1365 } else {
1366 free(src->front);
1367 src->front = src->back;
1368 }
1369 src->mask = sync_to_audio ? 0xFFFFFFFF : alloc_size-1;
1370 src->read_start = 0;
1371 src->read_end = sync_to_audio ? buffer_samples * src->num_channels : 0;
1372 src->buffer_pos = 0;
1373 }
1374 }
1375 1100
1376 void render_config_updated(void) 1101 void render_config_updated(void)
1377 { 1102 {
1378 uint8_t old_sync_to_audio = sync_to_audio; 1103 uint8_t old_sync_to_audio = sync_to_audio;
1379 1104
1436 render_close_audio(); 1161 render_close_audio();
1437 quitting = 0; 1162 quitting = 0;
1438 init_audio(); 1163 init_audio();
1439 render_set_video_standard(video_standard); 1164 render_set_video_standard(video_standard);
1440 1165
1441 double lowpass_cutoff = get_lowpass_cutoff(config);
1442 double rc = (1.0 / lowpass_cutoff) / (2.0 * M_PI);
1443 lock_audio();
1444 for (uint8_t i = 0; i < num_audio_sources; i++)
1445 {
1446 update_source(audio_sources[i], rc, old_sync_to_audio != sync_to_audio);
1447 }
1448 unlock_audio();
1449 for (uint8_t i = 0; i < num_inactive_audio_sources; i++)
1450 {
1451 update_source(inactive_audio_sources[i], rc, old_sync_to_audio != sync_to_audio);
1452 }
1453 drain_events(); 1166 drain_events();
1454 in_toggle = 0; 1167 in_toggle = 0;
1455 if (!was_paused) { 1168 if (!was_paused) {
1456 SDL_PauseAudio(0); 1169 SDL_PauseAudio(0);
1457 } 1170 }
1458 } 1171 }
1459 1172
1460 SDL_Window *render_get_window(void) 1173 SDL_Window *render_get_window(void)
1461 { 1174 {
1462 return main_window; 1175 return main_window;
1176 }
1177
1178 uint32_t render_audio_syncs_per_sec(void)
1179 {
1180 //sync samples with audio thread approximately every 8 lines when doing sync to video
1181 return sync_to_audio ? 0 : source_hz * (video_standard == VID_PAL ? 313 : 262) / 8;
1463 } 1182 }
1464 1183
1465 void render_set_video_standard(vid_std std) 1184 void render_set_video_standard(vid_std std)
1466 { 1185 {
1467 video_standard = std; 1186 video_standard = std;
1489 frame_repeat[source_hz-1] += display_hz - dst_frames; 1208 frame_repeat[source_hz-1] += display_hz - dst_frames;
1490 } 1209 }
1491 } 1210 }
1492 source_frame = 0; 1211 source_frame = 0;
1493 source_frame_count = frame_repeat[0]; 1212 source_frame_count = frame_repeat[0];
1494 //sync samples with audio thread approximately every 8 lines
1495 sync_samples = sync_to_audio ? buffer_samples : 8 * sample_rate / (source_hz * (std == VID_PAL ? 313 : 262));
1496 max_repeat++; 1213 max_repeat++;
1497 min_buffered = (((float)max_repeat * (float)sample_rate/(float)source_hz)/* / (float)buffer_samples*/);// + 0.9999; 1214 min_buffered = (((float)max_repeat * (float)sample_rate/(float)source_hz)/* / (float)buffer_samples*/);// + 0.9999;
1498 //min_buffered *= buffer_samples; 1215 //min_buffered *= buffer_samples;
1499 debug_message("Min samples buffered before audio start: %d\n", min_buffered); 1216 debug_message("Min samples buffered before audio start: %d\n", min_buffered);
1500 max_adjust = BASE_MAX_ADJUST / source_hz; 1217 max_adjust = BASE_MAX_ADJUST / source_hz;
1806 } else if (local_cur_min < min_buffered / 2) { 1523 } else if (local_cur_min < min_buffered / 2) {
1807 adjust_ratio = max_adjust; 1524 adjust_ratio = max_adjust;
1808 } 1525 }
1809 if (adjust_ratio != 0.0f) { 1526 if (adjust_ratio != 0.0f) {
1810 average_change = 0; 1527 average_change = 0;
1811 for (uint8_t i = 0; i < num_audio_sources; i++) 1528 render_audio_adjust_speed(adjust_ratio);
1812 { 1529
1813 audio_sources[i]->buffer_inc = ((double)audio_sources[i]->buffer_inc) + ((double)audio_sources[i]->buffer_inc) * adjust_ratio + 0.5;
1814 }
1815 } 1530 }
1816 while (source_frame_count > 0) 1531 while (source_frame_count > 0)
1817 { 1532 {
1818 render_update_display(); 1533 render_update_display();
1819 source_frame_count--; 1534 source_frame_count--;
1907 uint32_t render_overscan_top() 1622 uint32_t render_overscan_top()
1908 { 1623 {
1909 return overscan_top[video_standard]; 1624 return overscan_top[video_standard];
1910 } 1625 }
1911 1626
1912 void render_wait_quit(vdp_context * context) 1627 void render_wait_quit(void)
1913 { 1628 {
1914 SDL_Event event; 1629 SDL_Event event;
1915 while(SDL_WaitEvent(&event)) { 1630 while(SDL_WaitEvent(&event)) {
1916 switch (event.type) { 1631 switch (event.type) {
1917 case SDL_QUIT: 1632 case SDL_QUIT:
2075 drain_events(); 1790 drain_events();
2076 in_toggle = 0; 1791 in_toggle = 0;
2077 need_ui_fb_resize = 1; 1792 need_ui_fb_resize = 1;
2078 } 1793 }
2079 1794
2080 uint32_t render_audio_buffer()
2081 {
2082 return buffer_samples;
2083 }
2084
2085 uint32_t render_sample_rate()
2086 {
2087 return sample_rate;
2088 }
2089
2090 void render_errorbox(char *title, char *message) 1795 void render_errorbox(char *title, char *message)
2091 { 1796 {
2092 SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, title, message, NULL); 1797 SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, title, message, NULL);
2093 } 1798 }
2094 1799