diff --git a/src/VCMixer.cpp b/src/VCMixer.cpp index 3085cb5..bfbbe6e 100644 --- a/src/VCMixer.cpp +++ b/src/VCMixer.cpp @@ -21,27 +21,76 @@ struct VCMixer : Module { VCMixer() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS); - params[MIX_LVL_PARAM].config(0.0, 2.0, 1.0, "Master level", "%", 0, 100); - params[LVL_PARAM + 0].config(0.0, 1.0, 1.0, "Ch 1 level", "%", 0, 100); - params[LVL_PARAM + 1].config(0.0, 1.0, 1.0, "Ch 2 level", "%", 0, 100); - params[LVL_PARAM + 2].config(0.0, 1.0, 1.0, "Ch 3 level", "%", 0, 100); - params[LVL_PARAM + 3].config(0.0, 1.0, 1.0, "Ch 4 level", "%", 0, 100); + // x^1 scaling up to 6 dB + params[MIX_LVL_PARAM].config(0.0, 2.0, 1.0, "Master level", " dB", -10, 20); + // x^2 scaling up to 6 dB + params[LVL_PARAM + 0].config(0.0, M_SQRT2, 1.0, "Ch 1 level", " dB", -10, 40); + params[LVL_PARAM + 1].config(0.0, M_SQRT2, 1.0, "Ch 2 level", " dB", -10, 40); + params[LVL_PARAM + 2].config(0.0, M_SQRT2, 1.0, "Ch 3 level", " dB", -10, 40); + params[LVL_PARAM + 3].config(0.0, M_SQRT2, 1.0, "Ch 4 level", " dB", -10, 40); } void process(const ProcessArgs &args) override { - float mix = 0.f; + float mix[16] = {}; + int maxChannels = 1; + for (int i = 0; i < 4; i++) { - float ch = inputs[CH_INPUT + i].getVoltage(); - ch *= std::pow(params[LVL_PARAM + i].getValue(), 2.f); - if (inputs[CV_INPUT + i].isConnected()) - ch *= clamp(inputs[CV_INPUT + i].getVoltage() / 10.f, 0.f, 1.f); - outputs[CH_OUTPUT + i].setVoltage(ch); - mix += ch; + // Skip channel if not patched + if (!inputs[CH_INPUT + i].isConnected()) + continue; + + float in[16] = {}; + int channels = inputs[CH_INPUT + i].getChannels(); + maxChannels = std::max(maxChannels, channels); + + // Get input + inputs[CH_INPUT + i].getVoltages(in); + + // Apply fader gain + float gain = std::pow(params[LVL_PARAM + i].getValue(), 2.f); + for (int c = 0; c < channels; c++) { + in[c] *= gain; + } + + // Apply CV gain + if (inputs[CV_INPUT + i].isConnected()) { + for (int c = 0; c < channels; c++) { + float cv = clamp(inputs[CV_INPUT + i].getPolyVoltage(c) / 10.f, 0.f, 1.f); + in[c] *= cv; + } + } + + // Set channel output + if (outputs[CH_OUTPUT + i].isConnected()) { + outputs[CH_OUTPUT + i].setChannels(channels); + outputs[CH_OUTPUT + i].setVoltages(in); + } + + // Add to mix + for (int c = 0; c < channels; c++) { + mix[c] += in[c]; + } + } + + if (outputs[MIX_OUTPUT].isConnected()) { + // Apply mix knob gain + float gain = params[MIX_LVL_PARAM].getValue(); + for (int c = 0; c < maxChannels; c++) { + mix[c] *= gain; + } + + // Apply mix CV gain + if (inputs[MIX_CV_INPUT].isConnected()) { + for (int c = 0; c < maxChannels; c++) { + float cv = clamp(inputs[MIX_CV_INPUT].getPolyVoltage(c) / 10.f, 0.f, 1.f); + mix[c] *= cv; + } + } + + // Set mix output + outputs[MIX_OUTPUT].setChannels(maxChannels); + outputs[MIX_OUTPUT].setVoltages(mix); } - mix *= params[MIX_LVL_PARAM].getValue(); - if (inputs[MIX_CV_INPUT].isConnected()) - mix *= clamp(inputs[MIX_CV_INPUT].getVoltage() / 10.f, 0.f, 1.f); - outputs[MIX_OUTPUT].setVoltage(mix); } };