annotate plugin/LADSPAPluginFactory.cpp @ 117:c30728d5625c sv1-v0.9rc1

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