LV2: check required feature and options

When discovering LV2 plugins, verify if a plugin's required features
and required options can be be satisfied.

This replaces a previous blacklist with a whitelist of supported
features/options.
This commit is contained in:
Robin Gareus 2019-04-10 00:19:39 +02:00
parent 59b1193b56
commit 7fc7c18a07
Signed by: rgareus
GPG Key ID: A090BCE02CF57F04

View File

@ -82,6 +82,7 @@
#include "lv2/lv2plug.in/ns/extensions/units/units.h"
#include "lv2/lv2plug.in/ns/ext/patch/patch.h"
#include "lv2/lv2plug.in/ns/ext/port-groups/port-groups.h"
#include "lv2/lv2plug.in/ns/ext/parameters/parameters.h"
#ifdef HAVE_LV2_1_2_0
#include "lv2/lv2plug.in/ns/ext/buf-size/buf-size.h"
#include "lv2/lv2plug.in/ns/ext/options/options.h"
@ -180,6 +181,7 @@ public:
LilvNode* units_midiNote;
LilvNode* patch_writable;
LilvNode* patch_Message;
LilvNode* opts_requiredOptions;
#ifdef HAVE_LV2_1_2_0
LilvNode* bufz_powerOf2BlockLength;
LilvNode* bufz_fixedBlockLength;
@ -624,22 +626,6 @@ LV2Plugin::init(const void* c_plugin, samplecnt_t rate)
throw failed_constructor();
}
#ifdef HAVE_LV2_1_2_0
LilvNodes *required_features = lilv_plugin_get_required_features (plugin);
if (lilv_nodes_contains (required_features, _world.bufz_powerOf2BlockLength) ||
lilv_nodes_contains (required_features, _world.bufz_fixedBlockLength)
) {
error << string_compose(
_("LV2: \"%1\" buffer-size requirements cannot be satisfied."),
lilv_node_as_string(_impl->name)) << endmsg;
lilv_node_free(_impl->name);
lilv_node_free(_impl->author);
lilv_nodes_free(required_features);
throw failed_constructor();
}
lilv_nodes_free(required_features);
#endif
LilvNodes* optional_features = lilv_plugin_get_optional_features (plugin);
#ifdef HAVE_LV2_1_2_0
if (lilv_nodes_contains (optional_features, _world.bufz_coarseBlockLength)) {
@ -3258,6 +3244,7 @@ LV2World::LV2World()
units_db = lilv_new_uri(world, LV2_UNITS__db);
patch_writable = lilv_new_uri(world, LV2_PATCH__writable);
patch_Message = lilv_new_uri(world, LV2_PATCH__Message);
opts_requiredOptions = lilv_new_uri(world, LV2_OPTIONS__requiredOption);
#ifdef LV2_EXTENDED
lv2_noSampleAccurateCtrl = lilv_new_uri(world, "http://ardour.org/lv2/ext#noSampleAccurateControls"); // deprecated 2016-09-18
auto_can_write_automatation = lilv_new_uri(world, LV2_AUTOMATE_URI__can_write);
@ -3294,6 +3281,7 @@ LV2World::~LV2World()
lilv_node_free(auto_automation_controller);
#endif
lilv_node_free(patch_Message);
lilv_node_free(opts_requiredOptions);
lilv_node_free(patch_writable);
lilv_node_free(units_hz);
lilv_node_free(units_midiNote);
@ -3485,18 +3473,56 @@ LV2PluginInfo::discover()
}
#ifdef HAVE_LV2_1_2_0
LilvNodes *required_features = lilv_plugin_get_required_features (p);
if (lilv_nodes_contains (required_features, world.bufz_powerOf2BlockLength) ||
lilv_nodes_contains (required_features, world.bufz_fixedBlockLength)
) {
warning << string_compose(
_("Ignoring LV2 plugin \"%1\" because its buffer-size requirements cannot be satisfied."),
lilv_node_as_string(name)) << endmsg;
lilv_nodes_free(required_features);
lilv_node_free(name);
int err = 0;
LilvNodes* required_features = lilv_plugin_get_required_features (p);
LILV_FOREACH(nodes, i, required_features) {
const char* rf = lilv_node_as_uri (lilv_nodes_get (required_features, i));
bool ok = false;
if (!strcmp (rf, "http://lv2plug.in/ns/ext/instance-access")) { ok = true; }
if (!strcmp (rf, "http://lv2plug.in/ns/ext/data-access")) { ok = true; }
if (!strcmp (rf, LV2_STATE__makePath)) { ok = true; }
if (!strcmp (rf, LV2_LOG__log)) { ok = true; }
if (!strcmp (rf, LV2_WORKER__schedule)) { ok = true; }
if (!strcmp (rf, LV2_STATE_PREFIX "loadDefaultState")) { ok = true; }
if (!strcmp (rf, LV2_URID_MAP_URI)) { ok = true; }
if (!strcmp (rf, LV2_URID_UNMAP_URI)) { ok = true; }
if (!strcmp (rf, "http://lv2plug.in/ns/lv2core#isLive")) { ok = true; }
if (!ok) {
warning << string_compose (
_("Unsupported required LV2 feature: '%1' in '%2'."),
rf, lilv_node_as_string(name)) << endmsg;
err = 1;
}
}
if (err) {
continue;
}
lilv_nodes_free (required_features);
LilvNodes* required_options = lilv_world_find_nodes (world.world, lilv_plugin_get_uri (p), world.opts_requiredOptions, NULL);
if (required_options) {
LILV_FOREACH(nodes, i, required_options) {
const char* ro = lilv_node_as_uri (lilv_nodes_get (required_options, i));
bool ok = false;
if (!strcmp (ro, LV2_PARAMETERS__sampleRate)) { ok = true; }
if (!strcmp (ro, LV2_BUF_SIZE__minBlockLength)) { ok = true; }
if (!strcmp (ro, LV2_BUF_SIZE__maxBlockLength)) { ok = true; }
if (!strcmp (ro, LV2_BUF_SIZE__sequenceSize)) { ok = true; }
if (!ok) {
warning << string_compose (
_("Unsupported required LV2 option: '%1' in '%2'."),
ro, lilv_node_as_string(name)) << endmsg;
err = 1;
}
}
}
lilv_nodes_free(required_options);
if (err) {
continue;
}
lilv_nodes_free(required_features);
#endif
info->type = LV2;