annotate transform/TransformFactory.cpp @ 457:ef14acd6d102

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