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");