227 lines
6.1 KiB
C#
227 lines
6.1 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
|
|
using BizHawk.Emulation.Common;
|
|
|
|
namespace BizHawk.Emulation.Cores.Sony.PSP
|
|
{
|
|
[Core(
|
|
"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",
|
|
BoolButtons =
|
|
{
|
|
"Up", "Down", "Left", "Right", "Select", "Start", "L", "R", "Square", "Triangle", "Circle", "Cross",
|
|
"Menu", "Back",
|
|
"Power"
|
|
},
|
|
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},
|
|
}
|
|
};
|
|
|
|
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); } }
|
|
|
|
public int VsyncNumerator
|
|
{
|
|
[FeatureNotImplemented]
|
|
get
|
|
{
|
|
return NullVideo.DefaultVsyncNum;
|
|
}
|
|
}
|
|
|
|
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.");
|
|
}
|
|
}
|
|
}
|