################################################################################
#
# BOSS_NS2_NOISE_SUPPRESSOR
#
# LV2 plugin built from the MOD Audio Cookbook workflow: DPF source is embedded
# below and compiled against a pinned DPF checkout, producing an .lv2 bundle
# that the builder.mod.audio cloud builder can compile and package for the
# MOD Dwarf.
#
################################################################################

BOSS_NS2_NOISE_SUPPRESSOR_VERSION = 61d38eb638449647fb8395a35c5b8dab7e981ba7
BOSS_NS2_NOISE_SUPPRESSOR_SITE = https://github.com/DISTRHO/DPF.git
BOSS_NS2_NOISE_SUPPRESSOR_SITE_METHOD = git
BOSS_NS2_NOISE_SUPPRESSOR_GIT_SUBMODULES = YES
BOSS_NS2_NOISE_SUPPRESSOR_INSTALL_STAGING = NO
BOSS_NS2_NOISE_SUPPRESSOR_BUNDLES = boss-ns2-noise-suppressor.lv2

define BOSS_NS2_NOISE_SUPPRESSOR_PLUGIN_CPP
#include "DistrhoPlugin.hpp"
#include <cmath>

START_NAMESPACE_DISTRHO

// Circuit: Boss NS-2 style Noise Suppressor (noise gate).
// THRESHOLD sets how loud the input must get before the gate opens - turning
// it up makes suppression more aggressive, gating out more of the signal
// (hiss, amp hum, pickup noise) between notes. DECAY sets how long the gate
// takes to close back down once the signal drops below threshold, from a
// fast, slightly choppy cutoff at low settings to a slow, smooth fade at
// high settings. A small hysteresis gap between the opening and closing
// threshold stops the gate from chattering on/off when a signal is hovering
// right around the threshold level. Detection is done on a fast-attack,
// short-release envelope follower measured in dB, separate from the gate's
// own attack/decay behaviour.
class BossNS2NoiseSuppressor : public Plugin {
public:
    BossNS2NoiseSuppressor()
        : Plugin(2, 0, 0)
    {
        sampleRateChanged(getSampleRate());
    }

protected:
    const char* getLabel() const override { return "NS2Style"; }
    const char* getDescription() const override { return "Boss NS-2 style Noise Suppressor - MOD Audio Cookbook"; }
    const char* getMaker() const override { return "MODAudioCookbook"; }
    const char* getLicense() const override { return "ISC"; }
    uint32_t getVersion() const override { return d_version(1, 0, 0); }
    int64_t getUniqueId() const override { return d_cconst('N','S','2','S'); }

    void initParameter(uint32_t index, Parameter& parameter) override {
        switch (index) {
        case 0:
            parameter.hints = kParameterIsAutomatable;
            parameter.name = "Threshold";
            parameter.symbol = "threshold";
            parameter.ranges.def = 0.3f; parameter.ranges.min = 0.0f; parameter.ranges.max = 1.0f;
            break;
        case 1:
            parameter.hints = kParameterIsAutomatable;
            parameter.name = "Decay";
            parameter.symbol = "decay";
            parameter.ranges.def = 0.4f; parameter.ranges.min = 0.0f; parameter.ranges.max = 1.0f;
            break;
        }
    }

    float getParameterValue(uint32_t index) const override { return params[index]; }
    void  setParameterValue(uint32_t index, float value) override { params[index] = value; }

    void sampleRateChanged(double newSampleRate) override {
        sr = (float)newSampleRate;
        // Envelope detector: fast attack so transients are caught promptly,
        // short release so the detector tracks the actual signal level rather
        // than smearing it out. This is independent of the gate's own Decay.
        envAttackCoef  = expf(-1.0f / (0.0005f * sr));   // 0.5ms
        envReleaseCoef = expf(-1.0f / (0.05f  * sr));    // 50ms
        gateAttackCoef = expf(-1.0f / (0.001f * sr));    // 1ms - gate opens fast to avoid clipping transients
    }

    void activate() override {
        env = 0.0f;
        gateGain = 0.0f;
        gateOpen = false;
    }

    void run(const float** inputs, float** outputs, uint32_t frames) override {
        const float thresholdP = params[0];
        const float decayP     = params[1];

        // -80dB (gate barely engages, mostly transparent) up to -10dB
        // (aggressive, gates out anything but loud playing)
        const float thresholdDb = -80.0f + thresholdP * 70.0f;
        const float hysteresisDb = 3.0f;
        const float openDb  = thresholdDb + hysteresisDb;
        const float closeDb = thresholdDb - hysteresisDb;

        // Decay knob: 20ms (fast, choppy cutoff) up to 900ms (slow, smooth fade)
        const float decayMs = 20.0f + decayP * 880.0f;
        const float gateReleaseCoef = expf(-1.0f / (0.001f * decayMs * sr));

        for (uint32_t i = 0; i < frames; ++i) {
            const float x = inputs[0][i];
            const float rectified = x >= 0.0f ? x : -x;

            const float envCoef = rectified > env ? envAttackCoef : envReleaseCoef;
            env = envCoef * env + (1.0f - envCoef) * rectified;

            const float envDb = 20.0f * log10f(env + 1.0e-9f);

            if (!gateOpen && envDb > openDb)
                gateOpen = true;
            else if (gateOpen && envDb < closeDb)
                gateOpen = false;

            const float targetGain = gateOpen ? 1.0f : 0.0f;
            const float gainCoef = targetGain > gateGain ? gateAttackCoef : gateReleaseCoef;
            gateGain = gainCoef * gateGain + (1.0f - gainCoef) * targetGain;

            outputs[0][i] = x * gateGain;
        }
    }

private:
    float sr = 48000.0f;
    float params[2] = {0.3f, 0.4f};

    float env = 0.0f;
    float envAttackCoef = 0.0f, envReleaseCoef = 0.0f;

    float gateGain = 0.0f;
    float gateAttackCoef = 0.0f;
    bool  gateOpen = false;

    BossNS2NoiseSuppressor(const BossNS2NoiseSuppressor&) = delete;
    BossNS2NoiseSuppressor& operator=(const BossNS2NoiseSuppressor&) = delete;
};

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

END_NAMESPACE_DISTRHO

endef
export BOSS_NS2_NOISE_SUPPRESSOR_PLUGIN_CPP

define BOSS_NS2_NOISE_SUPPRESSOR_PLUGIN_INFO_H
#ifndef DISTRHO_PLUGIN_INFO_H_INCLUDED
#define DISTRHO_PLUGIN_INFO_H_INCLUDED

#define DISTRHO_PLUGIN_BRAND   "MODAudioCookbook"
#define DISTRHO_PLUGIN_NAME    "Boss NS-2 style Noise Suppressor"
#define DISTRHO_PLUGIN_URI     "https://mod.audio/cookbook/noisegate/ns2style"
#define DISTRHO_PLUGIN_NUM_INPUTS  1
#define DISTRHO_PLUGIN_NUM_OUTPUTS 1
#define DISTRHO_PLUGIN_IS_RT_SAFE  1
#define DISTRHO_PLUGIN_WANT_STATE 0
#define DISTRHO_PLUGIN_HAS_UI     0

#endif

endef
export BOSS_NS2_NOISE_SUPPRESSOR_PLUGIN_INFO_H

define BOSS_NS2_NOISE_SUPPRESSOR_PLUGIN_TTL
@prefix lv2:  <http://lv2plug.in/ns/lv2core#> .
@prefix doap: <http://usefulinc.com/ns/doap#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix rdf:  <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .

<https://mod.audio/cookbook/noisegate/ns2style>
    a lv2:Plugin , lv2:ExpanderPlugin ;
    doap:name "Boss NS-2 style Noise Suppressor" ;
    doap:license <http://opensource.org/licenses/isc> ;
    lv2:project <https://mod.audio/cookbook/noisegate/ns2style> ;
    lv2:optionalFeature lv2:hardRTCapable ;
    lv2:port
    [
        a lv2:AudioPort , lv2:InputPort ;
        lv2:index 0 ;
        lv2:symbol "in" ;
        lv2:name "In" ;
    ] ,
    [
        a lv2:AudioPort , lv2:OutputPort ;
        lv2:index 1 ;
        lv2:symbol "out" ;
        lv2:name "Out" ;
    ] ,
    [
        a lv2:InputPort , lv2:ControlPort ;
        lv2:index 2 ;
        lv2:symbol "threshold" ;
        lv2:name "Threshold" ;
        lv2:default 0.3 ;
        lv2:minimum 0.0 ;
        lv2:maximum 1.0 ;
    ] ,
    [
        a lv2:InputPort , lv2:ControlPort ;
        lv2:index 3 ;
        lv2:symbol "decay" ;
        lv2:name "Decay" ;
        lv2:default 0.4 ;
        lv2:minimum 0.0 ;
        lv2:maximum 1.0 ;
    ] .

endef
export BOSS_NS2_NOISE_SUPPRESSOR_PLUGIN_TTL

define BOSS_NS2_NOISE_SUPPRESSOR_MANIFEST_TTL
@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://mod.audio/cookbook/noisegate/ns2style>
    a lv2:Plugin ;
    lv2:binary <boss-ns2-noise-suppressor_dsp.so> ;
    rdfs:seeAlso <boss-ns2-noise-suppressor.ttl> .

<https://mod.audio/cookbook/noisegate/ns2style#preset-subtle-cleanup>
    a pset:Preset ;
    lv2:appliesTo <https://mod.audio/cookbook/noisegate/ns2style> ;
    rdfs:label "Subtle Cleanup" ;
    rdfs:seeAlso <presets/subtle-cleanup.ttl> .

<https://mod.audio/cookbook/noisegate/ns2style#preset-studio-vocal-gate>
    a pset:Preset ;
    lv2:appliesTo <https://mod.audio/cookbook/noisegate/ns2style> ;
    rdfs:label "Studio Vocal Gate" ;
    rdfs:seeAlso <presets/studio-vocal-gate.ttl> .

<https://mod.audio/cookbook/noisegate/ns2style#preset-high-gain-rig>
    a pset:Preset ;
    lv2:appliesTo <https://mod.audio/cookbook/noisegate/ns2style> ;
    rdfs:label "High Gain Rig" ;
    rdfs:seeAlso <presets/high-gain-rig.ttl> .

<https://mod.audio/cookbook/noisegate/ns2style#preset-live-stage>
    a pset:Preset ;
    lv2:appliesTo <https://mod.audio/cookbook/noisegate/ns2style> ;
    rdfs:label "Live Stage" ;
    rdfs:seeAlso <presets/live-stage.ttl> .

<https://mod.audio/cookbook/noisegate/ns2style#preset-smooth-fade>
    a pset:Preset ;
    lv2:appliesTo <https://mod.audio/cookbook/noisegate/ns2style> ;
    rdfs:label "Smooth Fade" ;
    rdfs:seeAlso <presets/smooth-fade.ttl> .

endef
export BOSS_NS2_NOISE_SUPPRESSOR_MANIFEST_TTL

define BOSS_NS2_NOISE_SUPPRESSOR_PLUGIN_MAKEFILE
#!/usr/bin/make -f
# Makefile for boss-ns2-noise-suppressor (MOD Audio Cookbook / DPF) #
# ------------------------------------------------ #

include ../../Makefile.base.mk

NAME = boss-ns2-noise-suppressor

all: lv2_dsp

BUILD_DIR = ../../build/boss-ns2-noise-suppressor

FILES_DSP = \
	DistrhoPluginBossNS2NoiseSuppressor.cpp

include ../../Makefile.plugins.mk

TARGETS += lv2_dsp

all: $(TARGETS)

endef
export BOSS_NS2_NOISE_SUPPRESSOR_PLUGIN_MAKEFILE

define BOSS_NS2_NOISE_SUPPRESSOR_PRESET_SUBTLE_CLEANUP_TTL
@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://mod.audio/cookbook/noisegate/ns2style#preset-subtle-cleanup>
    a pset:Preset ;
    lv2:appliesTo <https://mod.audio/cookbook/noisegate/ns2style> ;
    rdfs:label "Subtle Cleanup" ;
    lv2:port
        [ lv2:symbol "threshold" ; pset:value 0.15 ] ,
        [ lv2:symbol "decay" ; pset:value 0.6 ] .

endef
export BOSS_NS2_NOISE_SUPPRESSOR_PRESET_SUBTLE_CLEANUP_TTL

define BOSS_NS2_NOISE_SUPPRESSOR_PRESET_STUDIO_VOCAL_GATE_TTL
@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://mod.audio/cookbook/noisegate/ns2style#preset-studio-vocal-gate>
    a pset:Preset ;
    lv2:appliesTo <https://mod.audio/cookbook/noisegate/ns2style> ;
    rdfs:label "Studio Vocal Gate" ;
    lv2:port
        [ lv2:symbol "threshold" ; pset:value 0.35 ] ,
        [ lv2:symbol "decay" ; pset:value 0.5 ] .

endef
export BOSS_NS2_NOISE_SUPPRESSOR_PRESET_STUDIO_VOCAL_GATE_TTL

define BOSS_NS2_NOISE_SUPPRESSOR_PRESET_HIGH_GAIN_RIG_TTL
@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://mod.audio/cookbook/noisegate/ns2style#preset-high-gain-rig>
    a pset:Preset ;
    lv2:appliesTo <https://mod.audio/cookbook/noisegate/ns2style> ;
    rdfs:label "High Gain Rig" ;
    lv2:port
        [ lv2:symbol "threshold" ; pset:value 0.6 ] ,
        [ lv2:symbol "decay" ; pset:value 0.3 ] .

endef
export BOSS_NS2_NOISE_SUPPRESSOR_PRESET_HIGH_GAIN_RIG_TTL

define BOSS_NS2_NOISE_SUPPRESSOR_PRESET_LIVE_STAGE_TTL
@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://mod.audio/cookbook/noisegate/ns2style#preset-live-stage>
    a pset:Preset ;
    lv2:appliesTo <https://mod.audio/cookbook/noisegate/ns2style> ;
    rdfs:label "Live Stage" ;
    lv2:port
        [ lv2:symbol "threshold" ; pset:value 0.7 ] ,
        [ lv2:symbol "decay" ; pset:value 0.2 ] .

endef
export BOSS_NS2_NOISE_SUPPRESSOR_PRESET_LIVE_STAGE_TTL

define BOSS_NS2_NOISE_SUPPRESSOR_PRESET_SMOOTH_FADE_TTL
@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://mod.audio/cookbook/noisegate/ns2style#preset-smooth-fade>
    a pset:Preset ;
    lv2:appliesTo <https://mod.audio/cookbook/noisegate/ns2style> ;
    rdfs:label "Smooth Fade" ;
    lv2:port
        [ lv2:symbol "threshold" ; pset:value 0.25 ] ,
        [ lv2:symbol "decay" ; pset:value 0.9 ] .

endef
export BOSS_NS2_NOISE_SUPPRESSOR_PRESET_SMOOTH_FADE_TTL


define BOSS_NS2_NOISE_SUPPRESSOR_CONFIGURE_CMDS
	mkdir -p $(@D)/examples/boss-ns2-noise-suppressor
	mkdir -p $(@D)/examples/boss-ns2-noise-suppressor/presets
	printf '%s' "$$BOSS_NS2_NOISE_SUPPRESSOR_PLUGIN_CPP" > $(@D)/examples/boss-ns2-noise-suppressor/DistrhoPluginBossNS2NoiseSuppressor.cpp
	printf '%s' "$$BOSS_NS2_NOISE_SUPPRESSOR_PLUGIN_INFO_H" > $(@D)/examples/boss-ns2-noise-suppressor/DistrhoPluginInfo.h
	printf '%s' "$$BOSS_NS2_NOISE_SUPPRESSOR_PLUGIN_TTL" > $(@D)/examples/boss-ns2-noise-suppressor/boss-ns2-noise-suppressor.ttl
	printf '%s' "$$BOSS_NS2_NOISE_SUPPRESSOR_MANIFEST_TTL" > $(@D)/examples/boss-ns2-noise-suppressor/manifest.ttl
	printf '%s' "$$BOSS_NS2_NOISE_SUPPRESSOR_PLUGIN_MAKEFILE" > $(@D)/examples/boss-ns2-noise-suppressor/Makefile
	printf '%s' "$$BOSS_NS2_NOISE_SUPPRESSOR_PRESET_SUBTLE_CLEANUP_TTL" > $(@D)/examples/boss-ns2-noise-suppressor/presets/subtle-cleanup.ttl
	printf '%s' "$$BOSS_NS2_NOISE_SUPPRESSOR_PRESET_STUDIO_VOCAL_GATE_TTL" > $(@D)/examples/boss-ns2-noise-suppressor/presets/studio-vocal-gate.ttl
	printf '%s' "$$BOSS_NS2_NOISE_SUPPRESSOR_PRESET_HIGH_GAIN_RIG_TTL" > $(@D)/examples/boss-ns2-noise-suppressor/presets/high-gain-rig.ttl
	printf '%s' "$$BOSS_NS2_NOISE_SUPPRESSOR_PRESET_LIVE_STAGE_TTL" > $(@D)/examples/boss-ns2-noise-suppressor/presets/live-stage.ttl
	printf '%s' "$$BOSS_NS2_NOISE_SUPPRESSOR_PRESET_SMOOTH_FADE_TTL" > $(@D)/examples/boss-ns2-noise-suppressor/presets/smooth-fade.ttl
endef

define BOSS_NS2_NOISE_SUPPRESSOR_BUILD_CMDS
	$(TARGET_MAKE_ENV) $(TARGET_CONFIGURE_OPTS) $(MAKE) NOOPT=true -C $(@D)/examples/boss-ns2-noise-suppressor lv2_dsp
endef

define BOSS_NS2_NOISE_SUPPRESSOR_INSTALL_TARGET_CMDS
	cp $(@D)/examples/boss-ns2-noise-suppressor/manifest.ttl $(@D)/bin/boss-ns2-noise-suppressor.lv2/manifest.ttl
	cp $(@D)/examples/boss-ns2-noise-suppressor/boss-ns2-noise-suppressor.ttl $(@D)/bin/boss-ns2-noise-suppressor.lv2/boss-ns2-noise-suppressor.ttl
	mkdir -p $(@D)/bin/boss-ns2-noise-suppressor.lv2/presets
	cp $(@D)/examples/boss-ns2-noise-suppressor/presets/subtle-cleanup.ttl $(@D)/bin/boss-ns2-noise-suppressor.lv2/presets/subtle-cleanup.ttl
	cp $(@D)/examples/boss-ns2-noise-suppressor/presets/studio-vocal-gate.ttl $(@D)/bin/boss-ns2-noise-suppressor.lv2/presets/studio-vocal-gate.ttl
	cp $(@D)/examples/boss-ns2-noise-suppressor/presets/high-gain-rig.ttl $(@D)/bin/boss-ns2-noise-suppressor.lv2/presets/high-gain-rig.ttl
	cp $(@D)/examples/boss-ns2-noise-suppressor/presets/live-stage.ttl $(@D)/bin/boss-ns2-noise-suppressor.lv2/presets/live-stage.ttl
	cp $(@D)/examples/boss-ns2-noise-suppressor/presets/smooth-fade.ttl $(@D)/bin/boss-ns2-noise-suppressor.lv2/presets/smooth-fade.ttl
	mkdir -p $(TARGET_DIR)/usr/lib/lv2
	cp -r $(@D)/bin/boss-ns2-noise-suppressor.lv2 $(TARGET_DIR)/usr/lib/lv2/
endef

$(eval $(generic-package))
