JoystickDriver_DX5::JoystickDriver_DX5(bool exclude_xinput) : dii(NULL) { enum_device_list edl; std::set<uint32> exclude_vps; try { REQUIRE_DI_CALL( DirectInputCreate(GetModuleHandle(NULL), DIRECTINPUT_VERSION, &dii, NULL) ); REQUIRE_DI_CALL( dii->EnumDevices(DIDEVTYPE_JOYSTICK, GLOB_EnumJoysticksProc, &edl, DIEDFL_ATTACHEDONLY) ); if(exclude_xinput) { exclude_vps = GetXInputVidPid(); } for(unsigned i = 0; i < edl.valid_count; i++) { Joystick_DX5 *jdx5 = NULL; if(edl.ddi[i].guidProduct.Data1 && exclude_vps.count(edl.ddi[i].guidProduct.Data1)) continue; try { jdx5 = new Joystick_DX5(dii, &edl.ddi[i]); joys.push_back(jdx5); } catch(std::exception &e) { MDFND_PrintError(e.what()); if(jdx5 != NULL) { delete jdx5; jdx5 = NULL; } } } } catch(std::exception &e) { MDFND_PrintError(e.what()); } }
WAVRecord::~WAVRecord() { try { Finish(); } catch(std::exception &e) { MDFND_PrintError(e.what()); } }
FileStream::~FileStream() { try { close(); } catch(std::exception &e) { MDFND_PrintError(e.what()); } }
bool MDFNI_StartAVRecord(const char *path, double SoundRate) { try { QTRecord::VideoSpec spec; memset(&spec, 0, sizeof(spec)); spec.SoundRate = SoundRate; spec.SoundChan = MDFNGameInfo->soundchan; spec.VideoWidth = MDFNGameInfo->lcm_width; spec.VideoHeight = MDFNGameInfo->lcm_height; spec.VideoCodec = MDFN_GetSettingI("qtrecord.vcodec"); spec.MasterClock = MDFNGameInfo->MasterClock; if(spec.VideoWidth < MDFN_GetSettingUI("qtrecord.w_double_threshold")) spec.VideoWidth *= 2; if(spec.VideoHeight < MDFN_GetSettingUI("qtrecord.h_double_threshold")) spec.VideoHeight *= 2; spec.AspectXAdjust = ((double)MDFNGameInfo->nominal_width * 2) / spec.VideoWidth; spec.AspectYAdjust = ((double)MDFNGameInfo->nominal_height * 2) / spec.VideoHeight; MDFN_printf("\n"); MDFN_printf(_("Starting QuickTime recording to file \"%s\":\n"), path); MDFN_indent(1); MDFN_printf(_("Video width: %u\n"), spec.VideoWidth); MDFN_printf(_("Video height: %u\n"), spec.VideoHeight); MDFN_printf(_("Video codec: %s\n"), MDFN_GetSettingS("qtrecord.vcodec").c_str()); if(spec.SoundRate && spec.SoundChan) { MDFN_printf(_("Sound rate: %u\n"), std::min<uint32>(spec.SoundRate, 64000)); MDFN_printf(_("Sound channels: %u\n"), spec.SoundChan); } else MDFN_printf(_("Sound: Disabled\n")); MDFN_indent(-1); MDFN_printf("\n"); qtrecorder = new QTRecord(path, spec); } catch(std::exception &e) { MDFND_PrintError(e.what()); return(false); } return(true); }
bool MDFNI_StartWAVRecord(const char *path, double SoundRate) { try { wavrecorder = new WAVRecord(path, SoundRate, MDFNGameInfo->soundchan); } catch(std::exception &e) { MDFND_PrintError(e.what()); return(false); } return(true); }
void MDFN_PrintError(const char *format, ...) { char *temp; va_list ap; va_start(ap, format); temp = trio_vaprintf(format, ap); MDFND_PrintError(temp); free(temp); va_end(ap); }
void MDFN_PrintError(const char *format, ...) { char *temp; va_list ap; va_start(ap, format); temp = new char[4096]; vsnprintf(temp, 4096, format, ap); MDFND_PrintError(temp); free(temp); va_end(ap); }
static bool RunSexyALTest(SexyAL *interface, SexyAL_buffering *buffering, const char *device, int driver_type) { static const int to_format[9] = { SEXYAL_FMT_PCMU8, SEXYAL_FMT_PCMS8, SEXYAL_FMT_PCMU16, SEXYAL_FMT_PCMS16, SEXYAL_FMT_PCMU24, SEXYAL_FMT_PCMS24, SEXYAL_FMT_PCMU32, SEXYAL_FMT_PCMS32, SEXYAL_FMT_PCMFLOAT }; static const char *to_format_name[9] = { "8-bit unsigned", "8-bit signed", "16-bit unsigned", "16-bit signed", "24-bit unsigned", "24-bit signed", "32-bit unsigned", "32-bit signed", "float" }; // TODO: byte order format conversion. // TODO: source format. const int rate = 48000; const int numframes = (rate / 2 + 1) &~ 1; for(int src_channels = 1; src_channels <= 2; src_channels++) { for(int dest_channels = 1; dest_channels <= 2; dest_channels++) { //for(int src_format = 0; src_format < 9; src_format++) int src_format = 3; { for(int dest_format = 0; dest_format < 9; dest_format++) { printf("Source Format: %s, Source Channels: %d --- Dest Format: %s, Dest Channels: %d\n\n", to_format_name[src_format], src_channels, to_format_name[dest_format], dest_channels); memset(&format,0,sizeof(format)); Interface = (SexyAL *)SexyAL_Init(0); DriverTypes = Interface->EnumerateTypes(Interface); format.sampformat = to_format[dest_format]; format.channels = dest_channels; format.revbyteorder = 0; format.rate = rate; buffering->buffer_size = 0; buffering->period_size = 0; buffering->latency = 0; buffering->bt_gran = 0; if(!(Output=Interface->Open(Interface, device, &format, buffering, driver_type))) { MDFND_PrintError(_("Error opening a sound device.")); Interface->Destroy(Interface); Interface=0; return(0); } if(format.sampformat != to_format[dest_format]) printf("Warning: Could not set desired device format.\n"); if(format.channels != dest_channels) printf("Warning: Could not set desired device channel count.\n"); if(format.rate != rate) printf("Warning: Could not set desired device rate.\n"); format.sampformat = to_format[src_format]; format.channels = src_channels; format.revbyteorder = 0; format.rate = rate; Output->SetConvert(Output, &format); if(to_format[src_format] == SEXYAL_FMT_PCMS16) { int16 samples[numframes * src_channels]; for(int i = 0; i < numframes; i++) { int16 sval = 4095 * sin((double)i * 440 * M_PI * 2 / rate); for(int ch = 0; ch < src_channels; ch++) samples[i * src_channels + ch] = sval; } // Write half in one go, the rest in small chunks. if(!Output->Write(Output, samples, numframes / 2)) printf("Write count error 0\n"); for(int i = numframes / 2; i < numframes; i += 100) { int32 towrite = numframes - i; if(towrite > 100) towrite = 100; if(!Output->Write(Output, samples + i * src_channels, towrite)) printf("Write count error 1\n"); } } Output->Close(Output); Interface->Destroy(Interface); sleep(1); } } } } }
bool Sound_Init(MDFNGI *gi) { SexyAL_DriverInfo CurDriver; NeedReInit = false; SoundRate = 0; memset(&format, 0, sizeof(format)); memset(&buffering, 0, sizeof(buffering)); Interface = new SexyAL(); format.sampformat = SEXYAL_FMT_PCMS16; assert(gi->soundchan); format.channels = gi->soundchan; format.revbyteorder = 0; format.noninterleaved = false; format.rate = gi->soundrate ? gi->soundrate : MDFN_GetSettingUI("sound.rate"); buffering.ms = MDFN_GetSettingUI("sound.buffer_time"); if(!buffering.ms) { buffering.overhead_kludge = true; buffering.ms = 7 + floor(0.5 + 1.5 * 1000.0 / gi->fps * (256 * 65536)); } else buffering.overhead_kludge = false; buffering.period_us = MDFN_GetSettingUI("sound.period_time"); std::string zedevice = MDFN_GetSettingS("sound.device"); std::string zedriver = MDFN_GetSettingS("sound.driver"); MDFNI_printf(_("\nInitializing sound...\n")); MDFN_indent(1); if(!Interface->FindDriver(&CurDriver, zedriver.c_str())) { std::vector<SexyAL_DriverInfo> DriverTypes = Interface->GetDriverList(); MDFN_printf(_("\nUnknown sound driver \"%s\". Compiled-in sound drivers:\n"), zedriver.c_str()); MDFN_indent(2); for(unsigned x = 0; x < DriverTypes.size(); x++) { MDFN_printf("%s\n", DriverTypes[x].short_name); } MDFN_indent(-2); MDFN_printf("\n"); delete Interface; Interface = NULL; MDFN_indent(-1); return(FALSE); } if(!strcasecmp(zedevice.c_str(), "default")) MDFNI_printf(_("Using \"%s\" audio driver with SexyAL's default device selection."), CurDriver.name); else MDFNI_printf(_("Using \"%s\" audio driver with device \"%s\":"), CurDriver.name, zedevice.c_str()); MDFN_indent(1); //RunSexyALTest(Interface, &buffering, zedevice.c_str(), CurDriver.type); //exit(1); if(!(Output=Interface->Open(zedevice.c_str(), &format, &buffering, CurDriver.type))) { MDFND_PrintError(_("Error opening a sound device.")); delete Interface; Interface = NULL; MDFN_indent(-2); return(FALSE); } if(format.rate < 22050 || format.rate > 192000) { MDFND_PrintError(_("Set rate is out of range [22050-192000]")); Sound_Kill(); MDFN_indent(-2); return(FALSE); } MDFNI_printf(_("\nBits: %u%s\nRate: %u\nChannels: %u%s\nByte order: CPU %s\nBuffer size: %u sample frames(%f ms)\n"), (format.sampformat>>4)*8, (format.sampformat == SEXYAL_FMT_PCMFLOAT) ? _(" (floating-point)") : "",format.rate,format.channels,format.noninterleaved ? _(" (non-interleaved) ") : "", format.revbyteorder?"Reversed":"Native", buffering.buffer_size, (double)buffering.buffer_size * 1000 / format.rate); MDFNI_printf(_("Latency: %u sample frames(%f ms)\n"), buffering.latency, (double)buffering.latency * 1000 / format.rate); if(buffering.period_size) { //int64_t pt_test_result = ((int64_t)buffering.period_size * (1000 * 1000) / format.rate); int64_t bt_test_result = ((int64_t)(buffering.bt_gran ? buffering.bt_gran : buffering.period_size) * (1000 * 1000) / format.rate); MDFNI_printf(_("Period size: %u sample frames(%f ms)\n"), buffering.period_size, (double)buffering.period_size * 1000 / format.rate); if(bt_test_result > 5333) { MDFN_indent(1); if(!buffering.bt_gran) MDFN_printf(_("Warning: Period time is too large(it should be <= ~5.333ms). Video will appear very jerky.\n")); else MDFN_printf(_("Warning: Buffer update timing granularity is too large(%f; it should be <= ~5.333ms). Video will appear very jerky.\n"), (double)buffering.bt_gran * 1000 / format.rate); MDFN_indent(-1); } } format.sampformat = SEXYAL_FMT_PCMS16; format.channels = gi->soundchan?gi->soundchan:1; format.revbyteorder = 0; format.noninterleaved = false; //format.rate=gi->soundrate?gi->soundrate:soundrate; Output->SetConvert(Output, &format); EmuModBufferSize = (500 * format.rate + 999) / 1000; EmuModBuffer = (int16 *)calloc(sizeof(int16) * format.channels, EmuModBufferSize); SoundRate = format.rate; MDFN_indent(-2); return(1); }
bool MDFNI_InitializeModules(const std::vector<MDFNGI *> &ExternalSystems) { static MDFNGI *InternalSystems[] = { #ifdef WANT_NES_EMU &EmulatedNES, #endif #ifdef WANT_SNES_EMU &EmulatedSNES, #endif #ifdef WANT_GB_EMU &EmulatedGB, #endif #ifdef WANT_GBA_EMU &EmulatedGBA, #endif #ifdef WANT_PCE_EMU &EmulatedPCE, #endif #ifdef WANT_PCE_FAST_EMU &EmulatedPCE_Fast, #endif #ifdef WANT_LYNX_EMU &EmulatedLynx, #endif #ifdef WANT_MD_EMU &EmulatedMD, #endif #ifdef WANT_PCFX_EMU &EmulatedPCFX, #endif #ifdef WANT_NGP_EMU &EmulatedNGP, #endif #ifdef WANT_PSX_EMU &EmulatedPSX, #endif #ifdef WANT_VB_EMU &EmulatedVB, #endif #ifdef WANT_WSWAN_EMU &EmulatedWSwan, #endif #ifdef WANT_SMS_EMU &EmulatedSMS, &EmulatedGG, #endif &EmulatedCDPlay }; std::string i_modules_string, e_modules_string; for(unsigned int i = 0; i < sizeof(InternalSystems) / sizeof(MDFNGI *); i++) { AddSystem(InternalSystems[i]); if(i) i_modules_string += " "; i_modules_string += std::string(InternalSystems[i]->shortname); } for(unsigned int i = 0; i < ExternalSystems.size(); i++) { AddSystem(ExternalSystems[i]); if(i) i_modules_string += " "; e_modules_string += std::string(ExternalSystems[i]->shortname); } MDFNI_printf(_("Internal emulation modules: %s\n"), i_modules_string.c_str()); MDFNI_printf(_("External emulation modules: %s\n"), e_modules_string.c_str()); for(unsigned int i = 0; i < MDFNSystems.size(); i++) MDFNSystemsPrio.push_back(MDFNSystems[i]); MDFNSystemsPrio.sort(MDFNSystemsPrio_CompareFunc); #if 0 std::string a_modules; std::list<MDFNGI *>: iterator it; for(it = MDFNSystemsPrio. f #endif CDUtility::CDUtility_Init(); return(1); } int MDFNI_Initialize(const char *basedir, const std::vector<MDFNSetting> &DriverSettings) { // FIXME static static std::vector<MDFNSetting> dynamic_settings; if(!MDFN_RunMathTests()) { return(0); } memset(PortDataCache, 0, sizeof(PortDataCache)); memset(PortDataLenCache, 0, sizeof(PortDataLenCache)); memset(PortDeviceCache, 0, sizeof(PortDeviceCache)); lzo_init(); MDFNI_SetBaseDirectory(basedir); MDFN_InitFontData(); // Generate dynamic settings for(unsigned int i = 0; i < MDFNSystems.size(); i++) { MDFNSetting setting; const char *sysname; sysname = (const char *)MDFNSystems[i]->shortname; if(!MDFNSystems[i]->soundchan) printf("0 sound channels for %s????\n", sysname); if(MDFNSystems[i]->soundchan == 2) { BuildDynamicSetting(&setting, sysname, "forcemono", MDFNSF_COMMON_TEMPLATE | MDFNSF_CAT_SOUND, CSD_forcemono, MDFNST_BOOL, "0"); dynamic_settings.push_back(setting); } BuildDynamicSetting(&setting, sysname, "enable", MDFNSF_COMMON_TEMPLATE, CSD_enable, MDFNST_BOOL, "1"); dynamic_settings.push_back(setting); BuildDynamicSetting(&setting, sysname, "tblur", MDFNSF_COMMON_TEMPLATE | MDFNSF_CAT_VIDEO, CSD_tblur, MDFNST_BOOL, "0"); dynamic_settings.push_back(setting); BuildDynamicSetting(&setting, sysname, "tblur.accum", MDFNSF_COMMON_TEMPLATE | MDFNSF_CAT_VIDEO, CSD_tblur_accum, MDFNST_BOOL, "0"); dynamic_settings.push_back(setting); BuildDynamicSetting(&setting, sysname, "tblur.accum.amount", MDFNSF_COMMON_TEMPLATE | MDFNSF_CAT_VIDEO, CSD_tblur_accum_amount, MDFNST_FLOAT, "50", "0", "100"); dynamic_settings.push_back(setting); } if(DriverSettings.size()) MDFN_MergeSettings(DriverSettings); // First merge all settable settings, then load the settings from the SETTINGS FILE OF DOOOOM MDFN_MergeSettings(MednafenSettings); MDFN_MergeSettings(dynamic_settings); MDFN_MergeSettings(MDFNMP_Settings); for(unsigned int x = 0; x < MDFNSystems.size(); x++) { if(MDFNSystems[x]->Settings) MDFN_MergeSettings(MDFNSystems[x]->Settings); } MDFN_MergeSettings(RenamedSettings); if(!MFDN_LoadSettings(basedir)) return(0); #ifdef WANT_DEBUGGER MDFNDBG_Init(); #endif return(1); } void MDFNI_Kill(void) { MDFN_SaveSettings(); } static double multiplier_save, volume_save; static std::vector<int16> SoundBufPristine; static void ProcessAudio(EmulateSpecStruct *espec) { if(espec->SoundVolume != 1) volume_save = espec->SoundVolume; if(espec->soundmultiplier != 1) multiplier_save = espec->soundmultiplier; if(espec->SoundBuf && espec->SoundBufSize) { int16 *const SoundBuf = espec->SoundBuf + espec->SoundBufSizeALMS * MDFNGameInfo->soundchan; int32 SoundBufSize = espec->SoundBufSize - espec->SoundBufSizeALMS; const int32 SoundBufMaxSize = espec->SoundBufMaxSize - espec->SoundBufSizeALMS; if(qtrecorder && (volume_save != 1 || multiplier_save != 1)) { int32 orig_size = SoundBufPristine.size(); SoundBufPristine.resize(orig_size + SoundBufSize * MDFNGameInfo->soundchan); for(int i = 0; i < SoundBufSize * MDFNGameInfo->soundchan; i++) SoundBufPristine[orig_size + i] = SoundBuf[i]; } if(espec->NeedSoundReverse) { int16 *yaybuf = SoundBuf; int32 slen = SoundBufSize; if(MDFNGameInfo->soundchan == 1) { for(int x = 0; x < (slen / 2); x++) { int16 cha = yaybuf[slen - x - 1]; yaybuf[slen - x - 1] = yaybuf[x]; yaybuf[x] = cha; } } else if(MDFNGameInfo->soundchan == 2) { for(int x = 0; x < (slen * 2) / 2; x++) { int16 cha = yaybuf[slen * 2 - (x&~1) - ((x&1) ^ 1) - 1]; yaybuf[slen * 2 - (x&~1) - ((x&1) ^ 1) - 1] = yaybuf[x]; yaybuf[x] = cha; } } } try { if(wavrecorder) wavrecorder->WriteSound(SoundBuf, SoundBufSize); } catch(std::exception &e) { MDFND_PrintError(e.what()); delete wavrecorder; wavrecorder = NULL; } if(multiplier_save != LastSoundMultiplier) { ff_resampler.time_ratio(multiplier_save, 0.9965); LastSoundMultiplier = multiplier_save; } if(multiplier_save != 1) { if(FFDiscard) { if(SoundBufSize >= multiplier_save) SoundBufSize /= multiplier_save; } else { if(MDFNGameInfo->soundchan == 2) { assert(ff_resampler.max_write() >= SoundBufSize * 2); for(int i = 0; i < SoundBufSize * 2; i++) ff_resampler.buffer()[i] = SoundBuf[i]; } else { assert(ff_resampler.max_write() >= SoundBufSize * 2); for(int i = 0; i < SoundBufSize; i++) { ff_resampler.buffer()[i * 2] = SoundBuf[i]; ff_resampler.buffer()[i * 2 + 1] = 0; } } ff_resampler.write(SoundBufSize * 2); int avail = ff_resampler.avail(); int real_read = std::min((int)(SoundBufMaxSize * MDFNGameInfo->soundchan), avail); if(MDFNGameInfo->soundchan == 2) SoundBufSize = ff_resampler.read(SoundBuf, real_read ) >> 1; else SoundBufSize = ff_resampler.read_mono_hack(SoundBuf, real_read ); avail -= real_read; if(avail > 0) { printf("ff_resampler.avail() > espec->SoundBufMaxSize * MDFNGameInfo->soundchan - %d\n", avail); ff_resampler.clear(); } } } if(volume_save != 1) { if(volume_save < 1) { int volume = (int)(16384 * volume_save); for(int i = 0; i < SoundBufSize * MDFNGameInfo->soundchan; i++) SoundBuf[i] = (SoundBuf[i] * volume) >> 14; } else {
MDFNGI *MDFNI_LoadCD(const char *force_module, const char *devicename) { uint8 LayoutMD5[16]; MDFNI_CloseGame(); LastSoundMultiplier = 1; MDFN_printf(_("Loading %s...\n\n"), devicename ? devicename : _("PHYSICAL CD")); try { if(devicename && strlen(devicename) > 4 && !strcasecmp(devicename + strlen(devicename) - 4, ".m3u")) { std::vector<std::string> file_list; ReadM3U(file_list, devicename); for(unsigned i = 0; i < file_list.size(); i++) { CDInterfaces.push_back(new CDIF(file_list[i].c_str())); } GetFileBase(devicename); } else { CDInterfaces.push_back(new CDIF(devicename)); if(CDInterfaces[0]->IsPhysical()) { GetFileBase("cdrom"); } else GetFileBase(devicename); } } catch(std::exception &e) { MDFND_PrintError(e.what()); MDFN_PrintError(_("Error opening CD.")); return(0); } // // Print out a track list for all discs. // MDFN_indent(1); for(unsigned i = 0; i < CDInterfaces.size(); i++) { CDUtility::TOC toc; CDInterfaces[i]->ReadTOC(&toc); MDFN_printf(_("CD %d Layout:\n"), i + 1); MDFN_indent(1); for(int32 track = toc.first_track; track <= toc.last_track; track++) { MDFN_printf(_("Track %2d, LBA: %6d %s\n"), track, toc.tracks[track].lba, (toc.tracks[track].control & 0x4) ? "DATA" : "AUDIO"); } MDFN_printf("Leadout: %6d\n", toc.tracks[100].lba); MDFN_indent(-1); MDFN_printf("\n"); } MDFN_indent(-1); // // // Calculate layout MD5. The system emulation LoadCD() code is free to ignore this value and calculate // its own, or to use it to look up a game in its database. { md5_context layout_md5; layout_md5.starts(); for(unsigned i = 0; i < CDInterfaces.size(); i++) { CD_TOC toc; CDInterfaces[i]->ReadTOC(&toc); layout_md5.update_u32_as_lsb(toc.first_track); layout_md5.update_u32_as_lsb(toc.last_track); layout_md5.update_u32_as_lsb(toc.tracks[100].lba); for(uint32 track = toc.first_track; track <= toc.last_track; track++) { layout_md5.update_u32_as_lsb(toc.tracks[track].lba); layout_md5.update_u32_as_lsb(toc.tracks[track].control & 0x4); } } layout_md5.finish(LayoutMD5); } MDFNGameInfo = NULL; for(std::list<MDFNGI *>::iterator it = MDFNSystemsPrio.begin(); it != MDFNSystemsPrio.end(); it++) //_unsigned int x = 0; x < MDFNSystems.size(); x++) { char tmpstr[256]; trio_snprintf(tmpstr, 256, "%s.enable", (*it)->shortname); if(force_module) { if(!strcmp(force_module, (*it)->shortname)) { MDFNGameInfo = *it; break; } } else { // Is module enabled? if(!MDFN_GetSettingB(tmpstr)) continue; if(!(*it)->LoadCD || !(*it)->TestMagicCD) continue; if((*it)->TestMagicCD(&CDInterfaces)) { MDFNGameInfo = *it; break; } } } if(!MDFNGameInfo) { if(force_module) { MDFN_PrintError(_("Unrecognized system \"%s\"!"), force_module); return(0); } // This code path should never be taken, thanks to "cdplay" MDFN_PrintError(_("Could not find a system that supports this CD.")); return(0); } // This if statement will be true if force_module references a system without CDROM support. if(!MDFNGameInfo->LoadCD) { MDFN_PrintError(_("Specified system \"%s\" doesn't support CDs!"), force_module); return(0); } MDFN_printf(_("Using module: %s(%s)\n\n"), MDFNGameInfo->shortname, MDFNGameInfo->fullname); // TODO: include module name in hash memcpy(MDFNGameInfo->MD5, LayoutMD5, 16); if(!(MDFNGameInfo->LoadCD(&CDInterfaces))) { for(unsigned i = 0; i < CDInterfaces.size(); i++) delete CDInterfaces[i]; CDInterfaces.clear(); MDFNGameInfo = NULL; return(0); } MDFNI_SetLayerEnableMask(~0ULL); #ifdef WANT_DEBUGGER MDFNDBG_PostGameLoad(); #endif MDFNSS_CheckStates(); MDFNMOV_CheckMovies(); MDFN_ResetMessages(); // Save state, status messages, etc. TBlur_Init(); MDFN_StateEvilBegin(); if(MDFNGameInfo->GameType != GMT_PLAYER) { MDFN_LoadGameCheats(NULL); MDFNMP_InstallReadPatches(); } last_sound_rate = -1; memset(&last_pixel_format, 0, sizeof(MDFN_PixelFormat)); return(MDFNGameInfo); }
static void ProcessAudio(EmulateSpecStruct *espec) { if(espec->SoundVolume != 1) volume_save = espec->SoundVolume; if(espec->soundmultiplier != 1) multiplier_save = espec->soundmultiplier; if(espec->SoundBuf && espec->SoundBufSize) { int16 *const SoundBuf = espec->SoundBuf + espec->SoundBufSizeALMS * MDFNGameInfo->soundchan; int32 SoundBufSize = espec->SoundBufSize - espec->SoundBufSizeALMS; const int32 SoundBufMaxSize = espec->SoundBufMaxSize - espec->SoundBufSizeALMS; if(qtrecorder && (volume_save != 1 || multiplier_save != 1)) { int32 orig_size = SoundBufPristine.size(); SoundBufPristine.resize(orig_size + SoundBufSize * MDFNGameInfo->soundchan); for(int i = 0; i < SoundBufSize * MDFNGameInfo->soundchan; i++) SoundBufPristine[orig_size + i] = SoundBuf[i]; } #if 0 // // Sine wave sweep for test purposes. // { static double phase = 0; static double phase_inc = 0.000; static double phase_inc_inc = 0.000003; static int32 scounter = 0; int16 *sbuf = SoundBuf; int32 slen = SoundBufSize; if(MDFNGameInfo->soundchan == 2) { for(int i = 0; i < slen; i++) { int16 tmp = 127 * 256 * sin(phase); tmp = (scounter & 8) ? 127 * 256 : -127 * 256; sbuf[i * 2 + 0] = tmp; sbuf[i * 2 + 1] = tmp; phase += phase_inc; phase_inc += phase_inc_inc; scounter++; } } else { for(int i = 0; i < slen; i++) { int16 tmp = 127 * 256 * sin(phase); tmp = (scounter & 8) ? 127 * 256 : -127 * 256; sbuf[i] = tmp; phase += phase_inc; phase_inc += phase_inc_inc; scounter++; } } } #endif if(espec->NeedSoundReverse) { int16 *yaybuf = SoundBuf; int32 slen = SoundBufSize; if(MDFNGameInfo->soundchan == 1) { for(int x = 0; x < (slen / 2); x++) { int16 cha = yaybuf[slen - x - 1]; yaybuf[slen - x - 1] = yaybuf[x]; yaybuf[x] = cha; } } else if(MDFNGameInfo->soundchan == 2) { for(int x = 0; x < (slen * 2) / 2; x++) { int16 cha = yaybuf[slen * 2 - (x&~1) - ((x&1) ^ 1) - 1]; yaybuf[slen * 2 - (x&~1) - ((x&1) ^ 1) - 1] = yaybuf[x]; yaybuf[x] = cha; } } } try { if(wavrecorder) wavrecorder->WriteSound(SoundBuf, SoundBufSize); } catch(std::exception &e) { MDFND_PrintError(e.what()); delete wavrecorder; wavrecorder = NULL; } if(multiplier_save != LastSoundMultiplier) { ff_resampler.time_ratio(multiplier_save, 0.9965); LastSoundMultiplier = multiplier_save; } if(multiplier_save != 1) { if(FFDiscard) { if(SoundBufSize >= multiplier_save) SoundBufSize /= multiplier_save; } else { if(MDFNGameInfo->soundchan == 2) { assert(ff_resampler.max_write() >= SoundBufSize * 2); for(int i = 0; i < SoundBufSize * 2; i++) ff_resampler.buffer()[i] = SoundBuf[i]; } else { assert(ff_resampler.max_write() >= SoundBufSize * 2); for(int i = 0; i < SoundBufSize; i++) { ff_resampler.buffer()[i * 2] = SoundBuf[i]; ff_resampler.buffer()[i * 2 + 1] = 0; } } ff_resampler.write(SoundBufSize * 2); int avail = ff_resampler.avail(); int real_read = std::min((int)(SoundBufMaxSize * MDFNGameInfo->soundchan), avail); if(MDFNGameInfo->soundchan == 2) SoundBufSize = ff_resampler.read(SoundBuf, real_read ) >> 1; else SoundBufSize = ff_resampler.read_mono_hack(SoundBuf, real_read ); avail -= real_read; if(avail > 0) { printf("ff_resampler.avail() > espec->SoundBufMaxSize * MDFNGameInfo->soundchan - %d\n", avail); ff_resampler.clear(); } } }
MDFNGI *MDFNI_LoadCD(const char *force_module, const char *devicename) { uint8 LayoutMD5[16]; #ifdef NEED_CD static std::vector<CDIF *> CDInterfaces; // FIXME: Cleanup on error out. #endif MDFN_printf(_("Loading %s...\n\n"), devicename ? devicename : _("PHYSICAL CD")); try { if(devicename && strlen(devicename) > 4 && !strcasecmp(devicename + strlen(devicename) - 4, ".m3u")) { std::vector<std::string> file_list; ReadM3U(file_list, devicename); for(unsigned i = 0; i < file_list.size(); i++) { CDInterfaces.push_back(CDIF_Open(file_list[i].c_str(), false /* cdimage_memcache */)); } } else { CDInterfaces.push_back(CDIF_Open(devicename, false /* cdimage_memcache */)); } } catch(std::exception &e) { MDFND_PrintError(e.what()); MDFN_PrintError(_("Error opening CD.")); return(0); } // // Print out a track list for all discs. // MDFN_indent(1); for(unsigned i = 0; i < CDInterfaces.size(); i++) { CDUtility::TOC toc; CDInterfaces[i]->ReadTOC(&toc); MDFN_printf(_("CD %d Layout:\n"), i + 1); MDFN_indent(1); for(int32 track = toc.first_track; track <= toc.last_track; track++) { MDFN_printf(_("Track %2d, LBA: %6d %s\n"), track, toc.tracks[track].lba, (toc.tracks[track].control & 0x4) ? "DATA" : "AUDIO"); } MDFN_printf("Leadout: %6d\n", toc.tracks[100].lba); MDFN_indent(-1); MDFN_printf("\n"); } MDFN_indent(-1); // Calculate layout MD5. The system emulation LoadCD() code is free to ignore this value and calculate // its own, or to use it to look up a game in its database. { md5_context layout_md5; layout_md5.starts(); for(unsigned i = 0; i < CDInterfaces.size(); i++) { CD_TOC toc; CDInterfaces[i]->ReadTOC(&toc); layout_md5.update_u32_as_lsb(toc.first_track); layout_md5.update_u32_as_lsb(toc.last_track); layout_md5.update_u32_as_lsb(toc.tracks[100].lba); for(uint32 track = toc.first_track; track <= toc.last_track; track++) { layout_md5.update_u32_as_lsb(toc.tracks[track].lba); layout_md5.update_u32_as_lsb(toc.tracks[track].control & 0x4); } } layout_md5.finish(LayoutMD5); } // This if statement will be true if force_module references a system without CDROM support. if(!MDFNGameInfo->LoadCD) { MDFN_PrintError(_("Specified system \"%s\" doesn't support CDs!"), force_module); return(0); } MDFN_printf(_("Using module: %s(%s)\n\n"), MDFNGameInfo->shortname, MDFNGameInfo->fullname); // TODO: include module name in hash memcpy(MDFNGameInfo->MD5, LayoutMD5, 16); if(!(MDFNGameInfo->LoadCD(&CDInterfaces))) { for(unsigned i = 0; i < CDInterfaces.size(); i++) delete CDInterfaces[i]; CDInterfaces.clear(); MDFNGameInfo = NULL; return(0); } //MDFNI_SetLayerEnableMask(~0ULL); #ifdef WANT_DEBUGGER MDFNDBG_PostGameLoad(); #endif MDFN_ResetMessages(); // Save state, status messages, etc. // MDFN_LoadGameCheats(NULL); MDFNMP_InstallReadPatches(); return(MDFNGameInfo); }
bool InitSound(MDFNGI *gi) { SoundRate = 0; memset(&format,0,sizeof(format)); memset(&buffering,0,sizeof(buffering)); Interface = (SexyAL *)SexyAL_Init(0); DriverTypes = Interface->EnumerateTypes(Interface); format.sampformat = SEXYAL_FMT_PCMS16; assert(gi->soundchan); format.channels = gi->soundchan; format.revbyteorder = 0; format.rate = gi->soundrate ? gi->soundrate : MDFN_GetSettingUI("sound.rate"); buffering.ms = MDFN_GetSettingUI("sound.buffer_time"); buffering.period_us = MDFN_GetSettingUI("sound.period_time"); std::string zedevice = MDFN_GetSettingS("sound.device"); std::string zedriver = MDFN_GetSettingS("sound.driver"); CurDriverIndex = -1; if(!strcasecmp(zedriver.c_str(), "default")) CurDriverIndex = 0; else { for(int x = 0; DriverTypes[x].short_name; x++) { if(!strcasecmp(zedriver.c_str(), DriverTypes[x].short_name)) { CurDriverIndex = x; break; } } } MDFNI_printf(_("\nInitializing sound...\n")); MDFN_indent(1); if(CurDriverIndex == -1) { MDFN_printf(_("\nUnknown sound driver \"%s\". Supported sound drivers:\n"), zedriver.c_str()); MDFN_indent(2); for(int x = 0; DriverTypes[x].short_name; x++) { MDFN_printf("%s\n", DriverTypes[x].short_name); } MDFN_indent(-2); MDFN_printf("\n"); Interface->Destroy(Interface); Interface = NULL; MDFN_indent(-1); return(FALSE); } MDFNI_printf(_("Using \"%s\" audio driver with device \"%s\":"),DriverTypes[CurDriverIndex].name, zedevice.c_str()); MDFN_indent(1); //RunSexyALTest(Interface, &buffering, zedevice.c_str(), DriverTypes[CurDriverIndex].type); //exit(1); if(!(Output=Interface->Open(Interface, zedevice.c_str(), &format, &buffering, DriverTypes[CurDriverIndex].type))) { MDFND_PrintError(_("Error opening a sound device.")); Interface->Destroy(Interface); Interface=0; MDFN_indent(-2); return(FALSE); } if(format.rate<8192 || format.rate > 48000) { MDFND_PrintError(_("Set rate is out of range [8192-48000]")); KillSound(); MDFN_indent(-2); return(FALSE); } MDFNI_printf(_("\nBits: %u\nRate: %u\nChannels: %u\nByte order: CPU %s\nBuffer size: %u sample frames(%f ms)\n"), (format.sampformat>>4)*8,format.rate,format.channels,format.revbyteorder?"Reversed":"Native", buffering.buffer_size, (double)buffering.buffer_size * 1000 / format.rate); MDFNI_printf(_("Latency: %u sample frames(%f ms)\n"), buffering.latency, (double)buffering.latency * 1000 / format.rate); if(buffering.period_size) { int64_t pt_test_result = ((int64_t)buffering.period_size * (1000 * 1000) / format.rate); MDFNI_printf(_("Period size: %u sample frames(%f ms)\n"), buffering.period_size, (double)buffering.period_size * 1000 / format.rate); if(pt_test_result > 5333) { MDFN_indent(1); MDFN_printf(_("Warning: Period time is too large(it should be <= ~5.333ms). Video will appear very jerky.\n")); MDFN_indent(-1); } } format.sampformat=SEXYAL_FMT_PCMS16; format.channels=gi->soundchan?gi->soundchan:1; format.revbyteorder=0; //format.rate=gi->soundrate?gi->soundrate:soundrate; Output->SetConvert(Output, &format); EmuModBufferSize = (500 * format.rate + 999) / 1000; EmuModBuffer = (int16 *)calloc(sizeof(int16) * format.channels, EmuModBufferSize); SoundRate = format.rate; MDFN_indent(-2); return(1); }
void PumpWrap(void) { SDL_Event event; SDL_Event gtevents_temp[gtevents_size]; int numevents = 0; bool NITI; NITI = Netplay_IsTextInput(); if(Debugger_IsActive() || NITI || IsConsoleCheatConfigActive() || Help_IsActive()) { if(!krepeat) SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); krepeat = 1; } else { if(krepeat) SDL_EnableKeyRepeat(0, 0); krepeat = 0; } while(SDL_PollEvent(&event)) { if(Debugger_IsActive()) Debugger_Event(&event); else if(IsConsoleCheatConfigActive()) CheatEventHook(&event); NetplayEventHook(&event); /* This is a very ugly hack for some joystick hats that don't behave very well. */ if(event.type == SDL_JOYHATMOTION) { SDL_Event ne[64]; int count; //printf("Cheep: %d\n", event.jhat.value); if((count = SDL_PeepEvents(ne, 64, SDL_PEEKEVENT, SDL_EVENTMASK(SDL_JOYHATMOTION))) >= 1) { int x; int docon = 0; for(x=0;x<count;x++) if(event.jhat.which == ne[x].jhat.which) docon = 1; if(docon) continue; } } // && event.jhat. //if(event.type == SDL_JOYAXISMOTION) printf("Which: %d, axis: %d, value: %d\n", event.jaxis.which, event.jaxis.axis, event.jaxis.value); /* Handle the event, and THEN hand it over to the GUI. Order is important due to global variable mayhem(CEVT_TOGGLEFS. */ switch(event.type) { case SDL_ACTIVEEVENT: break; case SDL_SYSWMEVENT: break; case SDL_VIDEORESIZE: VideoResize(event.resize.w, event.resize.h); break; case SDL_VIDEOEXPOSE: break; case SDL_QUIT: NeedExitNow = 1;break; case SDL_USEREVENT: switch(event.user.code) { case CEVT_SET_STATE_STATUS: MT_SetStateStatus((StateStatusStruct *)event.user.data1); break; case CEVT_SET_MOVIE_STATUS: MT_SetMovieStatus((StateStatusStruct *)event.user.data1); break; case CEVT_WANT_EXIT: if(!Netplay_TryTextExit()) { SDL_Event evt; evt.quit.type = SDL_QUIT; SDL_PushEvent(&evt); } break; case CEVT_SET_GRAB_INPUT: SDL_WM_GrabInput(*(int *)event.user.data1 ? SDL_GRAB_ON : SDL_GRAB_OFF); free(event.user.data1); break; case CEVT_TOGGLEFS: NeedVideoChange = 1; break; case CEVT_VIDEOSYNC: NeedVideoChange = -1; break; case CEVT_PRINTERROR: MDFND_PrintError((char *)event.user.data1); free(event.user.data1); break; case CEVT_PRINTMESSAGE: MDFND_Message((char *)event.user.data1); free(event.user.data1); break; case CEVT_SHOWCURSOR: SDL_ShowCursor(*(int *)event.user.data1); free(event.user.data1); break; case CEVT_DISP_MESSAGE: VideoShowMessage((UTF8*)event.user.data1); break; default: if(numevents < gtevents_size) { memcpy(>events_temp[numevents], &event, sizeof(SDL_Event)); numevents++; } break; } break; default: if(numevents < gtevents_size) { memcpy(>events_temp[numevents], &event, sizeof(SDL_Event)); numevents++; } break; } } SDL_mutexP(EVMutex); for(int i = 0; i < numevents; i++) { memcpy((void *)>events[gte_write], >events_temp[i], sizeof(SDL_Event)); gte_write = (gte_write + 1) & (gtevents_size - 1); } SDL_mutexV(EVMutex); if(!CurGame) GameThread_HandleEvents(); }