| 84 | } |
| 85 | |
| 86 | void process(const ProcessArgs& args) override { |
| 87 | |
| 88 | // slew time in secs (so take inverse for lambda) |
| 89 | clickFilter.rise = clickFilter.fall = 1.0 / params[SLEW_TIME_PARAM].getValue(); |
| 90 | |
| 91 | const int maxInputChannels = std::max({1, inputs[IN_L_INPUT].getChannels(), inputs[IN_R_INPUT].getChannels()}); |
| 92 | const int maxFxReturnChannels = std::max({1, inputs[FROM_FX_L_INPUT].getChannels(), inputs[FROM_FX_R_INPUT].getChannels()}); |
| 93 | |
| 94 | const LatchMode latchMode = (LatchMode) params[LAUNCH_MODE_PARAM].getValue(); |
| 95 | const ReturnMode returnMode = (ReturnMode) params[MODE_PARAM].getValue(); |
| 96 | |
| 97 | |
| 98 | const bool launchCvTriggered = launchCvTrigger.process(inputs[LAUNCH_INPUT].getVoltage()); |
| 99 | const bool launchButtonPressed = launchButtonTrigger.process(launchButtonHeld); |
| 100 | |
| 101 | // logical or (high if either high) |
| 102 | const float launchValue = std::max(launchCvTrigger.isHigh(), launchButtonTrigger.isHigh()); |
| 103 | if (latchMode == LatchMode::TOGGLE_MODE) { |
| 104 | const bool risingEdge = launchCvTriggered || launchButtonPressed; |
| 105 | |
| 106 | if (risingEdge) { |
| 107 | active = !active; |
| 108 | } |
| 109 | } |
| 110 | |
| 111 | // FX send section |
| 112 | const float sendActive = clickFilter.process(args.sampleTime, (latchMode == LatchMode::TOGGLE_MODE) ? active : launchValue); |
| 113 | for (int c = 0; c < maxInputChannels; c += 4) { |
| 114 | const float_4 inL = inputs[IN_L_INPUT].getPolyVoltageSimd<float_4>(c); |
| 115 | const float_4 inR = inputs[IN_R_INPUT].getNormalPolyVoltageSimd<float_4>(inL, c); |
| 116 | |
| 117 | // we start be assuming that FXs can be polyphonic, but recognise that often they are not |
| 118 | outputs[TO_FX_L_OUTPUT].setVoltageSimd<float_4>(inL * sendActive, c); |
| 119 | outputs[TO_FX_R_OUTPUT].setVoltageSimd<float_4>(inR * sendActive, c); |
| 120 | } |
| 121 | // fx send polyphony is set by input polyphony |
| 122 | outputs[TO_FX_L_OUTPUT].setChannels(maxInputChannels); |
| 123 | outputs[TO_FX_R_OUTPUT].setChannels(maxInputChannels); |
| 124 | |
| 125 | |
| 126 | // FX return section |
| 127 | const float gainTaper = params[FX_GAIN_PARAM].getValue() < 0.f ? 30 * params[FX_GAIN_PARAM].getValue() : params[FX_GAIN_PARAM].getValue() * 12; |
| 128 | const float fxReturnGain = std::pow(10, gainTaper / 20.0f); |
| 129 | float_4 dryLeft, dryRight, outL, outR; |
| 130 | for (int c = 0; c < maxFxReturnChannels; c += 4) { |
| 131 | |
| 132 | const bool fxMonophonic = (maxInputChannels == 1); |
| 133 | if (fxMonophonic) { |
| 134 | // if the return fx is monophonic, mix down dry inputs to monophonic also |
| 135 | dryLeft = inputs[IN_L_INPUT].getVoltageSum(); |
| 136 | dryRight = inputs[IN_R_INPUT].isConnected() ? inputs[IN_R_INPUT].getVoltageSum() : inputs[IN_L_INPUT].getVoltageSum(); |
| 137 | } |
| 138 | else { |
| 139 | // if the return fx is polyphonic, then we don't need to do anything special |
| 140 | dryLeft = inputs[IN_L_INPUT].getPolyVoltageSimd<float_4>(c); |
| 141 | dryRight = inputs[IN_R_INPUT].getNormalPolyVoltageSimd<float_4>(dryLeft, c); |
| 142 | } |
| 143 |
nothing calls this directly
no test coverage detected