Mercurial > repos > blastem
comparison render_sdl.c @ 354:15dd6418fe67
Initial PSG support. Mostly works, noise channel is borked though.
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Thu, 23 May 2013 23:42:42 -0700 |
parents | 13f994c88c34 |
children | 79e4b466e7d0 |
comparison
equal
deleted
inserted
replaced
353:a60e527cd21f | 354:15dd6418fe67 |
---|---|
14 uint8_t levels[] = {0, 27, 49, 71, 87, 103, 119, 130, 146, 157, 174, 190, 206, 228, 255}; | 14 uint8_t levels[] = {0, 27, 49, 71, 87, 103, 119, 130, 146, 157, 174, 190, 206, 228, 255}; |
15 | 15 |
16 uint32_t min_delay; | 16 uint32_t min_delay; |
17 uint32_t frame_delay = 1000/60; | 17 uint32_t frame_delay = 1000/60; |
18 | 18 |
19 void render_init(int width, int height, char * title) | 19 int16_t * current_audio = NULL; |
20 { | 20 int16_t * next_audio = NULL; |
21 if (SDL_Init(SDL_INIT_VIDEO) < 0) { | 21 |
22 uint32_t buffer_samples, sample_rate; | |
23 uint32_t missing_count; | |
24 | |
25 SDL_mutex * audio_mutex; | |
26 SDL_cond * audio_ready; | |
27 SDL_cond * audio_cond; | |
28 | |
29 void audio_callback(void * userdata, uint8_t *byte_stream, int len) | |
30 { | |
31 //puts("audio_callback"); | |
32 int16_t * stream = (int16_t *)byte_stream; | |
33 int samples = len/(sizeof(int16_t)*2); | |
34 int16_t * source_buf; | |
35 | |
36 SDL_LockMutex(audio_mutex); | |
37 while (!current_audio) { | |
38 SDL_CondWait(audio_ready, audio_mutex); | |
39 } | |
40 source_buf = current_audio; | |
41 current_audio = NULL; | |
42 SDL_CondSignal(audio_cond); | |
43 SDL_UnlockMutex(audio_mutex); | |
44 | |
45 for (int i = 0; i < samples; i++) { | |
46 *(stream++) = source_buf[i]; | |
47 *(stream++) = source_buf[i]; | |
48 } | |
49 } | |
50 | |
51 void render_init(int width, int height, char * title, uint32_t fps) | |
52 { | |
53 if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) { | |
22 fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError()); | 54 fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError()); |
23 exit(1); | 55 exit(1); |
24 } | 56 } |
25 atexit(SDL_Quit); | 57 atexit(SDL_Quit); |
26 printf("width: %d, height: %d\n", width, height); | 58 printf("width: %d, height: %d\n", width, height); |
62 } | 94 } |
63 if (!min_delay) { | 95 if (!min_delay) { |
64 min_delay = 1; | 96 min_delay = 1; |
65 } | 97 } |
66 printf("minimum delay: %d\n", min_delay); | 98 printf("minimum delay: %d\n", min_delay); |
99 | |
100 frame_delay = 1000/fps; | |
101 | |
102 audio_mutex = SDL_CreateMutex(); | |
103 audio_cond = SDL_CreateCond(); | |
104 audio_ready = SDL_CreateCond(); | |
105 | |
106 SDL_AudioSpec desired, actual; | |
107 desired.freq = 48000; | |
108 desired.format = AUDIO_S16SYS; | |
109 desired.channels = 2; | |
110 desired.samples = 1024; | |
111 desired.callback = audio_callback; | |
112 desired.userdata = NULL; | |
113 | |
114 if (SDL_OpenAudio(&desired, &actual) < 0) { | |
115 fprintf(stderr, "Unable to open SDL audio: %s\n", SDL_GetError()); | |
116 exit(1); | |
117 } | |
118 buffer_samples = actual.samples; | |
119 sample_rate = actual.freq; | |
120 printf("Initialized audio at frequency %d with a %d sample buffer\n", actual.freq, actual.samples); | |
121 SDL_PauseAudio(0); | |
67 } | 122 } |
68 | 123 |
69 void render_context(vdp_context * context) | 124 void render_context(vdp_context * context) |
70 { | 125 { |
71 uint8_t *buf_8; | 126 uint8_t *buf_8; |
228 #define BUTTON_A 0x10 | 283 #define BUTTON_A 0x10 |
229 #define BUTTON_B 0x10 | 284 #define BUTTON_B 0x10 |
230 #define BUTTON_START 0x20 | 285 #define BUTTON_START 0x20 |
231 #define BUTTON_C 0x20 | 286 #define BUTTON_C 0x20 |
232 | 287 |
288 int32_t handle_event(SDL_Event *event) | |
289 { | |
290 FILE * outfile; | |
291 switch (event->type) { | |
292 case SDL_KEYDOWN: | |
293 switch(event->key.keysym.sym) | |
294 { | |
295 case SDLK_LEFTBRACKET: | |
296 render_dbg++; | |
297 if (render_dbg == 4) { | |
298 render_dbg = 0; | |
299 } | |
300 break; | |
301 case SDLK_RIGHTBRACKET: | |
302 debug_pal++; | |
303 if (debug_pal == 4) { | |
304 debug_pal = 0; | |
305 } | |
306 break; | |
307 case SDLK_t: | |
308 /*outfile = fopen("state.gst", "wb"); | |
309 fwrite("GST\0\0\0\xE0\x40", 1, 8, outfile); | |
310 vdp_save_state(context, outfile); | |
311 fclose(outfile); | |
312 puts("state saved to state.gst");*/ | |
313 break; | |
314 case SDLK_u: | |
315 return 1; | |
316 case SDLK_RETURN: | |
317 gamepad_1.input[GAMEPAD_TH0] |= BUTTON_START; | |
318 break; | |
319 case SDLK_UP: | |
320 gamepad_1.input[GAMEPAD_TH0] |= DPAD_UP; | |
321 gamepad_1.input[GAMEPAD_TH1] |= DPAD_UP; | |
322 break; | |
323 case SDLK_DOWN: | |
324 gamepad_1.input[GAMEPAD_TH0] |= DPAD_DOWN; | |
325 gamepad_1.input[GAMEPAD_TH1] |= DPAD_DOWN; | |
326 break; | |
327 case SDLK_LEFT: | |
328 gamepad_1.input[GAMEPAD_TH1] |= DPAD_LEFT; | |
329 break; | |
330 case SDLK_RIGHT: | |
331 gamepad_1.input[GAMEPAD_TH1] |= DPAD_RIGHT; | |
332 break; | |
333 case SDLK_a: | |
334 gamepad_1.input[GAMEPAD_TH0] |= BUTTON_A; | |
335 //printf("BUTTON_A Dn | GAMEPAD_TH0: %X\n", gamepad_1.input[GAMEPAD_TH0]); | |
336 break; | |
337 case SDLK_s: | |
338 gamepad_1.input[GAMEPAD_TH1] |= BUTTON_B; | |
339 gamepad_1.input[GAMEPAD_EXTRA] |= BUTTON_B; | |
340 break; | |
341 case SDLK_d: | |
342 gamepad_1.input[GAMEPAD_TH1] |= BUTTON_C; | |
343 gamepad_1.input[GAMEPAD_EXTRA] |= BUTTON_C; | |
344 break; | |
345 case SDLK_q: | |
346 gamepad_1.input[GAMEPAD_EXTRA] |= BUTTON_X; | |
347 break; | |
348 case SDLK_w: | |
349 gamepad_1.input[GAMEPAD_EXTRA] |= BUTTON_Y; | |
350 break; | |
351 case SDLK_e: | |
352 gamepad_1.input[GAMEPAD_EXTRA] |= BUTTON_Z; | |
353 break; | |
354 case SDLK_f: | |
355 gamepad_1.input[GAMEPAD_EXTRA] |= BUTTON_MODE; | |
356 break; | |
357 } | |
358 break; | |
359 case SDL_KEYUP: | |
360 switch(event->key.keysym.sym) | |
361 { | |
362 case SDLK_RETURN: | |
363 gamepad_1.input[GAMEPAD_TH0] &= ~BUTTON_START; | |
364 break; | |
365 case SDLK_UP: | |
366 gamepad_1.input[GAMEPAD_TH0] &= ~DPAD_UP; | |
367 gamepad_1.input[GAMEPAD_TH1] &= ~DPAD_UP; | |
368 break; | |
369 case SDLK_DOWN: | |
370 gamepad_1.input[GAMEPAD_TH0] &= ~DPAD_DOWN; | |
371 gamepad_1.input[GAMEPAD_TH1] &= ~DPAD_DOWN; | |
372 break; | |
373 case SDLK_LEFT: | |
374 gamepad_1.input[GAMEPAD_TH1] &= ~DPAD_LEFT; | |
375 break; | |
376 case SDLK_RIGHT: | |
377 gamepad_1.input[GAMEPAD_TH1] &= ~DPAD_RIGHT; | |
378 break; | |
379 case SDLK_a: | |
380 gamepad_1.input[GAMEPAD_TH0] &= ~BUTTON_A; | |
381 //printf("BUTTON_A Up | GAMEPAD_TH0: %X\n", gamepad_1.input[GAMEPAD_TH0]); | |
382 break; | |
383 case SDLK_s: | |
384 gamepad_1.input[GAMEPAD_TH1] &= ~BUTTON_B; | |
385 gamepad_1.input[GAMEPAD_EXTRA] &= ~BUTTON_B; | |
386 break; | |
387 case SDLK_d: | |
388 gamepad_1.input[GAMEPAD_TH1] &= ~BUTTON_C; | |
389 gamepad_1.input[GAMEPAD_EXTRA] &= ~BUTTON_C; | |
390 break; | |
391 case SDLK_q: | |
392 gamepad_1.input[GAMEPAD_EXTRA] &= ~BUTTON_X; | |
393 break; | |
394 case SDLK_w: | |
395 gamepad_1.input[GAMEPAD_EXTRA] &= ~BUTTON_Y; | |
396 break; | |
397 case SDLK_e: | |
398 gamepad_1.input[GAMEPAD_EXTRA] &= ~BUTTON_Z; | |
399 break; | |
400 case SDLK_f: | |
401 gamepad_1.input[GAMEPAD_EXTRA] &= ~BUTTON_MODE; | |
402 break; | |
403 } | |
404 break; | |
405 case SDL_QUIT: | |
406 puts(""); | |
407 exit(0); | |
408 } | |
409 return 0; | |
410 } | |
411 | |
233 uint32_t frame_counter = 0; | 412 uint32_t frame_counter = 0; |
234 uint32_t start = 0; | 413 uint32_t start = 0; |
235 int wait_render_frame(vdp_context * context, int frame_limit) | 414 int wait_render_frame(vdp_context * context, int frame_limit) |
236 { | 415 { |
237 FILE * outfile; | |
238 SDL_Event event; | 416 SDL_Event event; |
239 int ret = 0; | 417 int ret = 0; |
240 while(SDL_PollEvent(&event)) { | 418 while(SDL_PollEvent(&event)) { |
241 switch (event.type) { | 419 ret = handle_event(&event); |
242 case SDL_KEYDOWN: | |
243 switch(event.key.keysym.sym) | |
244 { | |
245 case SDLK_LEFTBRACKET: | |
246 render_dbg++; | |
247 if (render_dbg == 4) { | |
248 render_dbg = 0; | |
249 } | |
250 break; | |
251 case SDLK_RIGHTBRACKET: | |
252 debug_pal++; | |
253 if (debug_pal == 4) { | |
254 debug_pal = 0; | |
255 } | |
256 break; | |
257 case SDLK_t: | |
258 outfile = fopen("state.gst", "wb"); | |
259 fwrite("GST\0\0\0\xE0\x40", 1, 8, outfile); | |
260 vdp_save_state(context, outfile); | |
261 fclose(outfile); | |
262 puts("state saved to state.gst"); | |
263 break; | |
264 case SDLK_u: | |
265 ret = 1; | |
266 break; | |
267 case SDLK_RETURN: | |
268 gamepad_1.input[GAMEPAD_TH0] |= BUTTON_START; | |
269 break; | |
270 case SDLK_UP: | |
271 gamepad_1.input[GAMEPAD_TH0] |= DPAD_UP; | |
272 gamepad_1.input[GAMEPAD_TH1] |= DPAD_UP; | |
273 break; | |
274 case SDLK_DOWN: | |
275 gamepad_1.input[GAMEPAD_TH0] |= DPAD_DOWN; | |
276 gamepad_1.input[GAMEPAD_TH1] |= DPAD_DOWN; | |
277 break; | |
278 case SDLK_LEFT: | |
279 gamepad_1.input[GAMEPAD_TH1] |= DPAD_LEFT; | |
280 break; | |
281 case SDLK_RIGHT: | |
282 gamepad_1.input[GAMEPAD_TH1] |= DPAD_RIGHT; | |
283 break; | |
284 case SDLK_a: | |
285 gamepad_1.input[GAMEPAD_TH0] |= BUTTON_A; | |
286 //printf("BUTTON_A Dn | GAMEPAD_TH0: %X\n", gamepad_1.input[GAMEPAD_TH0]); | |
287 break; | |
288 case SDLK_s: | |
289 gamepad_1.input[GAMEPAD_TH1] |= BUTTON_B; | |
290 gamepad_1.input[GAMEPAD_EXTRA] |= BUTTON_B; | |
291 break; | |
292 case SDLK_d: | |
293 gamepad_1.input[GAMEPAD_TH1] |= BUTTON_C; | |
294 gamepad_1.input[GAMEPAD_EXTRA] |= BUTTON_C; | |
295 break; | |
296 case SDLK_q: | |
297 gamepad_1.input[GAMEPAD_EXTRA] |= BUTTON_X; | |
298 break; | |
299 case SDLK_w: | |
300 gamepad_1.input[GAMEPAD_EXTRA] |= BUTTON_Y; | |
301 break; | |
302 case SDLK_e: | |
303 gamepad_1.input[GAMEPAD_EXTRA] |= BUTTON_Z; | |
304 break; | |
305 case SDLK_f: | |
306 gamepad_1.input[GAMEPAD_EXTRA] |= BUTTON_MODE; | |
307 break; | |
308 } | |
309 break; | |
310 case SDL_KEYUP: | |
311 switch(event.key.keysym.sym) | |
312 { | |
313 case SDLK_RETURN: | |
314 gamepad_1.input[GAMEPAD_TH0] &= ~BUTTON_START; | |
315 break; | |
316 case SDLK_UP: | |
317 gamepad_1.input[GAMEPAD_TH0] &= ~DPAD_UP; | |
318 gamepad_1.input[GAMEPAD_TH1] &= ~DPAD_UP; | |
319 break; | |
320 case SDLK_DOWN: | |
321 gamepad_1.input[GAMEPAD_TH0] &= ~DPAD_DOWN; | |
322 gamepad_1.input[GAMEPAD_TH1] &= ~DPAD_DOWN; | |
323 break; | |
324 case SDLK_LEFT: | |
325 gamepad_1.input[GAMEPAD_TH1] &= ~DPAD_LEFT; | |
326 break; | |
327 case SDLK_RIGHT: | |
328 gamepad_1.input[GAMEPAD_TH1] &= ~DPAD_RIGHT; | |
329 break; | |
330 case SDLK_a: | |
331 gamepad_1.input[GAMEPAD_TH0] &= ~BUTTON_A; | |
332 //printf("BUTTON_A Up | GAMEPAD_TH0: %X\n", gamepad_1.input[GAMEPAD_TH0]); | |
333 break; | |
334 case SDLK_s: | |
335 gamepad_1.input[GAMEPAD_TH1] &= ~BUTTON_B; | |
336 gamepad_1.input[GAMEPAD_EXTRA] &= ~BUTTON_B; | |
337 break; | |
338 case SDLK_d: | |
339 gamepad_1.input[GAMEPAD_TH1] &= ~BUTTON_C; | |
340 gamepad_1.input[GAMEPAD_EXTRA] &= ~BUTTON_C; | |
341 break; | |
342 case SDLK_q: | |
343 gamepad_1.input[GAMEPAD_EXTRA] &= ~BUTTON_X; | |
344 break; | |
345 case SDLK_w: | |
346 gamepad_1.input[GAMEPAD_EXTRA] &= ~BUTTON_Y; | |
347 break; | |
348 case SDLK_e: | |
349 gamepad_1.input[GAMEPAD_EXTRA] &= ~BUTTON_Z; | |
350 break; | |
351 case SDLK_f: | |
352 gamepad_1.input[GAMEPAD_EXTRA] &= ~BUTTON_MODE; | |
353 break; | |
354 } | |
355 break; | |
356 case SDL_QUIT: | |
357 puts(""); | |
358 exit(0); | |
359 } | |
360 } | 420 } |
361 if (frame_limit) { | 421 if (frame_limit) { |
422 puts("evil frame limit"); | |
362 //TODO: Adjust frame delay so we actually get 60 FPS rather than 62.5 FPS | 423 //TODO: Adjust frame delay so we actually get 60 FPS rather than 62.5 FPS |
363 uint32_t current = SDL_GetTicks(); | 424 uint32_t current = SDL_GetTicks(); |
364 uint32_t desired = last_frame + frame_delay; | 425 uint32_t desired = last_frame + frame_delay; |
365 if (current < desired) { | 426 if (current < desired) { |
366 uint32_t delay = last_frame + frame_delay - current; | 427 uint32_t delay = last_frame + frame_delay - current; |
385 frame_counter = 0; | 446 frame_counter = 0; |
386 }*/ | 447 }*/ |
387 return ret; | 448 return ret; |
388 } | 449 } |
389 | 450 |
451 void render_wait_audio(psg_context * context) | |
452 { | |
453 SDL_LockMutex(audio_mutex); | |
454 while (current_audio != NULL) { | |
455 SDL_CondWait(audio_cond, audio_mutex); | |
456 } | |
457 current_audio = context->audio_buffer; | |
458 SDL_CondSignal(audio_ready); | |
459 | |
460 context->audio_buffer = context->back_buffer; | |
461 context->back_buffer = current_audio; | |
462 SDL_UnlockMutex(audio_mutex); | |
463 context->buffer_pos = 0; | |
464 } | |
465 | |
390 void render_fps(uint32_t fps) | 466 void render_fps(uint32_t fps) |
391 { | 467 { |
392 frame_delay = 1000/fps; | 468 frame_delay = 1000/fps; |
393 } | 469 } |
394 | 470 |
395 | 471 uint32_t render_audio_buffer() |
472 { | |
473 return buffer_samples; | |
474 } | |
475 | |
476 uint32_t render_sample_rate() | |
477 { | |
478 return sample_rate; | |
479 } | |
480 | |
481 |