BogaudioModules

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

MegaGate.cpp (17842B)


      1 
      2 #include "MegaGate.hpp"
      3 #include "dsp/pitch.hpp"
      4 
      5 #define VELOCITY_MINIMUM_DECIBELS "velocity_minimum_decibels"
      6 
      7 void MegaGate::Engine::reset() {
      8 	trigger.reset();
      9 	gatePulseGen.process(10.0);
     10 }
     11 
     12 void MegaGate::Engine::setSampleRate(float sr) {
     13 	velocitySL.setParams(sr, 5.0f, 1.0f);
     14 	tiltSL.setParams(sr, 10.0f, 2.0f);
     15 	leftVcaSL.setParams(sr, 5.0f, 1.0f);
     16 	rightVcaSL.setParams(sr, 5.0f, 1.0f);
     17 	leftFinalHP.setParams(sr, MultimodeFilter::BUTTERWORTH_TYPE, 2, MultimodeFilter::HIGHPASS_MODE, 80.0f, MultimodeFilter::minQbw, MultimodeFilter::LINEAR_BANDWIDTH_MODE, MultimodeFilter::MINIMUM_DELAY_MODE);
     18 	rightFinalHP.setParams(sr, MultimodeFilter::BUTTERWORTH_TYPE, 2, MultimodeFilter::HIGHPASS_MODE, 80.0f, MultimodeFilter::minQbw, MultimodeFilter::LINEAR_BANDWIDTH_MODE, MultimodeFilter::MINIMUM_DELAY_MODE);
     19 }
     20 
     21 void MegaGate::reset() {
     22 	for (int c = 0; c < _channels; ++c) {
     23 		_engines[c]->reset();
     24 	}
     25 }
     26 
     27 void MegaGate::sampleRateChange() {
     28 	_sampleRate = APP->engine->getSampleRate();
     29 	_sampleTime = APP->engine->getSampleTime();
     30 	for (int i = 0; i < _channels; ++i) {
     31 		_engines[i]->setSampleRate(_sampleRate);
     32 	}
     33 }
     34 
     35 json_t* MegaGate::saveToJson(json_t* root) {
     36 	root = LPGEnvBaseModule::saveToJson(root);
     37 	json_object_set_new(root, VELOCITY_MINIMUM_DECIBELS, json_real(_minVelocityDb));
     38 	return root;
     39 }
     40 
     41 void MegaGate::loadFromJson(json_t* root) {
     42 	LPGEnvBaseModule::loadFromJson(root);
     43 	json_t* mdb = json_object_get(root, VELOCITY_MINIMUM_DECIBELS);
     44 	if (mdb) {
     45 		_minVelocityDb = json_real_value(mdb);
     46 	}
     47 }
     48 
     49 bool MegaGate::active() {
     50 	return outputs[LEFT_OUTPUT].isConnected() || outputs[RIGHT_OUTPUT].isConnected() || outputs[ENV_OUTPUT].isConnected();
     51 }
     52 
     53 int MegaGate::channels() {
     54 	return inputs[GATE_INPUT].getChannels();
     55 }
     56 
     57 void MegaGate::addChannel(int c) {
     58 	_engines[c] = new Engine();
     59 	_engines[c]->reset();
     60 	_engines[c]->setSampleRate(_sampleRate);
     61 }
     62 
     63 void MegaGate::removeChannel(int c) {
     64 	delete _engines[c];
     65 	_engines[c] = NULL;
     66 }
     67 
     68 void MegaGate::modulateChannel(int c) {
     69 	_engines[c]->slew.modulate(
     70 		_sampleRate,
     71 		params[RISE_PARAM],
     72 		&inputs[RISE_INPUT],
     73 		300.0f * _timeScale,
     74 		params[RISE_SHAPE_PARAM],
     75 		params[FALL_PARAM],
     76 		&inputs[FALL_INPUT],
     77 		1000.0f * _timeScale,
     78 		params[FALL_SHAPE_PARAM],
     79 		c,
     80 		false,
     81 		&inputs[SHAPE_INPUT],
     82 		_riseShapeMode,
     83 		_fallShapeMode
     84 	);
     85 }
     86 
     87 void MegaGate::processChannel(const ProcessArgs& args, int c) {
     88 	Engine& e = *_engines[c];
     89 
     90 	float in = inputs[GATE_INPUT].getPolyVoltage(c);
     91 	if (e.trigger.process(in)) {
     92 		float time = clamp(params[MINIMUM_GATE_PARAM].getValue(), 0.0f, 1.0f);
     93 		if (inputs[MINIMUM_GATE_INPUT].isConnected()) {
     94 			time *= clamp(inputs[MINIMUM_GATE_INPUT].getPolyVoltage(c) / 10.0f, 0.0f, 1.0f);
     95 		}
     96 		time *= time;
     97 		time *= _timeScale;
     98 		e.gateSeconds = time;
     99 
    100 		e.gateElapsedSeconds = 0.0f;
    101 		if (_gateToTrigger) {
    102 			e.gateSeconds = std::max(0.01f, time);
    103 		}
    104 		else {
    105 			e.gateSeconds = time;
    106 		}
    107 	}
    108 	else {
    109 		e.gateElapsedSeconds += _sampleTime;
    110 	}
    111 
    112 	float gate = 0.0f;
    113 	if (e.gateElapsedSeconds < e.gateSeconds) {
    114 		gate = 10.0f;
    115 	}
    116 	else if (!_gateToTrigger) {
    117 		gate = in;
    118 	}
    119 
    120 	float velocity = 1.0f;
    121 	if (inputs[VELOCITY_INPUT].isConnected()) {
    122 		velocity = clamp(inputs[VELOCITY_INPUT].getPolyVoltage(c) / 10.0f, 0.0f, 1.0f);
    123 	}
    124 	velocity = e.velocitySL.next(velocity);
    125 	e.velocityAmp.setLevel(_minVelocityDb + velocity * (_maxVelocityDb - _minVelocityDb));
    126 	float env = e.velocityAmp.next(e.slew.next(gate));
    127 	env /= 10.0f;
    128 
    129 	float tilt = clamp(params[TILT_PARAM].getValue(), -1.0f, 1.0f);
    130 	if (inputs[TILT_INPUT].isConnected()) {
    131 		tilt *= clamp(inputs[TILT_INPUT].getPolyVoltage(c) / 5.0f, -1.0f, 1.0f);
    132 	}
    133 	tilt = e.tiltSL.next(tilt);
    134 
    135 	float leftEnv = env;
    136 	float rightEnv = env;
    137 	if (tilt < 0.0f) {
    138 		rightEnv *= 1.0f + tilt;
    139 	}
    140 	else {
    141 		leftEnv *= 1.0f - tilt;
    142 	}
    143 
    144 	float lpfEnv = clamp(params[LPF_ENV_PARAM].getValue(), -1.0f, 1.0f);
    145 	if (inputs[LPF_ENV_INPUT].isConnected()) {
    146 		float cv = clamp(params[LPF_ENV_ATTENUATOR_PARAM].getValue(), -1.0f, 1.0f);
    147 		cv *= clamp(inputs[LPF_ENV_INPUT].getPolyVoltage(c) / 5.0f, -1.0f, 1.0f);
    148 		lpfEnv = clamp(lpfEnv + cv, -1.0f, 1.0f);
    149 	}
    150 	float lpfBias = clamp(params[LPF_BIAS_PARAM].getValue(), -1.0f, 1.0f);
    151 	if (inputs[LPF_BIAS_INPUT].isConnected()) {
    152 		float cv = clamp(params[LPF_BIAS_ATTENUATOR_PARAM].getValue(), -1.0f, 1.0f);
    153 		cv *= clamp(inputs[LPF_BIAS_INPUT].getPolyVoltage(c) / 5.0f, -1.0f, 1.0f);
    154 		lpfBias = clamp(lpfBias + cv, -1.0f, 1.0f);
    155 	}
    156 	lpfBias *= lpfBias;
    157 	int lpfPoles = 1 + roundf(clamp(params[LPF_POLES_PARAM].getValue(), 0.0f, 3.0f));
    158 
    159 	float hpfEnv = clamp(params[HPF_ENV_PARAM].getValue(), -1.0f, 1.0f);
    160 	if (inputs[HPF_ENV_INPUT].isConnected()) {
    161 		float cv = clamp(params[HPF_ENV_ATTENUATOR_PARAM].getValue(), -1.0f, 1.0f);
    162 		cv *= clamp(inputs[HPF_ENV_INPUT].getPolyVoltage(c) / 5.0f, -1.0f, 1.0f);
    163 		hpfEnv = clamp(hpfEnv + cv, -1.0f, 1.0f);
    164 	}
    165 	float hpfBias = clamp(params[HPF_BIAS_PARAM].getValue(), -1.0f, 1.0f);
    166 	if (inputs[HPF_BIAS_INPUT].isConnected()) {
    167 		float cv = clamp(params[HPF_BIAS_ATTENUATOR_PARAM].getValue(), -1.0f, 1.0f);
    168 		cv *= clamp(inputs[HPF_BIAS_INPUT].getPolyVoltage(c) / 5.0f, -1.0f, 1.0f);
    169 		hpfBias = clamp(hpfBias + cv, -1.0f, 1.0f);
    170 	}
    171 	hpfBias *= hpfBias;
    172 	int hpfPoles = 1 + roundf(clamp(params[HPF_POLES_PARAM].getValue(), 0.0f, 3.0f));
    173 
    174 	bool serial = params[FILTERS_SERIAL_PARAM].getValue() > 0.5f;
    175 	bool linear = params[LINEAR_VCA_PARAM].getValue() > 0.5f;
    176 
    177 	float vcaEnv = clamp(params[VCA_ENV_PARAM].getValue(), -1.0f, 1.0f);
    178 	if (inputs[VCA_ENV_INPUT].isConnected()) {
    179 		float cv = clamp(params[VCA_ENV_ATTENUATOR_PARAM].getValue(), -1.0f, 1.0f);
    180 		cv *= clamp(inputs[VCA_ENV_INPUT].getPolyVoltage(c) / 5.0f, -1.0f, 1.0f);
    181 		vcaEnv = clamp(vcaEnv + cv, -1.0f, 1.0f);
    182 	}
    183 	float vcaBias = clamp(params[VCA_BIAS_PARAM].getValue(), 0.0f, 1.0f);
    184 	if (inputs[VCA_ENV_INPUT].isConnected()) {
    185 		float cv = clamp(params[VCA_BIAS_ATTENUATOR_PARAM].getValue(), -1.0f, 1.0f);
    186 		cv *= clamp(inputs[VCA_BIAS_INPUT].getPolyVoltage(c) / 5.0f, -1.0f, 1.0f);
    187 		vcaBias = clamp(vcaBias + cv, 0.0f, 1.0f);
    188 	}
    189 
    190 	{
    191 		float f = clamp(lpfBias + leftEnv * lpfEnv, 0.0f, 1.0f);
    192 		f *= maxFilterCutoff;
    193 		f = std::max(f, MultimodeFilter4::minFrequency);
    194 		e.leftLpf.setParams(
    195 			_sampleRate,
    196 			MultimodeFilter::BUTTERWORTH_TYPE,
    197 			lpfPoles,
    198 			MultimodeFilter::LOWPASS_MODE,
    199 			f,
    200 			0.0f
    201 		);
    202 	}
    203 	{
    204 		float f = clamp(hpfBias - leftEnv * hpfEnv, 0.0f, 1.0f);
    205 		f *= maxFilterCutoff;
    206 		f = std::max(f, MultimodeFilter4::minFrequency);
    207 		e.leftHpf.setParams(
    208 			_sampleRate,
    209 			MultimodeFilter::BUTTERWORTH_TYPE,
    210 			hpfPoles,
    211 			MultimodeFilter::HIGHPASS_MODE,
    212 			f,
    213 			0.0f
    214 		);
    215 	}
    216 	float level = clamp(vcaBias + leftEnv * vcaEnv, 0.0f, 1.0f);
    217 	level = e.leftVcaSL.next(level);
    218 
    219 	float leftIn = inputs[LEFT_INPUT].getPolyVoltage(c);
    220 	float leftOut = 0.0f;
    221 	if (serial) {
    222 		leftOut = e.leftHpf.next(e.leftLpf.next(leftIn));
    223 	}
    224 	else {
    225 		leftOut = e.leftLpf.next(leftIn) + e.leftHpf.next(leftIn);
    226 	}
    227 	leftOut = e.leftFinalHP.next(leftOut);
    228 	if (linear) {
    229 		leftOut *= level;
    230 	}
    231 	else {
    232 		e.leftVca.setLevel(Amplifier::minDecibels * (1.0f - level));
    233 		leftOut = e.leftVca.next(leftOut);
    234 	}
    235 
    236 	float rightOut = 0.0f;
    237 	if (outputs[RIGHT_OUTPUT].isConnected()) {
    238 		float rightIn = leftIn;
    239 		if (inputs[RIGHT_INPUT].isConnected()) {
    240 			rightIn = inputs[RIGHT_INPUT].getPolyVoltage(c);
    241 		}
    242 
    243 		{
    244 			float f = clamp(lpfBias + rightEnv * lpfEnv, 0.0f, 1.0f);
    245 			f *= maxFilterCutoff;
    246 			f = std::max(f, MultimodeFilter4::minFrequency);
    247 			e.rightLpf.setParams(
    248 				_sampleRate,
    249 				MultimodeFilter::BUTTERWORTH_TYPE,
    250 				lpfPoles,
    251 				MultimodeFilter::LOWPASS_MODE,
    252 				f,
    253 				0.0f
    254 			);
    255 		}
    256 		{
    257 			float f = clamp(hpfBias - rightEnv * hpfEnv, 0.0f, 1.0f);
    258 			f *= maxFilterCutoff;
    259 			f = std::max(f, MultimodeFilter4::minFrequency);
    260 			e.rightHpf.setParams(
    261 				_sampleRate,
    262 				MultimodeFilter::BUTTERWORTH_TYPE,
    263 				hpfPoles,
    264 				MultimodeFilter::HIGHPASS_MODE,
    265 				f,
    266 				0.0f
    267 			);
    268 		}
    269 		float level = clamp(vcaBias + rightEnv * vcaEnv, 0.0f, 1.0f);
    270 		level = e.rightVcaSL.next(level);
    271 
    272 		if (serial) {
    273 			rightOut = e.rightHpf.next(e.rightLpf.next(rightIn));
    274 		}
    275 		else {
    276 			rightOut = e.rightLpf.next(rightIn) + e.rightHpf.next(rightIn);
    277 		}
    278 		rightOut = e.rightFinalHP.next(rightOut);
    279 		if (linear) {
    280 			rightOut *= level;
    281 		}
    282 		else {
    283 			e.rightVca.setLevel(Amplifier::minDecibels * (1.0f - level));
    284 			rightOut = e.rightVca.next(rightOut);
    285 		}
    286 	}
    287 
    288 	outputs[ENV_OUTPUT].setChannels(_channels);
    289 	outputs[ENV_OUTPUT].setVoltage(env * 10.0f, c);
    290 	outputs[LEFT_OUTPUT].setChannels(_channels);
    291 	outputs[LEFT_OUTPUT].setVoltage(leftOut, c);
    292 	outputs[RIGHT_OUTPUT].setChannels(_channels);
    293 	outputs[RIGHT_OUTPUT].setVoltage(rightOut, c);
    294 }
    295 
    296 void MegaGate::processAlways(const ProcessArgs& args) {
    297 	{
    298 		int poles = params[LPF_POLES_PARAM].getValue();
    299 		lights[LPF_POLES_1_LIGHT].value = poles == 0;
    300 		lights[LPF_POLES_2_LIGHT].value = poles == 1;
    301 		lights[LPF_POLES_3_LIGHT].value = poles == 2;
    302 		lights[LPF_POLES_4_LIGHT].value = poles == 3;
    303 	}
    304 	{
    305 		int poles = params[HPF_POLES_PARAM].getValue();
    306 		lights[HPF_POLES_1_LIGHT].value = poles == 0;
    307 		lights[HPF_POLES_2_LIGHT].value = poles == 1;
    308 		lights[HPF_POLES_3_LIGHT].value = poles == 2;
    309 		lights[HPF_POLES_4_LIGHT].value = poles == 3;
    310 	}
    311 }
    312 
    313 struct MegaGateWidget : LPGEnvBaseWidget {
    314 	static constexpr int hp = 18;
    315 
    316 	MegaGateWidget(MegaGate* module) {
    317 		setModule(module);
    318 		box.size = Vec(RACK_GRID_WIDTH * hp, RACK_GRID_HEIGHT);
    319 		setPanel(box.size, "MegaGate");
    320 		createScrews();
    321 
    322 		// generated by svg_widgets.rb
    323 		auto riseParamPosition = Vec(17.5, 41.5);
    324 		auto riseShapeParamPosition = Vec(24.0, 89.0);
    325 		auto fallParamPosition = Vec(72.5, 41.5);
    326 		auto fallShapeParamPosition = Vec(79.0, 89.0);
    327 		auto minimumGateParamPosition = Vec(17.5, 176.0);
    328 		auto tiltParamPosition = Vec(72.5, 176.0);
    329 		auto gateToTriggerParamPosition = Vec(20.0, 255.0);
    330 		auto times10xParamPosition = Vec(20.0, 269.0);
    331 		auto filtersSerialParamPosition = Vec(90.0, 255.0);
    332 		auto linearVcaParamPosition = Vec(90.0, 269.0);
    333 		auto lpfEnvParamPosition = Vec(136.5, 42.0);
    334 		auto lpfEnvAttenuatorParamPosition = Vec(143.0, 81.0);
    335 		auto lpfBiasParamPosition = Vec(186.5, 42.0);
    336 		auto lpfBiasAttenuatorParamPosition = Vec(193.0, 81.0);
    337 		auto lpfPolesParamPosition = Vec(241.0, 87.0);
    338 		auto hpfEnvParamPosition = Vec(136.5, 157.0);
    339 		auto hpfEnvAttenuatorParamPosition = Vec(143.0, 196.0);
    340 		auto hpfBiasParamPosition = Vec(186.5, 157.0);
    341 		auto hpfBiasAttenuatorParamPosition = Vec(193.0, 196.0);
    342 		auto hpfPolesParamPosition = Vec(239.0, 202.0);
    343 		auto vcaEnvParamPosition = Vec(163.5, 271.0);
    344 		auto vcaEnvAttenuatorParamPosition = Vec(170.0, 310.0);
    345 		auto vcaBiasParamPosition = Vec(213.5, 271.0);
    346 		auto vcaBiasAttenuatorParamPosition = Vec(220.0, 310.0);
    347 
    348 		auto riseInputPosition = Vec(20.5, 118.0);
    349 		auto fallInputPosition = Vec(75.5, 118.0);
    350 		auto minimumGateInputPosition = Vec(20.5, 220.0);
    351 		auto tiltInputPosition = Vec(75.5, 220.0);
    352 		auto velocityInputPosition = Vec(8.5, 287.0);
    353 		auto shapeInputPosition = Vec(38.5, 287.0);
    354 		auto leftInputPosition = Vec(68.5, 287.0);
    355 		auto rightInputPosition = Vec(98.5, 287.0);
    356 		auto gateInputPosition = Vec(8.5, 324.0);
    357 		auto lpfEnvInputPosition = Vec(139.0, 106.0);
    358 		auto lpfBiasInputPosition = Vec(189.0, 106.0);
    359 		auto hpfEnvInputPosition = Vec(139.0, 221.0);
    360 		auto hpfBiasInputPosition = Vec(189.0, 221.0);
    361 		auto vcaEnvInputPosition = Vec(166.0, 335.0);
    362 		auto vcaBiasInputPosition = Vec(216.0, 335.0);
    363 
    364 		auto envOutputPosition = Vec(38.5, 324.0);
    365 		auto leftOutputPosition = Vec(68.5, 324.0);
    366 		auto rightOutputPosition = Vec(98.5, 324.0);
    367 
    368 		auto lpfPoles1LightPosition = Vec(239.0, 40.0);
    369 		auto lpfPoles2LightPosition = Vec(239.0, 52.0);
    370 		auto lpfPoles3LightPosition = Vec(239.0, 64.0);
    371 		auto lpfPoles4LightPosition = Vec(239.0, 76.0);
    372 		auto hpfPoles1LightPosition = Vec(237.0, 155.0);
    373 		auto hpfPoles2LightPosition = Vec(237.0, 167.0);
    374 		auto hpfPoles3LightPosition = Vec(237.0, 179.0);
    375 		auto hpfPoles4LightPosition = Vec(237.0, 191.0);
    376 		// end generated by svg_widgets.rb
    377 
    378 		addParam(createParam<Knob29>(riseParamPosition, module, MegaGate::RISE_PARAM));
    379 		addParam(createParam<Knob16>(riseShapeParamPosition, module, MegaGate::RISE_SHAPE_PARAM));
    380 		addParam(createParam<Knob29>(fallParamPosition, module, MegaGate::FALL_PARAM));
    381 		addParam(createParam<Knob16>(fallShapeParamPosition, module, MegaGate::FALL_SHAPE_PARAM));
    382 		addParam(createParam<Knob29>(minimumGateParamPosition, module, MegaGate::MINIMUM_GATE_PARAM));
    383 		addParam(createParam<Knob29>(tiltParamPosition, module, MegaGate::TILT_PARAM));
    384 		addParam(createParam<IndicatorButtonGreen9>(gateToTriggerParamPosition, module, MegaGate::GATE_TO_TRIGGER_PARAM));
    385 		addParam(createParam<IndicatorButtonGreen9>(times10xParamPosition, module, MegaGate::TIMES_10X_PARAM));
    386 		addParam(createParam<IndicatorButtonGreen9>(filtersSerialParamPosition, module, MegaGate::FILTERS_SERIAL_PARAM));
    387 		addParam(createParam<IndicatorButtonGreen9>(linearVcaParamPosition, module, MegaGate::LINEAR_VCA_PARAM));
    388 		addParam(createParam<Knob29>(lpfEnvParamPosition, module, MegaGate::LPF_ENV_PARAM));
    389 		addParam(createParam<Knob16>(lpfEnvAttenuatorParamPosition, module, MegaGate::LPF_ENV_ATTENUATOR_PARAM));
    390 		addParam(createParam<Knob29>(lpfBiasParamPosition, module, MegaGate::LPF_BIAS_PARAM));
    391 		addParam(createParam<Knob16>(lpfBiasAttenuatorParamPosition, module, MegaGate::LPF_BIAS_ATTENUATOR_PARAM));
    392 		addParam(createParam<StatefulButton9>(lpfPolesParamPosition, module, MegaGate::LPF_POLES_PARAM));
    393 		addParam(createParam<Knob29>(hpfEnvParamPosition, module, MegaGate::HPF_ENV_PARAM));
    394 		addParam(createParam<Knob16>(hpfEnvAttenuatorParamPosition, module, MegaGate::HPF_ENV_ATTENUATOR_PARAM));
    395 		addParam(createParam<Knob29>(hpfBiasParamPosition, module, MegaGate::HPF_BIAS_PARAM));
    396 		addParam(createParam<Knob16>(hpfBiasAttenuatorParamPosition, module, MegaGate::HPF_BIAS_ATTENUATOR_PARAM));
    397 		addParam(createParam<StatefulButton9>(hpfPolesParamPosition, module, MegaGate::HPF_POLES_PARAM));
    398 		addParam(createParam<Knob29>(vcaEnvParamPosition, module, MegaGate::VCA_ENV_PARAM));
    399 		addParam(createParam<Knob16>(vcaEnvAttenuatorParamPosition, module, MegaGate::VCA_ENV_ATTENUATOR_PARAM));
    400 		addParam(createParam<Knob29>(vcaBiasParamPosition, module, MegaGate::VCA_BIAS_PARAM));
    401 		addParam(createParam<Knob16>(vcaBiasAttenuatorParamPosition, module, MegaGate::VCA_BIAS_ATTENUATOR_PARAM));
    402 
    403 		addInput(createInput<Port24>(riseInputPosition, module, MegaGate::RISE_INPUT));
    404 		addInput(createInput<Port24>(fallInputPosition, module, MegaGate::FALL_INPUT));
    405 		addInput(createInput<Port24>(minimumGateInputPosition, module, MegaGate::MINIMUM_GATE_INPUT));
    406 		addInput(createInput<Port24>(tiltInputPosition, module, MegaGate::TILT_INPUT));
    407 		addInput(createInput<Port24>(velocityInputPosition, module, MegaGate::VELOCITY_INPUT));
    408 		addInput(createInput<Port24>(shapeInputPosition, module, MegaGate::SHAPE_INPUT));
    409 		addInput(createInput<Port24>(leftInputPosition, module, MegaGate::LEFT_INPUT));
    410 		addInput(createInput<Port24>(rightInputPosition, module, MegaGate::RIGHT_INPUT));
    411 		addInput(createInput<Port24>(gateInputPosition, module, MegaGate::GATE_INPUT));
    412 		addInput(createInput<Port24>(lpfEnvInputPosition, module, MegaGate::LPF_ENV_INPUT));
    413 		addInput(createInput<Port24>(lpfBiasInputPosition, module, MegaGate::LPF_BIAS_INPUT));
    414 		addInput(createInput<Port24>(hpfEnvInputPosition, module, MegaGate::HPF_ENV_INPUT));
    415 		addInput(createInput<Port24>(hpfBiasInputPosition, module, MegaGate::HPF_BIAS_INPUT));
    416 		addInput(createInput<Port24>(vcaEnvInputPosition, module, MegaGate::VCA_ENV_INPUT));
    417 		addInput(createInput<Port24>(vcaBiasInputPosition, module, MegaGate::VCA_BIAS_INPUT));
    418 
    419 		addOutput(createOutput<Port24>(envOutputPosition, module, MegaGate::ENV_OUTPUT));
    420 		addOutput(createOutput<Port24>(leftOutputPosition, module, MegaGate::LEFT_OUTPUT));
    421 		addOutput(createOutput<Port24>(rightOutputPosition, module, MegaGate::RIGHT_OUTPUT));
    422 
    423 		addChild(createLight<BGSmallLight<GreenLight>>(lpfPoles1LightPosition, module, MegaGate::LPF_POLES_1_LIGHT));
    424 		addChild(createLight<BGSmallLight<GreenLight>>(lpfPoles2LightPosition, module, MegaGate::LPF_POLES_2_LIGHT));
    425 		addChild(createLight<BGSmallLight<GreenLight>>(lpfPoles3LightPosition, module, MegaGate::LPF_POLES_3_LIGHT));
    426 		addChild(createLight<BGSmallLight<GreenLight>>(lpfPoles4LightPosition, module, MegaGate::LPF_POLES_4_LIGHT));
    427 		addChild(createLight<BGSmallLight<GreenLight>>(hpfPoles1LightPosition, module, MegaGate::HPF_POLES_1_LIGHT));
    428 		addChild(createLight<BGSmallLight<GreenLight>>(hpfPoles2LightPosition, module, MegaGate::HPF_POLES_2_LIGHT));
    429 		addChild(createLight<BGSmallLight<GreenLight>>(hpfPoles3LightPosition, module, MegaGate::HPF_POLES_3_LIGHT));
    430 		addChild(createLight<BGSmallLight<GreenLight>>(hpfPoles4LightPosition, module, MegaGate::HPF_POLES_4_LIGHT));
    431 	}
    432 
    433 	void contextMenu(Menu* menu) override {
    434 		LPGEnvBaseWidget::contextMenu(menu);
    435 		auto m = dynamic_cast<MegaGate*>(module);
    436 		assert(m);
    437 		OptionsMenuItem* mi = new OptionsMenuItem("Minimum velocity output gain");
    438 		mi->addItem(OptionMenuItem("-3db", [m]() { return m->_minVelocityDb == -3.0f; }, [m]() { m->_minVelocityDb = -3.0f; }));
    439 		mi->addItem(OptionMenuItem("-6db", [m]() { return m->_minVelocityDb == -6.0f; }, [m]() { m->_minVelocityDb = -6.0f; }));
    440 		mi->addItem(OptionMenuItem("-12db", [m]() { return m->_minVelocityDb == -12.0f; }, [m]() { m->_minVelocityDb = -12.0f; }));
    441 		mi->addItem(OptionMenuItem("-24db", [m]() { return m->_minVelocityDb == -24.0f; }, [m]() { m->_minVelocityDb = -24.0f; }));
    442 		mi->addItem(OptionMenuItem("-60db", [m]() { return m->_minVelocityDb == -60.0f; }, [m]() { m->_minVelocityDb = -60.0f; }));
    443 		OptionsMenuItem::addToMenu(mi, menu);
    444 	}
    445 };
    446 
    447 Model* modelMegaGate = createModel<MegaGate, MegaGateWidget>("Bogaudio-MegaGate", "MEGAGATE", "Low- and high-pass gate", "Low-pass gate", "Dual", "Polyphonic");