From 86629319c45f76f7974e794c8d181ab747917770 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Mon, 22 May 2017 16:44:27 -0400 Subject: [PATCH] C64: Start SID Filtering Set up infrastructure Still a lot to do. --- .../Commodore64/MOS/Sid.SoundProvider.cs | 7 +- .../Computers/Commodore64/MOS/Sid.cs | 134 +++++++++++++++--- 2 files changed, 122 insertions(+), 19 deletions(-) diff --git a/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/Sid.SoundProvider.cs b/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/Sid.SoundProvider.cs index bb19ff969f..0bec78785a 100644 --- a/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/Sid.SoundProvider.cs +++ b/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/Sid.SoundProvider.cs @@ -49,9 +49,14 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS public void GetSamplesSync(out short[] samples, out int nsamp) { Flush(); + + nsamp = _outputBufferIndex; + samples = _outputBuffer; - nsamp = _outputBufferIndex >> 1; + _outputBufferIndex = 0; + last_index = 0; } + } } diff --git a/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/Sid.cs b/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/Sid.cs index e561244749..2739d4a0fa 100644 --- a/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/Sid.cs +++ b/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/Sid.cs @@ -40,11 +40,15 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS private bool _filterSelectHiPass; private int _mixer; private readonly short[] _outputBuffer; + private int[] _outputBuffer_filtered; + private int[] _outputBuffer_not_filtered; private int _outputBufferIndex; + private int last_index; + private int filter_index; private int _potCounter; private int _potX; private int _potY; - private short _sample; + private int _sample; private int _voiceOutput0; private int _voiceOutput1; private int _voiceOutput2; @@ -57,6 +61,8 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS public Func ReadPotX; public Func ReadPotY; + public RealFFT fft; + private readonly int _cpuCyclesNum; private int _sampleCyclesNum; private readonly int _sampleCyclesDen; @@ -87,6 +93,8 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS _filterEnable[i] = false; _outputBuffer = new short[sampleRate]; + _outputBuffer_filtered = new int[sampleRate]; + _outputBuffer_not_filtered = new int[sampleRate]; } // ------------------------------------ @@ -145,39 +153,129 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS _envelopeOutput1 = _envelope1.Level; _envelopeOutput2 = _envelope2.Level; + int temp_v0 = (_voiceOutput0 * _envelopeOutput0); + int temp_v1 = (_voiceOutput1 * _envelopeOutput1); + int temp_v2 = (_voiceOutput2 * _envelopeOutput2); + + int temp_filtered = 0; + int temp_not_filtered = 0; + + //note that voice 3 disable is relevent only if it is not going to the filter + // see block diargam http://archive.6502.org/datasheets/mos_6581_sid.pdf + if (!_filterEnable[2] && _disableVoice3) + temp_v2 = 0; + + // break sound into filtered and non-filtered output + // we need to process the filtered parts in bulk, so let's do it here + if (_filterEnable[0]) + temp_filtered += temp_v0; + else + temp_not_filtered += temp_v0; + + if (_filterEnable[1]) + temp_filtered += temp_v1; + else + temp_not_filtered += temp_v1; + + if (_filterEnable[2]) + temp_filtered += temp_v2; + else + temp_not_filtered += temp_v2; + + _sampleCyclesNum += _sampleCyclesDen; if (_sampleCyclesNum >= _cpuCyclesNum) { _sampleCyclesNum -= _cpuCyclesNum; - _mixer = (_voiceOutput0 * _envelopeOutput0) >> 7; - _mixer += (_voiceOutput1 * _envelopeOutput1) >> 7; - _mixer += (_voiceOutput2 * _envelopeOutput2) >> 7; - _mixer = (_mixer * _volume) >> 4; - _mixer -= _volume << 8; - if (_mixer > 0x7FFF) - { - _mixer = 0x7FFF; - } - if (_mixer < -0x8000) - { - _mixer = -0x8000; - } - - _sample = unchecked((short)_mixer); if (_outputBufferIndex < _sampleRate) { - _outputBuffer[_outputBufferIndex++] = _sample; - _outputBuffer[_outputBufferIndex++] = _sample; + _outputBuffer_not_filtered[_outputBufferIndex] = temp_not_filtered; + _outputBuffer_filtered[filter_index] = temp_filtered; + _outputBufferIndex++; + filter_index++; } } } + + //here we need to apply filtering to the samples and add them back to the buffer + filter_operator(); + + for (int i = last_index; i < _outputBufferIndex; i++) + { + _mixer = _outputBuffer_not_filtered[i] + _outputBuffer_filtered[i-last_index]; + _mixer = _mixer >> 7; + _mixer = (_mixer * _volume) >> 4; + _mixer -= _volume << 8; + + if (_mixer > 0x7FFF) + { + _mixer = 0x7FFF; + } + if (_mixer < -0x8000) + { + _mixer = -0x8000; + } + + _outputBuffer[i * 2] = (short)_mixer; + _outputBuffer[i * 2 + 1] = (short)_mixer; + + } + + last_index = _outputBufferIndex; + filter_index = 0; } + + public void filter_operator() + { + double loc_filterFrequency = ((_filterFrequency + 30) * 2000) / 0x7FF; + double attenuation; + + int nsamp = filter_index; + + // pass the list of filtered samples to the FFT + // TODO + + // for each element in the frequency list, attenuate it according to the specs + //for (... + /* + // low pass filter + if (_filterSelectLoPass && current_voice_freq > loc_filterFrequency) + { + //attenuated at 12db per octave + attenuation = Math.Log(current_voice_freq / loc_filterFrequency, 2); + //temp_voice = temp_voice - 12 * attenuation; + attenuation = 12 * attenuation; + temp_voice = temp_voice * Math.Pow(2, -attenuation/10); + } + + // High pass filter + if (_filterSelectHiPass && current_voice_freq < _filterFrequency) + { + //attenuated at 12db per octave + attenuation = Math.Log(current_voice_freq / _filterFrequency, 2); + //temp_voice = temp_voice - 12 * Math.Abs(attenuation); + } + + // Band pass filter + if (_filterSelectBandPass) + { + //attenuated at 6db per octave + attenuation = Math.Log(current_voice_freq / _filterFrequency, 2); + //temp_voice = temp_voice - 6 * Math.Abs(attenuation); + } + */ + + // now transform back into time space and reassemble the attenuated frequency components + // TODO + + } // ---------------------------------- public void SyncState(Serializer ser) { + ser.Sync("last index", ref last_index); ser.Sync("_databus", ref _databus); ser.Sync("_cachedCycles", ref _cachedCycles); ser.Sync("_disableVoice3", ref _disableVoice3);