annotate plugin/LADSPAPluginFactory.cpp @ 1008:d9e0e59a1581

When using an aggregate model to pass data to a transform, zero-pad the shorter input to the duration of the longer rather than truncating the longer. (This is better behaviour for e.g. MATCH, and in any case the code was previously truncating incorrectly and ending up with garbage data at the end.)
author Chris Cannam
date Fri, 14 Nov 2014 13:51:33 +0000
parents 7aa9088e9bcd
children b14064bd1f97
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@150 33 #include "system/System.h"
Chris@145 34 #include "base/Preferences.h"
Chris@408 35 #include "base/Profiler.h"
Chris@0 36
Chris@260 37 //#define DEBUG_LADSPA_PLUGIN_FACTORY 1
Chris@260 38
Chris@35 39 #ifdef HAVE_LRDF
Chris@0 40 #include "lrdf.h"
Chris@35 41 #endif // HAVE_LRDF
Chris@0 42
Chris@0 43
Chris@0 44 LADSPAPluginFactory::LADSPAPluginFactory()
Chris@0 45 {
Chris@166 46 #ifdef HAVE_LRDF
Chris@166 47 lrdf_init();
Chris@166 48 #endif
Chris@0 49 }
Chris@0 50
Chris@0 51 LADSPAPluginFactory::~LADSPAPluginFactory()
Chris@0 52 {
Chris@0 53 for (std::set<RealTimePluginInstance *>::iterator i = m_instances.begin();
Chris@0 54 i != m_instances.end(); ++i) {
Chris@0 55 (*i)->setFactory(0);
Chris@0 56 delete *i;
Chris@0 57 }
Chris@0 58 m_instances.clear();
Chris@0 59 unloadUnusedLibraries();
Chris@166 60
Chris@166 61 #ifdef HAVE_LRDF
Chris@166 62 lrdf_cleanup();
Chris@166 63 #endif // HAVE_LRDF
Chris@0 64 }
Chris@0 65
Chris@0 66 const std::vector<QString> &
Chris@0 67 LADSPAPluginFactory::getPluginIdentifiers() const
Chris@0 68 {
Chris@0 69 return m_identifiers;
Chris@0 70 }
Chris@0 71
Chris@0 72 void
Chris@0 73 LADSPAPluginFactory::enumeratePlugins(std::vector<QString> &list)
Chris@0 74 {
Chris@408 75 Profiler profiler("LADSPAPluginFactory::enumeratePlugins");
Chris@408 76
Chris@0 77 for (std::vector<QString>::iterator i = m_identifiers.begin();
Chris@0 78 i != m_identifiers.end(); ++i) {
Chris@0 79
Chris@0 80 const LADSPA_Descriptor *descriptor = getLADSPADescriptor(*i);
Chris@0 81
Chris@0 82 if (!descriptor) {
Chris@844 83 cerr << "WARNING: LADSPAPluginFactory::enumeratePlugins: couldn't get descriptor for identifier " << *i << endl;
Chris@0 84 continue;
Chris@0 85 }
Chris@0 86
Chris@0 87 list.push_back(*i);
Chris@0 88 list.push_back(descriptor->Name);
Chris@0 89 list.push_back(QString("%1").arg(descriptor->UniqueID));
Chris@0 90 list.push_back(descriptor->Label);
Chris@0 91 list.push_back(descriptor->Maker);
Chris@0 92 list.push_back(descriptor->Copyright);
Chris@0 93 list.push_back("false"); // is synth
Chris@0 94 list.push_back("false"); // is grouped
Chris@165 95
Chris@165 96 if (m_taxonomy.find(*i) != m_taxonomy.end() && m_taxonomy[*i] != "") {
Chris@844 97 // cerr << "LADSPAPluginFactory: cat for " << *i << " found in taxonomy as " << m_taxonomy[descriptor->UniqueID] << endl;
Chris@165 98 list.push_back(m_taxonomy[*i]);
Chris@0 99 } else {
Chris@0 100 list.push_back("");
Chris@844 101 // cerr << "LADSPAPluginFactory: cat for " << *i << " not found (despite having " << m_fallbackCategories.size() << " fallbacks)" << endl;
Chris@0 102
Chris@0 103 }
Chris@0 104
Chris@0 105 list.push_back(QString("%1").arg(descriptor->PortCount));
Chris@0 106
Chris@0 107 for (unsigned long p = 0; p < descriptor->PortCount; ++p) {
Chris@0 108
Chris@0 109 int type = 0;
Chris@0 110 if (LADSPA_IS_PORT_CONTROL(descriptor->PortDescriptors[p])) {
Chris@0 111 type |= PortType::Control;
Chris@0 112 } else {
Chris@0 113 type |= PortType::Audio;
Chris@0 114 }
Chris@0 115 if (LADSPA_IS_PORT_INPUT(descriptor->PortDescriptors[p])) {
Chris@0 116 type |= PortType::Input;
Chris@0 117 } else {
Chris@0 118 type |= PortType::Output;
Chris@0 119 }
Chris@0 120
Chris@0 121 list.push_back(QString("%1").arg(p));
Chris@0 122 list.push_back(descriptor->PortNames[p]);
Chris@0 123 list.push_back(QString("%1").arg(type));
Chris@0 124 list.push_back(QString("%1").arg(getPortDisplayHint(descriptor, p)));
Chris@0 125 list.push_back(QString("%1").arg(getPortMinimum(descriptor, p)));
Chris@0 126 list.push_back(QString("%1").arg(getPortMaximum(descriptor, p)));
Chris@0 127 list.push_back(QString("%1").arg(getPortDefault(descriptor, p)));
Chris@0 128 }
Chris@0 129 }
Chris@0 130
Chris@0 131 unloadUnusedLibraries();
Chris@0 132 }
Chris@0 133
Chris@60 134 const RealTimePluginDescriptor *
Chris@60 135 LADSPAPluginFactory::getPluginDescriptor(QString identifier) const
Chris@60 136 {
Chris@60 137 std::map<QString, RealTimePluginDescriptor *>::const_iterator i =
Chris@60 138 m_rtDescriptors.find(identifier);
Chris@60 139
Chris@60 140 if (i != m_rtDescriptors.end()) {
Chris@60 141 return i->second;
Chris@60 142 }
Chris@60 143
Chris@60 144 return 0;
Chris@60 145 }
Chris@60 146
Chris@0 147 float
Chris@0 148 LADSPAPluginFactory::getPortMinimum(const LADSPA_Descriptor *descriptor, int port)
Chris@0 149 {
Chris@0 150 LADSPA_PortRangeHintDescriptor d =
Chris@0 151 descriptor->PortRangeHints[port].HintDescriptor;
Chris@0 152
Chris@0 153 float minimum = 0.0;
Chris@0 154
Chris@0 155 if (LADSPA_IS_HINT_BOUNDED_BELOW(d)) {
Chris@0 156 float lb = descriptor->PortRangeHints[port].LowerBound;
Chris@0 157 minimum = lb;
Chris@0 158 } else if (LADSPA_IS_HINT_BOUNDED_ABOVE(d)) {
Chris@0 159 float ub = descriptor->PortRangeHints[port].UpperBound;
Chris@0 160 minimum = std::min(0.0, ub - 1.0);
Chris@0 161 }
Chris@0 162
Chris@0 163 if (LADSPA_IS_HINT_SAMPLE_RATE(d)) {
Chris@0 164 minimum *= m_sampleRate;
Chris@0 165 }
Chris@0 166
Chris@356 167 if (LADSPA_IS_HINT_LOGARITHMIC(d)) {
Chris@356 168 if (minimum == 0.f) minimum = 1.f;
Chris@356 169 }
Chris@356 170
Chris@0 171 return minimum;
Chris@0 172 }
Chris@0 173
Chris@0 174 float
Chris@0 175 LADSPAPluginFactory::getPortMaximum(const LADSPA_Descriptor *descriptor, int port)
Chris@0 176 {
Chris@0 177 LADSPA_PortRangeHintDescriptor d =
Chris@0 178 descriptor->PortRangeHints[port].HintDescriptor;
Chris@0 179
Chris@0 180 float maximum = 1.0;
Chris@0 181
Chris@0 182 if (LADSPA_IS_HINT_BOUNDED_ABOVE(d)) {
Chris@0 183 float ub = descriptor->PortRangeHints[port].UpperBound;
Chris@0 184 maximum = ub;
Chris@0 185 } else {
Chris@0 186 float lb = descriptor->PortRangeHints[port].LowerBound;
Chris@0 187 maximum = lb + 1.0;
Chris@0 188 }
Chris@0 189
Chris@0 190 if (LADSPA_IS_HINT_SAMPLE_RATE(d)) {
Chris@0 191 maximum *= m_sampleRate;
Chris@0 192 }
Chris@0 193
Chris@0 194 return maximum;
Chris@0 195 }
Chris@0 196
Chris@0 197 float
Chris@0 198 LADSPAPluginFactory::getPortDefault(const LADSPA_Descriptor *descriptor, int port)
Chris@0 199 {
Chris@0 200 float minimum = getPortMinimum(descriptor, port);
Chris@0 201 float maximum = getPortMaximum(descriptor, port);
Chris@0 202 float deft;
Chris@0 203
Chris@0 204 if (m_portDefaults.find(descriptor->UniqueID) !=
Chris@0 205 m_portDefaults.end()) {
Chris@0 206 if (m_portDefaults[descriptor->UniqueID].find(port) !=
Chris@0 207 m_portDefaults[descriptor->UniqueID].end()) {
Chris@0 208
Chris@0 209 deft = m_portDefaults[descriptor->UniqueID][port];
Chris@0 210 if (deft < minimum) deft = minimum;
Chris@0 211 if (deft > maximum) deft = maximum;
Chris@0 212 return deft;
Chris@0 213 }
Chris@0 214 }
Chris@0 215
Chris@0 216 LADSPA_PortRangeHintDescriptor d =
Chris@0 217 descriptor->PortRangeHints[port].HintDescriptor;
Chris@0 218
Chris@0 219 bool logarithmic = LADSPA_IS_HINT_LOGARITHMIC(d);
Chris@0 220
Chris@356 221 float logmin = 0, logmax = 0;
Chris@356 222 if (logarithmic) {
Chris@356 223 float thresh = powf(10, -10);
Chris@356 224 if (minimum < thresh) logmin = -10;
Chris@356 225 else logmin = log10f(minimum);
Chris@356 226 if (maximum < thresh) logmax = -10;
Chris@356 227 else logmax = log10f(maximum);
Chris@356 228 }
Chris@356 229
Chris@690 230 // SVDEBUG << "LADSPAPluginFactory::getPortDefault: hint = " << d << endl;
Chris@356 231
Chris@0 232 if (!LADSPA_IS_HINT_HAS_DEFAULT(d)) {
Chris@0 233
Chris@0 234 deft = minimum;
Chris@0 235
Chris@0 236 } else if (LADSPA_IS_HINT_DEFAULT_MINIMUM(d)) {
Chris@0 237
Chris@0 238 deft = minimum;
Chris@0 239
Chris@0 240 } else if (LADSPA_IS_HINT_DEFAULT_LOW(d)) {
Chris@0 241
Chris@0 242 if (logarithmic) {
Chris@356 243 deft = powf(10, logmin * 0.75 + logmax * 0.25);
Chris@0 244 } else {
Chris@0 245 deft = minimum * 0.75 + maximum * 0.25;
Chris@0 246 }
Chris@0 247
Chris@0 248 } else if (LADSPA_IS_HINT_DEFAULT_MIDDLE(d)) {
Chris@0 249
Chris@0 250 if (logarithmic) {
Chris@356 251 deft = powf(10, logmin * 0.5 + logmax * 0.5);
Chris@0 252 } else {
Chris@0 253 deft = minimum * 0.5 + maximum * 0.5;
Chris@0 254 }
Chris@0 255
Chris@0 256 } else if (LADSPA_IS_HINT_DEFAULT_HIGH(d)) {
Chris@0 257
Chris@0 258 if (logarithmic) {
Chris@356 259 deft = powf(10, logmin * 0.25 + logmax * 0.75);
Chris@0 260 } else {
Chris@0 261 deft = minimum * 0.25 + maximum * 0.75;
Chris@0 262 }
Chris@0 263
Chris@0 264 } else if (LADSPA_IS_HINT_DEFAULT_MAXIMUM(d)) {
Chris@0 265
Chris@0 266 deft = maximum;
Chris@0 267
Chris@0 268 } else if (LADSPA_IS_HINT_DEFAULT_0(d)) {
Chris@0 269
Chris@0 270 deft = 0.0;
Chris@0 271
Chris@0 272 } else if (LADSPA_IS_HINT_DEFAULT_1(d)) {
Chris@0 273
Chris@0 274 deft = 1.0;
Chris@0 275
Chris@0 276 } else if (LADSPA_IS_HINT_DEFAULT_100(d)) {
Chris@0 277
Chris@0 278 deft = 100.0;
Chris@0 279
Chris@0 280 } else if (LADSPA_IS_HINT_DEFAULT_440(d)) {
Chris@0 281
Chris@145 282 // deft = 440.0;
Chris@145 283 deft = Preferences::getInstance()->getTuningFrequency();
Chris@0 284
Chris@0 285 } else {
Chris@0 286
Chris@0 287 deft = minimum;
Chris@0 288 }
Chris@356 289
Chris@356 290 //!!! No -- the min and max have already been multiplied by the rate,
Chris@356 291 //so it would happen twice if we did it here -- and e.g. DEFAULT_440
Chris@356 292 //doesn't want to be multiplied by the rate either
Chris@0 293
Chris@356 294 // if (LADSPA_IS_HINT_SAMPLE_RATE(d)) {
Chris@356 295 // deft *= m_sampleRate;
Chris@356 296 // }
Chris@0 297
Chris@0 298 return deft;
Chris@0 299 }
Chris@0 300
Chris@57 301 float
Chris@57 302 LADSPAPluginFactory::getPortQuantization(const LADSPA_Descriptor *descriptor, int port)
Chris@57 303 {
Chris@57 304 int displayHint = getPortDisplayHint(descriptor, port);
Chris@57 305 if (displayHint & PortHint::Toggled) {
Chris@57 306 return lrintf(getPortMaximum(descriptor, port)) -
Chris@57 307 lrintf(getPortMinimum(descriptor, port));
Chris@57 308 }
Chris@57 309 if (displayHint & PortHint::Integer) {
Chris@57 310 return 1.0;
Chris@57 311 }
Chris@57 312 return 0.0;
Chris@57 313 }
Chris@57 314
Chris@0 315 int
Chris@0 316 LADSPAPluginFactory::getPortDisplayHint(const LADSPA_Descriptor *descriptor, int port)
Chris@0 317 {
Chris@0 318 LADSPA_PortRangeHintDescriptor d =
Chris@0 319 descriptor->PortRangeHints[port].HintDescriptor;
Chris@0 320 int hint = PortHint::NoHint;
Chris@0 321
Chris@0 322 if (LADSPA_IS_HINT_TOGGLED(d)) hint |= PortHint::Toggled;
Chris@0 323 if (LADSPA_IS_HINT_INTEGER(d)) hint |= PortHint::Integer;
Chris@0 324 if (LADSPA_IS_HINT_LOGARITHMIC(d)) hint |= PortHint::Logarithmic;
Chris@0 325
Chris@0 326 return hint;
Chris@0 327 }
Chris@0 328
Chris@0 329
Chris@0 330 RealTimePluginInstance *
Chris@0 331 LADSPAPluginFactory::instantiatePlugin(QString identifier,
Chris@0 332 int instrument,
Chris@0 333 int position,
Chris@0 334 unsigned int sampleRate,
Chris@0 335 unsigned int blockSize,
Chris@0 336 unsigned int channels)
Chris@0 337 {
Chris@408 338 Profiler profiler("LADSPAPluginFactory::instantiatePlugin");
Chris@408 339
Chris@0 340 const LADSPA_Descriptor *descriptor = getLADSPADescriptor(identifier);
Chris@0 341
Chris@0 342 if (descriptor) {
Chris@0 343
Chris@0 344 LADSPAPluginInstance *instance =
Chris@0 345 new LADSPAPluginInstance
Chris@0 346 (this, instrument, identifier, position, sampleRate, blockSize, channels,
Chris@0 347 descriptor);
Chris@0 348
Chris@0 349 m_instances.insert(instance);
Chris@0 350
Chris@260 351 #ifdef DEBUG_LADSPA_PLUGIN_FACTORY
Chris@690 352 SVDEBUG << "LADSPAPluginFactory::instantiatePlugin("
Chris@687 353 << identifier << ": now have " << m_instances.size() << " instances" << endl;
Chris@260 354 #endif
Chris@78 355
Chris@0 356 return instance;
Chris@0 357 }
Chris@0 358
Chris@0 359 return 0;
Chris@0 360 }
Chris@0 361
Chris@0 362 void
Chris@0 363 LADSPAPluginFactory::releasePlugin(RealTimePluginInstance *instance,
Chris@0 364 QString identifier)
Chris@0 365 {
Chris@408 366 Profiler profiler("LADSPAPluginFactory::releasePlugin");
Chris@408 367
Chris@0 368 if (m_instances.find(instance) == m_instances.end()) {
Chris@843 369 cerr << "WARNING: LADSPAPluginFactory::releasePlugin: Not one of mine!"
Chris@843 370 << endl;
Chris@0 371 return;
Chris@0 372 }
Chris@0 373
Chris@0 374 QString type, soname, label;
Chris@0 375 PluginIdentifier::parseIdentifier(identifier, type, soname, label);
Chris@0 376
Chris@0 377 m_instances.erase(instance);
Chris@0 378
Chris@0 379 bool stillInUse = false;
Chris@0 380
Chris@0 381 for (std::set<RealTimePluginInstance *>::iterator ii = m_instances.begin();
Chris@0 382 ii != m_instances.end(); ++ii) {
Chris@0 383 QString itype, isoname, ilabel;
Chris@237 384 PluginIdentifier::parseIdentifier((*ii)->getPluginIdentifier(), itype, isoname, ilabel);
Chris@0 385 if (isoname == soname) {
Chris@260 386 #ifdef DEBUG_LADSPA_PLUGIN_FACTORY
Chris@690 387 SVDEBUG << "LADSPAPluginFactory::releasePlugin: dll " << soname << " is still in use for plugin " << ilabel << endl;
Chris@260 388 #endif
Chris@0 389 stillInUse = true;
Chris@0 390 break;
Chris@0 391 }
Chris@0 392 }
Chris@0 393
Chris@0 394 if (!stillInUse) {
Chris@118 395 if (soname != PluginIdentifier::BUILTIN_PLUGIN_SONAME) {
Chris@260 396 #ifdef DEBUG_LADSPA_PLUGIN_FACTORY
Chris@690 397 SVDEBUG << "LADSPAPluginFactory::releasePlugin: dll " << soname << " no longer in use, unloading" << endl;
Chris@260 398 #endif
Chris@118 399 unloadLibrary(soname);
Chris@118 400 }
Chris@0 401 }
Chris@78 402
Chris@260 403 #ifdef DEBUG_LADSPA_PLUGIN_FACTORY
Chris@690 404 SVDEBUG << "LADSPAPluginFactory::releasePlugin("
Chris@687 405 << identifier << ": now have " << m_instances.size() << " instances" << endl;
Chris@260 406 #endif
Chris@0 407 }
Chris@0 408
Chris@0 409 const LADSPA_Descriptor *
Chris@0 410 LADSPAPluginFactory::getLADSPADescriptor(QString identifier)
Chris@0 411 {
Chris@0 412 QString type, soname, label;
Chris@0 413 PluginIdentifier::parseIdentifier(identifier, type, soname, label);
Chris@0 414
Chris@0 415 if (m_libraryHandles.find(soname) == m_libraryHandles.end()) {
Chris@0 416 loadLibrary(soname);
Chris@0 417 if (m_libraryHandles.find(soname) == m_libraryHandles.end()) {
Chris@843 418 cerr << "WARNING: LADSPAPluginFactory::getLADSPADescriptor: loadLibrary failed for " << soname << endl;
Chris@0 419 return 0;
Chris@0 420 }
Chris@0 421 }
Chris@0 422
Chris@0 423 void *libraryHandle = m_libraryHandles[soname];
Chris@0 424
Chris@0 425 LADSPA_Descriptor_Function fn = (LADSPA_Descriptor_Function)
Chris@0 426 DLSYM(libraryHandle, "ladspa_descriptor");
Chris@0 427
Chris@0 428 if (!fn) {
Chris@843 429 cerr << "WARNING: LADSPAPluginFactory::getLADSPADescriptor: No descriptor function in library " << soname << endl;
Chris@0 430 return 0;
Chris@0 431 }
Chris@0 432
Chris@0 433 const LADSPA_Descriptor *descriptor = 0;
Chris@0 434
Chris@0 435 int index = 0;
Chris@0 436 while ((descriptor = fn(index))) {
Chris@0 437 if (descriptor->Label == label) return descriptor;
Chris@0 438 ++index;
Chris@0 439 }
Chris@0 440
Chris@843 441 cerr << "WARNING: LADSPAPluginFactory::getLADSPADescriptor: No such plugin as " << label << " in library " << soname << endl;
Chris@0 442
Chris@0 443 return 0;
Chris@0 444 }
Chris@0 445
Chris@0 446 void
Chris@0 447 LADSPAPluginFactory::loadLibrary(QString soName)
Chris@0 448 {
Chris@0 449 void *libraryHandle = DLOPEN(soName, RTLD_NOW);
Chris@106 450 if (libraryHandle) {
Chris@106 451 m_libraryHandles[soName] = libraryHandle;
Chris@690 452 SVDEBUG << "LADSPAPluginFactory::loadLibrary: Loaded library \"" << soName << "\"" << endl;
Chris@106 453 return;
Chris@106 454 }
Chris@106 455
Chris@106 456 if (QFileInfo(soName).exists()) {
Chris@106 457 DLERROR();
Chris@843 458 cerr << "LADSPAPluginFactory::loadLibrary: Library \"" << soName << "\" exists, but failed to load it" << endl;
Chris@106 459 return;
Chris@106 460 }
Chris@106 461
Chris@106 462 std::vector<QString> pathList = getPluginPath();
Chris@106 463
Chris@106 464 QString fileName = QFile(soName).fileName();
Chris@106 465 QString base = QFileInfo(soName).baseName();
Chris@106 466
Chris@106 467 for (std::vector<QString>::iterator i = pathList.begin();
Chris@106 468 i != pathList.end(); ++i) {
Chris@106 469
Chris@260 470 #ifdef DEBUG_LADSPA_PLUGIN_FACTORY
Chris@690 471 SVDEBUG << "Looking at: " << (*i) << endl;
Chris@260 472 #endif
Chris@106 473
Chris@106 474 QDir dir(*i, PLUGIN_GLOB,
Chris@106 475 QDir::Name | QDir::IgnoreCase,
Chris@106 476 QDir::Files | QDir::Readable);
Chris@106 477
Chris@106 478 if (QFileInfo(dir.filePath(fileName)).exists()) {
Chris@260 479 #ifdef DEBUG_LADSPA_PLUGIN_FACTORY
Chris@843 480 cerr << "Loading: " << fileName << endl;
Chris@260 481 #endif
Chris@106 482 libraryHandle = DLOPEN(dir.filePath(fileName), RTLD_NOW);
Chris@166 483 if (libraryHandle) {
Chris@166 484 m_libraryHandles[soName] = libraryHandle;
Chris@166 485 return;
Chris@166 486 }
Chris@106 487 }
Chris@106 488
Chris@106 489 for (unsigned int j = 0; j < dir.count(); ++j) {
Chris@106 490 QString file = dir.filePath(dir[j]);
Chris@106 491 if (QFileInfo(file).baseName() == base) {
Chris@260 492 #ifdef DEBUG_LADSPA_PLUGIN_FACTORY
Chris@843 493 cerr << "Loading: " << file << endl;
Chris@260 494 #endif
Chris@106 495 libraryHandle = DLOPEN(file, RTLD_NOW);
Chris@166 496 if (libraryHandle) {
Chris@166 497 m_libraryHandles[soName] = libraryHandle;
Chris@166 498 return;
Chris@166 499 }
Chris@106 500 }
Chris@106 501 }
Chris@106 502 }
Chris@106 503
Chris@843 504 cerr << "LADSPAPluginFactory::loadLibrary: Failed to locate plugin library \"" << soName << "\"" << endl;
Chris@0 505 }
Chris@0 506
Chris@0 507 void
Chris@0 508 LADSPAPluginFactory::unloadLibrary(QString soName)
Chris@0 509 {
Chris@0 510 LibraryHandleMap::iterator li = m_libraryHandles.find(soName);
Chris@0 511 if (li != m_libraryHandles.end()) {
Chris@690 512 // SVDEBUG << "unloading " << soname << endl;
Chris@0 513 DLCLOSE(m_libraryHandles[soName]);
Chris@0 514 m_libraryHandles.erase(li);
Chris@0 515 }
Chris@0 516 }
Chris@0 517
Chris@0 518 void
Chris@0 519 LADSPAPluginFactory::unloadUnusedLibraries()
Chris@0 520 {
Chris@0 521 std::vector<QString> toUnload;
Chris@0 522
Chris@0 523 for (LibraryHandleMap::iterator i = m_libraryHandles.begin();
Chris@0 524 i != m_libraryHandles.end(); ++i) {
Chris@0 525
Chris@0 526 bool stillInUse = false;
Chris@0 527
Chris@0 528 for (std::set<RealTimePluginInstance *>::iterator ii = m_instances.begin();
Chris@0 529 ii != m_instances.end(); ++ii) {
Chris@0 530
Chris@0 531 QString itype, isoname, ilabel;
Chris@237 532 PluginIdentifier::parseIdentifier((*ii)->getPluginIdentifier(), itype, isoname, ilabel);
Chris@0 533 if (isoname == i->first) {
Chris@0 534 stillInUse = true;
Chris@0 535 break;
Chris@0 536 }
Chris@0 537 }
Chris@0 538
Chris@0 539 if (!stillInUse) toUnload.push_back(i->first);
Chris@0 540 }
Chris@0 541
Chris@0 542 for (std::vector<QString>::iterator i = toUnload.begin();
Chris@0 543 i != toUnload.end(); ++i) {
Chris@118 544 if (*i != PluginIdentifier::BUILTIN_PLUGIN_SONAME) {
Chris@118 545 unloadLibrary(*i);
Chris@118 546 }
Chris@0 547 }
Chris@0 548 }
Chris@0 549
Chris@0 550
Chris@0 551 // It is only later, after they've gone,
Chris@0 552 // I realize they have delivered a letter.
Chris@0 553 // It's a letter from my wife. "What are you doing
Chris@0 554 // there?" my wife asks. "Are you drinking?"
Chris@0 555 // I study the postmark for hours. Then it, too, begins to fade.
Chris@0 556 // I hope someday to forget all this.
Chris@0 557
Chris@0 558
Chris@0 559 std::vector<QString>
Chris@0 560 LADSPAPluginFactory::getPluginPath()
Chris@0 561 {
Chris@0 562 std::vector<QString> pathList;
Chris@0 563 std::string path;
Chris@0 564
Chris@0 565 char *cpath = getenv("LADSPA_PATH");
Chris@0 566 if (cpath) path = cpath;
Chris@0 567
Chris@0 568 if (path == "") {
Chris@186 569
Chris@186 570 path = DEFAULT_LADSPA_PATH;
Chris@186 571
Chris@0 572 char *home = getenv("HOME");
Chris@186 573 if (home) {
Chris@186 574 std::string::size_type f;
Chris@186 575 while ((f = path.find("$HOME")) != std::string::npos &&
Chris@186 576 f < path.length()) {
Chris@186 577 path.replace(f, 5, home);
Chris@186 578 }
Chris@186 579 }
Chris@186 580
Chris@186 581 #ifdef _WIN32
Chris@220 582 char *pfiles = getenv("ProgramFiles");
Chris@220 583 if (!pfiles) pfiles = "C:\\Program Files";
Chris@220 584 {
Chris@186 585 std::string::size_type f;
Chris@186 586 while ((f = path.find("%ProgramFiles%")) != std::string::npos &&
Chris@186 587 f < path.length()) {
Chris@186 588 path.replace(f, 14, pfiles);
Chris@186 589 }
Chris@220 590 }
Chris@186 591 #endif
Chris@0 592 }
Chris@0 593
Chris@0 594 std::string::size_type index = 0, newindex = 0;
Chris@0 595
Chris@223 596 while ((newindex = path.find(PATH_SEPARATOR, index)) < path.size()) {
Chris@0 597 pathList.push_back(path.substr(index, newindex - index).c_str());
Chris@0 598 index = newindex + 1;
Chris@0 599 }
Chris@0 600
Chris@0 601 pathList.push_back(path.substr(index).c_str());
Chris@0 602
Chris@0 603 return pathList;
Chris@0 604 }
Chris@0 605
Chris@0 606
Chris@0 607 std::vector<QString>
Chris@0 608 LADSPAPluginFactory::getLRDFPath(QString &baseUri)
Chris@0 609 {
Chris@150 610 std::vector<QString> lrdfPaths;
Chris@150 611
Chris@150 612 #ifdef HAVE_LRDF
Chris@0 613 std::vector<QString> pathList = getPluginPath();
Chris@0 614
Chris@0 615 lrdfPaths.push_back("/usr/local/share/ladspa/rdf");
Chris@0 616 lrdfPaths.push_back("/usr/share/ladspa/rdf");
Chris@0 617
Chris@0 618 for (std::vector<QString>::iterator i = pathList.begin();
Chris@0 619 i != pathList.end(); ++i) {
Chris@0 620 lrdfPaths.push_back(*i + "/rdf");
Chris@0 621 }
Chris@0 622
Chris@0 623 baseUri = LADSPA_BASE;
Chris@953 624 #else
Chris@953 625 baseUri = "";
Chris@150 626 #endif
Chris@150 627
Chris@0 628 return lrdfPaths;
Chris@0 629 }
Chris@0 630
Chris@0 631 void
Chris@0 632 LADSPAPluginFactory::discoverPlugins()
Chris@0 633 {
Chris@408 634 Profiler profiler("LADSPAPluginFactory::discoverPlugins");
Chris@408 635
Chris@0 636 std::vector<QString> pathList = getPluginPath();
Chris@0 637
Chris@690 638 // SVDEBUG << "LADSPAPluginFactory::discoverPlugins - "
Chris@0 639 // << "discovering plugins; path is ";
Chris@259 640 // for (std::vector<QString>::iterator i = pathList.begin();
Chris@259 641 // i != pathList.end(); ++i) {
Chris@690 642 // SVDEBUG << "[" << i-<< "] ";
Chris@259 643 // }
Chris@690 644 // SVDEBUG << endl;
Chris@0 645
Chris@35 646 #ifdef HAVE_LRDF
Chris@166 647 // read the description files
Chris@0 648 //
Chris@0 649 QString baseUri;
Chris@0 650 std::vector<QString> lrdfPaths = getLRDFPath(baseUri);
Chris@0 651
Chris@0 652 bool haveSomething = false;
Chris@0 653
Chris@0 654 for (size_t i = 0; i < lrdfPaths.size(); ++i) {
Chris@0 655 QDir dir(lrdfPaths[i], "*.rdf;*.rdfs");
Chris@0 656 for (unsigned int j = 0; j < dir.count(); ++j) {
Chris@0 657 if (!lrdf_read_file(QString("file:" + lrdfPaths[i] + "/" + dir[j]).toStdString().c_str())) {
Chris@843 658 // cerr << "LADSPAPluginFactory: read RDF file " << (lrdfPaths[i] + "/" + dir[j]) << endl;
Chris@0 659 haveSomething = true;
Chris@0 660 }
Chris@0 661 }
Chris@0 662 }
Chris@0 663
Chris@0 664 if (haveSomething) {
Chris@0 665 generateTaxonomy(baseUri + "Plugin", "");
Chris@0 666 }
Chris@35 667 #endif // HAVE_LRDF
Chris@0 668
Chris@0 669 generateFallbackCategories();
Chris@0 670
Chris@0 671 for (std::vector<QString>::iterator i = pathList.begin();
Chris@0 672 i != pathList.end(); ++i) {
Chris@0 673
Chris@0 674 QDir pluginDir(*i, PLUGIN_GLOB);
Chris@0 675
Chris@0 676 for (unsigned int j = 0; j < pluginDir.count(); ++j) {
Chris@929 677 discoverPluginsFrom(QString("%1/%2").arg(*i).arg(pluginDir[j]));
Chris@0 678 }
Chris@0 679 }
Chris@0 680 }
Chris@0 681
Chris@0 682 void
Chris@929 683 LADSPAPluginFactory::discoverPluginsFrom(QString soname)
Chris@0 684 {
Chris@0 685 void *libraryHandle = DLOPEN(soname, RTLD_LAZY);
Chris@0 686
Chris@0 687 if (!libraryHandle) {
Chris@843 688 cerr << "WARNING: LADSPAPluginFactory::discoverPlugins: couldn't load plugin library "
Chris@843 689 << soname << " - " << DLERROR() << endl;
Chris@0 690 return;
Chris@0 691 }
Chris@0 692
Chris@0 693 LADSPA_Descriptor_Function fn = (LADSPA_Descriptor_Function)
Chris@0 694 DLSYM(libraryHandle, "ladspa_descriptor");
Chris@0 695
Chris@0 696 if (!fn) {
Chris@843 697 cerr << "WARNING: LADSPAPluginFactory::discoverPlugins: No descriptor function in " << soname << endl;
Chris@0 698 return;
Chris@0 699 }
Chris@0 700
Chris@0 701 const LADSPA_Descriptor *descriptor = 0;
Chris@0 702
Chris@0 703 int index = 0;
Chris@0 704 while ((descriptor = fn(index))) {
Chris@0 705
Chris@60 706 RealTimePluginDescriptor *rtd = new RealTimePluginDescriptor;
Chris@60 707 rtd->name = descriptor->Name;
Chris@60 708 rtd->label = descriptor->Label;
Chris@60 709 rtd->maker = descriptor->Maker;
Chris@60 710 rtd->copyright = descriptor->Copyright;
Chris@60 711 rtd->category = "";
Chris@60 712 rtd->isSynth = false;
Chris@60 713 rtd->parameterCount = 0;
Chris@60 714 rtd->audioInputPortCount = 0;
Chris@166 715 rtd->audioOutputPortCount = 0;
Chris@60 716 rtd->controlOutputPortCount = 0;
Chris@60 717
Chris@165 718 QString identifier = PluginIdentifier::createIdentifier
Chris@165 719 ("ladspa", soname, descriptor->Label);
Chris@165 720
Chris@35 721 #ifdef HAVE_LRDF
Chris@0 722 char *def_uri = 0;
Chris@0 723 lrdf_defaults *defs = 0;
Chris@0 724
Chris@165 725 if (m_lrdfTaxonomy[descriptor->UniqueID] != "") {
Chris@165 726 m_taxonomy[identifier] = m_lrdfTaxonomy[descriptor->UniqueID];
Chris@843 727 // cerr << "set id \"" << identifier << "\" to cat \"" << m_taxonomy[identifier] << "\" from LRDF" << endl;
Chris@843 728 // cout << identifier << "::" << m_taxonomy[identifier] << endl;
Chris@165 729 }
Chris@165 730
Chris@165 731 QString category = m_taxonomy[identifier];
Chris@0 732
Chris@973 733 if (category == "") {
Chris@973 734 std::string name = rtd->name;
Chris@0 735 if (name.length() > 4 &&
Chris@0 736 name.substr(name.length() - 4) == " VST") {
Chris@0 737 category = "VST effects";
Chris@165 738 m_taxonomy[identifier] = category;
Chris@0 739 }
Chris@0 740 }
Chris@0 741
Chris@60 742 rtd->category = category.toStdString();
Chris@60 743
Chris@843 744 // cerr << "Plugin id is " << descriptor->UniqueID
Chris@0 745 // << ", category is \"" << (category ? category : QString("(none)"))
Chris@0 746 // << "\", name is " << descriptor->Name
Chris@0 747 // << ", label is " << descriptor->Label
Chris@843 748 // << endl;
Chris@0 749
Chris@0 750 def_uri = lrdf_get_default_uri(descriptor->UniqueID);
Chris@0 751 if (def_uri) {
Chris@0 752 defs = lrdf_get_setting_values(def_uri);
Chris@0 753 }
Chris@0 754
Chris@259 755 unsigned int controlPortNumber = 1;
Chris@0 756
Chris@0 757 for (unsigned long i = 0; i < descriptor->PortCount; i++) {
Chris@0 758
Chris@0 759 if (LADSPA_IS_PORT_CONTROL(descriptor->PortDescriptors[i])) {
Chris@0 760
Chris@0 761 if (def_uri && defs) {
Chris@0 762
Chris@259 763 for (unsigned int j = 0; j < defs->count; j++) {
Chris@0 764 if (defs->items[j].pid == controlPortNumber) {
Chris@843 765 // 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] << endl;
Chris@0 766 m_portDefaults[descriptor->UniqueID][i] =
Chris@0 767 defs->items[j].value;
Chris@0 768 }
Chris@0 769 }
Chris@0 770 }
Chris@0 771
Chris@0 772 ++controlPortNumber;
Chris@0 773 }
Chris@0 774 }
Chris@35 775 #endif // HAVE_LRDF
Chris@0 776
Chris@60 777 for (unsigned long i = 0; i < descriptor->PortCount; i++) {
Chris@60 778 if (LADSPA_IS_PORT_CONTROL(descriptor->PortDescriptors[i])) {
Chris@60 779 if (LADSPA_IS_PORT_INPUT(descriptor->PortDescriptors[i])) {
Chris@60 780 ++rtd->parameterCount;
Chris@60 781 } else {
Chris@60 782 if (strcmp(descriptor->PortNames[i], "latency") &&
Chris@60 783 strcmp(descriptor->PortNames[i], "_latency")) {
Chris@60 784 ++rtd->controlOutputPortCount;
Chris@60 785 rtd->controlOutputPortNames.push_back
Chris@60 786 (descriptor->PortNames[i]);
Chris@60 787 }
Chris@60 788 }
Chris@60 789 } else {
Chris@60 790 if (LADSPA_IS_PORT_INPUT(descriptor->PortDescriptors[i])) {
Chris@60 791 ++rtd->audioInputPortCount;
Chris@166 792 } else if (LADSPA_IS_PORT_OUTPUT(descriptor->PortDescriptors[i])) {
Chris@166 793 ++rtd->audioOutputPortCount;
Chris@60 794 }
Chris@60 795 }
Chris@60 796 }
Chris@60 797
Chris@0 798 m_identifiers.push_back(identifier);
Chris@0 799
Chris@60 800 m_rtDescriptors[identifier] = rtd;
Chris@60 801
Chris@0 802 ++index;
Chris@0 803 }
Chris@0 804
Chris@0 805 if (DLCLOSE(libraryHandle) != 0) {
Chris@843 806 cerr << "WARNING: LADSPAPluginFactory::discoverPlugins - can't unload " << libraryHandle << endl;
Chris@0 807 return;
Chris@0 808 }
Chris@0 809 }
Chris@0 810
Chris@0 811 void
Chris@0 812 LADSPAPluginFactory::generateFallbackCategories()
Chris@0 813 {
Chris@0 814 std::vector<QString> pluginPath = getPluginPath();
Chris@0 815 std::vector<QString> path;
Chris@0 816
Chris@0 817 for (size_t i = 0; i < pluginPath.size(); ++i) {
Chris@0 818 if (pluginPath[i].contains("/lib/")) {
Chris@0 819 QString p(pluginPath[i]);
Chris@165 820 path.push_back(p);
Chris@0 821 p.replace("/lib/", "/share/");
Chris@0 822 path.push_back(p);
Chris@690 823 // SVDEBUG << "LADSPAPluginFactory::generateFallbackCategories: path element " << p << endl;
Chris@0 824 }
Chris@0 825 path.push_back(pluginPath[i]);
Chris@690 826 // SVDEBUG << "LADSPAPluginFactory::generateFallbackCategories: path element " << pluginPath[i] << endl;
Chris@0 827 }
Chris@0 828
Chris@0 829 for (size_t i = 0; i < path.size(); ++i) {
Chris@0 830
Chris@0 831 QDir dir(path[i], "*.cat");
Chris@0 832
Chris@690 833 // SVDEBUG << "LADSPAPluginFactory::generateFallbackCategories: directory " << path[i] << " has " << dir.count() << " .cat files" << endl;
Chris@0 834 for (unsigned int j = 0; j < dir.count(); ++j) {
Chris@0 835
Chris@0 836 QFile file(path[i] + "/" + dir[j]);
Chris@0 837
Chris@690 838 // SVDEBUG << "LADSPAPluginFactory::generateFallbackCategories: about to open " << (path[i]+ "/" + dir[j]) << endl;
Chris@0 839
Chris@0 840 if (file.open(QIODevice::ReadOnly)) {
Chris@843 841 // cerr << "...opened" << endl;
Chris@0 842 QTextStream stream(&file);
Chris@0 843 QString line;
Chris@0 844
Chris@0 845 while (!stream.atEnd()) {
Chris@0 846 line = stream.readLine();
Chris@843 847 // cerr << "line is: \"" << line << "\"" << endl;
Chris@165 848 QString id = PluginIdentifier::canonicalise
Chris@165 849 (line.section("::", 0, 0));
Chris@0 850 QString cat = line.section("::", 1, 1);
Chris@165 851 m_taxonomy[id] = cat;
Chris@843 852 // cerr << "set id \"" << id << "\" to cat \"" << cat << "\"" << endl;
Chris@0 853 }
Chris@0 854 }
Chris@0 855 }
Chris@0 856 }
Chris@0 857 }
Chris@0 858
Chris@0 859 void
Chris@0 860 LADSPAPluginFactory::generateTaxonomy(QString uri, QString base)
Chris@0 861 {
Chris@35 862 #ifdef HAVE_LRDF
Chris@0 863 lrdf_uris *uris = lrdf_get_instances(uri.toStdString().c_str());
Chris@0 864
Chris@0 865 if (uris != NULL) {
Chris@259 866 for (unsigned int i = 0; i < uris->count; ++i) {
Chris@165 867 m_lrdfTaxonomy[lrdf_get_uid(uris->items[i])] = base;
Chris@0 868 }
Chris@0 869 lrdf_free_uris(uris);
Chris@0 870 }
Chris@0 871
Chris@0 872 uris = lrdf_get_subclasses(uri.toStdString().c_str());
Chris@0 873
Chris@0 874 if (uris != NULL) {
Chris@259 875 for (unsigned int i = 0; i < uris->count; ++i) {
Chris@0 876 char *label = lrdf_get_label(uris->items[i]);
Chris@0 877 generateTaxonomy(uris->items[i],
Chris@0 878 base + (base.length() > 0 ? " > " : "") + label);
Chris@0 879 }
Chris@0 880 lrdf_free_uris(uris);
Chris@0 881 }
Chris@953 882 #else
Chris@953 883 // avoid unused parameter
Chris@953 884 (void)uri;
Chris@953 885 (void)base;
Chris@0 886 #endif
Chris@0 887 }
Chris@0 888
Chris@165 889 QString
Chris@165 890 LADSPAPluginFactory::getPluginCategory(QString identifier)
Chris@165 891 {
Chris@165 892 return m_taxonomy[identifier];
Chris@165 893 }
Chris@0 894