diff --git a/src/GomaII.cpp b/src/GomaII.cpp index c6bb7a0..a1772f7 100644 --- a/src/GomaII.cpp +++ b/src/GomaII.cpp @@ -45,10 +45,10 @@ struct GomaII : Module { configParam(GAIN_CH2_PARAM, 0.f, 1.f, 0.f, "Gain (Channel 2)", "%"); configParam(GAIN_CH3_PARAM, 0.f, 1.f, 0.f, "Gain (Channel 3)", "%"); - configSwitch(MODE_EXT_PARAM, 0.f, 1.f, 0.f, "Mode (Channel Ext)", {"Attenuverter", "Attenuator"}); - configSwitch(MODE_CH1_PARAM, 0.f, 1.f, 0.f, "Mode (Channel 1)", {"Attenuverter", "Attenuator"}); - configSwitch(MODE_CH2_PARAM, 0.f, 1.f, 0.f, "Mode (Channel 2)", {"Attenuverter", "Attenuator"}); - configSwitch(MODE_CH3_PARAM, 0.f, 1.f, 0.f, "Mode (Channel 3)", {"Attenuverter", "Attenuator"}); + configSwitch(MODE_EXT_PARAM, 0.f, 1.f, 1.f, "Mode (Channel Ext)", {"Attenuverter", "Attenuator"}); + configSwitch(MODE_CH1_PARAM, 0.f, 1.f, 1.f, "Mode (Channel 1)", {"Attenuverter", "Attenuator"}); + configSwitch(MODE_CH2_PARAM, 0.f, 1.f, 1.f, "Mode (Channel 2)", {"Attenuverter", "Attenuator"}); + configSwitch(MODE_CH3_PARAM, 0.f, 1.f, 1.f, "Mode (Channel 3)", {"Attenuverter", "Attenuator"}); configInput(EXT_INPUT, "External"); configInput(CH1_INPUT, "Channel 1"); diff --git a/src/SlewLFO.cpp b/src/SlewLFO.cpp index f35ee68..d6e0c58 100644 --- a/src/SlewLFO.cpp +++ b/src/SlewLFO.cpp @@ -1,5 +1,6 @@ #include "plugin.hpp" +using namespace simd; struct SlewLFO : Module { enum ParamId { @@ -29,19 +30,109 @@ struct SlewLFO : Module { SlewLFO() { config(PARAMS_LEN, INPUTS_LEN, OUTPUTS_LEN, LIGHTS_LEN); - configParam(CURVE_PARAM, 0.f, 1.f, 0.f, ""); - configParam(RISE_PARAM, 0.f, 1.f, 0.f, ""); - configParam(FALL_PARAM, 0.f, 1.f, 0.f, ""); - configParam(MODE_PARAM, 0.f, 1.f, 0.f, ""); - configParam(RATE_PARAM, 0.f, 1.f, 0.f, ""); - configParam(CAPACITOR_PARAM, 0.f, 1.f, 0.f, ""); - configInput(RISE_INPUT, ""); - configInput(FALL_INPUT, ""); - configInput(IN_INPUT, ""); - configOutput(OUT_OUTPUT, ""); + configParam(CURVE_PARAM, 0.f, 1.f, 0.f, "Curve"); + configParam(RISE_PARAM, 0.f, 1.f, 0.f, "Rise"); + configParam(FALL_PARAM, 0.f, 1.f, 0.f, "Fall"); + configSwitch(MODE_PARAM, 0.f, 1.f, 0.f, "Mode", {"LFO", "Slew"}); + configSwitch(RATE_PARAM, 0.f, 1.f, 0.f, "Rate", {"Slow", "Fast"}); + configParam(CAPACITOR_PARAM, 0.f, 1.f, 0.f, "Capacitor"); + configInput(RISE_INPUT, "Rise CV"); + configInput(FALL_INPUT, "Fall CV"); + configInput(IN_INPUT, "In"); + configOutput(OUT_OUTPUT, "Out"); } + float_4 out[4] = {}; void process(const ProcessArgs& args) override { + + float_4 in[4] = {}; + float_4 riseCV[4] = {}; + float_4 fallCV[4] = {}; + + // this is the number of active polyphony engines, defined by the input + const int numPolyphonyEngines = std::max({1, inputs[IN_INPUT].getChannels(), inputs[RISE_INPUT].getChannels(), inputs[FALL_INPUT].getChannels()}); + + // minimum and maximum slopes in volts per second + const float slewMin = (params[RATE_PARAM].getValue()) ? 10.f / 120e-3 : 10.f / 12; // slow: 12s to 10V, fast: 120ms to 10V + const float slewMax = (params[RATE_PARAM].getValue()) ? 10.f / 120e-6 : 10.f / 12e-3; // slow: 12 ms to 10V, fast: 120us to 10V + // Amount of extra slew per voltage difference + const float shapeScale = 1 / 10.f; + const float shape = params[CURVE_PARAM].getValue() * 0.998; + + const float_4 param_rise = params[RISE_PARAM].getValue() * 10.f; + const float_4 param_fall = params[FALL_PARAM].getValue() * 10.f; + + outputs[OUT_OUTPUT].setChannels(numPolyphonyEngines); + + for (int c = 0; c < numPolyphonyEngines; c += 4) { + if (params[MODE_PARAM].getValue()) { + in[c / 4] = inputs[IN_INPUT].getVoltageSimd(c); + } + else { + states[c / 4] = ifelse(out[c / 4] >= 10.f, float_4::mask(), states[c / 4]); + states[c / 4] = ifelse(out[c / 4] <= 0.f, 0.f, states[c / 4]); + in[c / 4] = ifelse(states[c / 4], 0.f, 10.f); + } + + + if (inputs[RISE_INPUT].isConnected()) { + riseCV[c / 4] = inputs[RISE_INPUT].getPolyVoltageSimd(c); + } + if (inputs[FALL_INPUT].isConnected()) { + fallCV[c / 4] = inputs[FALL_INPUT].getPolyVoltageSimd(c); + } + + riseCV[c / 4] += param_rise; + fallCV[c / 4] += param_fall; + + float_4 delta = in[c / 4] - out[c / 4]; + float_4 delta_gt_0 = delta > 0.f; + float_4 delta_lt_0 = delta < 0.f; + + float_4 rateCV = {}; + rateCV = ifelse(delta_gt_0, riseCV[c / 4], 0.f); + rateCV = ifelse(delta_lt_0, fallCV[c / 4], rateCV) * 0.1f; + + float_4 pm_one = simd::sgn(delta); + float_4 slew = slewMax * simd::pow(slewMin / slewMax, rateCV); + + out[c / 4] += slew * simd::crossfade(pm_one, shapeScale * delta, shape) * args.sampleTime; + out[c / 4] = ifelse(delta_gt_0 & (out[c / 4] > in[c / 4]), in[c / 4], out[c / 4]); + out[c / 4] = ifelse(delta_lt_0 & (out[c / 4] < in[c / 4]), in[c / 4], out[c / 4]); + + outputs[OUT_OUTPUT].setVoltageSimd(out[c / 4], c); + } + } + + float_4 phases[4] = {}; + float_4 states[4] = {}; // 0 rising, 1 falling + // unused + void processLFO(const ProcessArgs& args) { + // this is the number of active polyphony engines, defined by rise/fall CV + const int numPolyphonyEngines = std::max({1, inputs[RISE_INPUT].getChannels(), inputs[FALL_INPUT].getChannels()}); + outputs[OUT_OUTPUT].setChannels(numPolyphonyEngines); + + const float_4 attackShape = 1.f; // 1.f - params[CURVE_PARAM].getValue() * 0.8f; + const float_4 releaseShape = 1.f; // 1.f + 2 * params[CURVE_PARAM].getValue(); + + for (int c = 0; c < numPolyphonyEngines; c += 4) { + // get rise and fall (between 0 and 1) + const float_4 rise = inputs[RISE_INPUT].getNormalPolyVoltageSimd(10.f, c) / 10.f * params[RISE_PARAM].getValue(); + const float_4 fall = inputs[FALL_INPUT].getNormalPolyVoltageSimd(10.f, c) / 10.f * params[FALL_PARAM].getValue(); + + const float_4 riseMs = 12 * pow(10.f, -3 * (1 - rise)); + const float_4 fallMs = 12 * pow(10.f, -3 * (1 - fall)); + + states[c / 4] = ifelse(phases[c / 4] > 1.f, float_4::mask(), states[c / 4]); + states[c / 4] = ifelse(phases[c / 4] < 0.f, 0.f, states[c / 4]); + + phases[c / 4] += ifelse(states[c / 4], -args.sampleTime / fallMs, args.sampleTime / riseMs); + + out[c / 4] = 5.f * ifelse(states[c / 4], pow(phases[c / 4], releaseShape), pow(phases[c / 4], attackShape)); + + outputs[OUT_OUTPUT].setVoltageSimd(out[c / 4], c); + } + } };