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