feat(filter): Add modulation support and LFO integration
This commit is contained in:
parent
3c3fec9b90
commit
fe594a5494
6 changed files with 131 additions and 20 deletions
|
|
@ -1,21 +1,22 @@
|
||||||
#include "Filter.hpp"
|
#include "Filter.hpp"
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
#ifndef M_PI
|
#ifndef M_PI
|
||||||
#define M_PI 3.14159265358979323846
|
#define M_PI 3.14159265358979323846
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Filter::Filter(float initCutOff, float initQ, float initSampleRate)
|
Filter::Filter(float initCutOff, float initQ, float initSampleRate)
|
||||||
: cutOff_(initCutOff), q_(initQ), sampleRate_(initSampleRate),
|
: modulation_(0.0f), cutOff_(initCutOff), q_(initQ),
|
||||||
type_(kLowPass), g_(0.0f), lpL_(0.0f), bpL_(0.0f), lpR_(0.0f),
|
sampleRate_(initSampleRate), type_(kLowPass), g_(0.0f), lpL_(0.0f),
|
||||||
bpR_(0.0f) {
|
bpL_(0.0f), lpR_(0.0f), bpR_(0.0f) {
|
||||||
updateCoeffs();
|
updateCoeffs();
|
||||||
}
|
}
|
||||||
|
|
||||||
Filter::FilterType Filter::getType() const { return type_; }
|
Filter::FilterType Filter::getType() const { return type_; }
|
||||||
|
|
||||||
void Filter::updateCoeffs() {
|
void Filter::updateCoeffs() {
|
||||||
float f = cutOff_ / std::fmax(sampleRate_, 1.0f);
|
float f = (cutOff_ + modulation_) / std::fmax(sampleRate_, 1.0f);
|
||||||
if (f > kMaxNormalizedFrequency)
|
if (f > kMaxNormalizedFrequency)
|
||||||
f = kMaxNormalizedFrequency;
|
f = kMaxNormalizedFrequency;
|
||||||
g_ = 2.0f * std::sin(M_PI * f);
|
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 lp = lpL_;
|
||||||
float bp = bpL_;
|
float bp = bpL_;
|
||||||
|
|
||||||
for (uint32_t i = 0; i < frames; ++i) {
|
for (uint32_t i = 0; i < frames; ++i) {
|
||||||
|
if (modulation != nullptr)
|
||||||
|
setModulation(modulation[i]);
|
||||||
out[i] = processFrame(in[i], lp, bp);
|
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,
|
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 lpL = lpL_, bpL = bpL_;
|
||||||
float lpR = lpR_, bpR = bpR_;
|
float lpR = lpR_, bpR = bpR_;
|
||||||
|
|
||||||
for (uint32_t i = 0; i < frames; ++i) {
|
for (uint32_t i = 0; i < frames; ++i) {
|
||||||
|
if (modulation != nullptr)
|
||||||
|
setModulation(modulation[i]);
|
||||||
outL[i] = processFrame(inL[i], lpL, bpL);
|
outL[i] = processFrame(inL[i], lpL, bpL);
|
||||||
outR[i] = processFrame(inR[i], lpR, bpR);
|
outR[i] = processFrame(inR[i], lpR, bpR);
|
||||||
}
|
}
|
||||||
|
|
@ -88,3 +95,11 @@ void Filter::setSampleRate(float sr) {
|
||||||
sampleRate_ = sr;
|
sampleRate_ = sr;
|
||||||
updateCoeffs();
|
updateCoeffs();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float Filter::getModulation() const { return modulation_; }
|
||||||
|
void Filter::setModulation(float mod) {
|
||||||
|
if (modulation_ == mod)
|
||||||
|
return;
|
||||||
|
modulation_ = mod;
|
||||||
|
updateCoeffs();
|
||||||
|
}
|
||||||
|
|
@ -13,21 +13,26 @@ public:
|
||||||
enum FilterType { kLowPass, kHighPass, kBandPass, kNotch, kFilterTypeCount };
|
enum FilterType { kLowPass, kHighPass, kBandPass, kNotch, kFilterTypeCount };
|
||||||
|
|
||||||
void setCutOff(float freq);
|
void setCutOff(float freq);
|
||||||
void setQ(float q);
|
|
||||||
void setSampleRate(float sr);
|
|
||||||
void setType(FilterType type);
|
|
||||||
|
|
||||||
float getCutOff() const;
|
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,
|
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:
|
private:
|
||||||
void updateCoeffs();
|
void updateCoeffs();
|
||||||
|
float modulation_;
|
||||||
|
|
||||||
float processFrame(float input, float &lp, float &bp) const;
|
float processFrame(float input, float &lp, float &bp) const;
|
||||||
|
|
||||||
|
|
|
||||||
44
core/Oscillator.cpp
Normal file
44
core/Oscillator.cpp
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
#include "Oscillator.hpp"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
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_; }
|
||||||
39
core/Oscillator.hpp
Normal file
39
core/Oscillator.hpp
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
#ifndef OSCILLATOR_HPP_INCLUDED
|
||||||
|
#define OSCILLATOR_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#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
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/make -f
|
#!/usr/bin/make -f
|
||||||
NAME = SquidgeFilter
|
NAME = SquidgeFilter
|
||||||
|
|
||||||
FILES_DSP = SquidgeFilter.cpp ../../core/Filter.cpp
|
FILES_DSP = SquidgeFilter.cpp ../../core/Filter.cpp ../../core/Oscillator.cpp
|
||||||
|
|
||||||
TARGETS = vst3 clap
|
TARGETS = vst3 clap
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,12 @@
|
||||||
#include "DistrhoPluginInfo.h"
|
#include "DistrhoPluginInfo.h"
|
||||||
|
|
||||||
#include "../../core/Filter.hpp"
|
#include "../../core/Filter.hpp"
|
||||||
|
#include "../../core/Oscillator.hpp"
|
||||||
|
|
||||||
START_NAMESPACE_DISTRHO
|
START_NAMESPACE_DISTRHO
|
||||||
|
|
||||||
|
const int BUFFER_SIZE = 16384;
|
||||||
|
|
||||||
class SquidgeFilter : public Plugin {
|
class SquidgeFilter : public Plugin {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
@ -17,8 +20,8 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
SquidgeFilter() // Note: Constructor name must match class name
|
SquidgeFilter() // Note: Constructor name must match class name
|
||||||
: Plugin(kParameterCount, 0, 0),
|
: Plugin(kParameterCount, 0, 0), filter_(1000.0f, 0.707f, 48000.0f),
|
||||||
filter_(1000.0f, 0.707f, 48000.0f) { // Default: 1kHz, Q=0.707
|
lfo_(4.0f) { // Default: 1kHz, Q=0.707
|
||||||
filter_.setType(Filter::kLowPass);
|
filter_.setType(Filter::kLowPass);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -94,7 +97,6 @@ protected:
|
||||||
filter_.setQ(value);
|
filter_.setQ(value);
|
||||||
break;
|
break;
|
||||||
case kParamType:
|
case kParamType:
|
||||||
// Clamp value to valid enum range
|
|
||||||
int typeIdx = static_cast<int>(std::fmin(std::fmax(value, 0.0f), 3.0f));
|
int typeIdx = static_cast<int>(std::fmin(std::fmax(value, 0.0f), 3.0f));
|
||||||
filter_.setType(static_cast<Filter::FilterType>(typeIdx));
|
filter_.setType(static_cast<Filter::FilterType>(typeIdx));
|
||||||
break;
|
break;
|
||||||
|
|
@ -102,15 +104,21 @@ protected:
|
||||||
}
|
}
|
||||||
|
|
||||||
void run(const float **inputs, float **outputs, uint32_t frames) override {
|
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 {
|
void sampleRateChanged(double newSr) override {
|
||||||
filter_.setSampleRate(static_cast<float>(newSr));
|
filter_.setSampleRate(static_cast<float>(newSr));
|
||||||
|
lfo_.setSampleRate(newSr);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Filter filter_;
|
Filter filter_;
|
||||||
|
Oscillator lfo_;
|
||||||
|
float lfoBuffer_[BUFFER_SIZE];
|
||||||
|
|
||||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(SquidgeFilter);
|
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(SquidgeFilter);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue