annotate plugin/LADSPAPluginFactory.cpp @ 184:5a916fee6d2d

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