BogaudioModules

BogaudioModules for VCV Rack
Log | Files | Refs | README | LICENSE

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:
MREADME.md | 2++
Msrc/Mute8.cpp | 34++++++++++++++++++++++++++++++----
Msrc/Mute8.hpp | 4++++
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;