nothing to see here for now
This commit is contained in:
parent
5fa18dbb3e
commit
54b9c826cf
|
@ -212,7 +212,9 @@ namespace BizHawk.Emulation.Common
|
|||
{
|
||||
IsLagFrame = true;
|
||||
Frame++;
|
||||
nsamprecv = 0;
|
||||
retro.retro_run();
|
||||
Console.WriteLine("[{0}]", nsamprecv);
|
||||
}
|
||||
|
||||
public int Frame { get; private set; }
|
||||
|
@ -406,8 +408,13 @@ namespace BizHawk.Emulation.Common
|
|||
|
||||
short[] sampbuff = new short[0];
|
||||
|
||||
// debug
|
||||
int nsamprecv = 0;
|
||||
|
||||
void SetupResampler(double fps, double sps)
|
||||
{
|
||||
Console.WriteLine("FPS {0} SPS {1}", fps, sps);
|
||||
|
||||
// todo: more precise?
|
||||
uint spsnum = (uint)sps * 1000;
|
||||
uint spsden = (uint)1000;
|
||||
|
@ -418,6 +425,7 @@ namespace BizHawk.Emulation.Common
|
|||
void retro_audio_sample(short left, short right)
|
||||
{
|
||||
resampler.EnqueueSample(left, right);
|
||||
nsamprecv++;
|
||||
}
|
||||
|
||||
uint retro_audio_sample_batch(IntPtr data, uint frames)
|
||||
|
@ -426,6 +434,7 @@ namespace BizHawk.Emulation.Common
|
|||
sampbuff = new short[frames * 2];
|
||||
Marshal.Copy(data, sampbuff, 0, (int)(frames * 2));
|
||||
resampler.EnqueueSamples(sampbuff, (int)frames);
|
||||
nsamprecv += (int)frames;
|
||||
// what is the return from this used for?
|
||||
return frames;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,184 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES
|
||||
{
|
||||
public static class LibQuickNES
|
||||
{
|
||||
public const string dllname = "libquicknes.dll";
|
||||
|
||||
/// <summary>
|
||||
/// create a new quicknes context
|
||||
/// </summary>
|
||||
/// <returns>NULL on failure</returns>
|
||||
[DllImport(dllname, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern IntPtr qn_new();
|
||||
/// <summary>
|
||||
/// destroy a quicknes context
|
||||
/// </summary>
|
||||
/// <param name="e">context previously returned from qn_new()</param>
|
||||
[DllImport(dllname, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void qn_delete(IntPtr e);
|
||||
/// <summary>
|
||||
/// load an ines file
|
||||
/// </summary>
|
||||
/// <param name="e">context</param>
|
||||
/// <param name="data">file</param>
|
||||
/// <param name="length">length of file</param>
|
||||
/// <returns></returns>
|
||||
[DllImport(dllname, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern IntPtr qn_loadines(IntPtr e, byte[] data, int length);
|
||||
/// <summary>
|
||||
/// set audio sample rate
|
||||
/// </summary>
|
||||
/// <param name="e">context</param>
|
||||
/// <param name="rate">hz</param>
|
||||
/// <returns>string error</returns>
|
||||
[DllImport(dllname, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern IntPtr qn_set_sample_rate(IntPtr e, int rate);
|
||||
/// <summary>
|
||||
/// get required min dimensions of output video buffer (8bpp)
|
||||
/// </summary>
|
||||
/// <param name="e">context</param>
|
||||
/// <param name="width">width</param>
|
||||
/// <param name="height">height</param>
|
||||
[DllImport(dllname, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void qn_get_image_dimensions(IntPtr e, ref int width, ref int height);
|
||||
/// <summary>
|
||||
/// set output video buffer that will be used for all subsequent renders until replaced
|
||||
/// </summary>
|
||||
/// <param name="e">context</param>
|
||||
/// <param name="dest">8bpp, at least as big as qn_get_image_dimensions()</param>
|
||||
/// <param name="pitch">byte pitch</param>
|
||||
[DllImport(dllname, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void qn_set_pixels(IntPtr e, byte[] dest, int pitch);
|
||||
/// <summary>
|
||||
/// emulate a single frame
|
||||
/// </summary>
|
||||
/// <param name="e">context</param>
|
||||
/// <param name="pad1">pad 1 input</param>
|
||||
/// <param name="pad2">pad 2 input</param>
|
||||
/// <returns>string error</returns>
|
||||
[DllImport(dllname, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern IntPtr qn_emulate_frame(IntPtr e, int pad1, int pad2);
|
||||
/// <summary>
|
||||
/// get number of times joypad was read in most recent frame
|
||||
/// </summary>
|
||||
/// <param name="e">context</param>
|
||||
/// <returns>0 means lag</returns>
|
||||
[DllImport(dllname, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int qn_get_joypad_read_count(IntPtr e);
|
||||
/// <summary>
|
||||
/// get audio info for most recent frame
|
||||
/// </summary>
|
||||
/// <param name="e">context</param>
|
||||
/// <param name="sample_count">number of samples actually created</param>
|
||||
/// <param name="chan_count">1 for mono, 2 for stereo</param>
|
||||
[DllImport(dllname, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void qn_get_audio_info(IntPtr e, ref int sample_count, ref int chan_count);
|
||||
/// <summary>
|
||||
/// get audio for most recent frame. must not be called more than once per frame!
|
||||
/// </summary>
|
||||
/// <param name="e">context</param>
|
||||
/// <param name="dest">sample buffer</param>
|
||||
/// <param name="max_samples">length to read into sample buffer</param>
|
||||
/// <returns>length actually read</returns>
|
||||
[DllImport(dllname, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int qn_read_audio(IntPtr e, short[] dest, int max_samples);
|
||||
/// <summary>
|
||||
/// reset the console
|
||||
/// </summary>
|
||||
/// <param name="e">context</param>
|
||||
/// <param name="hard">true for powercycle, false for reset button</param>
|
||||
[DllImport(dllname, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void qn_reset(IntPtr e, bool hard);
|
||||
/// <summary>
|
||||
/// get the required byte size of a savestate
|
||||
/// </summary>
|
||||
/// <param name="e">context</param>
|
||||
/// <param name="size">size is returned</param>
|
||||
/// <returns>string error</returns>
|
||||
[DllImport(dllname, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern IntPtr qn_state_size(IntPtr e, ref int size);
|
||||
/// <summary>
|
||||
/// save state to buffer
|
||||
/// </summary>
|
||||
/// <param name="e">context</param>
|
||||
/// <param name="dest">buffer</param>
|
||||
/// <param name="size">length of buffer</param>
|
||||
/// <returns>string error</returns>
|
||||
[DllImport(dllname, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern IntPtr qn_state_save(IntPtr e, byte[] dest, int size);
|
||||
/// <summary>
|
||||
/// load state from buffer
|
||||
/// </summary>
|
||||
/// <param name="e">context</param>
|
||||
/// <param name="src">buffer</param>
|
||||
/// <param name="size">length of buffer</param>
|
||||
/// <returns>string error</returns>
|
||||
[DllImport(dllname, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern IntPtr qn_state_load(IntPtr e, byte[] src, int size);
|
||||
/// <summary>
|
||||
/// query battery ram state
|
||||
/// </summary>
|
||||
/// <param name="e">context</param>
|
||||
/// <returns>true if battery backup sram exists</returns>
|
||||
[DllImport(dllname, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern bool qn_has_battery_ram(IntPtr e);
|
||||
/// <summary>
|
||||
/// query battery ram size
|
||||
/// </summary>
|
||||
/// <param name="e">context</param>
|
||||
/// <param name="size">size is returned</param>
|
||||
/// <returns>string error</returns>
|
||||
[DllImport(dllname, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern IntPtr qn_battery_ram_size(IntPtr e, ref int size);
|
||||
/// <summary>
|
||||
/// save battery ram to buffer
|
||||
/// </summary>
|
||||
/// <param name="e">context</param>
|
||||
/// <param name="dest">buffer</param>
|
||||
/// <param name="size">size</param>
|
||||
/// <returns>string error</returns>
|
||||
[DllImport(dllname, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern IntPtr qn_battery_ram_save(IntPtr e, byte[] dest, int size);
|
||||
/// <summary>
|
||||
/// load battery ram from buffer
|
||||
/// </summary>
|
||||
/// <param name="e">context</param>
|
||||
/// <param name="src">buffer</param>
|
||||
/// <param name="size">size</param>
|
||||
/// <returns>string error</returns>
|
||||
[DllImport(dllname, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern IntPtr qn_battery_ram_load(IntPtr e, byte[] src, int size);
|
||||
/// <summary>
|
||||
/// clear battery ram
|
||||
/// </summary>
|
||||
/// <param name="e">context</param>
|
||||
/// <returns>string error</returns>
|
||||
[DllImport(dllname, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern IntPtr qn_battery_ram_clear(IntPtr e);
|
||||
/// <summary>
|
||||
/// set sprite limit; does not affect emulation
|
||||
/// </summary>
|
||||
/// <param name="e">context</param>
|
||||
/// <param name="n">0 to hide, 8 for normal, 64 for all</param>
|
||||
[DllImport(dllname, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void qn_set_sprite_limit(IntPtr e, int n);
|
||||
|
||||
/// <summary>
|
||||
/// handle "string error" as returned by some quicknes functions
|
||||
/// </summary>
|
||||
/// <param name="p"></param>
|
||||
public static void ThrowStringError(IntPtr p)
|
||||
{
|
||||
if (p == IntPtr.Zero)
|
||||
return;
|
||||
string s = Marshal.PtrToStringAnsi(p);
|
||||
throw new InvalidOperationException("LibQuickNES error: " + s);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,162 @@
|
|||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include "nes_emu/Nes_Emu.h"
|
||||
|
||||
// simulate the write so we'll know how long the buffer needs to be
|
||||
class Sim_Writer : public Data_Writer
|
||||
{
|
||||
long size_;
|
||||
public:
|
||||
Sim_Writer():size_(0) { }
|
||||
error_t write(const void *, long size)
|
||||
{
|
||||
size_ += size;
|
||||
return 0;
|
||||
}
|
||||
long size() const { return size_; }
|
||||
};
|
||||
|
||||
|
||||
#define EXPORT extern "C" __declspec(dllexport)
|
||||
|
||||
EXPORT Nes_Emu *qn_new()
|
||||
{
|
||||
return new Nes_Emu();
|
||||
}
|
||||
|
||||
EXPORT void qn_delete(Nes_Emu *e)
|
||||
{
|
||||
delete e;
|
||||
}
|
||||
|
||||
EXPORT const char *qn_loadines(Nes_Emu *e, const void *data, int length)
|
||||
{
|
||||
Mem_File_Reader r = Mem_File_Reader(data, length);
|
||||
Auto_File_Reader a = Auto_File_Reader(r);
|
||||
return e->load_ines(a);
|
||||
}
|
||||
|
||||
EXPORT const char *qn_set_sample_rate(Nes_Emu *e, int rate)
|
||||
{
|
||||
return e->set_sample_rate(rate);
|
||||
}
|
||||
|
||||
EXPORT void qn_get_image_dimensions(Nes_Emu *e, int *width, int *height)
|
||||
{
|
||||
if (width)
|
||||
*width = e->buffer_width;
|
||||
if (height)
|
||||
*height = e->buffer_height();
|
||||
}
|
||||
|
||||
EXPORT void qn_set_pixels(Nes_Emu *e, void *dest, int pitch)
|
||||
{
|
||||
e->set_pixels(dest, pitch);
|
||||
}
|
||||
|
||||
EXPORT const char *qn_emulate_frame(Nes_Emu *e, int pad1, int pad2)
|
||||
{
|
||||
return e->emulate_frame(pad1, pad2);
|
||||
}
|
||||
|
||||
EXPORT int qn_get_joypad_read_count(Nes_Emu *e)
|
||||
{
|
||||
return e->frame().joypad_read_count;
|
||||
}
|
||||
|
||||
EXPORT void qn_get_audio_info(Nes_Emu *e, int *sample_count, int *chan_count)
|
||||
{
|
||||
if (sample_count)
|
||||
*sample_count = e->frame().sample_count;
|
||||
if (chan_count)
|
||||
*chan_count = e->frame().chan_count;
|
||||
}
|
||||
|
||||
EXPORT int qn_read_audio(Nes_Emu *e, short *dest, int max_samples)
|
||||
{
|
||||
return e->read_samples(dest, max_samples);
|
||||
}
|
||||
|
||||
EXPORT void qn_reset(Nes_Emu *e, int hard)
|
||||
{
|
||||
e->reset(hard);
|
||||
}
|
||||
|
||||
EXPORT const char *qn_state_size(Nes_Emu *e, int *size)
|
||||
{
|
||||
Sim_Writer w = Sim_Writer();
|
||||
Auto_File_Writer a = Auto_File_Writer(w);
|
||||
const char *ret = e->save_state(a);
|
||||
if (size)
|
||||
*size = w.size();
|
||||
return ret;
|
||||
}
|
||||
|
||||
EXPORT const char *qn_state_save(Nes_Emu *e, void *dest, int size)
|
||||
{
|
||||
Mem_Writer w = Mem_Writer(dest, size, 0);
|
||||
Auto_File_Writer a = Auto_File_Writer(w);
|
||||
const char *ret = e->save_state(a);
|
||||
if (!ret && w.size() != size)
|
||||
return "Buffer Underrun!";
|
||||
return ret;
|
||||
}
|
||||
|
||||
EXPORT const char *qn_state_load(Nes_Emu *e, const void *src, int size)
|
||||
{
|
||||
Mem_File_Reader r = Mem_File_Reader(src, size);
|
||||
Auto_File_Reader a = Auto_File_Reader(r);
|
||||
return e->load_state(a);
|
||||
}
|
||||
|
||||
EXPORT int qn_has_battery_ram(Nes_Emu *e)
|
||||
{
|
||||
return e->has_battery_ram();
|
||||
}
|
||||
|
||||
EXPORT const char *qn_battery_ram_size(Nes_Emu *e, int *size)
|
||||
{
|
||||
Sim_Writer w = Sim_Writer();
|
||||
Auto_File_Writer a = Auto_File_Writer(w);
|
||||
const char *ret = e->save_battery_ram(a);
|
||||
if (size)
|
||||
*size = w.size();
|
||||
return ret;
|
||||
}
|
||||
|
||||
EXPORT const char *qn_battery_ram_save(Nes_Emu *e, void *dest, int size)
|
||||
{
|
||||
Mem_Writer w = Mem_Writer(dest, size, 0);
|
||||
Auto_File_Writer a = Auto_File_Writer(w);
|
||||
const char *ret = e->save_battery_ram(a);
|
||||
if (!ret && w.size() != size)
|
||||
return "Buffer Underrun!";
|
||||
return ret;
|
||||
}
|
||||
|
||||
EXPORT const char *qn_battery_ram_load(Nes_Emu *e, const void *src, int size)
|
||||
{
|
||||
Mem_File_Reader r = Mem_File_Reader(src, size);
|
||||
Auto_File_Reader a = Auto_File_Reader(r);
|
||||
return e->load_battery_ram(a);
|
||||
}
|
||||
|
||||
EXPORT const char *qn_battery_ram_clear(Nes_Emu *e)
|
||||
{
|
||||
int size = 0;
|
||||
const char *ret = qn_battery_ram_size(e, &size);
|
||||
if (ret)
|
||||
return ret;
|
||||
void *data = std::malloc(size);
|
||||
if (!data)
|
||||
return "Out of Memory!";
|
||||
std::memset(data, 0xff, size);
|
||||
ret = qn_battery_ram_load(e, data, size);
|
||||
std::free(data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
EXPORT void qn_set_sprite_limit(Nes_Emu *e, int n)
|
||||
{
|
||||
e->set_sprite_mode((Nes_Emu::sprite_mode_t)n);
|
||||
}
|
|
@ -11,6 +11,7 @@
|
|||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\bizinterface.cpp" />
|
||||
<ClCompile Include="..\fex\blargg_common.cpp" />
|
||||
<ClCompile Include="..\fex\blargg_errors.cpp" />
|
||||
<ClCompile Include="..\fex\Data_Reader.cpp" />
|
||||
|
@ -85,7 +86,7 @@
|
|||
<Optimization>Disabled</Optimization>
|
||||
<DisableSpecificWarnings>4244;4800;4804;4996</DisableSpecificWarnings>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)\..</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_WINDLL;%(PreprocessorDefinitions);DLLEXPORT=__declspec(dllexport)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>_WINDLL;%(PreprocessorDefinitions);DISABLE_AUTO_FILE</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
|
@ -102,7 +103,7 @@
|
|||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<DisableSpecificWarnings>4244;4800;4804;4996</DisableSpecificWarnings>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)\..</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_WINDLL;%(PreprocessorDefinitions);DLLEXPORT=__declspec(dllexport)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>_WINDLL;%(PreprocessorDefinitions);DISABLE_AUTO_FILE</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
|
|
|
@ -144,5 +144,8 @@
|
|||
<ClCompile Include="..\fex\Data_Reader.cpp">
|
||||
<Filter>Source Files\fex</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\bizinterface.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
Loading…
Reference in New Issue