svcore
1.9
|
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ 00002 00003 /* 00004 Sonic Visualiser 00005 An audio file viewer and annotation editor. 00006 Centre for Digital Music, Queen Mary, University of London. 00007 This file copyright 2006 Chris Cannam and QMUL. 00008 00009 This program is free software; you can redistribute it and/or 00010 modify it under the terms of the GNU General Public License as 00011 published by the Free Software Foundation; either version 2 of the 00012 License, or (at your option) any later version. See the file 00013 COPYING included with this distribution for more information. 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-hostsdk/Plugin.h> 00024 #include <vamp-hostsdk/PluginHostAdapter.h> 00025 #include <vamp-hostsdk/PluginWrapper.h> 00026 00027 #include "rdf/PluginRDFIndexer.h" 00028 #include "rdf/PluginRDFDescription.h" 00029 00030 #include "base/XmlExportable.h" 00031 00032 #include <iostream> 00033 #include <set> 00034 00035 #include <QRegExp> 00036 #include <QTextStream> 00037 00038 #include "base/Thread.h" 00039 00040 //#define DEBUG_TRANSFORM_FACTORY 1 00041 00042 TransformFactory * 00043 TransformFactory::m_instance = new TransformFactory; 00044 00045 TransformFactory * 00046 TransformFactory::getInstance() 00047 { 00048 return m_instance; 00049 } 00050 00051 void 00052 TransformFactory::deleteInstance() 00053 { 00054 SVDEBUG << "TransformFactory::deleteInstance called" << endl; 00055 delete m_instance; 00056 m_instance = 0; 00057 } 00058 00059 TransformFactory::TransformFactory() : 00060 m_transformsPopulated(false), 00061 m_uninstalledTransformsPopulated(false), 00062 m_thread(0), 00063 m_exiting(false), 00064 m_populatingSlowly(false) 00065 { 00066 } 00067 00068 TransformFactory::~TransformFactory() 00069 { 00070 m_exiting = true; 00071 if (m_thread) { 00072 #ifdef DEBUG_TRANSFORM_FACTORY 00073 SVDEBUG << "TransformFactory::~TransformFactory: waiting on thread" << endl; 00074 #endif 00075 m_thread->wait(); 00076 delete m_thread; 00077 #ifdef DEBUG_TRANSFORM_FACTORY 00078 SVDEBUG << "TransformFactory::~TransformFactory: waited and done" << endl; 00079 #endif 00080 } 00081 } 00082 00083 void 00084 TransformFactory::startPopulationThread() 00085 { 00086 m_uninstalledTransformsMutex.lock(); 00087 00088 if (m_thread) { 00089 m_uninstalledTransformsMutex.unlock(); 00090 return; 00091 } 00092 m_thread = new UninstalledTransformsPopulateThread(this); 00093 00094 m_uninstalledTransformsMutex.unlock(); 00095 00096 m_thread->start(); 00097 } 00098 00099 void 00100 TransformFactory::UninstalledTransformsPopulateThread::run() 00101 { 00102 m_factory->m_populatingSlowly = true; 00103 sleep(1); 00104 m_factory->populateUninstalledTransforms(); 00105 } 00106 00107 TransformList 00108 TransformFactory::getAllTransformDescriptions() 00109 { 00110 populateTransforms(); 00111 00112 std::set<TransformDescription> dset; 00113 for (TransformDescriptionMap::const_iterator i = m_transforms.begin(); 00114 i != m_transforms.end(); ++i) { 00115 #ifdef DEBUG_TRANSFORM_FACTORY 00116 cerr << "inserting transform into set: id = " << i->second.identifier << endl; 00117 #endif 00118 dset.insert(i->second); 00119 } 00120 00121 TransformList list; 00122 for (std::set<TransformDescription>::const_iterator i = dset.begin(); 00123 i != dset.end(); ++i) { 00124 #ifdef DEBUG_TRANSFORM_FACTORY 00125 cerr << "inserting transform into list: id = " << i->identifier << endl; 00126 #endif 00127 list.push_back(*i); 00128 } 00129 00130 return list; 00131 } 00132 00133 TransformDescription 00134 TransformFactory::getTransformDescription(TransformId id) 00135 { 00136 populateTransforms(); 00137 00138 if (m_transforms.find(id) == m_transforms.end()) { 00139 return TransformDescription(); 00140 } 00141 00142 return m_transforms[id]; 00143 } 00144 00145 bool 00146 TransformFactory::haveInstalledTransforms() 00147 { 00148 populateTransforms(); 00149 return !m_transforms.empty(); 00150 } 00151 00152 TransformList 00153 TransformFactory::getUninstalledTransformDescriptions() 00154 { 00155 m_populatingSlowly = false; 00156 populateUninstalledTransforms(); 00157 00158 std::set<TransformDescription> dset; 00159 for (TransformDescriptionMap::const_iterator i = m_uninstalledTransforms.begin(); 00160 i != m_uninstalledTransforms.end(); ++i) { 00161 #ifdef DEBUG_TRANSFORM_FACTORY 00162 cerr << "inserting transform into set: id = " << i->second.identifier << endl; 00163 #endif 00164 dset.insert(i->second); 00165 } 00166 00167 TransformList list; 00168 for (std::set<TransformDescription>::const_iterator i = dset.begin(); 00169 i != dset.end(); ++i) { 00170 #ifdef DEBUG_TRANSFORM_FACTORY 00171 cerr << "inserting transform into uninstalled list: id = " << i->identifier << endl; 00172 #endif 00173 list.push_back(*i); 00174 } 00175 00176 return list; 00177 } 00178 00179 TransformDescription 00180 TransformFactory::getUninstalledTransformDescription(TransformId id) 00181 { 00182 m_populatingSlowly = false; 00183 populateUninstalledTransforms(); 00184 00185 if (m_uninstalledTransforms.find(id) == m_uninstalledTransforms.end()) { 00186 return TransformDescription(); 00187 } 00188 00189 return m_uninstalledTransforms[id]; 00190 } 00191 00192 bool 00193 TransformFactory::haveUninstalledTransforms(bool waitForCheckToComplete) 00194 { 00195 if (waitForCheckToComplete) { 00196 populateUninstalledTransforms(); 00197 } else { 00198 if (!m_uninstalledTransformsMutex.tryLock()) { 00199 return false; 00200 } 00201 if (!m_uninstalledTransformsPopulated) { 00202 m_uninstalledTransformsMutex.unlock(); 00203 return false; 00204 } 00205 m_uninstalledTransformsMutex.unlock(); 00206 } 00207 00208 return !m_uninstalledTransforms.empty(); 00209 } 00210 00211 TransformFactory::TransformInstallStatus 00212 TransformFactory::getTransformInstallStatus(TransformId id) 00213 { 00214 populateTransforms(); 00215 00216 if (m_transforms.find(id) != m_transforms.end()) { 00217 return TransformInstalled; 00218 } 00219 00220 if (!m_uninstalledTransformsMutex.tryLock()) { 00221 // uninstalled transforms are being populated; this may take some time, 00222 // and they aren't critical 00223 return TransformUnknown; 00224 } 00225 00226 if (!m_uninstalledTransformsPopulated) { 00227 m_uninstalledTransformsMutex.unlock(); 00228 m_populatingSlowly = false; 00229 populateUninstalledTransforms(); 00230 m_uninstalledTransformsMutex.lock(); 00231 } 00232 00233 if (m_uninstalledTransforms.find(id) != m_uninstalledTransforms.end()) { 00234 m_uninstalledTransformsMutex.unlock(); 00235 return TransformNotInstalled; 00236 } 00237 00238 m_uninstalledTransformsMutex.unlock(); 00239 return TransformUnknown; 00240 } 00241 00242 00243 std::vector<TransformDescription::Type> 00244 TransformFactory::getAllTransformTypes() 00245 { 00246 populateTransforms(); 00247 00248 std::set<TransformDescription::Type> types; 00249 for (TransformDescriptionMap::const_iterator i = m_transforms.begin(); 00250 i != m_transforms.end(); ++i) { 00251 types.insert(i->second.type); 00252 } 00253 00254 std::vector<TransformDescription::Type> rv; 00255 for (std::set<TransformDescription::Type>::iterator i = types.begin(); i != types.end(); ++i) { 00256 rv.push_back(*i); 00257 } 00258 00259 return rv; 00260 } 00261 00262 std::vector<QString> 00263 TransformFactory::getTransformCategories(TransformDescription::Type transformType) 00264 { 00265 populateTransforms(); 00266 00267 std::set<QString> categories; 00268 for (TransformDescriptionMap::const_iterator i = m_transforms.begin(); 00269 i != m_transforms.end(); ++i) { 00270 if (i->second.type == transformType) { 00271 categories.insert(i->second.category); 00272 } 00273 } 00274 00275 bool haveEmpty = false; 00276 00277 std::vector<QString> rv; 00278 for (std::set<QString>::iterator i = categories.begin(); 00279 i != categories.end(); ++i) { 00280 if (*i != "") rv.push_back(*i); 00281 else haveEmpty = true; 00282 } 00283 00284 if (haveEmpty) rv.push_back(""); // make sure empty category sorts last 00285 00286 return rv; 00287 } 00288 00289 std::vector<QString> 00290 TransformFactory::getTransformMakers(TransformDescription::Type transformType) 00291 { 00292 populateTransforms(); 00293 00294 std::set<QString> makers; 00295 for (TransformDescriptionMap::const_iterator i = m_transforms.begin(); 00296 i != m_transforms.end(); ++i) { 00297 if (i->second.type == transformType) { 00298 makers.insert(i->second.maker); 00299 } 00300 } 00301 00302 bool haveEmpty = false; 00303 00304 std::vector<QString> rv; 00305 for (std::set<QString>::iterator i = makers.begin(); 00306 i != makers.end(); ++i) { 00307 if (*i != "") rv.push_back(*i); 00308 else haveEmpty = true; 00309 } 00310 00311 if (haveEmpty) rv.push_back(""); // make sure empty category sorts last 00312 00313 return rv; 00314 } 00315 00316 QString 00317 TransformFactory::getTransformTypeName(TransformDescription::Type type) const 00318 { 00319 switch (type) { 00320 case TransformDescription::Analysis: return tr("Analysis"); 00321 case TransformDescription::Effects: return tr("Effects"); 00322 case TransformDescription::EffectsData: return tr("Effects Data"); 00323 case TransformDescription::Generator: return tr("Generator"); 00324 case TransformDescription::UnknownType: return tr("Other"); 00325 } 00326 return tr("Other"); 00327 } 00328 00329 void 00330 TransformFactory::populateTransforms() 00331 { 00332 MutexLocker locker(&m_transformsMutex, 00333 "TransformFactory::populateTransforms"); 00334 if (m_transformsPopulated) { 00335 return; 00336 } 00337 00338 TransformDescriptionMap transforms; 00339 00340 populateFeatureExtractionPlugins(transforms); 00341 if (m_exiting) return; 00342 populateRealTimePlugins(transforms); 00343 if (m_exiting) return; 00344 00345 // disambiguate plugins with similar names 00346 00347 std::map<QString, int> names; 00348 std::map<QString, QString> pluginSources; 00349 std::map<QString, QString> pluginMakers; 00350 00351 for (TransformDescriptionMap::iterator i = transforms.begin(); 00352 i != transforms.end(); ++i) { 00353 00354 TransformDescription desc = i->second; 00355 00356 QString td = desc.name; 00357 QString tn = td.section(": ", 0, 0); 00358 QString pn = desc.identifier.section(":", 1, 1); 00359 00360 if (pluginSources.find(tn) != pluginSources.end()) { 00361 if (pluginSources[tn] != pn && pluginMakers[tn] != desc.maker) { 00362 ++names[tn]; 00363 } 00364 } else { 00365 ++names[tn]; 00366 pluginSources[tn] = pn; 00367 pluginMakers[tn] = desc.maker; 00368 } 00369 } 00370 00371 std::map<QString, int> counts; 00372 m_transforms.clear(); 00373 00374 for (TransformDescriptionMap::iterator i = transforms.begin(); 00375 i != transforms.end(); ++i) { 00376 00377 TransformDescription desc = i->second; 00378 QString identifier = desc.identifier; 00379 QString maker = desc.maker; 00380 00381 QString td = desc.name; 00382 QString tn = td.section(": ", 0, 0); 00383 QString to = td.section(": ", 1); 00384 00385 if (names[tn] > 1) { 00386 maker.replace(QRegExp(tr(" [\\(<].*$")), ""); 00387 tn = QString("%1 [%2]").arg(tn).arg(maker); 00388 } 00389 00390 if (to != "") { 00391 desc.name = QString("%1: %2").arg(tn).arg(to); 00392 } else { 00393 desc.name = tn; 00394 } 00395 00396 m_transforms[identifier] = desc; 00397 } 00398 00399 m_transformsPopulated = true; 00400 } 00401 00402 void 00403 TransformFactory::populateFeatureExtractionPlugins(TransformDescriptionMap &transforms) 00404 { 00405 std::vector<QString> plugs = 00406 FeatureExtractionPluginFactory::getAllPluginIdentifiers(); 00407 if (m_exiting) return; 00408 00409 for (int i = 0; i < (int)plugs.size(); ++i) { 00410 00411 QString pluginId = plugs[i]; 00412 00413 FeatureExtractionPluginFactory *factory = 00414 FeatureExtractionPluginFactory::instanceFor(pluginId); 00415 00416 if (!factory) { 00417 cerr << "WARNING: TransformFactory::populateTransforms: No feature extraction plugin factory for instance " << pluginId << endl; 00418 continue; 00419 } 00420 00421 Vamp::Plugin *plugin = 00422 factory->instantiatePlugin(pluginId, 44100); 00423 00424 if (!plugin) { 00425 cerr << "WARNING: TransformFactory::populateTransforms: Failed to instantiate plugin " << pluginId << endl; 00426 continue; 00427 } 00428 00429 QString pluginName = plugin->getName().c_str(); 00430 QString category = factory->getPluginCategory(pluginId); 00431 00432 Vamp::Plugin::OutputList outputs = 00433 plugin->getOutputDescriptors(); 00434 00435 for (int j = 0; j < (int)outputs.size(); ++j) { 00436 00437 QString transformId = QString("%1:%2") 00438 .arg(pluginId).arg(outputs[j].identifier.c_str()); 00439 00440 QString userName; 00441 QString friendlyName; 00442 QString units = outputs[j].unit.c_str(); 00443 QString description = plugin->getDescription().c_str(); 00444 QString maker = plugin->getMaker().c_str(); 00445 if (maker == "") maker = tr("<unknown maker>"); 00446 00447 QString longDescription = description; 00448 00449 if (longDescription == "") { 00450 if (outputs.size() == 1) { 00451 longDescription = tr("Extract features using \"%1\" plugin (from %2)") 00452 .arg(pluginName).arg(maker); 00453 } else { 00454 longDescription = tr("Extract features using \"%1\" output of \"%2\" plugin (from %3)") 00455 .arg(outputs[j].name.c_str()).arg(pluginName).arg(maker); 00456 } 00457 } else { 00458 if (outputs.size() == 1) { 00459 longDescription = tr("%1 using \"%2\" plugin (from %3)") 00460 .arg(longDescription).arg(pluginName).arg(maker); 00461 } else { 00462 longDescription = tr("%1 using \"%2\" output of \"%3\" plugin (from %4)") 00463 .arg(longDescription).arg(outputs[j].name.c_str()).arg(pluginName).arg(maker); 00464 } 00465 } 00466 00467 if (outputs.size() == 1) { 00468 userName = pluginName; 00469 friendlyName = pluginName; 00470 } else { 00471 userName = QString("%1: %2") 00472 .arg(pluginName) 00473 .arg(outputs[j].name.c_str()); 00474 friendlyName = outputs[j].name.c_str(); 00475 } 00476 00477 bool configurable = (!plugin->getPrograms().empty() || 00478 !plugin->getParameterDescriptors().empty()); 00479 00480 #ifdef DEBUG_TRANSFORM_FACTORY 00481 cerr << "Feature extraction plugin transform: " << transformId << " friendly name: " << friendlyName << endl; 00482 #endif 00483 00484 transforms[transformId] = 00485 TransformDescription(TransformDescription::Analysis, 00486 category, 00487 transformId, 00488 userName, 00489 friendlyName, 00490 description, 00491 longDescription, 00492 maker, 00493 units, 00494 configurable); 00495 } 00496 00497 delete plugin; 00498 } 00499 } 00500 00501 void 00502 TransformFactory::populateRealTimePlugins(TransformDescriptionMap &transforms) 00503 { 00504 std::vector<QString> plugs = 00505 RealTimePluginFactory::getAllPluginIdentifiers(); 00506 if (m_exiting) return; 00507 00508 static QRegExp unitRE("[\\[\\(]([A-Za-z0-9/]+)[\\)\\]]$"); 00509 00510 for (int i = 0; i < (int)plugs.size(); ++i) { 00511 00512 QString pluginId = plugs[i]; 00513 00514 RealTimePluginFactory *factory = 00515 RealTimePluginFactory::instanceFor(pluginId); 00516 00517 if (!factory) { 00518 cerr << "WARNING: TransformFactory::populateTransforms: No real time plugin factory for instance " << pluginId << endl; 00519 continue; 00520 } 00521 00522 const RealTimePluginDescriptor *descriptor = 00523 factory->getPluginDescriptor(pluginId); 00524 00525 if (!descriptor) { 00526 cerr << "WARNING: TransformFactory::populateTransforms: Failed to query plugin " << pluginId << endl; 00527 continue; 00528 } 00529 00531 // descriptor->audioInputPortCount == 0) continue; 00532 00533 // cout << "TransformFactory::populateRealTimePlugins: plugin " << pluginId << " has " << descriptor->controlOutputPortCount << " control output ports, " << descriptor->audioOutputPortCount << " audio outputs, " << descriptor->audioInputPortCount << " audio inputs" << endl; 00534 00535 QString pluginName = descriptor->name.c_str(); 00536 QString category = factory->getPluginCategory(pluginId); 00537 bool configurable = (descriptor->parameterCount > 0); 00538 QString maker = descriptor->maker.c_str(); 00539 if (maker == "") maker = tr("<unknown maker>"); 00540 00541 if (descriptor->audioInputPortCount > 0) { 00542 00543 for (int j = 0; j < (int)descriptor->controlOutputPortCount; ++j) { 00544 00545 QString transformId = QString("%1:%2").arg(pluginId).arg(j); 00546 QString userName; 00547 QString units; 00548 QString portName; 00549 00550 if (j < (int)descriptor->controlOutputPortNames.size() && 00551 descriptor->controlOutputPortNames[j] != "") { 00552 00553 portName = descriptor->controlOutputPortNames[j].c_str(); 00554 00555 userName = tr("%1: %2") 00556 .arg(pluginName) 00557 .arg(portName); 00558 00559 if (unitRE.indexIn(portName) >= 0) { 00560 units = unitRE.cap(1); 00561 } 00562 00563 } else if (descriptor->controlOutputPortCount > 1) { 00564 00565 userName = tr("%1: Output %2") 00566 .arg(pluginName) 00567 .arg(j + 1); 00568 00569 } else { 00570 00571 userName = pluginName; 00572 } 00573 00574 QString description; 00575 00576 if (portName != "") { 00577 description = tr("Extract \"%1\" data output from \"%2\" effect plugin (from %3)") 00578 .arg(portName) 00579 .arg(pluginName) 00580 .arg(maker); 00581 } else { 00582 description = tr("Extract data output %1 from \"%2\" effect plugin (from %3)") 00583 .arg(j + 1) 00584 .arg(pluginName) 00585 .arg(maker); 00586 } 00587 00588 transforms[transformId] = 00589 TransformDescription(TransformDescription::EffectsData, 00590 category, 00591 transformId, 00592 userName, 00593 userName, 00594 "", 00595 description, 00596 maker, 00597 units, 00598 configurable); 00599 } 00600 } 00601 00602 if (!descriptor->isSynth || descriptor->audioInputPortCount > 0) { 00603 00604 if (descriptor->audioOutputPortCount > 0) { 00605 00606 QString transformId = QString("%1:A").arg(pluginId); 00607 TransformDescription::Type type = TransformDescription::Effects; 00608 00609 QString description = tr("Transform audio signal with \"%1\" effect plugin (from %2)") 00610 .arg(pluginName) 00611 .arg(maker); 00612 00613 if (descriptor->audioInputPortCount == 0) { 00614 type = TransformDescription::Generator; 00615 QString description = tr("Generate audio signal using \"%1\" plugin (from %2)") 00616 .arg(pluginName) 00617 .arg(maker); 00618 } 00619 00620 transforms[transformId] = 00621 TransformDescription(type, 00622 category, 00623 transformId, 00624 pluginName, 00625 pluginName, 00626 "", 00627 description, 00628 maker, 00629 "", 00630 configurable); 00631 } 00632 } 00633 } 00634 } 00635 00636 void 00637 TransformFactory::populateUninstalledTransforms() 00638 { 00639 if (m_exiting) return; 00640 00641 populateTransforms(); 00642 if (m_exiting) return; 00643 00644 MutexLocker locker(&m_uninstalledTransformsMutex, 00645 "TransformFactory::populateUninstalledTransforms"); 00646 if (m_uninstalledTransformsPopulated) return; 00647 00648 PluginRDFIndexer::getInstance()->indexConfiguredURLs(); 00649 if (m_exiting) return; 00650 00652 00653 QStringList ids = PluginRDFIndexer::getInstance()->getIndexedPluginIds(); 00654 00655 for (QStringList::const_iterator i = ids.begin(); i != ids.end(); ++i) { 00656 00657 PluginRDFDescription desc(*i); 00658 00659 QString name = desc.getPluginName(); 00660 #ifdef DEBUG_TRANSFORM_FACTORY 00661 if (name == "") { 00662 cerr << "TransformFactory::populateUninstalledTransforms: " 00663 << "No name available for plugin " << *i 00664 << ", skipping" << endl; 00665 continue; 00666 } 00667 #endif 00668 00669 QString description = desc.getPluginDescription(); 00670 QString maker = desc.getPluginMaker(); 00671 QString infoUrl = desc.getPluginInfoURL(); 00672 00673 QStringList oids = desc.getOutputIds(); 00674 00675 for (QStringList::const_iterator j = oids.begin(); j != oids.end(); ++j) { 00676 00677 TransformId tid = Transform::getIdentifierForPluginOutput(*i, *j); 00678 00679 if (m_transforms.find(tid) != m_transforms.end()) { 00680 #ifdef DEBUG_TRANSFORM_FACTORY 00681 cerr << "TransformFactory::populateUninstalledTransforms: " 00682 << tid << " is installed; adding info url if appropriate, skipping rest" << endl; 00683 #endif 00684 if (infoUrl != "") { 00685 if (m_transforms[tid].infoUrl == "") { 00686 m_transforms[tid].infoUrl = infoUrl; 00687 } 00688 } 00689 continue; 00690 } 00691 00692 #ifdef DEBUG_TRANSFORM_FACTORY 00693 cerr << "TransformFactory::populateUninstalledTransforms: " 00694 << "adding " << tid << endl; 00695 #endif 00696 00697 QString oname = desc.getOutputName(*j); 00698 if (oname == "") oname = *j; 00699 00700 TransformDescription td; 00701 td.type = TransformDescription::Analysis; 00702 td.category = ""; 00703 td.identifier = tid; 00704 00705 if (oids.size() == 1) { 00706 td.name = name; 00707 } else if (name != "") { 00708 td.name = tr("%1: %2").arg(name).arg(oname); 00709 } 00710 00711 QString longDescription = description; 00713 if (longDescription == "") { 00714 if (oids.size() == 1) { 00715 longDescription = tr("Extract features using \"%1\" plugin (from %2)") 00716 .arg(name).arg(maker); 00717 } else { 00718 longDescription = tr("Extract features using \"%1\" output of \"%2\" plugin (from %3)") 00719 .arg(oname).arg(name).arg(maker); 00720 } 00721 } else { 00722 if (oids.size() == 1) { 00723 longDescription = tr("%1 using \"%2\" plugin (from %3)") 00724 .arg(longDescription).arg(name).arg(maker); 00725 } else { 00726 longDescription = tr("%1 using \"%2\" output of \"%3\" plugin (from %4)") 00727 .arg(longDescription).arg(oname).arg(name).arg(maker); 00728 } 00729 } 00730 00731 td.friendlyName = name; 00732 td.description = description; 00733 td.longDescription = longDescription; 00734 td.maker = maker; 00735 td.infoUrl = infoUrl; 00736 td.units = ""; 00737 td.configurable = false; 00738 00739 m_uninstalledTransforms[tid] = td; 00740 } 00741 00742 if (m_exiting) return; 00743 } 00744 00745 m_uninstalledTransformsPopulated = true; 00746 00747 #ifdef DEBUG_TRANSFORM_FACTORY 00748 cerr << "populateUninstalledTransforms exiting" << endl; 00749 #endif 00750 } 00751 00752 Transform 00753 TransformFactory::getDefaultTransformFor(TransformId id, int rate) 00754 { 00755 Transform t; 00756 t.setIdentifier(id); 00757 if (rate != 0) t.setSampleRate(rate); 00758 00759 Vamp::PluginBase *plugin = instantiateDefaultPluginFor(id, rate); 00760 00761 if (plugin) { 00762 t.setPluginVersion(QString("%1").arg(plugin->getPluginVersion())); 00763 setParametersFromPlugin(t, plugin); 00764 makeContextConsistentWithPlugin(t, plugin); 00765 delete plugin; 00766 } 00767 00768 return t; 00769 } 00770 00771 Vamp::PluginBase * 00772 TransformFactory::instantiatePluginFor(const Transform &transform) 00773 { 00774 Vamp::PluginBase *plugin = instantiateDefaultPluginFor 00775 (transform.getIdentifier(), transform.getSampleRate()); 00776 00777 if (plugin) { 00778 setPluginParameters(transform, plugin); 00779 } 00780 00781 return plugin; 00782 } 00783 00784 Vamp::PluginBase * 00785 TransformFactory::instantiateDefaultPluginFor(TransformId identifier, int rate) 00786 { 00787 Transform t; 00788 t.setIdentifier(identifier); 00789 if (rate == 0) rate = 44100; 00790 QString pluginId = t.getPluginIdentifier(); 00791 00792 Vamp::PluginBase *plugin = 0; 00793 00794 if (t.getType() == Transform::FeatureExtraction) { 00795 00796 FeatureExtractionPluginFactory *factory = 00797 FeatureExtractionPluginFactory::instanceFor(pluginId); 00798 00799 if (factory) { 00800 plugin = factory->instantiatePlugin(pluginId, rate); 00801 } 00802 00803 } else { 00804 00805 RealTimePluginFactory *factory = 00806 RealTimePluginFactory::instanceFor(pluginId); 00807 00808 if (factory) { 00809 plugin = factory->instantiatePlugin(pluginId, 0, 0, rate, 1024, 1); 00810 } 00811 } 00812 00813 return plugin; 00814 } 00815 00816 Vamp::Plugin * 00817 TransformFactory::downcastVampPlugin(Vamp::PluginBase *plugin) 00818 { 00819 Vamp::Plugin *vp = dynamic_cast<Vamp::Plugin *>(plugin); 00820 if (!vp) { 00821 // cerr << "makeConsistentWithPlugin: not a Vamp::Plugin" << endl; 00822 vp = dynamic_cast<Vamp::PluginHostAdapter *>(plugin); 00823 } 00824 if (!vp) { 00825 // cerr << "makeConsistentWithPlugin: not a Vamp::PluginHostAdapter" << endl; 00826 vp = dynamic_cast<Vamp::HostExt::PluginWrapper *>(plugin); 00827 } 00828 if (!vp) { 00829 // cerr << "makeConsistentWithPlugin: not a Vamp::HostExt::PluginWrapper" << endl; 00830 } 00831 return vp; 00832 } 00833 00834 bool 00835 TransformFactory::haveTransform(TransformId identifier) 00836 { 00837 populateTransforms(); 00838 return (m_transforms.find(identifier) != m_transforms.end()); 00839 } 00840 00841 QString 00842 TransformFactory::getTransformName(TransformId identifier) 00843 { 00844 if (m_transforms.find(identifier) != m_transforms.end()) { 00845 return m_transforms[identifier].name; 00846 } else return ""; 00847 } 00848 00849 QString 00850 TransformFactory::getTransformFriendlyName(TransformId identifier) 00851 { 00852 if (m_transforms.find(identifier) != m_transforms.end()) { 00853 return m_transforms[identifier].friendlyName; 00854 } else return ""; 00855 } 00856 00857 QString 00858 TransformFactory::getTransformUnits(TransformId identifier) 00859 { 00860 if (m_transforms.find(identifier) != m_transforms.end()) { 00861 return m_transforms[identifier].units; 00862 } else return ""; 00863 } 00864 00865 QString 00866 TransformFactory::getTransformInfoUrl(TransformId identifier) 00867 { 00868 if (m_transforms.find(identifier) != m_transforms.end()) { 00869 return m_transforms[identifier].infoUrl; 00870 } else return ""; 00871 } 00872 00873 Vamp::Plugin::InputDomain 00874 TransformFactory::getTransformInputDomain(TransformId identifier) 00875 { 00876 Transform transform; 00877 transform.setIdentifier(identifier); 00878 00879 if (transform.getType() != Transform::FeatureExtraction) { 00880 return Vamp::Plugin::TimeDomain; 00881 } 00882 00883 Vamp::Plugin *plugin = 00884 downcastVampPlugin(instantiateDefaultPluginFor(identifier, 0)); 00885 00886 if (plugin) { 00887 Vamp::Plugin::InputDomain d = plugin->getInputDomain(); 00888 delete plugin; 00889 return d; 00890 } 00891 00892 return Vamp::Plugin::TimeDomain; 00893 } 00894 00895 bool 00896 TransformFactory::isTransformConfigurable(TransformId identifier) 00897 { 00898 if (m_transforms.find(identifier) != m_transforms.end()) { 00899 return m_transforms[identifier].configurable; 00900 } else return false; 00901 } 00902 00903 bool 00904 TransformFactory::getTransformChannelRange(TransformId identifier, 00905 int &min, int &max) 00906 { 00907 QString id = identifier.section(':', 0, 2); 00908 00909 if (FeatureExtractionPluginFactory::instanceFor(id)) { 00910 00911 Vamp::Plugin *plugin = 00912 FeatureExtractionPluginFactory::instanceFor(id)-> 00913 instantiatePlugin(id, 44100); 00914 if (!plugin) return false; 00915 00916 min = plugin->getMinChannelCount(); 00917 max = plugin->getMaxChannelCount(); 00918 delete plugin; 00919 00920 return true; 00921 00922 } else if (RealTimePluginFactory::instanceFor(id)) { 00923 00924 // don't need to instantiate 00925 00926 const RealTimePluginDescriptor *descriptor = 00927 RealTimePluginFactory::instanceFor(id)-> 00928 getPluginDescriptor(id); 00929 if (!descriptor) return false; 00930 00931 min = descriptor->audioInputPortCount; 00932 max = descriptor->audioInputPortCount; 00933 00934 return true; 00935 } 00936 00937 return false; 00938 } 00939 00940 void 00941 TransformFactory::setParametersFromPlugin(Transform &transform, 00942 Vamp::PluginBase *plugin) 00943 { 00944 Transform::ParameterMap pmap; 00945 00947 00949 00950 Vamp::PluginBase::ParameterList parameters = 00951 plugin->getParameterDescriptors(); 00952 00953 for (Vamp::PluginBase::ParameterList::const_iterator i = parameters.begin(); 00954 i != parameters.end(); ++i) { 00955 pmap[i->identifier.c_str()] = plugin->getParameter(i->identifier); 00956 // cerr << "TransformFactory::setParametersFromPlugin: parameter " 00957 // << i->identifier << " -> value " << 00958 // pmap[i->identifier.c_str()] << endl; 00959 } 00960 00961 transform.setParameters(pmap); 00962 00963 if (plugin->getPrograms().empty()) { 00964 transform.setProgram(""); 00965 } else { 00966 transform.setProgram(plugin->getCurrentProgram().c_str()); 00967 } 00968 00969 RealTimePluginInstance *rtpi = 00970 dynamic_cast<RealTimePluginInstance *>(plugin); 00971 00972 Transform::ConfigurationMap cmap; 00973 00974 if (rtpi) { 00975 00976 RealTimePluginInstance::ConfigurationPairMap configurePairs = 00977 rtpi->getConfigurePairs(); 00978 00979 for (RealTimePluginInstance::ConfigurationPairMap::const_iterator i 00980 = configurePairs.begin(); i != configurePairs.end(); ++i) { 00981 cmap[i->first.c_str()] = i->second.c_str(); 00982 } 00983 } 00984 00985 transform.setConfiguration(cmap); 00986 } 00987 00988 void 00989 TransformFactory::setPluginParameters(const Transform &transform, 00990 Vamp::PluginBase *plugin) 00991 { 00993 00995 00996 RealTimePluginInstance *rtpi = 00997 dynamic_cast<RealTimePluginInstance *>(plugin); 00998 00999 if (rtpi) { 01000 const Transform::ConfigurationMap &cmap = transform.getConfiguration(); 01001 for (Transform::ConfigurationMap::const_iterator i = cmap.begin(); 01002 i != cmap.end(); ++i) { 01003 rtpi->configure(i->first.toStdString(), i->second.toStdString()); 01004 } 01005 } 01006 01007 if (transform.getProgram() != "") { 01008 plugin->selectProgram(transform.getProgram().toStdString()); 01009 } 01010 01011 const Transform::ParameterMap &pmap = transform.getParameters(); 01012 01013 Vamp::PluginBase::ParameterList parameters = 01014 plugin->getParameterDescriptors(); 01015 01016 for (Vamp::PluginBase::ParameterList::const_iterator i = parameters.begin(); 01017 i != parameters.end(); ++i) { 01018 QString key = i->identifier.c_str(); 01019 Transform::ParameterMap::const_iterator pmi = pmap.find(key); 01020 if (pmi != pmap.end()) { 01021 plugin->setParameter(i->identifier, pmi->second); 01022 } 01023 } 01024 } 01025 01026 void 01027 TransformFactory::makeContextConsistentWithPlugin(Transform &transform, 01028 Vamp::PluginBase *plugin) 01029 { 01030 const Vamp::Plugin *vp = downcastVampPlugin(plugin); 01031 01032 if (!vp) { 01033 // time domain input for real-time effects plugin 01034 if (!transform.getBlockSize()) { 01035 if (!transform.getStepSize()) transform.setStepSize(1024); 01036 transform.setBlockSize(transform.getStepSize()); 01037 } else { 01038 transform.setStepSize(transform.getBlockSize()); 01039 } 01040 } else { 01041 Vamp::Plugin::InputDomain domain = vp->getInputDomain(); 01042 if (!transform.getStepSize()) { 01043 transform.setStepSize(vp->getPreferredStepSize()); 01044 } 01045 if (!transform.getBlockSize()) { 01046 transform.setBlockSize(vp->getPreferredBlockSize()); 01047 } 01048 if (!transform.getBlockSize()) { 01049 transform.setBlockSize(1024); 01050 } 01051 if (!transform.getStepSize()) { 01052 if (domain == Vamp::Plugin::FrequencyDomain) { 01053 // cerr << "frequency domain, step = " << blockSize/2 << endl; 01054 transform.setStepSize(transform.getBlockSize()/2); 01055 } else { 01056 // cerr << "time domain, step = " << blockSize/2 << endl; 01057 transform.setStepSize(transform.getBlockSize()); 01058 } 01059 } 01060 } 01061 } 01062 01063 QString 01064 TransformFactory::getPluginConfigurationXml(const Transform &t) 01065 { 01066 QString xml; 01067 01068 Vamp::PluginBase *plugin = instantiateDefaultPluginFor 01069 (t.getIdentifier(), 0); 01070 if (!plugin) { 01071 cerr << "TransformFactory::getPluginConfigurationXml: " 01072 << "Unable to instantiate plugin for transform \"" 01073 << t.getIdentifier() << "\"" << endl; 01074 return xml; 01075 } 01076 01077 setPluginParameters(t, plugin); 01078 01079 QTextStream out(&xml); 01080 PluginXml(plugin).toXml(out); 01081 delete plugin; 01082 01083 return xml; 01084 } 01085 01086 void 01087 TransformFactory::setParametersFromPluginConfigurationXml(Transform &t, 01088 QString xml) 01089 { 01090 Vamp::PluginBase *plugin = instantiateDefaultPluginFor 01091 (t.getIdentifier(), 0); 01092 if (!plugin) { 01093 cerr << "TransformFactory::setParametersFromPluginConfigurationXml: " 01094 << "Unable to instantiate plugin for transform \"" 01095 << t.getIdentifier() << "\"" << endl; 01096 return; 01097 } 01098 01099 PluginXml(plugin).setParametersFromXml(xml); 01100 setParametersFromPlugin(t, plugin); 01101 delete plugin; 01102 } 01103 01104 TransformFactory::SearchResults 01105 TransformFactory::search(QString keyword) 01106 { 01107 QStringList keywords; 01108 keywords << keyword; 01109 return search(keywords); 01110 } 01111 01112 TransformFactory::SearchResults 01113 TransformFactory::search(QStringList keywords) 01114 { 01115 populateTransforms(); 01116 01117 if (keywords.size() > 1) { 01118 // Additional score for all keywords in a row 01119 keywords.push_back(keywords.join(" ")); 01120 } 01121 01122 SearchResults results; 01123 TextMatcher matcher; 01124 01125 for (TransformDescriptionMap::const_iterator i = m_transforms.begin(); 01126 i != m_transforms.end(); ++i) { 01127 01128 TextMatcher::Match match; 01129 01130 match.key = i->first; 01131 01132 matcher.test(match, keywords, 01133 getTransformTypeName(i->second.type), 01134 tr("Plugin type"), 5); 01135 01136 matcher.test(match, keywords, i->second.category, tr("Category"), 20); 01137 matcher.test(match, keywords, i->second.identifier, tr("System Identifier"), 6); 01138 matcher.test(match, keywords, i->second.name, tr("Name"), 30); 01139 matcher.test(match, keywords, i->second.description, tr("Description"), 20); 01140 matcher.test(match, keywords, i->second.maker, tr("Maker"), 10); 01141 matcher.test(match, keywords, i->second.units, tr("Units"), 10); 01142 01143 if (match.score > 0) results[i->first] = match; 01144 } 01145 01146 if (!m_uninstalledTransformsMutex.tryLock()) { 01147 // uninstalled transforms are being populated; this may take some time, 01148 // and they aren't critical, but we will speed them up if necessary 01149 cerr << "TransformFactory::search: Uninstalled transforms mutex is held, skipping" << endl; 01150 m_populatingSlowly = false; 01151 return results; 01152 } 01153 01154 if (!m_uninstalledTransformsPopulated) { 01155 cerr << "WARNING: TransformFactory::search: Uninstalled transforms are not populated yet" << endl 01156 << "and are not being populated either -- was the thread not started correctly?" << endl; 01157 m_uninstalledTransformsMutex.unlock(); 01158 return results; 01159 } 01160 01161 m_uninstalledTransformsMutex.unlock(); 01162 01163 for (TransformDescriptionMap::const_iterator i = m_uninstalledTransforms.begin(); 01164 i != m_uninstalledTransforms.end(); ++i) { 01165 01166 TextMatcher::Match match; 01167 01168 match.key = i->first; 01169 01170 matcher.test(match, keywords, 01171 getTransformTypeName(i->second.type), 01172 tr("Plugin type"), 2); 01173 01174 matcher.test(match, keywords, i->second.category, tr("Category"), 10); 01175 matcher.test(match, keywords, i->second.identifier, tr("System Identifier"), 3); 01176 matcher.test(match, keywords, i->second.name, tr("Name"), 15); 01177 matcher.test(match, keywords, i->second.description, tr("Description"), 10); 01178 matcher.test(match, keywords, i->second.maker, tr("Maker"), 5); 01179 matcher.test(match, keywords, i->second.units, tr("Units"), 5); 01180 01181 if (match.score > 0) results[i->first] = match; 01182 } 01183 01184 return results; 01185 } 01186