2 Copyright (C) 2000-2004 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include <sys/types.h>
28 #include <pbd/basename.h>
32 #include <pbd/pathscanner.h>
34 #include <ardour/ladspa.h>
35 #include <ardour/session.h>
36 #include <ardour/plugin_manager.h>
37 #include <ardour/plugin.h>
38 #include <ardour/ladspa_plugin.h>
39 #include <ardour/vst_plugin.h>
41 #include <pbd/error.h>
42 #include <pbd/stl_delete.h>
45 #include <CoreServices/CoreServices.h>
46 #include <AudioUnit/AudioUnit.h>
47 #endif // HAVE_COREAUDIO
51 using namespace ARDOUR;
54 PluginManager* PluginManager::_manager = 0;
56 PluginManager::PluginManager (AudioEngine& e)
62 if ((s = getenv ("LADSPA_RDF_PATH"))){
66 if (lrdf_path.length() == 0) {
67 lrdf_path = "/usr/local/share/ladspa/rdf:/usr/share/ladspa/rdf";
70 add_lrdf_data(lrdf_path);
73 if (Config->get_use_vst()) {
76 #endif /* VST_SUPPORT */
78 if ((s = getenv ("LADSPA_PATH"))) {
82 if ((s = getenv ("VST_PATH"))) {
84 } else if ((s = getenv ("VST_PLUGINS"))) {
96 PluginManager::refresh ()
100 if (Config->get_use_vst()) {
103 #endif // VST_SUPPORT
105 #ifdef HAVE_COREAUDIO
107 #endif // HAVE_COREAUDIO
111 PluginManager::ladspa_refresh ()
113 for (std::list<PluginInfo*>::iterator i = _ladspa_plugin_info.begin(); i != _ladspa_plugin_info.end(); ++i) {
117 _ladspa_plugin_info.clear ();
119 if (ladspa_path.length() == 0) {
120 ladspa_path = "/usr/local/lib/ladspa:/usr/lib/ladspa";
123 ladspa_discover_from_path (ladspa_path);
127 PluginManager::add_ladspa_directory (string path)
129 if (ladspa_discover_from_path (path) == 0) {
137 static bool ladspa_filter (const string& str, void *arg)
139 /* Not a dotfile, has a prefix before a period, suffix is "so" */
141 return str[0] != '.' && (str.length() > 3 && str.find (".so") == (str.length() - 3));
145 PluginManager::ladspa_discover_from_path (string path)
148 vector<string *> *plugin_objects;
149 vector<string *>::iterator x;
152 plugin_objects = scanner (ladspa_path, ladspa_filter, 0, true, true);
154 if (plugin_objects) {
155 for (x = plugin_objects->begin(); x != plugin_objects->end (); ++x) {
156 ladspa_discover (**x);
160 vector_delete (plugin_objects);
164 static bool rdf_filter (const string &str, void *arg)
166 return str[0] != '.' &&
167 ((str.find(".rdf") == (str.length() - 4)) ||
168 (str.find(".rdfs") == (str.length() - 5)) ||
169 (str.find(".n3") == (str.length() - 3)));
173 PluginManager::add_ladspa_presets()
175 add_presets ("ladspa");
179 PluginManager::add_vst_presets()
184 PluginManager::add_presets(string domain)
188 vector<string *> *presets;
189 vector<string *>::iterator x;
192 if ((envvar = getenv ("HOME")) == 0) {
196 string path = string_compose("%1/.%2/rdf", envvar, domain);
197 presets = scanner (path, rdf_filter, 0, true, true);
200 for (x = presets->begin(); x != presets->end (); ++x) {
201 string file = "file:" + **x;
202 if (lrdf_read_file(file.c_str())) {
203 warning << string_compose(_("Could not parse rdf file: %1"), *x) << endmsg;
208 vector_delete (presets);
212 PluginManager::add_lrdf_data (const string &path)
215 vector<string *>* rdf_files;
216 vector<string *>::iterator x;
219 rdf_files = scanner (path, rdf_filter, 0, true, true);
222 for (x = rdf_files->begin(); x != rdf_files->end (); ++x) {
223 uri = "file://" + **x;
225 if (lrdf_read_file(uri.c_str())) {
226 warning << "Could not parse rdf file: " << uri << endmsg;
231 vector_delete (rdf_files);
235 PluginManager::ladspa_discover (string path)
239 const LADSPA_Descriptor *descriptor;
240 LADSPA_Descriptor_Function dfunc;
243 if ((module = dlopen (path.c_str(), RTLD_NOW)) == 0) {
244 error << string_compose(_("LADSPA: cannot load module \"%1\" (%2)"), path, dlerror()) << endmsg;
248 dfunc = (LADSPA_Descriptor_Function) dlsym (module, "ladspa_descriptor");
250 if ((errstr = dlerror()) != 0) {
251 error << string_compose(_("LADSPA: module \"%1\" has no descriptor function."), path) << endmsg;
252 error << errstr << endmsg;
257 for (uint32_t i = 0; ; ++i) {
258 if ((descriptor = dfunc (i)) == 0) {
262 info = new PluginInfo;
263 info->name = descriptor->Name;
264 info->category = get_ladspa_category(descriptor->UniqueID);
269 info->type = PluginInfo::LADSPA;
270 info->unique_id = descriptor->UniqueID;
272 for (uint32_t n=0; n < descriptor->PortCount; ++n) {
273 if ( LADSPA_IS_PORT_AUDIO (descriptor->PortDescriptors[n]) ) {
274 if ( LADSPA_IS_PORT_INPUT (descriptor->PortDescriptors[n]) ) {
277 else if ( LADSPA_IS_PORT_OUTPUT (descriptor->PortDescriptors[n]) ) {
283 _ladspa_plugin_info.push_back (info);
286 // GDB WILL NOT LIKE YOU IF YOU DO THIS
292 boost::shared_ptr<Plugin>
293 PluginManager::load (Session& session, PluginInfo *info)
298 boost::shared_ptr<Plugin> plugin;
300 if (info->type == PluginInfo::VST) {
303 if (Config->get_use_vst()) {
306 if ((handle = fst_load (info->path.c_str())) == 0) {
307 error << string_compose(_("VST: cannot load module from \"%1\""), info->path) << endmsg;
309 plugin.reset (new VSTPlugin (_engine, session, handle));
312 error << _("You asked ardour to not use any VST plugins") << endmsg;
314 #else // !VST_SUPPORT
315 error << _("This version of ardour has no support for VST plugins") << endmsg;
316 return boost::shared_ptr<Plugin> ((Plugin*) 0);
317 #endif // !VST_SUPPORT
321 if ((module = dlopen (info->path.c_str(), RTLD_NOW)) == 0) {
322 error << string_compose(_("LADSPA: cannot load module from \"%1\""), info->path) << endmsg;
323 error << dlerror() << endmsg;
325 plugin.reset (new LadspaPlugin (module, _engine, session, info->index, session.frame_rate()));
329 plugin->set_info(*info);
333 catch (failed_constructor &err) {
334 return boost::shared_ptr<Plugin> ((Plugin*) 0);
338 boost::shared_ptr<Plugin>
339 ARDOUR::find_plugin(Session& session, string name, long unique_id, PluginInfo::Type type)
341 PluginManager *mgr = PluginManager::the_manager();
342 list<PluginInfo *>::iterator i;
343 list<PluginInfo *>* plugs = 0;
346 case PluginInfo::LADSPA:
347 plugs = &mgr->ladspa_plugin_info();
349 case PluginInfo::VST:
350 plugs = &mgr->vst_plugin_info();
351 unique_id = 0; // VST plugins don't have a unique id.
353 case PluginInfo::AudioUnit:
354 plugs = &mgr->au_plugin_info();
358 return boost::shared_ptr<Plugin> ((Plugin *) 0);
361 for (i = plugs->begin(); i != plugs->end(); ++i) {
362 if ((name == "" || (*i)->name == name) &&
363 (unique_id == 0 || (*i)->unique_id == unique_id)) {
364 return mgr->load (session, *i);
368 return boost::shared_ptr<Plugin> ((Plugin*) 0);
372 PluginManager::get_ladspa_category (uint32_t plugin_id)
375 lrdf_statement pattern;
377 snprintf(buf, sizeof(buf), "%s%" PRIu32, LADSPA_BASE, plugin_id);
378 pattern.subject = buf;
379 pattern.predicate = RDF_TYPE;
381 pattern.object_type = lrdf_uri;
383 lrdf_statement* matches1 = lrdf_matches (&pattern);
389 pattern.subject = matches1->object;
390 pattern.predicate = LADSPA_BASE "hasLabel";
392 pattern.object_type = lrdf_literal;
394 lrdf_statement* matches2 = lrdf_matches (&pattern);
395 lrdf_free_statements(matches1);
401 string label = matches2->object;
402 lrdf_free_statements(matches2);
410 PluginManager::vst_refresh ()
412 for (std::list<PluginInfo*>::iterator i = _vst_plugin_info.begin(); i != _vst_plugin_info.end(); ++i) {
416 _vst_plugin_info.clear ();
418 if (vst_path.length() == 0) {
419 vst_path = "/usr/local/lib/vst:/usr/lib/vst";
422 vst_discover_from_path (vst_path);
426 PluginManager::add_vst_directory (string path)
428 if (vst_discover_from_path (path) == 0) {
436 static bool vst_filter (const string& str, void *arg)
438 /* Not a dotfile, has a prefix before a period, suffix is "dll" */
440 return str[0] != '.' && (str.length() > 4 && str.find (".dll") == (str.length() - 4));
444 PluginManager::vst_discover_from_path (string path)
447 vector<string *> *plugin_objects;
448 vector<string *>::iterator x;
451 info << "detecting VST plugins along " << path << endmsg;
453 plugin_objects = scanner (vst_path, vst_filter, 0, true, true);
455 if (plugin_objects) {
456 for (x = plugin_objects->begin(); x != plugin_objects->end (); ++x) {
461 vector_delete (plugin_objects);
466 PluginManager::vst_discover (string path)
471 if ((finfo = fst_get_info (const_cast<char *> (path.c_str()))) == 0) {
475 if (!finfo->canProcessReplacing) {
476 warning << string_compose (_("VST plugin %1 does not support processReplacing, and so cannot be used in ardour at this time"),
481 info = new PluginInfo;
483 /* what a goddam joke freeware VST is */
485 if (!strcasecmp ("The Unnamed plugin", finfo->name)) {
486 info->name = PBD::basename_nosuffix (path);
488 info->name = finfo->name;
491 info->category = "VST";
494 info->n_inputs = finfo->numInputs;
495 info->n_outputs = finfo->numOutputs;
496 info->type = PluginInfo::VST;
498 _vst_plugin_info.push_back (info);
499 fst_free_info (finfo);
504 #endif // VST_SUPPORT
506 #ifdef HAVE_COREAUDIO
509 PluginManager::au_discover ()
511 _au_plugin_info.clear ();
513 int numTypes = 2; // this magic number was retrieved from the apple AUHost example.
515 ComponentDescription desc;
516 desc.componentFlags = 0;
517 desc.componentFlagsMask = 0;
518 desc.componentSubType = 0;
519 desc.componentManufacturer = 0;
521 vector<ComponentDescription> vCompDescs;
523 for (int i = 0; i < numTypes; ++i) {
525 desc.componentType = kAudioUnitType_MusicEffect;
527 desc.componentType = kAudioUnitType_Effect;
532 comp = FindNextComponent (NULL, &desc);
533 while (comp != NULL) {
534 ComponentDescription temp;
535 GetComponentInfo (comp, &temp, NULL, NULL, NULL);
536 vCompDescs.push_back(temp);
537 comp = FindNextComponent (comp, &desc);
542 for (unsigned int i = 0; i < vCompDescs.size(); ++i) {
544 // the following large block is just for determining the name of the plugin.
545 CFStringRef itemName = NULL;
546 // Marc Poirier -style item name
547 Component auComponent = FindNextComponent (0, &(vCompDescs[i]));
548 if (auComponent != NULL) {
549 ComponentDescription dummydesc;
550 Handle nameHandle = NewHandle(sizeof(void*));
551 if (nameHandle != NULL) {
552 OSErr err = GetComponentInfo(auComponent, &dummydesc, nameHandle, NULL, NULL);
554 ConstStr255Param nameString = (ConstStr255Param) (*nameHandle);
555 if (nameString != NULL) {
556 itemName = CFStringCreateWithPascalString(kCFAllocatorDefault, nameString, CFStringGetSystemEncoding());
559 DisposeHandle(nameHandle);
563 // if Marc-style fails, do the original way
564 if (itemName == NULL) {
565 CFStringRef compTypeString = UTCreateStringForOSType(vCompDescs[i].componentType);
566 CFStringRef compSubTypeString = UTCreateStringForOSType(vCompDescs[i].componentSubType);
567 CFStringRef compManufacturerString = UTCreateStringForOSType(vCompDescs[i].componentManufacturer);
569 itemName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@ - %@ - %@"),
570 compTypeString, compManufacturerString, compSubTypeString);
572 if (compTypeString != NULL)
573 CFRelease(compTypeString);
574 if (compSubTypeString != NULL)
575 CFRelease(compSubTypeString);
576 if (compManufacturerString != NULL)
577 CFRelease(compManufacturerString);
579 string realname = CFStringRefToStdString(itemName);
581 plug = new PluginInfo;
582 plug->name = realname;
583 plug->type = PluginInfo::AudioUnit;
586 plug->category = "AudioUnit";
588 _au_plugin_info.push_back(plug);
594 #endif // HAVE_COREAUDIO