annotate transform/TransformFactory.cpp @ 1879:652c5360e682

Ensure transforms are populated before instantiateDefaultPluginFor runs - otherwise if we have prior knowledge of a transform id, we can find ourselves trying to instantiate it before the plugin factory has heard of it and e.g. knows which server to use
author Chris Cannam
date Thu, 25 Jun 2020 12:20:06 +0100
parents 7b6e18380e8f
children
rev   line source
Chris@330 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@330 2
Chris@330 3 /*
Chris@330 4 Sonic Visualiser
Chris@330 5 An audio file viewer and annotation editor.
Chris@330 6 Centre for Digital Music, Queen Mary, University of London.
Chris@330 7 This file copyright 2006 Chris Cannam and QMUL.
Chris@330 8
Chris@330 9 This program is free software; you can redistribute it and/or
Chris@330 10 modify it under the terms of the GNU General Public License as
Chris@330 11 published by the Free Software Foundation; either version 2 of the
Chris@330 12 License, or (at your option) any later version. See the file
Chris@330 13 COPYING included with this distribution for more information.
Chris@330 14 */
Chris@330 15
Chris@330 16 #include "TransformFactory.h"
Chris@330 17
Chris@330 18 #include "plugin/FeatureExtractionPluginFactory.h"
Chris@1225 19
Chris@330 20 #include "plugin/RealTimePluginFactory.h"
Chris@332 21 #include "plugin/RealTimePluginInstance.h"
Chris@330 22 #include "plugin/PluginXml.h"
Chris@330 23
Chris@475 24 #include <vamp-hostsdk/Plugin.h>
Chris@475 25 #include <vamp-hostsdk/PluginHostAdapter.h>
Chris@475 26 #include <vamp-hostsdk/PluginWrapper.h>
Chris@330 27
Chris@457 28 #include "rdf/PluginRDFIndexer.h"
Chris@457 29 #include "rdf/PluginRDFDescription.h"
Chris@457 30
Chris@446 31 #include "base/XmlExportable.h"
Chris@446 32
Chris@330 33 #include <iostream>
Chris@330 34 #include <set>
Chris@1546 35 #include <functional>
Chris@330 36
Chris@330 37 #include <QRegExp>
Chris@350 38 #include <QTextStream>
Chris@330 39
Chris@460 40 #include "base/Thread.h"
Chris@460 41
Chris@810 42 //#define DEBUG_TRANSFORM_FACTORY 1
Chris@810 43
Chris@330 44 TransformFactory *
Chris@330 45 TransformFactory::m_instance = new TransformFactory;
Chris@330 46
Chris@330 47 TransformFactory *
Chris@330 48 TransformFactory::getInstance()
Chris@330 49 {
Chris@330 50 return m_instance;
Chris@330 51 }
Chris@330 52
Chris@574 53 void
Chris@574 54 TransformFactory::deleteInstance()
Chris@574 55 {
Chris@690 56 SVDEBUG << "TransformFactory::deleteInstance called" << endl;
Chris@574 57 delete m_instance;
Chris@1582 58 m_instance = nullptr;
Chris@574 59 }
Chris@574 60
Chris@457 61 TransformFactory::TransformFactory() :
Chris@457 62 m_transformsPopulated(false),
Chris@477 63 m_uninstalledTransformsPopulated(false),
Chris@1582 64 m_thread(nullptr),
Chris@976 65 m_exiting(false),
Chris@976 66 m_populatingSlowly(false)
Chris@457 67 {
Chris@457 68 }
Chris@457 69
Chris@330 70 TransformFactory::~TransformFactory()
Chris@330 71 {
Chris@574 72 m_exiting = true;
Chris@574 73 if (m_thread) {
Chris@600 74 #ifdef DEBUG_TRANSFORM_FACTORY
Chris@690 75 SVDEBUG << "TransformFactory::~TransformFactory: waiting on thread" << endl;
Chris@600 76 #endif
Chris@574 77 m_thread->wait();
Chris@574 78 delete m_thread;
Chris@600 79 #ifdef DEBUG_TRANSFORM_FACTORY
Chris@690 80 SVDEBUG << "TransformFactory::~TransformFactory: waited and done" << endl;
Chris@600 81 #endif
Chris@574 82 }
Chris@330 83 }
Chris@330 84
Chris@477 85 void
Chris@477 86 TransformFactory::startPopulationThread()
Chris@477 87 {
Chris@482 88 m_uninstalledTransformsMutex.lock();
Chris@477 89
Chris@482 90 if (m_thread) {
Chris@482 91 m_uninstalledTransformsMutex.unlock();
Chris@482 92 return;
Chris@482 93 }
Chris@482 94 m_thread = new UninstalledTransformsPopulateThread(this);
Chris@477 95
Chris@482 96 m_uninstalledTransformsMutex.unlock();
Chris@482 97
Chris@477 98 m_thread->start();
Chris@477 99 }
Chris@477 100
Chris@481 101 void
Chris@481 102 TransformFactory::UninstalledTransformsPopulateThread::run()
Chris@481 103 {
Chris@481 104 m_factory->m_populatingSlowly = true;
Chris@1865 105 while (!m_factory->havePopulated()) {
Chris@1865 106 sleep(1);
Chris@1865 107 }
Chris@481 108 m_factory->populateUninstalledTransforms();
Chris@481 109 }
Chris@481 110
Chris@330 111 TransformList
Chris@350 112 TransformFactory::getAllTransformDescriptions()
Chris@330 113 {
Chris@460 114 populateTransforms();
Chris@330 115
Chris@330 116 std::set<TransformDescription> dset;
Chris@1546 117 for (auto i = m_transforms.begin(); i != m_transforms.end(); ++i) {
Chris@600 118 #ifdef DEBUG_TRANSFORM_FACTORY
Chris@1546 119 cerr << "inserting transform into set: id = " << i->second.identifier << " (" << i->second.name << ")" << endl;
Chris@600 120 #endif
Chris@1429 121 dset.insert(i->second);
Chris@330 122 }
Chris@330 123
Chris@330 124 TransformList list;
Chris@1546 125 for (auto i = dset.begin(); i != dset.end(); ++i) {
Chris@600 126 #ifdef DEBUG_TRANSFORM_FACTORY
Chris@1546 127 cerr << "inserting transform into list: id = " << i->identifier << " (" << i->name << ")" << endl;
Chris@600 128 #endif
Chris@1429 129 list.push_back(*i);
Chris@330 130 }
Chris@330 131
Chris@330 132 return list;
Chris@330 133 }
Chris@330 134
Chris@350 135 TransformDescription
Chris@350 136 TransformFactory::getTransformDescription(TransformId id)
Chris@350 137 {
Chris@460 138 populateTransforms();
Chris@350 139
Chris@350 140 if (m_transforms.find(id) == m_transforms.end()) {
Chris@350 141 return TransformDescription();
Chris@350 142 }
Chris@350 143
Chris@350 144 return m_transforms[id];
Chris@350 145 }
Chris@350 146
Chris@485 147 bool
Chris@485 148 TransformFactory::haveInstalledTransforms()
Chris@485 149 {
Chris@485 150 populateTransforms();
Chris@485 151 return !m_transforms.empty();
Chris@485 152 }
Chris@485 153
Chris@457 154 TransformList
Chris@457 155 TransformFactory::getUninstalledTransformDescriptions()
Chris@457 156 {
Chris@479 157 m_populatingSlowly = false;
Chris@460 158 populateUninstalledTransforms();
Chris@457 159
Chris@457 160 std::set<TransformDescription> dset;
Chris@1546 161 for (auto i = m_uninstalledTransforms.begin();
Chris@1429 162 i != m_uninstalledTransforms.end(); ++i) {
Chris@600 163 #ifdef DEBUG_TRANSFORM_FACTORY
Chris@810 164 cerr << "inserting transform into set: id = " << i->second.identifier << endl;
Chris@600 165 #endif
Chris@1429 166 dset.insert(i->second);
Chris@457 167 }
Chris@457 168
Chris@457 169 TransformList list;
Chris@1546 170 for (auto i = dset.begin(); i != dset.end(); ++i) {
Chris@600 171 #ifdef DEBUG_TRANSFORM_FACTORY
Chris@810 172 cerr << "inserting transform into uninstalled list: id = " << i->identifier << endl;
Chris@600 173 #endif
Chris@1429 174 list.push_back(*i);
Chris@457 175 }
Chris@457 176
Chris@457 177 return list;
Chris@457 178 }
Chris@457 179
Chris@457 180 TransformDescription
Chris@457 181 TransformFactory::getUninstalledTransformDescription(TransformId id)
Chris@457 182 {
Chris@479 183 m_populatingSlowly = false;
Chris@460 184 populateUninstalledTransforms();
Chris@457 185
Chris@457 186 if (m_uninstalledTransforms.find(id) == m_uninstalledTransforms.end()) {
Chris@457 187 return TransformDescription();
Chris@457 188 }
Chris@457 189
Chris@457 190 return m_uninstalledTransforms[id];
Chris@457 191 }
Chris@457 192
Chris@485 193 bool
Chris@485 194 TransformFactory::haveUninstalledTransforms(bool waitForCheckToComplete)
Chris@485 195 {
Chris@485 196 if (waitForCheckToComplete) {
Chris@485 197 populateUninstalledTransforms();
Chris@485 198 } else {
Chris@485 199 if (!m_uninstalledTransformsMutex.tryLock()) {
Chris@485 200 return false;
Chris@485 201 }
Chris@485 202 if (!m_uninstalledTransformsPopulated) {
Chris@485 203 m_uninstalledTransformsMutex.unlock();
Chris@485 204 return false;
Chris@485 205 }
Chris@485 206 m_uninstalledTransformsMutex.unlock();
Chris@485 207 }
Chris@485 208
Chris@485 209 return !m_uninstalledTransforms.empty();
Chris@485 210 }
Chris@485 211
Chris@457 212 TransformFactory::TransformInstallStatus
Chris@457 213 TransformFactory::getTransformInstallStatus(TransformId id)
Chris@457 214 {
Chris@460 215 populateTransforms();
Chris@457 216
Chris@457 217 if (m_transforms.find(id) != m_transforms.end()) {
Chris@457 218 return TransformInstalled;
Chris@457 219 }
Chris@473 220
Chris@473 221 if (!m_uninstalledTransformsMutex.tryLock()) {
Chris@473 222 // uninstalled transforms are being populated; this may take some time,
Chris@473 223 // and they aren't critical
Chris@473 224 return TransformUnknown;
Chris@473 225 }
Chris@473 226
Chris@473 227 if (!m_uninstalledTransformsPopulated) {
Chris@473 228 m_uninstalledTransformsMutex.unlock();
Chris@479 229 m_populatingSlowly = false;
Chris@473 230 populateUninstalledTransforms();
Chris@473 231 m_uninstalledTransformsMutex.lock();
Chris@473 232 }
Chris@473 233
Chris@457 234 if (m_uninstalledTransforms.find(id) != m_uninstalledTransforms.end()) {
Chris@482 235 m_uninstalledTransformsMutex.unlock();
Chris@457 236 return TransformNotInstalled;
Chris@457 237 }
Chris@473 238
Chris@473 239 m_uninstalledTransformsMutex.unlock();
Chris@457 240 return TransformUnknown;
Chris@457 241 }
Chris@457 242
Chris@457 243
Chris@487 244 std::vector<TransformDescription::Type>
Chris@330 245 TransformFactory::getAllTransformTypes()
Chris@330 246 {
Chris@460 247 populateTransforms();
Chris@330 248
Chris@487 249 std::set<TransformDescription::Type> types;
Chris@1546 250 for (auto i = m_transforms.begin(); i != m_transforms.end(); ++i) {
Chris@330 251 types.insert(i->second.type);
Chris@330 252 }
Chris@330 253
Chris@487 254 std::vector<TransformDescription::Type> rv;
Chris@1546 255 for (auto i = types.begin(); i != types.end(); ++i) {
Chris@330 256 rv.push_back(*i);
Chris@330 257 }
Chris@330 258
Chris@330 259 return rv;
Chris@330 260 }
Chris@330 261
Chris@330 262 std::vector<QString>
Chris@487 263 TransformFactory::getTransformCategories(TransformDescription::Type transformType)
Chris@330 264 {
Chris@460 265 populateTransforms();
Chris@330 266
Chris@1546 267 std::set<QString, std::function<bool(QString, QString)>>
Chris@1546 268 categories(TransformDescription::compareUserStrings);
Chris@1546 269
Chris@1546 270 for (auto i = m_transforms.begin(); i != m_transforms.end(); ++i) {
Chris@330 271 if (i->second.type == transformType) {
Chris@330 272 categories.insert(i->second.category);
Chris@330 273 }
Chris@330 274 }
Chris@330 275
Chris@330 276 bool haveEmpty = false;
Chris@330 277
Chris@330 278 std::vector<QString> rv;
Chris@1546 279 for (auto i = categories.begin(); i != categories.end(); ++i) {
Chris@330 280 if (*i != "") rv.push_back(*i);
Chris@330 281 else haveEmpty = true;
Chris@330 282 }
Chris@330 283
Chris@330 284 if (haveEmpty) rv.push_back(""); // make sure empty category sorts last
Chris@330 285
Chris@330 286 return rv;
Chris@330 287 }
Chris@330 288
Chris@330 289 std::vector<QString>
Chris@487 290 TransformFactory::getTransformMakers(TransformDescription::Type transformType)
Chris@330 291 {
Chris@460 292 populateTransforms();
Chris@330 293
Chris@1546 294 std::set<QString, std::function<bool(QString, QString)>>
Chris@1546 295 makers(TransformDescription::compareUserStrings);
Chris@1546 296
Chris@1546 297 for (auto i = m_transforms.begin(); i != m_transforms.end(); ++i) {
Chris@330 298 if (i->second.type == transformType) {
Chris@330 299 makers.insert(i->second.maker);
Chris@330 300 }
Chris@330 301 }
Chris@330 302
Chris@330 303 bool haveEmpty = false;
Chris@330 304
Chris@330 305 std::vector<QString> rv;
Chris@1546 306 for (auto i = makers.begin(); i != makers.end(); ++i) {
Chris@330 307 if (*i != "") rv.push_back(*i);
Chris@330 308 else haveEmpty = true;
Chris@330 309 }
Chris@330 310
Chris@330 311 if (haveEmpty) rv.push_back(""); // make sure empty category sorts last
Chris@330 312
Chris@330 313 return rv;
Chris@330 314 }
Chris@330 315
Chris@487 316 QString
Chris@487 317 TransformFactory::getTransformTypeName(TransformDescription::Type type) const
Chris@487 318 {
Chris@487 319 switch (type) {
Chris@487 320 case TransformDescription::Analysis: return tr("Analysis");
Chris@487 321 case TransformDescription::Effects: return tr("Effects");
Chris@487 322 case TransformDescription::EffectsData: return tr("Effects Data");
Chris@487 323 case TransformDescription::Generator: return tr("Generator");
Chris@487 324 case TransformDescription::UnknownType: return tr("Other");
Chris@487 325 }
Chris@489 326 return tr("Other");
Chris@487 327 }
Chris@487 328
Chris@1865 329 bool
Chris@1865 330 TransformFactory::havePopulated()
Chris@1865 331 {
Chris@1865 332 MutexLocker locker(&m_transformsMutex, "TransformFactory::havePopulated");
Chris@1865 333 return m_transformsPopulated;
Chris@1865 334 }
Chris@1865 335
Chris@330 336 void
Chris@330 337 TransformFactory::populateTransforms()
Chris@330 338 {
Chris@460 339 MutexLocker locker(&m_transformsMutex,
Chris@460 340 "TransformFactory::populateTransforms");
Chris@460 341 if (m_transformsPopulated) {
Chris@460 342 return;
Chris@460 343 }
Chris@460 344
Chris@330 345 TransformDescriptionMap transforms;
Chris@330 346
Chris@330 347 populateFeatureExtractionPlugins(transforms);
Chris@576 348 if (m_exiting) return;
Chris@330 349 populateRealTimePlugins(transforms);
Chris@576 350 if (m_exiting) return;
Chris@330 351
Chris@330 352 // disambiguate plugins with similar names
Chris@330 353
Chris@330 354 std::map<QString, int> names;
Chris@330 355 std::map<QString, QString> pluginSources;
Chris@330 356 std::map<QString, QString> pluginMakers;
Chris@330 357
Chris@330 358 for (TransformDescriptionMap::iterator i = transforms.begin();
Chris@330 359 i != transforms.end(); ++i) {
Chris@330 360
Chris@330 361 TransformDescription desc = i->second;
Chris@330 362
Chris@330 363 QString td = desc.name;
Chris@330 364 QString tn = td.section(": ", 0, 0);
Chris@330 365 QString pn = desc.identifier.section(":", 1, 1);
Chris@330 366
Chris@330 367 if (pluginSources.find(tn) != pluginSources.end()) {
Chris@330 368 if (pluginSources[tn] != pn && pluginMakers[tn] != desc.maker) {
Chris@330 369 ++names[tn];
Chris@330 370 }
Chris@330 371 } else {
Chris@330 372 ++names[tn];
Chris@330 373 pluginSources[tn] = pn;
Chris@330 374 pluginMakers[tn] = desc.maker;
Chris@330 375 }
Chris@330 376 }
Chris@330 377
Chris@330 378 std::map<QString, int> counts;
Chris@330 379 m_transforms.clear();
Chris@330 380
Chris@330 381 for (TransformDescriptionMap::iterator i = transforms.begin();
Chris@330 382 i != transforms.end(); ++i) {
Chris@330 383
Chris@330 384 TransformDescription desc = i->second;
Chris@1429 385 QString identifier = desc.identifier;
Chris@330 386 QString maker = desc.maker;
Chris@330 387
Chris@330 388 QString td = desc.name;
Chris@330 389 QString tn = td.section(": ", 0, 0);
Chris@330 390 QString to = td.section(": ", 1);
Chris@330 391
Chris@1429 392 if (names[tn] > 1) {
Chris@330 393 maker.replace(QRegExp(tr(" [\\(<].*$")), "");
Chris@1429 394 tn = QString("%1 [%2]").arg(tn).arg(maker);
Chris@1429 395 }
Chris@330 396
Chris@330 397 if (to != "") {
Chris@330 398 desc.name = QString("%1: %2").arg(tn).arg(to);
Chris@330 399 } else {
Chris@330 400 desc.name = tn;
Chris@330 401 }
Chris@330 402
Chris@1429 403 m_transforms[identifier] = desc;
Chris@1429 404 }
Chris@457 405
Chris@457 406 m_transformsPopulated = true;
Chris@1865 407
Chris@1865 408 #ifdef DEBUG_TRANSFORM_FACTORY
Chris@1865 409 SVCERR << "populateTransforms exiting" << endl;
Chris@1865 410 #endif
Chris@1865 411
Chris@1865 412 emit transformsPopulated();
Chris@330 413 }
Chris@330 414
Chris@330 415 void
Chris@330 416 TransformFactory::populateFeatureExtractionPlugins(TransformDescriptionMap &transforms)
Chris@330 417 {
Chris@1225 418 FeatureExtractionPluginFactory *factory =
Chris@1225 419 FeatureExtractionPluginFactory::instance();
Chris@1227 420
Chris@1227 421 QString errorMessage;
Chris@1227 422 std::vector<QString> plugs = factory->getPluginIdentifiers(errorMessage);
Chris@1227 423 if (errorMessage != "") {
Chris@1227 424 m_errorString = tr("Failed to list Vamp plugins: %1").arg(errorMessage);
Chris@1227 425 }
Chris@1225 426
Chris@576 427 if (m_exiting) return;
Chris@330 428
Chris@1546 429 for (int i = 0; in_range_for(plugs, i); ++i) {
Chris@330 430
Chris@1429 431 QString pluginId = plugs[i];
Chris@330 432
Chris@1223 433 piper_vamp::PluginStaticData psd = factory->getPluginStaticData(pluginId);
Chris@330 434
Chris@1223 435 if (psd.pluginKey == "") {
Chris@1223 436 cerr << "WARNING: TransformFactory::populateTransforms: No plugin static data available for instance " << pluginId << endl;
Chris@1223 437 continue;
Chris@1223 438 }
Chris@1223 439
Chris@1223 440 QString pluginName = QString::fromStdString(psd.basic.name);
Chris@330 441 QString category = factory->getPluginCategory(pluginId);
Chris@1223 442
Chris@1223 443 const auto &basicOutputs = psd.basicOutputInfo;
Chris@330 444
Chris@1223 445 for (const auto &o: basicOutputs) {
Chris@330 446
Chris@1223 447 QString outputName = QString::fromStdString(o.name);
Chris@330 448
Chris@1429 449 QString transformId = QString("%1:%2")
Chris@1223 450 .arg(pluginId).arg(QString::fromStdString(o.identifier));
Chris@330 451
Chris@1429 452 QString userName;
Chris@330 453 QString friendlyName;
Chris@1223 454 //!!! return to this QString units = outputs[j].unit.c_str();
Chris@1223 455 QString description = QString::fromStdString(psd.basic.description);
Chris@1223 456 QString maker = QString::fromStdString(psd.maker);
Chris@330 457 if (maker == "") maker = tr("<unknown maker>");
Chris@330 458
Chris@443 459 QString longDescription = description;
Chris@443 460
Chris@443 461 if (longDescription == "") {
Chris@1223 462 if (basicOutputs.size() == 1) {
Chris@443 463 longDescription = tr("Extract features using \"%1\" plugin (from %2)")
Chris@330 464 .arg(pluginName).arg(maker);
Chris@330 465 } else {
Chris@443 466 longDescription = tr("Extract features using \"%1\" output of \"%2\" plugin (from %3)")
Chris@1223 467 .arg(outputName).arg(pluginName).arg(maker);
Chris@330 468 }
Chris@330 469 } else {
Chris@1223 470 if (basicOutputs.size() == 1) {
Chris@443 471 longDescription = tr("%1 using \"%2\" plugin (from %3)")
Chris@443 472 .arg(longDescription).arg(pluginName).arg(maker);
Chris@330 473 } else {
Chris@443 474 longDescription = tr("%1 using \"%2\" output of \"%3\" plugin (from %4)")
Chris@1223 475 .arg(longDescription).arg(outputName).arg(pluginName).arg(maker);
Chris@330 476 }
Chris@330 477 }
Chris@330 478
Chris@1429 479 if (basicOutputs.size() == 1) {
Chris@1429 480 userName = pluginName;
Chris@330 481 friendlyName = pluginName;
Chris@1429 482 } else {
Chris@1429 483 userName = QString("%1: %2").arg(pluginName).arg(outputName);
Chris@1223 484 friendlyName = outputName;
Chris@1429 485 }
Chris@330 486
Chris@1223 487 bool configurable = (!psd.programs.empty() ||
Chris@1223 488 !psd.parameters.empty());
Chris@330 489
Chris@600 490 #ifdef DEBUG_TRANSFORM_FACTORY
Chris@686 491 cerr << "Feature extraction plugin transform: " << transformId << " friendly name: " << friendlyName << endl;
Chris@600 492 #endif
Chris@330 493
Chris@1429 494 transforms[transformId] =
Chris@487 495 TransformDescription(TransformDescription::Analysis,
Chris@332 496 category,
Chris@332 497 transformId,
Chris@332 498 userName,
Chris@332 499 friendlyName,
Chris@332 500 description,
Chris@443 501 longDescription,
Chris@332 502 maker,
Chris@1223 503 //!!! units,
Chris@1223 504 "",
Chris@332 505 configurable);
Chris@1429 506 }
Chris@330 507 }
Chris@330 508 }
Chris@330 509
Chris@330 510 void
Chris@330 511 TransformFactory::populateRealTimePlugins(TransformDescriptionMap &transforms)
Chris@330 512 {
Chris@330 513 std::vector<QString> plugs =
Chris@1429 514 RealTimePluginFactory::getAllPluginIdentifiers();
Chris@576 515 if (m_exiting) return;
Chris@330 516
Chris@330 517 static QRegExp unitRE("[\\[\\(]([A-Za-z0-9/]+)[\\)\\]]$");
Chris@330 518
Chris@1546 519 for (int i = 0; in_range_for(plugs, i); ++i) {
Chris@330 520
Chris@1429 521 QString pluginId = plugs[i];
Chris@330 522
Chris@330 523 RealTimePluginFactory *factory =
Chris@330 524 RealTimePluginFactory::instanceFor(pluginId);
Chris@330 525
Chris@1429 526 if (!factory) {
Chris@1429 527 cerr << "WARNING: TransformFactory::populateTransforms: No real time plugin factory for instance " << pluginId << endl;
Chris@1429 528 continue;
Chris@1429 529 }
Chris@330 530
Chris@1830 531 RealTimePluginDescriptor descriptor =
Chris@330 532 factory->getPluginDescriptor(pluginId);
Chris@330 533
Chris@1830 534 if (descriptor.name == "") {
Chris@1429 535 cerr << "WARNING: TransformFactory::populateTransforms: Failed to query plugin " << pluginId << endl;
Chris@1429 536 continue;
Chris@1429 537 }
Chris@1429 538
Chris@1830 539 //!!! if (descriptor.controlOutputPortCount == 0 ||
Chris@1830 540 // descriptor.audioInputPortCount == 0) continue;
Chris@330 541
Chris@1830 542 // cout << "TransformFactory::populateRealTimePlugins: plugin " << pluginId << " has " << descriptor.controlOutputPortCount << " control output ports, " << descriptor.audioOutputPortCount << " audio outputs, " << descriptor.audioInputPortCount << " audio inputs" << endl;
Chris@1429 543
Chris@1830 544 QString pluginName = descriptor.name.c_str();
Chris@330 545 QString category = factory->getPluginCategory(pluginId);
Chris@1830 546 bool configurable = (descriptor.parameterCount > 0);
Chris@1830 547 QString maker = descriptor.maker.c_str();
Chris@330 548 if (maker == "") maker = tr("<unknown maker>");
Chris@330 549
Chris@1830 550 if (descriptor.audioInputPortCount > 0) {
Chris@330 551
Chris@1830 552 for (int j = 0; j < (int)descriptor.controlOutputPortCount; ++j) {
Chris@330 553
Chris@330 554 QString transformId = QString("%1:%2").arg(pluginId).arg(j);
Chris@330 555 QString userName;
Chris@330 556 QString units;
Chris@330 557 QString portName;
Chris@330 558
Chris@1830 559 if (j < (int)descriptor.controlOutputPortNames.size() &&
Chris@1830 560 descriptor.controlOutputPortNames[j] != "") {
Chris@330 561
Chris@1830 562 portName = descriptor.controlOutputPortNames[j].c_str();
Chris@330 563
Chris@330 564 userName = tr("%1: %2")
Chris@330 565 .arg(pluginName)
Chris@330 566 .arg(portName);
Chris@330 567
Chris@330 568 if (unitRE.indexIn(portName) >= 0) {
Chris@330 569 units = unitRE.cap(1);
Chris@330 570 }
Chris@330 571
Chris@1830 572 } else if (descriptor.controlOutputPortCount > 1) {
Chris@330 573
Chris@330 574 userName = tr("%1: Output %2")
Chris@330 575 .arg(pluginName)
Chris@330 576 .arg(j + 1);
Chris@330 577
Chris@330 578 } else {
Chris@330 579
Chris@330 580 userName = pluginName;
Chris@330 581 }
Chris@330 582
Chris@330 583 QString description;
Chris@330 584
Chris@330 585 if (portName != "") {
Chris@330 586 description = tr("Extract \"%1\" data output from \"%2\" effect plugin (from %3)")
Chris@330 587 .arg(portName)
Chris@330 588 .arg(pluginName)
Chris@330 589 .arg(maker);
Chris@330 590 } else {
Chris@330 591 description = tr("Extract data output %1 from \"%2\" effect plugin (from %3)")
Chris@330 592 .arg(j + 1)
Chris@330 593 .arg(pluginName)
Chris@330 594 .arg(maker);
Chris@330 595 }
Chris@330 596
Chris@330 597 transforms[transformId] =
Chris@487 598 TransformDescription(TransformDescription::EffectsData,
Chris@332 599 category,
Chris@332 600 transformId,
Chris@332 601 userName,
Chris@332 602 userName,
Chris@443 603 "",
Chris@332 604 description,
Chris@332 605 maker,
Chris@332 606 units,
Chris@332 607 configurable);
Chris@330 608 }
Chris@330 609 }
Chris@330 610
Chris@1830 611 if (!descriptor.isSynth || descriptor.audioInputPortCount > 0) {
Chris@330 612
Chris@1830 613 if (descriptor.audioOutputPortCount > 0) {
Chris@330 614
Chris@330 615 QString transformId = QString("%1:A").arg(pluginId);
Chris@487 616 TransformDescription::Type type = TransformDescription::Effects;
Chris@330 617
Chris@330 618 QString description = tr("Transform audio signal with \"%1\" effect plugin (from %2)")
Chris@330 619 .arg(pluginName)
Chris@330 620 .arg(maker);
Chris@330 621
Chris@1830 622 if (descriptor.audioInputPortCount == 0) {
Chris@487 623 type = TransformDescription::Generator;
Chris@330 624 QString description = tr("Generate audio signal using \"%1\" plugin (from %2)")
Chris@330 625 .arg(pluginName)
Chris@330 626 .arg(maker);
Chris@330 627 }
Chris@330 628
Chris@330 629 transforms[transformId] =
Chris@330 630 TransformDescription(type,
Chris@332 631 category,
Chris@332 632 transformId,
Chris@332 633 pluginName,
Chris@332 634 pluginName,
Chris@443 635 "",
Chris@332 636 description,
Chris@332 637 maker,
Chris@332 638 "",
Chris@332 639 configurable);
Chris@330 640 }
Chris@330 641 }
Chris@330 642 }
Chris@330 643 }
Chris@330 644
Chris@457 645 void
Chris@457 646 TransformFactory::populateUninstalledTransforms()
Chris@457 647 {
Chris@576 648 if (m_exiting) return;
Chris@576 649
Chris@460 650 populateTransforms();
Chris@576 651 if (m_exiting) return;
Chris@460 652
Chris@460 653 MutexLocker locker(&m_uninstalledTransformsMutex,
Chris@460 654 "TransformFactory::populateUninstalledTransforms");
Chris@460 655 if (m_uninstalledTransformsPopulated) return;
Chris@460 656
Chris@461 657 PluginRDFIndexer::getInstance()->indexConfiguredURLs();
Chris@576 658 if (m_exiting) return;
Chris@457 659
Chris@1844 660 PluginRDFIndexer::getInstance()->performConsistencyChecks();
Chris@1844 661
Chris@457 662 //!!! This will be amazingly slow
Chris@457 663
Chris@457 664 QStringList ids = PluginRDFIndexer::getInstance()->getIndexedPluginIds();
Chris@457 665
Chris@457 666 for (QStringList::const_iterator i = ids.begin(); i != ids.end(); ++i) {
Chris@457 667
Chris@457 668 PluginRDFDescription desc(*i);
Chris@457 669
Chris@457 670 QString name = desc.getPluginName();
Chris@600 671 #ifdef DEBUG_TRANSFORM_FACTORY
Chris@600 672 if (name == "") {
Chris@1844 673 SVCERR << "TransformFactory::populateUninstalledTransforms: "
Chris@810 674 << "No name available for plugin " << *i
Chris@810 675 << ", skipping" << endl;
Chris@600 676 continue;
Chris@600 677 }
Chris@600 678 #endif
Chris@457 679
Chris@457 680 QString description = desc.getPluginDescription();
Chris@457 681 QString maker = desc.getPluginMaker();
Chris@1845 682 Provider provider = desc.getPluginProvider();
Chris@457 683
Chris@457 684 QStringList oids = desc.getOutputIds();
Chris@457 685
Chris@457 686 for (QStringList::const_iterator j = oids.begin(); j != oids.end(); ++j) {
Chris@457 687
Chris@457 688 TransformId tid = Transform::getIdentifierForPluginOutput(*i, *j);
Chris@457 689
Chris@457 690 if (m_transforms.find(tid) != m_transforms.end()) {
Chris@600 691 #ifdef DEBUG_TRANSFORM_FACTORY
Chris@1844 692 SVCERR << "TransformFactory::populateUninstalledTransforms: "
Chris@1845 693 << tid << " is installed; adding provider if present, skipping rest" << endl;
Chris@600 694 #endif
Chris@1845 695 if (provider != Provider()) {
Chris@1845 696 if (m_transforms[tid].provider == Provider()) {
Chris@1845 697 m_transforms[tid].provider = provider;
Chris@468 698 }
Chris@468 699 }
Chris@457 700 continue;
Chris@457 701 }
Chris@457 702
Chris@600 703 #ifdef DEBUG_TRANSFORM_FACTORY
Chris@1844 704 SVCERR << "TransformFactory::populateUninstalledTransforms: "
Chris@1844 705 << "adding " << tid << endl;
Chris@600 706 #endif
Chris@457 707
Chris@457 708 QString oname = desc.getOutputName(*j);
Chris@457 709 if (oname == "") oname = *j;
Chris@457 710
Chris@457 711 TransformDescription td;
Chris@487 712 td.type = TransformDescription::Analysis;
Chris@457 713 td.category = "";
Chris@457 714 td.identifier = tid;
Chris@457 715
Chris@457 716 if (oids.size() == 1) {
Chris@457 717 td.name = name;
Chris@457 718 } else if (name != "") {
Chris@457 719 td.name = tr("%1: %2").arg(name).arg(oname);
Chris@457 720 }
Chris@457 721
Chris@462 722 QString longDescription = description;
Chris@462 723 //!!! basically duplicated from above
Chris@462 724 if (longDescription == "") {
Chris@462 725 if (oids.size() == 1) {
Chris@462 726 longDescription = tr("Extract features using \"%1\" plugin (from %2)")
Chris@462 727 .arg(name).arg(maker);
Chris@462 728 } else {
Chris@462 729 longDescription = tr("Extract features using \"%1\" output of \"%2\" plugin (from %3)")
Chris@462 730 .arg(oname).arg(name).arg(maker);
Chris@462 731 }
Chris@462 732 } else {
Chris@462 733 if (oids.size() == 1) {
Chris@462 734 longDescription = tr("%1 using \"%2\" plugin (from %3)")
Chris@462 735 .arg(longDescription).arg(name).arg(maker);
Chris@462 736 } else {
Chris@462 737 longDescription = tr("%1 using \"%2\" output of \"%3\" plugin (from %4)")
Chris@462 738 .arg(longDescription).arg(oname).arg(name).arg(maker);
Chris@462 739 }
Chris@462 740 }
Chris@462 741
Chris@457 742 td.friendlyName = name; //!!!???
Chris@457 743 td.description = description;
Chris@462 744 td.longDescription = longDescription;
Chris@457 745 td.maker = maker;
Chris@1845 746 td.provider = provider;
Chris@457 747 td.units = "";
Chris@457 748 td.configurable = false;
Chris@457 749
Chris@457 750 m_uninstalledTransforms[tid] = td;
Chris@457 751 }
Chris@574 752
Chris@576 753 if (m_exiting) return;
Chris@457 754 }
Chris@457 755
Chris@457 756 m_uninstalledTransformsPopulated = true;
Chris@460 757
Chris@600 758 #ifdef DEBUG_TRANSFORM_FACTORY
Chris@1844 759 SVCERR << "populateUninstalledTransforms exiting" << endl;
Chris@600 760 #endif
Chris@1865 761
Chris@1865 762 emit uninstalledTransformsPopulated();
Chris@457 763 }
Chris@350 764
Chris@350 765 Transform
Chris@1047 766 TransformFactory::getDefaultTransformFor(TransformId id, sv_samplerate_t rate)
Chris@350 767 {
Chris@350 768 Transform t;
Chris@350 769 t.setIdentifier(id);
Chris@1047 770 if (rate != 0) t.setSampleRate(rate);
Chris@350 771
Chris@1264 772 SVDEBUG << "TransformFactory::getDefaultTransformFor: identifier \""
Chris@1264 773 << id << "\"" << endl;
Chris@1264 774
Chris@1830 775 std::shared_ptr<Vamp::PluginBase> plugin = instantiateDefaultPluginFor(id, rate);
Chris@350 776
Chris@350 777 if (plugin) {
Chris@366 778 t.setPluginVersion(QString("%1").arg(plugin->getPluginVersion()));
Chris@350 779 setParametersFromPlugin(t, plugin);
Chris@350 780 makeContextConsistentWithPlugin(t, plugin);
Chris@350 781 }
Chris@350 782
Chris@350 783 return t;
Chris@350 784 }
Chris@350 785
Chris@1830 786 std::shared_ptr<Vamp::PluginBase>
Chris@351 787 TransformFactory::instantiatePluginFor(const Transform &transform)
Chris@351 788 {
Chris@1264 789 SVDEBUG << "TransformFactory::instantiatePluginFor: identifier \""
Chris@1264 790 << transform.getIdentifier() << "\"" << endl;
Chris@1264 791
Chris@1830 792 std::shared_ptr<Vamp::PluginBase> plugin = instantiateDefaultPluginFor
Chris@1047 793 (transform.getIdentifier(), transform.getSampleRate());
Chris@508 794
Chris@351 795 if (plugin) {
Chris@351 796 setPluginParameters(transform, plugin);
Chris@351 797 }
Chris@508 798
Chris@351 799 return plugin;
Chris@351 800 }
Chris@351 801
Chris@1830 802 std::shared_ptr<Vamp::PluginBase>
Chris@1047 803 TransformFactory::instantiateDefaultPluginFor(TransformId identifier,
Chris@1047 804 sv_samplerate_t rate)
Chris@350 805 {
Chris@1879 806 populateTransforms();
Chris@1879 807
Chris@350 808 Transform t;
Chris@350 809 t.setIdentifier(identifier);
Chris@1047 810 if (rate == 0) rate = 44100.0;
Chris@350 811 QString pluginId = t.getPluginIdentifier();
Chris@350 812
Chris@1830 813 std::shared_ptr<Vamp::PluginBase> plugin = nullptr;
Chris@350 814
Chris@350 815 if (t.getType() == Transform::FeatureExtraction) {
Chris@350 816
Chris@1264 817 SVDEBUG << "TransformFactory::instantiateDefaultPluginFor: identifier \""
Chris@1264 818 << identifier << "\" is a feature extraction transform" << endl;
Chris@1139 819
Chris@1225 820 FeatureExtractionPluginFactory *factory =
Chris@1225 821 FeatureExtractionPluginFactory::instance();
Chris@350 822
Chris@439 823 if (factory) {
Chris@1047 824 plugin = factory->instantiatePlugin(pluginId, rate);
Chris@439 825 }
Chris@350 826
Chris@1139 827 } else if (t.getType() == Transform::RealTimeEffect) {
Chris@1139 828
Chris@1264 829 SVDEBUG << "TransformFactory::instantiateDefaultPluginFor: identifier \""
Chris@1264 830 << identifier << "\" is a real-time transform" << endl;
Chris@350 831
Chris@350 832 RealTimePluginFactory *factory =
Chris@350 833 RealTimePluginFactory::instanceFor(pluginId);
Chris@439 834
Chris@439 835 if (factory) {
Chris@439 836 plugin = factory->instantiatePlugin(pluginId, 0, 0, rate, 1024, 1);
Chris@439 837 }
Chris@1139 838
Chris@1139 839 } else {
Chris@1264 840 SVDEBUG << "TransformFactory: ERROR: transform id \""
Chris@1264 841 << identifier << "\" is of unknown type" << endl;
Chris@350 842 }
Chris@350 843
Chris@350 844 return plugin;
Chris@350 845 }
Chris@350 846
Chris@330 847 bool
Chris@330 848 TransformFactory::haveTransform(TransformId identifier)
Chris@330 849 {
Chris@460 850 populateTransforms();
Chris@330 851 return (m_transforms.find(identifier) != m_transforms.end());
Chris@330 852 }
Chris@330 853
Chris@330 854 QString
Chris@330 855 TransformFactory::getTransformName(TransformId identifier)
Chris@330 856 {
Chris@330 857 if (m_transforms.find(identifier) != m_transforms.end()) {
Chris@1429 858 return m_transforms[identifier].name;
Chris@330 859 } else return "";
Chris@330 860 }
Chris@330 861
Chris@330 862 QString
Chris@330 863 TransformFactory::getTransformFriendlyName(TransformId identifier)
Chris@330 864 {
Chris@330 865 if (m_transforms.find(identifier) != m_transforms.end()) {
Chris@1429 866 return m_transforms[identifier].friendlyName;
Chris@330 867 } else return "";
Chris@330 868 }
Chris@330 869
Chris@330 870 QString
Chris@330 871 TransformFactory::getTransformUnits(TransformId identifier)
Chris@330 872 {
Chris@330 873 if (m_transforms.find(identifier) != m_transforms.end()) {
Chris@1429 874 return m_transforms[identifier].units;
Chris@330 875 } else return "";
Chris@330 876 }
Chris@330 877
Chris@1845 878 Provider
Chris@1845 879 TransformFactory::getTransformProvider(TransformId identifier)
Chris@472 880 {
Chris@472 881 if (m_transforms.find(identifier) != m_transforms.end()) {
Chris@1845 882 return m_transforms[identifier].provider;
Chris@1845 883 } else return {};
Chris@472 884 }
Chris@472 885
Chris@350 886 Vamp::Plugin::InputDomain
Chris@350 887 TransformFactory::getTransformInputDomain(TransformId identifier)
Chris@350 888 {
Chris@350 889 Transform transform;
Chris@350 890 transform.setIdentifier(identifier);
Chris@350 891
Chris@1264 892 SVDEBUG << "TransformFactory::getTransformInputDomain: identifier \""
Chris@1264 893 << identifier << "\"" << endl;
Chris@1264 894
Chris@350 895 if (transform.getType() != Transform::FeatureExtraction) {
Chris@350 896 return Vamp::Plugin::TimeDomain;
Chris@350 897 }
Chris@350 898
Chris@1830 899 std::shared_ptr<Vamp::Plugin> plugin =
Chris@1830 900 std::dynamic_pointer_cast<Vamp::Plugin>
Chris@1830 901 (instantiateDefaultPluginFor(identifier, 0));
Chris@350 902
Chris@350 903 if (plugin) {
Chris@350 904 Vamp::Plugin::InputDomain d = plugin->getInputDomain();
Chris@350 905 return d;
Chris@350 906 }
Chris@350 907
Chris@350 908 return Vamp::Plugin::TimeDomain;
Chris@350 909 }
Chris@350 910
Chris@330 911 bool
Chris@330 912 TransformFactory::isTransformConfigurable(TransformId identifier)
Chris@330 913 {
Chris@330 914 if (m_transforms.find(identifier) != m_transforms.end()) {
Chris@1429 915 return m_transforms[identifier].configurable;
Chris@330 916 } else return false;
Chris@330 917 }
Chris@330 918
Chris@330 919 bool
Chris@330 920 TransformFactory::getTransformChannelRange(TransformId identifier,
Chris@330 921 int &min, int &max)
Chris@330 922 {
Chris@330 923 QString id = identifier.section(':', 0, 2);
Chris@330 924
Chris@1225 925 if (RealTimePluginFactory::instanceFor(id)) {
Chris@350 926
Chris@1830 927 RealTimePluginDescriptor descriptor =
Chris@330 928 RealTimePluginFactory::instanceFor(id)->
Chris@330 929 getPluginDescriptor(id);
Chris@1830 930 if (descriptor.name == "") {
Chris@1830 931 return false;
Chris@1830 932 }
Chris@330 933
Chris@1830 934 min = descriptor.audioInputPortCount;
Chris@1830 935 max = descriptor.audioInputPortCount;
Chris@330 936
Chris@330 937 return true;
Chris@1225 938
Chris@1225 939 } else {
Chris@1225 940
Chris@1225 941 auto psd = FeatureExtractionPluginFactory::instance()->
Chris@1225 942 getPluginStaticData(id);
Chris@1225 943 if (psd.pluginKey == "") return false;
Chris@1225 944
Chris@1225 945 min = (int)psd.minChannelCount;
Chris@1225 946 max = (int)psd.maxChannelCount;
Chris@1225 947
Chris@1225 948 return true;
Chris@330 949 }
Chris@330 950
Chris@330 951 return false;
Chris@330 952 }
Chris@332 953
Chris@332 954 void
Chris@332 955 TransformFactory::setParametersFromPlugin(Transform &transform,
Chris@1830 956 std::shared_ptr<Vamp::PluginBase> plugin)
Chris@332 957 {
Chris@332 958 Transform::ParameterMap pmap;
Chris@332 959
Chris@350 960 //!!! record plugin & API version
Chris@350 961
Chris@350 962 //!!! check that this is the right plugin!
Chris@350 963
Chris@332 964 Vamp::PluginBase::ParameterList parameters =
Chris@332 965 plugin->getParameterDescriptors();
Chris@332 966
Chris@332 967 for (Vamp::PluginBase::ParameterList::const_iterator i = parameters.begin();
Chris@332 968 i != parameters.end(); ++i) {
Chris@332 969 pmap[i->identifier.c_str()] = plugin->getParameter(i->identifier);
Chris@810 970 // cerr << "TransformFactory::setParametersFromPlugin: parameter "
Chris@583 971 // << i->identifier << " -> value " <<
Chris@687 972 // pmap[i->identifier.c_str()] << endl;
Chris@332 973 }
Chris@332 974
Chris@332 975 transform.setParameters(pmap);
Chris@332 976
Chris@332 977 if (plugin->getPrograms().empty()) {
Chris@332 978 transform.setProgram("");
Chris@332 979 } else {
Chris@332 980 transform.setProgram(plugin->getCurrentProgram().c_str());
Chris@332 981 }
Chris@332 982
Chris@1830 983 std::shared_ptr<RealTimePluginInstance> rtpi =
Chris@1830 984 std::dynamic_pointer_cast<RealTimePluginInstance>(plugin);
Chris@332 985
Chris@332 986 Transform::ConfigurationMap cmap;
Chris@332 987
Chris@332 988 if (rtpi) {
Chris@332 989
Chris@332 990 RealTimePluginInstance::ConfigurationPairMap configurePairs =
Chris@332 991 rtpi->getConfigurePairs();
Chris@332 992
Chris@332 993 for (RealTimePluginInstance::ConfigurationPairMap::const_iterator i
Chris@332 994 = configurePairs.begin(); i != configurePairs.end(); ++i) {
Chris@332 995 cmap[i->first.c_str()] = i->second.c_str();
Chris@332 996 }
Chris@332 997 }
Chris@332 998
Chris@332 999 transform.setConfiguration(cmap);
Chris@332 1000 }
Chris@332 1001
Chris@332 1002 void
Chris@350 1003 TransformFactory::setPluginParameters(const Transform &transform,
Chris@1830 1004 std::shared_ptr<Vamp::PluginBase> plugin)
Chris@350 1005 {
Chris@350 1006 //!!! check plugin & API version (see e.g. PluginXml::setParameters)
Chris@350 1007
Chris@350 1008 //!!! check that this is the right plugin!
Chris@350 1009
Chris@1830 1010 std::shared_ptr<RealTimePluginInstance> rtpi =
Chris@1830 1011 std::dynamic_pointer_cast<RealTimePluginInstance>(plugin);
Chris@350 1012
Chris@350 1013 if (rtpi) {
Chris@350 1014 const Transform::ConfigurationMap &cmap = transform.getConfiguration();
Chris@350 1015 for (Transform::ConfigurationMap::const_iterator i = cmap.begin();
Chris@350 1016 i != cmap.end(); ++i) {
Chris@350 1017 rtpi->configure(i->first.toStdString(), i->second.toStdString());
Chris@350 1018 }
Chris@350 1019 }
Chris@350 1020
Chris@350 1021 if (transform.getProgram() != "") {
Chris@350 1022 plugin->selectProgram(transform.getProgram().toStdString());
Chris@350 1023 }
Chris@350 1024
Chris@350 1025 const Transform::ParameterMap &pmap = transform.getParameters();
Chris@350 1026
Chris@350 1027 Vamp::PluginBase::ParameterList parameters =
Chris@350 1028 plugin->getParameterDescriptors();
Chris@350 1029
Chris@350 1030 for (Vamp::PluginBase::ParameterList::const_iterator i = parameters.begin();
Chris@350 1031 i != parameters.end(); ++i) {
Chris@350 1032 QString key = i->identifier.c_str();
Chris@350 1033 Transform::ParameterMap::const_iterator pmi = pmap.find(key);
Chris@350 1034 if (pmi != pmap.end()) {
Chris@350 1035 plugin->setParameter(i->identifier, pmi->second);
Chris@350 1036 }
Chris@350 1037 }
Chris@350 1038 }
Chris@350 1039
Chris@350 1040 void
Chris@332 1041 TransformFactory::makeContextConsistentWithPlugin(Transform &transform,
Chris@1830 1042 std::shared_ptr<Vamp::PluginBase> plugin)
Chris@332 1043 {
Chris@1830 1044 std::shared_ptr<Vamp::Plugin> vp =
Chris@1830 1045 std::dynamic_pointer_cast<Vamp::Plugin>(plugin);
Chris@332 1046
Chris@332 1047 if (!vp) {
Chris@332 1048 // time domain input for real-time effects plugin
Chris@332 1049 if (!transform.getBlockSize()) {
Chris@332 1050 if (!transform.getStepSize()) transform.setStepSize(1024);
Chris@332 1051 transform.setBlockSize(transform.getStepSize());
Chris@332 1052 } else {
Chris@332 1053 transform.setStepSize(transform.getBlockSize());
Chris@332 1054 }
Chris@332 1055 } else {
Chris@332 1056 Vamp::Plugin::InputDomain domain = vp->getInputDomain();
Chris@332 1057 if (!transform.getStepSize()) {
Chris@1039 1058 transform.setStepSize((int)vp->getPreferredStepSize());
Chris@332 1059 }
Chris@332 1060 if (!transform.getBlockSize()) {
Chris@1039 1061 transform.setBlockSize((int)vp->getPreferredBlockSize());
Chris@332 1062 }
Chris@332 1063 if (!transform.getBlockSize()) {
Chris@332 1064 transform.setBlockSize(1024);
Chris@332 1065 }
Chris@332 1066 if (!transform.getStepSize()) {
Chris@332 1067 if (domain == Vamp::Plugin::FrequencyDomain) {
Chris@443 1068 // cerr << "frequency domain, step = " << blockSize/2 << endl;
Chris@332 1069 transform.setStepSize(transform.getBlockSize()/2);
Chris@332 1070 } else {
Chris@443 1071 // cerr << "time domain, step = " << blockSize/2 << endl;
Chris@332 1072 transform.setStepSize(transform.getBlockSize());
Chris@332 1073 }
Chris@332 1074 }
Chris@332 1075 }
Chris@332 1076 }
Chris@332 1077
Chris@350 1078 QString
Chris@350 1079 TransformFactory::getPluginConfigurationXml(const Transform &t)
Chris@332 1080 {
Chris@350 1081 QString xml;
Chris@350 1082
Chris@1264 1083 SVDEBUG << "TransformFactory::getPluginConfigurationXml: identifier \""
Chris@1264 1084 << t.getIdentifier() << "\"" << endl;
Chris@1264 1085
Chris@1830 1086 auto plugin = instantiateDefaultPluginFor(t.getIdentifier(), 0);
Chris@350 1087 if (!plugin) {
Chris@1264 1088 SVDEBUG << "TransformFactory::getPluginConfigurationXml: "
Chris@1264 1089 << "Unable to instantiate plugin for transform \""
Chris@1264 1090 << t.getIdentifier() << "\"" << endl;
Chris@350 1091 return xml;
Chris@332 1092 }
Chris@332 1093
Chris@351 1094 setPluginParameters(t, plugin);
Chris@351 1095
Chris@350 1096 QTextStream out(&xml);
Chris@350 1097 PluginXml(plugin).toXml(out);
Chris@332 1098
Chris@350 1099 return xml;
Chris@350 1100 }
Chris@332 1101
Chris@350 1102 void
Chris@350 1103 TransformFactory::setParametersFromPluginConfigurationXml(Transform &t,
Chris@350 1104 QString xml)
Chris@350 1105 {
Chris@1264 1106 SVDEBUG << "TransformFactory::setParametersFromPluginConfigurationXml: identifier \""
Chris@1264 1107 << t.getIdentifier() << "\"" << endl;
Chris@1264 1108
Chris@1830 1109 auto plugin = instantiateDefaultPluginFor(t.getIdentifier(), 0);
Chris@350 1110 if (!plugin) {
Chris@1264 1111 SVDEBUG << "TransformFactory::setParametersFromPluginConfigurationXml: "
Chris@1264 1112 << "Unable to instantiate plugin for transform \""
Chris@1264 1113 << t.getIdentifier() << "\"" << endl;
Chris@350 1114 return;
Chris@332 1115 }
Chris@332 1116
Chris@350 1117 PluginXml(plugin).setParametersFromXml(xml);
Chris@350 1118 setParametersFromPlugin(t, plugin);
Chris@332 1119 }
Chris@332 1120
Chris@443 1121 TransformFactory::SearchResults
Chris@443 1122 TransformFactory::search(QString keyword)
Chris@443 1123 {
Chris@443 1124 QStringList keywords;
Chris@443 1125 keywords << keyword;
Chris@443 1126 return search(keywords);
Chris@443 1127 }
Chris@443 1128
Chris@443 1129 TransformFactory::SearchResults
Chris@443 1130 TransformFactory::search(QStringList keywords)
Chris@443 1131 {
Chris@460 1132 populateTransforms();
Chris@443 1133
Chris@1842 1134 SearchResults results = searchUnadjusted(keywords);
Chris@1842 1135
Chris@447 1136 if (keywords.size() > 1) {
Chris@1842 1137
Chris@1842 1138 // If there are any hits for all keywords in a row, put them
Chris@1842 1139 // in (replacing previous hits for the same transforms) but
Chris@1842 1140 // ensure they score more than any of the others
Chris@1842 1141
Chris@1842 1142 int maxScore = 0;
Chris@1842 1143 for (auto r: results) {
Chris@1842 1144 if (r.second.score > maxScore) {
Chris@1842 1145 maxScore = r.second.score;
Chris@1842 1146 }
Chris@1842 1147 }
Chris@1842 1148
Chris@1842 1149 QStringList oneBigKeyword;
Chris@1842 1150 oneBigKeyword << keywords.join(" ");
Chris@1842 1151 SearchResults oneBigKeywordResults = searchUnadjusted(oneBigKeyword);
Chris@1842 1152 for (auto r: oneBigKeywordResults) {
Chris@1842 1153 results[r.first] = r.second;
Chris@1842 1154 results[r.first].score += maxScore;
Chris@1842 1155 }
Chris@447 1156 }
Chris@447 1157
Chris@1842 1158 return results;
Chris@1842 1159 }
Chris@1842 1160
Chris@1842 1161 TransformFactory::SearchResults
Chris@1842 1162 TransformFactory::searchUnadjusted(QStringList keywords)
Chris@1842 1163 {
Chris@443 1164 SearchResults results;
Chris@457 1165 TextMatcher matcher;
Chris@443 1166
Chris@443 1167 for (TransformDescriptionMap::const_iterator i = m_transforms.begin();
Chris@443 1168 i != m_transforms.end(); ++i) {
Chris@443 1169
Chris@457 1170 TextMatcher::Match match;
Chris@443 1171
Chris@457 1172 match.key = i->first;
Chris@443 1173
Chris@487 1174 matcher.test(match, keywords,
Chris@487 1175 getTransformTypeName(i->second.type),
Chris@487 1176 tr("Plugin type"), 5);
Chris@487 1177
Chris@457 1178 matcher.test(match, keywords, i->second.category, tr("Category"), 20);
Chris@457 1179 matcher.test(match, keywords, i->second.identifier, tr("System Identifier"), 6);
Chris@457 1180 matcher.test(match, keywords, i->second.name, tr("Name"), 30);
Chris@457 1181 matcher.test(match, keywords, i->second.description, tr("Description"), 20);
Chris@457 1182 matcher.test(match, keywords, i->second.maker, tr("Maker"), 10);
Chris@457 1183 matcher.test(match, keywords, i->second.units, tr("Units"), 10);
Chris@457 1184
Chris@457 1185 if (match.score > 0) results[i->first] = match;
Chris@457 1186 }
Chris@457 1187
Chris@460 1188 if (!m_uninstalledTransformsMutex.tryLock()) {
Chris@460 1189 // uninstalled transforms are being populated; this may take some time,
Chris@484 1190 // and they aren't critical, but we will speed them up if necessary
Chris@1264 1191 SVDEBUG << "TransformFactory::search: Uninstalled transforms mutex is held, skipping" << endl;
Chris@484 1192 m_populatingSlowly = false;
Chris@460 1193 return results;
Chris@460 1194 }
Chris@460 1195
Chris@460 1196 if (!m_uninstalledTransformsPopulated) {
Chris@1264 1197 SVDEBUG << "WARNING: TransformFactory::search: Uninstalled transforms are not populated yet" << endl
Chris@1264 1198 << "and are not being populated either -- was the thread not started correctly?" << endl;
Chris@460 1199 m_uninstalledTransformsMutex.unlock();
Chris@460 1200 return results;
Chris@460 1201 }
Chris@460 1202
Chris@460 1203 m_uninstalledTransformsMutex.unlock();
Chris@457 1204
Chris@457 1205 for (TransformDescriptionMap::const_iterator i = m_uninstalledTransforms.begin();
Chris@457 1206 i != m_uninstalledTransforms.end(); ++i) {
Chris@457 1207
Chris@457 1208 TextMatcher::Match match;
Chris@457 1209
Chris@457 1210 match.key = i->first;
Chris@457 1211
Chris@487 1212 matcher.test(match, keywords,
Chris@487 1213 getTransformTypeName(i->second.type),
Chris@487 1214 tr("Plugin type"), 2);
Chris@487 1215
Chris@457 1216 matcher.test(match, keywords, i->second.category, tr("Category"), 10);
Chris@457 1217 matcher.test(match, keywords, i->second.identifier, tr("System Identifier"), 3);
Chris@457 1218 matcher.test(match, keywords, i->second.name, tr("Name"), 15);
Chris@457 1219 matcher.test(match, keywords, i->second.description, tr("Description"), 10);
Chris@457 1220 matcher.test(match, keywords, i->second.maker, tr("Maker"), 5);
Chris@457 1221 matcher.test(match, keywords, i->second.units, tr("Units"), 5);
Chris@443 1222
Chris@443 1223 if (match.score > 0) results[i->first] = match;
Chris@443 1224 }
Chris@443 1225
Chris@1842 1226 #ifdef DEBUG_TRANSFORM_FACTORY
Chris@1842 1227 SVCERR << "TransformFactory::search: keywords are: " << keywords.join(", ")
Chris@1842 1228 << endl;
Chris@1842 1229 int n = int(results.size()), i = 1;
Chris@1842 1230 SVCERR << "TransformFactory::search: results (" << n << "):" << endl;
Chris@1842 1231
Chris@1842 1232 for (const auto &r: results) {
Chris@1842 1233 QStringList frags;
Chris@1842 1234 for (const auto &f: r.second.fragments) {
Chris@1842 1235 frags << QString("{\"%1\": \"%2\"}").arg(f.first).arg(f.second);
Chris@1842 1236 }
Chris@1842 1237 SVCERR << "[" << i << "/" << n << "] id " << r.first
Chris@1842 1238 << ": score " << r.second.score
Chris@1842 1239 << ", key " << r.second.key << ", fragments "
Chris@1842 1240 << frags.join(";") << endl;
Chris@1842 1241 ++i;
Chris@1842 1242 }
Chris@1842 1243 SVCERR << endl;
Chris@1842 1244 #endif
Chris@1842 1245
Chris@443 1246 return results;
Chris@443 1247 }
Chris@443 1248