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