using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.InteropServices; using BizHawk.Emulation.Common; namespace BizHawk.Emulation.Consoles.Sony.PSP { public class PSP : IEmulator, IVideoProvider, ISyncSoundProvider { public static readonly ControllerDefinition PSPController = new ControllerDefinition { Name = "PSP Controller", BoolButtons = { "Up", "Down", "Left", "Right", "Select", "Start", "L", "R", "Square", "Triangle", "Circle", "Cross", "Power" }, FloatControls = { "Stick X", "Stick Y" }, FloatRanges = // TODO { new[] {-1.0f, 0.0f, 1.0f}, new[] {-1.0f, 0.0f, 1.0f}, } }; public IVideoProvider VideoProvider { get { return this; } } public ISoundProvider SoundProvider { get { return null; } } public ISyncSoundProvider SyncSoundProvider { get { return this; } } public bool StartAsyncSound() { return false; } public void EndAsyncSound() { } public ControllerDefinition ControllerDefinition { get { return PSPController; } } public IController Controller { get; set; } public bool DeterministicEmulation { get { return true; } } public string SystemId { get { return "PSP"; } } public bool BinarySaveStatesPreferred { get { return true; } } public CoreComm CoreComm { get; private set; } public string BoardName { get { return null; } } PPSSPPDll.LogCB logcallback = null; Queue debugmsgs = new Queue(); void LogCallbackFunc(char type, string message) { debugmsgs.Enqueue(string.Format("PSP: {0} {1}", type, message)); } void LogFlush() { while (debugmsgs.Count > 0) { Console.WriteLine(debugmsgs.Dequeue()); } } public List> GetCpuFlagsAndRegisters() { throw new NotImplementedException(); } bool disposed = false; static PSP attachedcore = null; GCHandle vidhandle; public PSP(CoreComm comm, string isopath) { if (attachedcore != null) { attachedcore.Dispose(); attachedcore = null; } CoreComm = comm; logcallback = new PPSSPPDll.LogCB(LogCallbackFunc); bool good = PPSSPPDll.init(isopath, logcallback); LogFlush(); if (!good) throw new Exception("PPSSPP Init failed!"); vidhandle = GCHandle.Alloc(screenbuffer, GCHandleType.Pinned); PPSSPPDll.setvidbuff(vidhandle.AddrOfPinnedObject()); CoreComm.VsyncDen = 1; CoreComm.VsyncNum = 60; CoreComm.RomStatusDetails = "It puts the scythe in the chicken or it gets the abyss again!"; attachedcore = this; } public void Dispose() { if (!disposed) { vidhandle.Free(); PPSSPPDll.setvidbuff(IntPtr.Zero); PPSSPPDll.die(); logcallback = null; disposed = true; LogFlush(); Console.WriteLine("PSP Core Disposed."); } } public void FrameAdvance(bool render, bool rendersound = true) { PPSSPPDll.advance(); // problem 1: audio can be 48khz, if a particular core parameter is set. we're not accounting for that. // problem 2: we seem to be getting approximately the right amount of output, but with // a lot of jitter on the per-frame buffer size nsampavail = PPSSPPDll.mixsound(audiobuffer, audiobuffer.Length / 2); LogFlush(); //Console.WriteLine("Audio Service: {0}", nsampavail); } public int Frame { get { return 0; } } public int LagCount { get { return 0; } set { } } public bool IsLagFrame { get { return true; } } public byte[] ReadSaveRam() { return new byte[0]; } public void StoreSaveRam(byte[] data) { } public void ClearSaveRam() { } public bool SaveRamModified { get { return false; } set { } } public void ResetCounters() { } public void SaveStateText(System.IO.TextWriter writer) { } public void LoadStateText(System.IO.TextReader reader) { } public void SaveStateBinary(System.IO.BinaryWriter writer) { } public void LoadStateBinary(System.IO.BinaryReader reader) { } public byte[] SaveStateBinary() { return new byte[0]; } public MemoryDomainList MemoryDomains { get { throw new NotImplementedException(); } } const int screenwidth = 480; const int screenheight = 272; readonly int[] screenbuffer = new int[screenwidth * screenheight]; public int[] GetVideoBuffer() { return screenbuffer; } public int VirtualWidth { get { return screenwidth; } } public int BufferWidth { get { return screenwidth; } } public int BufferHeight { get { return screenheight; } } public int BackgroundColor { get { return unchecked((int)0xff000000); } } readonly short[] audiobuffer = new short[2048 * 2]; int nsampavail = 0; public void GetSamples(out short[] samples, out int nsamp) { samples = audiobuffer; nsamp = nsampavail; } public void DiscardSamples() { } } }