/* * This file is part of libsidplayfp, a SID player engine. * * Copyright 2011-2016 Leandro Nini * Copyright 2007-2010 Antti Lankila * Copyright 2004 Dag Lem * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #define SID_CPP #include "SID.h" #include #include "array.h" #include "Dac.h" #include "Filter6581.h" #include "Filter8580.h" #include "Potentiometer.h" #include "WaveformCalculator.h" #include "resample/TwoPassSincResampler.h" #include "resample/ZeroOrderResampler.h" namespace reSIDfp { const unsigned int ENV_DAC_BITS = 8; const unsigned int OSC_DAC_BITS = 12; /** * The waveform D/A converter introduces a DC offset in the signal * to the envelope multiplying D/A converter. The "zero" level of * the waveform D/A converter can be found as follows: * * Measure the "zero" voltage of voice 3 on the SID audio output * pin, routing only voice 3 to the mixer ($d417 = $0b, $d418 = * $0f, all other registers zeroed). * * Then set the sustain level for voice 3 to maximum and search for * the waveform output value yielding the same voltage as found * above. This is done by trying out different waveform output * values until the correct value is found, e.g. with the following * program: * * lda #$08 * sta $d412 * lda #$0b * sta $d417 * lda #$0f * sta $d418 * lda #$f0 * sta $d414 * lda #$21 * sta $d412 * lda #$01 * sta $d40e * * ldx #$00 * lda #$38 ; Tweak this to find the "zero" level *l cmp $d41b * bne l * stx $d40e ; Stop frequency counter - freeze waveform output * brk * * The waveform output range is 0x000 to 0xfff, so the "zero" * level should ideally have been 0x800. In the measured chip, the * waveform output "zero" level was found to be 0x380 (i.e. $d41b * = 0x38) at an audio output voltage of 5.94V. * * With knowledge of the mixer op-amp characteristics, further estimates * of waveform voltages can be obtained by sampling the EXT IN pin. * From EXT IN samples, the corresponding waveform output can be found by * using the model for the mixer. * * Such measurements have been done on a chip marked MOS 6581R4AR * 0687 14, and the following results have been obtained: * * The full range of one voice is approximately 1.5V. * * The "zero" level rides at approximately 5.0V. * * * zero-x did the measuring on the 8580 (https://sourceforge.net/p/vice-emu/bugs/1036/#c5b3): * When it sits on basic from powerup it's at 4.72 * Run 1.prg and check the output pin level. * Then run 2.prg andadjust it until the output level is the same... * 0x94-0xA8 gives me the same 4.72 1.prg shows. * On another 8580 it's 0x90-0x9C * Third chip 0x94-0xA8 * Fourth chip 0x90-0xA4 * On the 8580 that plays digis the output is 4.66 and 0x93 is the only value to reach that. * To me that seems as regular 8580s have somewhat wide 0-level range, * whereas that digi-compatible 8580 has it very narrow. * On my 6581R4AR has 0x3A as the only value giving the same output level as 1.prg */ //@{ unsigned int constexpr OFFSET_6581 = 0x380; unsigned int constexpr OFFSET_8580 = 0x9c0; //@} /** * Bus value stays alive for some time after each operation. * Values differs between chip models, the timings used here * are taken from VICE [1]. * See also the discussion "How do I reliably detect 6581/8580 sid?" on CSDb [2]. * * Results from real C64 (testprogs/SID/bitfade/delayfrq0.prg): * * (new SID) (250469/8580R5) (250469/8580R5) * delayfrq0 ~7a000 ~108000 * * (old SID) (250407/6581) * delayfrq0 ~01d00 * * [1]: http://sourceforge.net/p/vice-emu/patches/99/ * [2]: http://noname.c64.org/csdb/forums/?roomid=11&topicid=29025&showallposts=1 */ //@{ int constexpr BUS_TTL_6581 = 0x01d00; int constexpr BUS_TTL_8580 = 0xa2000; //@} SID::SID() : filter6581(new Filter6581()), filter8580(new Filter8580()), externalFilter(new ExternalFilter()), resampler(nullptr), potX(new Potentiometer()), potY(new Potentiometer()) { voice[0].reset(new Voice()); voice[1].reset(new Voice()); voice[2].reset(new Voice()); muted[0] = muted[1] = muted[2] = false; reset(); setChipModel(MOS8580); } SID::~SID() { // Needed to delete auto_ptr with complete type } void SID::setFilter6581Curve(double filterCurve) { filter6581->setFilterCurve(filterCurve); } void SID::setFilter8580Curve(double filterCurve) { filter8580->setFilterCurve(filterCurve); } void SID::enableFilter(bool enable) { filter6581->enable(enable); filter8580->enable(enable); } void SID::voiceSync(bool sync) { if (sync) { // Synchronize the 3 waveform generators. for (int i = 0; i < 3; i++) { voice[i]->wave()->synchronize(voice[(i + 1) % 3]->wave(), voice[(i + 2) % 3]->wave()); } } // Calculate the time to next voice sync nextVoiceSync = std::numeric_limits::max(); for (int i = 0; i < 3; i++) { WaveformGenerator* const wave = voice[i]->wave(); const unsigned int freq = wave->readFreq(); if (wave->readTest() || freq == 0 || !voice[(i + 1) % 3]->wave()->readSync()) { continue; } const unsigned int accumulator = wave->readAccumulator(); const unsigned int thisVoiceSync = ((0x7fffff - accumulator) & 0xffffff) / freq + 1; if (thisVoiceSync < nextVoiceSync) { nextVoiceSync = thisVoiceSync; } } } void SID::setChipModel(ChipModel model) { switch (model) { case MOS6581: filter = filter6581.get(); modelTTL = BUS_TTL_6581; break; case MOS8580: filter = filter8580.get(); modelTTL = BUS_TTL_8580; break; default: throw SIDError("Unknown chip type"); } this->model = model; // calculate waveform-related tables matrix_t* tables = WaveformCalculator::getInstance()->buildTable(model); // calculate envelope DAC table { Dac dacBuilder(ENV_DAC_BITS); dacBuilder.kinkedDac(model); for (unsigned int i = 0; i < (1 << ENV_DAC_BITS); i++) { envDAC[i] = static_cast(dacBuilder.getOutput(i)); } } // calculate oscillator DAC table const bool is6581 = model == MOS6581; { Dac dacBuilder(OSC_DAC_BITS); dacBuilder.kinkedDac(model); const double offset = dacBuilder.getOutput(is6581 ? OFFSET_6581 : OFFSET_8580); for (unsigned int i = 0; i < (1 << OSC_DAC_BITS); i++) { const double dacValue = dacBuilder.getOutput(i); oscDAC[i] = static_cast(dacValue - offset); } } // set voice tables for (int i = 0; i < 3; i++) { voice[i]->setEnvDAC(envDAC); voice[i]->setWavDAC(oscDAC); voice[i]->wave()->setModel(is6581); voice[i]->wave()->setWaveformModels(tables); } } void SID::reset() { for (int i = 0; i < 3; i++) { voice[i]->reset(); } filter6581->reset(); filter8580->reset(); externalFilter->reset(); if (resampler.get()) { resampler->reset(); } busValue = 0; busValueTtl = 0; voiceSync(false); } void SID::input(int value) { filter6581->input(value); filter8580->input(value); } unsigned char SID::read(int offset) { switch (offset) { case 0x19: // X value of paddle busValue = potX->readPOT(); busValueTtl = modelTTL; break; case 0x1a: // Y value of paddle busValue = potY->readPOT(); busValueTtl = modelTTL; break; case 0x1b: // Voice #3 waveform output busValue = voice[2]->wave()->readOSC(); busValueTtl = modelTTL; break; case 0x1c: // Voice #3 ADSR output busValue = voice[2]->envelope()->readENV(); busValueTtl = modelTTL; break; default: // Reading from a write-only or non-existing register // makes the bus discharge faster. // Emulate this by halving the residual TTL. busValueTtl /= 2; break; } return busValue; } void SID::write(int offset, unsigned char value) { busValue = value; busValueTtl = modelTTL; switch (offset) { case 0x00: // Voice #1 frequency (Low-byte) voice[0]->wave()->writeFREQ_LO(value); break; case 0x01: // Voice #1 frequency (High-byte) voice[0]->wave()->writeFREQ_HI(value); break; case 0x02: // Voice #1 pulse width (Low-byte) voice[0]->wave()->writePW_LO(value); break; case 0x03: // Voice #1 pulse width (bits #8-#15) voice[0]->wave()->writePW_HI(value); break; case 0x04: // Voice #1 control register voice[0]->writeCONTROL_REG(muted[0] ? 0 : value); break; case 0x05: // Voice #1 Attack and Decay length voice[0]->envelope()->writeATTACK_DECAY(value); break; case 0x06: // Voice #1 Sustain volume and Release length voice[0]->envelope()->writeSUSTAIN_RELEASE(value); break; case 0x07: // Voice #2 frequency (Low-byte) voice[1]->wave()->writeFREQ_LO(value); break; case 0x08: // Voice #2 frequency (High-byte) voice[1]->wave()->writeFREQ_HI(value); break; case 0x09: // Voice #2 pulse width (Low-byte) voice[1]->wave()->writePW_LO(value); break; case 0x0a: // Voice #2 pulse width (bits #8-#15) voice[1]->wave()->writePW_HI(value); break; case 0x0b: // Voice #2 control register voice[1]->writeCONTROL_REG(muted[1] ? 0 : value); break; case 0x0c: // Voice #2 Attack and Decay length voice[1]->envelope()->writeATTACK_DECAY(value); break; case 0x0d: // Voice #2 Sustain volume and Release length voice[1]->envelope()->writeSUSTAIN_RELEASE(value); break; case 0x0e: // Voice #3 frequency (Low-byte) voice[2]->wave()->writeFREQ_LO(value); break; case 0x0f: // Voice #3 frequency (High-byte) voice[2]->wave()->writeFREQ_HI(value); break; case 0x10: // Voice #3 pulse width (Low-byte) voice[2]->wave()->writePW_LO(value); break; case 0x11: // Voice #3 pulse width (bits #8-#15) voice[2]->wave()->writePW_HI(value); break; case 0x12: // Voice #3 control register voice[2]->writeCONTROL_REG(muted[2] ? 0 : value); break; case 0x13: // Voice #3 Attack and Decay length voice[2]->envelope()->writeATTACK_DECAY(value); break; case 0x14: // Voice #3 Sustain volume and Release length voice[2]->envelope()->writeSUSTAIN_RELEASE(value); break; case 0x15: // Filter cut off frequency (bits #0-#2) filter6581->writeFC_LO(value); filter8580->writeFC_LO(value); break; case 0x16: // Filter cut off frequency (bits #3-#10) filter6581->writeFC_HI(value); filter8580->writeFC_HI(value); break; case 0x17: // Filter control filter6581->writeRES_FILT(value); filter8580->writeRES_FILT(value); break; case 0x18: // Volume and filter modes filter6581->writeMODE_VOL(value); filter8580->writeMODE_VOL(value); break; default: break; } // Update voicesync just in case. voiceSync(false); } void SID::setSamplingParameters(double clockFrequency, SamplingMethod method, double samplingFrequency, double highestAccurateFrequency) { externalFilter->setClockFrequency(clockFrequency); switch (method) { case DECIMATE: resampler.reset(new ZeroOrderResampler(clockFrequency, samplingFrequency)); break; case RESAMPLE: resampler.reset(TwoPassSincResampler::create(clockFrequency, samplingFrequency, highestAccurateFrequency)); break; default: throw SIDError("Unknown sampling method"); } } void SID::clockSilent(unsigned int cycles) { ageBusValue(cycles); while (cycles != 0) { int delta_t = std::min(nextVoiceSync, cycles); if (delta_t > 0) { for (int i = 0; i < delta_t; i++) { // clock waveform generators (can affect OSC3) voice[0]->wave()->clock(); voice[1]->wave()->clock(); voice[2]->wave()->clock(); voice[0]->wave()->output(voice[2]->wave()); voice[1]->wave()->output(voice[0]->wave()); voice[2]->wave()->output(voice[1]->wave()); // clock ENV3 only voice[2]->envelope()->clock(); } cycles -= delta_t; nextVoiceSync -= delta_t; } if (nextVoiceSync == 0) { voiceSync(true); } } } } // namespace reSIDfp