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

    This file was auto-generated by the Introjucer!

    It contains the basic framework code for a JUCE plugin processor.

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

#include "PluginProcessor.h"
#include "PluginEditor.h"
#include <random>

using namespace gin;

String enableTextFunction (const Parameter&, float v)
{
    return v > 0.0f ? "On" : "Off";
}

String durationTextFunction (const Parameter&, float v)
{
    return NoteDuration::getNoteDurations()[size_t (v)].getName();
}

//==============================================================================
DelayAudioProcessor::DelayAudioProcessor()
{
    float mxd = float (NoteDuration::getNoteDurations().size()) - 1.0f;
    
    sync  = addExtParam ("sync",  "Sync",      "", "",   {   0.0f,   1.0f, 1.0f, 1.0f},    0.0f, 0.0f, enableTextFunction);
    time  = addExtParam ("time",  "Delay",     "", "",   {   0.0f, 120.0f, 0.0f, 0.3f},    1.0f, 0.0f);
    beat  = addExtParam ("beat",  "Delay",     "", "",   {   0.0f,    mxd, 1.0f, 1.0f},   13.0f, 0.0f, durationTextFunction);
    fb    = addExtParam ("fb",    "Feedback",  "", "dB", {-100.0f,   0.0f, 0.0f, 5.0f},  -10.0f, 0.1f);
    cf    = addExtParam ("cf",    "Crossfeed", "", "dB", {-100.0f,   0.0f, 0.0f, 5.0f}, -100.0f, 0.1f);
    mix   = addExtParam ("mix",   "Mix",       "", "%",  {   0.0f, 100.0f, 0.0f, 1.0f},    0.0f, 0.1f);
    
    delay = addIntParam ("delay", "Delay",     "", "",   {   0.0f, 120.0f, 0.0f, 1.0f},    1.0f, {0.2f, SmoothingType::eased});
    
    fb->conversionFunction  = [] (float in) { return Decibels::decibelsToGain (in); };
    cf->conversionFunction  = [] (float in) { return Decibels::decibelsToGain (in); };
    mix->conversionFunction = [] (float in) { return in / 100.0f; };
}

DelayAudioProcessor::~DelayAudioProcessor()
{
}

//==============================================================================
void DelayAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
{
    gin::Processor::prepareToPlay (sampleRate, samplesPerBlock);
    
    stereoDelay.setSampleRate (sampleRate);
}

void DelayAudioProcessor::reset()
{
    gin::Processor::reset();
    
    stereoDelay.reset();
}

void DelayAudioProcessor::releaseResources()
{
}

void DelayAudioProcessor::updateInternalParams()
{
    if (sync->isOn())
    {
        auto& duration = NoteDuration::getNoteDurations()[(size_t)beat->getUserValueInt()];
        delay->setUserValue (duration.toSeconds (getPlayHead()));
    }
    else
    {
        delay->setUserValue (time->getUserValue());
    }
}

void DelayAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer&)
{
    updateInternalParams();

    int numSamples = buffer.getNumSamples();
    if (isSmoothing())
    {
        int pos = 0;
        
        while (pos < numSamples)
        {
            auto workBuffer = sliceBuffer (buffer, pos, 1);
            
            stereoDelay.setParams (delay->getProcValue (1), mix->getProcValue (1),
                                   fb->getProcValue (1), cf->getProcValue (1));
            
            stereoDelay.process (workBuffer);
            
            pos++;
        }
    }
    else
    {
        stereoDelay.setParams (delay->getProcValue (numSamples), mix->getProcValue (numSamples),
                               fb->getProcValue (numSamples), cf->getProcValue (numSamples));
        
        stereoDelay.process (buffer);
    }
}

//==============================================================================
bool DelayAudioProcessor::hasEditor() const
{
    return true;
}

AudioProcessorEditor* DelayAudioProcessor::createEditor()
{
    return new DelayAudioProcessorEditor (*this);
}

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