commodore64: rewrote SID emulation, should be a lot more accurate

This commit is contained in:
saxxonpike 2012-11-15 00:22:57 +00:00
parent 5926918f8b
commit 0223225388
5 changed files with 349 additions and 474 deletions

View File

@ -4,14 +4,6 @@ using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64
{
public enum SidEnvelopeState
{
Disabled,
Attack,
Decay,
Release
}
public enum SidMode
{
Sid6581,
@ -20,24 +12,102 @@ namespace BizHawk.Emulation.Computers.Commodore64
public class VoiceRegs
{
public int ATK;
public int DCY;
public int ENV;
public int F;
public bool FILT;
public bool GATE;
public bool NOISE;
public int OSC;
public int PW;
public int RLS;
public bool RMOD;
public bool SAW;
public int SR;
public bool SQU;
public int STN;
public bool SYNC;
public bool TEST;
public bool TRI;
private EnvelopeGenerator envelope;
private WaveformGenerator generator;
private WaveformGenerator syncSource;
private short outputEnvLatch;
private short outputWaveLatch;
public VoiceRegs()
{
envelope = new EnvelopeGenerator();
generator = new WaveformGenerator(WaveformCalculator.BuildTable());
}
public void Clock()
{
generator.Clock();
envelope.Clock();
outputWaveLatch = generator.Output(syncSource);
outputEnvLatch = envelope.Output();
}
public short Output()
{
int sample = outputWaveLatch;
int velocity = outputEnvLatch;
int result = (sample * velocity) >> 4;
result -= 32768;
if (result > 32767)
result = 32767;
else if (result < -32768)
result = -32768;
return (short)result;
}
public byte ReadEnv()
{
return (byte)(outputEnvLatch >> 4);
}
public int ReadFreq()
{
return generator.ReadFreq();
}
public byte ReadOsc()
{
return (byte)(outputWaveLatch >> 4);
}
public void Reset()
{
generator.Reset();
envelope.Reset();
}
public void SetSyncSource(VoiceRegs source)
{
syncSource = source.generator;
}
public void WriteAttackDecay(byte val)
{
envelope.WriteAttackDecay(val);
}
public void WriteControl(byte val)
{
generator.WriteControl(val);
envelope.WriteControl(val);
}
public void WriteFreqLo(byte val)
{
generator.WriteFreqLo(val);
}
public void WriteFreqHi(byte val)
{
generator.WriteFreqHi(val);
}
public void WritePWLo(byte val)
{
generator.WritePWLo(val);
}
public void WritePWHi(byte val)
{
generator.WritePWHi(val);
}
public void WriteSustainRelease(byte val)
{
envelope.WriteSustainRelease(val);
}
}
public class SidRegs
@ -45,6 +115,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
public bool BP;
public bool D3;
public int FC;
public bool[] FILT = new bool[3];
public bool FILTEX;
public bool HP;
public bool LP;
@ -58,13 +129,13 @@ namespace BizHawk.Emulation.Computers.Commodore64
public SidRegs()
{
Voices = new VoiceRegs[3];
for (int i = 0; i < 3; i++)
Voices[i] = new VoiceRegs();
Voices[0] = new VoiceRegs();
Voices[1] = new VoiceRegs();
Voices[2] = new VoiceRegs();
// power on state
Voices[0].SR = 0x7FFFFF;
Voices[1].SR = 0x7FFFFF;
Voices[2].SR = 0x7FFFFF;
Voices[0].SetSyncSource(Voices[2]);
Voices[1].SetSyncSource(Voices[0]);
Voices[2].SetSyncSource(Voices[1]);
}
public byte this[int addr]
@ -78,84 +149,17 @@ namespace BizHawk.Emulation.Computers.Commodore64
addr &= 0x1F;
switch (addr)
{
case 0x00:
case 0x07:
case 0x0E:
result = Voices[addr / 7].F & 0xFF;
break;
case 0x01:
case 0x08:
case 0x0F:
result = (Voices[addr / 7].F & 0xFF00) >> 8;
break;
case 0x02:
case 0x09:
case 0x10:
result = Voices[addr / 7].PW & 0xFF;
break;
case 0x03:
case 0x0A:
case 0x11:
result = (Voices[addr / 7].PW & 0x0F00) >> 8;
break;
case 0x04:
case 0x0B:
case 0x12:
index = addr / 7;
result = Voices[index].GATE ? 0x01 : 0x00;
result |= Voices[index].SYNC ? 0x02 : 0x00;
result |= Voices[index].RMOD ? 0x04 : 0x00;
result |= Voices[index].TEST ? 0x08 : 0x00;
result |= Voices[index].TRI ? 0x10 : 0x00;
result |= Voices[index].SAW ? 0x20 : 0x00;
result |= Voices[index].SQU ? 0x40 : 0x00;
result |= Voices[index].NOISE ? 0x80 : 0x00;
break;
case 0x05:
case 0x0C:
case 0x13:
index = addr / 7;
result = (Voices[index].ATK & 0xF) << 4;
result |= Voices[index].DCY & 0xF;
break;
case 0x06:
case 0x0D:
case 0x14:
index = addr / 7;
result = (Voices[index].STN & 0xF) << 4;
result |= Voices[index].RLS & 0xF;
break;
case 0x15:
result = FC & 0x7;
break;
case 0x16:
result = (FC & 0x7F8) >> 3;
break;
case 0x17:
result = Voices[0].FILT ? 0x01 : 0x00;
result |= Voices[1].FILT ? 0x02 : 0x00;
result |= Voices[2].FILT ? 0x04 : 0x00;
result |= FILTEX ? 0x08 : 0x00;
result |= (RES & 0xF) << 4;
break;
case 0x18:
result = (VOL & 0xF);
result |= LP ? 0x10 : 0x00;
result |= BP ? 0x20 : 0x00;
result |= HP ? 0x40 : 0x00;
result |= D3 ? 0x80 : 0x00;
break;
case 0x19:
result = POTX ;
result = POTX;
break;
case 0x1A:
result = POTY;
break;
case 0x1B:
result = Voices[2].OSC >> 4;
result = Voices[2].ReadOsc();
break;
case 0x1C:
result = Voices[2].ENV;
result = Voices[2].ReadEnv();
break;
default:
result = 0;
@ -175,56 +179,43 @@ namespace BizHawk.Emulation.Computers.Commodore64
case 0x07:
case 0x0E:
index = addr / 7;
Voices[index].F &= 0xFF00;
Voices[index].F |= val;
Voices[index].WriteFreqLo(value);
break;
case 0x01:
case 0x08:
case 0x0F:
index = addr / 7;
Voices[index].F &= 0xFF;
Voices[index].F |= val << 8;
Voices[index].WriteFreqHi(value);
break;
case 0x02:
case 0x09:
case 0x10:
index = addr / 7;
Voices[index].PW &= 0x0F00;
Voices[index].PW |= val;
Voices[index].WritePWLo(value);
break;
case 0x03:
case 0x0A:
case 0x11:
index = addr / 7;
Voices[index].PW &= 0xFF;
Voices[index].PW |= (val & 0x0F) << 8;
Voices[index].WritePWHi(value);
break;
case 0x04:
case 0x0B:
case 0x12:
index = addr / 7;
Voices[index].GATE = ((val & 0x01) != 0x00);
Voices[index].SYNC = ((val & 0x02) != 0x00);
Voices[index].RMOD = ((val & 0x04) != 0x00);
Voices[index].TEST = ((val & 0x08) != 0x00);
Voices[index].TRI = ((val & 0x10) != 0x00);
Voices[index].SAW = ((val & 0x20) != 0x00);
Voices[index].SQU = ((val & 0x40) != 0x00);
Voices[index].NOISE = ((val & 0x80) != 0x00);
Voices[index].WriteControl(value);
break;
case 0x05:
case 0x0C:
case 0x13:
index = addr / 7;
Voices[index].ATK = (val >> 4) & 0xF;
Voices[index].DCY = val & 0xF;
Voices[index].WriteAttackDecay(value);
break;
case 0x06:
case 0x0D:
case 0x14:
index = addr / 7;
Voices[index].STN = (val >> 4) & 0xF;
Voices[index].RLS = val & 0xF;
Voices[index].WriteSustainRelease(value);
break;
case 0x15:
FC &= 0x7F8;
@ -235,9 +226,9 @@ namespace BizHawk.Emulation.Computers.Commodore64
FC |= val << 3;
break;
case 0x17:
Voices[0].FILT = ((val & 0x01) != 0x00);
Voices[1].FILT = ((val & 0x02) != 0x00);
Voices[2].FILT = ((val & 0x04) != 0x00);
FILT[0] = ((val & 0x01) != 0x00);
FILT[1] = ((val & 0x02) != 0x00);
FILT[2] = ((val & 0x04) != 0x00);
FILTEX = ((val & 0x08) != 0x00);
RES = (val >> 4);
break;
@ -248,18 +239,6 @@ namespace BizHawk.Emulation.Computers.Commodore64
HP = ((val & 0x40) != 0x00);
D3 = ((val & 0x80) != 0x00);
break;
case 0x19:
POTX = val;
break;
case 0x1A:
POTY = val;
break;
case 0x1B:
Voices[2].OSC = val << 4;
break;
case 0x1C:
Voices[2].ENV = val;
break;
}
}
}
@ -268,18 +247,6 @@ namespace BizHawk.Emulation.Computers.Commodore64
public partial class Sid : ISoundProvider
{
private int[] envRateIndex = {
9, 32, 63, 95,
149, 220, 267, 313,
392, 977, 1954, 3126,
3907, 11720, 19532, 31251
};
private int[] sustainLevels = {
0x00, 0x11, 0x22, 0x33,
0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xAA, 0xBB,
0xCC, 0xDD, 0xEE, 0xFF
};
private int[] syncIndex = { 2, 0, 1 };
private VoiceRegs[] voices;
@ -289,16 +256,8 @@ namespace BizHawk.Emulation.Computers.Commodore64
public int clock;
public int cyclesPerSample;
public bool[] envEnable = new bool[3];
public int[] envExp = new int[3];
public int[] envExpCounter = new int[3];
public int[] envRate = new int[3];
public int[] envRateCounter = new int[3];
public SidEnvelopeState[] envState = new SidEnvelopeState[3];
public bool[] lastGate = new bool[3];
public int output;
public SidRegs regs;
public int[] waveClock = new int[3];
public Sid(Region newRegion, int sampleRate)
{
@ -328,27 +287,6 @@ namespace BizHawk.Emulation.Computers.Commodore64
voices = regs.Voices;
}
private short Mix(int input, int volume, short mixSource)
{
// logarithmic volume (probably inaccurate)
int logVolume = volume * 256;
logVolume = (int)Math.Sqrt(logVolume);
// combine the volumes together 1:1
volume = (volume + logVolume) >> 1;
input &= 0xFFF;
input -= 0x800;
input *= volume;
input /= 255;
input += mixSource;
if (input > 32767)
input = 32767;
else if (input < -32768)
input = -32768;
return (short)input;
}
public byte Peek(int addr)
{
return regs[addr & 0x1F];
@ -356,31 +294,10 @@ namespace BizHawk.Emulation.Computers.Commodore64
public void PerformCycle()
{
// accumulator is 24 bits
clock = (clock + 1) & 0xFFFFFF;
ProcessAccumulator(0);
ProcessAccumulator(1);
ProcessAccumulator(2);
// process each voice
ProcessVoice(0);
ProcessVoice(1);
ProcessVoice(2);
// process voices again for best hard sync
if (voices[1].SYNC)
ProcessVoice(0);
if (voices[2].SYNC)
ProcessVoice(1);
if (voices[0].SYNC)
ProcessVoice(2);
// process each envelope
ProcessEnvelope(0);
ProcessEnvelope(1);
ProcessEnvelope(2);
// submit sample to soundprovider
voices[0].Clock();
voices[1].Clock();
voices[2].Clock();
SubmitSample();
// query pots every 512 cycles
@ -389,6 +306,8 @@ namespace BizHawk.Emulation.Computers.Commodore64
regs.POTX = ReadPotX() & 0xFF;
regs.POTY = ReadPotY() & 0xFF;
}
clock = (clock + 1) & 0xFFFFFF;
}
public void Poke(int addr, byte val)
@ -396,188 +315,6 @@ namespace BizHawk.Emulation.Computers.Commodore64
regs[addr & 0x1F] = val;
}
private void ProcessAccumulator(int index)
{
// test bit resets the oscillator
if (voices[index].TEST)
{
waveClock[index] = 0x000000;
voices[index].SR = 0x7FFFFF;
}
else
{
int lastWaveClock = waveClock[index];
// increment wave clock
waveClock[index] = (waveClock[index] + voices[index].F) & 0x00FFFFFF;
// process shift register if needed
if ((lastWaveClock & 0x100000) != (waveClock[index] & 0x100000))
ProcessShiftRegister(index);
}
}
private void ProcessEnvelope(int index)
{
envRateCounter[index] = (envRateCounter[index] + 1) & 0xFFFF;
if (envRateCounter[index] == envRate[index])
{
envRateCounter[index] = 0;
if (envState[index] != SidEnvelopeState.Disabled)
{
envExpCounter[index] = (envExpCounter[index] + 1) & 0xFF;
if (envExpCounter[index] == 0)
envState[index] = SidEnvelopeState.Disabled;
if (envExpCounter[index] == envExp[index])
{
switch (envState[index])
{
case SidEnvelopeState.Attack:
if (voices[index].ENV < 0xFF)
voices[index].ENV++;
if (voices[index].ENV == 0xFF)
{
envState[index] = SidEnvelopeState.Decay;
UpdateEnvelopeRateCounter(index);
}
break;
case SidEnvelopeState.Decay:
if (voices[index].ENV > sustainLevels[voices[index].STN] && voices[index].ENV > 0)
voices[index].ENV--;
break;
case SidEnvelopeState.Release:
if (voices[index].ENV > 0)
voices[index].ENV--;
if (voices[index].ENV == 0)
{
envState[index] = SidEnvelopeState.Disabled;
UpdateEnvelopeRateCounter(index);
}
break;
}
envExpCounter[index] = 0;
ProcessEnvelopeExpCounter(index);
}
else if (envState[index] == SidEnvelopeState.Attack)
{
ProcessEnvelopeExpCounter(index);
}
}
}
}
private void ProcessEnvelopeExpCounter(int index)
{
switch (voices[index].ENV)
{
case 0xFF:
envExp[index] = 1;
break;
case 0x5D:
envExp[index] = 2;
break;
case 0x36:
envExp[index] = 4;
break;
case 0x1A:
envExp[index] = 8;
break;
case 0x0E:
envExp[index] = 16;
break;
case 0x06:
envExp[index] = 30;
break;
case 0x00:
envExp[index] = 1;
break;
}
}
private void ProcessShiftRegister(int index)
{
int newBit = ((voices[index].SR >> 22) ^ (voices[index].SR >> 17)) & 0x1;
voices[index].SR = ((voices[index].SR << 1) | newBit) & 0x7FFFFF;
}
private void ProcessVoice(int index)
{
int triOutput;
int sawOutput;
int squOutput;
int noiseOutput;
int finalOutput = 0x00000FFF;
bool outputEnabled = false;
// triangle waveform
if (voices[index].TRI)
{
triOutput = (waveClock[index] >> 12) & 0xFFF;
if (voices[index].SYNC)
triOutput ^= voices[syncIndex[index]].OSC & 0x800;
if ((triOutput & 0x800) != 0x000)
triOutput ^= 0x7FF;
triOutput &= 0x7FF;
triOutput <<= 1;
finalOutput &= triOutput;
outputEnabled = true;
}
// saw waveform
if (voices[index].SAW)
{
sawOutput = (waveClock[index] >> 12) & 0xFFF;
finalOutput &= sawOutput;
outputEnabled = true;
}
// square waveform
if (voices[index].SQU)
{
if (voices[index].TEST)
{
squOutput = 0xFFF;
}
else
{
squOutput = (waveClock[index] >> 12) >= voices[index].PW ? 0xFFF : 0x000;
}
finalOutput &= squOutput;
outputEnabled = true;
}
// noise waveform
if (voices[index].NOISE)
{
// shift register information is from reSID
int sr = voices[index].SR;
noiseOutput = sr & 0x100000 >> 9;
noiseOutput |= sr & 0x040000 >> 8;
noiseOutput |= sr & 0x004000 >> 5;
noiseOutput |= sr & 0x000800 >> 3;
noiseOutput |= sr & 0x000200 >> 2;
noiseOutput |= sr & 0x000020 << 1;
noiseOutput |= sr & 0x000004 << 3;
noiseOutput |= sr & 0x000001 << 4;
finalOutput &= noiseOutput;
outputEnabled = true;
// other waveforms write into the shift register
if (voices[index].SQU || voices[index].TRI || voices[index].SAW)
WriteShiftRegister(index, finalOutput);
}
// write to internal reg
if (outputEnabled)
voices[index].OSC = finalOutput;
else
voices[index].OSC = 0x000;
}
public byte Read(ushort addr)
{
addr &= 0x1F;
@ -594,71 +331,11 @@ namespace BizHawk.Emulation.Computers.Commodore64
}
}
private void UpdateEnvelopeRateCounter(int index)
{
switch (envState[index])
{
case SidEnvelopeState.Attack:
envRate[index] = envRateIndex[voices[index].ATK] / 3;
break;
case SidEnvelopeState.Decay:
envRate[index] = envRateIndex[voices[index].DCY];
break;
case SidEnvelopeState.Release:
envRate[index] = envRateIndex[voices[index].RLS];
break;
}
ProcessEnvelopeExpCounter(index);
}
public void Write(ushort addr, byte val)
{
int index;
bool gate;
addr &= 0x1F;
switch (addr)
{
case 0x04:
case 0x0B:
case 0x12:
// set control
index = addr / 7;
gate = lastGate[index];
regs[addr] = val;
lastGate[index] = voices[index].GATE;
if (!gate && lastGate[index])
{
envExpCounter[index] = 0;
envState[index] = SidEnvelopeState.Attack;
voices[index].ENV = 0;
envRateCounter[index] = 0;
UpdateEnvelopeRateCounter(index);
ProcessEnvelopeExpCounter(index);
}
else if (gate && !lastGate[index])
{
envExpCounter[index] = 0;
envState[index] = SidEnvelopeState.Release;
UpdateEnvelopeRateCounter(index);
}
break;
case 0x05:
case 0x0C:
case 0x13:
// set attack/decay
index = addr / 7;
regs[addr] = val;
UpdateEnvelopeRateCounter(index);
break;
case 0x06:
case 0x0D:
case 0x14:
// set sustain/release
index = addr / 7;
regs[addr] = val;
UpdateEnvelopeRateCounter(index);
break;
case 0x19:
case 0x1A:
case 0x1B:
@ -670,19 +347,5 @@ namespace BizHawk.Emulation.Computers.Commodore64
break;
}
}
private void WriteShiftRegister(int index, int sample)
{
voices[index].SR &=
~((1 << 20) | (1 << 18) | (1 << 14) | (1 << 11) | (1 << 9) | (1 << 5) | (1 << 2) | (1 << 0)) |
((sample & 0x800) << 9) |
((sample & 0x400) << 8) |
((sample & 0x200) << 5) |
((sample & 0x100) << 3) |
((sample & 0x080) << 2) |
((sample & 0x040) >> 1) |
((sample & 0x020) >> 3) |
((sample & 0x010) >> 4);
}
}
}

View File

@ -5,7 +5,204 @@ using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64
{
// constants for the EnvelopeGenerator and calculation
// methods come from the libsidplayfp residfp library.
class EnvelopeGenerator
{
enum State
{
Attack, DecaySustain, Release
}
static int[] adsrTable = new int[]
{
0x7F00, 0x0006, 0x003C, 0x0330,
0x20C0, 0x6755, 0x3800, 0x500E,
0x1212, 0x0222, 0x1848, 0x59B8,
0x3840, 0x77E2, 0x7625, 0x0A93
};
int attack;
int decay;
byte envelopeCounter;
bool envelopePipeline;
int exponentialCounter;
int exponentialCounterPeriod;
bool gate;
bool holdZero;
int lfsr;
int rate;
int release;
State state;
int sustain;
public EnvelopeGenerator()
{
Reset();
}
public void Clock()
{
if (envelopePipeline)
{
--envelopeCounter;
envelopePipeline = false;
SetExponentialCounter();
}
if (lfsr != rate)
{
int feedback = ((lfsr >> 14) ^ (lfsr >> 13)) & 0x01;
lfsr = ((lfsr << 1) & 0x7FFF) | feedback;
return;
}
lfsr = 0x7FFF;
if ((state == State.Attack) || (++exponentialCounter == exponentialCounterPeriod))
{
exponentialCounter = 0;
if (holdZero)
{
return;
}
switch (state)
{
case State.Attack:
++envelopeCounter;
if (envelopeCounter == 0xFF)
{
state = State.DecaySustain;
rate = adsrTable[decay];
}
break;
case State.DecaySustain:
if (envelopeCounter == ((sustain << 4) | sustain))
{
return;
}
if (exponentialCounterPeriod != 1)
{
envelopePipeline = true;
return;
}
--envelopeCounter;
break;
case State.Release:
if (exponentialCounterPeriod != 1)
{
envelopePipeline = true;
return;
}
--envelopeCounter;
break;
}
SetExponentialCounter();
}
}
public short Output()
{
return envelopeCounter;
}
public byte ReadEnv()
{
return envelopeCounter;
}
public void Reset()
{
envelopeCounter = 0;
envelopePipeline = false;
attack = 0;
decay = 0;
sustain = 0;
release = 0;
gate = false;
lfsr = 0x7FFF;
exponentialCounter = 0;
exponentialCounterPeriod = 1;
state = State.Release;
rate = adsrTable[release];
holdZero = true;
}
private void SetExponentialCounter()
{
switch (envelopeCounter)
{
case 0xFF:
exponentialCounterPeriod = 1;
break;
case 0x5D:
exponentialCounterPeriod = 2;
break;
case 0x36:
exponentialCounterPeriod = 4;
break;
case 0x1A:
exponentialCounterPeriod = 8;
break;
case 0x0E:
exponentialCounterPeriod = 16;
break;
case 0x06:
exponentialCounterPeriod = 30;
break;
case 0x00:
exponentialCounterPeriod = 1;
holdZero = true;
break;
}
}
public void WriteAttackDecay(byte attackDecay)
{
attack = (attackDecay >> 4) & 0x0F;
decay = attackDecay & 0x0F;
if (state == State.Attack)
{
rate = adsrTable[attack];
}
else if (state == State.DecaySustain)
{
rate = adsrTable[decay];
}
}
public void WriteControl(byte control)
{
bool gateNext = ((control & 0x01) != 0);
if (!gate && gateNext)
{
state = State.Attack;
rate = adsrTable[attack];
holdZero = false;
envelopePipeline = false;
}
else if (gate && !gateNext)
{
state = State.Release;
rate = adsrTable[release];
}
gate = gateNext;
}
public void WriteSustainRelease(byte sustainRelease)
{
sustain = (sustainRelease >> 4) & 0x0F;
release = sustainRelease & 0x0F;
if (state == State.Release)
{
rate = adsrTable[release];
}
}
}
}

View File

@ -78,24 +78,31 @@ namespace BizHawk.Emulation.Computers.Commodore64
{
if (sampleCounter == 0)
{
short output;
output = Mix(voices[0].OSC, voices[0].ENV, 0);
output = Mix(voices[1].OSC, voices[1].ENV, output);
// voice 3 can be disabled with a specific register, but
// when the filter is enabled, it still plays
if (!regs.D3 || voices[2].FILT)
output = Mix(voices[2].OSC, voices[2].ENV, output);
int mixer;
mixer = voices[0].Output();
mixer += voices[1].Output();
mixer += voices[2].Output();
// the mixer is very loud at this point, let's make it quieter
mixer /= 6;
if (mixer > 32767)
mixer = 326767;
else if (mixer < -32768)
mixer = -32768;
short output = (short)mixer;
// run twice since the buffer expects stereo sound (I THINK)
for (int i = 0; i < 2; i++)
{
sampleCounter = cyclesPerSample;
sampleBufferIndex++;
if (sampleBufferIndex == sampleBufferCapacity)
sampleBufferIndex = 0;
sampleBuffer[sampleBufferIndex] = output;
}
sampleCounter = cyclesPerSample;
}
sampleCounter--;
}

View File

@ -5,7 +5,10 @@ using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64
{
class SidWaveformCalculator
// constants for the WaveformCalculator and calculation
// methods come from the libsidplayfp residfp library.
static class WaveformCalculator
{
struct CombinedWaveformConfig
{
@ -33,13 +36,13 @@ namespace BizHawk.Emulation.Computers.Commodore64
new CombinedWaveformConfig(0.9527834f, 1.794777f, 0.0f, 0.09806272f, 0.7752482f)
};
public short[][] BuildTable()
public static short[][] BuildTable()
{
short[][] wftable = new short[8][];
for (int i = 0; i < 8; i++)
wftable[i] = new short[4096];
for (int accumulator = 0; accumulator < 1 << 24; accumulator += 1 << 12)
for (int accumulator = 0; accumulator < (1 << 24); accumulator += (1 << 12))
{
int idx = (accumulator >> 12);
wftable[0][idx] = 0xFFF;
@ -55,7 +58,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
return wftable;
}
private short CalculateCombinedWaveForm(CombinedWaveformConfig config, int waveform, int accumulator)
private static short CalculateCombinedWaveForm(CombinedWaveformConfig config, int waveform, int accumulator)
{
float[] o = new float[12];

View File

@ -5,10 +5,13 @@ using System.Text;
namespace BizHawk.Emulation.Computers.Commodore64
{
// constants for the WaveformGenerator and calculation
// methods come from the libsidplayfp residfp library.
class WaveformGenerator
{
private int accumulator;
private short[] dac = new short[4096];
private int floatingOutputTtl;
private int freq;
private short[][] modelWave;
@ -29,8 +32,10 @@ namespace BizHawk.Emulation.Computers.Commodore64
private int waveform;
private int waveformOutput;
public WaveformGenerator()
public WaveformGenerator(short[][] newModelWave)
{
modelWave = newModelWave;
Reset();
}
public void Clock()
@ -88,7 +93,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
}
}
pulseOutput = ((accumulator >> 12) >= pw) ? 0xFFF : 0x000;
return dac[waveformOutput];
return (short)waveformOutput;
}
public int ReadAccumulator()