annotate plugin/DSSIPluginFactory.cpp @ 1833:21c792334c2e sensible-delimited-data-strings

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