708 lines
19 KiB
C++
708 lines
19 KiB
C++
/* 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
|