diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/instance.c | 115 | ||||
-rw-r--r-- | src/lib.c | 110 | ||||
-rw-r--r-- | src/lilv_internal.h | 26 | ||||
-rw-r--r-- | src/world.c | 10 | ||||
-rw-r--r-- | src/zix/tree.c | 158 |
5 files changed, 352 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; |