annotate transform/TransformFactory.cpp @ 76:af2725b5d6fe

* Implement harmonic cursor in spectrogram * Implement layer export. This doesn't quite do the right thing for the SV XML layer export yet -- it doesn't include layer display information, so when imported, it only creates an invisible model. Could also do with fixing CSV file import so as to work correctly for note and text layers.
author Chris Cannam
date Mon, 10 Apr 2006 17:22:59 +0000
parents 7afcfe666910
children 2beca8ddcdc3
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@66 23 #include "plugin/PluginXml.h"
Chris@0 24
Chris@56 25 #include "widgets/PluginParameterDialog.h"
Chris@56 26
Chris@64 27 #include "model/DenseTimeValueModel.h"
Chris@64 28
Chris@0 29 #include <iostream>
Chris@63 30 #include <set>
Chris@63 31
Chris@63 32 #include <QRegExp>
Chris@0 33
Chris@0 34 TransformFactory *
Chris@0 35 TransformFactory::m_instance = new TransformFactory;
Chris@0 36
Chris@0 37 TransformFactory *
Chris@0 38 TransformFactory::instance()
Chris@0 39 {
Chris@0 40 return m_instance;
Chris@0 41 }
Chris@0 42
Chris@0 43 TransformFactory::~TransformFactory()
Chris@0 44 {
Chris@0 45 }
Chris@0 46
Chris@0 47 TransformFactory::TransformList
Chris@0 48 TransformFactory::getAllTransforms()
Chris@0 49 {
Chris@16 50 if (m_transforms.empty()) populateTransforms();
Chris@16 51
Chris@0 52 TransformList list;
Chris@56 53 for (TransformDescriptionMap::const_iterator i = m_transforms.begin();
Chris@16 54 i != m_transforms.end(); ++i) {
Chris@56 55 list.push_back(i->second);
Chris@16 56 }
Chris@0 57
Chris@16 58 return list;
Chris@16 59 }
Chris@16 60
Chris@63 61 std::vector<QString>
Chris@63 62 TransformFactory::getAllTransformTypes()
Chris@63 63 {
Chris@63 64 if (m_transforms.empty()) populateTransforms();
Chris@63 65
Chris@63 66 std::set<QString> types;
Chris@63 67 for (TransformDescriptionMap::const_iterator i = m_transforms.begin();
Chris@63 68 i != m_transforms.end(); ++i) {
Chris@63 69 types.insert(i->second.type);
Chris@63 70 }
Chris@63 71
Chris@63 72 std::vector<QString> rv;
Chris@63 73 for (std::set<QString>::iterator i = types.begin(); i != types.end(); ++i) {
Chris@63 74 rv.push_back(*i);
Chris@63 75 }
Chris@63 76
Chris@63 77 return rv;
Chris@63 78 }
Chris@63 79
Chris@16 80 void
Chris@16 81 TransformFactory::populateTransforms()
Chris@16 82 {
Chris@60 83 TransformDescriptionMap transforms;
Chris@60 84
Chris@60 85 populateFeatureExtractionPlugins(transforms);
Chris@60 86 populateRealTimePlugins(transforms);
Chris@60 87
Chris@60 88 // disambiguate plugins with similar descriptions
Chris@60 89
Chris@60 90 std::map<QString, int> descriptions;
Chris@60 91
Chris@60 92 for (TransformDescriptionMap::iterator i = transforms.begin();
Chris@60 93 i != transforms.end(); ++i) {
Chris@60 94
Chris@60 95 TransformDesc desc = i->second;
Chris@60 96
Chris@60 97 ++descriptions[desc.description];
Chris@60 98 ++descriptions[QString("%1 [%2]").arg(desc.description).arg(desc.maker)];
Chris@60 99 }
Chris@60 100
Chris@60 101 std::map<QString, int> counts;
Chris@60 102 m_transforms.clear();
Chris@60 103
Chris@60 104 for (TransformDescriptionMap::iterator i = transforms.begin();
Chris@60 105 i != transforms.end(); ++i) {
Chris@60 106
Chris@60 107 TransformDesc desc = i->second;
Chris@60 108 QString name = desc.name;
Chris@60 109 QString description = desc.description;
Chris@60 110 QString maker = desc.maker;
Chris@60 111
Chris@60 112 if (descriptions[description] > 1) {
Chris@60 113 description = QString("%1 [%2]").arg(description).arg(maker);
Chris@60 114 if (descriptions[description] > 1) {
Chris@60 115 description = QString("%1 <%2>")
Chris@60 116 .arg(description).arg(++counts[description]);
Chris@60 117 }
Chris@60 118 }
Chris@60 119
Chris@60 120 desc.description = description;
Chris@60 121 m_transforms[name] = desc;
Chris@60 122 }
Chris@60 123 }
Chris@60 124
Chris@60 125 void
Chris@60 126 TransformFactory::populateFeatureExtractionPlugins(TransformDescriptionMap &transforms)
Chris@60 127 {
Chris@60 128 std::vector<QString> plugs =
Chris@0 129 FeatureExtractionPluginFactory::getAllPluginIdentifiers();
Chris@0 130
Chris@60 131 for (size_t i = 0; i < plugs.size(); ++i) {
Chris@47 132
Chris@60 133 QString pluginId = plugs[i];
Chris@0 134
Chris@0 135 FeatureExtractionPluginFactory *factory =
Chris@0 136 FeatureExtractionPluginFactory::instanceFor(pluginId);
Chris@0 137
Chris@20 138 if (!factory) {
Chris@20 139 std::cerr << "WARNING: TransformFactory::populateTransforms: No feature extraction plugin factory for instance " << pluginId.toLocal8Bit().data() << std::endl;
Chris@20 140 continue;
Chris@20 141 }
Chris@0 142
Chris@66 143 Vamp::Plugin *plugin =
Chris@20 144 factory->instantiatePlugin(pluginId, 48000);
Chris@0 145
Chris@20 146 if (!plugin) {
Chris@20 147 std::cerr << "WARNING: TransformFactory::populateTransforms: Failed to instantiate plugin " << pluginId.toLocal8Bit().data() << std::endl;
Chris@20 148 continue;
Chris@20 149 }
Chris@20 150
Chris@20 151 QString pluginDescription = plugin->getDescription().c_str();
Chris@66 152 Vamp::Plugin::OutputList outputs =
Chris@20 153 plugin->getOutputDescriptors();
Chris@0 154
Chris@20 155 for (size_t j = 0; j < outputs.size(); ++j) {
Chris@0 156
Chris@20 157 QString transformName = QString("%1:%2")
Chris@20 158 .arg(pluginId).arg(outputs[j].name.c_str());
Chris@20 159
Chris@20 160 QString userDescription;
Chris@60 161 QString friendlyName;
Chris@63 162 QString units = outputs[j].unit.c_str();
Chris@20 163
Chris@20 164 if (outputs.size() == 1) {
Chris@20 165 userDescription = pluginDescription;
Chris@60 166 friendlyName = pluginDescription;
Chris@20 167 } else {
Chris@20 168 userDescription = QString("%1: %2")
Chris@20 169 .arg(pluginDescription)
Chris@20 170 .arg(outputs[j].description.c_str());
Chris@60 171 friendlyName = outputs[j].description.c_str();
Chris@0 172 }
Chris@20 173
Chris@56 174 bool configurable = (!plugin->getPrograms().empty() ||
Chris@56 175 !plugin->getParameterDescriptors().empty());
Chris@56 176
Chris@60 177 transforms[transformName] =
Chris@63 178 TransformDesc(tr("Analysis Plugin"),
Chris@63 179 transformName,
Chris@56 180 userDescription,
Chris@60 181 friendlyName,
Chris@60 182 plugin->getMaker().c_str(),
Chris@63 183 units,
Chris@56 184 configurable);
Chris@0 185 }
Chris@0 186 }
Chris@60 187 }
Chris@47 188
Chris@60 189 void
Chris@60 190 TransformFactory::populateRealTimePlugins(TransformDescriptionMap &transforms)
Chris@60 191 {
Chris@60 192 std::vector<QString> plugs =
Chris@60 193 RealTimePluginFactory::getAllPluginIdentifiers();
Chris@47 194
Chris@63 195 QRegExp unitRE("[\\[\\(]([A-Za-z0-9/]+)[\\)\\]]$");
Chris@63 196
Chris@60 197 for (size_t i = 0; i < plugs.size(); ++i) {
Chris@60 198
Chris@60 199 QString pluginId = plugs[i];
Chris@47 200
Chris@60 201 RealTimePluginFactory *factory =
Chris@60 202 RealTimePluginFactory::instanceFor(pluginId);
Chris@47 203
Chris@60 204 if (!factory) {
Chris@60 205 std::cerr << "WARNING: TransformFactory::populateTransforms: No real time plugin factory for instance " << pluginId.toLocal8Bit().data() << std::endl;
Chris@60 206 continue;
Chris@47 207 }
Chris@47 208
Chris@60 209 const RealTimePluginDescriptor *descriptor =
Chris@60 210 factory->getPluginDescriptor(pluginId);
Chris@60 211
Chris@60 212 if (!descriptor) {
Chris@60 213 std::cerr << "WARNING: TransformFactory::populateTransforms: Failed to query plugin " << pluginId.toLocal8Bit().data() << std::endl;
Chris@60 214 continue;
Chris@60 215 }
Chris@60 216
Chris@60 217 if (descriptor->controlOutputPortCount == 0 ||
Chris@60 218 descriptor->audioInputPortCount == 0) continue;
Chris@60 219
Chris@60 220 std::cout << "TransformFactory::populateRealTimePlugins: plugin " << pluginId.toStdString() << " has " << descriptor->controlOutputPortCount << " output ports" << std::endl;
Chris@60 221
Chris@60 222 QString pluginDescription = descriptor->name.c_str();
Chris@60 223
Chris@60 224 for (size_t j = 0; j < descriptor->controlOutputPortCount; ++j) {
Chris@60 225
Chris@60 226 QString transformName = QString("%1:%2").arg(pluginId).arg(j);
Chris@60 227 QString userDescription;
Chris@63 228 QString units;
Chris@60 229
Chris@60 230 if (j < descriptor->controlOutputPortNames.size() &&
Chris@60 231 descriptor->controlOutputPortNames[j] != "") {
Chris@63 232
Chris@63 233 QString portName = descriptor->controlOutputPortNames[j].c_str();
Chris@63 234
Chris@60 235 userDescription = tr("%1: %2")
Chris@60 236 .arg(pluginDescription)
Chris@63 237 .arg(portName);
Chris@63 238
Chris@63 239 if (unitRE.indexIn(portName) >= 0) {
Chris@63 240 units = unitRE.cap(1);
Chris@63 241 }
Chris@63 242
Chris@60 243 } else if (descriptor->controlOutputPortCount > 1) {
Chris@63 244
Chris@60 245 userDescription = tr("%1: Output %2")
Chris@60 246 .arg(pluginDescription)
Chris@60 247 .arg(j + 1);
Chris@63 248
Chris@60 249 } else {
Chris@63 250
Chris@60 251 userDescription = pluginDescription;
Chris@60 252 }
Chris@60 253
Chris@63 254
Chris@60 255 bool configurable = (descriptor->parameterCount > 0);
Chris@60 256
Chris@60 257 transforms[transformName] =
Chris@63 258 TransformDesc(tr("Real-Time Plugin"),
Chris@63 259 transformName,
Chris@60 260 userDescription,
Chris@60 261 userDescription,
Chris@60 262 descriptor->maker.c_str(),
Chris@63 263 units,
Chris@60 264 configurable);
Chris@60 265 }
Chris@60 266 }
Chris@16 267 }
Chris@16 268
Chris@16 269 QString
Chris@16 270 TransformFactory::getTransformDescription(TransformName name)
Chris@16 271 {
Chris@16 272 if (m_transforms.find(name) != m_transforms.end()) {
Chris@56 273 return m_transforms[name].description;
Chris@16 274 } else return "";
Chris@0 275 }
Chris@0 276
Chris@18 277 QString
Chris@18 278 TransformFactory::getTransformFriendlyName(TransformName name)
Chris@18 279 {
Chris@60 280 if (m_transforms.find(name) != m_transforms.end()) {
Chris@60 281 return m_transforms[name].friendlyName;
Chris@60 282 } else return "";
Chris@18 283 }
Chris@18 284
Chris@63 285 QString
Chris@63 286 TransformFactory::getTransformUnits(TransformName name)
Chris@63 287 {
Chris@63 288 if (m_transforms.find(name) != m_transforms.end()) {
Chris@63 289 return m_transforms[name].units;
Chris@63 290 } else return "";
Chris@63 291 }
Chris@63 292
Chris@56 293 bool
Chris@57 294 TransformFactory::isTransformConfigurable(TransformName name)
Chris@57 295 {
Chris@57 296 if (m_transforms.find(name) != m_transforms.end()) {
Chris@57 297 return m_transforms[name].configurable;
Chris@57 298 } else return false;
Chris@57 299 }
Chris@57 300
Chris@57 301 bool
Chris@64 302 TransformFactory::getTransformChannelRange(TransformName name,
Chris@64 303 int &min, int &max)
Chris@64 304 {
Chris@64 305 QString id = name.section(':', 0, 2);
Chris@64 306
Chris@64 307 if (FeatureExtractionPluginFactory::instanceFor(id)) {
Chris@64 308
Chris@66 309 Vamp::Plugin *plugin =
Chris@64 310 FeatureExtractionPluginFactory::instanceFor(id)->
Chris@64 311 instantiatePlugin(id, 48000);
Chris@64 312 if (!plugin) return false;
Chris@64 313
Chris@64 314 min = plugin->getMinChannelCount();
Chris@64 315 max = plugin->getMaxChannelCount();
Chris@64 316 delete plugin;
Chris@64 317
Chris@64 318 return true;
Chris@64 319
Chris@64 320 } else if (RealTimePluginFactory::instanceFor(id)) {
Chris@64 321
Chris@64 322 const RealTimePluginDescriptor *descriptor =
Chris@64 323 RealTimePluginFactory::instanceFor(id)->
Chris@64 324 getPluginDescriptor(id);
Chris@64 325 if (!descriptor) return false;
Chris@64 326
Chris@64 327 min = descriptor->audioInputPortCount;
Chris@64 328 max = descriptor->audioInputPortCount;
Chris@64 329
Chris@64 330 return true;
Chris@64 331 }
Chris@64 332
Chris@64 333 return false;
Chris@64 334 }
Chris@64 335
Chris@64 336 bool
Chris@56 337 TransformFactory::getConfigurationForTransform(TransformName name,
Chris@56 338 Model *inputModel,
Chris@64 339 int &channel,
Chris@56 340 QString &configurationXml)
Chris@0 341 {
Chris@56 342 QString id = name.section(':', 0, 2);
Chris@56 343 QString output = name.section(':', 3);
Chris@56 344
Chris@56 345 bool ok = false;
Chris@56 346 configurationXml = m_lastConfigurations[name];
Chris@56 347
Chris@56 348 std::cerr << "last configuration: " << configurationXml.toStdString() << std::endl;
Chris@56 349
Chris@66 350 Vamp::PluginBase *plugin = 0;
Chris@60 351
Chris@56 352 if (FeatureExtractionPluginFactory::instanceFor(id)) {
Chris@60 353
Chris@60 354 plugin = FeatureExtractionPluginFactory::instanceFor(id)->instantiatePlugin
Chris@56 355 (id, inputModel->getSampleRate());
Chris@60 356
Chris@60 357 } else if (RealTimePluginFactory::instanceFor(id)) {
Chris@60 358
Chris@60 359 plugin = RealTimePluginFactory::instanceFor(id)->instantiatePlugin
Chris@60 360 (id, 0, 0, inputModel->getSampleRate(), 1024, 1);
Chris@60 361 }
Chris@60 362
Chris@60 363 if (plugin) {
Chris@60 364 if (configurationXml != "") {
Chris@66 365 PluginXml(plugin).setParametersFromXml(configurationXml);
Chris@56 366 }
Chris@64 367
Chris@64 368 int sourceChannels = 1;
Chris@64 369 if (dynamic_cast<DenseTimeValueModel *>(inputModel)) {
Chris@64 370 sourceChannels = dynamic_cast<DenseTimeValueModel *>(inputModel)
Chris@64 371 ->getChannelCount();
Chris@64 372 }
Chris@64 373
Chris@64 374 int minChannels = 1, maxChannels = sourceChannels;
Chris@64 375 getTransformChannelRange(name, minChannels, maxChannels);
Chris@64 376
Chris@64 377 int targetChannels = sourceChannels;
Chris@64 378 if (sourceChannels < minChannels) targetChannels = minChannels;
Chris@64 379 if (sourceChannels > maxChannels) targetChannels = maxChannels;
Chris@64 380
Chris@64 381 int defaultChannel = channel;
Chris@64 382
Chris@64 383 PluginParameterDialog *dialog = new PluginParameterDialog(plugin,
Chris@64 384 sourceChannels,
Chris@64 385 targetChannels,
Chris@64 386 defaultChannel);
Chris@60 387 if (dialog->exec() == QDialog::Accepted) {
Chris@60 388 ok = true;
Chris@60 389 }
Chris@66 390 configurationXml = PluginXml(plugin).toXmlString();
Chris@64 391 channel = dialog->getChannel();
Chris@60 392 delete dialog;
Chris@60 393 delete plugin;
Chris@56 394 }
Chris@56 395
Chris@56 396 if (ok) m_lastConfigurations[name] = configurationXml;
Chris@56 397
Chris@56 398 return ok;
Chris@0 399 }
Chris@0 400
Chris@0 401 Transform *
Chris@0 402 TransformFactory::createTransform(TransformName name, Model *inputModel,
Chris@64 403 int channel, QString configurationXml, bool start)
Chris@0 404 {
Chris@0 405 Transform *transform = 0;
Chris@0 406
Chris@64 407 //!!! use channel
Chris@64 408
Chris@56 409 QString id = name.section(':', 0, 2);
Chris@56 410 QString output = name.section(':', 3);
Chris@56 411
Chris@56 412 if (FeatureExtractionPluginFactory::instanceFor(id)) {
Chris@56 413 transform = new FeatureExtractionPluginTransform(inputModel,
Chris@56 414 id,
Chris@64 415 channel,
Chris@56 416 configurationXml,
Chris@56 417 output);
Chris@60 418 } else if (RealTimePluginFactory::instanceFor(id)) {
Chris@60 419 transform = new RealTimePluginTransform(inputModel,
Chris@60 420 id,
Chris@64 421 channel,
Chris@60 422 configurationXml,
Chris@63 423 getTransformUnits(name),
Chris@60 424 output.toInt());
Chris@0 425 } else {
Chris@56 426 std::cerr << "TransformFactory::createTransform: Unknown transform "
Chris@56 427 << name.toStdString() << std::endl;
Chris@0 428 }
Chris@0 429
Chris@0 430 if (start && transform) transform->start();
Chris@16 431 transform->setObjectName(name);
Chris@0 432 return transform;
Chris@0 433 }
Chris@0 434
Chris@0 435 Model *
Chris@56 436 TransformFactory::transform(TransformName name, Model *inputModel,
Chris@64 437 int channel, QString configurationXml)
Chris@0 438 {
Chris@64 439 Transform *t = createTransform(name, inputModel, channel,
Chris@64 440 configurationXml, false);
Chris@0 441
Chris@0 442 if (!t) return 0;
Chris@0 443
Chris@0 444 connect(t, SIGNAL(finished()), this, SLOT(transformFinished()));
Chris@0 445
Chris@0 446 t->start();
Chris@0 447 return t->detachOutputModel();
Chris@0 448 }
Chris@0 449
Chris@0 450 void
Chris@0 451 TransformFactory::transformFinished()
Chris@0 452 {
Chris@0 453 QObject *s = sender();
Chris@0 454 Transform *transform = dynamic_cast<Transform *>(s);
Chris@0 455
Chris@0 456 if (!transform) {
Chris@0 457 std::cerr << "WARNING: TransformFactory::transformFinished: sender is not a transform" << std::endl;
Chris@0 458 return;
Chris@0 459 }
Chris@0 460
Chris@0 461 transform->wait(); // unnecessary but reassuring
Chris@0 462 delete transform;
Chris@0 463 }
Chris@0 464