diff --git a/crap/eq.hpp b/crap/eq.hpp index e4a9b1f..91a5eda 100644 --- a/crap/eq.hpp +++ b/crap/eq.hpp @@ -7,7 +7,7 @@ #include #include "util.hpp" -#include "param.hpp" +#include "Param.hpp" #include "Crap.hpp" #include "Buffer2.hpp" #include "biquad.hpp" @@ -53,7 +53,7 @@ struct Crap_eq } static inline void - construct_params(param *params) + construct_params(Param *params) { for (int i = 0; i < BANDS; i++) { sprintf(params[0].name, "Band %i Frequency", i + 1); @@ -61,28 +61,28 @@ struct Crap_eq params[0].max = 20000; params[0].scale = SCALE_HZ; params[0].def = DEFAULT_440; - param_reset(¶ms[0]); + params[0].reset(); sprintf(params[1].name, "Band %i Gain", i + 1); params[1].min = -18; params[1].max = 18; params[1].scale = SCALE_DB; params[1].def = DEFAULT_0; - param_reset(¶ms[1]); + params[1].reset(); sprintf(params[2].name, "Band %i Bandwidth", i + 1); params[2].min = 0.0625; // 2^-4 could probably be 2^-3 params[2].max = 8; // 2^3 could probably be 2^2 params[2].scale = SCALE_FLOAT; params[2].def = DEFAULT_1; - param_reset(¶ms[2]); + params[2].reset(); params += 3; } } inline void - adjust_all(param *params) + adjust_all(Param *params) { for (int i = 0; i < BANDS; i++) { filters_L[i] = biquad_gen(FILT_PEAKING, diff --git a/crap/eq_const.hpp b/crap/eq_const.hpp index 30f803f..226fa02 100644 --- a/crap/eq_const.hpp +++ b/crap/eq_const.hpp @@ -1,8 +1,3 @@ -#define ID 0x0DEFACED -#define LABEL "crap_eq_const" -#define NAME "crap Constant Equalizer" -#define AUTHOR "Connor Olding" -#define COPYRIGHT "MIT" #define PARAMETERS 0 #define BLOCK_SIZE 256 @@ -10,90 +5,75 @@ #include #include "util.hpp" +#include "Param.hpp" +#include "Crap.hpp" +#include "Buffer2.hpp" #include "biquad.hpp" -#define BANDS 12 -typedef struct { - biquad filters[2][BANDS]; -} personal; +struct Crap_eq_const +:public AdjustAll> { + static constexpr ulong id = 0x0DEFACED; + static constexpr char label[] = "crap_eq_const"; + static constexpr char name[] = "crap Constant Equalizer"; + static constexpr char author[] = "Connor Olding"; + static constexpr char copyright[] = "MIT"; -TEMPLATE static void -process(personal *data, - T *in_L, T *in_R, - T *out_L, T *out_R, - unsigned long count) -{ - disable_denormals(); + static constexpr ulong bands = 12; + static constexpr ulong parameters = 0; - v2df buf[BLOCK_SIZE]; + biquad filters_L[bands]; + biquad filters_R[bands]; - biquad *f0, *f1; - - for (ulong pos = 0; pos < count; pos += BLOCK_SIZE) { - ulong rem = BLOCK_SIZE; - if (pos + BLOCK_SIZE > count) - rem = count - pos; - - for (ulong i = 0; i < rem; i++) { - buf[i][0] = in_L[i]; - buf[i][1] = in_R[i]; - } - - f0 = data->filters[0]; - f1 = data->filters[1]; - for (ulong i = 0; i < BANDS; i++) { + inline void + process2(v2df *buf, ulong rem) + { + biquad *f0, *f1; + f0 = filters_L; + f1 = filters_R; + for (ulong i = 0; i < bands; i++) { biquad_run_block_stereo(f0, f1, buf, rem); f0++; f1++; } - - for (ulong i = 0; i < rem; i++) { - out_L[i] = buf[i][0]; - out_R[i] = buf[i][1]; - } - - in_L += BLOCK_SIZE; - in_R += BLOCK_SIZE; - out_L += BLOCK_SIZE; - out_R += BLOCK_SIZE; } -} -INNER void -construct(personal *data) -{} + inline void + pause() + {} -INNER void -destruct(personal *data) -{} + inline void + resume() + { + for (int i = 0; i < bands; i++) { + biquad_init(&filters_L[i]); + biquad_init(&filters_R[i]); + } + } -INNER void -resume(personal *data) -{ - biquad *filters = data->filters[0]; - for (int i = 0; i < BANDS; i++) - biquad_init(&filters[i]); - memcpy(data->filters[1], filters, BANDS*sizeof(biquad)); -} + static inline void + construct_params(Param *params) + {} -INNER void -pause(personal *data) -{} + virtual void + adjust_all(Param *params) + { + biquad *f = filters_L; + f[ 0] = biquad_gen(FILT_PEAKING, 62.0, 5.3, 0.55, fs); + f[ 1] = biquad_gen(FILT_PEAKING, 72.0, -1.7, 1.92, fs); + f[ 2] = biquad_gen(FILT_PEAKING, 2070, -3.1, 0.10, fs); + f[ 3] = biquad_gen(FILT_PEAKING, 2324, 1.9, 0.96, fs); + f[ 4] = biquad_gen(FILT_PEAKING, 2340, -3.9, 0.12, fs); + f[ 5] = biquad_gen(FILT_PEAKING, 3346, 1.4, 0.25, fs); + f[ 6] = biquad_gen(FILT_PEAKING, 4800, -3.4, 0.24, fs); + f[ 7] = biquad_gen(FILT_PEAKING, 5734, 1.7, 0.13, fs); + f[ 8] = biquad_gen(FILT_PEAKING, 6046, 1.0, 0.11, fs); + f[ 9] = biquad_gen(FILT_PEAKING, 6300, -6.4, 1.00, fs); + f[10] = biquad_gen(FILT_PEAKING, 8390, 1.5, 0.15, fs); + f[11] = biquad_gen(FILT_PEAKING, 13333, 3.1, 0.19, fs); + } +}; -INNER void -adjust(personal *data, ulong fs) -{ - biquad *filters = data->filters[0]; - filters[ 0] = biquad_gen(FILT_PEAKING, 62.0, 5.3, 0.55, fs); - filters[ 1] = biquad_gen(FILT_PEAKING, 72.0, -1.7, 1.92, fs); - filters[ 2] = biquad_gen(FILT_PEAKING, 2070, -3.1, 0.10, fs); - filters[ 3] = biquad_gen(FILT_PEAKING, 2324, 1.9, 0.96, fs); - filters[ 4] = biquad_gen(FILT_PEAKING, 2340, -3.9, 0.12, fs); - filters[ 5] = biquad_gen(FILT_PEAKING, 3346, 1.4, 0.25, fs); - filters[ 6] = biquad_gen(FILT_PEAKING, 4800, -3.4, 0.24, fs); - filters[ 7] = biquad_gen(FILT_PEAKING, 5734, 1.7, 0.13, fs); - filters[ 8] = biquad_gen(FILT_PEAKING, 6046, 1.0, 0.11, fs); - filters[ 9] = biquad_gen(FILT_PEAKING, 6300, -6.4, 1.00, fs); - filters[10] = biquad_gen(FILT_PEAKING, 8390, 1.5, 0.15, fs); - filters[11] = biquad_gen(FILT_PEAKING, 13333, 3.1, 0.19, fs); -} +constexpr char Crap_eq_const::label[]; +constexpr char Crap_eq_const::name[]; +constexpr char Crap_eq_const::author[]; +constexpr char Crap_eq_const::copyright[]; diff --git a/include/Crap.hpp b/include/Crap.hpp index 325446f..ddee926 100644 --- a/include/Crap.hpp +++ b/include/Crap.hpp @@ -2,6 +2,14 @@ struct Crap { virtual inline ~Crap() {} + ulong id; + char *label; + char *name; + char *author; + char *copyright; + ulong bands; + ulong parameters; + virtual void pause() = 0; @@ -24,10 +32,10 @@ struct Crap { //construct_params(param *params) = 0; virtual void - adjust(param *params, ulong fs) = 0; + adjust(Param *params, ulong fs) = 0; virtual void - adjust_one(param *params, int i) = 0; + adjust_one(Param *params, int i) = 0; }; template @@ -35,17 +43,17 @@ struct AdjustAll : public virtual Mixin { ulong fs; virtual void - adjust_all(param *params) = 0; + adjust_all(Param *params) = 0; inline void - adjust(param *params, ulong fs_new) + adjust(Param *params, ulong fs_new) { fs = fs_new; adjust_all(params); } inline void - adjust_one(param *params, int i) + adjust_one(Param *params, int i) { adjust_all(params); } @@ -59,10 +67,10 @@ struct NoParams : public virtual Mixin { //construct_params(param *params) = 0; void - adjust(param *params, ulong fs) + adjust(Param *params, ulong fs) {} void - adjust_one(param *params, int i) + adjust_one(Param *params, int i) {} }; diff --git a/include/Param.hpp b/include/Param.hpp new file mode 100644 index 0000000..10b1227 --- /dev/null +++ b/include/Param.hpp @@ -0,0 +1,78 @@ +#define PARAM_NAME_LEN 24 + +// TOOD: dump enums in param namespace + +typedef enum { + SCALE_FLOAT, + SCALE_INT, + SCALE_TOGGLE, + SCALE_DB, + SCALE_LOG, + SCALE_HZ +} param_scale; + +typedef enum { + DEFAULT_0, + DEFAULT_1, + DEFAULT_100, + DEFAULT_440, + DEFAULT_MIN, + DEFAULT_LOW, // 25% + DEFAULT_HALF, // 50% + DEFAULT_HIGH, // 75% + DEFAULT_MAX +} param_default; + +struct Param { + char name[PARAM_NAME_LEN + 1]; + float value, min, max; + param_scale scale; + param_default def; + + Param() + {} + + /* + Param( + char *name, float min, float max, + param_scale scale, param_default def) + : name(name), min(min), max(max), scale(scale), def(def) + { + reset() + } + */ + + void + set(float percent) + { + if (scale >= SCALE_LOG) + value = exp(percent*(log(max/min)))*min; + else + value = percent*(max - min) + min; + } + + float + get() + { + if (scale >= SCALE_LOG) + return log(min/value)/log(min/max); + else + return (min - value)/(min - max); + } + + void + reset() + { + switch (def) { + case DEFAULT_0: value = 0; break; + case DEFAULT_1: value = 1; break; + case DEFAULT_100: value = 100; break; + case DEFAULT_440: value = 440; break; + case DEFAULT_MIN: value = min; break; + case DEFAULT_LOW: set(0.25); break; + case DEFAULT_HALF: set(0.5); break; + case DEFAULT_HIGH: set(0.75); break; + case DEFAULT_MAX: value = max; break; + } + } +}; diff --git a/template/ladspa.cpp b/template/ladspa.cpp index cad3ab9..09000df 100644 --- a/template/ladspa.cpp +++ b/template/ladspa.cpp @@ -14,142 +14,34 @@ #define PLUG_OUTPUT_R 3 #define PCOUNT (PARAMETERS + 4) +// LADSPA is a jerk and won't let us initialize anything +// before asking for a descriptor. +// in reality we could use a crap-ton of constexprs, +// but i just need something functional for now static void __attribute__ ((constructor)) plug_init(); +static void __attribute__ ((destructor)) plug_cleanup(); + +#define ALLOC(type, amount) (type *) calloc(amount, sizeof(type)) -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 + +LADSPA_PortDescriptor p_descs[PCOUNT]; +LADSPA_PortRangeHint p_hints[PCOUNT]; +static Param *global_params; +char **p_name_strings; char *p_names[PCOUNT]; -typedef struct { - LADSPA_Data *input_L; - LADSPA_Data *input_R; - LADSPA_Data *output_L; - LADSPA_Data *output_R; - - Crap *crap; - #if (PARAMETERS > 0) - LADSPA_Data *values[PARAMETERS]; - param params[PARAMETERS]; - #endif -} plug_t; - static void -plug_connect(LADSPA_Handle instance, unsigned long port, LADSPA_Data *data) +plug_cleanup() { - plug_t *plug = (plug_t *)instance; - if (port == PLUG_INPUT_L) - plug->input_L = data; - else if (port == PLUG_INPUT_R) - plug->input_R = data; - else if (port == PLUG_OUTPUT_L) - plug->output_L = data; - else if (port == PLUG_OUTPUT_R) - plug->output_R = data; - #if (PARAMETERS > 0) - else if (port < PARAMETERS + 4) - plug->values[port - 4] = data; - #endif -} - -static void -plug_resume(LADSPA_Handle instance) -{ - plug_t *plug = (plug_t *)instance; - plug->crap->resume(); -} - -static void -plug_pause(LADSPA_Handle instance) -{ - plug_t *plug = (plug_t *)instance; - plug->crap->pause(); -} - -static LADSPA_Handle -plug_construct(const LADSPA_Descriptor *descriptor, unsigned long fs) -{ - plug_t *plug = (plug_t *) calloc(1, sizeof(plug_t)); - plug->crap = new CrapPlug(); - #if (PARAMETERS > 0) - memcpy(plug->params, global_params, sizeof(param)*PARAMETERS); - plug->crap->adjust(plug->params, fs); - #else - plug->crap->adjust(NULL, fs); - #endif - return (LADSPA_Handle) plug; -} - -static void -plug_destruct(LADSPA_Handle instance) -{ - plug_t *plug = (plug_t *)instance; - delete plug->crap; - free(plug); -} - -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]) - continue; - if (*plug->values[i] != plug->params[i].value) { - plug->params[i].value = *plug->values[i]; - plug->crap->adjust_one(plug->params, i); - } + free(p_name_strings[i]); } - #endif - plug->crap->process( - plug->input_L, plug->input_R, - plug->output_L, plug->output_R, - count); -} - -TEMPLATE static constexpr -LADSPA_Descriptor gen_desc() { - return LADSPA_Descriptor { - .UniqueID = T::id, - .Label = T::label, - .Properties = 0, - .Name = T::name, - .Maker = T::author, - .Copyright = T::copyright, - .PortCount = PCOUNT, - .PortDescriptors = p_descs, - .PortRangeHints = p_hints, - .PortNames = (const char * const *) p_names, - - .instantiate = plug_construct, - .cleanup = plug_destruct, - .activate = plug_resume, - .deactivate = plug_pause, - .connect_port = plug_connect, - .run = plug_process, - .run_adding = NULL, - .set_run_adding_gain = NULL - }; -} - -static constexpr LADSPA_Descriptor plug_descs[] = { - gen_desc() -}; - -const LADSPA_Descriptor * -ladspa_descriptor(unsigned long index) -{ - if (index >= sizeof(plug_descs)/sizeof(plug_descs[0])) - return NULL; - return plug_descs + index; + free(p_name_strings); + free(global_params); } static void @@ -162,11 +54,15 @@ plug_init() p_hints[i] = (LADSPA_PortRangeHint){.HintDescriptor = 0}; } - #if (PARAMETERS > 0) + global_params = ALLOC(Param, PARAMETERS); + p_name_strings = ALLOC(char *, PARAMETERS); + CrapPlug::construct_params(global_params); for (int i = 0; i < PARAMETERS; i++) { + p_name_strings[i] = ALLOC(char, PARAM_NAME_LEN + 1); + int j = i + 4; - param *p = &global_params[i]; + Param *p = &global_params[i]; memcpy(p_name_strings[i], p->name, PARAM_NAME_LEN + 1); p_names[j] = p_name_strings[i]; @@ -194,5 +90,129 @@ plug_init() p_hints[j].HintDescriptor = hint; } - #endif +} + +struct plug_t { + LADSPA_Data *input_L; + LADSPA_Data *input_R; + LADSPA_Data *output_L; + LADSPA_Data *output_R; + + Crap *crap; + LADSPA_Data **values; + Param *params; +}; + +TEMPLATE +struct LADSPA_Plugin : public T { + static LADSPA_Handle + plug_construct(const LADSPA_Descriptor *descriptor, unsigned long fs) + { + plug_t *plug = ALLOC(plug_t, 1); + plug->crap = new CrapPlug(); + if (T::parameters > 0) { + plug->values = ALLOC(LADSPA_Data *, T::parameters); + plug->params = ALLOC(Param, T::parameters); + memcpy(plug->params, global_params, sizeof(Param)*T::parameters); + plug->crap->adjust(plug->params, fs); + } else { + plug->crap->adjust(NULL, fs); + } + return (LADSPA_Handle) plug; + } + + static void + plug_destruct(LADSPA_Handle instance) + { + plug_t *plug = (plug_t *)instance; + delete plug->crap; + free(plug->values); + free(plug->params); + free(plug); + } + + static void + plug_connect(LADSPA_Handle instance, unsigned long port, LADSPA_Data *data) + { + plug_t *plug = (plug_t *)instance; + if (port == PLUG_INPUT_L) + plug->input_L = data; + else if (port == PLUG_INPUT_R) + plug->input_R = data; + else if (port == PLUG_OUTPUT_L) + plug->output_L = data; + else if (port == PLUG_OUTPUT_R) + plug->output_R = data; + else if (T::parameters > 0 && port < T::parameters + 4) + plug->values[port - 4] = data; + } + + static void + plug_resume(LADSPA_Handle instance) + { + plug_t *plug = (plug_t *)instance; + plug->crap->resume(); + } + + static void + plug_pause(LADSPA_Handle instance) + { + plug_t *plug = (plug_t *)instance; + plug->crap->pause(); + } + + static void + plug_process(LADSPA_Handle instance, unsigned long count) + { + plug_t *plug = (plug_t *)instance; + for (int i = 0; i < T::parameters; i++) { + if (!plug->values[i]) + continue; + if (*plug->values[i] != plug->params[i].value) { + plug->params[i].value = *plug->values[i]; + plug->crap->adjust_one(plug->params, i); + } + } + plug->crap->process( + plug->input_L, plug->input_R, + plug->output_L, plug->output_R, + count); + } +}; + +TEMPLATE static constexpr +LADSPA_Descriptor gen_desc() { + return LADSPA_Descriptor { + .UniqueID = T::id, + .Label = T::label, + .Properties = 0, + .Name = T::name, + .Maker = T::author, + .Copyright = T::copyright, + .PortCount = 4 + T::parameters, + .PortDescriptors = p_descs, + .PortRangeHints = p_hints, + .PortNames = (const char * const *) p_names, + + .instantiate = T::plug_construct, + .cleanup = T::plug_destruct, + .activate = T::plug_resume, + .deactivate = T::plug_pause, + .connect_port = T::plug_connect, + .run = T::plug_process, + .run_adding = NULL, + .set_run_adding_gain = NULL + }; +} + +static constexpr LADSPA_Descriptor plug_descs[] = { + gen_desc>() +}; + +const LADSPA_Descriptor * +ladspa_descriptor(unsigned long index) +{ + if (index >= sizeof(plug_descs)/sizeof(plug_descs[0])) + return NULL; + return plug_descs + index; }