VU.cpp (4462B)
1 2 #include "VU.hpp" 3 4 void VU::sampleRateChange() { 5 float sr = APP->engine->getSampleRate(); 6 _lRms.setSampleRate(sr); 7 _rRms.setSampleRate(sr); 8 _lPeakRms.setSampleRate(sr); 9 _rPeakRms.setSampleRate(sr); 10 _lPeakSlew.setParams(sr, 750.0f, 1.0f); 11 _rPeakSlew.setParams(sr, 750.0f, 1.0f); 12 } 13 14 void VU::processAll(const ProcessArgs& args) { 15 float left = inputs[L_INPUT].getVoltageSum(); 16 outputs[L_OUTPUT].setChannels(inputs[L_INPUT].getChannels()); 17 outputs[L_OUTPUT].writeVoltages(inputs[L_INPUT].getVoltages()); 18 19 float right = 0.0f; 20 if (inputs[R_INPUT].isConnected()) { 21 right = inputs[R_INPUT].getVoltageSum(); 22 outputs[R_OUTPUT].setChannels(inputs[R_INPUT].getChannels()); 23 outputs[R_OUTPUT].writeVoltages(inputs[R_INPUT].getVoltages()); 24 } 25 else { 26 right = left; 27 outputs[R_OUTPUT].setChannels(inputs[L_INPUT].getChannels()); 28 outputs[R_OUTPUT].writeVoltages(inputs[L_INPUT].getVoltages()); 29 } 30 31 _lLevel = _lRms.next(left) / 5.0f; 32 _rLevel = _rRms.next(right) / 5.0f; 33 34 float lPeak = _lPeakRms.next(fabsf(left)) / 5.0f; 35 if (lPeak < _lPeakLevel) { 36 if (!_lPeakFalling) { 37 _lPeakFalling = true; 38 _lPeakSlew._last = _lPeakLevel; 39 } 40 lPeak = _lPeakSlew.next(lPeak); 41 } 42 else { 43 _lPeakFalling = false; 44 } 45 _lPeakLevel = lPeak; 46 47 float rPeak = _rPeakRms.next(fabsf(right)) / 5.0f; 48 if (rPeak < _rPeakLevel) { 49 if (!_rPeakFalling) { 50 _rPeakFalling = true; 51 _rPeakSlew._last = _rPeakLevel; 52 } 53 rPeak = _rPeakSlew.next(rPeak); 54 } 55 else { 56 _rPeakFalling = false; 57 } 58 _rPeakLevel = rPeak; 59 } 60 61 struct VUDisplay : LightEmittingWidget<OpaqueWidget> { 62 struct Level { 63 float db; 64 NVGcolor color; 65 Level(float db, const NVGcolor& color) : db(db), color(color) {} 66 }; 67 68 const NVGcolor bgColor = nvgRGBA(0xaa, 0xaa, 0xaa, 0xff); 69 VU* _module; 70 std::vector<Level> _levels; 71 72 VUDisplay(VU* module) : _module(module) { 73 for (int i = 1; i <= 36; ++i) { 74 float db = 12.0f - i*2.0f; 75 _levels.push_back(Level(db, decibelsToColor(db))); 76 } 77 } 78 79 bool isLit() override { 80 return _module && !_module->isBypassed(); 81 } 82 83 void draw(const DrawArgs& args) override { 84 nvgSave(args.vg); 85 for (int i = 0; i < 180; i += 5) { 86 drawBox(args, i, true); 87 nvgFillColor(args.vg, bgColor); 88 nvgFill(args.vg); 89 90 drawBox(args, i, false); 91 nvgFillColor(args.vg, bgColor); 92 nvgFill(args.vg); 93 } 94 nvgRestore(args.vg); 95 } 96 97 void drawLit(const DrawArgs& args) override { 98 assert(_module); 99 float lDb = amplitudeToDecibels(_module->_lLevel); 100 float rDb = amplitudeToDecibels(_module->_rLevel); 101 float lPeakDb = amplitudeToDecibels(_module->_lPeakLevel); 102 float rPeakDb = amplitudeToDecibels(_module->_rPeakLevel); 103 104 nvgSave(args.vg); 105 for (int i = 0; i < 180; i += 5) { 106 const Level& l = _levels.at(i / 5); 107 108 if (lPeakDb > l.db && lPeakDb < l.db + 2.0f) { 109 drawBox(args, i, true); 110 nvgFillColor(args.vg, nvgRGBA(0x00, 0xdd, 0xff, 0xff)); 111 nvgFill(args.vg); 112 } 113 if (lDb > l.db) { 114 drawBox(args, i, true); 115 nvgFillColor(args.vg, l.color); 116 nvgFill(args.vg); 117 } 118 119 if (rPeakDb > l.db && rPeakDb < l.db + 2.0f) { 120 drawBox(args, i, false); 121 nvgFillColor(args.vg, nvgRGBA(0x00, 0xdd, 0xff, 0xff)); 122 nvgFill(args.vg); 123 } 124 if (rDb > l.db) { 125 drawBox(args, i, false); 126 nvgFillColor(args.vg, l.color); 127 nvgFill(args.vg); 128 } 129 } 130 nvgRestore(args.vg); 131 } 132 133 void drawBox(const DrawArgs& args, int offset, bool left) { 134 nvgBeginPath(args.vg); 135 nvgRect(args.vg, left ? 3 : 10, offset + 1, 5, 4); 136 } 137 }; 138 139 struct VUWidget : BGModuleWidget { 140 static constexpr int hp = 3; 141 142 VUWidget(VU* module) { 143 setModule(module); 144 box.size = Vec(RACK_GRID_WIDTH * hp, RACK_GRID_HEIGHT); 145 setPanel(box.size, "VU"); 146 createScrews(); 147 148 { 149 auto display = new VUDisplay(module); 150 display->box.pos = Vec(13.5, 16.5); 151 display->box.size = Vec(18, 180); 152 addChild(display); 153 } 154 155 // generated by svg_widgets.rb 156 auto lInputPosition = Vec(10.5, 203.0); 157 auto rInputPosition = Vec(10.5, 238.0); 158 159 auto lOutputPosition = Vec(10.5, 276.0); 160 auto rOutputPosition = Vec(10.5, 311.0); 161 // end generated by svg_widgets.rb 162 163 addInput(createInput<Port24>(lInputPosition, module, VU::L_INPUT)); 164 addInput(createInput<Port24>(rInputPosition, module, VU::R_INPUT)); 165 166 addOutput(createOutput<Port24>(lOutputPosition, module, VU::L_OUTPUT)); 167 addOutput(createOutput<Port24>(rOutputPosition, module, VU::R_OUTPUT)); 168 } 169 }; 170 171 Model* modelVU = bogaudio::createModel<VU, VUWidget>("Bogaudio-VU", "VU", "Stereo signal meter", "Visual");