basic parameter support (LADSPA)

This commit is contained in:
Connor Olding 2014-01-29 19:36:08 -08:00
parent 1006245886
commit 329642ab55
6 changed files with 95 additions and 260 deletions

View file

@ -5,9 +5,9 @@ DISTNAME = crap
VERSION = git
FULLNAME = ${DISTNAME}-${VERSION}
BOTH = crap_eq_const
LADSPA_ONLY = crap_eq crap_noise
VST_ONLY = crap_eq crap_delay_test
BOTH = crap_eq crap_eq_const
LADSPA_ONLY = crap_noise
VST_ONLY = crap_delay_test
LADSPA = ${BOTH:=-ladspa} ${LADSPA_ONLY:=-ladspa}
VST = ${BOTH:=-vst} ${VST_ONLY:=-vst}
PLUGINS = ${LADSPA} ${VST}

View file

@ -45,10 +45,12 @@ remember to export `VST\_SDK\_DIR` to the path of your `vstsdk2.4/`
## TODO
* finish VST/LADSPA parameter/port support in templates
* convert crap\_eq and crap\_noise to the template format
* convert crap\_noise to the template format
* rename plugins (fix capitalization consistency and such)
* remove crap\_ prefixes?
* move to subdirs?
* make crap faster (hand-written SSE2? compiler directives?)
* reduce input/output buffers on biquads (shared)
* ease up on the preprocessor ifs
* polish parameter support

View file

@ -1,218 +0,0 @@
#include <stdlib.h>
#include <math.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "ladspa.h"
#include "crap_util.h"
typedef unsigned long ulong;
/* Ports:
* BANDS*0 to BANDS*1-1: gain
* BANDS*1 to BANDS*2-1: frequency
* BANDS*2 to BANDS*3-1: bandwidth
*/
#ifndef BANDS
#define BANDS 4
#endif
#define EQ_INPUT (BANDS*3+0)
#define EQ_OUTPUT (BANDS*3+1)
#define PCOUNT (BANDS*3+2)
#define GAIN_MIN -60
#define GAIN_MAX 18
#define FREQ_MIN 1
#define FREQ_MAX 20000
#define BW_MIN 0.02
#define BW_MAX 8
void __attribute__ ((constructor)) eq_init();
static const char *gain_desc = "Band %i Gain [dB]";
static const char *freq_desc = "Band %i Freq [Hz]";
static const char *band_desc = "Band %i Bandwidth [octaves]";
#define NAME_SIZE 32
LADSPA_PortDescriptor p_discs[PCOUNT];
LADSPA_PortRangeHint p_hints[PCOUNT];
char name_buffer[PCOUNT*NAME_SIZE];
char *p_names[PCOUNT];
typedef struct {
LADSPA_Data *chg[BANDS];
LADSPA_Data *chf[BANDS];
LADSPA_Data *chb[BANDS];
LADSPA_Data old_chg[BANDS];
LADSPA_Data old_chf[BANDS];
LADSPA_Data old_chb[BANDS];
LADSPA_Data *input;
LADSPA_Data *output;
biquad filters[BANDS];
LADSPA_Data fs;
} eq_t;
static void
activate_eq(LADSPA_Handle instance) {
eq_t *eq = (eq_t *)instance;
biquad *filters = eq->filters;
for (int i = 0; i < BANDS; i++)
biquad_init(&filters[i]);
}
static void
cleanup_eq(LADSPA_Handle instance) {
free(instance);
}
static void
connect_port_eq(LADSPA_Handle instance, ulong port, LADSPA_Data *data) {
eq_t *eq = (eq_t *)instance;
if (port < BANDS)
eq->chg[port - BANDS*0] = data;
else if (port < BANDS*2)
eq->chf[port - BANDS*1] = data;
else if (port < BANDS*3)
eq->chb[port - BANDS*2] = data;
else if (port == EQ_INPUT)
eq->input = data;
else if (port == EQ_OUTPUT)
eq->output = data;
}
static LADSPA_Handle
instantiate_eq(const LADSPA_Descriptor *descriptor, ulong s_rate) {
eq_t *eq = (eq_t *) calloc(1, sizeof(eq_t));
biquad *filters = eq->filters;
LADSPA_Data fs = s_rate;
eq->fs = fs;
const LADSPA_Data g = 0;
const LADSPA_Data f = 440;
const LADSPA_Data b = 1;
for (int i = 0; i < BANDS; i++) {
eq->old_chg[i] = g;
eq->old_chf[i] = f;
eq->old_chb[i] = b;
filters[i] = biquad_gen(1, f, g, b, fs);
}
return (LADSPA_Handle) eq;
}
static void
watch_parameters(eq_t *eq) {
biquad *filters = eq->filters;
const LADSPA_Data fs = eq->fs;
for (int i = 0; i < BANDS; i++) {
const LADSPA_Data rg = *(eq->chg[i]);
const LADSPA_Data rf = *(eq->chf[i]);
const LADSPA_Data rb = *(eq->chb[i]);
if ((rg != eq->old_chg[i])
|| (rf != eq->old_chf[i])
|| (rb != eq->old_chb[i])) {
const LADSPA_Data g = LIMIT(rg, GAIN_MIN, GAIN_MAX);
const LADSPA_Data f = LIMIT(rf, FREQ_MIN, FREQ_MAX);
const LADSPA_Data b = LIMIT(rb, BW_MIN, BW_MAX);
eq->old_chg[i] = g;
eq->old_chf[i] = f;
eq->old_chb[i] = b;
filters[i] = biquad_gen(1, f, g, b, fs);
}
}
}
static void
run_eq(LADSPA_Handle instance, ulong sample_count) {
eq_t *eq = (eq_t *) instance;
biquad *filters = eq->filters;
watch_parameters(eq);
const LADSPA_Data *input = eq->input;
LADSPA_Data *output = eq->output;
for (ulong pos = 0; pos < sample_count; pos++) {
LADSPA_Data samp = input[pos];
for (int i = 0; i < BANDS; i++)
samp = biquad_run(&filters[i], samp);
output[pos] = samp;
}
}
static LADSPA_Descriptor eqDescriptor = {
.UniqueID = 0xCAFED,
.Label = "crap_eq",
.Properties = 0,
.Name = "crap Parametric Equalizer",
.Maker = "Connor Olding",
.Copyright = "MIT",
.PortCount = PCOUNT,
.PortDescriptors = p_discs,
.PortRangeHints = p_hints,
.PortNames = p_names,
.activate = activate_eq,
.cleanup = cleanup_eq,
.connect_port = connect_port_eq,
.deactivate = NULL,
.instantiate = instantiate_eq,
.run = run_eq,
.run_adding = NULL,
.set_run_adding_gain = NULL
};
const LADSPA_Descriptor *
ladspa_descriptor(ulong index) {
if (index != 0)
return NULL;
return &eqDescriptor;
}
void
eq_init() {
#define INCTRL (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL)
#define BOUNDED (LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE)
for (int i = 0; i < PCOUNT; i++)
p_names[i] = &name_buffer[i*NAME_SIZE];
for (int i = 0; i < BANDS; i++) {
const int gi = i;
const int fi = i + BANDS;
const int bi = i + BANDS*2;
p_discs[gi] = INCTRL;
p_discs[fi] = INCTRL;
p_discs[bi] = INCTRL;
sprintf(p_names[gi], gain_desc, i);
sprintf(p_names[fi], freq_desc, i);
sprintf(p_names[bi], band_desc, i);
p_hints[gi].HintDescriptor = BOUNDED
| LADSPA_HINT_DEFAULT_0;
p_hints[fi].HintDescriptor = BOUNDED
| LADSPA_HINT_LOGARITHMIC
| LADSPA_HINT_DEFAULT_440;
p_hints[bi].HintDescriptor = BOUNDED
| LADSPA_HINT_DEFAULT_1;
p_hints[gi].LowerBound = GAIN_MIN;
p_hints[gi].UpperBound = GAIN_MAX;
p_hints[fi].LowerBound = FREQ_MIN;
p_hints[fi].UpperBound = FREQ_MAX;
p_hints[bi].LowerBound = BW_MIN;
p_hints[bi].UpperBound = BW_MAX;
}
p_discs[EQ_INPUT] = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO;
strcpy(p_names[EQ_INPUT], "Input");
p_hints[EQ_INPUT].HintDescriptor = 0;
p_discs[EQ_OUTPUT] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO;
strcpy(p_names[EQ_OUTPUT], "Output");
p_hints[EQ_OUTPUT].HintDescriptor = 0;
}

View file

@ -67,7 +67,7 @@ pause(personal *data) {
}
static void
construct(personal *data, param *params) {
construct_params(param *params) {
for (int i = 0; i < BANDS; i++) {
sprintf(params[0].name, "Band %i Frequency", i + 1);
params[0].min = 20;
@ -94,6 +94,10 @@ construct(personal *data, param *params) {
}
}
static void
construct(personal *data) {
}
static void
destruct(personal *data) {
}

View file

@ -3,44 +3,29 @@
//#INCLUDE
#ifndef PARAM_NAME_LEN
#define PARAM_NAME_LEN 24
#endif
#define PLUG_INPUT_L 0
#define PLUG_INPUT_R 1
#define PLUG_OUTPUT_L 2
#define PLUG_OUTPUT_R 3
#define PCOUNT (PARAMETERS + 4)
const LADSPA_PortDescriptor p_discs[PCOUNT] = {
LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO
,
LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO
,
LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO
,
LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO
//#PORT_DESCRIPTIONS
};
static void __attribute__ ((constructor)) plug_init();
const LADSPA_PortRangeHint p_hints[PCOUNT] = {
{.HintDescriptor = 0}
,
{.HintDescriptor = 0}
,
{.HintDescriptor = 0}
,
{.HintDescriptor = 0}
//#PORT_HINTS
};
const char *p_names[PCOUNT] = {
"L input"
,
"R input"
,
"L output"
,
"R output"
//#PORT_NAMES
LADSPA_PortDescriptor p_descs[PCOUNT];
LADSPA_PortRangeHint p_hints[PCOUNT];
char p_default_strings[4][PARAM_NAME_LEN + 1] = {
"Input L", "Input R",
"Output L", "Output R"
};
#if (PARAMETERS > 0)
static param global_params[PARAMETERS];
char p_name_strings[PARAMETERS][PARAM_NAME_LEN + 1];
#endif
char *p_names[PCOUNT];
typedef struct {
LADSPA_Data *input_L;
@ -48,8 +33,11 @@ typedef struct {
LADSPA_Data *output_L;
LADSPA_Data *output_R;
//#PORT_DATA
personal data;
#if (PARAMETERS > 0)
float *values[PARAMETERS];
param params[PARAMETERS];
#endif
} plug_t;
static void
@ -63,7 +51,10 @@ plug_connect(LADSPA_Handle instance, unsigned long port, LADSPA_Data *data) {
plug->output_L = data;
else if (port == PLUG_OUTPUT_R)
plug->output_R = data;
//#PORT_CONNECT
#if (PARAMETERS > 0)
else if (port < PARAMETERS + 4)
plug->values[port - 4] = data;
#endif
}
static void
@ -82,7 +73,12 @@ static LADSPA_Handle
plug_construct(const LADSPA_Descriptor *descriptor, unsigned long fs) {
plug_t *plug = (plug_t *) calloc(1, sizeof(plug_t));
construct(&plug->data);
#if (PARAMETERS > 0)
memcpy(plug->params, global_params, sizeof(param)*PARAMETERS);
adjust(&plug->data, plug->params, fs);
#else
adjust(&plug->data, fs);
#endif
return (LADSPA_Handle) plug;
}
@ -96,6 +92,14 @@ plug_destruct(LADSPA_Handle instance) {
static void
plug_process(LADSPA_Handle instance, unsigned long count) {
plug_t *plug = (plug_t *)instance;
#if (PARAMETERS > 0)
for (int i = 0; i < PARAMETERS; i++) {
if (*plug->values[i] != plug->params[i].value) {
plug->params[i].value = *plug->values[i];
adjust_one(&plug->data, plug->params, i);
}
}
#endif
process(&plug->data,
plug->input_L, plug->input_R,
plug->output_L, plug->output_R,
@ -110,7 +114,7 @@ static const LADSPA_Descriptor plug_desc = {
.Maker = AUTHOR,
.Copyright = COPYRIGHT,
.PortCount = PCOUNT,
.PortDescriptors = p_discs,
.PortDescriptors = p_descs,
.PortRangeHints = p_hints,
.PortNames = p_names,
@ -130,3 +134,47 @@ ladspa_descriptor(unsigned long index) {
return NULL;
return &plug_desc;
}
static void
plug_init() {
for (int i = 0; i < 4; i++) {
p_names[i] = p_default_strings[i];
p_descs[i] = LADSPA_PORT_AUDIO;
p_descs[i] |= (i < 2) ? LADSPA_PORT_INPUT : LADSPA_PORT_OUTPUT;
p_hints[i] = (LADSPA_PortRangeHint){.HintDescriptor = 0};
}
#if (PARAMETERS > 0)
construct_params(global_params);
for (int i = 0; i < PARAMETERS; i++) {
int j = i + 4;
param *p = &global_params[i];
memcpy(p_name_strings[i], p->name, PARAM_NAME_LEN + 1);
p_names[j] = p_name_strings[i];
p_descs[j] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
int hint = LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE;
p_hints[j].LowerBound = p->min;
p_hints[j].UpperBound = p->max;
if (p->scale == SCALE_INT) hint |= LADSPA_HINT_INTEGER;
if (p->scale == SCALE_TOGGLE) hint |= LADSPA_HINT_TOGGLED;
if (p->scale >= SCALE_LOG) hint |= LADSPA_HINT_LOGARITHMIC;
switch (p->def) {
case DEFAULT_0: hint |= LADSPA_HINT_DEFAULT_0; break;
case DEFAULT_1: hint |= LADSPA_HINT_DEFAULT_1; break;
case DEFAULT_100: hint |= LADSPA_HINT_DEFAULT_100; break;
case DEFAULT_440: hint |= LADSPA_HINT_DEFAULT_440; break;
case DEFAULT_MIN: hint |= LADSPA_HINT_DEFAULT_MINIMUM; break;
case DEFAULT_LOW: hint |= LADSPA_HINT_DEFAULT_LOW; break;
case DEFAULT_HIGH: hint |= LADSPA_HINT_DEFAULT_HIGH; break;
case DEFAULT_MAX: hint |= LADSPA_HINT_DEFAULT_MAXIMUM; break;
case DEFAULT_HALF: hint |= LADSPA_HINT_DEFAULT_MIDDLE; break;
}
p_hints[j].HintDescriptor = hint;
}
#endif
}

View file

@ -55,10 +55,9 @@ plugin::plugin(audioMasterCallback audioMaster)
setUniqueID(ID);
canProcessReplacing();
#if (PARAMETERS > 0)
::construct(&data, params);
#else
::construct(&data);
::construct_params(params);
#endif
::construct(&data);
}
plugin::~plugin()