~alextee/zrythm

bf08c9e039b4d8b3b981410fabe9bd4c6b98889a — Alexandros Theodotou 3 years ago dc99db8 noisegate-plugins
add bundled noisegate plugin
M ext/meson.build => ext/meson.build +1 -0
@@ 17,6 17,7 @@

subdir ('midilib')
subdir ('nanovg')
subdir ('noisegate-lv2')
subdir ('weakjack')
subdir ('whereami')
subdir ('zix')

A ext/noisegate-lv2/LICENSE => ext/noisegate-lv2/LICENSE +13 -0
@@ 0,0 1,13 @@
VEJA NoiseGate
Copyright (C) 2021 Jan Janssen <jan@moddevices.com>

Permission to use, copy, modify, and/or distribute this software for any purpose with
or without fee is hereby granted, provided that the above copyright notice and this
permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

A ext/noisegate-lv2/Makefile => ext/noisegate-lv2/Makefile +44 -0
@@ 0,0 1,44 @@
#!/usr/bin/make -f
# Makefile for noisegate.lv2 #
# --------------------------------- #

include Makefile.mk

NAME = noisegate

# --------------------------------------------------------------
# Installation path

INSTALL_PATH = /usr/local/lib/lv2
COMPLETE_INSTALL_PATH = $(DESTDIR)$(INSTALL_PATH)/$(NAME).lv2

# --------------------------------------------------------------
# Default target is to build all plugins

all: build
build: $(NAME)-build

# --------------------------------------------------------------
# Build rules

$(NAME)-build: $(NAME).lv2/$(NAME)$(LIB_EXT)

$(NAME).lv2/$(NAME)$(LIB_EXT): $(NAME).c gate_core.c circular_buffer.c
	$(CC) $^ $(BUILD_C_FLAGS) $(LINK_FLAGS) -lm $(SHARED) -o $@

# --------------------------------------------------------------

clean:
	rm -f $(NAME).lv2/$(NAME)$(LIB_EXT)

# --------------------------------------------------------------

install: build
	install -d $(DESTDIR)$(PREFIX)/lib/lv2/$(NAME).lv2

	install -m 644 $(NAME).lv2/*.so  $(DESTDIR)$(PREFIX)/lib/lv2/$(NAME).lv2/
	install -m 644 $(NAME).lv2/*.ttl $(DESTDIR)$(PREFIX)/lib/lv2/$(NAME).lv2/
	cp -rv $(NAME).lv2/modgui $(DESTDIR)$(PREFIX)/lib/lv2/$(NAME).lv2/

# --------------------------------------------------------------


A ext/noisegate-lv2/Makefile.mk => ext/noisegate-lv2/Makefile.mk +79 -0
@@ 0,0 1,79 @@
#!/usr/bin/make -f
# Makefile for noisegate.lv2 #
# ----------------------- #
#

AR  ?= ar
CC  ?= gcc
CXX ?= g++

# --------------------------------------------------------------
# Fallback to Linux if no other OS defined

ifneq ($(MACOS),true)
ifneq ($(WIN32),true)
LINUX=true
endif
endif

# --------------------------------------------------------------
# Set build and link flags

BASE_FLAGS = -Wall -Wextra -pipe -Wno-unused-parameter
BASE_OPTS  = -O3 -ffast-math

ifeq ($(MACOS),true)
# MacOS linker flags
LINK_OPTS  = -Wl,-dead_strip -Wl,-dead_strip_dylibs
else
# Common linker flags
LINK_OPTS  = -Wl,-O1 -Wl,--as-needed -Wl,--strip-all
endif

ifneq ($(WIN32),true)
# not needed for Windows
BASE_FLAGS += -fPIC -DPIC
endif

ifeq ($(DEBUG),true)
BASE_FLAGS += -O3 -g
LINK_OPTS   =
else
BASE_FLAGS += -DNDEBUG $(BASE_OPTS) -fvisibility=hidden -O3
CXXFLAGS   += -fvisibility-inlines-hidden
endif

BUILD_C_FLAGS   = $(BASE_FLAGS) -std=c99 -std=gnu99 $(CFLAGS)
BUILD_CXX_FLAGS = $(BASE_FLAGS) -std=c++11 $(CXXFLAGS) $(CPPFLAGS)

ifeq ($(MACOS),true)
# 'no-undefined' is always enabled on MacOS
LINK_FLAGS      = $(LINK_OPTS) $(LDFLAGS)
else
# add 'no-undefined'
LINK_FLAGS      = $(LINK_OPTS) -Wl,--no-undefined $(LDFLAGS)
endif

# --------------------------------------------------------------
# Set shared lib extension

LIB_EXT = .so

ifeq ($(MACOS),true)
LIB_EXT = .dylib
endif

ifeq ($(WIN32),true)
LIB_EXT = .dll
endif

# --------------------------------------------------------------
# Set shared library CLI arg

SHARED = -shared

ifeq ($(MACOS),true)
SHARED = -dynamiclib
endif

# --------------------------------------------------------------

A ext/noisegate-lv2/README.md => ext/noisegate-lv2/README.md +3 -0
@@ 0,0 1,3 @@
# Noise-Gate

A simple noisegate with seperate gate and audio input

A ext/noisegate-lv2/circular_buffer.c => ext/noisegate-lv2/circular_buffer.c +165 -0
@@ 0,0 1,165 @@
/*
  ==============================================================================

 * VEJA NoiseGate
 * Copyright (C) 2021 Jan Janssen <jan@moddevices.com>
 *
 * Permission to use, copy, modify, and/or distribute this software for any purpose with
 * or without fee is hereby granted, provided that the above copyright notice and this
 * permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
 * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

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

#include "circular_buffer.h"
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

void ringbuffer_clear(ringbuffer_t *buffer, uint32_t size)
{
    buffer->S=size;

    uint32_t q = 0;
    for ( q = 0; q < size; q++)
    {
        buffer->m_buffer[q] = 0.0f;
    }

    buffer->m_size = 0;
    buffer->m_front = 0;
    buffer->m_back  = buffer->S - 1;
    buffer->power = 0.0f;
}

void ringbuffer_push(ringbuffer_t *buffer)
{
    buffer->m_back = (buffer->m_back + 1) % buffer->S;

    if(buffer->m_size == buffer->S)
    {
        buffer->m_front = (buffer->m_front + 1) % buffer->S;
    }
    else
    {
        buffer->m_size++;
    }
}
    
void ringbuffer_push_sample(ringbuffer_t *buffer, const float x)
{
    ringbuffer_push(buffer);
    buffer->m_buffer[buffer->m_back] = x;
}
    
void ringbuffer_pop(ringbuffer_t *buffer)
{
    if(buffer->m_size > 0 ) 
    {
        buffer->m_size--;
        buffer->m_front = (buffer->m_front + 1) % buffer->S;
    }
}
    
void ringbuffer_back_erase(ringbuffer_t *buffer, const uint32_t n)
{
    if(n >= buffer->m_size)
    {
        ringbuffer_clear(buffer, buffer->S);
    }
    else 
    {
        buffer->m_size -= n;
        buffer->m_back = (buffer->m_front + buffer->m_size - 1) % buffer->S;
    }
}
    
void ringbuffer_front_erase(ringbuffer_t *buffer, const uint32_t n)
{
    if(n >= buffer->m_size)
    {
        ringbuffer_clear(buffer, buffer->S);
    }
    else 
    {
        buffer->m_size -= n;
        buffer->m_front = (buffer->m_front + n) % buffer->S;
    }
}

int ringbuffer_peek_index(ringbuffer_t *buffer)
{
	uint32_t peek_index = 0;
	float peek_value = 0;
	
	uint32_t i = 0;
	for (i = 0; i < buffer->S; i++)
	{
		if (peek_value < buffer->m_buffer[i])
		{
			peek_value = buffer->m_buffer[i];
			peek_index = i;
		}
	}

	return peek_index;
}

float ringbuffer_push_and_calculate_power(ringbuffer_t *buffer, const float input)
{
    float pow = sqrt(input * input) * (1.0f / buffer->S);

    if (buffer->m_size < buffer->S)
    {
        //remove old sample and add new one to windowPower
        buffer->power += pow;
        ringbuffer_push_sample(buffer, pow);
    }
    else
    {
        //remove old sample and add new one to windowPower
        buffer->power += pow - ringbuffer_front(buffer);
        ringbuffer_pop(buffer);
        ringbuffer_push_sample(buffer, pow);
    }

    return buffer->power;
}

float ringbuffer_front(ringbuffer_t *buffer)
{ 
	return buffer->m_buffer[buffer->m_front]; 
}

float ringbuffer_back(ringbuffer_t *buffer)
{ 
	return buffer->m_buffer[buffer->m_back]; 
}

float ringbuffer_get_val(ringbuffer_t *buffer, uint32_t index)
{ 
	return buffer->m_buffer[index]; 
}

int ringbuffer_empty(ringbuffer_t *buffer)
{ 
	return buffer->m_size == 0; 
}

int ringbuffer_full(ringbuffer_t *buffer)
{ 
	return buffer->m_size == buffer->S; 
}

float * ringbuffer_get_first_pointer(ringbuffer_t *buffer)
{
    return &buffer->m_buffer[buffer->m_back];
}
\ No newline at end of file

A ext/noisegate-lv2/circular_buffer.h => ext/noisegate-lv2/circular_buffer.h +52 -0
@@ 0,0 1,52 @@
/*
  ==============================================================================

 * VEJA NoiseGate
 * Copyright (C) 2021 Jan Janssen <jan@moddevices.com>
 *
 * Permission to use, copy, modify, and/or distribute this software for any purpose with
 * or without fee is hereby granted, provided that the above copyright notice and this
 * permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
 * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

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

#ifndef CIRCULAR_BUFFER_H
#define CIRCULAR_BUFFER_H

#include <stdint.h>

#define MAX_BUFFER_SIZE 128

typedef struct RINGBUFFER_T {
	uint32_t S;
	float m_buffer[MAX_BUFFER_SIZE];
	uint32_t m_size;
	uint32_t m_front;
	uint32_t m_back;
	float power;
} ringbuffer_t;

void ringbuffer_clear(ringbuffer_t *buffer, uint32_t size);
void ringbuffer_push(ringbuffer_t *buffer);
void ringbuffer_push_sample(ringbuffer_t *buffer, const float x);
void ringbuffer_pop(ringbuffer_t *buffer);
void ringbuffer_back_erase(ringbuffer_t *buffer, const uint32_t n);
void ringbuffer_front_erase(ringbuffer_t *buffer, const uint32_t n);
int ringbuffer_peek_index(ringbuffer_t *buffer);
float ringbuffer_push_and_calculate_power(ringbuffer_t *buffer, const float input);
float ringbuffer_front(ringbuffer_t *buffer);
float ringbuffer_back(ringbuffer_t *buffer);
float ringbuffer_get_val(ringbuffer_t *buffer, uint32_t index);
int ringbuffer_empty(ringbuffer_t *buffer);
int ringbuffer_full(ringbuffer_t *buffer);
float * ringbuffer_get_first_pointer(ringbuffer_t *buffer);

#endif // __RINGBUFFER_H__

A ext/noisegate-lv2/gate_core.c => ext/noisegate-lv2/gate_core.c +137 -0
@@ 0,0 1,137 @@
/*
  ==============================================================================

 * VEJA NoiseGate
 * Copyright (C) 2021 Jan Janssen <jan@moddevices.com>
 *
 * Permission to use, copy, modify, and/or distribute this software for any purpose with
 * or without fee is hereby granted, provided that the above copyright notice and this
 * permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
 * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

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

#include "gate_core.h"
#include "circular_buffer.h"
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <math.h>

/*******************************************************************************
								global functions
*******************************************************************************/

void Gate_Init(gate_t *gate)
{
    gate->_alpha = 1.0f;
    gate->_rmsValue = 0.0f;
    gate->_keyValue = 0.0f;
    gate->_upperThreshold = 0.0f;
    gate->_lowerThreshold = 0.0f;
    gate->_attackTime = 0;
    gate->_decayTime = 0;
    gate->_holdTime = 0;
    gate->_attackCounter = 0;
    gate->_decayCounter = 0;
    gate->_holdCounter = 0;
    gate->_currentState = IDLE;
    gate->_tau = 0;

    ringbuffer_clear(&gate->window, MAX_BUFFER_SIZE);
}

void Gate_UpdateParameters(gate_t *gate, const uint32_t sampleRate, const uint32_t attack, const uint32_t hold,
                            const uint32_t decay, const uint32_t alpha, const float upperThreshold,
                            const float lowerThreshold)
{
    gate->_tau = sampleRate * 0.001f; //sample time in ms

    gate->_upperThreshold = powf(10.0f, (upperThreshold / 20.0f)); // dB to level
    gate->_lowerThreshold = powf(10.0f, (lowerThreshold / 20.0f));
    gate->_attackTime = attack * gate->_tau;
    gate->_decayTime = decay * gate->_tau;
    gate->_holdTime = hold * gate->_tau;
    gate->_alpha = alpha;
}

float Gate_ApplyGate(gate_t *gate, const float input, const float key)
{
    //get new keyValue
    gate->_keyValue = ringbuffer_push_and_calculate_power(&gate->window, key);

    switch (gate->_currentState)
    {
        case IDLE:
            gate->_rmsValue = sqrt(gate->_keyValue * gate->_keyValue) * 0.707106781187;
            if (gate->_rmsValue > gate->_upperThreshold)
            {
                if (gate->_attackCounter > gate->_attackTime)
                {
                    gate->_currentState = HOLD;
                    gate->_holdCounter = 0;
                    gate->_attackCounter = 0;
                    return input;
                }
                else
                {
                    gate->_attackCounter++;
                    if (gate->_attackCounter != 0)
                        return (input * powf((float)gate->_attackCounter, 2.0f) / powf((float)gate->_attackTime, 2.0f));
                    else
                        return 0.0f;
                }
            }
            else
                return 0.0f;
        break;

        case HOLD:
            gate->_rmsValue = sqrt(gate->_keyValue * gate->_keyValue) * 0.707106781187;
            if (gate->_rmsValue > gate->_lowerThreshold)
                gate->_holdCounter = 0;
            else if (gate->_holdCounter < gate->_holdTime)
                gate->_holdCounter++;
            else if (gate->_holdCounter >= gate->_holdTime)
            {
                gate->_currentState = DECAY;
                gate->_decayCounter = 0;
            }

            return input;
        break;

        case DECAY:
            if (gate->_decayCounter > gate->_decayTime)
            {
                gate->_currentState = IDLE;
                return 0.0f;
            }
            else
            {
                float dif = (float)gate->_decayCounter - (float)gate->_decayTime;
                if (gate->_decayCounter != 0)
                {
                    gate->_decayCounter++;
                    return input * powf(dif, 2.0f) / powf((float)gate->_decayTime, 2.0f);
                }
                else
                {
                    gate->_decayCounter++;
                    return input;
                }
            }
        break;
    }

    //ERROR
    return 0;
}

A ext/noisegate-lv2/gate_core.h => ext/noisegate-lv2/gate_core.h +60 -0
@@ 0,0 1,60 @@
/*
  ==============================================================================

 * VEJA NoiseGate
 * Copyright (C) 2021 Jan Janssen <jan@moddevices.com>
 *
 * Permission to use, copy, modify, and/or distribute this software for any purpose with
 * or without fee is hereby granted, provided that the above copyright notice and this
 * permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
 * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

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

#ifndef GATE_CORE_H_INCLUDED
#define GATE_CORE_H_INCLUDED

#include <stdint.h> 
#include "circular_buffer.h"

typedef enum {
    IDLE,
    HOLD,
    DECAY
} gate_state_t;

typedef struct GATE_T {
    float _alpha;
    float _rmsValue, _keyValue, _upperThreshold, _lowerThreshold;
    uint32_t _attackTime, _decayTime, _holdTime;
    uint32_t _attackCounter, _decayCounter, _holdCounter;
    uint32_t _currentState;
    uint32_t _tau;
    
    gate_state_t state;

    ringbuffer_t window;
} gate_t;

/// <summary>This method called to initialize the Gate</summary>
void Gate_Init(gate_t *gate);

/// <summary>This method called to apply the Gate to the input sample</summary>
/// <param name="input">Holds input sample</param> 
/// <param name="output">Holds the address where the output should be written to</param> 
float Gate_ApplyGate(gate_t *gate, const float input, const float key);
                
/// <summary>This method called to set the length of the window</summary>
/// <param name="length">Holds the value that determines the window length</param>  
void Gate_UpdateParameters(gate_t *gate, const uint32_t sampleRate, const uint32_t attack, const uint32_t hold,
                      const uint32_t decay, const uint32_t alpha, const float upperThreshold,
                      const float lowerThreshold);

#endif //GATE_CORE_H_INCLUDED

A ext/noisegate-lv2/meson.build => ext/noisegate-lv2/meson.build +74 -0
@@ 0,0 1,74 @@
# Copyright (C) 2021 Alexandros Theodotou <alex at zrythm dot org>
#
# This file is part of Zrythm
#
# Zrythm is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Zrythm is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with Zrythm.  If not, see <https://www.gnu.org/licenses/>.

noisegate_uri = 'https://lv2.zrythm.org/VeJaPlugins/NoiseGate'

noisegate_cflags = [
  '-Wall', '-Wextra', '-pipe',
  '-Wno-unused-parameter', '-O3', '-g',
  '-DPLUGIN_URI="' + noisegate_uri + '"',
  '-DNDEBUG', '-ffast-math',
  '-fvisibility=hidden',
  '-fvisibility-inlines-hidden' ]

if not os_windows
  noisegate_cflags += [ '-fPIC', '-DPIC' ]
endif

noisegate_linkargs = []
if os_darwin
  noisegate_cflags += [ '-dynamiclib' ]
  noisegate_linkargs += [
    '-Wl,-dead_strip', '-Wl,-dead_strip_dylibs',
    '-Wl,--no-undefined' ]
else
  noisegate_cflags += [ '-shared' ]
  noisegate_linkargs += [
    '-Wl,-O1', '-Wl,--as-needed', '-Wl,--strip-all' ]
endif

noisegate_lv2_install_dir = zrythmdatadir / 'lv2/noisegate.lv2'
noisegate_so = shared_library (
  'noisegate',
  'circular_buffer.c',
  'noisegate.c',
  'gate_core.c',
  dependencies: libm,
  name_prefix: '',
  gnu_symbol_visibility: 'hidden',
  c_args: noisegate_cflags,
  link_args: noisegate_linkargs,
  install: true,
  install_dir: noisegate_lv2_install_dir,
  )

noisegate_lv2_config = configuration_data ()
noisegate_lv2_config.set (
  'PLUGIN_URI', noisegate_uri)

noisegate_lv2_manifest_ttl = configure_file (
  input: 'noisegate.lv2/manifest.ttl',
  output: 'manifest.ttl',
  configuration: noisegate_lv2_config,
  install: true,
  install_dir: noisegate_lv2_install_dir)
noisegate_lv2_ttl = configure_file (
  input: 'noisegate.lv2/noisegate.ttl',
  output: 'noisegate.ttl',
  configuration: noisegate_lv2_config,
  install: true,
  install_dir: noisegate_lv2_install_dir)

A ext/noisegate-lv2/noisegate.c => ext/noisegate-lv2/noisegate.c +163 -0
@@ 0,0 1,163 @@
/*
 * VEJA NoiseGate
 * Copyright (C) 2021 Jan Janssen <jan@moddevices.com>
 *
 * Permission to use, copy, modify, and/or distribute this software for any purpose with
 * or without fee is hereby granted, provided that the above copyright notice and this
 * permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
 * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdbool.h>
#include "lv2/lv2plug.in/ns/lv2core/lv2.h"

#include "gate_core.h"

/**********************************************************************************************************************************************************/

typedef enum {
    PLUGIN_INPUT,
    PLUGIN_KEY,
    PLUGIN_OUTPUT,
    PLUGIN_THRESHOLD,
    PLUGIN_ATTACK,
    PLUGIN_HOLD,
    PLUGIN_DECAY
}PortIndex;

/**********************************************************************************************************************************************************/

typedef struct{

    //ports
    float*            input;
    float*              key;
    float*           output;
    float*        threshold;
    float*           attack;
    float*             hold;
    float*            decay;

    uint32_t     sampleRate;

    gate_t noisegate;

} NoiseGate;

/**********************************************************************************************************************************************************/
//                                                                 local functions                                                                        //
/**********************************************************************************************************************************************************/

/**********************************************************************************************************************************************************/
static LV2_Handle
instantiate(const LV2_Descriptor*   descriptor,
double                              samplerate,
const char*                         bundle_path,
const LV2_Feature* const* features)
{
    NoiseGate* self = (NoiseGate*)malloc(sizeof(NoiseGate));

    self->sampleRate = (uint32_t)samplerate;

    Gate_Init(&self->noisegate);

    return (LV2_Handle)self;
}
/**********************************************************************************************************************************************************/
static void connect_port(LV2_Handle instance, uint32_t port, void *data)
{
    NoiseGate* self = (NoiseGate*)instance;

    switch (port)
    {
        case PLUGIN_INPUT:
            self->input = (float*) data;
            break;
        case PLUGIN_KEY:
            self->key = (float*) data;
            break;
        case PLUGIN_OUTPUT:
            self->output = (float*) data;
            break;
        case PLUGIN_THRESHOLD:
            self->threshold = (float*) data;
            break;
        case PLUGIN_ATTACK:
            self->attack = (float*) data;
            break;
        case PLUGIN_HOLD:
            self->hold = (float*) data;
            break;
        case PLUGIN_DECAY:
            self->decay = (float*) data;
            break;
    }
}
/**********************************************************************************************************************************************************/
void activate(LV2_Handle instance)
{
    // TODO: include the activate function code here
}

/**********************************************************************************************************************************************************/
void run(LV2_Handle instance, uint32_t n_samples)
{
    NoiseGate* self = (NoiseGate*)instance;

    //update parameters
    //lower threshold is 20dB lower
    Gate_UpdateParameters(&self->noisegate, (uint32_t)self->sampleRate,
                         (uint32_t)*self->attack, (uint32_t)*self->hold,
                         (uint32_t)*self->decay, 1, *self->threshold, *self->threshold - 20.0f);


    for (uint32_t i = 0; i < n_samples; ++i)
    {
        self->output[i] = Gate_ApplyGate(&self->noisegate, self->input[i], self->key[i]);
    }
}

/**********************************************************************************************************************************************************/
void deactivate(LV2_Handle instance)
{
    // TODO: include the deactivate function code here
}
/**********************************************************************************************************************************************************/
void cleanup(LV2_Handle instance)
{
    free(instance);
}
/**********************************************************************************************************************************************************/
const void* extension_data(const char* uri)
{
    return NULL;
}
/**********************************************************************************************************************************************************/
static const LV2_Descriptor Descriptor = {
    PLUGIN_URI,
    instantiate,
    connect_port,
    activate,
    run,
    deactivate,
    cleanup,
    extension_data
};
/**********************************************************************************************************************************************************/
LV2_SYMBOL_EXPORT
const LV2_Descriptor* lv2_descriptor(uint32_t index)
{
    if (index == 0) return &Descriptor;
    else return NULL;
}
/**********************************************************************************************************************************************************/

A ext/noisegate-lv2/noisegate.lv2/manifest.ttl => ext/noisegate-lv2/noisegate.lv2/manifest.ttl +9 -0
@@ 0,0 1,9 @@
@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#> .

<@PLUGIN_URI@>
	a lv2:Plugin ;
    lv2:binary <noisegate.so> ;
    rdfs:seeAlso <noisegate.ttl> ;
	lv2:optionalFeature lv2:hardRTCapable .

A ext/noisegate-lv2/noisegate.lv2/noisegate.ttl => ext/noisegate-lv2/noisegate.lv2/noisegate.ttl +104 -0
@@ 0,0 1,104 @@
@prefix lv2:  <http://lv2plug.in/ns/lv2core#>.
@prefix doap: <http://usefulinc.com/ns/doap#>.
@prefix epp: <http://lv2plug.in/ns/ext/port-props#>.
@prefix foaf: <http://xmlns.com/foaf/0.1/>.
@prefix mod: <http://moddevices.com/ns/modgui#>.
@prefix rdf:  <http://www.w3.org/1999/02/22-rdf-syntax-ns#>.
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>.
@prefix pset: <http://lv2plug.in/ns/ext/presets#>.
@prefix units: <http://lv2plug.in/ns/extensions/units#>.

<@PLUGIN_URI@>
a lv2:Plugin, lv2:DynamicsPlugin;

doap:name "[Z] NoiseGate";

doap:developer [
    foaf:name "VeJa plugins";
    foaf:homepage <>;
    foaf:mbox <mailto:jan@moddevices.com>;
    ];

doap:maintainer [
    foaf:name "VeJa plugins";
    foaf:homepage <http://moddevices.com>;
    foaf:mbox <mailto:jan@moddevices.com>;
    ];

    lv2:minorVersion 1;
    lv2:microVersion 0;

rdfs:comment """

Veja NoiseGate designed for MOD Devices

Adapted for Zrythm by Alexandros Theodotou

""";

lv2:port
[
    a lv2:AudioPort, lv2:InputPort;
    lv2:index 0;
    lv2:symbol "Input";
    lv2:name "Input";
    lv2:shortname "Input";
],
[
    a lv2:AudioPort, lv2:InputPort;
    lv2:index 1;
    lv2:symbol "Key";
    lv2:name "Key";
    lv2:shortname "Key";
],
[
    a lv2:AudioPort, lv2:OutputPort;
    lv2:index 2;
    lv2:symbol "Output";
    lv2:name "Output";
    lv2:shortname "Output";
],
[
    a lv2:ControlPort, lv2:InputPort;
    lv2:index 3;
    lv2:symbol "Threshold";
    lv2:name "Threshold";
    lv2:shortname "Threshold";
    lv2:default -60;
    lv2:minimum -80;
    lv2:maximum -10;
    units:unit   units:db
],
[
    a lv2:ControlPort, lv2:InputPort;
    lv2:index 4;
    lv2:symbol "Attack";
    lv2:name "Attack";
    lv2:shortname "Attack";
    lv2:default 10;
    lv2:minimum 1;
    lv2:maximum 100;
    units:unit   units:ms
],
[
    a lv2:ControlPort, lv2:InputPort;
    lv2:index 5;
    lv2:symbol "Hold";
    lv2:name "Hold";
    lv2:shortname "Hold";
    lv2:default 10;
    lv2:minimum 1;
    lv2:maximum 200;
    units:unit   units:ms
],
[
    a lv2:ControlPort, lv2:InputPort;
    lv2:index 6;
    lv2:symbol "Decay";
    lv2:name "Decay";
    lv2:shortname "Decay";
    lv2:default 10;
    lv2:minimum 1;
    lv2:maximum 200;
    units:unit   units:ms
].