text:
/*
  ==============================================================================

    RenderEngine.cpp
    Created: 19 Feb 2017 9:47:15pm
    Author:  tollie

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

#include "RenderEngine.h"

namespace p = boost::python;

//==============================================================================

void RenderEngine::fillAvailablePluginsInfo(const std::string& path,
                                            AudioPluginFormatManager& pluginFormatManager,
                                            OwnedArray<PluginDescription>& pluginDescriptions,
                                            KnownPluginList& pluginList
                                            ) {

    pluginFormatManager.addDefaultFormats();

    for (int i = pluginFormatManager.getNumFormats(); --i >= 0;)
    {
        pluginList.scanAndAddFile (String (path),
                                   true,
                                   pluginDescriptions,
                                   *pluginFormatManager.getFormat(i));
    }
}

std::string RenderEngine::getAvailablePluginsXml(const std::string& path) {
    AudioPluginFormatManager pluginFormatManager;
    OwnedArray<PluginDescription> pluginDescriptions;
    KnownPluginList pluginList;
    fillAvailablePluginsInfo(path, pluginFormatManager, pluginDescriptions, pluginList);

    XmlElement* ptr = pluginList.createXml();
    String serialized = ptr->createDocument("");
    delete ptr;

    return serialized.toStdString();
}

bool RenderEngine::loadPlugin (const std::string& path, int index)
{
    AudioPluginFormatManager pluginFormatManager;
    OwnedArray<PluginDescription> pluginDescriptions;
    KnownPluginList pluginList;
    fillAvailablePluginsInfo(path, pluginFormatManager, pluginDescriptions, pluginList);

    // If there is a problem here first check the preprocessor definitions
    // in the projucer are sensible - is it set up to scan for plugin's?
    jassert (pluginDescriptions.size() > 0);

    if (index >= pluginDescriptions.size()) {
        std::cout << "RenderEngine::loadPlugin error: plugin index " << index
        << "provided, but only " << pluginDescriptions.size()
        << "plugins detected" << std::endl;
        return false;
    }

    String errorMessage;

    if (plugin != nullptr) {
        plugin->releaseResources();
        delete plugin;
    }

    plugin = pluginFormatManager.createPluginInstance (*pluginDescriptions[index],
                                                       sampleRate,
                                                       bufferSize,
                                                       errorMessage);
    if (plugin != nullptr)
    {
        // Success so set up plugin, then set up features and get all available
        // parameters from this given plugin.
        plugin->prepareToPlay (sampleRate, bufferSize);
        plugin->setNonRealtime (true);

        mfcc.setup (512, 42, 13, 20, int (sampleRate / 2), sampleRate);

        // Resize the pluginParameters patch type to fit this plugin and init
        // all the values to 0.0f!
        fillAvailablePluginParameters (pluginParameters);

        return true;
    }

    std::cout << "RenderEngine::loadPlugin error: "
    << errorMessage.toStdString()
    << std::endl;

    return false;
}

//==============================================================================
void RenderEngine::renderPatch (const uint8  midiNote,
                                const uint8  midiVelocity,
                                const double noteLength,
                                const double renderLength)
{
    // Get the overriden patch and set the vst parameters with it.
    PluginPatch overridenPatch = getPatch();
    for (const auto& parameter : overridenPatch)
        plugin->setParameter (parameter.first, parameter.second);

    // Get the note on midiBuffer.
    MidiMessage onMessage = MidiMessage::noteOn (1,
                                                 midiNote,
                                                 midiVelocity);
    onMessage.setTimeStamp(0);
    MidiBuffer midiNoteBuffer;
    midiNoteBuffer.addEvent (onMessage, onMessage.getTimeStamp());

    // Setup fft here so it is destroyed when rendering is finished and
    // the stack unwinds so it doesn't share frames with a new patch.
    maxiFFT fft;
    fft.setup (fftSize, fftSize / 2, fftSize / 4);

    // Data structure to hold multi-channel audio data.
    AudioSampleBuffer audioBuffer (plugin->getTotalNumOutputChannels(),
                                   bufferSize);

    int numberOfBuffers = int (std::ceil (renderLength * sampleRate / bufferSize));

    // Clear and reserve memory for the audio storage!
    processedMonoAudioPreview.clear();
    processedMonoAudioPreview.reserve (numberOfBuffers * bufferSize);

    // Number of FFT, MFCC and RMS frames.
    int numberOfFFT = int (std::ceil (renderLength * sampleRate / fftSize)) * 4;
    rmsFrames.clear();
    rmsFrames.reserve (numberOfFFT);
    currentRmsFrame = 0.0;
    mfccFeatures.clear();
    mfccFeatures.reserve (numberOfFFT);

    plugin->prepareToPlay (sampleRate, bufferSize);

    for (int i = 0; i < numberOfBuffers; ++i)
    {
        // Trigger note off if in the correct audio buffer.
        ifTimeSetNoteOff (noteLength,
                          sampleRate,
                          bufferSize,
                          1,
                          midiNote,
                          midiVelocity,
                          i,
                          midiNoteBuffer);

        // Turn Midi to audio via the vst.
        plugin->processBlock (audioBuffer, midiNoteBuffer);

        // Get audio features and fill the datastructure.
        fillAudioFeatures (audioBuffer, fft);
    }
}

//=============================================================================
void RenderEngine::renderWav(boost::python::object wav)
{
    long sampleCount = p::len(wav);
    // Get the overriden patch and set the vst parameters with it.
    PluginPatch overridenPatch = getPatch();
    for (const auto& parameter : overridenPatch)
        plugin->setParameter (parameter.first, parameter.second);

    // empty MIDI note buffer
    MidiBuffer midiNoteBuffer;

    // Setup fft here so it is destroyed when rendering is finished and
    // the stack unwinds so it doesn't share frames with a new patch.
    maxiFFT fft;
    fft.setup (fftSize, fftSize / 2, fftSize / 4);

    // Data structure to hold multi-channel audio data.
    AudioSampleBuffer audioBuffer (plugin->getTotalNumOutputChannels(),
                                   bufferSize);

    int numberOfBuffers = int (std::ceil (sampleCount / bufferSize));

    // Clear and reserve memory for the audio storage!
    processedMonoAudioPreview.clear();
    processedMonoAudioPreview.reserve (numberOfBuffers * bufferSize);

    // Number of FFT, MFCC and RMS frames.
    int numberOfFFT = int (std::ceil (sampleCount / fftSize)) * 4;
    rmsFrames.clear();
    rmsFrames.reserve (numberOfFFT);
    currentRmsFrame = 0.0;
    mfccFeatures.clear();
    mfccFeatures.reserve (numberOfFFT);

    //wav = wav.astype(np::dtype::get_builtin<double>());

    plugin->prepareToPlay (sampleRate, bufferSize);

    for (int i = 0; i < numberOfBuffers; ++i)
    {
        // TODO: SLOW
        auto writePointers = audioBuffer.getArrayOfWritePointers();
        int numChannels = audioBuffer.getNumChannels();
        int remaining = (i < numberOfBuffers - 1) ? bufferSize : (sampleCount % bufferSize);
        // if buffer size divides sample count, last buffer is full-size
        remaining = (remaining == 0) ? bufferSize : remaining;

        for(int j = 0; j < remaining; j++) {
            double value = p::extract<double>(wav[j + i*bufferSize]);
            for (int k = 0; k < numChannels; k++) {
                writePointers[k][j] = value;
            }
        }

        // Turn Midi to audio via the vst.
        plugin->processBlock (audioBuffer, midiNoteBuffer);

        // Get audio features and fill the datastructure.
        fillAudioFeatures (audioBuffer, fft);
    }

}

//=============================================================================
void RenderEngine::fillAudioFeatures (const AudioSampleBuffer& data,
                                      maxiFFT&                 fft)
{
    // Keep it auto as it may or may not be double precision.
    const auto readptrs = data.getArrayOfReadPointers();
    for (int i = 0; i < data.getNumSamples(); ++i)
    {
        // Mono the frame.
        int channel = 0;
        auto currentFrame = readptrs[channel][i];
        const int numberChannels = data.getNumChannels();

        while (++channel < numberChannels)
            currentFrame += readptrs[channel][i];

        currentFrame /= numberChannels;

        // Save the audio for playback and plotting!
        processedMonoAudioPreview.push_back (currentFrame);

        // RMS.
        currentRmsFrame += (currentFrame * currentFrame);

        // Extract features.
        if (fft.process (currentFrame))
        {
            // This isn't real-time so I can take the luxuary of allocating
            // heap memory here.
            double* mfccs = new double[13];
            mfcc.mfcc (fft.magnitudes, mfccs);

            std::array<double, 13> mfccsFrame;
            std::memcpy (mfccsFrame.data(), mfccs, sizeof (double) * 13);

            // Add the mfcc frames here.
            mfccFeatures.push_back (mfccsFrame);
            delete[] mfccs;

            // Root Mean Square.
            currentRmsFrame /= fftSize;
            currentRmsFrame = sqrt (currentRmsFrame);
            rmsFrames.push_back (currentRmsFrame);
            currentRmsFrame = 0.0;
        }
    }
}

//=============================================================================
void RenderEngine::ifTimeSetNoteOff (const double noteLength,
                                     const double sampleRate,
                                     const int    bufferSize,
                                     const uint8  midiChannel,
                                     const uint8  midiPitch,
                                     const uint8  midiVelocity,
                                     const int    currentBufferIndex,
                                     MidiBuffer&  bufferToNoteOff)
{
    double eventFrame = noteLength * sampleRate;
    bool bufferBeginIsBeforeEvent = currentBufferIndex * bufferSize < eventFrame;
    bool bufferEndIsAfterEvent = (currentBufferIndex + 1) * bufferSize >= eventFrame;
    bool noteOffEvent = bufferBeginIsBeforeEvent && bufferEndIsAfterEvent;
    if (noteOffEvent)
    {
        MidiBuffer midiOffBuffer;
        MidiMessage offMessage = MidiMessage::noteOff (midiChannel,
                                                       midiPitch,
                                                       midiVelocity);
        offMessage.setTimeStamp(eventFrame);
        midiOffBuffer.addEvent(offMessage, offMessage.getTimeStamp());
        bufferToNoteOff = midiOffBuffer;
    }
}

//==============================================================================
bool RenderEngine::overridePluginParameter (const int   index,
                                            const float value)
{
    int biggestParameterIndex = pluginParameters.size() - 1;

    if (biggestParameterIndex < 0)
    {
        std::cout << "RenderEngine::overridePluginParameter error: " <<
                     "No patch set. Is the plugin loaded?" << std::endl;
        return false;
    }
    else if (index > pluginParameters[biggestParameterIndex].first)
    {
        std::cout << "RenderEngine::overridePluginParameter error: " <<
                     "Overriden parameter index is greater than the biggest parameter index." <<
                     std::endl;
        return false;
    }
    else if (index < 0)
    {
        std::cout << "RenderEngine::overridePluginParameter error: " <<
                     "Overriden parameter index is less than the smallest parameter index." <<
                     std::endl;
        return false;
    }
    else if (value < 0.0 || value > 1.0)
    {
        std::cout << "RenderEngine::overridePluginParameter error: " <<
                     "Keep the overriden value between 0.0 and 1.0." <<
                     std::endl;
        return false;
    }

    auto iterator = std::find_if (overridenParameters.begin(),
                                  overridenParameters.end(),
                                  [&index] (const std::pair<int, float>& parameter)
                                  {
                                      return parameter.first == index;
                                  });

    bool exists = (iterator != overridenParameters.end());

    if (exists)
        iterator->second = value;
    else
        overridenParameters.push_back(std::make_pair(index, value));

    return true;
}

//==============================================================================
bool RenderEngine::removeOverridenParameter (const int index)
{
    int biggestParameterIndex = pluginParameters.size() - 1;

    if (biggestParameterIndex < 0)
    {
        std::cout << "RenderEngine::removeOverridenParameter error: " <<
                     "No patch set. Is the plugin loaded?" << std::endl;
        return false;
    }
    else if (index > pluginParameters[biggestParameterIndex].first)
    {
        std::cout << "RenderEngine::removeOverridenParameter error: " <<
                     "Overriden parameter index is greater than the biggest parameter index." <<
                     std::endl;
        return false;
    }
    else if (index < 0)
    {
        std::cout << "RenderEngine::removeOverridenParameter error: " <<
                     "Overriden parameter index is less than the smallest parameter index." <<
                     std::endl;
        return false;
    }

    auto iterator = std::find_if (overridenParameters.begin(),
                                  overridenParameters.end(),
                                  [&index] (const std::pair<int, float>& parameter)
                                  {
                                      return parameter.first == index;
                                  });

    bool exists = (iterator != overridenParameters.end());

    if (exists)
    {
        overridenParameters.erase(iterator);
        return true;
    }

    std::cout << "RenderEngine::removeOverridenParameter error: " <<
                 "Overriden parameter does not exist." <<
                 std::endl;
    return false;
}

//==============================================================================
void RenderEngine::fillAvailablePluginParameters (PluginPatch& params)
{
    params.clear();
    params.reserve (plugin->getNumParameters());

    int usedParameterAmount = 0;
    for (int i = 0; i < plugin->getNumParameters(); ++i)
    {
        // Ensure the parameter is not unused.
        if (plugin->getParameterName(i) != "Param")
        {
            ++usedParameterAmount;
            params.push_back (std::make_pair (i, 0.0f));
        }
    }
    params.shrink_to_fit();
}

//==============================================================================
ParameterNameList RenderEngine::getPluginParametersDescription()
{
    ParameterNameList namedParameters;

    if (plugin != nullptr)
    {
        std::ostringstream ss;

        for (const auto& pair : pluginParameters)
        {
            namedParameters.push_back(std::make_pair(pair.first, plugin->getParameterName (pair.first).toStdString()));
        }
    }
    return namedParameters;
}

//==============================================================================
void RenderEngine::setPatch (const PluginPatch patch)
{
    const size_t currentParameterSize = pluginParameters.size();
    const size_t newPatchParameterSize = patch.size();

    if (currentParameterSize == newPatchParameterSize)
    {
        pluginParameters = patch;
    }
    else
    {
        std::cout << "RenderEngine::setPatch error: Incorrect patch size!" <<
        "\n- Current size:  " << currentParameterSize <<
        "\n- Supplied size: " << newPatchParameterSize << std::endl;
    }
}

//==============================================================================
const PluginPatch RenderEngine::getPatch()
{
    if (overridenParameters.size() == 0)
        return pluginParameters;

    PluginPatch overridenPluginParameters = pluginParameters;
    std::pair<int, float> copy;

    for (auto& parameter : overridenPluginParameters)
    {
        // Should we have overriden this parameter's index...
        if (std::any_of(overridenParameters.begin(), overridenParameters.end(),
                        [parameter, &copy] (std::pair<int, float> p)
                        {
                            copy = p;
                            return p.first == parameter.first;
                        }))
        {
            parameter = copy;
        }
    }
    return overridenPluginParameters;
}

//==============================================================================
const size_t RenderEngine::getPluginParameterSize()
{
    return pluginParameters.size();
}

//==============================================================================
const MFCCFeatures RenderEngine::getMFCCFrames()
{
    return mfccFeatures;
}

//==============================================================================
const MFCCFeatures RenderEngine::getNormalisedMFCCFrames(const std::array<double, 13>& mean,
                                                         const std::array<double, 13>& variance)
{
    MFCCFeatures normalisedMFCCFrames;
    normalisedMFCCFrames.resize (mfccFeatures.size());

    for (size_t i = 0; i < normalisedMFCCFrames.size(); ++i)
    {
        for (size_t j = 0; j < 13; ++j)
        {
            normalisedMFCCFrames[i][j] = mfccFeatures[i][j] - mean[j];
            normalisedMFCCFrames[i][j] /= variance[j];
        }
    }
    return normalisedMFCCFrames;
}

//==============================================================================
const std::vector<double> RenderEngine::getAudioFrames()
{
    return processedMonoAudioPreview;
}

//==============================================================================
const std::vector<double> RenderEngine::getRMSFrames()
{
    return rmsFrames;
}

//==============================================================================
bool RenderEngine::writeToWav(const std::string& path)
{
    const auto size = processedMonoAudioPreview.size();
    if (size == 0)
        return false;

    maxiRecorder recorder;
    recorder.setup (path);
    recorder.startRecording();
    const double* data = processedMonoAudioPreview.data();
    recorder.passData (data, size);
    recorder.stopRecording();
    recorder.saveToWav();
    return true;
}

repo_name: fedden/RenderMan

mime_type: text/x-c++


text:
/*
  ==============================================================================

    source.cpp
    Created: 18 Feb 2017 6:37:01pm
    Author:  tollie

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

#include "PatchGenerator.h"
#include <boost/python.hpp>
//#include <boost/python/numpy.hpp>

// Could also easily be namespace crap.
namespace wrap
{
    //==========================================================================
    // Converts a C++ vector to a Python list. All following functions
    // are essentially cheap ripoffs from this one.
    // https://gist.github.com/octavifs/5362272
    template <class T>
    boost::python::list vectorToList (std::vector<T> vector)
    {
    	typename std::vector<T>::iterator iter;
    	boost::python::list list;
    	for (iter = vector.begin(); iter != vector.end(); ++iter)
        {
    		list.append(*iter);
    	}
    	return list;
    }

    //==========================================================================
    // Yeah this is lazy. I know.
    template <class T>
    boost::python::list arrayToList (std::array<T, 13> array)
    {
    	typename std::array<T, 13>::iterator iter;
    	boost::python::list list;
    	for (iter = array.begin(); iter != array.end(); ++iter)
        {
    		list.append(*iter);
    	}
    	return list;
    }

    //==========================================================================
    // Converts a std::pair which is used as a parameter in C++
    // into a tuple with the respective types int and float for
    // use in Python.
    boost::python::tuple parameterToTuple (std::pair<int, float> parameter)
    {
        boost::python::tuple parameterTuple;
        parameterTuple = boost::python::make_tuple (parameter.first,
                                                    parameter.second);
        return parameterTuple;
    }

    //==========================================================================
    // Converts a PluginPatch ( std::vector <std::pair <int, float>> )
    // to a Python list.
    boost::python::list pluginPatchToListOfTuples (PluginPatch parameters)
    {
    	std::vector<std::pair<int, float>>::iterator iter;
    	boost::python::list list;
    	for (iter = parameters.begin(); iter != parameters.end(); ++iter)
        {
            auto tup = parameterToTuple (*iter);
    		list.append(tup);
    	}
    	return list;
    }

    //==========================================================================
    // std::vector <std::array <double, 13>> MFCCFeatures;
    boost::python::list mfccFramesToListOfLists (MFCCFeatures frames)
    {
        boost::python::list list;
        std::vector <std::array <double, 13>>::iterator iter;
        for (iter = frames.begin(); iter != frames.end(); ++iter)
        {
            auto l = arrayToList (*iter);
    		list.append(l);
    	}
    	return list;
    }

    //==========================================================================
    PluginPatch listOfTuplesToPluginPatch (boost::python::list listOfTuples)
    {
        PluginPatch patch;
        const size_t size = boost::python::len (listOfTuples);
        patch.reserve (size);
        std::pair <int, float> parameter;
        for (int i = 0; i < size; ++i)
        {
            boost::python::tuple tup;
            tup = boost::python::extract<boost::python::tuple> (listOfTuples[i]);
            int   index = int (boost::python::extract<float> (tup[0]));
            float value = float (boost::python::extract<float> (tup[1]));
            parameter = std::make_pair (index, value);
            patch.push_back (parameter);
        }
        return patch;
    }

    //==========================================================================
    class RenderEngineWrapper : public RenderEngine
    {
    public:
        RenderEngineWrapper (int sr, int bs, int ffts) :
            RenderEngine (sr, bs, ffts)
        { }

        void wrapperSetPatch (boost::python::list listOfTuples)
        {
            PluginPatch patch = listOfTuplesToPluginPatch (listOfTuples);
            RenderEngine::setPatch(patch);
        }

        boost::python::list wrapperGetPatch()
        {
            return pluginPatchToListOfTuples (RenderEngine::getPatch());
        }

        void wrapperRenderPatch (int    midiNote,
                                 int    midiVelocity,
                                 double noteLength,
                                 double renderLength)
        {
            if (midiNote > 255) midiNote = 255;
            if (midiNote < 0) midiNote = 0;
            if (midiVelocity > 255) midiVelocity = 255;
            if (midiVelocity < 0) midiVelocity = 0;
            RenderEngine::renderPatch(midiNote,
                                      midiVelocity,
                                      noteLength,
                                      renderLength);
        }

        void wrapperRenderWav (boost::python::object arr)
        {
            RenderEngine::renderWav(arr);
        }

        boost::python::list wrapperGetMFCCFrames()
        {
            return mfccFramesToListOfLists (RenderEngine::getMFCCFrames());
        }

        int wrapperGetPluginParameterSize()
        {
            return int (RenderEngine::getPluginParameterSize());
        }

        boost::python::list wrapperGetPluginParametersDescription()
        {
            //return RenderEngine::getPluginParametersDescription().toStdString();
            boost::python::list outputList;
            for (const auto& param : RenderEngine::getPluginParametersDescription()) {
                outputList.append(boost::python::make_tuple(param.first, param.second));
            }
            return outputList;
        }

        boost::python::list wrapperGetAudioFrames()
        {
            return vectorToList (RenderEngine::getAudioFrames());
        }

        boost::python::list wrapperGetRMSFrames()
        {
            return vectorToList (RenderEngine::getRMSFrames());
        }

        boost::python::dict wrapperGetPluginNames(const std::string& path)
        {
            AudioPluginFormatManager pluginFormatManager;
            OwnedArray<PluginDescription> pluginDescriptions;
            KnownPluginList pluginList;
            fillAvailablePluginsInfo(path, pluginFormatManager, pluginDescriptions, pluginList);

            boost::python::dict out;
            int index = 0;
            for (const auto& pluginDescription : pluginList) {
                out[pluginDescription->name.toStdString()] = index;
                index++;
            }
            return out;
        }
    };

    //==========================================================================
    class PatchGeneratorWrapper : public PatchGenerator
    {
    public:
        PatchGeneratorWrapper (RenderEngine& engine) :
            PatchGenerator (engine)
        { }

        boost::python::tuple wrapperGetRandomParameter (int index)
        {
            return parameterToTuple (PatchGenerator::getRandomParameter (index));
        }

        boost::python::list wrapperGetRandomPatch()
        {
            return pluginPatchToListOfTuples (PatchGenerator::getRandomPatch());
        }
    };
}

//==============================================================================
BOOST_PYTHON_MODULE(librenderman)
{
    using namespace boost::python;
    using namespace wrap;

    class_<RenderEngineWrapper>("RenderEngine", init<int, int, int>())
    .def("get_available_plugins_xml", &RenderEngineWrapper::getAvailablePluginsXml)
    .def("get_available_plugin_names", &RenderEngineWrapper::wrapperGetPluginNames)
    .def("load_plugin", &RenderEngineWrapper::loadPlugin)
    .def("set_patch", &RenderEngineWrapper::wrapperSetPatch)
    .def("get_patch", &RenderEngineWrapper::wrapperGetPatch)
    .def("render_patch", &RenderEngineWrapper::wrapperRenderPatch)
    .def("render_wav", &RenderEngineWrapper::wrapperRenderWav)
    .def("get_mfcc_frames", &RenderEngineWrapper::wrapperGetMFCCFrames)
    .def("get_plugin_parameter_size", &RenderEngineWrapper::wrapperGetPluginParameterSize)
    .def("get_plugin_parameters_description", &RenderEngineWrapper::wrapperGetPluginParametersDescription)
    .def("override_plugin_parameter", &RenderEngineWrapper::overridePluginParameter)
    .def("remove_overriden_plugin_parameter", &RenderEngineWrapper::removeOverridenParameter)
    .def("get_audio_frames", &RenderEngineWrapper::wrapperGetAudioFrames)
    .def("get_rms_frames", &RenderEngineWrapper::wrapperGetRMSFrames)
    .def("write_to_wav", &RenderEngineWrapper::writeToWav);

    class_<PatchGeneratorWrapper>("PatchGenerator", init<RenderEngineWrapper&>())
    .def("get_random_parameter", &PatchGeneratorWrapper::wrapperGetRandomParameter)
    .def("get_random_patch", &PatchGeneratorWrapper::wrapperGetRandomPatch);
}


text:
/*
  ==============================================================================

    PatchGenerator.h
    Created: 19 Feb 2017 9:50:46pm
    Author:  tollie

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

#ifndef PATCHGENERATOR_H_INCLUDED
#define PATCHGENERATOR_H_INCLUDED

#include "RenderEngine.h"

//==============================================================================
class PatchGenerator
{

public:
    PatchGenerator (RenderEngine& engine) :
        generator (std::random_device()())
    {
        skeletonPatch = engine.getPatch();
        for (auto& parameter : skeletonPatch)
            parameter.second = 0.0f;
    }

    std::pair<int, float> getRandomParameter (int index);

    PluginPatch getRandomPatch();

private:
    PluginPatch skeletonPatch;

    std::mt19937_64 generator;
};

#endif  // PATCHGENERATOR_H_INCLUDED


text:
/*
  ==============================================================================

    RenderEngine.h
    Created: 19 Feb 2017 9:47:15pm
    Author:  tollie

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

#ifndef RENDERENGINE_H_INCLUDED
#define RENDERENGINE_H_INCLUDED

#include <random>
#include <array>
#include <iomanip>
#include <sstream>
#include <string>
#include "Maximilian/maximilian.h"
#include "Maximilian/libs/maxiFFT.h"
#include "Maximilian/libs/maxiMFCC.h"
#include "../JuceLibraryCode/JuceHeader.h"
#include <boost/python.hpp>

using namespace juce;

typedef std::vector<std::pair<int, float>>  PluginPatch;
typedef std::vector<std::array<double, 13>> MFCCFeatures;
typedef std::vector<std::pair<int, std::string>> ParameterNameList;
typedef std::pair<OwnedArray<PluginDescription>, KnownPluginList> PluginsInfo;
typedef std::vector<std::pair<std::string, int>> PluginNames;

class RenderEngine
{
public:
    RenderEngine (int sr,
                  int bs,
                  int ffts) :
        sampleRate(sr),
        bufferSize(bs),
        fftSize(ffts),
        plugin(nullptr)
    {
        maxiSettings::setup (sampleRate, 1, bufferSize);
    }

    virtual ~RenderEngine()
    {
        if (plugin != nullptr)
        {
            plugin->releaseResources();
            delete plugin;
        }
    }

    std::string getAvailablePluginsXml(const std::string& path);

    void fillAvailablePluginsInfo(const std::string& path,
                                  AudioPluginFormatManager& pluginFormatManager,
                                  OwnedArray<PluginDescription>& pluginDescriptions,
                                  KnownPluginList& pluginList
                                  );

    bool loadPlugin (const std::string& path, int index = 0);

    void setPatch (const PluginPatch patch);

    const PluginPatch getPatch();

    void renderPatch (const uint8  midiNote,
                      const uint8  midiVelocity,
                      const double noteLength,
                      const double renderLength);

    void renderWav(boost::python::object wav);

    const MFCCFeatures getMFCCFrames();

    const MFCCFeatures getNormalisedMFCCFrames (const std::array<double, 13>& mean,
                                                const std::array<double, 13>& variance);

    const std::vector<double> getRMSFrames();

    const size_t getPluginParameterSize();

    ParameterNameList getPluginParametersDescription();

    bool overridePluginParameter (const int   index,
                                  const float value);

    bool removeOverridenParameter (const int index);

    const std::vector<double> getAudioFrames();

    bool writeToWav(const std::string& path);

private:
    void fillAudioFeatures (const AudioSampleBuffer& data,
                            maxiFFT&                 fft);

    void ifTimeSetNoteOff (const double noteLength,
                           const double sampleRate,
                           const int    bufferSize,
                           const uint8  midiChannel,
                           const uint8  midiPitch,
                           const uint8  midiVelocity,
                           const int    currentBufferIndex,
                           MidiBuffer&   bufferToNoteOff);

    void fillAvailablePluginParameters (PluginPatch& params);

    double               sampleRate;
    int                  bufferSize;
    int                  fftSize;
    maxiMFCC             mfcc;
    AudioPluginInstance* plugin;
    PluginPatch          pluginParameters;
    PluginPatch          overridenParameters;
    MFCCFeatures         mfccFeatures;
    std::vector<double>  processedMonoAudioPreview;
    std::vector<double>  rmsFrames;
    double               currentRmsFrame;
};

#endif  // RENDERENGINE_H_INCLUDED


text:
/*
  ==============================================================================

    PatchGenerator.cpp
    Created: 19 Feb 2017 9:50:47pm
    Author:  tollie

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

#include "PatchGenerator.h"

//==============================================================================
std::pair<int, float> PatchGenerator::getRandomParameter (int index)
{
    std::uniform_real_distribution<float> distribution (0, 1);
    float randomValue = distribution (generator);
    return std::make_pair (index, randomValue);
}

//==============================================================================
PluginPatch PatchGenerator::getRandomPatch()
{
    PluginPatch randomPatch = skeletonPatch;
    std::uniform_real_distribution<float> distribution (0, 1);
    for (auto& parameter : randomPatch)
        parameter.second = distribution (generator);
    return randomPatch;
}