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:
goyuken 2014-01-06 19:31:13 +00:00
parent 4ba9f332f5
commit 59ffca28ba
4 changed files with 148 additions and 47 deletions

View File

@ -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.

View File

@ -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);
}

65
quicknes/mingw/Makefile Normal file
View File

@ -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