Mercurial > repos > blastem
comparison libblastem.c @ 1931:374a5ae694e8 mame_interp
Merge from default
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sat, 18 Apr 2020 11:42:53 -0700 |
parents | 9fd4bedc1a31 |
children | b387f1c5a1d0 |
comparison
equal
deleted
inserted
replaced
1843:13abdc98379e | 1931:374a5ae694e8 |
---|---|
4 #include "system.h" | 4 #include "system.h" |
5 #include "util.h" | 5 #include "util.h" |
6 #include "vdp.h" | 6 #include "vdp.h" |
7 #include "render.h" | 7 #include "render.h" |
8 #include "io.h" | 8 #include "io.h" |
9 #include "genesis.h" | |
10 #include "sms.h" | |
9 | 11 |
10 static retro_environment_t retro_environment; | 12 static retro_environment_t retro_environment; |
11 RETRO_API void retro_set_environment(retro_environment_t re) | 13 RETRO_API void retro_set_environment(retro_environment_t re) |
12 { | 14 { |
13 retro_environment = re; | 15 retro_environment = re; |
16 # define input_descriptor_macro(pad_num) \ | |
17 { pad_num, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" }, \ | |
18 { pad_num, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" }, \ | |
19 { pad_num, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" }, \ | |
20 { pad_num, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" }, \ | |
21 { pad_num, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "A" }, \ | |
22 { pad_num, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "B" }, \ | |
23 { pad_num, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "Y" }, \ | |
24 { pad_num, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "X" }, \ | |
25 { pad_num, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "Z" }, \ | |
26 { pad_num, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "C" }, \ | |
27 { pad_num, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Mode" }, \ | |
28 { pad_num, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" }, \ | |
29 | |
30 static const struct retro_input_descriptor desc[] = { | |
31 input_descriptor_macro(0) | |
32 input_descriptor_macro(1) | |
33 input_descriptor_macro(2) | |
34 input_descriptor_macro(3) | |
35 input_descriptor_macro(4) | |
36 input_descriptor_macro(5) | |
37 input_descriptor_macro(6) | |
38 input_descriptor_macro(7) | |
39 { 0 }, | |
40 }; | |
41 | |
42 re(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, (void *)desc); | |
14 } | 43 } |
15 | 44 |
16 static retro_video_refresh_t retro_video_refresh; | 45 static retro_video_refresh_t retro_video_refresh; |
17 RETRO_API void retro_set_video_refresh(retro_video_refresh_t rvf) | 46 RETRO_API void retro_set_video_refresh(retro_video_refresh_t rvf) |
18 { | 47 { |
19 retro_video_refresh = rvf; | 48 retro_video_refresh = rvf; |
20 } | 49 } |
21 | 50 |
22 static retro_audio_sample_t retro_audio_sample; | |
23 RETRO_API void retro_set_audio_sample(retro_audio_sample_t ras) | 51 RETRO_API void retro_set_audio_sample(retro_audio_sample_t ras) |
24 { | 52 { |
25 retro_audio_sample = ras; | 53 } |
26 } | 54 |
27 | 55 static retro_audio_sample_batch_t retro_audio_sample_batch; |
28 RETRO_API void retro_set_audio_sample_batch(retro_audio_sample_batch_t rasb) | 56 RETRO_API void retro_set_audio_sample_batch(retro_audio_sample_batch_t rasb) |
29 { | 57 { |
58 retro_audio_sample_batch = rasb; | |
30 } | 59 } |
31 | 60 |
32 static retro_input_poll_t retro_input_poll; | 61 static retro_input_poll_t retro_input_poll; |
33 RETRO_API void retro_set_input_poll(retro_input_poll_t rip) | 62 RETRO_API void retro_set_input_poll(retro_input_poll_t rip) |
34 { | 63 { |
50 system_header *current_system; | 79 system_header *current_system; |
51 system_media media; | 80 system_media media; |
52 | 81 |
53 RETRO_API void retro_init(void) | 82 RETRO_API void retro_init(void) |
54 { | 83 { |
84 render_audio_initialized(RENDER_AUDIO_S16, 53693175 / (7 * 6 * 4), 2, 4, sizeof(int16_t)); | |
55 } | 85 } |
56 | 86 |
57 RETRO_API void retro_deinit(void) | 87 RETRO_API void retro_deinit(void) |
58 { | 88 { |
59 if (current_system) { | 89 if (current_system) { |
75 info->block_extract = 0; | 105 info->block_extract = 0; |
76 } | 106 } |
77 | 107 |
78 static vid_std video_standard; | 108 static vid_std video_standard; |
79 static uint32_t last_width, last_height; | 109 static uint32_t last_width, last_height; |
110 static uint32_t overscan_top, overscan_bot, overscan_left, overscan_right; | |
111 static void update_overscan(void) | |
112 { | |
113 uint8_t overscan; | |
114 retro_environment(RETRO_ENVIRONMENT_GET_OVERSCAN, &overscan); | |
115 if (overscan) { | |
116 overscan_top = overscan_bot = overscan_left = overscan_right = 0; | |
117 } else { | |
118 if (video_standard == VID_NTSC) { | |
119 overscan_top = 11; | |
120 overscan_bot = 8; | |
121 overscan_left = 13; | |
122 overscan_right = 14; | |
123 } else { | |
124 overscan_top = 30; | |
125 overscan_bot = 24; | |
126 overscan_left = 13; | |
127 overscan_right = 14; | |
128 } | |
129 } | |
130 } | |
131 | |
132 static int32_t sample_rate; | |
80 RETRO_API void retro_get_system_av_info(struct retro_system_av_info *info) | 133 RETRO_API void retro_get_system_av_info(struct retro_system_av_info *info) |
81 { | 134 { |
135 update_overscan(); | |
82 last_width = LINEBUF_SIZE; | 136 last_width = LINEBUF_SIZE; |
83 info->geometry.base_width = info->geometry.max_width = LINEBUF_SIZE; | 137 info->geometry.base_width = info->geometry.max_width = LINEBUF_SIZE - (overscan_left + overscan_right); |
84 info->geometry.base_height = video_standard == VID_NTSC ? 243 : 294; | 138 info->geometry.base_height = (video_standard == VID_NTSC ? 243 : 294) - (overscan_top + overscan_bot); |
85 last_height = info->geometry.base_height; | 139 last_height = info->geometry.base_height; |
86 info->geometry.max_height = info->geometry.base_height * 2; | 140 info->geometry.max_height = info->geometry.base_height * 2; |
87 info->geometry.aspect_ratio = 0; | 141 info->geometry.aspect_ratio = 0; |
88 info->timing.fps = video_standard == VID_NTSC ? 60 : 50; | 142 double master_clock = video_standard == VID_NTSC ? 53693175 : 53203395; |
89 info->timing.sample_rate = 53267; //approximate sample rate of YM2612 | 143 double lines = video_standard == VID_NTSC ? 262 : 313; |
144 info->timing.fps = master_clock / (3420.0 * lines); | |
145 info->timing.sample_rate = master_clock / (7 * 6 * 24); //sample rate of YM2612 | |
146 sample_rate = info->timing.sample_rate; | |
147 render_audio_initialized(RENDER_AUDIO_S16, info->timing.sample_rate, 2, 4, sizeof(int16_t)); | |
148 //force adjustment of resampling parameters since target sample rate may have changed slightly | |
149 current_system->set_speed_percent(current_system, 100); | |
90 } | 150 } |
91 | 151 |
92 RETRO_API void retro_set_controller_port_device(unsigned port, unsigned device) | 152 RETRO_API void retro_set_controller_port_device(unsigned port, unsigned device) |
93 { | 153 { |
94 } | 154 } |
162 RETRO_API void retro_cheat_set(unsigned index, bool enabled, const char *code) | 222 RETRO_API void retro_cheat_set(unsigned index, bool enabled, const char *code) |
163 { | 223 { |
164 } | 224 } |
165 | 225 |
166 /* Loads a game. */ | 226 /* Loads a game. */ |
227 static system_type stype; | |
167 RETRO_API bool retro_load_game(const struct retro_game_info *game) | 228 RETRO_API bool retro_load_game(const struct retro_game_info *game) |
168 { | 229 { |
169 serialize_size_cache = 0; | 230 serialize_size_cache = 0; |
170 if (game->path) { | 231 if (game->path) { |
171 media.dir = path_dirname(game->path); | 232 media.dir = path_dirname(game->path); |
173 media.extension = path_extension(game->path); | 234 media.extension = path_extension(game->path); |
174 } | 235 } |
175 media.buffer = malloc(nearest_pow2(game->size)); | 236 media.buffer = malloc(nearest_pow2(game->size)); |
176 memcpy(media.buffer, game->data, game->size); | 237 memcpy(media.buffer, game->data, game->size); |
177 media.size = game->size; | 238 media.size = game->size; |
178 current_system = alloc_config_system(detect_system_type(&media), &media, 0, 0); | 239 stype = detect_system_type(&media); |
240 current_system = alloc_config_system(stype, &media, 0, 0); | |
179 | 241 |
180 unsigned format = RETRO_PIXEL_FORMAT_XRGB8888; | 242 unsigned format = RETRO_PIXEL_FORMAT_XRGB8888; |
181 retro_environment(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &format); | 243 retro_environment(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &format); |
244 | |
182 return current_system != NULL; | 245 return current_system != NULL; |
183 } | 246 } |
184 | 247 |
185 /* Loads a "special" kind of game. Should not be used, | 248 /* Loads a "special" kind of game. Should not be used, |
186 * except in extreme cases. */ | 249 * except in extreme cases. */ |
209 } | 272 } |
210 | 273 |
211 /* Gets region of memory. */ | 274 /* Gets region of memory. */ |
212 RETRO_API void *retro_get_memory_data(unsigned id) | 275 RETRO_API void *retro_get_memory_data(unsigned id) |
213 { | 276 { |
277 switch (id) { | |
278 case RETRO_MEMORY_SYSTEM_RAM: | |
279 switch (stype) { | |
280 case SYSTEM_GENESIS: { | |
281 genesis_context *gen = (genesis_context *)current_system; | |
282 return (uint8_t *)gen->work_ram; | |
283 } | |
284 #ifndef NO_Z80 | |
285 case SYSTEM_SMS: { | |
286 sms_context *sms = (sms_context *)current_system; | |
287 return sms->ram; | |
288 } | |
289 #endif | |
290 } | |
291 break; | |
292 case RETRO_MEMORY_SAVE_RAM: | |
293 if (stype == SYSTEM_GENESIS) { | |
294 genesis_context *gen = (genesis_context *)current_system; | |
295 if (gen->save_type != SAVE_NONE) | |
296 return gen->save_storage; | |
297 } | |
298 break; | |
299 default: | |
300 break; | |
301 } | |
214 return NULL; | 302 return NULL; |
215 } | 303 } |
216 | 304 |
217 RETRO_API size_t retro_get_memory_size(unsigned id) | 305 RETRO_API size_t retro_get_memory_size(unsigned id) |
218 { | 306 { |
307 switch (id) { | |
308 case RETRO_MEMORY_SYSTEM_RAM: | |
309 switch (stype) { | |
310 case SYSTEM_GENESIS: | |
311 return RAM_WORDS * sizeof(uint16_t); | |
312 #ifndef NO_Z80 | |
313 case SYSTEM_SMS: | |
314 return SMS_RAM_SIZE; | |
315 #endif | |
316 } | |
317 break; | |
318 case RETRO_MEMORY_SAVE_RAM: | |
319 if (stype == SYSTEM_GENESIS) { | |
320 genesis_context *gen = (genesis_context *)current_system; | |
321 if (gen->save_type != SAVE_NONE) | |
322 return gen->save_size; | |
323 } | |
324 break; | |
325 default: | |
326 break; | |
327 } | |
219 return 0; | 328 return 0; |
220 } | 329 } |
221 | 330 |
222 //blastem render backend API implementation | 331 //blastem render backend API implementation |
223 uint32_t render_map_color(uint8_t r, uint8_t g, uint8_t b) | 332 uint32_t render_map_color(uint8_t r, uint8_t g, uint8_t b) |
252 } | 361 } |
253 } | 362 } |
254 | 363 |
255 void render_framebuffer_updated(uint8_t which, int width) | 364 void render_framebuffer_updated(uint8_t which, int width) |
256 { | 365 { |
257 unsigned height = video_standard == VID_NTSC ? 243 : 294; | 366 unsigned height = (video_standard == VID_NTSC ? 243 : 294) - (overscan_top + overscan_bot); |
367 width -= (overscan_left + overscan_right); | |
258 unsigned base_height = height; | 368 unsigned base_height = height; |
259 if (which != last_fb) { | 369 if (which != last_fb) { |
260 height *= 2; | 370 height *= 2; |
261 last_fb = which; | 371 last_fb = which; |
262 } | 372 } |
268 }; | 378 }; |
269 retro_environment(RETRO_ENVIRONMENT_SET_GEOMETRY, &geometry); | 379 retro_environment(RETRO_ENVIRONMENT_SET_GEOMETRY, &geometry); |
270 last_width = width; | 380 last_width = width; |
271 last_height = height; | 381 last_height = height; |
272 } | 382 } |
273 retro_video_refresh(fb, width, height, LINEBUF_SIZE * sizeof(uint32_t)); | 383 retro_video_refresh(fb + overscan_left + LINEBUF_SIZE * overscan_top, width, height, LINEBUF_SIZE * sizeof(uint32_t)); |
274 current_system->request_exit(current_system); | 384 current_system->request_exit(current_system); |
275 } | 385 } |
276 | 386 |
277 uint8_t render_get_active_framebuffer(void) | 387 uint8_t render_get_active_framebuffer(void) |
278 { | 388 { |
285 } | 395 } |
286 | 396 |
287 int render_fullscreen(void) | 397 int render_fullscreen(void) |
288 { | 398 { |
289 return 1; | 399 return 1; |
400 } | |
401 | |
402 uint32_t render_overscan_top() | |
403 { | |
404 return overscan_top; | |
405 } | |
406 | |
407 uint32_t render_overscan_bot() | |
408 { | |
409 return overscan_bot; | |
290 } | 410 } |
291 | 411 |
292 void process_events() | 412 void process_events() |
293 { | 413 { |
294 static int16_t prev_state[2][RETRO_DEVICE_ID_JOYPAD_L2]; | 414 static int16_t prev_state[2][RETRO_DEVICE_ID_JOYPAD_L2]; |
324 } | 444 } |
325 void render_infobox(char *title, char *message) | 445 void render_infobox(char *title, char *message) |
326 { | 446 { |
327 } | 447 } |
328 | 448 |
329 struct audio_source { | 449 uint8_t render_is_audio_sync(void) |
330 int32_t freq; | 450 { |
331 int32_t left_accum; | 451 //whether this is true depends on the libretro frontend implementation |
332 int32_t right_accum; | 452 //but the sync to audio path works better here |
333 int32_t num_samples; | 453 return 1; |
334 }; | 454 } |
335 | 455 |
336 static audio_source *audio_sources[8]; | 456 void render_buffer_consumed(audio_source *src) |
337 static uint8_t num_audio_sources; | 457 { |
338 audio_source *render_audio_source(uint64_t master_clock, uint64_t sample_divider, uint8_t channels) | 458 } |
339 { | 459 |
340 audio_sources[num_audio_sources] = calloc(1, sizeof(audio_source)); | 460 void *render_new_audio_opaque(void) |
341 audio_sources[num_audio_sources]->freq = master_clock / sample_divider; | 461 { |
342 return audio_sources[num_audio_sources++]; | 462 return NULL; |
343 } | 463 } |
344 | 464 |
345 void render_audio_adjust_clock(audio_source *src, uint64_t master_clock, uint64_t sample_divider) | 465 void render_free_audio_opaque(void *opaque) |
346 { | 466 { |
347 } | 467 } |
348 | 468 |
349 void render_audio_source_gaindb(audio_source *src, float gain) | 469 void render_lock_audio(void) |
350 { | 470 { |
351 //TODO: Implement this once I hook up a core option for individual FM/PSG gain | 471 } |
352 } | 472 |
353 | 473 void render_unlock_audio() |
354 static void check_put_sample(void) | 474 { |
355 { | 475 } |
356 for (int i = 0; i < num_audio_sources; i++) | 476 |
357 { | 477 uint32_t render_min_buffered(void) |
358 int32_t min_samples = audio_sources[i]->freq / 53267; | 478 { |
359 if (audio_sources[i]->num_samples < min_samples) { | 479 //not actually used in the sync to audio path |
360 return; | 480 return 4; |
361 } | 481 } |
362 } | 482 |
363 int16_t left = 0, right = 0; | 483 uint32_t render_audio_syncs_per_sec(void) |
364 for (int i = 0; i < num_audio_sources; i++) | 484 { |
365 { | 485 return 0; |
366 left += audio_sources[i]->left_accum / audio_sources[i]->num_samples; | 486 } |
367 right += audio_sources[i]->right_accum / audio_sources[i]->num_samples; | 487 |
368 audio_sources[i]->left_accum = audio_sources[i]->right_accum = audio_sources[i]->num_samples = 0; | 488 void render_audio_created(audio_source *src) |
369 } | 489 { |
370 retro_audio_sample(left, right); | 490 } |
371 } | 491 |
372 | 492 void render_do_audio_ready(audio_source *src) |
373 void render_put_mono_sample(audio_source *src, int16_t value) | 493 { |
374 { | 494 int16_t *tmp = src->front; |
375 src->left_accum += value; | 495 src->front = src->back; |
376 src->right_accum += value; | 496 src->back = tmp; |
377 src->num_samples++; | 497 src->front_populated = 1; |
378 check_put_sample(); | 498 src->buffer_pos = 0; |
379 } | 499 if (all_sources_ready()) { |
380 void render_put_stereo_sample(audio_source *src, int16_t left, int16_t right) | 500 int16_t buffer[8]; |
381 { | 501 int min_remaining_out; |
382 src->left_accum += left; | 502 mix_and_convert((uint8_t *)buffer, sizeof(buffer), &min_remaining_out); |
383 src->right_accum += right; | 503 retro_audio_sample_batch(buffer, sizeof(buffer)/(2*sizeof(*buffer))); |
384 src->num_samples++; | 504 } |
385 check_put_sample(); | 505 } |
386 } | 506 |
387 | 507 void render_source_paused(audio_source *src, uint8_t remaining_sources) |
388 void render_free_source(audio_source *src) | 508 { |
389 { | 509 } |
390 int index; | 510 |
391 for (index = 0; index < num_audio_sources; index++) | 511 void render_source_resumed(audio_source *src) |
392 { | 512 { |
393 if (audio_sources[index] == src) { | |
394 break; | |
395 } | |
396 } | |
397 num_audio_sources--; | |
398 audio_sources[index] = audio_sources[num_audio_sources]; | |
399 free(src); | |
400 } | 513 } |
401 | 514 |
402 void bindings_set_mouse_mode(uint8_t mode) | 515 void bindings_set_mouse_mode(uint8_t mode) |
403 { | 516 { |
404 } | 517 } |