lv2 tentative

This commit is contained in:
Stefano D'Angelo 2024-01-05 11:09:30 +01:00
parent 373202976d
commit 2e99de4618
5 changed files with 147 additions and 55 deletions

View File

@ -1 +1,12 @@
#define DATA_LV2_URI "{{=it.tibia.CGetUTF8StringLiteral(it.tibia.lv2.expandURI(it.lv2.uri))}}"
#define DATA_PRODUCT_AUDIO_INPUT_CHANNELS_N {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "input").reduce((s, x) => s += x.channels, 0)}}
#define DATA_PRODUCT_AUDIO_OUTPUT_CHANNELS_N {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "output").reduce((s, x) => s += x.channels, 0)}}
#define DATA_PRODUCT_CONTROL_INPUTS_N {{=it.product.parameters.filter(x => x.direction == "input").length}}
#define DATA_PRODUCT_CONTROL_OUTPUTS_N {{=it.product.parameters.filter(x => x.direction == "output").length}}
#if DATA_PRODUCT_CONTROL_INPUTS_N > 0
static float param_defaults[DATA_PRODUCT_CONTROL_INPUTS_N] = {
{{~it.tibia.lv2.ports.filter(x => x.type == "control" && x.direction == "input") :p}}{{=p.defaultValue.toExponential()}}f, {{~}}
};
#endif

View File

@ -3,6 +3,85 @@
#include "data.h"
#include "plugin.h"
typedef struct {
plugin p;
#if DATA_PRODUCT_AUDIO_INPUT_CHANNELS_N > 0
float * x[DATA_PRODUCT_AUDIO_INPUT_CHANNELS_N];
#endif
#if DATA_PRODUCT_AUDIO_OUTPUT_CHANNELS_N > 0
float * y[DATA_PRODUCT_AUDIO_OUTPUT_CHANNELS_N];
#endif
#if (DATA_PRODUCT_CONTROL_INPUTS_N + DATA_PRODUCT_CONTROL_OUTPUTS_N) > 0
float * c[DATA_PRODUCT_CONTROL_INPUTS_N + DATA_PRODUCT_CONTROL_OUTPUTS_N];
#endif
#if DATA_PRODUCT_CONTROL_INPUTS_N > 0
float params[DATA_PRODUCT_CONTROL_INPUTS_N};
#endif
} plugin_instance;
static const LV2_Handle instantiate(const struct LV2_Descriptor * descriptor, double sample_rate, const char * bundle_path, const LV2_Feature * const * features) {
plugin_instance *instance = malloc(sizeof(plugin_instance));
if (instance == NULL)
return NULL;
plugin_init(&instance->p);
plugin_set_sample_rate(&instance->p, sample_rate);
#if DATA_PRODUCT_CONTROL_INPUTS_N > 0
for (size_t i = 0; i < DATA_PRODUCT_CONTROL_INPUTS_N; i++)
instance->c[i] = NULL;
#endif
return instance;
}
static void connect_port(LV2_Handle instance, uint32_t port, void * data_location) {
plugin_instance * i = (plugin_instance *)instance;
#if DATA_PRODUCT_AUDIO_INPUT_CHANNELS_N > 0
if (port < DATA_PRODUCT_AUDIO_INPUT_CHANNELS_N) {
i->x[port] = data_location;
return;
}
port -= DATA_PRODUCT_AUDIO_INPUT_CHANNELS_N;
#endif
#if DATA_PRODUCT_AUDIO_OUTPUT_CHANNELS_N > 0
if (port < DATA_PRODUCT_AUDIO_OUTPUT_CHANNELS_N) {
i->y[port] = data_location;
return;
}
port -= DATA_PRODUCT_AUDIO_OUTPUT_CHANNELS_N;
#endif
#if (DATA_PRODUCT_CONTROL_INPUTS_N + DATA_PRODUCT_CONTROL_OUTPUTS_N) > 0
i->c[port] = data_location;
#endif
}
static void activate(LV2_Handle instance) {
plugin_instance * i = (plugin_instance *)instance;
#if DATA_PRODUCT_CONTROL_INPUTS_N > 0
for (size_t j = 0; j < DATA_PRODUCT_CONTROL_INPUTS_N; j++)
i->params[j] = i->c[j] != NULL ? i->c[j] : param_defaults[j];
plugin_set_parameter(&i->p, j, i->params[j]);
}
#endif
plugin_reset(&i->p);
}
static void run(LV2_Handle instance, uint32_t sample_count) {
plugin_instance * i = (plugin_instance *)instance;
#if DATA_PRODUCT_CONTROL_INPUTS_N > 0
for (size_t j = 0; j < DATA_PRODUCT_CONTROL_INPUTS_N; j++)
if (i->c[j] != i->params[j]) {
i->params[j] = i->c[j];
plugin_set_parameter(&i->p, j, i->params[j]);
}
#endif
plugin_process(&i->p, i->x, i->y, sample_count);
}
static void cleanup(LV2_Handle instance) {
plugin_instance * i = (plugin_instance *)instance;
plugin_fini(&i->p);
free(instance);
}
static const LV2_Descriptor descriptor = {
/* .URI = */ DATA_LV2_URI,
/* .instantiate = */ instantiate,

View File

@ -56,6 +56,8 @@ module.exports = function (data, api) {
}
}
data.tibia.lv2.ports.sort((a, b) => a.type != b.type ? (a.type == "audio" ? -1 : 1) : (a.direction != b.direction ? (a.direction == "input" ? -1 : 1) : 0));
api.generateFileFromTemplateFile(`data${sep}manifest.ttl`, `data${sep}manifest.ttl`, data);
api.copyFile(`src${sep}lv2.c`, `src${sep}lv2.c`);
api.generateFileFromTemplateFile(`src${sep}data.h`, `src${sep}data.h`, data);

View File

@ -28,13 +28,13 @@ static const Steinberg_TUID dataControllerCID = SMTG_INLINE_UID(DATA_VST3_CONTRO
#define DATA_VST3_SUBCATEGORY "{{=it.vst3.subCategory}}"
#define DATA_PLUGIN_BUSES_AUDIO_INPUT_N {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "input").length}}
#define DATA_PLUGIN_BUSES_AUDIO_OUTPUT_N {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "output").length}}
#define DATA_PLUGIN_BUSES_EVENT_INPUT_N {{=it.product.buses.filter(x => x.type == "event" && x.direction == "input").length}}
#define DATA_PLUGIN_BUSES_EVENT_OUTPUT_N {{=it.product.buses.filter(x => x.type == "event" && x.direction == "output").length}}
#define DATA_PRODUCT_BUSES_AUDIO_INPUT_N {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "input").length}}
#define DATA_PRODUCT_BUSES_AUDIO_OUTPUT_N {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "output").length}}
#define DATA_PRODUCT_BUSES_EVENT_INPUT_N {{=it.product.buses.filter(x => x.type == "event" && x.direction == "input").length}}
#define DATA_PRODUCT_BUSES_EVENT_OUTPUT_N {{=it.product.buses.filter(x => x.type == "event" && x.direction == "output").length}}
#if DATA_PLUGIN_BUSES_AUDIO_INPUT_N > 0
static struct Steinberg_Vst_BusInfo busInfoAudioInput[DATA_PLUGIN_BUSES_AUDIO_INPUT_N] = {
#if DATA_PRODUCT_BUSES_AUDIO_INPUT_N > 0
static struct Steinberg_Vst_BusInfo busInfoAudioInput[DATA_PRODUCT_BUSES_AUDIO_INPUT_N] = {
{{~it.product.buses.filter(x => x.type == "audio" && x.direction == "input") :b}}
{
/* .mediaType = */ Steinberg_Vst_MediaTypes_kAudio,
@ -48,8 +48,8 @@ static struct Steinberg_Vst_BusInfo busInfoAudioInput[DATA_PLUGIN_BUSES_AUDIO_IN
};
#endif
#if DATA_PLUGIN_BUSES_AUDIO_OUTPUT_N > 0
static struct Steinberg_Vst_BusInfo busInfoAudioOutput[DATA_PLUGIN_BUSES_AUDIO_OUTPUT_N] = {
#if DATA_PRODUCT_BUSES_AUDIO_OUTPUT_N > 0
static struct Steinberg_Vst_BusInfo busInfoAudioOutput[DATA_PRODUCT_BUSES_AUDIO_OUTPUT_N] = {
{{~it.product.buses.filter(x => x.type == "audio" && x.direction == "output") :b}}
{
/* .mediaType = */ Steinberg_Vst_MediaTypes_kAudio,
@ -63,8 +63,8 @@ static struct Steinberg_Vst_BusInfo busInfoAudioOutput[DATA_PLUGIN_BUSES_AUDIO_O
};
#endif
#if DATA_PLUGIN_BUSES_EVENT_INPUT_N > 0
static struct Steinberg_Vst_BusInfo busInfoEventInput[DATA_PLUGIN_BUSES_EVENT_INPUT_N] = {
#if DATA_PRODUCT_BUSES_EVENT_INPUT_N > 0
static struct Steinberg_Vst_BusInfo busInfoEventInput[DATA_PRODUCT_BUSES_EVENT_INPUT_N] = {
{{~it.product.buses.filter(x => x.type == "event" && x.direction == "input") :b}}
{
/* .mediaType = */ Steinberg_Vst_MediaTypes_kEvent,
@ -78,8 +78,8 @@ static struct Steinberg_Vst_BusInfo busInfoEventInput[DATA_PLUGIN_BUSES_EVENT_IN
};
#endif
#if DATA_PLUGIN_BUSES_EVENT_OUTPUT_N > 0
static struct Steinberg_Vst_BusInfo busInfoAudioInput[DATA_PLUGIN_BUSES_EVENT_OUTPUT_N] = {
#if DATA_PRODUCT_BUSES_EVENT_OUTPUT_N > 0
static struct Steinberg_Vst_BusInfo busInfoAudioInput[DATA_PRODUCT_BUSES_EVENT_OUTPUT_N] = {
{{~it.product.buses.filter(x => x.type == "event" && x.direction == "output") :b}}
{
/* .mediaType = */ Steinberg_Vst_MediaTypes_kEvent,
@ -93,10 +93,10 @@ static struct Steinberg_Vst_BusInfo busInfoAudioInput[DATA_PLUGIN_BUSES_EVENT_OU
};
#endif
#define DATA_PLUGIN_PARAMETERS_N {{=it.product.parameters.length}}
#define DATA_PRODUCT_PARAMETERS_N {{=it.product.parameters.length}}
#if DATA_PLUGIN_PARAMETERS_N > 0
static struct Steinberg_Vst_ParameterInfo parameterInfo[DATA_PLUGIN_PARAMETERS_N] = {
#if DATA_PRODUCT_PARAMETERS_N > 0
static struct Steinberg_Vst_ParameterInfo parameterInfo[DATA_PRODUCT_PARAMETERS_N] = {
{{~it.product.parameters :p:i}}
{
/* .id = */ {{=i}},

View File

@ -25,8 +25,8 @@ typedef struct pluginInstance {
Steinberg_FUnknown * context;
plugin p;
float sampleRate;
#if DATA_PLUGIN_PARAMETERS_N > 0
float parameters[DATA_PLUGIN_PARAMETERS_N];
#if DATA_PRODUCT_PARAMETERS_N > 0
float parameters[DATA_PRODUCT_PARAMETERS_N];
#endif
} pluginInstance;
@ -124,14 +124,14 @@ static Steinberg_int32 pluginGetBusCount(void *thisInterface, Steinberg_Vst_Medi
TRACE("plugin get bus count\n");
if (type == Steinberg_Vst_MediaTypes_kAudio) {
if (dir == Steinberg_Vst_BusDirections_kInput)
return DATA_PLUGIN_BUSES_AUDIO_INPUT_N;
return DATA_PRODUCT_BUSES_AUDIO_INPUT_N;
else if (dir == Steinberg_Vst_BusDirections_kOutput)
return DATA_PLUGIN_BUSES_AUDIO_OUTPUT_N;
return DATA_PRODUCT_BUSES_AUDIO_OUTPUT_N;
} else if (type == Steinberg_Vst_MediaTypes_kEvent) {
if (dir == Steinberg_Vst_BusDirections_kInput)
return DATA_PLUGIN_BUSES_EVENT_INPUT_N;
return DATA_PRODUCT_BUSES_EVENT_INPUT_N;
else if (dir == Steinberg_Vst_BusDirections_kOutput)
return DATA_PLUGIN_BUSES_EVENT_OUTPUT_N;
return DATA_PRODUCT_BUSES_EVENT_OUTPUT_N;
}
return 0;
}
@ -142,15 +142,15 @@ static Steinberg_tresult pluginGetBusInfo(void* thisInterface, Steinberg_Vst_Med
return Steinberg_kInvalidArgument;
if (type == Steinberg_Vst_MediaTypes_kAudio) {
if (dir == Steinberg_Vst_BusDirections_kInput) {
#if DATA_PLUGIN_BUSES_AUDIO_INPUT_N > 0
if (index >= DATA_PLUGIN_BUSES_AUDIO_INPUT_N)
#if DATA_PRODUCT_BUSES_AUDIO_INPUT_N > 0
if (index >= DATA_PRODUCT_BUSES_AUDIO_INPUT_N)
return Steinberg_kInvalidArgument;
*bus = busInfoAudioInput[index];
return Steinberg_kResultTrue;
#endif
} else if (dir == Steinberg_Vst_BusDirections_kOutput) {
#if DATA_PLUGIN_BUSES_AUDIO_OUTPUT_N > 0
if (index >= DATA_PLUGIN_BUSES_AUDIO_OUTPUT_N)
#if DATA_PRODUCT_BUSES_AUDIO_OUTPUT_N > 0
if (index >= DATA_PRODUCT_BUSES_AUDIO_OUTPUT_N)
return Steinberg_kInvalidArgument;
*bus = busInfoAudioOutput[index];
return Steinberg_kResultTrue;
@ -158,15 +158,15 @@ static Steinberg_tresult pluginGetBusInfo(void* thisInterface, Steinberg_Vst_Med
}
} else if (type == Steinberg_Vst_MediaTypes_kEvent) {
if (dir == Steinberg_Vst_BusDirections_kInput) {
#if DATA_PLUGIN_BUSES_EVENT_INPUT_N > 0
if (index >= DATA_PLUGIN_BUSES_AUDIO_INPUT_N)
#if DATA_PRODUCT_BUSES_EVENT_INPUT_N > 0
if (index >= DATA_PRODUCT_BUSES_AUDIO_INPUT_N)
return Steinberg_kInvalidArgument;
*bus = busInfoEventInput[index];
return Steinberg_kResultTrue;
#endif
} else if (dir == Steinberg_Vst_BusDirections_kOutput) {
#if DATA_PLUGIN_BUSES_EVENT_OUTPUT_N > 0
if (index >= DATA_PLUGIN_BUSES_AUDIO_OUTPUT_N)
#if DATA_PRODUCT_BUSES_EVENT_OUTPUT_N > 0
if (index >= DATA_PRODUCT_BUSES_AUDIO_OUTPUT_N)
return Steinberg_kInvalidArgument;
*bus = busInfoEventOutput[index];
return Steinberg_kResultTrue;
@ -187,15 +187,15 @@ static Steinberg_tresult pluginActivateBus(void* thisInterface, Steinberg_Vst_Me
return Steinberg_kInvalidArgument;
if (type == Steinberg_Vst_MediaTypes_kAudio) {
if (dir == Steinberg_Vst_BusDirections_kInput) {
#if DATA_PLUGIN_BUSES_AUDIO_INPUT_N > 0
if (index >= DATA_PLUGIN_BUSES_AUDIO_INPUT_N)
#if DATA_PRODUCT_BUSES_AUDIO_INPUT_N > 0
if (index >= DATA_PRODUCT_BUSES_AUDIO_INPUT_N)
return Steinberg_kInvalidArgument;
// TBD
return Steinberg_kResultTrue;
#endif
} else if (dir == Steinberg_Vst_BusDirections_kOutput) {
#if DATA_PLUGIN_BUSES_AUDIO_OUTPUT_N > 0
if (index >= DATA_PLUGIN_BUSES_AUDIO_OUTPUT_N)
#if DATA_PRODUCT_BUSES_AUDIO_OUTPUT_N > 0
if (index >= DATA_PRODUCT_BUSES_AUDIO_OUTPUT_N)
return Steinberg_kInvalidArgument;
// TBD
return Steinberg_kResultTrue;
@ -203,15 +203,15 @@ static Steinberg_tresult pluginActivateBus(void* thisInterface, Steinberg_Vst_Me
}
} else if (type == Steinberg_Vst_MediaTypes_kEvent) {
if (dir == Steinberg_Vst_BusDirections_kInput) {
#if DATA_PLUGIN_BUSES_EVENT_INPUT_N > 0
if (index >= DATA_PLUGIN_BUSES_AUDIO_INPUT_N)
#if DATA_PRODUCT_BUSES_EVENT_INPUT_N > 0
if (index >= DATA_PRODUCT_BUSES_AUDIO_INPUT_N)
return Steinberg_kInvalidArgument;
// TBD
return Steinberg_kResultTrue;
#endif
} else if (dir == Steinberg_Vst_BusDirections_kOutput) {
#if DATA_PLUGIN_BUSES_EVENT_OUTPUT_N > 0
if (index >= DATA_PLUGIN_BUSES_AUDIO_OUTPUT_N)
#if DATA_PRODUCT_BUSES_EVENT_OUTPUT_N > 0
if (index >= DATA_PRODUCT_BUSES_AUDIO_OUTPUT_N)
return Steinberg_kInvalidArgument;
// TBD
return Steinberg_kResultTrue;
@ -243,9 +243,9 @@ static Steinberg_tresult pluginSetState(void* thisInterface, struct Steinberg_I
TRACE("plugin set state\n");
if (state == NULL)
return Steinberg_kResultFalse;
#if DATA_PLUGIN_PARAMETERS_N > 0
#if DATA_PRODUCT_PARAMETERS_N > 0
pluginInstance *p = (pluginInstance *)thisInterface;
for (size_t i = 0; i < DATA_PLUGIN_PARAMETERS_N; i++) {
for (size_t i = 0; i < DATA_PRODUCT_PARAMETERS_N; i++) {
if (parameterInfo[i].flags & Steinberg_Vst_ParameterInfo_ParameterFlags_kIsReadOnly)
continue;
union { float f; uint32_t u; } v;
@ -266,9 +266,9 @@ static Steinberg_tresult pluginGetState(void* thisInterface, struct Steinberg_IB
TRACE("plugin get state\n");
if (state == NULL)
return Steinberg_kResultFalse;
#if DATA_PLUGIN_PARAMETERS_N > 0
#if DATA_PRODUCT_PARAMETERS_N > 0
pluginInstance *p = (pluginInstance *)thisInterface;
for (size_t i = 0; i < DATA_PLUGIN_PARAMETERS_N; i++) {
for (size_t i = 0; i < DATA_PRODUCT_PARAMETERS_N; i++) {
if (parameterInfo[i].flags & Steinberg_Vst_ParameterInfo_ParameterFlags_kIsReadOnly)
continue;
union { float f; uint32_t u; } v;
@ -323,7 +323,7 @@ static Steinberg_uint32 pluginIAudioProcessorRelease(void *thisInterface) {
static Steinberg_tresult pluginSetBusArrangements(void* thisInterface, Steinberg_Vst_SpeakerArrangement* inputs, Steinberg_int32 numIns, Steinberg_Vst_SpeakerArrangement* outputs, Steinberg_int32 numOuts) {
TRACE("plugin IAudioProcessor set bus arrangements\n");
if (numIns != DATA_PLUGIN_BUSES_AUDIO_INPUT_N || numOuts != DATA_PLUGIN_BUSES_AUDIO_OUTPUT_N)
if (numIns != DATA_PRODUCT_BUSES_AUDIO_INPUT_N || numOuts != DATA_PRODUCT_BUSES_AUDIO_OUTPUT_N)
return Steinberg_kResultFalse;
return Steinberg_kResultTrue;
}
@ -419,8 +419,8 @@ typedef struct controller {
Steinberg_Vst_IEditControllerVtbl * vtblIEditController;
Steinberg_uint32 refs;
Steinberg_FUnknown * context;
#if DATA_PLUGIN_PARAMETERS_N > 0
double parameters[DATA_PLUGIN_PARAMETERS_N];
#if DATA_PRODUCT_PARAMETERS_N > 0
double parameters[DATA_PRODUCT_PARAMETERS_N];
#endif
struct Steinberg_Vst_IComponentHandler* componentHandler;
} controller;
@ -467,8 +467,8 @@ static Steinberg_tresult controllerInitialize(void* thisInterface, struct Steinb
if (c->context != NULL)
return Steinberg_kResultFalse;
c->context = context;
#if DATA_PLUGIN_PARAMETERS_N > 0
for (int i = 0; i < DATA_PLUGIN_PARAMETERS_N; i++)
#if DATA_PRODUCT_PARAMETERS_N > 0
for (int i = 0; i < DATA_PRODUCT_PARAMETERS_N; i++)
c->parameters[i] = parameterInfo[i].defaultNormalizedValue;
#endif
return Steinberg_kResultOk;
@ -487,8 +487,8 @@ static Steinberg_tresult controllerSetComponentState(void* thisInterface, struct
TRACE("controller set component state %p %p\n", thisInterface, (void *)state);
if (state == NULL)
return Steinberg_kResultFalse;
#if DATA_PLUGIN_PARAMETERS_N > 0
for (size_t i = 0; i < DATA_PLUGIN_PARAMETERS_N; i++) {
#if DATA_PRODUCT_PARAMETERS_N > 0
for (size_t i = 0; i < DATA_PRODUCT_PARAMETERS_N; i++) {
if (parameterInfo[i].flags & Steinberg_Vst_ParameterInfo_ParameterFlags_kIsReadOnly)
continue;
union { float f; uint32_t u; } v;
@ -517,12 +517,12 @@ static Steinberg_tresult controllerGetState(void* thisInterface, struct Steinber
static Steinberg_int32 controllerGetParameterCount(void* thisInterface) {
TRACE("controller get parameter count\n");
return DATA_PLUGIN_PARAMETERS_N;
return DATA_PRODUCT_PARAMETERS_N;
}
static Steinberg_tresult controllerGetParameterInfo(void* thisInterface, Steinberg_int32 paramIndex, struct Steinberg_Vst_ParameterInfo* info) {
TRACE("controller get parameter info\n");
if (paramIndex < 0 || paramIndex >= DATA_PLUGIN_PARAMETERS_N)
if (paramIndex < 0 || paramIndex >= DATA_PRODUCT_PARAMETERS_N)
return Steinberg_kResultFalse;
*info = parameterInfo[paramIndex];
return Steinberg_kResultTrue;
@ -572,7 +572,7 @@ static void dToStr(double v, Steinberg_Vst_String128 s, int precision) {
static Steinberg_tresult controllerGetParamStringByValue(void* thisInterface, Steinberg_Vst_ParamID id, Steinberg_Vst_ParamValue valueNormalized, Steinberg_Vst_String128 string) {
TRACE("controller get param string by value\n");
if (id >= DATA_PLUGIN_PARAMETERS_N)
if (id >= DATA_PRODUCT_PARAMETERS_N)
return Steinberg_kResultFalse;
//mapping TBD
dToStr(valueNormalized, string, 2);
@ -609,7 +609,7 @@ void TCharToD(Steinberg_Vst_TChar* s, double *v) {
static Steinberg_tresult controllerGetParamValueByString(void* thisInterface, Steinberg_Vst_ParamID id, Steinberg_Vst_TChar* string, Steinberg_Vst_ParamValue* valueNormalized) {
TRACE("controller get param value by string\n");
if (id >= DATA_PLUGIN_PARAMETERS_N)
if (id >= DATA_PRODUCT_PARAMETERS_N)
return Steinberg_kResultFalse;
//mapping TBD
TCharToD(string, valueNormalized);
@ -630,7 +630,7 @@ static Steinberg_Vst_ParamValue controllerPlainParamToNormalized(void* thisInter
static Steinberg_Vst_ParamValue controllerGetParamNormalized(void* thisInterface, Steinberg_Vst_ParamID id) {
TRACE("controller get param normalized\n");
#if DATA_PLUGIN_PARAMETERS_N > 0
#if DATA_PRODUCT_PARAMETERS_N > 0
controller *c = (controller *)thisInterface;
return c->parameters[id];
#else
@ -640,8 +640,8 @@ static Steinberg_Vst_ParamValue controllerGetParamNormalized(void* thisInterface
static Steinberg_tresult controllerSetParamNormalized(void* thisInterface, Steinberg_Vst_ParamID id, Steinberg_Vst_ParamValue value) {
TRACE("controller set param normalized\n");
#if DATA_PLUGIN_PARAMETERS_N > 0
if (id >= DATA_PLUGIN_PARAMETERS_N)
#if DATA_PRODUCT_PARAMETERS_N > 0
if (id >= DATA_PRODUCT_PARAMETERS_N)
return Steinberg_kResultFalse;
controller *c = (controller *)thisInterface;
c->parameters[id] = value;