annotate transform/TransformFactory.cpp @ 537:3cc4b7cd2aa5

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