diff --git a/Makefile b/Makefile index 06e9521..ed9a92c 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ # ------------------------------ # # Define your plugins here as space-separated names -PLUGINS = SquidgeDistortion +PLUGINS = SquidgeDistortion SquidgeFilter # -------------------------------------------------------------- diff --git a/core/Filter.cpp b/core/Filter.cpp index 65b0589..328301a 100644 --- a/core/Filter.cpp +++ b/core/Filter.cpp @@ -1,71 +1,129 @@ #include "Filter.hpp" #include -Filter::Filter(float initCutOff, float initSampleRate) - : cutOff_(initCutOff), feedback_(0.0f), resonance_(0.1f), a1_(0.0f), - a2_(0.0f), a3_(0.0f), g_(0.0f), k_(2.0f), sampleRate_(initSampleRate), - s1L_(0.0f), s2L_(0.0f), s1R_(0.0f), s2R_(0.0f), outZL_(0.0f), - outZR_(0.0f) { - recompute(); -}; +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif -void Filter::process(const float *in, float *out, uint32_t frames) { - filter(in, out, frames, &s1L_, &s2L_, &outZL_); -}; -void Filter::processStereo(const float *inLeft, const float *inRight, - float *outLeft, float *outRight, uint32_t frames) { - filter(inLeft, outLeft, frames, &s1L_, &s2L_, &outZL_); - filter(inRight, outRight, frames, &s1R_, &s2R_, &outZR_); -}; +Filter::Filter(float initCutOff, float initQ, float initSampleRate) + : 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(); +} -void Filter::filter(const float *in, float *out, uint32_t frames, float *s1, - float *s2, float *outZ) { - for (uint32_t i = 0; i < frames; ++i) { - float x = in[i] + (feedback_ * (*outZ)); - float v3 = x - *s2; - if (resonance_ > 0.995f && std::fabs(v3) < 1.0e-9f) { - v3 = 1.0e-6f; - } - float v1 = (a1_ * (*s1)) + (a2_ * v3); - float v2 = (*s2) + (a2_ * (*s1)) + (a3_ * v3); - *s1 = (2.0f * v1) - *s1; - *s2 = (2.0f * v2) - *s2; - out[i] = v2; - *outZ = v2; +Filter::FilterType Filter::getType() const { return type_; } + +float Filter::clampFreq(float freq) { + return std::fmin(std::fmax(freq, kFilterMin), kFilterMax); +} + +void Filter::updateCoeffs() { + float totalFreq = clampFreq(cutOff_ + modulation_); + + float f = totalFreq / std::fmax(sampleRate_, 1.0f); + + if (f > kMaxNormalizedFrequency) + f = kMaxNormalizedFrequency; + if (f < 0.0001f) + f = 0.0001f; + + g_ = 2.0f * std::sin(M_PI * f); +} + +float Filter::processFrame(float input, float &lp, float &bp) const { + float hp = input - (bp / q_) - lp; + + bp = bp + g_ * hp; + lp = lp + g_ * bp; + + switch (type_) { + case kHighPass: + return hp; + case kBandPass: + return bp; + case kNotch: + return input - lp; + case kLowPass: + default: + return lp; } } -void Filter::recompute() { - float sr = std::fmax(sampleRate_, 1.0f); - float fc = std::fmin(std::fmax(cutOff_, 1.0f), 0.45f * sr); - g_ = std::tan(static_cast(M_PI) * (fc / sr)); - k_ = 2.0f * (1.0f - std::fmin(std::fmax(resonance_, 0.0f), 1.0f)); +void Filter::process(const float *in, float *out, uint32_t frames, + const float *modulation) { + float lp = lpL_; + float bp = bpL_; - float denom = 1.0f + (g_ * (g_ + k_)); - a1_ = 1.0f / denom; - a2_ = g_ * a1_; - a3_ = g_ * a2_; -}; + for (uint32_t i = 0; i < frames; ++i) { + if (modulation != nullptr) { + if (std::abs(modulation[i] - modulation_) > 0.001f) { + setModulation(modulation[i]); + } + } + out[i] = processFrame(in[i], lp, bp); + } -void Filter::setCutOff(float newCutOff) { - cutOff_ = newCutOff; - recompute(); + lpL_ = lp; + bpL_ = bp; } + +void Filter::processStereo(const float *inL, const float *inR, float *outL, + 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) { + if (std::abs(modulation[i] - modulation_) > 0.001f) { + setModulation(modulation[i]); + } + } + + float inValL = (inL != nullptr) ? inL[i] : 0.0f; + float inValR = (inR != nullptr) ? inR[i] : 0.0f; + + outL[i] = processFrame(inValL, lpL, bpL); + outR[i] = processFrame(inValR, lpR, bpR); + } + + lpL_ = lpL; + bpL_ = bpL; + lpR_ = lpR; + bpR_ = bpR; +} + float Filter::getCutOff() const { return cutOff_; } -void Filter::setFeedback(float newFeedback) { - feedback_ = std::fmin(std::fmax(newFeedback, 0.0f), 0.95f); +void Filter::setCutOff(float freq) { + cutOff_ = clampFreq(freq); + updateCoeffs(); } -float Filter::getFeedback() const { return feedback_; } -void Filter::setResonance(float newResonance) { - resonance_ = std::fmin(std::fmax(newResonance, 0.0f), 1.0f); - recompute(); -} -float Filter::getResonance() const { return resonance_; } +float Filter::getQ() const { return q_; } -void Filter::setSampleRate(float newSampleRate) { - sampleRate_ = newSampleRate; - recompute(); +void Filter::setQ(float q) { + q_ = std::fmin(std::fmax(q, kQMin), kQMax); + updateCoeffs(); } -float Filter::getSampleRate() const { return sampleRate_; } \ No newline at end of file + +void Filter::setType(FilterType type) { type_ = type; } + +float Filter::getSampleRate() const { return sampleRate_; } + +void Filter::setSampleRate(float sr) { + if (sr > 0.0f) { + sampleRate_ = sr; + updateCoeffs(); + } +} + +float Filter::getModulation() const { return modulation_; } + +void Filter::setModulation(float mod) { + if (std::abs(modulation_ - mod) > 0.0001f) { + modulation_ = mod; + updateCoeffs(); + } +} \ No newline at end of file diff --git a/core/Filter.hpp b/core/Filter.hpp index d83f359..ca8186c 100644 --- a/core/Filter.hpp +++ b/core/Filter.hpp @@ -1,45 +1,55 @@ #ifndef FILTER_HPP_INCLUDED #define FILTER_HPP_INCLUDED -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif + #include +constexpr float kMaxNormalizedFrequency = 0.16667f; +constexpr float kFilterMin = 20.0f; +constexpr float kFilterMax = 10000.0f; +constexpr float kQMin = 0.1f; +constexpr float kQMax = 20.0f; + 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); + Filter(float initCutOff = 1000.0f, float initQ = 0.707f, + float initSampleRate = 48000.0f); - void recompute(); - void setCutOff(float newCutOff); + enum FilterType { kLowPass, kHighPass, kBandPass, kNotch, kFilterTypeCount }; + + void setCutOff(float freq); float getCutOff() const; - void setFeedback(float newFeedback); - float getFeedback() const; - void setResonance(float newResonance); - float getResonance() const; - void setSampleRate(float newSampleRate); + + 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, + const float *modulation = nullptr); private: - void filter(const float *in, float *out, uint32_t frames, float *s1, - float *s2, float *outZ); + void updateCoeffs(); + float modulation_; + + float clampFreq(float freq); + float processFrame(float input, float &lp, float &bp) const; + float cutOff_; - float feedback_; - float resonance_; - float a1_; - float a2_; - float a3_; - float g_; - float k_; + float q_; float sampleRate_; - float s1L_; - float s2L_; - float s1R_; - float s2R_; - float outZL_; - float outZR_; + FilterType type_; + + float g_; + + float lpL_, bpL_; + float lpR_, bpR_; }; -#endif // FILTER_HPP_INCLUDED \ No newline at end of file +#endif \ No newline at end of file diff --git a/core/Oscillator.cpp b/core/Oscillator.cpp new file mode 100644 index 0000000..0f4b8a6 --- /dev/null +++ b/core/Oscillator.cpp @@ -0,0 +1,54 @@ +#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::reset() { phase_ = 0; } + +void Oscillator::recalc_() { inc_ = freq_ / sampleRate_; } + +void Oscillator::setFrequency(float newFreq) +{ + freq_ = std::fmax(newFreq, 0.0f); + recalc_(); +} +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..8b37067 --- /dev/null +++ b/core/Oscillator.hpp @@ -0,0 +1,41 @@ +#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; + + void reset(); + +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/SquidgeDistortion/DistrhoPluginInfo.h b/plugins/SquidgeDistortion/DistrhoPluginInfo.h index 488bce6..627f348 100644 --- a/plugins/SquidgeDistortion/DistrhoPluginInfo.h +++ b/plugins/SquidgeDistortion/DistrhoPluginInfo.h @@ -9,7 +9,7 @@ #define DISTRHO_PLUGIN_NUM_INPUTS 2 #define DISTRHO_PLUGIN_NUM_OUTPUTS 2 -#define DISTRHO_PLUGIN_NUM_PARAMETERS 6 +#define DISTRHO_PLUGIN_NUM_PARAMETERS 5 #define DISTRHO_PLUGIN_WANT_PROGRAMS 0 #define DISTRHO_PLUGIN_WANT_STATE 0 diff --git a/plugins/SquidgeDistortion/Makefile b/plugins/SquidgeDistortion/Makefile index dab2d7e..9b08a97 100644 --- a/plugins/SquidgeDistortion/Makefile +++ b/plugins/SquidgeDistortion/Makefile @@ -1,7 +1,7 @@ #!/usr/bin/make -f NAME = SquidgeDistortion -FILES_DSP = SquidgeDistortion.cpp ../../core/Gain.cpp ../../core/Clipper.cpp ../../core/Mixer.cpp ../../core/Filter.cpp +FILES_DSP = SquidgeDistortion.cpp ../../core/Gain.cpp ../../core/Clipper.cpp ../../core/Mixer.cpp TARGETS = vst3 clap diff --git a/plugins/SquidgeDistortion/SquidgeDistortion.cpp b/plugins/SquidgeDistortion/SquidgeDistortion.cpp index 8356f69..44d4ecb 100644 --- a/plugins/SquidgeDistortion/SquidgeDistortion.cpp +++ b/plugins/SquidgeDistortion/SquidgeDistortion.cpp @@ -5,7 +5,6 @@ #include #include "../../core/Clipper.hpp" -#include "../../core/Filter.hpp" #include "../../core/Gain.hpp" #include "../../core/Mixer.hpp" @@ -27,14 +26,11 @@ public: enum Parameters { kParamGain, kParamClipMode, - kParamFilter, - kParamFilterFeedback, kParamMixVolume, - kParamResonance, kParameterCount // must be last }; SquidgeDistortion() - : Plugin(kParameterCount, 0, 0), gain_(2.0f), mixer_(1.0f), filter_(440) { + : Plugin(kParameterCount, 0, 0), gain_(2.0f), mixer_(1.0f) { mixer_.setInputGain(kChannelDry, 0.0f); mixer_.setInputGain(kChannelWet, 1.0f); } @@ -75,22 +71,6 @@ protected: parameter.enumValues.values = const_cast(sClipModes); 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 = "Feedback"; - parameter.symbol = "filterfeedback"; - parameter.ranges.min = 0.0f; - parameter.ranges.def = 0.0f; - parameter.ranges.max = 0.95f; - parameter.hints = kParameterIsAutomatable; - break; case kParamMixVolume: parameter.name = "Dry/Wet"; parameter.symbol = "drywetvolume"; @@ -99,14 +79,6 @@ protected: parameter.ranges.max = 1.0f; parameter.hints = kParameterIsAutomatable; break; - case kParamResonance: - parameter.name = "Resonance"; - parameter.symbol = "resonance"; - parameter.ranges.min = 0.0f; - parameter.ranges.def = 0.1f; - parameter.ranges.max = 1.0f; - parameter.hints = kParameterIsAutomatable; - break; } } @@ -116,14 +88,8 @@ protected: return gain_.getGain(); case kParamClipMode: return (float)clipper_.getMode(); - case kParamFilter: - return (float)filter_.getCutOff(); - case kParamFilterFeedback: - return (float)filter_.getFeedback(); case kParamMixVolume: return mixer_.getInputGain(kChannelWet); - case kParamResonance: - return (float)filter_.getResonance(); } return 0.0f; } @@ -138,19 +104,10 @@ protected: static_cast(Clipper::kClipperModeCount - 1)); clipper_.setMode(static_cast(std::lround(value))); break; - case kParamFilter: - filter_.setCutOff(value); - break; - case kParamFilterFeedback: - filter_.setFeedback(value); - break; case kParamMixVolume: mixer_.setInputGain(kChannelWet, value); mixer_.setInputGain(kChannelDry, 1.0f - value); break; - case kParamResonance: - filter_.setResonance(value); - break; } } @@ -166,24 +123,17 @@ protected: buffers_.clippedR, 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], buffers_.lpL}; - const float *inputsR[2] = {inputs[1], buffers_.lpR}; + const float *inputsL[2] = {inputs[0], buffers_.clippedL}; + const float *inputsR[2] = {inputs[1], buffers_.clippedR}; mixer_.processStereo(inputsL, inputsR, outputs[0], outputs[1], frames); } - void sampleRateChanged(double newSr) override { - filter_.setSampleRate(static_cast(newSr)); - } - private: Gain gain_; Clipper clipper_; Mixer<2> mixer_; - Filter filter_; AudioBuffers buffers_; DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(SquidgeDistortion); diff --git a/plugins/SquidgeFilter/DistrhoPluginInfo.h b/plugins/SquidgeFilter/DistrhoPluginInfo.h new file mode 100644 index 0000000..c9adf22 --- /dev/null +++ b/plugins/SquidgeFilter/DistrhoPluginInfo.h @@ -0,0 +1,28 @@ +#ifndef DISTRHO_PLUGIN_INFO_H_INCLUDED +#define DISTRHO_PLUGIN_INFO_H_INCLUDED + +#define DISTRHO_PLUGIN_NAME "SquidgeFilter" +#define DISTRHO_PLUGIN_AUTHOR "SquidgeSoft" +#define DISTRHO_PLUGIN_URI "moe.liam.squidgesoft.SquidgeFilter" +#define DISTRHO_PLUGIN_CATEGORY "fx" + +#define DISTRHO_PLUGIN_NUM_INPUTS 2 +#define DISTRHO_PLUGIN_NUM_OUTPUTS 2 + +#define DISTRHO_PLUGIN_NUM_PARAMETERS 3 + +#define DISTRHO_PLUGIN_WANT_TIMEPOS 1 + +#define DISTRHO_PLUGIN_WANT_PROGRAMS 0 +#define DISTRHO_PLUGIN_WANT_STATE 0 +#define DISTRHO_PLUGIN_WANT_TIMEPOS 1 + +#define DISTRHO_PLUGIN_HAS_UI 0 +#define DISTRHO_PLUGIN_IS_SYNTH 0 + +#define DISTRHO_PLUGIN_PRIV_ID "moe.liam.squidgesoft.SquidgeFilter" +#define DISTRHO_PLUGIN_BRAND "SquidgeSoft" + +#define DISTRHO_PLUGIN_CLAP_ID "moe.liam.squidgesoft.SquidgeFilter" + +#endif \ No newline at end of file diff --git a/plugins/SquidgeFilter/Makefile b/plugins/SquidgeFilter/Makefile new file mode 100644 index 0000000..9728c49 --- /dev/null +++ b/plugins/SquidgeFilter/Makefile @@ -0,0 +1,11 @@ +#!/usr/bin/make -f +NAME = SquidgeFilter + +FILES_DSP = SquidgeFilter.cpp ../../core/Filter.cpp ../../core/Oscillator.cpp + +TARGETS = vst3 clap + +include ../../dpf/Makefile.plugins.mk + +all: $(TARGETS) + diff --git a/plugins/SquidgeFilter/SquidgeFilter.cpp b/plugins/SquidgeFilter/SquidgeFilter.cpp new file mode 100644 index 0000000..028f04e --- /dev/null +++ b/plugins/SquidgeFilter/SquidgeFilter.cpp @@ -0,0 +1,198 @@ +#include "DistrhoDetails.hpp" +#include "DistrhoPlugin.hpp" +#include "DistrhoPluginInfo.h" + +#include "../../core/Filter.hpp" +#include "../../core/Oscillator.hpp" + +START_NAMESPACE_DISTRHO + +const int BUFFER_SIZE = 16384; + +class SquidgeFilter : public Plugin { + +public: + enum Parameters { + kParamFreq, + kParamResonance, + kParamType, + kParamLFOSyncMode, + kParamLFOAmount, + kParameterCount // must be last + }; + + SquidgeFilter() + : Plugin(kParameterCount, 0, 0), filter_(440.0f, 2.0f, 48000.0f), + lfo_(20.0f), lfoSync_(0.0f) { + filter_.setType(Filter::kLowPass); + } + +protected: + const char *getLabel() const override { return "SquidgeFilter"; } + const char *getDescription() const override { + return "Simple State Variable Filter."; + } + const char *getMaker() const override { return "SquidgeSoft"; } + const char *getLicense() const override { return "GPL3"; } + uint32_t getVersion() const override { return d_version(0, 1, 0); } + int64_t getUniqueId() const override { return d_cconst('S', 'Q', 'F', 'T'); } + + void initParameter(uint32_t index, Parameter ¶meter) override { + switch (index) { + case kParamFreq: + parameter.name = "Frequency"; + parameter.symbol = "frequency"; + parameter.ranges.min = 20.0f; + parameter.ranges.def = 440.0f; + parameter.ranges.max = 10000.0f; + parameter.hints = kParameterIsAutomatable | kParameterIsLogarithmic; + break; + + case kParamResonance: + parameter.name = "Resonance"; + parameter.symbol = "resonance"; + parameter.ranges.min = 0.9f; + parameter.ranges.def = 2.0f; + parameter.ranges.max = 20.0f; + parameter.hints = kParameterIsAutomatable; + break; + + case kParamType: + parameter.name = "Filter Type"; + parameter.symbol = "type"; + parameter.ranges.min = 0.0f; + parameter.ranges.def = 0.0f; + parameter.ranges.max = Filter::kFilterTypeCount - 1; + parameter.hints = kParameterIsAutomatable | kParameterIsInteger; + parameter.enumValues.count = Filter::kFilterTypeCount; + parameter.enumValues.restrictedMode = true; + + static const ParameterEnumerationValue sTypes[Filter::kFilterTypeCount] = + {{0.0f, "Low Pass"}, + {1.0f, "High Pass"}, + {2.0f, "Band Pass"}, + {3.0f, "Notch"}}; + parameter.enumValues.values = + const_cast(sTypes); + break; + case kParamLFOAmount: + parameter.name = "LFO Amount"; + parameter.symbol = "lfoamount"; + parameter.ranges.min = 0.0f; + parameter.ranges.def = 0.0f; + parameter.ranges.max = 1000.0f; + + parameter.hints = kParameterIsAutomatable | kParameterIsInteger; + break; + case kParamLFOSyncMode: + parameter.name = "LFO Sync"; + parameter.symbol = "lfosync"; + parameter.ranges.min = 0.0f; + parameter.ranges.def = 3.0f; + parameter.ranges.max = 6.0f; + + parameter.hints = kParameterIsAutomatable | kParameterIsInteger; + + static const ParameterEnumerationValue sModes[] = { + {0.0f, "1/1 Bar"}, {1.0f, "1/2 Bar"}, {2.0f, "1/4 Bar"}, + {3.0f, "1/8 Bar"}, {4.0f, "1/16 Bar"}, {5.0f, "1/32 Bar"}, + {6.0f, "1/64 Bar"}}; + + parameter.enumValues.count = 7; + parameter.enumValues.restrictedMode = true; + parameter.enumValues.values = + const_cast(sModes); + break; + } + } + + float getParameterValue(uint32_t index) const override { + switch (index) { + case kParamFreq: + return filter_.getCutOff(); + case kParamResonance: + return filter_.getQ(); + case kParamType: + return static_cast(filter_.getType()); + case kParamLFOAmount: + return lfo_.getGain(); + break; + case kParamLFOSyncMode: + return lfoSync_; + }; + return 0.0f; + } + + void setParameterValue(uint32_t index, float value) override { + switch (index) { + case kParamFreq: + filter_.setCutOff(value); + break; + case kParamResonance: + filter_.setQ(value); + break; + case kParamLFOAmount: + lfo_.setGain(value); + break; + case kParamLFOSyncMode: + lfoSync_ = value; + break; + case kParamType: + int typeIdx = static_cast(std::fmin(std::fmax(value, 0.0f), 3.0f)); + filter_.setType(static_cast(typeIdx)); + break; + } + } + + void run(const float **inputs, float **outputs, uint32_t frames) override { + + const TimePosition &timePos = getTimePosition(); + + float targetFreq = 4.0f; + + if (timePos.bbt.valid && timePos.playing && + timePos.bbt.beatsPerMinute > 0.0) { + float bpb = static_cast(timePos.bbt.beatsPerBar); + float bpm = static_cast(timePos.bbt.beatsPerMinute); + float bar = static_cast(timePos.bbt.bar); + + if (bar != currentBar_) { + lfo_.reset(); + currentBar_ = bar; + } + + float baseFreq = (bpm / 60.0f) / bpb; + + static const float multipliers[] = {1.0f, 2.0f, 4.0f, 8.0f, + 16.0f, 32.0f, 64.0f}; + + targetFreq = baseFreq * multipliers[static_cast(lfoSync_)]; + } else { + targetFreq = 1.0f; + } + + lfo_.setFrequency(targetFreq); + 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 lfoSync_; + uint32_t currentBar_ = 0; + float lfoBuffer_[BUFFER_SIZE]; + + DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(SquidgeFilter); +}; + +Plugin *createPlugin() { return new SquidgeFilter(); } + +END_NAMESPACE_DISTRHO \ No newline at end of file diff --git a/plugins/SquidgeTemplate/DistrhoPluginInfo.h b/plugins/SquidgeTemplate/DistrhoPluginInfo.h new file mode 100644 index 0000000..c38773a --- /dev/null +++ b/plugins/SquidgeTemplate/DistrhoPluginInfo.h @@ -0,0 +1,26 @@ +#ifndef DISTRHO_PLUGIN_INFO_H_INCLUDED +#define DISTRHO_PLUGIN_INFO_H_INCLUDED + +#define DISTRHO_PLUGIN_NAME "SquidgeTemplate" +#define DISTRHO_PLUGIN_AUTHOR "SquidgeSoft" +#define DISTRHO_PLUGIN_URI "moe.liam.squidgesoft.SquidgeTemplate" +#define DISTRHO_PLUGIN_CATEGORY "fx" + +#define DISTRHO_PLUGIN_NUM_INPUTS 2 +#define DISTRHO_PLUGIN_NUM_OUTPUTS 2 + +#define DISTRHO_PLUGIN_NUM_PARAMETERS 1 + +#define DISTRHO_PLUGIN_WANT_TIMEPOS 0 + +#define DISTRHO_PLUGIN_WANT_PROGRAMS 0 +#define DISTRHO_PLUGIN_WANT_STATE 0 +#define DISTRHO_PLUGIN_HAS_UI 0 +#define DISTRHO_PLUGIN_IS_SYNTH 0 + +#define DISTRHO_PLUGIN_PRIV_ID "moe.liam.squidgesoft.SquidgeTemplate" +#define DISTRHO_PLUGIN_BRAND "SquidgeSoft" + +#define DISTRHO_PLUGIN_CLAP_ID "moe.liam.squidgesoft.SquidgeTemplate" + +#endif diff --git a/plugins/SquidgeTemplate/Makefile b/plugins/SquidgeTemplate/Makefile new file mode 100644 index 0000000..a8247ff --- /dev/null +++ b/plugins/SquidgeTemplate/Makefile @@ -0,0 +1,10 @@ +#!/usr/bin/make -f +NAME = squidgeTemplate + +FILES_DSP = squidgeTemplate.cpp ../../core/Gain.cpp + +TARGETS = vst3 clap + +include ../../dpf/Makefile.plugins.mk + +all: $(TARGETS) diff --git a/plugins/SquidgeTemplate/SquidgeTemplate.cpp b/plugins/SquidgeTemplate/SquidgeTemplate.cpp new file mode 100644 index 0000000..188a0b4 --- /dev/null +++ b/plugins/SquidgeTemplate/SquidgeTemplate.cpp @@ -0,0 +1,79 @@ +#include "DistrhoDetails.hpp" +#include "DistrhoPlugin.hpp" +#include "DistrhoPluginInfo.h" + +#include "../../core/Gain.hpp" + +START_NAMESPACE_DISTRHO + +class squidgeTemplate : public Plugin +{ +public: + enum Parameters + { + kParamGain, + kParameterCount + }; + + squidgeTemplate() + : Plugin(kParameterCount, 0, 0), gain_(1.0f) + { + } + +protected: + const char *getLabel() const override { return "squidgeTemplate"; } + const char *getDescription() const override { return "Generic squidge plugin template."; } + const char *getMaker() const override { return "SquidgeSoft"; } + const char *getLicense() const override { return "GPL3"; } + uint32_t getVersion() const override { return d_version(0, 1, 0); } + int64_t getUniqueId() const override { return d_cconst('S', 'Q', 'T', 'P'); } + + void initParameter(uint32_t index, Parameter ¶meter) override + { + switch (index) + { + case kParamGain: + parameter.name = "Gain"; + parameter.symbol = "gain"; + parameter.ranges.min = 0.0f; + parameter.ranges.def = 1.0f; + parameter.ranges.max = 2.0f; + parameter.hints = kParameterIsAutomatable; + break; + } + } + + float getParameterValue(uint32_t index) const override + { + if (index == kParamGain) + return gain_.getGain(); + return 0.0f; + } + + void setParameterValue(uint32_t index, float value) override + { + if (index == kParamGain) + gain_.setGain(value); + } + + void run(const float **inputs, float **outputs, uint32_t frames) override + { + gain_.processStereo(inputs[0], inputs[1], outputs[0], outputs[1], frames); + } + + void sampleRateChanged(double /*newSr*/) override + { + } + +private: + Gain gain_; + + DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(squidgeTemplate) +}; + +Plugin *createPlugin() +{ + return new squidgeTemplate(); +} + +END_NAMESPACE_DISTRHO