11   enum class Shape { FLEXIBLE, EXPONENTIAL, LINEAR };
 
   14   float attack_slope_ = 0;
 
   16   float decay_slope_ = 0;
 
   17   float sustain_level_ = 0;
 
   19   float release_slope_ = 0;
 
   21   float release_start_ = 0;  
 
   22   int   sustain_steps_ = 0;  
 
   23   bool  params_changed_ = 
true;
 
   26   enum class State { ATTACK, DECAY, SUSTAIN, RELEASE, DONE };
 
   28   State state_ = State::DONE;
 
   29   Shape shape_ = Shape::LINEAR;
 
   36   init_abc (
float time_s, 
float slope)
 
   38     bool positive = slope > 0;
 
   39     slope = std::abs (slope);
 
   41     const float t1y = 0.5f + 0.25f * slope;
 
   43     a_ = slope * ( 1.0135809670870777f + slope * (-1.2970447050283254f + slope *   7.2390617313972063f));
 
   44     b_ = slope * (-5.8998946320566281f + slope * ( 5.7282487210570903f + slope * -15.525953208626062f));
 
   45     c_ = 1 - (t1y * a_ + b_) * t1y;
 
   53     const float time_factor = 1 / (rate_ * time_s);
 
   70   compute_slope_params (
float seconds, 
float start_x, 
float end_x)
 
   75     int steps = std::max<int> (seconds * rate_, 1);
 
   77     if (shape_ == Shape::LINEAR)
 
   82         c_ = (end_x - start_x) / steps;
 
   84     else if (shape_ == Shape::EXPONENTIAL)
 
   89         const double RATIO = (state_ == State::ATTACK) ? 0.2 : 0.001;
 
   91         const double f = -log ((RATIO + 1) / RATIO) / steps;
 
   92         double factor = exp (f);
 
   93         c_ = (end_x - RATIO * (start_x - end_x)) * (1 - factor);
 
   97     else if (shape_ == Shape::FLEXIBLE)
 
   99         auto pos_time = [] (
auto x) { 
return std::max (x, 0.0001f);  };
 
  100         if (state_ == State::ATTACK)
 
  102             init_abc (pos_time (attack_), attack_slope_);
 
  104         else if (state_ == State::DECAY)
 
  107             float stretch = 1 / std::max (1 - sustain_level_, 0.01f);
 
  108             init_abc (-pos_time (decay_ * stretch), decay_slope_);
 
  110         else if (state_ == State::RELEASE)
 
  112             init_abc (-pos_time (release_), release_slope_);
 
  115             float l = std::max (release_start_, 0.01f);
 
  120     params_changed_ = 
false;
 
  125   set_shape (Shape shape)
 
  128     params_changed_ = 
true;
 
  134     params_changed_ = 
true;
 
  137   set_attack_slope (
float f)
 
  140     params_changed_ = 
true;
 
  146     params_changed_ = 
true;
 
  149   set_decay_slope (
float f)
 
  152     params_changed_ = 
true;
 
  155   set_sustain (
float f)
 
  157     sustain_level_ = f * 0.01f;
 
  158     params_changed_ = 
true;
 
  161   set_release (
float f)
 
  164     params_changed_ = 
true;
 
  167   set_release_slope (
float f)
 
  170     params_changed_ = 
true;
 
  173   set_rate (
int sample_rate)
 
  176     params_changed_ = 
true;
 
  182     state_          = State::ATTACK;
 
  183     params_changed_ = 
true;
 
  188     state_          = State::RELEASE;
 
  189     release_start_  = level_;
 
  190     params_changed_ = 
true;
 
  193   template<State STATE, Shape SHAPE>
 
  195   process (uint *iptr, 
float *samples, uint n_samples)
 
  202     const float sustain_level = sustain_level_;
 
  204     float level = level_;
 
  206     while (i < n_samples)
 
  208         samples[i++] = level;
 
  210         if (SHAPE == Shape::FLEXIBLE)
 
  211           level = (a * level + b) * level + c;
 
  213         if (SHAPE == Shape::EXPONENTIAL)
 
  214           level = b * level + c;
 
  216         if (SHAPE == Shape::LINEAR)
 
  219         if (STATE == State::ATTACK && level > 1)
 
  222             state_          = State::DECAY;
 
  223             params_changed_ = 
true;
 
  226         if (STATE == State::DECAY && level < sustain_level)
 
  228             state_          = State::SUSTAIN;
 
  229             level           = sustain_level;
 
  230             params_changed_ = 
true;
 
  233         if (STATE == State::RELEASE && level < 1e-5f)
 
  235             state_ = State::DONE;
 
  244   template<State STATE>
 
  246   process (uint *iptr, 
float *samples, uint n_samples)
 
  248     if (shape_ == Shape::LINEAR)
 
  249       process<STATE, Shape::LINEAR> (iptr, samples, n_samples);
 
  251     if (shape_ == Shape::EXPONENTIAL)
 
  252       process<STATE, Shape::EXPONENTIAL> (iptr, samples, n_samples);
 
  254     if (shape_ == Shape::FLEXIBLE)
 
  255       process<STATE, Shape::FLEXIBLE> (iptr, samples, n_samples);
 
  259   process (
float *samples, uint n_samples)
 
  262     if (state_ == State::ATTACK)
 
  264         compute_slope_params (attack_, 0, 1);
 
  265         process<State::ATTACK> (&i, samples, n_samples);
 
  267     if (state_ == State::DECAY)
 
  269         compute_slope_params (decay_, 1, sustain_level_);
 
  270         process<State::DECAY> (&i, samples, n_samples);
 
  272     if (state_ == State::RELEASE)
 
  274         compute_slope_params (release_, release_start_, 0);
 
  275         process<State::RELEASE> (&i, samples, n_samples);
 
  277     if (state_ == State::SUSTAIN)
 
  281             if (std::abs (sustain_level_ - level_) > 1e-5)
 
  283                 sustain_steps_ = std::max<int> (0.020f * rate_, 1);
 
  284                 c_ = (sustain_level_ - level_) / sustain_steps_;
 
  290             params_changed_ = 
false;
 
  292         while (sustain_steps_ && i < n_samples) 
 
  294             samples[i++] = level_;
 
  297             if (sustain_steps_ == 0)
 
  298               level_ = sustain_level_;
 
  300         while (i < n_samples)
 
  301           samples[i++] = level_;
 
  303     if (state_ == State::DONE)
 
  305         while (i < n_samples)
 
  312     if (state_ == State::SUSTAIN)
 
  314         return !params_changed_ && sustain_steps_ == 0;
 
  316     return state_ == State::DONE;
 
  321     return state_ == State::DONE;
 
Definition: smflexadsr.hh:9