diff --git a/core/Filter.cpp b/core/Filter.cpp index 86efe2d..b325d4b 100644 --- a/core/Filter.cpp +++ b/core/Filter.cpp @@ -1,21 +1,22 @@ #include "Filter.hpp" #include +#include #ifndef M_PI #define M_PI 3.14159265358979323846 #endif Filter::Filter(float initCutOff, float initQ, float initSampleRate) - : cutOff_(initCutOff), q_(initQ), sampleRate_(initSampleRate), - type_(kLowPass), g_(0.0f), lpL_(0.0f), bpL_(0.0f), lpR_(0.0f), - bpR_(0.0f) { + : modulation_(0.0f), cutOff_(initCutOff), q_(initQ), + sampleRate_(initSampleRate), type_(kLowPass), g_(0.0f), lpL_(0.0f), + bpL_(0.0f), lpR_(0.0f), bpR_(0.0f) { updateCoeffs(); } Filter::FilterType Filter::getType() const { return type_; } void Filter::updateCoeffs() { - float f = cutOff_ / std::fmax(sampleRate_, 1.0f); + float f = (cutOff_ + modulation_) / std::fmax(sampleRate_, 1.0f); if (f > kMaxNormalizedFrequency) f = kMaxNormalizedFrequency; g_ = 2.0f * std::sin(M_PI * f); @@ -41,11 +42,14 @@ float Filter::processFrame(float input, float &lp, float &bp) const { } } -void Filter::process(const float *in, float *out, uint32_t frames) { +void Filter::process(const float *in, float *out, uint32_t frames, + const float *modulation) { float lp = lpL_; float bp = bpL_; for (uint32_t i = 0; i < frames; ++i) { + if (modulation != nullptr) + setModulation(modulation[i]); out[i] = processFrame(in[i], lp, bp); } @@ -54,11 +58,14 @@ void Filter::process(const float *in, float *out, uint32_t frames) { } void Filter::processStereo(const float *inL, const float *inR, float *outL, - float *outR, uint32_t frames) { + float *outR, uint32_t frames, + const float *modulation) { float lpL = lpL_, bpL = bpL_; float lpR = lpR_, bpR = bpR_; for (uint32_t i = 0; i < frames; ++i) { + if (modulation != nullptr) + setModulation(modulation[i]); outL[i] = processFrame(inL[i], lpL, bpL); outR[i] = processFrame(inR[i], lpR, bpR); } @@ -88,3 +95,11 @@ void Filter::setSampleRate(float sr) { sampleRate_ = sr; updateCoeffs(); } + +float Filter::getModulation() const { return modulation_; } +void Filter::setModulation(float mod) { + if (modulation_ == mod) + return; + modulation_ = mod; + updateCoeffs(); +} \ No newline at end of file diff --git a/core/Filter.hpp b/core/Filter.hpp index 63420e0..ca0a9ac 100644 --- a/core/Filter.hpp +++ b/core/Filter.hpp @@ -13,21 +13,26 @@ public: enum FilterType { kLowPass, kHighPass, kBandPass, kNotch, kFilterTypeCount }; void setCutOff(float freq); - void setQ(float q); - void setSampleRate(float sr); - void setType(FilterType type); - float getCutOff() const; - float getQ() const; - float getSampleRate() const; - FilterType getType() const; - void process(const float *in, float *out, uint32_t frames); + void setQ(float q); + float getQ() const; + void setSampleRate(float sr); + float getSampleRate() const; + void setType(FilterType type); + FilterType getType() const; + void setModulation(float mod); + float getModulation() const; + + void process(const float *in, float *out, uint32_t frames, + const float *modulation = nullptr); void processStereo(const float *inL, const float *inR, float *outL, - float *outR, uint32_t frames); + float *outR, uint32_t frames, + const float *modulation = nullptr); private: void updateCoeffs(); + float modulation_; float processFrame(float input, float &lp, float &bp) const; diff --git a/core/Oscillator.cpp b/core/Oscillator.cpp new file mode 100644 index 0000000..523616d --- /dev/null +++ b/core/Oscillator.cpp @@ -0,0 +1,44 @@ +#include "Oscillator.hpp" + +#include + +Oscillator::Oscillator(float initFreq) + : freq_(initFreq), gain_(100.0f), waveShape_(kWaveShapeSine), + sampleRate_(48000.f), phase_(0.0f), inc_(0.0f) { + recalc_(); +}; + +void Oscillator::process(float *out, uint32_t frames) { + for (uint32_t i = 0; i < frames; ++i) { + switch (waveShape_) { + default: + case kWaveShapeSine: + out[i] = std::sinf(phase_ * 2.0f * M_PI) * gain_; + break; + } + phase_ += inc_; + if (phase_ >= 1.0f) + phase_ -= 1.0f; + } +} + +void Oscillator::recalc_() { inc_ = freq_ / sampleRate_; } + +void Oscillator::setFrequency(float newFreq) { + freq_ = std::fmax(newFreq, 0.0f); +} +float Oscillator::getFrequency() const { return freq_; }; + +void Oscillator::setGain(float newGain) { + gain_ = newGain > 0 ? newGain : 1.0f; +} +float Oscillator::getGain() const { return gain_; }; + +void Oscillator::setSampleRate(float newSampleRate) { + sampleRate_ = newSampleRate > 0 ? newSampleRate : 48000.0f; + recalc_(); +} +float Oscillator::getSampleRate() const { return sampleRate_; } + +void Oscillator::setWaveShape(WaveShape shape) { waveShape_ = shape; } +Oscillator::WaveShape Oscillator::getWaveShape() const { return waveShape_; } \ No newline at end of file diff --git a/core/Oscillator.hpp b/core/Oscillator.hpp new file mode 100644 index 0000000..e246ee9 --- /dev/null +++ b/core/Oscillator.hpp @@ -0,0 +1,39 @@ +#ifndef OSCILLATOR_HPP_INCLUDED +#define OSCILLATOR_HPP_INCLUDED + +#include + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +class Oscillator { + enum WaveShape { kWaveShapeSine, kWaveShapeTriangle, kWaveShapeSquare }; + +public: + Oscillator(float initFreq); + void process(float *out, uint32_t frames); + + void setFrequency(float newFreq); + float getFrequency() const; + + void setGain(float newGain); + float getGain() const; + + void setSampleRate(float newSampleRate); + float getSampleRate() const; + + void setWaveShape(WaveShape shape); + WaveShape getWaveShape() const; + +private: + float freq_; + float gain_; + WaveShape waveShape_; + float sampleRate_; + float phase_; + float inc_; + void recalc_(); +}; + +#endif // OSCILLATOR_HPP_INCLUDED \ No newline at end of file diff --git a/plugins/SquidgeFilter/Makefile b/plugins/SquidgeFilter/Makefile index 4d6640f..9728c49 100644 --- a/plugins/SquidgeFilter/Makefile +++ b/plugins/SquidgeFilter/Makefile @@ -1,7 +1,7 @@ #!/usr/bin/make -f NAME = SquidgeFilter -FILES_DSP = SquidgeFilter.cpp ../../core/Filter.cpp +FILES_DSP = SquidgeFilter.cpp ../../core/Filter.cpp ../../core/Oscillator.cpp TARGETS = vst3 clap diff --git a/plugins/SquidgeFilter/SquidgeFilter.cpp b/plugins/SquidgeFilter/SquidgeFilter.cpp index 1339b3f..2d06bac 100644 --- a/plugins/SquidgeFilter/SquidgeFilter.cpp +++ b/plugins/SquidgeFilter/SquidgeFilter.cpp @@ -3,9 +3,12 @@ #include "DistrhoPluginInfo.h" #include "../../core/Filter.hpp" +#include "../../core/Oscillator.hpp" START_NAMESPACE_DISTRHO +const int BUFFER_SIZE = 16384; + class SquidgeFilter : public Plugin { public: @@ -17,8 +20,8 @@ public: }; SquidgeFilter() // Note: Constructor name must match class name - : Plugin(kParameterCount, 0, 0), - filter_(1000.0f, 0.707f, 48000.0f) { // Default: 1kHz, Q=0.707 + : Plugin(kParameterCount, 0, 0), filter_(1000.0f, 0.707f, 48000.0f), + lfo_(4.0f) { // Default: 1kHz, Q=0.707 filter_.setType(Filter::kLowPass); } @@ -94,7 +97,6 @@ protected: filter_.setQ(value); break; case kParamType: - // Clamp value to valid enum range int typeIdx = static_cast(std::fmin(std::fmax(value, 0.0f), 3.0f)); filter_.setType(static_cast(typeIdx)); break; @@ -102,15 +104,21 @@ protected: } void run(const float **inputs, float **outputs, uint32_t frames) override { - filter_.processStereo(inputs[0], inputs[1], outputs[0], outputs[1], frames); + lfo_.process(lfoBuffer_, frames); + + filter_.processStereo(inputs[0], inputs[1], outputs[0], outputs[1], frames, + lfoBuffer_); } void sampleRateChanged(double newSr) override { filter_.setSampleRate(static_cast(newSr)); + lfo_.setSampleRate(newSr); } private: Filter filter_; + Oscillator lfo_; + float lfoBuffer_[BUFFER_SIZE]; DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(SquidgeFilter); };