commit ad97ca40660b2932326da2ccd3c4ae644479052f
parent 884518392929eed7299642a8a42e7b47c3d95f3f
Author: Matt Demanett <matt@demanett.net>
Date: Thu, 13 Feb 2020 22:50:54 -0500
MUTE8: add option to latch muting with triggers at the CV input. #98
Diffstat:
3 files changed, 36 insertions(+), 4 deletions(-)
diff --git a/README.md b/README.md
@@ -305,6 +305,8 @@ MUTE8 provides 8 independent manual or CV-controlled mutes. Each channel is mute
As with MIX4 and MIX8, a right-click on a mute button will solo that channel (pass that channel through while muting all others). Right or left click clears this.
+If context menu option "Latching CV triggers" is enabled, triggers on the CV inputs toggle muting on and off.
+
_Polyphony:_ <a href="#polyphony">Polyphonic</a>, where each of the 8 channels may be independently polyphonic, as defined by the cable at the channel's input.
#### PAN
diff --git a/src/Mute8.cpp b/src/Mute8.cpp
@@ -2,10 +2,25 @@
#include "Mute8.hpp"
#include "mixer.hpp"
+#define LATCHING_CVS "latching_cvs"
+
const float Mute8::maxDecibels = 0.0f;
const float Mute8::minDecibels = Amplifier::minDecibels;
const float Mute8::slewTimeMS = 5.0f;
+json_t* Mute8::dataToJson() {
+ json_t* root = json_object();
+ json_object_set_new(root, LATCHING_CVS, json_boolean(_latchingCVs));
+ return root;
+}
+
+void Mute8::dataFromJson(json_t* root) {
+ json_t* l = json_object_get(root, LATCHING_CVS);
+ if (l) {
+ _latchingCVs = json_is_true(l);
+ }
+}
+
void Mute8::reset() {
for (int i = 0; i < 8; ++i) {
for (int c = 0; c < maxChannels; ++c) {
@@ -41,8 +56,10 @@ void Mute8::stepChannel(int i, bool solo) {
outputs[OUTPUT1_OUTPUT + i].setChannels(n);
int mutedCount = 0;
for (int c = 0; c < n; ++c) {
- _triggers[i][c].process(inputs[MUTE1_INPUT + i].getPolyVoltage(c));
- bool muted = allMuted || _triggers[i][c].isHigh();
+ if (_triggers[i][c].process(inputs[MUTE1_INPUT + i].getPolyVoltage(c))) {
+ _latches[i][c] = !_latches[i][c];
+ }
+ bool muted = allMuted || (!_latchingCVs && _triggers[i][c].isHigh()) || (_latchingCVs && _latches[i][c]);
if (muted) {
++mutedCount;
_amplifiers[i][c].setLevel(_slewLimiters[i][c].next(minDecibels));
@@ -56,8 +73,10 @@ void Mute8::stepChannel(int i, bool solo) {
lights[MUTE1_LIGHT + i].value = mutedCount / (float)n;
}
else {
- _triggers[i][0].process(inputs[MUTE1_INPUT + i].getVoltage());
- bool muted = allMuted || _triggers[i][0].isHigh();
+ if (_triggers[i][0].process(inputs[MUTE1_INPUT + i].getVoltage())) {
+ _latches[i][0] = !_latches[i][0];
+ }
+ bool muted = allMuted || (!_latchingCVs && _triggers[i][0].isHigh()) || (_latchingCVs && _latches[i][0]);
if (muted) {
lights[MUTE1_LIGHT + i].value = 1.0f;
_amplifiers[i][0].setLevel(_slewLimiters[i][0].next(minDecibels));
@@ -180,6 +199,13 @@ struct Mute8Widget : ModuleWidget {
addChild(createLight<SmallLight<GreenLight>>(mute7LightPosition, module, Mute8::MUTE7_LIGHT));
addChild(createLight<SmallLight<GreenLight>>(mute8LightPosition, module, Mute8::MUTE8_LIGHT));
}
+
+ void appendContextMenu(Menu* menu) override {
+ Mute8* m = dynamic_cast<Mute8*>(module);
+ assert(m);
+ menu->addChild(new MenuLabel());
+ menu->addChild(new BoolOptionMenuItem("Latching CV triggers", [m]() { return &m->_latchingCVs; }));
+ }
};
Model* modelMute8 = bogaudio::createModel<Mute8, Mute8Widget>("Bogaudio-Mute8", "MUTE8", "Eight independent mutes with CV control", "Utility", "Polyphonic");
diff --git a/src/Mute8.hpp b/src/Mute8.hpp
@@ -73,6 +73,8 @@ struct Mute8 : BGModule {
Amplifier _amplifiers[8][maxChannels];
bogaudio::dsp::SlewLimiter _slewLimiters[8][maxChannels];
Trigger _triggers[8][maxChannels];
+ bool _latches[8][maxChannels] {};
+ bool _latchingCVs = false;
Mute8() {
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
@@ -86,6 +88,8 @@ struct Mute8 : BGModule {
configParam(MUTE8_PARAM, 0.0f, 3.0f, 0.0f, "Mute 8");
}
+ json_t* dataToJson() override;
+ void dataFromJson(json_t* root) override;
void reset() override;
void sampleRateChange() override;
void processAll(const ProcessArgs& args) override;