annotate transform/TransformFactory.cpp @ 64:4d59dc469b0f

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