From 022322538815f5fa9a997d9cb759eacd6e6b33bb Mon Sep 17 00:00:00 2001 From: saxxonpike Date: Thu, 15 Nov 2012 00:22:57 +0000 Subject: [PATCH] commodore64: rewrote SID emulation, should be a lot more accurate --- .../Computers/Commodore64/Sid.cs | 579 ++++-------------- .../Commodore64/SidEnvelopeGenerator.cs | 197 ++++++ .../Computers/Commodore64/SidSoundProvider.cs | 25 +- .../Commodore64/SidWaveformCalculator.cs | 11 +- .../Commodore64/SidWaveformGenerator.cs | 11 +- 5 files changed, 349 insertions(+), 474 deletions(-) diff --git a/BizHawk.Emulation/Computers/Commodore64/Sid.cs b/BizHawk.Emulation/Computers/Commodore64/Sid.cs index 3684e0925d..aceecdfa8c 100644 --- a/BizHawk.Emulation/Computers/Commodore64/Sid.cs +++ b/BizHawk.Emulation/Computers/Commodore64/Sid.cs @@ -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); - } } } diff --git a/BizHawk.Emulation/Computers/Commodore64/SidEnvelopeGenerator.cs b/BizHawk.Emulation/Computers/Commodore64/SidEnvelopeGenerator.cs index 3e5a58868a..d9e88a4dcc 100644 --- a/BizHawk.Emulation/Computers/Commodore64/SidEnvelopeGenerator.cs +++ b/BizHawk.Emulation/Computers/Commodore64/SidEnvelopeGenerator.cs @@ -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]; + } + } } } diff --git a/BizHawk.Emulation/Computers/Commodore64/SidSoundProvider.cs b/BizHawk.Emulation/Computers/Commodore64/SidSoundProvider.cs index e15b07d3c4..1070b9b54f 100644 --- a/BizHawk.Emulation/Computers/Commodore64/SidSoundProvider.cs +++ b/BizHawk.Emulation/Computers/Commodore64/SidSoundProvider.cs @@ -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--; } diff --git a/BizHawk.Emulation/Computers/Commodore64/SidWaveformCalculator.cs b/BizHawk.Emulation/Computers/Commodore64/SidWaveformCalculator.cs index 2e0f4e494d..c30db3194e 100644 --- a/BizHawk.Emulation/Computers/Commodore64/SidWaveformCalculator.cs +++ b/BizHawk.Emulation/Computers/Commodore64/SidWaveformCalculator.cs @@ -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]; diff --git a/BizHawk.Emulation/Computers/Commodore64/SidWaveformGenerator.cs b/BizHawk.Emulation/Computers/Commodore64/SidWaveformGenerator.cs index 16f2e4f110..07424d6302 100644 --- a/BizHawk.Emulation/Computers/Commodore64/SidWaveformGenerator.cs +++ b/BizHawk.Emulation/Computers/Commodore64/SidWaveformGenerator.cs @@ -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()