diff --git a/notes b/notes index 66a11f3..253bfd7 100644 --- a/notes +++ b/notes @@ -35,9 +35,7 @@ TODO { about-license info } - - fix overrun-by-1 on sample preview - - templatize svfilter and have mono version for synth use + - templatize svfilter and have mono version for synth use revert-to-saved menu action diff --git a/xybrid/nodelib/svfilter.cpp b/xybrid/nodelib/svfilter.cpp index 5060e9e..a027ff2 100644 --- a/xybrid/nodelib/svfilter.cpp +++ b/xybrid/nodelib/svfilter.cpp @@ -4,10 +4,15 @@ #include "audio/audioengine.h" using Xybrid::NodeLib::SVFilter; +using Xybrid::NodeLib::GenericSVFilter; using Xybrid::Data::AudioFrame; using namespace Xybrid::Audio; -void SVFilter::process(AudioFrame in, double cutoff, double resonance, int ovs) { +template class Xybrid::NodeLib::GenericSVFilter; +template class Xybrid::NodeLib::GenericSVFilter; + +template +void GenericSVFilter
::process(DT in, double cutoff, double resonance, int ovs) { if (ovs <= 0) return; cutoff = std::max(cutoff, 1.0); resonance = std::max(resonance, 0.01); diff --git a/xybrid/nodelib/svfilter.h b/xybrid/nodelib/svfilter.h index b70f802..b283cc2 100644 --- a/xybrid/nodelib/svfilter.h +++ b/xybrid/nodelib/svfilter.h @@ -7,32 +7,44 @@ namespace Xybrid::NodeLib { /// 12db Chamberlin State Variable Filter - class SVFilter { - // + template class GenericSVFilter { public: /// Default oversampling level. Enough to mostly eliminate artifacting at high cutoff. static const constexpr int DEFAULT_OVERSAMP = 3; - Data::AudioFrame low = 0.0; - Data::AudioFrame high = 0.0; - Data::AudioFrame band = 0.0; - Data::AudioFrame notch = 0.0; + DT low = 0.0; + DT high = 0.0; + DT band = 0.0; + DT notch = 0.0; - SVFilter() = default; - ~SVFilter() = default; + GenericSVFilter() = default; + ~GenericSVFilter() = default; // nothing used here should care about taking the raw approach - inline SVFilter(const SVFilter& o) { std::memcpy(static_cast(this), static_cast(&o), sizeof(SVFilter)); } - inline SVFilter& operator=(const SVFilter& o) { std::memcpy(static_cast(this), static_cast(&o), sizeof(SVFilter)); return *this; } + inline GenericSVFilter
(const GenericSVFilter
& o) { std::memcpy(static_cast(this), static_cast(&o), sizeof(o)); } + inline GenericSVFilter
& operator=(const GenericSVFilter
& o) { std::memcpy(static_cast(this), static_cast(&o), sizeof(o)); return *this; } - void process(Data::AudioFrame in, double cutoff, double resonance, int oversamp = DEFAULT_OVERSAMP); + void process(DT in, double cutoff, double resonance, int oversamp = DEFAULT_OVERSAMP); inline void reset() { low = 0.0; high = 0.0; band = 0.0; notch = 0.0; } - inline void normalize(double m = 1.0) { - low = low.clamp(m); - high = high.clamp(m); - band = band.clamp(m); - notch = notch.clamp(m); + inline void normalize(double m) { + if constexpr (std::is_arithmetic_v
) { + low = std::clamp(low, -m, m); + high = std::clamp(high, -m, m); + band = std::clamp(band, -m, m); + notch = std::clamp(notch, -m, m); + } else { + low = low.clamp(m); + high = high.clamp(m); + band = band.clamp(m); + notch = notch.clamp(m); + } } static inline double scaledResonance(double r) { return std::pow(10, r*5); } + }; + + /// 12db Chamberlin State Variable Filter + typedef GenericSVFilter SVFilter; + /// 12db Chamberlin State Variable Filter (mono version) + typedef GenericSVFilter SVFilterM; }