BogaudioModules

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

LVCF.cpp (8133B)


      1 
      2 #include "LVCF.hpp"
      3 #include "dsp/pitch.hpp"
      4 
      5 #define POLES_KEY "poles"
      6 #define BANDWIDTH_MODE_KEY "bandwidthMode"
      7 #define LINEAR_BANDWIDTH_MODE_KEY "linear"
      8 #define PITCH_BANDWIDTH_MODE_KEY "pitched"
      9 
     10 void LVCF::Engine::setParams(
     11 	int poles,
     12 	MultimodeFilter::Mode mode,
     13 	float frequency,
     14 	float qbw,
     15 	MultimodeFilter::BandwidthMode bwm
     16 ) {
     17 	frequency = semitoneToFrequency(_frequencySL.next(frequencyToSemitone(frequency)));
     18 	frequency = clamp(semitoneToFrequency(_frequencySL.next(frequencyToSemitone(frequency))), LVCF::minFrequency, LVCF::maxFrequency);
     19 
     20 	_filter.setParams(
     21 		_sampleRate,
     22 		MultimodeFilter::BUTTERWORTH_TYPE,
     23 		poles,
     24 		mode,
     25 		frequency,
     26 		qbw,
     27 		bwm
     28 	);
     29 }
     30 
     31 void LVCF::Engine::sampleRateChange() {
     32 	_sampleRate = APP->engine->getSampleRate();
     33 	_frequencySL.setParams(_sampleRate, 0.5f, frequencyToSemitone(maxFrequency - minFrequency));
     34 	_finalHP.setParams(_sampleRate, MultimodeFilter::BUTTERWORTH_TYPE, 2, MultimodeFilter::HIGHPASS_MODE, 80.0f, MultimodeFilter::minQbw, MultimodeFilter::LINEAR_BANDWIDTH_MODE, MultimodeFilter::MINIMUM_DELAY_MODE);
     35 }
     36 
     37 void LVCF::Engine::reset() {
     38 	_filter.reset();
     39 }
     40 
     41 float LVCF::Engine::next(float sample) {
     42 	return _finalHP.next(_filter.next(sample));
     43 }
     44 
     45 json_t* LVCF::saveToJson(json_t* root) {
     46 	json_object_set_new(root, POLES_KEY, json_integer(_polesSetting));
     47 
     48 	switch (_bandwidthMode) {
     49 		case MultimodeFilter::LINEAR_BANDWIDTH_MODE: {
     50 			json_object_set_new(root, BANDWIDTH_MODE_KEY, json_string(LINEAR_BANDWIDTH_MODE_KEY));
     51 			break;
     52 		}
     53 		case MultimodeFilter::PITCH_BANDWIDTH_MODE: {
     54 			json_object_set_new(root, BANDWIDTH_MODE_KEY, json_string(PITCH_BANDWIDTH_MODE_KEY));
     55 			break;
     56 		}
     57 		default: {}
     58 	}
     59 
     60 	return root;
     61 }
     62 
     63 void LVCF::loadFromJson(json_t* root) {
     64 	json_t* p = json_object_get(root, POLES_KEY);
     65 	if (p) {
     66 		_polesSetting = clamp(json_integer_value(p), 1, 12);
     67 	}
     68 
     69 	json_t* bwm = json_object_get(root, BANDWIDTH_MODE_KEY);
     70 	if (bwm) {
     71 		if (strcmp(json_string_value(bwm), LINEAR_BANDWIDTH_MODE_KEY) == 0) {
     72 			_bandwidthMode = MultimodeFilter::LINEAR_BANDWIDTH_MODE;
     73 		}
     74 		else {
     75 			_bandwidthMode = MultimodeFilter::PITCH_BANDWIDTH_MODE;
     76 		}
     77 	}
     78 }
     79 
     80 void LVCF::sampleRateChange() {
     81 	for (int c = 0; c < _channels; ++c) {
     82 		_engines[c]->sampleRateChange();
     83 	}
     84 }
     85 
     86 bool LVCF::active() {
     87 	return outputs[OUT_OUTPUT].isConnected();
     88 }
     89 
     90 int LVCF::channels() {
     91 	return inputs[IN_INPUT].getChannels();
     92 }
     93 
     94 void LVCF::addChannel(int c) {
     95 	_engines[c] = new Engine();
     96 }
     97 
     98 void LVCF::removeChannel(int c) {
     99 	delete _engines[c];
    100 	_engines[c] = NULL;
    101 }
    102 
    103 MultimodeFilter::Mode LVCF::modeParamValue() {
    104 	return (MultimodeFilter::Mode)(1 + clamp((int)params[MODE_PARAM].getValue(), 0, 4));
    105 }
    106 
    107 void LVCF::modulate() {
    108 	MultimodeFilter::Mode mode = modeParamValue();
    109 	if (_mode != mode || _poles != _polesSetting) {
    110 		_mode = mode;
    111 		_poles = _polesSetting;
    112 		for (int c = 0; c < _channels; ++c) {
    113 			_engines[c]->reset();
    114 		}
    115 	}
    116 
    117 	_q = clamp(params[Q_PARAM].getValue(), 0.0f, 1.0f);
    118 }
    119 
    120 void LVCF::modulateChannel(int c) {
    121 	Engine& e = *_engines[c];
    122 
    123 	float q = _q;
    124 	float f = clamp(params[FREQUENCY_PARAM].getValue(), 0.0f, 1.0f);
    125 	if (inputs[FREQUENCY_CV_INPUT].isConnected()) {
    126 		float fcv = clamp(inputs[FREQUENCY_CV_INPUT].getPolyVoltage(c) / 5.0f, -1.0f, 1.0f);
    127 		fcv *= clamp(params[FREQUENCY_CV_PARAM].getValue(), -1.0f, 1.0f);
    128 		f = std::max(0.0f, f + fcv);
    129 	}
    130 	f *= f;
    131 	f *= maxFrequency;
    132 	f = clamp(f, minFrequency, maxFrequency);
    133 
    134 	e.setParams(
    135 		_poles,
    136 		_mode,
    137 		f,
    138 		q,
    139 		_bandwidthMode
    140 	);
    141 }
    142 
    143 void LVCF::processAlways(const ProcessArgs& args) {
    144 	MultimodeFilter::Mode mode = modeParamValue();
    145 	lights[LOWPASS_LIGHT].value = mode == MultimodeFilter::LOWPASS_MODE;
    146 	lights[HIGHPASS_LIGHT].value = mode == MultimodeFilter::HIGHPASS_MODE;
    147 	lights[BANDPASS_LIGHT].value = mode == MultimodeFilter::BANDPASS_MODE;
    148 	lights[BANDREJECT_LIGHT].value = mode == MultimodeFilter::BANDREJECT_MODE;
    149 }
    150 
    151 void LVCF::processAll(const ProcessArgs& args) {
    152 	outputs[OUT_OUTPUT].setChannels(_channels);
    153 }
    154 
    155 void LVCF::processChannel(const ProcessArgs& args, int c) {
    156 	outputs[OUT_OUTPUT].setVoltage(_engines[c]->next(inputs[IN_INPUT].getVoltage(c)), c);
    157 }
    158 
    159 struct LVCFWidget : BGModuleWidget {
    160 	static constexpr int hp = 3;
    161 
    162 	LVCFWidget(LVCF* module) {
    163 		setModule(module);
    164 		box.size = Vec(RACK_GRID_WIDTH * hp, RACK_GRID_HEIGHT);
    165 		setPanel(box.size, "LVCF");
    166 		createScrews();
    167 
    168 		// generated by svg_widgets.rb
    169 		auto frequencyParamPosition = Vec(9.5, 39.0);
    170 		auto frequencyCvParamPosition = Vec(14.5, 93.5);
    171 		auto qParamPosition = Vec(9.5, 138.0);
    172 		auto modeParamPosition = Vec(18.0, 204.0);
    173 
    174 		auto inInputPosition = Vec(10.5, 228.0);
    175 		auto frequencyCvInputPosition = Vec(10.5, 263.0);
    176 
    177 		auto outOutputPosition = Vec(10.5, 301.0);
    178 
    179 		auto lowpassLightPosition = Vec(3.0, 181.0);
    180 		auto bandpassLightPosition = Vec(3.0, 194.0);
    181 		auto highpassLightPosition = Vec(25.0, 181.0);
    182 		auto bandrejectLightPosition = Vec(25.0, 194.0);
    183 		// end generated by svg_widgets.rb
    184 
    185 		addParam(createParam<Knob26>(frequencyParamPosition, module, LVCF::FREQUENCY_PARAM));
    186 		addParam(createParam<Knob16>(frequencyCvParamPosition, module, LVCF::FREQUENCY_CV_PARAM));
    187 		addParam(createParam<Knob26>(qParamPosition, module, LVCF::Q_PARAM));
    188 		addParam(createParam<StatefulButton9>(modeParamPosition, module, LVCF::MODE_PARAM));
    189 
    190 		addInput(createInput<Port24>(inInputPosition, module, LVCF::IN_INPUT));
    191 		addInput(createInput<Port24>(frequencyCvInputPosition, module, LVCF::FREQUENCY_CV_INPUT));
    192 
    193 		addOutput(createOutput<Port24>(outOutputPosition, module, LVCF::OUT_OUTPUT));
    194 
    195 		addChild(createLight<BGSmallLight<GreenLight>>(lowpassLightPosition, module, LVCF::LOWPASS_LIGHT));
    196 		addChild(createLight<BGSmallLight<GreenLight>>(bandpassLightPosition, module, LVCF::BANDPASS_LIGHT));
    197 		addChild(createLight<BGSmallLight<GreenLight>>(highpassLightPosition, module, LVCF::HIGHPASS_LIGHT));
    198 		addChild(createLight<BGSmallLight<GreenLight>>(bandrejectLightPosition, module, LVCF::BANDREJECT_LIGHT));
    199 	}
    200 
    201 	void contextMenu(Menu* menu) override {
    202 		auto m = dynamic_cast<LVCF*>(module);
    203 		assert(m);
    204 
    205 		OptionsMenuItem* s = new OptionsMenuItem("Slope");
    206 		s->addItem(OptionMenuItem("1 pole", [m]() { return m->_polesSetting == 1; }, [m]() { m->_polesSetting = 1; }));
    207 		s->addItem(OptionMenuItem("2 poles", [m]() { return m->_polesSetting == 2; }, [m]() { m->_polesSetting = 2; }));
    208 		s->addItem(OptionMenuItem("3 poles", [m]() { return m->_polesSetting == 3; }, [m]() { m->_polesSetting = 3; }));
    209 		s->addItem(OptionMenuItem("4 poles", [m]() { return m->_polesSetting == 4; }, [m]() { m->_polesSetting = 4; }));
    210 		s->addItem(OptionMenuItem("5 poles", [m]() { return m->_polesSetting == 5; }, [m]() { m->_polesSetting = 5; }));
    211 		s->addItem(OptionMenuItem("6 poles", [m]() { return m->_polesSetting == 6; }, [m]() { m->_polesSetting = 6; }));
    212 		s->addItem(OptionMenuItem("7 poles", [m]() { return m->_polesSetting == 7; }, [m]() { m->_polesSetting = 7; }));
    213 		s->addItem(OptionMenuItem("8 poles", [m]() { return m->_polesSetting == 8; }, [m]() { m->_polesSetting = 8; }));
    214 		s->addItem(OptionMenuItem("9 poles", [m]() { return m->_polesSetting == 9; }, [m]() { m->_polesSetting = 9; }));
    215 		s->addItem(OptionMenuItem("10 poles", [m]() { return m->_polesSetting == 10; }, [m]() { m->_polesSetting = 10; }));
    216 		s->addItem(OptionMenuItem("11 poles", [m]() { return m->_polesSetting == 11; }, [m]() { m->_polesSetting = 11; }));
    217 		s->addItem(OptionMenuItem("12 poles", [m]() { return m->_polesSetting == 12; }, [m]() { m->_polesSetting = 12; }));
    218 		OptionsMenuItem::addToMenu(s, menu);
    219 
    220 		OptionsMenuItem* bwm = new OptionsMenuItem("Bandwidth mode");
    221 		bwm->addItem(OptionMenuItem("Pitched", [m]() { return m->_bandwidthMode == MultimodeFilter::PITCH_BANDWIDTH_MODE; }, [m]() { m->_bandwidthMode = MultimodeFilter::PITCH_BANDWIDTH_MODE; }));
    222 		bwm->addItem(OptionMenuItem("Linear", [m]() { return m->_bandwidthMode == MultimodeFilter::LINEAR_BANDWIDTH_MODE; }, [m]() { m->_bandwidthMode = MultimodeFilter::LINEAR_BANDWIDTH_MODE; }));
    223 		OptionsMenuItem::addToMenu(bwm, menu);
    224 	}
    225 };
    226 
    227 Model* modelLVCF = createModel<LVCF, LVCFWidget>("Bogaudio-LVCF", "LVCF", "Multimode filter", "Filter", "Polyphonic");