bundle a-comp

This commit is contained in:
Robin Gareus 2016-07-03 03:21:44 +02:00
parent 9c29e99345
commit 94e5060168
7 changed files with 743 additions and 0 deletions

View File

@ -0,0 +1,260 @@
/* a-comp
* Copyright (C) 2016 Damien Zammit <damien@zamaudio.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*/
#include <math.h>
#include <stdlib.h>
#include "lv2/lv2plug.in/ns/lv2core/lv2.h"
#define ACOMP_URI "urn:ardour:a-comp"
typedef enum {
ACOMP_INPUT0 = 0,
ACOMP_INPUT1,
ACOMP_OUTPUT,
ACOMP_ATTACK,
ACOMP_RELEASE,
ACOMP_KNEE,
ACOMP_RATIO,
ACOMP_THRESHOLD,
ACOMP_MAKEUP,
ACOMP_GAINR,
ACOMP_OUTLEVEL,
ACOMP_SIDECHAIN,
} PortIndex;
typedef struct {
float* input0;
float* input1;
float* output;
float* attack;
float* release;
float* knee;
float* ratio;
float* thresdb;
float* makeup;
float* gainr;
float* outlevel;
float* sidechain;
float srate;
float old_yl;
float old_y1;
float old_yg;
} AComp;
static LV2_Handle
instantiate(const LV2_Descriptor* descriptor,
double rate,
const char* bundle_path,
const LV2_Feature* const* features)
{
AComp* acomp = (AComp*)malloc(sizeof(AComp));
acomp->srate = rate;
acomp->old_yl=acomp->old_y1=acomp->old_yg=0.f;
return (LV2_Handle)acomp;
}
static void
connect_port(LV2_Handle instance,
uint32_t port,
void* data)
{
AComp* acomp = (AComp*)instance;
switch ((PortIndex)port) {
case ACOMP_ATTACK:
acomp->attack = (float*)data;
break;
case ACOMP_RELEASE:
acomp->release = (float*)data;
break;
case ACOMP_KNEE:
acomp->knee = (float*)data;
break;
case ACOMP_RATIO:
acomp->ratio = (float*)data;
break;
case ACOMP_THRESHOLD:
acomp->thresdb = (float*)data;
break;
case ACOMP_MAKEUP:
acomp->makeup = (float*)data;
break;
case ACOMP_GAINR:
acomp->gainr = (float*)data;
break;
case ACOMP_OUTLEVEL:
acomp->outlevel = (float*)data;
break;
case ACOMP_SIDECHAIN:
acomp->sidechain = (float*)data;
break;
case ACOMP_INPUT0:
acomp->input0 = (float*)data;
break;
case ACOMP_INPUT1:
acomp->input1 = (float*)data;
break;
case ACOMP_OUTPUT:
acomp->output = (float*)data;
break;
}
}
// Force already-denormal float value to zero
static inline float
sanitize_denormal(float value) {
if (!isnormal(value)) {
value = 0.f;
}
return value;
}
static inline float
from_dB(float gdb) {
return (exp(gdb/20.f*log(10.f)));
}
static inline float
to_dB(float g) {
return (20.f*log10(g));
}
static void
activate(LV2_Handle instance)
{
AComp* acomp = (AComp*)instance;
*(acomp->gainr) = 0.0f;
*(acomp->outlevel) = -45.0f;
acomp->old_yl=acomp->old_y1=acomp->old_yg=0.f;
}
static void
run(LV2_Handle instance, uint32_t n_samples)
{
AComp* acomp = (AComp*)instance;
const float* const input0 = acomp->input0;
const float* const input1 = acomp->input1;
float* const output = acomp->output;
float srate = acomp->srate;
float width = (6.f * *(acomp->knee)) + 0.01;
float cdb=0.f;
float attack_coeff = exp(-1000.f/(*(acomp->attack) * srate));
float release_coeff = exp(-1000.f/(*(acomp->release) * srate));
float max = 0.f;
float lgaininp = 0.f;
float Lgain = 1.f;
float Lxg, Lxl, Lyg, Lyl, Ly1;
int usesidechain = (*(acomp->sidechain) < 0.5) ? 0 : 1;
uint32_t i;
float ingain;
float in0;
float in1;
float ratio = *(acomp->ratio);
float thresdb = *(acomp->thresdb);
for (i = 0; i < n_samples; i++) {
in0 = input0[i];
in1 = input1[i];
ingain = usesidechain ? in1 : in0;
Lyg = 0.f;
Lxg = (ingain==0.f) ? -160.f : to_dB(fabs(ingain));
Lxg = sanitize_denormal(Lxg);
Lyg = Lxg + (1.f/ratio-1.f)*(Lxg-thresdb+width/2.f)*(Lxg-thresdb+width/2.f)/(2.f*width);
if (2.f*(Lxg-thresdb) < -width) {
Lyg = Lxg;
} else {
Lyg = thresdb + (Lxg-thresdb)/ratio;
Lyg = sanitize_denormal(Lyg);
}
Lxl = Lxg - Lyg;
acomp->old_y1 = sanitize_denormal(acomp->old_y1);
acomp->old_yl = sanitize_denormal(acomp->old_yl);
Ly1 = fmaxf(Lxl, release_coeff * acomp->old_y1+(1.f-release_coeff)*Lxl);
Lyl = attack_coeff * acomp->old_yl+(1.f-attack_coeff)*Ly1;
Ly1 = sanitize_denormal(Ly1);
Lyl = sanitize_denormal(Lyl);
cdb = -Lyl;
Lgain = from_dB(cdb);
*(acomp->gainr) = Lyl;
lgaininp = in0 * Lgain;
output[i] = lgaininp * from_dB(*(acomp->makeup));
max = (fabsf(output[i]) > max) ? fabsf(output[i]) : sanitize_denormal(max);
acomp->old_yl = Lyl;
acomp->old_y1 = Ly1;
acomp->old_yg = Lyg;
}
*(acomp->outlevel) = (max == 0.f) ? -45.f : to_dB(max);
}
static void
deactivate(LV2_Handle instance)
{
}
static void
cleanup(LV2_Handle instance)
{
free(instance);
}
static const void*
extension_data(const char* uri)
{
return NULL;
}
static const LV2_Descriptor descriptor = {
ACOMP_URI,
instantiate,
connect_port,
activate,
run,
deactivate,
cleanup,
extension_data
};
LV2_SYMBOL_EXPORT
const LV2_Descriptor*
lv2_descriptor(uint32_t index)
{
switch (index) {
case 0:
return &descriptor;
default:
return NULL;
}
}

View File

@ -0,0 +1,153 @@
@prefix doap: <http://usefulinc.com/ns/doap#> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix mod: <http://moddevices.com/ns/mod#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix rsz: <http://lv2plug.in/ns/ext/resize-port#> .
@prefix ui: <http://lv2plug.in/ns/extensions/ui#> .
@prefix unit: <http://lv2plug.in/ns/extensions/units#> .
<urn:ardour:a-comp>
a lv2:Plugin , doap:Project;
lv2:optionalFeature <http://lv2plug.in/ns/lv2core#hardRTCapable> ,
<http://lv2plug.in/ns/ext/buf-size#boundedBlockLength> ;
lv2:requiredFeature <http://lv2plug.in/ns/ext/options#options> ,
<http://lv2plug.in/ns/ext/urid#map> ;
lv2:port [
a lv2:InputPort, lv2:AudioPort ;
lv2:index 0 ;
lv2:symbol "lv2_audio_in_1" ;
lv2:name "Audio Input 1" ;
] ,
[
a lv2:InputPort, lv2:AudioPort ;
lv2:index 1 ;
lv2:symbol "lv2_sidechain_in" ;
lv2:name "Sidechain Input" ;
lv2:portProperty lv2:isSideChain;
] ;
lv2:port [
a lv2:OutputPort, lv2:AudioPort ;
lv2:index 2 ;
lv2:symbol "lv2_audio_out_1" ;
lv2:name "Audio Output 1" ;
] ;
lv2:port [
a lv2:InputPort, lv2:ControlPort ;
lv2:index 3 ;
lv2:name "Attack" ;
lv2:symbol "att" ;
lv2:default 10.000000 ;
lv2:minimum 0.100000 ;
lv2:maximum 100.000000 ;
unit:unit unit:ms ;
] ,
[
a lv2:InputPort, lv2:ControlPort ;
lv2:index 4 ;
lv2:name "Release" ;
lv2:symbol "rel" ;
lv2:default 80.000000 ;
lv2:minimum 1.000000 ;
lv2:maximum 500.000000 ;
unit:unit unit:ms ;
] ,
[
a lv2:InputPort, lv2:ControlPort ;
lv2:index 5 ;
lv2:name "Knee" ;
lv2:symbol "kn" ;
lv2:default 0.000000 ;
lv2:minimum 0.000000 ;
lv2:maximum 8.000000 ;
unit:unit unit:db ;
] ,
[
a lv2:InputPort, lv2:ControlPort ;
lv2:index 6 ;
lv2:name "Ratio" ;
lv2:symbol "rat" ;
lv2:default 4.000000 ;
lv2:minimum 1.000000 ;
lv2:maximum 20.000000 ;
unit:unit [
rdfs:label " " ;
unit:symbol " " ;
unit:render "%f " ;
] ;
] ,
[
a lv2:InputPort, lv2:ControlPort ;
lv2:index 7 ;
lv2:name "Threshold" ;
lv2:symbol "thr" ;
lv2:default 0.000000 ;
lv2:minimum -80.000000 ;
lv2:maximum 0.000000 ;
unit:unit unit:db ;
] ,
[
a lv2:InputPort, lv2:ControlPort ;
lv2:index 8 ;
lv2:name "Makeup" ;
lv2:symbol "mak" ;
lv2:default 0.000000 ;
lv2:minimum 0.000000 ;
lv2:maximum 30.000000 ;
unit:unit unit:db ;
] ,
[
a lv2:OutputPort, lv2:ControlPort ;
lv2:index 9 ;
lv2:name "Gain Reduction" ;
lv2:symbol "gr" ;
lv2:default 0.000000 ;
lv2:minimum 0.000000 ;
lv2:maximum 20.000000 ;
unit:unit unit:db ;
] ,
[
a lv2:OutputPort, lv2:ControlPort ;
lv2:index 10 ;
lv2:name "Output Level" ;
lv2:symbol "outlevel" ;
lv2:default -45.000000 ;
lv2:minimum -45.000000 ;
lv2:maximum 20.000000 ;
unit:unit unit:db ;
] ,
[
a lv2:InputPort, lv2:ControlPort ;
lv2:index 11 ;
lv2:name "Sidechain" ;
lv2:symbol "sidech" ;
lv2:default 0.000000 ;
lv2:minimum 0.000000 ;
lv2:maximum 1.000000 ;
lv2:portProperty lv2:toggled ;
] ;
rdfs:comment """
A powerful mono compressor.
""" ;
mod:brand "Ardour" ;
mod:label "a-comp" ;
doap:name "a-comp" ;
doap:license "GPL v2+" ;
# ui:ui <urn:ardour:a-comp#ui>;
doap:maintainer [
foaf:name "Damien Zammit" ;
foaf:homepage <http://www.zamaudio.com> ;
] ;
lv2:microVersion 0 ;
lv2:minorVersion 1 .

View File

@ -0,0 +1,32 @@
@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#> .
@prefix ui: <http://lv2plug.in/ns/extensions/ui#> .
<urn:ardour:a-comp>
a lv2:Plugin ;
lv2:binary <a-comp@LIB_EXT@> ;
rdfs:seeAlso <a-comp.ttl> .
#<urn:ardour:a-comp#ui>
# a ui:GtkUI ;
# ui:binary <a-comp-ui@LIB_EXT@> ;
# rdfs:seeAlso <a-comp.ttl> .
<urn:ardour:a-comp#preset001>
a pset:Preset ;
lv2:appliesTo <urn:ardour:a-comp> ;
rdfs:label "Zero" ;
rdfs:seeAlso <presets.ttl> .
<urn:ardour:a-comp#preset002>
a pset:Preset ;
lv2:appliesTo <urn:ardour:a-comp> ;
rdfs:label "PoppySnare" ;
rdfs:seeAlso <presets.ttl> .
<urn:ardour:a-comp#preset003>
a pset:Preset ;
lv2:appliesTo <urn:ardour:a-comp> ;
rdfs:label "VocalLeveller" ;
rdfs:seeAlso <presets.ttl> .

View File

@ -0,0 +1,118 @@
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix pset: <http://lv2plug.in/ns/ext/presets#> .
<urn:ardour:a-comp#preset001>
lv2:port [
lv2:symbol "att" ;
pset:value 10.000000 ;
] ,
[
lv2:symbol "rel" ;
pset:value 80.000000 ;
] ,
[
lv2:symbol "kn" ;
pset:value 0.000000 ;
] ,
[
lv2:symbol "rat" ;
pset:value 4.000000 ;
] ,
[
lv2:symbol "thr" ;
pset:value 0.000000 ;
] ,
[
lv2:symbol "mak" ;
pset:value 0.000000 ;
] ,
[
lv2:symbol "gr" ;
pset:value 0.000000 ;
] ,
[
lv2:symbol "outlevel" ;
pset:value -45.000000 ;
] ,
[
lv2:symbol "sidech" ;
pset:value 0.000000 ;
] .
<urn:ardour:a-comp#preset002>
lv2:port [
lv2:symbol "att" ;
pset:value 10.000000 ;
] ,
[
lv2:symbol "rel" ;
pset:value 10.000000 ;
] ,
[
lv2:symbol "kn" ;
pset:value 1.000000 ;
] ,
[
lv2:symbol "rat" ;
pset:value 5.000000 ;
] ,
[
lv2:symbol "thr" ;
pset:value -18.000000 ;
] ,
[
lv2:symbol "mak" ;
pset:value 6.000000 ;
] ,
[
lv2:symbol "gr" ;
pset:value 0.000000 ;
] ,
[
lv2:symbol "outlevel" ;
pset:value -45.000000 ;
] ,
[
lv2:symbol "sidech" ;
pset:value 0.000000 ;
] .
<urn:ardour:a-comp#preset003>
lv2:port [
lv2:symbol "att" ;
pset:value 50.000000 ;
] ,
[
lv2:symbol "rel" ;
pset:value 400.000000 ;
] ,
[
lv2:symbol "kn" ;
pset:value 8.000000 ;
] ,
[
lv2:symbol "rat" ;
pset:value 5.000000 ;
] ,
[
lv2:symbol "thr" ;
pset:value -16.000000 ;
] ,
[
lv2:symbol "mak" ;
pset:value 9.000000 ;
] ,
[
lv2:symbol "gr" ;
pset:value 0.000000 ;
] ,
[
lv2:symbol "outlevel" ;
pset:value -45.000000 ;
] ,
[
lv2:symbol "sidech" ;
pset:value 0.000000 ;
] .

View File

@ -0,0 +1,119 @@
/* a-comp UI -- test/example
*
* Copyright (C) 2016 Robin Gareus <robin@gareus.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define ACOMP_URI "urn:ardour:a-comp"
#include <stdlib.h>
#include <gtkmm.h>
#include "lv2/lv2plug.in/ns/extensions/ui/ui.h"
using namespace Gtk;
typedef struct {
LV2UI_Write_Function write;
LV2UI_Controller controller;
Box* box;
Label* label;
} ACompUI;
/******************************************************************************
* GUI
*/
static void* setup_ui (ACompUI* ui) {
ui->box = manage (new HBox);
ui->label = manage (new Label ("Hello World"));
ui->box->pack_start (*ui->label, false, false, 4);
return ui->box->gobj ();
}
/******************************************************************************
* LV2 callbacks
*/
static LV2UI_Handle
instantiate (const LV2UI_Descriptor* descriptor,
const char* plugin_uri,
const char* bundle_path,
LV2UI_Write_Function write_function,
LV2UI_Controller controller,
LV2UI_Widget* widget,
const LV2_Feature* const* features)
{
ACompUI* ui = (ACompUI*)calloc (1, sizeof (ACompUI));
ui->write = write_function;
ui->controller = controller;
ui->box = NULL;
*widget = setup_ui (ui);
return ui;
}
static void
cleanup (LV2UI_Handle handle)
{
ACompUI* ui = (ACompUI*)handle;
free (ui);
}
static void
port_event (LV2UI_Handle handle,
uint32_t port_index,
uint32_t buffer_size,
uint32_t format,
const void* buffer)
{
ACompUI* ui = (ACompUI*)handle;
}
/******************************************************************************
* LV2 setup
*/
static const void*
extension_data (const char* uri)
{
return NULL;
}
static const LV2UI_Descriptor descriptor = {
ACOMP_URI "#ui",
instantiate,
cleanup,
port_event,
extension_data
};
LV2_SYMBOL_EXPORT
const LV2UI_Descriptor*
lv2ui_descriptor (uint32_t index)
{
switch (index) {
case 0:
return &descriptor;
default:
return NULL;
}
}

View File

@ -0,0 +1,60 @@
#!/usr/bin/env python
import os
import re
import shutil
import waflib.extras.autowaf as autowaf
import waflib.Options as Options, waflib.Utils as Utils
# Mandatory variables
top = '.'
out = 'build'
def options(opt):
autowaf.set_options(opt)
def configure(conf):
conf.load('compiler_c')
autowaf.configure(conf)
if Options.options.lv2:
autowaf.check_pkg(conf, 'lv2', atleast_version='1.0.0',
uselib_store='LV2_1_0_0')
def build(bld):
bundle = 'a-comp.lv2'
module_pat = re.sub('^lib', '', bld.env.cshlib_PATTERN)
module_ext = module_pat[module_pat.rfind('.'):]
if bld.is_defined ('HAVE_LV2'):
# Build RDF files
for i in ['manifest.ttl', 'a-comp.ttl', 'presets.ttl']:
bld(features = 'subst',
source = i + '.in',
target = '../../LV2/%s/%s' % (bundle, i),
install_path = '${LV2DIR}/%s' % bundle,
chmod = Utils.O644,
LIB_EXT = module_ext)
# Build plugin library
obj = bld(features = 'c cshlib',
source = 'a-comp.c',
name = 'a-comp',
cflags = [ '-fPIC' ],
target = '../../LV2/%s/a-comp' % bundle,
install_path = '${LV2DIR}/%s' % bundle,
use = 'LV2_1_0_0'
)
obj.env.cshlib_PATTERN = module_pat
# Build plugin GUI
obj = bld(features = 'cxx cxxshlib',
source = 'ui.cc',
name = 'a-comp-ui',
cxxflags = [ '-fPIC' ],
target = '../../LV2/%s/a-comp-ui' % bundle,
install_path = '${LV2DIR}/%s' % bundle,
uselib = 'GTKMM GTK',
use = 'LV2_1_0_0'
)
obj.env.cxxshlib_PATTERN = module_pat
# vi:set ts=4 sw=4 et:

View File

@ -219,6 +219,7 @@ children = [
'libs/audiographer',
'libs/canvas',
'libs/plugins/reasonablesynth.lv2',
'libs/plugins/a-comp.lv2',
'gtk2_ardour',
'export',
'midi_maps',