annotate plugin/LADSPAPluginFactory.cpp @ 319:3ff8f571da09

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