2013-04-29 01:57:41 +00:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Runtime.InteropServices;
|
|
|
|
|
using System.Threading;
|
|
|
|
|
|
|
|
|
|
namespace BizHawk.Emulation.Consoles.Nintendo.N64
|
|
|
|
|
{
|
2013-05-01 14:38:47 +00:00
|
|
|
|
public class N64 : IEmulator, IVideoProvider
|
2013-04-29 01:57:41 +00:00
|
|
|
|
{
|
2013-05-01 22:18:53 +00:00
|
|
|
|
static N64 AttachedCore = null;
|
2013-04-29 01:57:41 +00:00
|
|
|
|
public string SystemId { get { return "N64"; } }
|
|
|
|
|
|
|
|
|
|
public CoreComm CoreComm { get; private set; }
|
|
|
|
|
public byte[] rom;
|
|
|
|
|
public GameInfo game;
|
|
|
|
|
|
|
|
|
|
public IVideoProvider VideoProvider { get { return this; } }
|
|
|
|
|
public int[] frameBuffer = new int[640 * 480];
|
2013-04-30 00:36:54 +00:00
|
|
|
|
public int[] GetVideoBuffer()
|
|
|
|
|
{
|
|
|
|
|
for (int row = 0; row < 480; row++)
|
|
|
|
|
{
|
|
|
|
|
for (int col = 0; col < 640; col++)
|
|
|
|
|
{
|
|
|
|
|
int i = row * 640 + col;
|
|
|
|
|
frameBuffer[(479 - row) * 640 + col] = (m64p_FrameBuffer[(i * 3)] << 16) + (m64p_FrameBuffer[(i * 3) + 1] << 8) + (m64p_FrameBuffer[(i * 3) + 2]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return frameBuffer;
|
|
|
|
|
}
|
2013-04-29 01:57:41 +00:00
|
|
|
|
public int VirtualWidth { get { return 640; } }
|
|
|
|
|
public int BufferWidth { get { return 640; } }
|
|
|
|
|
public int BufferHeight { get { return 480; } }
|
|
|
|
|
public int BackgroundColor { get { return 0; } }
|
|
|
|
|
|
2013-05-01 14:38:47 +00:00
|
|
|
|
Sound.Utilities.SpeexResampler resampler;
|
|
|
|
|
|
2013-05-01 22:26:08 +00:00
|
|
|
|
uint m64pSamplingRate;
|
|
|
|
|
|
2013-05-01 14:38:47 +00:00
|
|
|
|
short[] m64pAudioBuffer = new short[2];
|
|
|
|
|
public ISoundProvider SoundProvider { get { return null; } }
|
|
|
|
|
public ISyncSoundProvider SyncSoundProvider { get { return resampler; } }
|
|
|
|
|
public bool StartAsyncSound() { return false; }
|
2013-04-29 01:57:41 +00:00
|
|
|
|
public void EndAsyncSound() { }
|
|
|
|
|
|
|
|
|
|
public ControllerDefinition ControllerDefinition { get { return N64ControllerDefinition; } }
|
|
|
|
|
public IController Controller { get; set; }
|
|
|
|
|
public static readonly ControllerDefinition N64ControllerDefinition = new ControllerDefinition
|
|
|
|
|
{
|
|
|
|
|
Name = "Nintento 64 Controller",
|
|
|
|
|
BoolButtons =
|
|
|
|
|
{
|
2013-05-02 01:54:44 +00:00
|
|
|
|
"P1 DPad R", "P1 DPad L", "P1 DPad D", "P1 DPad U", "P1 Start", "P1 Z", "P1 B", "P1 A", "P1 C Right", "P1 C Left", "P1 C Down", "P1 C Up", "P1 R", "P1 L",
|
|
|
|
|
"P2 DPad R", "P2 DPad L", "P2 DPad D", "P2 DPad U", "P2 Start", "P2 Z", "P2 B", "P2 A", "P2 C Right", "P2 C Left", "P2 C Down", "P2 C Up", "P2 R", "P2 L",
|
|
|
|
|
"P3 DPad R", "P3 DPad L", "P3 DPad D", "P3 DPad U", "P3 Start", "P3 Z", "P3 B", "P3 A", "P3 C Right", "P3 C Left", "P3 C Down", "P3 C Up", "P3 R", "P3 L",
|
|
|
|
|
"P4 DPad R", "P4 DPad L", "P4 DPad D", "P4 DPad U", "P4 Start", "P4 Z", "P4 B", "P4 A", "P4 C Right", "P4 C Left", "P4 C Down", "P4 C Up", "P4 R", "P4 L",
|
|
|
|
|
"Reset", "Power"
|
2013-04-29 01:57:41 +00:00
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
public int Frame { get; set; }
|
|
|
|
|
public int LagCount { get; set; }
|
|
|
|
|
public bool IsLagFrame { get { return true; } }
|
|
|
|
|
public void ResetFrameCounter() { }
|
2013-04-30 00:36:54 +00:00
|
|
|
|
public void FrameAdvance(bool render, bool rendersound)
|
|
|
|
|
{
|
|
|
|
|
m64pFrameComplete = false;
|
2013-05-02 22:08:54 +00:00
|
|
|
|
/*
|
|
|
|
|
sbyte x = 0;
|
|
|
|
|
sbyte y = 0;
|
|
|
|
|
if (Controller["P1 DPad R"]) x = 80;
|
|
|
|
|
if (Controller["P1 DPad L"]) x = -80;
|
|
|
|
|
if (Controller["P1 DPad D"]) y = -80;
|
|
|
|
|
if (Controller["P1 DPad U"]) y = 80;
|
|
|
|
|
InpSetKeys(0, ReadController(1), x, y);
|
|
|
|
|
*/
|
2013-05-02 03:38:57 +00:00
|
|
|
|
InpSetKeys(0, ReadController(1), 0, 0);
|
2013-04-30 00:36:54 +00:00
|
|
|
|
m64pCoreDoCommandPtr(m64p_command.M64CMD_ADVANCE_FRAME, 0, IntPtr.Zero);
|
|
|
|
|
while (m64pFrameComplete == false) { }
|
|
|
|
|
Frame++;
|
|
|
|
|
}
|
2013-04-29 01:57:41 +00:00
|
|
|
|
|
2013-05-02 03:38:57 +00:00
|
|
|
|
public int ReadController(int num)
|
|
|
|
|
{
|
|
|
|
|
int buttons = 0;
|
|
|
|
|
|
|
|
|
|
if (Controller["P1 DPad R"]) buttons |= (1 << 0);
|
|
|
|
|
if (Controller["P1 DPad L"]) buttons |= (1 << 1);
|
|
|
|
|
if (Controller["P1 DPad D"]) buttons |= (1 << 2);
|
|
|
|
|
if (Controller["P1 DPad U"]) buttons |= (1 << 3);
|
|
|
|
|
if (Controller["P1 Start"]) buttons |= (1 << 4);
|
|
|
|
|
if (Controller["P1 Z"]) buttons |= (1 << 5);
|
|
|
|
|
if (Controller["P1 B"]) buttons |= (1 << 6);
|
|
|
|
|
if (Controller["P1 A"]) buttons |= (1 << 7);
|
|
|
|
|
if (Controller["P1 C Right"]) buttons |= (1 << 8);
|
|
|
|
|
if (Controller["P1 C Left"]) buttons |= (1 << 9);
|
|
|
|
|
if (Controller["P1 C Down"]) buttons |= (1 << 10);
|
|
|
|
|
if (Controller["P1 C Up"]) buttons |= (1 << 11);
|
|
|
|
|
if (Controller["P1 R"]) buttons |= (1 << 12);
|
|
|
|
|
if (Controller["P1 L"]) buttons |= (1 << 13);
|
|
|
|
|
|
|
|
|
|
return buttons;
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-29 01:57:41 +00:00
|
|
|
|
public bool DeterministicEmulation { get; set; }
|
|
|
|
|
|
|
|
|
|
public byte[] ReadSaveRam() { return null; }
|
|
|
|
|
public void StoreSaveRam(byte[] data) { }
|
|
|
|
|
public void ClearSaveRam() { }
|
|
|
|
|
public bool SaveRamModified { get; set; }
|
|
|
|
|
|
|
|
|
|
void SyncState(Serializer ser)
|
|
|
|
|
{
|
|
|
|
|
ser.BeginSection("N64");
|
|
|
|
|
ser.EndSection();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void SaveStateText(TextWriter writer) { SyncState(Serializer.CreateTextWriter(writer)); }
|
|
|
|
|
public void LoadStateText(TextReader reader) { SyncState(Serializer.CreateTextReader(reader)); }
|
|
|
|
|
public void SaveStateBinary(BinaryWriter bw) { SyncState(Serializer.CreateBinaryWriter(bw)); }
|
|
|
|
|
public void LoadStateBinary(BinaryReader br) { SyncState(Serializer.CreateBinaryReader(br)); }
|
|
|
|
|
public byte[] SaveStateBinary()
|
|
|
|
|
{
|
|
|
|
|
MemoryStream ms = new MemoryStream();
|
|
|
|
|
BinaryWriter bw = new BinaryWriter(ms);
|
|
|
|
|
SaveStateBinary(bw);
|
|
|
|
|
bw.Flush();
|
|
|
|
|
return ms.ToArray();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public IList<MemoryDomain> MemoryDomains { get { return null; } }
|
|
|
|
|
public MemoryDomain MainMemory { get { return null; } }
|
|
|
|
|
|
2013-05-01 22:18:53 +00:00
|
|
|
|
bool disposed = false;
|
2013-05-01 14:38:47 +00:00
|
|
|
|
public void Dispose()
|
|
|
|
|
{
|
2013-05-01 22:18:53 +00:00
|
|
|
|
if (!disposed)
|
|
|
|
|
{
|
|
|
|
|
// Stop the core, and wait for it to end
|
|
|
|
|
m64pCoreDoCommandPtr(m64p_command.M64CMD_STOP, 0, IntPtr.Zero);
|
2013-05-01 22:32:31 +00:00
|
|
|
|
//m64pEmulator.Join();
|
|
|
|
|
while (emulator_running) { }
|
2013-05-01 22:18:53 +00:00
|
|
|
|
|
|
|
|
|
resampler.Dispose();
|
|
|
|
|
resampler = null;
|
|
|
|
|
|
|
|
|
|
m64pCoreDetachPlugin(m64p_plugin_type.M64PLUGIN_GFX);
|
|
|
|
|
m64pCoreDetachPlugin(m64p_plugin_type.M64PLUGIN_AUDIO);
|
|
|
|
|
m64pCoreDetachPlugin(m64p_plugin_type.M64PLUGIN_INPUT);
|
|
|
|
|
m64pCoreDetachPlugin(m64p_plugin_type.M64PLUGIN_RSP);
|
|
|
|
|
|
|
|
|
|
GfxPluginShutdown();
|
|
|
|
|
FreeLibrary(GfxDll);
|
|
|
|
|
|
|
|
|
|
AudPluginShutdown();
|
|
|
|
|
FreeLibrary(AudDll);
|
|
|
|
|
|
2013-05-02 03:38:57 +00:00
|
|
|
|
InpPluginShutdown();
|
|
|
|
|
FreeLibrary(InpDll);
|
|
|
|
|
|
2013-05-01 22:18:53 +00:00
|
|
|
|
RspPluginShutdown();
|
|
|
|
|
FreeLibrary(RspDll);
|
|
|
|
|
|
|
|
|
|
m64pCoreDoCommandPtr(m64p_command.M64CMD_ROM_CLOSE, 0, IntPtr.Zero);
|
|
|
|
|
m64pCoreShutdown();
|
|
|
|
|
FreeLibrary(CoreDll);
|
|
|
|
|
|
|
|
|
|
disposed = true;
|
|
|
|
|
}
|
2013-05-01 14:38:47 +00:00
|
|
|
|
}
|
2013-04-29 01:57:41 +00:00
|
|
|
|
|
2013-04-30 00:08:21 +00:00
|
|
|
|
[DllImport("kernel32.dll")]
|
|
|
|
|
public static extern IntPtr LoadLibrary(string dllToLoad);
|
|
|
|
|
|
|
|
|
|
[DllImport("kernel32.dll")]
|
|
|
|
|
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
|
|
|
|
|
|
|
|
|
|
[DllImport("kernel32.dll")]
|
|
|
|
|
public static extern bool FreeLibrary(IntPtr hModule);
|
|
|
|
|
|
|
|
|
|
enum m64p_error
|
|
|
|
|
{
|
|
|
|
|
M64ERR_SUCCESS = 0,
|
|
|
|
|
M64ERR_NOT_INIT, /* Function is disallowed before InitMupen64Plus() is called */
|
|
|
|
|
M64ERR_ALREADY_INIT, /* InitMupen64Plus() was called twice */
|
|
|
|
|
M64ERR_INCOMPATIBLE, /* API versions between components are incompatible */
|
|
|
|
|
M64ERR_INPUT_ASSERT, /* Invalid parameters for function call, such as ParamValue=NULL for GetCoreParameter() */
|
|
|
|
|
M64ERR_INPUT_INVALID, /* Invalid input data, such as ParamValue="maybe" for SetCoreParameter() to set a BOOL-type value */
|
|
|
|
|
M64ERR_INPUT_NOT_FOUND, /* The input parameter(s) specified a particular item which was not found */
|
|
|
|
|
M64ERR_NO_MEMORY, /* Memory allocation failed */
|
|
|
|
|
M64ERR_FILES, /* Error opening, creating, reading, or writing to a file */
|
|
|
|
|
M64ERR_INTERNAL, /* Internal error (bug) */
|
|
|
|
|
M64ERR_INVALID_STATE, /* Current program state does not allow operation */
|
|
|
|
|
M64ERR_PLUGIN_FAIL, /* A plugin function returned a fatal error */
|
|
|
|
|
M64ERR_SYSTEM_FAIL, /* A system function call, such as an SDL or file operation, failed */
|
|
|
|
|
M64ERR_UNSUPPORTED, /* Function call is not supported (ie, core not built with debugger) */
|
|
|
|
|
M64ERR_WRONG_TYPE /* A given input type parameter cannot be used for desired operation */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum m64p_plugin_type
|
|
|
|
|
{
|
|
|
|
|
M64PLUGIN_NULL = 0,
|
|
|
|
|
M64PLUGIN_RSP = 1,
|
|
|
|
|
M64PLUGIN_GFX,
|
|
|
|
|
M64PLUGIN_AUDIO,
|
|
|
|
|
M64PLUGIN_INPUT,
|
|
|
|
|
M64PLUGIN_CORE
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum m64p_command
|
|
|
|
|
{
|
|
|
|
|
M64CMD_NOP = 0,
|
|
|
|
|
M64CMD_ROM_OPEN,
|
|
|
|
|
M64CMD_ROM_CLOSE,
|
|
|
|
|
M64CMD_ROM_GET_HEADER,
|
|
|
|
|
M64CMD_ROM_GET_SETTINGS,
|
|
|
|
|
M64CMD_EXECUTE,
|
|
|
|
|
M64CMD_STOP,
|
|
|
|
|
M64CMD_PAUSE,
|
|
|
|
|
M64CMD_RESUME,
|
|
|
|
|
M64CMD_CORE_STATE_QUERY,
|
|
|
|
|
M64CMD_STATE_LOAD,
|
|
|
|
|
M64CMD_STATE_SAVE,
|
|
|
|
|
M64CMD_STATE_SET_SLOT,
|
|
|
|
|
M64CMD_SEND_SDL_KEYDOWN,
|
|
|
|
|
M64CMD_SEND_SDL_KEYUP,
|
|
|
|
|
M64CMD_SET_FRAME_CALLBACK,
|
|
|
|
|
M64CMD_TAKE_NEXT_SCREENSHOT,
|
|
|
|
|
M64CMD_CORE_STATE_SET,
|
|
|
|
|
M64CMD_READ_SCREEN,
|
|
|
|
|
M64CMD_RESET,
|
2013-04-30 01:50:27 +00:00
|
|
|
|
M64CMD_ADVANCE_FRAME,
|
|
|
|
|
M64CMD_SET_VI_CALLBACK
|
2013-04-30 00:08:21 +00:00
|
|
|
|
};
|
|
|
|
|
|
2013-04-30 01:14:07 +00:00
|
|
|
|
enum m64p_emu_state
|
2013-04-30 02:22:56 +00:00
|
|
|
|
{
|
|
|
|
|
M64EMU_STOPPED = 1,
|
|
|
|
|
M64EMU_RUNNING,
|
|
|
|
|
M64EMU_PAUSED
|
2013-04-30 01:14:07 +00:00
|
|
|
|
};
|
|
|
|
|
|
2013-04-30 00:08:21 +00:00
|
|
|
|
//[DllImport(@"..\..\libmupen64plus\mupen64plus-ui-console\projects\msvc11\Release\mupen64plus.dll", CallingConvention = CallingConvention.Cdecl)]
|
|
|
|
|
//static extern m64p_error CoreStartup(int APIVersion, string ConfigPath, string DataPath, string context, DebugCallback DebugCallback, string context2, IntPtr bar);
|
|
|
|
|
|
|
|
|
|
// Core Specifc functions
|
|
|
|
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
|
|
|
delegate m64p_error CoreStartup(int APIVersion, string ConfigPath, string DataPath, string Context, DebugCallback DebugCallback, string context2, IntPtr dummy);
|
|
|
|
|
CoreStartup m64pCoreStartup;
|
|
|
|
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
2013-05-01 22:18:53 +00:00
|
|
|
|
delegate m64p_error CoreShutdown();
|
|
|
|
|
CoreShutdown m64pCoreShutdown;
|
|
|
|
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
2013-04-30 00:08:21 +00:00
|
|
|
|
delegate m64p_error CoreAttachPlugin(m64p_plugin_type PluginType, IntPtr PluginLibHandle);
|
|
|
|
|
CoreAttachPlugin m64pCoreAttachPlugin;
|
2013-05-01 22:18:53 +00:00
|
|
|
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
|
|
|
delegate m64p_error CoreDetachPlugin(m64p_plugin_type PluginType);
|
|
|
|
|
CoreDetachPlugin m64pCoreDetachPlugin;
|
2013-04-30 00:08:21 +00:00
|
|
|
|
|
|
|
|
|
// The last parameter is a void pointer, so make a few delegates for the versions we want to use
|
|
|
|
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
|
|
|
delegate m64p_error CoreDoCommandByteArray(m64p_command Command, int ParamInt, byte[] ParamPtr);
|
|
|
|
|
CoreDoCommandByteArray m64pCoreDoCommandByteArray;
|
|
|
|
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
|
|
|
delegate m64p_error CoreDoCommandPtr(m64p_command Command, int ParamInt, IntPtr ParamPtr);
|
|
|
|
|
CoreDoCommandPtr m64pCoreDoCommandPtr;
|
|
|
|
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
|
|
|
delegate m64p_error CoreDoCommandRefInt(m64p_command Command, int ParamInt, ref int ParamPtr);
|
|
|
|
|
CoreDoCommandRefInt m64pCoreDoCommandRefInt;
|
2013-04-30 00:36:54 +00:00
|
|
|
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
|
|
|
delegate m64p_error CoreDoCommandFrameCallback(m64p_command Command, int ParamInt, FrameCallback ParamPtr);
|
|
|
|
|
CoreDoCommandFrameCallback m64pCoreDoCommandFrameCallback;
|
2013-04-30 01:50:27 +00:00
|
|
|
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
|
|
|
delegate m64p_error CoreDoCommandVICallback(m64p_command Command, int ParamInt, VICallback ParamPtr);
|
|
|
|
|
CoreDoCommandVICallback m64pCoreDoCommandVICallback;
|
2013-04-30 00:36:54 +00:00
|
|
|
|
|
|
|
|
|
// Graphics plugin specific
|
|
|
|
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
|
|
|
private delegate void ReadScreen2(byte[] framebuffer, ref int width, ref int height, int buffer);
|
|
|
|
|
ReadScreen2 GFXReadScreen2;
|
2013-04-30 00:08:21 +00:00
|
|
|
|
|
2013-04-30 03:24:44 +00:00
|
|
|
|
// Audio plugin specific
|
|
|
|
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
|
|
|
private delegate int GetBufferSize();
|
|
|
|
|
GetBufferSize AudGetBufferSize;
|
|
|
|
|
|
2013-05-02 03:38:57 +00:00
|
|
|
|
// Input plugin specific
|
|
|
|
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
2013-05-02 22:08:54 +00:00
|
|
|
|
private delegate int SetKeys(int num, int keys, sbyte X, sbyte Y);
|
2013-05-02 03:38:57 +00:00
|
|
|
|
SetKeys InpSetKeys;
|
|
|
|
|
|
2013-04-30 03:24:44 +00:00
|
|
|
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
|
|
|
private delegate void ReadAudioBuffer(short[] dest);
|
|
|
|
|
ReadAudioBuffer AudReadAudioBuffer;
|
2013-05-01 21:28:15 +00:00
|
|
|
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
|
|
|
private delegate int GetAudioRate();
|
|
|
|
|
GetAudioRate AudGetAudioRate;
|
2013-04-30 03:24:44 +00:00
|
|
|
|
|
2013-04-30 00:08:21 +00:00
|
|
|
|
// This has the same calling pattern for all the plugins
|
|
|
|
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
|
|
|
private delegate m64p_error PluginStartup(IntPtr CoreHandle, string Context, DebugCallback DebugCallback);
|
2013-05-01 22:18:53 +00:00
|
|
|
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
|
|
|
private delegate m64p_error PluginShutdown();
|
2013-04-30 00:08:21 +00:00
|
|
|
|
|
|
|
|
|
PluginStartup GfxPluginStartup;
|
|
|
|
|
PluginStartup RspPluginStartup;
|
2013-04-30 03:24:44 +00:00
|
|
|
|
PluginStartup AudPluginStartup;
|
2013-05-02 03:38:57 +00:00
|
|
|
|
PluginStartup InpPluginStartup;
|
2013-04-30 00:08:21 +00:00
|
|
|
|
|
2013-05-01 22:18:53 +00:00
|
|
|
|
PluginShutdown GfxPluginShutdown;
|
|
|
|
|
PluginShutdown RspPluginShutdown;
|
|
|
|
|
PluginShutdown AudPluginShutdown;
|
2013-05-02 03:38:57 +00:00
|
|
|
|
PluginShutdown InpPluginShutdown;
|
2013-05-01 22:18:53 +00:00
|
|
|
|
|
2013-05-02 00:33:44 +00:00
|
|
|
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
2013-04-30 00:08:21 +00:00
|
|
|
|
public delegate void DebugCallback(IntPtr Context, int level, string Message);
|
|
|
|
|
|
2013-05-02 00:33:44 +00:00
|
|
|
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
2013-04-30 00:36:54 +00:00
|
|
|
|
public delegate void FrameCallback();
|
|
|
|
|
FrameCallback m64pFrameCallback;
|
|
|
|
|
|
|
|
|
|
byte[] m64p_FrameBuffer = new byte[640 * 480 * 3];
|
|
|
|
|
public void Getm64pFrameBuffer()
|
|
|
|
|
{
|
|
|
|
|
int width = 0;
|
|
|
|
|
int height = 0;
|
|
|
|
|
GFXReadScreen2(m64p_FrameBuffer, ref width, ref height, 0);
|
2013-04-30 01:50:27 +00:00
|
|
|
|
//m64pFrameComplete = true;
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-02 00:33:44 +00:00
|
|
|
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
2013-04-30 01:50:27 +00:00
|
|
|
|
public delegate void VICallback();
|
|
|
|
|
VICallback m64pVICallback;
|
|
|
|
|
public void FrameComplete()
|
|
|
|
|
{
|
2013-05-01 22:26:08 +00:00
|
|
|
|
uint s = (uint)AudGetAudioRate();
|
|
|
|
|
if (s != m64pSamplingRate)
|
|
|
|
|
{
|
|
|
|
|
m64pSamplingRate = s;
|
|
|
|
|
resampler.ChangeRate(s, 44100, s, 44100);
|
2013-05-02 00:33:44 +00:00
|
|
|
|
//Console.WriteLine("N64 ARate Change {0}", s);
|
|
|
|
|
}
|
2013-05-01 14:38:47 +00:00
|
|
|
|
|
2013-05-01 22:26:08 +00:00
|
|
|
|
int m64pAudioBufferSize = AudGetBufferSize();
|
2013-05-01 14:38:47 +00:00
|
|
|
|
if (m64pAudioBuffer.Length < m64pAudioBufferSize)
|
|
|
|
|
m64pAudioBuffer = new short[m64pAudioBufferSize];
|
2013-05-01 22:26:08 +00:00
|
|
|
|
|
2013-04-30 03:24:44 +00:00
|
|
|
|
if (m64pAudioBufferSize > 0)
|
|
|
|
|
{
|
|
|
|
|
AudReadAudioBuffer(m64pAudioBuffer);
|
2013-05-01 14:38:47 +00:00
|
|
|
|
resampler.EnqueueSamples(m64pAudioBuffer, m64pAudioBufferSize / 2);
|
2013-04-30 03:24:44 +00:00
|
|
|
|
}
|
2013-04-30 00:36:54 +00:00
|
|
|
|
m64pFrameComplete = true;
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-30 00:08:21 +00:00
|
|
|
|
IntPtr CoreDll;
|
|
|
|
|
IntPtr GfxDll;
|
|
|
|
|
IntPtr RspDll;
|
2013-04-30 03:24:44 +00:00
|
|
|
|
IntPtr AudDll;
|
2013-05-02 03:38:57 +00:00
|
|
|
|
IntPtr InpDll;
|
2013-04-30 00:08:21 +00:00
|
|
|
|
|
|
|
|
|
Thread m64pEmulator;
|
|
|
|
|
|
2013-04-30 02:22:56 +00:00
|
|
|
|
volatile bool m64pFrameComplete = false;
|
2013-04-30 00:36:54 +00:00
|
|
|
|
|
2013-04-29 01:57:41 +00:00
|
|
|
|
public N64(CoreComm comm, GameInfo game, byte[] rom)
|
|
|
|
|
{
|
2013-05-01 22:18:53 +00:00
|
|
|
|
if (AttachedCore != null)
|
|
|
|
|
{
|
|
|
|
|
AttachedCore.Dispose();
|
|
|
|
|
AttachedCore = null;
|
|
|
|
|
}
|
2013-04-29 01:57:41 +00:00
|
|
|
|
CoreComm = comm;
|
|
|
|
|
this.rom = rom;
|
|
|
|
|
this.game = game;
|
2013-04-30 00:08:21 +00:00
|
|
|
|
|
|
|
|
|
// Load the core DLL and retrieve some function pointers
|
|
|
|
|
CoreDll = LoadLibrary("mupen64plus.dll");
|
|
|
|
|
GfxDll = LoadLibrary("mupen64plus-video-rice.dll");
|
|
|
|
|
RspDll = LoadLibrary("mupen64plus-rsp-hle.dll");
|
2013-04-30 03:24:44 +00:00
|
|
|
|
AudDll = LoadLibrary("mupen64plus-audio-bkm.dll");
|
2013-05-02 03:38:57 +00:00
|
|
|
|
InpDll = LoadLibrary("mupen64plus-input-bkm.dll");
|
2013-05-01 22:18:53 +00:00
|
|
|
|
|
2013-04-30 00:08:21 +00:00
|
|
|
|
m64pCoreStartup = (CoreStartup)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "CoreStartup"), typeof(CoreStartup));
|
2013-05-01 22:18:53 +00:00
|
|
|
|
m64pCoreShutdown = (CoreShutdown)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "CoreShutdown"), typeof(CoreShutdown));
|
2013-04-30 00:08:21 +00:00
|
|
|
|
m64pCoreDoCommandByteArray = (CoreDoCommandByteArray)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandByteArray));
|
|
|
|
|
m64pCoreDoCommandPtr = (CoreDoCommandPtr)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandPtr));
|
|
|
|
|
m64pCoreDoCommandRefInt = (CoreDoCommandRefInt)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandRefInt));
|
2013-04-30 00:36:54 +00:00
|
|
|
|
m64pCoreDoCommandFrameCallback = (CoreDoCommandFrameCallback)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandFrameCallback));
|
2013-04-30 01:50:27 +00:00
|
|
|
|
m64pCoreDoCommandVICallback = (CoreDoCommandVICallback)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandVICallback));
|
2013-04-30 00:08:21 +00:00
|
|
|
|
m64pCoreAttachPlugin = (CoreAttachPlugin)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "CoreAttachPlugin"), typeof(CoreAttachPlugin));
|
2013-05-01 22:18:53 +00:00
|
|
|
|
m64pCoreDetachPlugin = (CoreDetachPlugin)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "CoreDetachPlugin"), typeof(CoreDetachPlugin));
|
2013-04-30 00:08:21 +00:00
|
|
|
|
|
|
|
|
|
GfxPluginStartup = (PluginStartup)Marshal.GetDelegateForFunctionPointer(GetProcAddress(GfxDll, "PluginStartup"), typeof(PluginStartup));
|
2013-05-01 22:18:53 +00:00
|
|
|
|
GfxPluginShutdown = (PluginShutdown)Marshal.GetDelegateForFunctionPointer(GetProcAddress(GfxDll, "PluginShutdown"), typeof(PluginShutdown));
|
2013-04-30 00:36:54 +00:00
|
|
|
|
GFXReadScreen2 = (ReadScreen2)Marshal.GetDelegateForFunctionPointer(GetProcAddress(GfxDll, "ReadScreen2"), typeof(ReadScreen2));
|
2013-04-30 00:08:21 +00:00
|
|
|
|
|
2013-04-30 03:24:44 +00:00
|
|
|
|
AudPluginStartup = (PluginStartup)Marshal.GetDelegateForFunctionPointer(GetProcAddress(AudDll, "PluginStartup"), typeof(PluginStartup));
|
2013-05-01 22:18:53 +00:00
|
|
|
|
AudPluginShutdown = (PluginShutdown)Marshal.GetDelegateForFunctionPointer(GetProcAddress(AudDll, "PluginShutdown"), typeof(PluginShutdown));
|
2013-04-30 03:24:44 +00:00
|
|
|
|
AudGetBufferSize = (GetBufferSize)Marshal.GetDelegateForFunctionPointer(GetProcAddress(AudDll, "GetBufferSize"), typeof(GetBufferSize));
|
|
|
|
|
AudReadAudioBuffer = (ReadAudioBuffer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(AudDll, "ReadAudioBuffer"), typeof(ReadAudioBuffer));
|
2013-05-01 21:28:15 +00:00
|
|
|
|
AudGetAudioRate = (GetAudioRate)Marshal.GetDelegateForFunctionPointer(GetProcAddress(AudDll, "GetAudioRate"), typeof(GetAudioRate));
|
2013-04-30 03:24:44 +00:00
|
|
|
|
|
2013-05-02 03:38:57 +00:00
|
|
|
|
InpPluginStartup = (PluginStartup)Marshal.GetDelegateForFunctionPointer(GetProcAddress(InpDll, "PluginStartup"), typeof(PluginStartup));
|
|
|
|
|
InpPluginShutdown = (PluginShutdown)Marshal.GetDelegateForFunctionPointer(GetProcAddress(InpDll, "PluginShutdown"), typeof(PluginShutdown));
|
|
|
|
|
InpSetKeys = (SetKeys)Marshal.GetDelegateForFunctionPointer(GetProcAddress(InpDll, "SetKeys"), typeof(SetKeys));
|
|
|
|
|
|
2013-04-30 00:08:21 +00:00
|
|
|
|
RspPluginStartup = (PluginStartup)Marshal.GetDelegateForFunctionPointer(GetProcAddress(RspDll, "PluginStartup"), typeof(PluginStartup));
|
2013-05-01 22:18:53 +00:00
|
|
|
|
RspPluginShutdown = (PluginShutdown)Marshal.GetDelegateForFunctionPointer(GetProcAddress(RspDll, "PluginShutdown"), typeof(PluginShutdown));
|
2013-04-30 00:08:21 +00:00
|
|
|
|
|
|
|
|
|
// Set up the core
|
2013-05-02 00:33:44 +00:00
|
|
|
|
m64p_error result = m64pCoreStartup(0x20001, "", "", "Core", (IntPtr foo, int level, string Message) => { }, "", IntPtr.Zero);
|
2013-04-30 00:08:21 +00:00
|
|
|
|
result = m64pCoreDoCommandByteArray(m64p_command.M64CMD_ROM_OPEN, rom.Length, rom);
|
|
|
|
|
|
|
|
|
|
// Set up and connect the graphics plugin
|
2013-05-02 00:33:44 +00:00
|
|
|
|
result = GfxPluginStartup(CoreDll, "Video", (IntPtr foo, int level, string Message) => { });
|
2013-04-30 00:08:21 +00:00
|
|
|
|
result = m64pCoreAttachPlugin(m64p_plugin_type.M64PLUGIN_GFX, GfxDll);
|
|
|
|
|
|
|
|
|
|
// Set up a null audio plugin
|
2013-05-02 00:33:44 +00:00
|
|
|
|
result = AudPluginStartup(CoreDll, "Audio", (IntPtr foo, int level, string Message) => { });
|
2013-04-30 03:24:44 +00:00
|
|
|
|
result = m64pCoreAttachPlugin(m64p_plugin_type.M64PLUGIN_AUDIO, AudDll);
|
2013-04-30 00:08:21 +00:00
|
|
|
|
|
|
|
|
|
// Set up a null input plugin
|
2013-05-02 03:38:57 +00:00
|
|
|
|
result = AudPluginStartup(CoreDll, "Input", (IntPtr foo, int level, string Message) => { });
|
|
|
|
|
result = m64pCoreAttachPlugin(m64p_plugin_type.M64PLUGIN_INPUT, InpDll);
|
2013-04-30 00:08:21 +00:00
|
|
|
|
|
|
|
|
|
// Set up and connect the graphics plugin
|
2013-05-02 00:33:44 +00:00
|
|
|
|
result = RspPluginStartup(CoreDll, "RSP", (IntPtr foo, int level, string Message) => { });
|
2013-04-30 00:08:21 +00:00
|
|
|
|
result = m64pCoreAttachPlugin(m64p_plugin_type.M64PLUGIN_RSP, RspDll);
|
|
|
|
|
|
2013-04-30 00:36:54 +00:00
|
|
|
|
// Set up the frame callback function
|
|
|
|
|
m64pFrameCallback = new FrameCallback(Getm64pFrameBuffer);
|
|
|
|
|
result = m64pCoreDoCommandFrameCallback(m64p_command.M64CMD_SET_FRAME_CALLBACK, 0, m64pFrameCallback);
|
|
|
|
|
|
2013-04-30 01:50:27 +00:00
|
|
|
|
// Set up the vi callback function
|
|
|
|
|
m64pVICallback = new VICallback(FrameComplete);
|
|
|
|
|
result = m64pCoreDoCommandVICallback(m64p_command.M64CMD_SET_VI_CALLBACK, 0, m64pVICallback);
|
|
|
|
|
|
2013-04-30 00:08:21 +00:00
|
|
|
|
m64pEmulator = new Thread(ExecuteEmulator);
|
|
|
|
|
m64pEmulator.Start();
|
2013-04-30 01:14:07 +00:00
|
|
|
|
|
|
|
|
|
int state = -1;
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
m64pCoreDoCommandRefInt(m64p_command.M64CMD_CORE_STATE_QUERY, 1, ref state);
|
|
|
|
|
} while (state != (int)m64p_emu_state.M64EMU_PAUSED);
|
2013-05-01 14:38:47 +00:00
|
|
|
|
|
2013-05-02 00:33:44 +00:00
|
|
|
|
|
2013-05-01 22:26:08 +00:00
|
|
|
|
m64pSamplingRate = (uint)AudGetAudioRate();
|
|
|
|
|
resampler = new Sound.Utilities.SpeexResampler(6, m64pSamplingRate, 44100, m64pSamplingRate, 44100, null, null);
|
2013-05-02 00:33:44 +00:00
|
|
|
|
//Console.WriteLine("N64 Initial ARate {0}", m64pSamplingRate);
|
|
|
|
|
|
|
|
|
|
//resampler = new Sound.Utilities.SpeexResampler(6, 32000, 44100, 32000, 44100, null, null);
|
2013-05-01 22:18:53 +00:00
|
|
|
|
AttachedCore = this;
|
2013-04-30 00:08:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-05-01 22:32:31 +00:00
|
|
|
|
volatile bool emulator_running = false;
|
2013-04-30 00:08:21 +00:00
|
|
|
|
public void ExecuteEmulator()
|
|
|
|
|
{
|
2013-05-01 22:32:31 +00:00
|
|
|
|
emulator_running = true;
|
2013-04-30 00:08:21 +00:00
|
|
|
|
m64pCoreDoCommandPtr(m64p_command.M64CMD_EXECUTE, 0, IntPtr.Zero);
|
2013-05-01 22:32:31 +00:00
|
|
|
|
emulator_running = false;
|
2013-04-29 01:57:41 +00:00
|
|
|
|
}
|
2013-05-01 14:38:47 +00:00
|
|
|
|
|
|
|
|
|
|
2013-04-29 01:57:41 +00:00
|
|
|
|
}
|
|
|
|
|
}
|