BogaudioModules

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

FFB.cpp (6128B)


      1 
      2 #include "FFB.hpp"
      3 #include "dsp/pitch.hpp"
      4 
      5 void FFB::Engine::sampleRateChange() {
      6 	float sr = APP->engine->getSampleRate();
      7 	for (int i = 0; i < 14; i++) {
      8 		_slews[i].setParams(sr, 1.0f, 1.0f);
      9 	}
     10 	configureBands(sr, _semitonesOffset);
     11 }
     12 
     13 void FFB::Engine::setSemitonesOffset(float semitonesOffset) {
     14 	if (_semitonesOffset != semitonesOffset) {
     15 		_semitonesOffset = semitonesOffset;
     16 		configureBands(APP->engine->getSampleRate(), _semitonesOffset);
     17 	}
     18 }
     19 
     20 void FFB::Engine::configureBands(float sr, float semitonesOffset) {
     21 	_lowPass.setParams(
     22 		sr,
     23 		MultimodeFilter::BUTTERWORTH_TYPE,
     24 		12.0f,
     25 		MultimodeFilter::LOWPASS_MODE,
     26 		bandFrequency(0, semitonesOffset),
     27 		0.0f
     28 	);
     29 	for (int i = 0; i < 12; ++i) {
     30 		_bandPasses[i].setParams(
     31 			sr,
     32 			bandFrequency(i + 1, semitonesOffset),
     33 			0.22f / MultimodeFilter::maxBWPitch,
     34 			MultimodeFilter::PITCH_BANDWIDTH_MODE
     35 		);
     36 	}
     37 	_highPass.setParams(
     38 		sr,
     39 		MultimodeFilter::BUTTERWORTH_TYPE,
     40 		12.0f,
     41 		MultimodeFilter::HIGHPASS_MODE,
     42 		bandFrequency(13, semitonesOffset),
     43 		0.0f
     44 	);
     45 }
     46 
     47 float FFB::Engine::bandFrequency(int i, float semitonesOffset) {
     48 	static const float fs[14] = {
     49 		95.0f,
     50 		125.0f,
     51 		175.0f,
     52 		250.0f,
     53 		350.0f,
     54 		500.0f,
     55 		700.0f,
     56 		1000.0f,
     57 		1400.0f,
     58 		2000.0f,
     59 		2800.0f,
     60 		4000.0f,
     61 		5600.0f,
     62 		6900.0f
     63 	};
     64 	return semitoneToFrequency(frequencyToSemitone(fs[i]) + semitonesOffset);
     65 }
     66 
     67 void FFB::sampleRateChange() {
     68 	for (int c = 0; c < _channels; ++c) {
     69 		_engines[c]->sampleRateChange();
     70 	}
     71 }
     72 
     73 bool FFB::active() {
     74 	return outputs[ALL_OUTPUT].isConnected() || outputs[ODD_OUTPUT].isConnected() || outputs[EVEN_OUTPUT].isConnected();
     75 }
     76 
     77 int FFB::channels() {
     78 	return inputs[IN_INPUT].getChannels();
     79 }
     80 
     81 void FFB::addChannel(int c) {
     82 	_engines[c] = new Engine();
     83 }
     84 
     85 void FFB::removeChannel(int c) {
     86 	delete _engines[c];
     87 	_engines[c] = NULL;
     88 }
     89 
     90 void FFB::modulate() {
     91 	for (int i = 0; i < 14; ++i) {
     92 		_levels[i] = clamp(params[LOWPASS_PARAM + i].getValue(), 0.0f, 1.0f);
     93 	}
     94 }
     95 
     96 void FFB::modulateChannel(int c) {
     97 	Engine& e = *_engines[c];
     98 
     99 	for (int i = 0; i < 14; ++i) {
    100 		float level = e._slews[i].next(_levels[i]);
    101 		level = 1.0f - level;
    102 		level *= Amplifier::minDecibels;
    103 		e._amplifiers[i].setLevel(level);
    104 	}
    105 
    106 	float semitones = clamp(params[CV_PARAM].getValue(), -1.0f, 1.0f);
    107 	if (inputs[CV_INPUT].isConnected()) {
    108 		semitones *= clamp(inputs[CV_INPUT].getPolyVoltage(c) / 5.0f, -1.0f, 1.0f);
    109 	}
    110 	semitones *= 12.0f;
    111 	e.setSemitonesOffset(semitones);
    112 }
    113 
    114 void FFB::processChannel(const ProcessArgs& args, int c) {
    115 	Engine& e = *_engines[c];
    116 
    117 	float in = inputs[IN_INPUT].getVoltage(c);
    118 	float outAll = 0.0f;
    119 	outAll += e._amplifiers[0].next(e._lowPass.next(in));
    120 	outAll += e._amplifiers[13].next(e._highPass.next(in));
    121 	float outOdd = outAll;
    122 	float outEven = outAll;
    123 	for (int i = 1; i <= 12; ++i) {
    124 		float out = e._amplifiers[i].next(e._bandPasses[i - 1].next(in));
    125 		outAll += out;
    126 		outOdd += (i % 2 == 1) * out;
    127 		outEven += (i % 2 == 0) * out;
    128 	}
    129 
    130 	outputs[ALL_OUTPUT].setChannels(_channels);
    131 	outputs[ALL_OUTPUT].setVoltage(outAll, c);
    132 	outputs[ODD_OUTPUT].setChannels(_channels);
    133 	outputs[ODD_OUTPUT].setVoltage(outOdd, c);
    134 	outputs[EVEN_OUTPUT].setChannels(_channels);
    135 	outputs[EVEN_OUTPUT].setVoltage(outEven, c);
    136 }
    137 
    138 struct FFBWidget : BGModuleWidget {
    139 	static constexpr int hp = 8;
    140 
    141 	FFBWidget(FFB* module) {
    142 		setModule(module);
    143 		box.size = Vec(RACK_GRID_WIDTH * hp, RACK_GRID_HEIGHT);
    144 		setPanel(box.size, "FFB");
    145 		createScrews();
    146 
    147 		// generated by svg_widgets.rb
    148 		auto band1ParamPosition = Vec(7.5, 37.5);
    149 		auto band5ParamPosition = Vec(47.0, 37.5);
    150 		auto band9ParamPosition = Vec(86.5, 37.5);
    151 		auto band2ParamPosition = Vec(7.5, 88.5);
    152 		auto band6ParamPosition = Vec(47.0, 88.5);
    153 		auto band10ParamPosition = Vec(86.5, 88.5);
    154 		auto band3ParamPosition = Vec(7.5, 139.5);
    155 		auto band7ParamPosition = Vec(47.0, 139.5);
    156 		auto band11ParamPosition = Vec(86.5, 139.5);
    157 		auto band4ParamPosition = Vec(7.5, 190.5);
    158 		auto band8ParamPosition = Vec(47.0, 190.5);
    159 		auto band12ParamPosition = Vec(86.5, 190.5);
    160 		auto lowpassParamPosition = Vec(7.5, 241.5);
    161 		auto cvParamPosition = Vec(52.0, 246.5);
    162 		auto highpassParamPosition = Vec(86.5, 241.5);
    163 
    164 		auto inInputPosition = Vec(32.5, 282.0);
    165 		auto cvInputPosition = Vec(63.5, 282.0);
    166 
    167 		auto allOutputPosition = Vec(17.0, 324.0);
    168 		auto oddOutputPosition = Vec(48.0, 324.0);
    169 		auto evenOutputPosition = Vec(79.0, 324.0);
    170 		// end generated by svg_widgets.rb
    171 
    172 		addParam(createParam<Knob26>(band1ParamPosition, module, FFB::BAND_1_PARAM));
    173 		addParam(createParam<Knob26>(band5ParamPosition, module, FFB::BAND_5_PARAM));
    174 		addParam(createParam<Knob26>(band9ParamPosition, module, FFB::BAND_9_PARAM));
    175 		addParam(createParam<Knob26>(band2ParamPosition, module, FFB::BAND_2_PARAM));
    176 		addParam(createParam<Knob26>(band6ParamPosition, module, FFB::BAND_6_PARAM));
    177 		addParam(createParam<Knob26>(band10ParamPosition, module, FFB::BAND_10_PARAM));
    178 		addParam(createParam<Knob26>(band3ParamPosition, module, FFB::BAND_3_PARAM));
    179 		addParam(createParam<Knob26>(band7ParamPosition, module, FFB::BAND_7_PARAM));
    180 		addParam(createParam<Knob26>(band11ParamPosition, module, FFB::BAND_11_PARAM));
    181 		addParam(createParam<Knob26>(band4ParamPosition, module, FFB::BAND_4_PARAM));
    182 		addParam(createParam<Knob26>(band8ParamPosition, module, FFB::BAND_8_PARAM));
    183 		addParam(createParam<Knob26>(band12ParamPosition, module, FFB::BAND_12_PARAM));
    184 		addParam(createParam<Knob26>(lowpassParamPosition, module, FFB::LOWPASS_PARAM));
    185 		addParam(createParam<Knob16>(cvParamPosition, module, FFB::CV_PARAM));
    186 		addParam(createParam<Knob26>(highpassParamPosition, module, FFB::HIGHPASS_PARAM));
    187 
    188 		addInput(createInput<Port24>(inInputPosition, module, FFB::IN_INPUT));
    189 		addInput(createInput<Port24>(cvInputPosition, module, FFB::CV_INPUT));
    190 
    191 		addOutput(createOutput<Port24>(allOutputPosition, module, FFB::ALL_OUTPUT));
    192 		addOutput(createOutput<Port24>(oddOutputPosition, module, FFB::ODD_OUTPUT));
    193 		addOutput(createOutput<Port24>(evenOutputPosition, module, FFB::EVEN_OUTPUT));
    194 	}
    195 };
    196 
    197 Model* modelFFB = createModel<FFB, FFBWidget>("Bogaudio-FFB", "FFB", "Fixed filter bank", "Filter", "Polyphonic");