diff --git a/plugin.json b/plugin.json
index 76532ee..f13a266 100644
--- a/plugin.json
+++ b/plugin.json
@@ -210,6 +210,15 @@
"Polyphonic",
"Visual"
]
+ },
+ {
+ "slug": "MidSide",
+ "name": "Mid/Side",
+ "description": "Mid/side stereo encoder/decoder",
+ "tags": [
+ "Utility",
+ "Polyphonic"
+ ]
}
]
}
\ No newline at end of file
diff --git a/res/MidSide.svg b/res/MidSide.svg
new file mode 100644
index 0000000..ae206d3
--- /dev/null
+++ b/res/MidSide.svg
@@ -0,0 +1,541 @@
+
+
+
+
diff --git a/src/MidSide.cpp b/src/MidSide.cpp
new file mode 100644
index 0000000..ecc604b
--- /dev/null
+++ b/src/MidSide.cpp
@@ -0,0 +1,108 @@
+#include "plugin.hpp"
+
+
+struct MidSide : Module {
+ enum ParamIds {
+ ENC_WIDTH_PARAM,
+ DEC_WIDTH_PARAM,
+ NUM_PARAMS
+ };
+ enum InputIds {
+ ENC_WIDTH_INPUT,
+ ENC_LEFT_INPUT,
+ ENC_RIGHT_INPUT,
+ DEC_WIDTH_INPUT,
+ DEC_MID_INPUT,
+ DEC_SIDES_INPUT,
+ NUM_INPUTS
+ };
+ enum OutputIds {
+ ENC_MID_OUTPUT,
+ ENC_SIDES_OUTPUT,
+ DEC_LEFT_OUTPUT,
+ DEC_RIGHT_OUTPUT,
+ NUM_OUTPUTS
+ };
+ enum LightIds {
+ NUM_LIGHTS
+ };
+
+ MidSide() {
+ config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
+ configParam(ENC_WIDTH_PARAM, 0.f, 2.f, 1.f, "Encoder width", "%", 0, 100);
+ configParam(DEC_WIDTH_PARAM, 0.f, 2.f, 1.f, "Decoder width", "%", 0, 100);
+ }
+
+ void process(const ProcessArgs &args) override {
+ using simd::float_4;
+
+ // Encoder
+ {
+ int channels = std::max(inputs[ENC_LEFT_INPUT].getChannels(), inputs[ENC_RIGHT_INPUT].getChannels());
+ outputs[ENC_MID_OUTPUT].setChannels(channels);
+ outputs[ENC_SIDES_OUTPUT].setChannels(channels);
+
+ for (int c = 0; c < channels; c += 4) {
+ float_4 width = params[ENC_WIDTH_PARAM].getValue();
+ width += inputs[ENC_WIDTH_INPUT].getPolyVoltageSimd(c) / 10 * 2;
+ width = simd::fmax(width, 0.f);
+ float_4 left = inputs[ENC_LEFT_INPUT].getVoltageSimd(c);
+ float_4 right = inputs[ENC_RIGHT_INPUT].getVoltageSimd(c);
+ float_4 mid = (left + right) / 2;
+ float_4 sides = (left - right) / 2 * width;
+ outputs[ENC_MID_OUTPUT].setVoltageSimd(mid, c);
+ outputs[ENC_SIDES_OUTPUT].setVoltageSimd(sides, c);
+ }
+ }
+
+ // Decoder
+ {
+ int channels = std::max(inputs[DEC_MID_INPUT].getChannels(), inputs[DEC_SIDES_INPUT].getChannels());
+ outputs[DEC_LEFT_OUTPUT].setChannels(channels);
+ outputs[DEC_RIGHT_OUTPUT].setChannels(channels);
+
+ for (int c = 0; c < channels; c += 4) {
+ float_4 width = params[DEC_WIDTH_PARAM].getValue();
+ width += inputs[DEC_WIDTH_INPUT].getPolyVoltageSimd(c) / 10 * 2;
+ width = simd::fmax(width, 0.f);
+ float_4 mid = inputs[DEC_MID_INPUT].getVoltageSimd(c);
+ float_4 sides = inputs[DEC_SIDES_INPUT].getVoltageSimd(c);
+ float_4 left = (mid + sides * width) / 2;
+ float_4 right = (mid - sides * width) / 2;
+ outputs[DEC_LEFT_OUTPUT].setVoltageSimd(left, c);
+ outputs[DEC_RIGHT_OUTPUT].setVoltageSimd(right, c);
+ }
+ }
+ }
+};
+
+
+struct MidSideWidget : ModuleWidget {
+ MidSideWidget(MidSide *module) {
+ setModule(module);
+ setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/MidSide.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(18.699, 26.234)), module, MidSide::ENC_WIDTH_PARAM));
+ addParam(createParamCentered(mm2px(Vec(18.699, 81.235)), module, MidSide::DEC_WIDTH_PARAM));
+
+ addInput(createInputCentered(mm2px(Vec(6.699, 26.234)), module, MidSide::ENC_WIDTH_INPUT));
+ addInput(createInputCentered(mm2px(Vec(6.699, 41.234)), module, MidSide::ENC_LEFT_INPUT));
+ addInput(createInputCentered(mm2px(Vec(18.699, 41.234)), module, MidSide::ENC_RIGHT_INPUT));
+ addInput(createInputCentered(mm2px(Vec(6.699, 81.234)), module, MidSide::DEC_WIDTH_INPUT));
+ addInput(createInputCentered(mm2px(Vec(6.699, 96.234)), module, MidSide::DEC_MID_INPUT));
+ addInput(createInputCentered(mm2px(Vec(18.699, 96.234)), module, MidSide::DEC_SIDES_INPUT));
+
+ addOutput(createOutputCentered(mm2px(Vec(6.699, 57.253)), module, MidSide::ENC_MID_OUTPUT));
+ addOutput(createOutputCentered(mm2px(Vec(18.699, 57.253)), module, MidSide::ENC_SIDES_OUTPUT));
+ addOutput(createOutputCentered(mm2px(Vec(6.699, 112.252)), module, MidSide::DEC_LEFT_OUTPUT));
+ addOutput(createOutputCentered(mm2px(Vec(18.699, 112.252)), module, MidSide::DEC_RIGHT_OUTPUT));
+ }
+};
+
+
+Model *modelMidSide = createModel("MidSide");
\ No newline at end of file
diff --git a/src/plugin.cpp b/src/plugin.cpp
index 86f0e0e..f70a267 100644
--- a/src/plugin.cpp
+++ b/src/plugin.cpp
@@ -28,4 +28,5 @@ void init(rack::Plugin *p) {
p->addModel(modelMerge);
p->addModel(modelSum);
p->addModel(modelViz);
+ p->addModel(modelMidSide);
}
diff --git a/src/plugin.hpp b/src/plugin.hpp
index 7e9a5cb..a468122 100644
--- a/src/plugin.hpp
+++ b/src/plugin.hpp
@@ -28,5 +28,5 @@ extern Model *modelSplit;
extern Model *modelMerge;
extern Model *modelSum;
extern Model *modelViz;
-
+extern Model *modelMidSide;