BogaudioModules

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

ADSR.cpp (4809B)


      1 
      2 #include "ADSR.hpp"
      3 
      4 #define INVERT "invert"
      5 
      6 void ADSR::Engine::reset() {
      7 	gateTrigger.reset();
      8 	envelope.reset();
      9 }
     10 
     11 void ADSR::Engine::sampleRateChange() {
     12 	envelope.setSampleRate(APP->engine->getSampleRate());
     13 }
     14 
     15 void ADSR::reset() {
     16 	for (int c = 0; c < _channels; ++c) {
     17 		_engines[c]->reset();
     18 	}
     19 }
     20 
     21 void ADSR::sampleRateChange() {
     22 	for (int c = 0; c < _channels; ++c) {
     23 		_engines[c]->sampleRateChange();
     24 	}
     25 }
     26 
     27 json_t* ADSR::saveToJson(json_t* root) {
     28 	json_object_set_new(root, INVERT, json_real(_invert));
     29 	return root;
     30 }
     31 
     32 void ADSR::loadFromJson(json_t* root) {
     33 	json_t* i = json_object_get(root, INVERT);
     34 	if (i) {
     35 		_invert = json_real_value(i);
     36 	}
     37 }
     38 
     39 bool ADSR::active() {
     40 	return inputs[GATE_INPUT].isConnected() || outputs[OUT_OUTPUT].isConnected();
     41 }
     42 
     43 int ADSR::channels() {
     44 	return inputs[GATE_INPUT].getChannels();
     45 }
     46 
     47 void ADSR::addChannel(int c) {
     48 	_engines[c] = new Engine();
     49 	_engines[c]->reset();
     50 	_engines[c]->sampleRateChange();
     51 }
     52 
     53 void ADSR::removeChannel(int c) {
     54 	delete _engines[c];
     55 	_engines[c] = NULL;
     56 }
     57 
     58 void ADSR::modulate() {
     59 	_linearMode = params[LINEAR_PARAM].getValue() > 0.5f;
     60 }
     61 
     62 void ADSR::modulateChannel(int c) {
     63 	Engine& e = *_engines[c];
     64 
     65 	e.envelope.setAttack(powf(params[ATTACK_PARAM].getValue(), 2.0f) * 10.f);
     66 	e.envelope.setDecay(powf(params[DECAY_PARAM].getValue(), 2.0f) * 10.f);
     67 	e.envelope.setSustain(params[SUSTAIN_PARAM].getValue());
     68 	e.envelope.setRelease(powf(params[RELEASE_PARAM].getValue(), 2.0f) * 10.f);
     69 	e.envelope.setLinearShape(_linearMode);
     70 }
     71 
     72 void ADSR::processAlways(const ProcessArgs& args) {
     73 	_attackLightSum = _decayLightSum = _sustainLightSum = _releaseLightSum = 0;
     74 }
     75 
     76 void ADSR::processChannel(const ProcessArgs& args, int c) {
     77 	Engine& e = *_engines[c];
     78 
     79 	e.gateTrigger.process(inputs[GATE_INPUT].getVoltage(c));
     80 	e.envelope.setGate(e.gateTrigger.isHigh());
     81 	outputs[OUT_OUTPUT].setChannels(_channels);
     82 	outputs[OUT_OUTPUT].setVoltage(e.envelope.next() * 10.0f * _invert, c);
     83 
     84 	_attackLightSum += e.envelope.isStage(dsp::ADSR::ATTACK_STAGE);
     85 	_decayLightSum += e.envelope.isStage(dsp::ADSR::DECAY_STAGE);
     86 	_sustainLightSum += e.envelope.isStage(dsp::ADSR::SUSTAIN_STAGE);
     87 	_releaseLightSum += e.envelope.isStage(dsp::ADSR::RELEASE_STAGE);
     88 }
     89 
     90 void ADSR::postProcessAlways(const ProcessArgs& args) {
     91 	lights[ATTACK_LIGHT].value = _attackLightSum * _inverseChannels;
     92 	lights[DECAY_LIGHT].value = _decayLightSum * _inverseChannels;
     93 	lights[SUSTAIN_LIGHT].value = _sustainLightSum * _inverseChannels;
     94 	lights[RELEASE_LIGHT].value = _releaseLightSum * _inverseChannels;
     95 }
     96 
     97 struct ADSRWidget : BGModuleWidget {
     98 	static constexpr int hp = 3;
     99 
    100 	ADSRWidget(ADSR* module) {
    101 		setModule(module);
    102 		box.size = Vec(RACK_GRID_WIDTH * hp, RACK_GRID_HEIGHT);
    103 		setPanel(box.size, "ADSR");
    104 		createScrews();
    105 
    106 		// generated by svg_widgets.rb
    107 		auto attackParamPosition = Vec(8.0, 33.0);
    108 		auto decayParamPosition = Vec(8.0, 90.0);
    109 		auto sustainParamPosition = Vec(8.0, 147.0);
    110 		auto releaseParamPosition = Vec(8.0, 204.0);
    111 		auto linearParamPosition = Vec(25.5, 246.0);
    112 
    113 		auto gateInputPosition = Vec(10.5, 265.0);
    114 
    115 		auto outOutputPosition = Vec(10.5, 303.0);
    116 
    117 		auto attackLightPosition = Vec(20.8, 65.0);
    118 		auto decayLightPosition = Vec(20.8, 122.0);
    119 		auto sustainLightPosition = Vec(20.8, 179.0);
    120 		auto releaseLightPosition = Vec(20.8, 236.0);
    121 		// end generated by svg_widgets.rb
    122 
    123 		addParam(createParam<Knob29>(attackParamPosition, module, ADSR::ATTACK_PARAM));
    124 		addParam(createParam<Knob29>(decayParamPosition, module, ADSR::DECAY_PARAM));
    125 		addParam(createParam<Knob29>(sustainParamPosition, module, ADSR::SUSTAIN_PARAM));
    126 		addParam(createParam<Knob29>(releaseParamPosition, module, ADSR::RELEASE_PARAM));
    127 		addParam(createParam<IndicatorButtonGreen9>(linearParamPosition, module, ADSR::LINEAR_PARAM));
    128 
    129 		addInput(createInput<Port24>(gateInputPosition, module, ADSR::GATE_INPUT));
    130 
    131 		addOutput(createOutput<Port24>(outOutputPosition, module, ADSR::OUT_OUTPUT));
    132 
    133 		addChild(createLight<BGTinyLight<GreenLight>>(attackLightPosition, module, ADSR::ATTACK_LIGHT));
    134 		addChild(createLight<BGTinyLight<GreenLight>>(decayLightPosition, module, ADSR::DECAY_LIGHT));
    135 		addChild(createLight<BGTinyLight<GreenLight>>(sustainLightPosition, module, ADSR::SUSTAIN_LIGHT));
    136 		addChild(createLight<BGTinyLight<GreenLight>>(releaseLightPosition, module, ADSR::RELEASE_LIGHT));
    137 	}
    138 
    139 	void contextMenu(Menu* menu) override {
    140 		auto m = dynamic_cast<ADSR*>(module);
    141 		assert(m);
    142 		menu->addChild(new OptionMenuItem(
    143 			"Invert output",
    144 			[m]() { return m->_invert == -1.0f; },
    145 			[m]() {
    146 				if (m->_invert < 0.0f) {
    147 					m->_invert = 1.0f;
    148 				}
    149 				else {
    150 					m->_invert = -1.0f;
    151 				}
    152 			}
    153 		));
    154 	}
    155 };
    156 
    157 Model* modelADSR = bogaudio::createModel<ADSR, ADSRWidget>("Bogaudio-ADSR", "ADSR", "ADSR envelope generator", "Envelope generator", "Polyphonic");