fix "the sound bug" in quicknes. dll is now built with mingw and FPU precision is set high (both are required to fix)
This commit is contained in:
parent
4ba9f332f5
commit
59ffca28ba
|
@ -9,6 +9,33 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES
|
|||
{
|
||||
public class QuickNES : IEmulator, IVideoProvider, ISyncSoundProvider
|
||||
{
|
||||
private class FPCtrl : IDisposable
|
||||
{
|
||||
[DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern uint _control87(uint @new, uint mask);
|
||||
|
||||
public static void PrintCurrentFP()
|
||||
{
|
||||
uint curr = _control87(0, 0);
|
||||
Console.WriteLine("Current FP word: 0x{0:x8}", curr);
|
||||
}
|
||||
|
||||
uint cw;
|
||||
|
||||
public IDisposable Save()
|
||||
{
|
||||
cw = _control87(0, 0);
|
||||
_control87(0x00000, 0x30000);
|
||||
return this;
|
||||
}
|
||||
public void Dispose()
|
||||
{
|
||||
_control87(cw, 0x30000);
|
||||
}
|
||||
}
|
||||
|
||||
FPCtrl FP = new FPCtrl();
|
||||
|
||||
static QuickNES()
|
||||
{
|
||||
LibQuickNES.qn_setup_mappers();
|
||||
|
@ -16,24 +43,27 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES
|
|||
|
||||
public QuickNES(CoreComm nextComm, byte[] Rom)
|
||||
{
|
||||
CoreComm = nextComm;
|
||||
|
||||
Context = LibQuickNES.qn_new();
|
||||
if (Context == IntPtr.Zero)
|
||||
throw new InvalidOperationException("qn_new() returned NULL");
|
||||
try
|
||||
using (FP.Save())
|
||||
{
|
||||
LibQuickNES.ThrowStringError(LibQuickNES.qn_loadines(Context, Rom, Rom.Length));
|
||||
CoreComm = nextComm;
|
||||
|
||||
InitSaveRamBuff();
|
||||
InitSaveStateBuff();
|
||||
InitVideo();
|
||||
InitAudio();
|
||||
}
|
||||
catch
|
||||
{
|
||||
Dispose();
|
||||
throw;
|
||||
Context = LibQuickNES.qn_new();
|
||||
if (Context == IntPtr.Zero)
|
||||
throw new InvalidOperationException("qn_new() returned NULL");
|
||||
try
|
||||
{
|
||||
LibQuickNES.ThrowStringError(LibQuickNES.qn_loadines(Context, Rom, Rom.Length));
|
||||
|
||||
InitSaveRamBuff();
|
||||
InitSaveStateBuff();
|
||||
InitVideo();
|
||||
InitAudio();
|
||||
}
|
||||
catch
|
||||
{
|
||||
Dispose();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -84,22 +114,25 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES
|
|||
|
||||
public void FrameAdvance(bool render, bool rendersound = true)
|
||||
{
|
||||
if (Controller["Power"])
|
||||
LibQuickNES.qn_reset(Context, true);
|
||||
if (Controller["Reset"])
|
||||
LibQuickNES.qn_reset(Context, false);
|
||||
using (FP.Save())
|
||||
{
|
||||
if (Controller["Power"])
|
||||
LibQuickNES.qn_reset(Context, true);
|
||||
if (Controller["Reset"])
|
||||
LibQuickNES.qn_reset(Context, false);
|
||||
|
||||
int j1, j2;
|
||||
SetPads(out j1, out j2);
|
||||
int j1, j2;
|
||||
SetPads(out j1, out j2);
|
||||
|
||||
Frame++;
|
||||
LibQuickNES.ThrowStringError(LibQuickNES.qn_emulate_frame(Context, j1, j2));
|
||||
IsLagFrame = LibQuickNES.qn_get_joypad_read_count(Context) == 0;
|
||||
if (IsLagFrame)
|
||||
LagCount++;
|
||||
Frame++;
|
||||
LibQuickNES.ThrowStringError(LibQuickNES.qn_emulate_frame(Context, j1, j2));
|
||||
IsLagFrame = LibQuickNES.qn_get_joypad_read_count(Context) == 0;
|
||||
if (IsLagFrame)
|
||||
LagCount++;
|
||||
|
||||
Blit();
|
||||
DrainAudio();
|
||||
Blit();
|
||||
DrainAudio();
|
||||
}
|
||||
}
|
||||
|
||||
#region state
|
||||
|
@ -332,7 +365,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES
|
|||
|
||||
void DrainAudio()
|
||||
{
|
||||
NumSamples = LibQuickNES.qn_read_audio(Context, MonoBuff, 1024);
|
||||
NumSamples = LibQuickNES.qn_read_audio(Context, MonoBuff, MonoBuff.Length);
|
||||
unsafe
|
||||
{
|
||||
fixed (short *_src = &MonoBuff[0], _dst = &StereoBuff[0])
|
||||
|
|
Binary file not shown.
|
@ -36,14 +36,17 @@ EXPORT void qn_delete(Nes_Emu *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);
|
||||
Mem_File_Reader r(data, length);
|
||||
Auto_File_Reader a(r);
|
||||
return e->load_ines(a);
|
||||
}
|
||||
|
||||
EXPORT const char *qn_set_sample_rate(Nes_Emu *e, int rate)
|
||||
{
|
||||
return e->set_sample_rate(rate);
|
||||
const char *ret = e->set_sample_rate(rate);
|
||||
if (!ret)
|
||||
e->set_equalizer(Nes_Emu::nes_eq);
|
||||
return ret;
|
||||
}
|
||||
|
||||
EXPORT void qn_get_image_dimensions(Nes_Emu *e, int *width, int *height)
|
||||
|
@ -69,9 +72,9 @@ EXPORT void qn_blit(Nes_Emu *e, char *dest)
|
|||
// what is the point of the 256 color bitmap and the dynamic color allocation to it?
|
||||
// why not just render directly to a 512 color bitmap with static palette positions?
|
||||
|
||||
const char *src = (const char *)e->frame().pixels;
|
||||
const unsigned char *src = e->frame().pixels;
|
||||
const int srcpitch = e->frame().pitch;
|
||||
const char *srcend = src + e->image_height * srcpitch;
|
||||
const unsigned char *srcend = src + e->image_height * srcpitch;
|
||||
|
||||
const short *lut = e->frame().palette;
|
||||
const Nes_Emu::rgb_t *colors = e->nes_colors;
|
||||
|
@ -114,8 +117,8 @@ EXPORT void qn_reset(Nes_Emu *e, int 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);
|
||||
Sim_Writer w;
|
||||
Auto_File_Writer a(w);
|
||||
const char *ret = e->save_state(a);
|
||||
if (size)
|
||||
*size = w.size();
|
||||
|
@ -124,8 +127,8 @@ EXPORT const char *qn_state_size(Nes_Emu *e, int *size)
|
|||
|
||||
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);
|
||||
Mem_Writer w(dest, size, 0);
|
||||
Auto_File_Writer a(w);
|
||||
const char *ret = e->save_state(a);
|
||||
if (!ret && w.size() != size)
|
||||
return "Buffer Underrun!";
|
||||
|
@ -134,8 +137,8 @@ EXPORT const char *qn_state_save(Nes_Emu *e, void *dest, int size)
|
|||
|
||||
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);
|
||||
Mem_File_Reader r(src, size);
|
||||
Auto_File_Reader a(r);
|
||||
return e->load_state(a);
|
||||
}
|
||||
|
||||
|
@ -146,8 +149,8 @@ EXPORT int qn_has_battery_ram(Nes_Emu *e)
|
|||
|
||||
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);
|
||||
Sim_Writer w;
|
||||
Auto_File_Writer a(w);
|
||||
const char *ret = e->save_battery_ram(a);
|
||||
if (size)
|
||||
*size = w.size();
|
||||
|
@ -156,8 +159,8 @@ EXPORT const char *qn_battery_ram_size(Nes_Emu *e, int *size)
|
|||
|
||||
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);
|
||||
Mem_Writer w(dest, size, 0);
|
||||
Auto_File_Writer a(w);
|
||||
const char *ret = e->save_battery_ram(a);
|
||||
if (!ret && w.size() != size)
|
||||
return "Buffer Underrun!";
|
||||
|
@ -166,8 +169,8 @@ EXPORT const char *qn_battery_ram_save(Nes_Emu *e, void *dest, int size)
|
|||
|
||||
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);
|
||||
Mem_File_Reader r(src, size);
|
||||
Auto_File_Reader a(r);
|
||||
return e->load_battery_ram(a);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
CXX = g++
|
||||
CXXFLAGS = -Wall -DDISABLE_AUTO_FILE -D__LIBRETRO__ -I.. -Wno-multichar -O3
|
||||
TARGET = libquicknes.dll
|
||||
LDFLAGS = -shared -static-libgcc -static-libstdc++
|
||||
RM = rm
|
||||
CP = cp
|
||||
|
||||
SRCS = \
|
||||
../nes_emu/abstract_file.cpp \
|
||||
../nes_emu/apu_state.cpp \
|
||||
../nes_emu/Blip_Buffer.cpp \
|
||||
../nes_emu/Effects_Buffer.cpp \
|
||||
../nes_emu/Mapper_Fme7.cpp \
|
||||
../nes_emu/Mapper_Mmc5.cpp \
|
||||
../nes_emu/Mapper_Namco106.cpp \
|
||||
../nes_emu/Mapper_Vrc6.cpp \
|
||||
../nes_emu/misc_mappers.cpp \
|
||||
../nes_emu/Multi_Buffer.cpp \
|
||||
../nes_emu/Nes_Apu.cpp \
|
||||
../nes_emu/Nes_Buffer.cpp \
|
||||
../nes_emu/Nes_Cart.cpp \
|
||||
../nes_emu/Nes_Core.cpp \
|
||||
../nes_emu/Nes_Cpu.cpp \
|
||||
../nes_emu/nes_data.cpp \
|
||||
../nes_emu/Nes_Effects_Buffer.cpp \
|
||||
../nes_emu/Nes_Emu.cpp \
|
||||
../nes_emu/Nes_File.cpp \
|
||||
../nes_emu/Nes_Film.cpp \
|
||||
../nes_emu/Nes_Film_Data.cpp \
|
||||
../nes_emu/Nes_Film_Packer.cpp \
|
||||
../nes_emu/Nes_Fme7_Apu.cpp \
|
||||
../nes_emu/Nes_Mapper.cpp \
|
||||
../nes_emu/nes_mappers.cpp \
|
||||
../nes_emu/Nes_Mmc1.cpp \
|
||||
../nes_emu/Nes_Mmc3.cpp \
|
||||
../nes_emu/Nes_Namco_Apu.cpp \
|
||||
../nes_emu/Nes_Oscs.cpp \
|
||||
../nes_emu/Nes_Ppu.cpp \
|
||||
../nes_emu/Nes_Ppu_Impl.cpp \
|
||||
../nes_emu/Nes_Ppu_Rendering.cpp \
|
||||
../nes_emu/Nes_Recorder.cpp \
|
||||
../nes_emu/Nes_State.cpp \
|
||||
../nes_emu/nes_util.cpp \
|
||||
../nes_emu/Nes_Vrc6_Apu.cpp \
|
||||
../bizinterface.cpp \
|
||||
../fex/Data_Reader.cpp \
|
||||
../fex/blargg_errors.cpp \
|
||||
../fex/blargg_common.cpp
|
||||
|
||||
OBJS = $(SRCS:.cpp=.o)
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
%.o: %.cpp
|
||||
$(CXX) -c -o $@ $< $(CXXFLAGS)
|
||||
|
||||
$(TARGET) : $(OBJS)
|
||||
$(CXX) -o $@ $(LDFLAGS) $(OBJS)
|
||||
|
||||
clean:
|
||||
$(RM) $(OBJS)
|
||||
$(RM) $(TARGET)
|
||||
|
||||
install:
|
||||
$(CP) $(TARGET) ../../output/dll
|
Loading…
Reference in New Issue