BizHawk/BizHawk.Emulation.Cores/Consoles/Sony/PSP/PSP.cs

227 lines
6.1 KiB
C#
Raw Normal View History

using System;
using System.Collections.Generic;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Sony.PSP
{
[CoreAttributes(
"PPSSPP",
"hrydgard",
isPorted: true,
isReleased: false,
singleInstance: true)]
public class PSP : IEmulator, IVideoProvider, ISoundProvider
{
public PSP(CoreComm comm, string isopath)
{
ServiceProvider = new BasicServiceProvider(this);
if (attachedcore != null)
{
attachedcore.Dispose();
attachedcore = null;
}
CoreComm = comm;
glcontext = CoreComm.RequestGLContext(3, 0, true);
CoreComm.ActivateGLContext(glcontext);
logcallback = new PPSSPPDll.LogCB(LogCallbackFunc);
bool good = PPSSPPDll.BizInit(isopath, logcallback);
LogFlush();
if (!good)
throw new Exception("PPSSPP Init failed!");
CoreComm.RomStatusDetails = "It puts the scythe in the chicken or it gets the abyss again!";
attachedcore = this;
}
public static readonly ControllerDefinition PSPController = new ControllerDefinition
{
Name = "PSP Controller",
2013-06-25 23:44:17 +00:00
BoolButtons =
{
"Up", "Down", "Left", "Right", "Select", "Start", "L", "R", "Square", "Triangle", "Circle", "Cross",
"Menu", "Back",
"Power"
2013-06-25 23:44:17 +00:00
},
FloatControls =
{
"Left Stick X", "Left Stick Y", "Right Stick X", "Right Stick Y", "Left Trigger", "Right Trigger"
},
FloatRanges = // TODO
{
new[] {-1.0f, 0.0f, 1.0f},
new[] {-1.0f, 0.0f, 1.0f},
new[] {-1.0f, 0.0f, 1.0f},
new[] {-1.0f, 0.0f, 1.0f},
new[] {-1.0f, 0.0f, 1.0f},
new[] {-1.0f, 0.0f, 1.0f},
2013-06-25 23:44:17 +00:00
}
};
public ControllerDefinition ControllerDefinition { get { return PSPController; } }
public bool DeterministicEmulation { get { return true; } }
public string SystemId { get { return "PSP"; } }
public CoreComm CoreComm { get; private set; }
PPSSPPDll.LogCB logcallback = null;
Queue<string> debugmsgs = new Queue<string>();
PPSSPPDll.Input input = new PPSSPPDll.Input();
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());
}
}
bool disposed = false;
static PSP attachedcore = null;
object glcontext;
public IEmulatorServiceProvider ServiceProvider { get; private set; }
public void Dispose()
{
if (!disposed)
{
PPSSPPDll.BizClose();
logcallback = null;
disposed = true;
LogFlush();
Console.WriteLine("PSP Core Disposed.");
}
}
private void UpdateInput(IController c)
{
PPSSPPDll.Buttons b = 0;
if (c.IsPressed("Up")) b |= PPSSPPDll.Buttons.UP;
if (c.IsPressed("Down")) b |= PPSSPPDll.Buttons.DOWN;
if (c.IsPressed("Left")) b |= PPSSPPDll.Buttons.LEFT;
if (c.IsPressed("Right")) b |= PPSSPPDll.Buttons.RIGHT;
if (c.IsPressed("Select")) b |= PPSSPPDll.Buttons.SELECT;
if (c.IsPressed("Start")) b |= PPSSPPDll.Buttons.START;
if (c.IsPressed("L")) b |= PPSSPPDll.Buttons.LBUMPER;
if (c.IsPressed("R")) b |= PPSSPPDll.Buttons.RBUMPER;
if (c.IsPressed("Square")) b |= PPSSPPDll.Buttons.A;
if (c.IsPressed("Triangle")) b |= PPSSPPDll.Buttons.B;
if (c.IsPressed("Circle")) b |= PPSSPPDll.Buttons.X;
if (c.IsPressed("Cross")) b |= PPSSPPDll.Buttons.Y;
if (c.IsPressed("Menu")) b |= PPSSPPDll.Buttons.MENU;
if (c.IsPressed("Back")) b |= PPSSPPDll.Buttons.BACK;
input.SetButtons(b);
input.LeftStickX = c.GetFloat("Left Stick X");
input.LeftStickY = c.GetFloat("Left Stick Y");
input.RightStickX = c.GetFloat("Right Stick X");
input.RightStickY = c.GetFloat("Right Stick Y");
input.LeftTrigger = c.GetFloat("Left Trigger");
input.RightTrigger = c.GetFloat("Right Trigger");
}
public void FrameAdvance(IController controller, bool render, bool rendersound = true)
{
Frame++;
UpdateInput(controller);
PPSSPPDll.BizAdvance(screenbuffer, input);
// 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);
//Console.WriteLine(nsampavail);
//nsampavail = PPSSPPDll.mixsound(audiobuffer, audiobuffer.Length / 2);
LogFlush();
//Console.WriteLine("Audio Service: {0}", nsampavail);
}
public int Frame
{
get;
private set;
}
public void ResetCounters()
{
Frame = 0;
}
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 VirtualHeight { get { return screenheight; } }
public int BufferWidth { get { return screenwidth; } }
public int BufferHeight { get { return screenheight; } }
public int BackgroundColor { get { return unchecked((int)0xff000000); } }
2017-05-05 16:25:38 +00:00
public int VsyncNumerator
{
[FeatureNotImplemented]
get
{
return NullVideo.DefaultVsyncNum;
}
}
2017-05-05 16:25:38 +00:00
public int VsyncDenominator
{
[FeatureNotImplemented]
get
{
return NullVideo.DefaultVsyncDen;
}
}
readonly short[] audiobuffer = new short[2048 * 2];
int nsampavail = 0;
public void GetSamplesSync(out short[] samples, out int nsamp)
{
samples = audiobuffer;
nsamp = nsampavail;
//nsamp = 735;
}
public void DiscardSamples()
{
}
public bool CanProvideAsync
{
get { return false; }
}
public void SetSyncMode(SyncSoundMode mode)
{
if (mode == SyncSoundMode.Async)
{
throw new NotSupportedException("Async mode is not supported.");
}
}
public SyncSoundMode SyncMode
{
get { return SyncSoundMode.Sync; }
}
public void GetSamplesAsync(short[] samples)
{
throw new InvalidOperationException("Async mode is not supported.");
}
}
}