annotate plugin/LADSPAPluginFactory.cpp @ 360:ac300d385ab2

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