ColecoVision: SGM Sound
This commit is contained in:
parent
02c72a663a
commit
b0445521c9
|
@ -415,7 +415,8 @@
|
|||
<Compile Include="Consoles\Coleco\ColecoVision.ISoundProvider.cs">
|
||||
<DependentUpon>ColecoVision.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Coleco\AY_3_8910.cs" />
|
||||
<Compile Include="Consoles\Coleco\AY_3_8910_SGM.cs" />
|
||||
<Compile Include="Consoles\Coleco\SN76489col.cs" />
|
||||
<Compile Include="Consoles\Coleco\TMS9918A.cs" />
|
||||
<Compile Include="Consoles\Coleco\ColecoControllerDeck.cs" />
|
||||
<Compile Include="Consoles\Coleco\ColecoControllers.cs" />
|
||||
|
|
|
@ -6,15 +6,13 @@ using BizHawk.Emulation.Common;
|
|||
|
||||
namespace BizHawk.Emulation.Cores.ColecoVision
|
||||
{
|
||||
public sealed class AY_3_8910 : ISoundProvider
|
||||
public sealed class AY_3_8910_SGM
|
||||
{
|
||||
private readonly BlipBuffer _blip = new BlipBuffer(4096);
|
||||
private short[] _sampleBuffer = new short[0];
|
||||
public short[] _sampleBuffer = new short[4096];
|
||||
private short current_sample;
|
||||
|
||||
|
||||
public AY_3_8910()
|
||||
public AY_3_8910_SGM()
|
||||
{
|
||||
_blip.SetRates(894866 / 4.0, 44100);
|
||||
Reset();
|
||||
}
|
||||
|
||||
|
@ -22,8 +20,6 @@ namespace BizHawk.Emulation.Cores.ColecoVision
|
|||
|
||||
public byte port_sel;
|
||||
|
||||
public int total_clock; // TODO: what is this used for?
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
clock_A = clock_B = clock_C = 0x1000;
|
||||
|
@ -40,51 +36,13 @@ namespace BizHawk.Emulation.Cores.ColecoVision
|
|||
|
||||
public void DiscardSamples()
|
||||
{
|
||||
_blip.Clear();
|
||||
_sampleClock = 0;
|
||||
}
|
||||
|
||||
public void GetSamplesAsync(short[] samples)
|
||||
public void Sample()
|
||||
{
|
||||
throw new NotSupportedException("Async is not available");
|
||||
}
|
||||
|
||||
public bool CanProvideAsync => false;
|
||||
|
||||
public SyncSoundMode SyncMode => SyncSoundMode.Sync;
|
||||
|
||||
public void SetSyncMode(SyncSoundMode mode)
|
||||
{
|
||||
if (mode != SyncSoundMode.Sync)
|
||||
{
|
||||
throw new InvalidOperationException("Only Sync mode is supported.");
|
||||
}
|
||||
}
|
||||
|
||||
public void GetSamplesSync(out short[] samples, out int nsamp)
|
||||
{
|
||||
_blip.EndFrame((uint)_sampleClock);
|
||||
_sampleClock = 0;
|
||||
|
||||
nsamp = _blip.SamplesAvailable();
|
||||
int targetLength = nsamp * 2;
|
||||
if (_sampleBuffer.Length != targetLength)
|
||||
{
|
||||
_sampleBuffer = new short[targetLength];
|
||||
}
|
||||
|
||||
_blip.ReadSamplesLeft(_sampleBuffer, nsamp);
|
||||
for (int i = 0; i < _sampleBuffer.Length; i += 2)
|
||||
{
|
||||
_sampleBuffer[i + 1] = _sampleBuffer[i];
|
||||
}
|
||||
|
||||
samples = _sampleBuffer;
|
||||
}
|
||||
|
||||
public void GetSamples(short[] samples)
|
||||
{
|
||||
throw new Exception();
|
||||
_sampleBuffer[_sampleClock] = current_sample;
|
||||
_sampleClock++;
|
||||
}
|
||||
|
||||
private static readonly int[] VolumeTable =
|
||||
|
@ -94,7 +52,6 @@ namespace BizHawk.Emulation.Cores.ColecoVision
|
|||
};
|
||||
|
||||
private int _sampleClock;
|
||||
private int _latchedSample;
|
||||
|
||||
private int TotalExecutedCycles;
|
||||
private int PendingCycles;
|
||||
|
@ -117,9 +74,6 @@ namespace BizHawk.Emulation.Cores.ColecoVision
|
|||
private int noise_per;
|
||||
private int noise = 0x1;
|
||||
|
||||
public Func<byte, bool, byte> ReadMemory;
|
||||
public Func<byte, byte, bool, bool> WriteMemory;
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
ser.BeginSection("PSG");
|
||||
|
@ -147,32 +101,32 @@ namespace BizHawk.Emulation.Cores.ColecoVision
|
|||
ser.EndSection();
|
||||
}
|
||||
|
||||
public byte ReadPSG()
|
||||
public byte ReadReg()
|
||||
{
|
||||
return Register[port_sel];
|
||||
}
|
||||
|
||||
private void sync_psg_state()
|
||||
{
|
||||
sq_per_A = (Register[0] & 0xFF) | (((Register[4] & 0xF) << 8));
|
||||
sq_per_A = (Register[0] & 0xFF) | (((Register[1] & 0xF) << 8));
|
||||
if (sq_per_A == 0)
|
||||
{
|
||||
sq_per_A = 0x1000;
|
||||
}
|
||||
|
||||
sq_per_B = (Register[1] & 0xFF) | (((Register[5] & 0xF) << 8));
|
||||
sq_per_B = (Register[2] & 0xFF) | (((Register[3] & 0xF) << 8));
|
||||
if (sq_per_B == 0)
|
||||
{
|
||||
sq_per_B = 0x1000;
|
||||
}
|
||||
|
||||
sq_per_C = (Register[2] & 0xFF) | (((Register[6] & 0xF) << 8));
|
||||
sq_per_C = (Register[4] & 0xFF) | (((Register[5] & 0xF) << 8));
|
||||
if (sq_per_C == 0)
|
||||
{
|
||||
sq_per_C = 0x1000;
|
||||
}
|
||||
|
||||
env_per = (Register[3] & 0xFF) | (((Register[7] & 0xFF) << 8));
|
||||
env_per = (Register[11] & 0xFF) | (((Register[12] & 0xFF) << 8));
|
||||
if (env_per == 0)
|
||||
{
|
||||
env_per = 0x10000;
|
||||
|
@ -180,20 +134,20 @@ namespace BizHawk.Emulation.Cores.ColecoVision
|
|||
|
||||
env_per *= 2;
|
||||
|
||||
A_on = Register[8].Bit(0);
|
||||
B_on = Register[8].Bit(1);
|
||||
C_on = Register[8].Bit(2);
|
||||
A_noise = Register[8].Bit(3);
|
||||
B_noise = Register[8].Bit(4);
|
||||
C_noise = Register[8].Bit(5);
|
||||
A_on = Register[7].Bit(0);
|
||||
B_on = Register[7].Bit(1);
|
||||
C_on = Register[7].Bit(2);
|
||||
A_noise = Register[7].Bit(3);
|
||||
B_noise = Register[7].Bit(4);
|
||||
C_noise = Register[7].Bit(5);
|
||||
|
||||
noise_per = Register[9] & 0x1F;
|
||||
noise_per = Register[6] & 0x1F;
|
||||
if (noise_per == 0)
|
||||
{
|
||||
noise_per = 0x20;
|
||||
}
|
||||
|
||||
var shape_select = Register[10] & 0xF;
|
||||
var shape_select = Register[13] & 0xF;
|
||||
|
||||
if (shape_select < 4)
|
||||
env_shape = 0;
|
||||
|
@ -202,55 +156,44 @@ namespace BizHawk.Emulation.Cores.ColecoVision
|
|||
else
|
||||
env_shape = 2 + (shape_select - 8);
|
||||
|
||||
vol_A = Register[11] & 0xF;
|
||||
env_vol_A = (Register[11] >> 4) & 0x3;
|
||||
vol_A = Register[8] & 0xF;
|
||||
env_vol_A = (Register[8] >> 4) & 0x1;
|
||||
|
||||
vol_B = Register[12] & 0xF;
|
||||
env_vol_B = (Register[12] >> 4) & 0x3;
|
||||
vol_B = Register[9] & 0xF;
|
||||
env_vol_B = (Register[9] >> 4) & 0x1;
|
||||
|
||||
vol_C = Register[13] & 0xF;
|
||||
env_vol_C = (Register[13] >> 4) & 0x3;
|
||||
vol_C = Register[10] & 0xF;
|
||||
env_vol_C = (Register[10] >> 4) & 0x1;
|
||||
}
|
||||
|
||||
public bool WritePSG(byte value)
|
||||
public void WriteReg(byte value)
|
||||
{
|
||||
value &= 0xFF;
|
||||
value &= 0xFF;
|
||||
|
||||
if (port_sel == 4 || port_sel == 5 || port_sel == 6 || port_sel == 10)
|
||||
value &= 0xF;
|
||||
Register[port_sel] = value;
|
||||
|
||||
if (port_sel == 9)
|
||||
value &= 0x1F;
|
||||
sync_psg_state();
|
||||
|
||||
if (port_sel == 11 || port_sel == 12 || port_sel == 13)
|
||||
value &= 0x3F;
|
||||
if (port_sel == 13)
|
||||
{
|
||||
env_clock = env_per;
|
||||
|
||||
Register[port_sel] = value;
|
||||
|
||||
sync_psg_state();
|
||||
|
||||
if (port_sel == 10)
|
||||
if (env_shape == 0 || env_shape == 2 || env_shape == 3 || env_shape == 4 || env_shape == 5)
|
||||
{
|
||||
env_clock = env_per;
|
||||
|
||||
if (env_shape == 0 || env_shape == 2 || env_shape == 3 || env_shape == 4 || env_shape == 5)
|
||||
{
|
||||
env_E = 15;
|
||||
E_up_down = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
env_E = 0;
|
||||
E_up_down = 1;
|
||||
}
|
||||
env_E = 15;
|
||||
E_up_down = -1;
|
||||
}
|
||||
|
||||
return true;
|
||||
else
|
||||
{
|
||||
env_E = 0;
|
||||
E_up_down = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void generate_sound(int cycles_to_do)
|
||||
{
|
||||
// there are 4 cpu cycles for every psg cycle
|
||||
// there are 8 cpu cycles for every psg cycle
|
||||
bool sound_out_A;
|
||||
bool sound_out_B;
|
||||
bool sound_out_C;
|
||||
|
@ -259,12 +202,10 @@ namespace BizHawk.Emulation.Cores.ColecoVision
|
|||
{
|
||||
psg_clock++;
|
||||
|
||||
if (psg_clock == 4)
|
||||
if (psg_clock == 8)
|
||||
{
|
||||
psg_clock = 0;
|
||||
|
||||
total_clock++;
|
||||
|
||||
clock_A--;
|
||||
clock_B--;
|
||||
clock_C--;
|
||||
|
@ -355,10 +296,7 @@ namespace BizHawk.Emulation.Cores.ColecoVision
|
|||
}
|
||||
else
|
||||
{
|
||||
int shift_A = 3 - env_vol_A;
|
||||
if (shift_A < 0)
|
||||
shift_A = 0;
|
||||
v = (short)(sound_out_A ? (VolumeTable[env_E] >> shift_A) : 0);
|
||||
v = (short)(sound_out_A ? VolumeTable[env_E] : 0);
|
||||
}
|
||||
|
||||
if (env_vol_B == 0)
|
||||
|
@ -368,10 +306,7 @@ namespace BizHawk.Emulation.Cores.ColecoVision
|
|||
}
|
||||
else
|
||||
{
|
||||
int shift_B = 3 - env_vol_B;
|
||||
if (shift_B < 0)
|
||||
shift_B = 0;
|
||||
v += (short)(sound_out_B ? (VolumeTable[env_E] >> shift_B) : 0);
|
||||
v += (short)(sound_out_B ? VolumeTable[env_E] : 0);
|
||||
}
|
||||
|
||||
if (env_vol_C == 0)
|
||||
|
@ -380,19 +315,10 @@ namespace BizHawk.Emulation.Cores.ColecoVision
|
|||
}
|
||||
else
|
||||
{
|
||||
int shift_C = 3 - env_vol_C;
|
||||
if (shift_C < 0)
|
||||
shift_C = 0;
|
||||
v += (short)(sound_out_C ? (VolumeTable[env_E] >> shift_C) : 0);
|
||||
v += (short)(sound_out_C ? VolumeTable[env_E] : 0);
|
||||
}
|
||||
|
||||
if (v != _latchedSample)
|
||||
{
|
||||
_blip.AddDelta((uint)_sampleClock, v - _latchedSample);
|
||||
_latchedSample = v;
|
||||
}
|
||||
|
||||
_sampleClock++;
|
||||
current_sample = (short)v;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -26,7 +26,6 @@ namespace BizHawk.Emulation.Cores.ColecoVision
|
|||
|
||||
_frame++;
|
||||
_isLag = true;
|
||||
PSG.BeginFrame(_cpu.TotalExecutedCycles);
|
||||
|
||||
if (_tracer.Enabled)
|
||||
{
|
||||
|
@ -41,9 +40,42 @@ namespace BizHawk.Emulation.Cores.ColecoVision
|
|||
|
||||
bool intPending = (!tempRet1.Bit(4)) | (!tempRet2.Bit(4));
|
||||
|
||||
_vdp.ExecuteFrame(intPending);
|
||||
for (int scanLine = 0; scanLine < 262; scanLine++)
|
||||
{
|
||||
_vdp.RenderScanline(scanLine);
|
||||
|
||||
PSG.EndFrame(_cpu.TotalExecutedCycles);
|
||||
if (scanLine == 192)
|
||||
{
|
||||
_vdp.InterruptPending = true;
|
||||
|
||||
if (_vdp.EnableInterrupts)
|
||||
_cpu.NonMaskableInterrupt = true;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 228; i++)
|
||||
{
|
||||
PSG.generate_sound(1);
|
||||
if (use_SGM) { SGM_sound.generate_sound(1); }
|
||||
_cpu.ExecuteOne();
|
||||
|
||||
// pick out sound samples from the sound devies twice per scanline
|
||||
if ((i==76) || (i==152))
|
||||
{
|
||||
PSG.Sample();
|
||||
if (use_SGM) { SGM_sound.Sample(); }
|
||||
}
|
||||
}
|
||||
|
||||
_cpu.FlagI = false;
|
||||
if (intPending && scanLine == 50)
|
||||
{
|
||||
if (_vdp.EnableInterrupts)
|
||||
{
|
||||
_cpu.FlagI = true;
|
||||
intPending = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_isLag)
|
||||
{
|
||||
|
|
|
@ -1,11 +1,69 @@
|
|||
using BizHawk.Emulation.Cores.Components;
|
||||
using System;
|
||||
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Common.NumberExtensions;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.ColecoVision
|
||||
{
|
||||
public partial class ColecoVision
|
||||
public partial class ColecoVision : ISoundProvider
|
||||
{
|
||||
private SN76489 PSG;
|
||||
private AY_3_8910 SGM_sound;
|
||||
private readonly FakeSyncSound _fakeSyncSound;
|
||||
private SN76489col PSG;
|
||||
private AY_3_8910_SGM SGM_sound;
|
||||
|
||||
private short[] _sampleBuffer = new short[0];
|
||||
|
||||
public void DiscardSamples()
|
||||
{
|
||||
SGM_sound.DiscardSamples();
|
||||
PSG.DiscardSamples();
|
||||
}
|
||||
|
||||
public void GetSamplesAsync(short[] samples)
|
||||
{
|
||||
throw new NotSupportedException("Async is not available");
|
||||
}
|
||||
|
||||
public bool CanProvideAsync => false;
|
||||
|
||||
public SyncSoundMode SyncMode => SyncSoundMode.Sync;
|
||||
|
||||
public void SetSyncMode(SyncSoundMode mode)
|
||||
{
|
||||
if (mode != SyncSoundMode.Sync)
|
||||
{
|
||||
throw new InvalidOperationException("Only Sync mode is supported.");
|
||||
}
|
||||
}
|
||||
|
||||
public void GetSamplesSync(out short[] samples, out int nsamp)
|
||||
{
|
||||
nsamp = 524;
|
||||
|
||||
samples = new short[nsamp * 2];
|
||||
|
||||
for (int i = 0; i < nsamp; i++)
|
||||
{
|
||||
samples[i * 2] = PSG._sampleBuffer[i];
|
||||
samples[i * 2 + 1] = PSG._sampleBuffer[i];
|
||||
}
|
||||
|
||||
if (use_SGM)
|
||||
{
|
||||
for (int i = 0; i < nsamp; i++)
|
||||
{
|
||||
samples[i * 2] += SGM_sound._sampleBuffer[i];
|
||||
samples[i * 2 + 1] += SGM_sound._sampleBuffer[i];
|
||||
}
|
||||
}
|
||||
|
||||
DiscardSamples();
|
||||
}
|
||||
|
||||
public void GetSamples(short[] samples)
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,11 +33,8 @@ namespace BizHawk.Emulation.Cores.ColecoVision
|
|||
MemoryCallbacks = MemoryCallbacks
|
||||
};
|
||||
|
||||
PSG = new SN76489();
|
||||
_fakeSyncSound = new FakeSyncSound(PSG, 735);
|
||||
ser.Register<ISoundProvider>(_fakeSyncSound);
|
||||
|
||||
SGM_sound = new AY_3_8910();
|
||||
PSG = new SN76489col();
|
||||
SGM_sound = new AY_3_8910_SGM();
|
||||
|
||||
ControllerDeck = new ColecoVisionControllerDeck(_syncSettings.Port1, _syncSettings.Port2);
|
||||
|
||||
|
@ -61,7 +58,7 @@ namespace BizHawk.Emulation.Cores.ColecoVision
|
|||
ser.Register<ITraceable>(_tracer);
|
||||
|
||||
use_SGM = _syncSettings.UseSGM;
|
||||
Console.WriteLine(use_SGM);
|
||||
Console.WriteLine("Using the Super Game Module");
|
||||
}
|
||||
|
||||
private readonly Z80A _cpu;
|
||||
|
@ -147,7 +144,7 @@ namespace BizHawk.Emulation.Cores.ColecoVision
|
|||
|
||||
if (port == 0x52)
|
||||
{
|
||||
return SGM_sound.Register[SGM_sound.port_sel];
|
||||
return SGM_sound.ReadReg();
|
||||
}
|
||||
|
||||
if (port == 0x53)
|
||||
|
@ -196,7 +193,7 @@ namespace BizHawk.Emulation.Cores.ColecoVision
|
|||
|
||||
if (port >= 0xE0)
|
||||
{
|
||||
PSG.WritePsgData(value, _cpu.TotalExecutedCycles);
|
||||
PSG.WriteReg(value);
|
||||
}
|
||||
|
||||
if (use_SGM)
|
||||
|
@ -208,7 +205,7 @@ namespace BizHawk.Emulation.Cores.ColecoVision
|
|||
|
||||
if (port == 0x51)
|
||||
{
|
||||
SGM_sound.Register[SGM_sound.port_sel] = value;
|
||||
SGM_sound.WriteReg(value);
|
||||
}
|
||||
|
||||
if (port == 0x53)
|
||||
|
|
|
@ -0,0 +1,239 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Common.NumberExtensions;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.ColecoVision
|
||||
{
|
||||
public sealed class SN76489col
|
||||
{
|
||||
public short[] _sampleBuffer = new short[4096];
|
||||
private short current_sample;
|
||||
|
||||
public SN76489col()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
public byte[] Chan_vol = new byte[4];
|
||||
public ushort[] Chan_tone = new ushort[4];
|
||||
|
||||
public int chan_sel;
|
||||
public bool vol_tone;
|
||||
public bool noise_type;
|
||||
public int noise_rate;
|
||||
|
||||
private int _sampleClock;
|
||||
|
||||
private int psg_clock;
|
||||
|
||||
private int clock_A, clock_B, clock_C;
|
||||
|
||||
private bool A_up, B_up, C_up;
|
||||
|
||||
private int noise_clock;
|
||||
private int noise;
|
||||
|
||||
private static readonly byte[] LogScale = { 255, 203, 161, 128, 102, 86, 64, 51, 40, 32, 26, 20, 16, 13, 10, 0 };
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
clock_A = clock_B = clock_C = 0x1000;
|
||||
noise_clock = 0x10;
|
||||
chan_sel = 0;
|
||||
|
||||
// reset the shift register
|
||||
noise = 0x40000;
|
||||
|
||||
DiscardSamples();
|
||||
}
|
||||
|
||||
public void DiscardSamples()
|
||||
{
|
||||
_sampleClock = 0;
|
||||
}
|
||||
|
||||
public void Sample()
|
||||
{
|
||||
_sampleBuffer[_sampleClock] = current_sample;
|
||||
_sampleClock++;
|
||||
}
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
ser.BeginSection("SN76489");
|
||||
|
||||
ser.Sync("Chan_vol", ref Chan_vol, false);
|
||||
ser.Sync("Chan_tone", ref Chan_tone, false);
|
||||
|
||||
ser.Sync("Chan_sel", ref chan_sel);
|
||||
ser.Sync("vol_tone", ref vol_tone);
|
||||
ser.Sync("noise_type", ref noise_type);
|
||||
ser.Sync("noise_rate", ref noise_rate);
|
||||
|
||||
ser.Sync("Clock_A", ref clock_A);
|
||||
ser.Sync("Clock_B", ref clock_B);
|
||||
ser.Sync("Clock_C", ref clock_C);
|
||||
ser.Sync("noise_clock", ref noise_clock);
|
||||
|
||||
ser.Sync("psg_clock", ref psg_clock);
|
||||
ser.Sync("sample_clock", ref _sampleClock);
|
||||
|
||||
ser.Sync("A_up", ref A_up);
|
||||
ser.Sync("B_up", ref B_up);
|
||||
ser.Sync("C_up", ref C_up);
|
||||
ser.Sync("noise", ref noise);
|
||||
|
||||
ser.EndSection();
|
||||
}
|
||||
|
||||
public byte ReadReg()
|
||||
{
|
||||
// not used, reading not allowed, just return 0xFF
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
public void WriteReg(byte value)
|
||||
{
|
||||
// if bit 7 is set, change the latch, otherwise modify the currently latched register
|
||||
if (value.Bit(7))
|
||||
{
|
||||
chan_sel = (value >> 5) & 3;
|
||||
vol_tone = value.Bit(4);
|
||||
|
||||
if (vol_tone)
|
||||
{
|
||||
Chan_vol[chan_sel] &= 0xF0;
|
||||
Chan_vol[chan_sel] |= (byte)(value & 0xF);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (chan_sel < 3)
|
||||
{
|
||||
Chan_tone[chan_sel] &= 0x3F0;
|
||||
Chan_tone[chan_sel] |= (ushort)(value & 0xF);
|
||||
}
|
||||
else
|
||||
{
|
||||
noise_type = value.Bit(2);
|
||||
noise_rate = value & 3;
|
||||
|
||||
// reset the shift register
|
||||
noise = 0x40000;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (vol_tone)
|
||||
{
|
||||
Chan_vol[chan_sel] &= 0xF;
|
||||
Chan_vol[chan_sel] |= (byte)((value & 0xF) << 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (chan_sel < 3)
|
||||
{
|
||||
Chan_tone[chan_sel] &= 0xF;
|
||||
Chan_tone[chan_sel] |= (ushort)((value & 0x3F) << 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
noise_type = value.Bit(2);
|
||||
noise_rate = value & 3;
|
||||
|
||||
// reset the shift register
|
||||
noise = 0x40000;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void generate_sound(int cycles_to_do)
|
||||
{
|
||||
// there are 16 cpu cycles for every psg cycle
|
||||
|
||||
for (int i = 0; i < cycles_to_do; i++)
|
||||
{
|
||||
psg_clock++;
|
||||
|
||||
if (psg_clock == 16)
|
||||
{
|
||||
psg_clock = 0;
|
||||
|
||||
clock_A--;
|
||||
clock_B--;
|
||||
clock_C--;
|
||||
|
||||
// clock noise
|
||||
if (noise_clock == 0)
|
||||
{
|
||||
if (noise_type)
|
||||
{
|
||||
int bit = (noise & 1) ^ ((noise >> 1) & 1);
|
||||
noise = noise >> 1;
|
||||
noise |= bit << 14;
|
||||
}
|
||||
else
|
||||
{
|
||||
int bit = noise & 1;
|
||||
noise = noise >> 1;
|
||||
noise |= bit << 14;
|
||||
}
|
||||
|
||||
if (noise_rate == 0)
|
||||
{
|
||||
noise_clock = 0x10;
|
||||
}
|
||||
else if (noise_rate == 1)
|
||||
{
|
||||
noise_clock = 0x120;
|
||||
}
|
||||
else if (noise_rate == 2)
|
||||
{
|
||||
noise_clock = 0x40;
|
||||
}
|
||||
else
|
||||
{
|
||||
noise_clock = Chan_tone[2] + 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (clock_A == 0)
|
||||
{
|
||||
A_up = !A_up;
|
||||
clock_A = Chan_tone[0] + 1;
|
||||
}
|
||||
|
||||
if (clock_B == 0)
|
||||
{
|
||||
B_up = !B_up;
|
||||
clock_B = Chan_tone[1] + 1;
|
||||
}
|
||||
|
||||
if (clock_C == 0)
|
||||
{
|
||||
C_up = !C_up;
|
||||
clock_C = Chan_tone[2] + 1;
|
||||
}
|
||||
|
||||
// now calculate the volume of each channel and add them together
|
||||
// the magic number 42 is to make the volume comparable to the MSG volume
|
||||
int v;
|
||||
|
||||
v = (short)(A_up ? LogScale[Chan_vol[0]] * 42 : 0);
|
||||
|
||||
v += (short)(B_up ? LogScale[Chan_vol[1]] * 42 : 0);
|
||||
|
||||
v += (short)(C_up ? LogScale[Chan_vol[2]] * 42 : 0);
|
||||
|
||||
v += (short)(noise.Bit(0) ? LogScale[Chan_vol[3]] * 42 : 0);
|
||||
|
||||
current_sample = (short)v;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,11 +23,11 @@ namespace BizHawk.Emulation.Cores.ColecoVision
|
|||
private bool Mode3Bit => (Registers[1] & 8) > 0;
|
||||
private bool EnableDoubledSprites => (Registers[1] & 1) > 0;
|
||||
private bool EnableLargeSprites => (Registers[1] & 2) > 0;
|
||||
private bool EnableInterrupts => (Registers[1] & 32) > 0;
|
||||
public bool EnableInterrupts => (Registers[1] & 32) > 0;
|
||||
private bool DisplayOn => (Registers[1] & 64) > 0;
|
||||
private bool Mode16k => (Registers[1] & 128) > 0;
|
||||
|
||||
private bool InterruptPending
|
||||
public bool InterruptPending
|
||||
{
|
||||
get { return (StatusByte & 0x80) != 0; }
|
||||
set { StatusByte = (byte)((StatusByte & ~0x02) | (value ? 0x80 : 0x00)); }
|
||||
|
@ -39,38 +39,6 @@ namespace BizHawk.Emulation.Cores.ColecoVision
|
|||
private int TmsPatternNameTableBase;
|
||||
private int TmsSpriteAttributeBase;
|
||||
|
||||
public void ExecuteFrame(bool Int_pending)
|
||||
{
|
||||
for (int scanLine = 0; scanLine < 262; scanLine++)
|
||||
{
|
||||
RenderScanline(scanLine);
|
||||
|
||||
if (scanLine == 192)
|
||||
{
|
||||
|
||||
InterruptPending = true;
|
||||
|
||||
if (EnableInterrupts)
|
||||
Cpu.NonMaskableInterrupt = true;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 228; i++)
|
||||
{
|
||||
Cpu.ExecuteOne();
|
||||
}
|
||||
|
||||
Cpu.FlagI = false;
|
||||
if (Int_pending && scanLine==50)
|
||||
{
|
||||
if (EnableInterrupts)
|
||||
{
|
||||
Cpu.FlagI = true;
|
||||
Int_pending = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void WriteVdpControl(byte value)
|
||||
{
|
||||
if (VdpWaitingForLatchByte)
|
||||
|
@ -172,7 +140,7 @@ namespace BizHawk.Emulation.Cores.ColecoVision
|
|||
else TmsMode = 0;
|
||||
}
|
||||
|
||||
private void RenderScanline(int scanLine)
|
||||
public void RenderScanline(int scanLine)
|
||||
{
|
||||
if (scanLine >= 192)
|
||||
return;
|
||||
|
|
Loading…
Reference in New Issue