template wizardry resulting in a mono version of SVFilter for synth use

master
zetaPRIME 2022-03-23 01:32:07 -04:00
parent acbca4ae0b
commit a28d6e48b6
3 changed files with 35 additions and 20 deletions

4
notes
View File

@ -35,9 +35,7 @@ TODO {
about-license info 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 revert-to-saved menu action

View File

@ -4,10 +4,15 @@
#include "audio/audioengine.h" #include "audio/audioengine.h"
using Xybrid::NodeLib::SVFilter; using Xybrid::NodeLib::SVFilter;
using Xybrid::NodeLib::GenericSVFilter;
using Xybrid::Data::AudioFrame; using Xybrid::Data::AudioFrame;
using namespace Xybrid::Audio; using namespace Xybrid::Audio;
void SVFilter::process(AudioFrame in, double cutoff, double resonance, int ovs) { template class Xybrid::NodeLib::GenericSVFilter<AudioFrame>;
template class Xybrid::NodeLib::GenericSVFilter<double>;
template<typename DT>
void GenericSVFilter<DT>::process(DT in, double cutoff, double resonance, int ovs) {
if (ovs <= 0) return; if (ovs <= 0) return;
cutoff = std::max(cutoff, 1.0); cutoff = std::max(cutoff, 1.0);
resonance = std::max(resonance, 0.01); resonance = std::max(resonance, 0.01);

View File

@ -7,32 +7,44 @@
namespace Xybrid::NodeLib { namespace Xybrid::NodeLib {
/// 12db Chamberlin State Variable Filter /// 12db Chamberlin State Variable Filter
class SVFilter { template<typename DT> class GenericSVFilter {
//
public: public:
/// Default oversampling level. Enough to mostly eliminate artifacting at high cutoff. /// Default oversampling level. Enough to mostly eliminate artifacting at high cutoff.
static const constexpr int DEFAULT_OVERSAMP = 3; static const constexpr int DEFAULT_OVERSAMP = 3;
Data::AudioFrame low = 0.0; DT low = 0.0;
Data::AudioFrame high = 0.0; DT high = 0.0;
Data::AudioFrame band = 0.0; DT band = 0.0;
Data::AudioFrame notch = 0.0; DT notch = 0.0;
SVFilter() = default; GenericSVFilter() = default;
~SVFilter() = default; ~GenericSVFilter() = default;
// nothing used here should care about taking the raw approach // nothing used here should care about taking the raw approach
inline SVFilter(const SVFilter& o) { std::memcpy(static_cast<void*>(this), static_cast<const void*>(&o), sizeof(SVFilter)); } inline GenericSVFilter<DT>(const GenericSVFilter<DT>& o) { std::memcpy(static_cast<void*>(this), static_cast<const void*>(&o), sizeof(o)); }
inline SVFilter& operator=(const SVFilter& o) { std::memcpy(static_cast<void*>(this), static_cast<const void*>(&o), sizeof(SVFilter)); return *this; } inline GenericSVFilter<DT>& operator=(const GenericSVFilter<DT>& o) { std::memcpy(static_cast<void*>(this), static_cast<const void*>(&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 reset() { low = 0.0; high = 0.0; band = 0.0; notch = 0.0; }
inline void normalize(double m = 1.0) { inline void normalize(double m) {
low = low.clamp(m); if constexpr (std::is_arithmetic_v<DT>) {
high = high.clamp(m); low = std::clamp(low, -m, m);
band = band.clamp(m); high = std::clamp(high, -m, m);
notch = notch.clamp(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); } static inline double scaledResonance(double r) { return std::pow(10, r*5); }
}; };
/// 12db Chamberlin State Variable Filter
typedef GenericSVFilter<Data::AudioFrame> SVFilter;
/// 12db Chamberlin State Variable Filter (mono version)
typedef GenericSVFilter<double> SVFilterM;
} }