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:
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);