feat: add basic lp filter
This commit is contained in:
parent
2bd91c7d8e
commit
75843a7309
4 changed files with 134 additions and 9 deletions
49
core/Filter.cpp
Normal file
49
core/Filter.cpp
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
#include "Filter.hpp"
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
Filter::Filter(float initCutOff, float initSampleRate)
|
||||||
|
: cutOff_(initCutOff), feedback_(0.0f), alpha_(0.0f),
|
||||||
|
sampleRate_(initSampleRate), zL_(0.0f), zR_(0.0f) {
|
||||||
|
recompute();
|
||||||
|
};
|
||||||
|
|
||||||
|
void Filter::process(const float *in, float *out, uint32_t frames) {
|
||||||
|
filter(in, out, frames, &zL_);
|
||||||
|
};
|
||||||
|
void Filter::processStereo(const float *inLeft, const float *inRight,
|
||||||
|
float *outLeft, float *outRight, uint32_t frames) {
|
||||||
|
filter(inLeft, outLeft, frames, &zL_);
|
||||||
|
filter(inRight, outRight, frames, &zR_);
|
||||||
|
};
|
||||||
|
|
||||||
|
void Filter::filter(const float *in, float *out, uint32_t frames, float *z) {
|
||||||
|
for (uint32_t i = 0; i < frames; ++i) {
|
||||||
|
float feedbackInput = in[i] + (feedback_ * (*z));
|
||||||
|
*z = *z + alpha_ * (feedbackInput - *z);
|
||||||
|
out[i] = *z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Filter::recompute() {
|
||||||
|
float fc = std::fmax(cutOff_, 1.0f);
|
||||||
|
float rc = 1.0f / (2.0f * M_PI * fc);
|
||||||
|
float val = 1.0f - std::exp(-1.0f / (rc * sampleRate_));
|
||||||
|
alpha_ = std::fmin(val, 0.999f);
|
||||||
|
};
|
||||||
|
|
||||||
|
void Filter::setCutOff(float newCutOff) {
|
||||||
|
cutOff_ = newCutOff;
|
||||||
|
recompute();
|
||||||
|
}
|
||||||
|
float Filter::getCutOff() const { return cutOff_; }
|
||||||
|
|
||||||
|
void Filter::setFeedback(float newFeedback) {
|
||||||
|
feedback_ = std::fmin(std::fmax(newFeedback, 0.0f), 0.99f);
|
||||||
|
}
|
||||||
|
float Filter::getFeedback() const { return feedback_; }
|
||||||
|
|
||||||
|
void Filter::setSampleRate(float newSampleRate) {
|
||||||
|
sampleRate_ = newSampleRate;
|
||||||
|
recompute();
|
||||||
|
}
|
||||||
|
float Filter::getSampleRate() const { return sampleRate_; }
|
||||||
33
core/Filter.hpp
Normal file
33
core/Filter.hpp
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
#ifndef FILTER_HPP_INCLUDED
|
||||||
|
#define FILTER_HPP_INCLUDED
|
||||||
|
#ifndef M_PI
|
||||||
|
#define M_PI 3.14159265358979323846
|
||||||
|
#endif
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
class Filter {
|
||||||
|
public:
|
||||||
|
Filter(float initCutOff = 1.0f, float initSampleRate = 48000.0f);
|
||||||
|
void process(const float *in, float *out, uint32_t frames);
|
||||||
|
void processStereo(const float *inLeft, const float *inRight, float *outLeft,
|
||||||
|
float *outRight, uint32_t frames);
|
||||||
|
|
||||||
|
void recompute();
|
||||||
|
void setCutOff(float newCutOff);
|
||||||
|
float getCutOff() const;
|
||||||
|
void setFeedback(float newFeedback);
|
||||||
|
float getFeedback() const;
|
||||||
|
void setSampleRate(float newSampleRate);
|
||||||
|
float getSampleRate() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void filter(const float *in, float *out, uint32_t frames, float *z);
|
||||||
|
float cutOff_;
|
||||||
|
float feedback_;
|
||||||
|
float alpha_;
|
||||||
|
float sampleRate_;
|
||||||
|
float zL_;
|
||||||
|
float zR_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // FILTER_HPP_INCLUDED
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/make -f
|
#!/usr/bin/make -f
|
||||||
NAME = SquidgeDistortion
|
NAME = SquidgeDistortion
|
||||||
|
|
||||||
FILES_DSP = SquidgeDistortion.cpp ../../core/Gain.cpp ../../core/Clipper.cpp ../../core/Mixer.cpp
|
FILES_DSP = SquidgeDistortion.cpp ../../core/Gain.cpp ../../core/Clipper.cpp ../../core/Mixer.cpp ../../core/Filter.cpp
|
||||||
|
|
||||||
TARGETS = vst3 clap
|
TARGETS = vst3 clap
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
#include "DistrhoPluginInfo.h"
|
#include "DistrhoPluginInfo.h"
|
||||||
|
|
||||||
#include "../../core/Clipper.hpp"
|
#include "../../core/Clipper.hpp"
|
||||||
|
#include "../../core/Filter.hpp"
|
||||||
#include "../../core/Gain.hpp"
|
#include "../../core/Gain.hpp"
|
||||||
#include "../../core/Mixer.hpp"
|
#include "../../core/Mixer.hpp"
|
||||||
|
|
||||||
|
|
@ -10,6 +11,13 @@ START_NAMESPACE_DISTRHO
|
||||||
|
|
||||||
const int BUFFER_SIZE = 16384;
|
const int BUFFER_SIZE = 16384;
|
||||||
|
|
||||||
|
struct AudioBuffers {
|
||||||
|
float clippedL[BUFFER_SIZE];
|
||||||
|
float clippedR[BUFFER_SIZE];
|
||||||
|
float lpL[BUFFER_SIZE];
|
||||||
|
float lpR[BUFFER_SIZE];
|
||||||
|
};
|
||||||
|
|
||||||
class SquidgeDistortion : public Plugin {
|
class SquidgeDistortion : public Plugin {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
@ -17,11 +25,13 @@ public:
|
||||||
enum Parameters {
|
enum Parameters {
|
||||||
kParamGain,
|
kParamGain,
|
||||||
kParamClipMode,
|
kParamClipMode,
|
||||||
|
kParamFilter,
|
||||||
|
kParamFilterFeedback,
|
||||||
kParamMixVolume,
|
kParamMixVolume,
|
||||||
kParameterCount // must be last
|
kParameterCount // must be last
|
||||||
};
|
};
|
||||||
SquidgeDistortion()
|
SquidgeDistortion()
|
||||||
: Plugin(kParameterCount, 0, 0), gain_(2.0f), mixer_(1.0f) {
|
: Plugin(kParameterCount, 0, 0), gain_(2.0f), mixer_(1.0f), filter_(440) {
|
||||||
mixer_.setInputGain(kChannelDry, 0.0f);
|
mixer_.setInputGain(kChannelDry, 0.0f);
|
||||||
mixer_.setInputGain(kChannelWet, 1.0f);
|
mixer_.setInputGain(kChannelWet, 1.0f);
|
||||||
}
|
}
|
||||||
|
|
@ -62,6 +72,22 @@ protected:
|
||||||
parameter.enumValues.values =
|
parameter.enumValues.values =
|
||||||
const_cast<ParameterEnumerationValue *>(sClipModes);
|
const_cast<ParameterEnumerationValue *>(sClipModes);
|
||||||
break;
|
break;
|
||||||
|
case kParamFilter:
|
||||||
|
parameter.name = "Filter";
|
||||||
|
parameter.symbol = "filter";
|
||||||
|
parameter.ranges.min = 20.0f;
|
||||||
|
parameter.ranges.def = 1000.0f;
|
||||||
|
parameter.ranges.max = 10000.0f;
|
||||||
|
parameter.hints = kParameterIsAutomatable;
|
||||||
|
break;
|
||||||
|
case kParamFilterFeedback:
|
||||||
|
parameter.name = "Filter Feedback";
|
||||||
|
parameter.symbol = "filterfeedback";
|
||||||
|
parameter.ranges.min = 0.0f;
|
||||||
|
parameter.ranges.def = .1f;
|
||||||
|
parameter.ranges.max = 0.99f;
|
||||||
|
parameter.hints = kParameterIsAutomatable;
|
||||||
|
break;
|
||||||
case kParamMixVolume:
|
case kParamMixVolume:
|
||||||
parameter.name = "Dry/Wet";
|
parameter.name = "Dry/Wet";
|
||||||
parameter.symbol = "drywetvolume";
|
parameter.symbol = "drywetvolume";
|
||||||
|
|
@ -79,6 +105,10 @@ protected:
|
||||||
return gain_.getGain();
|
return gain_.getGain();
|
||||||
case kParamClipMode:
|
case kParamClipMode:
|
||||||
return (float)clipper_.getMode();
|
return (float)clipper_.getMode();
|
||||||
|
case kParamFilter:
|
||||||
|
return (float)filter_.getCutOff();
|
||||||
|
case kParamFilterFeedback:
|
||||||
|
return (float)filter_.getFeedback();
|
||||||
case kParamMixVolume:
|
case kParamMixVolume:
|
||||||
return mixer_.getInputGain(kChannelWet);
|
return mixer_.getInputGain(kChannelWet);
|
||||||
}
|
}
|
||||||
|
|
@ -93,6 +123,12 @@ protected:
|
||||||
case kParamClipMode:
|
case kParamClipMode:
|
||||||
clipper_.setMode((Clipper::ClipperMode)value);
|
clipper_.setMode((Clipper::ClipperMode)value);
|
||||||
break;
|
break;
|
||||||
|
case kParamFilter:
|
||||||
|
filter_.setCutOff(value);
|
||||||
|
break;
|
||||||
|
case kParamFilterFeedback:
|
||||||
|
filter_.setFeedback(value);
|
||||||
|
break;
|
||||||
case kParamMixVolume:
|
case kParamMixVolume:
|
||||||
mixer_.setInputGain(kChannelWet, value);
|
mixer_.setInputGain(kChannelWet, value);
|
||||||
mixer_.setInputGain(kChannelDry, 1.0f - value);
|
mixer_.setInputGain(kChannelDry, 1.0f - value);
|
||||||
|
|
@ -108,22 +144,29 @@ protected:
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
gain_.processStereo(inputs[0], inputs[1], wetBufferL_, wetBufferR_, frames);
|
gain_.processStereo(inputs[0], inputs[1], buffers_.clippedL,
|
||||||
clipper_.processStereo(wetBufferL_, wetBufferR_, wetBufferL_, wetBufferR_,
|
buffers_.clippedR, frames);
|
||||||
frames);
|
clipper_.processStereo(buffers_.clippedL, buffers_.clippedR,
|
||||||
|
buffers_.clippedL, buffers_.clippedR, frames);
|
||||||
|
filter_.processStereo(buffers_.clippedL, buffers_.clippedR, buffers_.lpL,
|
||||||
|
buffers_.lpR, frames);
|
||||||
|
|
||||||
const float *inputsL[2] = {inputs[0], wetBufferL_};
|
const float *inputsL[2] = {inputs[0], buffers_.lpL};
|
||||||
const float *inputsR[2] = {inputs[1], wetBufferR_};
|
const float *inputsR[2] = {inputs[1], buffers_.lpR};
|
||||||
|
|
||||||
mixer_.processStereo(inputsL, inputsR, outputs[0], outputs[1], frames);
|
mixer_.processStereo(inputsL, inputsR, outputs[0], outputs[1], frames);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sampleRateChanged(double newSr) override {
|
||||||
|
filter_.setSampleRate(static_cast<float>(newSr));
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Gain gain_;
|
Gain gain_;
|
||||||
Clipper clipper_;
|
Clipper clipper_;
|
||||||
Mixer<2> mixer_;
|
Mixer<2> mixer_;
|
||||||
float wetBufferL_[BUFFER_SIZE];
|
Filter filter_;
|
||||||
float wetBufferR_[BUFFER_SIZE];
|
AudioBuffers buffers_;
|
||||||
|
|
||||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(SquidgeDistortion);
|
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(SquidgeDistortion);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue