annotate plugin/LADSPAPluginFactory.cpp @ 97:22494cc28c9f

* Reduce number of allocations and deallocations by keeping a spare buffer around (we were generally deallocating and then immediately allocating again, so it's much better not to have to bother as very large allocations can tie up the system)
author Chris Cannam
date Thu, 04 May 2006 20:17:28 +0000
parents c983dda79f72
children 45175d8c5dc5
rev   line source
Chris@49 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@0 2
Chris@0 3 /*
Chris@52 4 Sonic Visualiser
Chris@52 5 An audio file viewer and annotation editor.
Chris@52 6 Centre for Digital Music, Queen Mary, University of London.
Chris@0 7
Chris@52 8 This program is free software; you can redistribute it and/or
Chris@52 9 modify it under the terms of the GNU General Public License as
Chris@52 10 published by the Free Software Foundation; either version 2 of the
Chris@52 11 License, or (at your option) any later version. See the file
Chris@52 12 COPYING included with this distribution for more information.
Chris@0 13 */
Chris@0 14
Chris@0 15 /*
Chris@0 16 This is a modified version of a source file from the
Chris@0 17 Rosegarden MIDI and audio sequencer and notation editor.
Chris@17 18 This file copyright 2000-2006 Chris Cannam and Richard Bown.
Chris@0 19 */
Chris@0 20
Chris@0 21 #include "LADSPAPluginFactory.h"
Chris@0 22 #include <iostream>
Chris@0 23
Chris@0 24 #include <QDir>
Chris@0 25 #include <QFile>
Chris@0 26 #include <QTextStream>
Chris@0 27
Chris@0 28 #include <cmath>
Chris@0 29
Chris@0 30 #include "LADSPAPluginInstance.h"
Chris@0 31 #include "PluginIdentifier.h"
Chris@0 32
Chris@0 33 #include "base/System.h"
Chris@0 34
Chris@35 35 #ifdef HAVE_LRDF
Chris@0 36 #include "lrdf.h"
Chris@35 37 #endif // HAVE_LRDF
Chris@0 38
Chris@0 39
Chris@0 40 LADSPAPluginFactory::LADSPAPluginFactory()
Chris@0 41 {
Chris@0 42 }
Chris@0 43
Chris@0 44 LADSPAPluginFactory::~LADSPAPluginFactory()
Chris@0 45 {
Chris@0 46 for (std::set<RealTimePluginInstance *>::iterator i = m_instances.begin();
Chris@0 47 i != m_instances.end(); ++i) {
Chris@0 48 (*i)->setFactory(0);
Chris@0 49 delete *i;
Chris@0 50 }
Chris@0 51 m_instances.clear();
Chris@0 52 unloadUnusedLibraries();
Chris@0 53 }
Chris@0 54
Chris@0 55 const std::vector<QString> &
Chris@0 56 LADSPAPluginFactory::getPluginIdentifiers() const
Chris@0 57 {
Chris@0 58 return m_identifiers;
Chris@0 59 }
Chris@0 60
Chris@0 61 void
Chris@0 62 LADSPAPluginFactory::enumeratePlugins(std::vector<QString> &list)
Chris@0 63 {
Chris@0 64 for (std::vector<QString>::iterator i = m_identifiers.begin();
Chris@0 65 i != m_identifiers.end(); ++i) {
Chris@0 66
Chris@0 67 const LADSPA_Descriptor *descriptor = getLADSPADescriptor(*i);
Chris@0 68
Chris@0 69 if (!descriptor) {
Chris@0 70 std::cerr << "WARNING: LADSPAPluginFactory::enumeratePlugins: couldn't get descriptor for identifier " << i->toStdString() << std::endl;
Chris@0 71 continue;
Chris@0 72 }
Chris@0 73
Chris@0 74 list.push_back(*i);
Chris@0 75 list.push_back(descriptor->Name);
Chris@0 76 list.push_back(QString("%1").arg(descriptor->UniqueID));
Chris@0 77 list.push_back(descriptor->Label);
Chris@0 78 list.push_back(descriptor->Maker);
Chris@0 79 list.push_back(descriptor->Copyright);
Chris@0 80 list.push_back("false"); // is synth
Chris@0 81 list.push_back("false"); // is grouped
Chris@0 82
Chris@0 83 if (m_taxonomy.find(descriptor->UniqueID) != m_taxonomy.end() &&
Chris@0 84 m_taxonomy[descriptor->UniqueID] != "") {
Chris@0 85 // std::cerr << "LADSPAPluginFactory: cat for " << i->toStdString()<< " found in taxonomy as " << m_taxonomy[descriptor->UniqueID] << std::endl;
Chris@0 86 list.push_back(m_taxonomy[descriptor->UniqueID]);
Chris@0 87
Chris@0 88 } else if (m_fallbackCategories.find(*i) !=
Chris@0 89 m_fallbackCategories.end()) {
Chris@0 90 list.push_back(m_fallbackCategories[*i]);
Chris@0 91 // std::cerr << "LADSPAPluginFactory: cat for " << i->toStdString() <<" found in fallbacks as " << m_fallbackCategories[*i] << std::endl;
Chris@0 92
Chris@0 93 } else {
Chris@0 94 list.push_back("");
Chris@0 95 // std::cerr << "LADSPAPluginFactory: cat for " << i->toStdString() << " not found (despite having " << m_fallbackCategories.size() << " fallbacks)" << std::endl;
Chris@0 96
Chris@0 97 }
Chris@0 98
Chris@0 99 list.push_back(QString("%1").arg(descriptor->PortCount));
Chris@0 100
Chris@0 101 for (unsigned long p = 0; p < descriptor->PortCount; ++p) {
Chris@0 102
Chris@0 103 int type = 0;
Chris@0 104 if (LADSPA_IS_PORT_CONTROL(descriptor->PortDescriptors[p])) {
Chris@0 105 type |= PortType::Control;
Chris@0 106 } else {
Chris@0 107 type |= PortType::Audio;
Chris@0 108 }
Chris@0 109 if (LADSPA_IS_PORT_INPUT(descriptor->PortDescriptors[p])) {
Chris@0 110 type |= PortType::Input;
Chris@0 111 } else {
Chris@0 112 type |= PortType::Output;
Chris@0 113 }
Chris@0 114
Chris@0 115 list.push_back(QString("%1").arg(p));
Chris@0 116 list.push_back(descriptor->PortNames[p]);
Chris@0 117 list.push_back(QString("%1").arg(type));
Chris@0 118 list.push_back(QString("%1").arg(getPortDisplayHint(descriptor, p)));
Chris@0 119 list.push_back(QString("%1").arg(getPortMinimum(descriptor, p)));
Chris@0 120 list.push_back(QString("%1").arg(getPortMaximum(descriptor, p)));
Chris@0 121 list.push_back(QString("%1").arg(getPortDefault(descriptor, p)));
Chris@0 122 }
Chris@0 123 }
Chris@0 124
Chris@0 125 unloadUnusedLibraries();
Chris@0 126 }
Chris@0 127
Chris@60 128 const RealTimePluginDescriptor *
Chris@60 129 LADSPAPluginFactory::getPluginDescriptor(QString identifier) const
Chris@60 130 {
Chris@60 131 std::map<QString, RealTimePluginDescriptor *>::const_iterator i =
Chris@60 132 m_rtDescriptors.find(identifier);
Chris@60 133
Chris@60 134 if (i != m_rtDescriptors.end()) {
Chris@60 135 return i->second;
Chris@60 136 }
Chris@60 137
Chris@60 138 return 0;
Chris@60 139 }
Chris@60 140
Chris@0 141 float
Chris@0 142 LADSPAPluginFactory::getPortMinimum(const LADSPA_Descriptor *descriptor, int port)
Chris@0 143 {
Chris@0 144 LADSPA_PortRangeHintDescriptor d =
Chris@0 145 descriptor->PortRangeHints[port].HintDescriptor;
Chris@0 146
Chris@0 147 float minimum = 0.0;
Chris@0 148
Chris@0 149 if (LADSPA_IS_HINT_BOUNDED_BELOW(d)) {
Chris@0 150 float lb = descriptor->PortRangeHints[port].LowerBound;
Chris@0 151 minimum = lb;
Chris@0 152 } else if (LADSPA_IS_HINT_BOUNDED_ABOVE(d)) {
Chris@0 153 float ub = descriptor->PortRangeHints[port].UpperBound;
Chris@0 154 minimum = std::min(0.0, ub - 1.0);
Chris@0 155 }
Chris@0 156
Chris@0 157 if (LADSPA_IS_HINT_SAMPLE_RATE(d)) {
Chris@0 158 minimum *= m_sampleRate;
Chris@0 159 }
Chris@0 160
Chris@0 161 return minimum;
Chris@0 162 }
Chris@0 163
Chris@0 164 float
Chris@0 165 LADSPAPluginFactory::getPortMaximum(const LADSPA_Descriptor *descriptor, int port)
Chris@0 166 {
Chris@0 167 LADSPA_PortRangeHintDescriptor d =
Chris@0 168 descriptor->PortRangeHints[port].HintDescriptor;
Chris@0 169
Chris@0 170 float maximum = 1.0;
Chris@0 171
Chris@0 172 if (LADSPA_IS_HINT_BOUNDED_ABOVE(d)) {
Chris@0 173 float ub = descriptor->PortRangeHints[port].UpperBound;
Chris@0 174 maximum = ub;
Chris@0 175 } else {
Chris@0 176 float lb = descriptor->PortRangeHints[port].LowerBound;
Chris@0 177 maximum = lb + 1.0;
Chris@0 178 }
Chris@0 179
Chris@0 180 if (LADSPA_IS_HINT_SAMPLE_RATE(d)) {
Chris@0 181 maximum *= m_sampleRate;
Chris@0 182 }
Chris@0 183
Chris@0 184 return maximum;
Chris@0 185 }
Chris@0 186
Chris@0 187 float
Chris@0 188 LADSPAPluginFactory::getPortDefault(const LADSPA_Descriptor *descriptor, int port)
Chris@0 189 {
Chris@0 190 float minimum = getPortMinimum(descriptor, port);
Chris@0 191 float maximum = getPortMaximum(descriptor, port);
Chris@0 192 float deft;
Chris@0 193
Chris@0 194 if (m_portDefaults.find(descriptor->UniqueID) !=
Chris@0 195 m_portDefaults.end()) {
Chris@0 196 if (m_portDefaults[descriptor->UniqueID].find(port) !=
Chris@0 197 m_portDefaults[descriptor->UniqueID].end()) {
Chris@0 198
Chris@0 199 deft = m_portDefaults[descriptor->UniqueID][port];
Chris@0 200 if (deft < minimum) deft = minimum;
Chris@0 201 if (deft > maximum) deft = maximum;
Chris@0 202 return deft;
Chris@0 203 }
Chris@0 204 }
Chris@0 205
Chris@0 206 LADSPA_PortRangeHintDescriptor d =
Chris@0 207 descriptor->PortRangeHints[port].HintDescriptor;
Chris@0 208
Chris@0 209 bool logarithmic = LADSPA_IS_HINT_LOGARITHMIC(d);
Chris@0 210
Chris@0 211 if (!LADSPA_IS_HINT_HAS_DEFAULT(d)) {
Chris@0 212
Chris@0 213 deft = minimum;
Chris@0 214
Chris@0 215 } else if (LADSPA_IS_HINT_DEFAULT_MINIMUM(d)) {
Chris@0 216
Chris@0 217 deft = minimum;
Chris@0 218
Chris@0 219 } else if (LADSPA_IS_HINT_DEFAULT_LOW(d)) {
Chris@0 220
Chris@0 221 if (logarithmic) {
Chris@0 222 deft = powf(10, log10(minimum) * 0.75 +
Chris@0 223 log10(maximum) * 0.25);
Chris@0 224 } else {
Chris@0 225 deft = minimum * 0.75 + maximum * 0.25;
Chris@0 226 }
Chris@0 227
Chris@0 228 } else if (LADSPA_IS_HINT_DEFAULT_MIDDLE(d)) {
Chris@0 229
Chris@0 230 if (logarithmic) {
Chris@0 231 deft = powf(10, log10(minimum) * 0.5 +
Chris@0 232 log10(maximum) * 0.5);
Chris@0 233 } else {
Chris@0 234 deft = minimum * 0.5 + maximum * 0.5;
Chris@0 235 }
Chris@0 236
Chris@0 237 } else if (LADSPA_IS_HINT_DEFAULT_HIGH(d)) {
Chris@0 238
Chris@0 239 if (logarithmic) {
Chris@0 240 deft = powf(10, log10(minimum) * 0.25 +
Chris@0 241 log10(maximum) * 0.75);
Chris@0 242 } else {
Chris@0 243 deft = minimum * 0.25 + maximum * 0.75;
Chris@0 244 }
Chris@0 245
Chris@0 246 } else if (LADSPA_IS_HINT_DEFAULT_MAXIMUM(d)) {
Chris@0 247
Chris@0 248 deft = maximum;
Chris@0 249
Chris@0 250 } else if (LADSPA_IS_HINT_DEFAULT_0(d)) {
Chris@0 251
Chris@0 252 deft = 0.0;
Chris@0 253
Chris@0 254 } else if (LADSPA_IS_HINT_DEFAULT_1(d)) {
Chris@0 255
Chris@0 256 deft = 1.0;
Chris@0 257
Chris@0 258 } else if (LADSPA_IS_HINT_DEFAULT_100(d)) {
Chris@0 259
Chris@0 260 deft = 100.0;
Chris@0 261
Chris@0 262 } else if (LADSPA_IS_HINT_DEFAULT_440(d)) {
Chris@0 263
Chris@0 264 deft = 440.0;
Chris@0 265
Chris@0 266 } else {
Chris@0 267
Chris@0 268 deft = minimum;
Chris@0 269 }
Chris@0 270
Chris@0 271 if (LADSPA_IS_HINT_SAMPLE_RATE(d)) {
Chris@0 272 deft *= m_sampleRate;
Chris@0 273 }
Chris@0 274
Chris@0 275 return deft;
Chris@0 276 }
Chris@0 277
Chris@57 278 float
Chris@57 279 LADSPAPluginFactory::getPortQuantization(const LADSPA_Descriptor *descriptor, int port)
Chris@57 280 {
Chris@57 281 int displayHint = getPortDisplayHint(descriptor, port);
Chris@57 282 if (displayHint & PortHint::Toggled) {
Chris@57 283 return lrintf(getPortMaximum(descriptor, port)) -
Chris@57 284 lrintf(getPortMinimum(descriptor, port));
Chris@57 285 }
Chris@57 286 if (displayHint & PortHint::Integer) {
Chris@57 287 return 1.0;
Chris@57 288 }
Chris@57 289 return 0.0;
Chris@57 290 }
Chris@57 291
Chris@0 292 int
Chris@0 293 LADSPAPluginFactory::getPortDisplayHint(const LADSPA_Descriptor *descriptor, int port)
Chris@0 294 {
Chris@0 295 LADSPA_PortRangeHintDescriptor d =
Chris@0 296 descriptor->PortRangeHints[port].HintDescriptor;
Chris@0 297 int hint = PortHint::NoHint;
Chris@0 298
Chris@0 299 if (LADSPA_IS_HINT_TOGGLED(d)) hint |= PortHint::Toggled;
Chris@0 300 if (LADSPA_IS_HINT_INTEGER(d)) hint |= PortHint::Integer;
Chris@0 301 if (LADSPA_IS_HINT_LOGARITHMIC(d)) hint |= PortHint::Logarithmic;
Chris@0 302
Chris@0 303 return hint;
Chris@0 304 }
Chris@0 305
Chris@0 306
Chris@0 307 RealTimePluginInstance *
Chris@0 308 LADSPAPluginFactory::instantiatePlugin(QString identifier,
Chris@0 309 int instrument,
Chris@0 310 int position,
Chris@0 311 unsigned int sampleRate,
Chris@0 312 unsigned int blockSize,
Chris@0 313 unsigned int channels)
Chris@0 314 {
Chris@0 315 const LADSPA_Descriptor *descriptor = getLADSPADescriptor(identifier);
Chris@0 316
Chris@0 317 if (descriptor) {
Chris@0 318
Chris@0 319 LADSPAPluginInstance *instance =
Chris@0 320 new LADSPAPluginInstance
Chris@0 321 (this, instrument, identifier, position, sampleRate, blockSize, channels,
Chris@0 322 descriptor);
Chris@0 323
Chris@0 324 m_instances.insert(instance);
Chris@0 325
Chris@78 326 std::cerr << "LADSPAPluginFactory::instantiatePlugin("
Chris@78 327 << identifier.toStdString() << ": now have " << m_instances.size() << " instances" << std::endl;
Chris@78 328
Chris@0 329 return instance;
Chris@0 330 }
Chris@0 331
Chris@0 332 return 0;
Chris@0 333 }
Chris@0 334
Chris@0 335 void
Chris@0 336 LADSPAPluginFactory::releasePlugin(RealTimePluginInstance *instance,
Chris@0 337 QString identifier)
Chris@0 338 {
Chris@0 339 if (m_instances.find(instance) == m_instances.end()) {
Chris@0 340 std::cerr << "WARNING: LADSPAPluginFactory::releasePlugin: Not one of mine!"
Chris@0 341 << std::endl;
Chris@0 342 return;
Chris@0 343 }
Chris@0 344
Chris@0 345 QString type, soname, label;
Chris@0 346 PluginIdentifier::parseIdentifier(identifier, type, soname, label);
Chris@0 347
Chris@0 348 m_instances.erase(instance);
Chris@0 349
Chris@0 350 bool stillInUse = false;
Chris@0 351
Chris@0 352 for (std::set<RealTimePluginInstance *>::iterator ii = m_instances.begin();
Chris@0 353 ii != m_instances.end(); ++ii) {
Chris@0 354 QString itype, isoname, ilabel;
Chris@0 355 PluginIdentifier::parseIdentifier((*ii)->getIdentifier(), itype, isoname, ilabel);
Chris@0 356 if (isoname == soname) {
Chris@78 357 std::cerr << "LADSPAPluginFactory::releasePlugin: dll " << soname.toStdString() << " is still in use for plugin " << ilabel.toStdString() << std::endl;
Chris@0 358 stillInUse = true;
Chris@0 359 break;
Chris@0 360 }
Chris@0 361 }
Chris@0 362
Chris@0 363 if (!stillInUse) {
Chris@78 364 std::cerr << "LADSPAPluginFactory::releasePlugin: dll " << soname.toStdString() << " no longer in use, unloading" << std::endl;
Chris@0 365 unloadLibrary(soname);
Chris@0 366 }
Chris@78 367
Chris@78 368 std::cerr << "LADSPAPluginFactory::releasePlugin("
Chris@78 369 << identifier.toStdString() << ": now have " << m_instances.size() << " instances" << std::endl;
Chris@0 370 }
Chris@0 371
Chris@0 372 const LADSPA_Descriptor *
Chris@0 373 LADSPAPluginFactory::getLADSPADescriptor(QString identifier)
Chris@0 374 {
Chris@0 375 QString type, soname, label;
Chris@0 376 PluginIdentifier::parseIdentifier(identifier, type, soname, label);
Chris@0 377
Chris@0 378 if (m_libraryHandles.find(soname) == m_libraryHandles.end()) {
Chris@0 379 loadLibrary(soname);
Chris@0 380 if (m_libraryHandles.find(soname) == m_libraryHandles.end()) {
Chris@0 381 std::cerr << "WARNING: LADSPAPluginFactory::getLADSPADescriptor: loadLibrary failed for " << soname.toStdString() << std::endl;
Chris@0 382 return 0;
Chris@0 383 }
Chris@0 384 }
Chris@0 385
Chris@0 386 void *libraryHandle = m_libraryHandles[soname];
Chris@0 387
Chris@0 388 LADSPA_Descriptor_Function fn = (LADSPA_Descriptor_Function)
Chris@0 389 DLSYM(libraryHandle, "ladspa_descriptor");
Chris@0 390
Chris@0 391 if (!fn) {
Chris@0 392 std::cerr << "WARNING: LADSPAPluginFactory::getLADSPADescriptor: No descriptor function in library " << soname.toStdString() << std::endl;
Chris@0 393 return 0;
Chris@0 394 }
Chris@0 395
Chris@0 396 const LADSPA_Descriptor *descriptor = 0;
Chris@0 397
Chris@0 398 int index = 0;
Chris@0 399 while ((descriptor = fn(index))) {
Chris@0 400 if (descriptor->Label == label) return descriptor;
Chris@0 401 ++index;
Chris@0 402 }
Chris@0 403
Chris@0 404 std::cerr << "WARNING: LADSPAPluginFactory::getLADSPADescriptor: No such plugin as " << label.toStdString() << " in library " << soname.toStdString() << std::endl;
Chris@0 405
Chris@0 406 return 0;
Chris@0 407 }
Chris@0 408
Chris@0 409 void
Chris@0 410 LADSPAPluginFactory::loadLibrary(QString soName)
Chris@0 411 {
Chris@0 412 void *libraryHandle = DLOPEN(soName, RTLD_NOW);
Chris@0 413 if (libraryHandle) m_libraryHandles[soName] = libraryHandle;
Chris@0 414 }
Chris@0 415
Chris@0 416 void
Chris@0 417 LADSPAPluginFactory::unloadLibrary(QString soName)
Chris@0 418 {
Chris@0 419 LibraryHandleMap::iterator li = m_libraryHandles.find(soName);
Chris@0 420 if (li != m_libraryHandles.end()) {
Chris@0 421 // std::cerr << "unloading " << soname.toStdString() << std::endl;
Chris@0 422 DLCLOSE(m_libraryHandles[soName]);
Chris@0 423 m_libraryHandles.erase(li);
Chris@0 424 }
Chris@0 425 }
Chris@0 426
Chris@0 427 void
Chris@0 428 LADSPAPluginFactory::unloadUnusedLibraries()
Chris@0 429 {
Chris@0 430 std::vector<QString> toUnload;
Chris@0 431
Chris@0 432 for (LibraryHandleMap::iterator i = m_libraryHandles.begin();
Chris@0 433 i != m_libraryHandles.end(); ++i) {
Chris@0 434
Chris@0 435 bool stillInUse = false;
Chris@0 436
Chris@0 437 for (std::set<RealTimePluginInstance *>::iterator ii = m_instances.begin();
Chris@0 438 ii != m_instances.end(); ++ii) {
Chris@0 439
Chris@0 440 QString itype, isoname, ilabel;
Chris@0 441 PluginIdentifier::parseIdentifier((*ii)->getIdentifier(), itype, isoname, ilabel);
Chris@0 442 if (isoname == i->first) {
Chris@0 443 stillInUse = true;
Chris@0 444 break;
Chris@0 445 }
Chris@0 446 }
Chris@0 447
Chris@0 448 if (!stillInUse) toUnload.push_back(i->first);
Chris@0 449 }
Chris@0 450
Chris@0 451 for (std::vector<QString>::iterator i = toUnload.begin();
Chris@0 452 i != toUnload.end(); ++i) {
Chris@0 453 unloadLibrary(*i);
Chris@0 454 }
Chris@0 455 }
Chris@0 456
Chris@0 457
Chris@0 458 // It is only later, after they've gone,
Chris@0 459 // I realize they have delivered a letter.
Chris@0 460 // It's a letter from my wife. "What are you doing
Chris@0 461 // there?" my wife asks. "Are you drinking?"
Chris@0 462 // I study the postmark for hours. Then it, too, begins to fade.
Chris@0 463 // I hope someday to forget all this.
Chris@0 464
Chris@0 465
Chris@0 466 std::vector<QString>
Chris@0 467 LADSPAPluginFactory::getPluginPath()
Chris@0 468 {
Chris@0 469 std::vector<QString> pathList;
Chris@0 470 std::string path;
Chris@0 471
Chris@0 472 char *cpath = getenv("LADSPA_PATH");
Chris@0 473 if (cpath) path = cpath;
Chris@0 474
Chris@0 475 if (path == "") {
Chris@0 476 path = "/usr/local/lib/ladspa:/usr/lib/ladspa";
Chris@0 477 char *home = getenv("HOME");
Chris@0 478 if (home) path = std::string(home) + "/.ladspa:" + path;
Chris@0 479 }
Chris@0 480
Chris@0 481 std::string::size_type index = 0, newindex = 0;
Chris@0 482
Chris@0 483 while ((newindex = path.find(':', index)) < path.size()) {
Chris@0 484 pathList.push_back(path.substr(index, newindex - index).c_str());
Chris@0 485 index = newindex + 1;
Chris@0 486 }
Chris@0 487
Chris@0 488 pathList.push_back(path.substr(index).c_str());
Chris@0 489
Chris@0 490 return pathList;
Chris@0 491 }
Chris@0 492
Chris@0 493
Chris@35 494 #ifdef HAVE_LRDF
Chris@0 495 std::vector<QString>
Chris@0 496 LADSPAPluginFactory::getLRDFPath(QString &baseUri)
Chris@0 497 {
Chris@0 498 std::vector<QString> pathList = getPluginPath();
Chris@0 499 std::vector<QString> lrdfPaths;
Chris@0 500
Chris@0 501 lrdfPaths.push_back("/usr/local/share/ladspa/rdf");
Chris@0 502 lrdfPaths.push_back("/usr/share/ladspa/rdf");
Chris@0 503
Chris@0 504 for (std::vector<QString>::iterator i = pathList.begin();
Chris@0 505 i != pathList.end(); ++i) {
Chris@0 506 lrdfPaths.push_back(*i + "/rdf");
Chris@0 507 }
Chris@0 508
Chris@0 509 baseUri = LADSPA_BASE;
Chris@0 510 return lrdfPaths;
Chris@0 511 }
Chris@0 512 #endif
Chris@0 513
Chris@0 514 void
Chris@0 515 LADSPAPluginFactory::discoverPlugins()
Chris@0 516 {
Chris@0 517 std::vector<QString> pathList = getPluginPath();
Chris@0 518
Chris@0 519 // std::cerr << "LADSPAPluginFactory::discoverPlugins - "
Chris@0 520 // << "discovering plugins; path is ";
Chris@0 521 for (std::vector<QString>::iterator i = pathList.begin();
Chris@0 522 i != pathList.end(); ++i) {
Chris@0 523 std::cerr << "[" << i->toStdString() << "] ";
Chris@0 524 }
Chris@0 525 std::cerr << std::endl;
Chris@0 526
Chris@35 527 #ifdef HAVE_LRDF
Chris@0 528 // Initialise liblrdf and read the description files
Chris@0 529 //
Chris@0 530 lrdf_init();
Chris@0 531
Chris@0 532 QString baseUri;
Chris@0 533 std::vector<QString> lrdfPaths = getLRDFPath(baseUri);
Chris@0 534
Chris@0 535 bool haveSomething = false;
Chris@0 536
Chris@0 537 for (size_t i = 0; i < lrdfPaths.size(); ++i) {
Chris@0 538 QDir dir(lrdfPaths[i], "*.rdf;*.rdfs");
Chris@0 539 for (unsigned int j = 0; j < dir.count(); ++j) {
Chris@0 540 if (!lrdf_read_file(QString("file:" + lrdfPaths[i] + "/" + dir[j]).toStdString().c_str())) {
Chris@0 541 // std::cerr << "LADSPAPluginFactory: read RDF file " << (lrdfPaths[i] + "/" + dir[j]) << std::endl;
Chris@0 542 haveSomething = true;
Chris@0 543 }
Chris@0 544 }
Chris@0 545 }
Chris@0 546
Chris@0 547 if (haveSomething) {
Chris@0 548 generateTaxonomy(baseUri + "Plugin", "");
Chris@0 549 }
Chris@35 550 #endif // HAVE_LRDF
Chris@0 551
Chris@0 552 generateFallbackCategories();
Chris@0 553
Chris@0 554 for (std::vector<QString>::iterator i = pathList.begin();
Chris@0 555 i != pathList.end(); ++i) {
Chris@0 556
Chris@0 557 QDir pluginDir(*i, PLUGIN_GLOB);
Chris@0 558
Chris@0 559 for (unsigned int j = 0; j < pluginDir.count(); ++j) {
Chris@0 560 discoverPlugins(QString("%1/%2").arg(*i).arg(pluginDir[j]));
Chris@0 561 }
Chris@0 562 }
Chris@0 563
Chris@35 564 #ifdef HAVE_LRDF
Chris@0 565 // Cleanup after the RDF library
Chris@0 566 //
Chris@0 567 lrdf_cleanup();
Chris@35 568 #endif // HAVE_LRDF
Chris@0 569 }
Chris@0 570
Chris@0 571 void
Chris@0 572 LADSPAPluginFactory::discoverPlugins(QString soname)
Chris@0 573 {
Chris@0 574 void *libraryHandle = DLOPEN(soname, RTLD_LAZY);
Chris@0 575
Chris@0 576 if (!libraryHandle) {
Chris@0 577 std::cerr << "WARNING: LADSPAPluginFactory::discoverPlugins: couldn't load plugin library "
Chris@0 578 << soname.toStdString() << " - " << DLERROR() << std::endl;
Chris@0 579 return;
Chris@0 580 }
Chris@0 581
Chris@0 582 LADSPA_Descriptor_Function fn = (LADSPA_Descriptor_Function)
Chris@0 583 DLSYM(libraryHandle, "ladspa_descriptor");
Chris@0 584
Chris@0 585 if (!fn) {
Chris@0 586 std::cerr << "WARNING: LADSPAPluginFactory::discoverPlugins: No descriptor function in " << soname.toStdString() << std::endl;
Chris@0 587 return;
Chris@0 588 }
Chris@0 589
Chris@0 590 const LADSPA_Descriptor *descriptor = 0;
Chris@0 591
Chris@0 592 int index = 0;
Chris@0 593 while ((descriptor = fn(index))) {
Chris@0 594
Chris@60 595 RealTimePluginDescriptor *rtd = new RealTimePluginDescriptor;
Chris@60 596 rtd->name = descriptor->Name;
Chris@60 597 rtd->label = descriptor->Label;
Chris@60 598 rtd->maker = descriptor->Maker;
Chris@60 599 rtd->copyright = descriptor->Copyright;
Chris@60 600 rtd->category = "";
Chris@60 601 rtd->isSynth = false;
Chris@60 602 rtd->parameterCount = 0;
Chris@60 603 rtd->audioInputPortCount = 0;
Chris@60 604 rtd->controlOutputPortCount = 0;
Chris@60 605
Chris@35 606 #ifdef HAVE_LRDF
Chris@0 607 char *def_uri = 0;
Chris@0 608 lrdf_defaults *defs = 0;
Chris@0 609
Chris@0 610 QString category = m_taxonomy[descriptor->UniqueID];
Chris@0 611
Chris@0 612 if (category == "" && descriptor->Name != 0) {
Chris@0 613 std::string name = descriptor->Name;
Chris@0 614 if (name.length() > 4 &&
Chris@0 615 name.substr(name.length() - 4) == " VST") {
Chris@0 616 category = "VST effects";
Chris@0 617 m_taxonomy[descriptor->UniqueID] = category;
Chris@0 618 }
Chris@0 619 }
Chris@0 620
Chris@60 621 rtd->category = category.toStdString();
Chris@60 622
Chris@0 623 // std::cerr << "Plugin id is " << descriptor->UniqueID
Chris@0 624 // << ", category is \"" << (category ? category : QString("(none)"))
Chris@0 625 // << "\", name is " << descriptor->Name
Chris@0 626 // << ", label is " << descriptor->Label
Chris@0 627 // << std::endl;
Chris@0 628
Chris@0 629 def_uri = lrdf_get_default_uri(descriptor->UniqueID);
Chris@0 630 if (def_uri) {
Chris@0 631 defs = lrdf_get_setting_values(def_uri);
Chris@0 632 }
Chris@0 633
Chris@0 634 int controlPortNumber = 1;
Chris@0 635
Chris@0 636 for (unsigned long i = 0; i < descriptor->PortCount; i++) {
Chris@0 637
Chris@0 638 if (LADSPA_IS_PORT_CONTROL(descriptor->PortDescriptors[i])) {
Chris@0 639
Chris@0 640 if (def_uri && defs) {
Chris@0 641
Chris@0 642 for (int j = 0; j < defs->count; j++) {
Chris@0 643 if (defs->items[j].pid == controlPortNumber) {
Chris@0 644 // std::cerr << "Default for this port (" << defs->items[j].pid << ", " << defs->items[j].label << ") is " << defs->items[j].value << "; applying this to port number " << i << " with name " << descriptor->PortNames[i] << std::endl;
Chris@0 645 m_portDefaults[descriptor->UniqueID][i] =
Chris@0 646 defs->items[j].value;
Chris@0 647 }
Chris@0 648 }
Chris@0 649 }
Chris@0 650
Chris@0 651 ++controlPortNumber;
Chris@0 652 }
Chris@0 653 }
Chris@35 654 #endif // HAVE_LRDF
Chris@0 655
Chris@60 656 for (unsigned long i = 0; i < descriptor->PortCount; i++) {
Chris@60 657 if (LADSPA_IS_PORT_CONTROL(descriptor->PortDescriptors[i])) {
Chris@60 658 if (LADSPA_IS_PORT_INPUT(descriptor->PortDescriptors[i])) {
Chris@60 659 ++rtd->parameterCount;
Chris@60 660 } else {
Chris@60 661 if (strcmp(descriptor->PortNames[i], "latency") &&
Chris@60 662 strcmp(descriptor->PortNames[i], "_latency")) {
Chris@60 663 ++rtd->controlOutputPortCount;
Chris@60 664 rtd->controlOutputPortNames.push_back
Chris@60 665 (descriptor->PortNames[i]);
Chris@60 666 }
Chris@60 667 }
Chris@60 668 } else {
Chris@60 669 if (LADSPA_IS_PORT_INPUT(descriptor->PortDescriptors[i])) {
Chris@60 670 ++rtd->audioInputPortCount;
Chris@60 671 }
Chris@60 672 }
Chris@60 673 }
Chris@60 674
Chris@0 675 QString identifier = PluginIdentifier::createIdentifier
Chris@0 676 ("ladspa", soname, descriptor->Label);
Chris@0 677 m_identifiers.push_back(identifier);
Chris@0 678
Chris@60 679 m_rtDescriptors[identifier] = rtd;
Chris@60 680
Chris@0 681 ++index;
Chris@0 682 }
Chris@0 683
Chris@0 684 if (DLCLOSE(libraryHandle) != 0) {
Chris@0 685 std::cerr << "WARNING: LADSPAPluginFactory::discoverPlugins - can't unload " << libraryHandle << std::endl;
Chris@0 686 return;
Chris@0 687 }
Chris@0 688 }
Chris@0 689
Chris@0 690 void
Chris@0 691 LADSPAPluginFactory::generateFallbackCategories()
Chris@0 692 {
Chris@0 693 std::vector<QString> pluginPath = getPluginPath();
Chris@0 694 std::vector<QString> path;
Chris@0 695
Chris@0 696 for (size_t i = 0; i < pluginPath.size(); ++i) {
Chris@0 697 if (pluginPath[i].contains("/lib/")) {
Chris@0 698 QString p(pluginPath[i]);
Chris@0 699 p.replace("/lib/", "/share/");
Chris@0 700 path.push_back(p);
Chris@0 701 // std::cerr << "LADSPAPluginFactory::generateFallbackCategories: path element " << p << std::endl;
Chris@0 702 }
Chris@0 703 path.push_back(pluginPath[i]);
Chris@0 704 // std::cerr << "LADSPAPluginFactory::generateFallbackCategories: path element " << pluginPath[i] << std::endl;
Chris@0 705 }
Chris@0 706
Chris@0 707 for (size_t i = 0; i < path.size(); ++i) {
Chris@0 708
Chris@0 709 QDir dir(path[i], "*.cat");
Chris@0 710
Chris@0 711 // std::cerr << "LADSPAPluginFactory::generateFallbackCategories: directory " << path[i] << " has " << dir.count() << " .cat files" << std::endl;
Chris@0 712 for (unsigned int j = 0; j < dir.count(); ++j) {
Chris@0 713
Chris@0 714 QFile file(path[i] + "/" + dir[j]);
Chris@0 715
Chris@0 716 // std::cerr << "LADSPAPluginFactory::generateFallbackCategories: about to open " << (path[i] + "/" + dir[j]) << std::endl;
Chris@0 717
Chris@0 718 if (file.open(QIODevice::ReadOnly)) {
Chris@0 719 // std::cerr << "...opened" << std::endl;
Chris@0 720 QTextStream stream(&file);
Chris@0 721 QString line;
Chris@0 722
Chris@0 723 while (!stream.atEnd()) {
Chris@0 724 line = stream.readLine();
Chris@0 725 // std::cerr << "line is: \"" << line << "\"" << std::endl;
Chris@0 726 QString id = line.section("::", 0, 0);
Chris@0 727 QString cat = line.section("::", 1, 1);
Chris@0 728 m_fallbackCategories[id] = cat;
Chris@0 729 // std::cerr << "set id \"" << id << "\" to cat \"" << cat << "\"" << std::endl;
Chris@0 730 }
Chris@0 731 }
Chris@0 732 }
Chris@0 733 }
Chris@0 734 }
Chris@0 735
Chris@0 736 void
Chris@0 737 LADSPAPluginFactory::generateTaxonomy(QString uri, QString base)
Chris@0 738 {
Chris@35 739 #ifdef HAVE_LRDF
Chris@0 740 lrdf_uris *uris = lrdf_get_instances(uri.toStdString().c_str());
Chris@0 741
Chris@0 742 if (uris != NULL) {
Chris@0 743 for (int i = 0; i < uris->count; ++i) {
Chris@0 744 m_taxonomy[lrdf_get_uid(uris->items[i])] = base;
Chris@0 745 }
Chris@0 746 lrdf_free_uris(uris);
Chris@0 747 }
Chris@0 748
Chris@0 749 uris = lrdf_get_subclasses(uri.toStdString().c_str());
Chris@0 750
Chris@0 751 if (uris != NULL) {
Chris@0 752 for (int i = 0; i < uris->count; ++i) {
Chris@0 753 char *label = lrdf_get_label(uris->items[i]);
Chris@0 754 generateTaxonomy(uris->items[i],
Chris@0 755 base + (base.length() > 0 ? " > " : "") + label);
Chris@0 756 }
Chris@0 757 lrdf_free_uris(uris);
Chris@0 758 }
Chris@0 759 #endif
Chris@0 760 }
Chris@0 761
Chris@0 762