| @@ -28,44 +28,72 @@ struct VCA : Module { | |||
| params[LEVEL2_PARAM].config(0.0, 1.0, 1.0, "Ch 2 level", "%", 0, 100); | |||
| } | |||
| void stepChannel(InputIds in, ParamIds level, InputIds lin, InputIds exp, OutputIds out) { | |||
| void processChannel(Input &in, Param &level, Input &lin, Input &exp, Output &out) { | |||
| if (!in.isConnected() || !out.isConnected()) | |||
| return; | |||
| // Get input | |||
| int channels = inputs[in].getChannels(); | |||
| float v[16]; | |||
| inputs[in].getVoltages(v); | |||
| int channels = in.getChannels(); | |||
| simd::f32_4 v[4]; | |||
| for (int c = 0; c < channels; c += 4) { | |||
| v[c / 4] = simd::f32_4::load(&in.voltages[c]); | |||
| } | |||
| // Apply knob gain | |||
| float gain = params[level].getValue(); | |||
| for (int c = 0; c < channels; c++) { | |||
| v[c] *= gain; | |||
| float gain = level.getValue(); | |||
| for (int c = 0; c < channels; c += 4) { | |||
| v[c / 4] *= gain; | |||
| } | |||
| // Apply linear CV gain | |||
| if (inputs[lin].isConnected()) { | |||
| for (int c = 0; c < channels; c++) { | |||
| float cv = clamp(inputs[lin].getPolyVoltage(c) / 10.f, 0.f, 1.f); | |||
| v[c] *= cv; | |||
| if (lin.isConnected()) { | |||
| if (lin.getChannels() == 1) { | |||
| float cv = lin.getVoltage() / 10.f; | |||
| cv = clamp(cv, 0.f, 1.f); | |||
| for (int c = 0; c < channels; c += 4) { | |||
| v[c / 4] *= cv; | |||
| } | |||
| } | |||
| else { | |||
| for (int c = 0; c < channels; c += 4) { | |||
| simd::f32_4 cv = simd::f32_4::load(&lin.voltages[c]) / 10.f; | |||
| cv = clamp(cv, 0.f, 1.f); | |||
| v[c / 4] *= cv; | |||
| } | |||
| } | |||
| } | |||
| // Apply exponential CV gain | |||
| const float expBase = 50.f; | |||
| if (inputs[exp].isConnected()) { | |||
| for (int c = 0; c < channels; c++) { | |||
| float cv = clamp(inputs[exp].getPolyVoltage(c) / 10.f, 0.f, 1.f); | |||
| if (exp.isConnected()) { | |||
| if (exp.getChannels() == 1) { | |||
| float cv = exp.getVoltage() / 10.f; | |||
| cv = clamp(cv, 0.f, 1.f); | |||
| cv = rescale(std::pow(expBase, cv), 1.f, expBase, 0.f, 1.f); | |||
| v[c] *= cv; | |||
| for (int c = 0; c < channels; c += 4) { | |||
| v[c / 4] *= cv; | |||
| } | |||
| } | |||
| else { | |||
| for (int c = 0; c < channels; c += 4) { | |||
| simd::f32_4 cv = simd::f32_4::load(&exp.voltages[c]) / 10.f; | |||
| cv = clamp(cv, 0.f, 1.f); | |||
| cv = rescale(pow(expBase, cv), 1.f, expBase, 0.f, 1.f); | |||
| v[c / 4] *= cv; | |||
| } | |||
| } | |||
| } | |||
| // Set output | |||
| outputs[out].setChannels(channels); | |||
| outputs[out].setVoltages(v); | |||
| out.setChannels(channels); | |||
| for (int c = 0; c < channels; c += 4) { | |||
| v[c / 4].store(&out.voltages[c]); | |||
| } | |||
| } | |||
| void process(const ProcessArgs &args) override { | |||
| stepChannel(IN1_INPUT, LEVEL1_PARAM, LIN1_INPUT, EXP1_INPUT, OUT1_OUTPUT); | |||
| stepChannel(IN2_INPUT, LEVEL2_PARAM, LIN2_INPUT, EXP2_INPUT, OUT2_OUTPUT); | |||
| processChannel(inputs[IN1_INPUT], params[LEVEL1_PARAM], inputs[LIN1_INPUT], inputs[EXP1_INPUT], outputs[OUT1_OUTPUT]); | |||
| processChannel(inputs[IN2_INPUT], params[LEVEL2_PARAM], inputs[LIN2_INPUT], inputs[EXP2_INPUT], outputs[OUT2_OUTPUT]); | |||
| } | |||
| }; | |||