AxibugEmuOnline/AxibugEmuOnline.Client/Assets/MyNes.Core/MMC5Sqr.cs
2024-07-03 18:22:22 +08:00

215 lines
5.1 KiB
C#

using System.IO;
namespace MyNes.Core
{
internal class MMC5Sqr
{
private byte[][] duty_cycle_sequences = new byte[4][]
{
new byte[8] { 0, 0, 0, 0, 0, 0, 0, 1 },
new byte[8] { 0, 0, 0, 0, 0, 0, 1, 1 },
new byte[8] { 0, 0, 0, 0, 1, 1, 1, 1 },
new byte[8] { 1, 1, 1, 1, 1, 1, 0, 0 }
};
private byte[] duration_table = new byte[32]
{
10, 254, 20, 2, 40, 4, 80, 6, 160, 8,
60, 10, 14, 12, 26, 14, 12, 16, 24, 18,
48, 20, 96, 22, 192, 24, 72, 26, 16, 28,
32, 30
};
private byte duty_cycle;
private bool length_halt;
private bool constant_volume_envelope;
private byte volume_devider_period;
private int timer;
private int period_devider;
private byte seqencer;
private bool length_enabled;
private int length_counter;
private bool envelope_start_flag;
private byte envelope_devider;
private byte envelope_decay_level_counter;
private byte envelope;
internal int output;
internal bool Outputable;
internal void HardReset()
{
duty_cycle = 0;
length_halt = false;
constant_volume_envelope = false;
volume_devider_period = 0;
timer = 0;
period_devider = 0;
seqencer = 0;
length_enabled = false;
length_counter = 0;
envelope_start_flag = false;
envelope_devider = 0;
envelope_decay_level_counter = 0;
envelope = 0;
}
internal void SoftReset()
{
HardReset();
}
internal void Clock()
{
period_devider--;
if (period_devider > 0)
{
return;
}
period_devider = timer + 1;
if (length_counter > 0)
{
if (Outputable)
{
output = duty_cycle_sequences[duty_cycle][seqencer] * envelope;
}
}
else
{
output = 0;
}
if (seqencer == 0)
{
seqencer = 7;
}
else
{
seqencer--;
}
}
internal void ClockLength()
{
if (length_counter > 0 && !length_halt)
{
length_counter--;
}
}
internal void ClockEnvelope()
{
if (envelope_start_flag)
{
envelope_start_flag = false;
envelope_decay_level_counter = 15;
envelope_devider = (byte)(volume_devider_period + 1);
}
else if (envelope_devider > 0)
{
envelope_devider--;
}
else
{
envelope_devider = (byte)(volume_devider_period + 1);
if (envelope_decay_level_counter > 0)
{
envelope_decay_level_counter--;
}
else if (length_halt)
{
envelope_decay_level_counter = 15;
}
}
envelope = (constant_volume_envelope ? volume_devider_period : envelope_decay_level_counter);
}
internal void Write0(ref byte value)
{
duty_cycle = (byte)((value & 0xC0) >> 6);
volume_devider_period = (byte)(value & 0xFu);
length_halt = (value & 0x20) != 0;
constant_volume_envelope = (value & 0x10) != 0;
envelope = (constant_volume_envelope ? volume_devider_period : envelope_decay_level_counter);
}
internal void Write2(ref byte value)
{
timer = (timer & 0xFF00) | value;
}
internal void Write3(ref byte value)
{
timer = (timer & 0xFF) | ((value & 7) << 8);
if (length_enabled)
{
length_counter = duration_table[value >> 3];
}
seqencer = 0;
envelope_start_flag = true;
}
internal void WriteEnabled(bool enabled)
{
length_enabled = enabled;
if (!length_enabled)
{
length_counter = 0;
}
}
internal bool ReadEnable()
{
return length_counter > 0;
}
internal void WriteStateData(ref BinaryWriter bin)
{
bin.Write(duty_cycle);
bin.Write(length_halt);
bin.Write(constant_volume_envelope);
bin.Write(volume_devider_period);
bin.Write(timer);
bin.Write(period_devider);
bin.Write(seqencer);
bin.Write(length_enabled);
bin.Write(length_counter);
bin.Write(envelope_start_flag);
bin.Write(envelope_devider);
bin.Write(envelope_decay_level_counter);
bin.Write(envelope);
bin.Write(output);
}
internal void ReadStateData(ref BinaryReader bin)
{
duty_cycle = bin.ReadByte();
length_halt = bin.ReadBoolean();
constant_volume_envelope = bin.ReadBoolean();
volume_devider_period = bin.ReadByte();
timer = bin.ReadInt32();
period_devider = bin.ReadInt32();
seqencer = bin.ReadByte();
length_enabled = bin.ReadBoolean();
length_counter = bin.ReadInt32();
envelope_start_flag = bin.ReadBoolean();
envelope_devider = bin.ReadByte();
envelope_decay_level_counter = bin.ReadByte();
envelope = bin.ReadByte();
output = bin.ReadInt32();
}
}
}