A2600: Refactor audio and savestate it.
This commit is contained in:
parent
c48d5be02a
commit
e60896c1b7
|
@ -126,10 +126,9 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
|
|||
private HMoveData _hmove;
|
||||
private BallData _ball;
|
||||
|
||||
private readonly Audio[] AUD = { new Audio(), new Audio() };
|
||||
private readonly Audio AUD =new Audio();
|
||||
|
||||
// current audio register state used to sample correct positions in the scanline (clrclk 0 and 114)
|
||||
////public byte[] current_audio_register = new byte[6];
|
||||
public readonly short[] LocalAudioCycles = new short[2000];
|
||||
|
||||
private static int ReverseBits(int value, int bits)
|
||||
|
@ -809,8 +808,8 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
|
|||
{
|
||||
if (AudioClocks < 2000)
|
||||
{
|
||||
LocalAudioCycles[AudioClocks] += (short)(AUD[0].Cycle() / 2);
|
||||
LocalAudioCycles[AudioClocks] += (short)(AUD[1].Cycle() / 2);
|
||||
LocalAudioCycles[AudioClocks] += (short)(AUD.Cycle_L() / 2);
|
||||
LocalAudioCycles[AudioClocks] += (short)(AUD.Cycle_R() / 2);
|
||||
AudioClocks++;
|
||||
}
|
||||
}
|
||||
|
@ -1258,27 +1257,27 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
|
|||
}
|
||||
else if (maskedAddr == 0x15) // AUDC0
|
||||
{
|
||||
AUD[0].AUDC = (byte)(value & 15);
|
||||
AUD.AUDC_L = (byte)(value & 15);
|
||||
}
|
||||
else if (maskedAddr == 0x16) // AUDC1
|
||||
{
|
||||
AUD[1].AUDC = (byte)(value & 15);
|
||||
AUD.AUDC_R = (byte)(value & 15);
|
||||
}
|
||||
else if (maskedAddr == 0x17) // AUDF0
|
||||
{
|
||||
AUD[0].AUDF = (byte)((value & 31) + 1);
|
||||
AUD.AUDF_L = (byte)((value & 31) + 1);
|
||||
}
|
||||
else if (maskedAddr == 0x18) // AUDF1
|
||||
{
|
||||
AUD[1].AUDF = (byte)((value & 31) + 1);
|
||||
AUD.AUDF_R = (byte)((value & 31) + 1);
|
||||
}
|
||||
else if (maskedAddr == 0x19) // AUDV0
|
||||
{
|
||||
AUD[0].AUDV = (byte)(value & 15);
|
||||
AUD.AUDV_L = (byte)(value & 15);
|
||||
}
|
||||
else if (maskedAddr == 0x1A) // AUDV1
|
||||
{
|
||||
AUD[1].AUDV = (byte)(value & 15);
|
||||
AUD.AUDV_R = (byte)(value & 15);
|
||||
}
|
||||
else if (maskedAddr == 0x1B) // GRP0
|
||||
{
|
||||
|
|
|
@ -8,88 +8,98 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
|
|||
public class Audio
|
||||
{
|
||||
// noise/division control
|
||||
public byte AUDC = 0;
|
||||
public byte AUDC_L = 0;
|
||||
public byte AUDC_R = 0;
|
||||
|
||||
// frequency divider
|
||||
public byte AUDF = 1;
|
||||
public byte AUDF_L = 1;
|
||||
public byte AUDF_R = 1;
|
||||
|
||||
// volume
|
||||
public byte AUDV = 0;
|
||||
public byte AUDV_L = 0;
|
||||
public byte AUDV_R = 0;
|
||||
|
||||
// 2 state counter
|
||||
private bool sr1 = true;
|
||||
private bool sr1_L = true;
|
||||
private bool sr1_R = true;
|
||||
|
||||
// 4 bit shift register
|
||||
private int sr4 = 0x0f;
|
||||
private int sr4_L = 0x0f;
|
||||
private int sr4_R = 0x0f;
|
||||
|
||||
// 5 bit shift register
|
||||
private int sr5 = 0x1f;
|
||||
private int sr5_L = 0x1f;
|
||||
private int sr5_R = 0x1f;
|
||||
|
||||
// 9 bit shift register
|
||||
private int sr9 = 0x1ff;
|
||||
private int sr9_L = 0x1ff;
|
||||
private int sr9_R = 0x1ff;
|
||||
|
||||
// 3 state counter
|
||||
private int sr3 = 2;
|
||||
private int sr3_L = 2;
|
||||
private int sr3_R = 2;
|
||||
|
||||
// counter based off AUDF
|
||||
private byte freqcnt;
|
||||
private byte freqcnt_L;
|
||||
private byte freqcnt_R;
|
||||
|
||||
// latched audio value
|
||||
private bool on = true;
|
||||
private bool on_L = true;
|
||||
private bool on_R = true;
|
||||
|
||||
private bool Run3()
|
||||
private bool Run3_L()
|
||||
{
|
||||
sr3++;
|
||||
if (sr3 == 3)
|
||||
sr3_L++;
|
||||
if (sr3_L == 3)
|
||||
{
|
||||
sr3 = 0;
|
||||
sr3_L = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool Run4()
|
||||
private bool Run4_L()
|
||||
{
|
||||
bool ret = (sr4 & 1) != 0;
|
||||
bool c = ((sr4 & 1) != 0) ^ ((sr4 & 2) != 0);
|
||||
sr4 = (sr4 >> 1) | (c ? 8 : 0);
|
||||
bool ret = (sr4_L & 1) != 0;
|
||||
bool c = ((sr4_L & 1) != 0) ^ ((sr4_L & 2) != 0);
|
||||
sr4_L = (sr4_L >> 1) | (c ? 8 : 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
private bool Run5()
|
||||
private bool Run5_L()
|
||||
{
|
||||
bool ret = (sr5 & 1) != 0;
|
||||
bool c = ((sr5 & 1) != 0) ^ ((sr5 & 4) != 0);
|
||||
sr5 = (sr5 >> 1) | (c ? 16 : 0);
|
||||
bool ret = (sr5_L & 1) != 0;
|
||||
bool c = ((sr5_L & 1) != 0) ^ ((sr5_L & 4) != 0);
|
||||
sr5_L = (sr5_L >> 1) | (c ? 16 : 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
private bool One4()
|
||||
private bool One4_L()
|
||||
{
|
||||
bool ret = (sr4 & 1) != 0;
|
||||
sr4 = (sr4 >> 1) | 8;
|
||||
bool ret = (sr4_L & 1) != 0;
|
||||
sr4_L = (sr4_L >> 1) | 8;
|
||||
return ret;
|
||||
}
|
||||
|
||||
private bool One5()
|
||||
private bool One5_L()
|
||||
{
|
||||
bool ret = (sr5 & 1) != 0;
|
||||
sr5 = (sr5 >> 1) | 16;
|
||||
bool ret = (sr5_L & 1) != 0;
|
||||
sr5_L = (sr5_L >> 1) | 16;
|
||||
return ret;
|
||||
}
|
||||
|
||||
private bool Run1()
|
||||
private bool Run1_L()
|
||||
{
|
||||
sr1 = !sr1;
|
||||
return !sr1;
|
||||
sr1_L = !sr1_L;
|
||||
return !sr1_L;
|
||||
}
|
||||
|
||||
private bool Run9()
|
||||
private bool Run9_L()
|
||||
{
|
||||
bool ret = (sr9 & 1) != 0;
|
||||
bool c = ((sr9 & 1) != 0) ^ ((sr9 & 16) != 0);
|
||||
sr9 = (sr9 >> 1) | (c ? 256 : 0);
|
||||
bool ret = (sr9_L & 1) != 0;
|
||||
bool c = ((sr9_L & 1) != 0) ^ ((sr9_L & 16) != 0);
|
||||
sr9_L = (sr9_L >> 1) | (c ? 256 : 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -97,92 +107,92 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
|
|||
/// call me approx 31k times a second
|
||||
/// </summary>
|
||||
/// <returns>16 bit audio sample</returns>
|
||||
public short Cycle()
|
||||
public short Cycle_L()
|
||||
{
|
||||
if (++freqcnt >= AUDF)
|
||||
if (++freqcnt_L >= AUDF_L)
|
||||
{
|
||||
freqcnt = 0;
|
||||
switch (AUDC)
|
||||
freqcnt_L = 0;
|
||||
switch (AUDC_L)
|
||||
{
|
||||
case 0x00:
|
||||
case 0x0b:
|
||||
// Both have a 1 s
|
||||
One5();
|
||||
on = One4();
|
||||
One5_L();
|
||||
on_L = One4_L();
|
||||
break;
|
||||
|
||||
case 0x01:
|
||||
// Both run, but the 5 bit is ignored
|
||||
on = Run4();
|
||||
on_L = Run4_L();
|
||||
//Run5();
|
||||
break;
|
||||
case 0x02:
|
||||
if ((sr5 & 0x0f) == 0 || (sr5 & 0x0f) == 0x0f)
|
||||
if ((sr5_L & 0x0f) == 0 || (sr5_L & 0x0f) == 0x0f)
|
||||
{
|
||||
on = Run4();
|
||||
on_L = Run4_L();
|
||||
}
|
||||
|
||||
Run5();
|
||||
Run5_L();
|
||||
break;
|
||||
case 0x03:
|
||||
if (Run5())
|
||||
if (Run5_L())
|
||||
{
|
||||
on = Run4();
|
||||
on_L = Run4_L();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 0x04:
|
||||
Run5();
|
||||
One4();
|
||||
on = Run1();
|
||||
Run5_L();
|
||||
One4_L();
|
||||
on_L = Run1_L();
|
||||
break;
|
||||
|
||||
case 0x05:
|
||||
One5();
|
||||
Run4();
|
||||
on = Run1();
|
||||
One5_L();
|
||||
Run4_L();
|
||||
on_L = Run1_L();
|
||||
break;
|
||||
|
||||
case 0x06:
|
||||
case 0x0a:
|
||||
Run5();
|
||||
if ((sr5 & 0x0f) == 0)
|
||||
Run5_L();
|
||||
if ((sr5_L & 0x0f) == 0)
|
||||
{
|
||||
on = false;
|
||||
on_L = false;
|
||||
}
|
||||
else if ((sr5 & 0x0f) == 0x0f)
|
||||
else if ((sr5_L & 0x0f) == 0x0f)
|
||||
{
|
||||
on = true;
|
||||
on_L = true;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 0x07:
|
||||
case 0x09:
|
||||
on = Run5();
|
||||
on_L = Run5_L();
|
||||
break;
|
||||
|
||||
case 0x08:
|
||||
on = Run9();
|
||||
on_L = Run9_L();
|
||||
break;
|
||||
case 0x0c:
|
||||
case 0x0d:
|
||||
if (Run3())
|
||||
if (Run3_L())
|
||||
{
|
||||
on = Run1();
|
||||
on_L = Run1_L();
|
||||
}
|
||||
|
||||
break;
|
||||
case 0x0e:
|
||||
if (Run3())
|
||||
if (Run3_L())
|
||||
{
|
||||
goto case 0x06;
|
||||
}
|
||||
|
||||
break;
|
||||
case 0x0f:
|
||||
if (Run3())
|
||||
if (Run3_L())
|
||||
{
|
||||
goto case 0x07;
|
||||
}
|
||||
|
@ -191,21 +201,189 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
|
|||
}
|
||||
}
|
||||
|
||||
return (short)(on ? AUDV * 1092 : 0);
|
||||
return (short)(on_L ? AUDV_L * 1092 : 0);
|
||||
}
|
||||
|
||||
private bool Run3_R()
|
||||
{
|
||||
sr3_R++;
|
||||
if (sr3_R == 3)
|
||||
{
|
||||
sr3_R = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool Run4_R()
|
||||
{
|
||||
bool ret = (sr4_R & 1) != 0;
|
||||
bool c = ((sr4_R & 1) != 0) ^ ((sr4_R & 2) != 0);
|
||||
sr4_R = (sr4_R >> 1) | (c ? 8 : 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
private bool Run5_R()
|
||||
{
|
||||
bool ret = (sr5_R & 1) != 0;
|
||||
bool c = ((sr5_R & 1) != 0) ^ ((sr5_R & 4) != 0);
|
||||
sr5_R = (sr5_R >> 1) | (c ? 16 : 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
private bool One4_R()
|
||||
{
|
||||
bool ret = (sr4_R & 1) != 0;
|
||||
sr4_R = (sr4_R >> 1) | 8;
|
||||
return ret;
|
||||
}
|
||||
|
||||
private bool One5_R()
|
||||
{
|
||||
bool ret = (sr5_R & 1) != 0;
|
||||
sr5_R = (sr5_R >> 1) | 16;
|
||||
return ret;
|
||||
}
|
||||
|
||||
private bool Run1_R()
|
||||
{
|
||||
sr1_R = !sr1_R;
|
||||
return !sr1_R;
|
||||
}
|
||||
|
||||
private bool Run9_R()
|
||||
{
|
||||
bool ret = (sr9_R & 1) != 0;
|
||||
bool c = ((sr9_R & 1) != 0) ^ ((sr9_R & 16) != 0);
|
||||
sr9_R = (sr9_R >> 1) | (c ? 256 : 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// call me approx 31k times a second
|
||||
/// </summary>
|
||||
/// <returns>16 bit audio sample</returns>
|
||||
public short Cycle_R()
|
||||
{
|
||||
if (++freqcnt_R >= AUDF_R)
|
||||
{
|
||||
freqcnt_R = 0;
|
||||
switch (AUDC_R)
|
||||
{
|
||||
case 0x00:
|
||||
case 0x0b:
|
||||
// Both have a 1 s
|
||||
One5_R();
|
||||
on_R = One4_R();
|
||||
break;
|
||||
|
||||
case 0x01:
|
||||
// Both run, but the 5 bit is ignored
|
||||
on_R = Run4_R();
|
||||
//Run5();
|
||||
break;
|
||||
case 0x02:
|
||||
if ((sr5_R & 0x0f) == 0 || (sr5_R & 0x0f) == 0x0f)
|
||||
{
|
||||
on_R = Run4_R();
|
||||
}
|
||||
|
||||
Run5_R();
|
||||
break;
|
||||
case 0x03:
|
||||
if (Run5_R())
|
||||
{
|
||||
on_R = Run4_R();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 0x04:
|
||||
Run5_R();
|
||||
One4_R();
|
||||
on_R = Run1_R();
|
||||
break;
|
||||
|
||||
case 0x05:
|
||||
One5_R();
|
||||
Run4_R();
|
||||
on_R = Run1_R();
|
||||
break;
|
||||
|
||||
case 0x06:
|
||||
case 0x0a:
|
||||
Run5_R();
|
||||
if ((sr5_R & 0x0f) == 0)
|
||||
{
|
||||
on_R = false;
|
||||
}
|
||||
else if ((sr5_R & 0x0f) == 0x0f)
|
||||
{
|
||||
on_R = true;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 0x07:
|
||||
case 0x09:
|
||||
on_R = Run5_R();
|
||||
break;
|
||||
|
||||
case 0x08:
|
||||
on_R = Run9_R();
|
||||
break;
|
||||
case 0x0c:
|
||||
case 0x0d:
|
||||
if (Run3_R())
|
||||
{
|
||||
on_R = Run1_R();
|
||||
}
|
||||
|
||||
break;
|
||||
case 0x0e:
|
||||
if (Run3_R())
|
||||
{
|
||||
goto case 0x06;
|
||||
}
|
||||
|
||||
break;
|
||||
case 0x0f:
|
||||
if (Run3_R())
|
||||
{
|
||||
goto case 0x07;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (short)(on_R ? AUDV_R * 1092 : 0);
|
||||
}
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
ser.Sync(nameof(AUDC), ref AUDC);
|
||||
ser.Sync(nameof(AUDF), ref AUDF);
|
||||
ser.Sync(nameof(AUDV), ref AUDV);
|
||||
ser.Sync(nameof(sr1), ref sr1);
|
||||
ser.Sync(nameof(sr3), ref sr3);
|
||||
ser.Sync(nameof(sr4), ref sr4);
|
||||
ser.Sync(nameof(sr5), ref sr5);
|
||||
ser.Sync(nameof(sr9), ref sr9);
|
||||
ser.Sync(nameof(freqcnt), ref freqcnt);
|
||||
ser.Sync(nameof(on), ref on);
|
||||
ser.Sync(nameof(AUDC_L), ref AUDC_L);
|
||||
ser.Sync(nameof(AUDF_L), ref AUDF_L);
|
||||
ser.Sync(nameof(AUDV_L), ref AUDV_L);
|
||||
ser.Sync(nameof(sr1_L), ref sr1_L);
|
||||
ser.Sync(nameof(sr3_L), ref sr3_L);
|
||||
ser.Sync(nameof(sr4_L), ref sr4_L);
|
||||
ser.Sync(nameof(sr5_L), ref sr5_L);
|
||||
ser.Sync(nameof(sr9_L), ref sr9_L);
|
||||
ser.Sync(nameof(freqcnt_L), ref freqcnt_L);
|
||||
ser.Sync(nameof(on_L), ref on_L);
|
||||
|
||||
ser.Sync(nameof(AUDC_R), ref AUDC_R);
|
||||
ser.Sync(nameof(AUDF_R), ref AUDF_R);
|
||||
ser.Sync(nameof(AUDV_R), ref AUDV_R);
|
||||
ser.Sync(nameof(sr1_R), ref sr1_R);
|
||||
ser.Sync(nameof(sr3_R), ref sr3_R);
|
||||
ser.Sync(nameof(sr4_R), ref sr4_R);
|
||||
ser.Sync(nameof(sr5_R), ref sr5_R);
|
||||
ser.Sync(nameof(sr9_R), ref sr9_R);
|
||||
ser.Sync(nameof(freqcnt_R), ref freqcnt_R);
|
||||
ser.Sync(nameof(on_R), ref on_R);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,6 +72,10 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
|
|||
ser.Sync(nameof(AudioClocks), ref AudioClocks);
|
||||
ser.Sync(nameof(New_Frame), ref New_Frame);
|
||||
|
||||
ser.BeginSection("Audio");
|
||||
AUD.SyncState(ser);
|
||||
ser.EndSection();
|
||||
|
||||
ser.BeginSection("Player0");
|
||||
_player0.SyncState(ser);
|
||||
ser.EndSection();
|
||||
|
|
Loading…
Reference in New Issue