diff 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
line wrap: on
line diff
--- a/libblastem.c	Thu Apr 18 22:06:47 2019 -0700
+++ b/libblastem.c	Sat Apr 18 11:42:53 2020 -0700
@@ -6,11 +6,40 @@
 #include "vdp.h"
 #include "render.h"
 #include "io.h"
+#include "genesis.h"
+#include "sms.h"
 
 static retro_environment_t retro_environment;
 RETRO_API void retro_set_environment(retro_environment_t re)
 {
 	retro_environment = re;
+#	define input_descriptor_macro(pad_num) \
+		{ pad_num, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT,  "D-Pad Left" }, \
+		{ pad_num, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP,    "D-Pad Up" }, \
+		{ pad_num, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN,  "D-Pad Down" }, \
+		{ pad_num, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" }, \
+		{ pad_num, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B,     "A" }, \
+		{ pad_num, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A,     "B" }, \
+		{ pad_num, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X,     "Y" }, \
+		{ pad_num, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y,     "X" }, \
+		{ pad_num, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L,     "Z" }, \
+		{ pad_num, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R,     "C" }, \
+		{ pad_num, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT,    "Mode" }, \
+		{ pad_num, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START,    "Start" }, \
+
+	static const struct retro_input_descriptor desc[] = {
+		input_descriptor_macro(0)
+		input_descriptor_macro(1)
+		input_descriptor_macro(2)
+		input_descriptor_macro(3)
+		input_descriptor_macro(4)
+		input_descriptor_macro(5)
+		input_descriptor_macro(6)
+		input_descriptor_macro(7)
+		{ 0 },
+	};
+
+	re(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, (void *)desc);
 }
 
 static retro_video_refresh_t retro_video_refresh;
@@ -19,14 +48,14 @@
 	retro_video_refresh = rvf;
 }
 
-static retro_audio_sample_t retro_audio_sample;
 RETRO_API void retro_set_audio_sample(retro_audio_sample_t ras)
 {
-	retro_audio_sample = ras;
 }
 
+static retro_audio_sample_batch_t retro_audio_sample_batch;
 RETRO_API void retro_set_audio_sample_batch(retro_audio_sample_batch_t rasb)
 {
+	retro_audio_sample_batch = rasb;
 }
 
 static retro_input_poll_t retro_input_poll;
@@ -52,6 +81,7 @@
 
 RETRO_API void retro_init(void)
 {
+	render_audio_initialized(RENDER_AUDIO_S16, 53693175 / (7 * 6 * 4), 2, 4, sizeof(int16_t));
 }
 
 RETRO_API void retro_deinit(void)
@@ -77,16 +107,46 @@
 
 static vid_std video_standard;
 static uint32_t last_width, last_height;
+static uint32_t overscan_top, overscan_bot, overscan_left, overscan_right;
+static void update_overscan(void)
+{
+	uint8_t overscan;
+	retro_environment(RETRO_ENVIRONMENT_GET_OVERSCAN, &overscan);
+	if (overscan) {
+		overscan_top = overscan_bot = overscan_left = overscan_right = 0;
+	} else {
+		if (video_standard == VID_NTSC) {
+			overscan_top = 11;
+			overscan_bot = 8;
+			overscan_left = 13;
+			overscan_right = 14;
+		} else {
+			overscan_top = 30;
+			overscan_bot = 24;
+			overscan_left = 13;
+			overscan_right = 14;
+		}
+	}
+}
+
+static int32_t sample_rate;
 RETRO_API void retro_get_system_av_info(struct retro_system_av_info *info)
 {
+	update_overscan();
 	last_width = LINEBUF_SIZE;
-	info->geometry.base_width = info->geometry.max_width = LINEBUF_SIZE;
-	info->geometry.base_height = video_standard == VID_NTSC ? 243 : 294;
+	info->geometry.base_width = info->geometry.max_width = LINEBUF_SIZE - (overscan_left + overscan_right);
+	info->geometry.base_height = (video_standard == VID_NTSC ? 243 : 294) - (overscan_top + overscan_bot);
 	last_height = info->geometry.base_height;
 	info->geometry.max_height = info->geometry.base_height * 2;
 	info->geometry.aspect_ratio = 0;
-	info->timing.fps = video_standard == VID_NTSC ? 60 : 50;
-	info->timing.sample_rate = 53267; //approximate sample rate of YM2612
+	double master_clock = video_standard == VID_NTSC ? 53693175 : 53203395;
+	double lines = video_standard == VID_NTSC ? 262 : 313;
+	info->timing.fps = master_clock / (3420.0 * lines);
+	info->timing.sample_rate = master_clock / (7 * 6 * 24); //sample rate of YM2612
+	sample_rate = info->timing.sample_rate;
+	render_audio_initialized(RENDER_AUDIO_S16, info->timing.sample_rate, 2, 4, sizeof(int16_t));
+	//force adjustment of resampling parameters since target sample rate may have changed slightly
+	current_system->set_speed_percent(current_system, 100);
 }
 
 RETRO_API void retro_set_controller_port_device(unsigned port, unsigned device)
@@ -164,6 +224,7 @@
 }
 
 /* Loads a game. */
+static system_type stype;
 RETRO_API bool retro_load_game(const struct retro_game_info *game)
 {
 	serialize_size_cache = 0;
@@ -175,10 +236,12 @@
 	media.buffer = malloc(nearest_pow2(game->size));
 	memcpy(media.buffer, game->data, game->size);
 	media.size = game->size;
-	current_system = alloc_config_system(detect_system_type(&media), &media, 0, 0);
+	stype = detect_system_type(&media);
+	current_system = alloc_config_system(stype, &media, 0, 0);
 	
 	unsigned format = RETRO_PIXEL_FORMAT_XRGB8888;
 	retro_environment(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &format);
+	
 	return current_system != NULL;
 }
 
@@ -211,11 +274,57 @@
 /* Gets region of memory. */
 RETRO_API void *retro_get_memory_data(unsigned id)
 {
+	switch (id) {
+	case RETRO_MEMORY_SYSTEM_RAM:
+		switch (stype) {
+		case SYSTEM_GENESIS: {
+			genesis_context *gen = (genesis_context *)current_system;
+			return (uint8_t *)gen->work_ram;
+		}
+#ifndef NO_Z80
+		case SYSTEM_SMS: {
+			sms_context *sms = (sms_context *)current_system;
+			return sms->ram;
+		}
+#endif
+		}
+		break;
+	case RETRO_MEMORY_SAVE_RAM:
+		if (stype == SYSTEM_GENESIS) {
+			genesis_context *gen = (genesis_context *)current_system;
+			if (gen->save_type != SAVE_NONE)
+				return gen->save_storage;
+		}
+		break;
+	default:
+		break;
+	}
 	return NULL;
 }
 
 RETRO_API size_t retro_get_memory_size(unsigned id)
 {
+	switch (id) {
+	case RETRO_MEMORY_SYSTEM_RAM:
+		switch (stype) {
+		case SYSTEM_GENESIS:
+			return RAM_WORDS * sizeof(uint16_t);
+#ifndef NO_Z80
+		case SYSTEM_SMS:
+			return SMS_RAM_SIZE;
+#endif
+		}
+		break;
+	case RETRO_MEMORY_SAVE_RAM:
+		if (stype == SYSTEM_GENESIS) {
+			genesis_context *gen = (genesis_context *)current_system;
+			if (gen->save_type != SAVE_NONE)
+				return gen->save_size;
+		}
+		break;
+	default:
+		break;
+	}
 	return 0;
 }
 
@@ -254,7 +363,8 @@
 
 void render_framebuffer_updated(uint8_t which, int width)
 {
-	unsigned height = video_standard == VID_NTSC ? 243 : 294;
+	unsigned height = (video_standard == VID_NTSC ? 243 : 294) - (overscan_top + overscan_bot);
+	width -= (overscan_left + overscan_right);
 	unsigned base_height = height;
 	if (which != last_fb) {
 		height *= 2;
@@ -270,7 +380,7 @@
 		last_width = width;
 		last_height = height;
 	}
-	retro_video_refresh(fb, width, height, LINEBUF_SIZE * sizeof(uint32_t));
+	retro_video_refresh(fb + overscan_left + LINEBUF_SIZE * overscan_top, width, height, LINEBUF_SIZE * sizeof(uint32_t));
 	current_system->request_exit(current_system);
 }
 
@@ -289,6 +399,16 @@
 	return 1;
 }
 
+uint32_t render_overscan_top()
+{
+	return overscan_top;
+}
+
+uint32_t render_overscan_bot()
+{
+	return overscan_bot;
+}
+
 void process_events()
 {
 	static int16_t prev_state[2][RETRO_DEVICE_ID_JOYPAD_L2];
@@ -326,77 +446,70 @@
 {
 }
 
-struct audio_source {
-	int32_t freq;
-	int32_t left_accum;
-	int32_t right_accum;
-	int32_t num_samples;
-};
+uint8_t render_is_audio_sync(void)
+{
+	//whether this is true depends on the libretro frontend implementation
+	//but the sync to audio path works better here
+	return 1;
+}
 
-static audio_source *audio_sources[8];
-static uint8_t num_audio_sources;
-audio_source *render_audio_source(uint64_t master_clock, uint64_t sample_divider, uint8_t channels)
+void render_buffer_consumed(audio_source *src)
 {
-	audio_sources[num_audio_sources] = calloc(1, sizeof(audio_source));
-	audio_sources[num_audio_sources]->freq = master_clock / sample_divider;
-	return audio_sources[num_audio_sources++];
 }
 
-void render_audio_adjust_clock(audio_source *src, uint64_t master_clock, uint64_t sample_divider)
+void *render_new_audio_opaque(void)
+{
+	return NULL;
+}
+
+void render_free_audio_opaque(void *opaque)
+{
+}
+
+void render_lock_audio(void)
+{
+}
+
+void render_unlock_audio()
 {
 }
 
-void render_audio_source_gaindb(audio_source *src, float gain)
+uint32_t render_min_buffered(void)
 {
-	//TODO: Implement this once I hook up a core option for individual FM/PSG gain
+	//not actually used in the sync to audio path
+	return 4;
 }
 
-static void check_put_sample(void)
+uint32_t render_audio_syncs_per_sec(void)
 {
-	for (int i = 0; i < num_audio_sources; i++)
-	{
-		int32_t min_samples = audio_sources[i]->freq / 53267;
-		if (audio_sources[i]->num_samples < min_samples) {
-			return;
-		}
-	}
-	int16_t left = 0, right = 0;
-	for (int i = 0; i < num_audio_sources; i++)
-	{
-		left += audio_sources[i]->left_accum / audio_sources[i]->num_samples;
-		right += audio_sources[i]->right_accum / audio_sources[i]->num_samples;
-		audio_sources[i]->left_accum = audio_sources[i]->right_accum = audio_sources[i]->num_samples = 0;
-	}
-	retro_audio_sample(left, right);
+	return 0;
+}
+
+void render_audio_created(audio_source *src)
+{
 }
 
-void render_put_mono_sample(audio_source *src, int16_t value)
+void render_do_audio_ready(audio_source *src)
 {
-	src->left_accum += value;
-	src->right_accum += value;
-	src->num_samples++;
-	check_put_sample();
-}
-void render_put_stereo_sample(audio_source *src, int16_t left, int16_t right)
-{
-	src->left_accum += left;
-	src->right_accum += right;
-	src->num_samples++;
-	check_put_sample();
+	int16_t *tmp = src->front;
+	src->front = src->back;
+	src->back = tmp;
+	src->front_populated = 1;
+	src->buffer_pos = 0;
+	if (all_sources_ready()) {
+		int16_t buffer[8];
+		int min_remaining_out;
+		mix_and_convert((uint8_t *)buffer, sizeof(buffer), &min_remaining_out);
+		retro_audio_sample_batch(buffer, sizeof(buffer)/(2*sizeof(*buffer)));
+	}
 }
 
-void render_free_source(audio_source *src)
+void render_source_paused(audio_source *src, uint8_t remaining_sources)
 {
-	int index;
-	for (index = 0; index < num_audio_sources; index++)
-	{
-		if (audio_sources[index] == src) {
-			break;
-		}
-	}
-	num_audio_sources--;
-	audio_sources[index] = audio_sources[num_audio_sources];
-	free(src);
+}
+
+void render_source_resumed(audio_source *src)
+{
 }
 
 void bindings_set_mouse_mode(uint8_t mode)