addressable_sequence.cpp (5012B)
1 2 #include "addressable_sequence.hpp" 3 4 #define POLY_INPUT "poly_input" 5 #define SELECT_ON_CLOCK "select_on_clock" 6 #define TRIGGERED_SELECT "triggered_select" 7 #define REVERSE_ON_NEGATIVE_CLOCK "reverse_on_negative_clock" 8 #define WRAP_SELECT_AT_STEPS "wrap_select_at_steps" 9 10 void AddressableSequenceModule::setInputIDs(int clockInputID, int selectInputID) { 11 _polyInputID = clockInputID; 12 _clockInputID = clockInputID; 13 _selectInputID = selectInputID; 14 } 15 16 void AddressableSequenceModule::reset() { 17 for (int i = 0; i < maxChannels; ++i) { 18 _step[i] = 0; 19 _select[i] = 0; 20 _clock[i].reset(); 21 _negativeClock[i].reset(); 22 _reset[i].reset(); 23 _selectTrigger[i].reset(); 24 } 25 } 26 27 void AddressableSequenceModule::sampleRateChange() { 28 float sr = APP->engine->getSampleRate(); 29 for (int i = 0; i < maxChannels; ++i) { 30 _timer[i].setParams(sr, 0.001f); 31 } 32 } 33 34 json_t* AddressableSequenceModule::saveToJson(json_t* root) { 35 json_object_set_new(root, POLY_INPUT, json_integer(_polyInputID)); 36 json_object_set_new(root, SELECT_ON_CLOCK, json_boolean(_selectOnClock)); 37 json_object_set_new(root, TRIGGERED_SELECT, json_boolean(_triggeredSelect)); 38 json_object_set_new(root, REVERSE_ON_NEGATIVE_CLOCK, json_boolean(_reverseOnNegativeClock)); 39 json_object_set_new(root, WRAP_SELECT_AT_STEPS, json_boolean(_wrapSelectAtSteps)); 40 return root; 41 } 42 43 void AddressableSequenceModule::loadFromJson(json_t* root) { 44 json_t* p = json_object_get(root, POLY_INPUT); 45 if (p) { 46 _polyInputID = json_integer_value(p); 47 } 48 49 json_t* s = json_object_get(root, SELECT_ON_CLOCK); 50 if (s) { 51 _selectOnClock = json_is_true(s); 52 } 53 54 json_t* t = json_object_get(root, TRIGGERED_SELECT); 55 if (t) { 56 _triggeredSelect = json_is_true(t); 57 } 58 59 json_t* r = json_object_get(root, REVERSE_ON_NEGATIVE_CLOCK); 60 if (r) { 61 _reverseOnNegativeClock = json_is_true(r); 62 } 63 64 json_t* w = json_object_get(root, WRAP_SELECT_AT_STEPS); 65 if (w) { 66 _wrapSelectAtSteps = json_is_true(w); 67 } 68 } 69 70 int AddressableSequenceModule::channels() { 71 assert(_polyInputID >= 0); 72 assert(_clockInputID >= 0); 73 assert(_selectInputID >= 0); 74 return _polyInputID == _selectInputID ? inputs[_selectInputID].getChannels() : inputs[_clockInputID].getChannels(); 75 } 76 77 int AddressableSequenceModule::nextStep( 78 int c, 79 Input* resetInput, 80 Input& clockInput, 81 Param* stepsParam, 82 Param& directionParam, 83 Param* selectParam, 84 Input& selectInput, 85 int n 86 ) { 87 bool reset = false; 88 if (resetInput) { 89 reset = _reset[c].process(resetInput->getPolyVoltage(c)); 90 if (reset) { 91 _timer[c].reset(); 92 } 93 } 94 bool timer = _timer[c].next(); 95 float clockVoltage = clockInput.getPolyVoltage(c); 96 bool clock = _clock[c].process(clockVoltage) && !timer; 97 bool negativeClock = _negativeClock[c].process(clockVoltage) && _reverseOnNegativeClock && !timer && !clock; 98 99 int steps = n; 100 if (stepsParam) { 101 float s = clamp(stepsParam->getValue(), 1.0f, 8.0f); 102 s -= 1.0f; 103 s /= 7.0f; 104 s *= n - 1; 105 s += 1.0f; 106 steps = s; 107 } 108 int reverse = 1 - 2 * (directionParam.getValue() == 0.0f); 109 _step[c] = (_step[c] + reverse * clock + -reverse * negativeClock) % steps; 110 _step[c] += (_step[c] < 0) * steps; 111 _step[c] -= _step[c] * reset; 112 113 float select = n; 114 if (selectParam) { 115 float s = clamp(selectParam->getValue(), 0.0f, 7.0f) / 7.0f; 116 select = s * (n - 1); 117 } 118 if (_triggeredSelect) { 119 if (_selectTrigger[c].process(selectInput.getPolyVoltage(c))) { 120 _select[c] = (1 + (int)_select[c]) % ((int)select + 1); 121 } 122 _select[c] -= _select[c] * reset; 123 } 124 else { 125 select += (clamp(selectInput.getPolyVoltage(c), -9.99f, 9.99f) / 10.f) * (float)n; 126 if (!_selectOnClock || clock) { 127 _select[c] = select; 128 } 129 } 130 131 int s = (_step[c] + (int)_select[c]) % (_wrapSelectAtSteps ? steps : n); 132 if (s < 0) { 133 return n + s; 134 } 135 return s; 136 } 137 138 int AddressableSequenceModule::setStep(int c, int i, int n) { 139 return _step[c] = i % n; 140 } 141 142 143 void AddressableSequenceBaseModuleWidget::contextMenu(Menu* menu) { 144 auto m = dynamic_cast<AddressableSequenceModule*>(module); 145 assert(m); 146 147 OptionsMenuItem* p = new OptionsMenuItem("Polyphony channels from"); 148 p->addItem(OptionMenuItem("CLOCK input", [m]() { return m->_polyInputID == m->_clockInputID; }, [m]() { m->_polyInputID = m->_clockInputID; })); 149 p->addItem(OptionMenuItem("SELECT input", [m]() { return m->_polyInputID == m->_selectInputID; }, [m]() { m->_polyInputID = m->_selectInputID; })); 150 OptionsMenuItem::addToMenu(p, menu); 151 152 menu->addChild(new BoolOptionMenuItem("Reverse step on negative clock", [m]() { return &m->_reverseOnNegativeClock; })); 153 menu->addChild(new BoolOptionMenuItem("Triggered select mode", [m]() { return &m->_triggeredSelect; })); 154 menu->addChild(new BoolOptionMenuItem("Wrap select at steps", [m]() { return &m->_wrapSelectAtSteps; })); 155 } 156 157 158 void AddressableSequenceModuleWidget::contextMenu(Menu* menu) { 159 AddressableSequenceBaseModuleWidget::contextMenu(menu); 160 161 auto m = dynamic_cast<AddressableSequenceModule*>(module); 162 assert(m); 163 menu->addChild(new BoolOptionMenuItem("Select on clock mode", [m]() { return &m->_selectOnClock; })); 164 }