rendered paste body#ifndef ENVELOPE_H#define ENVELOPE_H#include "arke.h"#include "IModule.h"#include <vector>class Envelope : public IModule{public: Envelope(); ~Envelope(); void noteOn(); void noteOff(); void reset(); bool update(); void process(float* buffer, uint sampleFrames); float run(uint samplesSince); void setAdsr(float att, float dec, float sus, float rel);private: struct Stage { float speed; float target; float threshold; }; bool active; bool gate; uint stage; float position; uint loopStart; uint loopEnd; Stage stages[4];};#endif //ENVELOPE_H#include "Envelope.h"#include "arke.h"#include <cmath>const float kThreshold = 0.001;Envelope::Envelope(){ position = 0.0f; stage = 0; setAdsr(1.0f, 1.0f, 1.0f, 1.0f);}Envelope::~Envelope(){}void Envelope::setAdsr(float att, float dec, float sus, float rel){ stages[0].target = 1.25f; stages[0].threshold = 1.0f; stages[0].speed = att; stages[1].target = sus; stages[1].threshold = sus; stages[1].speed = dec; stages[2].target = sus; stages[2].threshold = sus; stages[2].speed = dec; stages[3].target = 0.0f; stages[3].threshold = 0.0f; stages[3].speed = rel;}void Envelope::noteOff(){ gate = false;}void Envelope::noteOn(){ gate = true; active = true; position = 0.0f; stage = 0;}void Envelope::reset(){ active = false; gate = false;}bool Envelope::update(){ if(!gate) { stage = 3; } if(fabs(position - stages[stage].threshold) < kThreshold) { position = stages[stage].threshold; stage++; if(stage == 4) { reset(); } if((stage == 3) && gate) { stage = 2; } } return active;}void Envelope::process(float *buffer, uint sampleFrames){ // linear interpolation between envelope updates (user won't notice or care) float target = run(sampleFrames); float inc = (target - position) / (float) sampleFrames; while(sampleFrames--) { *buffer *= position; position += inc; buffer++; }}float Envelope::run(uint samplesSince){ /* The envelope is produced by an RC filter receiving different * coefficients depending on stage, receiving the stage target * as input. This would usually mean processing for samplesSince * samples, but I'm a cheap bastard so the filter is processed at * samplerate/samplesSince for one iteration. Slower for one or * two samples, faster for anything more since this function now * becomes an O(1) operation. Yay! */ // number of samples at sampleRate float timeConstant = stages[stage].speed * sampleRate / 1000.0f; // adjusted rate timeConstant = timeConstant / (float) samplesSince; // coefficient, adjusted to the new sampleRate float coeff = powf(1000.0f, -1.0f / timeConstant); // one "iteration" position = coeff * position + (1.0f - coeff) * stages[stage].target; // clip the value if(position > 1.0f) { position = 1.0f; } else if(position < 0.0f) { position = 0.0f; } // return return position;}