BogaudioModules

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

Assign.cpp (3999B)


      1 
      2 #include "Assign.hpp"
      3 
      4 void Assign::reset() {
      5 	_resetTrigger.reset();
      6 	_nextAssign = 0;
      7 	for (int c = 0; c < maxChannels; ++c) {
      8 		_gateTrigger[c].reset();
      9 		_gateHigh[c] = false;
     10 		_pitchInAssignment[c] = -1;
     11 		_gateInAssignment[c] = -1;
     12 		_pitchOutAssignment[c] = -1;
     13 		_gateOutAssignment[c] = -1;
     14 		_lastPitchOut[c] = 0.0f;
     15 		_assignedAtStep[c] = 0;
     16 	}
     17 }
     18 
     19 int Assign::channels() {
     20 	return inputs[GATE_INPUT].getChannels();
     21 }
     22 
     23 void Assign::addChannel(int c) {
     24 	_gateTrigger[c].reset();
     25 }
     26 
     27 void Assign::removeChannel(int c) {
     28 	_gateHigh[c] = false;
     29 	_assignedAtStep[c] = 0;
     30 	if (_pitchInAssignment[c] >= 0) {
     31 		_pitchOutAssignment[_pitchInAssignment[c]] = -1;
     32 		_lastPitchOut[_pitchInAssignment[c]] = 0.0f;
     33 		_pitchInAssignment[c] = -1;
     34 	}
     35 	if (_gateInAssignment[c] >= 0) {
     36 		_gateOutAssignment[_gateInAssignment[c]] = -1;
     37 		_gateInAssignment[c] = -1;
     38 	}
     39 	if (_nextAssign == c) {
     40 		_nextAssign = 0;
     41 	}
     42 }
     43 
     44 void Assign::modulate() {
     45 	_channelsOut = clamp((int)params[CHANNELS_PARAM].getValue(), 1, 16);
     46 }
     47 
     48 void Assign::postProcess(const ProcessArgs& args) {
     49 	++_step;
     50 	if (_resetTrigger.process(inputs[RESET_INPUT].getVoltage())) {
     51 		_nextAssign = 0;
     52 	}
     53 
     54 	for (int c = 0; c < _channels; ++c) {
     55 		if (_gateTrigger[c].process(inputs[GATE_INPUT].getPolyVoltage(c))) {
     56 			_gateHigh[c] = true;
     57 
     58 			if (_gateOutAssignment[_nextAssign] >= 0) {
     59 				int a = _nextAssign + 1;
     60 				int n = a + _channelsOut;
     61 				unsigned long minStep = -1;
     62 				int minI = _nextAssign;
     63 				for (; a < n; ++a) {
     64 					int i = a % _channelsOut;
     65 					if (_gateOutAssignment[i] < 0) {
     66 						_nextAssign = i;
     67 						goto CHANNEL_SELECTED;
     68 					}
     69 					if (_assignedAtStep[i] < minStep) {
     70 						minStep = _assignedAtStep[i];
     71 						minI = i;
     72 					}
     73 				}
     74 				_nextAssign = minI;
     75 			}
     76 
     77 		CHANNEL_SELECTED:
     78 			_pitchInAssignment[c] = _nextAssign;
     79 			_gateInAssignment[c] = _nextAssign;
     80 			_pitchOutAssignment[_nextAssign] = c;
     81 			_gateOutAssignment[_nextAssign] = c;
     82 			_assignedAtStep[c] = _step;
     83 			_nextAssign = (_nextAssign + 1) % _channelsOut;
     84 		}
     85 		else if (!_gateTrigger[c].isHigh() && _gateHigh[c]) {
     86 			_gateHigh[c] = false;
     87 			_pitchOutAssignment[_pitchInAssignment[c]] = -1;
     88 			_pitchInAssignment[c] = -1;
     89 			_gateOutAssignment[_gateInAssignment[c]] = -1;
     90 			_gateInAssignment[c] = -1;
     91 		}
     92 	}
     93 
     94 	outputs[PITCH_OUTPUT].setChannels(_channelsOut);
     95 	outputs[GATE_OUTPUT].setChannels(_channelsOut);
     96 	for (int c = 0; c < _channelsOut; ++c) {
     97 		float pitch = _lastPitchOut[c];
     98 		if (_pitchOutAssignment[c] >= 0) {
     99 			_lastPitchOut[c] = pitch = inputs[PITCH_INPUT].getPolyVoltage(_pitchOutAssignment[c]);
    100 		}
    101 		outputs[PITCH_OUTPUT].setVoltage(pitch, c);
    102 
    103 		float gate = _gateOutAssignment[c] >= 0 ? inputs[GATE_INPUT].getPolyVoltage(_gateOutAssignment[c]) : 0.0f;
    104 		outputs[GATE_OUTPUT].setVoltage(gate, c);
    105 	}
    106 }
    107 
    108 struct AssignWidget : BGModuleWidget {
    109 	static constexpr int hp = 3;
    110 
    111 	AssignWidget(Assign* module) {
    112 		setModule(module);
    113 		box.size = Vec(RACK_GRID_WIDTH * hp, RACK_GRID_HEIGHT);
    114 		setPanel(box.size, "Assign");
    115 		createScrews();
    116 
    117 		// generated by svg_widgets.rb
    118 		auto channelsParamPosition = Vec(9.5, 34.0);
    119 
    120 		auto pitchInputPosition = Vec(10.5, 78.0);
    121 		auto gateInputPosition = Vec(10.5, 113.0);
    122 		auto resetInputPosition = Vec(10.5, 148.0);
    123 
    124 		auto pitchOutputPosition = Vec(10.5, 186.0);
    125 		auto gateOutputPosition = Vec(10.5, 221.0);
    126 		// end generated by svg_widgets.rb
    127 
    128 		addParam(createParam<Knob26>(channelsParamPosition, module, Assign::CHANNELS_PARAM));
    129 
    130 		addInput(createInput<Port24>(pitchInputPosition, module, Assign::PITCH_INPUT));
    131 		addInput(createInput<Port24>(gateInputPosition, module, Assign::GATE_INPUT));
    132 		addInput(createInput<Port24>(resetInputPosition, module, Assign::RESET_INPUT));
    133 
    134 		addOutput(createOutput<Port24>(pitchOutputPosition, module, Assign::PITCH_OUTPUT));
    135 		addOutput(createOutput<Port24>(gateOutputPosition, module, Assign::GATE_OUTPUT));
    136 	}
    137 };
    138 
    139 Model* modelAssign = createModel<Assign, AssignWidget>("Bogaudio-Assign", "ASSIGN", "Polyphonic voice (re)assigner", "Polyphonic");