annotate transform/TransformFactory.cpp @ 56:2157fa46c1e7

* Add plugin parameter dialog, and use it to set up parameters for feature extraction plugins via a semi-opaque (translucent?) configurationXml string which is associated with a given transform instance. This is not yet saved to and restored from the SV file properly. * Remove no-longer-relevant BeatDetect and BeatDetectionFunction transforms (replaced a long time ago with the beat detector plugin).
author Chris Cannam
date Wed, 22 Mar 2006 17:38:29 +0000
parents d397ea0a79f5
children 7439f1696314
rev   line source
Chris@49 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@0 2
Chris@0 3 /*
Chris@52 4 Sonic Visualiser
Chris@52 5 An audio file viewer and annotation editor.
Chris@52 6 Centre for Digital Music, Queen Mary, University of London.
Chris@52 7 This file copyright 2006 Chris Cannam.
Chris@0 8
Chris@52 9 This program is free software; you can redistribute it and/or
Chris@52 10 modify it under the terms of the GNU General Public License as
Chris@52 11 published by the Free Software Foundation; either version 2 of the
Chris@52 12 License, or (at your option) any later version. See the file
Chris@52 13 COPYING included with this distribution for more information.
Chris@0 14 */
Chris@0 15
Chris@0 16 #include "TransformFactory.h"
Chris@0 17
Chris@0 18 #include "FeatureExtractionPluginTransform.h"
Chris@0 19
Chris@0 20 #include "plugin/FeatureExtractionPluginFactory.h"
Chris@0 21
Chris@56 22 #include "widgets/PluginParameterDialog.h"
Chris@56 23
Chris@0 24 #include <iostream>
Chris@0 25
Chris@0 26 TransformFactory *
Chris@0 27 TransformFactory::m_instance = new TransformFactory;
Chris@0 28
Chris@0 29 TransformFactory *
Chris@0 30 TransformFactory::instance()
Chris@0 31 {
Chris@0 32 return m_instance;
Chris@0 33 }
Chris@0 34
Chris@0 35 TransformFactory::~TransformFactory()
Chris@0 36 {
Chris@0 37 }
Chris@0 38
Chris@0 39 TransformFactory::TransformList
Chris@0 40 TransformFactory::getAllTransforms()
Chris@0 41 {
Chris@16 42 if (m_transforms.empty()) populateTransforms();
Chris@16 43
Chris@0 44 TransformList list;
Chris@56 45 for (TransformDescriptionMap::const_iterator i = m_transforms.begin();
Chris@16 46 i != m_transforms.end(); ++i) {
Chris@56 47 list.push_back(i->second);
Chris@16 48 }
Chris@0 49
Chris@16 50 return list;
Chris@16 51 }
Chris@16 52
Chris@16 53 void
Chris@16 54 TransformFactory::populateTransforms()
Chris@16 55 {
Chris@0 56 std::vector<QString> fexplugs =
Chris@0 57 FeatureExtractionPluginFactory::getAllPluginIdentifiers();
Chris@0 58
Chris@47 59 std::map<QString, QString> makers;
Chris@47 60
Chris@0 61 for (size_t i = 0; i < fexplugs.size(); ++i) {
Chris@0 62
Chris@0 63 QString pluginId = fexplugs[i];
Chris@0 64
Chris@0 65 FeatureExtractionPluginFactory *factory =
Chris@0 66 FeatureExtractionPluginFactory::instanceFor(pluginId);
Chris@0 67
Chris@20 68 if (!factory) {
Chris@20 69 std::cerr << "WARNING: TransformFactory::populateTransforms: No feature extraction plugin factory for instance " << pluginId.toLocal8Bit().data() << std::endl;
Chris@20 70 continue;
Chris@20 71 }
Chris@0 72
Chris@20 73 FeatureExtractionPlugin *plugin =
Chris@20 74 factory->instantiatePlugin(pluginId, 48000);
Chris@0 75
Chris@20 76 if (!plugin) {
Chris@20 77 std::cerr << "WARNING: TransformFactory::populateTransforms: Failed to instantiate plugin " << pluginId.toLocal8Bit().data() << std::endl;
Chris@20 78 continue;
Chris@20 79 }
Chris@20 80
Chris@20 81 QString pluginDescription = plugin->getDescription().c_str();
Chris@20 82 FeatureExtractionPlugin::OutputList outputs =
Chris@20 83 plugin->getOutputDescriptors();
Chris@0 84
Chris@20 85 for (size_t j = 0; j < outputs.size(); ++j) {
Chris@0 86
Chris@20 87 QString transformName = QString("%1:%2")
Chris@20 88 .arg(pluginId).arg(outputs[j].name.c_str());
Chris@20 89
Chris@20 90 QString userDescription;
Chris@20 91
Chris@20 92 if (outputs.size() == 1) {
Chris@20 93 userDescription = pluginDescription;
Chris@20 94 } else {
Chris@20 95 userDescription = QString("%1: %2")
Chris@20 96 .arg(pluginDescription)
Chris@20 97 .arg(outputs[j].description.c_str());
Chris@0 98 }
Chris@20 99
Chris@56 100 bool configurable = (!plugin->getPrograms().empty() ||
Chris@56 101 !plugin->getParameterDescriptors().empty());
Chris@56 102
Chris@56 103 m_transforms[transformName] =
Chris@56 104 TransformDesc(transformName,
Chris@56 105 userDescription,
Chris@56 106 configurable);
Chris@47 107
Chris@47 108 makers[transformName] = plugin->getMaker().c_str();
Chris@0 109 }
Chris@0 110 }
Chris@47 111
Chris@47 112 // disambiguate plugins with similar descriptions
Chris@47 113
Chris@47 114 std::map<QString, int> descriptions;
Chris@47 115
Chris@56 116 for (TransformDescriptionMap::iterator i = m_transforms.begin();
Chris@56 117 i != m_transforms.end(); ++i) {
Chris@47 118
Chris@56 119 TransformDesc desc = i->second;
Chris@47 120
Chris@56 121 ++descriptions[desc.description];
Chris@56 122 ++descriptions[QString("%1 [%2]").arg(desc.description).arg(makers[desc.name])];
Chris@47 123 }
Chris@47 124
Chris@47 125 std::map<QString, int> counts;
Chris@56 126 TransformDescriptionMap newMap;
Chris@47 127
Chris@56 128 for (TransformDescriptionMap::iterator i = m_transforms.begin();
Chris@56 129 i != m_transforms.end(); ++i) {
Chris@47 130
Chris@56 131 TransformDesc desc = i->second;
Chris@56 132 QString name = desc.name, description = desc.description;
Chris@47 133
Chris@47 134 if (descriptions[description] > 1) {
Chris@47 135 description = QString("%1 [%2]").arg(description).arg(makers[name]);
Chris@47 136 if (descriptions[description] > 1) {
Chris@47 137 description = QString("%1 <%2>")
Chris@47 138 .arg(description).arg(++counts[description]);
Chris@47 139 }
Chris@47 140 }
Chris@47 141
Chris@56 142 desc.description = description;
Chris@56 143 newMap[name] = desc;
Chris@47 144 }
Chris@47 145
Chris@47 146 m_transforms = newMap;
Chris@16 147 }
Chris@16 148
Chris@16 149 QString
Chris@16 150 TransformFactory::getTransformDescription(TransformName name)
Chris@16 151 {
Chris@16 152 if (m_transforms.find(name) != m_transforms.end()) {
Chris@56 153 return m_transforms[name].description;
Chris@16 154 } else return "";
Chris@0 155 }
Chris@0 156
Chris@18 157 QString
Chris@18 158 TransformFactory::getTransformFriendlyName(TransformName name)
Chris@18 159 {
Chris@18 160 QString description = getTransformDescription(name);
Chris@18 161
Chris@18 162 int i = description.indexOf(':');
Chris@18 163 if (i >= 0) {
Chris@18 164 return description.remove(0, i + 2);
Chris@18 165 } else {
Chris@18 166 return description;
Chris@18 167 }
Chris@18 168 }
Chris@18 169
Chris@56 170 bool
Chris@56 171 TransformFactory::getConfigurationForTransform(TransformName name,
Chris@56 172 Model *inputModel,
Chris@56 173 QString &configurationXml)
Chris@0 174 {
Chris@56 175 QString id = name.section(':', 0, 2);
Chris@56 176 QString output = name.section(':', 3);
Chris@56 177
Chris@56 178 bool ok = false;
Chris@56 179 configurationXml = m_lastConfigurations[name];
Chris@56 180
Chris@56 181 std::cerr << "last configuration: " << configurationXml.toStdString() << std::endl;
Chris@56 182
Chris@56 183 if (FeatureExtractionPluginFactory::instanceFor(id)) {
Chris@56 184 FeatureExtractionPlugin *plugin =
Chris@56 185 FeatureExtractionPluginFactory::instanceFor(id)->instantiatePlugin
Chris@56 186 (id, inputModel->getSampleRate());
Chris@56 187 if (plugin) {
Chris@56 188 if (configurationXml != "") {
Chris@56 189 plugin->setParametersFromXml(configurationXml);
Chris@56 190 }
Chris@56 191 PluginParameterDialog *dialog = new PluginParameterDialog(plugin);
Chris@56 192 if (dialog->exec() == QDialog::Accepted) {
Chris@56 193 ok = true;
Chris@56 194 }
Chris@56 195 configurationXml = plugin->toXmlString();
Chris@56 196 delete plugin;
Chris@56 197 }
Chris@56 198 }
Chris@56 199
Chris@56 200 if (ok) m_lastConfigurations[name] = configurationXml;
Chris@56 201
Chris@56 202 return ok;
Chris@0 203 }
Chris@0 204
Chris@0 205 Transform *
Chris@0 206 TransformFactory::createTransform(TransformName name, Model *inputModel,
Chris@56 207 QString configurationXml, bool start)
Chris@0 208 {
Chris@0 209 Transform *transform = 0;
Chris@0 210
Chris@56 211 // The only transform type we support at the moment is the
Chris@56 212 // FeatureExtractionPluginTransform. In future we may wish to
Chris@56 213 // support e.g. RealTimePluginTransform for audio->audio or
Chris@56 214 // audio->midi transforms using standard effects plugins.
Chris@56 215
Chris@56 216 QString id = name.section(':', 0, 2);
Chris@56 217 QString output = name.section(':', 3);
Chris@56 218
Chris@56 219 if (FeatureExtractionPluginFactory::instanceFor(id)) {
Chris@56 220 transform = new FeatureExtractionPluginTransform(inputModel,
Chris@56 221 id,
Chris@56 222 configurationXml,
Chris@56 223 output);
Chris@0 224 } else {
Chris@56 225 std::cerr << "TransformFactory::createTransform: Unknown transform "
Chris@56 226 << name.toStdString() << std::endl;
Chris@0 227 }
Chris@0 228
Chris@0 229 if (start && transform) transform->start();
Chris@16 230 transform->setObjectName(name);
Chris@0 231 return transform;
Chris@0 232 }
Chris@0 233
Chris@0 234 Model *
Chris@56 235 TransformFactory::transform(TransformName name, Model *inputModel,
Chris@56 236 QString configurationXml)
Chris@0 237 {
Chris@56 238 Transform *t = createTransform(name, inputModel, configurationXml, false);
Chris@0 239
Chris@0 240 if (!t) return 0;
Chris@0 241
Chris@0 242 connect(t, SIGNAL(finished()), this, SLOT(transformFinished()));
Chris@0 243
Chris@0 244 t->start();
Chris@0 245 return t->detachOutputModel();
Chris@0 246 }
Chris@0 247
Chris@0 248 void
Chris@0 249 TransformFactory::transformFinished()
Chris@0 250 {
Chris@0 251 QObject *s = sender();
Chris@0 252 Transform *transform = dynamic_cast<Transform *>(s);
Chris@0 253
Chris@0 254 if (!transform) {
Chris@0 255 std::cerr << "WARNING: TransformFactory::transformFinished: sender is not a transform" << std::endl;
Chris@0 256 return;
Chris@0 257 }
Chris@0 258
Chris@0 259 transform->wait(); // unnecessary but reassuring
Chris@0 260 delete transform;
Chris@0 261 }
Chris@0 262