BogaudioModules

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

LPG.cpp (6599B)


      1 
      2 #include "LPG.hpp"
      3 
      4 #define LPF_POLES "lpf_poles"
      5 
      6 void LPG::Engine::reset() {
      7 	trigger.reset();
      8 }
      9 
     10 void LPG::Engine::setSampleRate(float sr) {
     11 	vcaSL.setParams(sr, 5.0f, 1.0f);
     12 	finalHP.setParams(sr, MultimodeFilter::BUTTERWORTH_TYPE, 2, MultimodeFilter::HIGHPASS_MODE, 80.0f, MultimodeFilter::minQbw, MultimodeFilter::LINEAR_BANDWIDTH_MODE, MultimodeFilter::MINIMUM_DELAY_MODE);
     13 }
     14 
     15 void LPG::reset() {
     16 	for (int c = 0; c < _channels; ++c) {
     17 		_engines[c]->reset();
     18 	}
     19 }
     20 
     21 void LPG::sampleRateChange() {
     22 	_sampleRate = APP->engine->getSampleRate();
     23 	_sampleTime = APP->engine->getSampleTime();
     24 	for (int i = 0; i < _channels; ++i) {
     25 		_engines[i]->setSampleRate(_sampleRate);
     26 	}
     27 }
     28 
     29 json_t* LPG::saveToJson(json_t* root) {
     30 	json_object_set_new(root, LPF_POLES, json_integer(_lpfPoles));
     31 	return root;
     32 }
     33 
     34 void LPG::loadFromJson(json_t* root) {
     35 	json_t* p = json_object_get(root, LPF_POLES);
     36 	if (p) {
     37 		_lpfPoles = json_integer_value(p);
     38 	}
     39 }
     40 
     41 bool LPG::active() {
     42 	return outputs[OUT_OUTPUT].isConnected();
     43 }
     44 
     45 int LPG::channels() {
     46 	return inputs[GATE_INPUT].getChannels();
     47 }
     48 
     49 void LPG::addChannel(int c) {
     50 	_engines[c] = new Engine();
     51 	_engines[c]->reset();
     52 	_engines[c]->setSampleRate(_sampleRate);
     53 }
     54 
     55 void LPG::removeChannel(int c) {
     56 	delete _engines[c];
     57 	_engines[c] = NULL;
     58 }
     59 
     60 void LPG::modulateChannel(int c) {
     61 	_engines[c]->slew.modulate(
     62 		_sampleRate,
     63 		params[RESPONSE_PARAM],
     64 		&inputs[RESPONSE_INPUT],
     65 		100.0f * _timeScale,
     66 		params[RISE_SHAPE_PARAM],
     67 		params[RESPONSE_PARAM],
     68 		&inputs[RESPONSE_INPUT],
     69 		2000.0f * _timeScale,
     70 		params[FALL_SHAPE_PARAM],
     71 		c
     72 	);
     73 }
     74 
     75 void LPG::processChannel(const ProcessArgs& args, int c) {
     76 	Engine& e = *_engines[c];
     77 
     78 	if (e.trigger.process(inputs[GATE_INPUT].getPolyVoltage(c))) {
     79 		float time = clamp(params[RESPONSE_PARAM].getValue(), 0.0f, 1.0f);
     80 		if (inputs[RESPONSE_INPUT].isConnected()) {
     81 			time *= clamp(inputs[RESPONSE_INPUT].getPolyVoltage(c) / 10.0f, 0.0f, 1.0f);
     82 		}
     83 		time *= time;
     84 		time *= _timeScale * 0.1f;
     85 		time += 0.01f;
     86 		e.gateSeconds = time;
     87 
     88 		e.gateElapsedSeconds = 0.0f;
     89 		e.gateSeconds = time;
     90 	}
     91 	else {
     92 		e.gateElapsedSeconds += _sampleTime;
     93 	}
     94 
     95 	float gate = 0.0f;
     96 	if (e.gateElapsedSeconds < e.gateSeconds) {
     97 		gate = 10.0f;
     98 	}
     99 	float env = e.slew.next(gate);
    100 	env /= 10.0f;
    101 
    102 	float lpfEnv = clamp(params[LPF_ENV_PARAM].getValue(), -1.0f, 1.0f);
    103 	float lpfBias = clamp(params[LPF_BIAS_PARAM].getValue(), -1.0f, 1.0f);
    104 	if (inputs[LPF_INPUT].isConnected()) {
    105 		float cv = clamp(inputs[LPF_INPUT].getPolyVoltage(c) / 5.0f, -1.0f, 1.0f);
    106 		lpfBias = clamp(lpfBias + cv, -1.0f, 1.0f);
    107 	}
    108 	lpfBias *= lpfBias;
    109 	float f = clamp(lpfBias + env * lpfEnv, 0.0f, 1.0f);
    110 	f *= maxFilterCutoff;
    111 	f = std::max(f, MultimodeFilter4::minFrequency);
    112 	e.lpf.setParams(
    113 		_sampleRate,
    114 		MultimodeFilter::BUTTERWORTH_TYPE,
    115 		_lpfPoles,
    116 		MultimodeFilter::LOWPASS_MODE,
    117 		f,
    118 		0.0f
    119 	);
    120 
    121 	bool linear = params[LINEAR_VCA_PARAM].getValue() > 0.5f;
    122 	float vcaEnv = clamp(params[VCA_ENV_PARAM].getValue(), -1.0f, 1.0f);
    123 	float vcaBias = clamp(params[VCA_BIAS_PARAM].getValue(), 0.0f, 1.0f);
    124 	if (inputs[VCA_INPUT].isConnected()) {
    125 		float cv = clamp(inputs[VCA_INPUT].getPolyVoltage(c) / 5.0f, -1.0f, 1.0f);
    126 		vcaBias = clamp(vcaBias + cv, 0.0f, 1.0f);
    127 	}
    128 	float level = clamp(vcaBias + env * vcaEnv, 0.0f, 1.0f);
    129 	level = e.vcaSL.next(level);
    130 
    131 	float out = inputs[IN_INPUT].getPolyVoltage(c);
    132 	out = e.finalHP.next(e.lpf.next(out));
    133 	if (linear) {
    134 		out *= level;
    135 	}
    136 	else {
    137 		e.vca.setLevel(Amplifier::minDecibels * (1.0f - level));
    138 		out = e.vca.next(out);
    139 	}
    140 	outputs[OUT_OUTPUT].setChannels(_channels);
    141 	outputs[OUT_OUTPUT].setVoltage(out, c);
    142 }
    143 
    144 struct LPGWidget : BGModuleWidget {
    145 	static constexpr int hp = 8;
    146 
    147 	LPGWidget(LPG* module) {
    148 		setModule(module);
    149 		box.size = Vec(RACK_GRID_WIDTH * hp, RACK_GRID_HEIGHT);
    150 		setPanel(box.size, "LPG");
    151 		createScrews();
    152 
    153 		// generated by svg_widgets.rb
    154 		auto responseParamPosition = Vec(19.5, 50.0);
    155 		auto times10xParamPosition = Vec(26.0, 106.0);
    156 		auto riseShapeParamPosition = Vec(88.0, 50.0);
    157 		auto fallShapeParamPosition = Vec(88.0, 95.0);
    158 		auto lpfEnvParamPosition = Vec(27.0, 152.0);
    159 		auto lpfBiasParamPosition = Vec(75.5, 152.0);
    160 		auto vcaEnvParamPosition = Vec(27.5, 219.0);
    161 		auto vcaBiasParamPosition = Vec(75.0, 219.0);
    162 		auto linearVcaParamPosition = Vec(45.0, 258.0);
    163 
    164 		auto responseInputPosition = Vec(18.5, 287.0);
    165 		auto lpfInputPosition = Vec(48.5, 287.0);
    166 		auto vcaInputPosition = Vec(78.5, 287.0);
    167 		auto gateInputPosition = Vec(18.5, 324.0);
    168 		auto inInputPosition = Vec(48.5, 324.0);
    169 
    170 		auto outOutputPosition = Vec(78.5, 324.0);
    171 		// end generated by svg_widgets.rb
    172 
    173 		addParam(createParam<Knob45>(responseParamPosition, module, LPG::RESPONSE_PARAM));
    174 		addParam(createParam<IndicatorButtonGreen9>(times10xParamPosition, module, LPG::LONG_PARAM));
    175 		addParam(createParam<Knob16>(riseShapeParamPosition, module, LPG::RISE_SHAPE_PARAM));
    176 		addParam(createParam<Knob16>(fallShapeParamPosition, module, LPG::FALL_SHAPE_PARAM));
    177 		addParam(createParam<Knob26>(lpfEnvParamPosition, module, LPG::LPF_ENV_PARAM));
    178 		addParam(createParam<Knob26>(lpfBiasParamPosition, module, LPG::LPF_BIAS_PARAM));
    179 		addParam(createParam<Knob26>(vcaEnvParamPosition, module, LPG::VCA_ENV_PARAM));
    180 		addParam(createParam<Knob26>(vcaBiasParamPosition, module, LPG::VCA_BIAS_PARAM));
    181 		addParam(createParam<IndicatorButtonGreen9>(linearVcaParamPosition, module, LPG::LINEAR_VCA_PARAM));
    182 
    183 		addInput(createInput<Port24>(responseInputPosition, module, LPG::RESPONSE_INPUT));
    184 		addInput(createInput<Port24>(lpfInputPosition, module, LPG::LPF_INPUT));
    185 		addInput(createInput<Port24>(vcaInputPosition, module, LPG::VCA_INPUT));
    186 		addInput(createInput<Port24>(gateInputPosition, module, LPG::GATE_INPUT));
    187 		addInput(createInput<Port24>(inInputPosition, module, LPG::IN_INPUT));
    188 
    189 		addOutput(createOutput<Port24>(outOutputPosition, module, LPG::OUT_OUTPUT));
    190 	}
    191 
    192 	void contextMenu(Menu* menu) override {
    193 		auto m = dynamic_cast<LPG*>(module);
    194 		assert(m);
    195 		OptionsMenuItem* bwm = new OptionsMenuItem("LPF poles");
    196 		bwm->addItem(OptionMenuItem("1", [m]() { return m->_lpfPoles == 1; }, [m]() { m->_lpfPoles = 1; }));
    197 		bwm->addItem(OptionMenuItem("2", [m]() { return m->_lpfPoles == 2; }, [m]() { m->_lpfPoles = 2; }));
    198 		bwm->addItem(OptionMenuItem("3", [m]() { return m->_lpfPoles == 3; }, [m]() { m->_lpfPoles = 3; }));
    199 		bwm->addItem(OptionMenuItem("4", [m]() { return m->_lpfPoles == 4; }, [m]() { m->_lpfPoles = 4; }));
    200 		OptionsMenuItem::addToMenu(bwm, menu);
    201 	}
    202 };
    203 
    204 Model* modelLPG = createModel<LPG, LPGWidget>("Bogaudio-LPG", "LPG", "Low-pass gate", "Low-pass gate", "Polyphonic");