BogaudioModules

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

commit 138d0df11e637f82426b1586d0a8876679b22375
parent 188d169f6df5bc30cce4905f3d14804d7e1cc51d
Author: Matt Demanett <matt@demanett.net>
Date:   Tue,  3 Dec 2019 00:47:32 -0500

Add toggle for retrigger on AD; add ASR modules. #89 #90

Diffstat:
Mplugin.json | 9+++++++++
Mres-src/AD-src.svg | 19++++++++++++-------
Ares-src/ASR-src.svg | 178+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mres/AD.svg | 0
Ares/ASR.svg | 0
Msrc/AD.cpp | 11+++++++----
Msrc/AD.hpp | 5++++-
Asrc/ASR.cpp | 166+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/ASR.hpp | 86+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/bogaudio.cpp | 6++++--
10 files changed, 466 insertions(+), 14 deletions(-)

diff --git a/plugin.json b/plugin.json @@ -133,6 +133,15 @@ ] }, { + "slug": "Bogaudio-ASR", + "name": "ASR", + "description": "Utility attack/sustain/release envelope generator", + "tags": [ + "Envelope generator", + "Polyphonic" + ] + }, + { "slug": "Bogaudio-ADSR", "name": "ADSR", "description": "Utility ADSR envelope generator", diff --git a/res-src/AD-src.svg b/res-src/AD-src.svg @@ -109,9 +109,8 @@ <polyline points="0,0 45,0 45,380 0,380 0,0" stroke="#f2f2f2" stroke-width="1" fill="none" /> <!-- <polyline points="22.5,0 22.5,380" stroke-width="0.5" stroke="#0f0" /> --> - <!-- <polyline points="5,0 5,380" stroke-width="0.5" stroke="#0f0" /> --> - <!-- <polyline points="25,0 25,380" stroke-width="0.5" stroke="#0f0" /> --> - <!-- <polyline points="38,0 38,380" stroke-width="0.5" stroke="#0f0" /> --> + <!-- <polyline points="13,0 3,380" stroke-width="0.5" stroke="#0f0" /> --> + <!-- <polyline points="32,0 42,380" stroke-width="0.5" stroke="#0f0" /> --> <!-- <rect width="45" height="10" fill="#0f0" transform="translate(0 68)" /> --> <!-- <rect width="45" height="10" fill="#0f0" transform="translate(0 127)" /> --> <!-- <rect width="45" height="10" fill="#0f0" transform="translate(0 177)" /> --> @@ -138,12 +137,18 @@ <use id="DECAY_LIGHT" xlink:href="#light-tiny" transform="translate(20.8 40)" /> </g> - <g transform="translate(7.5 132.5)"> - <text font-size="5pt" letter-spacing="0.5px" transform="translate(0 6)">LOOP</text> - <use id="LOOP_PARAM" xlink:href="#button-small" transform="translate(21 -1)" /> + <g transform="translate(0 132.5)"> + <g transform="translate(2.5 0)"> + <text font-size="5pt" letter-spacing="0.5px" transform="translate(0 6)">RT</text> + <use id="RETRIGGER_PARAM" xlink:href="#button-small" transform="translate(9.5 -1)" /> + </g> + <g transform="translate(23.5 0)"> + <text font-size="5pt" letter-spacing="0.5px" transform="translate(0.3 6)">LP</text> + <use id="LOOP_PARAM" xlink:href="#button-small" transform="translate(9.5 -1)" /> + </g> </g> - <g transform="translate(13.5 147)"> + <g transform="translate(11 147)"> <text font-size="5pt" letter-spacing="1.5px" transform="translate(-1 6)">LIN</text> <use id="LINEAR_PARAM" xlink:href="#button-small" transform="translate(15 -1)" /> </g> diff --git a/res-src/ASR-src.svg b/res-src/ASR-src.svg @@ -0,0 +1,178 @@ +<svg + version="1.1" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + width="45" + height="380" + viewBox="0 0 45 380" +> + <style> + text { + fill: #333; + font-family: 'Roboto', sans-serif; + font-weight: bold; + } + text.title { + font-family: 'Comfortaa', sans-serif; + font-weight: normal; + } + text.brand { + font-family: 'Audiowide', sans-serif; + font-weight: bold; + } + </style> + + <defs> + <symbol id="knob" viewBox="0 0 45px 45px"> + <g transform="translate(22.5 22.5)"> + <polyline points="-5,0 5,0" stroke-width="1" stroke="#00f" /> + <polyline points="0,-5 0,5" stroke-width="1" stroke="#00f" /> + <circle cx="0" cy="0" r="14" stroke-width="1" stroke="#00f" fill="none" /> + </g> + </symbol> + + <symbol id="knob-smallest" viewBox="0 0 16px 16px"> + <g transform="translate(8 8)"> + <polyline points="-3,0 3,0" stroke-width="1" stroke="#00f" /> + <polyline points="0,-3 0,3" stroke-width="1" stroke="#00f" /> + <circle r="7.5" stroke-width="1" stroke="#00f" fill="none" /> + </g> + </symbol> + + <symbol id="knobguide" viewBox="0 0 45px 45px"> + <g transform="translate(22.5 22.5)"> + <g transform="rotate(-240) translate(17 0)"> + <g transform="translate(3 0) rotate(240)"> + <text font-size="6.5pt" transform="translate(-2.8 3.3)">0</text> + </g> + </g> + <g transform="rotate(-172.92) translate(17 0)"> + <polyline points="0,0 1.5,0" stroke-width="0.3" stroke="#333" /> + </g> + <g transform="rotate(-145.13) translate(17 0)"> + <g transform="translate(3 0) rotate(145.13)"> + <text font-size="6.5pt" transform="translate(-2.8 3.3)">1</text> + </g> + </g> + <g transform="rotate(-105.84) translate(17 0)"> + <polyline points="0,0 3,0" stroke-width="0.3" stroke="#333" /> + </g> + <g transform="rotate(-75.68) translate(17 0)"> + <polyline points="0,0 3,0" stroke-width="0.3" stroke="#333" /> + </g> + <g transform="rotate(-50.26) translate(17 0)"> + <polyline points="0,0 3,0" stroke-width="0.3" stroke="#333" /> + </g> + <g transform="rotate(-27.87) translate(17 0)"> + <g transform="translate(3 0) rotate(27.87)"> + <text font-size="6.5pt" transform="translate(-2.8 3.3)">5</text> + </g> + </g> + <g transform="rotate(-7.62) translate(17 0)"> + <polyline points="0,0 3,0" stroke-width="0.3" stroke="#333" /> + </g> + <g transform="rotate(11) translate(17 0)"> + <polyline points="0,0 3,0" stroke-width="0.3" stroke="#333" /> + </g> + <g transform="rotate(28.33) translate(17 0)"> + <polyline points="0,0 3,0" stroke-width="0.3" stroke="#333" /> + </g> + <g transform="rotate(44.6) translate(17 0)"> + <polyline points="0,0 3,0" stroke-width="0.3" stroke="#333" /> + </g> + <g transform="rotate(60) translate(17 0)"> + <polyline points="0,0 3,0" stroke-width="0.3" stroke="#333" /> + </g> + </g> + </symbol> + + <symbol id="input" viewBox="0 0 24px 24px"> + <g transform="translate(12 12)"> + <circle cx="0" cy="0" r="5" stroke-width="1" stroke="#0f0" fill="#0f0" /> + <circle cx="0" cy="0" r="10.5" stroke-width="3" stroke="#0f0" fill="none" /> + </g> + </symbol> + + <symbol id="output" viewBox="0 0 24px 24px"> + <g transform="translate(12 12)"> + <circle cx="0" cy="0" r="5" stroke-width="1" stroke="#f00" fill="#f00" /> + <circle cx="0" cy="0" r="10.5" stroke-width="3" stroke="#f00" fill="none" /> + </g> + </symbol> + + <symbol id="button-small" viewBox="0 0 9px 9px"> + <g transform="translate(4.5 4.5)"> + <circle r="4" stroke-width="1" stroke="#00f" fill="#f00" /> + </g> + </symbol> + + <symbol id="light-tiny" viewBox="0 0 1.1px 1.1px"> + <rect width="3.2" height="3.2" fill="#0f0" /> + </symbol> + </defs> + + <rect width="100%" height="100%" fill="#ddd" /> + <polyline points="1,1 44,1 44,379 1,379 1,1" stroke="#e4e4e4" stroke-width="0.5" fill="none" /> + <polyline points="0.5,0.5 44.5,0.5 44.5,379.5 0.5,379.5 0.5,0.5" stroke="#ebebeb" stroke-width="0.8" fill="none" /> + <polyline points="0,0 45,0 45,380 0,380 0,0" stroke="#f2f2f2" stroke-width="1" fill="none" /> + + <!-- <polyline points="22.5,0 22.5,380" stroke-width="0.5" stroke="#0f0" /> --> + <!-- <polyline points="13,0 13,380" stroke-width="0.5" stroke="#0f0" /> --> + <!-- <polyline points="32,0 32,380" stroke-width="0.5" stroke="#0f0" /> --> + <!-- <rect width="45" height="10" fill="#0f0" transform="translate(0 68)" /> --> + <!-- <rect width="45" height="10" fill="#0f0" transform="translate(0 127)" /> --> + <!-- <rect width="45" height="10" fill="#0f0" transform="translate(0 177)" /> --> + + <g transform="rotate(-90) translate(-376 13)"> + <text class="title" font-size="7pt" letter-spacing="2.5px">ASR</text> + <g transform="translate(0 12)"> + <text class="brand" font-size="7pt" letter-spacing="2px">BGA</text> + <rect width="3.0" height="3" fill="#ddd" transform="translate(11.5 -5)" /> + </g> + </g> + + <g transform="translate(0 25)"> + <text font-size="6pt" letter-spacing="1.5px" transform="translate(3.5 0)">ATTACK</text> + <use id="ATTACK_PARAM" xlink:href="#knob" transform="translate(0 0)" /> + <use xlink:href="#knobguide" transform="translate(0 0)" /> + <use id="ATTACK_LIGHT" xlink:href="#light-tiny" transform="translate(20.8 40)" /> + </g> + + <g transform="translate(0 82)"> + <text font-size="6pt" letter-spacing="1px" transform="translate(2.5 0)">RELEASE</text> + <use id="RELEASE_PARAM" xlink:href="#knob" transform="translate(0 0)" /> + <use xlink:href="#knobguide" transform="translate(0 0)" /> + <use id="RELEASE_LIGHT" xlink:href="#light-tiny" transform="translate(20.8 40)" /> + </g> + + <g transform="translate(3.5 130)"> + <text font-size="6pt" letter-spacing="1px" transform="translate(7 11)">S</text> + <use id="SUSTAIN_PARAM" xlink:href="#knob-smallest" transform="translate(14.5 0)" /> + </g> + + <g transform="translate(11 151)"> + <text font-size="5pt" letter-spacing="1.5px" transform="translate(-1 6)">LIN</text> + <use id="LINEAR_PARAM" xlink:href="#button-small" transform="translate(15 -1)" /> + </g> + + <g transform="translate(0 162)"> + <g transform="translate(5.5 0)"> + <rect width="34" height="10" fill="#fafafa" transform="translate(0 98)" /> + <rect width="34" height="108" rx="5" fill="#fafafa" /> + <use id="TRIGGER_INPUT" xlink:href="#input" transform="translate(5 3)" /> + <text font-size="5pt" letter-spacing="2px" transform="translate(6.5 35)">TRIG</text> + <use id="ATTACK_INPUT" xlink:href="#input" transform="translate(5 38)" /> + <text font-size="5pt" letter-spacing="2px" transform="translate(9 70)">ATT</text> + <use id="RELEASE_INPUT" xlink:href="#input" transform="translate(5 73)" /> + <text font-size="5pt" letter-spacing="2px" transform="translate(9 105)">REL</text> + </g> + <g transform="translate(5.5 111)"> + <rect width="34" height="10" fill="#bbb" transform="translate(0 -3)" /> + <rect width="34" height="70" rx="5" fill="#bbb" /> + <use id="ENV_OUTPUT" xlink:href="#output" transform="translate(5 0)" /> + <text font-size="5pt" letter-spacing="2px" transform="translate(8.5 32)">ENV</text> + <use id="EOC_OUTPUT" xlink:href="#output" transform="translate(5 35)" /> + <text font-size="5pt" letter-spacing="2px" transform="translate(8.5 67)">EOC</text> + </g> + </g> +</svg> diff --git a/res/AD.svg b/res/AD.svg Binary files differ. diff --git a/res/ASR.svg b/res/ASR.svg Binary files differ. diff --git a/src/AD.cpp b/src/AD.cpp @@ -78,6 +78,7 @@ void AD::modulateChannel(int c) { e.envelope.setLinearShape(_linearMode); + _retriggerMode = params[RETRIGGER_PARAM].getValue() > 0.5f; _loopMode = params[LOOP_PARAM].getValue() > 0.5f; _linearMode = params[LINEAR_PARAM].getValue() > 0.5f; } @@ -89,8 +90,8 @@ void AD::always(const ProcessArgs& args) { void AD::processChannel(const ProcessArgs& args, int c) { Engine& e = *_engines[c]; - e.trigger.process(inputs[TRIGGER_INPUT].getVoltage(c)); - if (!e.on && (e.trigger.isHigh() || (_loopMode && e.envelope.isStage(ADSR::STOPPED_STAGE)))) { + bool start = e.trigger.process(inputs[TRIGGER_INPUT].getVoltage(c)); + if (!e.on && ((start || (_retriggerMode && e.trigger.isHigh())) || (_loopMode && e.envelope.isStage(ADSR::STOPPED_STAGE)))) { e.on = true; } e.envelope.setGate(e.on); @@ -133,8 +134,9 @@ struct ADWidget : ModuleWidget { // generated by svg_widgets.rb auto attackParamPosition = Vec(8.0, 33.0); auto decayParamPosition = Vec(8.0, 90.0); - auto loopParamPosition = Vec(28.5, 131.5); - auto linearParamPosition = Vec(28.5, 146.0); + auto retriggerParamPosition = Vec(12.0, 131.5); + auto loopParamPosition = Vec(33.0, 131.5); + auto linearParamPosition = Vec(26.0, 146.0); auto triggerInputPosition = Vec(10.5, 163.5); auto attackInputPosition = Vec(10.5, 198.5); @@ -151,6 +153,7 @@ struct ADWidget : ModuleWidget { addParam(createParam<Knob29>(decayParamPosition, module, AD::DECAY_PARAM)); addParam(createParam<IndicatorButtonGreen9>(loopParamPosition, module, AD::LOOP_PARAM)); addParam(createParam<IndicatorButtonGreen9>(linearParamPosition, module, AD::LINEAR_PARAM)); + addParam(createParam<IndicatorButtonGreen9>(retriggerParamPosition, module, AD::RETRIGGER_PARAM)); addInput(createInput<Port24>(triggerInputPosition, module, AD::TRIGGER_INPUT)); addInput(createInput<Port24>(attackInputPosition, module, AD::ATTACK_INPUT)); diff --git a/src/AD.hpp b/src/AD.hpp @@ -16,6 +16,7 @@ struct AD : BGModule { DECAY_PARAM, LOOP_PARAM, LINEAR_PARAM, + RETRIGGER_PARAM, NUM_PARAMS }; @@ -43,7 +44,7 @@ struct AD : BGModule { Trigger trigger; rack::dsp::PulseGenerator eocPulseGen; bool on = false; - ADSR envelope; + bogaudio::dsp::ADSR envelope; bogaudio::dsp::SlewLimiter attackSL; bogaudio::dsp::SlewLimiter decaySL; @@ -57,6 +58,7 @@ struct AD : BGModule { void sampleRateChange(); }; Engine* _engines[maxChannels] {}; + bool _retriggerMode = true; bool _loopMode = false; bool _linearMode = false; int _attackLightSum; @@ -69,6 +71,7 @@ struct AD : BGModule { configParam<EnvelopeSegmentParamQuantity>(DECAY_PARAM, 0.0f, 1.0f, 0.31623f, "Decay", " s"); configParam(LOOP_PARAM, 0.0f, 1.0f, 0.0f, "Loop"); configParam(LINEAR_PARAM, 0.0f, 1.0f, 0.0f, "Linear"); + configParam(RETRIGGER_PARAM, 0.0f, 1.0f, 1.0f, "Retrigger"); } void reset() override; diff --git a/src/ASR.cpp b/src/ASR.cpp @@ -0,0 +1,166 @@ + +#include "ASR.hpp" + +#define INVERT "invert" + +void ASR::Engine::reset() { + trigger.reset(); + eocPulseGen.process(10.0); + envelope.reset(); + on = false; +} + +void ASR::Engine::sampleRateChange() { + float sr = APP->engine->getSampleRate(); + envelope.setSampleRate(sr); + attackSL.setParams(sr / (float)modulationSteps); + releaseSL.setParams(sr / (float)modulationSteps); +} + +void ASR::reset() { + for (int c = 0; c < _channels; ++c) { + _engines[c]->reset(); + } +} + +void ASR::sampleRateChange() { + for (int c = 0; c < _channels; ++c) { + _engines[c]->sampleRateChange(); + } +} + +json_t* ASR::dataToJson() { + json_t* root = json_object(); + json_object_set_new(root, INVERT, json_real(_invert)); + return root; +} + +void ASR::dataFromJson(json_t* root) { + json_t* i = json_object_get(root, INVERT); + if (i) { + _invert = json_real_value(i); + } +} + +bool ASR::active() { + return inputs[TRIGGER_INPUT].isConnected() || outputs[ENV_OUTPUT].isConnected() || outputs[EOC_OUTPUT].isConnected(); +} + +int ASR::channels() { + return std::max(1, inputs[TRIGGER_INPUT].getChannels()); +} + +void ASR::addChannel(int c) { + _engines[c] = new Engine(_modulationSteps); + _engines[c]->reset(); + _engines[c]->sampleRateChange(); +} + +void ASR::removeChannel(int c) { + delete _engines[c]; + _engines[c] = NULL; +} + +void ASR::modulateChannel(int c) { + Engine& e = *_engines[c]; + + float attack = powf(params[ATTACK_PARAM].getValue(), 2.0f); + if (inputs[ATTACK_INPUT].isConnected()) { + attack *= clamp(inputs[ATTACK_INPUT].getPolyVoltage(c) / 10.0f, 0.0f, 1.0f); + } + e.envelope.setAttack(e.attackSL.next(attack * 10.f)); + + float release = powf(params[RELEASE_PARAM].getValue(), 2.0f); + if (inputs[RELEASE_INPUT].isConnected()) { + release *= clamp(inputs[RELEASE_INPUT].getPolyVoltage(c) / 10.0f, 0.0f, 1.0f); + } + e.envelope.setRelease(e.releaseSL.next(release * 10.f)); + + e.envelope.setLinearShape(_linearMode); + + _linearMode = params[LINEAR_PARAM].getValue() > 0.5f; +} + +void ASR::always(const ProcessArgs& args) { + _attackLightSum = _releaseLightSum = 0; +} + +void ASR::processChannel(const ProcessArgs& args, int c) { + Engine& e = *_engines[c]; + + bool start = e.trigger.process(inputs[TRIGGER_INPUT].getVoltage(c)); + if (!e.on && start) { + e.on = true; + } + e.envelope.setGate(e.trigger.isHigh() && !e.envelope.isStage(ADSR::RELEASE_STAGE)); + outputs[ENV_OUTPUT].setChannels(_channels); + outputs[ENV_OUTPUT].setVoltage(e.envelope.next() * 10.0f * _invert * params[SUSTAIN_PARAM].getValue(), c); + if (e.on && e.envelope.isStage(ADSR::STOPPED_STAGE)) { + e.envelope.reset(); + e.on = false; + e.eocPulseGen.trigger(0.001f); + } + outputs[EOC_OUTPUT].setChannels(_channels); + outputs[EOC_OUTPUT].setVoltage(e.eocPulseGen.process(APP->engine->getSampleTime()) ? 5.0f : 0.0f, c); + + _attackLightSum += e.envelope.isStage(ADSR::ATTACK_STAGE); + _releaseLightSum += e.envelope.isStage(ADSR::RELEASE_STAGE); +} + +void ASR::postProcess(const ProcessArgs& args) { + lights[ATTACK_LIGHT].value = _attackLightSum / (float)_channels; + lights[RELEASE_LIGHT].value = _releaseLightSum / (float)_channels; +} + +struct ASRWidget : ModuleWidget { + static constexpr int hp = 3; + + ASRWidget(ASR* module) { + setModule(module); + box.size = Vec(RACK_GRID_WIDTH * hp, RACK_GRID_HEIGHT); + + { + SvgPanel *panel = new SvgPanel(); + panel->box.size = box.size; + panel->setBackground(APP->window->loadSvg(asset::plugin(pluginInstance, "res/ASR.svg"))); + addChild(panel); + } + + addChild(createWidget<ScrewSilver>(Vec(0, 0))); + addChild(createWidget<ScrewSilver>(Vec(box.size.x - 15, 365))); + + // generated by svg_widgets.rb + auto attackParamPosition = Vec(8.0, 33.0); + auto releaseParamPosition = Vec(8.0, 90.0); + auto sustainParamPosition = Vec(18.0, 130.0); + auto linearParamPosition = Vec(26.0, 150.0); + + auto triggerInputPosition = Vec(10.5, 165.0); + auto attackInputPosition = Vec(10.5, 200.0); + auto releaseInputPosition = Vec(10.5, 235.0); + + auto envOutputPosition = Vec(10.5, 273.0); + auto eocOutputPosition = Vec(10.5, 308.0); + + auto attackLightPosition = Vec(20.8, 65.0); + auto releaseLightPosition = Vec(20.8, 122.0); + // end generated by svg_widgets.rb + + addParam(createParam<Knob29>(attackParamPosition, module, ASR::ATTACK_PARAM)); + addParam(createParam<Knob29>(releaseParamPosition, module, ASR::RELEASE_PARAM)); + addParam(createParam<Knob16>(sustainParamPosition, module, ASR::SUSTAIN_PARAM)); + addParam(createParam<IndicatorButtonGreen9>(linearParamPosition, module, ASR::LINEAR_PARAM)); + + addInput(createInput<Port24>(triggerInputPosition, module, ASR::TRIGGER_INPUT)); + addInput(createInput<Port24>(attackInputPosition, module, ASR::ATTACK_INPUT)); + addInput(createInput<Port24>(releaseInputPosition, module, ASR::RELEASE_INPUT)); + + addOutput(createOutput<Port24>(envOutputPosition, module, ASR::ENV_OUTPUT)); + addOutput(createOutput<Port24>(eocOutputPosition, module, ASR::EOC_OUTPUT)); + + addChild(createLight<TinyLight<GreenLight>>(attackLightPosition, module, ASR::ATTACK_LIGHT)); + addChild(createLight<TinyLight<GreenLight>>(releaseLightPosition, module, ASR::RELEASE_LIGHT)); + } +}; + +Model* modelASR = createModel<ASR, ASRWidget>("Bogaudio-ASR", "ASR", "Utility attack/sustain/release envelope generator", "Envelope generator", "Polyphonic"); diff --git a/src/ASR.hpp b/src/ASR.hpp @@ -0,0 +1,86 @@ +#pragma once + +#include "bogaudio.hpp" +#include "dsp/envelope.hpp" +#include "dsp/signal.hpp" + +using namespace bogaudio::dsp; + +extern Model* modelASR; + +namespace bogaudio { + +struct ASR : BGModule { + enum ParamsIds { + ATTACK_PARAM, + RELEASE_PARAM, + SUSTAIN_PARAM, + LINEAR_PARAM, + NUM_PARAMS + }; + + enum InputsIds { + TRIGGER_INPUT, + ATTACK_INPUT, + RELEASE_INPUT, + NUM_INPUTS + }; + + enum OutputsIds { + ENV_OUTPUT, + EOC_OUTPUT, + NUM_OUTPUTS + }; + + enum LightsIds { + ATTACK_LIGHT, + RELEASE_LIGHT, + NUM_LIGHTS + }; + + struct Engine { + int modulationSteps; + Trigger trigger; + rack::dsp::PulseGenerator eocPulseGen; + bool on = false; + bogaudio::dsp::ADSR envelope; + bogaudio::dsp::SlewLimiter attackSL; + bogaudio::dsp::SlewLimiter releaseSL; + + Engine(int ms) : modulationSteps(ms) { + reset(); + sampleRateChange(); + envelope.setDecay(0.0f); + } + void reset(); + void sampleRateChange(); + }; + Engine* _engines[maxChannels] {}; + bool _linearMode = false; + int _attackLightSum; + int _releaseLightSum; + float _invert = 1.0f; + + ASR() { + config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); + configParam<EnvelopeSegmentParamQuantity>(ATTACK_PARAM, 0.0f, 1.0f, 0.141421f, "Attack", " s"); + configParam<EnvelopeSegmentParamQuantity>(RELEASE_PARAM, 0.0f, 1.0f, 0.31623f, "Release", " s"); + configParam(SUSTAIN_PARAM, 0.0f, 1.0f, 1.0f, "Sustain", "", 0.0f, 10.0f); + configParam(LINEAR_PARAM, 0.0f, 1.0f, 0.0f, "Linear"); + } + + void reset() override; + void sampleRateChange() override; + json_t* dataToJson() override; + void dataFromJson(json_t* root) override; + bool active() override; + int channels() override; + void addChannel(int c) override; + void removeChannel(int c) override; + void modulateChannel(int c) override; + void always(const ProcessArgs& args) override; + void processChannel(const ProcessArgs& args, int c) override; + void postProcess(const ProcessArgs& args) override; +}; + +} // namespace bogaudio diff --git a/src/bogaudio.cpp b/src/bogaudio.cpp @@ -8,6 +8,8 @@ #include "AMRM.hpp" #include "Analyzer.hpp" #include "AnalyzerXL.hpp" +#include "ASR.hpp" +#include "Assign.hpp" #include "Blank3.hpp" #include "Blank6.hpp" #include "Bool.hpp" @@ -50,6 +52,7 @@ #include "Sums.hpp" #include "Switch.hpp" #include "UMix.hpp" +#include "Unison.hpp" #include "VCA.hpp" #include "VCAmp.hpp" #include "VCM.hpp" @@ -64,8 +67,6 @@ #include "Test2.hpp" #include "template_panels.hpp" -#include "Unison.hpp" -#include "Assign.hpp" //NEW_INCLUDES_HERE Plugin *pluginInstance; @@ -88,6 +89,7 @@ void init(rack::Plugin *p) { p->addModel(modelShaper); p->addModel(modelShaperPlus); p->addModel(modelAD); + p->addModel(modelASR); p->addModel(modelADSR); p->addModel(modelFollow);