BizHawk/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/Sid.Envelope.cs

256 lines
4.9 KiB
C#

using BizHawk.Common;
namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
{
public sealed partial class Sid
{
private sealed class Envelope
{
[SaveState.DoNotSave] private const int StateAttack = 0;
[SaveState.DoNotSave] private const int StateDecay = 1;
[SaveState.DoNotSave] private const int StateRelease = 2;
private int _attack;
private int _decay;
private bool _delay;
private int _envCounter;
private int _expCounter;
private int _expPeriod;
private bool _freeze;
private int _lfsr;
private bool _gate;
private int _rate;
private int _release;
private int _state;
private int _sustain;
private static readonly int[] AdsrTable = {
0x7F00, 0x0006, 0x003C, 0x0330,
0x20C0, 0x6755, 0x3800, 0x500E,
0x1212, 0x0222, 0x1848, 0x59B8,
0x3840, 0x77E2, 0x7625, 0x0A93
};
private static readonly int[] ExpCounterTable = {
0xFF, 0x5D, 0x36, 0x1A, 0x0E, 0x06, 0x00
};
private static readonly int[] ExpPeriodTable = {
0x01, 0x02, 0x04, 0x08, 0x10, 0x1E, 0x01
};
private static readonly int[] SustainTable = {
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF
};
public Envelope()
{
HardReset();
}
public void ExecutePhase2()
{
if (!_delay)
{
_envCounter--;
_delay = true;
UpdateExpCounter();
}
if (_lfsr != _rate)
{
var feedback = ((_lfsr >> 14) ^ (_lfsr >> 13)) & 0x1;
_lfsr = ((_lfsr << 1) & 0x7FFF) | feedback;
return;
}
_lfsr = 0x7FFF;
if (_state != StateAttack && ++_expCounter != _expPeriod)
{
return;
}
_expCounter = 0;
if (_freeze)
return;
switch (_state)
{
case StateAttack:
_envCounter++;
if (_envCounter == 0xFF)
{
_state = StateDecay;
_rate = AdsrTable[_decay];
}
break;
case StateDecay:
if (_envCounter == SustainTable[_sustain])
{
return;
}
if (_expPeriod != 1)
{
_delay = false;
return;
}
_envCounter--;
break;
case StateRelease:
if (_expPeriod != 1)
{
_delay = false;
return;
}
_envCounter--;
break;
}
_envCounter &= 0xFF;
UpdateExpCounter();
}
public void HardReset()
{
_attack = 0;
_decay = 0;
_delay = true;
_envCounter = 0;
_expCounter = 0;
_expPeriod = ExpPeriodTable[0];
_freeze = false;
_gate = false;
_lfsr = 0x7FFF;
_rate = AdsrTable[_release];
_release = 0;
_state = StateRelease;
_sustain = 0;
}
private void UpdateExpCounter()
{
{
for (var i = 0; i < 7; i++)
{
if (_envCounter == ExpCounterTable[i])
_expPeriod = ExpPeriodTable[i];
}
if (_envCounter == 0)
_freeze = true;
}
}
// ------------------------------------
public int Attack
{
get
{
return _attack;
}
set
{
_attack = value & 0xF;
if (_state == StateAttack)
_rate = AdsrTable[_attack];
}
}
public int Decay
{
get
{
return _decay;
}
set
{
_decay = value & 0xF;
if (_state == StateDecay)
_rate = AdsrTable[_decay];
}
}
public bool Gate
{
get
{
return _gate;
}
set
{
var nextGate = value;
if (nextGate && !_gate)
{
_state = StateAttack;
_rate = AdsrTable[_attack];
_delay = true;
_freeze = false;
}
else if (!nextGate && _gate)
{
_state = StateRelease;
_rate = AdsrTable[_release];
}
_gate = nextGate;
}
}
public int Level
{
get
{
return _envCounter;
}
}
public int Release
{
get
{
return _release;
}
set
{
_release = value & 0xF;
if (_state == StateRelease)
_rate = AdsrTable[_release];
}
}
public int Sustain
{
get
{
return _sustain;
}
set
{
_sustain = value & 0xF;
}
}
// ------------------------------------
public void SyncState(Serializer ser)
{
ser.Sync("_attack", ref _attack);
ser.Sync("_decay", ref _decay);
ser.Sync("_delay", ref _delay);
ser.Sync("_envCounter", ref _envCounter);
ser.Sync("_expCounter", ref _expCounter);
ser.Sync("_expPeriod", ref _expPeriod);
ser.Sync("_freeze", ref _freeze);
ser.Sync("_lfsr", ref _lfsr);
ser.Sync("_gate", ref _gate);
ser.Sync("_rate", ref _rate);
ser.Sync("_release", ref _release);
ser.Sync("_state", ref _state);
ser.Sync("_sustain", ref _sustain);
}
// ------------------------------------
}
}
}