comparison render_sdl.c @ 1563:6a62434d6bb1

WIP dynamic rate control
author Michael Pavone <pavone@retrodev.com>
date Fri, 13 Apr 2018 22:25:50 -0700
parents d7b0d0ce8ed1
children 48b08986bf8f
comparison
equal deleted inserted replaced
1562:d7b0d0ce8ed1 1563:6a62434d6bb1
35 static uint8_t render_gl = 1; 35 static uint8_t render_gl = 1;
36 static uint8_t scanlines = 0; 36 static uint8_t scanlines = 0;
37 37
38 static uint32_t last_frame = 0; 38 static uint32_t last_frame = 0;
39 39
40 static int16_t * current_psg = NULL;
41 static int16_t * current_ym = NULL;
42
43 static uint32_t buffer_samples, sample_rate; 40 static uint32_t buffer_samples, sample_rate;
44 static uint32_t missing_count; 41 static uint32_t missing_count;
45 42
46 static SDL_mutex * audio_mutex; 43 static SDL_mutex * audio_mutex;
47 static SDL_cond * audio_ready; 44 static SDL_cond * audio_ready;
52 int16_t *front; 49 int16_t *front;
53 int16_t *back; 50 int16_t *back;
54 uint64_t buffer_fraction; 51 uint64_t buffer_fraction;
55 uint64_t buffer_inc; 52 uint64_t buffer_inc;
56 uint32_t buffer_pos; 53 uint32_t buffer_pos;
54 uint32_t read_start;
55 uint32_t read_end;
57 uint32_t lowpass_alpha; 56 uint32_t lowpass_alpha;
57 uint32_t mask;
58 int16_t last_left; 58 int16_t last_left;
59 int16_t last_right; 59 int16_t last_right;
60 uint8_t num_channels; 60 uint8_t num_channels;
61 uint8_t front_populated; 61 uint8_t front_populated;
62 uint8_t adjusted;
62 }; 63 };
63 64
64 static audio_source *audio_sources[8]; 65 static audio_source *audio_sources[8];
65 static uint8_t num_audio_sources; 66 static uint8_t num_audio_sources;
67 static uint8_t sync_to_audio;
68 static uint32_t min_buffered;
66 69
67 typedef void (*mix_func)(audio_source *audio, void *vstream, int len); 70 typedef void (*mix_func)(audio_source *audio, void *vstream, int len);
68 71
69 static void mix_s16(audio_source *audio, void *vstream, int len) 72 static void mix_s16(audio_source *audio, void *vstream, int len)
70 { 73 {
71 int samples = len/(sizeof(int16_t)*2); 74 int samples = len/(sizeof(int16_t)*2);
72 int16_t *stream = vstream; 75 int16_t *stream = vstream;
73 int16_t *end = stream + 2*samples; 76 int16_t *end = stream + 2*samples;
74 int16_t *src = audio->front; 77 int16_t *src = audio->front;
78 uint32_t i = audio->read_start;
79 uint32_t i_end = audio->read_end;
80 int16_t *cur = stream;
75 if (audio->num_channels == 1) { 81 if (audio->num_channels == 1) {
76 for (int16_t *cur = stream; cur < end;) 82 while (cur < end && i != i_end)
77 { 83 {
78 *(cur++) += *src; 84 *(cur++) += src[i];
79 *(cur++) += *(src++); 85 *(cur++) += src[i++];
86 i &= audio->mask;
80 } 87 }
81 } else { 88 } else {
82 for (int16_t *cur = stream; cur < end;) 89 while (cur < end && i != i_end)
83 { 90 {
84 *(cur++) += *(src++); 91 *(cur++) += src[i++];
85 *(cur++) += *(src++); 92 *(cur++) += src[i++];
86 } 93 i &= audio->mask;
94 }
95 }
96 if (cur != end) {
97 printf("Underflow of %d samples\n", (int)(end-cur)/2);
98 }
99 if (!sync_to_audio) {
100 audio->read_start = i;
87 } 101 }
88 } 102 }
89 103
90 static void mix_f32(audio_source *audio, void *vstream, int len) 104 static void mix_f32(audio_source *audio, void *vstream, int len)
91 { 105 {
92 int samples = len/(sizeof(float)*2); 106 int samples = len/(sizeof(float)*2);
93 float *stream = vstream; 107 float *stream = vstream;
94 float *end = stream + 2*samples; 108 float *end = stream + 2*samples;
95 int16_t *src = audio->front; 109 int16_t *src = audio->front;
110 uint32_t i = audio->read_start;
111 uint32_t i_end = audio->read_end;
112 float *cur = stream;
96 if (audio->num_channels == 1) { 113 if (audio->num_channels == 1) {
97 for (float *cur = stream; cur < end;) 114 while (cur < end && i != i_end)
98 { 115 {
99 *(cur++) += ((float)*src) / 0x7FFF; 116 *(cur++) += ((float)src[i]) / 0x7FFF;
100 *(cur++) += ((float)*(src++)) / 0x7FFF; 117 *(cur++) += ((float)src[i++]) / 0x7FFF;
118 i &= audio->mask;
101 } 119 }
102 } else { 120 } else {
103 for (float *cur = stream; cur < end;) 121 while(cur < end && i != i_end)
104 { 122 {
105 *(cur++) += ((float)*(src++)) / 0x7FFF; 123 *(cur++) += ((float)src[i++]) / 0x7FFF;
106 *(cur++) += ((float)*(src++)) / 0x7FFF; 124 *(cur++) += ((float)src[i++]) / 0x7FFF;
107 } 125 i &= audio->mask;
126 }
127 }
128 if (cur != end) {
129 printf("Underflow of %d samples\n", (int)(end-cur)/2);
130 }
131 if (!sync_to_audio) {
132 audio->read_start = i;
108 } 133 }
109 } 134 }
110 135
111 static void mix_null(audio_source *audio, void *vstream, int len) 136 static void mix_null(audio_source *audio, void *vstream, int len)
112 { 137 {
132 if (!quitting && num_populated < num_audio_sources) { 157 if (!quitting && num_populated < num_audio_sources) {
133 SDL_CondWait(audio_ready, audio_mutex); 158 SDL_CondWait(audio_ready, audio_mutex);
134 } 159 }
135 } while(!quitting && num_populated < num_audio_sources); 160 } while(!quitting && num_populated < num_audio_sources);
136 if (!quitting) { 161 if (!quitting) {
137 //int16_t *end = stream + 2*samples;
138 for (uint8_t i = 0; i < num_audio_sources; i++) 162 for (uint8_t i = 0; i < num_audio_sources; i++)
139 { 163 {
140 mix(audio_sources[i], byte_stream, len); 164 mix(audio_sources[i], byte_stream, len);
141 /*int16_t *src = audio_sources[i]->front;
142 if (audio_sources[i]->num_channels == 1) {
143 for (int16_t *cur = stream; cur < end;)
144 {
145 *(cur++) += *src;
146 *(cur++) += *(src++);
147 }
148 } else {
149 for (int16_t *cur = stream; cur < end;)
150 {
151 *(cur++) += *(src++);
152 *(cur++) += *(src++);
153 }
154 }*/
155 audio_sources[i]->front_populated = 0; 165 audio_sources[i]->front_populated = 0;
156 SDL_CondSignal(audio_sources[i]->cond); 166 SDL_CondSignal(audio_sources[i]->cond);
157 } 167 }
158 } 168 }
159 SDL_UnlockMutex(audio_mutex); 169 SDL_UnlockMutex(audio_mutex);
170 }
171
172 static int32_t buffered_diff_accum, accum_count, last_buffered = -1;
173 static uint8_t need_adjust;
174 static float adjust_ratio;
175 #define MIN_ACCUM_COUNT 3
176 #define BUFFER_FRAMES_THRESHOLD 6
177 #define MAX_ADJUST 0.01
178 static void audio_callback_drc(void *userData, uint8_t *byte_stream, int len)
179 {
180 //TODO: update progress tracking so we can adjust resample rate
181 memset(byte_stream, 0, len);
182 uint32_t min_buffered = 0xFFFFFFFF;
183 uint32_t min_remaining_buffer = 0xFFFFFFFF;
184 for (uint8_t i = 0; i < num_audio_sources; i++)
185 {
186 mix(audio_sources[i], byte_stream, len);
187 uint32_t buffered = (audio_sources[i]->read_end - audio_sources[i]->read_start) & audio_sources[i]->mask;
188 buffered /= audio_sources[i]->num_channels;
189 min_buffered = buffered < min_buffered ? buffered : min_buffered;
190 uint32_t remaining = (audio_sources[i]->mask + 1)/audio_sources[i]->num_channels - buffered;
191 min_remaining_buffer = remaining < min_remaining_buffer ? remaining : min_remaining_buffer;
192 }
193 if (last_buffered > -1) {
194 buffered_diff_accum += (int32_t)min_buffered - last_buffered;
195 accum_count++;
196 }
197 last_buffered = min_buffered;
198 if (accum_count > MIN_ACCUM_COUNT) {
199 float avg_change = (float)buffered_diff_accum / (float)accum_count, frames_to_problem;
200 if (buffered_diff_accum < 0) {
201 frames_to_problem = (float)min_buffered / -avg_change;
202 } else {
203 frames_to_problem = (float)min_remaining_buffer / avg_change;
204 }
205 if (frames_to_problem < BUFFER_FRAMES_THRESHOLD) {
206 need_adjust = num_audio_sources;
207 adjust_ratio = 1.5 * avg_change / buffer_samples;
208 buffered_diff_accum = 0;
209 accum_count = 0;
210 last_buffered = -1;
211 if (fabsf(adjust_ratio) > MAX_ADJUST) {
212 adjust_ratio = adjust_ratio > 0 ? MAX_ADJUST : -MAX_ADJUST;
213 }
214 printf("frames_to_problem: %f, avg_change: %f, adjust_ratio: %f\n", frames_to_problem, avg_change, adjust_ratio);
215 for (uint8_t i = 0; i < num_audio_sources; i++)
216 {
217 audio_sources[i]->adjusted = 0;
218 }
219 } else {
220 printf("no adjust - frames_to_problem: %f, avg_change: %f, min_buffered: %d, min_remaining_buffer: %d\n", frames_to_problem, avg_change, min_buffered, min_remaining_buffer);
221 }
222 } else {
223 printf("accum_count: %d, min_buffered: %d\n", accum_count, min_buffered);
224 }
225 if (abs(buffered_diff_accum) > 0x10000000) {
226 buffered_diff_accum /= 2;
227 accum_count /= 2;
228 }
229 }
230
231 static void lock_audio()
232 {
233 if (sync_to_audio) {
234 SDL_LockMutex(audio_mutex);
235 } else {
236 SDL_LockAudio();
237 }
238 }
239
240 static void unlock_audio()
241 {
242 if (sync_to_audio) {
243 SDL_UnlockMutex(audio_mutex);
244 } else {
245 SDL_UnlockAudio();
246 }
160 } 247 }
161 248
162 static void render_close_audio() 249 static void render_close_audio()
163 { 250 {
164 SDL_LockMutex(audio_mutex); 251 SDL_LockMutex(audio_mutex);
176 } 263 }
177 264
178 audio_source *render_audio_source(uint64_t master_clock, uint64_t sample_divider, uint8_t channels) 265 audio_source *render_audio_source(uint64_t master_clock, uint64_t sample_divider, uint8_t channels)
179 { 266 {
180 audio_source *ret = NULL; 267 audio_source *ret = NULL;
181 SDL_LockMutex(audio_mutex); 268 uint32_t alloc_size = sync_to_audio ? channels * buffer_samples : nearest_pow2(min_buffered * 2 * channels);
269 lock_audio();
182 if (num_audio_sources < 8) { 270 if (num_audio_sources < 8) {
183 ret = malloc(sizeof(audio_source)); 271 ret = malloc(sizeof(audio_source));
184 ret->front = malloc(channels * buffer_samples * sizeof(int16_t)); 272 ret->back = malloc(alloc_size * sizeof(int16_t));
185 ret->back = malloc(channels * buffer_samples * sizeof(int16_t)); 273 ret->front = sync_to_audio ? malloc(alloc_size * sizeof(int16_t)) : ret->back;
186 ret->front_populated = 0; 274 ret->front_populated = 0;
187 ret->cond = SDL_CreateCond(); 275 ret->cond = SDL_CreateCond();
188 ret->num_channels = channels; 276 ret->num_channels = channels;
277 ret->adjusted = 0;
189 audio_sources[num_audio_sources++] = ret; 278 audio_sources[num_audio_sources++] = ret;
190 } 279 }
191 SDL_UnlockMutex(audio_mutex); 280 unlock_audio();
192 if (!ret) { 281 if (!ret) {
193 fatal_error("Too many audio sources!"); 282 fatal_error("Too many audio sources!");
194 } else { 283 } else {
195 render_audio_adjust_clock(ret, master_clock, sample_divider); 284 render_audio_adjust_clock(ret, master_clock, sample_divider);
196 double lowpass_cutoff = get_lowpass_cutoff(config); 285 double lowpass_cutoff = get_lowpass_cutoff(config);
199 double alpha = dt / (dt + rc); 288 double alpha = dt / (dt + rc);
200 ret->lowpass_alpha = (int32_t)(((double)0x10000) * alpha); 289 ret->lowpass_alpha = (int32_t)(((double)0x10000) * alpha);
201 ret->buffer_pos = 0; 290 ret->buffer_pos = 0;
202 ret->buffer_fraction = 0; 291 ret->buffer_fraction = 0;
203 ret->last_left = ret->last_right = 0; 292 ret->last_left = ret->last_right = 0;
293 ret->read_start = ret->read_end = 0;
294 ret->mask = alloc_size-1;
204 } 295 }
205 return ret; 296 return ret;
206 } 297 }
207 298
208 void render_pause_source(audio_source *src) 299 void render_pause_source(audio_source *src)
209 { 300 {
210 SDL_LockMutex(audio_mutex); 301 uint8_t need_pause = 0;
302 lock_audio();
211 for (uint8_t i = 0; i < num_audio_sources; i++) 303 for (uint8_t i = 0; i < num_audio_sources; i++)
212 { 304 {
213 if (audio_sources[i] == src) { 305 if (audio_sources[i] == src) {
214 audio_sources[i] = audio_sources[--num_audio_sources]; 306 audio_sources[i] = audio_sources[--num_audio_sources];
215 SDL_CondSignal(audio_ready); 307 if (sync_to_audio) {
308 SDL_CondSignal(audio_ready);
309 }
216 break; 310 break;
217 } 311 }
218 } 312 }
219 SDL_UnlockMutex(audio_mutex); 313 if (!num_audio_sources) {
314 need_pause = 1;
315 }
316 unlock_audio();
317 if (need_pause) {
318 SDL_PauseAudio(1);
319 }
220 } 320 }
221 321
222 void render_resume_source(audio_source *src) 322 void render_resume_source(audio_source *src)
223 { 323 {
224 SDL_LockMutex(audio_mutex); 324 lock_audio();
225 if (num_audio_sources < 8) { 325 if (num_audio_sources < 8) {
226 audio_sources[num_audio_sources++] = src; 326 audio_sources[num_audio_sources++] = src;
227 } 327 }
228 SDL_UnlockMutex(audio_mutex); 328 unlock_audio();
329 if (sync_to_audio) {
330 SDL_PauseAudio(0);
331 }
229 } 332 }
230 333
231 void render_free_source(audio_source *src) 334 void render_free_source(audio_source *src)
232 { 335 {
233 render_pause_source(src); 336 render_pause_source(src);
234 337
235 free(src->front); 338 free(src->front);
236 free(src->back); 339 free(src->back);
237 SDL_DestroyCond(src->cond); 340 if (sync_to_audio) {
341 SDL_DestroyCond(src->cond);
342 }
238 free(src); 343 free(src);
239 } 344 }
240 345 static uint32_t sync_samples;
241 static void do_audio_ready(audio_source *src) 346 static void do_audio_ready(audio_source *src)
242 { 347 {
243 SDL_LockMutex(audio_mutex); 348 if (sync_to_audio) {
244 while (src->front_populated) { 349 SDL_LockMutex(audio_mutex);
245 SDL_CondWait(src->cond, audio_mutex); 350 while (src->front_populated) {
246 } 351 SDL_CondWait(src->cond, audio_mutex);
247 int16_t *tmp = src->front; 352 }
248 src->front = src->back; 353 int16_t *tmp = src->front;
249 src->back = tmp; 354 src->front = src->back;
250 src->front_populated = 1; 355 src->back = tmp;
251 src->buffer_pos = 0; 356 src->front_populated = 1;
252 SDL_CondSignal(audio_ready); 357 src->buffer_pos = 0;
253 SDL_UnlockMutex(audio_mutex); 358 SDL_CondSignal(audio_ready);
359 SDL_UnlockMutex(audio_mutex);
360 } else {
361 uint32_t num_buffered;
362 SDL_LockAudio();
363 src->read_end = src->buffer_pos;
364 num_buffered = (src->read_end - src->read_start) & src->mask;
365 if (need_adjust && !src->adjusted) {
366 src->adjusted = 1;
367 need_adjust--;
368 src->buffer_inc = ((double)src->buffer_inc) + ((double)src->buffer_inc) * adjust_ratio + 0.5;
369 }
370 SDL_UnlockAudio();
371 if (num_buffered >= min_buffered && SDL_GetAudioStatus() == SDL_AUDIO_PAUSED) {
372 SDL_PauseAudio(0);
373 }
374 }
254 } 375 }
255 376
256 static int16_t lowpass_sample(audio_source *src, int16_t last, int16_t current) 377 static int16_t lowpass_sample(audio_source *src, int16_t last, int16_t current)
257 { 378 {
258 int32_t tmp = current * src->lowpass_alpha + last * (0x10000 - src->lowpass_alpha); 379 int32_t tmp = current * src->lowpass_alpha + last * (0x10000 - src->lowpass_alpha);
274 while (src->buffer_fraction > BUFFER_INC_RES) 395 while (src->buffer_fraction > BUFFER_INC_RES)
275 { 396 {
276 src->buffer_fraction -= BUFFER_INC_RES; 397 src->buffer_fraction -= BUFFER_INC_RES;
277 interp_sample(src, src->last_left, value); 398 interp_sample(src, src->last_left, value);
278 399
279 if (src->buffer_pos == buffer_samples) { 400 if (((src->buffer_pos - src->read_end) & src->mask) >= sync_samples) {
280 do_audio_ready(src); 401 do_audio_ready(src);
281 } 402 }
403 src->buffer_pos &= src->mask;
282 } 404 }
283 src->last_left = value; 405 src->last_left = value;
284 } 406 }
285 407
286 void render_put_stereo_sample(audio_source *src, int16_t left, int16_t right) 408 void render_put_stereo_sample(audio_source *src, int16_t left, int16_t right)
293 src->buffer_fraction -= BUFFER_INC_RES; 415 src->buffer_fraction -= BUFFER_INC_RES;
294 416
295 interp_sample(src, src->last_left, left); 417 interp_sample(src, src->last_left, left);
296 interp_sample(src, src->last_right, right); 418 interp_sample(src, src->last_right, right);
297 419
298 if (src->buffer_pos == buffer_samples * 2) { 420 if (((src->buffer_pos - src->read_end) & src->mask)/2 >= sync_samples) {
299 do_audio_ready(src); 421 do_audio_ready(src);
300 } 422 }
423 src->buffer_pos &= src->mask;
301 } 424 }
302 src->last_left = left; 425 src->last_left = left;
303 src->last_right = right; 426 src->last_right = right;
304 } 427 }
305 428
534 static uint32_t overscan_bot[NUM_VID_STD] = {1, 17}; 657 static uint32_t overscan_bot[NUM_VID_STD] = {1, 17};
535 static uint32_t overscan_left[NUM_VID_STD] = {13, 13}; 658 static uint32_t overscan_left[NUM_VID_STD] = {13, 13};
536 static uint32_t overscan_right[NUM_VID_STD] = {14, 14}; 659 static uint32_t overscan_right[NUM_VID_STD] = {14, 14};
537 static vid_std video_standard = VID_NTSC; 660 static vid_std video_standard = VID_NTSC;
538 static char *vid_std_names[NUM_VID_STD] = {"ntsc", "pal"}; 661 static char *vid_std_names[NUM_VID_STD] = {"ntsc", "pal"};
662 static int display_hz;
663 static int source_hz;
664 static int source_frame;
665 static int source_frame_count;
666 static int frame_repeat[60];
539 void render_init(int width, int height, char * title, uint8_t fullscreen) 667 void render_init(int width, int height, char * title, uint8_t fullscreen)
540 { 668 {
541 if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) < 0) { 669 if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) < 0) {
542 fatal_error("Unable to init SDL: %s\n", SDL_GetError()); 670 fatal_error("Unable to init SDL: %s\n", SDL_GetError());
543 } 671 }
549 printf("width: %d, height: %d\n", width, height); 677 printf("width: %d, height: %d\n", width, height);
550 windowed_width = width; 678 windowed_width = width;
551 windowed_height = height; 679 windowed_height = height;
552 680
553 uint32_t flags = SDL_WINDOW_RESIZABLE; 681 uint32_t flags = SDL_WINDOW_RESIZABLE;
682
683 SDL_DisplayMode mode;
684 //TODO: Explicit multiple monitor support
685 SDL_GetCurrentDisplayMode(0, &mode);
686 display_hz = mode.refresh_rate;
554 687
555 if (fullscreen) { 688 if (fullscreen) {
556 flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; 689 flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
557 SDL_DisplayMode mode;
558 //TODO: Multiple monitor support
559 SDL_GetCurrentDisplayMode(0, &mode);
560 //the SDL2 migration guide suggests setting width and height to 0 when using SDL_WINDOW_FULLSCREEN_DESKTOP 690 //the SDL2 migration guide suggests setting width and height to 0 when using SDL_WINDOW_FULLSCREEN_DESKTOP
561 //but that doesn't seem to work right when using OpenGL, at least on Linux anyway 691 //but that doesn't seem to work right when using OpenGL, at least on Linux anyway
562 width = mode.w; 692 width = mode.w;
563 height = mode.h; 693 height = mode.h;
564 } 694 }
565 main_width = width; 695 main_width = width;
566 main_height = height; 696 main_height = height;
567 is_fullscreen = fullscreen; 697 is_fullscreen = fullscreen;
698
699 tern_val def = {.ptrval = "video"};
700 char *sync_src = tern_find_path_default(config, "system\0sync_source\0", def, TVAL_PTR).ptrval;
701 sync_to_audio = !strcmp(sync_src, "audio");
568 702
569 render_gl = 0; 703 render_gl = 0;
570 tern_val def = {.ptrval = "off"}; 704 char *vsync;
571 char *vsync = tern_find_path_default(config, "video\0vsync\0", def, TVAL_PTR).ptrval; 705 if (sync_to_audio) {
706 def.ptrval = "off";
707 vsync = tern_find_path_default(config, "video\0vsync\0", def, TVAL_PTR).ptrval;
708 } else {
709 vsync = "on";
710 }
572 711
573 tern_node *video = tern_find_node(config, "video"); 712 tern_node *video = tern_find_node(config, "video");
574 if (video) 713 if (video)
575 { 714 {
576 for (int i = 0; i < NUM_VID_STD; i++) 715 for (int i = 0; i < NUM_VID_STD; i++)
686 if (!samples) { 825 if (!samples) {
687 samples = 512; 826 samples = 512;
688 } 827 }
689 printf("config says: %d\n", samples); 828 printf("config says: %d\n", samples);
690 desired.samples = samples*2; 829 desired.samples = samples*2;
691 desired.callback = audio_callback; 830 desired.callback = sync_to_audio ? audio_callback : audio_callback_drc;
692 desired.userdata = NULL; 831 desired.userdata = NULL;
693 832
694 if (SDL_OpenAudio(&desired, &actual) < 0) { 833 if (SDL_OpenAudio(&desired, &actual) < 0) {
695 fatal_error("Unable to open SDL audio: %s\n", SDL_GetError()); 834 fatal_error("Unable to open SDL audio: %s\n", SDL_GetError());
696 } 835 }
706 } else { 845 } else {
707 printf("unsupported format %X\n", actual.format); 846 printf("unsupported format %X\n", actual.format);
708 warning("Unsupported audio sample format: %X\n", actual.format); 847 warning("Unsupported audio sample format: %X\n", actual.format);
709 mix = mix_null; 848 mix = mix_null;
710 } 849 }
711 SDL_PauseAudio(0);
712 850
713 uint32_t db_size; 851 uint32_t db_size;
714 char *db_data = read_bundled_file("gamecontrollerdb.txt", &db_size); 852 char *db_data = read_bundled_file("gamecontrollerdb.txt", &db_size);
715 if (db_data) { 853 if (db_data) {
716 int added = SDL_GameControllerAddMappingsFromRW(SDL_RWFromMem(db_data, db_size), 1); 854 int added = SDL_GameControllerAddMappingsFromRW(SDL_RWFromMem(db_data, db_size), 1);
717 free(db_data); 855 free(db_data);
718 printf("Added %d game controller mappings from gamecontrollerdb.txt\n", added); 856 printf("Added %d game controller mappings from gamecontrollerdb.txt\n", added);
719 } 857 }
720 858
721 SDL_JoystickEventState(SDL_ENABLE); 859 SDL_JoystickEventState(SDL_ENABLE);
860
861 render_set_video_standard(VID_NTSC);
722 862
723 atexit(render_quit); 863 atexit(render_quit);
724 } 864 }
725 865
726 SDL_Window *render_get_window(void) 866 SDL_Window *render_get_window(void)
729 } 869 }
730 870
731 void render_set_video_standard(vid_std std) 871 void render_set_video_standard(vid_std std)
732 { 872 {
733 video_standard = std; 873 video_standard = std;
874 source_hz = std == VID_PAL ? 50 : 60;
875 uint32_t max_repeat = 0;
876 if (abs(source_hz - display_hz) < 2) {
877 memset(frame_repeat, 0, sizeof(int)*display_hz);
878 } else {
879 int inc = display_hz * 100000 / source_hz;
880 int accum = 0;
881 int dst_frames = 0;
882 for (int src_frame = 0; src_frame < source_hz; src_frame++)
883 {
884 frame_repeat[src_frame] = -1;
885 accum += inc;
886 while (accum > 100000)
887 {
888 accum -= 100000;
889 frame_repeat[src_frame]++;
890 max_repeat = frame_repeat[src_frame] > max_repeat ? frame_repeat[src_frame] : max_repeat;
891 dst_frames++;
892 }
893 }
894 if (dst_frames != display_hz) {
895 frame_repeat[source_hz-1] += display_hz - dst_frames;
896 }
897 }
898 source_frame = 0;
899 source_frame_count = frame_repeat[0];
900 //sync samples with audio thread approximately every 8 lines
901 sync_samples = 8 * sample_rate / (source_hz * (VID_PAL ? 313 : 262));
902 max_repeat++;
903 min_buffered = (((float)max_repeat * 1.5 * (float)sample_rate/(float)source_hz) / (float)buffer_samples) + 0.9999;
904 min_buffered *= buffer_samples;
734 } 905 }
735 906
736 void render_update_caption(char *title) 907 void render_update_caption(char *title)
737 { 908 {
738 caption = title; 909 caption = title;
796 static uint32_t last_width, last_height; 967 static uint32_t last_width, last_height;
797 static uint8_t interlaced; 968 static uint8_t interlaced;
798 void render_framebuffer_updated(uint8_t which, int width) 969 void render_framebuffer_updated(uint8_t which, int width)
799 { 970 {
800 static uint8_t last; 971 static uint8_t last;
972 if (!sync_to_audio && which <= FRAMEBUFFER_EVEN && source_frame_count < 0) {
973 source_frame++;
974 if (source_frame >= source_hz) {
975 source_frame = 0;
976 }
977 source_frame_count = frame_repeat[source_frame];
978 //TODO: Figure out what to do about SDL Render API texture locking
979 return;
980 }
981
801 last_width = width; 982 last_width = width;
802 uint32_t height = which <= FRAMEBUFFER_EVEN 983 uint32_t height = which <= FRAMEBUFFER_EVEN
803 ? (video_standard == VID_NTSC ? 243 : 294) - (overscan_top[video_standard] + overscan_bot[video_standard]) 984 ? (video_standard == VID_NTSC ? 243 : 294) - (overscan_top[video_standard] + overscan_bot[video_standard])
804 : 240; 985 : 240;
805 FILE *screenshot_file = NULL; 986 FILE *screenshot_file = NULL;
906 } 1087 }
907 start = last_frame; 1088 start = last_frame;
908 frame_counter = 0; 1089 frame_counter = 0;
909 } 1090 }
910 } 1091 }
1092 while (source_frame_count > 0)
1093 {
1094 render_update_display();
1095 source_frame_count--;
1096 }
1097 source_frame++;
1098 if (source_frame >= source_hz) {
1099 source_frame = 0;
1100 }
1101 source_frame_count = frame_repeat[source_frame];
911 } 1102 }
912 1103
913 static ui_render_fun render_ui; 1104 static ui_render_fun render_ui;
914 void render_set_ui_render_fun(ui_render_fun fun) 1105 void render_set_ui_render_fun(ui_render_fun fun)
915 { 1106 {