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

    This file was auto-generated by the Jucer!

    It contains the basic startup code for a Juce application.

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

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

AudioProcessor* JUCE_CALLTYPE createPluginFilter();

//==============================================================================
JuceDemoHostAudioProcessor::JuceDemoHostAudioProcessor()
    : formatManager(),
      graph (formatManager),
      midiKeyState (nullptr)
{
    PropertiesFile::Options options;
    options.applicationName     = "Juce Audio Plugin Host";
    options.filenameSuffix      = "settings";
    options.osxLibrarySubFolder = "Preferences";

    appProperties = new ApplicationProperties();
    appProperties->setStorageParameters(options);

    formatManager.addDefaultFormats();
    formatManager.addFormat(new InternalPluginFormat());
    graph.ready(appProperties);

    graph.getGraph().setPlayConfigDetails(getTotalNumInputChannels(), getTotalNumOutputChannels(), getSampleRate(), getBlockSize());
}

JuceDemoHostAudioProcessor::~JuceDemoHostAudioProcessor()
{
    graph.clear();
}

//==============================================================================
void JuceDemoHostAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
{
    graph.getGraph().setPlayConfigDetails(getTotalNumInputChannels(), getTotalNumOutputChannels(), sampleRate, samplesPerBlock);
    graph.getGraph().prepareToPlay(sampleRate, samplesPerBlock);

    {
        const ScopedLock csl(midiKeyMutex);

        if (midiKeyState != nullptr)
            midiKeyState->reset();
    }
}

void JuceDemoHostAudioProcessor::releaseResources()
{
    graph.getGraph().releaseResources();
}

void JuceDemoHostAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages)
{
    const int numSamples = buffer.getNumSamples();

    graph.getGraph().setPlayHead (getPlayHead());

    {
        const ScopedLock csl(midiKeyMutex);

        if (midiKeyState != nullptr)
            midiKeyState->processNextMidiBuffer(midiMessages, 0, numSamples, true);
    }

    graph.getGraph().processBlock(buffer, midiMessages);

    // 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, numSamples);
}

//==============================================================================
AudioProcessorEditor* JuceDemoHostAudioProcessor::createEditor()
{
    return new JuceDemoHostAudioProcessorEditor (*this);
}

//==============================================================================
void JuceDemoHostAudioProcessor::getStateInformation (MemoryBlock& destData)
{
    ScopedPointer<XmlElement> xmlState (graph.createXml());
    copyXmlToBinary (*xmlState, destData);
}

void JuceDemoHostAudioProcessor::setStateInformation (const void* data, int sizeInBytes)
{
    ScopedPointer<XmlElement> xmlState (getXmlFromBinary (data, sizeInBytes));

    if (xmlState != nullptr && xmlState->hasTagName("FILTERGRAPH"))
        graph.restoreFromXml(*xmlState);
}

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

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

bool JuceDemoHostAudioProcessor::isInputChannelStereoPair (int /*index*/) const
{
    return true;
}

bool JuceDemoHostAudioProcessor::isOutputChannelStereoPair (int /*index*/) const
{
    return true;
}

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

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

bool JuceDemoHostAudioProcessor::silenceInProducesSilenceOut() const
{
    return false;
}

double JuceDemoHostAudioProcessor::getTailLengthSeconds() const
{
    return 0.0;
}

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