commit 1b26a973afb51288a153d26b24883391f4bd5f13 Author: Connor Olding Date: Wed May 22 15:56:59 2013 -0700 microphone check one two what is this diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d07f876 --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +Copyright (C) 2013 Connor Olding + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..dc844a2 --- /dev/null +++ b/Makefile @@ -0,0 +1,57 @@ +DISTNAME = crap +VERSION = git + +SHOBJ = crap_eq.so +MID = crap_util.o +OBJ = ${SHOBJ:.so=.o} ${MID} +SRC = ${OBJ:.o=.c} +HEADERS = crap_util.h ladspa.h + +PLACEBO_FLAGS = -fomit-frame-pointer -fstrength-reduce -funroll-loops -ffast-math +ALL_CFLAGS = -O3 ${PLACEBO_FLAGS} -std=c99 -fPIC -Wall ${CFLAGS} +ALL_LDFLAGS = -nostartfiles -shared ${LDFLAGS} + +PREFIX ?= /usr/local +EXEC_PREFIX ?= ${PREFIX} +LIBDIR ?= ${EXEC_PREFIX}/lib +LADSPADIR ?= ${LIBDIR}/ladspa + +# should CFLAGS really be used in linking too? seems odd + +FULLNAME = ${DISTNAME}-${VERSION} +ALL = ${OBJ} ${SHOBJ} +LADSPADEST = ${DESTDIR}${LADSPADIR} + +all: options ${ALL} + +.PHONY: options +options: + @echo "ALL_CFLAGS = ${ALL_CFLAGS}" + @echo "CPPFLAGS = ${CPPFLAGS}" + @echo "ALL_LDFLAGS = ${ALL_LDFLAGS}" + @echo "CC = ${CC}" + +%.so: %.o + @echo LD $< ${MID} -o $@ + @${CC} ${ALL_LDFLAGS} $< ${MID} -o $@ + +%.o: %.c ${HEADERS} + @echo CC $< -o $@ + @${CC} -c ${ALL_CFLAGS} ${CPPFLAGS} $< -o $@ + +install: all + mkdir -p ${LADSPADEST} + install -d ${LADSPADEST} + install -m 644 ${SHOBJ} ${LADSPADEST} + +clean: + -rm -f ${ALL} + +dist: + -rm -f ${FULLNAME}.tar.gz + mkdir -p ${FULLNAME} + cp LICENSE README.md Makefile ${HEADERS} ${SRC} ${FULLNAME} + tar -cf ${FULLNAME}.tar ${FULLNAME} + gzip ${FULLNAME}.tar + rm -rf ${FULLNAME} + diff --git a/README.md b/README.md new file mode 100644 index 0000000..08952fc --- /dev/null +++ b/README.md @@ -0,0 +1,12 @@ +# crap + +connor's rancid audio plugins. LADSPA. +alternatively, crazy-revealing androgynous panties + +### crap_eq + +multiband parametric EQ. try redefining BANDS. + +### crap_eq_const + +workinonit... diff --git a/crap_eq.c b/crap_eq.c new file mode 100644 index 0000000..c44bd9a --- /dev/null +++ b/crap_eq.c @@ -0,0 +1,232 @@ +#include +#include +#include + +#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 + +LADSPA_PortDescriptor p_discs[PCOUNT]; +LADSPA_PortRangeHint p_hints[PCOUNT]; +const char *p_names[PCOUNT]; + +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 +}; + +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; + + LADSPA_Data run_adding_gain; +} eq_t; + +const LADSPA_Descriptor * +ladspa_descriptor(ulong index) { + if (index != 0) + return NULL; + return &eqDescriptor; +} + +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; + eq->run_adding_gain = 1; + + 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; + biquad_gen(&filters[i], 1, f, g, b, fs); + } + + return (LADSPA_Handle) eq; +} + +static void +run_eq_for_real(LADSPA_Handle instance, ulong sample_count, int running) { + eq_t *eq = (eq_t *) instance; + + const LADSPA_Data fs = eq->fs; + biquad *filters = eq->filters; + + /* TODO: I don't think this should be here at all */ + 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]); + 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); + if ((g != eq->old_chg[i]) + || (f != eq->old_chf[i]) + || (b != eq->old_chb[i])) { + eq->old_chg[i] = g; + eq->old_chf[i] = f; + eq->old_chb[i] = b; + biquad_gen(&filters[i], 1, f, g, b, fs); + } + } + + 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++) { + /* TODO: skip over 0 gains? */ + samp = biquad_run(&filters[i], samp); + } + if (running) + output[pos] += eq->run_adding_gain * samp; + else + output[pos] = samp; + } +} + +static void +run_eq(LADSPA_Handle instance, ulong sample_count) { + run_eq_for_real(instance, sample_count, 0); +} + +static void +run_adding_eq(LADSPA_Handle instance, ulong sample_count) { + run_eq_for_real(instance, sample_count, 1); +} + +void +set_run_adding_gain(LADSPA_Handle instance, LADSPA_Data gain) { + eq_t *eq = (eq_t *) instance; + eq->run_adding_gain = gain; +} + +void +_init() { + #define INCTRL (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL) + #define BOUNDED (LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE) + 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; + + /* TODO: generate strings per band */ + p_names[gi] = "Band x Gain [dB]"; + p_names[fi] = "Band x Freq [Hz]"; + p_names[bi] = "Band x Bandwidth [octaves]"; + + 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; + p_names[EQ_INPUT] = "Input"; + p_hints[EQ_INPUT].HintDescriptor = 0; + + p_discs[EQ_OUTPUT] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO; + p_names[EQ_OUTPUT] = "Output"; + p_hints[EQ_OUTPUT].HintDescriptor = 0; + + eqDescriptor.activate = activate_eq; + eqDescriptor.cleanup = cleanup_eq; + eqDescriptor.connect_port = connect_port_eq; + eqDescriptor.deactivate = NULL; + eqDescriptor.instantiate = instantiate_eq; + eqDescriptor.run = run_eq; + eqDescriptor.run_adding = run_adding_eq; + eqDescriptor.set_run_adding_gain = set_run_adding_gain; +} + +void +_fini() { +} + diff --git a/crap_util.c b/crap_util.c new file mode 100644 index 0000000..a5aeaa8 --- /dev/null +++ b/crap_util.c @@ -0,0 +1,135 @@ +#include +#include +#include + +#include "crap_util.h" + +/* used to resemble https://github.com/swh/ladspa/blob/master/util/biquad.h */ + +void +biquad_init(biquad *bq) { + bq->x1 = 0; + bq->x2 = 0; + bq->y1 = 0; + bq->y2 = 0; +} + +biquad_interim +peaking(double cw, double Gf, double g) { + double GB = sqrt(Gf); + return (biquad_interim) { + .b0 = 1 + g * GB, + .b1 = -2 * cw, + .b2 = 1 - g * GB, + .a0 = 1 + g / GB, + .a1 = -2 * cw, + .a2 = 1 - g / GB + }; +} + +biquad_interim +highpass(double cw, double g) { + return (biquad_interim) { + .b0 = 1 + cw*0.5, + .b1 = -cw - 1, + .b2 = 1 + cw*0.5, + .a0 = 1 + g, + .a1 = -2*cw, + .a2 = 1 - g + }; +} + +/* TODO: rename */ +biquad_interim +orfanidi(double w0, double Gf, double g) { + /* simplified http://ece.rutgers.edu/~orfanidi/intro2sp/mdir/peq.m */ + double Dw, GfS, F, G00, F00, term1, term2, num, den; + double G1S, G1, G01, G11, F01, F11, W2, DO, coeff, C, D, A, B; + double v; + + Dw = atan(g)*2; + GfS = SQR(Gf); + + v = (Gf > 1) ? 1 : -1; + + F = v*(GfS - Gf); + G00 = v*(GfS - 1); + F00 = v*(Gf - 1); + + term1 = SQR(SQR(w0) - SQR(M_PI)); + term2 = F00 * SQR(M_PI) * SQR(Dw) / F; + num = term1 + term2 * GfS; + den = term1 + term2; + + G1S = num/den; + G1 = sqrt(G1S); + + G01 = v*(GfS - G1); + G11 = v*(GfS - G1S); + F01 = v*(Gf - G1); + F11 = fabs(Gf - G1S); + + /* bandwidth compensation goes nuts + * skip |= v*(Gf - G1S) < 0; */ + + W2 = sqrt(G11 / G00) * SQR(tan(w0/2)); + DO = (1 + sqrt(F00 / F11) * W2) * g; + + coeff = 2 * W2 / F; + C = F11 * SQR(DO) / F - coeff * (F01 - sqrt(F00 * F11)); + D = coeff * (G01 - sqrt(G00 * G11)); + + A = sqrt( C + D); + B = sqrt(GfS * C + Gf * D); + + return (biquad_interim) { + .b0 = -(G1 + W2 + B), + .b1 = 2*(G1 - W2), + .b2 = -(G1 - B + W2), + .a0 = -(1 + W2 + A), + .a1 = 2*(1 - W2), + .a2 = -(1 + W2 - A) + }; +} + +void +biquad_gen(biquad *bq, int type, double fc, double gain, double bw, double fs) { + /* TODO: use enum for type instead of just int */ + double w0, cw, sw, Gf, Q, a_peak, a_pass; + w0 = ANGULAR_LIM(fc, fs); + cw = cos(w0); + sw = sin(w0); + Gf = DB2LIN(gain); + Q = 1/(2 * sinh(LN_2_2 * bw * w0/sw)); + + a_peak = sw * (2 / Q); + a_pass = sw / (1 * Q); + /* skip = (fabs(Gf - 1) <= TINY); */ + biquad_interim bqi; + if (type == 0) bqi = peaking(cw, Gf, a_peak); + if (type == 1) bqi = orfanidi(w0, Gf, a_peak); + if (type == 2) bqi = highpass(cw, a_pass); + + double a0r = 1/bqi.a0; + bq->b0 = a0r * bqi.b0; + bq->b1 = a0r * bqi.b1; + bq->b2 = a0r * bqi.b2; + bq->a1 = -a0r * bqi.a1; + bq->a2 = -a0r * bqi.a2; +} + +bq_t +biquad_run(biquad *bq, bq_t x) { + bq_t y; + + y = bq->b0 * x + bq->b1 * bq->x1 + bq->b2 * bq->x2 + + bq->a1 * bq->y1 + bq->a2 * bq->y2; + if (IS_DENORMAL(y)) y = 0; + bq->x2 = bq->x1; + bq->x1 = x; + bq->y2 = bq->y1; + bq->y1 = y; + + return y; +} + diff --git a/crap_util.h b/crap_util.h new file mode 100644 index 0000000..12df2c2 --- /dev/null +++ b/crap_util.h @@ -0,0 +1,59 @@ +#ifndef M_PI +#define M_PI 3.14159265358979323846264338327 +#endif + +#ifndef M_LN2 +#define M_LN2 0.69314718055994530942 +#endif + +/* ln(2)/2 */ +#define LN_2_2 0.3465735902799726547086 + +#define SQR(x) ((x)*(x)) +#define DB2LIN(x) ((x) > -90 ? pow(10, (x) * 0.05) : 0) + +/* branchless, supposedly kills denormals when l=1 u=1 */ +#define CLIP(v,l,u) (fabs(v-l)+(l+u)-fabs(v-u))*0.5; +/* branches, but smaller and generic with no side effects */ +#define LIMIT(v,l,u) ((v)<(l)?(l):((v)>(u)?(u):(v))) + +/* frequency to rads/sec (angular frequency) */ +#define ANGULAR(fc, fs) (2 * M_PI / (fs) * (fc)) +#define ANGULAR_LIM(fc, fs) (2 * M_PI / (fs) * LIMIT((fc), 1, (fs)/2)) + +/* http://musicdsp.org/showone.php?id=51 */ +/* http://musicdsp.org/files/denormal.pdf */ +#ifdef BIQUAD_DOUBLE +typedef double bq_t; +#define IS_DENORMAL(f) (((*(uint64_t *)&f)&0x7FF0000000000000)==0) +#else +typedef float bq_t; +#define IS_DENORMAL(f) (((*(uint32_t *)&f)&0x7F800000)==0) +#endif + +typedef struct { + bq_t a1, a2, b0, b1, b2, x1, x2, y1, y2; +} biquad; + +typedef struct { + double b0, b1, b2, a0, a1, a2; +} biquad_interim; + +void +biquad_init(biquad *bq); + +biquad_interim +peaking(double cw, double Gf, double g); + +biquad_interim +highpass(double cw, double g); + +biquad_interim +orfanidi(double w0, double Gf, double g); + +void +biquad_gen(biquad *bq, int type, double fc, double gain, double bw, double fs); + +bq_t +biquad_run(biquad *bq, bq_t x); + diff --git a/ladspa.h b/ladspa.h new file mode 100644 index 0000000..ea74cca --- /dev/null +++ b/ladspa.h @@ -0,0 +1,116 @@ +/* ladspa.h + * Linux Audio Developer's Simple Plugin API Version 1.1[LGPL]. + * Copyright (C) 2000-2002 Richard W.E. Furse, Paul Barton-Davis, + * This program is licensed under the terms of the LGPL 2.1 License, + * and is distributed without any warranty. A copy of the license is + * available at . + */ +#ifndef LADSPA_INCLUDED +#define LADSPA_INCLUDED +#define LADSPA_VERSION "1.1" +#define LADSPA_VERSION_MAJOR 1 +#define LADSPA_VERSION_MINOR 1 +#ifdef __cplusplus +extern "C" { +#endif +typedef float LADSPA_Data; +typedef int LADSPA_Properties; +#define LADSPA_PROPERTY_REALTIME 0x1 +#define LADSPA_PROPERTY_INPLACE_BROKEN 0x2 +#define LADSPA_PROPERTY_HARD_RT_CAPABLE 0x4 +#define LADSPA_IS_REALTIME(x) ((x) & LADSPA_PROPERTY_REALTIME) +#define LADSPA_IS_INPLACE_BROKEN(x) ((x) & LADSPA_PROPERTY_INPLACE_BROKEN) +#define LADSPA_IS_HARD_RT_CAPABLE(x) ((x) & LADSPA_PROPERTY_HARD_RT_CAPABLE) +typedef int LADSPA_PortDescriptor; +#define LADSPA_PORT_INPUT 0x1 +#define LADSPA_PORT_OUTPUT 0x2 +#define LADSPA_PORT_CONTROL 0x4 +#define LADSPA_PORT_AUDIO 0x8 +#define LADSPA_IS_PORT_INPUT(x) ((x) & LADSPA_PORT_INPUT) +#define LADSPA_IS_PORT_OUTPUT(x) ((x) & LADSPA_PORT_OUTPUT) +#define LADSPA_IS_PORT_CONTROL(x) ((x) & LADSPA_PORT_CONTROL) +#define LADSPA_IS_PORT_AUDIO(x) ((x) & LADSPA_PORT_AUDIO) +typedef int LADSPA_PortRangeHintDescriptor; +#define LADSPA_HINT_BOUNDED_BELOW 0x1 +#define LADSPA_HINT_BOUNDED_ABOVE 0x2 +#define LADSPA_HINT_TOGGLED 0x4 +#define LADSPA_HINT_SAMPLE_RATE 0x8 +#define LADSPA_HINT_LOGARITHMIC 0x10 +#define LADSPA_HINT_INTEGER 0x20 +#define LADSPA_HINT_DEFAULT_MASK 0x3C0 +#define LADSPA_HINT_DEFAULT_NONE 0x0 +#define LADSPA_HINT_DEFAULT_MINIMUM 0x40 +#define LADSPA_HINT_DEFAULT_LOW 0x80 +#define LADSPA_HINT_DEFAULT_MIDDLE 0xC0 +#define LADSPA_HINT_DEFAULT_HIGH 0x100 +#define LADSPA_HINT_DEFAULT_MAXIMUM 0x140 +#define LADSPA_HINT_DEFAULT_0 0x200 +#define LADSPA_HINT_DEFAULT_1 0x240 +#define LADSPA_HINT_DEFAULT_100 0x280 +#define LADSPA_HINT_DEFAULT_440 0x2C0 +#define LADSPA_IS_HINT_BOUNDED_BELOW(x) ((x) & LADSPA_HINT_BOUNDED_BELOW) +#define LADSPA_IS_HINT_BOUNDED_ABOVE(x) ((x) & LADSPA_HINT_BOUNDED_ABOVE) +#define LADSPA_IS_HINT_TOGGLED(x) ((x) & LADSPA_HINT_TOGGLED) +#define LADSPA_IS_HINT_SAMPLE_RATE(x) ((x) & LADSPA_HINT_SAMPLE_RATE) +#define LADSPA_IS_HINT_LOGARITHMIC(x) ((x) & LADSPA_HINT_LOGARITHMIC) +#define LADSPA_IS_HINT_INTEGER(x) ((x) & LADSPA_HINT_INTEGER) +#define LADSPA_IS_HINT_HAS_DEFAULT(x) ((x) & LADSPA_HINT_DEFAULT_MASK) +#define LADSPA_IS_HINT_DEFAULT_MINIMUM(x) \ + (((x) & LADSPA_HINT_DEFAULT_MASK) == LADSPA_HINT_DEFAULT_MINIMUM) +#define LADSPA_IS_HINT_DEFAULT_LOW(x) \ + (((x) & LADSPA_HINT_DEFAULT_MASK) == LADSPA_HINT_DEFAULT_LOW) +#define LADSPA_IS_HINT_DEFAULT_MIDDLE(x) \ + (((x) & LADSPA_HINT_DEFAULT_MASK) == LADSPA_HINT_DEFAULT_MIDDLE) +#define LADSPA_IS_HINT_DEFAULT_HIGH(x) \ + (((x) & LADSPA_HINT_DEFAULT_MASK) == LADSPA_HINT_DEFAULT_HIGH) +#define LADSPA_IS_HINT_DEFAULT_MAXIMUM(x) \ + (((x) & LADSPA_HINT_DEFAULT_MASK) == LADSPA_HINT_DEFAULT_MAXIMUM) +#define LADSPA_IS_HINT_DEFAULT_0(x) \ + (((x) & LADSPA_HINT_DEFAULT_MASK) == LADSPA_HINT_DEFAULT_0) +#define LADSPA_IS_HINT_DEFAULT_1(x) \ + (((x) & LADSPA_HINT_DEFAULT_MASK) == LADSPA_HINT_DEFAULT_1) +#define LADSPA_IS_HINT_DEFAULT_100(x) \ + (((x) & LADSPA_HINT_DEFAULT_MASK) == LADSPA_HINT_DEFAULT_100) +#define LADSPA_IS_HINT_DEFAULT_440(x) \ + (((x) & LADSPA_HINT_DEFAULT_MASK) == LADSPA_HINT_DEFAULT_440) +typedef struct _LADSPA_PortRangeHint { + LADSPA_PortRangeHintDescriptor HintDescriptor; + LADSPA_Data LowerBound; + LADSPA_Data UpperBound; +} LADSPA_PortRangeHint; +typedef void * LADSPA_Handle; +typedef struct _LADSPA_Descriptor { + unsigned long UniqueID; + const char * Label; + LADSPA_Properties Properties; + const char * Name; + const char * Maker; + const char * Copyright; + unsigned long PortCount; + const LADSPA_PortDescriptor * PortDescriptors; + const char * const * PortNames; + const LADSPA_PortRangeHint * PortRangeHints; + void * ImplementationData; + LADSPA_Handle (*instantiate)( + const struct _LADSPA_Descriptor * Descriptor, + unsigned long SampleRate + ); + void (*connect_port)( + LADSPA_Handle Instance, + unsigned long Port, + LADSPA_Data * DataLocation + ); + void (*activate)(LADSPA_Handle Instance); + void (*run)(LADSPA_Handle Instance, unsigned long SampleCount); + void (*run_adding)(LADSPA_Handle Instance, unsigned long SampleCount); + void (*set_run_adding_gain)(LADSPA_Handle Instance, LADSPA_Data Gain); + void (*deactivate)(LADSPA_Handle Instance); + void (*cleanup)(LADSPA_Handle Instance); +} LADSPA_Descriptor; +const LADSPA_Descriptor * ladspa_descriptor(unsigned long Index); +typedef const LADSPA_Descriptor * + (*LADSPA_Descriptor_Function)(unsigned long Index); +#ifdef __cplusplus +} +#endif +#endif