/*
 * Author:  Nigel Redmon on 12/18/12.
 * Adapted: Harry van Haaren 2013
 *          harryhaaren@gmail.com
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

//
//  Original work granted under permissive license below:
//
//  ADSR.cpp
//
//  Created by Nigel Redmon on 12/18/12.
//  EarLevel Engineering: earlevel.com
//  Copyright 2012 Nigel Redmon
//
//  For a complete explanation of the ADSR envelope generator and code,
//  read the series of articles by the author, starting here:
//  http://www.earlevel.com/main/2013/06/01/envelope-generators/
//
//  License:
//
//  This source code is provided as is, without warranty.
//  You may copy and distribute verbatim copies of this document.
//  You may modify and use this source code to create binary code for your own purposes, free or commercial.
//

#include "dsp_adsr.hxx"
#include <math.h>

ADSR::ADSR(void)
{
	reset();
	setTargetRatioA (10.0092  );
	setTargetRatioDR(10.000002);

	setAttackRate(0.01);
	setDecayRate(0.04);
	setReleaseRate(0);
	setSustainLevel(1.0);
}

ADSR::~ADSR(void)
{
}

void ADSR::setAttackRate(float rate)
{
	attackRate = rate;
	attackCoef = calcCoef(rate, targetRatioA);
	attackBase = (1.0 + targetRatioA) * (1.0 - attackCoef);
}

void ADSR::setDecayRate(float rate)
{
	decayRate = rate;
	decayCoef = calcCoef(rate, targetRatioDR);
	decayBase = (sustainLevel - targetRatioDR) * (1.0 - decayCoef);
}

void ADSR::setReleaseRate(float rate)
{
	releaseRate = rate;
	releaseCoef = calcCoef(rate, targetRatioDR);
	releaseBase = -targetRatioDR * (1.0 - releaseCoef);
}

float ADSR::calcCoef(float rate, float targetRatio)
{
	return exp(-log((1.0 + targetRatio) / targetRatio) / rate);
}

void ADSR::setSustainLevel(float level)
{
	sustainLevel = level;
	decayBase = (sustainLevel - targetRatioDR) * (1.0 - decayCoef);
}

void ADSR::setTargetRatioA(float targetRatio)
{
	if (targetRatio < 0.000000001)
		targetRatio = 0.000000001;  // -180 dB
	targetRatioA = targetRatio;
	attackBase = (1.0 + targetRatioA) * (1.0 - attackCoef);
}

void ADSR::setTargetRatioDR(float targetRatio)
{
	if (targetRatio < 0.000000001)
		targetRatio = 0.000000001;  // -180 dB
	targetRatioDR = targetRatio;
	decayBase = (sustainLevel - targetRatioDR) * (1.0 - decayCoef);
	releaseBase = -targetRatioDR * (1.0 - releaseCoef);
}
