#pragma once #ifndef ADENV_H #define ADENV_H #include #ifdef __cplusplus namespace daisysp { /** Distinct stages that the phase of the envelope can be located in. @see AdEnv */ enum AdEnvSegment { /** located at phase location 0, and not currently running */ ADENV_SEG_IDLE, /** First segment of envelope where phase moves from MIN value to MAX value */ ADENV_SEG_ATTACK, /** Second segment of envelope where phase moves from MAX to MIN value */ ADENV_SEG_DECAY, /** The final segment of the envelope (currently decay) */ ADENV_SEG_LAST, }; /** Trigger-able envelope with adjustable min/max, and independent per-segment time control. \author shensley \todo - Add Cycling \todo - Implement Curve (its only linear for now). \todo - Maybe make this an ADsr_ that has AD/AR/Asr_ modes. */ class AdEnv { public: AdEnv() {} ~AdEnv() {} /** Initializes the ad envelope. Defaults: - current segment = idle - curve = linear - phase = 0 - min = 0 - max = 1 \param sample_rate sample rate of the audio engine being run */ void Init(float sample_rate); /** Processes the current sample of the envelope. This should be called once per sample period. \return the current envelope value. */ float Process(); /** Starts or retriggers the envelope.*/ inline void Trigger() { trigger_ = 1; } /** Sets the length of time (in seconds) for a specific segment. */ inline void SetTime(uint8_t seg, float time) { segment_time_[seg] = time; } /** Sets the amount of curve applied. A positve value will create a log curve. Input range: -100 to 100. (or more) */ inline void SetCurve(float scalar) { curve_scalar_ = scalar; } /** Sets the minimum value of the envelope output. Input range: -FLTmax_, to FLTmax_ */ inline void SetMin(float min) { min_ = min; } /** Sets the maximum value of the envelope output. Input range: -FLTmax_, to FLTmax_ */ inline void SetMax(float max) { max_ = max; } /** Returns the current output value without processing the next sample */ inline float GetValue() const { return (output_ * (max_ - min_)) + min_; } /** Returns the segment of the envelope that the phase is currently located in. */ inline uint8_t GetCurrentSegment() { return current_segment_; } /** Returns true if the envelope is currently in any stage apart from idle. */ inline bool IsRunning() const { return current_segment_ != ADENV_SEG_IDLE; } private: uint8_t current_segment_, prev_segment_; float segment_time_[ADENV_SEG_LAST]; float sample_rate_, min_, max_, output_, curve_scalar_; float c_inc_, curve_x_, retrig_val_; uint32_t phase_; uint8_t trigger_; }; } // namespace daisysp #endif #endif