RGate.cpp (9111B)
1 2 #include "RGate.hpp" 3 4 #define RESET_MODE "reset_mode" 5 #define INITIAL_CLOCK_SECONDS "initial_clock_seconds" 6 #define POLY_INPUT "poly_input" 7 8 void RGate::Engine::reset(bool triggers, bool hard, float initialClock) { 9 if (triggers) { 10 clockTrigger.reset(); 11 runTrigger.reset(); 12 initialGatePulseGen.process(10.0f); 13 } 14 if (hard) { 15 secondsSinceLastClock = -1.0f; 16 clockSeconds = initialClock; 17 dividedSeconds = -1.0f; 18 multipliedSeconds = -1.0f; 19 gateSeconds = 0.0f; 20 } 21 dividerCount = 0; 22 dividedProgressSeconds = 0.0f; 23 } 24 25 void RGate::reset() { 26 for (int c = 0; c < _channels; ++c) { 27 _engines[c]->reset(true, true, _initialClockPeriod); 28 } 29 } 30 31 void RGate::sampleRateChange() { 32 _sampleTime = APP->engine->getSampleTime(); 33 } 34 35 json_t* RGate::saveToJson(json_t* root) { 36 root = OutputRangeModule<BGModule>::saveToJson(root); 37 json_object_set_new(root, RESET_MODE, json_integer(_resetMode)); 38 json_object_set_new(root, INITIAL_CLOCK_SECONDS, json_real(_initialClockPeriod)); 39 json_object_set_new(root, POLY_INPUT, json_integer(_polyInputID)); 40 return root; 41 } 42 43 void RGate::loadFromJson(json_t* root) { 44 OutputRangeModule<BGModule>::loadFromJson(root); 45 46 json_t* rm = json_object_get(root, RESET_MODE); 47 if (rm) { 48 ResetMode m = (ResetMode)json_integer_value(rm); 49 switch (m) { 50 case HARD_RESETMODE: 51 case SOFT_RESETMODE: { 52 _resetMode = m; 53 break; 54 } 55 default: { 56 _resetMode = defaultResetMode; 57 } 58 } 59 } 60 61 json_t* ics = json_object_get(root, INITIAL_CLOCK_SECONDS); 62 if (ics) { 63 _initialClockPeriod = std::max(0.0f, (float)json_real_value(ics)); 64 } 65 66 json_t* p = json_object_get(root, POLY_INPUT); 67 if (p) { 68 _polyInputID = json_integer_value(p); 69 } 70 } 71 72 bool RGate::active() { 73 return outputs[GATE_OUTPUT].isConnected(); 74 } 75 76 int RGate::channels() { 77 return inputs[_polyInputID].getChannels(); 78 } 79 80 void RGate::addChannel(int c) { 81 _engines[c] = new Engine(); 82 _engines[c]->reset(true, true, _initialClockPeriod); 83 } 84 85 void RGate::removeChannel(int c) { 86 delete _engines[c]; 87 _engines[c] = NULL; 88 } 89 90 void RGate::modulateChannel(int c) { 91 Engine& e = *_engines[c]; 92 93 e.gatePercentage = clamp(params[LENGTH_PARAM].getValue(), 0.0f, 1.0f); 94 if (inputs[LENGTH_INPUT].isConnected()) { 95 e.gatePercentage *= clamp(inputs[LENGTH_INPUT].getPolyVoltage(c) / 10.0f, 0.0f, 1.0f); 96 } 97 98 float division = clamp(params[CLOCK_DIVIDE_PARAM].getValue(), 0.0f, 1.0f); 99 if (inputs[CLOCK_DIVIDE_INPUT].isConnected()) { 100 division *= clamp(inputs[CLOCK_DIVIDE_INPUT].getPolyVoltage(c) / 10.0f, 0.0f, 1.0f); 101 } 102 division *= division; 103 division *= 63.0f; 104 division += 1.0f; 105 e.division = clamp((int)roundf(division), 1, 64); 106 107 float multiplication = clamp(params[CLOCK_MULTIPLY_PARAM].getValue(), 0.0f, 1.0f); 108 if (inputs[CLOCK_MULTIPLE_INPUT].isConnected()) { 109 multiplication *= clamp(inputs[CLOCK_MULTIPLE_INPUT].getPolyVoltage(c) / 10.0f, 0.0f, 1.0f); 110 } 111 multiplication *= multiplication; 112 multiplication *= 63.0f; 113 multiplication += 1.0f; 114 e.multiplication = clamp((int)roundf(multiplication), 1, 64); 115 } 116 117 void RGate::processChannel(const ProcessArgs& args, int c) { 118 Engine& e = *_engines[c]; 119 120 if (e.runTrigger.process(inputs[RESET_INPUT].getPolyVoltage(c))) { 121 switch (_resetMode) { 122 case HARD_RESETMODE: { 123 e.reset(false, true, _initialClockPeriod); 124 break; 125 } 126 case SOFT_RESETMODE: { 127 e.reset(false, false, _initialClockPeriod); 128 break; 129 } 130 } 131 } 132 133 float out = -1.0f; 134 bool clock = false; 135 if (inputs[CLOCK_INPUT].isConnected()) { 136 clock = e.clockTrigger.process(inputs[CLOCK_INPUT].getPolyVoltage(c)); 137 if (clock) { 138 if (e.secondsSinceLastClock > 0.0f) { 139 e.clockSeconds = e.secondsSinceLastClock; 140 } 141 e.secondsSinceLastClock = 0.0f; 142 } 143 144 if (e.secondsSinceLastClock >= 0.0f) { 145 e.secondsSinceLastClock += _sampleTime; 146 e.dividedSeconds = e.clockSeconds * (float)e.division; 147 e.multipliedSeconds = e.dividedSeconds / (float)e.multiplication; 148 e.gateSeconds = std::max(0.001f, e.multipliedSeconds * e.gatePercentage); 149 if (clock) { 150 if (e.dividerCount < 1) { 151 e.dividedProgressSeconds = 0.0f; 152 } 153 else { 154 e.dividedProgressSeconds += _sampleTime; 155 } 156 ++e.dividerCount; 157 if (e.dividerCount >= e.division) { 158 e.dividerCount = 0; 159 } 160 } 161 else { 162 e.dividedProgressSeconds += _sampleTime; 163 } 164 165 if (e.dividedProgressSeconds < e.dividedSeconds) { 166 float multipliedProgressSeconds = e.dividedProgressSeconds / e.multipliedSeconds; 167 multipliedProgressSeconds -= (float)(int)multipliedProgressSeconds; 168 multipliedProgressSeconds *= e.multipliedSeconds; 169 out += 2.0f * (float)(multipliedProgressSeconds <= e.gateSeconds); 170 } 171 } 172 } 173 174 out += _rangeOffset; 175 out *= _rangeScale; 176 outputs[GATE_OUTPUT].setChannels(_channels); 177 outputs[GATE_OUTPUT].setVoltage(out, c); 178 } 179 180 struct IPQuantity : Quantity { 181 RGate* _module; 182 183 IPQuantity(RGate* m) : _module(m) {} 184 185 void setValue(float value) override { 186 value = clamp(value, getMinValue(), getMaxValue()); 187 if (_module) { 188 _module->_initialClockPeriod = value; 189 } 190 } 191 192 float getValue() override { 193 if (_module) { 194 return _module->_initialClockPeriod; 195 } 196 return RGate::defaultInitialClockPeriod; 197 } 198 199 float getMinValue() override { return 0.0f; } 200 float getMaxValue() override { return 1.0f; } 201 float getDefaultValue() override { return RGate::defaultInitialClockPeriod; } 202 float getDisplayValue() override { return getValue() * 1000.0f; } 203 void setDisplayValue(float displayValue) override { setValue(displayValue / 1000.0f); } 204 std::string getLabel() override { return "Initial clock"; } 205 std::string getUnit() override { return "ms"; } 206 }; 207 208 struct IPSlider : ui::Slider { 209 IPSlider(RGate* module) { 210 quantity = new IPQuantity(module); 211 box.size.x = 200.0f; 212 } 213 virtual ~IPSlider() { 214 delete quantity; 215 } 216 }; 217 218 struct IPMenuItem : MenuItem { 219 RGate* _module; 220 221 IPMenuItem(RGate* m) : _module(m) { 222 this->text = "Initial clock"; 223 this->rightText = "▸"; 224 } 225 226 Menu* createChildMenu() override { 227 Menu* menu = new Menu; 228 menu->addChild(new IPSlider(_module)); 229 return menu; 230 } 231 }; 232 233 struct RGateWidget : BGModuleWidget { 234 static constexpr int hp = 5; 235 236 RGateWidget(RGate* module) { 237 setModule(module); 238 box.size = Vec(RACK_GRID_WIDTH * hp, RACK_GRID_HEIGHT); 239 setPanel(box.size, "RGate"); 240 createScrews(); 241 242 // generated by svg_widgets.rb 243 auto lengthParamPosition = Vec(18.5, 48.0); 244 auto clockDivideParamPosition = Vec(24.5, 129.0); 245 auto clockMultiplyParamPosition = Vec(24.5, 200.0); 246 247 auto lengthInputPosition = Vec(10.5, 251.0); 248 auto clockDivideInputPosition = Vec(40.5, 251.0); 249 auto resetInputPosition = Vec(10.5, 288.0); 250 auto clockMultipleInputPosition = Vec(40.5, 288.0); 251 auto clockInputPosition = Vec(10.5, 325.0); 252 253 auto gateOutputPosition = Vec(40.5, 325.0); 254 // end generated by svg_widgets.rb 255 256 addParam(createParam<Knob38>(lengthParamPosition, module, RGate::LENGTH_PARAM)); 257 addParam(createParam<Knob26>(clockDivideParamPosition, module, RGate::CLOCK_DIVIDE_PARAM)); 258 addParam(createParam<Knob26>(clockMultiplyParamPosition, module, RGate::CLOCK_MULTIPLY_PARAM)); 259 260 addInput(createInput<Port24>(lengthInputPosition, module, RGate::LENGTH_INPUT)); 261 addInput(createInput<Port24>(clockDivideInputPosition, module, RGate::CLOCK_DIVIDE_INPUT)); 262 addInput(createInput<Port24>(resetInputPosition, module, RGate::RESET_INPUT)); 263 addInput(createInput<Port24>(clockMultipleInputPosition, module, RGate::CLOCK_MULTIPLE_INPUT)); 264 addInput(createInput<Port24>(clockInputPosition, module, RGate::CLOCK_INPUT)); 265 266 addOutput(createOutput<Port24>(gateOutputPosition, module, RGate::GATE_OUTPUT)); 267 } 268 269 void contextMenu(Menu* menu) override { 270 auto m = dynamic_cast<RGate*>(module); 271 assert(m); 272 273 OptionsMenuItem* p = new OptionsMenuItem("Polyphony channels from"); 274 p->addItem(OptionMenuItem("CLOCK input", [m]() { return m->_polyInputID == RGate::CLOCK_INPUT; }, [m]() { m->_polyInputID = RGate::CLOCK_INPUT; })); 275 p->addItem(OptionMenuItem("LEN input", [m]() { return m->_polyInputID == RGate::LENGTH_INPUT; }, [m]() { m->_polyInputID = RGate::LENGTH_INPUT; })); 276 OptionsMenuItem::addToMenu(p, menu); 277 278 OptionsMenuItem* r = new OptionsMenuItem("RESET mode"); 279 r->addItem(OptionMenuItem("Hard: reset clock period and divider", [m]() { return m->_resetMode == RGate::HARD_RESETMODE; }, [m]() { m->_resetMode = RGate::HARD_RESETMODE; })); 280 r->addItem(OptionMenuItem("Soft: reseet clock divider", [m]() { return m->_resetMode == RGate::SOFT_RESETMODE; }, [m]() { m->_resetMode = RGate::SOFT_RESETMODE; })); 281 OptionsMenuItem::addToMenu(r, menu); 282 283 menu->addChild(new IPMenuItem(m)); 284 285 OptionsMenuItem* mi = new OptionsMenuItem("Range"); 286 mi->addItem(OutputRangeOptionMenuItem(m, "0V-10V", 1.0f, 5.0f)); 287 mi->addItem(OutputRangeOptionMenuItem(m, "0V-5V", 1.0f, 2.5f)); 288 mi->addItem(OutputRangeOptionMenuItem(m, "+/-10V", 0.0f, 10.0f)); 289 mi->addItem(OutputRangeOptionMenuItem(m, "+/-5V", 0.0f, 5.0f)); 290 OptionsMenuItem::addToMenu(mi, menu); 291 } 292 }; 293 294 Model* modelRGate = createModel<RGate, RGateWidget>("Bogaudio-RGate", "RGATE", "Clock-relative gate generator & clock divider/multiplier", "Clock modulator", "Polyphonic");