BogaudioModules

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

Walk.cpp (5884B)


      1 
      2 #include "Walk.hpp"
      3 
      4 #define POLY_INPUT "poly_input"
      5 #define JUMP_MODE "jump_mode"
      6 #define JUMP_MODE_JUMP "jump"
      7 #define JUMP_MODE_TRACKHOLD "track_and_hold"
      8 #define JUMP_MODE_SAMPLEHOLD "sample_and_hold"
      9 
     10 void Walk::reset() {
     11 	for (int i = 0; i < maxChannels; ++i) {
     12 		_jumpTrigger[i].reset();
     13 	}
     14 }
     15 
     16 void Walk::sampleRateChange() {
     17 	for (int i = 0; i < maxChannels; ++i) {
     18 		_slew[i].setParams(APP->engine->getSampleRate(), 100.0f, 10.0f);
     19 	}
     20 }
     21 
     22 json_t* Walk::saveToJson(json_t* root) {
     23 	json_object_set_new(root, POLY_INPUT, json_integer(_polyInputID));
     24 	switch (_jumpMode) {
     25 		case JUMP_JUMPMODE: {
     26 			json_object_set_new(root, JUMP_MODE, json_string(JUMP_MODE_JUMP));
     27 			break;
     28 		}
     29 		case TRACKHOLD_JUMPMODE: {
     30 			json_object_set_new(root, JUMP_MODE, json_string(JUMP_MODE_TRACKHOLD));
     31 			break;
     32 		}
     33 		case SAMPLEHOLD_JUMPMODE: {
     34 			json_object_set_new(root, JUMP_MODE, json_string(JUMP_MODE_SAMPLEHOLD));
     35 			break;
     36 		}
     37 	}
     38 	return root;
     39 }
     40 
     41 void Walk::loadFromJson(json_t* root) {
     42 	json_t* p = json_object_get(root, POLY_INPUT);
     43 	if (p) {
     44 		_polyInputID = json_integer_value(p);
     45 	}
     46 
     47 	json_t* jm = json_object_get(root, JUMP_MODE);
     48 	if (jm) {
     49 		if (strcmp(json_string_value(jm), JUMP_MODE_JUMP) == 0) {
     50 			_jumpMode = JUMP_JUMPMODE;
     51 		}
     52 		else if (strcmp(json_string_value(jm), JUMP_MODE_TRACKHOLD) == 0) {
     53 			_jumpMode = TRACKHOLD_JUMPMODE;
     54 		}
     55 		else if (strcmp(json_string_value(jm), JUMP_MODE_SAMPLEHOLD) == 0) {
     56 			_jumpMode = SAMPLEHOLD_JUMPMODE;
     57 		}
     58 	}
     59 }
     60 
     61 int Walk::channels() {
     62 	int id = _polyInputID;
     63 	if (!(_polyInputID == OFFSET_INPUT || _polyInputID == SCALE_INPUT || _polyInputID == JUMP_INPUT)) {
     64 		id = RATE_INPUT;
     65 	}
     66 	return inputs[id].getChannels();
     67 }
     68 
     69 void Walk::modulateChannel(int c) {
     70 	float rate = params[RATE_PARAM].getValue();
     71 	if (inputs[RATE_INPUT].isConnected()) {
     72 		rate *= clamp(inputs[RATE_INPUT].getPolyVoltage(c) / 10.0f, 0.0f, 1.0f);
     73 	}
     74 	rate = 0.2f * powf(rate, 5.0f);
     75 	_walk[c].setParams(APP->engine->getSampleRate(), rate);
     76 
     77 	_offset[c] = params[OFFSET_PARAM].getValue();
     78 	if (inputs[OFFSET_INPUT].isConnected()) {
     79 		_offset[c] *= clamp(inputs[OFFSET_INPUT].getPolyVoltage(c) / 5.0f, -1.0f, 1.0f);
     80 	}
     81 	_offset[c] *= 5.0f;
     82 
     83 	_scale[c] = params[SCALE_PARAM].getValue();
     84 	if (inputs[SCALE_INPUT].isConnected()) {
     85 		_scale[c] *= clamp(inputs[SCALE_INPUT].getPolyVoltage(c) / 10.0f, 0.0f, 1.0f);
     86 	}
     87 }
     88 
     89 void Walk::processChannel(const ProcessArgs& args, int c) {
     90 	float triggered = _jumpTrigger[c].process(inputs[JUMP_INPUT].getPolyVoltage(c));
     91 	float out = _walk[c].next();
     92 
     93 	switch (_jumpMode) {
     94 		case JUMP_JUMPMODE: {
     95 			if (triggered) {
     96 				_walk[c].jump();
     97 			}
     98 			break;
     99 		}
    100 		case TRACKHOLD_JUMPMODE: {
    101 			if (_jumpTrigger[c].isHigh()) {
    102 				_lastOut[c] = out;
    103 			}
    104 			else {
    105 				out = _lastOut[c];
    106 			}
    107 			break;
    108 		}
    109 		case SAMPLEHOLD_JUMPMODE: {
    110 			if (triggered) {
    111 				_lastOut[c] = out;
    112 			}
    113 			else {
    114 				out = _lastOut[c];
    115 			}
    116 			break;
    117 		}
    118 	}
    119 
    120 	out = _slew[c].next(out);
    121 	out *= _scale[c];
    122 	out += _offset[c];
    123 
    124 	outputs[OUT_OUTPUT].setChannels(_channels);
    125 	outputs[OUT_OUTPUT].setVoltage(out, c);
    126 }
    127 
    128 struct WalkWidget : BGModuleWidget {
    129 	static constexpr int hp = 3;
    130 
    131 	WalkWidget(Walk* module) {
    132 		setModule(module);
    133 		box.size = Vec(RACK_GRID_WIDTH * hp, RACK_GRID_HEIGHT);
    134 		setPanel(box.size, "Walk");
    135 		createScrews();
    136 
    137 		// generated by svg_widgets.rb
    138 		auto rateParamPosition = Vec(8.0, 36.5);
    139 		auto offsetParamPosition = Vec(14.5, 91.0);
    140 		auto scaleParamPosition = Vec(14.5, 130.0);
    141 
    142 		auto rateInputPosition = Vec(10.5, 160.0);
    143 		auto offsetInputPosition = Vec(10.5, 195.0);
    144 		auto scaleInputPosition = Vec(10.5, 230.0);
    145 		auto jumpInputPosition = Vec(10.5, 265.0);
    146 
    147 		auto outOutputPosition = Vec(10.5, 303.0);
    148 		// end generated by svg_widgets.rb
    149 
    150 		addParam(createParam<Knob29>(rateParamPosition, module, Walk::RATE_PARAM));
    151 		addParam(createParam<Knob16>(offsetParamPosition, module, Walk::OFFSET_PARAM));
    152 		addParam(createParam<Knob16>(scaleParamPosition, module, Walk::SCALE_PARAM));
    153 
    154 		addInput(createInput<Port24>(rateInputPosition, module, Walk::RATE_INPUT));
    155 		addInput(createInput<Port24>(offsetInputPosition, module, Walk::OFFSET_INPUT));
    156 		addInput(createInput<Port24>(scaleInputPosition, module, Walk::SCALE_INPUT));
    157 		addInput(createInput<Port24>(jumpInputPosition, module, Walk::JUMP_INPUT));
    158 
    159 		addOutput(createOutput<Port24>(outOutputPosition, module, Walk::OUT_OUTPUT));
    160 	}
    161 
    162 	void contextMenu(Menu* menu) override {
    163 		auto m = dynamic_cast<Walk*>(module);
    164 		assert(m);
    165 
    166 		OptionsMenuItem* p = new OptionsMenuItem("Polyphony channels from");
    167 		p->addItem(OptionMenuItem("RATE input", [m]() { return m->_polyInputID == Walk::RATE_INPUT; }, [m]() { m->_polyInputID = Walk::RATE_INPUT; }));
    168 		p->addItem(OptionMenuItem("OFFSET input", [m]() { return m->_polyInputID == Walk::OFFSET_INPUT; }, [m]() { m->_polyInputID = Walk::OFFSET_INPUT; }));
    169 		p->addItem(OptionMenuItem("SCALE input", [m]() { return m->_polyInputID == Walk::SCALE_INPUT; }, [m]() { m->_polyInputID = Walk::SCALE_INPUT; }));
    170 		p->addItem(OptionMenuItem("JUMP input", [m]() { return m->_polyInputID == Walk::JUMP_INPUT; }, [m]() { m->_polyInputID = Walk::JUMP_INPUT; }));
    171 		OptionsMenuItem::addToMenu(p, menu);
    172 
    173 		OptionsMenuItem* jm = new OptionsMenuItem("Jump input action");
    174 		jm->addItem(OptionMenuItem("Jump", [m]() { return m->_jumpMode == Walk::JUMP_JUMPMODE; }, [m]() { m->_jumpMode = Walk::JUMP_JUMPMODE; }));
    175 		jm->addItem(OptionMenuItem("Sample and hold", [m]() { return m->_jumpMode == Walk::SAMPLEHOLD_JUMPMODE; }, [m]() { m->_jumpMode = Walk::SAMPLEHOLD_JUMPMODE; }));
    176 		jm->addItem(OptionMenuItem("Track and hold", [m]() { return m->_jumpMode == Walk::TRACKHOLD_JUMPMODE; }, [m]() { m->_jumpMode = Walk::TRACKHOLD_JUMPMODE; }));
    177 		OptionsMenuItem::addToMenu(jm, menu);
    178 	}
    179 };
    180 
    181 Model* modelWalk = bogaudio::createModel<Walk, WalkWidget>("Bogaudio-Walk", "WALK", "Random-walk CV source", "Random", "Sample and hold", "Polyphonic");