BogaudioModules

BogaudioModules for VCV Rack
Log | Files | Refs | README | LICENSE

Pgmr.cpp (11332B)


      1 
      2 #include "Pgmr.hpp"
      3 
      4 #define SELECT_TRIGGERS "SELECT_TRIGGERS"
      5 #define SAVE_LAST_TRIGGERED_TO_PATCH "save_last_triggered_to_patch"
      6 #define LAST_TRIGGERED_STEP "last_triggered_step"
      7 #define LAST_TRIGGERED_ELEMENTS_COUNT "last_triggered_elements_count"
      8 
      9 void Pgmr::reset() {
     10 	std::lock_guard<SpinLock> lock(_elementsLock);
     11 
     12 	for (int c = 0; c < maxChannels; ++c) {
     13 		_lastSteps[c] = -1;
     14 		_allPulseGens[c].process(1000.0f);
     15 	}
     16 	for (auto* element : _elements) {
     17 		element->reset();
     18 	}
     19 }
     20 
     21 void Pgmr::sampleRateChange() {
     22 	_sampleTime = APP->engine->getSampleTime();
     23 }
     24 
     25 json_t* Pgmr::saveToJson(json_t* root) {
     26 	root = OutputRangeAddressableSequenceModule::saveToJson(root);
     27 	json_object_set_new(root, SELECT_TRIGGERS, json_boolean(_selectTriggers));
     28 	json_object_set_new(root, SAVE_LAST_TRIGGERED_TO_PATCH, json_boolean(_saveLastTriggeredToPatch));
     29 	if (_saveLastTriggeredToPatch) {
     30 		json_t* a = json_array();
     31 		for (int c = 0; c < maxChannels; ++c) {
     32 			json_array_append_new(a, json_integer(_step[c]));
     33 		}
     34 		json_object_set_new(root, LAST_TRIGGERED_STEP, a);
     35 		json_object_set_new(root, LAST_TRIGGERED_ELEMENTS_COUNT, json_integer(_elements.size()));
     36 	}
     37 	return root;
     38 }
     39 
     40 void Pgmr::loadFromJson(json_t* root) {
     41 	OutputRangeAddressableSequenceModule::loadFromJson(root);
     42 
     43 	json_t* st = json_object_get(root, SELECT_TRIGGERS);
     44 	if (st) {
     45 		_selectTriggers = json_is_true(st);
     46 	}
     47 
     48 	json_t* sl = json_object_get(root, SAVE_LAST_TRIGGERED_TO_PATCH);
     49 	if (sl) {
     50 		_saveLastTriggeredToPatch = json_is_true(sl);
     51 		if (_saveLastTriggeredToPatch) {
     52 			json_t* a = json_object_get(root, LAST_TRIGGERED_STEP);
     53 			json_t* sz = json_object_get(root, LAST_TRIGGERED_ELEMENTS_COUNT);
     54 			if (a && json_array_size(a) == maxChannels && sz) {
     55 				_restoreLastTriggeredExpectedElementsN = json_integer_value(sz);
     56 				std::vector<int> restoreSteps(maxChannels);
     57 				for (int c = 0; c < maxChannels; ++c) {
     58 					json_t* s = json_array_get(a, c);
     59 					if (s) {
     60 						restoreSteps[c] = json_integer_value(s);
     61 					}
     62 				}
     63 				_restoreLastTriggered = new std::function<void()>([this, restoreSteps]() {
     64 					for (int c = 0; c < maxChannels; ++c) {
     65 						setStep(c, restoreSteps[c], _elements.size());
     66 					}
     67 				});
     68 			}
     69 		}
     70 	}
     71 }
     72 
     73 void Pgmr::modulate() {
     74 	_selectOnClock = params[SELECT_ON_CLOCK_PARAM].getValue() > 0.5f;
     75 }
     76 
     77 void Pgmr::processAlways(const ProcessArgs& args) {
     78 	if (expanderConnected()) {
     79 		PgmrExpanderMessage* te = toExpander();
     80 		te->baseID = _id;
     81 		te->position = 1;
     82 		te->rangeOffset = _rangeOffset;
     83 		te->rangeScale = _rangeScale;
     84 	}
     85 }
     86 
     87 void Pgmr::processChannel(const ProcessArgs& args, int c) {
     88 	std::lock_guard<SpinLock> lock(_elementsLock);
     89 	std::vector<PgmrStep*>& steps = _elements;
     90 	int stepsN = steps.size();
     91 
     92 	if (c == 0) {
     93 		for (int i = 0; i < stepsN; ++i) {
     94 			steps[i]->lightSum = 0.0f;
     95 		}
     96 	}
     97 
     98 	int step = nextStep(
     99 		c,
    100 		NULL,
    101 		inputs[CLOCK_INPUT],
    102 		NULL,
    103 		params[DIRECTION_PARAM],
    104 		NULL,
    105 		inputs[SELECT_INPUT],
    106 		stepsN
    107 	);
    108 	for (int i = 0; i < stepsN; ++i) {
    109 		if (steps[i]->triggers[c].process(steps[i]->selectParam.getValue() + steps[i]->selectInput.getPolyVoltage(c))) {
    110 			step = setStep(c, i, stepsN);
    111 		}
    112 	}
    113 
    114 	{
    115 		float out = steps[step]->aParam.getValue();
    116 		out += _rangeOffset;
    117 		out *= _rangeScale;
    118 		outputs[A_OUTPUT].setChannels(_channels);
    119 		outputs[A_OUTPUT].setVoltage(out, c);
    120 	}
    121 	{
    122 		float out = steps[step]->bParam.getValue();
    123 		out += _rangeOffset;
    124 		out *= _rangeScale;
    125 		outputs[B_OUTPUT].setChannels(_channels);
    126 		outputs[B_OUTPUT].setVoltage(out, c);
    127 	}
    128 	{
    129 		float out = steps[step]->cParam.getValue();
    130 		out += _rangeOffset;
    131 		out *= _rangeScale;
    132 		outputs[C_OUTPUT].setChannels(_channels);
    133 		outputs[C_OUTPUT].setVoltage(out, c);
    134 	}
    135 	{
    136 		float out = steps[step]->dParam.getValue();
    137 		out += _rangeOffset;
    138 		out *= _rangeScale;
    139 		outputs[D_OUTPUT].setChannels(_channels);
    140 		outputs[D_OUTPUT].setVoltage(out, c);
    141 	}
    142 
    143 	if (step != _lastSteps[c]) {
    144 		_lastSteps[c] = step;
    145 		_allPulseGens[c].trigger(0.001f);
    146 		steps[step]->pulseGens[c].trigger(0.001f);
    147 	}
    148 	outputs[SELECT_ALL_OUTPUT].setChannels(_channels);
    149 	outputs[SELECT_ALL_OUTPUT].setVoltage(_allPulseGens[c].process(_sampleTime) * 5.0f, c);
    150 
    151 	for (int i = 0; i < stepsN; ++i) {
    152 		steps[i]->selectedOutput.setChannels(_channels);
    153 		steps[i]->selectedOutput.setVoltage((steps[i]->pulseGens[c].process(_sampleTime) || (!_selectTriggers && step == i)) * 5.0f, c);
    154 
    155 		steps[i]->lightSum += step == i;
    156 	}
    157 
    158 	if (c == _channels - 1) {
    159 		for (int i = 0; i < stepsN; ++i) {
    160 			steps[i]->selectedLight.value = steps[i]->lightSum * _inverseChannels;
    161 		}
    162 	}
    163 }
    164 
    165 void Pgmr::elementsChanged() {
    166 	if (_restoreLastTriggered && (int)_elements.size() == _restoreLastTriggeredExpectedElementsN) {
    167 		(*_restoreLastTriggered)();
    168 		delete _restoreLastTriggered;
    169 		_restoreLastTriggered = NULL;
    170 	}
    171 }
    172 
    173 
    174 struct PgmrWidget : AddressableSequenceBaseModuleWidget {
    175 	static constexpr int hp = 15;
    176 
    177 	PgmrWidget(Pgmr* module) {
    178 		setModule(module);
    179 		box.size = Vec(RACK_GRID_WIDTH * hp, RACK_GRID_HEIGHT);
    180 		setPanel(box.size, "Pgmr");
    181 		createScrews();
    182 
    183 		// generated by svg_widgets.rb
    184 		auto directionParamPosition = Vec(28.0, 263.7);
    185 		auto selectOnClockParamPosition = Vec(28.0, 277.2);
    186 		auto cva1ParamPosition = Vec(54.5, 40.5);
    187 		auto cvb1ParamPosition = Vec(54.5, 94.5);
    188 		auto cvc1ParamPosition = Vec(54.5, 148.5);
    189 		auto cvd1ParamPosition = Vec(54.5, 202.5);
    190 		auto select1ParamPosition = Vec(58.5, 267.0);
    191 		auto cva2ParamPosition = Vec(99.5, 40.5);
    192 		auto cvb2ParamPosition = Vec(99.5, 94.5);
    193 		auto cvc2ParamPosition = Vec(99.5, 148.5);
    194 		auto cvd2ParamPosition = Vec(99.5, 202.5);
    195 		auto select2ParamPosition = Vec(103.5, 267.0);
    196 		auto cva3ParamPosition = Vec(144.5, 40.5);
    197 		auto cvb3ParamPosition = Vec(144.5, 94.5);
    198 		auto cvc3ParamPosition = Vec(144.5, 148.5);
    199 		auto cvd3ParamPosition = Vec(144.5, 202.5);
    200 		auto select3ParamPosition = Vec(148.5, 267.0);
    201 		auto cva4ParamPosition = Vec(189.5, 40.5);
    202 		auto cvb4ParamPosition = Vec(189.5, 94.5);
    203 		auto cvc4ParamPosition = Vec(189.5, 148.5);
    204 		auto cvd4ParamPosition = Vec(189.5, 202.5);
    205 		auto select4ParamPosition = Vec(193.5, 267.0);
    206 
    207 		auto clockInputPosition = Vec(10.5, 226.0);
    208 		auto selectInputPosition = Vec(10.5, 290.0);
    209 		auto select1InputPosition = Vec(55.5, 290.0);
    210 		auto select2InputPosition = Vec(100.5, 290.0);
    211 		auto select3InputPosition = Vec(145.5, 290.0);
    212 		auto select4InputPosition = Vec(190.5, 290.0);
    213 
    214 		auto aOutputPosition = Vec(10.5, 59.0);
    215 		auto bOutputPosition = Vec(10.5, 94.0);
    216 		auto cOutputPosition = Vec(10.5, 129.0);
    217 		auto dOutputPosition = Vec(10.5, 164.0);
    218 		auto selectAllOutputPosition = Vec(10.5, 330.0);
    219 		auto select1OutputPosition = Vec(55.5, 330.0);
    220 		auto select2OutputPosition = Vec(100.5, 330.0);
    221 		auto select3OutputPosition = Vec(145.5, 330.0);
    222 		auto select4OutputPosition = Vec(190.5, 330.0);
    223 
    224 		auto select1LightPosition = Vec(64.3, 255.0);
    225 		auto select2LightPosition = Vec(109.3, 255.0);
    226 		auto select3LightPosition = Vec(154.3, 255.0);
    227 		auto select4LightPosition = Vec(199.3, 255.0);
    228 		// end generated by svg_widgets.rb
    229 
    230 		addParam(createParam<IndicatorButtonGreen9>(directionParamPosition, module, Pgmr::DIRECTION_PARAM));
    231 		addParam(createParam<IndicatorButtonGreen9>(selectOnClockParamPosition, module, Pgmr::SELECT_ON_CLOCK_PARAM));
    232 		addParam(createParam<Knob26>(cva1ParamPosition, module, Pgmr::CVA1_PARAM));
    233 		addParam(createParam<Knob26>(cvb1ParamPosition, module, Pgmr::CVB1_PARAM));
    234 		addParam(createParam<Knob26>(cvc1ParamPosition, module, Pgmr::CVC1_PARAM));
    235 		addParam(createParam<Knob26>(cvd1ParamPosition, module, Pgmr::CVD1_PARAM));
    236 		addParam(createParam<Button18>(select1ParamPosition, module, Pgmr::SELECT1_PARAM));
    237 		addParam(createParam<Knob26>(cva2ParamPosition, module, Pgmr::CVA2_PARAM));
    238 		addParam(createParam<Knob26>(cvb2ParamPosition, module, Pgmr::CVB2_PARAM));
    239 		addParam(createParam<Knob26>(cvc2ParamPosition, module, Pgmr::CVC2_PARAM));
    240 		addParam(createParam<Knob26>(cvd2ParamPosition, module, Pgmr::CVD2_PARAM));
    241 		addParam(createParam<Button18>(select2ParamPosition, module, Pgmr::SELECT2_PARAM));
    242 		addParam(createParam<Knob26>(cva3ParamPosition, module, Pgmr::CVA3_PARAM));
    243 		addParam(createParam<Knob26>(cvb3ParamPosition, module, Pgmr::CVB3_PARAM));
    244 		addParam(createParam<Knob26>(cvc3ParamPosition, module, Pgmr::CVC3_PARAM));
    245 		addParam(createParam<Knob26>(cvd3ParamPosition, module, Pgmr::CVD3_PARAM));
    246 		addParam(createParam<Button18>(select3ParamPosition, module, Pgmr::SELECT3_PARAM));
    247 		addParam(createParam<Knob26>(cva4ParamPosition, module, Pgmr::CVA4_PARAM));
    248 		addParam(createParam<Knob26>(cvb4ParamPosition, module, Pgmr::CVB4_PARAM));
    249 		addParam(createParam<Knob26>(cvc4ParamPosition, module, Pgmr::CVC4_PARAM));
    250 		addParam(createParam<Knob26>(cvd4ParamPosition, module, Pgmr::CVD4_PARAM));
    251 		addParam(createParam<Button18>(select4ParamPosition, module, Pgmr::SELECT4_PARAM));
    252 
    253 		addInput(createInput<Port24>(clockInputPosition, module, Pgmr::CLOCK_INPUT));
    254 		addInput(createInput<Port24>(selectInputPosition, module, Pgmr::SELECT_INPUT));
    255 		addInput(createInput<Port24>(select1InputPosition, module, Pgmr::SELECT1_INPUT));
    256 		addInput(createInput<Port24>(select2InputPosition, module, Pgmr::SELECT2_INPUT));
    257 		addInput(createInput<Port24>(select3InputPosition, module, Pgmr::SELECT3_INPUT));
    258 		addInput(createInput<Port24>(select4InputPosition, module, Pgmr::SELECT4_INPUT));
    259 
    260 		addOutput(createOutput<Port24>(aOutputPosition, module, Pgmr::A_OUTPUT));
    261 		addOutput(createOutput<Port24>(bOutputPosition, module, Pgmr::B_OUTPUT));
    262 		addOutput(createOutput<Port24>(cOutputPosition, module, Pgmr::C_OUTPUT));
    263 		addOutput(createOutput<Port24>(dOutputPosition, module, Pgmr::D_OUTPUT));
    264 		addOutput(createOutput<Port24>(selectAllOutputPosition, module, Pgmr::SELECT_ALL_OUTPUT));
    265 		addOutput(createOutput<Port24>(select1OutputPosition, module, Pgmr::SELECT1_OUTPUT));
    266 		addOutput(createOutput<Port24>(select2OutputPosition, module, Pgmr::SELECT2_OUTPUT));
    267 		addOutput(createOutput<Port24>(select3OutputPosition, module, Pgmr::SELECT3_OUTPUT));
    268 		addOutput(createOutput<Port24>(select4OutputPosition, module, Pgmr::SELECT4_OUTPUT));
    269 
    270 		addChild(createLight<BGSmallLight<GreenLight>>(select1LightPosition, module, Pgmr::SELECT1_LIGHT));
    271 		addChild(createLight<BGSmallLight<GreenLight>>(select2LightPosition, module, Pgmr::SELECT2_LIGHT));
    272 		addChild(createLight<BGSmallLight<GreenLight>>(select3LightPosition, module, Pgmr::SELECT3_LIGHT));
    273 		addChild(createLight<BGSmallLight<GreenLight>>(select4LightPosition, module, Pgmr::SELECT4_LIGHT));
    274 	}
    275 
    276 	void contextMenu(Menu* menu) override {
    277 		AddressableSequenceBaseModuleWidget::contextMenu(menu);
    278 
    279 		auto m = dynamic_cast<Pgmr*>(module);
    280 		assert(m);
    281 		OptionsMenuItem* so = new OptionsMenuItem("Output on selected step");
    282 		so->addItem(OptionMenuItem("Gate", [m]() { return !m->_selectTriggers; }, [m]() { m->_selectTriggers = false; }));
    283 		so->addItem(OptionMenuItem("Trigger", [m]() { return m->_selectTriggers; }, [m]() { m->_selectTriggers = true; }));
    284 		OptionsMenuItem::addToMenu(so, menu);
    285 
    286 		menu->addChild(new BoolOptionMenuItem("Save last selected step to patch", [m]() { return &m->_saveLastTriggeredToPatch; }));
    287 
    288 		OutputRangeOptionMenuItem::addOutputRangeOptionsToMenu(module, menu);
    289 	}
    290 };
    291 
    292 Model* modelPgmr = createModel<Pgmr, PgmrWidget>("Bogaudio-Pgmr", "PGMR", "4-step programmer and sequencer", "Sequencer", "Polyphonic");