annotate transform/TransformFactory.cpp @ 443:381ec750eeee

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