commit 079511c3a3ab67b54aba42ab6d17153e91d4e402
parent 1bdb285aec1ae3a8fede575dbd2f1d9f81e8ad3e
Author: Matt Demanett <matt@demanett.net>
Date: Wed, 18 Sep 2019 00:11:02 -0400
Poly: SHAPER[+], DADSRH[+], DGATE.
Diffstat:
M | src/DADSRH.cpp | | | 106 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
M | src/DADSRH.hpp | | | 80 | +++++++++++++------------------------------------------------------------------ |
M | src/DADSRHPlus.cpp | | | 106 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
M | src/DADSRHPlus.hpp | | | 80 | +++++++++++++------------------------------------------------------------------ |
M | src/DGate.cpp | | | 102 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------- |
M | src/DGate.hpp | | | 32 | ++++++++++++++++++++------------ |
M | src/Shaper.cpp | | | 89 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
M | src/Shaper.hpp | | | 65 | ++++++++++++----------------------------------------------------- |
M | src/ShaperPlus.cpp | | | 89 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
M | src/ShaperPlus.hpp | | | 68 | +++++++++++++++----------------------------------------------------- |
M | src/dadsrh_core.cpp | | | 74 | +++++++++++++++++++++++++++++++++++++++++--------------------------------- |
M | src/dadsrh_core.hpp | | | 38 | +++++++++++++++++++------------------- |
M | src/shaper_core.cpp | | | 56 | ++++++++++++++++++++++++++++++++------------------------ |
M | src/shaper_core.hpp | | | 30 | +++++++++++++++--------------- |
14 files changed, 645 insertions(+), 370 deletions(-)
diff --git a/src/DADSRH.cpp b/src/DADSRH.cpp
@@ -1,6 +1,112 @@
#include "DADSRH.hpp"
+void DADSRH::reset() {
+ for (int c = 0; c < maxChannels; ++c) {
+ if (_core[c]) {
+ _core[c]->reset();
+ }
+ }
+}
+
+int DADSRH::channels() {
+ return inputs[TRIGGER_INPUT].getChannels();
+}
+
+void DADSRH::addEngine(int c) {
+ _core[c] = new DADSRHCore(
+ params[DELAY_PARAM],
+ params[ATTACK_PARAM],
+ params[DECAY_PARAM],
+ params[SUSTAIN_PARAM],
+ params[RELEASE_PARAM],
+ params[HOLD_PARAM],
+ params[ATTACK_SHAPE_PARAM],
+ params[DECAY_SHAPE_PARAM],
+ params[RELEASE_SHAPE_PARAM],
+ params[TRIGGER_PARAM],
+ params[MODE_PARAM],
+ params[LOOP_PARAM],
+ params[SPEED_PARAM],
+ params[RETRIGGER_PARAM],
+
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ inputs[TRIGGER_INPUT],
+
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ outputs[ENV_OUTPUT],
+ outputs[INV_OUTPUT],
+ outputs[TRIGGER_OUTPUT],
+
+ _delayLights,
+ _attackLights,
+ _decayLights,
+ _sustainLights,
+ _releaseLights,
+ lights[ATTACK_SHAPE1_LIGHT],
+ lights[ATTACK_SHAPE2_LIGHT],
+ lights[ATTACK_SHAPE3_LIGHT],
+ lights[DECAY_SHAPE1_LIGHT],
+ lights[DECAY_SHAPE2_LIGHT],
+ lights[DECAY_SHAPE3_LIGHT],
+ lights[RELEASE_SHAPE1_LIGHT],
+ lights[RELEASE_SHAPE2_LIGHT],
+ lights[RELEASE_SHAPE3_LIGHT],
+
+ _triggerOnLoad,
+ _shouldTriggerOnLoad
+ );
+}
+
+void DADSRH::removeEngine(int c) {
+ delete _core[c];
+ _core[c] = NULL;
+}
+
+void DADSRH::processChannel(const ProcessArgs& args, int c) {
+ _core[c]->step(c, _channels);
+}
+
+void DADSRH::postProcess(const ProcessArgs& args) {
+ float delaySum = 0.0f;
+ float attackSum = 0.0f;
+ float decaySum = 0.0f;
+ float sustainSum = 0.0f;
+ float releaseSum = 0.0f;
+ for (int c = 0; c < maxChannels; ++c) {
+ if (_core[c]) {
+ delaySum += _delayLights[c];
+ attackSum += _attackLights[c];
+ decaySum += _decayLights[c];
+ sustainSum += _sustainLights[c];
+ releaseSum += _releaseLights[c];
+ }
+ }
+ lights[DELAY_LIGHT].value = delaySum / (float)_channels;
+ lights[ATTACK_LIGHT].value = attackSum / (float)_channels;
+ lights[DECAY_LIGHT].value = decaySum / (float)_channels;
+ lights[SUSTAIN_LIGHT].value = sustainSum / (float)_channels;
+ lights[RELEASE_LIGHT].value = releaseSum / (float)_channels;
+}
+
+bool DADSRH::shouldTriggerOnNextLoad() {
+ for (int c = 0; c < maxChannels; ++c) {
+ if (_core[c] && _core[c]->_stage != _core[c]->STOPPED_STAGE) {
+ return true;
+ }
+ }
+ return false;
+}
+
struct DADSRHWidget : TriggerOnLoadModuleWidget {
static constexpr int hp = 10;
diff --git a/src/DADSRH.hpp b/src/DADSRH.hpp
@@ -57,7 +57,12 @@ struct DADSRH : TriggerOnLoadModule {
NUM_LIGHTS
};
- DADSRHCore* _core;
+ DADSRHCore* _core[maxChannels] {};
+ float _delayLights[maxChannels] {};
+ float _attackLights[maxChannels] {};
+ float _decayLights[maxChannels] {};
+ float _sustainLights[maxChannels] {};
+ float _releaseLights[maxChannels] {};
DADSRH() {
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
@@ -75,75 +80,16 @@ struct DADSRH : TriggerOnLoadModule {
configParam(LOOP_PARAM, 0.0f, 1.0f, 1.0f, "Loop");
configParam(SPEED_PARAM, 0.0f, 1.0f, 1.0f, "Speed");
configParam(RETRIGGER_PARAM, 0.0f, 1.0f, 1.0f, "Retrigger");
-
- _core = new DADSRHCore(
- params[DELAY_PARAM],
- params[ATTACK_PARAM],
- params[DECAY_PARAM],
- params[SUSTAIN_PARAM],
- params[RELEASE_PARAM],
- params[HOLD_PARAM],
- params[ATTACK_SHAPE_PARAM],
- params[DECAY_SHAPE_PARAM],
- params[RELEASE_SHAPE_PARAM],
- params[TRIGGER_PARAM],
- params[MODE_PARAM],
- params[LOOP_PARAM],
- params[SPEED_PARAM],
- params[RETRIGGER_PARAM],
-
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- inputs[TRIGGER_INPUT],
-
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- outputs[ENV_OUTPUT],
- outputs[INV_OUTPUT],
- outputs[TRIGGER_OUTPUT],
-
- lights[DELAY_LIGHT],
- lights[ATTACK_LIGHT],
- lights[DECAY_LIGHT],
- lights[SUSTAIN_LIGHT],
- lights[RELEASE_LIGHT],
- lights[ATTACK_SHAPE1_LIGHT],
- lights[ATTACK_SHAPE2_LIGHT],
- lights[ATTACK_SHAPE3_LIGHT],
- lights[DECAY_SHAPE1_LIGHT],
- lights[DECAY_SHAPE2_LIGHT],
- lights[DECAY_SHAPE3_LIGHT],
- lights[RELEASE_SHAPE1_LIGHT],
- lights[RELEASE_SHAPE2_LIGHT],
- lights[RELEASE_SHAPE3_LIGHT],
-
- _triggerOnLoad,
- _shouldTriggerOnLoad
- );
- reset();
- }
- virtual ~DADSRH() {
- delete _core;
}
- void reset() override {
- _core->reset();
- }
+ void reset() override;
+ int channels() override;
+ void addEngine(int c) override;
+ void removeEngine(int c) override;
+ void processChannel(const ProcessArgs& args, int c) override;
+ void postProcess(const ProcessArgs& args) override;
- void processChannel(const ProcessArgs& args, int _c) override {
- _core->step();
- }
-
- bool shouldTriggerOnNextLoad() override {
- return _core->_stage != _core->STOPPED_STAGE;
- }
+ bool shouldTriggerOnNextLoad() override;
};
} // namespace bogaudio
diff --git a/src/DADSRHPlus.cpp b/src/DADSRHPlus.cpp
@@ -1,6 +1,112 @@
#include "DADSRHPlus.hpp"
+void DADSRHPlus::reset() {
+ for (int c = 0; c < maxChannels; ++c) {
+ if (_core[c]) {
+ _core[c]->reset();
+ }
+ }
+}
+
+int DADSRHPlus::channels() {
+ return inputs[TRIGGER_INPUT].getChannels();
+}
+
+void DADSRHPlus::addEngine(int c) {
+ _core[c] = new DADSRHCore(
+ params[DELAY_PARAM],
+ params[ATTACK_PARAM],
+ params[DECAY_PARAM],
+ params[SUSTAIN_PARAM],
+ params[RELEASE_PARAM],
+ params[HOLD_PARAM],
+ params[ATTACK_SHAPE_PARAM],
+ params[DECAY_SHAPE_PARAM],
+ params[RELEASE_SHAPE_PARAM],
+ params[TRIGGER_PARAM],
+ params[MODE_PARAM],
+ params[LOOP_PARAM],
+ params[SPEED_PARAM],
+ params[RETRIGGER_PARAM],
+
+ &inputs[DELAY_INPUT],
+ &inputs[ATTACK_INPUT],
+ &inputs[DECAY_INPUT],
+ &inputs[SUSTAIN_INPUT],
+ &inputs[RELEASE_INPUT],
+ &inputs[HOLD_INPUT],
+ inputs[TRIGGER_INPUT],
+
+ &outputs[DELAY_OUTPUT],
+ &outputs[ATTACK_OUTPUT],
+ &outputs[DECAY_OUTPUT],
+ &outputs[SUSTAIN_OUTPUT],
+ &outputs[RELEASE_OUTPUT],
+ outputs[ENV_OUTPUT],
+ outputs[INV_OUTPUT],
+ outputs[TRIGGER_OUTPUT],
+
+ _delayLights,
+ _attackLights,
+ _decayLights,
+ _sustainLights,
+ _releaseLights,
+ lights[ATTACK_SHAPE1_LIGHT],
+ lights[ATTACK_SHAPE2_LIGHT],
+ lights[ATTACK_SHAPE3_LIGHT],
+ lights[DECAY_SHAPE1_LIGHT],
+ lights[DECAY_SHAPE2_LIGHT],
+ lights[DECAY_SHAPE3_LIGHT],
+ lights[RELEASE_SHAPE1_LIGHT],
+ lights[RELEASE_SHAPE2_LIGHT],
+ lights[RELEASE_SHAPE3_LIGHT],
+
+ _triggerOnLoad,
+ _shouldTriggerOnLoad
+ );
+}
+
+void DADSRHPlus::removeEngine(int c) {
+ delete _core[c];
+ _core[c] = NULL;
+}
+
+void DADSRHPlus::processChannel(const ProcessArgs& args, int c) {
+ _core[c]->step(c, _channels);
+}
+
+void DADSRHPlus::postProcess(const ProcessArgs& args) {
+ float delaySum = 0.0f;
+ float attackSum = 0.0f;
+ float decaySum = 0.0f;
+ float sustainSum = 0.0f;
+ float releaseSum = 0.0f;
+ for (int c = 0; c < maxChannels; ++c) {
+ if (_core[c]) {
+ delaySum += _delayLights[c];
+ attackSum += _attackLights[c];
+ decaySum += _decayLights[c];
+ sustainSum += _sustainLights[c];
+ releaseSum += _releaseLights[c];
+ }
+ }
+ lights[DELAY_LIGHT].value = delaySum / (float)_channels;
+ lights[ATTACK_LIGHT].value = attackSum / (float)_channels;
+ lights[DECAY_LIGHT].value = decaySum / (float)_channels;
+ lights[SUSTAIN_LIGHT].value = sustainSum / (float)_channels;
+ lights[RELEASE_LIGHT].value = releaseSum / (float)_channels;
+}
+
+bool DADSRHPlus::shouldTriggerOnNextLoad() {
+ for (int c = 0; c < maxChannels; ++c) {
+ if (_core[c] && _core[c]->_stage != _core[c]->STOPPED_STAGE) {
+ return true;
+ }
+ }
+ return false;
+}
+
struct DADSRHPlusWidget : TriggerOnLoadModuleWidget {
static constexpr int hp = 15;
diff --git a/src/DADSRHPlus.hpp b/src/DADSRHPlus.hpp
@@ -68,7 +68,12 @@ struct DADSRHPlus : TriggerOnLoadModule {
NUM_LIGHTS
};
- DADSRHCore* _core;
+ DADSRHCore* _core[maxChannels] {};
+ float _delayLights[maxChannels] {};
+ float _attackLights[maxChannels] {};
+ float _decayLights[maxChannels] {};
+ float _sustainLights[maxChannels] {};
+ float _releaseLights[maxChannels] {};
DADSRHPlus() {
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
@@ -86,75 +91,16 @@ struct DADSRHPlus : TriggerOnLoadModule {
configParam(LOOP_PARAM, 0.0f, 1.0f, 1.0f, "Loop");
configParam(SPEED_PARAM, 0.0f, 1.0f, 1.0f, "Speed");
configParam(RETRIGGER_PARAM, 0.0f, 1.0f, 1.0f, "Retrigger");
-
- _core = new DADSRHCore(
- params[DELAY_PARAM],
- params[ATTACK_PARAM],
- params[DECAY_PARAM],
- params[SUSTAIN_PARAM],
- params[RELEASE_PARAM],
- params[HOLD_PARAM],
- params[ATTACK_SHAPE_PARAM],
- params[DECAY_SHAPE_PARAM],
- params[RELEASE_SHAPE_PARAM],
- params[TRIGGER_PARAM],
- params[MODE_PARAM],
- params[LOOP_PARAM],
- params[SPEED_PARAM],
- params[RETRIGGER_PARAM],
-
- &inputs[DELAY_INPUT],
- &inputs[ATTACK_INPUT],
- &inputs[DECAY_INPUT],
- &inputs[SUSTAIN_INPUT],
- &inputs[RELEASE_INPUT],
- &inputs[HOLD_INPUT],
- inputs[TRIGGER_INPUT],
-
- &outputs[DELAY_OUTPUT],
- &outputs[ATTACK_OUTPUT],
- &outputs[DECAY_OUTPUT],
- &outputs[SUSTAIN_OUTPUT],
- &outputs[RELEASE_OUTPUT],
- outputs[ENV_OUTPUT],
- outputs[INV_OUTPUT],
- outputs[TRIGGER_OUTPUT],
-
- lights[DELAY_LIGHT],
- lights[ATTACK_LIGHT],
- lights[DECAY_LIGHT],
- lights[SUSTAIN_LIGHT],
- lights[RELEASE_LIGHT],
- lights[ATTACK_SHAPE1_LIGHT],
- lights[ATTACK_SHAPE2_LIGHT],
- lights[ATTACK_SHAPE3_LIGHT],
- lights[DECAY_SHAPE1_LIGHT],
- lights[DECAY_SHAPE2_LIGHT],
- lights[DECAY_SHAPE3_LIGHT],
- lights[RELEASE_SHAPE1_LIGHT],
- lights[RELEASE_SHAPE2_LIGHT],
- lights[RELEASE_SHAPE3_LIGHT],
-
- _triggerOnLoad,
- _shouldTriggerOnLoad
- );
- reset();
- }
- virtual ~DADSRHPlus() {
- delete _core;
}
- void reset() override {
- _core->reset();
- }
+ void reset() override;
+ int channels() override;
+ void addEngine(int c) override;
+ void removeEngine(int c) override;
+ void processChannel(const ProcessArgs& args, int c) override;
+ void postProcess(const ProcessArgs& args) override;
- void processChannel(const ProcessArgs& args, int _c) override {
- _core->step();
- }
-
- bool shouldTriggerOnNextLoad() override {
- return _core->_stage != _core->STOPPED_STAGE;
- }
+ bool shouldTriggerOnNextLoad() override;
};
} // namespace bogaudio
diff --git a/src/DGate.cpp b/src/DGate.cpp
@@ -1,44 +1,68 @@
#include "DGate.hpp"
+void DGate::Engine::reset() {
+ trigger.reset();
+ triggerOuptutPulseGen.process(10.0);
+ stage = STOPPED_STAGE;
+ stageProgress = 0.0;
+ delayLight = 0.0;
+ gateLight = 0.0;
+}
+
void DGate::reset() {
- _trigger.reset();
- _triggerOuptutPulseGen.process(10.0);
- _stage = STOPPED_STAGE;
- _stageProgress = 0.0;
+ for (int c = 0; c < maxChannels; ++c) {
+ if (_engines[c]) {
+ _engines[c]->reset();
+ }
+ }
+}
+
+int DGate::channels() {
+ return inputs[TRIGGER_INPUT].getChannels();
+}
+
+void DGate::addEngine(int c) {
+ _engines[c] = new Engine();
+ _engines[c]->reset();
+}
+
+void DGate::removeEngine(int c) {
+ delete _engines[c];
+ _engines[c] = NULL;
}
-void DGate::processChannel(const ProcessArgs& args, int _c) {
+void DGate::processChannel(const ProcessArgs& args, int c) {
float envelope = 0.0;
bool complete = false;
if (
- _trigger.process(params[TRIGGER_PARAM].getValue() + inputs[TRIGGER_INPUT].getVoltage()) ||
- (_firstStep && _triggerOnLoad && _shouldTriggerOnLoad && params[LOOP_PARAM].getValue() <= 0.0)
+ _engines[c]->trigger.process(params[TRIGGER_PARAM].getValue() + inputs[TRIGGER_INPUT].getPolyVoltage(c)) ||
+ (_engines[c]->firstStep && _triggerOnLoad && _shouldTriggerOnLoad && params[LOOP_PARAM].getValue() <= 0.0)
) {
- _stage = DELAY_STAGE;
- _stageProgress = 0.0;
+ _engines[c]->stage = DELAY_STAGE;
+ _engines[c]->stageProgress = 0.0;
}
else {
- switch (_stage) {
+ switch (_engines[c]->stage) {
case STOPPED_STAGE: {
break;
}
case DELAY_STAGE: {
- if (stepStage(params[DELAY_PARAM])) {
- _stage = GATE_STAGE;
- _stageProgress = 0.0;
+ if (stepStage(c, params[DELAY_PARAM])) {
+ _engines[c]->stage = GATE_STAGE;
+ _engines[c]->stageProgress = 0.0;
}
break;
}
case GATE_STAGE: {
- if (stepStage(params[GATE_PARAM])) {
+ if (stepStage(c, params[GATE_PARAM])) {
complete = true;
- if (params[LOOP_PARAM].getValue() <= 0.0 || _trigger.isHigh()) {
- _stage = DELAY_STAGE;
- _stageProgress = 0.0;
+ if (params[LOOP_PARAM].getValue() <= 0.0 || _engines[c]->trigger.isHigh()) {
+ _engines[c]->stage = DELAY_STAGE;
+ _engines[c]->stageProgress = 0.0;
}
else {
- _stage = STOPPED_STAGE;
+ _engines[c]->stage = STOPPED_STAGE;
}
}
else {
@@ -49,26 +73,50 @@ void DGate::processChannel(const ProcessArgs& args, int _c) {
}
}
- outputs[GATE_OUTPUT].setVoltage(envelope * 10.0);
+ outputs[GATE_OUTPUT].setChannels(_channels);
+ outputs[GATE_OUTPUT].setVoltage(envelope * 10.0, c);
if (complete) {
- _triggerOuptutPulseGen.trigger(0.001);
+ _engines[c]->triggerOuptutPulseGen.trigger(0.001);
}
- outputs[END_OUTPUT].setVoltage(_triggerOuptutPulseGen.process(APP->engine->getSampleTime()) ? 5.0 : 0.0);
+ outputs[END_OUTPUT].setChannels(_channels);
+ outputs[END_OUTPUT].setVoltage(_engines[c]->triggerOuptutPulseGen.process(APP->engine->getSampleTime()) ? 5.0 : 0.0, c);
+
+ _engines[c]->delayLight = _engines[c]->stage == DELAY_STAGE;
+ _engines[c]->gateLight = _engines[c]->stage == GATE_STAGE;
- lights[DELAY_LIGHT].value = _stage == DELAY_STAGE;
- lights[GATE_LIGHT].value = _stage == GATE_STAGE;
+ _engines[c]->firstStep = false;
+}
- _firstStep = false;
+void DGate::postProcess(const ProcessArgs& args) {
+ float delaySum = 0.0f;
+ float gateSum = 0.0f;
+ for (int c = 0; c < maxChannels; ++c) {
+ if (_engines[c]) {
+ delaySum += _engines[c]->delayLight;
+ gateSum += _engines[c]->gateLight;
+ }
+ }
+ lights[DELAY_LIGHT].value = delaySum / (float)_channels;
+ lights[GATE_LIGHT].value = gateSum / (float)_channels;
}
-bool DGate::stepStage(Param& knob) {
+bool DGate::stepStage(int c, Param& knob) {
float t = knob.getValue();
t = pow(t, 2);
t *= 10.0;
- _stageProgress += APP->engine->getSampleTime();
- return _stageProgress > t;
+ _engines[c]->stageProgress += APP->engine->getSampleTime();
+ return _engines[c]->stageProgress > t;
}
+bool DGate::shouldTriggerOnNextLoad() {
+ for (int c = 0; c < maxChannels; ++c) {
+ if (_engines[c] && _engines[c]->stage != STOPPED_STAGE) {
+ return true;
+ }
+ }
+ return false;
+};
+
struct DGateWidget : TriggerOnLoadModuleWidget {
static constexpr int hp = 3;
diff --git a/src/DGate.hpp b/src/DGate.hpp
@@ -39,11 +39,19 @@ struct DGate : TriggerOnLoadModule {
GATE_STAGE
};
- bool _firstStep = true;
- Trigger _trigger;
- rack::dsp::PulseGenerator _triggerOuptutPulseGen;
- Stage _stage;
- float _stageProgress;
+ struct Engine {
+ bool firstStep = true;
+ Trigger trigger;
+ rack::dsp::PulseGenerator triggerOuptutPulseGen;
+ Stage stage;
+ float stageProgress;
+ float delayLight;
+ float gateLight;
+
+ void reset();
+ };
+
+ Engine *_engines[maxChannels] {};
DGate() {
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
@@ -51,16 +59,16 @@ struct DGate : TriggerOnLoadModule {
configParam<EnvelopeSegmentParamQuantity>(GATE_PARAM, 0.0f, 1.0f, 0.31623f, "Gate", " s");
configParam(LOOP_PARAM, 0.0f, 1.0f, 1.0f, "Loop");
configParam(TRIGGER_PARAM, 0.0f, 1.0f, 0.0f, "Trigger");
-
- reset();
}
void reset() override;
- void processChannel(const ProcessArgs& args, int _c) override;
- bool stepStage(Param& knob);
- bool shouldTriggerOnNextLoad() override {
- return _stage != STOPPED_STAGE;
- };
+ int channels() override;
+ void addEngine(int c) override;
+ void removeEngine(int c) override;
+ void processChannel(const ProcessArgs& args, int c) override;
+ void postProcess(const ProcessArgs& args) override;
+ bool stepStage(int c, Param& knob);
+ bool shouldTriggerOnNextLoad() override;
};
} // namespace bogaudio
diff --git a/src/Shaper.cpp b/src/Shaper.cpp
@@ -1,6 +1,95 @@
#include "Shaper.hpp"
+void Shaper::reset() {
+ for (int c = 0; c < maxChannels; ++c) {
+ if (_core[c]) {
+ _core[c]->reset();
+ }
+ }
+}
+
+int Shaper::channels() {
+ return std::max(inputs[SIGNAL_INPUT].getChannels(), inputs[TRIGGER_INPUT].getChannels());
+}
+
+void Shaper::addEngine(int c) {
+ _core[c] = new ShaperCore(
+ params[ATTACK_PARAM],
+ params[ON_PARAM],
+ params[DECAY_PARAM],
+ params[OFF_PARAM],
+ params[ENV_PARAM],
+ params[SIGNAL_PARAM],
+ params[TRIGGER_PARAM],
+ params[SPEED_PARAM],
+ params[LOOP_PARAM],
+
+ inputs[SIGNAL_INPUT],
+ inputs[TRIGGER_INPUT],
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+
+ outputs[SIGNAL_OUTPUT],
+ outputs[ENV_OUTPUT],
+ outputs[INV_OUTPUT],
+ outputs[TRIGGER_OUTPUT],
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+
+ _attackLights,
+ _onLights,
+ _decayLights,
+ _offLights,
+
+ _triggerOnLoad,
+ _shouldTriggerOnLoad
+ );
+}
+
+void Shaper::removeEngine(int c) {
+ delete _core[c];
+ _core[c] = NULL;
+}
+
+void Shaper::processChannel(const ProcessArgs& args, int c) {
+ _core[c]->step(c, _channels);
+}
+
+void Shaper::postProcess(const ProcessArgs& args) {
+ float attackSum = 0.0f;
+ float onSum = 0.0f;
+ float decaySum = 0.0f;
+ float offSum = 0.0f;
+ for (int c = 0; c < maxChannels; ++c) {
+ if (_core[c]) {
+ attackSum += _attackLights[c];
+ onSum += _onLights[c];
+ decaySum += _decayLights[c];
+ offSum += _offLights[c];
+ }
+ }
+ lights[ATTACK_LIGHT].value = attackSum / (float)_channels;
+ lights[ON_LIGHT].value = onSum / (float)_channels;
+ lights[DECAY_LIGHT].value = decaySum / (float)_channels;
+ lights[OFF_LIGHT].value = offSum / (float)_channels;
+}
+
+bool Shaper::shouldTriggerOnNextLoad() {
+ for (int c = 0; c < maxChannels; ++c) {
+ if (_core[c] && _core[c]->_stage != _core[c]->STOPPED_STAGE) {
+ return true;
+ }
+ }
+ return false;
+}
+
struct ShaperWidget : TriggerOnLoadModuleWidget {
static constexpr int hp = 10;
diff --git a/src/Shaper.hpp b/src/Shaper.hpp
@@ -44,7 +44,11 @@ struct Shaper : TriggerOnLoadModule {
NUM_LIGHTS
};
- ShaperCore* _core;
+ ShaperCore* _core[maxChannels] {};
+ float _attackLights[maxChannels] {};
+ float _onLights[maxChannels] {};
+ float _decayLights[maxChannels] {};
+ float _offLights[maxChannels] {};
Shaper() {
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
@@ -57,61 +61,16 @@ struct Shaper : TriggerOnLoadModule {
configParam(TRIGGER_PARAM, 0.0f, 1.0f, 0.0f, "Trigger");
configParam(SPEED_PARAM, 0.0f, 1.0f, 1.0f, "Speed");
configParam(LOOP_PARAM, 0.0f, 1.0f, 1.0f, "Loop");
-
- _core = new ShaperCore(
- params[ATTACK_PARAM],
- params[ON_PARAM],
- params[DECAY_PARAM],
- params[OFF_PARAM],
- params[ENV_PARAM],
- params[SIGNAL_PARAM],
- params[TRIGGER_PARAM],
- params[SPEED_PARAM],
- params[LOOP_PARAM],
-
- inputs[SIGNAL_INPUT],
- inputs[TRIGGER_INPUT],
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
-
- outputs[SIGNAL_OUTPUT],
- outputs[ENV_OUTPUT],
- outputs[INV_OUTPUT],
- outputs[TRIGGER_OUTPUT],
- NULL,
- NULL,
- NULL,
- NULL,
-
- lights[ATTACK_LIGHT],
- lights[ON_LIGHT],
- lights[DECAY_LIGHT],
- lights[OFF_LIGHT],
-
- _triggerOnLoad,
- _shouldTriggerOnLoad
- );
- reset();
- }
- virtual ~Shaper() {
- delete _core;
}
- void reset() override {
- _core->reset();
- }
+ void reset() override;
+ int channels() override;
+ void addEngine(int c) override;
+ void removeEngine(int c) override;
+ void processChannel(const ProcessArgs& args, int c) override;
+ void postProcess(const ProcessArgs& args) override;
- void processChannel(const ProcessArgs& args, int _c) override {
- _core->step();
- }
-
- bool shouldTriggerOnNextLoad() override {
- return _core->_stage != _core->STOPPED_STAGE;
- }
+ bool shouldTriggerOnNextLoad() override;
};
} // namespace bogaudio
diff --git a/src/ShaperPlus.cpp b/src/ShaperPlus.cpp
@@ -1,6 +1,95 @@
#include "ShaperPlus.hpp"
+void ShaperPlus::reset() {
+ for (int c = 0; c < maxChannels; ++c) {
+ if (_core[c]) {
+ _core[c]->reset();
+ }
+ }
+}
+
+int ShaperPlus::channels() {
+ return std::max(inputs[SIGNAL_INPUT].getChannels(), inputs[TRIGGER_INPUT].getChannels());
+}
+
+void ShaperPlus::addEngine(int c) {
+ _core[c] = new ShaperCore(
+ params[ATTACK_PARAM],
+ params[ON_PARAM],
+ params[DECAY_PARAM],
+ params[OFF_PARAM],
+ params[ENV_PARAM],
+ params[SIGNAL_PARAM],
+ params[TRIGGER_PARAM],
+ params[SPEED_PARAM],
+ params[LOOP_PARAM],
+
+ inputs[SIGNAL_INPUT],
+ inputs[TRIGGER_INPUT],
+ &inputs[ATTACK_INPUT],
+ &inputs[ON_INPUT],
+ &inputs[DECAY_INPUT],
+ &inputs[OFF_INPUT],
+ &inputs[ENV_INPUT],
+ &inputs[SIGNALCV_INPUT],
+
+ outputs[SIGNAL_OUTPUT],
+ outputs[ENV_OUTPUT],
+ outputs[INV_OUTPUT],
+ outputs[TRIGGER_OUTPUT],
+ &outputs[ATTACK_OUTPUT],
+ &outputs[ON_OUTPUT],
+ &outputs[DECAY_OUTPUT],
+ &outputs[OFF_OUTPUT],
+
+ _attackLights,
+ _onLights,
+ _decayLights,
+ _offLights,
+
+ _triggerOnLoad,
+ _shouldTriggerOnLoad
+ );
+}
+
+void ShaperPlus::removeEngine(int c) {
+ delete _core[c];
+ _core[c] = NULL;
+}
+
+void ShaperPlus::processChannel(const ProcessArgs& args, int c) {
+ _core[c]->step(c, _channels);
+}
+
+void ShaperPlus::postProcess(const ProcessArgs& args) {
+ float attackSum = 0.0f;
+ float onSum = 0.0f;
+ float decaySum = 0.0f;
+ float offSum = 0.0f;
+ for (int c = 0; c < maxChannels; ++c) {
+ if (_core[c]) {
+ attackSum += _attackLights[c];
+ onSum += _onLights[c];
+ decaySum += _decayLights[c];
+ offSum += _offLights[c];
+ }
+ }
+ lights[ATTACK_LIGHT].value = attackSum / (float)_channels;
+ lights[ON_LIGHT].value = onSum / (float)_channels;
+ lights[DECAY_LIGHT].value = decaySum / (float)_channels;
+ lights[OFF_LIGHT].value = offSum / (float)_channels;
+}
+
+bool ShaperPlus::shouldTriggerOnNextLoad() {
+ for (int c = 0; c < maxChannels; ++c) {
+ if (_core[c] && _core[c]->_stage != _core[c]->STOPPED_STAGE) {
+ return true;
+ }
+ }
+ return false;
+}
+
struct ShaperPlusWidget : TriggerOnLoadModuleWidget {
static constexpr int hp = 15;
diff --git a/src/ShaperPlus.hpp b/src/ShaperPlus.hpp
@@ -21,6 +21,7 @@ struct ShaperPlus : TriggerOnLoadModule {
LOOP_PARAM,
NUM_PARAMS
};
+
enum InputIds {
SIGNAL_INPUT,
TRIGGER_INPUT,
@@ -32,6 +33,7 @@ struct ShaperPlus : TriggerOnLoadModule {
SIGNALCV_INPUT,
NUM_INPUTS
};
+
enum OutputIds {
SIGNAL_OUTPUT,
ENV_OUTPUT,
@@ -43,6 +45,7 @@ struct ShaperPlus : TriggerOnLoadModule {
OFF_OUTPUT,
NUM_OUTPUTS
};
+
enum LightIds {
ATTACK_LIGHT,
ON_LIGHT,
@@ -51,7 +54,11 @@ struct ShaperPlus : TriggerOnLoadModule {
NUM_LIGHTS
};
- ShaperCore* _core;
+ ShaperCore* _core[maxChannels] {};
+ float _attackLights[maxChannels] {};
+ float _onLights[maxChannels] {};
+ float _decayLights[maxChannels] {};
+ float _offLights[maxChannels] {};
ShaperPlus() {
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
@@ -64,61 +71,16 @@ struct ShaperPlus : TriggerOnLoadModule {
configParam(TRIGGER_PARAM, 0.0f, 1.0f, 0.0f, "Trigger");
configParam(SPEED_PARAM, 0.0f, 1.0f, 1.0f, "Speed");
configParam(LOOP_PARAM, 0.0f, 1.0f, 1.0f, "Loop");
-
- _core = new ShaperCore(
- params[ATTACK_PARAM],
- params[ON_PARAM],
- params[DECAY_PARAM],
- params[OFF_PARAM],
- params[ENV_PARAM],
- params[SIGNAL_PARAM],
- params[TRIGGER_PARAM],
- params[SPEED_PARAM],
- params[LOOP_PARAM],
-
- inputs[SIGNAL_INPUT],
- inputs[TRIGGER_INPUT],
- &inputs[ATTACK_INPUT],
- &inputs[ON_INPUT],
- &inputs[DECAY_INPUT],
- &inputs[OFF_INPUT],
- &inputs[ENV_INPUT],
- &inputs[SIGNALCV_INPUT],
-
- outputs[SIGNAL_OUTPUT],
- outputs[ENV_OUTPUT],
- outputs[INV_OUTPUT],
- outputs[TRIGGER_OUTPUT],
- &outputs[ATTACK_OUTPUT],
- &outputs[ON_OUTPUT],
- &outputs[DECAY_OUTPUT],
- &outputs[OFF_OUTPUT],
-
- lights[ATTACK_LIGHT],
- lights[ON_LIGHT],
- lights[DECAY_LIGHT],
- lights[OFF_LIGHT],
-
- _triggerOnLoad,
- _shouldTriggerOnLoad
- );
- reset();
- }
- virtual ~ShaperPlus() {
- delete _core;
- }
-
- void reset() override {
- _core->reset();
}
- void processChannel(const ProcessArgs& args, int _c) override {
- _core->step();
- }
+ void reset() override;
+ int channels() override;
+ void addEngine(int c) override;
+ void removeEngine(int c) override;
+ void processChannel(const ProcessArgs& args, int c) override;
+ void postProcess(const ProcessArgs& args) override;
- bool shouldTriggerOnNextLoad() override {
- return _core->_stage != _core->STOPPED_STAGE;
- }
+ bool shouldTriggerOnNextLoad() override;
};
} // namespace bogaudio
diff --git a/src/dadsrh_core.cpp b/src/dadsrh_core.cpp
@@ -8,7 +8,7 @@ void DADSRHCore::reset() {
_releaseLevel = _holdProgress = _stageProgress = _envelope = 0.0;
}
-void DADSRHCore::step() {
+void DADSRHCore::step(int c, int channels) {
const int SHAPE1 = 1;
const int SHAPE2 = 2;
const int SHAPE3 = 3;
@@ -17,7 +17,7 @@ void DADSRHCore::step() {
bool slow = _speedParam.getValue() <= 0.5;
if (
- _trigger.process(_triggerParam.getValue() + _triggerInput.getVoltage()) ||
+ _trigger.process(_triggerParam.getValue() + _triggerInput.getPolyVoltage(c)) ||
(_firstStep && _triggerOnLoad && _shouldTriggerOnLoad && _loopParam.getValue() < 0.5 && _modeParam.getValue() < 0.5)
) {
if (_stage == STOPPED_STAGE || _retriggerParam.getValue() <= 0.5) {
@@ -36,8 +36,8 @@ void DADSRHCore::step() {
_stageProgress = _envelope = 0.0;
// we're skipping the delay; subtract the full delay time from hold time so that env has the same shape as if we'd waited out the delay.
- float delayTime = knobTime(_delayParam, _delayInput, slow, true);
- float holdTime = knobTime(_holdParam, _holdInput, slow);
+ float delayTime = knobTime(c, _delayParam, _delayInput, slow, true);
+ float holdTime = knobTime(c, _holdParam, _holdInput, slow);
_holdProgress = fminf(1.0, delayTime / holdTime);
break;
}
@@ -62,9 +62,9 @@ void DADSRHCore::step() {
}
// reset hold to what it would have been at this point in the attack the first time through.
- float delayTime = knobTime(_delayParam, _delayInput, slow, true);
- float attackTime = knobTime(_attackParam, _attackInput, slow);
- float holdTime = knobTime(_holdParam, _holdInput, slow);
+ float delayTime = knobTime(c, _delayParam, _delayInput, slow, true);
+ float attackTime = knobTime(c, _attackParam, _attackInput, slow);
+ float holdTime = knobTime(c, _holdParam, _holdInput, slow);
_holdProgress = fminf(1.0, (delayTime + _stageProgress * attackTime) / holdTime);
break;
}
@@ -86,7 +86,7 @@ void DADSRHCore::step() {
bool holdComplete = _holdProgress >= 1.0;
if (!holdComplete) {
// run the hold accumulation even if we're not in hold mode, in case we switch mid-cycle.
- _holdProgress += stepAmount(_holdParam, _holdInput, slow);
+ _holdProgress += stepAmount(c, _holdParam, _holdInput, slow);
holdComplete = _holdProgress >= 1.0;
}
@@ -107,7 +107,7 @@ void DADSRHCore::step() {
}
case DELAY_STAGE: {
- _stageProgress += stepAmount(_delayParam, _delayInput, slow, true);
+ _stageProgress += stepAmount(c, _delayParam, _delayInput, slow, true);
if (_stageProgress >= 1.0) {
_stage = ATTACK_STAGE;
_stageProgress = 0.0;
@@ -116,7 +116,7 @@ void DADSRHCore::step() {
}
case ATTACK_STAGE: {
- _stageProgress += stepAmount(_attackParam, _attackInput, slow);
+ _stageProgress += stepAmount(c, _attackParam, _attackInput, slow);
switch ((int)_attackShapeParam.getValue()) {
case SHAPE2: {
_envelope = _stageProgress;
@@ -139,8 +139,8 @@ void DADSRHCore::step() {
}
case DECAY_STAGE: {
- float sustainLevel = knobAmount(_sustainParam, _sustainInput);
- _stageProgress += stepAmount(_decayParam, _decayInput, slow);
+ float sustainLevel = knobAmount(c, _sustainParam, _sustainInput);
+ _stageProgress += stepAmount(c, _decayParam, _decayInput, slow);
switch ((int)_decayShapeParam.getValue()) {
case SHAPE2: {
_envelope = 1.0 - _stageProgress;
@@ -164,12 +164,12 @@ void DADSRHCore::step() {
}
case SUSTAIN_STAGE: {
- _envelope = knobAmount(_sustainParam, _sustainInput);
+ _envelope = knobAmount(c, _sustainParam, _sustainInput);
break;
}
case RELEASE_STAGE: {
- _stageProgress += stepAmount(_releaseParam, _releaseInput, slow);
+ _stageProgress += stepAmount(c, _releaseParam, _releaseInput, slow);
switch ((int)_releaseShapeParam.getValue()) {
case SHAPE2: {
_envelope = 1.0 - _stageProgress;
@@ -201,35 +201,43 @@ void DADSRHCore::step() {
}
float env = _envelope * 10.0;
- _envOutput.setVoltage(env);
- _invOutput.setVoltage(10.0 - env);
+ _envOutput.setChannels(channels);
+ _envOutput.setVoltage(env, c);
+ _invOutput.setChannels(channels);
+ _invOutput.setVoltage(10.0 - env, c);
if (complete) {
_triggerOuptutPulseGen.trigger(0.001);
}
- _triggerOutput.setVoltage(_triggerOuptutPulseGen.process(APP->engine->getSampleTime()) ? 5.0 : 0.0);
+ _triggerOutput.setChannels(channels);
+ _triggerOutput.setVoltage(_triggerOuptutPulseGen.process(APP->engine->getSampleTime()) ? 5.0 : 0.0, c);
if (_delayOutput) {
- _delayOutput->value = _stage == DELAY_STAGE ? 5.0 : 0.0;
+ _delayOutput->setChannels(channels);
+ _delayOutput->setVoltage(_stage == DELAY_STAGE ? 5.0 : 0.0, c);
}
if (_attackOutput) {
- _attackOutput->value = _stage == ATTACK_STAGE ? 5.0 : 0.0;
+ _attackOutput->setChannels(channels);
+ _attackOutput->setVoltage(_stage == ATTACK_STAGE ? 5.0 : 0.0, c);
}
if (_decayOutput) {
- _decayOutput->value = _stage == DECAY_STAGE ? 5.0 : 0.0;
+ _decayOutput->setChannels(channels);
+ _decayOutput->setVoltage(_stage == DECAY_STAGE ? 5.0 : 0.0, c);
}
if (_sustainOutput) {
- _sustainOutput->value = _stage == SUSTAIN_STAGE ? 5.0 : 0.0;
+ _sustainOutput->setChannels(channels);
+ _sustainOutput->setVoltage(_stage == SUSTAIN_STAGE ? 5.0 : 0.0, c);
}
if (_releaseOutput) {
- _releaseOutput->value = _stage == RELEASE_STAGE ? 5.0 : 0.0;
+ _releaseOutput->setChannels(channels);
+ _releaseOutput->setVoltage(_stage == RELEASE_STAGE ? 5.0 : 0.0, c);
}
- _delayLight.value = _stage == DELAY_STAGE;
- _attackLight.value = _stage == ATTACK_STAGE;
- _decayLight.value = _stage == DECAY_STAGE;
- _sustainLight.value = _stage == SUSTAIN_STAGE;
- _releaseLight.value = _stage == RELEASE_STAGE;
+ _delayLights[c] = _stage == DELAY_STAGE;
+ _attackLights[c] = _stage == ATTACK_STAGE;
+ _decayLights[c] = _stage == DECAY_STAGE;
+ _sustainLights[c] = _stage == SUSTAIN_STAGE;
+ _releaseLights[c] = _stage == RELEASE_STAGE;
_attackShape1Light.value = (int)_attackShapeParam.value == SHAPE1;
_attackShape2Light.value = (int)_attackShapeParam.value == SHAPE2;
@@ -244,21 +252,21 @@ void DADSRHCore::step() {
_firstStep = false;
}
-float DADSRHCore::stepAmount(Param& knob, Input* cv, bool slow, bool allowZero) {
- return APP->engine->getSampleTime() / knobTime(knob, cv, slow, allowZero);
+float DADSRHCore::stepAmount(int c, Param& knob, Input* cv, bool slow, bool allowZero) {
+ return APP->engine->getSampleTime() / knobTime(c, knob, cv, slow, allowZero);
}
-float DADSRHCore::knobTime(Param& knob, Input* cv, bool slow, bool allowZero) {
- float t = knobAmount(knob, cv);
+float DADSRHCore::knobTime(int c, Param& knob, Input* cv, bool slow, bool allowZero) {
+ float t = knobAmount(c, knob, cv);
t = pow(t, 2.0);
t = fmaxf(t, allowZero ? 0.0 : 0.001);
return t * (slow ? 100.0 : 10.0);
}
-float DADSRHCore::knobAmount(Param& knob, Input* cv) const {
+float DADSRHCore::knobAmount(int c, Param& knob, Input* cv) const {
float v = clamp(knob.getValue(), 0.0f, 1.0f);
if (cv && cv->isConnected()) {
- v *= clamp(cv->getVoltage() / 10.0f, 0.0f, 1.0f);
+ v *= clamp(cv->getPolyVoltage(c) / 10.0f, 0.0f, 1.0f);
}
return v;
}
diff --git a/src/dadsrh_core.hpp b/src/dadsrh_core.hpp
@@ -46,11 +46,11 @@ struct DADSRHCore {
Output& _invOutput;
Output& _triggerOutput;
- Light& _delayLight;
- Light& _attackLight;
- Light& _decayLight;
- Light& _sustainLight;
- Light& _releaseLight;
+ float* _delayLights;
+ float* _attackLights;
+ float* _decayLights;
+ float* _sustainLights;
+ float* _releaseLights;
Light& _attackShape1Light;
Light& _attackShape2Light;
Light& _attackShape3Light;
@@ -102,11 +102,11 @@ struct DADSRHCore {
Output& invOutput,
Output& triggerOutput,
- Light& delayLight,
- Light& attackLight,
- Light& decayLight,
- Light& sustainLight,
- Light& releaseLight,
+ float* delayLights,
+ float* attackLights,
+ float* decayLights,
+ float* sustainLights,
+ float* releaseLights,
Light& attackShape1Light,
Light& attackShape2Light,
Light& attackShape3Light,
@@ -151,11 +151,11 @@ struct DADSRHCore {
, _invOutput(invOutput)
, _triggerOutput(triggerOutput)
- , _delayLight(delayLight)
- , _attackLight(attackLight)
- , _decayLight(decayLight)
- , _sustainLight(sustainLight)
- , _releaseLight(releaseLight)
+ , _delayLights(delayLights)
+ , _attackLights(attackLights)
+ , _decayLights(decayLights)
+ , _sustainLights(sustainLights)
+ , _releaseLights(releaseLights)
, _attackShape1Light(attackShape1Light)
, _attackShape2Light(attackShape2Light)
, _attackShape3Light(attackShape3Light)
@@ -173,11 +173,11 @@ struct DADSRHCore {
}
void reset();
- void step();
+ void step(int c, int channels);
- float stepAmount(Param& knob, Input* cv, bool slow, bool allowZero = false);
- float knobTime(Param& knob, Input* cv, bool slow, bool allowZero = false);
- float knobAmount(Param& knob, Input* cv) const;
+ float stepAmount(int c, Param& knob, Input* cv, bool slow, bool allowZero = false);
+ float knobTime(int c, Param& knob, Input* cv, bool slow, bool allowZero = false);
+ float knobAmount(int c, Param& knob, Input* cv) const;
};
} // namespace bogaudio
diff --git a/src/shaper_core.cpp b/src/shaper_core.cpp
@@ -8,11 +8,11 @@ void ShaperCore::reset() {
_stageProgress = 0.0;
}
-void ShaperCore::step() {
+void ShaperCore::step(int c, int channels) {
bool complete = false;
bool slow = _speedParam.getValue() <= 0.0;
if (
- _trigger.process(_triggerParam.getValue() + _triggerInput.getVoltage()) ||
+ _trigger.process(_triggerParam.getValue() + _triggerInput.getPolyVoltage(c)) ||
(_firstStep && _triggerOnLoad && _shouldTriggerOnLoad && _loopParam.getValue() <= 0.0)
) {
_stage = ATTACK_STAGE;
@@ -24,28 +24,28 @@ void ShaperCore::step() {
break;
}
case ATTACK_STAGE: {
- if (stepStage(_attackParam, _attackInput, slow)) {
+ if (stepStage(_attackParam, _attackInput, slow, c)) {
_stage = ON_STAGE;
_stageProgress = 0.0;
}
break;
}
case ON_STAGE: {
- if (stepStage(_onParam, _onInput, slow)) {
+ if (stepStage(_onParam, _onInput, slow, c)) {
_stage = DECAY_STAGE;
_stageProgress = 0.0;
}
break;
}
case DECAY_STAGE: {
- if (stepStage(_decayParam, _decayInput, slow)) {
+ if (stepStage(_decayParam, _decayInput, slow, c)) {
_stage = OFF_STAGE;
_stageProgress = 0.0;
}
break;
}
case OFF_STAGE: {
- if (stepStage(_offParam, _offInput, slow)) {
+ if (stepStage(_offParam, _offInput, slow, c)) {
complete = true;
if (_loopParam.getValue() <= 0.0 || _trigger.isHigh()) {
_stage = ATTACK_STAGE;
@@ -82,42 +82,50 @@ void ShaperCore::step() {
}
}
- float signalLevel = levelParam(_signalParam, _signalCVInput);
- _signalOutput.setVoltage(signalLevel * envelope * _signalInput.getVoltageSum());
+ float signalLevel = levelParam(_signalParam, _signalCVInput, c);
+ _signalOutput.setChannels(channels);
+ _signalOutput.setVoltage(signalLevel * envelope * _signalInput.getPolyVoltage(c), c);
- float envLevel = levelParam(_envParam, _envInput);
+ float envLevel = levelParam(_envParam, _envInput, c);
float envOutput = clamp(envLevel * envelope, 0.0f, 10.0f);
- _envOutput.setVoltage(envOutput);
- _invOutput.setVoltage(10.0 - envOutput);
+ _envOutput.setChannels(channels);
+ _envOutput.setVoltage(envOutput, c);
+ _invOutput.setChannels(channels);
+ _invOutput.setVoltage(10.0 - envOutput, c);
if (complete) {
_triggerOuptutPulseGen.trigger(0.001);
}
- _triggerOutput.setVoltage(_triggerOuptutPulseGen.process(APP->engine->getSampleTime()) ? 5.0 : 0.0);
+ _triggerOutput.setChannels(channels);
+ _triggerOutput.setVoltage(_triggerOuptutPulseGen.process(APP->engine->getSampleTime()) ? 5.0 : 0.0, c);
if (_attackOutput) {
- _attackOutput->setVoltage(_stage == ATTACK_STAGE ? 5.0 : 0.0);
+ _attackOutput->setChannels(channels);
+ _attackOutput->setVoltage(_stage == ATTACK_STAGE ? 5.0 : 0.0, c);
}
if (_onOutput) {
- _onOutput->setVoltage(_stage == ON_STAGE ? 5.0 : 0.0);
+ _onOutput->setChannels(channels);
+ _onOutput->setVoltage(_stage == ON_STAGE ? 5.0 : 0.0, c);
}
if (_decayOutput) {
- _decayOutput->setVoltage(_stage == DECAY_STAGE ? 5.0 : 0.0);
+ _decayOutput->setChannels(channels);
+ _decayOutput->setVoltage(_stage == DECAY_STAGE ? 5.0 : 0.0, c);
}
if (_offOutput) {
- _offOutput->setVoltage(_stage == OFF_STAGE ? 5.0 : 0.0);
+ _offOutput->setChannels(channels);
+ _offOutput->setVoltage(_stage == OFF_STAGE ? 5.0 : 0.0, c);
}
- _attackLight.value = _stage == ATTACK_STAGE;
- _onLight.value = _stage == ON_STAGE;
- _decayLight.value = _stage == DECAY_STAGE;
- _offLight.value = _stage == OFF_STAGE;
+ _attackLights[c] = _stage == ATTACK_STAGE;
+ _onLights[c] = _stage == ON_STAGE;
+ _decayLights[c] = _stage == DECAY_STAGE;
+ _offLights[c] = _stage == OFF_STAGE;
_firstStep = false;
}
-bool ShaperCore::stepStage(Param& knob, Input* cv, bool slow) {
- float t = levelParam(knob, cv);
+bool ShaperCore::stepStage(Param& knob, Input* cv, bool slow, int c) {
+ float t = levelParam(knob, cv, c);
t = pow(t, 2);
t = fmaxf(t, 0.001);
t *= slow ? 100.0 : 10.0;
@@ -125,10 +133,10 @@ bool ShaperCore::stepStage(Param& knob, Input* cv, bool slow) {
return _stageProgress > 1.0;
}
-float ShaperCore::levelParam(Param& knob, Input* cv) const {
+float ShaperCore::levelParam(Param& knob, Input* cv, int c) const {
float v = clamp(knob.getValue(), 0.0f, 1.0f);
if (cv && cv->isConnected()) {
- v *= clamp(cv->getVoltage() / 10.0f, 0.0f, 1.0f);
+ v *= clamp(cv->getPolyVoltage(c) / 10.0f, 0.0f, 1.0f);
}
return v;
}
diff --git a/src/shaper_core.hpp b/src/shaper_core.hpp
@@ -41,10 +41,10 @@ struct ShaperCore {
Output* _decayOutput;
Output* _offOutput;
- Light& _attackLight;
- Light& _onLight;
- Light& _decayLight;
- Light& _offLight;
+ float* _attackLights;
+ float* _onLights;
+ float* _decayLights;
+ float* _offLights;
bool _firstStep = true;
bool& _triggerOnLoad;
@@ -83,10 +83,10 @@ struct ShaperCore {
Output* decayOutput,
Output* offOutput,
- Light& attackLight,
- Light& onLight,
- Light& decayLight,
- Light& offLight,
+ float* attackLights,
+ float* onLights,
+ float* decayLights,
+ float* offLights,
bool& triggerOnLoad,
bool& shouldTriggerOnLoad
@@ -118,10 +118,10 @@ struct ShaperCore {
, _decayOutput(decayOutput)
, _offOutput(offOutput)
- , _attackLight(attackLight)
- , _onLight(onLight)
- , _decayLight(decayLight)
- , _offLight(offLight)
+ , _attackLights(attackLights)
+ , _onLights(onLights)
+ , _decayLights(decayLights)
+ , _offLights(offLights)
, _triggerOnLoad(triggerOnLoad)
, _shouldTriggerOnLoad(shouldTriggerOnLoad)
@@ -130,10 +130,10 @@ struct ShaperCore {
}
void reset();
- void step();
+ void step(int c, int channels);
- bool stepStage(Param& knob, Input* cv, bool slow);
- float levelParam(Param& knob, Input* cv) const;
+ bool stepStage(Param& knob, Input* cv, bool slow, int c);
+ float levelParam(Param& knob, Input* cv, int c) const;
};
} // namespace bogaudio