annotate plugin/DSSIPluginFactory.cpp @ 360:ac300d385ab2

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