public void Stop() { // Are we already stopped? if (this.State == ConsoleState.Stopped) { return; } if (this.workerThread != null && this.workerThread.ManagedThreadId == Thread.CurrentThread.ManagedThreadId) { } // The worker's trying to kill itself? I dunno what to do. Screw it. ///////////////// // Stop the core. if (this.State == ConsoleState.Running) { this.InternalPause(); } // Close the game source. try { this.GameSource.Close(); } catch { } // Might happen, but I don't care. The game source shouldn't have done that. // Done! FreeDOCore.Destroy(); this.State = ConsoleState.Stopped; }
public static void LoadState(string fileName) { BinaryReader reader = null; try { reader = new BinaryReader(new FileStream(fileName, FileMode.Open)); var saveData = reader.ReadBytes((int)FreeDOCore.GetSaveSize()); unsafe { fixed(byte *saveDataPtr = saveData) { var pointer = new IntPtr(saveDataPtr); FreeDOCore.DoLoad(pointer); } } reader.Close(); } finally { if (reader != null) { reader.Close(); } } }
private void ExternalInterface_FrameTrigger() { // We got a signal that multi-task mode has completed a frame! // Done with this frame. this.isSwapFrameSignaled = true; // Use of multi-task mode requires that we ask the core to update our VDL frame for us. FreeDOCore.DoFrameMultitask(this.framePtr); }
public static void SaveState(string fileName) { BinaryWriter binaryWriter = null; try { ////////////////////////////////// // Create directory if it doesn't exist string saveDirectory = Path.GetDirectoryName(fileName); if (saveDirectory == null) { throw new DirectoryNotFoundException("Could not identify containing folder for: " + fileName); } if (!Directory.Exists(saveDirectory)) { Directory.CreateDirectory(saveDirectory); } ////////////////////////////////// // Save binary data from core emulation. binaryWriter = new BinaryWriter(new FileStream(fileName, FileMode.Create)); var saveData = new byte[FreeDOCore.GetSaveSize()]; unsafe { fixed(byte *saveDataPtr = saveData) { var pointer = new IntPtr(saveDataPtr); FreeDOCore.DoSave(pointer); } } binaryWriter.Write(saveData); binaryWriter.Close(); } finally { if (binaryWriter != null) { binaryWriter.Close(); } } }
public unsafe static void CopyBitmap(IntPtr currentFrame, BitmapDefinition bitmapDefinition, int copyWidth, int copyHeight, bool addBlackBorder, bool copyPointlessAlphaByte, bool allowCrop, ScalingAlgorithm scalingAlgorithm) { Bitmap bitmapToPrepare = bitmapDefinition.Bitmap; BitmapData bitmapData = bitmapToPrepare.LockBits(new Rectangle(0, 0, bitmapToPrepare.Width, bitmapToPrepare.Height), ImageLockMode.WriteOnly, bitmapToPrepare.PixelFormat); int newWidth = 0; int newHeight = 0; FreeDOCore.GetFrameBitmap( currentFrame , bitmapData.Scan0 , bitmapToPrepare.Width , bitmapDefinition.Crop , copyWidth , copyHeight , addBlackBorder , copyPointlessAlphaByte , allowCrop , scalingAlgorithm , out newWidth , out newHeight); bitmapToPrepare.UnlockBits(bitmapData); }
public void ReadSector(IntPtr destinationBuffer, int sectorNumber) { FreeDOCore.SetAnvilFix(2); // Set fix for anvil bios }
private void WorkerThread() { const int MAXIMUM_FRAME_COUNT = 100; long lastSample = 0; long lastTarget = 0; long targetPeriod = 0; int currentHertz = 12500000; bool highResolution = false; int overshootSleepThreshold = System.Math.Max(5, TimingHelper.GetResolution()); // Calculate a default target period in case there are no // audio samples for the upcoming frame (which is pretty unlikely). targetPeriod = (long)(PerformanceCounter.Frequency / 60.0); int sleepTime = 0; do { // We're awake! Wreak havoc! ///////////////////// // If we need to, update some core values. // Set arm clock? lock (this.clockSpeedSemaphore) { if (this.cpuClockHertz.HasValue && currentHertz != this.cpuClockHertz.Value) { currentHertz = this.cpuClockHertz.Value; FreeDOCore.SetArmClock(currentHertz); } } // Set high resolution mode? if (highResolution != this.renderHighResolution.Value) { highResolution = this.renderHighResolution.Value; FreeDOCore.SetTextureQuality(highResolution ? 1 : 0); } // Execute a frame. isSwapFrameSignaled = false; int lastFrameCount = 0; var frameWatch = new PerformanceStopWatch(); frameWatch.Start(); do { if (doFreeDOMultitask) { FreeDOCore.DoExecuteFrameMultitask(this.framePtr); } else { FreeDOCore.DoExecuteFrame(this.framePtr); } lastFrameCount++; } while (isSwapFrameSignaled == false && lastFrameCount < MAXIMUM_FRAME_COUNT); frameWatch.Stop(); /////////// // Signal completion. var doneWatch = new PerformanceStopWatch(); doneWatch.Start(); if (FrameDone != null) { FrameDone(this, new EventArgs()); } doneWatch.Stop(); /////////// // Set new target period depending on how many audio samples were pushed. if (lastAudioSampleCount > 0) { // Figure out how much time was emulated. double lastFrameSeconds = lastAudioSampleCount / (double)44100; // If there were multiple frames, account for this. if (lastFrameCount > 0) { lastFrameSeconds = lastFrameSeconds / lastFrameCount; } targetPeriod = (long)(PerformanceCounter.Frequency * lastFrameSeconds); lastAudioSampleCount = 0; } /////////// // Identify how long to sleep (if at all). long currentOvershoot = 0; long cheatAmount = 0; if (lastSample == 0) { // This is the first sample; this one's a freebee. lastSample = PerformanceCounter.Current; lastTarget = lastSample; // Pretend we're right on target! sleepTime = 0; } else { long currentSample = PerformanceCounter.Current; long currentDelta = currentSample - lastSample; long currentTarget = lastTarget + targetPeriod * lastFrameCount; currentOvershoot = currentTarget - currentSample; speedCalculator.AddSample((currentDelta / (double)lastFrameCount) / (double)PerformanceCounter.Frequency); // Are we ahead of schedule? if (currentOvershoot > 0) { // We're AHEAD OF schedule. // This is easy. We'll sleep if we're far enough ahead. sleepTime = (int)(((currentOvershoot) / (double)PerformanceCounter.Frequency) * 1000); // However, Our sleeps must always be at least the system's minimum sleep granularity. if (sleepTime < overshootSleepThreshold) { sleepTime = 0; } } else { // We're BEHIND schedule! No sleeping! sleepTime = 0; if (currentOvershoot < -maxLagTicks) { // We're REALLY BEHIND schedule. HOLY SHIT! // There's no way we can catch up. Just "give up" and accept a new target schedule. cheatAmount = currentOvershoot; currentTarget = currentSample; } } // Save the values for next time. lastSample = currentSample; lastTarget = currentTarget; } if (cheatAmount != 0) { healthCalculator.ReportCheat(cheatAmount); } // Let the audio plugin know the current "schedule". this.audioPlugin.FrameDone(cheatAmount > 0 ? 0 : currentOvershoot, cheatAmount); ///////////// // Sleep if we've been instructed to. var sleepWatch = new PerformanceStopWatch(); sleepWatch.Start(); if (sleepTime > 0 && !this.stopWorkerSignal) { Thread.Sleep(sleepTime); } sleepWatch.Stop(); // Some debug output. if (FourDO.Utilities.Globals.RunOptions.LogCPUTiming) { Trace.WriteLine(string.Format("CpuTiming - Frames:\t{0}\tSleepReq:\t{1:00.00}\tSlept:\t{2:00.00}\tSleepScrewup:\t{3:00.00}\tFrameTm:\t{4:00.00}\tDoneTm:\t{5:00.00}\tTargetOff:\t{6:00.00}\tCheatTm:\t{7:00.00}" , lastFrameCount , sleepTime , sleepWatch.TotalMilliseconds , sleepWatch.TotalMilliseconds - sleepTime , frameWatch.TotalMilliseconds , doneWatch.TotalMilliseconds , ((currentOvershoot) / (double)PerformanceCounter.Frequency) * 1000 , ((cheatAmount) / (double)PerformanceCounter.Frequency) * 1000 )); } } while (this.stopWorkerSignal == false); }
public void Start(string biosRom1FileName, string biosRom2FileName, IGameSource gameSource, string nvramFileName) { int fixMode = 0; /////////// // If they haven't initialized us properly, complain! if (!this.maxLagTicks.HasValue) { throw new InvalidOperationException("Audio buffer not set!"); } if (!this.cpuClockHertz.HasValue) { throw new InvalidOperationException("CPU Clock speed not set!"); } if (!this.renderHighResolution.HasValue) { throw new InvalidOperationException("High resolution setting not set!"); } // Are we already started? if (this.workerThread != null) { return; } this.GameSource = gameSource; ////////////// // Attempt to load Bios #1. try { this.biosRom1Copy = System.IO.File.ReadAllBytes(biosRom1FileName); } catch { throw new BadBiosRom1Exception(); } // Also get outta here if it's not the right length. if (this.biosRom1Copy.Length != ROM1_SIZE) { throw new BadBiosRom1Exception(); } if (this.biosRom1Copy[28] == 234) { FreeDOCore.SetAnvilFix(30); } //bios anvil ////////////// // Attempt to load Bios #2. // If we don't load Bios #2, we'll just use all zeroes. this.biosRom2Copy = new byte[ROM2_SIZE]; // Allocate full size to get all 0's // Load from file, if a file was chosen byte[] biosRom2Bytes = null; if (!string.IsNullOrWhiteSpace(biosRom2FileName)) { try { biosRom2Bytes = System.IO.File.ReadAllBytes(biosRom2FileName); } catch { throw new BadBiosRom2Exception(); } // Bios #2 is allowed to be less than or equal to the right size. // The only example file I know of is less than (912KB) the actual size on the hardware (1MB). if (biosRom2Bytes.Length > ROM2_SIZE || biosRom2Bytes.Length == 0) { throw new BadBiosRom2Exception(); } // Copy to the member variable. biosRom2Bytes.CopyTo(this.biosRom2Copy, 0); } ////////////// // Load a copy of the nvram. try { // If we previously had a game open, and they have now loaded // a new game, we want to make sure the game that was previously // open does not accidentally save. lock (nvramCopySemaphore) { // Note that we copy to the OLD nvram file name, just in case. if (this.nvramTimer.Enabled == true) { Memory.WriteMemoryDump(this.nvramFileName, this.nvramCopyPtr, NVRAM_SIZE); } this.nvramTimer.Enabled = false; // Read the new NVRAM into memory. Memory.ReadMemoryDump(this.nvramCopy, nvramFileName, NVRAM_SIZE); } } catch { throw new BadNvramFileException(); } // Freak out if the nvram isn't the right size. if (this.nvramCopy.Length != NVRAM_SIZE) { throw new BadNvramFileException(); } // Remember the file name. this.nvramFileName = nvramFileName; ////////////// // Attempt to start up the game source (it is allowed to throw errors). try { this.GameSource.Open(); } catch { throw new BadGameRomException(); } FreeDOCore.SetFixMode(fixMode); ///////////////// // Initialize the core FreeDOCore.Initialize(); //////////////// // Set fix mode GameRecord record = GameRegistrar.GetGameRecordById(this.GameSource.GetGameId()); if (record != null) { if ( record.Id == "F3AF1B13" || // Crash 'n Burn (JP) record.Id == "217344B0" // Crash 'n Burn (US) ) { fixMode = fixMode | (int)FixMode.FIX_BIT_TIMING_1; } if (record.Id == "DBB419FA" || // Street Figthter 2, for intro sync record.Id == "07C32F10" ||// Street Figthter 2, for intro sync record.Id == "5282889F" ||// Street Figthter 2, for intro sync record.Id == "7340307E" // Street Figthter 2, for intro sync ) { fixMode = fixMode | (int)FixMode.FIX_BIT_TIMING_2; } if (record.Id == "CB8EE795" // Dinopark Tycoon ) { fixMode = fixMode | (int)FixMode.FIX_BIT_TIMING_3; } if (record.Id == "1A370EBA" || // Microcosm record.Id == "B35C911D"// Microcosm ) { fixMode = fixMode | (int)FixMode.FIX_BIT_TIMING_5; } if (record.Id == "0511D3D2" || // Alone in the Dark record.Id == "9F7D72BC" ||// Alone in the Dark record.Id == "E843C635"// Alone in the Dark ) { fixMode = fixMode | (int)FixMode.FIX_BIT_TIMING_6; } if (record.Id == "2AABA5B9" || // Samurai Shodown (EU-US) record.Id == "BF61BB32" // Samurai Shodown (JP) ) { fixMode = fixMode | (int)FixMode.FIX_BIT_GRAPHICS_STEP_Y; } } FreeDOCore.SetFixMode(fixMode); ///////////////// // Start the core thread this.InternalResume(false); }