From 723ee1cf1f0452aa600318b6464fb6c5f1b5a969 Mon Sep 17 00:00:00 2001 From: Leandro Nini Date: Sun, 28 Jun 2026 14:40:10 +0200 Subject: [PATCH] Rework voltage summers --- src/Filter.cpp | 40 -------------------------- src/Filter.h | 60 +++++++++++++++++++++------------------ src/Filter6581.h | 12 ++++---- src/Filter8580.h | 8 ++++-- src/FilterModelConfig.cpp | 4 +-- src/FilterModelConfig.h | 50 +++++++++++++------------------- 6 files changed, 66 insertions(+), 108 deletions(-) diff --git a/src/Filter.cpp b/src/Filter.cpp index dbc5ded..e3e79e3 100644 --- a/src/Filter.cpp +++ b/src/Filter.cpp @@ -27,49 +27,9 @@ namespace reSIDfp { -static constexpr int summerIdx[5] = -{ - FilterModelConfig::summer_offset<0>::value, - FilterModelConfig::summer_offset<1>::value, - FilterModelConfig::summer_offset<2>::value, - FilterModelConfig::summer_offset<3>::value, - FilterModelConfig::summer_offset<4>::value -}; - -static constexpr int mixerIdx[8] = -{ - FilterModelConfig::mixer_offset<0>::value, - FilterModelConfig::mixer_offset<1>::value, - FilterModelConfig::mixer_offset<2>::value, - FilterModelConfig::mixer_offset<3>::value, - FilterModelConfig::mixer_offset<4>::value, - FilterModelConfig::mixer_offset<5>::value, - FilterModelConfig::mixer_offset<6>::value, - FilterModelConfig::mixer_offset<7>::value -}; - void Filter::updateMixing() { currentVolume = volume + (vol * (1<<16)); - - int Nsum = 0; - int Nmix = 0; - - (filt1 ? Nsum : Nmix)++; - (filt2 ? Nsum : Nmix)++; - - if (filt3) Nsum++; - else if (!voice3off) Nmix++; - - (filtE ? Nsum : Nmix)++; - - currentSummer = summer + summerIdx[Nsum]; - - if (lp) Nmix++; - if (bp) Nmix++; - if (hp) Nmix++; - - currentMixer = mixer + mixerIdx[Nmix]; } void Filter::writeFC_LO(uint8_t fc_lo) diff --git a/src/Filter.h b/src/Filter.h index b5342bf..d21994a 100644 --- a/src/Filter.h +++ b/src/Filter.h @@ -51,12 +51,6 @@ class Filter const Integrator& m_bpIntegrator; - /// Current filter/voice mixer setting. - uint16_t* currentMixer = nullptr; - - /// Filter input summer setting. - uint16_t* currentSummer = nullptr; - /// Filter resonance value. uint16_t* currentResonance = nullptr; @@ -106,6 +100,17 @@ class Filter /// Selects which inputs to route through filter. uint8_t filt = 0; +private: + inline int32_t getNormalizedVoice(float v, uint8_t env) const + { + return m_fmc.getNormalizedVoice(v, env); + } + + inline int32_t getNormalizedScaledVoice(float v, uint8_t env, float scale) const + { + return m_fmc.getNormalizedVoice(v*scale, env); + } + protected: /** * Update filter cutoff frequency. @@ -131,12 +136,11 @@ class Filter virtual void restartIntegrators() = 0; - inline int32_t getNormalizedVoice(float v, uint8_t env) const - { - return m_fmc.getNormalizedVoice(v, env); - } + virtual float toFilterScale() const = 0; + + virtual float toMixerScale(bool filter) const = 0; - virtual int32_t getNormalizedMixerVoice(float v, uint8_t env) const = 0; + virtual float voice3OffScale() const = 0; public: Filter(const FilterModelConfig& fmc, @@ -227,33 +231,33 @@ uint16_t Filter::clock(Voice& voice1, Voice& voice2, Voice& voice3) // Voltage summer for filter input int32_t Vsum = 0; - Vsum += filt1 ? getNormalizedVoice(wav1, env1) : 0; - Vsum += filt2 ? getNormalizedVoice(wav2, env2) : 0; - Vsum += filt3 ? getNormalizedVoice(wav3, env3) : 0; - Vsum += filtE ? getNormalizedVoice(extin, 0) : 0; + Vsum += filt1 ? getNormalizedVoice(wav1, env1) : getNormalizedScaledVoice(wav1, env1, toFilterScale()); + Vsum += filt2 ? getNormalizedVoice(wav2, env2) : getNormalizedScaledVoice(wav2, env2, toFilterScale()); + Vsum += filt3 ? getNormalizedVoice(wav3, env3) : getNormalizedScaledVoice(wav3, env3, toFilterScale()); + Vsum += filtE ? getNormalizedVoice(extin, 0) : getNormalizedScaledVoice(extin, 0, toFilterScale()); Vsum += Vlp; Vsum += currentResonance[Vbp]; // Filter - Vhp = currentSummer[Vsum]; + Vhp = summer[Vsum]; Vbp = m_hpIntegrator.solve(Vhp); Vlp = m_bpIntegrator.solve(Vbp); - int32_t Vfilt = 0; - if (lp) Vfilt += Vlp; - if (bp) Vfilt += Vbp; - if (hp) Vfilt += Vhp; + // Voice 3 is silenced by voice3off if it is not routed through the filter. + const float v3Scale = voice3off ? voice3OffScale() : 1.f; // Voltage summer for mixer input int32_t Vmix = 0; - Vmix += filt1 ? 0 : getNormalizedMixerVoice(wav1, env1); - Vmix += filt2 ? 0 : getNormalizedMixerVoice(wav2, env2); - // Voice 3 is silenced by voice3off if it is not routed through the filter - Vmix += (filt3 || voice3off) ? 0 : getNormalizedMixerVoice(wav3, env3); - Vmix += filtE ? 0 : getNormalizedMixerVoice(extin, 0); - Vmix += Vfilt; - - return currentVolume[currentMixer[Vmix]]; + Vmix += getNormalizedScaledVoice(wav1, env1, toMixerScale(filt1)); + Vmix += getNormalizedScaledVoice(wav2, env2, toMixerScale(filt2)); + Vmix += getNormalizedScaledVoice(wav3, env3, toMixerScale(filt3) * v3Scale); + Vmix += getNormalizedScaledVoice(extin, 0, toMixerScale(filtE)); + // FIXME + Vmix += lp ? Vlp : 32768; + Vmix += bp ? Vbp : 32768; + Vmix += hp ? Vhp : 32768; + + return currentVolume[mixer[Vmix]]; } } // namespace reSIDfp diff --git a/src/Filter6581.h b/src/Filter6581.h index b068e6e..0297265 100644 --- a/src/Filter6581.h +++ b/src/Filter6581.h @@ -338,15 +338,15 @@ class Filter6581 final : public Filter void restartIntegrators() override { hpIntegrator.restart(); bpIntegrator.restart(); } - /* - * The filter input resistors on the 6581 are slightly bigger than the voice ones, - * scale the values accordingly. - */ - int32_t getNormalizedMixerVoice(float v, uint8_t env) const override + constexpr float toFilterScale() const override { return 0.05625f * 0.03f; } + + constexpr float toMixerScale(bool filter) const override { - return getNormalizedVoice(v * static_cast(FilterModelConfig6581::VF_TR_RATIO), env); + return filter ? 0.05625f * 0.045f : static_cast(FilterModelConfig6581::VF_TR_RATIO); } + constexpr float voice3OffScale() const override { return 0.05625f * 2.f; } + public: Filter6581() : Filter(*FilterModelConfig6581::getInstance(), hpIntegrator, bpIntegrator), diff --git a/src/Filter8580.h b/src/Filter8580.h index 7ebe49c..ba211c1 100644 --- a/src/Filter8580.h +++ b/src/Filter8580.h @@ -295,11 +295,15 @@ class Filter8580 final : public Filter void restartIntegrators() override { hpIntegrator.restart(); bpIntegrator.restart(); } - int32_t getNormalizedMixerVoice(float v, uint8_t env) const override + constexpr float toFilterScale() const override { return 0.02625f * 0.03f; } + + constexpr float toMixerScale(bool filter) const override { - return getNormalizedVoice(v, env); + return filter ? 0.02625f * 0.045f : 1.f; } + constexpr float voice3OffScale() const override { return 0.02625f * 2.f; } + public: Filter8580() : Filter(*FilterModelConfig8580::getInstance(), hpIntegrator, bpIntegrator), diff --git a/src/FilterModelConfig.cpp b/src/FilterModelConfig.cpp index 5135e83..946f426 100644 --- a/src/FilterModelConfig.cpp +++ b/src/FilterModelConfig.cpp @@ -48,8 +48,8 @@ FilterModelConfig::FilterModelConfig( norm(1.0 / denorm), N16(norm * UINT16_MAX), voice_voltage_range(vvr), - mixer(new uint16_t[mixer_offset<8>::value]), - summer(new uint16_t[summer_offset<5>::value]), + mixer(new uint16_t[7 << 16]), + summer(new uint16_t[6 << 16]), volume(new uint16_t[16 * (1 << 16)]), resonance(new uint16_t[16 * (1 << 16)]) { diff --git a/src/FilterModelConfig.h b/src/FilterModelConfig.h index d875653..ff2481e 100644 --- a/src/FilterModelConfig.h +++ b/src/FilterModelConfig.h @@ -173,8 +173,7 @@ class FilterModelConfig virtual double getVoiceDC(uint8_t env) const = 0; /** - * The filter summer operates at n ~ 1, and has 5 fundamentally different - * input configurations (2 - 6 input "resistors"). + * The filter summer operates at n ~ 1, and has 6 input "resistors". * * Note that all "on" transistors are modeled as one. This is not * entirely accurate, since the input for each transistor is different, @@ -185,27 +184,22 @@ class FilterModelConfig { const double r_N16 = 1. / N16; - int idx = 0; - for (int i = 0; i < 5; i++) - { - const int idiv = 2 + i; // 2 - 6 input "resistors". - const int size = idiv << 16; - const double n = idiv; - const double r_idiv = 1. / idiv; - opampModel.reset(); + constexpr int idiv = 6; + constexpr int size = idiv << 16; + const double n = idiv; + constexpr double r_idiv = 1. / idiv; + opampModel.reset(); - for (int vi = 0; vi < size; vi++) - { - const double vin = vmin + vi * r_N16 * r_idiv; /* vmin .. vmax */ - summer[idx++] = getNormalizedValue(opampModel.solve(n, vin)); - } + for (int vi = 0; vi < size; vi++) + { + const double vin = vmin + vi * r_N16 * r_idiv; /* vmin .. vmax */ + summer[vi] = getNormalizedValue(opampModel.solve(n, vin)); } } /** * The audio mixer operates at n ~ 8/6 (6581) or 8/5 (8580), - * and has 8 fundamentally different input configurations - * (0 - 7 input "resistors"). + * and has 7 input "resistors". * * All "on", transistors are modeled as one - see comments above for * the filter summer. @@ -214,20 +208,16 @@ class FilterModelConfig { const double r_N16 = 1. / N16; - int idx = 0; - for (int i = 0; i < 8; i++) - { - const int idiv = (i == 0) ? 1 : i; - const int size = (i == 0) ? 1 : i << 16; - const double n = i * nRatio; - const double r_idiv = 1. / idiv; - opampModel.reset(); + constexpr int idiv = 7; + constexpr int size = idiv << 16; + const double n = idiv * nRatio; + constexpr double r_idiv = 1. / idiv; + opampModel.reset(); - for (int vi = 0; vi < size; vi++) - { - const double vin = vmin + vi * r_N16 * r_idiv; /* vmin .. vmax */ - mixer[idx++] = getNormalizedValue(opampModel.solve(n, vin)); - } + for (int vi = 0; vi < size; vi++) + { + const double vin = vmin + vi * r_N16 * r_idiv; /* vmin .. vmax */ + mixer[vi] = getNormalizedValue(opampModel.solve(n, vin)); } }