From 7c36a8bf987e7ef0722b25254394d81f1033fdbb Mon Sep 17 00:00:00 2001 From: yaw-man Date: Sun, 21 Aug 2022 22:37:33 -0300 Subject: [PATCH] Add resonant filter plugin --- src/CMakeLists.txt | 3 +- src/yaw-vowel/CMakeLists.txt | 1 + src/yaw-vowel/dsp.cpp | 53 ++++++++------------------- src/yaw-vowel/filter.cpp | 24 +++++++++++++ src/yaw-vowel/filter.h | 70 ++++++++++++++++++++++++++++++++++++ 5 files changed, 112 insertions(+), 39 deletions(-) create mode 100644 src/yaw-vowel/filter.cpp create mode 100644 src/yaw-vowel/filter.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 504e1df..01a9451 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,3 +1,4 @@ cmake_minimum_required(VERSION 3.10) add_subdirectory(yaw-tab) -add_subdirectory(yaw-shepard) \ No newline at end of file +add_subdirectory(yaw-shepard) +add_subdirectory(yaw-vowel) \ No newline at end of file diff --git a/src/yaw-vowel/CMakeLists.txt b/src/yaw-vowel/CMakeLists.txt index 5cd8664..d001cdc 100644 --- a/src/yaw-vowel/CMakeLists.txt +++ b/src/yaw-vowel/CMakeLists.txt @@ -4,6 +4,7 @@ dpf_add_plugin(yaw-vowel TARGETS vst2 FILES_DSP dsp.cpp + filter.cpp FILES_UI wtutil.cpp wintab.cpp diff --git a/src/yaw-vowel/dsp.cpp b/src/yaw-vowel/dsp.cpp index 0091087..ba4a4c1 100644 --- a/src/yaw-vowel/dsp.cpp +++ b/src/yaw-vowel/dsp.cpp @@ -1,4 +1,5 @@ #include "DistrhoPlugin.hpp" +#include "filter.h" START_NAMESPACE_DISTRHO @@ -7,7 +8,7 @@ class TabPlugin : public Plugin public: TabPlugin() : Plugin(kParameterCount, 0, 0), - sampleRate(getSampleRate()) + hzNyq(0.5 * getSampleRate()) { // clear all parameters std::memset(fParameters, 0, sizeof(float) * kParameterCount); @@ -15,13 +16,13 @@ public: } protected: - const char* getLabel() const override { return "yaw-tab"; } + const char* getLabel() const override { return "yaw-vowel"; } const char* getDescription() const override { return "Drawing tablet synth UI"; } const char* getMaker() const override { return "yaw-audio"; } - const char* getHomePage() const override { return "https://yaw.man/plugins/yaw-tab"; } - const char* getLicense() const override { return "ISC"; } + const char* getHomePage() const override { return "https://yaw.man/plugins/yaw-vowel"; } + const char* getLicense() const override { return "Fuck you pay me"; } uint32_t getVersion() const override { return d_version(1, 0, 0); } - int64_t getUniqueId() const override { return d_cconst('y', 'w', 't', 'b'); } + int64_t getUniqueId() const override { return d_cconst('y', 'v', 'w', 'l'); } void initParameter(uint32_t index, Parameter& parameter) override @@ -69,7 +70,7 @@ protected: void sampleRateChanged(double newRate) override { - sampleRate = newRate; + hzNyq = newRate / 2; } float getParameterValue(uint32_t index) const override @@ -80,49 +81,25 @@ protected: void setParameterValue(uint32_t idx, float val) override { fParameters[idx] = val; - switch (idx) { - case ktpax: - period = 0.02f * val * static_cast(sampleRate); - break; - case ktpay: - break; - case ktpaz: - break; - case ktpap: - volume = val; - break; - case kParameterButtonA: - break; - case kParameterButtonB: - break; - } + if( kParameterTime == idx ) return; + double x = (fParameters[ktpax] * 700.0 + 200.0) / (2.0 * hzNyq); + double y = (fParameters[ktpay] * 1900.0 + 500.0) / (2.0 * hzNyq); + double p = fParameters[ktpap]; + filter.set(x, y, p); } void run(const float** inputs, float** outputs, uint32_t frames) override { - - for (uint32_t i = 0; i < frames; ++i) { - counter++; - if (counter > period) { - outputs[0][i] = outputs[1][i] = volume; - counter = 0; - } - else { - outputs[0][i] = outputs[1][i] = 0.0f; - } - } - + filter.process(outputs, inputs, frames); parity = !parity; fParameters[kParameterTime] += parity ? 1 : -1; } private: float fParameters[kParameterCount]; - float period = 0.f; - float counter = 0.f; - float volume = 0.f; - double sampleRate; + double hzNyq; bool parity = false; + Filter filter; DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(TabPlugin) }; diff --git a/src/yaw-vowel/filter.cpp b/src/yaw-vowel/filter.cpp new file mode 100644 index 0000000..ff27cad --- /dev/null +++ b/src/yaw-vowel/filter.cpp @@ -0,0 +1,24 @@ +#include "filter.h" + +void Resonator::clear() +{ + xp = xpp = yp = ypp = 0; +} + +void Resonator::process(float* output, const float* const input, uint32_t frames) +{ + for(uint32_t i = 0; i < frames; ++i){ + float x = static_cast(input[i] * scale); + float y = x - xpp - app * ypp + ap * yp; + output[i] = y; + xpp = xp; + xp = x; + ypp = yp; + yp = y; + } +} + +void Resonator::set(double _app, double _ap, double _scale) +{ + app = _app; ap = _ap; scale = _scale; +} \ No newline at end of file diff --git a/src/yaw-vowel/filter.h b/src/yaw-vowel/filter.h new file mode 100644 index 0000000..a8d8278 --- /dev/null +++ b/src/yaw-vowel/filter.h @@ -0,0 +1,70 @@ +#include "DistrhoPlugin.hpp" +#include +#include + +class Resonator +{ +public: + Resonator(): + xp(0), xpp(0), yp(0), ypp(0), app(0), ap(0), scale(1){}; + + void process(float *output, const float *const input, uint32_t frames); + void clear(); + void set(double _app, double _ap, double _scale); + +private: + float xp; + float xpp; + float yp; + float ypp; + double app; + double ap; + double scale; +}; + +class Filter +{ +public: + Filter(){}; + + void process(float **outputs, const float **inputs, uint32_t frames) + { + for (uint chn = 0; chn < 2; ++chn) + { + for (uint32_t j = 0; j < frames; ++j) + { + outputs[chn][j] = inputs[chn][j]; + } + + for (auto& r : res[chn]) + { + r.process(outputs[chn], outputs[chn], frames); + } + } + + + } + + //Compute filter coefficients from + //frequency as a proportion of the sample rate + //REMEMBER: THAT'S DOUBLE THE Nyquist RATE, dummy + //and resonance in [0, 1] + void set(double x, double y, double p) + { + double r = p * 0.99; + double app = r * r; + double xap = (1.0 + r * r) * cos(M_PI * x); + double yap = (1.0 + r * r) * cos(M_PI * y); + double scale = sqrt(0.5 - 0.5 * r * r); + for (auto& channelFilter : res) + { + channelFilter[0].set(app, xap, scale); + channelFilter[1].set(app, xap, scale); + channelFilter[2].set(app, yap, scale); + channelFilter[3].set(app, yap, scale); + } + } + +private: + std::array, 2> res; +}; \ No newline at end of file