diff --git a/plugin.json b/plugin.json index 2d0166d..eb5a779 100644 --- a/plugin.json +++ b/plugin.json @@ -103,6 +103,15 @@ "Polyphonic" ] }, + { + "slug": "Mixer", + "name": "Mixer", + "description": "Mixes 6 signals", + "tags": [ + "Mixer", + "Polyphonic" + ] + }, { "slug": "VCMixer", "name": "Mixer", @@ -133,7 +142,8 @@ "Mixer", "Utility", "Dual" - ] + ], + "hidden": true }, { "slug": "Mutes", diff --git a/res/Mixer.svg b/res/Mixer.svg new file mode 100644 index 0000000..315c468 --- /dev/null +++ b/res/Mixer.svg @@ -0,0 +1,272 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/Sum.svg b/res/Sum.svg index 06433f0..869c8ff 100644 --- a/res/Sum.svg +++ b/res/Sum.svg @@ -1,6 +1,4 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + id="svg157" + sodipodi:docname="SUM.svg" + inkscape:version="0.92.3 (2405546, 2018-03-11)"> + id="metadata161"> image/svg+xml - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - + style="display:none"> + + + + + + style="fill:#ff00ff" /> + style="fill:#ff00ff" /> + style="fill:#ff00ff" /> + style="fill:#ff00ff" /> + style="fill:#ff00ff" /> - - diff --git a/src/Mixer.cpp b/src/Mixer.cpp new file mode 100644 index 0000000..77ef064 --- /dev/null +++ b/src/Mixer.cpp @@ -0,0 +1,84 @@ +#include "plugin.hpp" + + +using simd::float_4; + + +struct Mixer : Module { + enum ParamId { + LEVEL_PARAM, + PARAMS_LEN + }; + enum InputId { + ENUMS(IN_INPUTS, 6), + INPUTS_LEN + }; + enum OutputId { + OUT_OUTPUT, + OUTPUTS_LEN + }; + enum LightId { + LIGHTS_LEN + }; + + Mixer() { + config(PARAMS_LEN, INPUTS_LEN, OUTPUTS_LEN, LIGHTS_LEN); + configParam(LEVEL_PARAM, 0.f, 1.f, 1.f, "Level", "%", 0, 100); + for (int i = 0; i < 6; i++) + configInput(IN_INPUTS + i, string::f("Channel %d", i + 1)); + configOutput(OUT_OUTPUT, "Mix"); + } + + void process(const ProcessArgs& args) override { + // Get number of channels + int channels = 1; + for (int i = 0; i < 6; i++) + channels = std::max(channels, inputs[IN_INPUTS + i].getChannels()); + + float gain = params[LEVEL_PARAM].getValue(); + + // Iterate polyphonic channels + for (int c = 0; c < channels; c += 4) { + float_4 out = 0.f; + // Mix input + for (int i = 0; i < 6; i++) { + out += inputs[IN_INPUTS + i].getVoltageSimd(c); + } + + // Apply gain + out *= gain; + + // Set output + outputs[OUT_OUTPUT].setVoltageSimd(out, c); + } + + outputs[OUT_OUTPUT].setChannels(channels); + } +}; + + +struct MixerWidget : ModuleWidget { + MixerWidget(Mixer* module) { + setModule(module); + setPanel(createPanel(asset::plugin(pluginInstance, "res/Mixer.svg"))); + + addChild(createWidget(Vec(RACK_GRID_WIDTH, 0))); + addChild(createWidget(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0))); + 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(createParamCentered(mm2px(Vec(7.62, 24.723)), module, Mixer::LEVEL_PARAM)); + + addInput(createInputCentered(mm2px(Vec(7.62, 46.059)), module, Mixer::IN_INPUTS + 0)); + addInput(createInputCentered(mm2px(Vec(7.62, 56.219)), module, Mixer::IN_INPUTS + 1)); + addInput(createInputCentered(mm2px(Vec(7.62, 66.379)), module, Mixer::IN_INPUTS + 2)); + addInput(createInputCentered(mm2px(Vec(7.62, 76.539)), module, Mixer::IN_INPUTS + 3)); + addInput(createInputCentered(mm2px(Vec(7.62, 86.699)), module, Mixer::IN_INPUTS + 4)); + addInput(createInputCentered(mm2px(Vec(7.62, 96.859)), module, Mixer::IN_INPUTS + 5)); + + addOutput(createOutputCentered(mm2px(Vec(7.62, 113.115)), module, Mixer::OUT_OUTPUT)); + } +}; + + +Model* modelMixer = createModel("Mixer"); \ No newline at end of file diff --git a/src/VCF.cpp b/src/VCF.cpp index de1a0a9..6483476 100644 --- a/src/VCF.cpp +++ b/src/VCF.cpp @@ -68,10 +68,13 @@ static const int UPSAMPLE = 2; struct VCF : Module { enum ParamIds { FREQ_PARAM, - FINE_PARAM, // removed + FINE_PARAM, // removed in 2.0 RES_PARAM, FREQ_CV_PARAM, DRIVE_PARAM, + // Added in 2.0 + RES_CV_PARAM, + DRIVE_CV_PARAM, NUM_PARAMS }; enum InputIds { @@ -95,11 +98,13 @@ struct VCF : Module { VCF() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS); // Multiply and offset for backward patch compatibility - configParam(FREQ_PARAM, 0.f, 1.f, 0.5f, "Frequency", " Hz", std::pow(2, 10.f), dsp::FREQ_C4 / std::pow(2, 5.f)); + configParam(FREQ_PARAM, 0.f, 1.f, 0.5f, "Cutoff frequency", " Hz", std::pow(2, 10.f), dsp::FREQ_C4 / std::pow(2, 5.f)); configParam(FINE_PARAM, 0.f, 1.f, 0.5f, "Fine frequency"); configParam(RES_PARAM, 0.f, 1.f, 0.f, "Resonance", "%", 0.f, 100.f); - configParam(FREQ_CV_PARAM, -1.f, 1.f, 0.f, "Frequency modulation", "%", 0.f, 100.f); + configParam(RES_CV_PARAM, -1.f, 1.f, 0.f, "Resonance CV", "%", 0.f, 100.f); + configParam(FREQ_CV_PARAM, -1.f, 1.f, 0.f, "Cutoff frequency CV", "%", 0.f, 100.f); configParam(DRIVE_PARAM, 0.f, 1.f, 0.f, "Drive", "", 0, 11); + configParam(DRIVE_CV_PARAM, -1.f, 1.f, 0.f, "Drive CV", "%", 0, 100); configInput(FREQ_INPUT, "Frequency"); configInput(RES_INPUT, "Resonance"); configInput(DRIVE_INPUT, "Drive"); @@ -121,7 +126,9 @@ struct VCF : Module { } float driveParam = params[DRIVE_PARAM].getValue(); + float driveCvParam = params[DRIVE_CV_PARAM].getValue(); float resParam = params[RES_PARAM].getValue(); + float resCvParam = params[RES_CV_PARAM].getValue(); float fineParam = params[FINE_PARAM].getValue(); fineParam = dsp::quadraticBipolar(fineParam * 2.f - 1.f) * 7.f / 12.f; float freqCvParam = params[FREQ_CV_PARAM].getValue(); @@ -137,7 +144,8 @@ struct VCF : Module { float_4 input = float_4::load(inputs[IN_INPUT].getVoltages(c)) / 5.f; // Drive gain - float_4 drive = driveParam + inputs[DRIVE_INPUT].getPolyVoltageSimd(c) / 10.f; + // TODO Make center of knob unity gain, 0 is off like a VCA + float_4 drive = driveParam + inputs[DRIVE_INPUT].getPolyVoltageSimd(c) / 10.f * driveCvParam; drive = clamp(drive, 0.f, 1.f); float_4 gain = simd::pow(1.f + drive, 5); input *= gain; @@ -146,7 +154,7 @@ struct VCF : Module { input += 1e-6f * (2.f * random::uniform() - 1.f); // Set resonance - float_4 resonance = resParam + inputs[RES_INPUT].getPolyVoltageSimd(c) / 10.f; + float_4 resonance = resParam + inputs[RES_INPUT].getPolyVoltageSimd(c) / 10.f * resCvParam; resonance = clamp(resonance, 0.f, 1.f); filter->resonance = simd::pow(resonance, 2) * 10.f; @@ -208,8 +216,8 @@ struct VCFWidget : ModuleWidget { addParam(createParamCentered(mm2px(Vec(8.895, 56.388)), module, VCF::RES_PARAM)); addParam(createParamCentered(mm2px(Vec(26.665, 56.388)), module, VCF::DRIVE_PARAM)); addParam(createParamCentered(mm2px(Vec(6.996, 80.603)), module, VCF::FREQ_CV_PARAM)); - // addParam(createParamCentered(mm2px(Vec(17.833, 80.603)), module, VCF::RESCV_PARAM)); - // addParam(createParamCentered(mm2px(Vec(28.67, 80.603)), module, VCF::DRIVE_CV_PARAM)); + addParam(createParamCentered(mm2px(Vec(17.833, 80.603)), module, VCF::RES_CV_PARAM)); + addParam(createParamCentered(mm2px(Vec(28.67, 80.603)), module, VCF::DRIVE_CV_PARAM)); addInput(createInputCentered(mm2px(Vec(6.996, 96.813)), module, VCF::FREQ_INPUT)); addInput(createInputCentered(mm2px(Vec(17.833, 96.813)), module, VCF::RES_INPUT)); diff --git a/src/plugin.cpp b/src/plugin.cpp index a4a0c79..07d5017 100644 --- a/src/plugin.cpp +++ b/src/plugin.cpp @@ -15,6 +15,7 @@ void init(Plugin* p) { p->addModel(modelLFO2); p->addModel(modelDelay); p->addModel(modelADSR); + p->addModel(modelMixer); p->addModel(modelVCMixer); p->addModel(model_8vert); p->addModel(modelUnity); diff --git a/src/plugin.hpp b/src/plugin.hpp index 57db473..a61ef8f 100644 --- a/src/plugin.hpp +++ b/src/plugin.hpp @@ -15,6 +15,7 @@ extern Model* modelLFO; extern Model* modelLFO2; extern Model* modelDelay; extern Model* modelADSR; +extern Model* modelMixer; extern Model* modelVCMixer; extern Model* model_8vert; extern Model* modelUnity;