diff --git a/BizHawk.Emulation/Consoles/Nintendo/Gameboy/Gambatte.cs b/BizHawk.Emulation/Consoles/Nintendo/Gameboy/Gambatte.cs
index 686de8bb5c..632f6acd96 100644
--- a/BizHawk.Emulation/Consoles/Nintendo/Gameboy/Gambatte.cs
+++ b/BizHawk.Emulation/Consoles/Nintendo/Gameboy/Gambatte.cs
@@ -113,10 +113,8 @@ namespace BizHawk.Emulation.Consoles.GB
return (LibGambatte.gambatte_iscgb(GambatteState));
}
- public void FrameAdvance(bool render, bool rendersound)
+ internal void FrameAdvancePrep()
{
- uint nsamp = 35112; // according to gambatte docs, this is the nominal length of a frame in 2mhz clocks
-
Controller.UpdateControls(Frame++);
// update our local copy of the controller data
@@ -155,21 +153,14 @@ namespace BizHawk.Emulation.Consoles.GB
else
tracecb = null;
LibGambatte.gambatte_settracecallback(GambatteState, tracecb);
+ }
- LibGambatte.gambatte_runfor(GambatteState, VideoBuffer, 160, soundbuff, ref nsamp);
-
- //Console.WriteLine("===");
-
+ internal void FrameAdvancePost()
+ {
// upload any modified data to the memory domains
-
foreach (var r in MemoryRefreshers)
r.RefreshRead();
- if (rendersound)
- soundbuffcontains = (int)nsamp;
- else
- soundbuffcontains = 0;
-
if (IsLagFrame)
LagCount++;
@@ -177,6 +168,22 @@ namespace BizHawk.Emulation.Consoles.GB
endofframecallback(LibGambatte.gambatte_cpuread(GambatteState, 0xff40));
}
+ public void FrameAdvance(bool render, bool rendersound)
+ {
+ FrameAdvancePrep();
+
+ uint nsamp = 35112; // according to gambatte docs, this is the nominal length of a frame in 2mhz clocks
+
+ LibGambatte.gambatte_runfor(GambatteState, VideoBuffer, 160, soundbuff, ref nsamp);
+
+ if (rendersound)
+ soundbuffcontains = (int)nsamp;
+ else
+ soundbuffcontains = 0;
+
+ FrameAdvancePost();
+ }
+
///
/// throw exception with intelligible message on some kinds of bad rom
///
@@ -720,11 +727,11 @@ namespace BizHawk.Emulation.Consoles.GB
///
/// sample pairs before resampling
///
- short[] soundbuff = new short[(35112 + 2064) * 2];
+ internal short[] soundbuff = new short[(35112 + 2064) * 2];
///
/// how many sample pairs are in soundbuff
///
- int soundbuffcontains = 0;
+ internal int soundbuffcontains = 0;
Sound.Utilities.SpeexResampler resampler;
Sound.Utilities.DCFilter dcfilter;
diff --git a/BizHawk.Emulation/Consoles/Nintendo/Gameboy/GambatteLink.cs b/BizHawk.Emulation/Consoles/Nintendo/Gameboy/GambatteLink.cs
index 2f614aee22..7e6a465d83 100644
--- a/BizHawk.Emulation/Consoles/Nintendo/Gameboy/GambatteLink.cs
+++ b/BizHawk.Emulation/Consoles/Nintendo/Gameboy/GambatteLink.cs
@@ -20,6 +20,10 @@ namespace BizHawk.Emulation.Consoles.GB
L = new Gameboy(new CoreComm(), leftinfo, leftrom);
R = new Gameboy(new CoreComm(), rightinfo, rightrom);
+ // connect link cable
+ LibGambatte.gambatte_linkstatus(L.GambatteState, 259);
+ LibGambatte.gambatte_linkstatus(R.GambatteState, 259);
+
L.Controller = LCont;
R.Controller = RCont;
@@ -72,12 +76,81 @@ namespace BizHawk.Emulation.Consoles.GB
}
Frame++;
- L.FrameAdvance(render, rendersound);
- R.FrameAdvance(render, rendersound);
+ L.FrameAdvancePrep();
+ R.FrameAdvancePrep();
+
+ unsafe
+ {
+ fixed (int* leftvbuff = &VideoBuffer[0])
+ {
+ int* rightvbuff = leftvbuff + 160;
+ const int pitch = 160 * 2;
+
+ fixed (short* leftsbuff = L.soundbuff, rightsbuff = R.soundbuff)
+ {
+
+ const int step = 32; // could be 1024 for GB
+
+ int nL = 0;
+ int nR = 0;
+
+ for (int target = step; target <= 35112; target += step)
+ {
+
+ if (nL < target)
+ {
+ uint nsamp = (uint)(target - nL);
+ LibGambatte.gambatte_runfor(L.GambatteState, leftvbuff, pitch, leftsbuff + nL * 2, ref nsamp);
+ nL += (int)nsamp;
+ }
+ if (nR < target)
+ {
+ uint nsamp = (uint)(target - nR);
+ LibGambatte.gambatte_runfor(R.GambatteState, rightvbuff, pitch, rightsbuff + nR * 2, ref nsamp);
+ nR += (int)nsamp;
+ }
+ // poll link cable statuses
+
+ if (LibGambatte.gambatte_linkstatus(L.GambatteState, 256) != 0) // ClockTrigger
+ {
+ LibGambatte.gambatte_linkstatus(L.GambatteState, 257); // ack
+ int lo = LibGambatte.gambatte_linkstatus(L.GambatteState, 258); // GetOut
+ int ro = LibGambatte.gambatte_linkstatus(R.GambatteState, 258);
+ LibGambatte.gambatte_linkstatus(L.GambatteState, ro & 0xff); // ShiftIn
+ LibGambatte.gambatte_linkstatus(R.GambatteState, lo & 0xff); // ShiftIn
+ }
+ if (LibGambatte.gambatte_linkstatus(R.GambatteState, 256) != 0) // ClockTrigger
+ {
+ LibGambatte.gambatte_linkstatus(R.GambatteState, 257); // ack
+ int lo = LibGambatte.gambatte_linkstatus(L.GambatteState, 258); // GetOut
+ int ro = LibGambatte.gambatte_linkstatus(R.GambatteState, 258);
+ LibGambatte.gambatte_linkstatus(L.GambatteState, ro & 0xff); // ShiftIn
+ LibGambatte.gambatte_linkstatus(R.GambatteState, lo & 0xff); // ShiftIn
+ }
+
+ }
+
+ if (rendersound)
+ {
+ L.soundbuffcontains = nL;
+ R.soundbuffcontains = nR;
+ }
+ else
+ {
+ L.soundbuffcontains = 0;
+ R.soundbuffcontains = 0;
+ }
+
+ }
+
+ }
+ }
+
+ L.FrameAdvancePost();
+ R.FrameAdvancePost();
IsLagFrame = L.IsLagFrame && R.IsLagFrame;
if (IsLagFrame)
LagCount++;
- BlitFrameBuffer();
}
public int Frame { get; private set; }
@@ -217,21 +290,6 @@ namespace BizHawk.Emulation.Consoles.GB
public int BufferHeight { get { return 144; } }
public int BackgroundColor { get { return unchecked((int)0xff000000); } }
- void BlitFrameBuffer()
- {
- var lb = L.GetVideoBuffer();
- var rb = R.GetVideoBuffer();
- int destpos = 0;
- for (int y = 0; y < 144; y++)
- {
- Buffer.BlockCopy(lb, 160 * 4 * y, VideoBuffer, destpos, 160 * 4);
- destpos += 160 * 4;
- Buffer.BlockCopy(rb, 160 * 4 * y, VideoBuffer, destpos, 160 * 4);
- destpos += 160 * 4;
- }
- }
-
-
public void GetSamples(out short[] samples, out int nsamp)
{
// TODO
diff --git a/BizHawk.Emulation/Consoles/Nintendo/Gameboy/LibGambatte.cs b/BizHawk.Emulation/Consoles/Nintendo/Gameboy/LibGambatte.cs
index f0d5073b4a..bb6f304eea 100644
--- a/BizHawk.Emulation/Consoles/Nintendo/Gameboy/LibGambatte.cs
+++ b/BizHawk.Emulation/Consoles/Nintendo/Gameboy/LibGambatte.cs
@@ -69,6 +69,8 @@ namespace BizHawk.Emulation.Consoles.GB
/// sample number at which the video frame was produced. -1 means no frame was produced.
[DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int gambatte_runfor(IntPtr core, int[] videobuf, int pitch, short[] soundbuf, ref uint samples);
+ [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)]
+ unsafe public static extern int gambatte_runfor(IntPtr core, int* videobuf, int pitch, short* soundbuf, ref uint samples);
///
/// Reset to initial state.
diff --git a/BizHawk.MultiClient/MainForm.cs b/BizHawk.MultiClient/MainForm.cs
index 8cd7968ef5..1ddc8d5811 100644
--- a/BizHawk.MultiClient/MainForm.cs
+++ b/BizHawk.MultiClient/MainForm.cs
@@ -2003,7 +2003,7 @@ namespace BizHawk.MultiClient
break;
case "GB":
case "GBC":
- if (false) // DEBUG
+ if (true) // DEBUG
{
if (Global.Config.GB_ForceDMG) game.AddOption("ForceDMG");
if (Global.Config.GB_GBACGB) game.AddOption("GBACGB");
diff --git a/BizHawk.MultiClient/output/dll/libgambatte.dll b/BizHawk.MultiClient/output/dll/libgambatte.dll
index 37504f64f0..72b7c33dd6 100644
Binary files a/BizHawk.MultiClient/output/dll/libgambatte.dll and b/BizHawk.MultiClient/output/dll/libgambatte.dll differ