diff --git a/plugins/community/repos/bsp/README.md b/plugins/community/repos/bsp/README.md index 5f037b9c..b37bb61d 100644 --- a/plugins/community/repos/bsp/README.md +++ b/plugins/community/repos/bsp/README.md @@ -32,6 +32,21 @@ NOTE: here's an example video: https://vimeo.com/288968750 +# Legato + +Meant for legato-slides, this module applies a slew filter to the incoming (V/oct) signal. + +Two parameter sets are used to configure the slide speed +1) when a new note is triggered ("min") +2) when the next note is played while the previous note key is still held down (i.e. no new trigger) ("max") + +- Connect the original V/oct signal to the "I" input +- Connect the trigger (gate) to the "T" input. +- The "R" knob (rate) determines the interpolation speed between the min/max parameter sets. The speed can be modulated via the "M" input. Whe a new note is triggered, the interpolation is reset to 0. +- The "min" and "max" knobs are used to adjust the rise and fall rates + + + # Obxd_VCF An adaption of Filatov Vadim's excellent Ob-Xd filter. Distributed under terms of the GNU General Public License V3. diff --git a/plugins/community/repos/bsp/make.objects b/plugins/community/repos/bsp/make.objects index 9cae6605..e641b3e8 100644 --- a/plugins/community/repos/bsp/make.objects +++ b/plugins/community/repos/bsp/make.objects @@ -2,6 +2,7 @@ ALL_OBJ= \ src/AttenuMixer.o \ src/DownSampler.o \ src/bsp.o \ + src/Legato.o \ src/Obxd_VCF.o \ src/RMS.o \ src/Scanner.o \ diff --git a/plugins/community/repos/bsp/res/Legato.svg b/plugins/community/repos/bsp/res/Legato.svg new file mode 100644 index 00000000..fafa4f3e --- /dev/null +++ b/plugins/community/repos/bsp/res/Legato.svg @@ -0,0 +1,555 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/community/repos/bsp/src/Legato.cpp b/plugins/community/repos/bsp/src/Legato.cpp new file mode 100644 index 00000000..ea703bfd --- /dev/null +++ b/plugins/community/repos/bsp/src/Legato.cpp @@ -0,0 +1,197 @@ +/* +Copyright (c) 2018 bsp + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include + +#include "bsp.hpp" +#include "dsp/digital.hpp" + +namespace rack_plugin_bsp { + +struct Legato : Module { + enum ParamIds { + DECAY_RATE_PARAM, + SMOOTH_MIN_RISE_PARAM, + SMOOTH_MIN_FALL_PARAM, + SMOOTH_MAX_RISE_PARAM, + SMOOTH_MAX_FALL_PARAM, + NUM_PARAMS + }; + enum InputIds { + CTL_INPUT, + TRIG_INPUT, + RATE_MOD_INPUT, + NUM_INPUTS + }; + enum OutputIds { + CTL_OUTPUT, + NUM_OUTPUTS + }; + + double smoothed_sign; + double last_smoothed_val; + double smoothed_val; + double decay_t; + + SchmittTrigger trigger; + + double rcp_sample_rate; + + Legato() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) { + smoothed_sign = 0.0; + last_smoothed_val = 0.0; + smoothed_val = 0.0; + decay_t = 0.0; + handleSampleRateChanged(); + } + + void handleSampleRateChanged(void) { + rcp_sample_rate = 1.0 / double(engineGetSampleRate()); + } + + void onSampleRateChange() override { + Module::onSampleRateChange(); + + handleSampleRateChanged(); + } + + void step() override; +}; + + +void Legato::step() { + + // Read ctl input + float inVal = inputs[CTL_INPUT].value; + + if(trigger.process(inputs[TRIG_INPUT].value)) + { + decay_t = 0.0; + smoothed_sign = 0.0f; + } + else + { + double dcyR = params[DECAY_RATE_PARAM].value; + + if(inputs[RATE_MOD_INPUT].active) + { + dcyR += inputs[RATE_MOD_INPUT].value * (1.0 / 5); + if(dcyR < 0.0) + dcyR = 0.0; + else if(dcyR > 1.0) + dcyR = 1.0; + } + + dcyR *= dcyR; + dcyR *= dcyR; + dcyR *= 4000.0f; + dcyR += 1.0f; + dcyR *= rcp_sample_rate; // divide by sample rate + decay_t += dcyR; + if(decay_t >= 1.0) + decay_t = 1.0; + } + + double smoothAmt; + + if(smoothed_sign >= 0.0f) + { + smoothAmt = params[SMOOTH_MIN_RISE_PARAM].value + (params[SMOOTH_MAX_RISE_PARAM].value - params[SMOOTH_MIN_RISE_PARAM].value) * decay_t; + } + else + { + smoothAmt = params[SMOOTH_MIN_FALL_PARAM].value + (params[SMOOTH_MAX_FALL_PARAM].value - params[SMOOTH_MIN_FALL_PARAM].value) * decay_t; + } + + smoothAmt = (1.0 - smoothAmt); + smoothAmt *= smoothAmt; + smoothAmt *= smoothAmt; + smoothAmt *= smoothAmt; + + smoothed_val = smoothed_val + (inVal - smoothed_val) * smoothAmt; + + smoothed_sign = (smoothed_val - last_smoothed_val); + last_smoothed_val = smoothed_val; + + outputs[CTL_OUTPUT].value = float(smoothed_val); + +#if 0 + static int xxx = 0; + if(0 == (++xxx & 32767)) + { + printf("xxx smoothAmt=%g decay_t=%g\n", smoothAmt, decay_t); + } +#endif +} + + +struct LegatoWidget : ModuleWidget { + LegatoWidget(Legato *module); +}; + +LegatoWidget::LegatoWidget(Legato *module) : ModuleWidget(module) { + setPanel(SVG::load(assetPlugin(plugin, "res/Legato.svg"))); + + addChild(Widget::create(Vec(15, 0))); + addChild(Widget::create(Vec(15, 365))); + + float cx; + float cy; + +#define STY 30.0f + cx = 12.0f; + cy = 50.0f; + addInput(Port::create(Vec(11.0f, cy), Port::INPUT, module, Legato::CTL_INPUT)); + cy += STY; + addInput(Port::create(Vec(11.0f, cy), Port::INPUT, module, Legato::TRIG_INPUT)); + cy += STY; + addParam(ParamWidget::create(Vec(cx, cy), module, Legato::DECAY_RATE_PARAM, 0.0f, 1.0f, 0.2f)); + cy += STY; + addInput(Port::create(Vec(11.0f, cy), Port::INPUT, module, Legato::RATE_MOD_INPUT)); +#undef STY + +#define STY 30.0f + cx = 12.0f; + cy = 185.0f; + addParam(ParamWidget::create(Vec(cx, cy), module, Legato::SMOOTH_MIN_RISE_PARAM, 0.0f, 1.0f, 0.0f)); + cy += STY; + addParam(ParamWidget::create(Vec(cx, cy), module, Legato::SMOOTH_MIN_FALL_PARAM, 0.0f, 1.0f, 0.0f)); + + cy += 10.0f; + cy += STY; + addParam(ParamWidget::create(Vec(cx, cy), module, Legato::SMOOTH_MAX_RISE_PARAM, 0.0f, 1.0f, 0.6f)); + cy += STY; + addParam(ParamWidget::create(Vec(cx, cy), module, Legato::SMOOTH_MAX_FALL_PARAM, 0.0f, 1.0f, 0.6f)); +#undef STX +#undef STY + + addOutput(Port::create(Vec(11, 325), Port::OUTPUT, module, Legato::CTL_OUTPUT)); +} + +} // namespace rack_plugin_bsp + +using namespace rack_plugin_bsp; + +RACK_PLUGIN_MODEL_INIT(bsp, Legato) { + Model *modelLegato = Model::create("bsp", "Legato", "Legato", SLEW_LIMITER_TAG, UTILITY_TAG); + return modelLegato; +} diff --git a/plugins/community/repos/bsp/src/bsp.cpp b/plugins/community/repos/bsp/src/bsp.cpp index 9d3e7889..5e225c80 100644 --- a/plugins/community/repos/bsp/src/bsp.cpp +++ b/plugins/community/repos/bsp/src/bsp.cpp @@ -2,6 +2,7 @@ RACK_PLUGIN_MODEL_DECLARE(bsp, AttenuMixer); RACK_PLUGIN_MODEL_DECLARE(bsp, DownSampler); +RACK_PLUGIN_MODEL_DECLARE(bsp, Legato); RACK_PLUGIN_MODEL_DECLARE(bsp, Obxd_VCF); RACK_PLUGIN_MODEL_DECLARE(bsp, RMS); RACK_PLUGIN_MODEL_DECLARE(bsp, Scanner); @@ -15,6 +16,7 @@ RACK_PLUGIN_INIT(bsp) { RACK_PLUGIN_MODEL_ADD(bsp, AttenuMixer); RACK_PLUGIN_MODEL_ADD(bsp, DownSampler); + RACK_PLUGIN_MODEL_ADD(bsp, Legato); RACK_PLUGIN_MODEL_ADD(bsp, Obxd_VCF); RACK_PLUGIN_MODEL_ADD(bsp, RMS); RACK_PLUGIN_MODEL_ADD(bsp, Scanner); diff --git a/plugins/community/repos/bsp/src/curve_test.tks b/plugins/community/repos/bsp/src/curve_test.tks new file mode 100644 index 00000000..5a4d06a9 --- /dev/null +++ b/plugins/community/repos/bsp/src/curve_test.tks @@ -0,0 +1,132 @@ + +use tksdl; +use tkopengl; + +int numframesrendered=0; + +float shape = 0.0f; + +function onDraw() { + + float dt=FPS.precision; + glClearColor(0,0,0.2,1); + // glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); + glClear(GL_COLOR_BUFFER_BIT); + glDisable(GL_DEPTH_TEST); + + if( !(++numframesrendered&127) ) + trace "FPS.real="+FPS.real; + + zglInitOrtho(1, 1); + glColor3f(0.9,0.9,0.9); + + float cx = -1.0f; + float stepCx = (2.0f / Viewport.width); + + float x = 0.0f; + float stepX = (1.0f / Viewport.width); + + float lx = 0; + float ly = 0; + + glBegin(GL_LINES); + loop(Viewport.width) + { + float cy = 0.0f; + + float triY = x*2; + if(triY > 1.0f) + triY = (2.0f - triY); + + float expY = sin(x*PI); + expY = mathPowerf(expY, mathPowerf(1.0f - shape, 9.0f)*64 + 1.0f); + + float rectY = triY; + // rectY = (triY < 0.5) ? 0.0f : 1.0f; + rectY = mathPowerf(triY * 2.0f, mathPowerf((shape - 0.75f)*4, 20) * 400.0f + 1.0f); + if(rectY > 1.0f) + rectY = 1.0f; + + float t; + + if(shape < 0.5f) + { + cy = expY; + } + else if( (shape >= 0.5f) && (shape < 0.75f)) + { + t = (shape -0.5f) * 4.0f; + cy = expY + (triY - expY) * t; + } + else if(shape >= 0.75f) + { + t = (shape - 0.75f) * 4.0f; + cy = triY + (rectY - triY) * t; + } + + // cy = triY; + // cy = expY; + + glVertex2f(lx, ly); + glVertex2f(cx, cy); + lx = cx; + ly = cy; + cx += stepCx; + x += stepX; + } + + glVertex2f(0.0f, 0.0f); + glVertex2f(1.0f, 0.0f); + + glEnd(); +} + +function onMouse(int _x, int _y, int _cbs, int _nbs) { + print "x="+_x+" y="+_y+" cbs="+_cbs+" nbs="+_nbs; + + shape = (_y / float(Viewport.height)); +} + +function onKeyboard(Key _k) { + switch(_k.pressed) + { + case VKEY_ESCAPE: + SDL.exitEventLoop(); + break; + } +} + +int tim_count = 0; +function onTimer() { + // trace "xxx onTimer"; + // if(++tim_count > 100) + // SDL.exitEventLoop(); +} + +function main() { + use callbacks; + + FPS.tickInterval=1000.0/60; + //FPS.limit=30; + FPS.limit=60; + + SDL.eventPolling = false; // tksdl default is "true" (do not block while waiting for an SDL event) + SDL.timerInterval = 20; + + // SDL.dpiAwareness = true; // no OS scaling + // SDL.dpiAwareness = false; // assume 96dpi and let OS scale window to actual DPI + + // SDL.touchInput = true; // enable WM_POINTER* messages + + Viewport.multisampleSamples = 4; + Viewport.multisampleBuffers = 1; + // Viewport.stencilBits = 8; + Viewport.openWindow(640, 480); + //Viewport.openScreen(640, 480, 32); + //Viewport.swapInterval(1); + + trace "xxx Viewport.dpi="+Viewport.dpi; + trace "xxx entering eventloop"; + + SDL.eventLoop(); +} diff --git a/vst2_bin/plugins/bsp/README.md b/vst2_bin/plugins/bsp/README.md index 5f037b9c..b37bb61d 100644 --- a/vst2_bin/plugins/bsp/README.md +++ b/vst2_bin/plugins/bsp/README.md @@ -32,6 +32,21 @@ NOTE: here's an example video: https://vimeo.com/288968750 +# Legato + +Meant for legato-slides, this module applies a slew filter to the incoming (V/oct) signal. + +Two parameter sets are used to configure the slide speed +1) when a new note is triggered ("min") +2) when the next note is played while the previous note key is still held down (i.e. no new trigger) ("max") + +- Connect the original V/oct signal to the "I" input +- Connect the trigger (gate) to the "T" input. +- The "R" knob (rate) determines the interpolation speed between the min/max parameter sets. The speed can be modulated via the "M" input. Whe a new note is triggered, the interpolation is reset to 0. +- The "min" and "max" knobs are used to adjust the rise and fall rates + + + # Obxd_VCF An adaption of Filatov Vadim's excellent Ob-Xd filter. Distributed under terms of the GNU General Public License V3. diff --git a/vst2_bin/plugins/bsp/res/Legato.svg b/vst2_bin/plugins/bsp/res/Legato.svg new file mode 100644 index 00000000..fafa4f3e --- /dev/null +++ b/vst2_bin/plugins/bsp/res/Legato.svg @@ -0,0 +1,555 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +