TransformFactory.cpp
Go to the documentation of this file.
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2 
3 /*
4  Sonic Visualiser
5  An audio file viewer and annotation editor.
6  Centre for Digital Music, Queen Mary, University of London.
7  This file copyright 2006 Chris Cannam and QMUL.
8 
9  This program is free software; you can redistribute it and/or
10  modify it under the terms of the GNU General Public License as
11  published by the Free Software Foundation; either version 2 of the
12  License, or (at your option) any later version. See the file
13  COPYING included with this distribution for more information.
14 */
15 
16 #include "TransformFactory.h"
17 
19 
22 #include "plugin/PluginXml.h"
23 
24 #include <vamp-hostsdk/Plugin.h>
25 #include <vamp-hostsdk/PluginHostAdapter.h>
26 #include <vamp-hostsdk/PluginWrapper.h>
27 
28 #include "rdf/PluginRDFIndexer.h"
30 
31 #include "base/XmlExportable.h"
32 
33 #include <iostream>
34 #include <set>
35 #include <functional>
36 
37 #include <QRegExp>
38 #include <QTextStream>
39 
40 #include "base/Thread.h"
41 
42 //#define DEBUG_TRANSFORM_FACTORY 1
43 
46 
49 {
50  return m_instance;
51 }
52 
53 void
55 {
56  SVDEBUG << "TransformFactory::deleteInstance called" << endl;
57  delete m_instance;
58  m_instance = nullptr;
59 }
60 
62  m_transformsPopulated(false),
64  m_thread(nullptr),
65  m_exiting(false),
66  m_populatingSlowly(false)
67 {
68 }
69 
71 {
72  m_exiting = true;
73  if (m_thread) {
74 #ifdef DEBUG_TRANSFORM_FACTORY
75  SVDEBUG << "TransformFactory::~TransformFactory: waiting on thread" << endl;
76 #endif
77  m_thread->wait();
78  delete m_thread;
79 #ifdef DEBUG_TRANSFORM_FACTORY
80  SVDEBUG << "TransformFactory::~TransformFactory: waited and done" << endl;
81 #endif
82  }
83 }
84 
85 void
87 {
89 
90  if (m_thread) {
92  return;
93  }
95 
97 
98  m_thread->start();
99 }
100 
101 void
103 {
104  m_factory->m_populatingSlowly = true;
105  while (!m_factory->havePopulated()) {
106  sleep(1);
107  }
108  m_factory->populateUninstalledTransforms();
109 }
110 
113 {
115 
116  std::set<TransformDescription> dset;
117  for (auto i = m_transforms.begin(); i != m_transforms.end(); ++i) {
118 #ifdef DEBUG_TRANSFORM_FACTORY
119  cerr << "inserting transform into set: id = " << i->second.identifier << " (" << i->second.name << ")" << endl;
120 #endif
121  dset.insert(i->second);
122  }
123 
124  TransformList list;
125  for (auto i = dset.begin(); i != dset.end(); ++i) {
126 #ifdef DEBUG_TRANSFORM_FACTORY
127  cerr << "inserting transform into list: id = " << i->identifier << " (" << i->name << ")" << endl;
128 #endif
129  list.push_back(*i);
130  }
131 
132  return list;
133 }
134 
137 {
139 
140  if (m_transforms.find(id) == m_transforms.end()) {
141  return TransformDescription();
142  }
143 
144  return m_transforms[id];
145 }
146 
147 bool
149 {
151  return !m_transforms.empty();
152 }
153 
156 {
157  m_populatingSlowly = false;
159 
160  std::set<TransformDescription> dset;
161  for (auto i = m_uninstalledTransforms.begin();
162  i != m_uninstalledTransforms.end(); ++i) {
163 #ifdef DEBUG_TRANSFORM_FACTORY
164  cerr << "inserting transform into set: id = " << i->second.identifier << endl;
165 #endif
166  dset.insert(i->second);
167  }
168 
169  TransformList list;
170  for (auto i = dset.begin(); i != dset.end(); ++i) {
171 #ifdef DEBUG_TRANSFORM_FACTORY
172  cerr << "inserting transform into uninstalled list: id = " << i->identifier << endl;
173 #endif
174  list.push_back(*i);
175  }
176 
177  return list;
178 }
179 
182 {
183  m_populatingSlowly = false;
185 
186  if (m_uninstalledTransforms.find(id) == m_uninstalledTransforms.end()) {
187  return TransformDescription();
188  }
189 
190  return m_uninstalledTransforms[id];
191 }
192 
193 bool
195 {
196  if (waitForCheckToComplete) {
198  } else {
199  if (!m_uninstalledTransformsMutex.tryLock()) {
200  return false;
201  }
204  return false;
205  }
207  }
208 
209  return !m_uninstalledTransforms.empty();
210 }
211 
214 {
216 
217  if (m_transforms.find(id) != m_transforms.end()) {
218  return TransformInstalled;
219  }
220 
221  if (!m_uninstalledTransformsMutex.tryLock()) {
222  // uninstalled transforms are being populated; this may take some time,
223  // and they aren't critical
224  return TransformUnknown;
225  }
226 
229  m_populatingSlowly = false;
232  }
233 
234  if (m_uninstalledTransforms.find(id) != m_uninstalledTransforms.end()) {
236  return TransformNotInstalled;
237  }
238 
240  return TransformUnknown;
241 }
242 
243 
244 std::vector<TransformDescription::Type>
246 {
248 
249  std::set<TransformDescription::Type> types;
250  for (auto i = m_transforms.begin(); i != m_transforms.end(); ++i) {
251  types.insert(i->second.type);
252  }
253 
254  std::vector<TransformDescription::Type> rv;
255  for (auto i = types.begin(); i != types.end(); ++i) {
256  rv.push_back(*i);
257  }
258 
259  return rv;
260 }
261 
262 std::vector<QString>
264 {
266 
267  std::set<QString, std::function<bool(QString, QString)>>
269 
270  for (auto i = m_transforms.begin(); i != m_transforms.end(); ++i) {
271  if (i->second.type == transformType) {
272  categories.insert(i->second.category);
273  }
274  }
275 
276  bool haveEmpty = false;
277 
278  std::vector<QString> rv;
279  for (auto i = categories.begin(); i != categories.end(); ++i) {
280  if (*i != "") rv.push_back(*i);
281  else haveEmpty = true;
282  }
283 
284  if (haveEmpty) rv.push_back(""); // make sure empty category sorts last
285 
286  return rv;
287 }
288 
289 std::vector<QString>
291 {
293 
294  std::set<QString, std::function<bool(QString, QString)>>
296 
297  for (auto i = m_transforms.begin(); i != m_transforms.end(); ++i) {
298  if (i->second.type == transformType) {
299  makers.insert(i->second.maker);
300  }
301  }
302 
303  bool haveEmpty = false;
304 
305  std::vector<QString> rv;
306  for (auto i = makers.begin(); i != makers.end(); ++i) {
307  if (*i != "") rv.push_back(*i);
308  else haveEmpty = true;
309  }
310 
311  if (haveEmpty) rv.push_back(""); // make sure empty category sorts last
312 
313  return rv;
314 }
315 
316 QString
318 {
319  switch (type) {
320  case TransformDescription::Analysis: return tr("Analysis");
321  case TransformDescription::Effects: return tr("Effects");
322  case TransformDescription::EffectsData: return tr("Effects Data");
323  case TransformDescription::Generator: return tr("Generator");
324  case TransformDescription::UnknownType: return tr("Other");
325  }
326  return tr("Other");
327 }
328 
329 bool
331 {
332  MutexLocker locker(&m_transformsMutex, "TransformFactory::havePopulated");
333  return m_transformsPopulated;
334 }
335 
336 void
338 {
340  "TransformFactory::populateTransforms");
341  if (m_transformsPopulated) {
342  return;
343  }
344 
345  TransformDescriptionMap transforms;
346 
348  if (m_exiting) return;
349  populateRealTimePlugins(transforms);
350  if (m_exiting) return;
351 
352  // disambiguate plugins with similar names
353 
354  std::map<QString, int> names;
355  std::map<QString, QString> pluginSources;
356  std::map<QString, QString> pluginMakers;
357 
358  for (TransformDescriptionMap::iterator i = transforms.begin();
359  i != transforms.end(); ++i) {
360 
361  TransformDescription desc = i->second;
362 
363  QString td = desc.name;
364  QString tn = td.section(": ", 0, 0);
365  QString pn = desc.identifier.section(":", 1, 1);
366 
367  if (pluginSources.find(tn) != pluginSources.end()) {
368  if (pluginSources[tn] != pn && pluginMakers[tn] != desc.maker) {
369  ++names[tn];
370  }
371  } else {
372  ++names[tn];
373  pluginSources[tn] = pn;
374  pluginMakers[tn] = desc.maker;
375  }
376  }
377 
378  std::map<QString, int> counts;
379  m_transforms.clear();
380 
381  for (TransformDescriptionMap::iterator i = transforms.begin();
382  i != transforms.end(); ++i) {
383 
384  TransformDescription desc = i->second;
385  QString identifier = desc.identifier;
386  QString maker = desc.maker;
387 
388  QString td = desc.name;
389  QString tn = td.section(": ", 0, 0);
390  QString to = td.section(": ", 1);
391 
392  if (names[tn] > 1) {
393  maker.replace(QRegExp(tr(" [\\(<].*$")), "");
394  tn = QString("%1 [%2]").arg(tn).arg(maker);
395  }
396 
397  if (to != "") {
398  desc.name = QString("%1: %2").arg(tn).arg(to);
399  } else {
400  desc.name = tn;
401  }
402 
403  m_transforms[identifier] = desc;
404  }
405 
406  m_transformsPopulated = true;
407 
408 #ifdef DEBUG_TRANSFORM_FACTORY
409  SVCERR << "populateTransforms exiting" << endl;
410 #endif
411 
412  emit transformsPopulated();
413 }
414 
415 void
417 {
420 
421  QString errorMessage;
422  std::vector<QString> plugs = factory->getPluginIdentifiers(errorMessage);
423  if (errorMessage != "") {
424  m_errorString = tr("Failed to list Vamp plugins: %1").arg(errorMessage);
425  }
426 
427  if (m_exiting) return;
428 
429  for (int i = 0; in_range_for(plugs, i); ++i) {
430 
431  QString pluginId = plugs[i];
432 
433  piper_vamp::PluginStaticData psd = factory->getPluginStaticData(pluginId);
434 
435  if (psd.pluginKey == "") {
436  cerr << "WARNING: TransformFactory::populateTransforms: No plugin static data available for instance " << pluginId << endl;
437  continue;
438  }
439 
440  QString pluginName = QString::fromStdString(psd.basic.name);
441  QString category = factory->getPluginCategory(pluginId);
442 
443  const auto &basicOutputs = psd.basicOutputInfo;
444 
445  for (const auto &o: basicOutputs) {
446 
447  QString outputName = QString::fromStdString(o.name);
448 
449  QString transformId = QString("%1:%2")
450  .arg(pluginId).arg(QString::fromStdString(o.identifier));
451 
452  QString userName;
453  QString friendlyName;
455  QString description = QString::fromStdString(psd.basic.description);
456  QString maker = QString::fromStdString(psd.maker);
457  if (maker == "") maker = tr("<unknown maker>");
458 
459  QString longDescription = description;
460 
461  if (longDescription == "") {
462  if (basicOutputs.size() == 1) {
463  longDescription = tr("Extract features using \"%1\" plugin (from %2)")
464  .arg(pluginName).arg(maker);
465  } else {
466  longDescription = tr("Extract features using \"%1\" output of \"%2\" plugin (from %3)")
467  .arg(outputName).arg(pluginName).arg(maker);
468  }
469  } else {
470  if (basicOutputs.size() == 1) {
471  longDescription = tr("%1 using \"%2\" plugin (from %3)")
472  .arg(longDescription).arg(pluginName).arg(maker);
473  } else {
474  longDescription = tr("%1 using \"%2\" output of \"%3\" plugin (from %4)")
475  .arg(longDescription).arg(outputName).arg(pluginName).arg(maker);
476  }
477  }
478 
479  if (basicOutputs.size() == 1) {
480  userName = pluginName;
481  friendlyName = pluginName;
482  } else {
483  userName = QString("%1: %2").arg(pluginName).arg(outputName);
484  friendlyName = outputName;
485  }
486 
487  bool configurable = (!psd.programs.empty() ||
488  !psd.parameters.empty());
489 
490 #ifdef DEBUG_TRANSFORM_FACTORY
491  cerr << "Feature extraction plugin transform: " << transformId << " friendly name: " << friendlyName << endl;
492 #endif
493 
494  transforms[transformId] =
496  category,
497  transformId,
498  userName,
499  friendlyName,
500  description,
501  longDescription,
502  maker,
504  "",
505  configurable);
506  }
507  }
508 }
509 
510 void
512 {
513  std::vector<QString> plugs =
515  if (m_exiting) return;
516 
517  static QRegExp unitRE("[\\[\\(]([A-Za-z0-9/]+)[\\)\\]]$");
518 
519  for (int i = 0; in_range_for(plugs, i); ++i) {
520 
521  QString pluginId = plugs[i];
522 
523  RealTimePluginFactory *factory =
525 
526  if (!factory) {
527  cerr << "WARNING: TransformFactory::populateTransforms: No real time plugin factory for instance " << pluginId << endl;
528  continue;
529  }
530 
531  RealTimePluginDescriptor descriptor =
532  factory->getPluginDescriptor(pluginId);
533 
534  if (descriptor.name == "") {
535  cerr << "WARNING: TransformFactory::populateTransforms: Failed to query plugin " << pluginId << endl;
536  continue;
537  }
538 
540 // descriptor.audioInputPortCount == 0) continue;
541 
542 // cout << "TransformFactory::populateRealTimePlugins: plugin " << pluginId << " has " << descriptor.controlOutputPortCount << " control output ports, " << descriptor.audioOutputPortCount << " audio outputs, " << descriptor.audioInputPortCount << " audio inputs" << endl;
543 
544  QString pluginName = descriptor.name.c_str();
545  QString category = factory->getPluginCategory(pluginId);
546  bool configurable = (descriptor.parameterCount > 0);
547  QString maker = descriptor.maker.c_str();
548  if (maker == "") maker = tr("<unknown maker>");
549 
550  if (descriptor.audioInputPortCount > 0) {
551 
552  for (int j = 0; j < (int)descriptor.controlOutputPortCount; ++j) {
553 
554  QString transformId = QString("%1:%2").arg(pluginId).arg(j);
555  QString userName;
556  QString units;
557  QString portName;
558 
559  if (j < (int)descriptor.controlOutputPortNames.size() &&
560  descriptor.controlOutputPortNames[j] != "") {
561 
562  portName = descriptor.controlOutputPortNames[j].c_str();
563 
564  userName = tr("%1: %2")
565  .arg(pluginName)
566  .arg(portName);
567 
568  if (unitRE.indexIn(portName) >= 0) {
569  units = unitRE.cap(1);
570  }
571 
572  } else if (descriptor.controlOutputPortCount > 1) {
573 
574  userName = tr("%1: Output %2")
575  .arg(pluginName)
576  .arg(j + 1);
577 
578  } else {
579 
580  userName = pluginName;
581  }
582 
583  QString description;
584 
585  if (portName != "") {
586  description = tr("Extract \"%1\" data output from \"%2\" effect plugin (from %3)")
587  .arg(portName)
588  .arg(pluginName)
589  .arg(maker);
590  } else {
591  description = tr("Extract data output %1 from \"%2\" effect plugin (from %3)")
592  .arg(j + 1)
593  .arg(pluginName)
594  .arg(maker);
595  }
596 
597  transforms[transformId] =
599  category,
600  transformId,
601  userName,
602  userName,
603  "",
604  description,
605  maker,
606  units,
607  configurable);
608  }
609  }
610 
611  if (!descriptor.isSynth || descriptor.audioInputPortCount > 0) {
612 
613  if (descriptor.audioOutputPortCount > 0) {
614 
615  QString transformId = QString("%1:A").arg(pluginId);
617 
618  QString description = tr("Transform audio signal with \"%1\" effect plugin (from %2)")
619  .arg(pluginName)
620  .arg(maker);
621 
622  if (descriptor.audioInputPortCount == 0) {
624  QString description = tr("Generate audio signal using \"%1\" plugin (from %2)")
625  .arg(pluginName)
626  .arg(maker);
627  }
628 
629  transforms[transformId] =
631  category,
632  transformId,
633  pluginName,
634  pluginName,
635  "",
636  description,
637  maker,
638  "",
639  configurable);
640  }
641  }
642  }
643 }
644 
645 void
647 {
648  if (m_exiting) return;
649 
651  if (m_exiting) return;
652 
654  "TransformFactory::populateUninstalledTransforms");
656 
658  if (m_exiting) return;
659 
661 
663 
664  QStringList ids = PluginRDFIndexer::getInstance()->getIndexedPluginIds();
665 
666  for (QStringList::const_iterator i = ids.begin(); i != ids.end(); ++i) {
667 
668  PluginRDFDescription desc(*i);
669 
670  QString name = desc.getPluginName();
671 #ifdef DEBUG_TRANSFORM_FACTORY
672  if (name == "") {
673  SVCERR << "TransformFactory::populateUninstalledTransforms: "
674  << "No name available for plugin " << *i
675  << ", skipping" << endl;
676  continue;
677  }
678 #endif
679 
680  QString description = desc.getPluginDescription();
681  QString maker = desc.getPluginMaker();
682  Provider provider = desc.getPluginProvider();
683 
684  QStringList oids = desc.getOutputIds();
685 
686  for (QStringList::const_iterator j = oids.begin(); j != oids.end(); ++j) {
687 
689 
690  if (m_transforms.find(tid) != m_transforms.end()) {
691 #ifdef DEBUG_TRANSFORM_FACTORY
692  SVCERR << "TransformFactory::populateUninstalledTransforms: "
693  << tid << " is installed; adding provider if present, skipping rest" << endl;
694 #endif
695  if (provider != Provider()) {
696  if (m_transforms[tid].provider == Provider()) {
697  m_transforms[tid].provider = provider;
698  }
699  }
700  continue;
701  }
702 
703 #ifdef DEBUG_TRANSFORM_FACTORY
704  SVCERR << "TransformFactory::populateUninstalledTransforms: "
705  << "adding " << tid << endl;
706 #endif
707 
708  QString oname = desc.getOutputName(*j);
709  if (oname == "") oname = *j;
710 
713  td.category = "";
714  td.identifier = tid;
715 
716  if (oids.size() == 1) {
717  td.name = name;
718  } else if (name != "") {
719  td.name = tr("%1: %2").arg(name).arg(oname);
720  }
721 
722  QString longDescription = description;
724  if (longDescription == "") {
725  if (oids.size() == 1) {
726  longDescription = tr("Extract features using \"%1\" plugin (from %2)")
727  .arg(name).arg(maker);
728  } else {
729  longDescription = tr("Extract features using \"%1\" output of \"%2\" plugin (from %3)")
730  .arg(oname).arg(name).arg(maker);
731  }
732  } else {
733  if (oids.size() == 1) {
734  longDescription = tr("%1 using \"%2\" plugin (from %3)")
735  .arg(longDescription).arg(name).arg(maker);
736  } else {
737  longDescription = tr("%1 using \"%2\" output of \"%3\" plugin (from %4)")
738  .arg(longDescription).arg(oname).arg(name).arg(maker);
739  }
740  }
741 
742  td.friendlyName = name;
743  td.description = description;
744  td.longDescription = longDescription;
745  td.maker = maker;
746  td.provider = provider;
747  td.units = "";
748  td.configurable = false;
749 
750  m_uninstalledTransforms[tid] = td;
751  }
752 
753  if (m_exiting) return;
754  }
755 
757 
758 #ifdef DEBUG_TRANSFORM_FACTORY
759  SVCERR << "populateUninstalledTransforms exiting" << endl;
760 #endif
761 
763 }
764 
765 Transform
767 {
768  Transform t;
769  t.setIdentifier(id);
770  if (rate != 0) t.setSampleRate(rate);
771 
772  SVDEBUG << "TransformFactory::getDefaultTransformFor: identifier \""
773  << id << "\"" << endl;
774 
775  std::shared_ptr<Vamp::PluginBase> plugin = instantiateDefaultPluginFor(id, rate);
776 
777  if (plugin) {
778  t.setPluginVersion(QString("%1").arg(plugin->getPluginVersion()));
779  setParametersFromPlugin(t, plugin);
781  }
782 
783  return t;
784 }
785 
786 std::shared_ptr<Vamp::PluginBase>
788 {
789  SVDEBUG << "TransformFactory::instantiatePluginFor: identifier \""
790  << transform.getIdentifier() << "\"" << endl;
791 
792  std::shared_ptr<Vamp::PluginBase> plugin = instantiateDefaultPluginFor
793  (transform.getIdentifier(), transform.getSampleRate());
794 
795  if (plugin) {
796  setPluginParameters(transform, plugin);
797  }
798 
799  return plugin;
800 }
801 
802 std::shared_ptr<Vamp::PluginBase>
804  sv_samplerate_t rate)
805 {
807 
808  Transform t;
809  t.setIdentifier(identifier);
810  if (rate == 0) rate = 44100.0;
811  QString pluginId = t.getPluginIdentifier();
812 
813  std::shared_ptr<Vamp::PluginBase> plugin = nullptr;
814 
816 
817  SVDEBUG << "TransformFactory::instantiateDefaultPluginFor: identifier \""
818  << identifier << "\" is a feature extraction transform" << endl;
819 
822 
823  if (factory) {
824  plugin = factory->instantiatePlugin(pluginId, rate);
825  }
826 
827  } else if (t.getType() == Transform::RealTimeEffect) {
828 
829  SVDEBUG << "TransformFactory::instantiateDefaultPluginFor: identifier \""
830  << identifier << "\" is a real-time transform" << endl;
831 
832  RealTimePluginFactory *factory =
834 
835  if (factory) {
836  plugin = factory->instantiatePlugin(pluginId, 0, 0, rate, 1024, 1);
837  }
838 
839  } else {
840  SVDEBUG << "TransformFactory: ERROR: transform id \""
841  << identifier << "\" is of unknown type" << endl;
842  }
843 
844  return plugin;
845 }
846 
847 bool
849 {
851  return (m_transforms.find(identifier) != m_transforms.end());
852 }
853 
854 QString
856 {
857  if (m_transforms.find(identifier) != m_transforms.end()) {
858  return m_transforms[identifier].name;
859  } else return "";
860 }
861 
862 QString
864 {
865  if (m_transforms.find(identifier) != m_transforms.end()) {
866  return m_transforms[identifier].friendlyName;
867  } else return "";
868 }
869 
870 QString
872 {
873  if (m_transforms.find(identifier) != m_transforms.end()) {
874  return m_transforms[identifier].units;
875  } else return "";
876 }
877 
878 Provider
880 {
881  if (m_transforms.find(identifier) != m_transforms.end()) {
882  return m_transforms[identifier].provider;
883  } else return {};
884 }
885 
886 Vamp::Plugin::InputDomain
888 {
889  Transform transform;
890  transform.setIdentifier(identifier);
891 
892  SVDEBUG << "TransformFactory::getTransformInputDomain: identifier \""
893  << identifier << "\"" << endl;
894 
895  if (transform.getType() != Transform::FeatureExtraction) {
896  return Vamp::Plugin::TimeDomain;
897  }
898 
899  std::shared_ptr<Vamp::Plugin> plugin =
900  std::dynamic_pointer_cast<Vamp::Plugin>
901  (instantiateDefaultPluginFor(identifier, 0));
902 
903  if (plugin) {
904  Vamp::Plugin::InputDomain d = plugin->getInputDomain();
905  return d;
906  }
907 
908  return Vamp::Plugin::TimeDomain;
909 }
910 
911 bool
913 {
914  if (m_transforms.find(identifier) != m_transforms.end()) {
915  return m_transforms[identifier].configurable;
916  } else return false;
917 }
918 
919 bool
921  int &min, int &max)
922 {
923  QString id = identifier.section(':', 0, 2);
924 
926 
927  RealTimePluginDescriptor descriptor =
929  getPluginDescriptor(id);
930  if (descriptor.name == "") {
931  return false;
932  }
933 
934  min = descriptor.audioInputPortCount;
935  max = descriptor.audioInputPortCount;
936 
937  return true;
938 
939  } else {
940 
942  getPluginStaticData(id);
943  if (psd.pluginKey == "") return false;
944 
945  min = (int)psd.minChannelCount;
946  max = (int)psd.maxChannelCount;
947 
948  return true;
949  }
950 
951  return false;
952 }
953 
954 void
956  std::shared_ptr<Vamp::PluginBase> plugin)
957 {
959 
961 
963 
964  Vamp::PluginBase::ParameterList parameters =
965  plugin->getParameterDescriptors();
966 
967  for (Vamp::PluginBase::ParameterList::const_iterator i = parameters.begin();
968  i != parameters.end(); ++i) {
969  pmap[i->identifier.c_str()] = plugin->getParameter(i->identifier);
970 // cerr << "TransformFactory::setParametersFromPlugin: parameter "
971 // << i->identifier << " -> value " <<
972 // pmap[i->identifier.c_str()] << endl;
973  }
974 
975  transform.setParameters(pmap);
976 
977  if (plugin->getPrograms().empty()) {
978  transform.setProgram("");
979  } else {
980  transform.setProgram(plugin->getCurrentProgram().c_str());
981  }
982 
983  std::shared_ptr<RealTimePluginInstance> rtpi =
984  std::dynamic_pointer_cast<RealTimePluginInstance>(plugin);
985 
987 
988  if (rtpi) {
989 
991  rtpi->getConfigurePairs();
992 
993  for (RealTimePluginInstance::ConfigurationPairMap::const_iterator i
994  = configurePairs.begin(); i != configurePairs.end(); ++i) {
995  cmap[i->first.c_str()] = i->second.c_str();
996  }
997  }
998 
999  transform.setConfiguration(cmap);
1000 }
1001 
1002 void
1004  std::shared_ptr<Vamp::PluginBase> plugin)
1005 {
1007 
1009 
1010  std::shared_ptr<RealTimePluginInstance> rtpi =
1011  std::dynamic_pointer_cast<RealTimePluginInstance>(plugin);
1012 
1013  if (rtpi) {
1014  const Transform::ConfigurationMap &cmap = transform.getConfiguration();
1015  for (Transform::ConfigurationMap::const_iterator i = cmap.begin();
1016  i != cmap.end(); ++i) {
1017  rtpi->configure(i->first.toStdString(), i->second.toStdString());
1018  }
1019  }
1020 
1021  if (transform.getProgram() != "") {
1022  plugin->selectProgram(transform.getProgram().toStdString());
1023  }
1024 
1025  const Transform::ParameterMap &pmap = transform.getParameters();
1026 
1027  Vamp::PluginBase::ParameterList parameters =
1028  plugin->getParameterDescriptors();
1029 
1030  for (Vamp::PluginBase::ParameterList::const_iterator i = parameters.begin();
1031  i != parameters.end(); ++i) {
1032  QString key = i->identifier.c_str();
1033  Transform::ParameterMap::const_iterator pmi = pmap.find(key);
1034  if (pmi != pmap.end()) {
1035  plugin->setParameter(i->identifier, pmi->second);
1036  }
1037  }
1038 }
1039 
1040 void
1042  std::shared_ptr<Vamp::PluginBase> plugin)
1043 {
1044  std::shared_ptr<Vamp::Plugin> vp =
1045  std::dynamic_pointer_cast<Vamp::Plugin>(plugin);
1046 
1047  if (!vp) {
1048  // time domain input for real-time effects plugin
1049  if (!transform.getBlockSize()) {
1050  if (!transform.getStepSize()) transform.setStepSize(1024);
1051  transform.setBlockSize(transform.getStepSize());
1052  } else {
1053  transform.setStepSize(transform.getBlockSize());
1054  }
1055  } else {
1056  Vamp::Plugin::InputDomain domain = vp->getInputDomain();
1057  if (!transform.getStepSize()) {
1058  transform.setStepSize((int)vp->getPreferredStepSize());
1059  }
1060  if (!transform.getBlockSize()) {
1061  transform.setBlockSize((int)vp->getPreferredBlockSize());
1062  }
1063  if (!transform.getBlockSize()) {
1064  transform.setBlockSize(1024);
1065  }
1066  if (!transform.getStepSize()) {
1067  if (domain == Vamp::Plugin::FrequencyDomain) {
1068 // cerr << "frequency domain, step = " << blockSize/2 << endl;
1069  transform.setStepSize(transform.getBlockSize()/2);
1070  } else {
1071 // cerr << "time domain, step = " << blockSize/2 << endl;
1072  transform.setStepSize(transform.getBlockSize());
1073  }
1074  }
1075  }
1076 }
1077 
1078 QString
1080 {
1081  QString xml;
1082 
1083  SVDEBUG << "TransformFactory::getPluginConfigurationXml: identifier \""
1084  << t.getIdentifier() << "\"" << endl;
1085 
1086  auto plugin = instantiateDefaultPluginFor(t.getIdentifier(), 0);
1087  if (!plugin) {
1088  SVDEBUG << "TransformFactory::getPluginConfigurationXml: "
1089  << "Unable to instantiate plugin for transform \""
1090  << t.getIdentifier() << "\"" << endl;
1091  return xml;
1092  }
1093 
1094  setPluginParameters(t, plugin);
1095 
1096  QTextStream out(&xml);
1097  PluginXml(plugin).toXml(out);
1098 
1099  return xml;
1100 }
1101 
1102 void
1104  QString xml)
1105 {
1106  SVDEBUG << "TransformFactory::setParametersFromPluginConfigurationXml: identifier \""
1107  << t.getIdentifier() << "\"" << endl;
1108 
1109  auto plugin = instantiateDefaultPluginFor(t.getIdentifier(), 0);
1110  if (!plugin) {
1111  SVDEBUG << "TransformFactory::setParametersFromPluginConfigurationXml: "
1112  << "Unable to instantiate plugin for transform \""
1113  << t.getIdentifier() << "\"" << endl;
1114  return;
1115  }
1116 
1117  PluginXml(plugin).setParametersFromXml(xml);
1118  setParametersFromPlugin(t, plugin);
1119 }
1120 
1123 {
1124  QStringList keywords;
1125  keywords << keyword;
1126  return search(keywords);
1127 }
1128 
1130 TransformFactory::search(QStringList keywords)
1131 {
1133 
1134  SearchResults results = searchUnadjusted(keywords);
1135 
1136  if (keywords.size() > 1) {
1137 
1138  // If there are any hits for all keywords in a row, put them
1139  // in (replacing previous hits for the same transforms) but
1140  // ensure they score more than any of the others
1141 
1142  int maxScore = 0;
1143  for (auto r: results) {
1144  if (r.second.score > maxScore) {
1145  maxScore = r.second.score;
1146  }
1147  }
1148 
1149  QStringList oneBigKeyword;
1150  oneBigKeyword << keywords.join(" ");
1151  SearchResults oneBigKeywordResults = searchUnadjusted(oneBigKeyword);
1152  for (auto r: oneBigKeywordResults) {
1153  results[r.first] = r.second;
1154  results[r.first].score += maxScore;
1155  }
1156  }
1157 
1158  return results;
1159 }
1160 
1163 {
1164  SearchResults results;
1165  TextMatcher matcher;
1166 
1167  for (TransformDescriptionMap::const_iterator i = m_transforms.begin();
1168  i != m_transforms.end(); ++i) {
1169 
1170  TextMatcher::Match match;
1171 
1172  match.key = i->first;
1173 
1174  matcher.test(match, keywords,
1175  getTransformTypeName(i->second.type),
1176  tr("Plugin type"), 5);
1177 
1178  matcher.test(match, keywords, i->second.category, tr("Category"), 20);
1179  matcher.test(match, keywords, i->second.identifier, tr("System Identifier"), 6);
1180  matcher.test(match, keywords, i->second.name, tr("Name"), 30);
1181  matcher.test(match, keywords, i->second.description, tr("Description"), 20);
1182  matcher.test(match, keywords, i->second.maker, tr("Maker"), 10);
1183  matcher.test(match, keywords, i->second.units, tr("Units"), 10);
1184 
1185  if (match.score > 0) results[i->first] = match;
1186  }
1187 
1188  if (!m_uninstalledTransformsMutex.tryLock()) {
1189  // uninstalled transforms are being populated; this may take some time,
1190  // and they aren't critical, but we will speed them up if necessary
1191  SVDEBUG << "TransformFactory::search: Uninstalled transforms mutex is held, skipping" << endl;
1192  m_populatingSlowly = false;
1193  return results;
1194  }
1195 
1197  SVDEBUG << "WARNING: TransformFactory::search: Uninstalled transforms are not populated yet" << endl
1198  << "and are not being populated either -- was the thread not started correctly?" << endl;
1200  return results;
1201  }
1202 
1204 
1205  for (TransformDescriptionMap::const_iterator i = m_uninstalledTransforms.begin();
1206  i != m_uninstalledTransforms.end(); ++i) {
1207 
1208  TextMatcher::Match match;
1209 
1210  match.key = i->first;
1211 
1212  matcher.test(match, keywords,
1213  getTransformTypeName(i->second.type),
1214  tr("Plugin type"), 2);
1215 
1216  matcher.test(match, keywords, i->second.category, tr("Category"), 10);
1217  matcher.test(match, keywords, i->second.identifier, tr("System Identifier"), 3);
1218  matcher.test(match, keywords, i->second.name, tr("Name"), 15);
1219  matcher.test(match, keywords, i->second.description, tr("Description"), 10);
1220  matcher.test(match, keywords, i->second.maker, tr("Maker"), 5);
1221  matcher.test(match, keywords, i->second.units, tr("Units"), 5);
1222 
1223  if (match.score > 0) results[i->first] = match;
1224  }
1225 
1226 #ifdef DEBUG_TRANSFORM_FACTORY
1227  SVCERR << "TransformFactory::search: keywords are: " << keywords.join(", ")
1228  << endl;
1229  int n = int(results.size()), i = 1;
1230  SVCERR << "TransformFactory::search: results (" << n << "):" << endl;
1231 
1232  for (const auto &r: results) {
1233  QStringList frags;
1234  for (const auto &f: r.second.fragments) {
1235  frags << QString("{\"%1\": \"%2\"}").arg(f.first).arg(f.second);
1236  }
1237  SVCERR << "[" << i << "/" << n << "] id " << r.first
1238  << ": score " << r.second.score
1239  << ", key " << r.second.key << ", fragments "
1240  << frags.join(";") << endl;
1241  ++i;
1242  }
1243  SVCERR << endl;
1244 #endif
1245 
1246  return results;
1247 }
1248 
double sv_samplerate_t
Sample rate.
Definition: BaseTypes.h:51
TransformInstallStatus getTransformInstallStatus(TransformId id)
sv_samplerate_t getSampleRate() const
Definition: Transform.cpp:378
Transform getDefaultTransformFor(TransformId identifier, sv_samplerate_t rate=0)
A single transform ID can lead to many possible Transforms, with different parameters and execution c...
std::vector< QString > getTransformCategories(TransformDescription::Type)
QString getTransformTypeName(TransformDescription::Type) const
std::vector< std::string > controlOutputPortNames
void setParametersFromPlugin(Transform &transform, std::shared_ptr< Vamp::PluginBase > plugin)
Set the plugin parameters, program and configuration strings on the given Transform object from the g...
TransformDescriptionMap m_transforms
TransformList getUninstalledTransformDescriptions()
void transformsPopulated()
virtual void setParametersFromXml(QString xml)
Set the parameters and program of a plugin from an XML plugin element as returned by toXml...
Definition: PluginXml.cpp:195
int getStepSize() const
Definition: Transform.cpp:318
void setPluginParameters(const Transform &transform, std::shared_ptr< Vamp::PluginBase > plugin)
Set the parameters, program and configuration strings on the given plugin from the given Transform ob...
QMutex m_uninstalledTransformsMutex
std::map< TransformId, TransformDescription > TransformDescriptionMap
TransformDescription getTransformDescription(TransformId id)
void setSampleRate(sv_samplerate_t rate)
Definition: Transform.cpp:384
std::vector< TransformDescription > TransformList
Vamp::Plugin::InputDomain getTransformInputDomain(TransformId identifier)
Provider getPluginProvider() const
virtual std::vector< QString > getPluginIdentifiers(QString &errorMsg)=0
Return all installed plugin identifiers.
virtual RealTimePluginDescriptor getPluginDescriptor(QString identifier) const =0
Get some basic information about a plugin (rapidly).
bool haveTransform(TransformId identifier)
Return true if the given transform is known.
const ParameterMap & getParameters() const
Definition: Transform.cpp:244
Type getType() const
Definition: Transform.cpp:203
static RealTimePluginFactory * instanceFor(QString identifier)
QString getOutputName(QString outputId) const
void setPluginVersion(QString version)
Definition: Transform.cpp:288
QStringList getOutputIds() const
void uninstalledTransformsPopulated()
UninstalledTransformsPopulateThread * m_thread
std::map< QString, QString > ConfigurationMap
Definition: Transform.h:92
std::shared_ptr< Vamp::PluginBase > instantiatePluginFor(const Transform &transform)
Load an appropriate plugin for the given transform and set the parameters, program and configuration ...
void toXml(QTextStream &stream, QString indent="", QString extraAttributes="") const override
Export plugin settings to XML.
Definition: PluginXml.cpp:62
QString getProgram() const
Definition: Transform.cpp:294
std::map< std::string, std::string > ConfigurationPairMap
bool m_uninstalledTransformsPopulated
const ConfigurationMap & getConfiguration() const
Definition: Transform.cpp:263
void test(Match &match, QStringList keywords, QString text, QString textType, int score)
Definition: TextMatcher.cpp:27
static TransformId getIdentifierForPluginOutput(QString pluginIdentifier, QString output="")
Definition: Transform.cpp:237
static std::vector< QString > getAllPluginIdentifiers()
virtual QString getPluginCategory(QString identifier)=0
Get category metadata about a plugin (without instantiating it).
SearchResults search(QString keyword)
QString getTransformName(TransformId identifier)
Full name of a transform, suitable for putting on a menu.
QString getTransformFriendlyName(TransformId identifier)
Brief but friendly name of a transform, suitable for use as the name of the output layer...
static TransformFactory * getInstance()
bool getTransformChannelRange(TransformId identifier, int &minChannels, int &maxChannels)
If the transform has a prescribed number or range of channel inputs, return true and set minChannels ...
static TransformFactory * m_instance
TransformList getAllTransformDescriptions()
A rather eccentric interface for matching texts in differently-scored fields.
Definition: TextMatcher.h:27
virtual std::shared_ptr< RealTimePluginInstance > instantiatePlugin(QString identifier, int clientId, int position, sv_samplerate_t sampleRate, int blockSize, int channels)=0
Instantiate a plugin.
void setIdentifier(TransformId id)
Definition: Transform.cpp:173
QString getPluginDescription() const
void populateUninstalledTransforms()
void populateFeatureExtractionPlugins(TransformDescriptionMap &)
QString getPluginConfigurationXml(const Transform &transform)
Retrieve a <plugin ...
std::shared_ptr< Vamp::PluginBase > instantiateDefaultPluginFor(TransformId id, sv_samplerate_t rate)
bool isTransformConfigurable(TransformId identifier)
Return true if the transform has any configurable parameters, i.e.
QStringList getIndexedPluginIds()
bool havePopulated()
Return true if the transforms have been populated, i.e.
Provider getTransformProvider(TransformId identifier)
void setConfiguration(const ConfigurationMap &cm)
Definition: Transform.cpp:269
QString getPluginMaker() const
std::vector< TransformDescription::Type > getAllTransformTypes()
virtual std::shared_ptr< Vamp::Plugin > instantiatePlugin(QString identifier, sv_samplerate_t inputSampleRate)=0
Instantiate (load) and return pointer to the plugin with the given identifier, at the given sample ra...
std::vector< QString > getTransformMakers(TransformDescription::Type)
void setBlockSize(int s)
Definition: Transform.cpp:336
static FeatureExtractionPluginFactory * instance()
std::map< QString, float > ParameterMap
Definition: Transform.h:86
bool in_range_for(const C &container, T i)
Check whether an integer index is in range for a container, avoiding overflows and signed/unsigned co...
Definition: BaseTypes.h:37
#define SVDEBUG
Definition: Debug.h:106
void performConsistencyChecks()
Perform various checks for consistency of RDF definitions, printing warnings to stderr/logfile as app...
TransformId getIdentifier() const
Definition: Transform.cpp:179
QString getPluginName() const
void setParametersFromPluginConfigurationXml(Transform &transform, QString xml)
Set the plugin parameters, program and configuration strings on the given Transform object from the g...
bool haveUninstalledTransforms(bool waitForCheckToComplete=false)
std::map< TransformId, TextMatcher::Match > SearchResults
static bool compareUserStrings(QString s1, QString s2)
QString getTransformUnits(TransformId identifier)
Metadata associated with a transform.
virtual ConfigurationPairMap getConfigurePairs()
#define SVCERR
Definition: Debug.h:109
virtual QString getPluginCategory(QString identifier)=0
Get category metadata about a plugin (without instantiating it).
void populateRealTimePlugins(TransformDescriptionMap &)
bool indexConfiguredURLs()
Index all URLs obtained from index files defined in the current settings.
static PluginRDFIndexer * getInstance()
virtual piper_vamp::PluginStaticData getPluginStaticData(QString ident)=0
Return static data for the given plugin.
QString getPluginIdentifier() const
Definition: Transform.cpp:213
void setProgram(QString program)
Definition: Transform.cpp:300
void makeContextConsistentWithPlugin(Transform &transform, std::shared_ptr< Vamp::PluginBase > plugin)
If the given Transform object has no processing step and block sizes set, set them to appropriate def...
void startPopulationThread()
TransformFactory has a background thread that can populate uninstalled transforms from network RDF re...
static void deleteInstance()
virtual ~TransformFactory()
SearchResults searchUnadjusted(QStringList keywords)
TransformDescription getUninstalledTransformDescription(TransformId id)
TransformDescriptionMap m_uninstalledTransforms
QString TransformId
Definition: Transform.h:30
void setStepSize(int s)
Definition: Transform.cpp:324
int getBlockSize() const
Definition: Transform.cpp:330
void setParameters(const ParameterMap &pm)
Definition: Transform.cpp:250