BogaudioModules

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

ASR.cpp (5021B)


      1 
      2 #include "ASR.hpp"
      3 
      4 #define INVERT "invert"
      5 
      6 void ASR::Engine::reset() {
      7 	trigger.reset();
      8 	eocPulseGen.process(10.0);
      9 	envelope.reset();
     10 	on = false;
     11 }
     12 
     13 void ASR::Engine::sampleRateChange() {
     14 	float sr = APP->engine->getSampleRate();
     15 	envelope.setSampleRate(sr);
     16 	attackSL.setParams(sr / (float)modulationSteps);
     17 	releaseSL.setParams(sr / (float)modulationSteps);
     18 }
     19 
     20 void ASR::reset() {
     21 	for (int c = 0; c < _channels; ++c) {
     22 		_engines[c]->reset();
     23 	}
     24 }
     25 
     26 void ASR::sampleRateChange() {
     27 	for (int c = 0; c < _channels; ++c) {
     28 		_engines[c]->sampleRateChange();
     29 	}
     30 }
     31 
     32 json_t* ASR::saveToJson(json_t* root) {
     33 	json_object_set_new(root, INVERT, json_real(_invert));
     34 	return root;
     35 }
     36 
     37 void ASR::loadFromJson(json_t* root) {
     38 	json_t* i = json_object_get(root, INVERT);
     39 	if (i) {
     40 		_invert = json_real_value(i);
     41 	}
     42 }
     43 
     44 bool ASR::active() {
     45 	return inputs[TRIGGER_INPUT].isConnected() || outputs[ENV_OUTPUT].isConnected() || outputs[EOC_OUTPUT].isConnected();
     46 }
     47 
     48 int ASR::channels() {
     49 	return inputs[TRIGGER_INPUT].getChannels();
     50 }
     51 
     52 void ASR::addChannel(int c) {
     53 	_engines[c] = new Engine(_modulationSteps);
     54 	_engines[c]->reset();
     55 	_engines[c]->sampleRateChange();
     56 }
     57 
     58 void ASR::removeChannel(int c) {
     59 	delete _engines[c];
     60 	_engines[c] = NULL;
     61 }
     62 
     63 void ASR::modulateChannel(int c) {
     64 	Engine& e = *_engines[c];
     65 
     66 	float attack = powf(params[ATTACK_PARAM].getValue(), 2.0f);
     67 	if (inputs[ATTACK_INPUT].isConnected()) {
     68 		attack *= clamp(inputs[ATTACK_INPUT].getPolyVoltage(c) / 10.0f, 0.0f, 1.0f);
     69 	}
     70 	e.envelope.setAttack(e.attackSL.next(attack * 10.f));
     71 
     72 	float release = powf(params[RELEASE_PARAM].getValue(), 2.0f);
     73 	if (inputs[RELEASE_INPUT].isConnected()) {
     74 		release *= clamp(inputs[RELEASE_INPUT].getPolyVoltage(c) / 10.0f, 0.0f, 1.0f);
     75 	}
     76 	e.envelope.setRelease(e.releaseSL.next(release * 10.f));
     77 
     78 	e.envelope.setLinearShape(_linearMode);
     79 
     80 	_linearMode = params[LINEAR_PARAM].getValue() > 0.5f;
     81 }
     82 
     83 void ASR::processAlways(const ProcessArgs& args) {
     84 	_attackLightSum = _releaseLightSum = 0;
     85 }
     86 
     87 void ASR::processChannel(const ProcessArgs& args, int c) {
     88 	Engine& e = *_engines[c];
     89 
     90 	bool start = e.trigger.process(inputs[TRIGGER_INPUT].getVoltage(c));
     91 	if (!e.on && start) {
     92 		e.on = true;
     93 	}
     94 	e.envelope.setGate(e.trigger.isHigh() && !e.envelope.isStage(ADSR::RELEASE_STAGE));
     95 	outputs[ENV_OUTPUT].setChannels(_channels);
     96 	outputs[ENV_OUTPUT].setVoltage(e.envelope.next() * 10.0f * _invert * params[SUSTAIN_PARAM].getValue(), c);
     97 	if (e.on && e.envelope.isStage(ADSR::STOPPED_STAGE)) {
     98 		e.envelope.reset();
     99 		e.on = false;
    100 		e.eocPulseGen.trigger(0.001f);
    101 	}
    102 	outputs[EOC_OUTPUT].setChannels(_channels);
    103 	outputs[EOC_OUTPUT].setVoltage(e.eocPulseGen.process(APP->engine->getSampleTime()) ? 5.0f : 0.0f, c);
    104 
    105 	_attackLightSum += e.envelope.isStage(ADSR::ATTACK_STAGE) || e.envelope.isStage(ADSR::SUSTAIN_STAGE);
    106 	_releaseLightSum += e.envelope.isStage(ADSR::RELEASE_STAGE) || e.envelope.isStage(ADSR::SUSTAIN_STAGE);
    107 }
    108 
    109 void ASR::postProcessAlways(const ProcessArgs& args) {
    110 	lights[ATTACK_LIGHT].value = _attackLightSum * _inverseChannels;
    111 	lights[RELEASE_LIGHT].value = _releaseLightSum * _inverseChannels;
    112 }
    113 
    114 struct ASRWidget : BGModuleWidget {
    115 	static constexpr int hp = 3;
    116 
    117 	ASRWidget(ASR* module) {
    118 		setModule(module);
    119 		box.size = Vec(RACK_GRID_WIDTH * hp, RACK_GRID_HEIGHT);
    120 		setPanel(box.size, "ASR");
    121 		createScrews();
    122 
    123 		// generated by svg_widgets.rb
    124 		auto attackParamPosition = Vec(8.0, 33.0);
    125 		auto releaseParamPosition = Vec(8.0, 90.0);
    126 		auto sustainParamPosition = Vec(18.0, 130.0);
    127 		auto linearParamPosition = Vec(26.0, 150.0);
    128 
    129 		auto triggerInputPosition = Vec(10.5, 165.0);
    130 		auto attackInputPosition = Vec(10.5, 200.0);
    131 		auto releaseInputPosition = Vec(10.5, 235.0);
    132 
    133 		auto envOutputPosition = Vec(10.5, 273.0);
    134 		auto eocOutputPosition = Vec(10.5, 308.0);
    135 
    136 		auto attackLightPosition = Vec(20.8, 65.0);
    137 		auto releaseLightPosition = Vec(20.8, 122.0);
    138 		// end generated by svg_widgets.rb
    139 
    140 		addParam(createParam<Knob29>(attackParamPosition, module, ASR::ATTACK_PARAM));
    141 		addParam(createParam<Knob29>(releaseParamPosition, module, ASR::RELEASE_PARAM));
    142 		addParam(createParam<Knob16>(sustainParamPosition, module, ASR::SUSTAIN_PARAM));
    143 		addParam(createParam<IndicatorButtonGreen9>(linearParamPosition, module, ASR::LINEAR_PARAM));
    144 
    145 		addInput(createInput<Port24>(triggerInputPosition, module, ASR::TRIGGER_INPUT));
    146 		addInput(createInput<Port24>(attackInputPosition, module, ASR::ATTACK_INPUT));
    147 		addInput(createInput<Port24>(releaseInputPosition, module, ASR::RELEASE_INPUT));
    148 
    149 		addOutput(createOutput<Port24>(envOutputPosition, module, ASR::ENV_OUTPUT));
    150 		addOutput(createOutput<Port24>(eocOutputPosition, module, ASR::EOC_OUTPUT));
    151 
    152 		addChild(createLight<BGTinyLight<GreenLight>>(attackLightPosition, module, ASR::ATTACK_LIGHT));
    153 		addChild(createLight<BGTinyLight<GreenLight>>(releaseLightPosition, module, ASR::RELEASE_LIGHT));
    154 	}
    155 };
    156 
    157 Model* modelASR = createModel<ASR, ASRWidget>("Bogaudio-ASR", "ASR", "Attack/sustain/release envelope generator", "Envelope generator", "Polyphonic");