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