/* * This file is part of libsidplayfp, a SID player engine. * * Copyright 2011-2014 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 "Filter6581.h" #include "Filter8580.h" #include "Potentiometer.h" #include "WaveformCalculator.h" #include "resample/TwoPassSincResampler.h" #include "resample/ZeroOrderResampler.h" namespace reSIDfp { /** * Bus value stays alive for some time after each operation. * * This values has been adjusted empirically according to the discussion * "How do I reliably detect 6581/8580 sid?" on CSDb [1]. * * [1]: http://noname.c64.org/csdb/forums/?roomid=11&topicid=29025&showallposts=1 */ //@{ const int BUS_TTL_6581 = 0x1000; const int BUS_TTL_8580 = 0xa2000; //@} SID::SID() : filter6581(new Filter6581()), filter8580(new Filter8580()), externalFilter(new ExternalFilter()), resampler(0), 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::writeImmediate(int offset, unsigned char value) { switch (offset) { case 0x00: voice[0]->wave()->writeFREQ_LO(value); break; case 0x01: voice[0]->wave()->writeFREQ_HI(value); break; case 0x02: voice[0]->wave()->writePW_LO(value); break; case 0x03: voice[0]->wave()->writePW_HI(value); break; case 0x04: voice[0]->writeCONTROL_REG(muted[0] ? 0 : value); break; case 0x05: voice[0]->envelope()->writeATTACK_DECAY(value); break; case 0x06: voice[0]->envelope()->writeSUSTAIN_RELEASE(value); break; case 0x07: voice[1]->wave()->writeFREQ_LO(value); break; case 0x08: voice[1]->wave()->writeFREQ_HI(value); break; case 0x09: voice[1]->wave()->writePW_LO(value); break; case 0x0a: voice[1]->wave()->writePW_HI(value); break; case 0x0b: voice[1]->writeCONTROL_REG(muted[1] ? 0 : value); break; case 0x0c: voice[1]->envelope()->writeATTACK_DECAY(value); break; case 0x0d: voice[1]->envelope()->writeSUSTAIN_RELEASE(value); break; case 0x0e: voice[2]->wave()->writeFREQ_LO(value); break; case 0x0f: voice[2]->wave()->writeFREQ_HI(value); break; case 0x10: voice[2]->wave()->writePW_LO(value); break; case 0x11: voice[2]->wave()->writePW_HI(value); break; case 0x12: voice[2]->writeCONTROL_REG(muted[2] ? 0 : value); break; case 0x13: voice[2]->envelope()->writeATTACK_DECAY(value); break; case 0x14: voice[2]->envelope()->writeSUSTAIN_RELEASE(value); break; case 0x15: filter6581->writeFC_LO(value); filter8580->writeFC_LO(value); break; case 0x16: filter6581->writeFC_HI(value); filter8580->writeFC_HI(value); break; case 0x17: filter6581->writeRES_FILT(value); filter8580->writeRES_FILT(value); break; case 0x18: filter6581->writeMODE_VOL(value); filter8580->writeMODE_VOL(value); break; default: break; } /* Update voicesync just in case. */ voiceSync(false); } 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++) { const unsigned int freq = voice[i]->wave()->readFreq(); if (voice[i]->wave()->readTest() || freq == 0 || !voice[(i + 1) % 3]->wave()->readSync()) { continue; } const unsigned int accumulator = voice[i]->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\n"); } this->model = model; /* calculate waveform-related tables, feed them to the generator */ matrix_t* tables = WaveformCalculator::getInstance()->buildTable(model); /* update voice offsets */ for (int i = 0; i < 3; i++) { voice[i]->envelope()->setChipModel(model); voice[i]->wave()->setChipModel(model); 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; delayedOffset = -1; voiceSync(false); } void SID::input(int value) { filter6581->input(value); filter8580->input(value); } unsigned char SID::read(int offset) { // FIXME: is bus TTL actually reset after read? // FIXME: are read values actually latched? switch (offset) { case 0x19: busValue = potX->readPOT(); busValueTtl = modelTTL; break; case 0x1a: busValue = potY->readPOT(); busValueTtl = modelTTL; break; case 0x1b: busValue = voice[2]->wave()->readOSC(); break; case 0x1c: busValue = voice[2]->envelope()->readENV(); busValueTtl = modelTTL; break; default: busValueTtl /= 2; // FIXME: what's this??? break; } return busValue; } void SID::write(int offset, unsigned char value) { busValue = value; busValueTtl = modelTTL; if (model == MOS8580) { delayedOffset = offset; delayedValue = value; } else { writeImmediate(offset, value); } } 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\n"); } } void SID::clockSilent(unsigned int cycles) { ageBusValue(cycles); while (cycles != 0) { int delta_t = std::min(nextVoiceSync, cycles); if (delta_t > 0) { if (delayedOffset != -1) { delta_t = 1; } 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(); /* clock ENV3 only */ voice[2]->envelope()->clock(); } if (delayedOffset != -1) { writeImmediate(delayedOffset, delayedValue); delayedOffset = -1; } cycles -= delta_t; nextVoiceSync -= delta_t; } if (nextVoiceSync == 0) { voiceSync(true); } } } } // namespace reSIDfp