annotate transform/TransformFactory.cpp @ 60:3086ff194ea0

* More structural work on feature extraction plugin C <-> C++ adapter * Allow use of LADSPA/DSSI plugins with control outputs as feature extraction plugins (DSSI with MIDI output still to come) * Reorder labels on spectrogram status box * Minor tweaks in doc etc.
author Chris Cannam
date Mon, 27 Mar 2006 15:03:02 +0000
parents 7439f1696314
children ba405e5e69d3
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@60 19 #include "RealTimePluginTransform.h"
Chris@0 20
Chris@0 21 #include "plugin/FeatureExtractionPluginFactory.h"
Chris@60 22 #include "plugin/RealTimePluginFactory.h"
Chris@0 23
Chris@56 24 #include "widgets/PluginParameterDialog.h"
Chris@56 25
Chris@0 26 #include <iostream>
Chris@0 27
Chris@0 28 TransformFactory *
Chris@0 29 TransformFactory::m_instance = new TransformFactory;
Chris@0 30
Chris@0 31 TransformFactory *
Chris@0 32 TransformFactory::instance()
Chris@0 33 {
Chris@0 34 return m_instance;
Chris@0 35 }
Chris@0 36
Chris@0 37 TransformFactory::~TransformFactory()
Chris@0 38 {
Chris@0 39 }
Chris@0 40
Chris@0 41 TransformFactory::TransformList
Chris@0 42 TransformFactory::getAllTransforms()
Chris@0 43 {
Chris@16 44 if (m_transforms.empty()) populateTransforms();
Chris@16 45
Chris@0 46 TransformList list;
Chris@56 47 for (TransformDescriptionMap::const_iterator i = m_transforms.begin();
Chris@16 48 i != m_transforms.end(); ++i) {
Chris@56 49 list.push_back(i->second);
Chris@16 50 }
Chris@0 51
Chris@16 52 return list;
Chris@16 53 }
Chris@16 54
Chris@16 55 void
Chris@16 56 TransformFactory::populateTransforms()
Chris@16 57 {
Chris@60 58 TransformDescriptionMap transforms;
Chris@60 59
Chris@60 60 populateFeatureExtractionPlugins(transforms);
Chris@60 61 populateRealTimePlugins(transforms);
Chris@60 62
Chris@60 63 // disambiguate plugins with similar descriptions
Chris@60 64
Chris@60 65 std::map<QString, int> descriptions;
Chris@60 66
Chris@60 67 for (TransformDescriptionMap::iterator i = transforms.begin();
Chris@60 68 i != transforms.end(); ++i) {
Chris@60 69
Chris@60 70 TransformDesc desc = i->second;
Chris@60 71
Chris@60 72 ++descriptions[desc.description];
Chris@60 73 ++descriptions[QString("%1 [%2]").arg(desc.description).arg(desc.maker)];
Chris@60 74 }
Chris@60 75
Chris@60 76 std::map<QString, int> counts;
Chris@60 77 m_transforms.clear();
Chris@60 78
Chris@60 79 for (TransformDescriptionMap::iterator i = transforms.begin();
Chris@60 80 i != transforms.end(); ++i) {
Chris@60 81
Chris@60 82 TransformDesc desc = i->second;
Chris@60 83 QString name = desc.name;
Chris@60 84 QString description = desc.description;
Chris@60 85 QString maker = desc.maker;
Chris@60 86
Chris@60 87 if (descriptions[description] > 1) {
Chris@60 88 description = QString("%1 [%2]").arg(description).arg(maker);
Chris@60 89 if (descriptions[description] > 1) {
Chris@60 90 description = QString("%1 <%2>")
Chris@60 91 .arg(description).arg(++counts[description]);
Chris@60 92 }
Chris@60 93 }
Chris@60 94
Chris@60 95 desc.description = description;
Chris@60 96 m_transforms[name] = desc;
Chris@60 97 }
Chris@60 98 }
Chris@60 99
Chris@60 100 void
Chris@60 101 TransformFactory::populateFeatureExtractionPlugins(TransformDescriptionMap &transforms)
Chris@60 102 {
Chris@60 103 std::vector<QString> plugs =
Chris@0 104 FeatureExtractionPluginFactory::getAllPluginIdentifiers();
Chris@0 105
Chris@60 106 for (size_t i = 0; i < plugs.size(); ++i) {
Chris@47 107
Chris@60 108 QString pluginId = plugs[i];
Chris@0 109
Chris@0 110 FeatureExtractionPluginFactory *factory =
Chris@0 111 FeatureExtractionPluginFactory::instanceFor(pluginId);
Chris@0 112
Chris@20 113 if (!factory) {
Chris@20 114 std::cerr << "WARNING: TransformFactory::populateTransforms: No feature extraction plugin factory for instance " << pluginId.toLocal8Bit().data() << std::endl;
Chris@20 115 continue;
Chris@20 116 }
Chris@0 117
Chris@20 118 FeatureExtractionPlugin *plugin =
Chris@20 119 factory->instantiatePlugin(pluginId, 48000);
Chris@0 120
Chris@20 121 if (!plugin) {
Chris@20 122 std::cerr << "WARNING: TransformFactory::populateTransforms: Failed to instantiate plugin " << pluginId.toLocal8Bit().data() << std::endl;
Chris@20 123 continue;
Chris@20 124 }
Chris@20 125
Chris@20 126 QString pluginDescription = plugin->getDescription().c_str();
Chris@20 127 FeatureExtractionPlugin::OutputList outputs =
Chris@20 128 plugin->getOutputDescriptors();
Chris@0 129
Chris@20 130 for (size_t j = 0; j < outputs.size(); ++j) {
Chris@0 131
Chris@20 132 QString transformName = QString("%1:%2")
Chris@20 133 .arg(pluginId).arg(outputs[j].name.c_str());
Chris@20 134
Chris@20 135 QString userDescription;
Chris@60 136 QString friendlyName;
Chris@20 137
Chris@20 138 if (outputs.size() == 1) {
Chris@20 139 userDescription = pluginDescription;
Chris@60 140 friendlyName = pluginDescription;
Chris@20 141 } else {
Chris@20 142 userDescription = QString("%1: %2")
Chris@20 143 .arg(pluginDescription)
Chris@20 144 .arg(outputs[j].description.c_str());
Chris@60 145 friendlyName = outputs[j].description.c_str();
Chris@0 146 }
Chris@20 147
Chris@56 148 bool configurable = (!plugin->getPrograms().empty() ||
Chris@56 149 !plugin->getParameterDescriptors().empty());
Chris@56 150
Chris@60 151 transforms[transformName] =
Chris@56 152 TransformDesc(transformName,
Chris@56 153 userDescription,
Chris@60 154 friendlyName,
Chris@60 155 plugin->getMaker().c_str(),
Chris@56 156 configurable);
Chris@0 157 }
Chris@0 158 }
Chris@60 159 }
Chris@47 160
Chris@60 161 void
Chris@60 162 TransformFactory::populateRealTimePlugins(TransformDescriptionMap &transforms)
Chris@60 163 {
Chris@60 164 std::vector<QString> plugs =
Chris@60 165 RealTimePluginFactory::getAllPluginIdentifiers();
Chris@47 166
Chris@60 167 for (size_t i = 0; i < plugs.size(); ++i) {
Chris@60 168
Chris@60 169 QString pluginId = plugs[i];
Chris@47 170
Chris@60 171 RealTimePluginFactory *factory =
Chris@60 172 RealTimePluginFactory::instanceFor(pluginId);
Chris@47 173
Chris@60 174 if (!factory) {
Chris@60 175 std::cerr << "WARNING: TransformFactory::populateTransforms: No real time plugin factory for instance " << pluginId.toLocal8Bit().data() << std::endl;
Chris@60 176 continue;
Chris@47 177 }
Chris@47 178
Chris@60 179 const RealTimePluginDescriptor *descriptor =
Chris@60 180 factory->getPluginDescriptor(pluginId);
Chris@60 181
Chris@60 182 if (!descriptor) {
Chris@60 183 std::cerr << "WARNING: TransformFactory::populateTransforms: Failed to query plugin " << pluginId.toLocal8Bit().data() << std::endl;
Chris@60 184 continue;
Chris@60 185 }
Chris@60 186
Chris@60 187 if (descriptor->controlOutputPortCount == 0 ||
Chris@60 188 descriptor->audioInputPortCount == 0) continue;
Chris@60 189
Chris@60 190 std::cout << "TransformFactory::populateRealTimePlugins: plugin " << pluginId.toStdString() << " has " << descriptor->controlOutputPortCount << " output ports" << std::endl;
Chris@60 191
Chris@60 192 QString pluginDescription = descriptor->name.c_str();
Chris@60 193
Chris@60 194 for (size_t j = 0; j < descriptor->controlOutputPortCount; ++j) {
Chris@60 195
Chris@60 196 QString transformName = QString("%1:%2").arg(pluginId).arg(j);
Chris@60 197 QString userDescription;
Chris@60 198
Chris@60 199 if (j < descriptor->controlOutputPortNames.size() &&
Chris@60 200 descriptor->controlOutputPortNames[j] != "") {
Chris@60 201 userDescription = tr("%1: %2")
Chris@60 202 .arg(pluginDescription)
Chris@60 203 .arg(descriptor->controlOutputPortNames[j].c_str());
Chris@60 204 } else if (descriptor->controlOutputPortCount > 1) {
Chris@60 205 userDescription = tr("%1: Output %2")
Chris@60 206 .arg(pluginDescription)
Chris@60 207 .arg(j + 1);
Chris@60 208 } else {
Chris@60 209 userDescription = pluginDescription;
Chris@60 210 }
Chris@60 211
Chris@60 212 bool configurable = (descriptor->parameterCount > 0);
Chris@60 213
Chris@60 214 transforms[transformName] =
Chris@60 215 TransformDesc(transformName,
Chris@60 216 userDescription,
Chris@60 217 userDescription,
Chris@60 218 descriptor->maker.c_str(),
Chris@60 219 configurable);
Chris@60 220 }
Chris@60 221 }
Chris@16 222 }
Chris@16 223
Chris@16 224 QString
Chris@16 225 TransformFactory::getTransformDescription(TransformName name)
Chris@16 226 {
Chris@16 227 if (m_transforms.find(name) != m_transforms.end()) {
Chris@56 228 return m_transforms[name].description;
Chris@16 229 } else return "";
Chris@0 230 }
Chris@0 231
Chris@18 232 QString
Chris@18 233 TransformFactory::getTransformFriendlyName(TransformName name)
Chris@18 234 {
Chris@60 235 if (m_transforms.find(name) != m_transforms.end()) {
Chris@60 236 return m_transforms[name].friendlyName;
Chris@60 237 } else return "";
Chris@18 238 }
Chris@18 239
Chris@56 240 bool
Chris@57 241 TransformFactory::isTransformConfigurable(TransformName name)
Chris@57 242 {
Chris@57 243 if (m_transforms.find(name) != m_transforms.end()) {
Chris@57 244 return m_transforms[name].configurable;
Chris@57 245 } else return false;
Chris@57 246 }
Chris@57 247
Chris@57 248 bool
Chris@56 249 TransformFactory::getConfigurationForTransform(TransformName name,
Chris@56 250 Model *inputModel,
Chris@56 251 QString &configurationXml)
Chris@0 252 {
Chris@56 253 QString id = name.section(':', 0, 2);
Chris@56 254 QString output = name.section(':', 3);
Chris@56 255
Chris@56 256 bool ok = false;
Chris@56 257 configurationXml = m_lastConfigurations[name];
Chris@56 258
Chris@56 259 std::cerr << "last configuration: " << configurationXml.toStdString() << std::endl;
Chris@56 260
Chris@60 261 PluginInstance *plugin = 0;
Chris@60 262
Chris@56 263 if (FeatureExtractionPluginFactory::instanceFor(id)) {
Chris@60 264
Chris@60 265 plugin = FeatureExtractionPluginFactory::instanceFor(id)->instantiatePlugin
Chris@56 266 (id, inputModel->getSampleRate());
Chris@60 267
Chris@60 268 } else if (RealTimePluginFactory::instanceFor(id)) {
Chris@60 269
Chris@60 270 plugin = RealTimePluginFactory::instanceFor(id)->instantiatePlugin
Chris@60 271 (id, 0, 0, inputModel->getSampleRate(), 1024, 1);
Chris@60 272 }
Chris@60 273
Chris@60 274 if (plugin) {
Chris@60 275 if (configurationXml != "") {
Chris@60 276 plugin->setParametersFromXml(configurationXml);
Chris@56 277 }
Chris@60 278 PluginParameterDialog *dialog = new PluginParameterDialog(plugin);
Chris@60 279 if (dialog->exec() == QDialog::Accepted) {
Chris@60 280 ok = true;
Chris@60 281 }
Chris@60 282 configurationXml = plugin->toXmlString();
Chris@60 283 delete dialog;
Chris@60 284 delete plugin;
Chris@56 285 }
Chris@56 286
Chris@56 287 if (ok) m_lastConfigurations[name] = configurationXml;
Chris@56 288
Chris@56 289 return ok;
Chris@0 290 }
Chris@0 291
Chris@0 292 Transform *
Chris@0 293 TransformFactory::createTransform(TransformName name, Model *inputModel,
Chris@56 294 QString configurationXml, bool start)
Chris@0 295 {
Chris@0 296 Transform *transform = 0;
Chris@0 297
Chris@56 298 QString id = name.section(':', 0, 2);
Chris@56 299 QString output = name.section(':', 3);
Chris@56 300
Chris@56 301 if (FeatureExtractionPluginFactory::instanceFor(id)) {
Chris@56 302 transform = new FeatureExtractionPluginTransform(inputModel,
Chris@56 303 id,
Chris@56 304 configurationXml,
Chris@56 305 output);
Chris@60 306 } else if (RealTimePluginFactory::instanceFor(id)) {
Chris@60 307 transform = new RealTimePluginTransform(inputModel,
Chris@60 308 id,
Chris@60 309 configurationXml,
Chris@60 310 output.toInt());
Chris@0 311 } else {
Chris@56 312 std::cerr << "TransformFactory::createTransform: Unknown transform "
Chris@56 313 << name.toStdString() << std::endl;
Chris@0 314 }
Chris@0 315
Chris@0 316 if (start && transform) transform->start();
Chris@16 317 transform->setObjectName(name);
Chris@0 318 return transform;
Chris@0 319 }
Chris@0 320
Chris@0 321 Model *
Chris@56 322 TransformFactory::transform(TransformName name, Model *inputModel,
Chris@56 323 QString configurationXml)
Chris@0 324 {
Chris@56 325 Transform *t = createTransform(name, inputModel, configurationXml, false);
Chris@0 326
Chris@0 327 if (!t) return 0;
Chris@0 328
Chris@0 329 connect(t, SIGNAL(finished()), this, SLOT(transformFinished()));
Chris@0 330
Chris@0 331 t->start();
Chris@0 332 return t->detachOutputModel();
Chris@0 333 }
Chris@0 334
Chris@0 335 void
Chris@0 336 TransformFactory::transformFinished()
Chris@0 337 {
Chris@0 338 QObject *s = sender();
Chris@0 339 Transform *transform = dynamic_cast<Transform *>(s);
Chris@0 340
Chris@0 341 if (!transform) {
Chris@0 342 std::cerr << "WARNING: TransformFactory::transformFinished: sender is not a transform" << std::endl;
Chris@0 343 return;
Chris@0 344 }
Chris@0 345
Chris@0 346 transform->wait(); // unnecessary but reassuring
Chris@0 347 delete transform;
Chris@0 348 }
Chris@0 349