Example #1
0
/**
 * wav_dump_stop(): Stop dumping a WAV file.
 * @return 0 on success; non-zero on error.
 */
int wav_dump_stop(void)
{
	if (!WAV_Dumping || !WAV_File)
	{
		WAV_Dumping = 0;
		vdraw_text_write("Not dumping WAV sound.", 1000);
		Sync_Gens_Window_SoundMenu();
		return 1;
	}
	
	/* Get the current position in the WAV file. */
	uint32_t wav_pos = (uint32_t)ftell(WAV_File);
	
	/* Seek to the beginning of the WAV file in order to update the header. */
	fseek(WAV_File, 0, SEEK_SET);
	
	/* Set the size values in the header. */
	WAV_Header.riff.ChunkSize	= cpu_to_le32(wav_pos - 8);
	WAV_Header.data.SubchunkSize	= cpu_to_le32(wav_pos - 8 - sizeof(WAV_Header.riff) - sizeof(WAV_Header.fmt));
	
	/* Write the final header. */
	fwrite(&WAV_Header, sizeof(WAV_Header), 1, WAV_File);
	
	/* Close the file. */
	fclose(WAV_File);
	WAV_File = NULL;
	WAV_Dumping = 0;
	vdraw_text_write("WAV dump stopped.", 1000);
	Sync_Gens_Window_SoundMenu();
	return 0;
}
Example #2
0
/**
 * Detect_Country_Genesis(): Detect the country code of a Genesis game.
 * @param MD_ROM Pointer to the MD_ROM struct.
 */
void Detect_Country_Genesis(ROM_t* MD_ROM)
{
	static const int c_tab[3]  = { 4, 1, 8 };
	static const int gm_tab[3] = { 1, 0, 1 };
	static const int cm_tab[3] = { 0, 0, 1 };
	
	int i, coun = 0;
	char c;
	
	if (!MD_ROM)
		return;
	
	if (!strncasecmp(MD_ROM->Country_Codes, "eur", 3))
		coun |= 8;
	else if (!strncasecmp(MD_ROM->Country_Codes, "usa", 3))
		coun |= 4;
	else if (!strncasecmp(MD_ROM->Country_Codes, "jap", 3))
		coun |= 1;
	else
	{
		for (i = 0; i < 4; i++)
		{
			c = toupper(MD_ROM->Country_Codes[i]);
			
			if (c == 'U')
				coun |= 4;
			else if (c == 'J')
				coun |= 1;
			else if (c == 'E')
				coun |= 8;
			else if (c < 16)
				coun |= c;
			else if ((c >= '0') && (c <= '9'))
				coun |= c - '0';
			else if ((c >= 'A') && (c <= 'F'))
				coun |= c - 'A' + 10;
		}
	}
	
	// Check what country should be set.
	if (coun & c_tab[Country_Order[0]])
	{
		Game_Mode = gm_tab[Country_Order[0]];
		CPU_Mode = cm_tab[Country_Order[0]];
	}
	else if (coun & c_tab[Country_Order[1]])
	{
		Game_Mode = gm_tab[Country_Order[1]];
		CPU_Mode = cm_tab[Country_Order[1]];
	}
	else if (coun & c_tab[Country_Order[2]])
	{
		Game_Mode = gm_tab[Country_Order[2]];
		CPU_Mode = cm_tab[Country_Order[2]];
	}
	else if (coun & 2)
	{
		Game_Mode = 0;
		CPU_Mode = 1;
	}
	else
	{
		Game_Mode = 1;
		CPU_Mode = 0;
	}
	
	if (Game_Mode)
	{
		if (CPU_Mode)
			vdraw_text_write("Europe system (50 FPS)", 1500);
		else
			vdraw_text_write("USA system (60 FPS)", 1500);
	}
	else
	{
		if (CPU_Mode)
			vdraw_text_write("Japan system (50 FPS)", 1500);
		else
			vdraw_text_write("Japan system (60 FPS)", 1500);
	}
	
	if (CPU_Mode)
	{
		VDP_Status |= 0x0001;
		_32X_VDP.Mode &= ~0x8000;
	}
	else
	{
		_32X_VDP.Mode |= 0x8000;
		VDP_Status &= 0xFFFE;
	}
}
Example #3
0
/**
 * wav_dump_start(): Start dumping a WAV file.
 * @return 0 on success; non-zero on error.
 */
int wav_dump_start(void)
{
#ifdef GENS_OS_WIN32
	// Make sure relative pathnames are handled correctly on Win32.
	pSetCurrentDirectoryU(PathNames.Gens_Save_Path);
#endif
	
	/* A game must be loaded in order to dump a WAV. */
	if (!Game)
		return 0;
	
	if (WAV_Dumping)
	{
		vdraw_text_write("WAV sound is already dumping.", 1000);
		return 0;
	}
	
	/* Build the filename. */
	char filename[GENS_PATH_MAX];
	int num = -1;
	do
	{
		num++;
		szprintf(filename, sizeof(filename), "%s%s_%03d.wav", PathNames.Dump_WAV_Dir, ROM_Filename, num);
	} while (!access(filename, F_OK));
	
	/* Open the file. */
	WAV_File = fopen(filename, "wb");
	if (!WAV_File)
	{
		vdraw_text_write("Error opening WAV file.", 1000);
		return 1;
	}
	
	/* Create the WAV header. */
	memset(&WAV_Header, 0x00, sizeof(WAV_Header));
	
	/* "RIFF" header. */
	static const char ChunkID_RIFF[4] = {'R', 'I', 'F', 'F'};
	static const char FormatID_WAV[4] = {'W', 'A', 'V', 'E'};
	memcpy(WAV_Header.riff.ChunkID, ChunkID_RIFF, sizeof(WAV_Header.riff.ChunkID));
	memcpy(WAV_Header.riff.Format, FormatID_WAV, sizeof(WAV_Header.riff.Format));
	
	/* "fmt " header. */
	static const char SubchunkID_fmt[4] = {'f', 'm', 't', ' '};
	memcpy(WAV_Header.fmt.SubchunkID, SubchunkID_fmt, sizeof(WAV_Header.fmt.SubchunkID));
	WAV_Header.fmt.SubchunkSize	= cpu_to_le32(sizeof(WAV_Header.fmt) - 8);
	WAV_Header.fmt.AudioFormat	= cpu_to_le16(1); /* PCM */
	WAV_Header.fmt.NumChannels	= cpu_to_le16((audio_get_stereo() ? 2 : 1));
	WAV_Header.fmt.SampleRate	= cpu_to_le32(audio_get_sound_rate());
	WAV_Header.fmt.BitsPerSample	= cpu_to_le16(16); /* Gens is currently hard-coded to 16-bit audio. */
	
	/* Calculated fields. */
	WAV_Header.fmt.BlockAlign	= cpu_to_le16(WAV_Header.fmt.NumChannels * (WAV_Header.fmt.BitsPerSample / 8));
	WAV_Header.fmt.ByteRate		= cpu_to_le32(WAV_Header.fmt.BlockAlign * WAV_Header.fmt.SampleRate);
	
	/* "data" header. */
	static const char SubchunkID_data[4] = {'d', 'a', 't', 'a'};
	memcpy(WAV_Header.data.SubchunkID, SubchunkID_data, sizeof(WAV_Header.data.SubchunkID));
	
	/* Write the initial header to the file. */
	fwrite(&WAV_Header, sizeof(WAV_Header), 1, WAV_File);
	
	/* WAV dump started. */
	vdraw_text_write("Starting to dump WAV sound.", 1000);
	WAV_Dumping = 1;
	Sync_Gens_Window_SoundMenu();
	return 0;
}
Example #4
0
/**
 * vdraw_ddraw_init(): Initialize the DirectDraw video subsystem.
 * @return 0 on success; non-zero on error.
 */
int vdraw_ddraw_init(void)
{
	DDSURFACEDESC2 ddsd;
	
	vdraw_ddraw_end();
	
	mdp_render_t *rendMode = get_mdp_render_t();
	const int scale = rendMode->scale;
	
	// Determine the window size using the scaling factor.
	if (scale <= 0)
		return -1;
	const int w = 320 * scale;
	const int h = 240 * scale;
	
	if (vdraw_get_fullscreen())
	{
		Res_X = w;
		Res_Y = h;
	}
	
	// Return value.
	int rval;
	
	// Initialize DirectDraw.
	// TODO: Initialize DirectDraw on the monitor with most of Gens/GS onscreen.
	LPDIRECTDRAW lpDD_Init;
	rval = DirectDrawCreate(NULL, &lpDD_Init, NULL);
	if (FAILED(rval))
	{
		LOG_MSG(video, LOG_MSG_LEVEL_ERROR,
			"DirectDrawCreate() failed: 0x%08X", rval);
		return -2;
	}
	
	rval = lpDD_Init->QueryInterface(IID_IDirectDraw7, (LPVOID*)&lpDD);
	if (FAILED(rval))
	{
		if (lpDD_Init)
			lpDD_Init->Release();
		
		LOG_MSG(video, LOG_MSG_LEVEL_ERROR,
			"lpDD_Init->QueryInterface(IID_IDirectDraw4) failed: 0x%08X", rval);
		LOG_MSG(video, LOG_MSG_LEVEL_ERROR,
			"This can usually be fixed by upgrading DirectX.");
		return -3;
	}
	
	// Free the DirectDraw initialization object.
	lpDD_Init->Release();
	
	// Set the cooperative level.
	vdraw_ddraw_set_cooperative_level();
	
	// TODO: 15-bit color override. ("Force 555" or "Force 565" in the config file.)
	memset(&ddsd, 0, sizeof(ddsd));
	ddsd.dwSize = sizeof(ddsd);
	
	// TODO: Figure out what FS_No_Res_Change is for.
	// TODO: Figure out if this is correct.
	if (vdraw_get_fullscreen() /* && !FS_No_Res_Change*/)
	{
		// Use the color depth setting.
		// NOTE: "15-bit" color requires 16-bit to be specified.
		rval = lpDD->SetDisplayMode(Res_X, Res_Y, (bppOut == 15 ? 16 : bppOut), 0, 0);
		if (FAILED(rval))
		{
			vdraw_ddraw_free_all(false);
			LOG_MSG(video, LOG_MSG_LEVEL_ERROR,
				"lpDD->SetDisplayMode() failed: 0x%08X", rval);
			
			// If render mode is set to Normal, try using Double instead.
			if (rendMode_FS == RenderMgr::begin() && rendMode_FS != RenderMgr::end())
			{
				LOG_MSG(video, LOG_MSG_LEVEL_ERROR,
					"Renderer is set to Normal; attempting to use Double instead.");
				rendMode_FS++;
				vdraw_set_renderer(rendMode_FS);
				vdraw_text_write("Normal rendering failed. Using Double.", 1500);
				Sync_Gens_Window_GraphicsMenu();
			}
			
			return -4;
		}
	}
	
#if 0
	// Check the current color depth.
	unsigned char newBpp;
	lpDD->GetDisplayMode(&ddsd);
	switch (ddsd.ddpfPixelFormat.dwGBitMask)
	{
		case 0x03E0:
			// 15-bit color.
			newBpp = 15;
			break;
		case 0x07E0:
			// 16-bit color.
			newBpp = 16;
			break;
		case 0x00FF00:
		default:
			// 32-bit color.
			newBpp = 32;
			break;
	}
	
	if (newBpp != bppOut)
		vdraw_set_bpp(newBpp, false);
#endif
	
	// Clear ddsd.
	memset(&ddsd, 0x00, sizeof(ddsd));
	ddsd.dwSize = sizeof(ddsd);
	
	if (vdraw_get_fullscreen() && Video.VSync_FS)
	{
		ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
		ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX;
		ddsd.dwBackBufferCount = 2;
	}
	else
	{
		ddsd.dwFlags = DDSD_CAPS;
		ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
	}
	
	// Create the primary surface.
	rval = lpDD->CreateSurface(&ddsd, &lpDDS_Primary, NULL);
	if (FAILED(rval))
	{
		vdraw_ddraw_free_all(false);
		LOG_MSG(video, LOG_MSG_LEVEL_ERROR,
			"lpDD->CreateSurface(&lpDDS_Primary) failed: 0x%08X", rval);
		return -5;
	}
	
	if (vdraw_get_fullscreen())
	{
		if (Video.VSync_FS)
		{
			ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER;
			
			rval = lpDDS_Primary->GetAttachedSurface(&ddsd.ddsCaps, &lpDDS_Flip);
			if (FAILED(rval))
			{
				vdraw_ddraw_free_all(false);
				LOG_MSG(video, LOG_MSG_LEVEL_ERROR,
					"lpDDS_Primary->GetAttachSurface() failed: 0x%08X", rval);
				return -6;
			}
			
			lpDDS_Blit = lpDDS_Flip;
		}
		else
		{
			lpDDS_Blit = lpDDS_Primary;
		}
	}
	else
	{
		rval = lpDD->CreateClipper(0, &lpDDC_Clipper, NULL);
		if (FAILED(rval))
		{
			vdraw_ddraw_free_all(false);
			LOG_MSG(video, LOG_MSG_LEVEL_ERROR,
				"lpDD->CreateClipper() failed: 0x%08X", rval);
			return -7;
		}
		
		rval = lpDDC_Clipper->SetHWnd(0, gens_window);
		if (FAILED(rval))
		{
			vdraw_ddraw_free_all(false);
			LOG_MSG(video, LOG_MSG_LEVEL_ERROR,
				"lpDDC_Clipper->SetHWnd() failed: 0x%08X", rval);
			return -8;
		}
		
		rval = lpDDS_Primary->SetClipper(lpDDC_Clipper);
		if (FAILED(rval))
		{
			vdraw_ddraw_free_all(false);
			LOG_MSG(video, LOG_MSG_LEVEL_ERROR,
				"lpDDC_Primary->SetClipper() failed: 0x%08X", rval);
			return -9;
		}
	}
	
	// Clear ddsd again.
	memset(&ddsd, 0, sizeof(ddsd));
	ddsd.dwSize = sizeof(ddsd);
	ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
	
	// Determine the width and height.
	// NOTE: For DirectDraw, the actual 336 width is used.
	if (vdraw_ddraw_is_hw_render())
	{
		// Normal render mode. 320x240 [336x240]
		ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
		ddsd.dwWidth = 336;
		ddsd.dwHeight = 240;
	}
	else
	{
		// Larger than 1x.
		ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY;
		ddsd.dwWidth = w;
		ddsd.dwHeight = h;
	}
	
	// Set the pixel format.
	ddsd.dwFlags |= DDSD_PIXELFORMAT;
	ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
	ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB;
	ddsd.ddpfPixelFormat.dwFourCC = 0; // RGB
	ddsd.ddpfPixelFormat.dwRGBAlphaBitMask = 0;
	
	// Bits per component.
	switch (bppOut)
	{
		case 15:
			// 15-bit color. (555)
			ddsd.ddpfPixelFormat.dwRGBBitCount = 16;
			ddsd.ddpfPixelFormat.dwRBitMask = 0x7C00;
			ddsd.ddpfPixelFormat.dwGBitMask = 0x03E0;
			ddsd.ddpfPixelFormat.dwBBitMask = 0x001F;
			break;
		
		case 16:
			// 16-bit color. (555)
			ddsd.ddpfPixelFormat.dwRGBBitCount = 16;
			ddsd.ddpfPixelFormat.dwRBitMask = 0xF800;
			ddsd.ddpfPixelFormat.dwGBitMask = 0x07E0;
			ddsd.ddpfPixelFormat.dwBBitMask = 0x001F;
			break;
		
		case 32:
		default:
			// 32-bit color.
			ddsd.ddpfPixelFormat.dwRGBBitCount = 32;
			ddsd.ddpfPixelFormat.dwRBitMask = 0xFF0000;
			ddsd.ddpfPixelFormat.dwGBitMask = 0x00FF00;
			ddsd.ddpfPixelFormat.dwBBitMask = 0x0000FF;
			break;
	}
	
	// Create the back surface.
	rval = lpDD->CreateSurface(&ddsd, &lpDDS_Back, NULL);
	if (FAILED(rval))
	{
		// Failed to create the back surface.
		// If we attempted to create it in video memory, try system memory instead.
		if (ddsd.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY)
		{
			LOG_MSG(video, LOG_MSG_LEVEL_ERROR,
				"lpDD->CreateSurface(&lpDDS_Back, DDSCAPS_VIDEOMEMORY) failed: 0x%08X", rval);
			LOG_MSG(video, LOG_MSG_LEVEL_ERROR,
				"Attempting to use DDSCAPS_SYSTEMMEMORY instead.");
			ddsd.ddsCaps.dwCaps &= ~DDSCAPS_VIDEOMEMORY;
			ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
			rval = lpDD->CreateSurface(&ddsd, &lpDDS_Back, NULL);
			if (FAILED(rval))
			{
				// Failed to create the back surface in system memory.
				vdraw_ddraw_free_all(false);
				LOG_MSG(video, LOG_MSG_LEVEL_ERROR,
					"lpDD->CreateSurface(&lpDDS_Back, DDSCAPS_SYSTEMMEMORY) failed: 0x%08X", rval);
				return -10;
			}
		}
		else
		{
			vdraw_ddraw_free_all(false);
			LOG_MSG(video, LOG_MSG_LEVEL_ERROR,
				"lpDD->CreateSurface(&lpDDS_Back, DDSCAPS_SYSTEMMEMORY) failed: 0x%08X", rval);
			return -11;
		}
	}
	
	// TODO: Check if this is right.
	// I think this might be causing the frame counter flicker in full screen mode.
	//if (!vdraw_get_fullscreen() || (rendMode >= 1 && (/*FS_No_Res_Change ||*/ Res_X != 640 || Res_Y != 480)))
	if (!vdraw_get_fullscreen() || !vdraw_ddraw_is_hw_render())
		lpDDS_Blit = lpDDS_Back;
	
	if (vdraw_ddraw_is_hw_render())
	{
		// Normal rendering mode uses MD_Screen directly.
		memset(&ddsd, 0, sizeof(ddsd));
		ddsd.dwSize = sizeof(ddsd);
		
		// TODO: This causes issues if the selected color depth isn't the
		// same as the desktop color depth. This only affects windowed mode,
		// since in fullscreen, the desktop color depth is changed.
		rval = lpDDS_Back->GetSurfaceDesc(&ddsd);
		if (FAILED(rval))
		{
			vdraw_ddraw_free_all(false);
			LOG_MSG(video, LOG_MSG_LEVEL_ERROR,
				"lpDDS_Back->GetSurfaceDesc() failed: 0x%08X", rval);
			return -12;
		}
		
		ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH | DDSD_LPSURFACE | DDSD_PIXELFORMAT;
		ddsd.dwWidth = 336;
		ddsd.dwHeight = 240;
		
		if (ddsd.ddpfPixelFormat.dwRGBBitCount > 16)
		{
			// 32-bit color.
			ddsd.lpSurface = MD_Screen.u32;
			ddsd.lPitch = 336 * 4;
		}
		else
		{
			// 15-bit or 16-bit color.
			ddsd.lpSurface = MD_Screen.u16;
			ddsd.lPitch = 336 * 2;
		}
		
		rval = lpDDS_Back->SetSurfaceDesc(&ddsd, 0);
		if (FAILED(rval))
		{
			vdraw_ddraw_free_all(false);
			LOG_MSG(video, LOG_MSG_LEVEL_ERROR,
				"lpDDS_Back->SetSurfaceDesc() failed: 0x%08X", rval);
			return -13;
		}
	}
	
	// Initialize the destination rectangle.
	vdraw_ddraw_adjust_RectDest();
	
	// Reset the render mode.
	vdraw_reset_renderer(false);
	
	// Synchronize menus.
	Sync_Gens_Window();
	
	// vdraw_ddraw initialized.
	return 0;
}