slowly covering lv2 core
This commit is contained in:
parent
520b1ff9cf
commit
8d577e7e46
26
notes
Normal file
26
notes
Normal file
@ -0,0 +1,26 @@
|
||||
company {
|
||||
name:
|
||||
VST3: PFactoryInfo.vendor
|
||||
LV2: not used
|
||||
url:
|
||||
VST3: PFactoryInfo.url
|
||||
LV2: not used
|
||||
email:
|
||||
VST3: PFactoryInfo.email
|
||||
LV2: not used
|
||||
}
|
||||
|
||||
product {
|
||||
name:
|
||||
VST3: PClassInfo{,2,W}.name
|
||||
LV2: manifest.ttl plugin doap:name
|
||||
version:
|
||||
VST3: PClassInfo{2,W}.version (first 3 numbers)
|
||||
LV2: not used
|
||||
buildVersion:
|
||||
VST3: PClassInfo{2,W}.version (last number)
|
||||
LV2: not used
|
||||
bundleName:
|
||||
VST3: plugin folder name, plugin .dll name, Info.plist
|
||||
LV2: plugin folder name, plugin .dll name, manifest.ttl plugin lv2:binary
|
||||
}
|
@ -5,7 +5,7 @@ CFLAGS = -fPIC -Wall -Wpedantic -Wextra -Wno-unused-parameter
|
||||
|
||||
BUNDLE_DIR = ${BUNDLE_NAME}.lv2
|
||||
|
||||
SO_FILE := ${BUNDLE_NAME}.so
|
||||
SO_FILE = ${BUNDLE_NAME}.so
|
||||
|
||||
all: build/${BUNDLE_DIR}/manifest.ttl build/${BUNDLE_DIR}/${SO_FILE}
|
||||
|
||||
@ -13,7 +13,7 @@ build/${BUNDLE_DIR}/manifest.ttl: data/manifest.ttl | build/${BUNDLE_DIR}
|
||||
cp $^ $@
|
||||
|
||||
build/${BUNDLE_DIR}/${SO_FILE}: src/lv2.c | build/${BUNDLE_DIR}
|
||||
${CC} $^ -o $@ ${CFLAGS} -shared
|
||||
${CC} $^ -o $@ ${CFLAGS} ${CFLAGS_EXTRA} ${LIBS_EXTRA} -shared
|
||||
|
||||
build/${BUNDLE_DIR}:
|
||||
mkdir -p $@
|
||||
@ -21,4 +21,4 @@ build/${BUNDLE_DIR}:
|
||||
clean:
|
||||
rm -fr build
|
||||
|
||||
.PHONY: clean
|
||||
.PHONY: all clean
|
||||
|
@ -1 +1,3 @@
|
||||
BUNDLE_NAME := {{=it.product.bundleName}}
|
||||
CFLAGS_EXTRA := {{=it.make && it.make.cflags ? it.make.cflags : ""}} {{=it.lv2_make && it.lv2_make.cflags ? it.lv2_make.cflags : ""}}
|
||||
LIBS_EXTRA := {{=it.make && it.make.libs ? it.make.libs : ""}} {{=it.lv2_make && it.lv2_make.libs ? it.lv2_make.libs : ""}}
|
||||
|
@ -12,12 +12,17 @@
|
||||
{{?}}
|
||||
lv2:binary <{{=it.product.bundleName}}.so> ;
|
||||
doap:name "{{=it.product.name}}" ;
|
||||
lv2:minorVersion {{=/^([0-9]+)\./.exec(it.lv2.version)[1]}} ;
|
||||
lv2:microVersion {{=/^[0-9]+\.([0-9]+)/.exec(it.lv2.version)[1]}} ;
|
||||
lv2:optionalFeature lv2:hardRTCapable ;
|
||||
lv2:port [
|
||||
{{~it.tibia.lv2.ports :p:i}}
|
||||
a {{?p.type == "control"}}lv2:ControlPort{{??}}{{?p.cv}}lv2:CVPort{{??}}lv2:AudioPort{{?}}{{?}} ,
|
||||
{{?p.direction == "input"}}lv2:InputPort{{??}}lv2:OutputPort{{?}} ;
|
||||
lv2:name "{{=p.name}}" ;
|
||||
{{?"shortName" in p}}
|
||||
lv2:shortName "{{=p.shortName.substring(0, 16)}}" ;
|
||||
{{?}}
|
||||
lv2:symbol "{{=p.symbol}}" ;
|
||||
{{?"defaultValue" in p}}
|
||||
lv2:default {{=p.defaultValue.toExponential()}} ;
|
||||
@ -30,6 +35,18 @@
|
||||
{{?}}
|
||||
{{?p.sidechain}}
|
||||
lv2:portProperty lv2:isSideChain ;
|
||||
{{?}}
|
||||
{{?p.isBypass}}
|
||||
lv2:designation lv2:enabled ;
|
||||
{{?}}
|
||||
{{?p.isLatency}}
|
||||
lv2:designation lv2:latency ;
|
||||
{{?}}
|
||||
{{?p.toggled}}
|
||||
lv2:portProperty lv2:toggled ;
|
||||
{{?}}
|
||||
{{?p.optional}}
|
||||
lv2:portProperty lv2:connectionOptional ;
|
||||
{{?}}
|
||||
lv2:index {{=i}}
|
||||
{{?i < it.tibia.lv2.ports.length - 1}}
|
||||
|
@ -6,7 +6,24 @@
|
||||
#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, {{~}}
|
||||
|
||||
# define DATA_PARAM_BYPASS 1
|
||||
# define DATA_PARAM_TOGGLED (1<<1)
|
||||
|
||||
static struct {
|
||||
float min;
|
||||
float max;
|
||||
float def;
|
||||
uint32_t flags;
|
||||
} param_data[DATA_PRODUCT_CONTROL_INPUTS_N] = {
|
||||
{{~it.tibia.lv2.ports.filter(x => x.type == "control" && x.direction == "input") :p}}
|
||||
{
|
||||
/* .min = */ {{=p.minimum.toExponential()}}f,
|
||||
/* .max = */ {{=p.maximum.toExponential()}}f,
|
||||
/* .def = */ {{=p.defaultValue.toExponential()}}f,
|
||||
/* .flags = */ 0{{?p.isBypass}} | DATA_PARAM_BYPASS{{?}}{{?p.toggled}} | DATA_PARAM_TOGGLED{{?}}
|
||||
},
|
||||
{{~}}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -26,6 +26,14 @@ static LV2_Handle instantiate(const struct LV2_Descriptor * descriptor, double s
|
||||
return NULL;
|
||||
plugin_init(&instance->p);
|
||||
plugin_set_sample_rate(&instance->p, sample_rate);
|
||||
#if DATA_PRODUCT_AUDIO_INPUT_CHANNELS_N > 0
|
||||
for (size_t i = 0; i < DATA_PRODUCT_AUDIO_INPUT_CHANNELS_N; i++)
|
||||
instance->x[i] = NULL;
|
||||
#endif
|
||||
#if DATA_PRODUCT_AUDIO_OUTPUT_CHANNELS_N > 0
|
||||
for (size_t i = 0; i < DATA_PRODUCT_AUDIO_OUTPUT_CHANNELS_N; i++)
|
||||
instance->y[i] = NULL;
|
||||
#endif
|
||||
#if DATA_PRODUCT_CONTROL_INPUTS_N > 0
|
||||
for (size_t i = 0; i < DATA_PRODUCT_CONTROL_INPUTS_N; i++)
|
||||
instance->c[i] = NULL;
|
||||
@ -58,22 +66,39 @@ 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];
|
||||
i->params[j] = i->c[j] != NULL ? *i->c[j] : param_data[j].def;
|
||||
plugin_set_parameter(&i->p, j, i->params[j]);
|
||||
}
|
||||
#endif
|
||||
plugin_reset(&i->p);
|
||||
}
|
||||
|
||||
static inline float clampf(float x, float m, float M) {
|
||||
return x < m ? m : (x > M ? M : x);
|
||||
}
|
||||
|
||||
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]);
|
||||
for (size_t j = 0; j < DATA_PRODUCT_CONTROL_INPUTS_N; j++) {
|
||||
if (i->c[j] == NULL)
|
||||
continue;
|
||||
float v;
|
||||
if (param_data[j].flags & DATA_PARAM_BYPASS)
|
||||
v = *i->c[j] > 0.f ? 0.f : 1.f;
|
||||
else if (param_data[j].flags & DATA_PARAM_TOGGLED)
|
||||
v = *i->c[j] > 0.f ? 1.f : 0.f;
|
||||
else
|
||||
v = clampf(*i->c[j], param_data[j].min, param_data[j].max);
|
||||
|
||||
if (v != i->params[j]) {
|
||||
i->params[j] = v;
|
||||
plugin_set_parameter(&i->p, j, v);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
plugin_process(&i->p, i->x, i->y, sample_count);
|
||||
}
|
||||
|
||||
|
@ -1,28 +0,0 @@
|
||||
typedef struct plugin {
|
||||
// FILL ME
|
||||
char abc;
|
||||
} plugin;
|
||||
|
||||
void plugin_init(plugin *instance) {
|
||||
// WRITE ME
|
||||
}
|
||||
|
||||
void plugin_fini(plugin *instance) {
|
||||
// WRITE ME
|
||||
}
|
||||
|
||||
void plugin_set_sample_rate(plugin *instance, float sample_rate) {
|
||||
// WRITE ME
|
||||
}
|
||||
|
||||
void plugin_reset(plugin *instance) {
|
||||
// WRITE ME
|
||||
}
|
||||
|
||||
void plugin_set_parameter(plugin *instance, size_t index, float value) {
|
||||
// WRITE ME
|
||||
}
|
||||
|
||||
void plugin_process(plugin *instance, const float **inputs, float **outputs, size_t n_samples) {
|
||||
// WRITE ME
|
||||
}
|
@ -27,23 +27,11 @@ module.exports = function (data, api) {
|
||||
for (var id in data.lv2.prefixes)
|
||||
data.tibia.lv2.prefixes.push({ id: id, uri: data.lv2.prefixes[id] });
|
||||
|
||||
var symbols = {};
|
||||
function getSymbol(name) {
|
||||
name = name.toLowerCase().replace(/[^0-9a-z]/g, "_");
|
||||
var n = name;
|
||||
var i = 1;
|
||||
while (n in symbols) {
|
||||
n = name + i;
|
||||
i++;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
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 = getSymbol(p.shortName);
|
||||
e.symbol = data.lv2.parameterSymbols[i];
|
||||
data.tibia.lv2.ports.push(e);
|
||||
}
|
||||
|
||||
@ -52,7 +40,7 @@ module.exports = function (data, api) {
|
||||
var b = audioBuses[i];
|
||||
for (var j = 0; j < b.channels; j++) {
|
||||
var e = { type: "audio", direction: b.direction, name: b.name, sidechain: b.sidechain, cv: b.cv };
|
||||
e.symbol = getSymbol(b.name);
|
||||
e.symbol = data.lv2.busSymbols[i] + "_" + j;
|
||||
data.tibia.lv2.ports.push(e);
|
||||
}
|
||||
}
|
||||
@ -62,5 +50,4 @@ module.exports = function (data, api) {
|
||||
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);
|
||||
api.copyFileIfNotExists(`src${sep}plugin.h`, `src${sep}plugin.h`);
|
||||
};
|
||||
|
@ -5,8 +5,8 @@ CFLAGS = -fPIC -Wall -Wpedantic -Wextra -Wno-unused-parameter
|
||||
|
||||
BUNDLE_DIR = ${BUNDLE_NAME}.vst3
|
||||
|
||||
SO_DIR := $(shell uname -m)-linux
|
||||
SO_FILE := ${SO_DIR}/${BUNDLE_NAME}.so
|
||||
SO_DIR = $(shell uname -m)-linux
|
||||
SO_FILE = ${SO_DIR}/${BUNDLE_NAME}.so
|
||||
|
||||
all: build/${BUNDLE_DIR}/Contents/Info.plist build/${BUNDLE_DIR}/Contents/${SO_FILE}
|
||||
|
||||
@ -14,7 +14,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} -I${VST3_C_API_DIR} -shared
|
||||
${CC} $^ -o $@ ${CFLAGS} ${CFLAGS_EXTRA} ${LIBS_EXTRA} -shared
|
||||
|
||||
build/${BUNDLE_DIR}/Contents build/${BUNDLE_DIR}/Contents/${SO_DIR}:
|
||||
mkdir -p $@
|
||||
@ -22,4 +22,4 @@ build/${BUNDLE_DIR}/Contents build/${BUNDLE_DIR}/Contents/${SO_DIR}:
|
||||
clean:
|
||||
rm -fr build
|
||||
|
||||
.PHONY: clean
|
||||
.PHONY: all clean
|
||||
|
@ -1,2 +1,3 @@
|
||||
BUNDLE_NAME := {{=it.product.bundleName}}
|
||||
VST3_C_API_DIR := ../../../vst3_c_api
|
||||
CFLAGS_EXTRA := {{=it.make && it.make.cflags ? it.make.cflags : ""}} {{=it.vst3_make && it.vst3_make.cflags ? it.vst3_make.cflags : ""}}
|
||||
LIBS_EXTRA := {{=it.make && it.make.libs ? it.make.libs : ""}} {{=it.vst3_make && it.vst3_make.libs ? it.vst3_make.libs : ""}}
|
||||
|
@ -1,28 +0,0 @@
|
||||
typedef struct plugin {
|
||||
// FILL ME
|
||||
char abc;
|
||||
} plugin;
|
||||
|
||||
void plugin_init(plugin *instance) {
|
||||
// WRITE ME
|
||||
}
|
||||
|
||||
void plugin_fini(plugin *instance) {
|
||||
// WRITE ME
|
||||
}
|
||||
|
||||
void plugin_set_sample_rate(plugin *instance, float sample_rate) {
|
||||
// WRITE ME
|
||||
}
|
||||
|
||||
void plugin_reset(plugin *instance) {
|
||||
// WRITE ME
|
||||
}
|
||||
|
||||
void plugin_set_parameter(plugin *instance, size_t index, float value) {
|
||||
// WRITE ME
|
||||
}
|
||||
|
||||
void plugin_process(plugin *instance, const float **inputs, float **outputs, size_t n_samples) {
|
||||
// WRITE ME
|
||||
}
|
@ -5,5 +5,4 @@ module.exports = function (data, api) {
|
||||
api.generateFileFromTemplateFile(`data${sep}Info.plist`, `data${sep}Info.plist`, data);
|
||||
api.copyFile(`src${sep}vst3.c`, `src${sep}vst3.c`);
|
||||
api.generateFileFromTemplateFile(`src${sep}data.h`, `src${sep}data.h`, data);
|
||||
api.copyFileIfNotExists(`src${sep}plugin.h`, `src${sep}plugin.h`);
|
||||
};
|
||||
|
@ -5,6 +5,9 @@
|
||||
},
|
||||
"uri": "@example:tibia_test",
|
||||
"project": "@example:project",
|
||||
"types": [ "@lv2:AmplifierPlugin" ]
|
||||
"types": [ "@lv2:AmplifierPlugin" ],
|
||||
"version": "1.0",
|
||||
"busSymbols": [ "input", "output" ],
|
||||
"parameterSymbols": [ "gain", "bypass" ]
|
||||
}
|
||||
}
|
||||
|
5
test/make.json
Normal file
5
test/make.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"make": {
|
||||
"libs": "-lm"
|
||||
}
|
||||
}
|
@ -30,6 +30,11 @@ void plugin_set_parameter(plugin *instance, size_t index, float value) {
|
||||
}
|
||||
}
|
||||
|
||||
float plugin_get_parameter(plugin *instance, size_t index) {
|
||||
// no output parameters
|
||||
return 0.f;
|
||||
}
|
||||
|
||||
void plugin_process(plugin *instance, const float **inputs, float **outputs, size_t n_samples) {
|
||||
const float g = instance->bypass ? 1.f : powf(10.f, 0.05f * instance->gain);
|
||||
for (size_t i = 0; i < n_samples; i++)
|
||||
|
@ -10,16 +10,20 @@
|
||||
"direction": "input",
|
||||
"channels": 1,
|
||||
"name": "Input",
|
||||
"shortName": "Input",
|
||||
"sidechain": false,
|
||||
"cv": false
|
||||
"cv": false,
|
||||
"optional": false
|
||||
},
|
||||
{
|
||||
"type": "audio",
|
||||
"direction": "output",
|
||||
"channels": 1,
|
||||
"name": "Output",
|
||||
"shortName": "Output",
|
||||
"sidechain": false,
|
||||
"cv": false
|
||||
"cv": false,
|
||||
"optional": false
|
||||
}
|
||||
],
|
||||
"parameters": [
|
||||
@ -30,9 +34,12 @@
|
||||
"steps": 0,
|
||||
"direction": "input",
|
||||
"isBypass": false,
|
||||
"isLatency": false,
|
||||
"defaultValue": 0.0,
|
||||
"minimum": -60.0,
|
||||
"maximum": 12.0
|
||||
"maximum": 12.0,
|
||||
"toggled": false,
|
||||
"optional": false
|
||||
},
|
||||
{
|
||||
"name": "Bypass",
|
||||
@ -41,9 +48,12 @@
|
||||
"steps": 1,
|
||||
"direction": "input",
|
||||
"isBypass": true,
|
||||
"defaultValue": 0.0,
|
||||
"isLatency": false,
|
||||
"defaultValue": 0,
|
||||
"minimum": 0,
|
||||
"maximum": 1
|
||||
"maximum": 1,
|
||||
"toggled": true,
|
||||
"optional": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -2,8 +2,8 @@
|
||||
|
||||
dir=`dirname $0`
|
||||
$dir/../tibia $dir/product.json,$dir/company.json,$dir/vst3.json $dir/../templates/vst3 $dir/../out/vst3
|
||||
$dir/../tibia $dir/product.json,$dir/company.json,$dir/vst3.json $dir/../templates/vst3-make $dir/../out/vst3
|
||||
$dir/../tibia $dir/product.json,$dir/company.json,$dir/vst3.json,$dir/make.json,$dir/vst3-make.json $dir/../templates/vst3-make $dir/../out/vst3
|
||||
cp $dir/plugin.h $dir/../out/vst3/src
|
||||
$dir/../tibia $dir/product.json,$dir/company.json,$dir/lv2.json $dir/../templates/lv2 $dir/../out/lv2
|
||||
$dir/../tibia $dir/product.json,$dir/company.json,$dir/lv2.json $dir/../templates/lv2-make $dir/../out/lv2
|
||||
$dir/../tibia $dir/product.json,$dir/company.json,$dir/lv2.json,$dir/make.json $dir/../templates/lv2-make $dir/../out/lv2
|
||||
cp $dir/plugin.h $dir/../out/lv2/src
|
||||
|
5
test/vst3-make.json
Normal file
5
test/vst3-make.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"vst3_make": {
|
||||
"cflags": "-I../../../vst3_c_api"
|
||||
}
|
||||
}
|
9
tibia
9
tibia
@ -62,15 +62,6 @@ var api = {
|
||||
var dir = outputDir + path.sep + path.dirname(outFile);
|
||||
fs.mkdirSync(dir, { recursive: true });
|
||||
fs.copyFileSync(template + path.sep + inFile, outputDir + path.sep + outFile);
|
||||
},
|
||||
|
||||
copyFileIfNotExists: function (inFile, outFile) {
|
||||
var p = outputDir + path.sep + outFile;
|
||||
if (fs.existsSync(p))
|
||||
return;
|
||||
var dir = outputDir + path.sep + path.dirname(outFile);
|
||||
fs.mkdirSync(dir, { recursive: true });
|
||||
fs.copyFileSync(template + path.sep + inFile, p);
|
||||
}
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user