diff --git a/notes b/notes new file mode 100644 index 0000000..58b8847 --- /dev/null +++ b/notes @@ -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 +} diff --git a/templates/lv2-make/Makefile b/templates/lv2-make/Makefile index 7782d6e..0927071 100644 --- a/templates/lv2-make/Makefile +++ b/templates/lv2-make/Makefile @@ -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 diff --git a/templates/lv2-make/vars.mk b/templates/lv2-make/vars.mk index 92b8d2a..8d966e7 100644 --- a/templates/lv2-make/vars.mk +++ b/templates/lv2-make/vars.mk @@ -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 : ""}} diff --git a/templates/lv2/data/manifest.ttl b/templates/lv2/data/manifest.ttl index 00e13af..3bca74d 100644 --- a/templates/lv2/data/manifest.ttl +++ b/templates/lv2/data/manifest.ttl @@ -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}} diff --git a/templates/lv2/src/data.h b/templates/lv2/src/data.h index 30b87fa..257f1fe 100644 --- a/templates/lv2/src/data.h +++ b/templates/lv2/src/data.h @@ -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 diff --git a/templates/lv2/src/lv2.c b/templates/lv2/src/lv2.c index d71b850..341ff6c 100644 --- a/templates/lv2/src/lv2.c +++ b/templates/lv2/src/lv2.c @@ -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); } diff --git a/templates/lv2/src/plugin.h b/templates/lv2/src/plugin.h deleted file mode 100644 index e7f186b..0000000 --- a/templates/lv2/src/plugin.h +++ /dev/null @@ -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 -} diff --git a/templates/lv2/tibia-index.js b/templates/lv2/tibia-index.js index 6270a9a..299a9d7 100644 --- a/templates/lv2/tibia-index.js +++ b/templates/lv2/tibia-index.js @@ -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`); }; diff --git a/templates/vst3-make/Makefile b/templates/vst3-make/Makefile index c18ebd6..50300fe 100644 --- a/templates/vst3-make/Makefile +++ b/templates/vst3-make/Makefile @@ -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 diff --git a/templates/vst3-make/vars.mk b/templates/vst3-make/vars.mk index 0826cc2..103ae50 100644 --- a/templates/vst3-make/vars.mk +++ b/templates/vst3-make/vars.mk @@ -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 : ""}} diff --git a/templates/vst3/src/plugin.h b/templates/vst3/src/plugin.h deleted file mode 100644 index e7f186b..0000000 --- a/templates/vst3/src/plugin.h +++ /dev/null @@ -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 -} diff --git a/templates/vst3/tibia-index.js b/templates/vst3/tibia-index.js index 0ed422e..d5ad8cf 100644 --- a/templates/vst3/tibia-index.js +++ b/templates/vst3/tibia-index.js @@ -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`); }; diff --git a/test/lv2.json b/test/lv2.json index 25c438e..42006dd 100644 --- a/test/lv2.json +++ b/test/lv2.json @@ -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" ] } } diff --git a/test/make.json b/test/make.json new file mode 100644 index 0000000..6f2f74c --- /dev/null +++ b/test/make.json @@ -0,0 +1,5 @@ +{ + "make": { + "libs": "-lm" + } +} diff --git a/test/plugin.h b/test/plugin.h index 80a425e..6eb2b64 100644 --- a/test/plugin.h +++ b/test/plugin.h @@ -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++) diff --git a/test/product.json b/test/product.json index 31bf5ae..aeea18a 100644 --- a/test/product.json +++ b/test/product.json @@ -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 } ] } diff --git a/test/run.sh b/test/run.sh index f82e9a1..ef694f5 100755 --- a/test/run.sh +++ b/test/run.sh @@ -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 diff --git a/test/vst3-make.json b/test/vst3-make.json new file mode 100644 index 0000000..172090e --- /dev/null +++ b/test/vst3-make.json @@ -0,0 +1,5 @@ +{ + "vst3_make": { + "cflags": "-I../../../vst3_c_api" + } +} diff --git a/tibia b/tibia index fe15fe0..8421260 100755 --- a/tibia +++ b/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); } };