summaryrefslogtreecommitdiffstats
path: root/src/libs/engine/NodeFactory.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/engine/NodeFactory.cpp')
-rw-r--r--src/libs/engine/NodeFactory.cpp707
1 files changed, 707 insertions, 0 deletions
diff --git a/src/libs/engine/NodeFactory.cpp b/src/libs/engine/NodeFactory.cpp
new file mode 100644
index 00000000..176d3f47
--- /dev/null
+++ b/src/libs/engine/NodeFactory.cpp
@@ -0,0 +1,707 @@
+/* This file is part of Om. Copyright (C) 2006 Dave Robillard.
+ *
+ * Om is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * Om is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "NodeFactory.h"
+#include "config.h"
+#include <cstdlib>
+#include <pthread.h>
+#include <dirent.h>
+#include <float.h>
+#include <cmath>
+#include <dlfcn.h>
+#include "AudioDriver.h"
+#include "MidiNoteNode.h"
+#include "MidiTriggerNode.h"
+#include "MidiControlNode.h"
+#include "AudioInputNode.h"
+#include "AudioOutputNode.h"
+#include "ControlInputNode.h"
+#include "ControlOutputNode.h"
+#include "MidiInputNode.h"
+#include "MidiOutputNode.h"
+#include "TransportNode.h"
+#include "PluginLibrary.h"
+#include "Plugin.h"
+#include "Patch.h"
+#include "Om.h"
+#include "OmApp.h"
+#ifdef HAVE_SLV2
+#include "LV2Plugin.h"
+#include <slv2/slv2.h>
+#endif
+#ifdef HAVE_LADSPA
+#include "LADSPAPlugin.h"
+#endif
+#ifdef HAVE_DSSI
+#include "DSSIPlugin.h"
+#endif
+
+using std::string;
+using std::cerr; using std::cout; using std::endl;
+
+
+namespace Om {
+
+
+/* I am perfectly aware that the vast majority of this class is a
+ * vomit inducing nightmare at the moment ;)
+ */
+
+
+
+NodeFactory::NodeFactory()
+: m_has_loaded(false)
+{
+ pthread_mutex_init(&m_plugin_list_mutex, NULL);
+
+ // Add builtin plugin types to m_internal_plugins list
+ // FIXME: ewwww, definitely a better way to do this!
+ //Plugin* pi = NULL;
+
+ Patch* parent = new Patch("dummy", 1, NULL, 1, 1, 1);
+
+ Node* n = NULL;
+ n = new AudioInputNode("foo", 1, parent, 1, 1);
+ m_internal_plugins.push_back(new Plugin(n->plugin()));
+ delete n;
+ n = new AudioOutputNode("foo", 1, parent, 1, 1);
+ m_internal_plugins.push_back(new Plugin(n->plugin()));
+ delete n;
+ n = new ControlInputNode("foo", 1, parent, 1, 1);
+ m_internal_plugins.push_back(new Plugin(n->plugin()));
+ delete n;
+ n = new ControlOutputNode("foo", 1, parent, 1, 1);
+ m_internal_plugins.push_back(new Plugin(n->plugin()));
+ delete n;
+ n = new MidiInputNode("foo", 1, parent, 1, 1);
+ m_internal_plugins.push_back(new Plugin(n->plugin()));
+ delete n;
+ n = new MidiOutputNode("foo", 1, parent, 1, 1);
+ m_internal_plugins.push_back(new Plugin(n->plugin()));
+ delete n;
+ n = new MidiNoteNode("foo", 1, parent, 1, 1);
+ m_internal_plugins.push_back(new Plugin(n->plugin()));
+ delete n;
+ n = new MidiTriggerNode("foo", 1, parent, 1, 1);
+ m_internal_plugins.push_back(new Plugin(n->plugin()));
+ delete n;
+ n = new MidiControlNode("foo", 1, parent, 1, 1);
+ m_internal_plugins.push_back(new Plugin(n->plugin()));
+ delete n;
+ n = new TransportNode("foo", 1, parent, 1, 1);
+ m_internal_plugins.push_back(new Plugin(n->plugin()));
+ delete n;
+
+
+ delete parent;
+}
+
+
+NodeFactory::~NodeFactory()
+{
+ for (list<Plugin*>::iterator i = m_plugins.begin(); i != m_plugins.end(); ++i)
+ delete (*i);
+
+ for (list<PluginLibrary*>::iterator i = m_libraries.begin(); i != m_libraries.end(); ++i) {
+ (*i)->close();
+ delete (*i);
+ }
+}
+
+
+void
+NodeFactory::load_plugins()
+{
+ // Only load if we havn't already, so every client connecting doesn't cause
+ // this (expensive!) stuff to happen. Not the best solution - would be nice
+ // if clients could refresh plugins list for whatever reason :/
+ if (!m_has_loaded) {
+ pthread_mutex_lock(&m_plugin_list_mutex);
+
+ m_plugins.clear();
+ m_plugins = m_internal_plugins;
+
+#if HAVE_SLV2
+ load_lv2_plugins();
+#endif
+#if HAVE_DSSI
+ load_dssi_plugins();
+#endif
+#if HAVE_LADSPA
+ load_ladspa_plugins();
+#endif
+
+ m_has_loaded = true;
+
+ pthread_mutex_unlock(&m_plugin_list_mutex);
+ }
+}
+
+
+/** Loads a plugin.
+ *
+ * Calls the load_*_plugin functions to actually do things, just a wrapper.
+ */
+Node*
+NodeFactory::load_plugin(const Plugin* a_plugin, const string& name, size_t poly, Patch* parent)
+{
+ assert(parent != NULL);
+ assert(poly == 1 || poly == parent->internal_poly());
+ assert(a_plugin);
+
+ pthread_mutex_lock(&m_plugin_list_mutex);
+
+ Node* r = NULL;
+ Plugin* plugin = NULL;
+
+ // Attempt to find the plugin in loaded DB
+ if (a_plugin->type() != Plugin::Internal) {
+ list<Plugin*>::iterator i;
+ if (a_plugin->plug_label().length() == 0) {
+ for (i = m_plugins.begin(); i != m_plugins.end(); ++i) {
+ if (a_plugin->uri() == (*i)->uri()) {
+ plugin = *i;
+ break;
+ }
+ }
+ } else {
+ for (i = m_plugins.begin(); i != m_plugins.end(); ++i) {
+ if (a_plugin->uri() == (*i)->uri()) {
+ plugin = *i;
+ break;
+ }
+ }
+ }
+
+ if (plugin == NULL)
+ return NULL;
+ }
+
+ switch (a_plugin->type()) {
+#if HAVE_SLV2
+ case Plugin::LV2:
+ r = load_lv2_plugin(plugin->uri(), name, poly, parent);
+ break;
+#endif
+#if HAVE_DSSI
+ case Plugin::DSSI:
+ r = load_dssi_plugin(plugin->uri(), name, poly, parent);
+ break;
+#endif
+#if HAVE_LADSPA
+ case Plugin::LADSPA:
+ r = load_ladspa_plugin(plugin->uri(), name, poly, parent);
+ break;
+#endif
+ case Plugin::Internal:
+ r = load_internal_plugin(a_plugin->uri(), name, poly, parent);
+ break;
+ default:
+ cerr << "[NodeFactory] WARNING: Unknown plugin type." << endl;
+ }
+
+ pthread_mutex_unlock(&m_plugin_list_mutex);
+
+ return r;
+}
+
+
+/** Loads an internal plugin.
+ */
+Node*
+NodeFactory::load_internal_plugin(const string& uri, const string& name, size_t poly, Patch* parent)
+{
+ assert(parent != NULL);
+ assert(poly == 1 || poly == parent->internal_poly());
+ assert(uri.length() > 3);
+ assert(uri.substr(0, 3) == "om:");
+
+ string plug_label = uri.substr(3);
+
+ if (plug_label == "midi_input") {
+ MidiInputNode* tn = new MidiInputNode(name, 1, parent, om->audio_driver()->sample_rate(), om->audio_driver()->buffer_size());
+ return tn;
+ } else if (plug_label == "midi_output") {
+ MidiOutputNode* tn = new MidiOutputNode(name, 1, parent, om->audio_driver()->sample_rate(), om->audio_driver()->buffer_size());
+ return tn;
+ } else if (plug_label == "audio_input") {
+ AudioInputNode* in = new AudioInputNode(name, poly, parent,
+ om->audio_driver()->sample_rate(), om->audio_driver()->buffer_size());
+ return in;
+ } else if (plug_label == "control_input") {
+ ControlInputNode* in = new ControlInputNode(name, poly, parent,
+ om->audio_driver()->sample_rate(), om->audio_driver()->buffer_size());
+ return in;
+ } else if (plug_label == "audio_output") {
+ AudioOutputNode* on = new AudioOutputNode(name, poly, parent,
+ om->audio_driver()->sample_rate(), om->audio_driver()->buffer_size());
+ return on;
+ } else if (plug_label == "control_output") {
+ ControlOutputNode* on = new ControlOutputNode(name, poly, parent,
+ om->audio_driver()->sample_rate(), om->audio_driver()->buffer_size());
+ return on;
+ } else if (plug_label == "note_in" || plug_label == "midi_note_in") {
+ MidiNoteNode* mn = new MidiNoteNode(name, poly, parent, om->audio_driver()->sample_rate(), om->audio_driver()->buffer_size());
+ return mn;
+ } else if (plug_label == "trigger_in" || plug_label == "midi_trigger_in") {
+ MidiTriggerNode* mn = new MidiTriggerNode(name, 1, parent, om->audio_driver()->sample_rate(), om->audio_driver()->buffer_size());
+ return mn;
+ } else if (plug_label == "midi_control_in") {
+ MidiControlNode* mn = new MidiControlNode(name, 1, parent, om->audio_driver()->sample_rate(), om->audio_driver()->buffer_size());
+ return mn;
+ } else if (plug_label == "transport") {
+ TransportNode* tn = new TransportNode(name, 1, parent, om->audio_driver()->sample_rate(), om->audio_driver()->buffer_size());
+ return tn;
+ } else {
+ cerr << "Unknown internal plugin type '" << plug_label << "'" << endl;
+ }
+
+ return NULL;
+}
+
+
+#ifdef HAVE_SLV2
+
+/** Loads information about all LV2 plugins into internal plugin database.
+ */
+void
+NodeFactory::load_lv2_plugins()
+{
+ SLV2List plugins = slv2_list_new();
+ slv2_list_load_all(plugins);
+
+ //cerr << "[NodeFactory] Found " << slv2_list_get_length(plugins) << " LV2 plugins." << endl;
+
+ for (unsigned long i=0; i < slv2_list_get_length(plugins); ++i) {
+
+ SLV2Plugin* lv2_plug = slv2_list_get_plugin_by_index(plugins, i);
+
+
+ //om_plug->library(plugin_library);
+
+ const char* uri = (const char*)slv2_plugin_get_uri(lv2_plug);
+ //cerr << "LV2 plugin: " << uri << endl;
+
+ bool found = false;
+ for (list<Plugin*>::const_iterator i = m_plugins.begin(); i != m_plugins.end(); ++i) {
+ if (!strcmp((*i)->uri().c_str(), uri)) {
+ cerr << "Warning: Duplicate LV2 plugin (" << uri << ").\nUsing "
+ << (*i)->lib_path() << " version." << endl;
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ //printf("[NodeFactory] Found LV2 plugin %s\n", uri);
+ Plugin* om_plug = new Plugin();
+ om_plug->type(Plugin::LV2);
+ om_plug->slv2_plugin(lv2_plug);
+ om_plug->uri(uri);
+ // FIXME FIXME FIXME temporary hack
+ om_plug->library(NULL);
+ om_plug->lib_path("FIXMEpath");
+ om_plug->plug_label("FIXMElabel");
+ unsigned char* name = slv2_plugin_get_name(lv2_plug);
+ om_plug->name((char*)name);
+ free(name);
+ om_plug->type(Plugin::LV2);
+ m_plugins.push_back(om_plug);
+ }
+ }
+
+ slv2_list_free(plugins);
+}
+
+
+/** Loads a LV2 plugin.
+ * Returns 'poly' independant plugins as a Node*
+ */
+Node*
+NodeFactory::load_lv2_plugin(const string& plug_uri,
+ const string& node_name,
+ size_t poly,
+ Patch* parent)
+{
+ // Find (Om) Plugin
+ Plugin* plugin = NULL;
+ list<Plugin*>::iterator i;
+ for (i = m_plugins.begin(); i != m_plugins.end(); ++i) {
+ plugin = (*i);
+ if ((*i)->uri() == plug_uri) break;
+ }
+
+ Node* n = NULL;
+
+ if (plugin) {
+ n = new Om::LV2Plugin(node_name, poly, parent, plugin->slv2_plugin(),
+ om->audio_driver()->sample_rate(), om->audio_driver()->buffer_size());
+ bool success = ((LV2Plugin*)n)->instantiate();
+ if (!success) {
+ delete n;
+ n = NULL;
+ }
+ n->plugin(plugin);
+ }
+
+ return n;
+}
+
+#endif // HAVE_SLV2
+
+
+#if HAVE_DSSI
+
+/** Loads information about all DSSI plugins into internal plugin database.
+ */
+void
+NodeFactory::load_dssi_plugins()
+{
+ // FIXME: too much code duplication with load_ladspa_plugin
+
+ char* env_dssi_path = getenv("DSSI_PATH");
+ string dssi_path;
+ if (!env_dssi_path) {
+ cerr << "[NodeFactory] DSSI_PATH is empty. Assuming /usr/lib/dssi:/usr/local/lib/dssi:~/.dssi" << endl;
+ dssi_path = string("/usr/lib/dssi:/usr/local/lib/dssi:").append(
+ getenv("HOME")).append("/.dssi");
+ } else {
+ dssi_path = env_dssi_path;
+ }
+
+ DSSI_Descriptor_Function df = NULL;
+ DSSI_Descriptor* descriptor = NULL;
+
+ string dir;
+ string full_lib_name;
+
+ // Yep, this should use an sstream alright..
+ while (dssi_path != "") {
+ dir = dssi_path.substr(0, dssi_path.find(':'));
+ if (dssi_path.find(':') != string::npos)
+ dssi_path = dssi_path.substr(dssi_path.find(':')+1);
+ else
+ dssi_path = "";
+
+ DIR* pdir = opendir(dir.c_str());
+ if (pdir == NULL) {
+ //cerr << "[NodeFactory] Unreadable directory in DSSI_PATH: " << dir.c_str() << endl;
+ continue;
+ }
+
+ struct dirent* pfile;
+ while ((pfile = readdir(pdir))) {
+
+ if (!strcmp(pfile->d_name, ".") || !strcmp(pfile->d_name, ".."))
+ continue;
+
+ full_lib_name = dir +"/"+ pfile->d_name;
+
+ // Load descriptor function
+ // Loaded with LAZY here, will be loaded with NOW on node loading
+ void* handle = dlopen(full_lib_name.c_str(), RTLD_LAZY);
+ if (handle == NULL)
+ continue;
+
+ df = (DSSI_Descriptor_Function)dlsym(handle, "dssi_descriptor");
+ if (df == NULL) {
+ // Not a DSSI plugin library
+ dlclose(handle);
+ continue;
+ }
+
+ PluginLibrary* plugin_library = new PluginLibrary(full_lib_name);
+ m_libraries.push_back(plugin_library);
+
+ const LADSPA_Descriptor* ld = NULL;
+
+ for (unsigned long i=0; (descriptor = (DSSI_Descriptor*)df(i)) != NULL; ++i) {
+ ld = descriptor->LADSPA_Plugin;
+ assert(ld != NULL);
+ Plugin* plugin = new Plugin();
+ assert(plugin_library != NULL);
+ plugin->library(plugin_library);
+ plugin->lib_path(dir + "/" + pfile->d_name);
+ plugin->plug_label(ld->Label);
+ plugin->name(ld->Name);
+ plugin->type(Plugin::DSSI);
+ plugin->id(ld->UniqueID);
+
+ bool found = false;
+ for (list<Plugin*>::const_iterator i = m_plugins.begin(); i != m_plugins.end(); ++i) {
+ if ((*i)->uri() == plugin->uri()) {
+ cerr << "Warning: Duplicate DSSI plugin (" << plugin->lib_name() << ":"
+ << plugin->plug_label() << ")" << " found.\nUsing " << (*i)->lib_path()
+ << " version." << endl;
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ m_plugins.push_back(plugin);
+ else
+ delete plugin;
+ }
+
+ df = NULL;
+ descriptor = NULL;
+ dlclose(handle);
+ }
+ closedir(pdir);
+ }
+}
+
+
+/** Creates a Node by instancing a DSSI plugin.
+ */
+Node*
+NodeFactory::load_dssi_plugin(const string& uri,
+ const string& name, size_t poly, Patch* parent)
+{
+ // FIXME: awful code duplication here
+
+ assert(uri != "");
+ assert(name != "");
+ assert(poly > 0);
+
+ DSSI_Descriptor_Function df = NULL;
+ const Plugin* plugin = NULL;
+ Node* n = NULL;
+ void* handle = NULL;
+
+ // Attempt to find the lib
+ list<Plugin*>::iterator i;
+ for (i = m_plugins.begin(); i != m_plugins.end(); ++i) {
+ plugin = (*i);
+ if (plugin->uri() == uri) break;
+ }
+
+ assert(plugin->id() != 0);
+
+ if (i == m_plugins.end()) {
+ cerr << "Did not find DSSI plugin " << uri << " in database." << endl;
+ return NULL;
+ } else {
+ assert(plugin != NULL);
+ plugin->library()->open();
+ handle = plugin->library()->handle();
+ assert(handle != NULL);
+
+ // Load descriptor function
+ dlerror();
+ df = (DSSI_Descriptor_Function)dlsym(handle, "dssi_descriptor");
+ if (df == NULL || dlerror() != NULL) {
+ cerr << "Looks like this isn't a DSSI plugin." << endl;
+ return NULL;
+ }
+ }
+
+ // Attempt to find the plugin in lib
+ DSSI_Descriptor* descriptor = NULL;
+ for (unsigned long i=0; (descriptor = (DSSI_Descriptor*)df(i)) != NULL; ++i) {
+ if (descriptor->LADSPA_Plugin != NULL
+ && descriptor->LADSPA_Plugin->UniqueID == plugin->id()) {
+ break;
+ }
+ }
+
+ if (descriptor == NULL) {
+ cerr << "Could not find plugin \"" << plugin->id() << "\" in " << plugin->lib_name() << endl;
+ return NULL;
+ }
+
+ n = new DSSIPlugin(name, poly, parent, descriptor,
+ om->audio_driver()->sample_rate(), om->audio_driver()->buffer_size());
+ bool success = ((DSSIPlugin*)n)->instantiate();
+ if (!success) {
+ delete n;
+ n = NULL;
+ }
+
+ n->plugin(plugin);
+
+ return n;
+}
+#endif // HAVE_DSSI
+
+
+#ifdef HAVE_LADSPA
+/** Loads information about all LADSPA plugins into internal plugin database.
+ */
+void
+NodeFactory::load_ladspa_plugins()
+{
+ char* env_ladspa_path = getenv("LADSPA_PATH");
+ string ladspa_path;
+ if (!env_ladspa_path) {
+ cerr << "[NodeFactory] LADSPA_PATH is empty. Assuming /usr/lib/ladspa:/usr/local/lib/ladspa:~/.ladspa" << endl;
+ ladspa_path = string("/usr/lib/ladspa:/usr/local/lib/ladspa:").append(
+ getenv("HOME")).append("/.ladspa");
+ } else {
+ ladspa_path = env_ladspa_path;
+ }
+
+ LADSPA_Descriptor_Function df = NULL;
+ LADSPA_Descriptor* descriptor = NULL;
+
+ string dir;
+ string full_lib_name;
+
+ // Yep, this should use an sstream alright..
+ while (ladspa_path != "") {
+ dir = ladspa_path.substr(0, ladspa_path.find(':'));
+ if (ladspa_path.find(':') != string::npos)
+ ladspa_path = ladspa_path.substr(ladspa_path.find(':')+1);
+ else
+ ladspa_path = "";
+
+ DIR* pdir = opendir(dir.c_str());
+ if (pdir == NULL) {
+ //cerr << "[NodeFactory] Unreadable directory in LADSPA_PATH: " << dir.c_str() << endl;
+ continue;
+ }
+
+ struct dirent* pfile;
+ while ((pfile = readdir(pdir))) {
+
+ if (!strcmp(pfile->d_name, ".") || !strcmp(pfile->d_name, ".."))
+ continue;
+
+ full_lib_name = dir +"/"+ pfile->d_name;
+
+ // Load descriptor function
+ // Loaded with LAZY here, will be loaded with NOW on node loading
+ void* handle = dlopen(full_lib_name.c_str(), RTLD_LAZY);
+ if (handle == NULL)
+ continue;
+
+ df = (LADSPA_Descriptor_Function)dlsym(handle, "ladspa_descriptor");
+ if (df == NULL) {
+ dlclose(handle);
+ continue;
+ }
+
+ PluginLibrary* plugin_library = new PluginLibrary(full_lib_name);
+ m_libraries.push_back(plugin_library);
+
+ for (unsigned long i=0; (descriptor = (LADSPA_Descriptor*)df(i)) != NULL; ++i) {
+ Plugin* plugin = new Plugin();
+ assert(plugin_library != NULL);
+ plugin->library(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);
+
+ bool found = false;
+ for (list<Plugin*>::const_iterator i = m_plugins.begin(); i != m_plugins.end(); ++i) {
+ if ((*i)->uri() == plugin->uri()) {
+ cerr << "Warning: Duplicate LADSPA plugin " << plugin->uri()
+ << " found.\nChoosing " << (*i)->lib_path()
+ << " over " << plugin->lib_path() << endl;
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ m_plugins.push_back(plugin);
+ else
+ delete plugin;
+ }
+
+ df = NULL;
+ descriptor = NULL;
+ dlclose(handle);
+ }
+ closedir(pdir);
+ }
+}
+
+
+/** Loads a LADSPA plugin.
+ * Returns 'poly' independant plugins as a Node*
+ */
+Node*
+NodeFactory::load_ladspa_plugin(const string& uri,
+ const string& name, size_t poly, Patch* parent)
+{
+ assert(uri != "");
+ assert(name != "");
+ assert(poly > 0);
+
+ LADSPA_Descriptor_Function df = NULL;
+ Plugin* plugin = NULL;
+ Node* n = NULL;
+ void* plugin_lib = NULL;
+
+ // Attempt to find the lib
+ list<Plugin*>::iterator i;
+ for (i = m_plugins.begin(); i != m_plugins.end(); ++i) {
+ plugin = (*i);
+ if (plugin->uri() == uri) break;
+ }
+
+ assert(plugin->id() != 0);
+
+ if (i == m_plugins.end()) {
+ cerr << "Did not find LADSPA plugin " << uri << " in database." << endl;
+ return NULL;
+ } else {
+ assert(plugin != NULL);
+ plugin->library()->open();
+ plugin_lib = plugin->library()->handle();
+ assert(plugin_lib != NULL);
+
+ // Load descriptor function
+ dlerror();
+ df = (LADSPA_Descriptor_Function)dlsym(plugin_lib, "ladspa_descriptor");
+ if (df == NULL || dlerror() != NULL) {
+ cerr << "Looks like this isn't a LADSPA plugin." << endl;
+ return NULL;
+ }
+ }
+
+ // Attempt to find the plugin in lib
+ LADSPA_Descriptor* descriptor = NULL;
+ for (unsigned long i=0; (descriptor = (LADSPA_Descriptor*)df(i)) != NULL; ++i) {
+ if (descriptor->UniqueID == plugin->id()) {
+ break;
+ }
+ }
+
+ if (descriptor == NULL) {
+ cerr << "Could not find plugin \"" << plugin->id() << "\" in " << plugin->lib_path() << endl;
+ return NULL;
+ }
+
+ n = new LADSPAPlugin(name, poly, parent, descriptor,
+ om->audio_driver()->sample_rate(), om->audio_driver()->buffer_size());
+ bool success = ((LADSPAPlugin*)n)->instantiate();
+ if (!success) {
+ delete n;
+ n = NULL;
+ }
+
+ n->plugin(plugin);
+
+ return n;
+}
+
+
+#endif // HAVE_LADSPA
+
+
+} // namespace Om