diff --git a/Makefile b/Makefile index e674179..7ac1858 100755 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ FULLNAME = ${DISTNAME}-${VERSION} BOTH = crap_eq_const LADSPA_ONLY = crap_eq crap_noise -VST_ONLY = crap_delay_test +VST_ONLY = crap_eq crap_delay_test LADSPA = ${BOTH:=-ladspa} ${LADSPA_ONLY:=-ladspa} VST = ${BOTH:=-vst} ${VST_ONLY:=-vst} PLUGINS = ${LADSPA} ${VST} diff --git a/crap_eq.h b/crap_eq.h new file mode 100755 index 0000000..b5b91b2 --- /dev/null +++ b/crap_eq.h @@ -0,0 +1,120 @@ +#include +#include +#include +#include +#include + +#define BIQUAD_DOUBLE +#include "crap_util.h" +#include "param.h" + +typedef unsigned long ulong; + +#define BANDS 4 + +#define ID 0x000CAFED +#define LABEL "crap_eq" +#define NAME "crap Parametric Equalizer" +#define AUTHOR "Connor Olding" +#define COPYRIGHT "MIT" +#define PARAMETERS (BANDS*3) + +typedef struct { + biquad filters[2][BANDS]; + float fs; +} personal; + +static bq_t +process_one(biquad *filters, bq_t samp) +{ + for (int i = 0; i < BANDS; i++) + samp = biquad_run(&filters[i], samp); + return samp; +} + +static void +process(personal *data, + float *in_L, float *in_R, + float *out_L, float *out_R, + unsigned long count) { + for (unsigned long pos = 0; pos < count; pos++) { + out_L[pos] = process_one(data->filters[0], in_L[pos]); + out_R[pos] = process_one(data->filters[1], in_R[pos]); + } +} + +static void +process_double(personal *data, + double *in_L, double *in_R, + double *out_L, double *out_R, + unsigned long count) { + for (unsigned long pos = 0; pos < count; pos++) { + out_L[pos] = process_one(data->filters[0], in_L[pos]); + out_R[pos] = process_one(data->filters[1], in_R[pos]); + } +} + +static 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 void +pause(personal *data) { +} + +static void +construct(personal *data, param *params) { + for (int i = 0; i < BANDS; i++) { + sprintf(params[0].name, "Band %i Frequency", i + 1); + params[0].min = 20; + params[0].max = 20000; + params[0].scale = SCALE_HZ; + params[0].def = DEFAULT_440; + param_reset(¶ms[0]); + + 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]); + + sprintf(params[2].name, "Band %i Bandwidth", i + 1); + params[2].min = 0.0625; + params[2].max = 8; + params[2].scale = SCALE_FLOAT; + params[2].def = DEFAULT_1; + param_reset(¶ms[2]); + + params += 3; + } +} + +static void +destruct(personal *data) { +} + +static void +adjust(personal *data, param *params, unsigned long fs) { + data->fs = fs; + biquad *filters = data->filters[0]; + for (int i = 0; i < BANDS; i++) { + filters[i] = biquad_gen(0, + params[0].value, params[1].value, params[2].value, fs); + params += 3; + } + resume(data); +} + +static void +adjust_one(personal *data, param *params, unsigned int index) { + float fs = data->fs; + params += index/3*3; + data->filters[0][index/3] = biquad_gen(0, + params[0].value, params[1].value, params[2].value, fs); + resume(data); +} diff --git a/param.h b/param.h new file mode 100755 index 0000000..575cee4 --- /dev/null +++ b/param.h @@ -0,0 +1,65 @@ +#define PARAM_NAME_LEN 24 + +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; + +typedef struct { + char name[PARAM_NAME_LEN + 1]; + float value, min, max; + param_scale scale; + param_default def; +} param; + +#include + +void +param_set(param *p, float percent) +{ + if (p->scale >= SCALE_LOG) + p->value = exp(percent*(log(p->max/p->min)))*p->min; + else + p->value = percent*(p->max - p->min) + p->min; +} + +float +param_get(param *p) +{ + if (p->scale >= SCALE_LOG) + return log(p->min/p->value)/log(p->min/p->max); + else + return (p->min - p->value)/(p->min - p->max); +} + +void +param_reset(param *p) +{ + switch (p->def) { + case DEFAULT_0: p->value = 0; break; + case DEFAULT_1: p->value = 1; break; + case DEFAULT_100: p->value = 100; break; + case DEFAULT_440: p->value = 440; break; + case DEFAULT_MIN: p->value = p->min; break; + case DEFAULT_LOW: param_set(p, 0.25); break; + case DEFAULT_HALF: param_set(p, 0.5); break; + case DEFAULT_HIGH: param_set(p, 0.75); break; + case DEFAULT_MAX: p->value = p->max; break; + } +} diff --git a/template-vst.cpp b/template-vst.cpp index 7c8580d..9c10f37 100644 --- a/template-vst.cpp +++ b/template-vst.cpp @@ -1,8 +1,12 @@ +#include #include "public.sdk/source/vst2.x/audioeffectx.h" -//#include "vstparam.h" //#INCLUDE +// VST 2.4 by standard only holds 8 (+ 1 null) length strings, +// but this is never the case in practice. I've seen up to 24. +#define MAX_PARAM_LEN 24 + class plugin : public AudioEffectX { public: @@ -16,23 +20,23 @@ public: bool setProcessPrecision(VstInt32 precision); - /* - void setParameter(VstInt32, float); - float getParameter(VstInt32); - void getParameterLabel(VstInt32, char *); - void getParameterDisplay(VstInt32, char *); - void getParameterName(VstInt32, char *); - */ - void setSampleRate(float); bool getEffectName(char *); bool getVendorString(char *); bool getProductString(char *); //VstInt32 getVendorVersion(); + #if (PARAMETERS > 0) + void setParameter(VstInt32, float); + float getParameter(VstInt32); + void getParameterName(VstInt32, char *); // eg. Gain + void getParameterDisplay(VstInt32, char *); // eg. -3.3 + void getParameterLabel(VstInt32, char *); // eg. dB + #endif + private: #if (PARAMETERS > 0) - VstParam *m_params[PARAMETERS]; + param params[PARAMETERS]; #endif personal data; @@ -46,20 +50,20 @@ createEffectInstance(audioMasterCallback audioMaster) { plugin::plugin(audioMasterCallback audioMaster) : AudioEffectX(audioMaster, 1, PARAMETERS) { -//#VST_PARAMS - //m_params[n] = new VstParam("Input", "dB", -12.0, 12.0, 0.0, NULL, NULL, 1, NULL); setNumInputs(2); setNumOutputs(2); setUniqueID(ID); canProcessReplacing(); + #if (PARAMETERS > 0) + ::construct(&data, params); + #else ::construct(&data); + #endif } plugin::~plugin() { ::destruct(&data); - //for (int i = 0; i < PARAMETERS; i++) - // delete m_params[i]; } void @@ -92,18 +96,17 @@ plugin::processDoubleReplacing(double **inputs, double **outputs, VstInt32 count bool plugin::setProcessPrecision(VstInt32 precision) { - return true; + return true; } -/* -parameter funcs go here - if (index >= PARAMETERS) return; -*/ - void plugin::setSampleRate(float fs) { AudioEffectX::setSampleRate(fs); + #if (PARAMETERS > 0) + ::adjust(&data, params, (unsigned long) fs); + #else ::adjust(&data, (unsigned long) fs); + #endif #ifdef DELAY setInitialDelay(global_delay); #endif @@ -111,20 +114,97 @@ plugin::setSampleRate(float fs) { bool plugin::getEffectName(char *name) { - vst_strncpy(name, LABEL, kVstMaxEffectNameLen); - return true; + vst_strncpy(name, LABEL, kVstMaxEffectNameLen); + return true; } bool plugin::getProductString(char *text) { - vst_strncpy(text, NAME, kVstMaxProductStrLen); - return true; + vst_strncpy(text, NAME, kVstMaxProductStrLen); + return true; } bool plugin::getVendorString(char *text) { - vst_strncpy(text, AUTHOR, kVstMaxVendorStrLen); - return true; + vst_strncpy(text, AUTHOR, kVstMaxVendorStrLen); + return true; } + +#if (PARAMETERS > 0) +void +plugin::setParameter(VstInt32 index, float value) +{ + if (index >= PARAMETERS) return; + param_set(¶ms[index], value); + ::adjust_one(&data, params, index); +} + +float +plugin::getParameter(VstInt32 index) +{ + if (index >= PARAMETERS) return 0; + return param_get(¶ms[index]); +} + +void +plugin::getParameterName(VstInt32 index, char *text) +{ + if (index >= PARAMETERS) return; + vst_strncpy(text, params[index].name, MAX_PARAM_LEN); +} + +void +plugin::getParameterDisplay(VstInt32 index, char *text) +{ + if (index >= PARAMETERS) return; + + param *p = ¶ms[index]; + char display[MAX_PARAM_LEN]; + + switch (p->scale) { + case SCALE_FLOAT: + case SCALE_LOG: + case SCALE_HZ: + case SCALE_DB: + sprintf(display, "%0.2f", p->value); + break; + case SCALE_INT: + sprintf(display, "%i", (int) p->value); + break; + case SCALE_TOGGLE: + sprintf(display, (param_get(p) < 0.5) ? "off" : "on"); + break; + default: + sprintf(display, "error"); + } + + vst_strncpy(text, display, MAX_PARAM_LEN); +} + +void +plugin::getParameterLabel(VstInt32 index, char *text) +{ + if (index >= PARAMETERS) return; + + param *p = ¶ms[index]; + char display[MAX_PARAM_LEN]; + + switch (p->scale) { + case SCALE_HZ: + sprintf(display, "Hz"); + break; + case SCALE_DB: + sprintf(display, "dB"); + break; + case SCALE_FLOAT: + case SCALE_INT: + case SCALE_TOGGLE: + case SCALE_LOG: + display[0] = 0; + } + + vst_strncpy(text, display, MAX_PARAM_LEN); +} +#endif