/*
  ==============================================================================

    adsr.h
    Created: 25 Oct 2025 2:09:32pm
    Author:  mickl

  ==============================================================================
*/

#pragma once
#include <stdint.h>
/** Distinct stages that the phase of the envelope can be located in.
- IDLE   = located at phase location 0, and not currently running
- ATTACK  = First segment of envelope where phase moves from 0 to 1
- DECAY   = Second segment of envelope where phase moves from 1 to SUSTAIN value
- RELEASE =     Fourth segment of envelop where phase moves from SUSTAIN to 0
*/
enum
{
    ADSR_SEG_IDLE = 0,
    ADSR_SEG_ATTACK = 1,
    ADSR_SEG_DECAY = 2,
    ADSR_SEG_RELEASE = 4
};


/** adsr envelope module

Original author(s) : Paul Batchelor

Ported from Soundpipe by Ben Sergentanis, May 2020

Remake by Steffan DIedrichsen, May 2021
*/
class Adsr
{
public:
    Adsr() {}
    ~Adsr() {}
    /** Initializes the Adsr module.
        \param sample_rate - The sample rate of the audio engine being run.
    */
    void Init(float sample_rate, int blockSize = 1);
    /**
     \function Retrigger forces the envelope back to attack phase
     \param hard  resets the history to zero, results in a click.
     */
    void Retrigger(bool hard);
    /** Processes one sample through the filter and returns one sample.
        \param gate - trigger the envelope, hold it to sustain
    */
    float Process(bool gate);
    /** Sets time
        Set time per segment in seconds
    */
    void SetTime(int seg, float time);
    void SetAttackTime(float timeInS, float shape = 0.0f);
    void SetDecayTime(float timeInS);
    void SetReleaseTime(float timeInS);

private:
    void SetTimeConstant(float timeInS, float& time, float& coeff);

public:
    /** Sustain level
        \param sus_level - sets sustain level, 0...1.0
    */
    inline void SetSustainLevel(float sus_level)
    {
        sus_level = (sus_level <= 0.f) ? -0.01f // forces envelope into idle
            : (sus_level > 1.f) ? 1.f : sus_level;
        sus_level_ = sus_level;
    }
    /** get the current envelope segment
        \return the segment of the envelope that the phase is currently located in.
    */
    inline uint8_t GetCurrentSegment() { return mode_; }
    /** Tells whether envelope is active
        \return true if the envelope is currently in any stage apart from idle.
    */
    inline bool IsRunning() const { return mode_ != ADSR_SEG_IDLE; }

private:
    float   sus_level_{ 0.f };
    float   x_{ 0.f };
    float   attackShape_{ -1.f };
    float   attackTarget_{ 0.0f };
    float   attackTime_{ -1.0f };
    float   decayTime_{ -1.0f };
    float   releaseTime_{ -1.0f };
    float   attackD0_{ 0.f };
    float   decayD0_{ 0.f };
    float   releaseD0_{ 0.f };
    int     sample_rate_;
    uint8_t mode_{ ADSR_SEG_IDLE };
    bool    gate_{ false };
};