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

89 lines
2.0 KiB
C#

namespace StoicGoose.Core.Sound
{
/* Channel 4, supports noise */
public sealed class SoundChannel4
{
const int counterReload = 2048;
readonly static byte[] noiseLfsrTaps = { 14, 10, 13, 4, 8, 6, 9, 11 };
ushort counter;
byte pointer;
public byte OutputLeft { get; set; }
public byte OutputRight { get; set; }
readonly WaveTableReadDelegate waveTableReadDelegate;
/* REG_SND_CH4_PITCH */
public ushort Pitch { get; set; }
/* REG_SND_CH4_VOL */
public byte VolumeLeft { get; set; }
public byte VolumeRight { get; set; }
/* REG_SND_CTRL */
public bool IsEnabled { get; set; }
public bool IsNoiseEnabled { get; set; }
/* REG_SND_NOISE */
public byte NoiseMode { get; set; }
public bool NoiseReset { get; set; }
public bool NoiseEnable { get; set; }
/* REG_SND_RANDOM */
public ushort NoiseLfsr { get; set; }
public SoundChannel4(WaveTableReadDelegate waveTableRead) => waveTableReadDelegate = waveTableRead;
public void Reset()
{
counter = counterReload;
pointer = 0;
OutputLeft = OutputRight = 0;
Pitch = 0;
VolumeLeft = VolumeRight = 0;
IsEnabled = false;
IsNoiseEnabled = false;
NoiseMode = 0;
NoiseReset = NoiseEnable = false;
NoiseLfsr = 0;
}
public void Step()
{
counter--;
if (counter == Pitch)
{
if (NoiseEnable)
{
var tap = noiseLfsrTaps[NoiseMode];
var noise = (1 ^ (NoiseLfsr >> 7) ^ (NoiseLfsr >> tap)) & 0b1;
NoiseLfsr = (ushort)(((NoiseLfsr << 1) | noise) & 0x7FFF);
}
var data = IsNoiseEnabled ? ((NoiseLfsr & 0b1) * 0x0F) : waveTableReadDelegate((ushort)(pointer >> 1));
if (!IsNoiseEnabled)
{
if ((pointer & 0b1) == 0b1) data >>= 4;
data &= 0x0F;
}
OutputLeft = (byte)(data * VolumeLeft);
OutputRight = (byte)(data * VolumeRight);
if (NoiseReset)
{
NoiseLfsr = 0;
OutputLeft = OutputRight = 0;
NoiseReset = false;
}
pointer++;
pointer &= 0b11111;
counter = counterReload;
}
}
}
}