/** * 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; }
/** * 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; } }
/** * 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; }
/** * 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; }