diff --git a/src/BizHawk.Emulation.Cores/Consoles/Watara/SuperVision/ASIC.Audio.cs b/src/BizHawk.Emulation.Cores/Consoles/Watara/SuperVision/ASIC.Audio.cs
index c9497b718c..2e46eacd48 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Watara/SuperVision/ASIC.Audio.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Watara/SuperVision/ASIC.Audio.cs
@@ -8,9 +8,30 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
{
public partial class ASIC : ISoundProvider
{
+ ///
+ /// Output sample rate
+ ///
public const double SAMPLE_RATE = 44100;
- public double FRAME_RATE => _sv.CpuFreq / _sv.CpuClocksPerFrame;
- public double samplesPerFrame => SAMPLE_RATE / FRAME_RATE;
+
+ ///
+ /// Total number of audio samples in a frame
+ ///
+ public double SamplesPerFrame => SAMPLE_RATE / _sv.RefreshRate;
+
+ ///
+ /// Total CPU cycles in a frame
+ ///
+ public int CpuTicksPerFrame => (int)_sv.CpuTicksPerFrame;
+
+ ///
+ /// The calculated CPU tick position within the frame
+ ///
+ public int TickPos;
+
+ ///
+ /// Keeps track of additional ticks outside of the frame window that need to be processed as a part of the next frame
+ ///
+ public int TicksOverrun;
///
/// CH1: the right square wave channel
@@ -25,7 +46,9 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
///
/// CH4: the noise channel
///
- private CH_Noise _ch4;
+ public CH_Noise _ch4;
+
+
public void InitAudio()
{
@@ -33,18 +56,41 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
_ch2 = new CH_Square(this, 2);
_ch4 = new CH_Noise(this);
- ch1Buff = new short[(int)samplesPerFrame];
- ch2Buff = new short[(int)samplesPerFrame];
- ch4LBuff = new short[(int)samplesPerFrame];
- ch4RBuff = new short[(int)samplesPerFrame];
+ ch1Buff = new short[(int)SamplesPerFrame];
+ ch2Buff = new short[(int)SamplesPerFrame];
+
+ ch4LBuff = new short[(int)SamplesPerFrame];
+ ch4RBuff = new short[(int)SamplesPerFrame];
}
- public void AudioClock(int ticks)
+ public void AudioClock(int incomingTicks)
{
+ int ticks = incomingTicks + TicksOverrun;
+
+ // determine frame boundaries
+ if (TickPos + ticks >= CpuTicksPerFrame)
+ {
+ // we are about to overrun the frame
+ TicksOverrun = TickPos + ticks - CpuTicksPerFrame;
+ // set ticks to run only up to the frame boundary
+ ticks -= TicksOverrun;
+ }
+ else
+ {
+ // still within frame boundaries
+ TicksOverrun = 0;
+ }
+
_ch1.Clock(ticks);
_ch2.Clock(ticks);
_ch4.Clock(ticks);
+
+ TickPos += ticks;
+ if (TickPos == CpuTicksPerFrame)
+ {
+ TickPos = 0;
+ }
}
public void SyncAudioState(Serializer ser)
@@ -151,7 +197,7 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
_chIndex = chIndex;
- _blip = new BlipBuffer((int)(_asic.samplesPerFrame * 2));
+ _blip = new BlipBuffer((int)(_asic.SamplesPerFrame));
_blip.SetRates(_cpuFreq, SAMPLE_RATE);
}
@@ -177,7 +223,7 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
if (_tickBuffer >= ticksPerFreq)
{
_tickBuffer -= ticksPerFreq;
- int sample = GetSquareWaveSample(_asic._sv.FrameClock, FreqActual, DutyCycle) * Volume / 15;
+ int sample = GetSquareWaveSample(_asic.TickPos + t, FreqActual, DutyCycle);
_blip.AddDelta((uint)_asic._sv.FrameClock, (short)sample);
}
}
@@ -190,7 +236,7 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
public void LengthChanged() => _lenCounter = Length;
- private static int GetSquareWaveSample(double time, double freq, int dutyCycle)
+ private int GetSquareWaveSample(double time, double freq, int dutyCycle)
{
double sTime = time / SAMPLE_RATE;
double period = 1.0 / freq;
@@ -203,12 +249,12 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
_ => 0.50
};
double currentTimeInPeriod = sTime % period;
- return currentTimeInPeriod < period * dutyCycleFraction ? short.MaxValue / 32 : short.MinValue / 32;
+ return currentTimeInPeriod < period * dutyCycleFraction ? Volume * 8 : Volume * -8;
}
public virtual void SyncState(Serializer ser)
{
- ser.BeginSection($"AUDIO_CH{_chIndex}_NOISE");
+ ser.BeginSection($"AUDIO_CH{_chIndex}_SQUARE");
ser.Sync(nameof(LenPrescaler), ref _lenPrescaler);
ser.Sync(nameof(_lenCounter), ref _lenCounter);
ser.Sync(nameof(_tickBuffer), ref _tickBuffer);
@@ -311,10 +357,10 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
_asic = asic;
_noiseFreqs = NoiseFreqEntry.Init(_cpuFreq);
- _blipL = new BlipBuffer((int) (_asic.samplesPerFrame * 2));
+ _blipL = new BlipBuffer((int) (_asic.SamplesPerFrame));
_blipL.SetRates(_cpuFreq, SAMPLE_RATE);
- _blipR = new BlipBuffer((int) (_asic.samplesPerFrame * 2));
+ _blipR = new BlipBuffer((int) (_asic.SamplesPerFrame));
_blipR.SetRates(_cpuFreq, SAMPLE_RATE);
}
@@ -341,8 +387,8 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
{
_tickBuffer -= _currNoiseFreq.TicksPerFreq;
ClockLFSR();
- _blipL.AddDelta((uint)_asic._sv.FrameClock, LeftChannelOutput ? (short)LFSR : 0);
- _blipR.AddDelta((uint)_asic._sv.FrameClock, RightChannelOutput ? (short)LFSR : 0);
+ _blipL.AddDelta((uint)(_asic.TickPos + t), LeftChannelOutput ? (short)LFSR : 0);
+ _blipR.AddDelta((uint)(_asic.TickPos + t), RightChannelOutput ? (short)LFSR : 0);
}
}
}
@@ -480,10 +526,10 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
public void GetSamplesSync(out short[] samples, out int nsamp)
{
- nsamp = (int)samplesPerFrame;
+ nsamp = (int)SamplesPerFrame;
// L
- _ch2.Blip.EndFrame((uint) _sv.CpuClocksPerFrame);
+ _ch2.Blip.EndFrame((uint)CpuTicksPerFrame);
int ch2Nsamp = _ch2.Blip.SamplesAvailable();
if (ch2Nsamp != nsamp)
{
@@ -491,7 +537,7 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
}
_ch2.Blip.ReadSamples(ch2Buff, nsamp, false);
- _ch4.BlipL.EndFrame((uint) _sv.CpuClocksPerFrame);
+ _ch4.BlipL.EndFrame((uint)CpuTicksPerFrame);
int ch4LNsamp = _ch4.BlipL.SamplesAvailable();
if (ch4LNsamp != nsamp)
{
@@ -500,7 +546,7 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
_ch4.BlipL.ReadSamples(ch4LBuff, nsamp, false);
// R
- _ch1.Blip.EndFrame((uint)_sv.CpuClocksPerFrame);
+ _ch1.Blip.EndFrame((uint)CpuTicksPerFrame);
int ch1Nsamp = _ch1.Blip.SamplesAvailable();
if (ch1Nsamp != nsamp)
{
@@ -508,7 +554,7 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
}
_ch1.Blip.ReadSamples(ch1Buff, nsamp, false);
- _ch4.BlipR.EndFrame((uint) _sv.CpuClocksPerFrame);
+ _ch4.BlipR.EndFrame((uint)CpuTicksPerFrame);
int ch4RNsamp = _ch4.BlipR.SamplesAvailable();
if (ch4RNsamp != nsamp)
{
@@ -531,6 +577,8 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
samples[o] = (short)ClampSample(left);
samples[o + 1] = (short)ClampSample(right);
}
+
+ DiscardSamples();
}
private static int ClampSample(int sample)
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Watara/SuperVision/Memory.cs b/src/BizHawk.Emulation.Cores/Consoles/Watara/SuperVision/Memory.cs
index 3e95996723..d622dcce94 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Watara/SuperVision/Memory.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Watara/SuperVision/Memory.cs
@@ -23,9 +23,6 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
}
private int _bankSelect;
- private int _bankOffset => BankSelect << 14;
-
-
///
/// True when the CPU is accessing memory
///
@@ -72,7 +69,8 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
// 1: 2nd 16k
// 2: 3rd 16k
// etc..
- result = _cartridge.ReadByte((ushort) ((address % 0x4000) + (_bankOffset % _cartridge.CartROMSize)));
+ //result = _cartridge.ReadByte((ushort) ((address % 0x4000) + (_bankOffset % _cartridge.CartROMSize)));
+ result = _cartridge.ReadByte((ushort) ((address % 0x4000) + ((BankSelect * 0x4000) % _cartridge.CartROMSize)));
break;
// 0xC000 - 0xFFFF
@@ -133,7 +131,7 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
case 6:
case 7:
// fixed to the last 16K in the cart address space
- _cartridge.WriteByte((ushort) ((address % 0x4000) + (_bankOffset % _cartridge.CartROMSize)), value);
+ _cartridge.WriteByte((ushort) ((address % 0x4000) + ((BankSelect * 0x4000) % _cartridge.CartROMSize)), value);
break;
}
}
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Watara/SuperVision/SuperVision.IEmulator.cs b/src/BizHawk.Emulation.Cores/Consoles/Watara/SuperVision/SuperVision.IEmulator.cs
index c623aef911..89f2135da5 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Watara/SuperVision/SuperVision.IEmulator.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Watara/SuperVision/SuperVision.IEmulator.cs
@@ -13,14 +13,24 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
public bool DeterministicEmulation => true;
- private double _cpuClocksPerFrame;
- private double _cpuClocksPerSecond;
+ ///
+ /// CPU frequency
+ ///
+ public double CpuFreq;
+
+ ///
+ /// Total number of CPU cycles in a frame
+ ///
+ public double CpuTicksPerFrame;
+
+ ///
+ /// Number of frames per second
+ ///
+ public double RefreshRate;
+
private int _frameClock;
private int _frame;
- public double CpuFreq => _cpuClocksPerSecond;
- public double CpuClocksPerFrame => _cpuClocksPerFrame;
-
public int FrameClock
{
get => _frameClock;
@@ -30,18 +40,18 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
private void CalcClock()
{
- _cpuClocksPerSecond = 4_000_000.0;
- _cpuClocksPerFrame =
+ CpuFreq = 4_000_000.0;
+ CpuTicksPerFrame =
(40 + 1) * // pixel clocks per scanline + 1 latch write pixel clock
6 * // cpu clocks per pixel
160 * // scanlines per field
2; // fields per frame
- double refreshRate = _cpuClocksPerSecond / _cpuClocksPerFrame; // 50.8130081300813
+ RefreshRate = CpuFreq / CpuTicksPerFrame; // 50.8130081300813
_asic.Screen.SetRates(
- (int) _cpuClocksPerSecond,
- (int) _cpuClocksPerFrame);
+ (int) CpuFreq,
+ (int) CpuTicksPerFrame);
_asic.InitAudio();
}
@@ -66,14 +76,14 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
//_asic.FrameStart = true;
- while (_frameClock < _cpuClocksPerFrame)
+ while (_frameClock < CpuTicksPerFrame)
{
int ticks = _cpu.ExecuteInstruction();
_asic.Clock(ticks);
//_cpu.ExecuteOne();
}
- _frameClock %= (int)_cpuClocksPerFrame;
+ _frameClock %= (int)CpuTicksPerFrame;
_frame++;
if (_isLag)