/*
 *  Copyleft (C) 2000 David Griffiths <dave@pawfal.org>
 *
 *  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 2 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, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/ 

#include "Envelope.h"

Envelope::Envelope() :
m_Attack(0.0f),
m_Decay(0.5f),
m_Sustain(1.0f),
m_Release(1.0f),
m_Volume(0.5f)
{
	m_Trigger=new bool[SpiralInfo::POLY];
	m_t=new double[SpiralInfo::POLY];

	for (int n=0; n<SpiralInfo::POLY; n++)
	{
		m_Trigger[n]=false;
		m_t[n]=-1.0f;
	}

	m_SampleTime=1.0/(double)(SpiralInfo::SAMPLERATE);
}

Envelope::~Envelope() 
{
	delete[] m_Trigger;
	delete[] m_t;
}

void Envelope::GetOutput(int V, short *data)
{
	float Vol=0;
	bool Freeze=false;
	// find out what part of the envelope we are in
	
	// if the env hasn't been triggered
	if (m_t[V]<0) 
	{
		Zero(data);
		return; 
	}
	
	// if we've run off the end
	if (m_t[V]>m_Attack+m_Decay+m_Release)
	{
		m_t[V]=-1;
		Zero(data);
		return;
	}
	
	float temp=0;
	
	// we are in the envelope then...
	for (int n=0; n<SpiralInfo::BUFSIZE; n++)
	{
		// in the attack
		if (m_t[V]<m_Attack)
		{
			//if (n==0) cerr<<"in attack"<<endl;
			// get normalised position to
			// get the volume between 0 and 1
			temp=m_t[V]/m_Attack;
		}
		else
		// in the decay
		if (m_t[V]<m_Attack+m_Decay)
		{
			//if (n==0) cerr<<"in decay"<<endl;
			// normalised position in m_Attack->m_Decay range
			float nt=(m_t[V]-m_Attack)/m_Decay;
			
			// volume between 1 and m_Sustain
			temp=(1-nt)+(m_Sustain*nt);
		}
		else
		// in the release
		{
			//if (n==0) cerr<<"in release"<<endl;
			// normalised position in m_Decay->m_Release range
			float nt=(m_t[V]-(m_Attack+m_Decay))/m_Release;
			
			// volume between m_Sustain and 0			
			temp=m_Sustain*(1-nt);
			
			if (m_Release<0.2f)
			{
				temp=m_Sustain;
			}	
			
			if (m_Trigger[V]) Freeze=true;
		}
		
		// multiply up to fixed short representation
		// and scale by volume
		
		data[n]=static_cast<short>(temp*SpiralInfo::MAXSAMPLE*m_Volume); 
		
		if (!Freeze) m_t[V]+=m_SampleTime;
	}
	
	
	
}

void Envelope::Zero(short *data)
{
	for (int n=0; n<SpiralInfo::BUFSIZE; n++)
	{
		data[n]=0;
	}
}

void Envelope::Randomise()
{
	m_Attack=RandFloat();
	m_Decay=RandFloat();
	m_Sustain=RandFloat();
	m_Release=RandFloat();
	m_Volume=RandFloat();
}

istream &operator>>(istream &s, Envelope &o)
{
	s>>o.m_Attack>>o.m_Decay>>o.m_Sustain>>o.m_Release>>o.m_Volume;
	return s;
}

ostream &operator<<(ostream &s, Envelope &o)
{
	s<<o.m_Attack<<" "<<o.m_Decay<<" "<<o.m_Sustain<<" "<<o.m_Release<<" "<<o.m_Volume<<" ";
	return s;
}
