More audio
This commit is contained in:
parent
85061362ae
commit
58473484a0
|
@ -8,9 +8,30 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
|
||||||
{
|
{
|
||||||
public partial class ASIC : ISoundProvider
|
public partial class ASIC : ISoundProvider
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Output sample rate
|
||||||
|
/// </summary>
|
||||||
public const double SAMPLE_RATE = 44100;
|
public const double SAMPLE_RATE = 44100;
|
||||||
public double FRAME_RATE => _sv.CpuFreq / _sv.CpuClocksPerFrame;
|
|
||||||
public double samplesPerFrame => SAMPLE_RATE / FRAME_RATE;
|
/// <summary>
|
||||||
|
/// Total number of audio samples in a frame
|
||||||
|
/// </summary>
|
||||||
|
public double SamplesPerFrame => SAMPLE_RATE / _sv.RefreshRate;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Total CPU cycles in a frame
|
||||||
|
/// </summary>
|
||||||
|
public int CpuTicksPerFrame => (int)_sv.CpuTicksPerFrame;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The calculated CPU tick position within the frame
|
||||||
|
/// </summary>
|
||||||
|
public int TickPos;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Keeps track of additional ticks outside of the frame window that need to be processed as a part of the next frame
|
||||||
|
/// </summary>
|
||||||
|
public int TicksOverrun;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// CH1: the right square wave channel
|
/// CH1: the right square wave channel
|
||||||
|
@ -25,7 +46,9 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// CH4: the noise channel
|
/// CH4: the noise channel
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private CH_Noise _ch4;
|
public CH_Noise _ch4;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void InitAudio()
|
public void InitAudio()
|
||||||
{
|
{
|
||||||
|
@ -33,18 +56,41 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
|
||||||
_ch2 = new CH_Square(this, 2);
|
_ch2 = new CH_Square(this, 2);
|
||||||
_ch4 = new CH_Noise(this);
|
_ch4 = new CH_Noise(this);
|
||||||
|
|
||||||
ch1Buff = new short[(int)samplesPerFrame];
|
ch1Buff = new short[(int)SamplesPerFrame];
|
||||||
ch2Buff = new short[(int)samplesPerFrame];
|
ch2Buff = new short[(int)SamplesPerFrame];
|
||||||
ch4LBuff = new short[(int)samplesPerFrame];
|
|
||||||
ch4RBuff = 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);
|
_ch1.Clock(ticks);
|
||||||
_ch2.Clock(ticks);
|
_ch2.Clock(ticks);
|
||||||
|
|
||||||
_ch4.Clock(ticks);
|
_ch4.Clock(ticks);
|
||||||
|
|
||||||
|
TickPos += ticks;
|
||||||
|
if (TickPos == CpuTicksPerFrame)
|
||||||
|
{
|
||||||
|
TickPos = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SyncAudioState(Serializer ser)
|
public void SyncAudioState(Serializer ser)
|
||||||
|
@ -151,7 +197,7 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
|
||||||
|
|
||||||
_chIndex = chIndex;
|
_chIndex = chIndex;
|
||||||
|
|
||||||
_blip = new BlipBuffer((int)(_asic.samplesPerFrame * 2));
|
_blip = new BlipBuffer((int)(_asic.SamplesPerFrame));
|
||||||
_blip.SetRates(_cpuFreq, SAMPLE_RATE);
|
_blip.SetRates(_cpuFreq, SAMPLE_RATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,7 +223,7 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
|
||||||
if (_tickBuffer >= ticksPerFreq)
|
if (_tickBuffer >= ticksPerFreq)
|
||||||
{
|
{
|
||||||
_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);
|
_blip.AddDelta((uint)_asic._sv.FrameClock, (short)sample);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -190,7 +236,7 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
|
||||||
public void LengthChanged() => _lenCounter = Length;
|
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 sTime = time / SAMPLE_RATE;
|
||||||
double period = 1.0 / freq;
|
double period = 1.0 / freq;
|
||||||
|
@ -203,12 +249,12 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
|
||||||
_ => 0.50
|
_ => 0.50
|
||||||
};
|
};
|
||||||
double currentTimeInPeriod = sTime % period;
|
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)
|
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(LenPrescaler), ref _lenPrescaler);
|
||||||
ser.Sync(nameof(_lenCounter), ref _lenCounter);
|
ser.Sync(nameof(_lenCounter), ref _lenCounter);
|
||||||
ser.Sync(nameof(_tickBuffer), ref _tickBuffer);
|
ser.Sync(nameof(_tickBuffer), ref _tickBuffer);
|
||||||
|
@ -311,10 +357,10 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
|
||||||
_asic = asic;
|
_asic = asic;
|
||||||
_noiseFreqs = NoiseFreqEntry.Init(_cpuFreq);
|
_noiseFreqs = NoiseFreqEntry.Init(_cpuFreq);
|
||||||
|
|
||||||
_blipL = new BlipBuffer((int) (_asic.samplesPerFrame * 2));
|
_blipL = new BlipBuffer((int) (_asic.SamplesPerFrame));
|
||||||
_blipL.SetRates(_cpuFreq, SAMPLE_RATE);
|
_blipL.SetRates(_cpuFreq, SAMPLE_RATE);
|
||||||
|
|
||||||
_blipR = new BlipBuffer((int) (_asic.samplesPerFrame * 2));
|
_blipR = new BlipBuffer((int) (_asic.SamplesPerFrame));
|
||||||
_blipR.SetRates(_cpuFreq, SAMPLE_RATE);
|
_blipR.SetRates(_cpuFreq, SAMPLE_RATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -341,8 +387,8 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
|
||||||
{
|
{
|
||||||
_tickBuffer -= _currNoiseFreq.TicksPerFreq;
|
_tickBuffer -= _currNoiseFreq.TicksPerFreq;
|
||||||
ClockLFSR();
|
ClockLFSR();
|
||||||
_blipL.AddDelta((uint)_asic._sv.FrameClock, LeftChannelOutput ? (short)LFSR : 0);
|
_blipL.AddDelta((uint)(_asic.TickPos + t), LeftChannelOutput ? (short)LFSR : 0);
|
||||||
_blipR.AddDelta((uint)_asic._sv.FrameClock, RightChannelOutput ? (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)
|
public void GetSamplesSync(out short[] samples, out int nsamp)
|
||||||
{
|
{
|
||||||
nsamp = (int)samplesPerFrame;
|
nsamp = (int)SamplesPerFrame;
|
||||||
|
|
||||||
// L
|
// L
|
||||||
_ch2.Blip.EndFrame((uint) _sv.CpuClocksPerFrame);
|
_ch2.Blip.EndFrame((uint)CpuTicksPerFrame);
|
||||||
int ch2Nsamp = _ch2.Blip.SamplesAvailable();
|
int ch2Nsamp = _ch2.Blip.SamplesAvailable();
|
||||||
if (ch2Nsamp != nsamp)
|
if (ch2Nsamp != nsamp)
|
||||||
{
|
{
|
||||||
|
@ -491,7 +537,7 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
|
||||||
}
|
}
|
||||||
_ch2.Blip.ReadSamples(ch2Buff, nsamp, false);
|
_ch2.Blip.ReadSamples(ch2Buff, nsamp, false);
|
||||||
|
|
||||||
_ch4.BlipL.EndFrame((uint) _sv.CpuClocksPerFrame);
|
_ch4.BlipL.EndFrame((uint)CpuTicksPerFrame);
|
||||||
int ch4LNsamp = _ch4.BlipL.SamplesAvailable();
|
int ch4LNsamp = _ch4.BlipL.SamplesAvailable();
|
||||||
if (ch4LNsamp != nsamp)
|
if (ch4LNsamp != nsamp)
|
||||||
{
|
{
|
||||||
|
@ -500,7 +546,7 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
|
||||||
_ch4.BlipL.ReadSamples(ch4LBuff, nsamp, false);
|
_ch4.BlipL.ReadSamples(ch4LBuff, nsamp, false);
|
||||||
|
|
||||||
// R
|
// R
|
||||||
_ch1.Blip.EndFrame((uint)_sv.CpuClocksPerFrame);
|
_ch1.Blip.EndFrame((uint)CpuTicksPerFrame);
|
||||||
int ch1Nsamp = _ch1.Blip.SamplesAvailable();
|
int ch1Nsamp = _ch1.Blip.SamplesAvailable();
|
||||||
if (ch1Nsamp != nsamp)
|
if (ch1Nsamp != nsamp)
|
||||||
{
|
{
|
||||||
|
@ -508,7 +554,7 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
|
||||||
}
|
}
|
||||||
_ch1.Blip.ReadSamples(ch1Buff, nsamp, false);
|
_ch1.Blip.ReadSamples(ch1Buff, nsamp, false);
|
||||||
|
|
||||||
_ch4.BlipR.EndFrame((uint) _sv.CpuClocksPerFrame);
|
_ch4.BlipR.EndFrame((uint)CpuTicksPerFrame);
|
||||||
int ch4RNsamp = _ch4.BlipR.SamplesAvailable();
|
int ch4RNsamp = _ch4.BlipR.SamplesAvailable();
|
||||||
if (ch4RNsamp != nsamp)
|
if (ch4RNsamp != nsamp)
|
||||||
{
|
{
|
||||||
|
@ -531,6 +577,8 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
|
||||||
samples[o] = (short)ClampSample(left);
|
samples[o] = (short)ClampSample(left);
|
||||||
samples[o + 1] = (short)ClampSample(right);
|
samples[o + 1] = (short)ClampSample(right);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DiscardSamples();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int ClampSample(int sample)
|
private static int ClampSample(int sample)
|
||||||
|
|
|
@ -23,9 +23,6 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
|
||||||
}
|
}
|
||||||
private int _bankSelect;
|
private int _bankSelect;
|
||||||
|
|
||||||
private int _bankOffset => BankSelect << 14;
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// True when the CPU is accessing memory
|
/// True when the CPU is accessing memory
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -72,7 +69,8 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
|
||||||
// 1: 2nd 16k
|
// 1: 2nd 16k
|
||||||
// 2: 3rd 16k
|
// 2: 3rd 16k
|
||||||
// etc..
|
// 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;
|
break;
|
||||||
|
|
||||||
// 0xC000 - 0xFFFF
|
// 0xC000 - 0xFFFF
|
||||||
|
@ -133,7 +131,7 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
|
||||||
case 6:
|
case 6:
|
||||||
case 7:
|
case 7:
|
||||||
// fixed to the last 16K in the cart address space
|
// 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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,14 +13,24 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
|
||||||
|
|
||||||
public bool DeterministicEmulation => true;
|
public bool DeterministicEmulation => true;
|
||||||
|
|
||||||
private double _cpuClocksPerFrame;
|
/// <summary>
|
||||||
private double _cpuClocksPerSecond;
|
/// CPU frequency
|
||||||
|
/// </summary>
|
||||||
|
public double CpuFreq;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Total number of CPU cycles in a frame
|
||||||
|
/// </summary>
|
||||||
|
public double CpuTicksPerFrame;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Number of frames per second
|
||||||
|
/// </summary>
|
||||||
|
public double RefreshRate;
|
||||||
|
|
||||||
private int _frameClock;
|
private int _frameClock;
|
||||||
private int _frame;
|
private int _frame;
|
||||||
|
|
||||||
public double CpuFreq => _cpuClocksPerSecond;
|
|
||||||
public double CpuClocksPerFrame => _cpuClocksPerFrame;
|
|
||||||
|
|
||||||
public int FrameClock
|
public int FrameClock
|
||||||
{
|
{
|
||||||
get => _frameClock;
|
get => _frameClock;
|
||||||
|
@ -30,18 +40,18 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
|
||||||
|
|
||||||
private void CalcClock()
|
private void CalcClock()
|
||||||
{
|
{
|
||||||
_cpuClocksPerSecond = 4_000_000.0;
|
CpuFreq = 4_000_000.0;
|
||||||
_cpuClocksPerFrame =
|
CpuTicksPerFrame =
|
||||||
(40 + 1) * // pixel clocks per scanline + 1 latch write pixel clock
|
(40 + 1) * // pixel clocks per scanline + 1 latch write pixel clock
|
||||||
6 * // cpu clocks per pixel
|
6 * // cpu clocks per pixel
|
||||||
160 * // scanlines per field
|
160 * // scanlines per field
|
||||||
2; // fields per frame
|
2; // fields per frame
|
||||||
|
|
||||||
double refreshRate = _cpuClocksPerSecond / _cpuClocksPerFrame; // 50.8130081300813
|
RefreshRate = CpuFreq / CpuTicksPerFrame; // 50.8130081300813
|
||||||
|
|
||||||
_asic.Screen.SetRates(
|
_asic.Screen.SetRates(
|
||||||
(int) _cpuClocksPerSecond,
|
(int) CpuFreq,
|
||||||
(int) _cpuClocksPerFrame);
|
(int) CpuTicksPerFrame);
|
||||||
|
|
||||||
_asic.InitAudio();
|
_asic.InitAudio();
|
||||||
}
|
}
|
||||||
|
@ -66,14 +76,14 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
|
||||||
|
|
||||||
//_asic.FrameStart = true;
|
//_asic.FrameStart = true;
|
||||||
|
|
||||||
while (_frameClock < _cpuClocksPerFrame)
|
while (_frameClock < CpuTicksPerFrame)
|
||||||
{
|
{
|
||||||
int ticks = _cpu.ExecuteInstruction();
|
int ticks = _cpu.ExecuteInstruction();
|
||||||
_asic.Clock(ticks);
|
_asic.Clock(ticks);
|
||||||
//_cpu.ExecuteOne();
|
//_cpu.ExecuteOne();
|
||||||
}
|
}
|
||||||
|
|
||||||
_frameClock %= (int)_cpuClocksPerFrame;
|
_frameClock %= (int)CpuTicksPerFrame;
|
||||||
_frame++;
|
_frame++;
|
||||||
|
|
||||||
if (_isLag)
|
if (_isLag)
|
||||||
|
|
Loading…
Reference in New Issue