annotate plugin/transform/TransformFactory.cpp @ 325:82a2d3161e14

* Document FileSource
author Chris Cannam
date Thu, 01 Nov 2007 12:34:17 +0000
parents 32e50b620a6c
children bb6e4c46e202
rev   line source
Chris@320 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@320 2
Chris@320 3 /*
Chris@320 4 Sonic Visualiser
Chris@320 5 An audio file viewer and annotation editor.
Chris@320 6 Centre for Digital Music, Queen Mary, University of London.
Chris@320 7 This file copyright 2006 Chris Cannam and QMUL.
Chris@320 8
Chris@320 9 This program is free software; you can redistribute it and/or
Chris@320 10 modify it under the terms of the GNU General Public License as
Chris@320 11 published by the Free Software Foundation; either version 2 of the
Chris@320 12 License, or (at your option) any later version. See the file
Chris@320 13 COPYING included with this distribution for more information.
Chris@320 14 */
Chris@320 15
Chris@320 16 #include "TransformFactory.h"
Chris@320 17
Chris@320 18 #include "FeatureExtractionPluginTransform.h"
Chris@320 19 #include "RealTimePluginTransform.h"
Chris@320 20
Chris@320 21 #include "plugin/FeatureExtractionPluginFactory.h"
Chris@320 22 #include "plugin/RealTimePluginFactory.h"
Chris@320 23 #include "plugin/PluginXml.h"
Chris@320 24
Chris@320 25 #include "widgets/PluginParameterDialog.h"
Chris@320 26
Chris@320 27 #include "data/model/DenseTimeValueModel.h"
Chris@320 28
Chris@320 29 #include "vamp-sdk/PluginHostAdapter.h"
Chris@320 30
Chris@320 31 #include "audioio/AudioCallbackPlaySource.h" //!!! shouldn't include here
Chris@320 32
Chris@320 33 #include <iostream>
Chris@320 34 #include <set>
Chris@320 35
Chris@320 36 #include <QRegExp>
Chris@320 37
Chris@320 38 TransformFactory *
Chris@320 39 TransformFactory::m_instance = new TransformFactory;
Chris@320 40
Chris@320 41 TransformFactory *
Chris@320 42 TransformFactory::getInstance()
Chris@320 43 {
Chris@320 44 return m_instance;
Chris@320 45 }
Chris@320 46
Chris@320 47 TransformFactory::~TransformFactory()
Chris@320 48 {
Chris@320 49 }
Chris@320 50
Chris@320 51 TransformFactory::TransformList
Chris@320 52 TransformFactory::getAllTransforms()
Chris@320 53 {
Chris@320 54 if (m_transforms.empty()) populateTransforms();
Chris@320 55
Chris@320 56 std::set<TransformDesc> dset;
Chris@320 57 for (TransformDescriptionMap::const_iterator i = m_transforms.begin();
Chris@320 58 i != m_transforms.end(); ++i) {
Chris@320 59 dset.insert(i->second);
Chris@320 60 }
Chris@320 61
Chris@320 62 TransformList list;
Chris@320 63 for (std::set<TransformDesc>::const_iterator i = dset.begin();
Chris@320 64 i != dset.end(); ++i) {
Chris@320 65 list.push_back(*i);
Chris@320 66 }
Chris@320 67
Chris@320 68 return list;
Chris@320 69 }
Chris@320 70
Chris@320 71 std::vector<QString>
Chris@320 72 TransformFactory::getAllTransformTypes()
Chris@320 73 {
Chris@320 74 if (m_transforms.empty()) populateTransforms();
Chris@320 75
Chris@320 76 std::set<QString> types;
Chris@320 77 for (TransformDescriptionMap::const_iterator i = m_transforms.begin();
Chris@320 78 i != m_transforms.end(); ++i) {
Chris@320 79 types.insert(i->second.type);
Chris@320 80 }
Chris@320 81
Chris@320 82 std::vector<QString> rv;
Chris@320 83 for (std::set<QString>::iterator i = types.begin(); i != types.end(); ++i) {
Chris@320 84 rv.push_back(*i);
Chris@320 85 }
Chris@320 86
Chris@320 87 return rv;
Chris@320 88 }
Chris@320 89
Chris@320 90 std::vector<QString>
Chris@320 91 TransformFactory::getTransformCategories(QString transformType)
Chris@320 92 {
Chris@320 93 if (m_transforms.empty()) populateTransforms();
Chris@320 94
Chris@320 95 std::set<QString> categories;
Chris@320 96 for (TransformDescriptionMap::const_iterator i = m_transforms.begin();
Chris@320 97 i != m_transforms.end(); ++i) {
Chris@320 98 if (i->second.type == transformType) {
Chris@320 99 categories.insert(i->second.category);
Chris@320 100 }
Chris@320 101 }
Chris@320 102
Chris@320 103 bool haveEmpty = false;
Chris@320 104
Chris@320 105 std::vector<QString> rv;
Chris@320 106 for (std::set<QString>::iterator i = categories.begin();
Chris@320 107 i != categories.end(); ++i) {
Chris@320 108 if (*i != "") rv.push_back(*i);
Chris@320 109 else haveEmpty = true;
Chris@320 110 }
Chris@320 111
Chris@320 112 if (haveEmpty) rv.push_back(""); // make sure empty category sorts last
Chris@320 113
Chris@320 114 return rv;
Chris@320 115 }
Chris@320 116
Chris@320 117 std::vector<QString>
Chris@320 118 TransformFactory::getTransformMakers(QString transformType)
Chris@320 119 {
Chris@320 120 if (m_transforms.empty()) populateTransforms();
Chris@320 121
Chris@320 122 std::set<QString> makers;
Chris@320 123 for (TransformDescriptionMap::const_iterator i = m_transforms.begin();
Chris@320 124 i != m_transforms.end(); ++i) {
Chris@320 125 if (i->second.type == transformType) {
Chris@320 126 makers.insert(i->second.maker);
Chris@320 127 }
Chris@320 128 }
Chris@320 129
Chris@320 130 bool haveEmpty = false;
Chris@320 131
Chris@320 132 std::vector<QString> rv;
Chris@320 133 for (std::set<QString>::iterator i = makers.begin();
Chris@320 134 i != makers.end(); ++i) {
Chris@320 135 if (*i != "") rv.push_back(*i);
Chris@320 136 else haveEmpty = true;
Chris@320 137 }
Chris@320 138
Chris@320 139 if (haveEmpty) rv.push_back(""); // make sure empty category sorts last
Chris@320 140
Chris@320 141 return rv;
Chris@320 142 }
Chris@320 143
Chris@320 144 void
Chris@320 145 TransformFactory::populateTransforms()
Chris@320 146 {
Chris@320 147 TransformDescriptionMap transforms;
Chris@320 148
Chris@320 149 populateFeatureExtractionPlugins(transforms);
Chris@320 150 populateRealTimePlugins(transforms);
Chris@320 151
Chris@320 152 // disambiguate plugins with similar names
Chris@320 153
Chris@320 154 std::map<QString, int> names;
Chris@320 155 std::map<QString, QString> pluginSources;
Chris@320 156 std::map<QString, QString> pluginMakers;
Chris@320 157
Chris@320 158 for (TransformDescriptionMap::iterator i = transforms.begin();
Chris@320 159 i != transforms.end(); ++i) {
Chris@320 160
Chris@320 161 TransformDesc desc = i->second;
Chris@320 162
Chris@320 163 QString td = desc.name;
Chris@320 164 QString tn = td.section(": ", 0, 0);
Chris@320 165 QString pn = desc.identifier.section(":", 1, 1);
Chris@320 166
Chris@320 167 if (pluginSources.find(tn) != pluginSources.end()) {
Chris@320 168 if (pluginSources[tn] != pn && pluginMakers[tn] != desc.maker) {
Chris@320 169 ++names[tn];
Chris@320 170 }
Chris@320 171 } else {
Chris@320 172 ++names[tn];
Chris@320 173 pluginSources[tn] = pn;
Chris@320 174 pluginMakers[tn] = desc.maker;
Chris@320 175 }
Chris@320 176 }
Chris@320 177
Chris@320 178 std::map<QString, int> counts;
Chris@320 179 m_transforms.clear();
Chris@320 180
Chris@320 181 for (TransformDescriptionMap::iterator i = transforms.begin();
Chris@320 182 i != transforms.end(); ++i) {
Chris@320 183
Chris@320 184 TransformDesc desc = i->second;
Chris@320 185 QString identifier = desc.identifier;
Chris@320 186 QString maker = desc.maker;
Chris@320 187
Chris@320 188 QString td = desc.name;
Chris@320 189 QString tn = td.section(": ", 0, 0);
Chris@320 190 QString to = td.section(": ", 1);
Chris@320 191
Chris@320 192 if (names[tn] > 1) {
Chris@320 193 maker.replace(QRegExp(tr(" [\\(<].*$")), "");
Chris@320 194 tn = QString("%1 [%2]").arg(tn).arg(maker);
Chris@320 195 }
Chris@320 196
Chris@320 197 if (to != "") {
Chris@320 198 desc.name = QString("%1: %2").arg(tn).arg(to);
Chris@320 199 } else {
Chris@320 200 desc.name = tn;
Chris@320 201 }
Chris@320 202
Chris@320 203 m_transforms[identifier] = desc;
Chris@320 204 }
Chris@320 205 }
Chris@320 206
Chris@320 207 void
Chris@320 208 TransformFactory::populateFeatureExtractionPlugins(TransformDescriptionMap &transforms)
Chris@320 209 {
Chris@320 210 std::vector<QString> plugs =
Chris@320 211 FeatureExtractionPluginFactory::getAllPluginIdentifiers();
Chris@320 212
Chris@320 213 for (size_t i = 0; i < plugs.size(); ++i) {
Chris@320 214
Chris@320 215 QString pluginId = plugs[i];
Chris@320 216
Chris@320 217 FeatureExtractionPluginFactory *factory =
Chris@320 218 FeatureExtractionPluginFactory::instanceFor(pluginId);
Chris@320 219
Chris@320 220 if (!factory) {
Chris@320 221 std::cerr << "WARNING: TransformFactory::populateTransforms: No feature extraction plugin factory for instance " << pluginId.toLocal8Bit().data() << std::endl;
Chris@320 222 continue;
Chris@320 223 }
Chris@320 224
Chris@320 225 Vamp::Plugin *plugin =
Chris@320 226 factory->instantiatePlugin(pluginId, 48000);
Chris@320 227
Chris@320 228 if (!plugin) {
Chris@320 229 std::cerr << "WARNING: TransformFactory::populateTransforms: Failed to instantiate plugin " << pluginId.toLocal8Bit().data() << std::endl;
Chris@320 230 continue;
Chris@320 231 }
Chris@320 232
Chris@320 233 QString pluginName = plugin->getName().c_str();
Chris@320 234 QString category = factory->getPluginCategory(pluginId);
Chris@320 235
Chris@320 236 Vamp::Plugin::OutputList outputs =
Chris@320 237 plugin->getOutputDescriptors();
Chris@320 238
Chris@320 239 for (size_t j = 0; j < outputs.size(); ++j) {
Chris@320 240
Chris@320 241 QString transformId = QString("%1:%2")
Chris@320 242 .arg(pluginId).arg(outputs[j].identifier.c_str());
Chris@320 243
Chris@320 244 QString userName;
Chris@320 245 QString friendlyName;
Chris@320 246 QString units = outputs[j].unit.c_str();
Chris@320 247 QString description = plugin->getDescription().c_str();
Chris@320 248 QString maker = plugin->getMaker().c_str();
Chris@320 249 if (maker == "") maker = tr("<unknown maker>");
Chris@320 250
Chris@320 251 if (description == "") {
Chris@320 252 if (outputs.size() == 1) {
Chris@320 253 description = tr("Extract features using \"%1\" plugin (from %2)")
Chris@320 254 .arg(pluginName).arg(maker);
Chris@320 255 } else {
Chris@320 256 description = tr("Extract features using \"%1\" output of \"%2\" plugin (from %3)")
Chris@320 257 .arg(outputs[j].name.c_str()).arg(pluginName).arg(maker);
Chris@320 258 }
Chris@320 259 } else {
Chris@320 260 if (outputs.size() == 1) {
Chris@320 261 description = tr("%1 using \"%2\" plugin (from %3)")
Chris@320 262 .arg(description).arg(pluginName).arg(maker);
Chris@320 263 } else {
Chris@320 264 description = tr("%1 using \"%2\" output of \"%3\" plugin (from %4)")
Chris@320 265 .arg(description).arg(outputs[j].name.c_str()).arg(pluginName).arg(maker);
Chris@320 266 }
Chris@320 267 }
Chris@320 268
Chris@320 269 if (outputs.size() == 1) {
Chris@320 270 userName = pluginName;
Chris@320 271 friendlyName = pluginName;
Chris@320 272 } else {
Chris@320 273 userName = QString("%1: %2")
Chris@320 274 .arg(pluginName)
Chris@320 275 .arg(outputs[j].name.c_str());
Chris@320 276 friendlyName = outputs[j].name.c_str();
Chris@320 277 }
Chris@320 278
Chris@320 279 bool configurable = (!plugin->getPrograms().empty() ||
Chris@320 280 !plugin->getParameterDescriptors().empty());
Chris@320 281
Chris@320 282 // std::cerr << "Feature extraction plugin transform: " << transformId.toStdString() << std::endl;
Chris@320 283
Chris@320 284 transforms[transformId] =
Chris@320 285 TransformDesc(tr("Analysis"),
Chris@320 286 category,
Chris@320 287 transformId,
Chris@320 288 userName,
Chris@320 289 friendlyName,
Chris@320 290 description,
Chris@320 291 maker,
Chris@320 292 units,
Chris@320 293 configurable);
Chris@320 294 }
Chris@320 295
Chris@320 296 delete plugin;
Chris@320 297 }
Chris@320 298 }
Chris@320 299
Chris@320 300 void
Chris@320 301 TransformFactory::populateRealTimePlugins(TransformDescriptionMap &transforms)
Chris@320 302 {
Chris@320 303 std::vector<QString> plugs =
Chris@320 304 RealTimePluginFactory::getAllPluginIdentifiers();
Chris@320 305
Chris@320 306 static QRegExp unitRE("[\\[\\(]([A-Za-z0-9/]+)[\\)\\]]$");
Chris@320 307
Chris@320 308 for (size_t i = 0; i < plugs.size(); ++i) {
Chris@320 309
Chris@320 310 QString pluginId = plugs[i];
Chris@320 311
Chris@320 312 RealTimePluginFactory *factory =
Chris@320 313 RealTimePluginFactory::instanceFor(pluginId);
Chris@320 314
Chris@320 315 if (!factory) {
Chris@320 316 std::cerr << "WARNING: TransformFactory::populateTransforms: No real time plugin factory for instance " << pluginId.toLocal8Bit().data() << std::endl;
Chris@320 317 continue;
Chris@320 318 }
Chris@320 319
Chris@320 320 const RealTimePluginDescriptor *descriptor =
Chris@320 321 factory->getPluginDescriptor(pluginId);
Chris@320 322
Chris@320 323 if (!descriptor) {
Chris@320 324 std::cerr << "WARNING: TransformFactory::populateTransforms: Failed to query plugin " << pluginId.toLocal8Bit().data() << std::endl;
Chris@320 325 continue;
Chris@320 326 }
Chris@320 327
Chris@320 328 //!!! if (descriptor->controlOutputPortCount == 0 ||
Chris@320 329 // descriptor->audioInputPortCount == 0) continue;
Chris@320 330
Chris@320 331 // std::cout << "TransformFactory::populateRealTimePlugins: plugin " << pluginId.toStdString() << " has " << descriptor->controlOutputPortCount << " control output ports, " << descriptor->audioOutputPortCount << " audio outputs, " << descriptor->audioInputPortCount << " audio inputs" << std::endl;
Chris@320 332
Chris@320 333 QString pluginName = descriptor->name.c_str();
Chris@320 334 QString category = factory->getPluginCategory(pluginId);
Chris@320 335 bool configurable = (descriptor->parameterCount > 0);
Chris@320 336 QString maker = descriptor->maker.c_str();
Chris@320 337 if (maker == "") maker = tr("<unknown maker>");
Chris@320 338
Chris@320 339 if (descriptor->audioInputPortCount > 0) {
Chris@320 340
Chris@320 341 for (size_t j = 0; j < descriptor->controlOutputPortCount; ++j) {
Chris@320 342
Chris@320 343 QString transformId = QString("%1:%2").arg(pluginId).arg(j);
Chris@320 344 QString userName;
Chris@320 345 QString units;
Chris@320 346 QString portName;
Chris@320 347
Chris@320 348 if (j < descriptor->controlOutputPortNames.size() &&
Chris@320 349 descriptor->controlOutputPortNames[j] != "") {
Chris@320 350
Chris@320 351 portName = descriptor->controlOutputPortNames[j].c_str();
Chris@320 352
Chris@320 353 userName = tr("%1: %2")
Chris@320 354 .arg(pluginName)
Chris@320 355 .arg(portName);
Chris@320 356
Chris@320 357 if (unitRE.indexIn(portName) >= 0) {
Chris@320 358 units = unitRE.cap(1);
Chris@320 359 }
Chris@320 360
Chris@320 361 } else if (descriptor->controlOutputPortCount > 1) {
Chris@320 362
Chris@320 363 userName = tr("%1: Output %2")
Chris@320 364 .arg(pluginName)
Chris@320 365 .arg(j + 1);
Chris@320 366
Chris@320 367 } else {
Chris@320 368
Chris@320 369 userName = pluginName;
Chris@320 370 }
Chris@320 371
Chris@320 372 QString description;
Chris@320 373
Chris@320 374 if (portName != "") {
Chris@320 375 description = tr("Extract \"%1\" data output from \"%2\" effect plugin (from %3)")
Chris@320 376 .arg(portName)
Chris@320 377 .arg(pluginName)
Chris@320 378 .arg(maker);
Chris@320 379 } else {
Chris@320 380 description = tr("Extract data output %1 from \"%2\" effect plugin (from %3)")
Chris@320 381 .arg(j + 1)
Chris@320 382 .arg(pluginName)
Chris@320 383 .arg(maker);
Chris@320 384 }
Chris@320 385
Chris@320 386 transforms[transformId] =
Chris@320 387 TransformDesc(tr("Effects Data"),
Chris@320 388 category,
Chris@320 389 transformId,
Chris@320 390 userName,
Chris@320 391 userName,
Chris@320 392 description,
Chris@320 393 maker,
Chris@320 394 units,
Chris@320 395 configurable);
Chris@320 396 }
Chris@320 397 }
Chris@320 398
Chris@320 399 if (!descriptor->isSynth || descriptor->audioInputPortCount > 0) {
Chris@320 400
Chris@320 401 if (descriptor->audioOutputPortCount > 0) {
Chris@320 402
Chris@320 403 QString transformId = QString("%1:A").arg(pluginId);
Chris@320 404 QString type = tr("Effects");
Chris@320 405
Chris@320 406 QString description = tr("Transform audio signal with \"%1\" effect plugin (from %2)")
Chris@320 407 .arg(pluginName)
Chris@320 408 .arg(maker);
Chris@320 409
Chris@320 410 if (descriptor->audioInputPortCount == 0) {
Chris@320 411 type = tr("Generators");
Chris@320 412 QString description = tr("Generate audio signal using \"%1\" plugin (from %2)")
Chris@320 413 .arg(pluginName)
Chris@320 414 .arg(maker);
Chris@320 415 }
Chris@320 416
Chris@320 417 transforms[transformId] =
Chris@320 418 TransformDesc(type,
Chris@320 419 category,
Chris@320 420 transformId,
Chris@320 421 pluginName,
Chris@320 422 pluginName,
Chris@320 423 description,
Chris@320 424 maker,
Chris@320 425 "",
Chris@320 426 configurable);
Chris@320 427 }
Chris@320 428 }
Chris@320 429 }
Chris@320 430 }
Chris@320 431
Chris@320 432 QString
Chris@320 433 TransformFactory::getTransformName(TransformId identifier)
Chris@320 434 {
Chris@320 435 if (m_transforms.find(identifier) != m_transforms.end()) {
Chris@320 436 return m_transforms[identifier].name;
Chris@320 437 } else return "";
Chris@320 438 }
Chris@320 439
Chris@320 440 QString
Chris@320 441 TransformFactory::getTransformFriendlyName(TransformId identifier)
Chris@320 442 {
Chris@320 443 if (m_transforms.find(identifier) != m_transforms.end()) {
Chris@320 444 return m_transforms[identifier].friendlyName;
Chris@320 445 } else return "";
Chris@320 446 }
Chris@320 447
Chris@320 448 QString
Chris@320 449 TransformFactory::getTransformUnits(TransformId identifier)
Chris@320 450 {
Chris@320 451 if (m_transforms.find(identifier) != m_transforms.end()) {
Chris@320 452 return m_transforms[identifier].units;
Chris@320 453 } else return "";
Chris@320 454 }
Chris@320 455
Chris@320 456 bool
Chris@320 457 TransformFactory::isTransformConfigurable(TransformId identifier)
Chris@320 458 {
Chris@320 459 if (m_transforms.find(identifier) != m_transforms.end()) {
Chris@320 460 return m_transforms[identifier].configurable;
Chris@320 461 } else return false;
Chris@320 462 }
Chris@320 463
Chris@320 464 bool
Chris@320 465 TransformFactory::getTransformChannelRange(TransformId identifier,
Chris@320 466 int &min, int &max)
Chris@320 467 {
Chris@320 468 QString id = identifier.section(':', 0, 2);
Chris@320 469
Chris@320 470 if (FeatureExtractionPluginFactory::instanceFor(id)) {
Chris@320 471
Chris@320 472 Vamp::Plugin *plugin =
Chris@320 473 FeatureExtractionPluginFactory::instanceFor(id)->
Chris@320 474 instantiatePlugin(id, 48000);
Chris@320 475 if (!plugin) return false;
Chris@320 476
Chris@320 477 min = plugin->getMinChannelCount();
Chris@320 478 max = plugin->getMaxChannelCount();
Chris@320 479 delete plugin;
Chris@320 480
Chris@320 481 return true;
Chris@320 482
Chris@320 483 } else if (RealTimePluginFactory::instanceFor(id)) {
Chris@320 484
Chris@320 485 const RealTimePluginDescriptor *descriptor =
Chris@320 486 RealTimePluginFactory::instanceFor(id)->
Chris@320 487 getPluginDescriptor(id);
Chris@320 488 if (!descriptor) return false;
Chris@320 489
Chris@320 490 min = descriptor->audioInputPortCount;
Chris@320 491 max = descriptor->audioInputPortCount;
Chris@320 492
Chris@320 493 return true;
Chris@320 494 }
Chris@320 495
Chris@320 496 return false;
Chris@320 497 }
Chris@320 498
Chris@320 499 bool
Chris@320 500 TransformFactory::getChannelRange(TransformId identifier, Vamp::PluginBase *plugin,
Chris@320 501 int &minChannels, int &maxChannels)
Chris@320 502 {
Chris@320 503 Vamp::Plugin *vp = 0;
Chris@320 504 if ((vp = dynamic_cast<Vamp::Plugin *>(plugin)) ||
Chris@320 505 (vp = dynamic_cast<Vamp::PluginHostAdapter *>(plugin))) {
Chris@320 506 minChannels = vp->getMinChannelCount();
Chris@320 507 maxChannels = vp->getMaxChannelCount();
Chris@320 508 return true;
Chris@320 509 } else {
Chris@320 510 return getTransformChannelRange(identifier, minChannels, maxChannels);
Chris@320 511 }
Chris@320 512 }
Chris@320 513
Chris@320 514 Model *
Chris@320 515 TransformFactory::getConfigurationForTransform(TransformId identifier,
Chris@320 516 const std::vector<Model *> &candidateInputModels,
Chris@320 517 PluginTransform::ExecutionContext &context,
Chris@320 518 QString &configurationXml,
Chris@320 519 AudioCallbackPlaySource *source,
Chris@320 520 size_t startFrame,
Chris@320 521 size_t duration)
Chris@320 522 {
Chris@320 523 if (candidateInputModels.empty()) return 0;
Chris@320 524
Chris@320 525 //!!! This will need revision -- we'll have to have a callback
Chris@320 526 //from the dialog for when the candidate input model is changed,
Chris@320 527 //as we'll need to reinitialise the channel settings in the dialog
Chris@320 528 Model *inputModel = candidateInputModels[0]; //!!! for now
Chris@320 529 QStringList candidateModelNames;
Chris@320 530 std::map<QString, Model *> modelMap;
Chris@320 531 for (size_t i = 0; i < candidateInputModels.size(); ++i) {
Chris@320 532 QString modelName = candidateInputModels[i]->objectName();
Chris@320 533 QString origModelName = modelName;
Chris@320 534 int dupcount = 1;
Chris@320 535 while (modelMap.find(modelName) != modelMap.end()) {
Chris@320 536 modelName = tr("%1 <%2>").arg(origModelName).arg(++dupcount);
Chris@320 537 }
Chris@320 538 modelMap[modelName] = candidateInputModels[i];
Chris@320 539 candidateModelNames.push_back(modelName);
Chris@320 540 }
Chris@320 541
Chris@320 542 QString id = identifier.section(':', 0, 2);
Chris@320 543 QString output = identifier.section(':', 3);
Chris@320 544 QString outputLabel = "";
Chris@320 545 QString outputDescription = "";
Chris@320 546
Chris@320 547 bool ok = false;
Chris@320 548 configurationXml = m_lastConfigurations[identifier];
Chris@320 549
Chris@320 550 // std::cerr << "last configuration: " << configurationXml.toStdString() << std::endl;
Chris@320 551
Chris@320 552 Vamp::PluginBase *plugin = 0;
Chris@320 553
Chris@320 554 bool frequency = false;
Chris@320 555 bool effect = false;
Chris@320 556 bool generator = false;
Chris@320 557
Chris@320 558 if (FeatureExtractionPluginFactory::instanceFor(id)) {
Chris@320 559
Chris@320 560 std::cerr << "getConfigurationForTransform: instantiating Vamp plugin" << std::endl;
Chris@320 561
Chris@320 562 Vamp::Plugin *vp =
Chris@320 563 FeatureExtractionPluginFactory::instanceFor(id)->instantiatePlugin
Chris@320 564 (id, inputModel->getSampleRate());
Chris@320 565
Chris@320 566 if (vp) {
Chris@320 567
Chris@320 568 plugin = vp;
Chris@320 569 frequency = (vp->getInputDomain() == Vamp::Plugin::FrequencyDomain);
Chris@320 570
Chris@320 571 std::vector<Vamp::Plugin::OutputDescriptor> od =
Chris@320 572 vp->getOutputDescriptors();
Chris@320 573 if (od.size() > 1) {
Chris@320 574 for (size_t i = 0; i < od.size(); ++i) {
Chris@320 575 if (od[i].identifier == output.toStdString()) {
Chris@320 576 outputLabel = od[i].name.c_str();
Chris@320 577 outputDescription = od[i].description.c_str();
Chris@320 578 break;
Chris@320 579 }
Chris@320 580 }
Chris@320 581 }
Chris@320 582 }
Chris@320 583
Chris@320 584 } else if (RealTimePluginFactory::instanceFor(id)) {
Chris@320 585
Chris@320 586 RealTimePluginFactory *factory = RealTimePluginFactory::instanceFor(id);
Chris@320 587 const RealTimePluginDescriptor *desc = factory->getPluginDescriptor(id);
Chris@320 588
Chris@320 589 if (desc->audioInputPortCount > 0 &&
Chris@320 590 desc->audioOutputPortCount > 0 &&
Chris@320 591 !desc->isSynth) {
Chris@320 592 effect = true;
Chris@320 593 }
Chris@320 594
Chris@320 595 if (desc->audioInputPortCount == 0) {
Chris@320 596 generator = true;
Chris@320 597 }
Chris@320 598
Chris@320 599 if (output != "A") {
Chris@320 600 int outputNo = output.toInt();
Chris@320 601 if (outputNo >= 0 && outputNo < int(desc->controlOutputPortCount)) {
Chris@320 602 outputLabel = desc->controlOutputPortNames[outputNo].c_str();
Chris@320 603 }
Chris@320 604 }
Chris@320 605
Chris@320 606 size_t sampleRate = inputModel->getSampleRate();
Chris@320 607 size_t blockSize = 1024;
Chris@320 608 size_t channels = 1;
Chris@320 609 if (effect && source) {
Chris@320 610 sampleRate = source->getTargetSampleRate();
Chris@320 611 blockSize = source->getTargetBlockSize();
Chris@320 612 channels = source->getTargetChannelCount();
Chris@320 613 }
Chris@320 614
Chris@320 615 RealTimePluginInstance *rtp = factory->instantiatePlugin
Chris@320 616 (id, 0, 0, sampleRate, blockSize, channels);
Chris@320 617
Chris@320 618 plugin = rtp;
Chris@320 619
Chris@320 620 if (effect && source && rtp) {
Chris@320 621 source->setAuditioningPlugin(rtp);
Chris@320 622 }
Chris@320 623 }
Chris@320 624
Chris@320 625 if (plugin) {
Chris@320 626
Chris@320 627 context = PluginTransform::ExecutionContext(context.channel, plugin);
Chris@320 628
Chris@320 629 if (configurationXml != "") {
Chris@320 630 PluginXml(plugin).setParametersFromXml(configurationXml);
Chris@320 631 }
Chris@320 632
Chris@320 633 int sourceChannels = 1;
Chris@320 634 if (dynamic_cast<DenseTimeValueModel *>(inputModel)) {
Chris@320 635 sourceChannels = dynamic_cast<DenseTimeValueModel *>(inputModel)
Chris@320 636 ->getChannelCount();
Chris@320 637 }
Chris@320 638
Chris@320 639 int minChannels = 1, maxChannels = sourceChannels;
Chris@320 640 getChannelRange(identifier, plugin, minChannels, maxChannels);
Chris@320 641
Chris@320 642 int targetChannels = sourceChannels;
Chris@320 643 if (!effect) {
Chris@320 644 if (sourceChannels < minChannels) targetChannels = minChannels;
Chris@320 645 if (sourceChannels > maxChannels) targetChannels = maxChannels;
Chris@320 646 }
Chris@320 647
Chris@320 648 int defaultChannel = context.channel;
Chris@320 649
Chris@320 650 PluginParameterDialog *dialog = new PluginParameterDialog(plugin);
Chris@320 651
Chris@320 652 if (candidateModelNames.size() > 1 && !generator) {
Chris@320 653 dialog->setCandidateInputModels(candidateModelNames);
Chris@320 654 }
Chris@320 655
Chris@320 656 if (startFrame != 0 || duration != 0) {
Chris@320 657 dialog->setShowSelectionOnlyOption(true);
Chris@320 658 }
Chris@320 659
Chris@320 660 if (targetChannels > 0) {
Chris@320 661 dialog->setChannelArrangement(sourceChannels, targetChannels,
Chris@320 662 defaultChannel);
Chris@320 663 }
Chris@320 664
Chris@320 665 dialog->setOutputLabel(outputLabel, outputDescription);
Chris@320 666
Chris@320 667 dialog->setShowProcessingOptions(true, frequency);
Chris@320 668
Chris@320 669 if (dialog->exec() == QDialog::Accepted) {
Chris@320 670 ok = true;
Chris@320 671 }
Chris@320 672
Chris@320 673 QString selectedInput = dialog->getInputModel();
Chris@320 674 if (selectedInput != "") {
Chris@320 675 if (modelMap.find(selectedInput) != modelMap.end()) {
Chris@320 676 inputModel = modelMap[selectedInput];
Chris@320 677 std::cerr << "Found selected input \"" << selectedInput.toStdString() << "\" in model map, result is " << inputModel << std::endl;
Chris@320 678 } else {
Chris@320 679 std::cerr << "Failed to find selected input \"" << selectedInput.toStdString() << "\" in model map" << std::endl;
Chris@320 680 }
Chris@320 681 } else {
Chris@320 682 std::cerr << "Selected input empty: \"" << selectedInput.toStdString() << "\"" << std::endl;
Chris@320 683 }
Chris@320 684
Chris@320 685 configurationXml = PluginXml(plugin).toXmlString();
Chris@320 686 context.channel = dialog->getChannel();
Chris@320 687
Chris@320 688 if (startFrame != 0 || duration != 0) {
Chris@320 689 if (dialog->getSelectionOnly()) {
Chris@320 690 context.startFrame = startFrame;
Chris@320 691 context.duration = duration;
Chris@320 692 }
Chris@320 693 }
Chris@320 694
Chris@320 695 dialog->getProcessingParameters(context.stepSize,
Chris@320 696 context.blockSize,
Chris@320 697 context.windowType);
Chris@320 698
Chris@320 699 context.makeConsistentWithPlugin(plugin);
Chris@320 700
Chris@320 701 delete dialog;
Chris@320 702
Chris@320 703 if (effect && source) {
Chris@320 704 source->setAuditioningPlugin(0); // will delete our plugin
Chris@320 705 } else {
Chris@320 706 delete plugin;
Chris@320 707 }
Chris@320 708 }
Chris@320 709
Chris@320 710 if (ok) m_lastConfigurations[identifier] = configurationXml;
Chris@320 711
Chris@320 712 return ok ? inputModel : 0;
Chris@320 713 }
Chris@320 714
Chris@320 715 PluginTransform::ExecutionContext
Chris@320 716 TransformFactory::getDefaultContextForTransform(TransformId identifier,
Chris@320 717 Model *inputModel)
Chris@320 718 {
Chris@320 719 PluginTransform::ExecutionContext context(-1);
Chris@320 720
Chris@320 721 QString id = identifier.section(':', 0, 2);
Chris@320 722
Chris@320 723 if (FeatureExtractionPluginFactory::instanceFor(id)) {
Chris@320 724
Chris@320 725 Vamp::Plugin *vp =
Chris@320 726 FeatureExtractionPluginFactory::instanceFor(id)->instantiatePlugin
Chris@320 727 (id, inputModel ? inputModel->getSampleRate() : 48000);
Chris@320 728
Chris@320 729 if (vp) {
Chris@320 730 context = PluginTransform::ExecutionContext(-1, vp);
Chris@320 731 delete vp;
Chris@320 732 }
Chris@320 733 }
Chris@320 734
Chris@320 735 return context;
Chris@320 736 }
Chris@320 737
Chris@320 738 Transform *
Chris@320 739 TransformFactory::createTransform(TransformId identifier, Model *inputModel,
Chris@320 740 const PluginTransform::ExecutionContext &context,
Chris@320 741 QString configurationXml)
Chris@320 742 {
Chris@320 743 Transform *transform = 0;
Chris@320 744
Chris@320 745 QString id = identifier.section(':', 0, 2);
Chris@320 746 QString output = identifier.section(':', 3);
Chris@320 747
Chris@320 748 if (FeatureExtractionPluginFactory::instanceFor(id)) {
Chris@320 749 transform = new FeatureExtractionPluginTransform(inputModel,
Chris@320 750 id,
Chris@320 751 context,
Chris@320 752 configurationXml,
Chris@320 753 output);
Chris@320 754 } else if (RealTimePluginFactory::instanceFor(id)) {
Chris@320 755 transform = new RealTimePluginTransform(inputModel,
Chris@320 756 id,
Chris@320 757 context,
Chris@320 758 configurationXml,
Chris@320 759 getTransformUnits(identifier),
Chris@320 760 output == "A" ? -1 :
Chris@320 761 output.toInt());
Chris@320 762 } else {
Chris@320 763 std::cerr << "TransformFactory::createTransform: Unknown transform \""
Chris@320 764 << identifier.toStdString() << "\"" << std::endl;
Chris@320 765 return transform;
Chris@320 766 }
Chris@320 767
Chris@320 768 if (transform) transform->setObjectName(identifier);
Chris@320 769 return transform;
Chris@320 770 }
Chris@320 771
Chris@320 772 Model *
Chris@320 773 TransformFactory::transform(TransformId identifier, Model *inputModel,
Chris@320 774 const PluginTransform::ExecutionContext &context,
Chris@320 775 QString configurationXml)
Chris@320 776 {
Chris@320 777 Transform *t = createTransform(identifier, inputModel, context,
Chris@320 778 configurationXml);
Chris@320 779
Chris@320 780 if (!t) return 0;
Chris@320 781
Chris@320 782 connect(t, SIGNAL(finished()), this, SLOT(transformFinished()));
Chris@320 783
Chris@320 784 m_runningTransforms.insert(t);
Chris@320 785
Chris@320 786 t->start();
Chris@320 787 Model *model = t->detachOutputModel();
Chris@320 788
Chris@320 789 if (model) {
Chris@320 790 QString imn = inputModel->objectName();
Chris@320 791 QString trn = getTransformFriendlyName(identifier);
Chris@320 792 if (imn != "") {
Chris@320 793 if (trn != "") {
Chris@320 794 model->setObjectName(tr("%1: %2").arg(imn).arg(trn));
Chris@320 795 } else {
Chris@320 796 model->setObjectName(imn);
Chris@320 797 }
Chris@320 798 } else if (trn != "") {
Chris@320 799 model->setObjectName(trn);
Chris@320 800 }
Chris@320 801 } else {
Chris@320 802 t->wait();
Chris@320 803 }
Chris@320 804
Chris@320 805 return model;
Chris@320 806 }
Chris@320 807
Chris@320 808 void
Chris@320 809 TransformFactory::transformFinished()
Chris@320 810 {
Chris@320 811 QObject *s = sender();
Chris@320 812 Transform *transform = dynamic_cast<Transform *>(s);
Chris@320 813
Chris@320 814 std::cerr << "TransformFactory::transformFinished(" << transform << ")" << std::endl;
Chris@320 815
Chris@320 816 if (!transform) {
Chris@320 817 std::cerr << "WARNING: TransformFactory::transformFinished: sender is not a transform" << std::endl;
Chris@320 818 return;
Chris@320 819 }
Chris@320 820
Chris@320 821 if (m_runningTransforms.find(transform) == m_runningTransforms.end()) {
Chris@320 822 std::cerr << "WARNING: TransformFactory::transformFinished("
Chris@320 823 << transform
Chris@320 824 << "): I have no record of this transform running!"
Chris@320 825 << std::endl;
Chris@320 826 }
Chris@320 827
Chris@320 828 m_runningTransforms.erase(transform);
Chris@320 829
Chris@320 830 transform->wait(); // unnecessary but reassuring
Chris@320 831 delete transform;
Chris@320 832 }
Chris@320 833
Chris@320 834 void
Chris@320 835 TransformFactory::modelAboutToBeDeleted(Model *m)
Chris@320 836 {
Chris@320 837 TransformSet affected;
Chris@320 838
Chris@320 839 for (TransformSet::iterator i = m_runningTransforms.begin();
Chris@320 840 i != m_runningTransforms.end(); ++i) {
Chris@320 841
Chris@320 842 Transform *t = *i;
Chris@320 843
Chris@320 844 if (t->getInputModel() == m || t->getOutputModel() == m) {
Chris@320 845 affected.insert(t);
Chris@320 846 }
Chris@320 847 }
Chris@320 848
Chris@320 849 for (TransformSet::iterator i = affected.begin();
Chris@320 850 i != affected.end(); ++i) {
Chris@320 851
Chris@320 852 Transform *t = *i;
Chris@320 853
Chris@320 854 t->abandon();
Chris@320 855
Chris@320 856 t->wait(); // this should eventually call back on
Chris@320 857 // transformFinished, which will remove from
Chris@320 858 // m_runningTransforms and delete.
Chris@320 859 }
Chris@320 860 }
Chris@320 861