#include "AudioInputSource.h"
#include <cmath>

AudioInputSource::AudioInputSource()
	: type (silence), frequencyHz (440.0), amplitude (0.5), sampleRate (44100.0),
	  phase (0.0), samplePosition (0)
{
	zeromem (pinkState, sizeof (pinkState));
}

void AudioInputSource::setSilence()
{
	type = silence;
}

void AudioInputSource::setSine (double frequencyHzToUse, float amplitudeToUse)
{
	type = sine;
	frequencyHz = frequencyHzToUse;
	amplitude = amplitudeToUse;
	phase = 0.0;
}

void AudioInputSource::setWhiteNoise (float amplitudeToUse)
{
	type = whiteNoise;
	amplitude = amplitudeToUse;
}

void AudioInputSource::setPinkNoise (float amplitudeToUse)
{
	type = pinkNoise;
	amplitude = amplitudeToUse;
	zeromem (pinkState, sizeof (pinkState));
}

void AudioInputSource::setImpulse (float amplitudeToUse)
{
	type = impulse;
	amplitude = amplitudeToUse;
	samplePosition = 0;
}

void AudioInputSource::prepare (double sampleRateToUse)
{
	sampleRate = sampleRateToUse;
	phase = 0.0;
	samplePosition = 0;
}

// Paul Kellet's "economy" pink noise filter - good enough for exercising a
// plugin's frequency-dependent behaviour, not intended to be metrologically
// accurate.
float AudioInputSource::nextPinkSample (float white)
{
	pinkState[0] = 0.99886f * pinkState[0] + white * 0.0555179f;
	pinkState[1] = 0.99332f * pinkState[1] + white * 0.0750759f;
	pinkState[2] = 0.96900f * pinkState[2] + white * 0.1538520f;
	pinkState[3] = 0.86650f * pinkState[3] + white * 0.3104856f;
	pinkState[4] = 0.55000f * pinkState[4] + white * 0.5329522f;
	pinkState[5] = -0.7616f * pinkState[5] - white * 0.0168980f;
	float pink = pinkState[0] + pinkState[1] + pinkState[2] + pinkState[3]
			   + pinkState[4] + pinkState[5] + pinkState[6] + white * 0.5362f;
	pinkState[6] = white * 0.115926f;
	return pink * 0.11f; // roughly normalises the summed gain back towards +-1
}

void AudioInputSource::fillNextBlock (AudioSampleBuffer &buffer, int numChannels, int numSamples)
{
	switch (type)
	{
		case silence:
			for (int ch = 0; ch < numChannels; ++ch)
				buffer.clear (ch, 0, numSamples);
			break;

		case sine:
		{
			const double twoPi = 2.0 * double_Pi;
			const double phaseIncrement = twoPi * frequencyHz / sampleRate;
			double p = phase;

			for (int i = 0; i < numSamples; ++i)
			{
				const float sample = amplitude * (float) std::sin (p);
				for (int ch = 0; ch < numChannels; ++ch)
					buffer.setSample (ch, i, sample);
				p += phaseIncrement;
			}
			phase = std::fmod (p, twoPi);
			break;
		}

		case whiteNoise:
			for (int i = 0; i < numSamples; ++i)
			{
				const float sample = amplitude * (2.0f * random.nextFloat() - 1.0f);
				for (int ch = 0; ch < numChannels; ++ch)
					buffer.setSample (ch, i, sample);
			}
			break;

		case pinkNoise:
			for (int i = 0; i < numSamples; ++i)
			{
				const float white = 2.0f * random.nextFloat() - 1.0f;
				const float sample = amplitude * nextPinkSample (white);
				for (int ch = 0; ch < numChannels; ++ch)
					buffer.setSample (ch, i, sample);
			}
			break;

		case impulse:
			for (int i = 0; i < numSamples; ++i)
			{
				const float sample = (samplePosition == 0) ? amplitude : 0.0f;
				for (int ch = 0; ch < numChannels; ++ch)
					buffer.setSample (ch, i, sample);
				++samplePosition;
			}
			break;
	}
}
