Do ChannelF timings a bit better; some cleanups
This commit is contained in:
parent
ca104aec8a
commit
c17930c40f
|
@ -12,32 +12,71 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
|||
|
||||
public bool DeterministicEmulation { get; set; }
|
||||
|
||||
private double cpuFreq;
|
||||
private double refreshRate => region == RegionType.NTSC ? 60.5307257846 : 50.0801282051;
|
||||
|
||||
public int ClockPerFrame;
|
||||
public int FrameClock = 0;
|
||||
public int FrameClock;
|
||||
|
||||
private void CalcClock()
|
||||
{
|
||||
// CPU speeds from https://en.wikipedia.org/wiki/Fairchild_Channel_F
|
||||
// also https://github.com/mamedev/mame/blob/c8192c898ce7f68c0c0b87e44199f0d3e710439b/src/mame/drivers/channelf.cpp
|
||||
double cpuFreq, pixelClock;
|
||||
int pixelClocksPerFrame;
|
||||
if (Region == DisplayType.NTSC)
|
||||
{
|
||||
cpuFreq = 1.7897725;
|
||||
{
|
||||
// NTSC CPU speed is NTSC Colorburst / 2
|
||||
const double NTSC_COLORBURST = 4500000 * 227.5 / 286;
|
||||
cpuFreq = NTSC_COLORBURST / 2;
|
||||
// NTSC pixel clock is NTSC Colorburst * 8 / 7
|
||||
pixelClock = NTSC_COLORBURST * 8 / 7;
|
||||
// NTSC refresh rate is (pixelclock * 8 / 7) / (256 * 264)
|
||||
pixelClocksPerFrame = 256 * 264;
|
||||
// (aka (1023750000 * 8) / (256 * 264 * 286 * 7)
|
||||
// reduced to 234375 / 3872
|
||||
VsyncNumerator = 234375;
|
||||
VsyncDenominator = 3872;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (version == ConsoleVersion.ChannelF)
|
||||
{
|
||||
cpuFreq = 2.0;
|
||||
// PAL CPU speed is 2MHz
|
||||
cpuFreq = 2000000;
|
||||
// PAL pixel clock is 4MHz
|
||||
pixelClock = 4000000;
|
||||
// PAL refresh rate is pixelclock / (256 * 312)
|
||||
pixelClocksPerFrame = 256 * 312;
|
||||
// reduced to 15625 / 312
|
||||
VsyncNumerator = 15625;
|
||||
VsyncDenominator = 312;
|
||||
}
|
||||
else if (version == ConsoleVersion.ChannelF_II)
|
||||
{
|
||||
cpuFreq = 1.9704972;
|
||||
// PAL CPU speed for gen 2 seems to be contested
|
||||
// various sources seem to say 1.77MHz (i.e. PAL Colorburst * 2 / 5)
|
||||
// wikipedia used to have such, before changing it to 1.97MHz (i.e. PAL Colorburst * 4 / 9)
|
||||
// if we assume the pixel clock is double the cpu freq, then 1.97MHz makes more sense (49.3Hz)
|
||||
// 1.77MHz * 2 would result in 44.3Hz, complete nonsense for PAL
|
||||
// however, this kind of relationship between the CPU freq and pixel clock is necessarily the case (see NTSC)
|
||||
// wikipedia's numbers seem to come from a mame contributor (e5frog) editing the page anyways, so it's probably trustworthy
|
||||
const double PAL_COLORBURST = 15625 * 283.75 + 25;
|
||||
cpuFreq = PAL_COLORBURST * 4 / 9;
|
||||
// not entirely sure what the pixel clock for PAL is here
|
||||
// presumingly, it's just cpuFreq * 2?
|
||||
pixelClock = PAL_COLORBURST * 8 / 9;
|
||||
// PAL refresh rate is pixelclock / (256 * 312)
|
||||
pixelClocksPerFrame = 256 * 312;
|
||||
// (aka (4433618.75 * 8) / (256 * 312 * 9)
|
||||
// reduced to 17734475 / 359424
|
||||
VsyncNumerator = 17734475;
|
||||
VsyncDenominator = 359424;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
var c = ((cpuFreq * 1000000) / refreshRate);
|
||||
var c = cpuFreq * pixelClocksPerFrame / pixelClock;
|
||||
ClockPerFrame = (int) c;
|
||||
|
||||
SetupAudio();
|
||||
|
|
|
@ -5,48 +5,26 @@ using BizHawk.Emulation.Common;
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||
{
|
||||
public partial class ChannelF : ISettable<ChannelF.ChannelFSettings, ChannelF.ChannelFSyncSettings>
|
||||
public partial class ChannelF : ISettable<object, ChannelF.ChannelFSyncSettings>
|
||||
{
|
||||
internal ChannelFSettings Settings = new ChannelFSettings();
|
||||
internal ChannelFSyncSettings SyncSettings = new ChannelFSyncSettings();
|
||||
private ChannelFSyncSettings _syncSettings;
|
||||
|
||||
public ChannelFSettings GetSettings()
|
||||
{
|
||||
return Settings.Clone();
|
||||
}
|
||||
public object GetSettings()
|
||||
=> null;
|
||||
|
||||
public ChannelFSyncSettings GetSyncSettings()
|
||||
{
|
||||
return SyncSettings.Clone();
|
||||
}
|
||||
=> _syncSettings.Clone();
|
||||
|
||||
public PutSettingsDirtyBits PutSettings(ChannelFSettings o)
|
||||
{
|
||||
Settings = o;
|
||||
return PutSettingsDirtyBits.None;
|
||||
}
|
||||
public PutSettingsDirtyBits PutSettings(object o)
|
||||
=> PutSettingsDirtyBits.None;
|
||||
|
||||
public PutSettingsDirtyBits PutSyncSettings(ChannelFSyncSettings o)
|
||||
{
|
||||
bool ret = ChannelFSyncSettings.NeedsReboot(SyncSettings, o);
|
||||
SyncSettings = o;
|
||||
var ret = ChannelFSyncSettings.NeedsReboot(_syncSettings, o);
|
||||
_syncSettings = o;
|
||||
return ret ? PutSettingsDirtyBits.RebootCore : PutSettingsDirtyBits.None;
|
||||
}
|
||||
|
||||
[CoreSettings]
|
||||
public class ChannelFSettings
|
||||
{
|
||||
public ChannelFSettings Clone()
|
||||
{
|
||||
return (ChannelFSettings)MemberwiseClone();
|
||||
}
|
||||
|
||||
public ChannelFSettings()
|
||||
{
|
||||
SettingsUtil.SetDefaultValues(this);
|
||||
}
|
||||
}
|
||||
|
||||
[CoreSettings]
|
||||
public class ChannelFSyncSettings
|
||||
{
|
||||
|
|
|
@ -6,40 +6,48 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
|||
/// Sound related functions
|
||||
/// </summary>
|
||||
public partial class ChannelF : ISoundProvider
|
||||
{
|
||||
private int tone = 0;
|
||||
private short[] sampleBuffer;
|
||||
private int[] toneBuffer;
|
||||
private readonly double sampleRate = 44100;
|
||||
private readonly double decay = 0.998;
|
||||
private readonly int rampUpTime = 10;
|
||||
private int samplesPerFrame;
|
||||
private double cyclesPerSample;
|
||||
private double amplitude = 0;
|
||||
private int rampCounter = 0;
|
||||
{
|
||||
private const double SAMPLE_RATE = 44100;
|
||||
private const double DECAY = 0.998;
|
||||
private const int RAMP_UP_TIME = 10;
|
||||
|
||||
private int _tone;
|
||||
private short[] _sampleBuffer;
|
||||
private double[] _filteredSampleBuffer;
|
||||
private int[] _toneBuffer;
|
||||
private int _samplesPerFrame;
|
||||
private double _cyclesPerSample;
|
||||
private double _amplitude;
|
||||
private int _rampCounter;
|
||||
|
||||
private int _currTone;
|
||||
private int _samplePosition;
|
||||
|
||||
private short[] _finalSampleBuffer = [ ];
|
||||
|
||||
private void SetupAudio()
|
||||
{
|
||||
samplesPerFrame = (int)(sampleRate / refreshRate);
|
||||
cyclesPerSample = ClockPerFrame / (double)samplesPerFrame;
|
||||
sampleBuffer = new short[samplesPerFrame];
|
||||
toneBuffer = new int[samplesPerFrame];
|
||||
_samplesPerFrame = (int)(SAMPLE_RATE * VsyncDenominator / VsyncNumerator);
|
||||
// TODO: more precise audio clocking
|
||||
_cyclesPerSample = ClockPerFrame / (double)_samplesPerFrame;
|
||||
_sampleBuffer = new short[_samplesPerFrame];
|
||||
_filteredSampleBuffer = new double[_samplesPerFrame];
|
||||
_toneBuffer = new int[_samplesPerFrame];
|
||||
}
|
||||
|
||||
private void AudioChange()
|
||||
{
|
||||
var currSample = (int)(FrameClock / cyclesPerSample);
|
||||
var currSample = (int)(FrameClock / _cyclesPerSample);
|
||||
|
||||
while (currSample < samplesPerFrame)
|
||||
while (currSample < _samplesPerFrame)
|
||||
{
|
||||
toneBuffer[currSample++] = tone;
|
||||
_toneBuffer[currSample++] = _tone;
|
||||
}
|
||||
}
|
||||
|
||||
private int GetWaveSample(double time, int tone)
|
||||
private static int GetWaveSample(double time, int tone)
|
||||
{
|
||||
int t = 0;
|
||||
|
||||
var t = 0;
|
||||
switch (tone)
|
||||
{
|
||||
case 0:
|
||||
|
@ -63,79 +71,71 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
|||
|
||||
return t;
|
||||
}
|
||||
|
||||
private int GetSineWaveSample(double time, double freq)
|
||||
#if false
|
||||
private static int GetSineWaveSample(double time, double freq)
|
||||
{
|
||||
double sTime = time / sampleRate;
|
||||
double sAngle = 2.0 * Math.PI * sTime * freq;
|
||||
var sTime = time / SAMPLE_RATE;
|
||||
var sAngle = 2.0 * Math.PI * sTime * freq;
|
||||
return (int)(Math.Sin(sAngle) * 0x8000);
|
||||
}
|
||||
|
||||
private int GetSquareWaveSample(double time, double freq)
|
||||
}
|
||||
#endif
|
||||
private static int GetSquareWaveSample(double time, double freq)
|
||||
{
|
||||
double sTime = time / sampleRate;
|
||||
double period = 1.0 / freq;
|
||||
double halfPeriod = period / 2.0;
|
||||
double currentTimeInPeriod = sTime % period;
|
||||
var sTime = time / SAMPLE_RATE;
|
||||
var period = 1.0 / freq;
|
||||
var halfPeriod = period / 2.0;
|
||||
var currentTimeInPeriod = sTime % period;
|
||||
return currentTimeInPeriod < halfPeriod ? 32766 : -32766;
|
||||
}
|
||||
|
||||
private void ApplyLowPassFilter(short[] samples, double cutoffFrequency)
|
||||
private static void ApplyLowPassFilter(short[] samples, double cutoffFrequency)
|
||||
{
|
||||
if (samples == null || samples.Length == 0)
|
||||
return;
|
||||
|
||||
double rc = 1.0 / (cutoffFrequency * 2 * Math.PI);
|
||||
double dt = 1.0 / sampleRate;
|
||||
double alpha = dt / (rc + dt);
|
||||
var rc = 1.0 / (cutoffFrequency * 2 * Math.PI);
|
||||
const double dt = 1.0 / SAMPLE_RATE;
|
||||
var alpha = dt / (rc + dt);
|
||||
|
||||
short previousSample = samples[0];
|
||||
for (int i = 1; i < samples.Length; i++)
|
||||
var previousSample = samples[0];
|
||||
for (var i = 1; i < samples.Length; i++)
|
||||
{
|
||||
samples[i] = (short)(previousSample + alpha * (samples[i] - previousSample));
|
||||
previousSample = samples[i];
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyBassBoostFilter(short[] samples, double boostAmount, double cutoffFrequency)
|
||||
private static void ApplyBassBoostFilter(short[] samples, double[] filteredSamples, double boostAmount, double cutoffFrequency)
|
||||
{
|
||||
if (samples == null || samples.Length == 0)
|
||||
return;
|
||||
|
||||
double A = Math.Pow(10, boostAmount / 40);
|
||||
double omega = 2 * Math.PI * cutoffFrequency / sampleRate;
|
||||
double sn = Math.Sin(omega);
|
||||
double cs = Math.Cos(omega);
|
||||
double alpha = sn / 2 * Math.Sqrt((A + 1 / A) * (1 / 0.707 - 1) + 2);
|
||||
double beta = 2 * Math.Sqrt(A) * alpha;
|
||||
var A = Math.Pow(10, boostAmount / 40);
|
||||
var omega = 2 * Math.PI * cutoffFrequency / SAMPLE_RATE;
|
||||
var sn = Math.Sin(omega);
|
||||
var cs = Math.Cos(omega);
|
||||
var alpha = sn / 2 * Math.Sqrt((A + 1 / A) * (1 / 0.707 - 1) + 2);
|
||||
var beta = 2 * Math.Sqrt(A) * alpha;
|
||||
|
||||
double b0 = A * ((A + 1) - (A - 1) * cs + beta);
|
||||
double b1 = 2 * A * ((A - 1) - (A + 1) * cs);
|
||||
double b2 = A * ((A + 1) - (A - 1) * cs - beta);
|
||||
double a0 = (A + 1) + (A - 1) * cs + beta;
|
||||
double a1 = -2 * ((A - 1) + (A + 1) * cs);
|
||||
double a2 = (A + 1) + (A - 1) * cs - beta;
|
||||
var b0 = A * ((A + 1) - (A - 1) * cs + beta);
|
||||
var b1 = 2 * A * ((A - 1) - (A + 1) * cs);
|
||||
var b2 = A * ((A + 1) - (A - 1) * cs - beta);
|
||||
var a0 = (A + 1) + (A - 1) * cs + beta;
|
||||
var a1 = -2 * ((A - 1) + (A + 1) * cs);
|
||||
var a2 = (A + 1) + (A - 1) * cs - beta;
|
||||
|
||||
double[] filteredSamples = new double[samples.Length];
|
||||
filteredSamples[0] = samples[0];
|
||||
filteredSamples[1] = samples[1];
|
||||
|
||||
for (int i = 2; i < samples.Length; i++)
|
||||
for (var i = 2; i < samples.Length; i++)
|
||||
{
|
||||
filteredSamples[i] = (b0 / a0) * samples[i] + (b1 / a0) * samples[i - 1] + (b2 / a0) * samples[i - 2]
|
||||
- (a1 / a0) * filteredSamples[i - 1] - (a2 / a0) * filteredSamples[i - 2];
|
||||
}
|
||||
|
||||
for (int i = 0; i < samples.Length; i++)
|
||||
for (var i = 0; i < samples.Length; i++)
|
||||
{
|
||||
samples[i] = Clamp((short)filteredSamples[i], short.MinValue, short.MaxValue);
|
||||
}
|
||||
|
||||
short Clamp(short value, short min, short max)
|
||||
{
|
||||
if (value < min) return min;
|
||||
if (value > max) return max;
|
||||
return value;
|
||||
samples[i] = (short)Math.Min(Math.Max(filteredSamples[i], short.MinValue), short.MaxValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -156,76 +156,77 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
|||
|
||||
public void DiscardSamples()
|
||||
{
|
||||
sampleBuffer = new short[samplesPerFrame];
|
||||
Array.Clear(_sampleBuffer, 0, _sampleBuffer.Length);
|
||||
|
||||
// pre-populate the tonebuffer with the last active tone from the frame (will be overwritten if and when a tone change happens)
|
||||
int lastTone = toneBuffer[^1];
|
||||
for (int i = 0; i < toneBuffer.Length; i++)
|
||||
toneBuffer[i] = lastTone;
|
||||
var lastTone = _toneBuffer[^1];
|
||||
for (var i = 0; i < _toneBuffer.Length; i++)
|
||||
_toneBuffer[i] = lastTone;
|
||||
}
|
||||
|
||||
int currTone = 0;
|
||||
int samplePosition = 0;
|
||||
|
||||
public void GetSamplesSync(out short[] samples, out int nsamp)
|
||||
{
|
||||
// process tone buffer
|
||||
for (int t = 0; t < toneBuffer.Length; t++)
|
||||
for (var t = 0; t < _toneBuffer.Length; t++)
|
||||
{
|
||||
var tValue = toneBuffer[t];
|
||||
var tValue = _toneBuffer[t];
|
||||
|
||||
if (currTone != tValue)
|
||||
if (_currTone != tValue)
|
||||
{
|
||||
// tone is changing
|
||||
if (tValue == 0)
|
||||
{
|
||||
// immediate silence
|
||||
currTone = tValue;
|
||||
sampleBuffer[t] = 0;
|
||||
_currTone = tValue;
|
||||
_sampleBuffer[t] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// tone change
|
||||
amplitude = 1;
|
||||
samplePosition = 0;
|
||||
rampCounter = rampUpTime;
|
||||
currTone = tValue;
|
||||
_amplitude = 1;
|
||||
_samplePosition = 0;
|
||||
_rampCounter = RAMP_UP_TIME;
|
||||
_currTone = tValue;
|
||||
|
||||
if (rampCounter <= 0)
|
||||
sampleBuffer[t] = (short)((GetWaveSample(samplePosition++, currTone) * amplitude) / 30);
|
||||
if (_rampCounter <= 0)
|
||||
_sampleBuffer[t] = (short)((GetWaveSample(_samplePosition++, _currTone) * _amplitude) / 30);
|
||||
}
|
||||
}
|
||||
else if (currTone > 0)
|
||||
else if (_currTone > 0)
|
||||
{
|
||||
// tone is continuing
|
||||
if (rampCounter <= 0)
|
||||
if (_rampCounter <= 0)
|
||||
{
|
||||
amplitude *= decay;
|
||||
samplePosition %= samplesPerFrame;
|
||||
sampleBuffer[t] = (short)((GetWaveSample(samplePosition++, currTone) * amplitude) / 30);
|
||||
_amplitude *= DECAY;
|
||||
_samplePosition %= _samplesPerFrame;
|
||||
_sampleBuffer[t] = (short)((GetWaveSample(_samplePosition++, _currTone) * _amplitude) / 30);
|
||||
}
|
||||
else
|
||||
{
|
||||
rampCounter--;
|
||||
_rampCounter--;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// explicit silence
|
||||
sampleBuffer[t] = 0;
|
||||
_sampleBuffer[t] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
ApplyBassBoostFilter(sampleBuffer, 4.0, 600);
|
||||
ApplyLowPassFilter(sampleBuffer, 10000);
|
||||
ApplyBassBoostFilter(_sampleBuffer, _filteredSampleBuffer, 4.0, 600);
|
||||
ApplyLowPassFilter(_sampleBuffer, 10000);
|
||||
|
||||
nsamp = sampleBuffer.Length;
|
||||
samples = new short[nsamp * 2];
|
||||
nsamp = _sampleBuffer.Length;
|
||||
if (_finalSampleBuffer.Length < nsamp * 2)
|
||||
{
|
||||
_finalSampleBuffer = new short[nsamp * 2];
|
||||
}
|
||||
samples = _finalSampleBuffer;
|
||||
|
||||
for (int i = 0, s = 0; i < nsamp; i++, s += 2)
|
||||
{
|
||||
samples[s] = (short)(sampleBuffer[i] * 10);
|
||||
samples[s + 1] = (short)(sampleBuffer[i] * 10);
|
||||
samples[s] = (short)(_sampleBuffer[i] * 10);
|
||||
samples[s + 1] = (short)(_sampleBuffer[i] * 10);
|
||||
}
|
||||
|
||||
DiscardSamples();
|
||||
|
|
|
@ -18,15 +18,16 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
|||
ser.Sync(nameof(_isLag), ref _isLag);
|
||||
ser.Sync(nameof(_lagCount), ref _lagCount);
|
||||
|
||||
ser.Sync(nameof(tone), ref tone);
|
||||
ser.Sync(nameof(sampleBuffer), ref sampleBuffer, false);
|
||||
ser.Sync(nameof(toneBuffer), ref toneBuffer, false);
|
||||
ser.Sync(nameof(samplesPerFrame), ref samplesPerFrame);
|
||||
ser.Sync(nameof(cyclesPerSample), ref cyclesPerSample);
|
||||
ser.Sync(nameof(amplitude), ref amplitude);
|
||||
ser.Sync(nameof(rampCounter), ref rampCounter);
|
||||
ser.Sync(nameof(currTone), ref currTone);
|
||||
ser.Sync(nameof(samplePosition), ref samplePosition);
|
||||
ser.Sync(nameof(_tone), ref _tone);
|
||||
ser.Sync(nameof(_sampleBuffer), ref _sampleBuffer, false);
|
||||
ser.Sync(nameof(_filteredSampleBuffer), ref _filteredSampleBuffer, false);
|
||||
ser.Sync(nameof(_toneBuffer), ref _toneBuffer, false);
|
||||
ser.Sync(nameof(_samplesPerFrame), ref _samplesPerFrame);
|
||||
ser.Sync(nameof(_cyclesPerSample), ref _cyclesPerSample);
|
||||
ser.Sync(nameof(_amplitude), ref _amplitude);
|
||||
ser.Sync(nameof(_rampCounter), ref _rampCounter);
|
||||
ser.Sync(nameof(_currTone), ref _currTone);
|
||||
ser.Sync(nameof(_samplePosition), ref _samplePosition);
|
||||
|
||||
ser.Sync(nameof(StateConsole), ref StateConsole, false);
|
||||
ser.Sync(nameof(StateRight), ref StateRight, false);
|
||||
|
|
|
@ -99,8 +99,8 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
|||
public int BufferWidth => 256 - lBorder - rBorder;
|
||||
public int BufferHeight => (64 * scanlineRepeats) - tBorder - bBorder;
|
||||
public int BackgroundColor => Colors.ARGB(0xFF, 0xFF, 0xFF);
|
||||
public int VsyncNumerator => (int)refreshRate;
|
||||
public int VsyncDenominator => 1;
|
||||
public int VsyncNumerator { get; private set; }
|
||||
public int VsyncDenominator { get; private set; }
|
||||
|
||||
public int[] TrimOutputBuffer(int[] buff, int leftTrim, int topTrim, int rightTrim, int bottomTrim)
|
||||
{
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
|||
public partial class ChannelF : IDriveLight
|
||||
{
|
||||
[CoreConstructor(VSystemID.Raw.ChannelF)]
|
||||
public ChannelF(CoreLoadParameters<ChannelFSettings, ChannelFSyncSettings> lp)
|
||||
public ChannelF(CoreLoadParameters<object, ChannelFSyncSettings> lp)
|
||||
{
|
||||
var ser = new BasicServiceProvider(this);
|
||||
ServiceProvider = ser;
|
||||
|
@ -18,13 +18,11 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
|||
_gameInfo = lp.Roms.Select(r => r.Game).ToList();
|
||||
_files = lp.Roms.Select(r => r.RomData).ToList();
|
||||
|
||||
Settings = lp.Settings ?? new ChannelFSettings();
|
||||
SyncSettings = lp.SyncSettings ?? new ChannelFSyncSettings();
|
||||
_syncSettings = lp.SyncSettings ?? new ChannelFSyncSettings();
|
||||
region = _syncSettings.Region;
|
||||
version = _syncSettings.Version;
|
||||
|
||||
region = SyncSettings.Region;
|
||||
version = SyncSettings.Version;
|
||||
|
||||
MemoryCallbacks = new MemoryCallbackSystem(new[] { "System Bus" });
|
||||
MemoryCallbacks = new MemoryCallbackSystem([ "System Bus" ]);
|
||||
|
||||
ControllerDefinition = ChannelFControllerDefinition;
|
||||
|
||||
|
@ -40,7 +38,6 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
|||
}
|
||||
|
||||
Cartridge = VesCartBase.Configure(_gameInfo[0], _files[0]);
|
||||
|
||||
|
||||
CPU = new F3850
|
||||
{
|
||||
|
|
|
@ -126,9 +126,9 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
|||
OutputLatch[addr] = value;
|
||||
latch_y = (value | 0xC0) ^ 0xFF;
|
||||
var audio = ((value) >> 6) & 0x03;
|
||||
if (audio != tone)
|
||||
if (audio != _tone)
|
||||
{
|
||||
tone = audio;
|
||||
_tone = audio;
|
||||
AudioChange();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue