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

    This file was auto-generated by the Jucer!

    It contains the basic startup code for a Juce application.

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

#include "PluginProcessor.h"
#include "PluginEditor.h"


//==============================================================================
ThePilgrimAudioProcessor::ThePilgrimAudioProcessor()
{
    filterParameter.setValue(0.5);
    mixParameter.setValue(1.0);

    globalSampleRate = getSampleRate();
    if (globalSampleRate <= 0.0)
        globalSampleRate = 44100.0;
}

ThePilgrimAudioProcessor::~ThePilgrimAudioProcessor()
{
}

//==============================================================================
const String ThePilgrimAudioProcessor::getName() const
{
    return JucePlugin_Name;
}

int ThePilgrimAudioProcessor::getNumParameters()
{
    return totalNumParams;
}

float ThePilgrimAudioProcessor::getParameter (int index)
{
	if (index == 0)
		return filterParameter.getValue();
	else if (index == 1)
		return mixParameter.getValue();
	return 0.0f;
}

void ThePilgrimAudioProcessor::setParameter (int index, float newValue)
{
	if (index == filterFreqParam)
		filterParameter.setValue(newValue);
	else if (index == mixParam)
		mixParameter.setValue(newValue);
}

const String ThePilgrimAudioProcessor::getParameterName (int index)
{
	if (index == filterFreqParam)
		return "Filter Freq";
	else if (index == mixParam)
		return "Mix";
    return String();
}

const String ThePilgrimAudioProcessor::getParameterText (int index)
{
	String output;
	double newFilterFreq;
        double smoothValue = filterParameter.getSmoothedValue();

	if (index == 0) {

		if (smoothValue <= 0.5)
		{
			newFilterFreq = filterParameter.getValue() * 2.0;						// Scale 0.0-0.5 to 0-1
			newFilterFreq = newFilterFreq * newFilterFreq * newFilterFreq;	// Cube values for smoother control
			newFilterFreq  = (newFilterFreq * 19940.0) + 60;				// Scale to 60Hz to 20000Hz LOWPASS
		}
		else
		{
			newFilterFreq = (filterParameter.getValue() - 0.5) * 2.0;				// Scale 0.5-1.0 to 0-1
			newFilterFreq = newFilterFreq * newFilterFreq * newFilterFreq;	// Cube values for smoother control
			newFilterFreq = (newFilterFreq * 18980.0) + 20;					// 20Hz to 19000Hz HIGHPASS
		}

		output = String(newFilterFreq)+"Hz";
		return output;
	}
	else if (index == 1)
	{
		int percent = (int(mixParameter.getValue()) * 100);
		output = String(percent)+"%";
		return output;
	}
    return String();
}

const String ThePilgrimAudioProcessor::getInputChannelName (int channelIndex) const
{
    return String (channelIndex + 1);
}

const String ThePilgrimAudioProcessor::getOutputChannelName (int channelIndex) const
{
    return String (channelIndex + 1);
}

bool ThePilgrimAudioProcessor::isInputChannelStereoPair (int index) const
{
    return true;
}

bool ThePilgrimAudioProcessor::isOutputChannelStereoPair (int index) const
{
    return true;
}

bool ThePilgrimAudioProcessor::acceptsMidi() const
{
#if JucePlugin_WantsMidiInput
    return true;
#else
    return false;
#endif
}

bool ThePilgrimAudioProcessor::producesMidi() const
{
#if JucePlugin_ProducesMidiOutput
    return true;
#else
    return false;
#endif
}

int ThePilgrimAudioProcessor::getNumPrograms()
{
    return 0;
}

int ThePilgrimAudioProcessor::getCurrentProgram()
{
    return 0;
}

void ThePilgrimAudioProcessor::setCurrentProgram (int index)
{
}

const String ThePilgrimAudioProcessor::getProgramName (int index)
{
    return String("Default");
}

void ThePilgrimAudioProcessor::changeProgramName (int index, const String& newName)
{
}

//==============================================================================
void ThePilgrimAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
{
    // Use this method as the place to do any pre-playback
    // initialisation that you need..
    globalSampleRate=sampleRate;
    updateFilter();
    lowFilterL.reset();
    lowFilterR.reset();
    highFilterL.reset();
    highFilterR.reset();
    dryBuffer.setSize(2, samplesPerBlock);
    dryBuffer.clear();
}

void ThePilgrimAudioProcessor::releaseResources()
{
    // When playback stops, you can use this as an opportunity to free up any
    // spare memory, etc.
}

void ThePilgrimAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer&)
{
	// TIDY UP THIS SO ANY VALUE WORKS
	int samplesUntilSmooth = 8;
	int currentSmoothSample = 0;
	int smoothSampleWas = 0;

        const int numberOfSamples = buffer.getNumSamples();

    // This is the place where you'd normally do the guts of your plugin's
    // audio processing...

	// The 'for' loop cycles through each channel at a time.
    for (int channel = 0; channel < getTotalNumInputChannels(); ++channel)
    {
        float* channelData = buffer.getWritePointer(channel);

        dryBuffer.copyFrom(channel, 0, channelData, numberOfSamples);
        const float* dryData = dryBuffer.getReadPointer(channel);

			for (int i = 0; i < numberOfSamples; ++i)
			{

			// Smoother //
				currentSmoothSample++;
				if (currentSmoothSample>samplesUntilSmooth) {
					filterParameter.smooth();
					mixParameter.smooth();
					currentSmoothSample=currentSmoothSample-samplesUntilSmooth;
					updateFilter();
				}
			//////////////


				// Filter Channels
				if (channel == 0){
					channelData[i] = lowFilterL.processSingleSampleRaw(channelData[i]);
					channelData[i] = highFilterL.processSingleSampleRaw(channelData[i]);}
				else if (channel == 1){
					channelData[i] = lowFilterR.processSingleSampleRaw(channelData[i]);
					channelData[i] = highFilterR.processSingleSampleRaw(channelData[i]);}
				//////////////////

				// Mix (Wet/Dry)
				channelData[i] = (channelData[i] * mixParameter.getSmoothedValue()) + (dryData[i] * ((mixParameter.getSmoothedValue() - 1) * -1.0));
				/////

					//channelData[i] = channelData[i] * filterParameter.getSmoothedValue();
			}

		currentSmoothSample=smoothSampleWas;

    }

    // In case we have more outputs than inputs, we'll clear any output
    // channels that didn't contain input data, (because these aren't
    // guaranteed to be empty - they may contain garbage).
    for (int i = getTotalNumInputChannels(); i < getTotalNumOutputChannels(); ++i)
        buffer.clear (i, 0, numberOfSamples);
}

void ThePilgrimAudioProcessor::updateFilter()
{
	double filterFreq = double(filterParameter.getSmoothedValue());

	if (filterParameter.getSmoothedValue() <= 0.5)
	{
		double newFilterFreq = filterFreq * 2.0;						// Scale 0.0-0.5 to 0-1
		newFilterFreq = newFilterFreq * newFilterFreq * newFilterFreq;	// Cube values for smoother control
		newFilterFreq  = (newFilterFreq * 19940.0) + 60;				// Scale to 60Hz to 20000Hz LOWPASS
		lowFilterL.makeLowPass(globalSampleRate, newFilterFreq);
		lowFilterR.makeLowPass(globalSampleRate, newFilterFreq);
		highFilterL.makeHighPass(globalSampleRate, 20.0);
		highFilterR.makeHighPass(globalSampleRate, 20.0);
	}
	else if (filterParameter.getSmoothedValue() > 0.5)
	{
		double newFilterFreq = (filterFreq - 0.5) * 2.0;				// Scale 0.5-1.0 to 0-1
		newFilterFreq = newFilterFreq * newFilterFreq * newFilterFreq;	// Cube values for smoother control
		newFilterFreq = (newFilterFreq * 18980.0) + 20;					// 20Hz to 19000Hz HIGHPASS
		highFilterL.makeHighPass(globalSampleRate, newFilterFreq);
		highFilterR.makeHighPass(globalSampleRate, newFilterFreq);
		lowFilterL.makeLowPass(globalSampleRate, 20000.0);
		lowFilterR.makeLowPass(globalSampleRate, 20000.0);
	}

}

//==============================================================================
#if ! JUCE_AUDIOPROCESSOR_NO_GUI
bool ThePilgrimAudioProcessor::hasEditor() const
{
    return true; // (change this to false if you choose to not supply an editor)
}

AudioProcessorEditor* ThePilgrimAudioProcessor::createEditor()
{
    return new ThePilgrimAudioProcessorEditor (this);
}
#endif

//==============================================================================
void ThePilgrimAudioProcessor::getStateInformation (MemoryBlock& destData)
{
    // You should use this method to store your parameters in the memory block.
    // You could do that either as raw data, or use the XML or ValueTree classes
    // as intermediaries to make it easy to save and load complex data.
	// Create an outer XML element..
    XmlElement xml ("MYPLUGINSETTINGS");

    // add some attributes to it..
	// xml.setAttribute ("uiWidth", lastUIWidth);
	// xml.setAttribute ("uiHeight", lastUIHeight);
    //xml.setAttribute ("gain", gain);
	// xml.setAttribute ("delay", delay);
	xml.setAttribute ("freq", filterParameter.getValue());
	xml.setAttribute ("mix", mixParameter.getValue());

    // then use this helper function to stuff it into the binary blob and return it..
    copyXmlToBinary (xml, destData);
}

void ThePilgrimAudioProcessor::setStateInformation (const void* data, int sizeInBytes)
{
    // You should use this method to restore your parameters from this memory block,
    // whose contents will have been created by the getStateInformation() call.

	//timeSinceChunkCalled = Time::getMillisecondCounter();

	ScopedPointer<XmlElement> xmlState (getXmlFromBinary (data, sizeInBytes));

    if (xmlState != 0)
    {
        // make sure that it's actually our type of XML object..
        if (xmlState->hasTagName ("MYPLUGINSETTINGS"))
        {
            // ok, now pull out our parameters..
			// gain  = xmlState->getIntAttribute ("gain", gain);
            //lastUIHeight = xmlState->getIntAttribute ("uiHeight", lastUIHeight);

            filterParameter.setValue((float) xmlState->getDoubleAttribute ("freq", 0));
            mixParameter.setValue((float) xmlState->getDoubleAttribute ("mix", 0));

        }
	}
}

//==============================================================================
// This creates new instances of the plugin..
AudioProcessor* JUCE_CALLTYPE createPluginFilter()
{
    return new ThePilgrimAudioProcessor();
}
