diff --git a/BizHawk.Emulation.Common/Interfaces/Services/ISoundProvider.cs b/BizHawk.Emulation.Common/Interfaces/Services/ISoundProvider.cs
index 0cae9fb3ee..08fe412400 100644
--- a/BizHawk.Emulation.Common/Interfaces/Services/ISoundProvider.cs
+++ b/BizHawk.Emulation.Common/Interfaces/Services/ISoundProvider.cs
@@ -4,14 +4,14 @@
///
/// This service provides the ability to output sound from the client,
- /// If available the client will provide sound ouput
+ /// If available the client will provide sound output
/// If unavailable the client will fallback to a default sound implementation
/// that generates empty samples (silence)
///
public interface ISoundProvider : IEmulatorService
{
///
- /// Returns true if a core can provide Async sound
+ /// Gets a value indicating whether a core can provide Async sound
///
bool CanProvideAsync { get; }
@@ -25,21 +25,20 @@
void SetSyncMode(SyncSoundMode mode);
///
- /// Reports which mode the sound provider is currently in
+ /// Gets which mode the sound provider is currently in
///
SyncSoundMode SyncMode { get; }
///
- /// Provides samples in syncmode
+ /// Provides samples in sync mode
/// If the core is not in sync mode, this should throw an InvalidOperationException
///
void GetSamplesSync(out short[] samples, out int nsamp);
///
/// Provides samples in async mode
- /// If the core is not in async mode, this shoudl throw an InvalidOperationException
+ /// If the core is not in async mode, this should throw an InvalidOperationException
///
- ///
void GetSamplesAsync(short[] samples);
///
diff --git a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj
index 7904687d90..9515bc1629 100644
--- a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj
+++ b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj
@@ -448,7 +448,7 @@
Gambatte.cs
- Gambatte.cs
+ Gambatte.cs
Gambatte.cs
@@ -478,6 +478,9 @@
GambatteLink.cs
+
+ GambatteLink.cs
+
GambatteLink.cs
@@ -496,6 +499,9 @@
GambatteLink.cs
+
+ GambatteLink.cs
+
diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GBColors.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GBColors.cs
index 28bd968dd1..7e20de9573 100644
--- a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GBColors.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GBColors.cs
@@ -64,10 +64,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
}
// "gameboy colors" mode on older versions of VBA
- static int gbGetValue(int min, int max, int v)
+ private static int gbGetValue(int min, int max, int v)
{
return (int)(min + (float)(max - min) * (2.0 * (v / 31.0) - (v / 31.0) * (v / 31.0)));
}
+
public static Triple OldVBAColor(Triple c)
{
Triple ret;
@@ -102,10 +103,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
// possibly represents a GBA screen, more or less
// but probably not (black point?)
- static int GBAGamma(int input)
+ private static int GBAGamma(int input)
{
return (int)Math.Round(Math.Pow(input / 31.0, 3.5 / 2.2) * 255.0);
}
+
public static Triple GBAColor(Triple c)
{
Triple ret;
@@ -144,6 +146,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
case ColorType.vbabgbold: f = OldVBAColor; break;
case ColorType.gba: f = GBAColor; break;
}
+
int i = 0;
for (int b = 0; b < 32; b++)
for (int g = 0; g < 32; g++)
diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GBDisassembler.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GBDisassembler.cs
index 49b70e768c..2f2fdf81c5 100644
--- a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GBDisassembler.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GBDisassembler.cs
@@ -1,8 +1,7 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
+using System.Collections.Generic;
+
using BizHawk.Emulation.Common;
+using BizHawk.Emulation.Common.Components.Z80GB;
namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
{
@@ -13,15 +12,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
get { yield return "Z80GB"; }
}
- public override string PCRegisterName
- {
- get { return "PC"; }
- }
+ public override string PCRegisterName => "PC";
public override string Disassemble(MemoryDomain m, uint addr, out int length)
{
ushort tmp;
- string ret = Common.Components.Z80GB.NewDisassembler.Disassemble((ushort)addr, (a) => m.PeekByte(a), out tmp);
+ string ret = NewDisassembler.Disassemble((ushort)addr, a => m.PeekByte(a), out tmp);
length = tmp;
return ret;
}
diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.IEmulator.cs
index 2854a82acf..25ea29a6c9 100644
--- a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.IEmulator.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.IEmulator.cs
@@ -22,8 +22,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
{
// target number of samples to emit: length of 1 frame minus whatever overflow
uint samplesEmitted = TICKSINFRAME - frameOverflow;
- Debug.Assert(samplesEmitted * 2 <= soundbuff.Length);
- if (LibGambatte.gambatte_runfor(GambatteState, soundbuff, ref samplesEmitted) > 0)
+ Debug.Assert(samplesEmitted * 2 <= _soundbuff.Length);
+ if (LibGambatte.gambatte_runfor(GambatteState, _soundbuff, ref samplesEmitted) > 0)
{
LibGambatte.gambatte_blitto(GambatteState, VideoBuffer, 160);
}
@@ -50,7 +50,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
// runfor() always ends after creating a video frame, so sync-up is guaranteed
// when the display has been off, some frames can be markedly shorter than expected
uint samplesEmitted = TICKSINFRAME;
- if (LibGambatte.gambatte_runfor(GambatteState, soundbuff, ref samplesEmitted) > 0)
+ if (LibGambatte.gambatte_runfor(GambatteState, _soundbuff, ref samplesEmitted) > 0)
{
LibGambatte.gambatte_blitto(GambatteState, VideoBuffer, 160);
}
diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs
index a3db6902ad..46faa1b150 100644
--- a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs
@@ -179,7 +179,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
TimeCallback = new LibGambatte.RTCCallback(GetCurrentTime);
LibGambatte.gambatte_setrtccallback(GambatteState, TimeCallback);
- CDCallback = new LibGambatte.CDCallback(CDCallbackProc);
+ _cdCallback = new LibGambatte.CDCallback(CDCallbackProc);
NewSaveCoreSetBuff();
}
@@ -291,14 +291,14 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
if (Tracer.Enabled)
{
- tracecb = MakeTrace;
+ _tracecb = MakeTrace;
}
else
{
- tracecb = null;
+ _tracecb = null;
}
- LibGambatte.gambatte_settracecallback(GambatteState, tracecb);
+ LibGambatte.gambatte_settracecallback(GambatteState, _tracecb);
LibGambatte.gambatte_setlayers(GambatteState, (_settings.DisplayBG ? 1 : 0) | (_settings.DisplayOBJ ? 2 : 0) | (_settings.DisplayWindow ? 4 : 0 ) );
}
diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambatteLink.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambatteLink.IEmulator.cs
new file mode 100644
index 0000000000..817505e0ae
--- /dev/null
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambatteLink.IEmulator.cs
@@ -0,0 +1,192 @@
+using System;
+using BizHawk.Emulation.Common;
+
+namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
+{
+ public partial class GambatteLink : IEmulator
+ {
+ public IEmulatorServiceProvider ServiceProvider { get; }
+
+ public ControllerDefinition ControllerDefinition => DualGbController;
+
+ public IController Controller { get; set; }
+
+ public void FrameAdvance(bool render, bool rendersound = true)
+ {
+ LCont.Clear();
+ RCont.Clear();
+
+ foreach (var s in DualGbController.BoolButtons)
+ {
+ if (Controller.IsPressed(s))
+ {
+ if (s.Contains("P1 "))
+ {
+ LCont.Set(s.Replace("P1 ", string.Empty));
+ }
+ else if (s.Contains("P2 "))
+ {
+ RCont.Set(s.Replace("P2 ", string.Empty));
+ }
+ }
+ }
+
+ bool cablediscosignalNew = Controller.IsPressed("Toggle Cable");
+ if (cablediscosignalNew && !_cablediscosignal)
+ {
+ _cableconnected ^= true;
+ Console.WriteLine("Cable connect status to {0}", _cableconnected);
+ LinkConnected = _cableconnected;
+ }
+
+ _cablediscosignal = cablediscosignalNew;
+
+ Frame++;
+ L.FrameAdvancePrep();
+ R.FrameAdvancePrep();
+
+ unsafe
+ {
+ fixed (int* leftvbuff = &VideoBuffer[0])
+ {
+ // use pitch to have both cores write to the same video buffer, interleaved
+ int* rightvbuff = leftvbuff + 160;
+ const int Pitch = 160 * 2;
+
+ fixed (short* leftsbuff = LeftBuffer, rightsbuff = RightBuffer)
+ {
+ const int Step = 32; // could be 1024 for GB
+
+ int nL = _overflowL;
+ int nR = _overflowR;
+
+ // slowly step our way through the frame, while continually checking and resolving link cable status
+ for (int target = 0; target < SampPerFrame;)
+ {
+ target += Step;
+ if (target > SampPerFrame)
+ {
+ target = SampPerFrame; // don't run for slightly too long depending on step
+ }
+
+ // gambatte_runfor() aborts early when a frame is produced, but we don't want that, hence the while()
+ while (nL < target)
+ {
+ uint nsamp = (uint)(target - nL);
+ if (LibGambatte.gambatte_runfor(L.GambatteState, leftsbuff + (nL * 2), ref nsamp) > 0)
+ {
+ LibGambatte.gambatte_blitto(L.GambatteState, leftvbuff, Pitch);
+ }
+
+ nL += (int)nsamp;
+ }
+
+ while (nR < target)
+ {
+ uint nsamp = (uint)(target - nR);
+ if (LibGambatte.gambatte_runfor(R.GambatteState, rightsbuff + (nR * 2), ref nsamp) > 0)
+ {
+ LibGambatte.gambatte_blitto(R.GambatteState, rightvbuff, Pitch);
+ }
+
+ nR += (int)nsamp;
+ }
+
+ // poll link cable statuses, but not when the cable is disconnected
+ if (!_cableconnected)
+ {
+ continue;
+ }
+
+ 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
+ }
+ }
+
+ _overflowL = nL - SampPerFrame;
+ _overflowR = nR - SampPerFrame;
+ if (_overflowL < 0 || _overflowR < 0)
+ {
+ throw new Exception("Timing problem?");
+ }
+
+ if (rendersound)
+ {
+ PrepSound();
+ }
+
+ // copy extra samples back to beginning
+ for (int i = 0; i < _overflowL * 2; i++)
+ {
+ LeftBuffer[i] = LeftBuffer[i + (SampPerFrame * 2)];
+ }
+
+ for (int i = 0; i < _overflowR * 2; i++)
+ {
+ RightBuffer[i] = RightBuffer[i + (SampPerFrame * 2)];
+ }
+ }
+ }
+ }
+
+ L.FrameAdvancePost();
+ R.FrameAdvancePost();
+ IsLagFrame = L.IsLagFrame && R.IsLagFrame;
+ if (IsLagFrame)
+ {
+ LagCount++;
+ }
+ }
+
+ public int Frame { get; private set; }
+
+ public string SystemId => "DGB";
+
+ public bool DeterministicEmulation => L.DeterministicEmulation && R.DeterministicEmulation;
+
+ public string BoardName => L.BoardName + '|' + R.BoardName;
+
+ public void ResetCounters()
+ {
+ Frame = 0;
+ LagCount = 0;
+ IsLagFrame = false;
+ }
+
+ public CoreComm CoreComm { get; }
+
+ public void Dispose()
+ {
+ if (!_disposed)
+ {
+ L.Dispose();
+ L = null;
+
+ R.Dispose();
+ R = null;
+
+ _blipLeft.Dispose();
+ _blipLeft = null;
+
+ _blipRight.Dispose();
+ _blipRight = null;
+
+ _disposed = true;
+ }
+ }
+ }
+}
diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambatteLink.IStatable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambatteLink.IStatable.cs
index b84396a207..44d477940f 100644
--- a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambatteLink.IStatable.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambatteLink.IStatable.cs
@@ -19,12 +19,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
IsLagFrame = IsLagFrame,
LagCount = LagCount,
Frame = Frame,
- overflowL = overflowL,
- overflowR = overflowR,
- LatchL = LatchL,
- LatchR = LatchR,
- cableconnected = cableconnected,
- cablediscosignal = cablediscosignal
+ overflowL = _overflowL,
+ overflowR = _overflowR,
+ LatchL = _latchLeft,
+ LatchR = _latchRight,
+ cableconnected = _cableconnected,
+ cablediscosignal = _cablediscosignal
};
ser.Serialize(writer, s);
// write extra copy of stuff we don't use
@@ -41,12 +41,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
IsLagFrame = s.IsLagFrame;
LagCount = s.LagCount;
Frame = s.Frame;
- overflowL = s.overflowL;
- overflowR = s.overflowR;
- LatchL = s.LatchL;
- LatchR = s.LatchR;
- cableconnected = s.cableconnected;
- cablediscosignal = s.cablediscosignal;
+ _overflowL = s.overflowL;
+ _overflowR = s.overflowR;
+ _latchLeft = s.LatchL;
+ _latchRight = s.LatchR;
+ _cableconnected = s.cableconnected;
+ _cablediscosignal = s.cablediscosignal;
}
public void SaveStateBinary(BinaryWriter writer)
@@ -57,12 +57,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
writer.Write(IsLagFrame);
writer.Write(LagCount);
writer.Write(Frame);
- writer.Write(overflowL);
- writer.Write(overflowR);
- writer.Write(LatchL);
- writer.Write(LatchR);
- writer.Write(cableconnected);
- writer.Write(cablediscosignal);
+ writer.Write(_overflowL);
+ writer.Write(_overflowR);
+ writer.Write(_latchLeft);
+ writer.Write(_latchRight);
+ writer.Write(_cableconnected);
+ writer.Write(_cablediscosignal);
}
public void LoadStateBinary(BinaryReader reader)
@@ -73,12 +73,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
IsLagFrame = reader.ReadBoolean();
LagCount = reader.ReadInt32();
Frame = reader.ReadInt32();
- overflowL = reader.ReadInt32();
- overflowR = reader.ReadInt32();
- LatchL = reader.ReadInt32();
- LatchR = reader.ReadInt32();
- cableconnected = reader.ReadBoolean();
- cablediscosignal = reader.ReadBoolean();
+ _overflowL = reader.ReadInt32();
+ _overflowR = reader.ReadInt32();
+ _latchLeft = reader.ReadInt32();
+ _latchRight = reader.ReadInt32();
+ _cableconnected = reader.ReadBoolean();
+ _cablediscosignal = reader.ReadBoolean();
}
public byte[] SaveStateBinary()
diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambatteLink.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambatteLink.cs
index 06bfcfe30b..6c585cd6a4 100644
--- a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambatteLink.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambatteLink.cs
@@ -1,7 +1,5 @@
using System;
-
using BizHawk.Emulation.Common;
-using BizHawk.Emulation.Cores.Nintendo.SNES;
namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
{
@@ -9,8 +7,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
"DualGambatte",
"sinamas/natt",
isPorted: true,
- isReleased: true
- )]
+ isReleased: true)]
[ServiceNotApplicable(typeof(IDriveLight))]
public partial class GambatteLink : IEmulator, IVideoProvider, ISoundProvider, IInputPollable, ISaveRam, IStatable, ILinkable,
IDebuggable, ISettable, ICodeDataLogger
@@ -18,12 +15,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
public GambatteLink(CoreComm comm, GameInfo leftinfo, byte[] leftrom, GameInfo rightinfo, byte[] rightrom, object Settings, object SyncSettings, bool deterministic)
{
ServiceProvider = new BasicServiceProvider(this);
- GambatteLinkSettings _Settings = (GambatteLinkSettings)Settings ?? new GambatteLinkSettings();
- GambatteLinkSyncSettings _SyncSettings = (GambatteLinkSyncSettings)SyncSettings ?? new GambatteLinkSyncSettings();
+ GambatteLinkSettings settings = (GambatteLinkSettings)Settings ?? new GambatteLinkSettings();
+ GambatteLinkSyncSettings syncSettings = (GambatteLinkSyncSettings)SyncSettings ?? new GambatteLinkSyncSettings();
CoreComm = comm;
- L = new Gameboy(new CoreComm(comm.ShowMessage, comm.Notify), leftinfo, leftrom, _Settings.L, _SyncSettings.L, deterministic);
- R = new Gameboy(new CoreComm(comm.ShowMessage, comm.Notify), rightinfo, rightrom, _Settings.R, _SyncSettings.R, deterministic);
+ L = new Gameboy(new CoreComm(comm.ShowMessage, comm.Notify), leftinfo, leftrom, settings.L, syncSettings.L, deterministic);
+ R = new Gameboy(new CoreComm(comm.ShowMessage, comm.Notify), rightinfo, rightrom, settings.R, syncSettings.R, deterministic);
// connect link cable
LibGambatte.gambatte_linkstatus(L.GambatteState, 259);
@@ -49,41 +46,42 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
LagCount = 0;
IsLagFrame = false;
- blip_left = new BlipBuffer(1024);
- blip_right = new BlipBuffer(1024);
- blip_left.SetRates(2097152 * 2, 44100);
- blip_right.SetRates(2097152 * 2, 44100);
+ _blipLeft = new BlipBuffer(1024);
+ _blipRight = new BlipBuffer(1024);
+ _blipLeft.SetRates(2097152 * 2, 44100);
+ _blipRight.SetRates(2097152 * 2, 44100);
SetMemoryDomains();
}
public bool LinkConnected { get; private set; }
- bool disposed = false;
+ private bool _disposed = false;
+
+ private Gameboy L;
+ private Gameboy R;
- Gameboy L;
- Gameboy R;
// counter to ensure we do 35112 samples per frame
- int overflowL = 0;
- int overflowR = 0;
- /// if true, the link cable is currently connected
- bool cableconnected = true;
- /// if true, the link cable toggle signal is currently asserted
- bool cablediscosignal = false;
+ private int _overflowL = 0;
+ private int _overflowR = 0;
+
+ // if true, the link cable is currently connected
+ private bool _cableconnected = true;
+
+ // if true, the link cable toggle signal is currently asserted
+ private bool _cablediscosignal = false;
const int SampPerFrame = 35112;
- SaveController LCont = new SaveController(Gameboy.GbController);
- SaveController RCont = new SaveController(Gameboy.GbController);
+ private readonly SaveController LCont = new SaveController(Gameboy.GbController);
+ private readonly SaveController RCont = new SaveController(Gameboy.GbController);
public bool IsCGBMode(bool right)
{
return right ? R.IsCGBMode() : L.IsCGBMode();
}
- public IEmulatorServiceProvider ServiceProvider { get; private set; }
-
- public static readonly ControllerDefinition DualGbController = new ControllerDefinition
+ private static readonly ControllerDefinition DualGbController = new ControllerDefinition
{
Name = "Dual Gameboy Controller",
BoolButtons =
@@ -93,263 +91,5 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
"Toggle Cable"
}
};
-
- public ControllerDefinition ControllerDefinition { get { return DualGbController; } }
- public IController Controller { get; set; }
-
- public void FrameAdvance(bool render, bool rendersound = true)
- {
- LCont.Clear();
- RCont.Clear();
-
- foreach (var s in DualGbController.BoolButtons)
- {
- if (Controller.IsPressed(s))
- {
- if (s.Contains("P1 "))
- LCont.Set(s.Replace("P1 ", ""));
- else if (s.Contains("P2 "))
- RCont.Set(s.Replace("P2 ", ""));
- }
- }
- bool cablediscosignal_new = Controller.IsPressed("Toggle Cable");
- if (cablediscosignal_new && !cablediscosignal)
- {
- cableconnected ^= true;
- Console.WriteLine("Cable connect status to {0}", cableconnected);
- LinkConnected = cableconnected;
- }
- cablediscosignal = cablediscosignal_new;
-
- Frame++;
- L.FrameAdvancePrep();
- R.FrameAdvancePrep();
-
- unsafe
- {
- fixed (int* leftvbuff = &VideoBuffer[0])
- {
- // use pitch to have both cores write to the same video buffer, interleaved
- int* rightvbuff = leftvbuff + 160;
- const int pitch = 160 * 2;
-
- fixed (short* leftsbuff = LeftBuffer, rightsbuff = RightBuffer)
- {
-
- const int step = 32; // could be 1024 for GB
-
- int nL = overflowL;
- int nR = overflowR;
-
- // slowly step our way through the frame, while continually checking and resolving link cable status
- for (int target = 0; target < SampPerFrame;)
- {
- target += step;
- if (target > SampPerFrame)
- target = SampPerFrame; // don't run for slightly too long depending on step
-
- // gambatte_runfor() aborts early when a frame is produced, but we don't want that, hence the while()
- while (nL < target)
- {
- uint nsamp = (uint)(target - nL);
- if (LibGambatte.gambatte_runfor(L.GambatteState, leftsbuff + nL * 2, ref nsamp) > 0)
- LibGambatte.gambatte_blitto(L.GambatteState, leftvbuff, pitch);
- nL += (int)nsamp;
- }
- while (nR < target)
- {
- uint nsamp = (uint)(target - nR);
- if (LibGambatte.gambatte_runfor(R.GambatteState, rightsbuff + nR * 2, ref nsamp) > 0)
- LibGambatte.gambatte_blitto(R.GambatteState, rightvbuff, pitch);
- nR += (int)nsamp;
- }
-
- // poll link cable statuses, but not when the cable is disconnected
- if (!cableconnected)
- continue;
-
- 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
- }
- }
- overflowL = nL - SampPerFrame;
- overflowR = nR - SampPerFrame;
- if (overflowL < 0 || overflowR < 0)
- throw new Exception("Timing problem?");
-
- if (rendersound)
- {
- PrepSound();
- }
- // copy extra samples back to beginning
- for (int i = 0; i < overflowL * 2; i++)
- LeftBuffer[i] = LeftBuffer[i + SampPerFrame * 2];
- for (int i = 0; i < overflowR * 2; i++)
- RightBuffer[i] = RightBuffer[i + SampPerFrame * 2];
-
- }
-
- }
- }
-
- L.FrameAdvancePost();
- R.FrameAdvancePost();
- IsLagFrame = L.IsLagFrame && R.IsLagFrame;
- if (IsLagFrame)
- LagCount++;
- }
-
- public int Frame { get; private set; }
-
- public string SystemId { get { return "DGB"; } }
- public bool DeterministicEmulation { get { return L.DeterministicEmulation && R.DeterministicEmulation; } }
-
- public string BoardName { get { return L.BoardName + '|' + R.BoardName; } }
-
- public void ResetCounters()
- {
- Frame = 0;
- LagCount = 0;
- IsLagFrame = false;
- }
-
- public CoreComm CoreComm { get; private set; }
-
- public void Dispose()
- {
- if (!disposed)
- {
- L.Dispose();
- L = null;
- R.Dispose();
- R = null;
- blip_left.Dispose();
- blip_left = null;
- blip_right.Dispose();
- blip_right = null;
-
- disposed = true;
- }
- }
-
- #region SoundProvider
-
- // i tried using the left and right buffers and then mixing them together... it was kind of a mess of code, and slow
-
- BlipBuffer blip_left;
- BlipBuffer blip_right;
-
- short[] LeftBuffer = new short[(35112 + 2064) * 2];
- short[] RightBuffer = new short[(35112 + 2064) * 2];
-
- short[] SampleBuffer = new short[1536];
- int SampleBufferContains = 0;
-
- int LatchL;
- int LatchR;
-
- unsafe void PrepSound()
- {
- fixed (short* sl = LeftBuffer, sr = RightBuffer)
- {
- for (uint i = 0; i < SampPerFrame * 2; i += 2)
- {
- int s = (sl[i] + sl[i + 1]) / 2;
- if (s != LatchL)
- {
- blip_left.AddDelta(i, s - LatchL);
- LatchL = s;
- }
- s = (sr[i] + sr[i + 1]) / 2;
- if (s != LatchR)
- {
- blip_right.AddDelta(i, s - LatchR);
- LatchR = s;
- }
- }
-
- }
-
- blip_left.EndFrame(SampPerFrame * 2);
- blip_right.EndFrame(SampPerFrame * 2);
- int count = blip_left.SamplesAvailable();
- if (count != blip_right.SamplesAvailable())
- throw new Exception("Sound problem?");
-
- // calling blip.Clear() causes rounding fractions to be reset,
- // and if only one channel is muted, in subsequent frames we can be off by a sample or two
- // not a big deal, but we didn't account for it. so we actually complete the entire
- // audio read and then stamp it out if muted.
-
- blip_left.ReadSamplesLeft(SampleBuffer, count);
- if (L.Muted)
- {
- fixed (short* p = SampleBuffer)
- {
- for (int i = 0; i < SampleBuffer.Length; i += 2)
- p[i] = 0;
- }
- }
-
- blip_right.ReadSamplesRight(SampleBuffer, count);
- if (R.Muted)
- {
- fixed (short* p = SampleBuffer)
- {
- for (int i = 1; i < SampleBuffer.Length; i += 2)
- p[i] = 0;
- }
- }
- SampleBufferContains = count;
- }
-
- public void GetSamplesSync(out short[] samples, out int nsamp)
- {
- nsamp = SampleBufferContains;
- samples = SampleBuffer;
- }
-
- public void DiscardSamples()
- {
- SampleBufferContains = 0;
- }
-
- public bool CanProvideAsync
- {
- get { return false; }
- }
-
- public void SetSyncMode(SyncSoundMode mode)
- {
- if (mode == SyncSoundMode.Async)
- {
- throw new NotSupportedException("Async mode is not supported.");
- }
- }
-
- public SyncSoundMode SyncMode
- {
- get { return SyncSoundMode.Sync; }
- }
-
- public void GetSamplesAsync(short[] samples)
- {
- throw new InvalidOperationException("Async mode is not supported.");
- }
-
- #endregion
}
}
diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GamebatteLink.ISoundProvider.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GamebatteLink.ISoundProvider.cs
new file mode 100644
index 0000000000..b958c79aff
--- /dev/null
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GamebatteLink.ISoundProvider.cs
@@ -0,0 +1,110 @@
+using System;
+using BizHawk.Emulation.Common;
+
+namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
+{
+ public partial class GambatteLink : ISoundProvider
+ {
+ public bool CanProvideAsync => false;
+
+ public void SetSyncMode(SyncSoundMode mode)
+ {
+ if (mode == SyncSoundMode.Async)
+ {
+ throw new NotSupportedException("Async mode is not supported.");
+ }
+ }
+
+ public SyncSoundMode SyncMode => SyncSoundMode.Sync;
+
+ public void GetSamplesSync(out short[] samples, out int nsamp)
+ {
+ nsamp = _sampleBufferContains;
+ samples = SampleBuffer;
+ }
+
+ public void GetSamplesAsync(short[] samples)
+ {
+ throw new InvalidOperationException("Async mode is not supported.");
+ }
+
+ public void DiscardSamples()
+ {
+ _sampleBufferContains = 0;
+ }
+
+ // i tried using the left and right buffers and then mixing them together... it was kind of a mess of code, and slow
+ private BlipBuffer _blipLeft;
+ private BlipBuffer _blipRight;
+
+ private readonly short[] LeftBuffer = new short[(35112 + 2064) * 2];
+ private readonly short[] RightBuffer = new short[(35112 + 2064) * 2];
+
+ private readonly short[] SampleBuffer = new short[1536];
+ private int _sampleBufferContains = 0;
+
+ private int _latchLeft;
+ private int _latchRight;
+
+ private unsafe void PrepSound()
+ {
+ fixed (short* sl = LeftBuffer, sr = RightBuffer)
+ {
+ for (uint i = 0; i < SampPerFrame * 2; i += 2)
+ {
+ int s = (sl[i] + sl[i + 1]) / 2;
+ if (s != _latchLeft)
+ {
+ _blipLeft.AddDelta(i, s - _latchLeft);
+ _latchLeft = s;
+ }
+
+ s = (sr[i] + sr[i + 1]) / 2;
+ if (s != _latchRight)
+ {
+ _blipRight.AddDelta(i, s - _latchRight);
+ _latchRight = s;
+ }
+ }
+ }
+
+ _blipLeft.EndFrame(SampPerFrame * 2);
+ _blipRight.EndFrame(SampPerFrame * 2);
+ int count = _blipLeft.SamplesAvailable();
+ if (count != _blipRight.SamplesAvailable())
+ {
+ throw new Exception("Sound problem?");
+ }
+
+ // calling blip.Clear() causes rounding fractions to be reset,
+ // and if only one channel is muted, in subsequent frames we can be off by a sample or two
+ // not a big deal, but we didn't account for it. so we actually complete the entire
+ // audio read and then stamp it out if muted.
+ _blipLeft.ReadSamplesLeft(SampleBuffer, count);
+ if (L.Muted)
+ {
+ fixed (short* p = SampleBuffer)
+ {
+ for (int i = 0; i < SampleBuffer.Length; i += 2)
+ {
+ p[i] = 0;
+ }
+ }
+ }
+
+ _blipRight.ReadSamplesRight(SampleBuffer, count);
+ if (R.Muted)
+ {
+ fixed (short* p = SampleBuffer)
+ {
+ for (int i = 1; i < SampleBuffer.Length; i += 2)
+ {
+ p[i] = 0;
+ }
+ }
+ }
+
+ _sampleBufferContains = count;
+ }
+ }
+}