parameter_unmap

This commit is contained in:
Stefano D'Angelo 2024-02-19 14:40:03 +01:00
parent ecf6c7608a
commit 8f24eb7b8b
21 changed files with 152 additions and 16 deletions

2
TODO
View File

@ -12,7 +12,7 @@
* #if > 0 -> dotjs
* more mappings, lv2 port props
* latency mechanism, see https://steinbergmedia.github.io/vst3_dev_portal/pages/Technical+Documentation/Workflow+Diagrams/Get+Latency+Call+Sequence.html, https://steinbergmedia.github.io/vst3_doc/vstinterfaces/classSteinberg_1_1Vst_1_1IAudioProcessor.html#af8884671ccefe68e0a86e72413a0fcf8, https://steinbergmedia.github.io/vst3_dev_portal/pages/Technical+Documentation/Workflow+Diagrams/Audio+Processor+Call+Sequence.html
* vst3 don't include/link libm if not needed, etc. (reduce to minimum reqs)
* don't include/link libm if not needed, etc. (reduce to minimum reqs)
* proper parameter automation
* proper sample accurate midi (see https://lv2plug.in/book/#_midi_gate)
* whole midi properly (see https://github.com/harryhaaren/lv2/blob/master/lv2/lv2plug.in/ns/ext/midi/midi.h, https://www.midi.org/specifications-old/item/table-1-summary-of-midi-message, http://midi.teragonaudio.com/tech/midispec.htm)

View File

@ -45,7 +45,7 @@ CXXFLAGS = ${CFLAGS}
CXXFLAGS_ALL = -I${DATA_DIR}/src -I${PLUGIN_DIR} -fPIC -std=c++11 ${CXXFLAGS} ${CXXFLAGS_EXTRA}
LDFLAGS =
LDFLAGS_ALL = -shared -static-libstdc++ -landroid
LDFLAGS_ALL = -shared -static-libstdc++ -lm -landroid
ifeq (${HAS_MIDI_IN}, yes)
LDFLAGS += -lamidi
endif

View File

@ -42,6 +42,7 @@ static struct {
# define PARAM_BYPASS 1
# define PARAM_TOGGLED (1<<1)
# define PARAM_INTEGER (1<<2)
# define PARAM_MAP_LOG (1<<3)
static struct {
char out;
@ -49,6 +50,7 @@ static struct {
float min;
float max;
uint32_t flags;
float mapK;
} param_data[PARAMETERS_N] = {
{{~it.product.parameters :p}}
{
@ -56,7 +58,8 @@ static struct {
/* .def = */ {{=p.defaultValue.toExponential()}},
/* .min = */ {{=p.minimum.toExponential()}}f,
/* .max = */ {{=p.maximum.toExponential()}}f,
/* .flags = */ {{?p.isBypass}}PARAM_BYPASS{{??}}0{{?p.toggled}} | PARAM_TOGGLED{{?}}{{?p.integer}} | PARAM_INTEGER{{?}}{{?}}
/* .flags = */ {{?p.isBypass}}PARAM_BYPASS{{??}}0{{?p.toggled}} | PARAM_TOGGLED{{?}}{{?p.integer}} | PARAM_INTEGER{{?}}{{?p.map == "logarithmic"}} | PARAM_MAP_LOG{{?}}{{?}},
/* .mapK = */ {{?p.map == "logarithmic"}}{{=Number(2.0 * Math.log(Math.sqrt(p.maximum * p.minimum) / Math.abs(p.minimum))).toExponential()}}f{{??}}0.f{{?}}
},
{{~}}
};

View File

@ -4,8 +4,20 @@
#include <stdlib.h>
#include <stdint.h>
#include <math.h>
#include "data.h"
#if PARAMETERS_N > 0
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wunused-function"
static float parameter_unmap(size_t index, float value) {
const float v = param_data[index].flags & PARAM_MAP_LOG ? logf(value / param_data[index].min) / param_data[index].mapK : (value - param_data[index].min) / (param_data[index].max - param_data[index].min);
return v < 0.f ? 0.f : (v > 1.f ? 1.f : v);
}
# pragma GCC diagnostic pop
#endif
#include "plugin.h"
#include <string.h>

View File

@ -20,7 +20,7 @@ CFLAGS = -O3 -Wall -Wpedantic -Wextra
CFLAGS_ALL = -I${DATA_DIR}/src -I${PLUGIN_DIR} -I${TINYWAV_DIR} -I${MIDI_PARSER_DIR}/include -fPIC ${CFLAGS} ${CFLAGS_EXTRA}
LDFLAGS =
LDFLAGS_ALL = ${LDFLAGS} ${LDFLAGS_EXTRA}
LDFLAGS_ALL = -lm ${LDFLAGS} ${LDFLAGS_EXTRA}
CXXFLAGS = ${CFLAGS}
CXXFLAGS_ALL = -I${DATA_DIR}/src -I${PLUGIN_DIR} -I${TINYWAV_DIR} -I${MIDI_PARSER_DIR}/include -fPIC ${CXXFLAGS} ${CXXFLAGS_EXTRA}

View File

@ -42,6 +42,7 @@ static struct {
# define PARAM_BYPASS 1
# define PARAM_TOGGLED (1<<1)
# define PARAM_INTEGER (1<<2)
# define PARAM_MAP_LOG (1<<3)
static struct {
const char * id;
@ -50,6 +51,7 @@ static struct {
float min;
float max;
uint32_t flags;
float mapK;
} param_data[PARAMETERS_N] = {
{{~it.product.parameters :p:i}}
{
@ -58,7 +60,8 @@ static struct {
/* .def = */ {{=p.defaultValue.toExponential()}}f,
/* .min = */ {{=p.minimum.toExponential()}}f,
/* .max = */ {{=p.maximum.toExponential()}}f,
/* .flags = */ {{?p.isBypass}}PARAM_BYPASS{{??}}0{{?p.toggled}} | PARAM_TOGGLED{{?}}{{?p.integer}} | PARAM_INTEGER{{?}}{{?}}
/* .flags = */ {{?p.isBypass}}PARAM_BYPASS{{??}}0{{?p.toggled}} | PARAM_TOGGLED{{?}}{{?p.integer}} | PARAM_INTEGER{{?}}{{?p.map == "logarithmic"}} | PARAM_MAP_LOG{{?}}{{?}},
/* .mapK = */ {{?p.map == "logarithmic"}}{{=Number(2.0 * Math.log(Math.sqrt(p.maximum * p.minimum) / Math.abs(p.minimum))).toExponential()}}f{{??}}0.f{{?}}
},
{{~}}
};

View File

@ -1,7 +1,19 @@
#include <stdlib.h>
#include <stdint.h>
#include <math.h>
#include "data.h"
#if PARAMETERS_N > 0
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wunused-function"
static float parameter_unmap(size_t index, float value) {
const float v = param_data[index].flags & PARAM_MAP_LOG ? logf(value / param_data[index].min) / param_data[index].mapK : (value - param_data[index].min) / (param_data[index].max - param_data[index].min);
return v < 0.f ? 0.f : (v > 1.f ? 1.f : v);
}
# pragma GCC diagnostic pop
#endif
#include "plugin.h"
#include <stdio.h>

View File

@ -15,5 +15,5 @@ include ${SYSTEM_FILES_DIR}/Makefile
C_SOURCES += ${C_SRCS_EXTRA}
CFLAGS += -I${DATA_DIR}/src -I${PLUGIN_DIR} ${CFLAGS_EXTRA}
LDFLAGS += ${LDFLAGS_EXTRA}
LDFLAGS += -lm ${LDFLAGS_EXTRA}
CXXFLAGS += -I${DATA_DIR}/src -I${PLUGIN_DIR} ${CXXFLAGS_EXTRA}

View File

@ -2,6 +2,11 @@
#include <stdint.h>
#include "data.h"
#if NUM_PARAMETERS > 0
float parameter_unmap(size_t index, float value);
#endif
#include "plugin.h"
#include <string.h>
@ -56,11 +61,9 @@ static float parameterMap(int i, float v) {
return param_data[i].flags & PARAM_MAP_LOG ? param_data[i].min * expf(param_data[i].mapK * v) : param_data[i].min + (param_data[i].max - param_data[i].min) * v;
}
/*
static float parameterUnmap(int i, float v) {
return param_data[i].flags & PARAM_MAP_LOG ? logf(v / param_data[i].min) / param_data[i].mapK : (v - param_data[i].min) / (param_data[i].max - param_data[i].min);
}
*/
static float parameterAdjust(int i, float v) {
v = param_data[i].flags & (PARAM_BYPASS | PARAM_TOGGLED) ? (v >= 0.5f ? 1.f : 0.f)
@ -71,6 +74,13 @@ static float parameterAdjust(int i, float v) {
static void setParameter(int i, float v) {
plugin_set_parameter(&instance, i, parameterAdjust(i, v));
}
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wunused-function"
float parameter_unmap(size_t index, float value) {
return clampf(parameterUnmap(index, value), 0.f, 1.f);
}
# pragma GCC diagnostic pop
#endif
#if NUM_ADC > 0

View File

@ -42,6 +42,7 @@ static struct {
# define PARAM_BYPASS 1
# define PARAM_TOGGLED (1<<1)
# define PARAM_INTEGER (1<<2)
# define PARAM_MAP_LOG (1<<3)
static struct {
char out;
@ -49,6 +50,7 @@ static struct {
float min;
float max;
uint32_t flags;
float mapK;
} param_data[PARAMETERS_N] = {
{{~it.product.parameters :p}}
{
@ -56,7 +58,8 @@ static struct {
/* .def = */ {{=p.defaultValue.toExponential()}},
/* .min = */ {{=p.minimum.toExponential()}}f,
/* .max = */ {{=p.maximum.toExponential()}}f,
/* .flags = */ {{?p.isBypass}}PARAM_BYPASS{{??p.isLatency}}PARAM_INTEGER{{??}}0{{?p.toggled}} | PARAM_TOGGLED{{?}}{{?p.integer}} | PARAM_INTEGER{{?}}{{?}}
/* .flags = */ {{?p.isBypass}}PARAM_BYPASS{{??}}0{{?p.toggled}} | PARAM_TOGGLED{{?}}{{?p.integer}} | PARAM_INTEGER{{?}}{{?p.map == "logarithmic"}} | PARAM_MAP_LOG{{?}}{{?}},
/* .mapK = */ {{?p.map == "logarithmic"}}{{=Number(2.0 * Math.log(Math.sqrt(p.maximum * p.minimum) / Math.abs(p.minimum))).toExponential()}}f{{??}}0.f{{?}}
},
{{~}}
};

View File

@ -4,9 +4,22 @@
#include <stdlib.h>
#include <stdint.h>
#include <math.h>
#include "data.h"
#if PARAMETERS_N > 0
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wunused-function"
static float parameter_unmap(size_t index, float value) {
const float v = param_data[index].flags & PARAM_MAP_LOG ? logf(value / param_data[index].min) / param_data[index].mapK : (value - param_data[index].min) / (param_data[index].max - param_data[index].min);
return v < 0.f ? 0.f : (v > 1.f ? 1.f : v);
}
# pragma GCC diagnostic pop
#endif
#include "plugin.h"
#if PARAMETERS_N > 0
#include <algorithm>
#endif

View File

@ -32,7 +32,7 @@ CFLAGS = -O3 -Wall -Wpedantic -Wextra
CFLAGS_ALL = -I${DATA_DIR}/src -I${PLUGIN_DIR} -fPIC ${CFLAGS} ${CFLAGS_EXTRA}
LDFLAGS =
LDFLAGS_ALL = -shared ${LDFLAGS} ${LDFLAGS_EXTRA}
LDFLAGS_ALL = -shared -lm ${LDFLAGS} ${LDFLAGS_EXTRA}
CXXFLAGS = ${CFLAGS}
CXXFLAGS_ALL = -I${DATA_DIR}/src -I${PLUGIN_DIR} -fPIC ${CXXFLAGS} ${CXXFLAGS_EXTRA}

View File

@ -18,6 +18,7 @@ static uint32_t midi_in_index[DATA_PRODUCT_MIDI_INPUTS_N] = {
# 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 {
uint32_t index;
@ -25,6 +26,7 @@ static struct {
float max;
float def;
uint32_t flags;
float mapK;
} param_data[DATA_PRODUCT_CONTROL_INPUTS_N] = {
{{~it.tibia.lv2.ports.filter(x => x.type == "control" && x.direction == "input") :p}}
{
@ -32,11 +34,16 @@ static struct {
/* .min = */ {{=p.minimum.toExponential()}}f,
/* .max = */ {{=p.maximum.toExponential()}}f,
/* .def = */ {{=p.defaultValue.toExponential()}}f,
/* .flags = */ {{?p.isBypass}}DATA_PARAM_BYPASS{{??p.isLatency}}DATA_PARAM_INTEGER{{??}}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()}}f{{??}}0.f{{?}}
},
{{~}}
};
static uint32_t param_in_data_index[DATA_PRODUCT_CONTROL_INPUTS_N + DATA_PRODUCT_CONTROL_OUTPUTS_N] = {
{{~it.tibia.lv2.ports.filter(x => x.type == "control") :p}}{{=p.inDataIndex >= 0 ? p.inDataIndex : "(uint32_t)-1"}}, {{~}}
};
#endif
#if DATA_PRODUCT_CONTROL_OUTPUTS_N > 0

View File

@ -1,7 +1,20 @@
#include <stdlib.h>
#include <stdint.h>
#include <math.h>
#include "data.h"
#if DATA_PRODUCT_CONTROL_INPUTS_N > 0
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wunused-function"
static float parameter_unmap(size_t index, float value) {
const uint32_t i = param_in_data_index[index];
const float v = param_data[i].flags & DATA_PARAM_MAP_LOG ? logf(value / param_data[i].min) / param_data[i].mapK : (value - param_data[i].min) / (param_data[i].max - param_data[i].min);
return v < 0.f ? 0.f : (v > 1.f ? 1.f : v);
}
# pragma GCC diagnostic pop
#endif
#include "plugin.h"
#include "lv2/core/lv2.h"

View File

@ -91,12 +91,18 @@ module.exports = function (data, api, outputCommon, outputData) {
data.tibia.lv2.ports.push.apply(data.tibia.lv2.ports, midiPorts);
var ports = [];
var j = 0;
for (var i = 0; i < data.product.parameters.length; i++) {
var p = data.product.parameters[i];
var e = Object.create(p);
e.type = "control";
e.symbol = data.lv2.parameterSymbols[i];
e.paramIndex = i;
if (p.direction == "input") {
e.inDataIndex = j;
j++;
} else
e.inDataIndex = -1;
ports.push(e);
}
ports.sort((a, b) => a.direction != b.direction ? (a.direction == "input" ? -1 : 1) : 0);

View File

@ -190,6 +190,10 @@ static struct {
{{~}}
};
static size_t paramDataIndex[DATA_PRODUCT_PARAMETERS_N] = {
{{~it.product.parameters.filter(x => !x.isLatency) :p}}{{=p.dataIndex >= 0 ? p.dataIndex : "(size_t)-1"}}, {{~}}
};
# endif
#endif

View File

@ -7,6 +7,11 @@
#include "vst3_c_api.h"
#pragma GCC diagnostic pop
#include "data.h"
#if DATA_PRODUCT_CONTROL_INPUTS_N > 0
static float parameter_unmap(size_t index, float value);
#endif
#include "plugin.h"
#if defined(__i386__) || defined(__x86_64__)
@ -48,6 +53,15 @@ static double parameterAdjust(Steinberg_Vst_ParamID id, double v) {
return clamp(v, parameterData[id].min, parameterData[id].max);
}
#if DATA_PRODUCT_PARAMETERS_N > 0
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wunused-function"
static float parameter_unmap(size_t index, float value) {
return clamp(parameterUnmap(paramDataIndex[index], value), 0.0, 1.0);
}
# pragma GCC diagnostic pop
#endif
typedef struct pluginInstance {
Steinberg_Vst_IComponentVtbl * vtblIComponent;
Steinberg_Vst_IAudioProcessorVtbl * vtblIAudioProcessor;

View File

@ -32,8 +32,17 @@ module.exports = function (data, api, outputCommon, outputData) {
}
};
for (var i = 0; i < data.product.parameters.length; i++)
data.product.parameters[i].paramIndex = i;
var j = 0;
for (var i = 0; i < data.product.parameters.length; i++) {
var p = data.product.parameters[i]
p.paramIndex = i;
if (p.isLatency)
p.dataIndex = -1;
else {
p.dataIndex = j;
j++;
}
}
}
api.generateFileFromTemplateFile(`data${sep}Info.plist`, `data${sep}Info.plist`, data);

View File

@ -3,17 +3,24 @@
#define DATA_PRODUCT_MIDI_INPUTS_N {{=it.product.buses.filter(x => x.type == "midi" && x.direction == "input").length}}
#define DATA_PRODUCT_MIDI_OUTPUTS_N {{=it.product.buses.filter(x => x.type == "midi" && x.direction == "output").length}}
#define DATA_PRODUCT_PARAMETERS_N {{=it.product.parameters.length}}
#define DATA_PRODUCT_PARAMETERS_INPUT_N {{=it.product.parameters.filter(x => x.direction == "input").length}}
#define DATA_PRODUCT_PARAMETERS_OUTPUT_N {{=it.product.parameters.filter(x => x.direction == "output").length}}
#if DATA_PRODUCT_PARAMETERS_N > 0
static struct {
char out;
float min;
float max;
float def;
float mapK;
} param_data[DATA_PRODUCT_PARAMETERS_N] = {
{{~it.product.parameters :p}}
{
/* .out = */ {{=p.direction == "output" ? 1 : 0}},
/* .def = */ {{=p.defaultValue.toExponential()}}
/* .out = */ {{=p.direction == "output" ? 1 : 0}},
/* .min = */ {{=p.minimum.toExponential()}}f,
/* .max = */ {{=p.maximum.toExponential()}}f,
/* .def = */ {{=p.defaultValue.toExponential()}},
/* .mapK = */ {{?p.map == "logarithmic"}}{{=Number(2.0 * Math.log(Math.sqrt(p.maximum * p.minimum) / Math.abs(p.minimum))).toExponential()}}f{{??}}0.f{{?}}
},
{{~}}
};

View File

@ -6,6 +6,26 @@
#include <stdint.h>
#include "data.h"
#if DATA_PRODUCT_PARAMETERS_INPUT_N > 0
static float logf(float x) {
union { float f; int32_t i; } v;
v.f = x;
int e = v.i >> 23;
v.i = (v.i & 0x007fffff) | 0x3f800000;
const float y = (float)e - 129.213475204444817f + v.f * (3.148297929334117f + v.f * (-1.098865286222744f + v.f * 0.1640425613334452f));
return 0.693147180559945f * y;
}
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wunused-function"
static float parameter_unmap(size_t index, float value) {
const float v = param_data[index].mapK != 0 ? logf(value / param_data[index].min) / param_data[index].mapK : (value - param_data[index].min) / (param_data[index].max - param_data[index].min);
return v < 0.f ? 0.f : (v > 1.f ? 1.f : v);
}
# pragma GCC diagnostic pop
#endif
#include "plugin.h"
#include "memset.h"

View File

@ -91,7 +91,7 @@ static void plugin_process(plugin *instance, const float **inputs, float **outpu
static void plugin_midi_msg_in(plugin *instance, size_t index, const uint8_t * data) {
(void)index;
if ((data[0] & 0xf0 == 0x90) && (data[2] != 0))
if (((data[0] & 0xf0) == 0x90) && (data[2] != 0))
//approx instance->cutoff_k = powf(2.f, (1.f / 12.f) * (note - 60));
instance->cutoff_k = data[1] < 64 ? (-0.19558034980097166f * data[1] - 2.361735109225749f) / (data[1] - 75.57552349522389f) : (393.95397927344214f - 7.660826245588588f * data[1]) / (data[1] - 139.0755234952239f);
}