annotate plugin/LADSPAPluginFactory.cpp @ 1196:c7b9c902642f spectrogram-minor-refactor

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