Mono.cpp (5590B)
1 2 #include "Mono.hpp" 3 4 void Mono::sampleRateChange() { 5 float sr = APP->engine->getSampleRate(); 6 _detectorRMS.setSampleRate(sr); 7 _attackSL.setParams(sr, 50.0f); 8 _releaseSL.setParams(sr, _releaseMS); 9 for (int c = 0; c < maxChannels; ++c) { 10 _channelRMSs[c].setSampleRate(sr); 11 } 12 } 13 14 void Mono::modulate() { 15 float comp = clamp(params[COMPRESSION_PARAM].getValue(), 0.0f, 1.0f); 16 _ratio = (comp * comp) * 25.0f + 1.0f; 17 _releaseMS = std::max(200.0f, comp * 500.0f); 18 _releaseSL.setParams(APP->engine->getSampleRate(), _releaseMS); 19 20 float level = clamp(params[LEVEL_PARAM].getValue(), 0.0f, 1.0f); 21 level = 1.0f - level; 22 level *= _levelAmp.minDecibels; 23 _levelAmp.setLevel(level); 24 } 25 26 void Mono::processAll(const ProcessArgs& args) { 27 _activeChannels = inputs[POLY_INPUT].getChannels(); 28 float out = 0.0f; 29 for (int c = 0; c < _activeChannels; ++c) { 30 float v = inputs[POLY_INPUT].getVoltage(c); 31 out += v; 32 _channelLevels[c] = _channelRMSs[c].next(v) / 5.0f; 33 } 34 for (int c = _activeChannels; c < maxChannels; ++c) { 35 _channelLevels[c] = _channelRMSs[c].next(0.0f) / 5.0f; 36 } 37 38 float env = _detectorRMS.next(out); 39 if (env > _lastEnv) { 40 env = _attackSL.next(env, _lastEnv); 41 } 42 else { 43 env = _releaseSL.next(env, _lastEnv); 44 } 45 _lastEnv = env; 46 47 float detectorDb = amplitudeToDecibels(env / 5.0f); 48 _compressionDb = _compressor.compressionDb(detectorDb, 0.0f, _ratio, true); 49 _compAmp.setLevel(-_compressionDb); 50 51 out = _compAmp.next(out); 52 out = _levelAmp.next(out); 53 out = _saturator.next(out); 54 outputs[MONO_OUTPUT].setVoltage(out); 55 } 56 57 struct MonoWidget : BGModuleWidget { 58 struct ChannelsDisplay : LightEmittingWidget<OpaqueWidget> { 59 const NVGcolor inactiveBgColor = nvgRGBA(0xaa, 0xaa, 0xaa, 0xff); 60 const NVGcolor activeBgColor = nvgRGBA(0x66, 0x66, 0x66, 0xff); 61 Mono* _module; 62 63 ChannelsDisplay(Mono* module) : _module(module) { 64 } 65 66 bool isLit() override { 67 return _module && !_module->isBypassed(); 68 } 69 70 void draw(const DrawArgs& args) override { 71 int active = 0; 72 if (_module) { 73 active = _module->_activeChannels; 74 } 75 76 nvgSave(args.vg); 77 for (int i = 0; i < Mono::maxChannels; ++i) { 78 nvgBeginPath(args.vg); 79 if (i >= active) { 80 nvgCircle(args.vg, (i % 4) * 10 + 5.0f, (i / 4) * 10 + 5.0f, 3.2f); 81 nvgFillColor(args.vg, inactiveBgColor); 82 nvgFill(args.vg); 83 } 84 } 85 nvgRestore(args.vg); 86 } 87 88 void drawLit(const DrawArgs& args) override { 89 assert(_module); 90 nvgSave(args.vg); 91 for (int i = 0; i < Mono::maxChannels; ++i) { 92 nvgBeginPath(args.vg); 93 if (i < _module->_activeChannels) { 94 nvgCircle(args.vg, (i % 4) * 10 + 5.0f, (i / 4) * 10 + 5.0f, 3.2f); 95 nvgFillColor(args.vg, activeBgColor); 96 nvgFill(args.vg); 97 if (_module->_channelLevels[i] > 0.0f) { 98 nvgFillColor(args.vg, decibelsToColor(amplitudeToDecibels(_module->_channelLevels[i]))); 99 nvgFill(args.vg); 100 } 101 } 102 } 103 nvgRestore(args.vg); 104 } 105 }; 106 107 struct CompressionDisplay : LightEmittingWidget<OpaqueWidget> { 108 struct Level { 109 float db; 110 NVGcolor color; 111 Level(float db, const NVGcolor& color) : db(db), color(color) {} 112 }; 113 114 const NVGcolor bgColor = nvgRGBA(0xaa, 0xaa, 0xaa, 0xff); 115 Mono* _module; 116 std::vector<Level> _levels; 117 118 CompressionDisplay(Mono* module) : _module(module) { 119 auto color = nvgRGBA(0xff, 0xaa, 0x00, 0xff); 120 _levels.push_back(Level(12.0f, color)); 121 for (int i = 1; i <= 6; ++i) { 122 float db = 12.0f - i*2.0f; 123 _levels.push_back(Level(db, color)); 124 } 125 } 126 127 bool isLit() override { 128 return _module && !_module->isBypassed(); 129 } 130 131 void draw(const DrawArgs& args) override { 132 nvgSave(args.vg); 133 for (int i = 0; i < 35; i += 5) { 134 drawBox(args, i); 135 nvgFillColor(args.vg, bgColor); 136 nvgFill(args.vg); 137 } 138 nvgRestore(args.vg); 139 } 140 141 void drawLit(const DrawArgs& args) override { 142 float compressionDb = 0.0f; 143 if (_module && !_module->isBypassed()) { 144 compressionDb = _module->_compressionDb; 145 } 146 147 nvgSave(args.vg); 148 for (int i = 0; i < 35; i += 5) { 149 const Level& l = _levels.at(i / 5); 150 if (compressionDb > l.db) { 151 drawBox(args, i); 152 nvgFillColor(args.vg, l.color); 153 nvgFill(args.vg); 154 } 155 } 156 nvgRestore(args.vg); 157 } 158 159 void drawBox(const DrawArgs& args, int offset) { 160 nvgBeginPath(args.vg); 161 nvgRect(args.vg, 3, offset + 1, 5, 4); 162 } 163 }; 164 165 static constexpr int hp = 3; 166 167 MonoWidget(Mono* module) { 168 setModule(module); 169 box.size = Vec(RACK_GRID_WIDTH * hp, RACK_GRID_HEIGHT); 170 setPanel(box.size, "Mono"); 171 createScrews(); 172 173 { 174 auto display = new ChannelsDisplay(module); 175 display->box.pos = Vec(2.5f, 30.0f); 176 display->box.size = Vec(40.0f, 40.0f); 177 addChild(display); 178 } 179 180 { 181 auto display = new CompressionDisplay(module); 182 display->box.pos = Vec(17.5f, 142.5f); 183 display->box.size = Vec(18.0f, 50.0f); 184 addChild(display); 185 } 186 187 // generated by svg_widgets.rb 188 auto compressionParamPosition = Vec(9.5, 99.5); 189 auto levelParamPosition = Vec(9.5, 205.5); 190 191 auto polyInputPosition = Vec(10.5, 254.0); 192 193 auto monoOutputPosition = Vec(10.5, 292.0); 194 // end generated by svg_widgets.rb 195 196 addParam(createParam<Knob26>(compressionParamPosition, module, Mono::COMPRESSION_PARAM)); 197 addParam(createParam<Knob26>(levelParamPosition, module, Mono::LEVEL_PARAM)); 198 199 addInput(createInput<Port24>(polyInputPosition, module, Mono::POLY_INPUT)); 200 201 addOutput(createOutput<Port24>(monoOutputPosition, module, Mono::MONO_OUTPUT)); 202 } 203 }; 204 205 Model* modelMono = createModel<Mono, MonoWidget>("Bogaudio-Mono", "MONO", "Polyphonic-to-monophonic converter with onboard compressor", "Polyphonic");