annotate plugin/DSSIPluginFactory.cpp @ 458:f60360209e5c

* Fix race condition in FFTFileCache when reading from the same FFT model from multiple threads (e.g. when applying more than one plugin at once)
author Chris Cannam
date Wed, 15 Oct 2008 12:08:02 +0000
parents 115f60df1e4d
children b4a8d8221eaf
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.
Chris@0 19 */
Chris@0 20
Chris@0 21 #include "DSSIPluginFactory.h"
Chris@0 22 #include <iostream>
Chris@0 23
Chris@0 24 #include <QString>
Chris@0 25
Chris@0 26 #include "DSSIPluginInstance.h"
Chris@0 27 #include "PluginIdentifier.h"
Chris@0 28
Chris@405 29 #include <cstdlib>
Chris@405 30
Chris@408 31 #include "base/Profiler.h"
Chris@408 32
Chris@0 33 //!!!
Chris@150 34 #include "plugin/plugins/SamplePlayer.h"
Chris@0 35
Chris@150 36 #include "system/System.h"
Chris@0 37
Chris@35 38 #ifdef HAVE_LRDF
Chris@0 39 #include "lrdf.h"
Chris@35 40 #endif // HAVE_LRDF
Chris@0 41
Chris@0 42
Chris@0 43 DSSIPluginFactory::DSSIPluginFactory() :
Chris@0 44 LADSPAPluginFactory()
Chris@0 45 {
Chris@0 46 m_hostDescriptor.DSSI_API_Version = 2;
Chris@0 47 m_hostDescriptor.request_transport_information = NULL;
Chris@0 48 m_hostDescriptor.request_midi_send = DSSIPluginInstance::requestMidiSend;
Chris@0 49 m_hostDescriptor.request_non_rt_thread = DSSIPluginInstance::requestNonRTThread;
Chris@0 50 m_hostDescriptor.midi_send = DSSIPluginInstance::midiSend;
Chris@0 51 }
Chris@0 52
Chris@0 53 DSSIPluginFactory::~DSSIPluginFactory()
Chris@0 54 {
Chris@0 55 // nothing else to do here either
Chris@0 56 }
Chris@0 57
Chris@0 58 void
Chris@0 59 DSSIPluginFactory::enumeratePlugins(std::vector<QString> &list)
Chris@0 60 {
Chris@408 61 Profiler profiler("DSSIPluginFactory::enumeratePlugins");
Chris@408 62
Chris@0 63 for (std::vector<QString>::iterator i = m_identifiers.begin();
Chris@0 64 i != m_identifiers.end(); ++i) {
Chris@0 65
Chris@0 66 const DSSI_Descriptor *ddesc = getDSSIDescriptor(*i);
Chris@0 67 if (!ddesc) continue;
Chris@0 68
Chris@0 69 const LADSPA_Descriptor *descriptor = ddesc->LADSPA_Plugin;
Chris@0 70 if (!descriptor) continue;
Chris@0 71
Chris@0 72 // std::cerr << "DSSIPluginFactory::enumeratePlugins: Name " << (descriptor->Name ? descriptor->Name : "NONE" ) << std::endl;
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((ddesc->run_synth || ddesc->run_multiple_synths) ? "true" : "false");
Chris@0 81 list.push_back(ddesc->run_multiple_synths ? "true" : "false");
Chris@165 82 list.push_back(m_taxonomy[*i]);
Chris@0 83 list.push_back(QString("%1").arg(descriptor->PortCount));
Chris@0 84
Chris@0 85 for (unsigned long p = 0; p < descriptor->PortCount; ++p) {
Chris@0 86
Chris@0 87 int type = 0;
Chris@0 88 if (LADSPA_IS_PORT_CONTROL(descriptor->PortDescriptors[p])) {
Chris@0 89 type |= PortType::Control;
Chris@0 90 } else {
Chris@0 91 type |= PortType::Audio;
Chris@0 92 }
Chris@0 93 if (LADSPA_IS_PORT_INPUT(descriptor->PortDescriptors[p])) {
Chris@0 94 type |= PortType::Input;
Chris@0 95 } else {
Chris@0 96 type |= PortType::Output;
Chris@0 97 }
Chris@0 98
Chris@0 99 list.push_back(QString("%1").arg(p));
Chris@0 100 list.push_back(descriptor->PortNames[p]);
Chris@0 101 list.push_back(QString("%1").arg(type));
Chris@0 102 list.push_back(QString("%1").arg(getPortDisplayHint(descriptor, p)));
Chris@0 103 list.push_back(QString("%1").arg(getPortMinimum(descriptor, p)));
Chris@0 104 list.push_back(QString("%1").arg(getPortMaximum(descriptor, p)));
Chris@0 105 list.push_back(QString("%1").arg(getPortDefault(descriptor, p)));
Chris@0 106 }
Chris@0 107 }
Chris@0 108
Chris@0 109 unloadUnusedLibraries();
Chris@0 110 }
Chris@0 111
Chris@0 112 RealTimePluginInstance *
Chris@0 113 DSSIPluginFactory::instantiatePlugin(QString identifier,
Chris@0 114 int instrument,
Chris@0 115 int position,
Chris@0 116 unsigned int sampleRate,
Chris@0 117 unsigned int blockSize,
Chris@0 118 unsigned int channels)
Chris@0 119 {
Chris@408 120 Profiler profiler("DSSIPluginFactory::instantiatePlugin");
Chris@408 121
Chris@0 122 const DSSI_Descriptor *descriptor = getDSSIDescriptor(identifier);
Chris@0 123
Chris@0 124 if (descriptor) {
Chris@0 125
Chris@0 126 DSSIPluginInstance *instance =
Chris@0 127 new DSSIPluginInstance
Chris@0 128 (this, instrument, identifier, position, sampleRate, blockSize, channels,
Chris@0 129 descriptor);
Chris@0 130
Chris@0 131 m_instances.insert(instance);
Chris@0 132
Chris@0 133 return instance;
Chris@0 134 }
Chris@0 135
Chris@0 136 return 0;
Chris@0 137 }
Chris@0 138
Chris@0 139 const DSSI_Descriptor *
Chris@0 140 DSSIPluginFactory::getDSSIDescriptor(QString identifier)
Chris@0 141 {
Chris@0 142 QString type, soname, label;
Chris@0 143 PluginIdentifier::parseIdentifier(identifier, type, soname, label);
Chris@0 144
Chris@0 145 if (soname == PluginIdentifier::BUILTIN_PLUGIN_SONAME) {
Chris@0 146 if (label == "sample_player") {
Chris@0 147 const DSSI_Descriptor *descriptor = SamplePlayer::getDescriptor(0);
Chris@0 148 if (descriptor) {
Chris@0 149 descriptor->receive_host_descriptor(&m_hostDescriptor);
Chris@0 150 }
Chris@0 151 return descriptor;
Chris@0 152 } else {
Chris@0 153 return 0;
Chris@0 154 }
Chris@0 155 }
Chris@0 156
Chris@0 157 bool firstInLibrary = false;
Chris@0 158
Chris@0 159 if (m_libraryHandles.find(soname) == m_libraryHandles.end()) {
Chris@0 160 loadLibrary(soname);
Chris@0 161 if (m_libraryHandles.find(soname) == m_libraryHandles.end()) {
Chris@0 162 std::cerr << "WARNING: DSSIPluginFactory::getDSSIDescriptor: loadLibrary failed for " << soname.toStdString() << std::endl;
Chris@0 163 return 0;
Chris@0 164 }
Chris@0 165 firstInLibrary = true;
Chris@0 166 }
Chris@0 167
Chris@0 168 void *libraryHandle = m_libraryHandles[soname];
Chris@0 169
Chris@0 170 DSSI_Descriptor_Function fn = (DSSI_Descriptor_Function)
Chris@0 171 DLSYM(libraryHandle, "dssi_descriptor");
Chris@0 172
Chris@0 173 if (!fn) {
Chris@0 174 std::cerr << "WARNING: DSSIPluginFactory::getDSSIDescriptor: No descriptor function in library " << soname.toStdString() << std::endl;
Chris@0 175 return 0;
Chris@0 176 }
Chris@0 177
Chris@0 178 const DSSI_Descriptor *descriptor = 0;
Chris@0 179
Chris@0 180 int index = 0;
Chris@0 181 while ((descriptor = fn(index))) {
Chris@0 182 if (descriptor->LADSPA_Plugin->Label == label) {
Chris@0 183 if (firstInLibrary && (descriptor->DSSI_API_Version >= 2)) {
Chris@0 184 descriptor->receive_host_descriptor(&m_hostDescriptor);
Chris@0 185 }
Chris@0 186 return descriptor;
Chris@0 187 }
Chris@0 188 ++index;
Chris@0 189 }
Chris@0 190
Chris@0 191 std::cerr << "WARNING: DSSIPluginFactory::getDSSIDescriptor: No such plugin as " << label.toStdString() << " in library " << soname.toStdString() << std::endl;
Chris@0 192
Chris@0 193 return 0;
Chris@0 194 }
Chris@0 195
Chris@0 196 const LADSPA_Descriptor *
Chris@0 197 DSSIPluginFactory::getLADSPADescriptor(QString identifier)
Chris@0 198 {
Chris@0 199 const DSSI_Descriptor *dssiDescriptor = getDSSIDescriptor(identifier);
Chris@0 200 if (dssiDescriptor) return dssiDescriptor->LADSPA_Plugin;
Chris@0 201 else return 0;
Chris@0 202 }
Chris@0 203
Chris@0 204
Chris@0 205 std::vector<QString>
Chris@0 206 DSSIPluginFactory::getPluginPath()
Chris@0 207 {
Chris@0 208 std::vector<QString> pathList;
Chris@0 209 std::string path;
Chris@0 210
Chris@0 211 char *cpath = getenv("DSSI_PATH");
Chris@0 212 if (cpath) path = cpath;
Chris@0 213
Chris@0 214 if (path == "") {
Chris@186 215
Chris@186 216 path = DEFAULT_DSSI_PATH;
Chris@186 217
Chris@0 218 char *home = getenv("HOME");
Chris@66 219 if (home) {
Chris@186 220 std::string::size_type f;
Chris@186 221 while ((f = path.find("$HOME")) != std::string::npos &&
Chris@186 222 f < path.length()) {
Chris@186 223 path.replace(f, 5, home);
Chris@186 224 }
Chris@66 225 }
Chris@186 226
Chris@186 227 #ifdef _WIN32
Chris@220 228 char *pfiles = getenv("ProgramFiles");
Chris@220 229 if (!pfiles) pfiles = "C:\\Program Files";
Chris@220 230 {
Chris@186 231 std::string::size_type f;
Chris@186 232 while ((f = path.find("%ProgramFiles%")) != std::string::npos &&
Chris@186 233 f < path.length()) {
Chris@186 234 path.replace(f, 14, pfiles);
Chris@186 235 }
Chris@220 236 }
Chris@186 237 #endif
Chris@0 238 }
Chris@0 239
Chris@0 240 std::string::size_type index = 0, newindex = 0;
Chris@0 241
Chris@223 242 while ((newindex = path.find(PATH_SEPARATOR, index)) < path.size()) {
Chris@0 243 pathList.push_back(path.substr(index, newindex - index).c_str());
Chris@0 244 index = newindex + 1;
Chris@0 245 }
Chris@0 246
Chris@0 247 pathList.push_back(path.substr(index).c_str());
Chris@0 248
Chris@0 249 return pathList;
Chris@0 250 }
Chris@0 251
Chris@0 252
Chris@0 253 std::vector<QString>
Chris@0 254 DSSIPluginFactory::getLRDFPath(QString &baseUri)
Chris@0 255 {
Chris@150 256 std::vector<QString> lrdfPaths;
Chris@150 257
Chris@150 258 #ifdef HAVE_LRDF
Chris@0 259 std::vector<QString> pathList = getPluginPath();
Chris@0 260
Chris@0 261 lrdfPaths.push_back("/usr/local/share/dssi/rdf");
Chris@0 262 lrdfPaths.push_back("/usr/share/dssi/rdf");
Chris@0 263
Chris@0 264 lrdfPaths.push_back("/usr/local/share/ladspa/rdf");
Chris@0 265 lrdfPaths.push_back("/usr/share/ladspa/rdf");
Chris@0 266
Chris@0 267 for (std::vector<QString>::iterator i = pathList.begin();
Chris@0 268 i != pathList.end(); ++i) {
Chris@0 269 lrdfPaths.push_back(*i + "/rdf");
Chris@0 270 }
Chris@0 271
Chris@0 272 #ifdef DSSI_BASE
Chris@0 273 baseUri = DSSI_BASE;
Chris@0 274 #else
Chris@0 275 baseUri = "http://dssi.sourceforge.net/ontology#";
Chris@0 276 #endif
Chris@150 277 #endif
Chris@0 278
Chris@0 279 return lrdfPaths;
Chris@0 280 }
Chris@0 281
Chris@0 282
Chris@0 283 void
Chris@0 284 DSSIPluginFactory::discoverPlugins(QString soname)
Chris@0 285 {
Chris@408 286 Profiler profiler("DSSIPluginFactory::discoverPlugins");
Chris@408 287
Chris@0 288 // Note that soname is expected to be a full path at this point,
Chris@0 289 // of a file that is known to exist
Chris@0 290
Chris@0 291 void *libraryHandle = DLOPEN(soname, RTLD_LAZY);
Chris@0 292
Chris@0 293 if (!libraryHandle) {
Chris@0 294 std::cerr << "WARNING: DSSIPluginFactory::discoverPlugins: couldn't load plugin library "
Chris@0 295 << soname.toStdString() << " - " << DLERROR() << std::endl;
Chris@0 296 return;
Chris@0 297 }
Chris@0 298
Chris@0 299 DSSI_Descriptor_Function fn = (DSSI_Descriptor_Function)
Chris@0 300 DLSYM(libraryHandle, "dssi_descriptor");
Chris@0 301
Chris@0 302 if (!fn) {
Chris@0 303 std::cerr << "WARNING: DSSIPluginFactory::discoverPlugins: No descriptor function in " << soname.toStdString() << std::endl;
Chris@0 304 return;
Chris@0 305 }
Chris@0 306
Chris@0 307 const DSSI_Descriptor *descriptor = 0;
Chris@0 308
Chris@0 309 int index = 0;
Chris@0 310 while ((descriptor = fn(index))) {
Chris@0 311
Chris@0 312 const LADSPA_Descriptor *ladspaDescriptor = descriptor->LADSPA_Plugin;
Chris@0 313 if (!ladspaDescriptor) {
Chris@0 314 std::cerr << "WARNING: DSSIPluginFactory::discoverPlugins: No LADSPA descriptor for plugin " << index << " in " << soname.toStdString() << std::endl;
Chris@0 315 ++index;
Chris@0 316 continue;
Chris@0 317 }
Chris@0 318
Chris@60 319 RealTimePluginDescriptor *rtd = new RealTimePluginDescriptor;
Chris@60 320 rtd->name = ladspaDescriptor->Name;
Chris@60 321 rtd->label = ladspaDescriptor->Label;
Chris@60 322 rtd->maker = ladspaDescriptor->Maker;
Chris@60 323 rtd->copyright = ladspaDescriptor->Copyright;
Chris@60 324 rtd->category = "";
Chris@60 325 rtd->isSynth = (descriptor->run_synth ||
Chris@60 326 descriptor->run_multiple_synths);
Chris@60 327 rtd->parameterCount = 0;
Chris@60 328 rtd->audioInputPortCount = 0;
Chris@166 329 rtd->audioOutputPortCount = 0;
Chris@60 330 rtd->controlOutputPortCount = 0;
Chris@60 331
Chris@165 332 QString identifier = PluginIdentifier::createIdentifier
Chris@165 333 ("dssi", soname, ladspaDescriptor->Label);
Chris@165 334
Chris@35 335 #ifdef HAVE_LRDF
Chris@0 336 char *def_uri = 0;
Chris@0 337 lrdf_defaults *defs = 0;
Chris@0 338
Chris@165 339 QString category = m_taxonomy[identifier];
Chris@165 340
Chris@166 341 if (category == "" && m_lrdfTaxonomy[ladspaDescriptor->UniqueID] != "") {
Chris@166 342 m_taxonomy[identifier] = m_lrdfTaxonomy[ladspaDescriptor->UniqueID];
Chris@165 343 category = m_taxonomy[identifier];
Chris@165 344 }
Chris@0 345
Chris@0 346 if (category == "" && ladspaDescriptor->Name != 0) {
Chris@0 347 std::string name = ladspaDescriptor->Name;
Chris@0 348 if (name.length() > 4 &&
Chris@0 349 name.substr(name.length() - 4) == " VST") {
Chris@0 350 if (descriptor->run_synth || descriptor->run_multiple_synths) {
Chris@0 351 category = "VST instruments";
Chris@0 352 } else {
Chris@0 353 category = "VST effects";
Chris@0 354 }
Chris@165 355 m_taxonomy[identifier] = category;
Chris@0 356 }
Chris@0 357 }
Chris@60 358
Chris@60 359 rtd->category = category.toStdString();
Chris@0 360
Chris@167 361 // std::cerr << "Plugin id is " << ladspaDescriptor->UniqueID
Chris@167 362 // << ", identifier is \"" << identifier.toStdString()
Chris@167 363 // << "\", category is \"" << category.toStdString()
Chris@167 364 // << "\", name is " << ladspaDescriptor->Name
Chris@167 365 // << ", label is " << ladspaDescriptor->Label
Chris@167 366 // << std::endl;
Chris@0 367
Chris@0 368 def_uri = lrdf_get_default_uri(ladspaDescriptor->UniqueID);
Chris@0 369 if (def_uri) {
Chris@0 370 defs = lrdf_get_setting_values(def_uri);
Chris@0 371 }
Chris@0 372
Chris@259 373 unsigned int controlPortNumber = 1;
Chris@0 374
Chris@0 375 for (unsigned long i = 0; i < ladspaDescriptor->PortCount; i++) {
Chris@0 376
Chris@0 377 if (LADSPA_IS_PORT_CONTROL(ladspaDescriptor->PortDescriptors[i])) {
Chris@0 378
Chris@0 379 if (def_uri && defs) {
Chris@0 380
Chris@259 381 for (unsigned int j = 0; j < defs->count; j++) {
Chris@0 382 if (defs->items[j].pid == controlPortNumber) {
Chris@0 383 // 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 " << ladspaDescriptor->PortNames[i] << std::endl;
Chris@0 384 m_portDefaults[ladspaDescriptor->UniqueID][i] =
Chris@0 385 defs->items[j].value;
Chris@0 386 }
Chris@0 387 }
Chris@0 388 }
Chris@0 389
Chris@0 390 ++controlPortNumber;
Chris@0 391 }
Chris@0 392 }
Chris@35 393 #endif // HAVE_LRDF
Chris@0 394
Chris@60 395 for (unsigned long i = 0; i < ladspaDescriptor->PortCount; i++) {
Chris@60 396 if (LADSPA_IS_PORT_CONTROL(ladspaDescriptor->PortDescriptors[i])) {
Chris@60 397 if (LADSPA_IS_PORT_INPUT(ladspaDescriptor->PortDescriptors[i])) {
Chris@60 398 ++rtd->parameterCount;
Chris@60 399 } else {
Chris@60 400 if (strcmp(ladspaDescriptor->PortNames[i], "latency") &&
Chris@60 401 strcmp(ladspaDescriptor->PortNames[i], "_latency")) {
Chris@60 402 ++rtd->controlOutputPortCount;
Chris@60 403 rtd->controlOutputPortNames.push_back
Chris@60 404 (ladspaDescriptor->PortNames[i]);
Chris@60 405 }
Chris@60 406 }
Chris@60 407 } else {
Chris@60 408 if (LADSPA_IS_PORT_INPUT(ladspaDescriptor->PortDescriptors[i])) {
Chris@60 409 ++rtd->audioInputPortCount;
Chris@166 410 } else if (LADSPA_IS_PORT_OUTPUT(ladspaDescriptor->PortDescriptors[i])) {
Chris@166 411 ++rtd->audioOutputPortCount;
Chris@60 412 }
Chris@60 413 }
Chris@60 414 }
Chris@60 415
Chris@0 416 m_identifiers.push_back(identifier);
Chris@0 417
Chris@60 418 m_rtDescriptors[identifier] = rtd;
Chris@60 419
Chris@0 420 ++index;
Chris@0 421 }
Chris@0 422
Chris@0 423 if (DLCLOSE(libraryHandle) != 0) {
Chris@0 424 std::cerr << "WARNING: DSSIPluginFactory::discoverPlugins - can't unload " << libraryHandle << std::endl;
Chris@0 425 return;
Chris@0 426 }
Chris@0 427 }
Chris@0 428
Chris@0 429
Chris@0 430