commit 0b5dc72b3b7023b9301ac6d93b56969eea5d4e70
parent eeb52cc954fadb5bbfe4b24a9802835226d7af02
Author: Matt Demanett <matt@demanett.net>
Date: Mon, 13 Apr 2020 18:42:04 -0400
ADDR-SEQ, 8:1, 1:8, PGMR: add option where negative triggers will step backwards.
Diffstat:
3 files changed, 45 insertions(+), 2 deletions(-)
diff --git a/src/addressable_sequence.cpp b/src/addressable_sequence.cpp
@@ -4,12 +4,14 @@
#define POLY_INPUT "poly_input"
#define SELECT_ON_CLOCK "select_on_clock"
#define TRIGGERED_SELECT "triggered_select"
+#define REVERSE_ON_NEGATIVE_CLOCK "reverse_on_negative_clock"
void AddressableSequenceModule::reset() {
for (int i = 0; i < maxChannels; ++i) {
_step[i] = 0;
_select[i] = 0;
_clock[i].reset();
+ _negativeClock[i].reset();
_reset[i].reset();
_selectTrigger[i].reset();
}
@@ -27,6 +29,7 @@ json_t* AddressableSequenceModule::dataToJson() {
json_object_set_new(root, POLY_INPUT, json_integer(_polyInputID));
json_object_set_new(root, SELECT_ON_CLOCK, json_boolean(_selectOnClock));
json_object_set_new(root, TRIGGERED_SELECT, json_boolean(_triggeredSelect));
+ json_object_set_new(root, REVERSE_ON_NEGATIVE_CLOCK, json_boolean(_reverseOnNegativeClock));
return root;
}
@@ -45,6 +48,11 @@ void AddressableSequenceModule::dataFromJson(json_t* root) {
if (t) {
_triggeredSelect = json_is_true(t);
}
+
+ json_t* r = json_object_get(root, REVERSE_ON_NEGATIVE_CLOCK);
+ if (r) {
+ _reverseOnNegativeClock = json_is_true(r);
+ }
}
int AddressableSequenceModule::channels() {
@@ -72,14 +80,16 @@ int AddressableSequenceModule::nextStep(
}
}
bool timer = _timer[c].next();
- bool clock = _clock[c].process(clockInput.getPolyVoltage(c)) && !timer;
+ float clockVoltage = clockInput.getPolyVoltage(c);
+ bool clock = _clock[c].process(clockVoltage) && !timer;
+ bool negativeClock = _negativeClock[c].process(clockVoltage) && _reverseOnNegativeClock && !timer && !clock;
int steps = n;
if (stepsParam) {
steps = clamp(stepsParam->getValue(), 1.0f, (float)n);
}
int reverse = 1 - 2 * (directionParam.getValue() == 0.0f);
- _step[c] = (_step[c] + reverse * clock) % steps;
+ _step[c] = (_step[c] + reverse * clock + -reverse * negativeClock) % steps;
_step[c] += (_step[c] < 0) * steps;
_step[c] -= _step[c] * reset;
diff --git a/src/addressable_sequence.hpp b/src/addressable_sequence.hpp
@@ -12,6 +12,7 @@ struct AddressableSequenceModule : BGModule {
int _clockInputID = -1;
int _selectInputID = -1;
Trigger _clock[maxChannels];
+ NegativeTrigger _negativeClock[maxChannels];
Trigger _reset[maxChannels];
Trigger _selectTrigger[maxChannels];
bogaudio::dsp::Timer _timer[maxChannels];
@@ -19,6 +20,7 @@ struct AddressableSequenceModule : BGModule {
float _select[maxChannels] {};
bool _selectOnClock = false;
bool _triggeredSelect = false;
+ bool _reverseOnNegativeClock = false;
void setInputIDs(int clockInputID, int selectInputID) {
_polyInputID = clockInputID;
@@ -53,6 +55,8 @@ struct AddressableSequenceBaseModuleWidget : ModuleWidget {
p->addItem(OptionMenuItem("CLOCK input", [m]() { return m->_polyInputID == m->_clockInputID; }, [m]() { m->_polyInputID = m->_clockInputID; }));
p->addItem(OptionMenuItem("SELECT input", [m]() { return m->_polyInputID == m->_selectInputID; }, [m]() { m->_polyInputID = m->_selectInputID; }));
OptionsMenuItem::addToMenu(p, menu);
+
+ menu->addChild(new BoolOptionMenuItem("Reverse step on negative clock", [m]() { return &m->_reverseOnNegativeClock; }));
}
};
diff --git a/src/rack_overrides.hpp b/src/rack_overrides.hpp
@@ -12,6 +12,7 @@ struct Trigger : rack::dsp::SchmittTrigger {
: _highThreshold(highThreshold)
, _lowThreshold(lowThreshold)
{
+ assert(_highThreshold > _lowThreshold);
reset();
}
@@ -31,6 +32,34 @@ struct Trigger : rack::dsp::SchmittTrigger {
}
};
+struct NegativeTrigger : rack::dsp::SchmittTrigger {
+ float _highThreshold;
+ float _lowThreshold;
+
+ NegativeTrigger(float highThreshold = -1.0f, float lowThreshold = -0.1f)
+ : _highThreshold(highThreshold)
+ , _lowThreshold(lowThreshold)
+ {
+ assert(_highThreshold < _lowThreshold);
+ reset();
+ }
+
+ bool process(float in) {
+ if (state) {
+ if (in >= _lowThreshold) {
+ state = false;
+ }
+ }
+ else {
+ if (in <= _highThreshold) {
+ state = true;
+ return true;
+ }
+ }
+ return false;
+ }
+};
+
inline float getZoom() {
return APP->scene->rackScroll->zoomWidget->zoom;
}