00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "TransformFactory.h"
00017
00018 #include "plugin/FeatureExtractionPluginFactory.h"
00019 #include "plugin/RealTimePluginFactory.h"
00020 #include "plugin/RealTimePluginInstance.h"
00021 #include "plugin/PluginXml.h"
00022
00023 #include "vamp-sdk/Plugin.h"
00024 #include "vamp-sdk/PluginHostAdapter.h"
00025 #include "vamp-sdk/hostext/PluginWrapper.h"
00026
00027 #include <iostream>
00028 #include <set>
00029
00030 #include <QRegExp>
00031 #include <QTextStream>
00032
00033 TransformFactory *
00034 TransformFactory::m_instance = new TransformFactory;
00035
00036 TransformFactory *
00037 TransformFactory::getInstance()
00038 {
00039 return m_instance;
00040 }
00041
00042 TransformFactory::~TransformFactory()
00043 {
00044 }
00045
00046 TransformList
00047 TransformFactory::getAllTransformDescriptions()
00048 {
00049 if (m_transforms.empty()) populateTransforms();
00050
00051 std::set<TransformDescription> dset;
00052 for (TransformDescriptionMap::const_iterator i = m_transforms.begin();
00053 i != m_transforms.end(); ++i) {
00054
00055 dset.insert(i->second);
00056 }
00057
00058 TransformList list;
00059 for (std::set<TransformDescription>::const_iterator i = dset.begin();
00060 i != dset.end(); ++i) {
00061
00062 list.push_back(*i);
00063 }
00064
00065 return list;
00066 }
00067
00068 TransformDescription
00069 TransformFactory::getTransformDescription(TransformId id)
00070 {
00071 if (m_transforms.empty()) populateTransforms();
00072
00073 if (m_transforms.find(id) == m_transforms.end()) {
00074 return TransformDescription();
00075 }
00076
00077 return m_transforms[id];
00078 }
00079
00080 std::vector<QString>
00081 TransformFactory::getAllTransformTypes()
00082 {
00083 if (m_transforms.empty()) populateTransforms();
00084
00085 std::set<QString> types;
00086 for (TransformDescriptionMap::const_iterator i = m_transforms.begin();
00087 i != m_transforms.end(); ++i) {
00088 types.insert(i->second.type);
00089 }
00090
00091 std::vector<QString> rv;
00092 for (std::set<QString>::iterator i = types.begin(); i != types.end(); ++i) {
00093 rv.push_back(*i);
00094 }
00095
00096 return rv;
00097 }
00098
00099 std::vector<QString>
00100 TransformFactory::getTransformCategories(QString transformType)
00101 {
00102 if (m_transforms.empty()) populateTransforms();
00103
00104 std::set<QString> categories;
00105 for (TransformDescriptionMap::const_iterator i = m_transforms.begin();
00106 i != m_transforms.end(); ++i) {
00107 if (i->second.type == transformType) {
00108 categories.insert(i->second.category);
00109 }
00110 }
00111
00112 bool haveEmpty = false;
00113
00114 std::vector<QString> rv;
00115 for (std::set<QString>::iterator i = categories.begin();
00116 i != categories.end(); ++i) {
00117 if (*i != "") rv.push_back(*i);
00118 else haveEmpty = true;
00119 }
00120
00121 if (haveEmpty) rv.push_back("");
00122
00123 return rv;
00124 }
00125
00126 std::vector<QString>
00127 TransformFactory::getTransformMakers(QString transformType)
00128 {
00129 if (m_transforms.empty()) populateTransforms();
00130
00131 std::set<QString> makers;
00132 for (TransformDescriptionMap::const_iterator i = m_transforms.begin();
00133 i != m_transforms.end(); ++i) {
00134 if (i->second.type == transformType) {
00135 makers.insert(i->second.maker);
00136 }
00137 }
00138
00139 bool haveEmpty = false;
00140
00141 std::vector<QString> rv;
00142 for (std::set<QString>::iterator i = makers.begin();
00143 i != makers.end(); ++i) {
00144 if (*i != "") rv.push_back(*i);
00145 else haveEmpty = true;
00146 }
00147
00148 if (haveEmpty) rv.push_back("");
00149
00150 return rv;
00151 }
00152
00153 void
00154 TransformFactory::populateTransforms()
00155 {
00156 TransformDescriptionMap transforms;
00157
00158 populateFeatureExtractionPlugins(transforms);
00159 populateRealTimePlugins(transforms);
00160
00161
00162
00163 std::map<QString, int> names;
00164 std::map<QString, QString> pluginSources;
00165 std::map<QString, QString> pluginMakers;
00166
00167 for (TransformDescriptionMap::iterator i = transforms.begin();
00168 i != transforms.end(); ++i) {
00169
00170 TransformDescription desc = i->second;
00171
00172 QString td = desc.name;
00173 QString tn = td.section(": ", 0, 0);
00174 QString pn = desc.identifier.section(":", 1, 1);
00175
00176 if (pluginSources.find(tn) != pluginSources.end()) {
00177 if (pluginSources[tn] != pn && pluginMakers[tn] != desc.maker) {
00178 ++names[tn];
00179 }
00180 } else {
00181 ++names[tn];
00182 pluginSources[tn] = pn;
00183 pluginMakers[tn] = desc.maker;
00184 }
00185 }
00186
00187 std::map<QString, int> counts;
00188 m_transforms.clear();
00189
00190 for (TransformDescriptionMap::iterator i = transforms.begin();
00191 i != transforms.end(); ++i) {
00192
00193 TransformDescription desc = i->second;
00194 QString identifier = desc.identifier;
00195 QString maker = desc.maker;
00196
00197 QString td = desc.name;
00198 QString tn = td.section(": ", 0, 0);
00199 QString to = td.section(": ", 1);
00200
00201 if (names[tn] > 1) {
00202 maker.replace(QRegExp(tr(" [\\(<].*$")), "");
00203 tn = QString("%1 [%2]").arg(tn).arg(maker);
00204 }
00205
00206 if (to != "") {
00207 desc.name = QString("%1: %2").arg(tn).arg(to);
00208 } else {
00209 desc.name = tn;
00210 }
00211
00212 m_transforms[identifier] = desc;
00213 }
00214 }
00215
00216 void
00217 TransformFactory::populateFeatureExtractionPlugins(TransformDescriptionMap &transforms)
00218 {
00219 std::vector<QString> plugs =
00220 FeatureExtractionPluginFactory::getAllPluginIdentifiers();
00221
00222 for (size_t i = 0; i < plugs.size(); ++i) {
00223
00224 QString pluginId = plugs[i];
00225
00226 FeatureExtractionPluginFactory *factory =
00227 FeatureExtractionPluginFactory::instanceFor(pluginId);
00228
00229 if (!factory) {
00230 std::cerr << "WARNING: TransformFactory::populateTransforms: No feature extraction plugin factory for instance " << pluginId.toLocal8Bit().data() << std::endl;
00231 continue;
00232 }
00233
00234 Vamp::Plugin *plugin =
00235 factory->instantiatePlugin(pluginId, 44100);
00236
00237 if (!plugin) {
00238 std::cerr << "WARNING: TransformFactory::populateTransforms: Failed to instantiate plugin " << pluginId.toLocal8Bit().data() << std::endl;
00239 continue;
00240 }
00241
00242 QString pluginName = plugin->getName().c_str();
00243 QString category = factory->getPluginCategory(pluginId);
00244
00245 Vamp::Plugin::OutputList outputs =
00246 plugin->getOutputDescriptors();
00247
00248 for (size_t j = 0; j < outputs.size(); ++j) {
00249
00250 QString transformId = QString("%1:%2")
00251 .arg(pluginId).arg(outputs[j].identifier.c_str());
00252
00253 QString userName;
00254 QString friendlyName;
00255 QString units = outputs[j].unit.c_str();
00256 QString description = plugin->getDescription().c_str();
00257 QString maker = plugin->getMaker().c_str();
00258 if (maker == "") maker = tr("<unknown maker>");
00259
00260 if (description == "") {
00261 if (outputs.size() == 1) {
00262 description = tr("Extract features using \"%1\" plugin (from %2)")
00263 .arg(pluginName).arg(maker);
00264 } else {
00265 description = tr("Extract features using \"%1\" output of \"%2\" plugin (from %3)")
00266 .arg(outputs[j].name.c_str()).arg(pluginName).arg(maker);
00267 }
00268 } else {
00269 if (outputs.size() == 1) {
00270 description = tr("%1 using \"%2\" plugin (from %3)")
00271 .arg(description).arg(pluginName).arg(maker);
00272 } else {
00273 description = tr("%1 using \"%2\" output of \"%3\" plugin (from %4)")
00274 .arg(description).arg(outputs[j].name.c_str()).arg(pluginName).arg(maker);
00275 }
00276 }
00277
00278 if (outputs.size() == 1) {
00279 userName = pluginName;
00280 friendlyName = pluginName;
00281 } else {
00282 userName = QString("%1: %2")
00283 .arg(pluginName)
00284 .arg(outputs[j].name.c_str());
00285 friendlyName = outputs[j].name.c_str();
00286 }
00287
00288 bool configurable = (!plugin->getPrograms().empty() ||
00289 !plugin->getParameterDescriptors().empty());
00290
00291
00292
00293 transforms[transformId] =
00294 TransformDescription(tr("Analysis"),
00295 category,
00296 transformId,
00297 userName,
00298 friendlyName,
00299 description,
00300 maker,
00301 units,
00302 configurable);
00303 }
00304
00305 delete plugin;
00306 }
00307 }
00308
00309 void
00310 TransformFactory::populateRealTimePlugins(TransformDescriptionMap &transforms)
00311 {
00312 std::vector<QString> plugs =
00313 RealTimePluginFactory::getAllPluginIdentifiers();
00314
00315 static QRegExp unitRE("[\\[\\(]([A-Za-z0-9/]+)[\\)\\]]$");
00316
00317 for (size_t i = 0; i < plugs.size(); ++i) {
00318
00319 QString pluginId = plugs[i];
00320
00321 RealTimePluginFactory *factory =
00322 RealTimePluginFactory::instanceFor(pluginId);
00323
00324 if (!factory) {
00325 std::cerr << "WARNING: TransformFactory::populateTransforms: No real time plugin factory for instance " << pluginId.toLocal8Bit().data() << std::endl;
00326 continue;
00327 }
00328
00329 const RealTimePluginDescriptor *descriptor =
00330 factory->getPluginDescriptor(pluginId);
00331
00332 if (!descriptor) {
00333 std::cerr << "WARNING: TransformFactory::populateTransforms: Failed to query plugin " << pluginId.toLocal8Bit().data() << std::endl;
00334 continue;
00335 }
00336
00338
00339
00340
00341
00342 QString pluginName = descriptor->name.c_str();
00343 QString category = factory->getPluginCategory(pluginId);
00344 bool configurable = (descriptor->parameterCount > 0);
00345 QString maker = descriptor->maker.c_str();
00346 if (maker == "") maker = tr("<unknown maker>");
00347
00348 if (descriptor->audioInputPortCount > 0) {
00349
00350 for (size_t j = 0; j < descriptor->controlOutputPortCount; ++j) {
00351
00352 QString transformId = QString("%1:%2").arg(pluginId).arg(j);
00353 QString userName;
00354 QString units;
00355 QString portName;
00356
00357 if (j < descriptor->controlOutputPortNames.size() &&
00358 descriptor->controlOutputPortNames[j] != "") {
00359
00360 portName = descriptor->controlOutputPortNames[j].c_str();
00361
00362 userName = tr("%1: %2")
00363 .arg(pluginName)
00364 .arg(portName);
00365
00366 if (unitRE.indexIn(portName) >= 0) {
00367 units = unitRE.cap(1);
00368 }
00369
00370 } else if (descriptor->controlOutputPortCount > 1) {
00371
00372 userName = tr("%1: Output %2")
00373 .arg(pluginName)
00374 .arg(j + 1);
00375
00376 } else {
00377
00378 userName = pluginName;
00379 }
00380
00381 QString description;
00382
00383 if (portName != "") {
00384 description = tr("Extract \"%1\" data output from \"%2\" effect plugin (from %3)")
00385 .arg(portName)
00386 .arg(pluginName)
00387 .arg(maker);
00388 } else {
00389 description = tr("Extract data output %1 from \"%2\" effect plugin (from %3)")
00390 .arg(j + 1)
00391 .arg(pluginName)
00392 .arg(maker);
00393 }
00394
00395 transforms[transformId] =
00396 TransformDescription(tr("Effects Data"),
00397 category,
00398 transformId,
00399 userName,
00400 userName,
00401 description,
00402 maker,
00403 units,
00404 configurable);
00405 }
00406 }
00407
00408 if (!descriptor->isSynth || descriptor->audioInputPortCount > 0) {
00409
00410 if (descriptor->audioOutputPortCount > 0) {
00411
00412 QString transformId = QString("%1:A").arg(pluginId);
00413 QString type = tr("Effects");
00414
00415 QString description = tr("Transform audio signal with \"%1\" effect plugin (from %2)")
00416 .arg(pluginName)
00417 .arg(maker);
00418
00419 if (descriptor->audioInputPortCount == 0) {
00420 type = tr("Generators");
00421 QString description = tr("Generate audio signal using \"%1\" plugin (from %2)")
00422 .arg(pluginName)
00423 .arg(maker);
00424 }
00425
00426 transforms[transformId] =
00427 TransformDescription(type,
00428 category,
00429 transformId,
00430 pluginName,
00431 pluginName,
00432 description,
00433 maker,
00434 "",
00435 configurable);
00436 }
00437 }
00438 }
00439 }
00440
00441
00442 Transform
00443 TransformFactory::getDefaultTransformFor(TransformId id, size_t rate)
00444 {
00445 Transform t;
00446 t.setIdentifier(id);
00447 if (rate != 0) t.setSampleRate(rate);
00448
00449 Vamp::PluginBase *plugin = instantiateDefaultPluginFor(id, rate);
00450
00451 if (plugin) {
00452 t.setPluginVersion(QString("%1").arg(plugin->getPluginVersion()));
00453 setParametersFromPlugin(t, plugin);
00454 makeContextConsistentWithPlugin(t, plugin);
00455 delete plugin;
00456 }
00457
00458 return t;
00459 }
00460
00461 Vamp::PluginBase *
00462 TransformFactory::instantiatePluginFor(const Transform &transform)
00463 {
00464 Vamp::PluginBase *plugin = instantiateDefaultPluginFor
00465 (transform.getIdentifier(), transform.getSampleRate());
00466 if (plugin) {
00467 setPluginParameters(transform, plugin);
00468 }
00469 return plugin;
00470 }
00471
00472 Vamp::PluginBase *
00473 TransformFactory::instantiateDefaultPluginFor(TransformId identifier, size_t rate)
00474 {
00475 Transform t;
00476 t.setIdentifier(identifier);
00477 if (rate == 0) rate = 44100;
00478 QString pluginId = t.getPluginIdentifier();
00479
00480 Vamp::PluginBase *plugin = 0;
00481
00482 if (t.getType() == Transform::FeatureExtraction) {
00483
00484 FeatureExtractionPluginFactory *factory =
00485 FeatureExtractionPluginFactory::instanceFor(pluginId);
00486
00487 plugin = factory->instantiatePlugin(pluginId, rate);
00488
00489 } else {
00490
00491 RealTimePluginFactory *factory =
00492 RealTimePluginFactory::instanceFor(pluginId);
00493
00494 plugin = factory->instantiatePlugin(pluginId, 0, 0, rate, 1024, 1);
00495 }
00496
00497 return plugin;
00498 }
00499
00500 Vamp::Plugin *
00501 TransformFactory::downcastVampPlugin(Vamp::PluginBase *plugin)
00502 {
00503 Vamp::Plugin *vp = dynamic_cast<Vamp::Plugin *>(plugin);
00504 if (!vp) {
00505
00506 vp = dynamic_cast<Vamp::PluginHostAdapter *>(plugin);
00507 }
00508 if (!vp) {
00509
00510 vp = dynamic_cast<Vamp::HostExt::PluginWrapper *>(plugin);
00511 }
00512 if (!vp) {
00513
00514 }
00515 return vp;
00516 }
00517
00518 bool
00519 TransformFactory::haveTransform(TransformId identifier)
00520 {
00521 if (m_transforms.empty()) populateTransforms();
00522 return (m_transforms.find(identifier) != m_transforms.end());
00523 }
00524
00525 QString
00526 TransformFactory::getTransformName(TransformId identifier)
00527 {
00528 if (m_transforms.find(identifier) != m_transforms.end()) {
00529 return m_transforms[identifier].name;
00530 } else return "";
00531 }
00532
00533 QString
00534 TransformFactory::getTransformFriendlyName(TransformId identifier)
00535 {
00536 if (m_transforms.find(identifier) != m_transforms.end()) {
00537 return m_transforms[identifier].friendlyName;
00538 } else return "";
00539 }
00540
00541 QString
00542 TransformFactory::getTransformUnits(TransformId identifier)
00543 {
00544 if (m_transforms.find(identifier) != m_transforms.end()) {
00545 return m_transforms[identifier].units;
00546 } else return "";
00547 }
00548
00549 Vamp::Plugin::InputDomain
00550 TransformFactory::getTransformInputDomain(TransformId identifier)
00551 {
00552 Transform transform;
00553 transform.setIdentifier(identifier);
00554
00555 if (transform.getType() != Transform::FeatureExtraction) {
00556 return Vamp::Plugin::TimeDomain;
00557 }
00558
00559 Vamp::Plugin *plugin =
00560 downcastVampPlugin(instantiateDefaultPluginFor(identifier, 0));
00561
00562 if (plugin) {
00563 Vamp::Plugin::InputDomain d = plugin->getInputDomain();
00564 delete plugin;
00565 return d;
00566 }
00567
00568 return Vamp::Plugin::TimeDomain;
00569 }
00570
00571 bool
00572 TransformFactory::isTransformConfigurable(TransformId identifier)
00573 {
00574 if (m_transforms.find(identifier) != m_transforms.end()) {
00575 return m_transforms[identifier].configurable;
00576 } else return false;
00577 }
00578
00579 bool
00580 TransformFactory::getTransformChannelRange(TransformId identifier,
00581 int &min, int &max)
00582 {
00583 QString id = identifier.section(':', 0, 2);
00584
00585 if (FeatureExtractionPluginFactory::instanceFor(id)) {
00586
00587 Vamp::Plugin *plugin =
00588 FeatureExtractionPluginFactory::instanceFor(id)->
00589 instantiatePlugin(id, 44100);
00590 if (!plugin) return false;
00591
00592 min = plugin->getMinChannelCount();
00593 max = plugin->getMaxChannelCount();
00594 delete plugin;
00595
00596 return true;
00597
00598 } else if (RealTimePluginFactory::instanceFor(id)) {
00599
00600
00601
00602 const RealTimePluginDescriptor *descriptor =
00603 RealTimePluginFactory::instanceFor(id)->
00604 getPluginDescriptor(id);
00605 if (!descriptor) return false;
00606
00607 min = descriptor->audioInputPortCount;
00608 max = descriptor->audioInputPortCount;
00609
00610 return true;
00611 }
00612
00613 return false;
00614 }
00615
00616 void
00617 TransformFactory::setParametersFromPlugin(Transform &transform,
00618 Vamp::PluginBase *plugin)
00619 {
00620 Transform::ParameterMap pmap;
00621
00623
00625
00626 Vamp::PluginBase::ParameterList parameters =
00627 plugin->getParameterDescriptors();
00628
00629 for (Vamp::PluginBase::ParameterList::const_iterator i = parameters.begin();
00630 i != parameters.end(); ++i) {
00631 pmap[i->identifier.c_str()] = plugin->getParameter(i->identifier);
00632 }
00633
00634 transform.setParameters(pmap);
00635
00636 if (plugin->getPrograms().empty()) {
00637 transform.setProgram("");
00638 } else {
00639 transform.setProgram(plugin->getCurrentProgram().c_str());
00640 }
00641
00642 RealTimePluginInstance *rtpi =
00643 dynamic_cast<RealTimePluginInstance *>(plugin);
00644
00645 Transform::ConfigurationMap cmap;
00646
00647 if (rtpi) {
00648
00649 RealTimePluginInstance::ConfigurationPairMap configurePairs =
00650 rtpi->getConfigurePairs();
00651
00652 for (RealTimePluginInstance::ConfigurationPairMap::const_iterator i
00653 = configurePairs.begin(); i != configurePairs.end(); ++i) {
00654 cmap[i->first.c_str()] = i->second.c_str();
00655 }
00656 }
00657
00658 transform.setConfiguration(cmap);
00659 }
00660
00661 void
00662 TransformFactory::setPluginParameters(const Transform &transform,
00663 Vamp::PluginBase *plugin)
00664 {
00666
00668
00669 RealTimePluginInstance *rtpi =
00670 dynamic_cast<RealTimePluginInstance *>(plugin);
00671
00672 if (rtpi) {
00673 const Transform::ConfigurationMap &cmap = transform.getConfiguration();
00674 for (Transform::ConfigurationMap::const_iterator i = cmap.begin();
00675 i != cmap.end(); ++i) {
00676 rtpi->configure(i->first.toStdString(), i->second.toStdString());
00677 }
00678 }
00679
00680 if (transform.getProgram() != "") {
00681 plugin->selectProgram(transform.getProgram().toStdString());
00682 }
00683
00684 const Transform::ParameterMap &pmap = transform.getParameters();
00685
00686 Vamp::PluginBase::ParameterList parameters =
00687 plugin->getParameterDescriptors();
00688
00689 for (Vamp::PluginBase::ParameterList::const_iterator i = parameters.begin();
00690 i != parameters.end(); ++i) {
00691 QString key = i->identifier.c_str();
00692 Transform::ParameterMap::const_iterator pmi = pmap.find(key);
00693 if (pmi != pmap.end()) {
00694 plugin->setParameter(i->identifier, pmi->second);
00695 }
00696 }
00697 }
00698
00699 void
00700 TransformFactory::makeContextConsistentWithPlugin(Transform &transform,
00701 Vamp::PluginBase *plugin)
00702 {
00703 const Vamp::Plugin *vp = downcastVampPlugin(plugin);
00704
00705 if (!vp) {
00706
00707 if (!transform.getBlockSize()) {
00708 if (!transform.getStepSize()) transform.setStepSize(1024);
00709 transform.setBlockSize(transform.getStepSize());
00710 } else {
00711 transform.setStepSize(transform.getBlockSize());
00712 }
00713 } else {
00714 Vamp::Plugin::InputDomain domain = vp->getInputDomain();
00715 if (!transform.getStepSize()) {
00716 transform.setStepSize(vp->getPreferredStepSize());
00717 }
00718 if (!transform.getBlockSize()) {
00719 transform.setBlockSize(vp->getPreferredBlockSize());
00720 }
00721 if (!transform.getBlockSize()) {
00722 transform.setBlockSize(1024);
00723 }
00724 if (!transform.getStepSize()) {
00725 if (domain == Vamp::Plugin::FrequencyDomain) {
00726
00727 transform.setStepSize(transform.getBlockSize()/2);
00728 } else {
00729
00730 transform.setStepSize(transform.getBlockSize());
00731 }
00732 }
00733 }
00734 }
00735
00736 QString
00737 TransformFactory::getPluginConfigurationXml(const Transform &t)
00738 {
00739 QString xml;
00740
00741 Vamp::PluginBase *plugin = instantiateDefaultPluginFor
00742 (t.getIdentifier(), 0);
00743 if (!plugin) {
00744 std::cerr << "TransformFactory::getPluginConfigurationXml: "
00745 << "Unable to instantiate plugin for transform \""
00746 << t.getIdentifier().toStdString() << "\"" << std::endl;
00747 return xml;
00748 }
00749
00750 setPluginParameters(t, plugin);
00751
00752 QTextStream out(&xml);
00753 PluginXml(plugin).toXml(out);
00754 delete plugin;
00755
00756 return xml;
00757 }
00758
00759 void
00760 TransformFactory::setParametersFromPluginConfigurationXml(Transform &t,
00761 QString xml)
00762 {
00763 Vamp::PluginBase *plugin = instantiateDefaultPluginFor
00764 (t.getIdentifier(), 0);
00765 if (!plugin) {
00766 std::cerr << "TransformFactory::setParametersFromPluginConfigurationXml: "
00767 << "Unable to instantiate plugin for transform \""
00768 << t.getIdentifier().toStdString() << "\"" << std::endl;
00769 return;
00770 }
00771
00772 PluginXml(plugin).setParametersFromXml(xml);
00773 setParametersFromPlugin(t, plugin);
00774 delete plugin;
00775 }
00776