From 30536e4ce4709a75dc611f388854a3ca9277ed6e Mon Sep 17 00:00:00 2001
From: hemmer <915048+hemmer@users.noreply.github.com>
Date: Sun, 4 Apr 2021 18:38:41 +0100
Subject: [PATCH] Added Hexmix VCA.
---
plugin.json | 11 +
res/HexmixVCA.svg | 29100 ++++++++++++++++++++++++++++++++++++++++++++
src/HexmixVCA.cpp | 178 +
src/plugin.cpp | 1 +
src/plugin.hpp | 2 +-
5 files changed, 29291 insertions(+), 1 deletion(-)
create mode 100644 res/HexmixVCA.svg
create mode 100644 src/HexmixVCA.cpp
diff --git a/plugin.json b/plugin.json
index 39f7e68..6cfb7c4 100644
--- a/plugin.json
+++ b/plugin.json
@@ -99,6 +99,17 @@
"Mixer",
"Hardware clone"
]
+ },
+ {
+ "slug": "HexmixVCA",
+ "name": "HexmixVCA",
+ "description": "Six channel VCA with response curve range from logarithmic to linear and to exponential",
+ "modularGridUrl": "https://www.modulargrid.net/e/befaco-hexmix-vca",
+ "tags": [
+ "Mixer",
+ "Hardware clone",
+ "VCA"
+ ]
}
]
}
\ No newline at end of file
diff --git a/res/HexmixVCA.svg b/res/HexmixVCA.svg
new file mode 100644
index 0000000..8b6c78e
--- /dev/null
+++ b/res/HexmixVCA.svg
@@ -0,0 +1,29100 @@
+
+
diff --git a/src/HexmixVCA.cpp b/src/HexmixVCA.cpp
new file mode 100644
index 0000000..90a6e98
--- /dev/null
+++ b/src/HexmixVCA.cpp
@@ -0,0 +1,178 @@
+#include "plugin.hpp"
+
+struct BefacoTinyKnobRed : app::SvgKnob {
+ BefacoTinyKnobRed() {
+ minAngle = -0.8 * M_PI;
+ maxAngle = 0.8 * M_PI;
+ setSvg(APP->window->loadSvg(asset::plugin(pluginInstance, "res/BefacoTinyKnobRed.svg")));
+ }
+};
+
+struct BefacoTinyKnobWhite : app::SvgKnob {
+ BefacoTinyKnobWhite() {
+ minAngle = -0.8 * M_PI;
+ maxAngle = 0.8 * M_PI;
+ setSvg(APP->window->loadSvg(asset::system("res/ComponentLibrary/BefacoTinyKnob.svg")));
+ }
+};
+
+static float gainFunction(float x, float shape) {
+ float lin = x;
+ if (shape > 0.f) {
+ float log = 11.f * x / (10.f * x + 1.f);
+ return crossfade(lin, log, shape);
+ }
+ else {
+ float exp = std::pow(x, 4);
+ return crossfade(lin, exp, -shape);
+ }
+}
+
+struct HexmixVCA : Module {
+ enum ParamIds {
+ ENUMS(SHAPE_PARAM, 6),
+ ENUMS(VOL_PARAM, 6),
+ NUM_PARAMS
+ };
+ enum InputIds {
+ ENUMS(IN_INPUT, 6),
+ ENUMS(CV_INPUT, 6),
+ NUM_INPUTS
+ };
+ enum OutputIds {
+ ENUMS(OUT_OUTPUT, 6),
+ NUM_OUTPUTS
+ };
+ enum LightIds {
+ NUM_LIGHTS
+ };
+
+ const static int numRows = 6;
+ dsp::ClockDivider cvDivider;
+ float outputLevels[numRows] = {1.f};
+ float shapes[numRows] = {0.f};
+
+ HexmixVCA() {
+ config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
+ for (int i = 0; i < numRows; ++i) {
+ configParam(SHAPE_PARAM + i, -1.f, 1.f, 0.f, "VCA response");
+ configParam(VOL_PARAM + i, 0.f, 1.f, 1.f, "Output level");
+ }
+ cvDivider.setDivision(16);
+ }
+
+ void process(const ProcessArgs& args) override {
+ simd::float_4 mix[4] = {};
+ int maxChannels = 1;
+
+ // only calculate gains/shapes every 16 samples
+ if (cvDivider.process()) {
+ for (int row = 0; row < numRows; ++row) {
+ shapes[row] = params[SHAPE_PARAM + row].getValue();
+ outputLevels[row] = params[VOL_PARAM + row].getValue();
+ }
+ }
+
+ for (int row = 0; row < numRows; ++row) {
+
+ int channels = 1;
+ simd::float_4 in[4] = {};
+ bool input_is_connected = inputs[IN_INPUT + row].isConnected();
+ if (input_is_connected) {
+ channels = inputs[row].getChannels();
+ maxChannels = std::max(maxChannels, channels);
+
+ float cvGain = clamp(inputs[CV_INPUT + row].getNormalVoltage(10.f) / 10.f, 0.f, 1.f);
+ float gain = gainFunction(cvGain, shapes[row]);
+
+ for (int c = 0; c < channels; c += 4) {
+ in[c / 4] = simd::float_4::load(inputs[row].getVoltages(c)) * gain * outputLevels[row];
+ }
+ }
+
+ // if not the final row
+ if (row != numRows - 1) {
+ if (outputs[OUT_OUTPUT + row].isConnected()) {
+ outputs[OUT_OUTPUT + row].setChannels(channels);
+ for (int c = 0; c < channels; c += 4) {
+ in[c / 4].store(outputs[OUT_OUTPUT + row].getVoltages(c));
+ }
+ }
+ else {
+ // else add to mix
+ for (int c = 0; c < channels; c += 4) {
+ mix[c / 4] += in[c / 4];
+ }
+ }
+ }
+ // final row
+ else {
+ if (outputs[OUT_OUTPUT + row].isConnected()) {
+
+ outputs[OUT_OUTPUT + row].setChannels(maxChannels);
+
+ // last channel must always go into mix
+ for (int c = 0; c < channels; c += 4) {
+ mix[c / 4] += in[c / 4];
+ }
+
+ for (int c = 0; c < maxChannels; c += 4) {
+ mix[c / 4].store(outputs[OUT_OUTPUT + row].getVoltages(c));
+ }
+ }
+ }
+
+ }
+ }
+};
+
+
+struct HexmixVCAWidget : ModuleWidget {
+ HexmixVCAWidget(HexmixVCA* module) {
+ setModule(module);
+ setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/HexmixVCA.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(20.412, 15.51)), module, HexmixVCA::SHAPE_PARAM + 0));
+ addParam(createParamCentered(mm2px(Vec(20.412, 34.115)), module, HexmixVCA::SHAPE_PARAM + 1));
+ addParam(createParamCentered(mm2px(Vec(20.412, 52.72)), module, HexmixVCA::SHAPE_PARAM + 2));
+ addParam(createParamCentered(mm2px(Vec(20.412, 71.325)), module, HexmixVCA::SHAPE_PARAM + 3));
+ addParam(createParamCentered(mm2px(Vec(20.412, 89.93)), module, HexmixVCA::SHAPE_PARAM + 4));
+ addParam(createParamCentered(mm2px(Vec(20.412, 108.536)), module, HexmixVCA::SHAPE_PARAM + 5));
+
+ addParam(createParamCentered(mm2px(Vec(35.458, 15.51)), module, HexmixVCA::VOL_PARAM + 0));
+ addParam(createParamCentered(mm2px(Vec(35.458, 34.115)), module, HexmixVCA::VOL_PARAM + 1));
+ addParam(createParamCentered(mm2px(Vec(35.458, 52.72)), module, HexmixVCA::VOL_PARAM + 2));
+ addParam(createParamCentered(mm2px(Vec(35.458, 71.325)), module, HexmixVCA::VOL_PARAM + 3));
+ addParam(createParamCentered(mm2px(Vec(35.458, 89.93)), module, HexmixVCA::VOL_PARAM + 4));
+ addParam(createParamCentered(mm2px(Vec(35.458, 108.536)), module, HexmixVCA::VOL_PARAM + 5));
+
+ addInput(createInputCentered(mm2px(Vec(6.581, 15.51)), module, HexmixVCA::IN_INPUT + 0));
+ addInput(createInputCentered(mm2px(Vec(6.581, 34.115)), module, HexmixVCA::IN_INPUT + 1));
+ addInput(createInputCentered(mm2px(Vec(6.581, 52.72)), module, HexmixVCA::IN_INPUT + 2));
+ addInput(createInputCentered(mm2px(Vec(6.581, 71.325)), module, HexmixVCA::IN_INPUT + 3));
+ addInput(createInputCentered(mm2px(Vec(6.581, 89.93)), module, HexmixVCA::IN_INPUT + 4));
+ addInput(createInputCentered(mm2px(Vec(6.581, 108.536)), module, HexmixVCA::IN_INPUT + 5));
+
+ addInput(createInputCentered(mm2px(Vec(52.083, 15.51)), module, HexmixVCA::CV_INPUT + 0));
+ addInput(createInputCentered(mm2px(Vec(52.083, 34.115)), module, HexmixVCA::CV_INPUT + 1));
+ addInput(createInputCentered(mm2px(Vec(52.083, 52.72)), module, HexmixVCA::CV_INPUT + 2));
+ addInput(createInputCentered(mm2px(Vec(52.083, 71.325)), module, HexmixVCA::CV_INPUT + 3));
+ addInput(createInputCentered(mm2px(Vec(52.083, 89.93)), module, HexmixVCA::CV_INPUT + 4));
+ addInput(createInputCentered(mm2px(Vec(52.083, 108.536)), module, HexmixVCA::CV_INPUT + 5));
+
+ addOutput(createOutputCentered(mm2px(Vec(64.222, 15.51)), module, HexmixVCA::OUT_OUTPUT + 0));
+ addOutput(createOutputCentered(mm2px(Vec(64.222, 34.115)), module, HexmixVCA::OUT_OUTPUT + 1));
+ addOutput(createOutputCentered(mm2px(Vec(64.222, 52.72)), module, HexmixVCA::OUT_OUTPUT + 2));
+ addOutput(createOutputCentered(mm2px(Vec(64.222, 71.325)), module, HexmixVCA::OUT_OUTPUT + 3));
+ addOutput(createOutputCentered(mm2px(Vec(64.222, 89.93)), module, HexmixVCA::OUT_OUTPUT + 4));
+ addOutput(createOutputCentered(mm2px(Vec(64.222, 108.536)), module, HexmixVCA::OUT_OUTPUT + 5));
+ }
+};
+
+
+Model* modelHexmixVCA = createModel("HexmixVCA");
\ No newline at end of file
diff --git a/src/plugin.cpp b/src/plugin.cpp
index ef5e791..cf8fa03 100644
--- a/src/plugin.cpp
+++ b/src/plugin.cpp
@@ -14,4 +14,5 @@ void init(rack::Plugin *p) {
p->addModel(modelSlewLimiter);
p->addModel(modelDualAtenuverter);
p->addModel(modelPercall);
+ p->addModel(modelHexmixVCA);
}
diff --git a/src/plugin.hpp b/src/plugin.hpp
index bd0c725..d2997f0 100644
--- a/src/plugin.hpp
+++ b/src/plugin.hpp
@@ -14,7 +14,7 @@ extern Model *modelMixer;
extern Model *modelSlewLimiter;
extern Model *modelDualAtenuverter;
extern Model *modelPercall;
-
+extern Model *modelHexmixVCA;
struct Knurlie : SvgScrew {
Knurlie() {