BogaudioModules

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

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