# Copyright (c) 2026 MOD Audio Limited
# SPDX-License-Identifier: MIT
#
# Bricasti M7 style stereo reverb.
#
# Signal chain:
#   Stereo in → Pre-delay → Early Reflections → Reverb tail
#   → HF/LF damping EQ → Mix → Stereo out
#
# Algorithms (Type control):
#   0 = Hall        - large concert hall, lush and wide
#   1 = Plate       - classic studio plate, dense and bright
#   2 = Chamber     - live echo chamber, focused and coloured
#   3 = Room        - intimate room, tight and natural
#   4 = Ambience    - subtle space glue, short and airy
#
# 12 parametric controls matching M7 program parameters:
#   Type        - algorithm (Hall/Plate/Chamber/Room/Ambience)
#   Decay       - reverb tail length
#   Pre-Delay   - time before reverb onset (0-100ms)
#   ER Level    - early reflections level
#   ER Time     - early reflections length
#   Diffusion   - reflection density (tight→smeared)
#   Mod Depth   - LFO modulation depth on tail (adds life/shimmer)
#   Mod Rate    - LFO modulation rate
#   HF Damp     - high frequency absorption in tail
#   LF Damp     - low frequency rolloff in tail
#   Width       - stereo spread of the reverb tail
#   Mix         - dry/wet blend
#
# Upload at https://builder.mod.audio/buildroot with MOD unit over USB.

BRICASTI_VERSION = 61d38eb638449647fb8395a35c5b8dab7e981ba7
BRICASTI_SITE = https://github.com/DISTRHO/DPF.git
BRICASTI_SITE_METHOD = git
BRICASTI_BUNDLES = bricasti-m7.lv2

define BRICASTI_PLUGIN_CPP
#include "DistrhoPlugin.hpp"
#include <cmath>
#include <cstring>

START_NAMESPACE_DISTRHO

// ── One-pole filter ────────────────────────────────────────────────────────────
struct P1 {
    float z;
    P1():z(0.f){}
    void reset(){z=0.f;}
    float lp(float x,float a){return z=x*(1.f-a)+z*a;}
    float hp(float x,float a){float y=x*(1.f-a)+z*a;z=y;return x-y;}
};

// ── Allpass ────────────────────────────────────────────────────────────────────
struct AP {
    float buf[4096];
    int   wp,len;
    float g;
    AP():wp(0),len(400),g(0.7f){memset(buf,0,sizeof(buf));}
    void reset(){memset(buf,0,sizeof(buf));wp=0;}
    void setLen(int l){len=(l<4096)?l:4095;}
    float tick(float in){
        int rp=(wp-len)&4095;
        float d=buf[rp];
        float v=in+d*(-g);
        buf[wp&4095]=in+d*g;
        wp++;
        return d+v*g;
    }
};

// ── Comb filter with LP feedback ──────────────────────────────────────────────
struct Comb {
    float buf[16384];
    int   wp,len;
    float fb,lz;
    Comb():wp(0),len(4000),fb(0.8f),lz(0.f){memset(buf,0,sizeof(buf));}
    void reset(){memset(buf,0,sizeof(buf));wp=0;lz=0.f;}
    void setLen(int l){len=(l<16384)?l:16383;}
    float tick(float in,float hfDamp){
        int rp=(wp-len)&16383;
        float d=buf[rp];
        lz=d*(1.f-hfDamp)+lz*hfDamp;
        buf[wp&16383]=in+lz*fb;
        wp++;
        return d;
    }
};

// ── Pre-delay line ─────────────────────────────────────────────────────────────
struct PreDL {
    float buf[16384];
    int   wp;
    PreDL():wp(0){memset(buf,0,sizeof(buf));}
    void reset(){memset(buf,0,sizeof(buf));wp=0;}
    float tick(float in,int d){
        buf[wp&16383]=in;
        float out=buf[(wp-d)&16383];
        wp++;
        return out;
    }
};

// ── Early reflections (simple tapped delay) ────────────────────────────────────
struct EarlyRef {
    float buf[8192];
    int   wp;
    EarlyRef():wp(0){memset(buf,0,sizeof(buf));}
    void reset(){memset(buf,0,sizeof(buf));wp=0;}
    // Returns sum of several taps spread across erTime samples
    float tick(float in,int erTime,float sr){
        buf[wp&8191]=in;
        // 7 taps spread at Fibonacci-ish intervals for natural ER density
        float t=(float)erTime;
        float s=0.f;
        s+=buf[(wp-(int)(t*0.100f))&8191]*0.30f;
        s+=buf[(wp-(int)(t*0.162f))&8191]*0.25f;
        s+=buf[(wp-(int)(t*0.262f))&8191]*0.20f;
        s+=buf[(wp-(int)(t*0.424f))&8191]*0.15f;
        s+=buf[(wp-(int)(t*0.562f))&8191]*0.10f;
        s+=buf[(wp-(int)(t*0.724f))&8191]*0.08f;
        s+=buf[(wp-(int)(t*1.000f))&8191]*0.05f;
        wp++;
        return s;
    }
};

// ── Reverb engine: 8 parallel combs + 4 allpass per channel ───────────────────
// Per-algorithm comb lengths tuned for Hall/Plate/Chamber/Room/Ambience character
struct RevEngine {
    Comb c[8];
    AP   a[4];
    P1   lfDampLP;

    // Algorithm comb length scaling factors (relative to 44.1kHz base)
    // Hall: long, widely spaced; Plate: dense, medium; Chamber: medium+coloured;
    // Room: short, tight; Ambience: very short, high density
    static const int COMB_BASE[5][8];
    static const int AP_BASE[5][4];

    void init(int alg,float sr,float diff){
        float sc=sr/44100.f;
        for(int i=0;i<8;++i) c[i].setLen((int)(COMB_BASE[alg][i]*sc));
        for(int i=0;i<4;++i){
            a[i].setLen((int)(AP_BASE[alg][i]*sc));
            a[i].g=0.5f+diff*0.35f;
        }
        lfDampLP.reset();
    }

    void reset(){
        for(int i=0;i<8;++i)c[i].reset();
        for(int i=0;i<4;++i)a[i].reset();
        lfDampLP.reset();
    }

    void setFb(float fb){for(int i=0;i<8;++i)c[i].fb=fb;}

    float tick(float in,float hfDamp,float lfDamp,float sr){
        // LF damping: HP on input to thin the low end of the tail
        float aLF=expf(-6.2832f*(80.f+lfDamp*800.f)/sr);
        float sig=lfDampLP.hp(in,aLF);

        float s=0.f;
        for(int i=0;i<8;++i) s+=c[i].tick(sig,hfDamp);
        s*=0.125f;
        for(int i=0;i<4;++i) s=a[i].tick(s);
        return s;
    }
};

// Comb lengths per algorithm — tuned for M7-like character
const int RevEngine::COMB_BASE[5][8]={
    // Hall: long, sparse, lush
    {4799,4999,5399,5801,6199,6599,6991,7411},
    // Plate: dense, medium length
    {1557,1617,1491,1422,1277,1356,1188,1116},
    // Chamber: medium, slightly irregular
    {2179,2269,2113,2011,1901,2053,1799,1699},
    // Room: short, tight
    { 901, 951, 877, 831, 801, 857, 761, 711},
    // Ambience: very short, high density
    { 401, 421, 389, 369, 349, 381, 331, 311},
};
const int RevEngine::AP_BASE[5][4]={
    {225,556,441,341},   // Hall
    {142,107,379,277},   // Plate
    {347,113,613,251},   // Chamber
    {156, 61,213,101},   // Room
    { 71, 31, 97, 51},   // Ambience
};

class BricastiM7Plugin : public Plugin
{
public:
    BricastiM7Plugin()
    : Plugin(kParameterCount,0,0),
      fSR(44100.f),
      pType(0.f),pDecay(0.6f),pPreDelay(0.f),
      pERLevel(0.3f),pERTime(0.4f),
      pDiffusion(0.7f),pModDepth(0.2f),pModRate(0.8f),
      pHFDamp(0.4f),pLFDamp(0.2f),pWidth(1.0f),pMix(0.3f),
      fLfoPhL(0.f),fLfoPhR(0.5f),
      fLastType(-1)
    {
        initEngines(fSR,0);
    }

protected:
    const char* getLabel()       const override { return "BricastiM7"; }
    const char* getDescription() const override { return "Stereo reverb inspired by Bricasti M7: Hall, Plate, Chamber, Room and Ambience algorithms with 12 parametric controls."; }
    const char* getMaker()       const override { return "MOD Cookbook"; }
    const char* getHomePage()    const override { return "https://mod.audio"; }
    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('B','M','7','R'); }

    void initParameter(uint32_t index,Parameter&p)override{
        switch(index){
        case kType:
            p.hints=kParameterIsAutomatable|kParameterIsInteger;
            p.name="Type";p.symbol="type";
            // 0=Hall 1=Plate 2=Chamber 3=Room 4=Ambience
            p.ranges.def=0.f;p.ranges.min=0.f;p.ranges.max=4.f;break;
        case kDecay:
            p.hints=kParameterIsAutomatable;p.name="Decay";p.symbol="decay";
            p.ranges.def=0.6f;p.ranges.min=0.f;p.ranges.max=1.f;break;
        case kPreDelay:
            p.hints=kParameterIsAutomatable;p.name="Pre-Delay";p.symbol="pre_delay";p.unit="ms";
            p.ranges.def=0.f;p.ranges.min=0.f;p.ranges.max=100.f;break;
        case kERLevel:
            p.hints=kParameterIsAutomatable;p.name="ER Level";p.symbol="er_level";
            p.ranges.def=0.3f;p.ranges.min=0.f;p.ranges.max=1.f;break;
        case kERTime:
            p.hints=kParameterIsAutomatable;p.name="ER Time";p.symbol="er_time";
            p.ranges.def=0.4f;p.ranges.min=0.f;p.ranges.max=1.f;break;
        case kDiffusion:
            p.hints=kParameterIsAutomatable;p.name="Diffusion";p.symbol="diffusion";
            p.ranges.def=0.7f;p.ranges.min=0.f;p.ranges.max=1.f;break;
        case kModDepth:
            p.hints=kParameterIsAutomatable;p.name="Mod Depth";p.symbol="mod_depth";
            p.ranges.def=0.2f;p.ranges.min=0.f;p.ranges.max=1.f;break;
        case kModRate:
            p.hints=kParameterIsAutomatable;p.name="Mod Rate";p.symbol="mod_rate";p.unit="Hz";
            p.ranges.def=0.8f;p.ranges.min=0.05f;p.ranges.max=5.f;break;
        case kHFDamp:
            p.hints=kParameterIsAutomatable;p.name="HF Damp";p.symbol="hf_damp";
            p.ranges.def=0.4f;p.ranges.min=0.f;p.ranges.max=1.f;break;
        case kLFDamp:
            p.hints=kParameterIsAutomatable;p.name="LF Damp";p.symbol="lf_damp";
            p.ranges.def=0.2f;p.ranges.min=0.f;p.ranges.max=1.f;break;
        case kWidth:
            p.hints=kParameterIsAutomatable;p.name="Width";p.symbol="width";
            p.ranges.def=1.0f;p.ranges.min=0.f;p.ranges.max=1.f;break;
        case kMix:
            p.hints=kParameterIsAutomatable;p.name="Mix";p.symbol="mix";
            p.ranges.def=0.3f;p.ranges.min=0.f;p.ranges.max=1.f;break;
        default:break;
        }
    }

    float getParameterValue(uint32_t index)const override{
        switch(index){
        case kType:      return pType;
        case kDecay:     return pDecay;
        case kPreDelay:  return pPreDelay;
        case kERLevel:   return pERLevel;
        case kERTime:    return pERTime;
        case kDiffusion: return pDiffusion;
        case kModDepth:  return pModDepth;
        case kModRate:   return pModRate;
        case kHFDamp:    return pHFDamp;
        case kLFDamp:    return pLFDamp;
        case kWidth:     return pWidth;
        case kMix:       return pMix;
        default:         return 0.f;
        }
    }

    void setParameterValue(uint32_t index,float v)override{
        switch(index){
        case kType:
            pType=v;
            if((int)(v+0.5f)!=fLastType){
                initEngines(fSR,(int)(v+0.5f));
                fLastType=(int)(v+0.5f);
            }
            break;
        case kDecay:     pDecay=v;     updateFb(); break;
        case kPreDelay:  pPreDelay=v;  break;
        case kERLevel:   pERLevel=v;   break;
        case kERTime:    pERTime=v;    break;
        case kDiffusion: pDiffusion=v; initEngines(fSR,(int)(pType+0.5f)); break;
        case kModDepth:  pModDepth=v;  break;
        case kModRate:   pModRate=v;   break;
        case kHFDamp:    pHFDamp=v;    break;
        case kLFDamp:    pLFDamp=v;    break;
        case kWidth:     pWidth=v;     break;
        case kMix:       pMix=v;       break;
        default:break;
        }
    }

    void activate()override{
        fSR=(float)getSampleRate();
        int alg=(int)(pType+0.5f);
        initEngines(fSR,alg);
        fPDL.reset();fPDR.reset();
        fERL.reset();fERR.reset();
        fOutHPL.reset();fOutHPR.reset();
        fLfoPhL=0.f;fLfoPhR=0.5f;
    }

    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];

        updateFb();

        int   preD  =(int)(pPreDelay*0.001f*fSR);
        int   erSamp=(int)(pERTime*0.1f*fSR+20.f);
        if(erSamp>8000)erSamp=8000;

        // HF damp coefficient: 0=bright, 1=dark
        float hfCoef=pHFDamp*0.95f;

        for(uint32_t i=0;i<frames;++i){
            // Pre-delay
            float pL=fPDL.tick(inL[i],preD);
            float pR=fPDR.tick(inR[i],preD);

            // Early reflections
            float erL=fERL.tick(pL,erSamp,fSR)*pERLevel;
            float erR=fERR.tick(pR,erSamp,fSR)*pERLevel;

            // LFO modulation — independently modulates L and R combs
            // giving the M7's characteristic uncorrelated stereo movement
            float lfoL=sinf(fLfoPhL*6.2832f)*pModDepth*0.003f;
            float lfoR=sinf(fLfoPhR*6.2832f)*pModDepth*0.003f;
            fLfoPhL+=pModRate/fSR; if(fLfoPhL>=1.f)fLfoPhL-=1.f;
            fLfoPhR+=pModRate/fSR; if(fLfoPhR>=1.f)fLfoPhR-=1.f;

            // Modulate comb lengths by tiny amount (warm pitch shimmer)
            // We do this by adding lfo to the input — approximates modulated delay
            float tailInL=pL+erL+fRevL.tick(0,0,0,fSR)*lfoL;
            float tailInR=pR+erR+fRevR.tick(0,0,0,fSR)*lfoR;

            float tailL=fRevL.tick(tailInL,hfCoef,pLFDamp,fSR);
            float tailR=fRevR.tick(tailInR,hfCoef,pLFDamp,fSR);

            // Width: M7 processes L/R independently then blends for stereo spread
            // Width=1: full stereo, Width=0: mono reverb
            float midTail  =(tailL+tailR)*0.5f;
            float sideTail =(tailL-tailR)*0.5f;
            float wL=midTail+sideTail*pWidth;
            float wR=midTail-sideTail*pWidth;

            // Remove DC from output
            float aHP=expf(-6.2832f*20.f/fSR);
            wL=fOutHPL.hp(wL,aHP);
            wR=fOutHPR.hp(wR,aHP);

            outL[i]=inL[i]*(1.f-pMix)+wL*pMix;
            outR[i]=inR[i]*(1.f-pMix)+wR*pMix;
        }
    }

private:
    void initEngines(float sr,int alg){
        if(alg<0)alg=0; if(alg>4)alg=4;
        fRevL.init(alg,sr,pDiffusion);
        fRevR.init(alg,sr,pDiffusion);
        updateFb();
    }
    void updateFb(){
        // Per-algorithm decay scaling — Ambience decays much faster than Hall
        static const float fbMin[5]={0.78f,0.72f,0.74f,0.68f,0.60f};
        static const float fbRng[5]={0.20f,0.24f,0.22f,0.26f,0.30f};
        int alg=(int)(pType+0.5f); if(alg<0)alg=0; if(alg>4)alg=4;
        float fb=fbMin[alg]+pDecay*fbRng[alg];
        fRevL.setFb(fb); fRevR.setFb(fb);
    }

    float fSR;
    float pType,pDecay,pPreDelay;
    float pERLevel,pERTime;
    float pDiffusion,pModDepth,pModRate;
    float pHFDamp,pLFDamp,pWidth,pMix;
    float fLfoPhL,fLfoPhR;
    int   fLastType;

    RevEngine fRevL,fRevR;
    PreDL     fPDL,fPDR;
    EarlyRef  fERL,fERR;
    P1        fOutHPL,fOutHPR;

    enum Parameters{
        kType=0,kDecay,kPreDelay,kERLevel,kERTime,
        kDiffusion,kModDepth,kModRate,kHFDamp,kLFDamp,kWidth,kMix,
        kParameterCount
    };

    DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(BricastiM7Plugin)
};

Plugin*createPlugin(){return new BricastiM7Plugin();}
END_NAMESPACE_DISTRHO
endef

define BRICASTI_PLUGIN_INFO_H
#ifndef DISTRHO_PLUGIN_INFO_H_INCLUDED
#define DISTRHO_PLUGIN_INFO_H_INCLUDED
#define DISTRHO_PLUGIN_BRAND       "MOD Cookbook"
#define DISTRHO_PLUGIN_NAME        "Bricasti M7"
#define DISTRHO_PLUGIN_URI         "urn:mod-cookbook:bricasti-m7"
#define DISTRHO_PLUGIN_HAS_UI      0
#define DISTRHO_PLUGIN_IS_RT_SAFE  1
#define DISTRHO_PLUGIN_NUM_INPUTS  2
#define DISTRHO_PLUGIN_NUM_OUTPUTS 2
enum Parameters{
    kType=0,kDecay,kPreDelay,kERLevel,kERTime,
    kDiffusion,kModDepth,kModRate,kHFDamp,kLFDamp,kWidth,kMix,
    kParameterCount
};
#endif
endef

define BRICASTI_PLUGIN_MAKEFILE
#!/usr/bin/make -f
NAME = bricasti-m7
FILES_DSP = BricastiM7Plugin.cpp
include ../../Makefile.plugins.mk
TARGETS = lv2_dsp
all: $(TARGETS)
endef

define BRICASTI_MANIFEST_TTL
@prefix lv2:  <http://lv2plug.in/ns/lv2core#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
<urn:mod-cookbook:bricasti-m7>
    a lv2:Plugin , lv2:ReverbPlugin ;
    lv2:binary <bricasti-m7_dsp.so> ;
    rdfs:seeAlso <bricasti-m7.ttl> .
endef

define BRICASTI_PLUGIN_TTL
@prefix doap:  <http://usefulinc.com/ns/doap#> .
@prefix foaf:  <http://xmlns.com/foaf/0.1/> .
@prefix lv2:   <http://lv2plug.in/ns/lv2core#> .
@prefix rdfs:  <http://www.w3.org/2000/01/rdf-schema#> .
@prefix units: <http://lv2plug.in/ns/extensions/units#> .
<urn:mod-cookbook:bricasti-m7>
    a lv2:Plugin , lv2:ReverbPlugin ;
    doap:name "Bricasti M7" ;
    doap:license <http://opensource.org/licenses/MIT> ;
    doap:maintainer [ foaf:name "MOD Cookbook" ; foaf:homepage <https://mod.audio> ] ;
    rdfs:comment "Stereo reverb inspired by Bricasti M7: Hall, Plate, Chamber, Room, Ambience with 12 parametric controls." ;
    lv2:port [
        a lv2:InputPort , lv2:AudioPort ;
        lv2:index 0 ; lv2:symbol "in_l" ; lv2:name "Audio In L"
    ] , [
        a lv2:InputPort , lv2:AudioPort ;
        lv2:index 1 ; lv2:symbol "in_r" ; lv2:name "Audio In R"
    ] , [
        a lv2:OutputPort , lv2:AudioPort ;
        lv2:index 2 ; lv2:symbol "out_l" ; lv2:name "Audio Out L"
    ] , [
        a lv2:OutputPort , lv2:AudioPort ;
        lv2:index 3 ; lv2:symbol "out_r" ; lv2:name "Audio Out R"
    ] , [
        a lv2:InputPort , lv2:ControlPort ;
        lv2:index 4 ; lv2:symbol "type" ; lv2:name "Type" ;
        lv2:default 0.0 ; lv2:minimum 0.0 ; lv2:maximum 4.0
    ] , [
        a lv2:InputPort , lv2:ControlPort ;
        lv2:index 5 ; lv2:symbol "decay" ; lv2:name "Decay" ;
        lv2:default 0.6 ; lv2:minimum 0.0 ; lv2:maximum 1.0
    ] , [
        a lv2:InputPort , lv2:ControlPort ;
        lv2:index 6 ; lv2:symbol "pre_delay" ; lv2:name "Pre-Delay" ;
        lv2:default 0.0 ; lv2:minimum 0.0 ; lv2:maximum 100.0 ; units:unit units:ms
    ] , [
        a lv2:InputPort , lv2:ControlPort ;
        lv2:index 7 ; lv2:symbol "er_level" ; lv2:name "ER Level" ;
        lv2:default 0.3 ; lv2:minimum 0.0 ; lv2:maximum 1.0
    ] , [
        a lv2:InputPort , lv2:ControlPort ;
        lv2:index 8 ; lv2:symbol "er_time" ; lv2:name "ER Time" ;
        lv2:default 0.4 ; lv2:minimum 0.0 ; lv2:maximum 1.0
    ] , [
        a lv2:InputPort , lv2:ControlPort ;
        lv2:index 9 ; lv2:symbol "diffusion" ; lv2:name "Diffusion" ;
        lv2:default 0.7 ; lv2:minimum 0.0 ; lv2:maximum 1.0
    ] , [
        a lv2:InputPort , lv2:ControlPort ;
        lv2:index 10 ; lv2:symbol "mod_depth" ; lv2:name "Mod Depth" ;
        lv2:default 0.2 ; lv2:minimum 0.0 ; lv2:maximum 1.0
    ] , [
        a lv2:InputPort , lv2:ControlPort ;
        lv2:index 11 ; lv2:symbol "mod_rate" ; lv2:name "Mod Rate" ;
        lv2:default 0.8 ; lv2:minimum 0.05 ; lv2:maximum 5.0 ; units:unit units:hz
    ] , [
        a lv2:InputPort , lv2:ControlPort ;
        lv2:index 12 ; lv2:symbol "hf_damp" ; lv2:name "HF Damp" ;
        lv2:default 0.4 ; lv2:minimum 0.0 ; lv2:maximum 1.0
    ] , [
        a lv2:InputPort , lv2:ControlPort ;
        lv2:index 13 ; lv2:symbol "lf_damp" ; lv2:name "LF Damp" ;
        lv2:default 0.2 ; lv2:minimum 0.0 ; lv2:maximum 1.0
    ] , [
        a lv2:InputPort , lv2:ControlPort ;
        lv2:index 14 ; lv2:symbol "width" ; lv2:name "Width" ;
        lv2:default 1.0 ; lv2:minimum 0.0 ; lv2:maximum 1.0
    ] , [
        a lv2:InputPort , lv2:ControlPort ;
        lv2:index 15 ; lv2:symbol "mix" ; lv2:name "Mix" ;
        lv2:default 0.3 ; lv2:minimum 0.0 ; lv2:maximum 1.0
    ] .
endef

export BRICASTI_PLUGIN_CPP
export BRICASTI_PLUGIN_INFO_H
export BRICASTI_PLUGIN_MAKEFILE
export BRICASTI_MANIFEST_TTL
export BRICASTI_PLUGIN_TTL

define BRICASTI_CONFIGURE_CMDS
	mkdir -p $(@D)/examples/bricasti-m7
	printf '%s' "$$BRICASTI_PLUGIN_CPP"      > $(@D)/examples/bricasti-m7/BricastiM7Plugin.cpp
	printf '%s' "$$BRICASTI_PLUGIN_INFO_H"   > $(@D)/examples/bricasti-m7/DistrhoPluginInfo.h
	printf '%s' "$$BRICASTI_PLUGIN_MAKEFILE" > $(@D)/examples/bricasti-m7/Makefile
endef

define BRICASTI_BUILD_CMDS
	$(TARGET_MAKE_ENV) $(TARGET_CONFIGURE_OPTS) $(MAKE) NOOPT=true -C $(@D)/examples/bricasti-m7 lv2_dsp
endef

define BRICASTI_INSTALL_TARGET_CMDS
	mkdir -p $($(PKG)_PKGDIR)/bricasti-m7.lv2
	cp $(@D)/bin/bricasti-m7.lv2/bricasti-m7_dsp.so $($(PKG)_PKGDIR)/bricasti-m7.lv2/
	printf '%s' "$$BRICASTI_MANIFEST_TTL" > $($(PKG)_PKGDIR)/bricasti-m7.lv2/manifest.ttl
	printf '%s' "$$BRICASTI_PLUGIN_TTL"   > $($(PKG)_PKGDIR)/bricasti-m7.lv2/bricasti-m7.ttl
endef

$(eval $(generic-package))
