summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/instance.c115
-rw-r--r--src/lib.c110
-rw-r--r--src/lilv_internal.h26
-rw-r--r--src/world.c10
-rw-r--r--src/zix/tree.c158
-rw-r--r--wscript8
6 files changed, 360 insertions, 67 deletions
diff --git a/src/instance.c b/src/instance.c
index 0c470e1..0d4457d 100644
--- a/src/instance.c
+++ b/src/instance.c
@@ -1,5 +1,5 @@
/*
- Copyright 2007-2011 David Robillard <http://drobilla.net>
+ Copyright 2007-2012 David Robillard <http://drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
@@ -37,82 +37,63 @@ lilv_plugin_instantiate(const LilvPlugin* plugin,
local_features[0] = NULL;
}
- const LilvNode* const lib_uri_node = lilv_plugin_get_library_uri(plugin);
- const char* const lib_uri = lilv_node_as_uri(lib_uri_node);
- const char* const lib_path = lilv_uri_to_path(lib_uri);
+ const LilvNode* const lib_uri = lilv_plugin_get_library_uri(plugin);
+ const LilvNode* const bundle_uri = lilv_plugin_get_bundle_uri(plugin);
- if (!lib_path)
- return NULL;
+ const char* bundle_path = lilv_uri_to_path(
+ lilv_node_as_uri(lilv_plugin_get_bundle_uri(plugin)));
- dlerror();
- void* lib = dlopen(lib_path, RTLD_NOW);
+ LilvLib* lib = lilv_lib_open(plugin->world, lib_uri, bundle_path, features);
if (!lib) {
- LILV_ERRORF("Failed to open library %s (%s)\n", lib_path, dlerror());
return NULL;
}
- LV2_Descriptor_Function df = (LV2_Descriptor_Function)
- lilv_dlfunc(lib, "lv2_descriptor");
-
- if (!df) {
- LILV_ERRORF("No `lv2_descriptor' in %s\n", lib_path);
- dlclose(lib);
+ // Parse bundle URI to use as base URI
+ const char* bundle_uri_str = lilv_node_as_uri(bundle_uri);
+ SerdURI base_uri;
+ if (serd_uri_parse((const uint8_t*)bundle_uri_str, &base_uri)) {
+ lilv_lib_close(lib);
return NULL;
- } else {
- // Search for plugin by URI
-
- const char* bundle_path = lilv_uri_to_path(
- lilv_node_as_uri(lilv_plugin_get_bundle_uri(plugin)));
-
- for (uint32_t i = 0; true; ++i) {
- const LV2_Descriptor* ld = df(i);
- if (!ld) {
- LILV_ERRORF("No plugin <%s> in %s\n",
- lilv_node_as_uri(lilv_plugin_get_uri(plugin)),
- lib_path);
- dlclose(lib);
- break; // return NULL
- }
-
- // Parse bundle URI to use as base URI
- const LilvNode* bundle_uri = lilv_plugin_get_bundle_uri(plugin);
- const char* bundle_uri_str = lilv_node_as_uri(bundle_uri);
- SerdURI base_uri;
- if (serd_uri_parse((const uint8_t*)bundle_uri_str, &base_uri)) {
- dlclose(lib);
- break;
- }
-
- // Resolve library plugin URI against base URI
- SerdURI abs_uri;
- SerdNode abs_uri_node = serd_node_new_uri_from_string(
- (const uint8_t*)ld->URI, &base_uri, &abs_uri);
- if (!abs_uri_node.buf) {
- LILV_ERRORF("Failed to parse plugin URI `%s'\n", ld->URI);
- dlclose(lib);
- break;
- }
-
- if (!strcmp((const char*)abs_uri_node.buf,
- lilv_node_as_uri(lilv_plugin_get_uri(plugin)))) {
- // Create LilvInstance to return
- result = (LilvInstance*)malloc(sizeof(LilvInstance));
- result->lv2_descriptor = ld;
- result->lv2_handle = ld->instantiate(
- ld, sample_rate, (char*)bundle_path,
- (features) ? features : local_features);
- result->pimpl = lib;
- serd_node_free(&abs_uri_node);
- break;
- } else {
- serd_node_free(&abs_uri_node);
- }
+ }
+
+ // Search for plugin by URI
+ for (uint32_t i = 0; true; ++i) {
+ const LV2_Descriptor* ld = lilv_lib_get_plugin(lib, i);
+ if (!ld) {
+ LILV_ERRORF("No plugin <%s> in <%s>\n",
+ lilv_node_as_uri(lilv_plugin_get_uri(plugin)),
+ lilv_node_as_uri(lib_uri));
+ lilv_lib_close(lib);
+ break; // return NULL
+ }
+
+ // Resolve library plugin URI against base URI
+ SerdURI abs_uri;
+ SerdNode abs_uri_node = serd_node_new_uri_from_string(
+ (const uint8_t*)ld->URI, &base_uri, &abs_uri);
+ if (!abs_uri_node.buf) {
+ LILV_ERRORF("Failed to parse plugin URI `%s'\n", ld->URI);
+ lilv_lib_close(lib);
+ break;
+ }
+
+ if (!strcmp((const char*)abs_uri_node.buf,
+ lilv_node_as_uri(lilv_plugin_get_uri(plugin)))) {
+ // Create LilvInstance to return
+ result = (LilvInstance*)malloc(sizeof(LilvInstance));
+ result->lv2_descriptor = ld;
+ result->lv2_handle = ld->instantiate(
+ ld, sample_rate, (char*)bundle_path,
+ (features) ? features : local_features);
+ result->pimpl = lib;
+ serd_node_free(&abs_uri_node);
+ break;
+ } else {
+ serd_node_free(&abs_uri_node);
}
}
if (result) {
- assert(lilv_plugin_get_num_ports(plugin) > 0);
-
// Failed to instantiate
if (result->lv2_handle == NULL) {
free(result);
@@ -138,7 +119,7 @@ lilv_instance_free(LilvInstance* instance)
instance->lv2_descriptor->cleanup(instance->lv2_handle);
instance->lv2_descriptor = NULL;
- dlclose(instance->pimpl);
+ lilv_lib_close((LilvLib*)instance->pimpl);
instance->pimpl = NULL;
free(instance);
}
diff --git a/src/lib.c b/src/lib.c
new file mode 100644
index 0000000..bc5a62a
--- /dev/null
+++ b/src/lib.c
@@ -0,0 +1,110 @@
+/*
+ Copyright 2012 David Robillard <http://drobilla.net>
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#include "lilv_internal.h"
+
+LilvLib*
+lilv_lib_open(LilvWorld* world,
+ const LilvNode* uri,
+ const char* bundle_path,
+ const LV2_Feature*const* features)
+{
+ ZixTreeIter* i = NULL;
+ const struct LilvHeader key = { world, (LilvNode*)uri };
+ if (!zix_tree_find(world->libs, &key, &i)) {
+ LilvLib* llib = (LilvLib*)zix_tree_get(i);
+ ++llib->refs;
+ return llib;
+ }
+
+ const char* const lib_uri = lilv_node_as_uri(uri);
+ const char* const lib_path = lilv_uri_to_path(lib_uri);
+ if (!lib_path) {
+ return NULL;
+ }
+
+ dlerror();
+ void* lib = dlopen(lib_path, RTLD_NOW);
+ if (!lib) {
+ LILV_ERRORF("Failed to open library %s (%s)\n", lib_path, dlerror());
+ return NULL;
+ }
+
+ LV2_Descriptor_Function df = (LV2_Descriptor_Function)
+ lilv_dlfunc(lib, "lv2_descriptor");
+
+#ifdef LILV_NEW_LV2
+ LV2_Lib_Descriptor_Function ldf = (LV2_Lib_Descriptor_Function)
+ lilv_dlfunc(lib, "lv2_lib_descriptor");
+
+ const LV2_Lib_Descriptor* desc = NULL;
+ if (ldf) {
+ desc = ldf(bundle_path, features);
+ if (!desc) {
+ LILV_ERRORF("Call to `lv2_lib_descriptor' in %s failed\n", lib_path);
+ return NULL;
+ }
+ } else
+#endif
+ if (!df) {
+ LILV_ERRORF("No `lv2_descriptor' or `lv2_lib_descriptor' in %s\n",
+ lib_path);
+ dlclose(lib);
+ return NULL;
+ }
+
+ LilvLib* llib = (LilvLib*)malloc(sizeof(LilvLib));
+ llib->world = world;
+ llib->uri = lilv_node_duplicate(uri);
+ llib->lib = lib;
+ llib->lv2_descriptor = df;
+#ifdef LILV_NEW_LV2
+ llib->desc = desc;
+#endif
+ llib->refs = 1;
+
+ zix_tree_insert(world->libs, llib, NULL);
+ return llib;
+}
+
+const LV2_Descriptor*
+lilv_lib_get_plugin(LilvLib* lib, uint32_t index)
+{
+ if (lib->lv2_descriptor) {
+ return lib->lv2_descriptor(index);
+ }
+#ifdef LILV_NEW_LV2
+ if (lib->desc) {
+ return lib->desc->get_plugin(lib->desc->handle, index);
+ }
+#endif
+ return NULL;
+}
+
+void
+lilv_lib_close(LilvLib* lib)
+{
+ if (--lib->refs == 0) {
+ dlclose(lib->lib);
+
+ ZixTreeIter* i = NULL;
+ if (!zix_tree_find(lib->world->libs, lib, &i)) {
+ zix_tree_remove(lib->world->libs, i);
+ }
+
+ free(lib);
+ }
+}
diff --git a/src/lilv_internal.h b/src/lilv_internal.h
index 2ebaa0c..a80bfdb 100644
--- a/src/lilv_internal.h
+++ b/src/lilv_internal.h
@@ -96,6 +96,17 @@ typedef struct {
} LilvDynManifest;
#endif
+typedef struct {
+ LilvWorld* world;
+ LilvNode* uri;
+ void* lib;
+ LV2_Descriptor_Function lv2_descriptor;
+#ifdef LILV_NEW_LV2
+ const LV2_Lib_Descriptor* desc;
+#endif
+ uint32_t refs;
+} LilvLib;
+
struct LilvPluginImpl {
LilvWorld* world;
LilvNode* plugin_uri;
@@ -119,6 +130,11 @@ struct LilvPluginClassImpl {
LilvNode* label;
};
+struct LilvInstancePimpl {
+ LilvWorld* world;
+ LilvLib* lib;
+};
+
typedef struct {
bool dyn_manifest;
bool filter_language;
@@ -134,6 +150,7 @@ struct LilvWorldImpl {
LilvSpec* specs;
LilvPlugins* plugins;
LilvNodes* loaded_files;
+ ZixTree* libs;
struct {
SordNode* dc_replaces;
SordNode* doap_name;
@@ -245,6 +262,15 @@ LilvPluginClass* lilv_plugin_class_new(LilvWorld* world,
void lilv_plugin_class_free(LilvPluginClass* plugin_class);
+LilvLib*
+lilv_lib_open(LilvWorld* world,
+ const LilvNode* uri,
+ const char* bundle_path,
+ const LV2_Feature*const* features);
+
+const LV2_Descriptor* lilv_lib_get_plugin(LilvLib* lib, uint32_t index);
+void lilv_lib_close(LilvLib* lib);
+
LilvNodes* lilv_nodes_new(void);
LilvPlugins* lilv_plugins_new(void);
LilvScalePoints* lilv_scale_points_new(void);
diff --git a/src/world.c b/src/world.c
index 3ae9f7c..7eea802 100644
--- a/src/world.c
+++ b/src/world.c
@@ -41,6 +41,11 @@ lilv_world_new(void)
world->loaded_files = zix_tree_new(
false, lilv_resource_node_cmp, NULL, (ZixDestroyFunc)lilv_node_free);
+#ifdef LILV_NEW_LV2
+ world->libs = zix_tree_new(
+ false, lilv_header_compare_by_uri, NULL, NULL);
+#endif
+
#define NS_DCTERMS "http://purl.org/dc/terms/"
#define NS_DYNMAN "http://lv2plug.in/ns/ext/dynmanifest#"
#define NS_PSET "http://lv2plug.in/ns/ext/presets#"
@@ -131,6 +136,11 @@ lilv_world_free(LilvWorld* world)
zix_tree_free((ZixTree*)world->loaded_files);
world->loaded_files = NULL;
+#ifdef LILV_NEW_LV2
+ zix_tree_free((ZixTree*)world->libs);
+ world->libs = NULL;
+#endif
+
zix_tree_free((ZixTree*)world->plugin_classes);
world->plugin_classes = NULL;
diff --git a/src/zix/tree.c b/src/zix/tree.c
index 39f3b36..c8a5bb4 100644
--- a/src/zix/tree.c
+++ b/src/zix/tree.c
@@ -440,6 +440,164 @@ zix_tree_insert(ZixTree* t, void* e, ZixTreeIter** ti)
ZIX_API
ZixStatus
+zix_tree_remove(ZixTree* t, ZixTreeIter* ti)
+{
+ ZixTreeNode* const n = ti;
+ ZixTreeNode** pp = NULL; // parent pointer
+ ZixTreeNode* to_balance = n->parent; // lowest node to balance
+ int8_t d_balance = 0; // delta(balance) for n->parent
+
+ DEBUG_PRINTF("*** REMOVE %ld\n", (intptr_t)n->data);
+
+ if ((n == t->root) && !n->left && !n->right) {
+ t->root = NULL;
+ if (t->destroy) {
+ t->destroy(n->data);
+ }
+ free(n);
+ --t->size;
+ assert(t->size == 0);
+ return ZIX_STATUS_SUCCESS;
+ }
+
+ // Set pp to the parent pointer to n, if applicable
+ if (n->parent) {
+ assert(n->parent->left == n || n->parent->right == n);
+ if (n->parent->left == n) { // n is left child
+ pp = &n->parent->left;
+ d_balance = 1;
+ } else { // n is right child
+ assert(n->parent->right == n);
+ pp = &n->parent->right;
+ d_balance = -1;
+ }
+ }
+
+ assert(!pp || *pp == n);
+
+ int height_change = 0;
+ if (!n->left && !n->right) {
+ // n is a leaf, just remove it
+ if (pp) {
+ *pp = NULL;
+ to_balance = n->parent;
+ height_change = (!n->parent->left && !n->parent->right) ? -1 : 0;
+ }
+ } else if (!n->left) {
+ // Replace n with right (only) child
+ if (pp) {
+ *pp = n->right;
+ to_balance = n->parent;
+ } else {
+ t->root = n->right;
+ }
+ n->right->parent = n->parent;
+ height_change = -1;
+ } else if (!n->right) {
+ // Replace n with left (only) child
+ if (pp) {
+ *pp = n->left;
+ to_balance = n->parent;
+ } else {
+ t->root = n->left;
+ }
+ n->left->parent = n->parent;
+ height_change = -1;
+ } else {
+ // Replace n with in-order successor (leftmost child of right subtree)
+ ZixTreeNode* replace = n->right;
+ while (replace->left) {
+ assert(replace->left->parent == replace);
+ replace = replace->left;
+ }
+
+ // Remove replace from parent (replace_p)
+ if (replace->parent->left == replace) {
+ height_change = replace->parent->right ? 0 : -1;
+ d_balance = 1;
+ to_balance = replace->parent;
+ replace->parent->left = replace->right;
+ } else {
+ assert(replace->parent == n);
+ height_change = replace->parent->left ? 0 : -1;
+ d_balance = -1;
+ to_balance = replace->parent;
+ replace->parent->right = replace->right;
+ }
+
+ if (to_balance == n) {
+ to_balance = replace;
+ }
+
+ if (replace->right) {
+ replace->right->parent = replace->parent;
+ }
+
+ replace->balance = n->balance;
+
+ // Swap node to delete with replace
+ if (pp) {
+ *pp = replace;
+ } else {
+ assert(t->root == n);
+ t->root = replace;
+ }
+ replace->parent = n->parent;
+ replace->left = n->left;
+ n->left->parent = replace;
+ replace->right = n->right;
+ if (n->right) {
+ n->right->parent = replace;
+ }
+
+ assert(!replace->parent
+ || replace->parent->left == replace
+ || replace->parent->right == replace);
+ }
+
+ // Rebalance starting at to_balance upwards.
+ for (ZixTreeNode* i = to_balance; i; i = i->parent) {
+ i->balance += d_balance;
+ if (d_balance == 0 || i->balance == -1 || i->balance == 1) {
+ break;
+ }
+
+ assert(i != n);
+ i = zix_tree_rebalance(t, i, &height_change);
+ if (i->balance == 0) {
+ height_change = -1;
+ }
+
+ if (i->parent) {
+ if (i == i->parent->left) {
+ d_balance = height_change * -1;
+ } else {
+ assert(i == i->parent->right);
+ d_balance = height_change;
+ }
+ }
+ }
+
+ DUMP(t);
+
+ if (t->destroy) {
+ t->destroy(n->data);
+ }
+ free(n);
+
+ --t->size;
+
+#ifdef ZIX_TREE_VERIFY
+ if (!verify(t, t->root)) {
+ return ZIX_STATUS_ERROR;
+ }
+#endif
+
+ return ZIX_STATUS_SUCCESS;
+}
+
+ZIX_API
+ZixStatus
zix_tree_find(const ZixTree* t, const void* e, ZixTreeIter** ti)
{
ZixTreeNode* n = t->root;
diff --git a/wscript b/wscript
index 489032e..fc65efa 100644
--- a/wscript
+++ b/wscript
@@ -77,6 +77,8 @@ def configure(conf):
conf.env['BASH_COMPLETION'] = not Options.options.no_bash_completion
autowaf.check_pkg(conf, 'lv2core', uselib_store='LV2CORE', mandatory=True)
+ autowaf.check_pkg(conf, 'lv2core', uselib_store='NEW_LV2CORE',
+ atleast_version='6.7', mandatory=False)
autowaf.check_pkg(conf, 'serd-0', uselib_store='SERD',
atleast_version='0.11.0', mandatory=True)
autowaf.check_pkg(conf, 'sord-0', uselib_store='SORD',
@@ -88,6 +90,9 @@ def configure(conf):
autowaf.check_pkg(conf, 'lv2-lv2plug.in-ns-ext-urid',
uselib_store='LV2_URID', mandatory=False)
+ if conf.is_defined('HAVE_NEW_LV2CORE'):
+ autowaf.define(conf, 'LILV_NEW_LV2', 1)
+
defines = ['_POSIX_C_SOURCE', '_BSD_SOURCE']
if Options.platform == 'darwin':
defines += ['_DARWIN_C_SOURCE']
@@ -159,6 +164,8 @@ def configure(conf):
bool(conf.env['LILV_DYN_MANIFEST']))
autowaf.display_msg(conf, "State/Preset support",
conf.is_defined('HAVE_LV2_STATE'))
+ autowaf.display_msg(conf, "New LV2 discovery API support",
+ bool(conf.env['LILV_NEW_LV2']))
autowaf.display_msg(conf, "Python bindings",
conf.is_defined('LILV_PYTHON'))
@@ -187,6 +194,7 @@ sord-0
lib_source = '''
src/collections.c
src/instance.c
+ src/lib.c
src/node.c
src/plugin.c
src/pluginclass.c