From bf08c9e039b4d8b3b981410fabe9bd4c6b98889a Mon Sep 17 00:00:00 2001 From: Alexandros Theodotou Date: Wed, 28 Jul 2021 17:12:59 +0100 Subject: [PATCH] add bundled noisegate plugin --- ext/meson.build | 1 + ext/noisegate-lv2/LICENSE | 13 ++ ext/noisegate-lv2/Makefile | 44 +++++ ext/noisegate-lv2/Makefile.mk | 79 +++++++++ ext/noisegate-lv2/README.md | 3 + ext/noisegate-lv2/circular_buffer.c | 165 ++++++++++++++++++ ext/noisegate-lv2/circular_buffer.h | 52 ++++++ ext/noisegate-lv2/gate_core.c | 137 +++++++++++++++ ext/noisegate-lv2/gate_core.h | 60 +++++++ ext/noisegate-lv2/meson.build | 74 ++++++++ ext/noisegate-lv2/noisegate.c | 163 +++++++++++++++++ ext/noisegate-lv2/noisegate.lv2/manifest.ttl | 9 + ext/noisegate-lv2/noisegate.lv2/noisegate.ttl | 104 +++++++++++ 13 files changed, 904 insertions(+) create mode 100644 ext/noisegate-lv2/LICENSE create mode 100644 ext/noisegate-lv2/Makefile create mode 100644 ext/noisegate-lv2/Makefile.mk create mode 100644 ext/noisegate-lv2/README.md create mode 100644 ext/noisegate-lv2/circular_buffer.c create mode 100644 ext/noisegate-lv2/circular_buffer.h create mode 100644 ext/noisegate-lv2/gate_core.c create mode 100644 ext/noisegate-lv2/gate_core.h create mode 100644 ext/noisegate-lv2/meson.build create mode 100644 ext/noisegate-lv2/noisegate.c create mode 100644 ext/noisegate-lv2/noisegate.lv2/manifest.ttl create mode 100644 ext/noisegate-lv2/noisegate.lv2/noisegate.ttl diff --git a/ext/meson.build b/ext/meson.build index 2029209e4..4562ff7b2 100644 --- a/ext/meson.build +++ b/ext/meson.build @@ -17,6 +17,7 @@ subdir ('midilib') subdir ('nanovg') +subdir ('noisegate-lv2') subdir ('weakjack') subdir ('whereami') subdir ('zix') diff --git a/ext/noisegate-lv2/LICENSE b/ext/noisegate-lv2/LICENSE new file mode 100644 index 000000000..ac9533925 --- /dev/null +++ b/ext/noisegate-lv2/LICENSE @@ -0,0 +1,13 @@ +VEJA NoiseGate +Copyright (C) 2021 Jan Janssen + +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. diff --git a/ext/noisegate-lv2/Makefile b/ext/noisegate-lv2/Makefile new file mode 100644 index 000000000..1feb4451b --- /dev/null +++ b/ext/noisegate-lv2/Makefile @@ -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/ + +# -------------------------------------------------------------- + diff --git a/ext/noisegate-lv2/Makefile.mk b/ext/noisegate-lv2/Makefile.mk new file mode 100644 index 000000000..90216f9b3 --- /dev/null +++ b/ext/noisegate-lv2/Makefile.mk @@ -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 + +# -------------------------------------------------------------- diff --git a/ext/noisegate-lv2/README.md b/ext/noisegate-lv2/README.md new file mode 100644 index 000000000..60ade324f --- /dev/null +++ b/ext/noisegate-lv2/README.md @@ -0,0 +1,3 @@ +# Noise-Gate + +A simple noisegate with seperate gate and audio input diff --git a/ext/noisegate-lv2/circular_buffer.c b/ext/noisegate-lv2/circular_buffer.c new file mode 100644 index 000000000..b1ae4f8e3 --- /dev/null +++ b/ext/noisegate-lv2/circular_buffer.c @@ -0,0 +1,165 @@ +/* + ============================================================================== + + * VEJA NoiseGate + * Copyright (C) 2021 Jan Janssen + * + * 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 +#include +#include +#include + +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 diff --git a/ext/noisegate-lv2/circular_buffer.h b/ext/noisegate-lv2/circular_buffer.h new file mode 100644 index 000000000..6a10dcff7 --- /dev/null +++ b/ext/noisegate-lv2/circular_buffer.h @@ -0,0 +1,52 @@ +/* + ============================================================================== + + * VEJA NoiseGate + * Copyright (C) 2021 Jan Janssen + * + * 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 + +#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__ diff --git a/ext/noisegate-lv2/gate_core.c b/ext/noisegate-lv2/gate_core.c new file mode 100644 index 000000000..aecf05b8c --- /dev/null +++ b/ext/noisegate-lv2/gate_core.c @@ -0,0 +1,137 @@ +/* + ============================================================================== + + * VEJA NoiseGate + * Copyright (C) 2021 Jan Janssen + * + * 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 +#include +#include +#include +#include + +/******************************************************************************* + 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; +} diff --git a/ext/noisegate-lv2/gate_core.h b/ext/noisegate-lv2/gate_core.h new file mode 100644 index 000000000..9f0abcc87 --- /dev/null +++ b/ext/noisegate-lv2/gate_core.h @@ -0,0 +1,60 @@ +/* + ============================================================================== + + * VEJA NoiseGate + * Copyright (C) 2021 Jan Janssen + * + * 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 +#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; + +/// This method called to initialize the Gate +void Gate_Init(gate_t *gate); + +/// This method called to apply the Gate to the input sample +/// Holds input sample +/// Holds the address where the output should be written to +float Gate_ApplyGate(gate_t *gate, const float input, const float key); + +/// This method called to set the length of the window +/// Holds the value that determines the window length +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 diff --git a/ext/noisegate-lv2/meson.build b/ext/noisegate-lv2/meson.build new file mode 100644 index 000000000..63ca09d97 --- /dev/null +++ b/ext/noisegate-lv2/meson.build @@ -0,0 +1,74 @@ +# Copyright (C) 2021 Alexandros Theodotou +# +# 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 . + +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) diff --git a/ext/noisegate-lv2/noisegate.c b/ext/noisegate-lv2/noisegate.c new file mode 100644 index 000000000..9525b4892 --- /dev/null +++ b/ext/noisegate-lv2/noisegate.c @@ -0,0 +1,163 @@ +/* + * VEJA NoiseGate + * Copyright (C) 2021 Jan Janssen + * + * 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 +#include +#include +#include +#include +#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; +} +/**********************************************************************************************************************************************************/ diff --git a/ext/noisegate-lv2/noisegate.lv2/manifest.ttl b/ext/noisegate-lv2/noisegate.lv2/manifest.ttl new file mode 100644 index 000000000..f69deed81 --- /dev/null +++ b/ext/noisegate-lv2/noisegate.lv2/manifest.ttl @@ -0,0 +1,9 @@ +@prefix lv2: . +@prefix rdfs: . +@prefix pset: . + +<@PLUGIN_URI@> + a lv2:Plugin ; + lv2:binary ; + rdfs:seeAlso ; + lv2:optionalFeature lv2:hardRTCapable . diff --git a/ext/noisegate-lv2/noisegate.lv2/noisegate.ttl b/ext/noisegate-lv2/noisegate.lv2/noisegate.ttl new file mode 100644 index 000000000..001c88780 --- /dev/null +++ b/ext/noisegate-lv2/noisegate.lv2/noisegate.ttl @@ -0,0 +1,104 @@ +@prefix lv2: . +@prefix doap: . +@prefix epp: . +@prefix foaf: . +@prefix mod: . +@prefix rdf: . +@prefix rdfs: . +@prefix pset: . +@prefix units: . + +<@PLUGIN_URI@> +a lv2:Plugin, lv2:DynamicsPlugin; + +doap:name "[Z] NoiseGate"; + +doap:developer [ + foaf:name "VeJa plugins"; + foaf:homepage <>; + foaf:mbox ; + ]; + +doap:maintainer [ + foaf:name "VeJa plugins"; + foaf:homepage ; + foaf:mbox ; + ]; + + 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 +]. -- 2.45.2