StoicGoose.Unity/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannel3.cs

89 lines
1.8 KiB
C#

namespace StoicGoose.Core.Sound
{
/* Channel 3, has optional sweep */
public sealed class SoundChannel3
{
const int counterReload = 2048;
const int sweepReload = 32 * 256;
ushort counter;
byte pointer;
public byte OutputLeft { get; set; }
public byte OutputRight { get; set; }
int sweepCounter;
int sweepCycles;
readonly WaveTableReadDelegate waveTableReadDelegate;
/* REG_SND_CH3_PITCH */
public ushort Pitch { get; set; }
/* REG_SND_CH3_VOL */
public byte VolumeLeft { get; set; }
public byte VolumeRight { get; set; }
/* REG_SND_CTRL */
public bool IsEnabled { get; set; }
public bool IsSweepEnabled { get; set; }
/* REG_SND_SWEEP_VALUE */
public sbyte SweepValue { get; set; }
/* REG_SND_SWEEP_TIME */
public byte SweepTime { get; set; }
public SoundChannel3(WaveTableReadDelegate waveTableRead) => waveTableReadDelegate = waveTableRead;
public void Reset()
{
counter = counterReload;
pointer = 0;
OutputLeft = OutputRight = 0;
Pitch = 0;
VolumeLeft = VolumeRight = 0;
IsEnabled = false;
IsSweepEnabled = false;
sweepCounter = 0;
sweepCycles = sweepReload;
SweepValue = 0;
SweepTime = 0;
}
public void Step()
{
if (IsSweepEnabled)
{
sweepCycles--;
if (sweepCycles == 0)
{
sweepCounter--;
if (sweepCounter <= 0)
{
sweepCounter = SweepTime;
Pitch = (ushort)(Pitch + SweepValue);
}
}
sweepCycles = sweepReload;
}
counter--;
if (counter == Pitch)
{
var data = waveTableReadDelegate((ushort)(pointer >> 1));
if ((pointer & 0b1) == 0b1) data >>= 4;
data &= 0x0F;
OutputLeft = (byte)(data * VolumeLeft);
OutputRight = (byte)(data * VolumeRight);
pointer++;
pointer &= 0b11111;
counter = counterReload;
}
}
}
}