BogaudioModules

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

commit b7f6859beafd6a3d7ad83c322249e74d29306ac4
parent 0074730a82229d1d8d6ad6aa6ec750cfa592ebcc
Author: Matt Demanett <matt@demanett.net>
Date:   Tue, 19 Jan 2021 00:12:51 -0500

NSGT: add controls for attack/release times on the context menu. #154

Diffstat:
MREADME-prerelease.md | 2+-
Msrc/Nsgt.cpp | 138++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Msrc/Nsgt.hpp | 9+++++++++
3 files changed, 144 insertions(+), 5 deletions(-)

diff --git a/README-prerelease.md b/README-prerelease.md @@ -825,7 +825,7 @@ _Polyphony:_ <a href="#polyphony">Polyphonic</a>, with polyphony defined by the #### <a name="nsgt"></a> NSGT -NSGT is a compact (6HP) [noise gate](https://en.wikipedia.org/wiki/Noise_gate). Its controls behave the same as the corresponding controls on PRESSOR. +NSGT is a compact (6HP) [noise gate](https://en.wikipedia.org/wiki/Noise_gate). Its controls behave the same as the corresponding controls on PRESSOR. Controls for attack and release times are on the context menu. _Polyphony:_ <a href="#polyphony">Polyphonic</a>, with polyphony defined by the L input. diff --git a/src/Nsgt.cpp b/src/Nsgt.cpp @@ -1,11 +1,11 @@ #include "Nsgt.hpp" +#define ATTACK_MS "attack_ms" +#define RELEASE_MS "release_ms" + void Nsgt::Engine::sampleRateChange() { - float sampleRate = APP->engine->getSampleRate(); - detector.setSampleRate(sampleRate); - attackSL.setParams(sampleRate, 150.0f); - releaseSL.setParams(sampleRate, 600.0f); + detector.setSampleRate(APP->engine->getSampleRate()); } void Nsgt::sampleRateChange() { @@ -14,6 +14,24 @@ void Nsgt::sampleRateChange() { } } +json_t* Nsgt::toJson(json_t* root) { + json_object_set_new(root, ATTACK_MS, json_real(_attackMs)); + json_object_set_new(root, RELEASE_MS, json_real(_releaseMs)); + return root; +} + +void Nsgt::fromJson(json_t* root) { + json_t* a = json_object_get(root, ATTACK_MS); + if (a) { + _attackMs = std::max(0.0f, (float)json_real_value(a)); + } + + json_t* r = json_object_get(root, RELEASE_MS); + if (r) { + _releaseMs = std::max(0.0f, (float)json_real_value(r)); + } +} + bool Nsgt::active() { return outputs[LEFT_OUTPUT].isConnected() || outputs[RIGHT_OUTPUT].isConnected(); } @@ -60,6 +78,10 @@ void Nsgt::modulateChannel(int c) { ratio = 1.0f / ratio; e.ratio = ratio; } + + float sr = APP->engine->getSampleRate(); + e.attackSL.setParams(sr, _attackMs); + e.releaseSL.setParams(sr, _releaseMs); } void Nsgt::processChannel(const ProcessArgs& args, int c) { @@ -89,6 +111,106 @@ void Nsgt::processChannel(const ProcessArgs& args, int c) { } } +struct ARQuantity : Quantity { + typedef std::function<float&(Nsgt* m)> ValueRefFN; + + Nsgt* _module; + std::string _label; + float _maxMs; + float _defaultMs; + ValueRefFN _moduleValueRef; + + ARQuantity( + Nsgt* m, + const char* label, + float maxMs, + float defaultMs, + ValueRefFN moduleValueRef + ) + : _module(m) + , _label(label) + , _maxMs(maxMs) + , _defaultMs(defaultMs) + , _moduleValueRef(moduleValueRef) + {} + + void setValue(float value) override { + value = clamp(value, getMinValue(), getMaxValue()); + if (_module) { + _moduleValueRef(_module) = valueToMs(value); + } + } + + float getValue() override { + if (_module) { + return msToValue(_moduleValueRef(_module)); + } + return getDefaultValue(); + } + + float getMinValue() override { return 0.0f; } + float getMaxValue() override { return msToValue(_maxMs); } + float getDefaultValue() override { return msToValue(_defaultMs); } + float getDisplayValue() override { return roundf(valueToMs(getValue())); } + void setDisplayValue(float displayValue) override { setValue(msToValue(displayValue)); } + std::string getLabel() override { return _label; } + std::string getUnit() override { return "ms"; } + float valueToMs(float v) { return v * v * _maxMs; } + float msToValue(float ms) { return sqrtf(ms / _maxMs); }; +}; + +struct ARSlider : ui::Slider { + ARSlider(ARQuantity* q) { + quantity = q; // q now owned. + box.size.x = 200.0f; + } + virtual ~ARSlider() { + delete quantity; + } +}; + +struct AttackMenuItem : MenuItem { + Nsgt* _module; + + AttackMenuItem(Nsgt* m) : _module(m) { + this->text = "Attack time"; + this->rightText = "▸"; + } + + Menu* createChildMenu() override { + Menu* menu = new Menu; + menu->addChild(new ARSlider(new ARQuantity( + _module, + "Attack", + Nsgt::maxAttackMs, + Nsgt::defaultAttackMs, + [](Nsgt* m) -> float& { return m->_attackMs; } + ))); + return menu; + } +}; + +struct ReleaseMenuItem : MenuItem { + Nsgt* _module; + + ReleaseMenuItem(Nsgt* m) : _module(m) { + this->text = "Release time"; + this->rightText = "▸"; + } + + Menu* createChildMenu() override { + Menu* menu = new Menu; + menu->addChild(new ARSlider(new ARQuantity( + _module, + "Release", + Nsgt::maxReleaseMs, + Nsgt::defaultReleaseMs, + [](Nsgt* m) -> float& { return m->_releaseMs; } + ))); + return menu; + } +}; + struct NsgtWidget : BGModuleWidget { static constexpr int hp = 6; @@ -124,6 +246,14 @@ struct NsgtWidget : BGModuleWidget { addOutput(createOutput<Port24>(leftOutputPosition, module, Nsgt::LEFT_OUTPUT)); addOutput(createOutput<Port24>(rightOutputPosition, module, Nsgt::RIGHT_OUTPUT)); } + + void contextMenu(Menu* menu) override { + auto m = dynamic_cast<Nsgt*>(module); + assert(m); + + menu->addChild(new AttackMenuItem(m)); + menu->addChild(new ReleaseMenuItem(m)); + } }; Model* modelNsgt = bogaudio::createModel<Nsgt, NsgtWidget>("Bogaudio-Nsgt", "NSGT", "Noise gate", "Dynamics", "Polyphonic"); diff --git a/src/Nsgt.hpp b/src/Nsgt.hpp @@ -48,8 +48,15 @@ struct Nsgt : BGModule { void sampleRateChange(); }; + static constexpr float defaultAttackMs = 150.0f; + static constexpr float maxAttackMs = 500.0f; + static constexpr float defaultReleaseMs = 600.0f; + static constexpr float maxReleaseMs = 2000.0f; + Engine* _engines[maxChannels] {}; bool _softKnee = true; + float _attackMs = defaultAttackMs; + float _releaseMs = defaultReleaseMs; Nsgt() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS); @@ -59,6 +66,8 @@ struct Nsgt : BGModule { } void sampleRateChange() override; + json_t* toJson(json_t* root) override; + void fromJson(json_t* root) override; bool active() override; int channels() override; void addChannel(int c) override;