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

76 lines
1.8 KiB
C#

namespace StoicGoose.Core.Sound
{
/* Channel 2, supports PCM voice */
public sealed class SoundChannel2
{
const int counterReload = 2048;
ushort counter;
byte pointer;
public byte OutputLeft { get; set; }
public byte OutputRight { get; set; }
readonly WaveTableReadDelegate waveTableReadDelegate;
/* REG_SND_CH2_PITCH */
public ushort Pitch { get; set; }
/* REG_SND_CH2_VOL */
public byte VolumeLeft { get; set; }
public byte VolumeRight { get; set; }
/* REG_SND_CTRL */
public bool IsEnabled { get; set; }
public bool IsVoiceEnabled { get; set; }
/* REG_SND_VOICE_CTRL */
public bool PcmRightFull { get; set; }
public bool PcmRightHalf { get; set; }
public bool PcmLeftFull { get; set; }
public bool PcmLeftHalf { get; set; }
public SoundChannel2(WaveTableReadDelegate waveTableRead) => waveTableReadDelegate = waveTableRead;
public void Reset()
{
counter = counterReload;
pointer = 0;
OutputLeft = OutputRight = 0;
Pitch = 0;
VolumeLeft = VolumeRight = 0;
IsEnabled = false;
IsVoiceEnabled = false;
PcmRightFull = PcmRightHalf = PcmLeftFull = PcmLeftHalf = false;
}
public void Step()
{
if (IsVoiceEnabled)
{
var pcm = (ushort)(VolumeLeft << 4 | VolumeRight);
OutputLeft = (byte)(PcmLeftFull ? pcm : (PcmLeftHalf ? pcm >> 1 : 0));
OutputRight = (byte)(PcmRightFull ? pcm : (PcmRightHalf ? pcm >> 1 : 0));
}
else
{
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;
}
}
}
}
}