From 84888a643398e9d119dd7c8e80c0f8c4f6dfb9ce Mon Sep 17 00:00:00 2001 From: Stefano D'Angelo Date: Thu, 16 Jan 2025 20:58:23 +0100 Subject: [PATCH] vst3 split internal parameter data and possibly fixed a bunch of issues --- templates/vst3/src/data.h | 43 ++++- templates/vst3/src/vst3.c | 333 +++++++++++++++++++++++++--------- templates/vst3/tibia-index.js | 15 +- 3 files changed, 293 insertions(+), 98 deletions(-) diff --git a/templates/vst3/src/data.h b/templates/vst3/src/data.h index ec284a3..5a6095e 100644 --- a/templates/vst3/src/data.h +++ b/templates/vst3/src/data.h @@ -192,7 +192,7 @@ static struct Steinberg_Vst_ParameterInfo parameterInfo[DATA_PRODUCT_PARAMETERS_ # define DATA_PARAM_INTEGER (1<<2) # define DATA_PARAM_MAP_LOG (1<<3) -static struct { +typedef struct { size_t index; double min; double max; @@ -200,8 +200,11 @@ static struct { uint32_t flags; double mapK; // scalePoints? -} parameterData[DATA_PRODUCT_PARAMETERS_N] = { -{{~it.product.parameters.filter(x => !x.isLatency) :p:i}} +} ParameterData; + +# if DATA_PRODUCT_PARAMETERS_IN_N > 0 +static ParameterData parameterInData[DATA_PRODUCT_PARAMETERS_IN_N] = { +{{~it.product.parameters.filter(x => x.direction == "input") :p:i}} { /* .index = */ {{=p.paramIndex}}, /* .min = */ {{=p.minimum.toExponential()}}, @@ -212,6 +215,30 @@ static struct { }, {{~}} }; +# endif + +# if DATA_PRODUCT_PARAMETERS_OUT_N > 0 +static ParameterData parameterOutData[DATA_PRODUCT_PARAMETERS_OUT_N] = { +{{~it.product.parameters.filter(x => !x.isLatency && x.direction == "output") :p:i}} + { + /* .index = */ {{=p.paramIndex}}, + /* .min = */ {{=p.minimum.toExponential()}}, + /* .max = */ {{=p.maximum.toExponential()}}, + /* .def = */ {{=p.defaultValue.toExponential()}}, + /* .flags = */ 0{{?p.toggled}} | DATA_PARAM_TOGGLED{{?}}{{?p.integer}} | DATA_PARAM_INTEGER{{?}}{{?p.map == "logarithmic"}} | DATA_PARAM_MAP_LOG{{?}}, + /* .mapK = */ {{?p.map == "logarithmic"}}{{=Number(2.0 * Math.log(Math.sqrt(p.maximum * p.minimum) / Math.abs(p.minimum))).toExponential()}}{{??}}0.0{{?}} + }, +{{~}} +}; + +static size_t parameterOutDataToInfoIndex[DATA_PRODUCT_PARAMETERS_OUT_N] = { + {{=it.product.parameters.filter(x => !x.isLatency && x.direction == "output").map(x => x.paramInfoIndex).join(", ")}} +}; +# endif + +static size_t parameterInfoToDataIndex[DATA_PRODUCT_PARAMETERS_N] = { + {{=it.product.parameters.filter(x => !x.isLatency).map(x => x.paramDataIndex).join(", ")}} +}; # endif @@ -230,11 +257,13 @@ static struct { * Parameter indices/ids: * * parameterInfo.id: hash of parameter id (+ extra sometimes), univocally identifies parameter across plugin versions (a la lv2:symbol) - * parameterGetIndexById(): returns parameterData's array index based on id (parameterInfo.id) - * parameterData.index/p.paramIndex: Tibia parameter index, as used in plugin.h - * latency out parameter is never added to parameterInfo and parameterData (specially handled) + * parameterGetIndexById(): returns parameterInfo array index based on id (parameterInfo.id) + * parameterInfoToDataIndex: maps parameterInfo array indices to parameter(In/Out)Data indices + * parameterOutDataToInfoIndex: maps parameterOutData indices to parameterInfo array indices + * parameter(In/Out)Data.index/p.paramIndex: Tibia parameter index, as used in plugin.h + * latency out parameter is never added to parameterInfo and parameter(In/Out)Data (specially handled) */ {{?it.product.state && it.product.state.dspCustom}} -#define STATE_DSP_CUSTOM +#define DATA_STATE_DSP_CUSTOM {{?}} diff --git a/templates/vst3/src/vst3.c b/templates/vst3/src/vst3.c index 220dd16..847742f 100644 --- a/templates/vst3/src/vst3.c +++ b/templates/vst3/src/vst3.c @@ -57,7 +57,6 @@ // https://github.com/rubberduck-vba/Rubberduck/wiki/COM-in-plain-C // https://devblogs.microsoft.com/oldnewthing/20040205-00/?p=40733 -//#define TIBIA_TRACE #ifdef TIBIA_TRACE # define TRACE(...) printf(__VA_ARGS__); fflush(stdout); #else @@ -160,6 +159,7 @@ static double clamp(double x, double m, double M) { return x < m ? m : (x > M ? M : x); } +#if DATA_PRODUCT_PARAMETERS_N + DATA_PRODUCT_BUSES_MIDI_INPUT_N > 0 static int parameterGetIndexById(Steinberg_Vst_ParamID id) { for (int i = 0; i < DATA_PRODUCT_PARAMETERS_N + 3 * DATA_PRODUCT_BUSES_MIDI_INPUT_N; i++) if (parameterInfo[i].id == id) @@ -167,19 +167,67 @@ static int parameterGetIndexById(Steinberg_Vst_ParamID id) { return -1; } -static double parameterMap(int i, double v) { - return parameterData[i].flags & DATA_PARAM_MAP_LOG ? parameterData[i].min * exp(parameterData[i].mapK * v) : parameterData[i].min + (parameterData[i].max - parameterData[i].min) * v; +# if DATA_PRODUCT_PARAMETERS_N > 0 +static double parameterMap(const ParameterData *data, double v) { + return data->flags & DATA_PARAM_MAP_LOG ? data->min * exp(data->mapK * v) : data->min + (data->max - data->min) * v; } -static double parameterUnmap(int i, double v) { - return parameterData[i].flags & DATA_PARAM_MAP_LOG ? log(v / parameterData[i].min) / parameterData[i].mapK : (v - parameterData[i].min) / (parameterData[i].max - parameterData[i].min); +static double parameterUnmap(const ParameterData *data, double v) { + return data->flags & DATA_PARAM_MAP_LOG ? log(v / data->min) / data->mapK : (v - data->min) / (data->max - data->min); } -static double parameterAdjust(int i, double v) { - v = parameterData[i].flags & (DATA_PARAM_BYPASS | DATA_PARAM_TOGGLED) ? (v >= 0.5 ? 1.0 : 0.0) - : (parameterData[i].flags & DATA_PARAM_INTEGER ? (int32_t)(v + (v >= 0.0 ? 0.5 : -0.5)) : v); - return clamp(v, parameterData[i].min, parameterData[i].max); +static double parameterAdjust(const ParameterData *data, double v) { + v = data->flags & (DATA_PARAM_BYPASS | DATA_PARAM_TOGGLED) ? (v >= 0.5 ? 1.0 : 0.0) + : (data->flags & DATA_PARAM_INTEGER ? (int32_t)(v + (v >= 0.0 ? 0.5 : -0.5)) : v); + return clamp(v, data->min, data->max); } +# endif + +static ParameterData *parameterGetDataByIndex(size_t index) { +# if DATA_PRODUCT_BUSES_MIDI_INPUT_N > 0 +# if DATA_PRODUCT_PARAMETERS_N > 0 + if (index >= DATA_PRODUCT_PARAMETERS_N) +# endif + return NULL; +# endif +# if DATA_PRODUCT_PARAMETERS_N > 0 +# if (DATA_PRODUCT_PARAMETERS_IN_N > 0) && (DATA_PRODUCT_PARAMETERS_OUT_N > 0) + ParameterData *p = (parameterInfo[index].flags & Steinberg_Vst_ParameterInfo_ParameterFlags_kIsReadOnly ? parameterOutData : parameterInData) + parameterInfoToDataIndex[index]; +# elif DATA_PRODUCT_PARAMETERS_IN_N > 0 + ParameterData *p = parameterInData + parameterInfoToDataIndex[index]; +# else + ParameterData *p = parameterOutData + parameterInfoToDataIndex[index]; +# endif + return p; +# endif +} + +static double parameterMapByIndex(size_t index, double v) { +# if DATA_PRODUCT_PARAMETERS_N > 0 + ParameterData *p = parameterGetDataByIndex(index); +# if DATA_PRODUCT_BUSES_MIDI_INPUT_N > 0 + if (p == NULL) + return v; +# endif + return parameterMap(p, v); +# else + return v; +# endif +} + +static double parameterUnmapByIndex(size_t index, double v) { +# if DATA_PRODUCT_PARAMETERS_N > 0 + ParameterData *p = parameterGetDataByIndex(index); +# if DATA_PRODUCT_BUSES_MIDI_INPUT_N > 0 + if (p == NULL) + return v; +# endif + return parameterUnmap(p, v); +# else + return v; +# endif +} +#endif typedef struct pluginInstance { Steinberg_Vst_IComponentVtbl * vtblIComponent; @@ -189,8 +237,11 @@ typedef struct pluginInstance { Steinberg_FUnknown * context; plugin p; float sampleRate; -#if DATA_PRODUCT_PARAMETERS_N > 0 - float parameters[DATA_PRODUCT_PARAMETERS_N]; +#if DATA_PRODUCT_PARAMETERS_IN_N > 0 + float parametersIn[DATA_PRODUCT_PARAMETERS_IN_N]; +#endif +#if DATA_PRODUCT_PARAMETERS_OUT_N > 0 + float parametersOut[DATA_PRODUCT_PARAMETERS_OUT_N]; #endif #if DATA_PRODUCT_CHANNELS_AUDIO_INPUT_N > 0 const float * inputs[DATA_PRODUCT_CHANNELS_AUDIO_INPUT_N]; @@ -215,7 +266,7 @@ typedef struct pluginInstance { char midiOutputsActive[DATA_PRODUCT_BUSES_MIDI_OUTPUT_N]; #endif void * mem; -#ifdef STATE_DSP_CUSTOM +#ifdef DATA_STATE_DSP_CUSTOM struct Steinberg_IBStream * state; #endif } pluginInstance; @@ -223,7 +274,7 @@ typedef struct pluginInstance { static Steinberg_Vst_IComponentVtbl pluginVtblIComponent; static Steinberg_Vst_IAudioProcessorVtbl pluginVtblIAudioProcessor; -#ifdef STATE_DSP_CUSTOM +#ifdef DATA_STATE_DSP_CUSTOM static int pluginWriteStateCb(void *handle, const char *data, size_t length) { pluginInstance *p = (pluginInstance *)handle; size_t written = 0; @@ -246,8 +297,9 @@ static void pluginLoadParameterCb(void *handle, size_t index, float value) { i--; # endif pluginInstance *p = (pluginInstance *)handle; - p->parameters[i] = parameterAdjust(i, value); - plugin_set_parameter(&p->p, index, p->parameters[i]); + size_t ii = parameterInfoToDataIndex[i]; + p->parametersIn[ii] = parameterAdjust(parameterInData + ii, value); + plugin_set_parameter(&p->p, index, p->parametersIn[ii]); } # endif #endif @@ -319,7 +371,7 @@ static Steinberg_tresult pluginInitialize(void *thisInterface, struct Steinberg_ /* .format = */ "vst3", /* .get_bindir = */ getBindirCb, /* .get_datadir = */ getDatadirCb, -#ifdef STATE_DSP_CUSTOM +#ifdef DATA_STATE_DSP_CUSTOM /* .write_state = */ pluginWriteStateCb, # if DATA_PRODUCT_PARAMETERS_IN_N > 0 /* .load_parameter = */ pluginLoadParameterCb @@ -332,13 +384,16 @@ static Steinberg_tresult pluginInitialize(void *thisInterface, struct Steinberg_ #endif }; plugin_init(&p->p, &cbs); -#if DATA_PRODUCT_PARAMETERS_N > 0 - for (size_t i = 0; i < DATA_PRODUCT_PARAMETERS_N; i++) { - p->parameters[i] = parameterData[i].def; - if (!(parameterInfo[i].flags & Steinberg_Vst_ParameterInfo_ParameterFlags_kIsReadOnly)) - plugin_set_parameter(&p->p, parameterData[i].index, parameterData[i].def); +#if DATA_PRODUCT_PARAMETERS_IN_N > 0 + for (size_t i = 0; i < DATA_PRODUCT_PARAMETERS_IN_N; i++) { + p->parametersIn[i] = parameterInData[i].def; + plugin_set_parameter(&p->p, parameterInData[i].index, parameterInData[i].def); } #endif +#if DATA_PRODUCT_PARAMETERS_OUT_N > 0 + for (size_t i = 0; i < DATA_PRODUCT_PARAMETERS_OUT_N; i++) + p->parametersOut[i] = parameterOutData[i].def; +#endif #if DATA_PRODUCT_BUSES_AUDIO_INPUT_N + DATA_PRODUCT_BUSES_AUDIO_OUTPUT_N + DATA_PRODUCT_BUSES_MIDI_INPUT_N + DATA_PRODUCT_BUSES_MIDI_OUTPUT_N > 0 p->neededBusesActive = 0; # if DATA_PRODUCT_BUSES_AUDIO_INPUT_N > 0 @@ -554,7 +609,7 @@ static Steinberg_tresult pluginSetState(void* thisInterface, struct Steinberg_IB TRACE("plugin set state\n"); if (state == NULL) return Steinberg_kResultFalse; -#ifdef STATE_DSP_CUSTOM +#ifdef DATA_STATE_DSP_CUSTOM pluginInstance *p = (pluginInstance *)((char *)thisInterface - offsetof(pluginInstance, vtblIComponent)); if (state->lpVtbl->seek(state, 0, Steinberg_IBStream_IStreamSeekMode_kIBSeekEnd, NULL) != Steinberg_kResultOk) return Steinberg_kResultFalse; @@ -580,11 +635,9 @@ static Steinberg_tresult pluginSetState(void* thisInterface, struct Steinberg_IB plugin_state_load(&p->p, data, length); free(data); #else -# if DATA_PRODUCT_PARAMETERS_N > 0 +# if DATA_PRODUCT_PARAMETERS_IN_N > 0 pluginInstance *p = (pluginInstance *)((char *)thisInterface - offsetof(pluginInstance, vtblIComponent)); - for (size_t i = 0; i < DATA_PRODUCT_PARAMETERS_N; i++) { - if (parameterInfo[i].flags & Steinberg_Vst_ParameterInfo_ParameterFlags_kIsReadOnly) - continue; + for (size_t i = 0; i < DATA_PRODUCT_PARAMETERS_IN_N; i++) { union { float f; uint32_t u; } v; Steinberg_int32 n; state->lpVtbl->read(state, &v, 4, &n); @@ -592,8 +645,8 @@ static Steinberg_tresult pluginSetState(void* thisInterface, struct Steinberg_IB return Steinberg_kResultFalse; if (IS_BIG_ENDIAN) v.u = SWAP_UINT32(v.u); - p->parameters[i] = parameterAdjust(i, v.f); - plugin_set_parameter(&p->p, parameterData[i].index, p->parameters[i]); + p->parametersIn[i] = parameterAdjust(parameterInData + i, v.f); + plugin_set_parameter(&p->p, parameterInData[i].index, p->parametersIn[i]); } # endif #endif @@ -604,19 +657,17 @@ static Steinberg_tresult pluginGetState(void* thisInterface, struct Steinberg_IB TRACE("plugin get state\n"); if (state == NULL) return Steinberg_kResultFalse; -#ifdef STATE_DSP_CUSTOM +#ifdef DATA_STATE_DSP_CUSTOM pluginInstance *p = (pluginInstance *)((char *)thisInterface - offsetof(pluginInstance, vtblIComponent)); p->state = state; if (plugin_state_save(&p->p) != 0) return Steinberg_kResultFalse; #else -# if DATA_PRODUCT_PARAMETERS_N > 0 +# if DATA_PRODUCT_PARAMETERS_IN_N > 0 pluginInstance *p = (pluginInstance *)((char *)thisInterface - offsetof(pluginInstance, vtblIComponent)); - for (size_t i = 0; i < DATA_PRODUCT_PARAMETERS_N; i++) { - if (parameterInfo[i].flags & Steinberg_Vst_ParameterInfo_ParameterFlags_kIsReadOnly) - continue; + for (size_t i = 0; i < DATA_PRODUCT_PARAMETERS_IN_N; i++) { union { float f; uint32_t u; } v; - v.f = p->parameters[i]; + v.f = p->parametersIn[i]; if (IS_BIG_ENDIAN) v.u = SWAP_UINT32(v.u); Steinberg_int32 n; @@ -749,7 +800,7 @@ static Steinberg_tresult pluginSetProcessing(void* thisInterface, Steinberg_TBoo } static void processParams(pluginInstance *p, struct Steinberg_Vst_ProcessData *data, char before) { -#if DATA_PRODUCT_PARAMETERS_N + DATA_PRODUCT_BUSES_MIDI_INPUT_N > 0 +#if DATA_PRODUCT_PARAMETERS_IN_N + DATA_PRODUCT_BUSES_MIDI_INPUT_N > 0 if (data->inputParameterChanges == NULL) return; Steinberg_int32 n = data->inputParameterChanges->lpVtbl->getParameterCount(data->inputParameterChanges); @@ -783,6 +834,8 @@ static void processParams(pluginInstance *p, struct Steinberg_Vst_ProcessData *d case 1: { // pitch bend change + // MIDI spec: 0 = max down bend, 8192 = no bend, 16383 = max up bend + // to make it symmetrical we have max down bend = 1 instead uint16_t x = (uint16_t)(16382.0 * v) + 1; data[0] = 0xe0 /* | channel */; data[1] = (x >> 7) & 0x7f; @@ -802,11 +855,14 @@ static void processParams(pluginInstance *p, struct Steinberg_Vst_ProcessData *d continue; } # endif - v = parameterAdjust(pi, parameterMap(pi, v)); - if (v != p->parameters[pi]) { - p->parameters[pi] = v; - plugin_set_parameter(&p->p, parameterData[pi].index, p->parameters[pi]); +# if DATA_PRODUCT_PARAMETERS_IN_N > 0 + size_t ii = parameterInfoToDataIndex[pi]; + v = parameterAdjust(parameterInData + ii, parameterMap(parameterInData + ii, v)); + if (v != p->parametersIn[ii]) { + p->parametersIn[ii] = v; + plugin_set_parameter(&p->p, parameterInData[ii].index, v); } +# endif } #endif } @@ -897,22 +953,20 @@ static Steinberg_tresult pluginProcess(void* thisInterface, struct Steinberg_Vst processParams(p, data, 0); -#if DATA_PRODUCT_PARAMETERS_N > 0 - for (Steinberg_int32 i = 0; i < DATA_PRODUCT_PARAMETERS_N; i++) { - if (!(parameterInfo[i].flags & Steinberg_Vst_ParameterInfo_ParameterFlags_kIsReadOnly)) +#if DATA_PRODUCT_PARAMETERS_OUT_N > 0 + for (Steinberg_int32 i = 0; i < DATA_PRODUCT_PARAMETERS_OUT_N; i++) { + float v = plugin_get_parameter(&p->p, parameterOutData[i].index); + if (v == p->parametersOut[i]) continue; - float v = plugin_get_parameter(&p->p, parameterData[i].index); - if (v == p->parameters[i]) - continue; - p->parameters[i] = v; + p->parametersOut[i] = v; if (data->outputParameterChanges == NULL) continue; - Steinberg_Vst_ParamID id = parameterInfo[i].id; + Steinberg_Vst_ParamID id = parameterInfo[parameterOutDataToInfoIndex[i]].id; Steinberg_int32 index; struct Steinberg_Vst_IParamValueQueue *q = data->outputParameterChanges->lpVtbl->addParameterData(data->outputParameterChanges, &id, &index); if (q == NULL) continue; - q->lpVtbl->addPoint(q, data->numSamples - 1, parameterUnmap(i, v), &index); + q->lpVtbl->addPoint(q, data->numSamples - 1, parameterUnmap(parameterOutData + i, v), &index); } #endif @@ -995,8 +1049,14 @@ typedef struct controller { #endif Steinberg_uint32 refs; Steinberg_FUnknown * context; -#if DATA_PRODUCT_PARAMETERS_N + DATA_PRODUCT_BUSES_MIDI_INPUT_N > 0 - double parameters[DATA_PRODUCT_PARAMETERS_N + 3 * DATA_PRODUCT_BUSES_MIDI_INPUT_N]; +#if DATA_PRODUCT_PARAMETERS_IN_N > 0 + double parametersIn[DATA_PRODUCT_PARAMETERS_IN_N]; +#endif +#if DATA_PRODUCT_PARAMETERS_OUT_N > 0 + double parametersOut[DATA_PRODUCT_PARAMETERS_OUT_N]; +#endif +#if DATA_PRODUCT_BUSES_MIDI_INPUT_N > 0 + double parametersMidiIn[3 * DATA_PRODUCT_BUSES_MIDI_INPUT_N]; #endif struct Steinberg_Vst_IComponentHandler * componentHandler; #ifdef DATA_UI @@ -1007,6 +1067,26 @@ typedef struct controller { static Steinberg_Vst_IEditControllerVtbl controllerVtblIEditController; +#if DATA_PRODUCT_PARAMETERS_N > 0 +static void controllerGetParamDataValuePtrs(controller *ctrl, size_t index, ParameterData **p, double **pv) { +# if (DATA_PRODUCT_PARAMETERS_IN_N > 0) && (DATA_PRODUCT_PARAMETERS_OUT_N > 0) + if (parameterInfo[index].flags & Steinberg_Vst_ParameterInfo_ParameterFlags_kIsReadOnly) { + *p = parameterOutData + parameterInfoToDataIndex[index]; + *pv = ctrl->parametersOut + parameterInfoToDataIndex[index]; + } else { + *p = parameterInData + parameterInfoToDataIndex[index]; + *pv = ctrl->parametersIn + parameterInfoToDataIndex[index]; + } +# elif DATA_PRODUCT_PARAMETER_IN_N > 0 + *p = parameterInData + paramterInfoToDataIndex[index]; + *pv = ctrl->parametersIn + parameterInfoToDataIndex[index]; +# else + *p = parameterOutData + paramterInfoToDataIndex[index]; + *pv = ctrl->parametersOut + parameterInfoToDataIndex[index]; +# endif +} +#endif + #ifdef DATA_UI # ifdef __linux__ @@ -1168,16 +1248,31 @@ static Steinberg_tresult plugViewIsPlatformTypeSupported(void* thisInterface, St } # if DATA_PRODUCT_PARAMETERS_N > 0 -static void plugViewUpdateParameter(plugView *view, size_t index) { +# if DATA_PRODUCT_PARAMETERS_IN_N > 0 +static void plugViewUpdateParameterIn(plugView *view, size_t index) { if (view->ui) - plugin_ui_set_parameter(view->ui, parameterData[index].index, view->ctrl->parameters[index]); + plugin_ui_set_parameter(view->ui, parameterInData[index].index, view->ctrl->parametersIn[index]); } +# endif + +# if DATA_PRODUCT_PARAMETERS_OUT_N > 0 +static void plugViewUpdateParameterOut(plugView *view, size_t index) { + if (view->ui) + plugin_ui_set_parameter(view->ui, parameterOutData[index].index, view->ctrl->parametersOut[index]); +} +# endif static void plugViewUpdateAllParameters(plugView *view) { if (view->ui == NULL) return; - for (size_t i = 0; i < DATA_PRODUCT_PARAMETERS_N; i++) - plugin_ui_set_parameter(view->ui, parameterData[i].index, view->ctrl->parameters[i]); +# if DATA_PRODUCT_PARAMETERS_IN_N > 0 + for (size_t i = 0; i < DATA_PRODUCT_PARAMETERS_IN_N; i++) + plugin_ui_set_parameter(view->ui, parameterInData[i].index, view->ctrl->parametersIn[i]); +# endif +# if DATA_PRODUCT_PARAMETERS_OUT_N > 0 + for (size_t i = 0; i < DATA_PRODUCT_PARAMETERS_OUT_N; i++) + plugin_ui_set_parameter(view->ui, parameterOutData[i].index, view->ctrl->parametersOut[i]); +# endif } static void plugViewSetParameterBeginCb(void *handle, size_t index) { @@ -1201,8 +1296,12 @@ static void plugViewSetParameterCb(void *handle, size_t index, float value) { index = index >= DATA_PARAM_LATENCY_INDEX ? index - 1 : index; # endif plugView *v = (plugView *)handle; - v->ctrl->parameters[index] = parameterAdjust(index, value); // let Reaper find the updated value - v->ctrl->componentHandler->lpVtbl->performEdit(v->ctrl->componentHandler, parameterInfo[index].id, parameterUnmap(index, v->ctrl->parameters[index])); + + ParameterData *p; + double *pv; + controllerGetParamDataValuePtrs(v->ctrl, index, &p, &pv); + *pv = parameterAdjust(p, value); // let Reaper find the updated value + v->ctrl->componentHandler->lpVtbl->performEdit(v->ctrl->componentHandler, parameterInfo[index].id, parameterUnmap(p, *pv)); } static void plugViewSetParameterEndCb(void *handle, size_t index) { @@ -1568,15 +1667,19 @@ static Steinberg_tresult controllerInitialize(void* thisInterface, struct Steinb if (c->context != NULL) return Steinberg_kResultFalse; c->context = context; -#if DATA_PRODUCT_PARAMETERS_N > 0 - for (int i = 0; i < DATA_PRODUCT_PARAMETERS_N; i++) - c->parameters[i] = parameterData[i].def; +#if DATA_PRODUCT_PARAMETERS_IN_N > 0 + for (int i = 0; i < DATA_PRODUCT_PARAMETERS_IN_N; i++) + c->parametersIn[i] = parameterInData[i].def; +#endif +#if DATA_PRODUCT_PARAMETERS_OUT_N > 0 + for (int i = 0; i < DATA_PRODUCT_PARAMETERS_OUT_N; i++) + c->parametersOut[i] = parameterOutData[i].def; #endif #if DATA_PRODUCT_BUSES_MIDI_INPUT_N > 0 - for (int i = DATA_PRODUCT_PARAMETERS_N; i < DATA_PRODUCT_PARAMETERS_N + 3 * DATA_PRODUCT_BUSES_MIDI_INPUT_N; i += 3) { - c->parameters[i] = 0.0; - c->parameters[i + 1] = 0.5; - c->parameters[i + 2] = 0.0; + for (int i = 0; i < 3 * DATA_PRODUCT_BUSES_MIDI_INPUT_N; i += 3) { + c->parametersMidiIn[i] = 0.0; + c->parametersMidiIn[i + 1] = 0.5; + c->parametersMidiIn[i + 2] = 0.0; } #endif return Steinberg_kResultOk; @@ -1593,11 +1696,9 @@ 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_PRODUCT_PARAMETERS_N > 0 +#if DATA_PRODUCT_PARAMETERS_IN_N > 0 controller *c = (controller *)((char *)thisInterface - offsetof(controller, vtblIEditController)); - for (size_t i = 0; i < DATA_PRODUCT_PARAMETERS_N; i++) { - if (parameterInfo[i].flags & Steinberg_Vst_ParameterInfo_ParameterFlags_kIsReadOnly) - continue; + for (size_t i = 0; i < DATA_PRODUCT_PARAMETERS_IN_N; i++) { union { float f; uint32_t u; } v; Steinberg_int32 n; state->lpVtbl->read(state, &v, 4, &n); @@ -1605,7 +1706,7 @@ static Steinberg_tresult controllerSetComponentState(void* thisInterface, struct return Steinberg_kResultFalse; if (IS_BIG_ENDIAN) v.u = SWAP_UINT32(v.u); - c->parameters[i] = parameterAdjust(i, v.f); + c->parametersIn[i] = parameterAdjust(parameterInData + i, v.f); } #endif TRACE(" ok\n"); @@ -1613,14 +1714,13 @@ static Steinberg_tresult controllerSetComponentState(void* thisInterface, struct } static Steinberg_tresult controllerSetState(void* thisInterface, struct Steinberg_IBStream* state) { + // TODO: we need this implemented for Reaper, need to re-check this TRACE("controller set state\n"); if (state == NULL) return Steinberg_kResultFalse; -#if DATA_PRODUCT_PARAMETERS_N > 0 +#if DATA_PRODUCT_PARAMETERS_IN_N > 0 controller *c = (controller *)((char *)thisInterface - offsetof(controller, vtblIEditController)); - for (size_t i = 0; i < DATA_PRODUCT_PARAMETERS_N; i++) { - if (parameterInfo[i].flags & Steinberg_Vst_ParameterInfo_ParameterFlags_kIsReadOnly) - continue; + for (size_t i = 0; i < DATA_PRODUCT_PARAMETERS_IN_N; i++) { union { float f; uint32_t u; } v; Steinberg_int32 n; state->lpVtbl->read(state, &v, 4, &n); @@ -1628,11 +1728,11 @@ static Steinberg_tresult controllerSetState(void* thisInterface, struct Steinber return Steinberg_kResultFalse; if (IS_BIG_ENDIAN) v.u = SWAP_UINT32(v.u); - c->parameters[i] = parameterAdjust(i, v.f); + c->parametersIn[i] = parameterAdjust(parameterInData + i, v.f); # ifdef DATA_UI if (c->views) for (size_t j = 0; j < c->viewsCount; j++) - plugViewUpdateParameter(c->views[j], i); + plugViewUpdateParameterIn(c->views[j], i); # endif } #endif @@ -1640,16 +1740,15 @@ static Steinberg_tresult controllerSetState(void* thisInterface, struct Steinber } static Steinberg_tresult controllerGetState(void* thisInterface, struct Steinberg_IBStream* state) { + // TODO: we need this implemented for Reaper, need to re-check this TRACE("controller get state\n"); if (state == NULL) return Steinberg_kResultFalse; -#if DATA_PRODUCT_PARAMETERS_N > 0 +#if DATA_PRODUCT_PARAMETERS_IN_N > 0 controller *c = (controller *)((char *)thisInterface - offsetof(controller, vtblIEditController)); - for (size_t i = 0; i < DATA_PRODUCT_PARAMETERS_N; i++) { - if (parameterInfo[i].flags & Steinberg_Vst_ParameterInfo_ParameterFlags_kIsReadOnly) - continue; + for (size_t i = 0; i < DATA_PRODUCT_PARAMETERS_IN_N; i++) { union { float f; uint32_t u; } v; - v.f = c->parameters[i]; + v.f = c->parametersIn[i]; if (IS_BIG_ENDIAN) v.u = SWAP_UINT32(v.u); Steinberg_int32 n; @@ -1672,10 +1771,16 @@ static Steinberg_tresult controllerGetParameterInfo(void* thisInterface, Steinbe (void)thisInterface; TRACE("controller get parameter info\n"); +#if DATA_PRODUCT_PARAMETERS_N + DATA_PRODUCT_BUSES_MIDI_INPUT_N > 0 if (paramIndex < 0 || paramIndex >= DATA_PRODUCT_PARAMETERS_N + 3 * DATA_PRODUCT_BUSES_MIDI_INPUT_N) return Steinberg_kResultFalse; *info = parameterInfo[paramIndex]; return Steinberg_kResultTrue; +#else + (void)paramIndex; + (void)info; + return Steinberg_kResultFalse; +#endif } static void dToStr(double v, Steinberg_Vst_String128 s, int precision) { @@ -1724,11 +1829,18 @@ static Steinberg_tresult controllerGetParamStringByValue(void* thisInterface, St (void)thisInterface; TRACE("controller get param string by value\n"); +#if DATA_PRODUCT_PARAMETERS_N + DATA_PRODUCT_BUSES_MIDI_INPUT_N > 0 int pi = parameterGetIndexById(id); if (pi >= DATA_PRODUCT_PARAMETERS_N + 3 * DATA_PRODUCT_BUSES_MIDI_INPUT_N || pi < 0) return Steinberg_kResultFalse; - dToStr(pi >= DATA_PRODUCT_PARAMETERS_N ? valueNormalized : parameterMap(pi, valueNormalized), string, 2); + dToStr(parameterMapByIndex(pi, valueNormalized), string, 2); return Steinberg_kResultTrue; +#else + (void)id; + (void)valueNormalized; + (void)string; + return Steinberg_kResultFalse; +#endif } void TCharToD(Steinberg_Vst_TChar* s, double *v) { @@ -1763,29 +1875,48 @@ static Steinberg_tresult controllerGetParamValueByString(void* thisInterface, St (void)thisInterface; TRACE("controller get param value by string\n"); +#if DATA_PRODUCT_PARAMETERS_N + DATA_PRODUCT_BUSES_MIDI_INPUT_N > 0 int pi = parameterGetIndexById(id); if (pi >= DATA_PRODUCT_PARAMETERS_N + 3 * DATA_PRODUCT_BUSES_MIDI_INPUT_N || pi < 0) return Steinberg_kResultFalse; double v; TCharToD(string, &v); - *valueNormalized = pi >= DATA_PRODUCT_PARAMETERS_N ? v : parameterUnmap(pi, v); + *valueNormalized = parameterUnmapByIndex(pi, v); return Steinberg_kResultTrue; +#else + (void)id; + (void)string; + (void)valueNormalized; + return Steinberg_kResultFalse; +#endif } static Steinberg_Vst_ParamValue controllerNormalizedParamToPlain(void* thisInterface, Steinberg_Vst_ParamID id, Steinberg_Vst_ParamValue valueNormalized) { (void)thisInterface; TRACE("controller normalized param to plain\n"); +#if DATA_PRODUCT_PARAMETERS_N > 0 int pi = parameterGetIndexById(id); - return pi >= DATA_PRODUCT_PARAMETERS_N ? valueNormalized : parameterMap(pi, valueNormalized); + return parameterMapByIndex(pi, valueNormalized); +#else + (void)id; + (void)valueNormalized; + return 0.0; +#endif } static Steinberg_Vst_ParamValue controllerPlainParamToNormalized(void* thisInterface, Steinberg_Vst_ParamID id, Steinberg_Vst_ParamValue plainValue) { (void)thisInterface; TRACE("controller plain param to normalized\n"); +#if DATA_PRODUCT_PARAMETERS_N > 0 int pi = parameterGetIndexById(id); - return pi >= DATA_PRODUCT_PARAMETERS_N ? plainValue : parameterUnmap(pi, plainValue); + return parameterUnmapByIndex(pi, plainValue); +#else + (void)id; + (void)plainValue; + return 0.0; +#endif } static Steinberg_Vst_ParamValue controllerGetParamNormalized(void* thisInterface, Steinberg_Vst_ParamID id) { @@ -1794,10 +1925,15 @@ static Steinberg_Vst_ParamValue controllerGetParamNormalized(void* thisInterface controller *c = (controller *)((char *)thisInterface - offsetof(controller, vtblIEditController)); int pi = parameterGetIndexById(id); # if DATA_PRODUCT_BUSES_MIDI_INPUT_N > 0 - return pi >= DATA_PRODUCT_PARAMETERS_N ? c->parameters[pi] : parameterUnmap(pi, c->parameters[pi]); -# else - return parameterUnmap(pi, c->parameters[pi]); +# if DATA_PRODUCT_PARAMETERS_N > 0 + if (pi >= DATA_PRODUCT_PARAMETERS_N) +# endif + return c->parametersMidiIn[pi - DATA_PRODUCT_PARAMETERS_N]; # endif + ParameterData *p; + double *pv; + controllerGetParamDataValuePtrs(c, pi, &p, &pv); + return parameterUnmap(p, *pv); #else (void)thisInterface; (void)id; @@ -1812,12 +1948,29 @@ static Steinberg_tresult controllerSetParamNormalized(void* thisInterface, Stein if (pi >= DATA_PRODUCT_PARAMETERS_N + 3 * DATA_PRODUCT_BUSES_MIDI_INPUT_N || pi < 0) return Steinberg_kResultFalse; controller *c = (controller *)((char *)thisInterface - offsetof(controller, vtblIEditController)); - c->parameters[pi] = pi >= DATA_PRODUCT_PARAMETERS_N ? value : parameterAdjust(pi, parameterMap(pi, value)); -# ifdef DATA_UI +# if DATA_PRODUCT_BUSES_MIDI_INPUT_N > 0 + if (pi >= DATA_PRODUCT_PARAMETERS_N) { + c->parametersMidiIn[pi - DATA_PRODUCT_PARAMETERS_N] = value; + } else { +# endif +# if DATA_PRODUCT_PARAMETERS_N > 0 + ParameterData *p; + double *pv; + controllerGetParamDataValuePtrs(c, pi, &p, &pv); + *pv = parameterAdjust(p, parameterMap(p, value)); +# endif +# if DATA_PRODUCT_BUSES_MIDI_INPUT_N > 0 + } +# endif +# if defined(DATA_UI) && (DATA_PRODUCT_PARAMETERS_N > 0) if (pi < DATA_PRODUCT_PARAMETERS_N) for (size_t i = 0; i < c->viewsCount; i++) - if(c->views[i]) - plugViewUpdateParameter(c->views[i], pi); + if(c->views[i]) { + if (parameterInfo[pi].flags & Steinberg_Vst_ParameterInfo_ParameterFlags_kIsReadOnly) + plugViewUpdateParameterOut(c->views[i], pi); + else + plugViewUpdateParameterIn(c->views[i], pi); + } # endif return Steinberg_kResultTrue; #else diff --git a/templates/vst3/tibia-index.js b/templates/vst3/tibia-index.js index 553c0af..5d21e6e 100644 --- a/templates/vst3/tibia-index.js +++ b/templates/vst3/tibia-index.js @@ -52,8 +52,21 @@ module.exports = function (data, api, outputCommon, outputData) { } }; - for (var i = 0; i < data.product.parameters.length; i++) + var inIdx = 0; + var outIdx = 0; + for (var i = 0; i < data.product.parameters.length; i++) { data.product.parameters[i].paramIndex = i; + if (data.product.parameters[i].isLatency) + continue; + data.product.parameters[i].paramInfoIndex = inIdx + outIdx; + if (data.product.parameters[i].direction == "input") { + data.product.parameters[i].paramDataIndex = inIdx; + inIdx++; + } else { + data.product.parameters[i].paramDataIndex = outIdx; + outIdx++; + } + } } api.copyFile(`data${sep}PkgInfo`, `data${sep}PkgInfo`);