################################################################################
# mutable-beads - LV2 port of Mutable Instruments Beads granular audio processor.
# Features time-stretching, pitch shifting, grain window shaping, 
# built-in reverb, pitch randomization, and freeze buffer controls.
################################################################################

MUTABLE_BEADS_VERSION = main
MUTABLE_BEADS_SITE = https://github.com/DISTRHO/DPF.git
MUTABLE_BEADS_SITE_METHOD = git
MUTABLE_BEADS_BUNDLES = mutable-beads.lv2

define MUTABLE_BEADS_PLUGIN_INFO_H
#ifndef DISTRHO_PLUGIN_INFO_H_INCLUDED
#define DISTRHO_PLUGIN_INFO_H_INCLUDED

#define DISTRHO_PLUGIN_BRAND   "Mutable Instruments"
#define DISTRHO_PLUGIN_NAME    "Beads"
#define DISTRHO_PLUGIN_URI     "https://github.com/austin-dsp/lv2-plugins/mutable-beads"
#define DISTRHO_PLUGIN_CLAP_ID "com.mutableinstruments.beads"

#define DISTRHO_PLUGIN_NUM_INPUTS   2
#define DISTRHO_PLUGIN_NUM_OUTPUTS  2
#define DISTRHO_PLUGIN_IS_RT_SAFE   1
#define DISTRHO_PLUGIN_IS_SYNTH     0
#define DISTRHO_PLUGIN_HAS_UI       0
#define DISTRHO_PLUGIN_WANT_STATE   0
#define DISTRHO_PLUGIN_WANT_LATENCY 0
#define DISTRHO_PLUGIN_WANT_TIMEPOS 0
#define DISTRHO_PLUGIN_WANT_MIDI_INPUT  0
#define DISTRHO_PLUGIN_WANT_MIDI_OUTPUT 0

enum Parameters {
    pTime = 0,
    pSize,
    pShape,
    pPitch,
    pDensity,
    pTexture,
    pDryWet,
    pReverb,
    pAttenurandom,
    pFreeze,

    kParameterCount
};

#endif // DISTRHO_PLUGIN_INFO_H_INCLUDED

endef

define MUTABLE_BEADS_PLUGIN_CPP
#include "DistrhoPlugin.hpp"
#include <cmath>
#include <vector>
#include <algorithm>
#include <cstdlib>

START_NAMESPACE_DISTRHO

static const size_t BUFFER_SIZE = 192000; // ~4 seconds at 48kHz

struct Grain {
    bool active;
    float startPos;
    float playPos;
    float durationSamples;
    float pitchRatio;
    float envelopePhase;
    float shape;
};

class MutableBeadsPlugin : public Plugin {
public:
    MutableBeadsPlugin() : Plugin(kParameterCount, 0, 0), fSampleRate(48000.0f), fWriteHead(0) {
        fParams[pTime] = 0.5f;
        fParams[pSize] = 0.3f;
        fParams[pShape] = 0.5f;
        fParams[pPitch] = 0.0f;
        fParams[pDensity] = 0.5f;
        fParams[pTexture] = 0.2f;
        fParams[pDryWet] = 0.5f;
        fParams[pReverb] = 0.2f;
        fParams[pAttenurandom] = 0.0f;
        fParams[pFreeze] = 0.0f;

        fBufferL.assign(BUFFER_SIZE, 0.0f);
        fBufferR.assign(BUFFER_SIZE, 0.0f);
        fReverbBufferL.assign(24000, 0.0f);
        fReverbBufferR.assign(24000, 0.0f);
        fReverbHead = 0;

        fGrainTriggerCounter = 0.0f;

        for (int i = 0; i < 16; ++i) {
            fGrains[i].active = false;
        }
    }

protected:
    const char* getLabel() const override { return "MutableBeads"; }
    const char* getDescription() const override {
        return "Granular audio processor and texture synthesizer based on "
               "Mutable Instruments Beads Eurorack module.";
    }
    const char* getMaker() const override { return "Mutable Instruments / AustinDSP"; }
    const char* getLicense() const override { return "MIT"; }
    uint32_t getVersion() const override { return d_version(1, 0, 0); }
    int64_t getUniqueId() const override { return d_cconst('M', 'I', 'B', 'D'); }

    void sampleRateChanged(double newSampleRate) override {
        fSampleRate = (float)newSampleRate;
    }

    void initParameter(uint32_t index, Parameter& parameter) override {
        parameter.hints = kParameterIsAutomatable;
        switch(index) {
            case pTime:
                parameter.name = "Time";
                parameter.symbol = "time";
                parameter.ranges.def = 0.5f;
                parameter.ranges.min = 0.0f;
                parameter.ranges.max = 1.0f;
                break;
            case pSize:
                parameter.name = "Size";
                parameter.symbol = "size";
                parameter.ranges.def = 0.3f;
                parameter.ranges.min = 0.01f;
                parameter.ranges.max = 1.0f;
                break;
            case pShape:
                parameter.name = "Envelope Shape";
                parameter.symbol = "shape";
                parameter.ranges.def = 0.5f;
                parameter.ranges.min = 0.0f;
                parameter.ranges.max = 1.0f;
                break;
            case pPitch:
                parameter.name = "Pitch Transpose";
                parameter.symbol = "pitch";
                parameter.unit = "semitones";
                parameter.ranges.def = 0.0f;
                parameter.ranges.min = -24.0f;
                parameter.ranges.max = 24.0f;
                break;
            case pDensity:
                parameter.name = "Grain Density";
                parameter.symbol = "density";
                parameter.ranges.def = 0.5f;
                parameter.ranges.min = 0.0f;
                parameter.ranges.max = 1.0f;
                break;
            case pTexture:
                parameter.name = "Texture / Filter";
                parameter.symbol = "texture";
                parameter.ranges.def = 0.2f;
                parameter.ranges.min = 0.0f;
                parameter.ranges.max = 1.0f;
                break;
            case pDryWet:
                parameter.name = "Dry / Wet";
                parameter.symbol = "dry_wet";
                parameter.ranges.def = 0.5f;
                parameter.ranges.min = 0.0f;
                parameter.ranges.max = 1.0f;
                break;
            case pReverb:
                parameter.name = "Reverb Amount";
                parameter.symbol = "reverb";
                parameter.ranges.def = 0.2f;
                parameter.ranges.min = 0.0f;
                parameter.ranges.max = 1.0f;
                break;
            case pAttenurandom:
                parameter.name = "Pitch Randomization";
                parameter.symbol = "attenurandom";
                parameter.ranges.def = 0.0f;
                parameter.ranges.min = 0.0f;
                parameter.ranges.max = 1.0f;
                break;
            case pFreeze:
                parameter.name = "Freeze Buffer";
                parameter.symbol = "freeze";
                parameter.hints = kParameterIsAutomatable | kParameterIsBoolean;
                parameter.ranges.def = 0.0f;
                parameter.ranges.min = 0.0f;
                parameter.ranges.max = 1.0f;
                break;
        }
    }

    float getParameterValue(uint32_t index) const override { return fParams[index]; }
    void setParameterValue(uint32_t index, float value) override { fParams[index] = value; }

    void run(const float** inputs, float** outputs, uint32_t frames) override {
        const float* inL = inputs[0];
        const float* inR = inputs[1];
        float* outL = outputs[0];
        float* outR = outputs[1];

        float timeVal = fParams[pTime];
        float sizeVal = fParams[pSize];
        float shapeVal = fParams[pShape];
        float pitchVal = fParams[pPitch];
        float densityVal = fParams[pDensity];
        float dryWetVal = fParams[pDryWet];
        float reverbVal = fParams[pReverb];
        float randVal = fParams[pAttenurandom];
        bool freezeOn = fParams[pFreeze] > 0.5f;

        float grainIntervalSamples = (1.0f - densityVal * 0.95f) * fSampleRate * 0.2f + 120.0f;

        for (uint32_t i = 0; i < frames; ++i) {
            if (!freezeOn) {
                fBufferL[fWriteHead] = inL[i];
                fBufferR[fWriteHead] = inR[i];
                fWriteHead = (fWriteHead + 1) % BUFFER_SIZE;
            }

            fGrainTriggerCounter += 1.0f;
            if (fGrainTriggerCounter >= grainIntervalSamples) {
                fGrainTriggerCounter = 0.0f;
                spawnGrain(timeVal, sizeVal, shapeVal, pitchVal, randVal);
            }

            float grainOutL = 0.0f;
            float grainOutR = 0.0f;

            for (int g = 0; g < 16; ++g) {
                if (!fGrains[g].active) continue;

                float sampleL = readBufferInterpolated(fBufferL, fGrains[g].playPos);
                float sampleR = readBufferInterpolated(fBufferR, fGrains[g].playPos);

                float envNorm = fGrains[g].envelopePhase / fGrains[g].durationSamples;
                float envWeight = 0.0f;

                if (fGrains[g].shape < 0.5f) {
                    envWeight = std::sin(envNorm * 3.14159265f);
                } else {
                    envWeight = std::pow(1.0f - envNorm, 2.0f);
                }

                grainOutL += sampleL * envWeight;
                grainOutR += sampleR * envWeight;

                fGrains[g].playPos += fGrains[g].pitchRatio;
                if (fGrains[g].playPos >= BUFFER_SIZE) fGrains[g].playPos -= BUFFER_SIZE;
                if (fGrains[g].playPos < 0) fGrains[g].playPos += BUFFER_SIZE;

                fGrains[g].envelopePhase += 1.0f;
                if (fGrains[g].envelopePhase >= fGrains[g].durationSamples) {
                    fGrains[g].active = false;
                }
            }

            float revL = 0.0f, revR = 0.0f;
            if (reverbVal > 0.001f) {
                size_t delTap1 = (fReverbHead + 12000 - 3217) % 12000;
                size_t delTap2 = (fReverbHead + 12000 - 5411) % 12000;
                fReverbBufferL[fReverbHead] = grainOutL + fReverbBufferR[delTap1] * 0.6f * reverbVal;
                fReverbBufferR[fReverbHead] = grainOutR + fReverbBufferL[delTap2] * 0.6f * reverbVal;

                revL = fReverbBufferL[delTap1] * reverbVal;
                revR = fReverbBufferR[delTap2] * reverbVal;

                fReverbHead = (fReverbHead + 1) % 12000;
            }

            float finalWetL = grainOutL + revL;
            float finalWetR = grainOutR + revR;

            outL[i] = inL[i] * (1.0f - dryWetVal) + finalWetL * dryWetVal;
            outR[i] = inR[i] * (1.0f - dryWetVal) + finalWetR * dryWetVal;
        }
    }

private:
    void spawnGrain(float timeVal, float sizeVal, float shapeVal, float pitchVal, float randVal) {
        int targetGrain = -1;

        // 1. Search for an inactive grain slot
        for (int g = 0; g < 16; ++g) {
            if (!fGrains[g].active) {
                targetGrain = g;
                break;
            }
        }

        // 2. Voice stealing: If all 16 slots are active, steal the grain nearest completion
        if (targetGrain == -1) {
            float maxPhaseRatio = -1.0f;
            for (int g = 0; g < 16; ++g) {
                float phaseRatio = fGrains[g].envelopePhase / fGrains[g].durationSamples;
                if (phaseRatio > maxPhaseRatio) {
                    maxPhaseRatio = phaseRatio;
                    targetGrain = g;
                }
            }
        }

        if (targetGrain >= 0 && targetGrain < 16) {
            Grain& grain = fGrains[targetGrain];
            grain.active = true;

            float delayOffsetSamples = timeVal * (BUFFER_SIZE - 4800);
            float startPos = (float)fWriteHead - delayOffsetSamples;
            if (startPos < 0) startPos += BUFFER_SIZE;

            grain.startPos = startPos;
            grain.playPos = startPos;
            grain.durationSamples = (sizeVal * 0.5f + 0.02f) * fSampleRate;

            float randPitchOffset = 0.0f;
            if (randVal > 0.01f) {
                float r = ((float)rand() / (float)RAND_MAX) * 2.0f - 1.0f;
                randPitchOffset = r * randVal * 12.0f;
            }

            float finalPitch = pitchVal + randPitchOffset;
            grain.pitchRatio = std::pow(2.0f, finalPitch / 12.0f);
            grain.envelopePhase = 0.0f;
            grain.shape = shapeVal;
        }
    }

    inline float readBufferInterpolated(const std::vector<float>& buf, float index) const {
        int i0 = (int)index;
        int i1 = (i0 + 1) % BUFFER_SIZE;
        float frac = index - (float)i0;
        return buf[i0] * (1.0f - frac) + buf[i1] * frac;
    }

    float fParams[kParameterCount];
    float fSampleRate;
    size_t fWriteHead;

    std::vector<float> fBufferL;
    std::vector<float> fBufferR;

    std::vector<float> fReverbBufferL;
    std::vector<float> fReverbBufferR;
    size_t fReverbHead;

    float fGrainTriggerCounter;
    Grain fGrains[16];

    DISTRHO_DECLARE_NON_COPYABLE(MutableBeadsPlugin)
};

Plugin* createPlugin() { return new MutableBeadsPlugin(); }

END_NAMESPACE_DISTRHO

endef

define MUTABLE_BEADS_PLUGIN_MAKEFILE
#!/usr/bin/make -f
NAME      = mutable-beads
FILES_DSP = Plugin.cpp
include ../../Makefile.plugins.mk
TARGETS = lv2_dsp
all: $(TARGETS)

endef

define MUTABLE_BEADS_MANIFEST_TTL
@prefix lv2:  <http://lv2plug.in/ns/lv2core#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix pset: <http://lv2plug.in/ns/ext/presets#> .

<https://github.com/austin-dsp/lv2-plugins/mutable-beads>
    a lv2:Plugin ;
    lv2:binary <mutable-beads_dsp.so> ;
    rdfs:seeAlso <mutable-beads.ttl> .

<https://github.com/austin-dsp/lv2-plugins/mutable-beads#preset-cloud-reverb-wash>
    a pset:Preset ;
    lv2:appliesTo <https://github.com/austin-dsp/lv2-plugins/mutable-beads> ;
    rdfs:seeAlso <cloud-reverb-wash.ttl> .

<https://github.com/austin-dsp/lv2-plugins/mutable-beads#preset-octave-shimmer>
    a pset:Preset ;
    lv2:appliesTo <https://github.com/austin-dsp/lv2-plugins/mutable-beads> ;
    rdfs:seeAlso <octave-shimmer.ttl> .

<https://github.com/austin-dsp/lv2-plugins/mutable-beads#preset-granular-rhythmic-delay>
    a pset:Preset ;
    lv2:appliesTo <https://github.com/austin-dsp/lv2-plugins/mutable-beads> ;
    rdfs:seeAlso <granular-rhythmic-delay.ttl> .

<https://github.com/austin-dsp/lv2-plugins/mutable-beads#preset-random-pitch-texture>
    a pset:Preset ;
    lv2:appliesTo <https://github.com/austin-dsp/lv2-plugins/mutable-beads> ;
    rdfs:seeAlso <random-pitch-texture.ttl> .

<https://github.com/austin-dsp/lv2-plugins/mutable-beads#preset-micro-loop-freeze>
    a pset:Preset ;
    lv2:appliesTo <https://github.com/austin-dsp/lv2-plugins/mutable-beads> ;
    rdfs:seeAlso <micro-loop-freeze.ttl> .

endef

define MUTABLE_BEADS_PLUGIN_TTL
@prefix lv2:   <http://lv2plug.in/ns/lv2core#> .
@prefix rdf:   <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs:  <http://www.w3.org/2000/01/rdf-schema#> .
@prefix doap:  <http://usefulinc.com/ns/doap#> .
@prefix units: <http://lv2plug.in/ns/extensions/units#> .
@prefix pprop: <http://lv2plug.in/ns/ext/port-props#> .

<https://github.com/austin-dsp/lv2-plugins/mutable-beads>
    a lv2:Plugin ;
    doap:name "Mutable Instruments Beads" ;
    doap:license <https://opensource.org/licenses/MIT> ;
    lv2:project <https://github.com/austin-dsp/lv2-plugins/mutable-beads> ;
    lv2:optionalFeature lv2:hardRTCapable ;
    lv2:port
    [
        a lv2:InputPort, lv2:AudioPort ;
        lv2:index 0 ;
        lv2:symbol "audio_in_l" ;
        lv2:name "Audio Input L" ;
    ] ,
    [
        a lv2:InputPort, lv2:AudioPort ;
        lv2:index 1 ;
        lv2:symbol "audio_in_r" ;
        lv2:name "Audio Input R" ;
    ] ,
    [
        a lv2:OutputPort, lv2:AudioPort ;
        lv2:index 2 ;
        lv2:symbol "audio_out_l" ;
        lv2:name "Audio Output L" ;
    ] ,
    [
        a lv2:OutputPort, lv2:AudioPort ;
        lv2:index 3 ;
        lv2:symbol "audio_out_r" ;
        lv2:name "Audio Output R" ;
    ] ,
    [
        a lv2:InputPort, lv2:ControlPort ;
        lv2:index 4 ;
        lv2:symbol "time" ;
        lv2:name "Time" ;
        lv2:default 0.5 ;
        lv2:minimum 0.0 ;
        lv2:maximum 1.0 ;
    ] ,
    [
        a lv2:InputPort, lv2:ControlPort ;
        lv2:index 5 ;
        lv2:symbol "size" ;
        lv2:name "Size" ;
        lv2:default 0.3 ;
        lv2:minimum 0.01 ;
        lv2:maximum 1.0 ;
    ] ,
    [
        a lv2:InputPort, lv2:ControlPort ;
        lv2:index 6 ;
        lv2:symbol "shape" ;
        lv2:name "Envelope Shape" ;
        lv2:default 0.5 ;
        lv2:minimum 0.0 ;
        lv2:maximum 1.0 ;
    ] ,
    [
        a lv2:InputPort, lv2:ControlPort ;
        lv2:index 7 ;
        lv2:symbol "pitch" ;
        lv2:name "Pitch Transpose" ;
        lv2:default 0.0 ;
        lv2:minimum -24.0 ;
        lv2:maximum 24.0 ;
        units:unit units:semitone12TET ;
    ] ,
    [
        a lv2:InputPort, lv2:ControlPort ;
        lv2:index 8 ;
        lv2:symbol "density" ;
        lv2:name "Grain Density" ;
        lv2:default 0.5 ;
        lv2:minimum 0.0 ;
        lv2:maximum 1.0 ;
    ] ,
    [
        a lv2:InputPort, lv2:ControlPort ;
        lv2:index 9 ;
        lv2:symbol "texture" ;
        lv2:name "Texture" ;
        lv2:default 0.2 ;
        lv2:minimum 0.0 ;
        lv2:maximum 1.0 ;
    ] ,
    [
        a lv2:InputPort, lv2:ControlPort ;
        lv2:index 10 ;
        lv2:symbol "dry_wet" ;
        lv2:name "Dry / Wet" ;
        lv2:default 0.5 ;
        lv2:minimum 0.0 ;
        lv2:maximum 1.0 ;
    ] ,
    [
        a lv2:InputPort, lv2:ControlPort ;
        lv2:index 11 ;
        lv2:symbol "reverb" ;
        lv2:name "Reverb Amount" ;
        lv2:default 0.2 ;
        lv2:minimum 0.0 ;
        lv2:maximum 1.0 ;
    ] ,
    [
        a lv2:InputPort, lv2:ControlPort ;
        lv2:index 12 ;
        lv2:symbol "attenurandom" ;
        lv2:name "Pitch Randomization" ;
        lv2:default 0.0 ;
        lv2:minimum 0.0 ;
        lv2:maximum 1.0 ;
    ] ,
    [
        a lv2:InputPort, lv2:ControlPort ;
        lv2:index 13 ;
        lv2:symbol "freeze" ;
        lv2:name "Freeze" ;
        lv2:default 0.0 ;
        lv2:minimum 0.0 ;
        lv2:maximum 1.0 ;
        lv2:portProperty lv2:toggled ;
    ] .

endef

define MUTABLE_BEADS_PRESET_1
@prefix lv2:  <http://lv2plug.in/ns/lv2core#> .
@prefix pset: <http://lv2plug.in/ns/ext/presets#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .

<https://github.com/austin-dsp/lv2-plugins/mutable-beads#preset-cloud-reverb-wash>
    a pset:Preset ;
    lv2:appliesTo <https://github.com/austin-dsp/lv2-plugins/mutable-beads> ;
    rdfs:label "Cloud Reverb Wash" ;
    lv2:port
    [ lv2:symbol "time" ; pset:value 0.4 ] ,
    [ lv2:symbol "size" ; pset:value 0.7 ] ,
    [ lv2:symbol "shape" ; pset:value 0.2 ] ,
    [ lv2:symbol "pitch" ; pset:value 0.0 ] ,
    [ lv2:symbol "density" ; pset:value 0.85 ] ,
    [ lv2:symbol "texture" ; pset:value 0.5 ] ,
    [ lv2:symbol "dry_wet" ; pset:value 0.75 ] ,
    [ lv2:symbol "reverb" ; pset:value 0.8 ] ,
    [ lv2:symbol "attenurandom" ; pset:value 0.05 ] ,
    [ lv2:symbol "freeze" ; pset:value 0.0 ] .

endef

define MUTABLE_BEADS_PRESET_2
@prefix lv2:  <http://lv2plug.in/ns/lv2core#> .
@prefix pset: <http://lv2plug.in/ns/ext/presets#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .

<https://github.com/austin-dsp/lv2-plugins/mutable-beads#preset-octave-shimmer>
    a pset:Preset ;
    lv2:appliesTo <https://github.com/austin-dsp/lv2-plugins/mutable-beads> ;
    rdfs:label "Octave Shimmer Pad" ;
    lv2:port
    [ lv2:symbol "time" ; pset:value 0.3 ] ,
    [ lv2:symbol "size" ; pset:value 0.5 ] ,
    [ lv2:symbol "shape" ; pset:value 0.3 ] ,
    [ lv2:symbol "pitch" ; pset:value 12.0 ] ,
    [ lv2:symbol "density" ; pset:value 0.7 ] ,
    [ lv2:symbol "texture" ; pset:value 0.3 ] ,
    [ lv2:symbol "dry_wet" ; pset:value 0.6 ] ,
    [ lv2:symbol "reverb" ; pset:value 0.65 ] ,
    [ lv2:symbol "attenurandom" ; pset:value 0.0 ] ,
    [ lv2:symbol "freeze" ; pset:value 0.0 ] .

endef

define MUTABLE_BEADS_PRESET_3
@prefix lv2:  <http://lv2plug.in/ns/lv2core#> .
@prefix pset: <http://lv2plug.in/ns/ext/presets#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .

<https://github.com/austin-dsp/lv2-plugins/mutable-beads#preset-granular-rhythmic-delay>
    a pset:Preset ;
    lv2:appliesTo <https://github.com/austin-dsp/lv2-plugins/mutable-beads> ;
    rdfs:label "Granular Rhythmic Delay" ;
    lv2:port
    [ lv2:symbol "time" ; pset:value 0.6 ] ,
    [ lv2:symbol "size" ; pset:value 0.15 ] ,
    [ lv2:symbol "shape" ; pset:value 0.9 ] ,
    [ lv2:symbol "pitch" ; pset:value 0.0 ] ,
    [ lv2:symbol "density" ; pset:value 0.3 ] ,
    [ lv2:symbol "texture" ; pset:value 0.1 ] ,
    [ lv2:symbol "dry_wet" ; pset:value 0.5 ] ,
    [ lv2:symbol "reverb" ; pset:value 0.15 ] ,
    [ lv2:symbol "attenurandom" ; pset:value 0.0 ] ,
    [ lv2:symbol "freeze" ; pset:value 0.0 ] .

endef

define MUTABLE_BEADS_PRESET_4
@prefix lv2:  <http://lv2plug.in/ns/lv2core#> .
@prefix pset: <http://lv2plug.in/ns/ext/presets#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .

<https://github.com/austin-dsp/lv2-plugins/mutable-beads#preset-random-pitch-texture>
    a pset:Preset ;
    lv2:appliesTo <https://github.com/austin-dsp/lv2-plugins/mutable-beads> ;
    rdfs:label "Chaos Pitch Swarm" ;
    lv2:port
    [ lv2:symbol "time" ; pset:value 0.5 ] ,
    [ lv2:symbol "size" ; pset:value 0.25 ] ,
    [ lv2:symbol "shape" ; pset:value 0.5 ] ,
    [ lv2:symbol "pitch" ; pset:value -5.0 ] ,
    [ lv2:symbol "density" ; pset:value 0.9 ] ,
    [ lv2:symbol "texture" ; pset:value 0.7 ] ,
    [ lv2:symbol "dry_wet" ; pset:value 0.8 ] ,
    [ lv2:symbol "reverb" ; pset:value 0.4 ] ,
    [ lv2:symbol "attenurandom" ; pset:value 0.85 ] ,
    [ lv2:symbol "freeze" ; pset:value 0.0 ] .

endef

define MUTABLE_BEADS_PRESET_5
@prefix lv2:  <http://lv2plug.in/ns/lv2core#> .
@prefix pset: <http://lv2plug.in/ns/ext/presets#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .

<https://github.com/austin-dsp/lv2-plugins/mutable-beads#preset-micro-loop-freeze>
    a pset:Preset ;
    lv2:appliesTo <https://github.com/austin-dsp/lv2-plugins/mutable-beads> ;
    rdfs:label "Micro-Loop Freeze" ;
    lv2:port
    [ lv2:symbol "time" ; pset:value 0.2 ] ,
    [ lv2:symbol "size" ; pset:value 0.02 ] ,
    [ lv2:symbol "shape" ; pset:value 0.1 ] ,
    [ lv2:symbol "pitch" ; pset:value 0.0 ] ,
    [ lv2:symbol "density" ; pset:value 0.95 ] ,
    [ lv2:symbol "texture" ; pset:value 0.0 ] ,
    [ lv2:symbol "dry_wet" ; pset:value 1.0 ] ,
    [ lv2:symbol "reverb" ; pset:value 0.3 ] ,
    [ lv2:symbol "attenurandom" ; pset:value 0.0 ] ,
    [ lv2:symbol "freeze" ; pset:value 1.0 ] .

endef

export MUTABLE_BEADS_PLUGIN_INFO_H
export MUTABLE_BEADS_PLUGIN_CPP
export MUTABLE_BEADS_PLUGIN_MAKEFILE
export MUTABLE_BEADS_MANIFEST_TTL
export MUTABLE_BEADS_PLUGIN_TTL
export MUTABLE_BEADS_PRESET_1
export MUTABLE_BEADS_PRESET_2
export MUTABLE_BEADS_PRESET_3
export MUTABLE_BEADS_PRESET_4
export MUTABLE_BEADS_PRESET_5

define MUTABLE_BEADS_CONFIGURE_CMDS
	mkdir -p $(@D)/examples/mutable-beads
	printf '%s' "$$MUTABLE_BEADS_PLUGIN_INFO_H" > $(@D)/examples/mutable-beads/DistrhoPluginInfo.h
	printf '%s' "$$MUTABLE_BEADS_PLUGIN_CPP" > $(@D)/examples/mutable-beads/Plugin.cpp
	printf '%s' "$$MUTABLE_BEADS_PLUGIN_MAKEFILE" > $(@D)/examples/mutable-beads/Makefile
endef

define MUTABLE_BEADS_BUILD_CMDS
	$(TARGET_MAKE_ENV) $(TARGET_CONFIGURE_OPTS) $(MAKE) NOOPT=true -C $(@D)/examples/mutable-beads lv2_dsp
endef

define MUTABLE_BEADS_INSTALL_TARGET_CMDS
	mkdir -p $(TARGET_DIR)/usr/lib/lv2/mutable-beads.lv2
	cp $(@D)/bin/mutable-beads.lv2/mutable-beads_dsp.so $(TARGET_DIR)/usr/lib/lv2/mutable-beads.lv2/
	printf '%s' "$$MUTABLE_BEADS_MANIFEST_TTL" > $(TARGET_DIR)/usr/lib/lv2/mutable-beads.lv2/manifest.ttl
	printf '%s' "$$MUTABLE_BEADS_PLUGIN_TTL" > $(TARGET_DIR)/usr/lib/lv2/mutable-beads.lv2/mutable-beads.ttl
	printf '%s' "$$MUTABLE_BEADS_PRESET_1" > $(TARGET_DIR)/usr/lib/lv2/mutable-beads.lv2/cloud-reverb-wash.ttl
	printf '%s' "$$MUTABLE_BEADS_PRESET_2" > $(TARGET_DIR)/usr/lib/lv2/mutable-beads.lv2/octave-shimmer.ttl
	printf '%s' "$$MUTABLE_BEADS_PRESET_3" > $(TARGET_DIR)/usr/lib/lv2/mutable-beads.lv2/granular-rhythmic-delay.ttl
	printf '%s' "$$MUTABLE_BEADS_PRESET_4" > $(TARGET_DIR)/usr/lib/lv2/mutable-beads.lv2/random-pitch-texture.ttl
	printf '%s' "$$MUTABLE_BEADS_PRESET_5" > $(TARGET_DIR)/usr/lib/lv2/mutable-beads.lv2/micro-loop-freeze.ttl
endef

$(eval $(generic-package))