#include "wiring_constants.h"
#ifndef Env_follower_h
#define Env_follower_h
#include "Arduino.h"

namespace atoav {

class SmoothingFilter {
  public:
      void Init(float smoothing_time_ms, float sample_rate) {
        a = exp(-TWO_PI / (smoothing_time_ms * 0.001f * sample_rate));
        b = 1.0f - a;
        z = 0.0f;
      }

      inline float Process(float in) {
        z = (in * b) + (z * a);
        return z;
      }

      void setSmoothing(float smoothing_time_ms, float sample_rate) {
        a = exp(-TWO_PI / (smoothing_time_ms * 0.001f * sample_rate));
        b = 1.0f - a;
      }

  private:
    float a;
    float b;
    float z;
};


class EnvelopeFollower {
  public:
    void Init(float sample_rate) {
      sample_rate = sample_rate;
      attack = 200.0f;
      decay = 4000.0f;
      smoothing = 50.0f;
      value  = 0.0f;
      smoothing_filter.Init(smoothing, sample_rate);
    }

    void SetAttack(float attack_ms) {
      attack = pow(0.01, 1.0 / (attack_ms * sample_rate * 0.001));
    }

    void SetDecay(float decay_ms) {
      decay = pow(0.01, 1.0 / (decay_ms * sample_rate * 0.001));
    }

    void SetSmoothing(float smoothing_ms) {
      smoothing_filter.setSmoothing(smoothing_ms, sample_rate);
    }

    float Process(float in) {
      abs_value = smoothing_filter.Process(abs(in));
      if (abs_value > value) {
        value = attack * (value - abs_value) + abs_value;
      } else {
        value = decay * (value - abs_value) + abs_value;
      }
      return value;
    }

    float value;

    float getValue() {
      if (value == 0.0f || value == -0.0f) {
        return value;
      }
      return max(0.0f, (3.0f + log10(value)) / 3.0f);
      // return value;
    }


  private:
    float sample_rate;
    float attack;
    float decay;
    float smoothing;
    float abs_value = 0.0f;
    SmoothingFilter smoothing_filter;
};
};





#endif