From 9dfdc414c6c007d0cd60aa0d3a19ccbd64249afd Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Sat, 9 Jul 2022 06:55:04 -0400 Subject: [PATCH] Add VCVBezelBig to Logic. Add dividers to lights. Fix polyphony in Process. --- res/VCVBezelBig.svg | 50 ++++++++++++++++++++++++++++ src/Compare.cpp | 35 +++++++++++--------- src/Logic.cpp | 45 +++++++++++++++++++++++-- src/Process.cpp | 81 +++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 186 insertions(+), 25 deletions(-) create mode 100644 res/VCVBezelBig.svg diff --git a/res/VCVBezelBig.svg b/res/VCVBezelBig.svg new file mode 100644 index 0000000..17d7d5e --- /dev/null +++ b/res/VCVBezelBig.svg @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Compare.cpp b/src/Compare.cpp index 25073fa..9520e2c 100644 --- a/src/Compare.cpp +++ b/src/Compare.cpp @@ -30,6 +30,8 @@ struct Compare : Module { LIGHTS_LEN }; + dsp::ClockDivider lightDivider; + Compare() { config(PARAMS_LEN, INPUTS_LEN, OUTPUTS_LEN, LIGHTS_LEN); configParam(B_PARAM, -10.f, 10.f, 0.f, "B offset", " V"); @@ -43,6 +45,8 @@ struct Compare : Module { configOutput(LIMGATE_OUTPUT, "Limit gate"); configOutput(GREATER_OUTPUT, "A>B"); configOutput(LESS_OUTPUT, "A b ? 10.f : 0.f, c); - if (a > b) - anyGreater = true; + anyGreater = anyGreater || (a > b); outputs[LESS_OUTPUT].setVoltage(a < b ? 10.f : 0.f, c); - if (a < b) - anyLess = true; + anyLess = anyLess || (a < b); } outputs[MAX_OUTPUT].setChannels(channels); @@ -99,14 +99,17 @@ struct Compare : Module { outputs[GREATER_OUTPUT].setChannels(channels); outputs[LESS_OUTPUT].setChannels(channels); - lights[CLIP_LIGHT + 0].setBrightnessSmooth(anyClipped && channels <= 1, args.sampleTime); - lights[CLIP_LIGHT + 1].setBrightnessSmooth(anyClipped && channels > 1, args.sampleTime); - lights[LIM_LIGHT + 0].setBrightnessSmooth(anyLimmed && channels <= 1, args.sampleTime); - lights[LIM_LIGHT + 1].setBrightnessSmooth(anyLimmed && channels > 1, args.sampleTime); - lights[GREATER_LIGHT + 0].setBrightnessSmooth(anyGreater && channels <= 1, args.sampleTime); - lights[GREATER_LIGHT + 1].setBrightnessSmooth(anyGreater && channels > 1, args.sampleTime); - lights[LESS_LIGHT + 0].setBrightnessSmooth(anyLess && channels <= 1, args.sampleTime); - lights[LESS_LIGHT + 1].setBrightnessSmooth(anyLess && channels > 1, args.sampleTime); + if (lightDivider.process()) { + float lightTime = args.sampleTime * lightDivider.getDivision(); + lights[CLIP_LIGHT + 0].setBrightnessSmooth(anyClipped && channels <= 1, lightTime); + lights[CLIP_LIGHT + 1].setBrightnessSmooth(anyClipped && channels > 1, lightTime); + lights[LIM_LIGHT + 0].setBrightnessSmooth(anyLimmed && channels <= 1, lightTime); + lights[LIM_LIGHT + 1].setBrightnessSmooth(anyLimmed && channels > 1, lightTime); + lights[GREATER_LIGHT + 0].setBrightnessSmooth(anyGreater && channels <= 1, lightTime); + lights[GREATER_LIGHT + 1].setBrightnessSmooth(anyGreater && channels > 1, lightTime); + lights[LESS_LIGHT + 0].setBrightnessSmooth(anyLess && channels <= 1, lightTime); + lights[LESS_LIGHT + 1].setBrightnessSmooth(anyLess && channels > 1, lightTime); + } } }; diff --git a/src/Logic.cpp b/src/Logic.cpp index 186f3aa..7131cbb 100644 --- a/src/Logic.cpp +++ b/src/Logic.cpp @@ -88,16 +88,55 @@ struct Logic : Module { // Set lights if (lightDivider.process()) { + float lightTime = args.sampleTime * lightDivider.getDivision(); lights[B_BUTTON_LIGHT].setBrightness(bPush); for (int i = 0; i < 8; i++) { - lights[NOTA_LIGHT + 2 * i + 0].setBrightness(anyState[i] && channels == 1); - lights[NOTA_LIGHT + 2 * i + 1].setBrightness(anyState[i] && channels > 1); + lights[NOTA_LIGHT + 2 * i + 0].setBrightnessSmooth(anyState[i] && channels == 1, lightTime); + lights[NOTA_LIGHT + 2 * i + 1].setBrightnessSmooth(anyState[i] && channels > 1, lightTime); } } } }; +struct VCVBezelBig : app::SvgSwitch { + VCVBezelBig() { + momentary = true; + addFrame(Svg::load(asset::plugin(pluginInstance, "res/VCVBezelBig.svg"))); + } +}; + + +template +struct VCVBezelLightBig : TBase { + VCVBezelLightBig() { + this->borderColor = color::BLACK_TRANSPARENT; + this->bgColor = color::BLACK_TRANSPARENT; + this->box.size = mm2px(math::Vec(9.53, 9.53)); + } +}; + + +template +struct LightButton : TBase { + app::ModuleLightWidget* light; + + LightButton() { + light = new TLight; + // Move center of light to center of box + light->box.pos = this->box.size.div(2).minus(light->box.size.div(2)); + this->addChild(light); + } + + app::ModuleLightWidget* getLight() { + return light; + } +}; + + +using VCVBezelLightBigWhite = LightButton>; + + struct LogicWidget : ModuleWidget { LogicWidget(Logic* module) { setModule(module); @@ -108,7 +147,7 @@ struct LogicWidget : ModuleWidget { 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(createLightParamCentered>(mm2px(Vec(12.7, 26.755)), module, Logic::B_PARAM, Logic::B_BUTTON_LIGHT)); + addParam(createLightParamCentered(mm2px(Vec(12.7, 26.755)), module, Logic::B_PARAM, Logic::B_BUTTON_LIGHT)); addInput(createInputCentered(mm2px(Vec(7.299, 52.31)), module, Logic::A_INPUT)); addInput(createInputCentered(mm2px(Vec(18.136, 52.31)), module, Logic::B_INPUT)); diff --git a/src/Process.cpp b/src/Process.cpp index 02e2b29..edde2c3 100644 --- a/src/Process.cpp +++ b/src/Process.cpp @@ -4,7 +4,7 @@ struct Process : Module { enum ParamId { SLEW_PARAM, - PUSH_PARAM, + GATE_PARAM, PARAMS_LEN }; enum InputId { @@ -23,25 +23,94 @@ struct Process : Module { OUTPUTS_LEN }; enum LightId { + GATE_LIGHT, LIGHTS_LEN }; + bool state[16] = {}; + float sample1[16] = {}; + float sample2[16] = {}; + float holdValue[16] = {}; + float slewValue[16] = {}; + float glideValue[16] = {}; + Process() { config(PARAMS_LEN, INPUTS_LEN, OUTPUTS_LEN, LIGHTS_LEN); - configParam(SLEW_PARAM, std::log2(1e-3f), std::log2(10.f), std::log2(0.1f), "Slew", " ms/V", 2, 1000); - configButton(PUSH_PARAM, "Gate"); + configParam(SLEW_PARAM, std::log2(1e-3f), std::log2(10.f), std::log2(1e-3f), "Slew", " ms/V", 2, 1000); + configButton(GATE_PARAM, "Gate"); configInput(SLEW_INPUT, "Slew"); configInput(IN_INPUT, "Voltage"); configInput(GATE_INPUT, "Gate"); configOutput(SH1_OUTPUT, "Sample & hold"); configOutput(SH2_OUTPUT, "Sample & hold 2"); - configOutput(TH_OUTPUT, "Trigger & hold"); - configOutput(HT_OUTPUT, "Hold & trigger"); + configOutput(TH_OUTPUT, "Track & hold"); + configOutput(HT_OUTPUT, "Hold & track"); configOutput(SLEW_OUTPUT, "Slew"); configOutput(GLIDE_OUTPUT, "Glide"); } void process(const ProcessArgs& args) override { + int channels = inputs[IN_INPUT].getChannels(); + bool gateButton = params[GATE_PARAM].getValue() > 0.f; + + for (int c = 0; c < channels; c++) { + float in = inputs[IN_INPUT].getVoltage(c); + + float slewPitch = -params[SLEW_PARAM].getValue() - inputs[SLEW_INPUT].getPolyVoltage(c); + // V/s + float slew = dsp::approxExp2_taylor5(slewPitch + 30.f) / 1073741824; + + float gateValue = inputs[GATE_INPUT].getPolyVoltage(c); + + if (!state[c]) { + if (gateValue >= 2.f || gateButton) { + // Triggered + state[c] = true; + // Hold and track + holdValue[c] = in; + // Sample and hold + sample2[c] = sample1[c]; + sample1[c] = in; + // Glide + // TODO delay timer + glideValue[c] = in; + } + } + else { + if (gateValue <= 0.1f && !gateButton) { + // Untriggered + state[c] = false; + // Track and hold + holdValue[c] = in; + } + } + + // Slew each value + float slewDelta = slew * args.sampleTime; + if (state[c]) { + slewValue[c] = in; + } + else { + slewValue[c] += clamp(in - slewValue[c], -slewDelta, slewDelta); + } + glideValue[c] += clamp(in - glideValue[c], -slewDelta, slewDelta); + + outputs[SH1_OUTPUT].setVoltage(sample1[c], c); + outputs[SH2_OUTPUT].setVoltage(sample2[c], c); + outputs[TH_OUTPUT].setVoltage(state[c] ? holdValue[c] : in, c); + outputs[HT_OUTPUT].setVoltage(state[c] ? in : holdValue[c], c); + outputs[SLEW_OUTPUT].setVoltage(slewValue[c], c); + outputs[GLIDE_OUTPUT].setVoltage(glideValue[c], c); + } + + outputs[SH1_OUTPUT].setChannels(channels); + outputs[SH2_OUTPUT].setChannels(channels); + outputs[TH_OUTPUT].setChannels(channels); + outputs[HT_OUTPUT].setChannels(channels); + outputs[SLEW_OUTPUT].setChannels(channels); + outputs[GLIDE_OUTPUT].setChannels(channels); + + lights[GATE_LIGHT].setBrightness(gateButton); } }; @@ -57,7 +126,7 @@ struct ProcessWidget : ModuleWidget { addChild(createWidget(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); addParam(createParamCentered(mm2px(Vec(12.646, 26.755)), module, Process::SLEW_PARAM)); - // addParam(createParamCentered(mm2px(Vec(18.136, 52.31)), module, Process::PUSH_PARAM)); + addParam(createLightParamCentered>(mm2px(Vec(18.136, 52.31)), module, Process::GATE_PARAM, Process::GATE_LIGHT)); addInput(createInputCentered(mm2px(Vec(7.299, 52.31)), module, Process::SLEW_INPUT)); addInput(createInputCentered(mm2px(Vec(7.297, 67.53)), module, Process::IN_INPUT));