/*
	==============================================================================
	This file is part of Tal-Reverb by Patrick Kunz.

	Copyright(c) 2005-2009 Patrick Kunz, TAL
	Togu Audio Line, Inc.
	http://kunz.corrupt.ch

	This file may be licensed under the terms of of the
	GNU General Public License Version 2 (the ``GPL'').

	Software distributed under the License is distributed
	on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
	express or implied. See the GPL for the specific language
	governing rights and limitations.

	You should have received a copy of the GPL along with this
	program. If not, go to http://www.gnu.org/licenses/gpl.html
	or write to the Free Software Foundation, Inc.,  
	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
	==============================================================================
 */

#if !defined(__CombFilter_h)
#define __CombFilter_h

#include "math.h"
#include "AudioUtils.h"

class CombFilter
{
private:
    float sampleRateFactor;

	float gain, minDamp;
	float* buffer;
	int readPtr1, readPtr2, writePtr;
	float z1;
	int bufferLengthDelay;
	float filterStore;

	AudioUtils audioUtils;

public:
	// delay times in milliseconds
	CombFilter(float delayTime, float minDamp, long sampleRate)
	{
		bufferLengthDelay = (int)(delayTime * sampleRate / 1000);
		bufferLengthDelay = audioUtils.getNextNearPrime(bufferLengthDelay);
		buffer = new float[bufferLengthDelay];

		//zero out the buffer (silence)
		for (int i = 0; i < bufferLengthDelay; i++)
			buffer[i] = 0.0f;

		writePtr = 0;

		//set read pointer to start of buffer
		readPtr1 = 0;
		z1 = filterStore = 0.0f;
		this->minDamp = minDamp;

        this->sampleRateFactor = 44100.0f / sampleRate;
        if (this->sampleRateFactor > 1.0f)
        {
            this->sampleRateFactor = 1.0f;
        }
	}

	~CombFilter()
	{
		delete buffer;
	}

	// delayIntensity [0..1]
	inline float processInterpolated(float input, float damp, float feedback, float delay)
	{
        damp *= this->sampleRateFactor;

		float offset = (bufferLengthDelay - 2) * delay + 1.0f;
		readPtr1 = writePtr - (int)floorf(offset);

		if (readPtr1 < 0) 
			readPtr1 += bufferLengthDelay;

		readPtr2 = readPtr1 - 1;
		if (readPtr2 < 0) 
			readPtr2 += bufferLengthDelay;

		// interpolate, see paper: http://www.stanford.edu/~dattorro/EffectDesignPart2.pdf
		float frac = offset - (int)floorf(offset);
		float output = buffer[readPtr2] + buffer[readPtr1] * (1-frac) - (1-frac) * z1;
		z1 = output;

		damp = minDamp * damp;
		filterStore =  output * (1.0f - damp) + filterStore * damp;
		buffer[writePtr] = input + (filterStore * feedback);

		if (++writePtr >= bufferLengthDelay) 
			writePtr = 0;
		return output;
	}

	inline float process(float input, float damp, float feedback, float delay)
	{
        damp *= this->sampleRateFactor;

		float offset = (bufferLengthDelay - 2) * delay + 1.0f;
		readPtr1 = writePtr - (int)floorf(offset);

		if (readPtr1 < 0) 
			readPtr1 += bufferLengthDelay;

		float output = buffer[readPtr1];
		filterStore =  output * (1.0f - damp) + filterStore * damp;
		buffer[writePtr] = input + (filterStore * feedback);

		if (++writePtr >= bufferLengthDelay)
			writePtr = 0;
		return output;
	}
};
#endif
