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 @@
+
+
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 @@
-
-
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;