From 5791d19a0f56c65ef7b89da80f4bcc3e1cee0c93 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Thu, 11 Oct 2007 17:24:49 +0000 Subject: Fix awful plugin loading situation. Don't double-lookup plugins on discovery/load. O(log(n)) plugin searching instead of 2*O(n). Don't keep discovered LADSPA plugins loaded (until a node is instantiated). git-svn-id: http://svn.drobilla.net/lad/ingen@876 a436a847-0d15-0410-975c-d299462d15a1 --- src/libs/engine/NodeFactory.cpp | 336 +++++++++++++++------------------------- 1 file changed, 125 insertions(+), 211 deletions(-) (limited to 'src/libs/engine/NodeFactory.cpp') diff --git a/src/libs/engine/NodeFactory.cpp b/src/libs/engine/NodeFactory.cpp index c2b9536a..24d32929 100644 --- a/src/libs/engine/NodeFactory.cpp +++ b/src/libs/engine/NodeFactory.cpp @@ -53,86 +53,42 @@ NodeFactory::NodeFactory(Ingen::Shared::World* world) : _world(world) , _has_loaded(false) { - // Add builtin plugin types to _internal_plugins list - // FIXME: ewwww, definitely a better way to do this! - - PatchImpl* parent = new PatchImpl(*world->local_engine, "dummy", 1, NULL, 1, 1, 1); - - NodeImpl* n = NULL; - n = new MidiNoteNode("foo", 1, parent, 1, 1); - _internal_plugins.push_back(new PluginImpl(n->plugin_impl())); - delete n; - n = new MidiTriggerNode("foo", 1, parent, 1, 1); - _internal_plugins.push_back(new PluginImpl(n->plugin_impl())); - delete n; - n = new MidiControlNode("foo", 1, parent, 1, 1); - _internal_plugins.push_back(new PluginImpl(n->plugin_impl())); - delete n; - n = new TransportNode("foo", 1, parent, 1, 1); - _internal_plugins.push_back(new PluginImpl(n->plugin_impl())); - delete n; - - delete parent; } NodeFactory::~NodeFactory() { - for (list::iterator i = _plugins.begin(); i != _plugins.end(); ++i) - delete (*i); - _plugins.clear(); - - for (Libraries::iterator i = _libraries.begin(); i != _libraries.end(); ++i) { - delete i->second; - } - _libraries.clear(); -} - - -Glib::Module* -NodeFactory::library(const string& path) -{ - Glib::Module* plugin_library = NULL; - Libraries::iterator library_i = _libraries.find(path); - if (library_i != _libraries.end()) { - plugin_library = library_i->second; - assert(plugin_library); - } else { - plugin_library = new Glib::Module(path, Glib::MODULE_BIND_LOCAL); - if (plugin_library && *plugin_library) { - _libraries.insert(make_pair(path, plugin_library)); - return plugin_library; - } - } + for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i) + if (i->second->type() != Plugin::Internal) + delete i->second; - return NULL; + _plugins.clear(); } -const PluginImpl* +PluginImpl* NodeFactory::plugin(const string& uri) { - for (list::iterator i = _plugins.begin(); i != _plugins.end(); ++i) - if ((*i)->uri() == uri) - return (*i); - - return NULL; + Plugins::const_iterator i = _plugins.find(uri); + return ((i != _plugins.end()) ? i->second : NULL); } /** DEPRECATED: Find a plugin by type, lib, label. * - * Do not use. + * Slow. Evil. Do not use. */ -const PluginImpl* +PluginImpl* NodeFactory::plugin(const string& type, const string& lib, const string& label) { if (type == "" || lib == "" || label == "") return NULL; - for (list::iterator i = _plugins.begin(); i != _plugins.end(); ++i) - if ((*i)->type_string() == type && (*i)->lib_name() == lib && (*i)->plug_label() == label) - return (*i); + for (Plugins::const_iterator i = _plugins.begin(); i != _plugins.end(); ++i) + if (i->second->type_string() == type + && i->second->lib_name() == lib + && i->second->plug_label() == label) + return i->second; cerr << "ERROR: Failed to find " << type << " plugin " << lib << " / " << label << endl; @@ -149,12 +105,14 @@ NodeFactory::load_plugins() // this (expensive!) stuff to happen. Not the best solution - would be nice // if clients could refresh plugins list for whatever reason :/ if (!_has_loaded) { - _plugins.clear(); - _plugins = _internal_plugins; + _plugins.clear(); // FIXME: assert empty? + + load_internal_plugins(); #ifdef HAVE_SLV2 load_lv2_plugins(); #endif + #ifdef HAVE_LADSPA load_ladspa_plugins(); #endif @@ -171,65 +129,32 @@ NodeFactory::load_plugins() * Calls the load_*_plugin functions to actually do things, just a wrapper. */ NodeImpl* -NodeFactory::load_plugin(const PluginImpl* a_plugin, - const string& name, - bool polyphonic, - PatchImpl* parent) +NodeFactory::load_plugin(PluginImpl* plugin, + const string& name, + bool polyphonic, + PatchImpl* parent) { assert(parent != NULL); - assert(a_plugin); + assert(plugin); NodeImpl* r = NULL; - PluginImpl* plugin = NULL; const SampleRate srate = parent->sample_rate(); const size_t buffer_size = parent->buffer_size(); - // FIXME FIXME FIXME: double lookup - - // Attempt to find the plugin in loaded DB - if (a_plugin->type() != Plugin::Internal) { - - // DEPRECATED: Search by lib name / plug label - if (a_plugin->uri().length() == 0) { - assert(a_plugin->lib_name().length() > 0 && a_plugin->plug_label().length() > 0); - //cerr << "Searching for: " << a_plugin->lib_name() << " : " << a_plugin->plug_label() << endl; - for (list::iterator i = _plugins.begin(); i != _plugins.end(); ++i) { - //cerr << (*i)->lib_name() << " : " << (*i)->plug_label() << endl; - if (a_plugin->lib_name() == (*i)->lib_name() && a_plugin->plug_label() == (*i)->plug_label()) { - plugin = *i; - break; - } - } - } else { - // Search by URI - for (list::iterator i = _plugins.begin(); i != _plugins.end(); ++i) { - if (a_plugin->uri() == (*i)->uri()) { - plugin = *i; - break; - } - } - } - - if (plugin == NULL) { - cerr << "DID NOT FIND PLUGIN " << name << endl; - return NULL; - } - } - - switch (a_plugin->type()) { + switch (plugin->type()) { #ifdef HAVE_SLV2 case Plugin::LV2: - r = load_lv2_plugin(plugin->uri(), name, polyphonic, parent, srate, buffer_size); + r = load_lv2_plugin(plugin, name, polyphonic, parent, srate, buffer_size); break; #endif #ifdef HAVE_LADSPA case Plugin::LADSPA: - r = load_ladspa_plugin(plugin->uri(), name, polyphonic, parent, srate, buffer_size); + r = load_ladspa_plugin(plugin, name, polyphonic, parent, srate, buffer_size); break; #endif case Plugin::Internal: - r = load_internal_plugin(a_plugin->uri(), name, polyphonic, parent, srate, buffer_size); + r = load_internal_plugin(plugin, name, polyphonic, parent, srate, buffer_size); break; default: cerr << "[NodeFactory] WARNING: Unknown plugin type." << endl; @@ -239,25 +164,48 @@ NodeFactory::load_plugin(const PluginImpl* a_plugin, } +void +NodeFactory::load_internal_plugins() +{ + // This is a touch gross... + + PatchImpl* parent = new PatchImpl(*_world->local_engine, "dummy", 1, NULL, 1, 1, 1); + + NodeImpl* n = NULL; + n = new MidiNoteNode("foo", 1, parent, 1, 1); + _plugins.insert(make_pair(n->plugin_impl()->uri(), n->plugin_impl())); + delete n; + n = new MidiTriggerNode("foo", 1, parent, 1, 1); + _plugins.insert(make_pair(n->plugin_impl()->uri(), n->plugin_impl())); + delete n; + n = new MidiControlNode("foo", 1, parent, 1, 1); + _plugins.insert(make_pair(n->plugin_impl()->uri(), n->plugin_impl())); + delete n; + n = new TransportNode("foo", 1, parent, 1, 1); + _plugins.insert(make_pair(n->plugin_impl()->uri(), n->plugin_impl())); + delete n; + + delete parent; +} + + /** Loads an internal plugin. */ NodeImpl* -NodeFactory::load_internal_plugin(const string& uri, +NodeFactory::load_internal_plugin(PluginImpl* plugin, const string& name, bool polyphonic, PatchImpl* parent, SampleRate srate, size_t buffer_size) { + assert(plugin); + assert(plugin->type() == Plugin::Internal); assert(parent != NULL); - assert(uri.length() > 6); - assert(uri.substr(0, 6) == "ingen:"); + assert(plugin->uri().length() > 6); + assert(plugin->uri().substr(0, 6) == "ingen:"); - for (list::iterator i = _internal_plugins.begin(); i != _internal_plugins.end(); ++i) - if ((*i)->uri() == uri) - return (*i)->instantiate(name, polyphonic, parent, srate, buffer_size); - - return NULL; + return plugin->instantiate(name, polyphonic, parent, srate, buffer_size); } @@ -276,37 +224,24 @@ NodeFactory::load_lv2_plugins() SLV2Plugin lv2_plug = slv2_plugins_get_at(plugins, i); - const char* uri = (const char*)slv2_plugin_get_uri(lv2_plug); - assert(uri); - //cerr << "\t" << uri << endl; - - PluginImpl* plug = NULL; - - bool found = false; - for (list::const_iterator i = _plugins.begin(); i != _plugins.end(); ++i) { - if (!strcmp((*i)->uri().c_str(), uri)) { - plug = (*i); - found = true; - break; - } - } - - if (!found) - plug = new PluginImpl(Plugin::LV2, uri); - - plug->slv2_plugin(lv2_plug); - plug->module(NULL); // FIXME? - plug->lib_path(slv2_uri_to_path(slv2_plugin_get_library_uri(lv2_plug))); - char* name = slv2_plugin_get_name(lv2_plug); - if (!name) { +#ifndef NDEBUG + const string uri((const char*)slv2_plugin_get_uri(lv2_plug)); + assert(_plugins.find(uri) == _plugins.end()); +#endif + + PluginImpl* const plugin = new PluginImpl(Plugin::LV2, uri); + + plugin->slv2_plugin(lv2_plug); + plugin->lib_path(slv2_uri_to_path(slv2_plugin_get_library_uri(lv2_plug))); + char* const name = slv2_plugin_get_name(lv2_plug); + if (name) { + plugin->name(name); + free(name); + _plugins.insert(make_pair(uri, plugin)); + } else { cerr << "ERROR: LV2 Plugin " << uri << " has no name. Ignoring." << endl; continue; } - plug->name(name); - free(name); - - if (!found) - _plugins.push_back(plug); } slv2_plugins_free(_world->slv2_world, plugins); @@ -317,36 +252,31 @@ NodeFactory::load_lv2_plugins() * Returns 'poly' independant plugins as a NodeImpl* */ NodeImpl* -NodeFactory::load_lv2_plugin(const string& plug_uri, +NodeFactory::load_lv2_plugin(PluginImpl* plugin, const string& node_name, bool polyphonic, PatchImpl* parent, SampleRate srate, size_t buffer_size) { - // Find (internal) Plugin - PluginImpl* plugin = NULL; - list::iterator i; - for (i = _plugins.begin(); i != _plugins.end(); ++i) { - plugin = (*i); - if ((*i)->uri() == plug_uri) break; - } - + assert(plugin); + assert(plugin->type() == Plugin::LV2); + NodeImpl* n = NULL; - if (plugin) { - n = new LV2Node(plugin, node_name, polyphonic, parent, srate, buffer_size); - - Glib::Mutex::Lock lock(_world->rdf_world->mutex()); - - const bool success = ((LV2Node*)n)->instantiate(); - - if (!success) { - delete n; - n = NULL; - } + plugin->load(); // FIXME: unload + + n = new LV2Node(plugin, node_name, polyphonic, parent, srate, buffer_size); + + Glib::Mutex::Lock lock(_world->rdf_world->mutex()); + + const bool success = ((LV2Node*)n)->instantiate(); + + if (!success) { + delete n; + n = NULL; } - + return n; } @@ -369,12 +299,9 @@ NodeFactory::load_ladspa_plugins() ladspa_path = env_ladspa_path; } - string dir; - string full_lib_name; - // Yep, this should use an sstream alright.. while (ladspa_path != "") { - dir = ladspa_path.substr(0, ladspa_path.find(':')); + const string dir = ladspa_path.substr(0, ladspa_path.find(':')); if (ladspa_path.find(':') != string::npos) ladspa_path = ladspa_path.substr(ladspa_path.find(':')+1); else @@ -395,26 +322,25 @@ NodeFactory::load_ladspa_plugins() if (!strcmp(pfile->d_name, ".") || !strcmp(pfile->d_name, "..")) continue; - full_lib_name = dir +"/"+ pfile->d_name; + const string lib_path = dir +"/"+ pfile->d_name; // Ignore stupid libtool files. Kludge alert. - if (full_lib_name.substr(full_lib_name.length()-3) == ".la") { + if (lib_path.substr(lib_path.length()-3) == ".la") { //cerr << "WARNING: Skipping stupid libtool file " << pfile->d_name << endl; continue; } - Glib::Module* plugin_library = library(full_lib_name); - if (!plugin_library) { - cerr << "WARNING: Failed to load library " << full_lib_name << endl; + Glib::Module* plugin_library = new Glib::Module(lib_path, Glib::MODULE_BIND_LOCAL); + if (!plugin_library || !(*plugin_library)) { + cerr << "WARNING: Failed to load LADSPA library " << lib_path << endl; continue; } bool found = plugin_library->get_symbol("ladspa_descriptor", (void*&)df); if (!found || !df) { cerr << "WARNING: Non-LADSPA library found in LADSPA path: " << - full_lib_name << endl; + lib_path << endl; // Not a LADSPA plugin library - _libraries.erase(full_lib_name); delete plugin_library; continue; } @@ -422,32 +348,29 @@ NodeFactory::load_ladspa_plugins() for (unsigned long i=0; (descriptor = (LADSPA_Descriptor*)df(i)) != NULL; ++i) { char id_str[11]; snprintf(id_str, 11, "%lu", descriptor->UniqueID); - string uri = string("ladspa:").append(id_str); - PluginImpl* plugin = new PluginImpl(Plugin::LADSPA, uri); + const string uri = string("ladspa:").append(id_str); - assert(plugin_library != NULL); - plugin->module(plugin_library); - plugin->lib_path(dir + "/" + pfile->d_name); - plugin->plug_label(descriptor->Label); - plugin->name(descriptor->Name); - plugin->type(Plugin::LADSPA); - plugin->id(descriptor->UniqueID); + const Plugins::const_iterator i = _plugins.find(uri); - bool found = false; - for (list::const_iterator i = _plugins.begin(); i != _plugins.end(); ++i) { - if ((*i)->uri() == plugin->uri()) { - cerr << "Warning: Duplicate LADSPA plugin " << plugin->uri() - << " found.\n Choosing " << (*i)->lib_path() - << " over " << plugin->lib_path() << endl; - found = true; - break; - } + if (i == _plugins.end()) { + PluginImpl* plugin = new PluginImpl(Plugin::LADSPA, uri); + + assert(plugin_library != NULL); + plugin->module(NULL); + plugin->lib_path(lib_path); + plugin->plug_label(descriptor->Label); + plugin->name(descriptor->Name); + plugin->type(Plugin::LADSPA); + plugin->id(descriptor->UniqueID); + + _plugins.insert(make_pair(uri, plugin)); + } else { + cerr << "Warning: Duplicate LADSPA plugin " << uri << " found." << endl; + cerr << "\tUsing " << i->second->lib_path() << " over " << lib_path << endl; } - if (!found) - _plugins.push_back(plugin); - else - delete plugin; } + + delete plugin_library; } closedir(pdir); } @@ -458,37 +381,28 @@ NodeFactory::load_ladspa_plugins() * Returns 'poly' independant plugins as a NodeImpl* */ NodeImpl* -NodeFactory::load_ladspa_plugin(const string& uri, +NodeFactory::load_ladspa_plugin(PluginImpl* plugin, const string& name, bool polyphonic, PatchImpl* parent, SampleRate srate, size_t buffer_size) { - assert(uri != ""); + assert(plugin); + assert(plugin->type() == Plugin::LADSPA); + assert(plugin->id() != 0); assert(name != ""); LADSPA_Descriptor_Function df = NULL; - PluginImpl* plugin = NULL; NodeImpl* n = NULL; - - // Attempt to find the lib - list::iterator i; - for (i = _plugins.begin(); i != _plugins.end(); ++i) { - plugin = (*i); - if (plugin->uri() == uri) break; - } - assert(plugin->id() != 0); - - if (i == _plugins.end()) { - cerr << "Did not find LADSPA plugin " << uri << " in database." << endl; + plugin->load(); // FIXME: unload + assert(plugin->module()); + assert(*plugin->module()); + + if (!plugin->module()->get_symbol("ladspa_descriptor", (void*&)df)) { + cerr << "Looks like this isn't a LADSPA plugin." << endl; return NULL; - } else { - if (!plugin->module()->get_symbol("ladspa_descriptor", (void*&)df)) { - cerr << "Looks like this isn't a LADSPA plugin." << endl; - return NULL; - } } // Attempt to find the plugin in lib -- cgit v1.2.1