diff --git a/notes b/notes index 5f13ff8..b030c1a 100644 --- a/notes +++ b/notes @@ -84,6 +84,10 @@ product { unit of measure (from predefined list, see tibia-index.js), default "" VST3: ParameterInfo units LV2: manifest.ttl lv2:port units:unit + map: + "linear" vs "logarithmic" + VST3: + LV2: manifest.ttl lv2:port lv2:portProperty pprops:logarithmic } ] } diff --git a/templates/lv2/data/manifest.ttl b/templates/lv2/data/manifest.ttl index a2abc88..86b7f9a 100644 --- a/templates/lv2/data/manifest.ttl +++ b/templates/lv2/data/manifest.ttl @@ -78,6 +78,9 @@ {{?p.integer}} lv2:portProperty lv2:integer ; {{?}} +{{?p.map == "logarithmic"}} + lv2:portProperty pprops:logarithmic ; +{{?}} {{?p.scalePoints}} lv2:scalePoint [ {{~Object.entries(p.scalePoints) :sp:j}} diff --git a/templates/lv2/tibia-index.js b/templates/lv2/tibia-index.js index 039347d..e7c80ad 100644 --- a/templates/lv2/tibia-index.js +++ b/templates/lv2/tibia-index.js @@ -7,6 +7,7 @@ module.exports = function (data, api) { { id: "doap", uri: "http://usefulinc.com/ns/doap#" }, { id: "foaf", uri: "http://xmlns.com/foaf/0.1/" }, { id: "lv2", uri: "http://lv2plug.in/ns/lv2core#" }, + { id: "pprops", uri: "http://lv2plug.in/ns/ext/port-props#" }, { id: "rdf", uri: "http://www.w3.org/1999/02/22-rdf-syntax-ns#" }, { id: "rdfs", uri: "http://www.w3.org/2000/01/rdf-schema#" }, { id: "units", uri: "http://lv2plug.in/ns/extensions/units#" } diff --git a/templates/vst3-make/Makefile b/templates/vst3-make/Makefile index 50300fe..8bba71d 100644 --- a/templates/vst3-make/Makefile +++ b/templates/vst3-make/Makefile @@ -2,6 +2,7 @@ include vars.mk CC = gcc CFLAGS = -fPIC -Wall -Wpedantic -Wextra -Wno-unused-parameter +LIBS = -lm BUNDLE_DIR = ${BUNDLE_NAME}.vst3 @@ -14,7 +15,7 @@ build/${BUNDLE_DIR}/Contents/Info.plist: data/Info.plist | build/${BUNDLE_DIR}/C cp $^ $@ build/${BUNDLE_DIR}/Contents/${SO_FILE}: src/vst3.c | build/${BUNDLE_DIR}/Contents/${SO_DIR} - ${CC} $^ -o $@ ${CFLAGS} ${CFLAGS_EXTRA} ${LIBS_EXTRA} -shared + ${CC} $^ -o $@ ${CFLAGS} ${CFLAGS_EXTRA} ${LIBS} ${LIBS_EXTRA} -shared build/${BUNDLE_DIR}/Contents build/${BUNDLE_DIR}/Contents/${SO_DIR}: mkdir -p $@ diff --git a/templates/vst3/src/.vst3.c.swp b/templates/vst3/src/.vst3.c.swp new file mode 100644 index 0000000..fb49b37 Binary files /dev/null and b/templates/vst3/src/.vst3.c.swp differ diff --git a/templates/vst3/src/data.h b/templates/vst3/src/data.h index ca71c79..2a4db33 100644 --- a/templates/vst3/src/data.h +++ b/templates/vst3/src/data.h @@ -116,7 +116,7 @@ static struct Steinberg_Vst_ParameterInfo parameterInfo[DATA_PRODUCT_PARAMETERS_ /* .shortTitle = */ { {{~Array.from(p.shortName) :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 }, /* .units = */ { {{~Array.from(p.unit in it.tibia.vst3.units ? it.tibia.vst3.units[p.unit] : "") :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 }, /* .stepCount = */ {{?p.toggled}}1{{??p.list && p.scalePoints.length > 1}}Number(1 / (p.scalePoints.length - 1)).toExponential(){{??p.integer}}Number(p.maximum - p.minimum).toExponential(){{??}}0{{?}}, - /* .defaultNormalizedValue = */ {{=Number((p.defaultValue - p.minimum) / (p.maximum - p.minimum)).toExponential()}}, + /* .defaultNormalizedValue = */ {{?p.map == "logarithmic"}}{{=Number(Math.log(p.defaultValue / p.minimum) / (2 * Math.log(Math.sqrt(p.minimum * p.maximum) / Math.abs(p.minimum)))).toExponential()}}{{??}}{{=Number((p.defaultValue - p.minimum) / (p.maximum - p.minimum)).toExponential()}}{{?}}, /* .unitId = */ 0, /* .flags = */ {{?p.direction == "input"}}Steinberg_Vst_ParameterInfo_ParameterFlags_kCanAutomate{{??}}Steinberg_Vst_ParameterInfo_ParameterFlags_kIsReadOnly{{?}} {{?}} @@ -127,6 +127,7 @@ static struct Steinberg_Vst_ParameterInfo parameterInfo[DATA_PRODUCT_PARAMETERS_ # define DATA_PARAM_BYPASS 1 # define DATA_PARAM_TOGGLED (1<<1) # define DATA_PARAM_INTEGER (1<<2) +# define DATA_PARAM_MAP_LOG (1<<3) static struct { size_t index; @@ -134,6 +135,7 @@ static struct { double max; double def; uint32_t flags; + double mapK; // scalePoints? } parameterData[DATA_PRODUCT_PARAMETERS_N] = { {{~it.product.parameters.filter(x => !x.isLatency) :p:i}} @@ -142,7 +144,8 @@ static struct { /* .min = */ {{=p.minimum.toExponential()}}, /* .max = */ {{=p.maximum.toExponential()}}, /* .def = */ {{=p.defaultValue.toExponential()}}, - /* .flags = */ {{?p.isBypass}}DATA_PARAM_BYPASS{{??}}0{{?p.toggled}} | DATA_PARAM_TOGGLED{{?}}{{?p.integer}} | DATA_PARAM_INTEGER{{?}}{{?}} + /* .flags = */ {{?p.isBypass}}DATA_PARAM_BYPASS{{??}}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{{?}} }, {{~}} }; diff --git a/templates/vst3/src/vst3.c b/templates/vst3/src/vst3.c index 42ac155..22ba6f3 100644 --- a/templates/vst3/src/vst3.c +++ b/templates/vst3/src/vst3.c @@ -1,6 +1,7 @@ #include #include #include +#include #include "vst3_c_api.h" #include "data.h" #include "plugin.h" @@ -9,11 +10,11 @@ // https://github.com/rubberduck-vba/Rubberduck/wiki/COM-in-plain-C // https://devblogs.microsoft.com/oldnewthing/20040205-00/?p=40733 -#ifdef NDEBUG -# define TRACE(...) /* do nothing */ -#else +#ifdef TIBIA_TRACE # include # define TRACE(...) printf(__VA_ARGS__) +#else +# define TRACE(...) /* do nothing */ #endif #if defined(__i386__) || defined(__x86_64__) @@ -25,13 +26,20 @@ static double clamp(double x, double m, double M) { return x < m ? m : (x > M ? M : x); } -static double parameterMap(Steinberg_Vst_ParamID id, double v) { +static double parameterMapLinear(Steinberg_Vst_ParamID id, double v) { return parameterData[id].min + (parameterData[id].max - parameterData[id].min) * v; } -static double parameterUnmap(Steinberg_Vst_ParamID id, double v) { +static double parameterUnmapLinear(Steinberg_Vst_ParamID id, double v) { return (v - parameterData[id].min) / (parameterData[id].max - parameterData[id].min); } +static double parameterMap(Steinberg_Vst_ParamID id, double v) { + return parameterData[id].flags & DATA_PARAM_MAP_LOG ? parameterData[id].min * exp(parameterData[id].mapK * v) : parameterMapLinear(id, v); +} + +static double parameterUnmap(Steinberg_Vst_ParamID id, double v) { + return parameterData[id].flags & DATA_PARAM_MAP_LOG ? log(v / parameterData[id].min) / parameterData[id].mapK : parameterUnmapLinear(id, v); +} static double parameterAdjust(Steinberg_Vst_ParamID id, double v) { v = parameterData[id].flags & (DATA_PARAM_BYPASS | DATA_PARAM_TOGGLED) ? v >= 0.5 ? 1.0 : 0.0 @@ -437,7 +445,7 @@ static Steinberg_tresult pluginProcess(void* thisInterface, struct Steinberg_Vst if (o != 0) continue; Steinberg_Vst_ParamID id = q->lpVtbl->getParameterId(q); - v = parameterAdjust(id, parameterMap(id, v)); + v = parameterAdjust(id, parameterMapLinear(id, v)); if (v != p->parameters[id]) { p->parameters[id] = v; plugin_set_parameter(&p->p, parameterData[id].index, p->parameters[id]); @@ -504,7 +512,7 @@ static Steinberg_tresult pluginProcess(void* thisInterface, struct Steinberg_Vst if (o <= 0) continue; Steinberg_Vst_ParamID id = q->lpVtbl->getParameterId(q); - v = parameterAdjust(id, parameterMap(id, v)); + v = parameterAdjust(id, parameterMapLinear(id, v)); if (v != p->parameters[id]) { p->parameters[id] = v; plugin_set_parameter(&p->p, parameterData[id].index, p->parameters[id]); @@ -526,7 +534,7 @@ static Steinberg_tresult pluginProcess(void* thisInterface, struct Steinberg_Vst struct Steinberg_Vst_IParamValueQueue *q = data->outputParameterChanges->lpVtbl->addParameterData(data->outputParameterChanges, &id, &index); if (q == NULL) continue; - q->lpVtbl->addPoint(q, data->numSamples - 1, v, &index); + q->lpVtbl->addPoint(q, data->numSamples - 1, parameterUnmap(id, v), &index); } #endif @@ -789,11 +797,13 @@ static Steinberg_tresult controllerGetParamValueByString(void* thisInterface, St static Steinberg_Vst_ParamValue controllerNormalizedParamToPlain(void* thisInterface, Steinberg_Vst_ParamID id, Steinberg_Vst_ParamValue valueNormalized) { TRACE("controller normalized param to plain\n"); +printf("map %d %g -> %g\n", id, valueNormalized, parameterMap(id, valueNormalized)); return parameterMap(id, valueNormalized); } static Steinberg_Vst_ParamValue controllerPlainParamToNormalized(void* thisInterface, Steinberg_Vst_ParamID id, Steinberg_Vst_ParamValue plainValue) { TRACE("controller plain param to normalized\n"); +printf("unmap %d %g -> %g\n", id, plainValue, parameterUnmap(id, plainValue)); return parameterUnmap(id, plainValue); } diff --git a/test/product.json b/test/product.json index 4128589..1229458 100644 --- a/test/product.json +++ b/test/product.json @@ -33,19 +33,20 @@ "direction": "input", "isBypass": false, "isLatency": false, - "defaultValue": 0.0, - "minimum": -60.0, - "maximum": 12.0, + "defaultValue": 10.0, + "minimum": 1.0, + "maximum": 100.0, "toggled": false, "optional": false, "integer": false, "scalePoints": { - "0": 0.0, - "Max": 12.0, - "Min": -60.0 + "0": 1.0, + "Max": 100.0, + "Min": 10.0 }, "list": false, - "unit": "db" + "unit": "db", + "map": "logarithmic" }, { "name": "Bypass", @@ -64,7 +65,8 @@ "On": 1 }, "list": true, - "unit": "" + "unit": "", + "map": "linear" } ] }