diff --git a/src/Filter6581.cpp b/src/Filter6581.cpp index cf7162f..fd2f4b9 100644 --- a/src/Filter6581.cpp +++ b/src/Filter6581.cpp @@ -72,4 +72,9 @@ void Filter6581::setFilterRange(double adjustment) FilterModelConfig6581::getInstance()->setFilterRange(adjustment); } +void Filter6581::enableOldCaps(bool enable) +{ + FilterModelConfig6581::getInstance()->enableOldCaps(enable); +} + } // namespace reSIDfp diff --git a/src/Filter6581.h b/src/Filter6581.h index 74c2d60..a9c0285 100644 --- a/src/Filter6581.h +++ b/src/Filter6581.h @@ -361,6 +361,13 @@ class Filter6581 final : public Filter * This also affects the range. Default is 0.5 */ void setFilterRange(double adjustment); + + /** + * Set filter offset and range based on single parameter. + * + * @param enable true to enable old 2200pF caps, false to use new 470pF caps. + */ + void enableOldCaps(bool enable); }; } // namespace reSIDfp diff --git a/src/FilterModelConfig.cpp b/src/FilterModelConfig.cpp index 77dfcc8..b4b61bf 100644 --- a/src/FilterModelConfig.cpp +++ b/src/FilterModelConfig.cpp @@ -41,6 +41,7 @@ FilterModelConfig::FilterModelConfig( Vdd(vdd), Vth(vth), Vddt(Vdd - Vth), + uCox(ucox), vmin(opamp_voltage[0].x), vmax(std::max(Vddt, opamp_voltage[0].y)), denorm(vmax - vmin), @@ -52,7 +53,7 @@ FilterModelConfig::FilterModelConfig( volume(new unsigned short[16 * (1 << 16)]), resonance(new unsigned short[16 * (1 << 16)]) { - setUCox(ucox); + calcCurrFactorCoeff(); // Convert op-amp voltage transfer to 16 bit values. @@ -87,9 +88,8 @@ FilterModelConfig::~FilterModelConfig() delete [] resonance; } -void FilterModelConfig::setUCox(double new_uCox) +void FilterModelConfig::calcCurrFactorCoeff() { - uCox = new_uCox; currFactorCoeff = denorm * (uCox / 2. * 1.0e-6 / C); } diff --git a/src/FilterModelConfig.h b/src/FilterModelConfig.h index 2e23a18..b02bfc7 100644 --- a/src/FilterModelConfig.h +++ b/src/FilterModelConfig.h @@ -168,7 +168,7 @@ class FilterModelConfig ~FilterModelConfig(); - void setUCox(double new_uCox); + void calcCurrFactorCoeff(); virtual double getVoiceDC(unsigned int env) const = 0; diff --git a/src/FilterModelConfig6581.cpp b/src/FilterModelConfig6581.cpp index 0c3179f..2f345d2 100644 --- a/src/FilterModelConfig6581.cpp +++ b/src/FilterModelConfig6581.cpp @@ -1,7 +1,7 @@ /* * This file is part of libsidplayfp, a SID player engine. * - * Copyright 2011-2024 Leandro Nini + * Copyright 2011-2026 Leandro Nini * Copyright 2007-2010 Antti Lankila * Copyright 2010 Dag Lem * @@ -83,6 +83,9 @@ constexpr Spline::Point opamp_voltage[OPAMP_SIZE] = { 10.31, 0.81 }, // Approximate end of actual range }; +constexpr double CAPS_OLD = 2200e-12; // ASSY 326298 uses 2200pF caps +constexpr double CAPS_NEW = 470e-12; // Standard caps used on other ASSY + std::unique_ptr FilterModelConfig6581::instance(nullptr); std::once_flag flag6581; @@ -110,13 +113,32 @@ void FilterModelConfig6581::setFilterRange(double adjustment) if (std::abs(uCox - new_uCox) < 1e-12) return; - setUCox(new_uCox); + uCox = new_uCox; + updateParams(); +} + +void FilterModelConfig6581::enableOldCaps(bool enable) +{ + if (m_oldCaps == enable) + return; + + m_oldCaps = enable; + updateParams(); +} + +void FilterModelConfig6581::updateParams() +{ + calcCurrFactorCoeff(); + + double caps_mult = m_oldCaps ? CAPS_NEW/CAPS_OLD : 1.0; + currFactorCoeff *= caps_mult; + vcr_mult = uCox * caps_mult; } FilterModelConfig6581::FilterModelConfig6581() : FilterModelConfig( 1.5, // voice voltage range FIXME should theoretically be ~3,571V - 470e-12, // capacitor value - FIXME ASSY 326298 uses 2200pF caps + CAPS_NEW, // capacitor value 12. * VOLTAGE_SKEW, // Vdd 1.31, // Vth 20e-6, // uCox @@ -127,8 +149,11 @@ FilterModelConfig6581::FilterModelConfig6581() : WL_snake(1.0 / 115.0), dac_zero(6.65), dac_scale(2.63), - dac(DAC_BITS) + dac(DAC_BITS), + m_oldCaps(false) { + updateParams(); + dac.kinkedDac(MOS6581); { diff --git a/src/FilterModelConfig6581.h b/src/FilterModelConfig6581.h index df568f5..19b90b7 100644 --- a/src/FilterModelConfig6581.h +++ b/src/FilterModelConfig6581.h @@ -1,7 +1,7 @@ /* * This file is part of libsidplayfp, a SID player engine. * - * Copyright 2011-2025 Leandro Nini + * Copyright 2011-2026 Leandro Nini * Copyright 2007-2010 Antti Lankila * Copyright 2004,2010 Dag Lem * @@ -75,12 +75,17 @@ class FilterModelConfig6581 final : public FilterModelConfig double vcr_n_Ids_term[1 << 16]; //@} + double vcr_mult; + bool m_oldCaps; + // Voice DC offset LUT double voiceDC[256]; private: double getDacZero(double adjustment) const { return dac_zero + 3. * adjustment - 1.; } + void updateParams(); + FilterModelConfig6581(); ~FilterModelConfig6581() = default; @@ -99,6 +104,8 @@ class FilterModelConfig6581 final : public FilterModelConfig void setFilterRange(double adjustment); + void enableOldCaps(bool enable); + /** * Construct an 11 bit cutoff frequency DAC output voltage table. * Ownership is transferred to the requester which becomes responsible @@ -114,7 +121,7 @@ class FilterModelConfig6581 final : public FilterModelConfig inline unsigned short getVcr_nVg(int i) const { return vcr_nVg[i]; } inline unsigned short getVcr_n_Ids_term(int i) const { - return to_ushort(vcr_n_Ids_term[i] * uCox); + return to_ushort(vcr_n_Ids_term[i] * vcr_mult); } // only used if SLOPE_FACTOR is defined static inline constexpr double getUt() { return Ut; } diff --git a/src/SID.cpp b/src/SID.cpp index 628c91c..ea7a979 100644 --- a/src/SID.cpp +++ b/src/SID.cpp @@ -178,6 +178,11 @@ void SID::enableFilter(bool enable) filter8580->enable(enable); } +void SID::enableOld6581caps(bool enable) +{ + filter6581->enableOldCaps(enable); +} + void SID::voiceSync(bool sync) { if (sync) diff --git a/src/SID.h b/src/SID.h index d8a9264..ffd4352 100644 --- a/src/SID.h +++ b/src/SID.h @@ -264,7 +264,7 @@ class SID * * @see Filter6581::setFilterRange(double) */ - void setFilter6581Range ( double adjustment ); + void setFilter6581Range(double adjustment); /** * Set filter curve parameter for 8580 model. @@ -279,6 +279,11 @@ class SID * @param enable false to turn off filter emulation */ void enableFilter(bool enable); + + /** + * Enable/disable old caps (2200pF) for 6581 model. + */ + void enableOld6581caps(bool enable); }; } // namespace reSIDfp diff --git a/src/residfp/residfp.cpp b/src/residfp/residfp.cpp index f4c6935..3258a0c 100644 --- a/src/residfp/residfp.cpp +++ b/src/residfp/residfp.cpp @@ -131,3 +131,8 @@ void residfp::enableFilter(bool enable) { sid.enableFilter(enable); } + +void residfp::enableOld6581caps(bool enable) +{ + sid.enableOld6581caps(enable); +} diff --git a/src/residfp/residfp.h b/src/residfp/residfp.h index f12e0e8..c81277c 100644 --- a/src/residfp/residfp.h +++ b/src/residfp/residfp.h @@ -175,7 +175,7 @@ class RESIDFP_EXTERN residfp void setFilter6581Curve(double filterCurve); /** - * Set filter range parameter for 6581 model + * Set filter range parameter for 6581 model. * * @see Filter6581::setFilterRange(double) */ @@ -194,6 +194,14 @@ class RESIDFP_EXTERN residfp * @param enable false to turn off filter emulation */ void enableFilter(bool enable); + + /** + * Enable/disable old caps for 6581 model. + * + * @param enable true to enable old 2200pF caps used on ASSY 326298 + * false to use the standard 470pF caps. + */ + void enableOld6581caps(bool enable); }; }