# Copyright (c) 2026 MOD Audio Limited
# SPDX-License-Identifier: MIT

TRANCE_GATE_VERSION = 61d38eb638449647fb8395a35c5b8dab7e981ba7
TRANCE_GATE_SITE = https://github.com/DISTRHO/DPF.git
TRANCE_GATE_SITE_METHOD = git
TRANCE_GATE_BUNDLES = trance-gate.lv2

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

START_NAMESPACE_DISTRHO

class TranceGatePlugin : public Plugin
{
public:
    TranceGatePlugin()
        : Plugin(kParameterCount, 0, 0),
          fGateLength(0.8f),
          fAttack(0.005f),
          fRelease(0.02f),
          fSwing(0.0f),
          fSampleRate(48000.0f),
          fCurrentStep(0),
          fStepPos(0.0f),
          fStepSamples(12000.0f),
          fGainL(0.0f),
          fGainR(0.0f),
          fMidiClockCount(0),
          fMidiClockPhase(0.0f),
          fClockReceived(false)
    {
        // default pattern: alternating on/off
        for (int s = 0; s < 8; ++s)
        {
            fStepOn[s]     = (s % 2 == 0) ? 1.0f : 0.0f;
            fStepVol[s]    = 1.0f;
            fStepPan[s]    = 0.0f;
        }
    }

protected:
    const char* getLabel()       const override { return "TranceGate"; }
    const char* getDescription() const override { return "8-step stereo trance gate with MIDI clock sync, per-step volume and pan."; }
    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('T', 'G', '8', 's'); }

    void initParameter(uint32_t index, Parameter& parameter) override
    {
        // Global parameters first
        if (index == kGateLength) {
            parameter.hints      = kParameterIsAutomatable;
            parameter.name       = "Gate Length";
            parameter.symbol     = "gate_length";
            parameter.unit       = "%";
            parameter.ranges.def = 80.0f;
            parameter.ranges.min = 5.0f;
            parameter.ranges.max = 100.0f;
            return;
        }
        if (index == kAttack) {
            parameter.hints      = kParameterIsAutomatable;
            parameter.name       = "Attack";
            parameter.symbol     = "attack";
            parameter.unit       = "ms";
            parameter.ranges.def = 5.0f;
            parameter.ranges.min = 0.1f;
            parameter.ranges.max = 100.0f;
            return;
        }
        if (index == kRelease) {
            parameter.hints      = kParameterIsAutomatable;
            parameter.name       = "Release";
            parameter.symbol     = "release";
            parameter.unit       = "ms";
            parameter.ranges.def = 20.0f;
            parameter.ranges.min = 0.1f;
            parameter.ranges.max = 200.0f;
            return;
        }
        if (index == kSwing) {
            parameter.hints      = kParameterIsAutomatable;
            parameter.name       = "Swing";
            parameter.symbol     = "swing";
            parameter.unit       = "%";
            parameter.ranges.def = 0.0f;
            parameter.ranges.min = 0.0f;
            parameter.ranges.max = 75.0f;
            return;
        }

        // Per-step parameters
        int step    = (index - kStepsStart) / 3;
        int param   = (index - kStepsStart) % 3;
        if (step < 0 || step > 7) return;

        char name[32];
        char sym[32];

        if (param == 0) {
            // On/Off — integer toggle 0 or 1
            snprintf(name, sizeof(name), "Step %d On", step + 1);
            snprintf(sym,  sizeof(sym),  "step%d_on",  step + 1);
            parameter.hints      = kParameterIsAutomatable | kParameterIsInteger;
            parameter.name       = name;
            parameter.symbol     = sym;
            parameter.unit       = "";
            parameter.ranges.def = (step % 2 == 0) ? 1.0f : 0.0f;
            parameter.ranges.min = 0.0f;
            parameter.ranges.max = 1.0f;
        } else if (param == 1) {
            snprintf(name, sizeof(name), "Step %d Volume", step + 1);
            snprintf(sym,  sizeof(sym),  "step%d_vol",    step + 1);
            parameter.hints      = kParameterIsAutomatable;
            parameter.name       = name;
            parameter.symbol     = sym;
            parameter.unit       = "%";
            parameter.ranges.def = 100.0f;
            parameter.ranges.min = 0.0f;
            parameter.ranges.max = 100.0f;
        } else {
            snprintf(name, sizeof(name), "Step %d Pan", step + 1);
            snprintf(sym,  sizeof(sym),  "step%d_pan",    step + 1);
            parameter.hints      = kParameterIsAutomatable;
            parameter.name       = name;
            parameter.symbol     = sym;
            parameter.unit       = "";
            parameter.ranges.def = 0.0f;
            parameter.ranges.min = -1.0f;
            parameter.ranges.max = 1.0f;
        }
    }

    float getParameterValue(uint32_t index) const override
    {
        switch (index)
        {
        case kGateLength: return fGateLength * 100.0f;
        case kAttack:     return fAttack  * 1000.0f;
        case kRelease:    return fRelease * 1000.0f;
        case kSwing:      return fSwing   * 100.0f;
        default: break;
        }
        if (index >= kStepsStart && index < kParameterCount)
        {
            int step  = (index - kStepsStart) / 3;
            int param = (index - kStepsStart) % 3;
            if (step < 0 || step > 7) return 0.0f;
            if (param == 0) return fStepOn[step];
            if (param == 1) return fStepVol[step] * 100.0f;
            return fStepPan[step];
        }
        return 0.0f;
    }

    void setParameterValue(uint32_t index, float value) override
    {
        switch (index)
        {
        case kGateLength: fGateLength = value / 100.0f; return;
        case kAttack:     fAttack     = value / 1000.0f; return;
        case kRelease:    fRelease    = value / 1000.0f; return;
        case kSwing:      fSwing      = value / 100.0f; return;
        default: break;
        }
        if (index >= kStepsStart && index < kParameterCount)
        {
            int step  = (index - kStepsStart) / 3;
            int param = (index - kStepsStart) % 3;
            if (step < 0 || step > 7) return;
            if (param == 0) fStepOn[step]  = (value >= 0.5f) ? 1.0f : 0.0f;
            else if (param == 1) fStepVol[step] = value / 100.0f;
            else fStepPan[step] = value;
        }
    }

    void activate() override
    {
        fSampleRate     = (float)getSampleRate();
        fCurrentStep    = 0;
        fStepPos        = 0.0f;
        fStepSamples    = fSampleRate * 0.25f; // fallback: 120bpm 16th
        fGainL          = 0.0f;
        fGainR          = 0.0f;
        fMidiClockCount = 0;
        fMidiClockPhase = 0.0f;
        fClockReceived  = false;
    }

    // MIDI clock: 24 ppqn. One step = one 16th note = 6 clock pulses.
    void handleMidi(const uint8_t* data, uint32_t /*size*/) override
    {
        uint8_t status = data[0];
        if (status == 0xF8) // MIDI clock tick
        {
            fMidiClockCount++;
            // 6 ticks per 16th note step
            if (fMidiClockCount >= 6)
            {
                fMidiClockCount = 0;
                advanceStep();
            }
        }
        else if (status == 0xFA || status == 0xFB) // Start / Continue
        {
            fMidiClockCount = 0;
            fCurrentStep    = 0;
            fStepPos        = 0.0f;
            fGainL          = 0.0f;
            fGainR          = 0.0f;
            fClockReceived  = true;
        }
        else if (status == 0xFC) // Stop
        {
            fClockReceived = false;
        }
    }

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

        const float sr       = fSampleRate;
        const float atkCoeff = 1.0f - expf(-1.0f / (fAttack  * sr + 1.0f));
        const float relCoeff = 1.0f - expf(-1.0f / (fRelease * sr + 1.0f));

        for (uint32_t i = 0; i < frames; ++i)
        {
            int   step    = fCurrentStep & 7;
            bool  on      = (fStepOn[step] >= 0.5f);
            float vol     = fStepVol[step];
            float pan     = fStepPan[step]; // -1 to +1

            // Constant power pan
            float panAngle = (pan + 1.0f) * 0.25f * 3.14159265f; // 0 to pi/2
            float panL = cosf(panAngle);
            float panR = sinf(panAngle);

            // Gate target gain
            float targetGain = on ? vol : 0.0f;

            // Smooth gain with attack/release
            float coeff = (targetGain > fGainL) ? atkCoeff : relCoeff;
            fGainL += coeff * (targetGain * panL - fGainL);
            fGainR += coeff * (targetGain * panR - fGainR);

            outL[i] = inL[i] * fGainL;
            outR[i] = inR[i] * fGainR;

            // Internal clock fallback when no MIDI clock received
            if (!fClockReceived)
            {
                fStepPos += 1.0f;
                float stepLen = fStepSamples;
                // apply swing to odd steps
                if (step & 1)
                    stepLen *= (1.0f + fSwing * 0.5f);
                if (fStepPos >= stepLen)
                {
                    fStepPos -= stepLen;
                    fCurrentStep = (fCurrentStep + 1) & 7;
                }
            }
        }
    }

private:
    // global params
    float fGateLength;
    float fAttack;
    float fRelease;
    float fSwing;

    // per-step params
    float fStepOn[8];
    float fStepVol[8];
    float fStepPan[8];

    // runtime
    float    fSampleRate;
    int      fCurrentStep;
    float    fStepPos;
    float    fStepSamples;
    float    fGainL, fGainR;
    int      fMidiClockCount;
    float    fMidiClockPhase;
    bool     fClockReceived;

    void advanceStep()
    {
        fStepPos     = 0.0f;
        fCurrentStep = (fCurrentStep + 1) & 7;
    }

    DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(TranceGatePlugin)
};

Plugin* createPlugin() { return new TranceGatePlugin(); }

END_NAMESPACE_DISTRHO
endef

define TRANCE_GATE_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             "Trance Gate"
#define DISTRHO_PLUGIN_URI              "urn:mod-cookbook:trance-gate"

#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
#define DISTRHO_PLUGIN_WANT_MIDI_INPUT  1

enum Parameters {
    kGateLength = 0,
    kAttack,
    kRelease,
    kSwing,
    kStepsStart,
    // Step 1
    kStep1On  = kStepsStart,
    kStep1Vol,
    kStep1Pan,
    // Step 2
    kStep2On,
    kStep2Vol,
    kStep2Pan,
    // Step 3
    kStep3On,
    kStep3Vol,
    kStep3Pan,
    // Step 4
    kStep4On,
    kStep4Vol,
    kStep4Pan,
    // Step 5
    kStep5On,
    kStep5Vol,
    kStep5Pan,
    // Step 6
    kStep6On,
    kStep6Vol,
    kStep6Pan,
    // Step 7
    kStep7On,
    kStep7Vol,
    kStep7Pan,
    // Step 8
    kStep8On,
    kStep8Vol,
    kStep8Pan,
    kParameterCount
};

#endif
endef

define TRANCE_GATE_PLUGIN_MAKEFILE
#!/usr/bin/make -f
NAME = trance-gate
FILES_DSP = TranceGatePlugin.cpp
include ../../Makefile.plugins.mk
TARGETS = lv2_dsp
all: $(TARGETS)
endef

define TRANCE_GATE_MANIFEST_TTL
@prefix lv2:  <http://lv2plug.in/ns/lv2core#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .

<urn:mod-cookbook:trance-gate>
    a lv2:Plugin , lv2:GatePlugin ;
    lv2:binary <trance-gate_dsp.so> ;
    rdfs:seeAlso <trance-gate.ttl> .
endef

define TRANCE_GATE_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 midi:  <http://lv2plug.in/ns/ext/midi#> .
@prefix rdfs:  <http://www.w3.org/2000/01/rdf-schema#> .
@prefix units: <http://lv2plug.in/ns/extensions/units#> .
@prefix atom:  <http://lv2plug.in/ns/ext/atom#> .
@prefix urid:  <http://lv2plug.in/ns/ext/urid#> .

<urn:mod-cookbook:trance-gate>
    a lv2:Plugin , lv2:GatePlugin ;
    doap:name "Trance Gate" ;
    doap:license <http://opensource.org/licenses/MIT> ;
    doap:maintainer [
        foaf:name "MOD Cookbook" ;
        foaf:homepage <https://mod.audio>
    ] ;
    rdfs:comment "8-step stereo trance gate with MIDI clock sync, per-step volume and pan." ;
    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 , atom:AtomPort ;
        atom:bufferType atom:Sequence ;
        atom:supports midi:MidiEvent ;
        lv2:index 4 ;
        lv2:symbol "midi_in" ;
        lv2:name "MIDI In"
    ] , [
        a lv2:InputPort , lv2:ControlPort ;
        lv2:index 5 ;
        lv2:symbol "gate_length" ;
        lv2:name "Gate Length" ;
        lv2:default 80.0 ;
        lv2:minimum 5.0 ;
        lv2:maximum 100.0 ;
        units:unit units:pc
    ] , [
        a lv2:InputPort , lv2:ControlPort ;
        lv2:index 6 ;
        lv2:symbol "attack" ;
        lv2:name "Attack" ;
        lv2:default 5.0 ;
        lv2:minimum 0.1 ;
        lv2:maximum 100.0 ;
        units:unit units:ms
    ] , [
        a lv2:InputPort , lv2:ControlPort ;
        lv2:index 7 ;
        lv2:symbol "release" ;
        lv2:name "Release" ;
        lv2:default 20.0 ;
        lv2:minimum 0.1 ;
        lv2:maximum 200.0 ;
        units:unit units:ms
    ] , [
        a lv2:InputPort , lv2:ControlPort ;
        lv2:index 8 ;
        lv2:symbol "swing" ;
        lv2:name "Swing" ;
        lv2:default 0.0 ;
        lv2:minimum 0.0 ;
        lv2:maximum 75.0 ;
        units:unit units:pc
    ] , [
        a lv2:InputPort , lv2:ControlPort ;
        lv2:index 9 ;
        lv2:symbol "step1_on" ;
        lv2:name "Step 1 On" ;
        lv2:default 1.0 ;
        lv2:minimum 0.0 ;
        lv2:maximum 1.0
    ] , [
        a lv2:InputPort , lv2:ControlPort ;
        lv2:index 10 ;
        lv2:symbol "step1_vol" ;
        lv2:name "Step 1 Volume" ;
        lv2:default 100.0 ;
        lv2:minimum 0.0 ;
        lv2:maximum 100.0 ;
        units:unit units:pc
    ] , [
        a lv2:InputPort , lv2:ControlPort ;
        lv2:index 11 ;
        lv2:symbol "step1_pan" ;
        lv2:name "Step 1 Pan" ;
        lv2:default 0.0 ;
        lv2:minimum -1.0 ;
        lv2:maximum 1.0
    ] , [
        a lv2:InputPort , lv2:ControlPort ;
        lv2:index 12 ;
        lv2:symbol "step2_on" ;
        lv2:name "Step 2 On" ;
        lv2:default 0.0 ;
        lv2:minimum 0.0 ;
        lv2:maximum 1.0
    ] , [
        a lv2:InputPort , lv2:ControlPort ;
        lv2:index 13 ;
        lv2:symbol "step2_vol" ;
        lv2:name "Step 2 Volume" ;
        lv2:default 100.0 ;
        lv2:minimum 0.0 ;
        lv2:maximum 100.0 ;
        units:unit units:pc
    ] , [
        a lv2:InputPort , lv2:ControlPort ;
        lv2:index 14 ;
        lv2:symbol "step2_pan" ;
        lv2:name "Step 2 Pan" ;
        lv2:default 0.0 ;
        lv2:minimum -1.0 ;
        lv2:maximum 1.0
    ] , [
        a lv2:InputPort , lv2:ControlPort ;
        lv2:index 15 ;
        lv2:symbol "step3_on" ;
        lv2:name "Step 3 On" ;
        lv2:default 1.0 ;
        lv2:minimum 0.0 ;
        lv2:maximum 1.0
    ] , [
        a lv2:InputPort , lv2:ControlPort ;
        lv2:index 16 ;
        lv2:symbol "step3_vol" ;
        lv2:name "Step 3 Volume" ;
        lv2:default 100.0 ;
        lv2:minimum 0.0 ;
        lv2:maximum 100.0 ;
        units:unit units:pc
    ] , [
        a lv2:InputPort , lv2:ControlPort ;
        lv2:index 17 ;
        lv2:symbol "step3_pan" ;
        lv2:name "Step 3 Pan" ;
        lv2:default 0.0 ;
        lv2:minimum -1.0 ;
        lv2:maximum 1.0
    ] , [
        a lv2:InputPort , lv2:ControlPort ;
        lv2:index 18 ;
        lv2:symbol "step4_on" ;
        lv2:name "Step 4 On" ;
        lv2:default 0.0 ;
        lv2:minimum 0.0 ;
        lv2:maximum 1.0
    ] , [
        a lv2:InputPort , lv2:ControlPort ;
        lv2:index 19 ;
        lv2:symbol "step4_vol" ;
        lv2:name "Step 4 Volume" ;
        lv2:default 100.0 ;
        lv2:minimum 0.0 ;
        lv2:maximum 100.0 ;
        units:unit units:pc
    ] , [
        a lv2:InputPort , lv2:ControlPort ;
        lv2:index 20 ;
        lv2:symbol "step4_pan" ;
        lv2:name "Step 4 Pan" ;
        lv2:default 0.0 ;
        lv2:minimum -1.0 ;
        lv2:maximum 1.0
    ] , [
        a lv2:InputPort , lv2:ControlPort ;
        lv2:index 21 ;
        lv2:symbol "step5_on" ;
        lv2:name "Step 5 On" ;
        lv2:default 1.0 ;
        lv2:minimum 0.0 ;
        lv2:maximum 1.0
    ] , [
        a lv2:InputPort , lv2:ControlPort ;
        lv2:index 22 ;
        lv2:symbol "step5_vol" ;
        lv2:name "Step 5 Volume" ;
        lv2:default 100.0 ;
        lv2:minimum 0.0 ;
        lv2:maximum 100.0 ;
        units:unit units:pc
    ] , [
        a lv2:InputPort , lv2:ControlPort ;
        lv2:index 23 ;
        lv2:symbol "step5_pan" ;
        lv2:name "Step 5 Pan" ;
        lv2:default 0.0 ;
        lv2:minimum -1.0 ;
        lv2:maximum 1.0
    ] , [
        a lv2:InputPort , lv2:ControlPort ;
        lv2:index 24 ;
        lv2:symbol "step6_on" ;
        lv2:name "Step 6 On" ;
        lv2:default 0.0 ;
        lv2:minimum 0.0 ;
        lv2:maximum 1.0
    ] , [
        a lv2:InputPort , lv2:ControlPort ;
        lv2:index 25 ;
        lv2:symbol "step6_vol" ;
        lv2:name "Step 6 Volume" ;
        lv2:default 100.0 ;
        lv2:minimum 0.0 ;
        lv2:maximum 100.0 ;
        units:unit units:pc
    ] , [
        a lv2:InputPort , lv2:ControlPort ;
        lv2:index 26 ;
        lv2:symbol "step6_pan" ;
        lv2:name "Step 6 Pan" ;
        lv2:default 0.0 ;
        lv2:minimum -1.0 ;
        lv2:maximum 1.0
    ] , [
        a lv2:InputPort , lv2:ControlPort ;
        lv2:index 27 ;
        lv2:symbol "step7_on" ;
        lv2:name "Step 7 On" ;
        lv2:default 1.0 ;
        lv2:minimum 0.0 ;
        lv2:maximum 1.0
    ] , [
        a lv2:InputPort , lv2:ControlPort ;
        lv2:index 28 ;
        lv2:symbol "step7_vol" ;
        lv2:name "Step 7 Volume" ;
        lv2:default 100.0 ;
        lv2:minimum 0.0 ;
        lv2:maximum 100.0 ;
        units:unit units:pc
    ] , [
        a lv2:InputPort , lv2:ControlPort ;
        lv2:index 29 ;
        lv2:symbol "step7_pan" ;
        lv2:name "Step 7 Pan" ;
        lv2:default 0.0 ;
        lv2:minimum -1.0 ;
        lv2:maximum 1.0
    ] , [
        a lv2:InputPort , lv2:ControlPort ;
        lv2:index 30 ;
        lv2:symbol "step8_on" ;
        lv2:name "Step 8 On" ;
        lv2:default 0.0 ;
        lv2:minimum 0.0 ;
        lv2:maximum 1.0
    ] , [
        a lv2:InputPort , lv2:ControlPort ;
        lv2:index 31 ;
        lv2:symbol "step8_vol" ;
        lv2:name "Step 8 Volume" ;
        lv2:default 100.0 ;
        lv2:minimum 0.0 ;
        lv2:maximum 100.0 ;
        units:unit units:pc
    ] , [
        a lv2:InputPort , lv2:ControlPort ;
        lv2:index 32 ;
        lv2:symbol "step8_pan" ;
        lv2:name "Step 8 Pan" ;
        lv2:default 0.0 ;
        lv2:minimum -1.0 ;
        lv2:maximum 1.0
    ] .
endef

export TRANCE_GATE_PLUGIN_CPP
export TRANCE_GATE_PLUGIN_INFO_H
export TRANCE_GATE_PLUGIN_MAKEFILE
export TRANCE_GATE_MANIFEST_TTL
export TRANCE_GATE_PLUGIN_TTL

define TRANCE_GATE_CONFIGURE_CMDS
	mkdir -p $(@D)/examples/trance-gate
	printf '%s' "$$TRANCE_GATE_PLUGIN_CPP"      > $(@D)/examples/trance-gate/TranceGatePlugin.cpp
	printf '%s' "$$TRANCE_GATE_PLUGIN_INFO_H"   > $(@D)/examples/trance-gate/DistrhoPluginInfo.h
	printf '%s' "$$TRANCE_GATE_PLUGIN_MAKEFILE" > $(@D)/examples/trance-gate/Makefile
endef

define TRANCE_GATE_BUILD_CMDS
	$(TARGET_MAKE_ENV) $(TARGET_CONFIGURE_OPTS) $(MAKE) NOOPT=true -C $(@D)/examples/trance-gate lv2_dsp
endef

define TRANCE_GATE_INSTALL_TARGET_CMDS
	mkdir -p $($(PKG)_PKGDIR)/trance-gate.lv2
	cp $(@D)/bin/trance-gate.lv2/trance-gate_dsp.so $($(PKG)_PKGDIR)/trance-gate.lv2/
	printf '%s' "$$TRANCE_GATE_MANIFEST_TTL" > $($(PKG)_PKGDIR)/trance-gate.lv2/manifest.ttl
	printf '%s' "$$TRANCE_GATE_PLUGIN_TTL"   > $($(PKG)_PKGDIR)/trance-gate.lv2/trance-gate.ttl
endef

$(eval $(generic-package))
