From 6062a32921e4fa2c55172924f306f0de3e077574 Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Fri, 22 Oct 2021 16:30:56 -0400 Subject: [PATCH] Implement Delay redesign from Pyer. --- res/Delay.svg | 976 ++++++++++++++++++++++++++++----------- src/Delay.cpp | 108 +++-- src/SequentialSwitch.cpp | 2 +- src/VCA-1.cpp | 4 +- 4 files changed, 775 insertions(+), 315 deletions(-) diff --git a/res/Delay.svg b/res/Delay.svg index 4a922f7..80999e2 100644 --- a/res/Delay.svg +++ b/res/Delay.svg @@ -1,6 +1,4 @@ - - - - + id="svg232" + sodipodi:docname="DELAY.svg" + inkscape:version="0.92.3 (2405546, 2018-03-11)"> + id="metadata236"> image/svg+xml - + + + + + + + + id="ea213cdb-be5e-459c-b498-07b154a5545a" + data-name="FND BG"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + id="g153"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Delay.cpp b/src/Delay.cpp index a27785e..e1afaec 100644 --- a/src/Delay.cpp +++ b/src/Delay.cpp @@ -5,25 +5,38 @@ #define HISTORY_SIZE (1<<21) struct Delay : Module { - enum ParamIds { + enum ParamId { TIME_PARAM, FEEDBACK_PARAM, - COLOR_PARAM, + TONE_PARAM, MIX_PARAM, + // new in 2.0 + TIME_CV_PARAM, + FEEDBACK_CV_PARAM, + TONE_CV_PARAM, + MIX_CV_PARAM, NUM_PARAMS }; - enum InputIds { + enum InputId { TIME_INPUT, FEEDBACK_INPUT, - COLOR_INPUT, + TONE_INPUT, MIX_INPUT, IN_INPUT, + // new in 2.0 + CLOCK_INPUT, NUM_INPUTS }; - enum OutputIds { - OUT_OUTPUT, + enum OutputId { + MIX_OUTPUT, + // new in 2.0 + WET_OUTPUT, NUM_OUTPUTS }; + enum LightId { + PERIOD_LIGHT, + NUM_LIGHTS + }; dsp::DoubleRingBuffer historyBuffer; dsp::DoubleRingBuffer outBuffer; @@ -33,17 +46,29 @@ struct Delay : Module { dsp::RCFilter highpassFilter; Delay() { - config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS); + config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); configParam(TIME_PARAM, 0.f, 1.f, 0.5f, "Time", " s", 10.f / 1e-3, 1e-3); configParam(FEEDBACK_PARAM, 0.f, 1.f, 0.5f, "Feedback", "%", 0, 100); - configParam(COLOR_PARAM, 0.f, 1.f, 0.5f, "Color", "%", 0, 100); + configParam(TONE_PARAM, 0.f, 1.f, 0.5f, "Tone", "%", 0, 200, -100); configParam(MIX_PARAM, 0.f, 1.f, 0.5f, "Mix", "%", 0, 100); + configParam(TIME_CV_PARAM, -1.f, 1.f, 0.f, "Time CV", "%", 0, 100); + getParamQuantity(TIME_CV_PARAM)->randomizeEnabled = false; + configParam(FEEDBACK_CV_PARAM, -1.f, 1.f, 0.f, "Feedback CV", "%", 0, 100); + getParamQuantity(FEEDBACK_CV_PARAM)->randomizeEnabled = false; + configParam(TONE_CV_PARAM, -1.f, 1.f, 0.f, "Tone CV", "%", 0, 100); + getParamQuantity(TONE_CV_PARAM)->randomizeEnabled = false; + configParam(MIX_CV_PARAM, -1.f, 1.f, 0.f, "Mix CV", "%", 0, 100); + getParamQuantity(MIX_CV_PARAM)->randomizeEnabled = false; + configInput(TIME_INPUT, "Time"); configInput(FEEDBACK_INPUT, "Feedback"); - configInput(COLOR_INPUT, "Color"); + configInput(TONE_INPUT, "Tone"); configInput(MIX_INPUT, "Mix"); configInput(IN_INPUT, "Audio"); - configOutput(OUT_OUTPUT, "Audio"); + configInput(CLOCK_INPUT, "Clock"); + + configOutput(MIX_OUTPUT, "Mix"); + configOutput(WET_OUTPUT, "Wet"); src = src_new(SRC_SINC_FASTEST, 1, NULL); assert(src); @@ -55,13 +80,13 @@ struct Delay : Module { void process(const ProcessArgs& args) override { // Get input to delay block - float in = inputs[IN_INPUT].getVoltage(); - float feedback = params[FEEDBACK_PARAM].getValue() + inputs[FEEDBACK_INPUT].getVoltage() / 10.f; + float in = inputs[IN_INPUT].getVoltageSum(); + float feedback = params[FEEDBACK_PARAM].getValue() + inputs[FEEDBACK_INPUT].getVoltage() / 10.f * params[FEEDBACK_CV_PARAM].getValue(); feedback = clamp(feedback, 0.f, 1.f); float dry = in + lastWet * feedback; // Compute delay time in seconds - float delay = params[TIME_PARAM].getValue() + inputs[TIME_INPUT].getVoltage() / 10.f; + float delay = params[TIME_PARAM].getValue() + inputs[TIME_INPUT].getVoltage() / 10.f * params[TIME_CV_PARAM].getValue(); delay = clamp(delay, 0.f, 1.f); delay = 1e-3 * std::pow(10.f / 1e-3, delay); // Number of delay samples @@ -100,7 +125,7 @@ struct Delay : Module { } // Apply color to delay wet output - float color = params[COLOR_PARAM].getValue() + inputs[COLOR_INPUT].getVoltage() / 10.f; + float color = params[TONE_PARAM].getValue() + inputs[TONE_INPUT].getVoltage() / 10.f * params[TONE_CV_PARAM].getValue(); color = clamp(color, 0.f, 1.f); float colorFreq = std::pow(100.f, 2.f * color - 1.f); @@ -116,10 +141,20 @@ struct Delay : Module { lastWet = wet; - float mix = params[MIX_PARAM].getValue() + inputs[MIX_INPUT].getVoltage() / 10.f; + float mix = params[MIX_PARAM].getValue() + inputs[MIX_INPUT].getVoltage() / 10.f * params[MIX_CV_PARAM].getValue(); mix = clamp(mix, 0.f, 1.f); float out = crossfade(in, wet, mix); - outputs[OUT_OUTPUT].setVoltage(out); + outputs[MIX_OUTPUT].setVoltage(out); + } + + void fromJson(json_t* rootJ) override { + // These attenuators didn't exist in version <2.0, so set to 1 for default compatibility. + params[TIME_CV_PARAM].setValue(1.f); + params[FEEDBACK_CV_PARAM].setValue(1.f); + params[TONE_CV_PARAM].setValue(1.f); + params[MIX_CV_PARAM].setValue(1.f); + + Module::fromJson(rootJ); } }; @@ -129,22 +164,31 @@ struct DelayWidget : ModuleWidget { setModule(module); setPanel(createPanel(asset::plugin(pluginInstance, "res/Delay.svg"))); - addChild(createWidget(Vec(15, 0))); - addChild(createWidget(Vec(box.size.x - 30, 0))); - addChild(createWidget(Vec(15, 365))); - addChild(createWidget(Vec(box.size.x - 30, 365))); - - addParam(createParam(Vec(67, 57), module, Delay::TIME_PARAM)); - addParam(createParam(Vec(67, 123), module, Delay::FEEDBACK_PARAM)); - addParam(createParam(Vec(67, 190), module, Delay::COLOR_PARAM)); - addParam(createParam(Vec(67, 257), module, Delay::MIX_PARAM)); - - addInput(createInput(Vec(14, 63), module, Delay::TIME_INPUT)); - addInput(createInput(Vec(14, 129), module, Delay::FEEDBACK_INPUT)); - addInput(createInput(Vec(14, 196), module, Delay::COLOR_INPUT)); - addInput(createInput(Vec(14, 263), module, Delay::MIX_INPUT)); - addInput(createInput(Vec(14, 320), module, Delay::IN_INPUT)); - addOutput(createOutput(Vec(73, 320), module, Delay::OUT_OUTPUT)); + addChild(createWidget(Vec(RACK_GRID_WIDTH, 0))); + addChild(createWidget(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0))); + addChild(createWidget(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); + addChild(createWidget(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); + + addParam(createParamCentered(mm2px(Vec(12.579, 26.747)), module, Delay::TIME_PARAM)); + addParam(createParamCentered(mm2px(Vec(32.899, 26.747)), module, Delay::FEEDBACK_PARAM)); + addParam(createParamCentered(mm2px(Vec(12.579, 56.388)), module, Delay::TONE_PARAM)); + addParam(createParamCentered(mm2px(Vec(32.899, 56.388)), module, Delay::MIX_PARAM)); + addParam(createParamCentered(mm2px(Vec(6.605, 80.561)), module, Delay::TIME_CV_PARAM)); + addParam(createParamCentered(mm2px(Vec(17.442, 80.561)), module, Delay::FEEDBACK_CV_PARAM)); + addParam(createParamCentered(mm2px(Vec(28.278, 80.561)), module, Delay::TONE_CV_PARAM)); + addParam(createParamCentered(mm2px(Vec(39.115, 80.561)), module, Delay::MIX_CV_PARAM)); + + addInput(createInputCentered(mm2px(Vec(6.605, 96.859)), module, Delay::TIME_INPUT)); + addInput(createInputCentered(mm2px(Vec(17.442, 96.859)), module, Delay::FEEDBACK_INPUT)); + addInput(createInputCentered(mm2px(Vec(28.278, 96.819)), module, Delay::TONE_INPUT)); + addInput(createInputCentered(mm2px(Vec(39.115, 96.819)), module, Delay::MIX_INPUT)); + addInput(createInputCentered(mm2px(Vec(6.605, 113.115)), module, Delay::IN_INPUT)); + addInput(createInputCentered(mm2px(Vec(17.442, 113.115)), module, Delay::CLOCK_INPUT)); + + addOutput(createOutputCentered(mm2px(Vec(28.278, 113.115)), module, Delay::WET_OUTPUT)); + addOutput(createOutputCentered(mm2px(Vec(39.115, 113.115)), module, Delay::MIX_OUTPUT)); + + addChild(createLightCentered>(mm2px(Vec(22.738, 16.428)), module, Delay::PERIOD_LIGHT)); } }; diff --git a/src/SequentialSwitch.cpp b/src/SequentialSwitch.cpp index 4c02634..c209802 100644 --- a/src/SequentialSwitch.cpp +++ b/src/SequentialSwitch.cpp @@ -121,7 +121,7 @@ struct SequentialSwitch : Module { void fromJson(json_t* rootJ) override { Module::fromJson(rootJ); - // Get version to check if we should transform STEPS_PARAM + // If version <2.0 we should transform STEPS_PARAM json_t* versionJ = json_object_get(rootJ, "version"); if (versionJ) { std::string version = json_string_value(versionJ); diff --git a/src/VCA-1.cpp b/src/VCA-1.cpp index f8045db..9638f54 100644 --- a/src/VCA-1.cpp +++ b/src/VCA-1.cpp @@ -34,12 +34,12 @@ struct VCA_1 : Module { } void process(const ProcessArgs& args) override { - int channels = std::max(inputs[IN_INPUT].getChannels(), 1); + int channels = std::max({1, inputs[IN_INPUT].getChannels(), inputs[CV_INPUT].getChannels()}); float level = params[LEVEL_PARAM].getValue(); for (int c = 0; c < channels; c++) { // Get input - float in = inputs[IN_INPUT].getVoltage(c); + float in = inputs[IN_INPUT].getPolyVoltage(c); // Get gain float gain = level;