commit 5b143766a79d1ab0dd439d6df0cceabf7a0a7c17
parent 643798c60569e04d2f6b3196c20b2a3ac1b3e3fd
Author: Matt Demanett <matt@demanett.net>
Date: Sun, 25 Jul 2021 21:52:43 -0400
Add unipolar mode for knob matrix mixers. #178
Diffstat:
5 files changed, 40 insertions(+), 2 deletions(-)
diff --git a/README-prerelease.md b/README-prerelease.md
@@ -665,7 +665,7 @@ _Polyphony:_ <a href="#polyphony">Polyphonic</a>, as on MATRIX44.
A 4x4 channel matrix mixer. Each input can be routed with an independent level to each of the eight output mixes. MATRIX44 is expandable with <a href="matrix44cvm">MX44CVM</a>.
-*Note that the matrix knobs are attenuverters, and default to zero.* That means there will be no output, regardless of the inputs, until some knobs are changed to non-zero values.
+*Note that the matrix knobs are attenuverters, and default to zero.* That means there will be no output, regardless of the inputs, until some knobs are changed to non-zero values. The knobs can be set to unipolar mode, as below; they still default to zero.
Saturation (soft clipping) limits each output to +/-12V. This can be changed to a hard clip at +/-12V on the context menu ("Output clipping") -- as described on UMIX, this is mode is better if you need to precisely sum CVs.
@@ -675,6 +675,8 @@ Option "Average" sets the output to be the average of its inputs. The divisor f
The knobs visually indicate their values with green/orange colors. This can be disabled on the context menu.
+Option "Unipolar" sets the knobs to travel from zero to 100% over their full travel (which is to say that they can no longer be set to invert the input). The panel does not update; the tick at noon for each knob indicates 50% in this mode.
+
_Polyphony:_ <a href="#polyphony">Polyphonic</a>, with polyphonic channels defined by input 1.
#### <a name="matrix44cvm"></a> MX44CVM
diff --git a/src/matrix_base.cpp b/src/matrix_base.cpp
@@ -177,19 +177,41 @@ void MatrixModuleWidget::contextMenu(Menu* menu) {
#define INDICATOR_KNOBS "indicator_knobs"
+#define UNIPOLAR "unipolar"
json_t* KnobMatrixModule::toJson(json_t* root) {
root = MatrixBaseModule::toJson(root);
json_object_set_new(root, INDICATOR_KNOBS, json_boolean(_indicatorKnobs));
+ json_object_set_new(root, UNIPOLAR, json_boolean(_unipolar));
return root;
}
void KnobMatrixModule::fromJson(json_t* root) {
MatrixBaseModule::fromJson(root);
+
json_t* k = json_object_get(root, INDICATOR_KNOBS);
if (k) {
_indicatorKnobs = json_is_true(k);
}
+
+ json_t* u = json_object_get(root, UNIPOLAR);
+ if (u) {
+ _unipolar = json_is_true(u);
+ updateParamMinimumValues();
+ }
+}
+
+void KnobMatrixModule::updateParamMinimumValues() {
+ if (_unipolar) {
+ for (int i = 0, n = _ins * _outs; i < n; ++i) {
+ paramQuantities[i]->minValue = 0.0f;
+ params[i].value = std::max(params[i].value, 0.0f);
+ }
+ } else {
+ for (int i = 0, n = _ins * _outs; i < n; ++i) {
+ paramQuantities[i]->minValue = -1.0f;
+ }
+ }
}
@@ -197,6 +219,7 @@ void KnobMatrixModuleWidget::createKnob(math::Vec& position, KnobMatrixModule* m
auto knob = dynamic_cast<IndicatorKnob19*>(createParam<IndicatorKnob19>(position, module, id));
if (module) {
knob->setDrawColorsCallback([module]() { return module->_indicatorKnobs; });
+ knob->setUnipolarCallback([module]() { return module->_unipolar; });
}
addParam(knob);
_knobs.push_back(knob);
@@ -217,6 +240,11 @@ void KnobMatrixModuleWidget::contextMenu(Menu* menu) {
[m]() { return m->_indicatorKnobs; },
[m, this]() { m->_indicatorKnobs = !m->_indicatorKnobs; this->redrawKnobs(); }
));
+ menu->addChild(new OptionMenuItem(
+ "Unipolar",
+ [m]() { return m->_unipolar; },
+ [m, this]() { m->_unipolar = !m->_unipolar; m->updateParamMinimumValues(); this->redrawKnobs(); }
+ ));
}
diff --git a/src/matrix_base.hpp b/src/matrix_base.hpp
@@ -73,6 +73,7 @@ struct MatrixModuleWidget : MatrixBaseModuleWidget {
struct KnobMatrixModule : MatrixModule {
bool _indicatorKnobs = true;
+ bool _unipolar = false;
KnobMatrixModule() {} // call configMatrixModule()
KnobMatrixModule(int ins, int outs, int firstParamID, int firstInputID, int firstOutputID)
@@ -81,6 +82,7 @@ struct KnobMatrixModule : MatrixModule {
json_t* toJson(json_t* root) override;
void fromJson(json_t* root) override;
+ void updateParamMinimumValues();
};
struct KnobMatrixModuleWidget : MatrixModuleWidget {
diff --git a/src/widgets.cpp b/src/widgets.cpp
@@ -92,7 +92,11 @@ Knob68::Knob68() : BGKnob("knob_68px", 68) {
void IndicatorKnob::IKWidget::setAngle(float a) {
assert(a >= -1.0f && a <= 1.0f);
- _angle = a * 0.83f * M_PI;
+ const float range = 0.83f * M_PI;
+ _angle = a * range;
+ if (_unipolarCB && _unipolarCB()) {
+ _angle = 2.0f * _angle - range;
+ }
if (a < 0.0f) {
_color.r = 1.0f; // 0xff
_color.g = 0.6f; // 0x99
diff --git a/src/widgets.hpp b/src/widgets.hpp
@@ -66,6 +66,7 @@ struct IndicatorKnob : Knob, SkinnableWidget {
NVGcolor _rim = nvgRGBA(0x33, 0x33, 0x33, 0xff);
NVGcolor _center = nvgRGBA(0xee, 0xee, 0xee, 0xff);
std::function<bool()> _drawColorsCB;
+ std::function<bool()> _unipolarCB;
void setAngle(float a);
void draw(const DrawArgs& args) override;
@@ -79,6 +80,7 @@ struct IndicatorKnob : Knob, SkinnableWidget {
void onHover(const event::Hover& e) override;
void onChange(const event::Change& e) override;
inline void setDrawColorsCallback(std::function<bool()> fn) { w->_drawColorsCB = fn; }
+ inline void setUnipolarCallback(std::function<bool()> fn) { w->_unipolarCB = fn; }
void redraw();
void skinChanged(const std::string& skin) override;
};