annotate transform/TransformFactory.cpp @ 63:ba405e5e69d3

* Add auto-normalize option to waveform layer * Various fixes to display of dB/metered levels in waveform layer. Still need to fix to ensure they don't waste half the display * Add mix channels option to waveform layer * Use multiple transforms menus, one per transform type -- not sure about this * Give centroid plugin two outputs, for log and linear frequency weightings * Show scale units from plugin in time-value display
author Chris Cannam
date Wed, 29 Mar 2006 12:35:17 +0000
parents 3086ff194ea0
children 4d59dc469b0f
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@63 27 #include <set>
Chris@63 28
Chris@63 29 #include <QRegExp>
Chris@0 30
Chris@0 31 TransformFactory *
Chris@0 32 TransformFactory::m_instance = new TransformFactory;
Chris@0 33
Chris@0 34 TransformFactory *
Chris@0 35 TransformFactory::instance()
Chris@0 36 {
Chris@0 37 return m_instance;
Chris@0 38 }
Chris@0 39
Chris@0 40 TransformFactory::~TransformFactory()
Chris@0 41 {
Chris@0 42 }
Chris@0 43
Chris@0 44 TransformFactory::TransformList
Chris@0 45 TransformFactory::getAllTransforms()
Chris@0 46 {
Chris@16 47 if (m_transforms.empty()) populateTransforms();
Chris@16 48
Chris@0 49 TransformList list;
Chris@56 50 for (TransformDescriptionMap::const_iterator i = m_transforms.begin();
Chris@16 51 i != m_transforms.end(); ++i) {
Chris@56 52 list.push_back(i->second);
Chris@16 53 }
Chris@0 54
Chris@16 55 return list;
Chris@16 56 }
Chris@16 57
Chris@63 58 std::vector<QString>
Chris@63 59 TransformFactory::getAllTransformTypes()
Chris@63 60 {
Chris@63 61 if (m_transforms.empty()) populateTransforms();
Chris@63 62
Chris@63 63 std::set<QString> types;
Chris@63 64 for (TransformDescriptionMap::const_iterator i = m_transforms.begin();
Chris@63 65 i != m_transforms.end(); ++i) {
Chris@63 66 types.insert(i->second.type);
Chris@63 67 }
Chris@63 68
Chris@63 69 std::vector<QString> rv;
Chris@63 70 for (std::set<QString>::iterator i = types.begin(); i != types.end(); ++i) {
Chris@63 71 rv.push_back(*i);
Chris@63 72 }
Chris@63 73
Chris@63 74 return rv;
Chris@63 75 }
Chris@63 76
Chris@16 77 void
Chris@16 78 TransformFactory::populateTransforms()
Chris@16 79 {
Chris@60 80 TransformDescriptionMap transforms;
Chris@60 81
Chris@60 82 populateFeatureExtractionPlugins(transforms);
Chris@60 83 populateRealTimePlugins(transforms);
Chris@60 84
Chris@60 85 // disambiguate plugins with similar descriptions
Chris@60 86
Chris@60 87 std::map<QString, int> descriptions;
Chris@60 88
Chris@60 89 for (TransformDescriptionMap::iterator i = transforms.begin();
Chris@60 90 i != transforms.end(); ++i) {
Chris@60 91
Chris@60 92 TransformDesc desc = i->second;
Chris@60 93
Chris@60 94 ++descriptions[desc.description];
Chris@60 95 ++descriptions[QString("%1 [%2]").arg(desc.description).arg(desc.maker)];
Chris@60 96 }
Chris@60 97
Chris@60 98 std::map<QString, int> counts;
Chris@60 99 m_transforms.clear();
Chris@60 100
Chris@60 101 for (TransformDescriptionMap::iterator i = transforms.begin();
Chris@60 102 i != transforms.end(); ++i) {
Chris@60 103
Chris@60 104 TransformDesc desc = i->second;
Chris@60 105 QString name = desc.name;
Chris@60 106 QString description = desc.description;
Chris@60 107 QString maker = desc.maker;
Chris@60 108
Chris@60 109 if (descriptions[description] > 1) {
Chris@60 110 description = QString("%1 [%2]").arg(description).arg(maker);
Chris@60 111 if (descriptions[description] > 1) {
Chris@60 112 description = QString("%1 <%2>")
Chris@60 113 .arg(description).arg(++counts[description]);
Chris@60 114 }
Chris@60 115 }
Chris@60 116
Chris@60 117 desc.description = description;
Chris@60 118 m_transforms[name] = desc;
Chris@60 119 }
Chris@60 120 }
Chris@60 121
Chris@60 122 void
Chris@60 123 TransformFactory::populateFeatureExtractionPlugins(TransformDescriptionMap &transforms)
Chris@60 124 {
Chris@60 125 std::vector<QString> plugs =
Chris@0 126 FeatureExtractionPluginFactory::getAllPluginIdentifiers();
Chris@0 127
Chris@60 128 for (size_t i = 0; i < plugs.size(); ++i) {
Chris@47 129
Chris@60 130 QString pluginId = plugs[i];
Chris@0 131
Chris@0 132 FeatureExtractionPluginFactory *factory =
Chris@0 133 FeatureExtractionPluginFactory::instanceFor(pluginId);
Chris@0 134
Chris@20 135 if (!factory) {
Chris@20 136 std::cerr << "WARNING: TransformFactory::populateTransforms: No feature extraction plugin factory for instance " << pluginId.toLocal8Bit().data() << std::endl;
Chris@20 137 continue;
Chris@20 138 }
Chris@0 139
Chris@20 140 FeatureExtractionPlugin *plugin =
Chris@20 141 factory->instantiatePlugin(pluginId, 48000);
Chris@0 142
Chris@20 143 if (!plugin) {
Chris@20 144 std::cerr << "WARNING: TransformFactory::populateTransforms: Failed to instantiate plugin " << pluginId.toLocal8Bit().data() << std::endl;
Chris@20 145 continue;
Chris@20 146 }
Chris@20 147
Chris@20 148 QString pluginDescription = plugin->getDescription().c_str();
Chris@20 149 FeatureExtractionPlugin::OutputList outputs =
Chris@20 150 plugin->getOutputDescriptors();
Chris@0 151
Chris@20 152 for (size_t j = 0; j < outputs.size(); ++j) {
Chris@0 153
Chris@20 154 QString transformName = QString("%1:%2")
Chris@20 155 .arg(pluginId).arg(outputs[j].name.c_str());
Chris@20 156
Chris@20 157 QString userDescription;
Chris@60 158 QString friendlyName;
Chris@63 159 QString units = outputs[j].unit.c_str();
Chris@20 160
Chris@20 161 if (outputs.size() == 1) {
Chris@20 162 userDescription = pluginDescription;
Chris@60 163 friendlyName = pluginDescription;
Chris@20 164 } else {
Chris@20 165 userDescription = QString("%1: %2")
Chris@20 166 .arg(pluginDescription)
Chris@20 167 .arg(outputs[j].description.c_str());
Chris@60 168 friendlyName = outputs[j].description.c_str();
Chris@0 169 }
Chris@20 170
Chris@56 171 bool configurable = (!plugin->getPrograms().empty() ||
Chris@56 172 !plugin->getParameterDescriptors().empty());
Chris@56 173
Chris@60 174 transforms[transformName] =
Chris@63 175 TransformDesc(tr("Analysis Plugin"),
Chris@63 176 transformName,
Chris@56 177 userDescription,
Chris@60 178 friendlyName,
Chris@60 179 plugin->getMaker().c_str(),
Chris@63 180 units,
Chris@56 181 configurable);
Chris@0 182 }
Chris@0 183 }
Chris@60 184 }
Chris@47 185
Chris@60 186 void
Chris@60 187 TransformFactory::populateRealTimePlugins(TransformDescriptionMap &transforms)
Chris@60 188 {
Chris@60 189 std::vector<QString> plugs =
Chris@60 190 RealTimePluginFactory::getAllPluginIdentifiers();
Chris@47 191
Chris@63 192 QRegExp unitRE("[\\[\\(]([A-Za-z0-9/]+)[\\)\\]]$");
Chris@63 193
Chris@60 194 for (size_t i = 0; i < plugs.size(); ++i) {
Chris@60 195
Chris@60 196 QString pluginId = plugs[i];
Chris@47 197
Chris@60 198 RealTimePluginFactory *factory =
Chris@60 199 RealTimePluginFactory::instanceFor(pluginId);
Chris@47 200
Chris@60 201 if (!factory) {
Chris@60 202 std::cerr << "WARNING: TransformFactory::populateTransforms: No real time plugin factory for instance " << pluginId.toLocal8Bit().data() << std::endl;
Chris@60 203 continue;
Chris@47 204 }
Chris@47 205
Chris@60 206 const RealTimePluginDescriptor *descriptor =
Chris@60 207 factory->getPluginDescriptor(pluginId);
Chris@60 208
Chris@60 209 if (!descriptor) {
Chris@60 210 std::cerr << "WARNING: TransformFactory::populateTransforms: Failed to query plugin " << pluginId.toLocal8Bit().data() << std::endl;
Chris@60 211 continue;
Chris@60 212 }
Chris@60 213
Chris@60 214 if (descriptor->controlOutputPortCount == 0 ||
Chris@60 215 descriptor->audioInputPortCount == 0) continue;
Chris@60 216
Chris@60 217 std::cout << "TransformFactory::populateRealTimePlugins: plugin " << pluginId.toStdString() << " has " << descriptor->controlOutputPortCount << " output ports" << std::endl;
Chris@60 218
Chris@60 219 QString pluginDescription = descriptor->name.c_str();
Chris@60 220
Chris@60 221 for (size_t j = 0; j < descriptor->controlOutputPortCount; ++j) {
Chris@60 222
Chris@60 223 QString transformName = QString("%1:%2").arg(pluginId).arg(j);
Chris@60 224 QString userDescription;
Chris@63 225 QString units;
Chris@60 226
Chris@60 227 if (j < descriptor->controlOutputPortNames.size() &&
Chris@60 228 descriptor->controlOutputPortNames[j] != "") {
Chris@63 229
Chris@63 230 QString portName = descriptor->controlOutputPortNames[j].c_str();
Chris@63 231
Chris@60 232 userDescription = tr("%1: %2")
Chris@60 233 .arg(pluginDescription)
Chris@63 234 .arg(portName);
Chris@63 235
Chris@63 236 if (unitRE.indexIn(portName) >= 0) {
Chris@63 237 units = unitRE.cap(1);
Chris@63 238 }
Chris@63 239
Chris@60 240 } else if (descriptor->controlOutputPortCount > 1) {
Chris@63 241
Chris@60 242 userDescription = tr("%1: Output %2")
Chris@60 243 .arg(pluginDescription)
Chris@60 244 .arg(j + 1);
Chris@63 245
Chris@60 246 } else {
Chris@63 247
Chris@60 248 userDescription = pluginDescription;
Chris@60 249 }
Chris@60 250
Chris@63 251
Chris@60 252 bool configurable = (descriptor->parameterCount > 0);
Chris@60 253
Chris@60 254 transforms[transformName] =
Chris@63 255 TransformDesc(tr("Real-Time Plugin"),
Chris@63 256 transformName,
Chris@60 257 userDescription,
Chris@60 258 userDescription,
Chris@60 259 descriptor->maker.c_str(),
Chris@63 260 units,
Chris@60 261 configurable);
Chris@60 262 }
Chris@60 263 }
Chris@16 264 }
Chris@16 265
Chris@16 266 QString
Chris@16 267 TransformFactory::getTransformDescription(TransformName name)
Chris@16 268 {
Chris@16 269 if (m_transforms.find(name) != m_transforms.end()) {
Chris@56 270 return m_transforms[name].description;
Chris@16 271 } else return "";
Chris@0 272 }
Chris@0 273
Chris@18 274 QString
Chris@18 275 TransformFactory::getTransformFriendlyName(TransformName name)
Chris@18 276 {
Chris@60 277 if (m_transforms.find(name) != m_transforms.end()) {
Chris@60 278 return m_transforms[name].friendlyName;
Chris@60 279 } else return "";
Chris@18 280 }
Chris@18 281
Chris@63 282 QString
Chris@63 283 TransformFactory::getTransformUnits(TransformName name)
Chris@63 284 {
Chris@63 285 if (m_transforms.find(name) != m_transforms.end()) {
Chris@63 286 return m_transforms[name].units;
Chris@63 287 } else return "";
Chris@63 288 }
Chris@63 289
Chris@56 290 bool
Chris@57 291 TransformFactory::isTransformConfigurable(TransformName name)
Chris@57 292 {
Chris@57 293 if (m_transforms.find(name) != m_transforms.end()) {
Chris@57 294 return m_transforms[name].configurable;
Chris@57 295 } else return false;
Chris@57 296 }
Chris@57 297
Chris@57 298 bool
Chris@56 299 TransformFactory::getConfigurationForTransform(TransformName name,
Chris@56 300 Model *inputModel,
Chris@56 301 QString &configurationXml)
Chris@0 302 {
Chris@56 303 QString id = name.section(':', 0, 2);
Chris@56 304 QString output = name.section(':', 3);
Chris@56 305
Chris@56 306 bool ok = false;
Chris@56 307 configurationXml = m_lastConfigurations[name];
Chris@56 308
Chris@56 309 std::cerr << "last configuration: " << configurationXml.toStdString() << std::endl;
Chris@56 310
Chris@60 311 PluginInstance *plugin = 0;
Chris@60 312
Chris@56 313 if (FeatureExtractionPluginFactory::instanceFor(id)) {
Chris@60 314
Chris@60 315 plugin = FeatureExtractionPluginFactory::instanceFor(id)->instantiatePlugin
Chris@56 316 (id, inputModel->getSampleRate());
Chris@60 317
Chris@60 318 } else if (RealTimePluginFactory::instanceFor(id)) {
Chris@60 319
Chris@60 320 plugin = RealTimePluginFactory::instanceFor(id)->instantiatePlugin
Chris@60 321 (id, 0, 0, inputModel->getSampleRate(), 1024, 1);
Chris@60 322 }
Chris@60 323
Chris@60 324 if (plugin) {
Chris@60 325 if (configurationXml != "") {
Chris@60 326 plugin->setParametersFromXml(configurationXml);
Chris@56 327 }
Chris@60 328 PluginParameterDialog *dialog = new PluginParameterDialog(plugin);
Chris@60 329 if (dialog->exec() == QDialog::Accepted) {
Chris@60 330 ok = true;
Chris@60 331 }
Chris@60 332 configurationXml = plugin->toXmlString();
Chris@60 333 delete dialog;
Chris@60 334 delete plugin;
Chris@56 335 }
Chris@56 336
Chris@56 337 if (ok) m_lastConfigurations[name] = configurationXml;
Chris@56 338
Chris@56 339 return ok;
Chris@0 340 }
Chris@0 341
Chris@0 342 Transform *
Chris@0 343 TransformFactory::createTransform(TransformName name, Model *inputModel,
Chris@56 344 QString configurationXml, bool start)
Chris@0 345 {
Chris@0 346 Transform *transform = 0;
Chris@0 347
Chris@56 348 QString id = name.section(':', 0, 2);
Chris@56 349 QString output = name.section(':', 3);
Chris@56 350
Chris@56 351 if (FeatureExtractionPluginFactory::instanceFor(id)) {
Chris@56 352 transform = new FeatureExtractionPluginTransform(inputModel,
Chris@56 353 id,
Chris@56 354 configurationXml,
Chris@56 355 output);
Chris@60 356 } else if (RealTimePluginFactory::instanceFor(id)) {
Chris@60 357 transform = new RealTimePluginTransform(inputModel,
Chris@60 358 id,
Chris@60 359 configurationXml,
Chris@63 360 getTransformUnits(name),
Chris@60 361 output.toInt());
Chris@0 362 } else {
Chris@56 363 std::cerr << "TransformFactory::createTransform: Unknown transform "
Chris@56 364 << name.toStdString() << std::endl;
Chris@0 365 }
Chris@0 366
Chris@0 367 if (start && transform) transform->start();
Chris@16 368 transform->setObjectName(name);
Chris@0 369 return transform;
Chris@0 370 }
Chris@0 371
Chris@0 372 Model *
Chris@56 373 TransformFactory::transform(TransformName name, Model *inputModel,
Chris@56 374 QString configurationXml)
Chris@0 375 {
Chris@56 376 Transform *t = createTransform(name, inputModel, configurationXml, false);
Chris@0 377
Chris@0 378 if (!t) return 0;
Chris@0 379
Chris@0 380 connect(t, SIGNAL(finished()), this, SLOT(transformFinished()));
Chris@0 381
Chris@0 382 t->start();
Chris@0 383 return t->detachOutputModel();
Chris@0 384 }
Chris@0 385
Chris@0 386 void
Chris@0 387 TransformFactory::transformFinished()
Chris@0 388 {
Chris@0 389 QObject *s = sender();
Chris@0 390 Transform *transform = dynamic_cast<Transform *>(s);
Chris@0 391
Chris@0 392 if (!transform) {
Chris@0 393 std::cerr << "WARNING: TransformFactory::transformFinished: sender is not a transform" << std::endl;
Chris@0 394 return;
Chris@0 395 }
Chris@0 396
Chris@0 397 transform->wait(); // unnecessary but reassuring
Chris@0 398 delete transform;
Chris@0 399 }
Chris@0 400