annotate plugin/transform/ModelTransformerFactory.cpp @ 331:f620ce48c950

* Further naming change: Transformer -> ModelTransformer. The Transform class now describes a thing that can be done, and the ModelTransformer does it to a Model.
author Chris Cannam
date Wed, 07 Nov 2007 12:59:01 +0000
parents plugin/transform/TransformerFactory.cpp@3179d8b29336
children 13e5870040e6
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@331 16 #include "ModelTransformerFactory.h"
Chris@320 17
Chris@331 18 #include "FeatureExtractionModelTransformer.h"
Chris@331 19 #include "RealTimeEffectModelTransformer.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@331 38 ModelTransformerFactory *
Chris@331 39 ModelTransformerFactory::m_instance = new ModelTransformerFactory;
Chris@320 40
Chris@331 41 ModelTransformerFactory *
Chris@331 42 ModelTransformerFactory::getInstance()
Chris@320 43 {
Chris@320 44 return m_instance;
Chris@320 45 }
Chris@320 46
Chris@331 47 ModelTransformerFactory::~ModelTransformerFactory()
Chris@320 48 {
Chris@320 49 }
Chris@320 50
Chris@329 51 TransformList
Chris@331 52 ModelTransformerFactory::getAllTransforms()
Chris@320 53 {
Chris@329 54 if (m_transforms.empty()) populateTransforms();
Chris@320 55
Chris@329 56 std::set<TransformDescription> dset;
Chris@329 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@329 62 TransformList list;
Chris@329 63 for (std::set<TransformDescription>::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@331 72 ModelTransformerFactory::getAllTransformerTypes()
Chris@320 73 {
Chris@329 74 if (m_transforms.empty()) populateTransforms();
Chris@320 75
Chris@320 76 std::set<QString> types;
Chris@329 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@331 91 ModelTransformerFactory::getTransformerCategories(QString transformType)
Chris@320 92 {
Chris@329 93 if (m_transforms.empty()) populateTransforms();
Chris@320 94
Chris@320 95 std::set<QString> categories;
Chris@329 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@331 118 ModelTransformerFactory::getTransformerMakers(QString transformType)
Chris@320 119 {
Chris@329 120 if (m_transforms.empty()) populateTransforms();
Chris@320 121
Chris@320 122 std::set<QString> makers;
Chris@329 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@331 145 ModelTransformerFactory::populateTransforms()
Chris@320 146 {
Chris@329 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@329 158 for (TransformDescriptionMap::iterator i = transforms.begin();
Chris@320 159 i != transforms.end(); ++i) {
Chris@320 160
Chris@329 161 TransformDescription 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@329 181 for (TransformDescriptionMap::iterator i = transforms.begin();
Chris@320 182 i != transforms.end(); ++i) {
Chris@320 183
Chris@329 184 TransformDescription 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@331 208 ModelTransformerFactory::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@331 221 std::cerr << "WARNING: ModelTransformerFactory::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@331 229 std::cerr << "WARNING: ModelTransformerFactory::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@329 285 TransformDescription(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@331 301 ModelTransformerFactory::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@331 316 std::cerr << "WARNING: ModelTransformerFactory::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@331 324 std::cerr << "WARNING: ModelTransformerFactory::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@331 331 // std::cout << "ModelTransformerFactory::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@329 387 TransformDescription(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@328 406 QString description = tr("Transformer 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@329 418 TransformDescription(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@326 432 bool
Chris@331 433 ModelTransformerFactory::haveTransformer(TransformId identifier)
Chris@326 434 {
Chris@326 435 return (m_transforms.find(identifier) != m_transforms.end());
Chris@326 436 }
Chris@326 437
Chris@320 438 QString
Chris@331 439 ModelTransformerFactory::getTransformerName(TransformId identifier)
Chris@320 440 {
Chris@320 441 if (m_transforms.find(identifier) != m_transforms.end()) {
Chris@320 442 return m_transforms[identifier].name;
Chris@320 443 } else return "";
Chris@320 444 }
Chris@320 445
Chris@320 446 QString
Chris@331 447 ModelTransformerFactory::getTransformerFriendlyName(TransformId identifier)
Chris@320 448 {
Chris@320 449 if (m_transforms.find(identifier) != m_transforms.end()) {
Chris@320 450 return m_transforms[identifier].friendlyName;
Chris@320 451 } else return "";
Chris@320 452 }
Chris@320 453
Chris@320 454 QString
Chris@331 455 ModelTransformerFactory::getTransformerUnits(TransformId identifier)
Chris@320 456 {
Chris@320 457 if (m_transforms.find(identifier) != m_transforms.end()) {
Chris@320 458 return m_transforms[identifier].units;
Chris@320 459 } else return "";
Chris@320 460 }
Chris@320 461
Chris@320 462 bool
Chris@331 463 ModelTransformerFactory::isTransformerConfigurable(TransformId identifier)
Chris@320 464 {
Chris@320 465 if (m_transforms.find(identifier) != m_transforms.end()) {
Chris@320 466 return m_transforms[identifier].configurable;
Chris@320 467 } else return false;
Chris@320 468 }
Chris@320 469
Chris@320 470 bool
Chris@331 471 ModelTransformerFactory::getTransformerChannelRange(TransformId identifier,
Chris@320 472 int &min, int &max)
Chris@320 473 {
Chris@320 474 QString id = identifier.section(':', 0, 2);
Chris@320 475
Chris@320 476 if (FeatureExtractionPluginFactory::instanceFor(id)) {
Chris@320 477
Chris@320 478 Vamp::Plugin *plugin =
Chris@320 479 FeatureExtractionPluginFactory::instanceFor(id)->
Chris@320 480 instantiatePlugin(id, 48000);
Chris@320 481 if (!plugin) return false;
Chris@320 482
Chris@320 483 min = plugin->getMinChannelCount();
Chris@320 484 max = plugin->getMaxChannelCount();
Chris@320 485 delete plugin;
Chris@320 486
Chris@320 487 return true;
Chris@320 488
Chris@320 489 } else if (RealTimePluginFactory::instanceFor(id)) {
Chris@320 490
Chris@320 491 const RealTimePluginDescriptor *descriptor =
Chris@320 492 RealTimePluginFactory::instanceFor(id)->
Chris@320 493 getPluginDescriptor(id);
Chris@320 494 if (!descriptor) return false;
Chris@320 495
Chris@320 496 min = descriptor->audioInputPortCount;
Chris@320 497 max = descriptor->audioInputPortCount;
Chris@320 498
Chris@320 499 return true;
Chris@320 500 }
Chris@320 501
Chris@320 502 return false;
Chris@320 503 }
Chris@320 504
Chris@320 505 bool
Chris@331 506 ModelTransformerFactory::getChannelRange(TransformId identifier, Vamp::PluginBase *plugin,
Chris@320 507 int &minChannels, int &maxChannels)
Chris@320 508 {
Chris@320 509 Vamp::Plugin *vp = 0;
Chris@320 510 if ((vp = dynamic_cast<Vamp::Plugin *>(plugin)) ||
Chris@320 511 (vp = dynamic_cast<Vamp::PluginHostAdapter *>(plugin))) {
Chris@320 512 minChannels = vp->getMinChannelCount();
Chris@320 513 maxChannels = vp->getMaxChannelCount();
Chris@320 514 return true;
Chris@320 515 } else {
Chris@328 516 return getTransformerChannelRange(identifier, minChannels, maxChannels);
Chris@320 517 }
Chris@320 518 }
Chris@320 519
Chris@320 520 Model *
Chris@331 521 ModelTransformerFactory::getConfigurationForTransformer(TransformId identifier,
Chris@320 522 const std::vector<Model *> &candidateInputModels,
Chris@328 523 PluginTransformer::ExecutionContext &context,
Chris@320 524 QString &configurationXml,
Chris@320 525 AudioCallbackPlaySource *source,
Chris@320 526 size_t startFrame,
Chris@320 527 size_t duration)
Chris@320 528 {
Chris@320 529 if (candidateInputModels.empty()) return 0;
Chris@320 530
Chris@320 531 //!!! This will need revision -- we'll have to have a callback
Chris@320 532 //from the dialog for when the candidate input model is changed,
Chris@320 533 //as we'll need to reinitialise the channel settings in the dialog
Chris@320 534 Model *inputModel = candidateInputModels[0]; //!!! for now
Chris@320 535 QStringList candidateModelNames;
Chris@320 536 std::map<QString, Model *> modelMap;
Chris@320 537 for (size_t i = 0; i < candidateInputModels.size(); ++i) {
Chris@320 538 QString modelName = candidateInputModels[i]->objectName();
Chris@320 539 QString origModelName = modelName;
Chris@320 540 int dupcount = 1;
Chris@320 541 while (modelMap.find(modelName) != modelMap.end()) {
Chris@320 542 modelName = tr("%1 <%2>").arg(origModelName).arg(++dupcount);
Chris@320 543 }
Chris@320 544 modelMap[modelName] = candidateInputModels[i];
Chris@320 545 candidateModelNames.push_back(modelName);
Chris@320 546 }
Chris@320 547
Chris@320 548 QString id = identifier.section(':', 0, 2);
Chris@320 549 QString output = identifier.section(':', 3);
Chris@320 550 QString outputLabel = "";
Chris@320 551 QString outputDescription = "";
Chris@320 552
Chris@320 553 bool ok = false;
Chris@320 554 configurationXml = m_lastConfigurations[identifier];
Chris@320 555
Chris@320 556 // std::cerr << "last configuration: " << configurationXml.toStdString() << std::endl;
Chris@320 557
Chris@320 558 Vamp::PluginBase *plugin = 0;
Chris@320 559
Chris@320 560 bool frequency = false;
Chris@320 561 bool effect = false;
Chris@320 562 bool generator = false;
Chris@320 563
Chris@320 564 if (FeatureExtractionPluginFactory::instanceFor(id)) {
Chris@320 565
Chris@328 566 std::cerr << "getConfigurationForTransformer: instantiating Vamp plugin" << std::endl;
Chris@320 567
Chris@320 568 Vamp::Plugin *vp =
Chris@320 569 FeatureExtractionPluginFactory::instanceFor(id)->instantiatePlugin
Chris@320 570 (id, inputModel->getSampleRate());
Chris@320 571
Chris@320 572 if (vp) {
Chris@320 573
Chris@320 574 plugin = vp;
Chris@320 575 frequency = (vp->getInputDomain() == Vamp::Plugin::FrequencyDomain);
Chris@320 576
Chris@320 577 std::vector<Vamp::Plugin::OutputDescriptor> od =
Chris@320 578 vp->getOutputDescriptors();
Chris@320 579 if (od.size() > 1) {
Chris@320 580 for (size_t i = 0; i < od.size(); ++i) {
Chris@320 581 if (od[i].identifier == output.toStdString()) {
Chris@320 582 outputLabel = od[i].name.c_str();
Chris@320 583 outputDescription = od[i].description.c_str();
Chris@320 584 break;
Chris@320 585 }
Chris@320 586 }
Chris@320 587 }
Chris@320 588 }
Chris@320 589
Chris@320 590 } else if (RealTimePluginFactory::instanceFor(id)) {
Chris@320 591
Chris@320 592 RealTimePluginFactory *factory = RealTimePluginFactory::instanceFor(id);
Chris@320 593 const RealTimePluginDescriptor *desc = factory->getPluginDescriptor(id);
Chris@320 594
Chris@320 595 if (desc->audioInputPortCount > 0 &&
Chris@320 596 desc->audioOutputPortCount > 0 &&
Chris@320 597 !desc->isSynth) {
Chris@320 598 effect = true;
Chris@320 599 }
Chris@320 600
Chris@320 601 if (desc->audioInputPortCount == 0) {
Chris@320 602 generator = true;
Chris@320 603 }
Chris@320 604
Chris@320 605 if (output != "A") {
Chris@320 606 int outputNo = output.toInt();
Chris@320 607 if (outputNo >= 0 && outputNo < int(desc->controlOutputPortCount)) {
Chris@320 608 outputLabel = desc->controlOutputPortNames[outputNo].c_str();
Chris@320 609 }
Chris@320 610 }
Chris@320 611
Chris@320 612 size_t sampleRate = inputModel->getSampleRate();
Chris@320 613 size_t blockSize = 1024;
Chris@320 614 size_t channels = 1;
Chris@320 615 if (effect && source) {
Chris@320 616 sampleRate = source->getTargetSampleRate();
Chris@320 617 blockSize = source->getTargetBlockSize();
Chris@320 618 channels = source->getTargetChannelCount();
Chris@320 619 }
Chris@320 620
Chris@320 621 RealTimePluginInstance *rtp = factory->instantiatePlugin
Chris@320 622 (id, 0, 0, sampleRate, blockSize, channels);
Chris@320 623
Chris@320 624 plugin = rtp;
Chris@320 625
Chris@320 626 if (effect && source && rtp) {
Chris@320 627 source->setAuditioningPlugin(rtp);
Chris@320 628 }
Chris@320 629 }
Chris@320 630
Chris@320 631 if (plugin) {
Chris@320 632
Chris@328 633 context = PluginTransformer::ExecutionContext(context.channel, plugin);
Chris@320 634
Chris@320 635 if (configurationXml != "") {
Chris@320 636 PluginXml(plugin).setParametersFromXml(configurationXml);
Chris@320 637 }
Chris@320 638
Chris@320 639 int sourceChannels = 1;
Chris@320 640 if (dynamic_cast<DenseTimeValueModel *>(inputModel)) {
Chris@320 641 sourceChannels = dynamic_cast<DenseTimeValueModel *>(inputModel)
Chris@320 642 ->getChannelCount();
Chris@320 643 }
Chris@320 644
Chris@320 645 int minChannels = 1, maxChannels = sourceChannels;
Chris@320 646 getChannelRange(identifier, plugin, minChannels, maxChannels);
Chris@320 647
Chris@320 648 int targetChannels = sourceChannels;
Chris@320 649 if (!effect) {
Chris@320 650 if (sourceChannels < minChannels) targetChannels = minChannels;
Chris@320 651 if (sourceChannels > maxChannels) targetChannels = maxChannels;
Chris@320 652 }
Chris@320 653
Chris@320 654 int defaultChannel = context.channel;
Chris@320 655
Chris@320 656 PluginParameterDialog *dialog = new PluginParameterDialog(plugin);
Chris@320 657
Chris@320 658 if (candidateModelNames.size() > 1 && !generator) {
Chris@320 659 dialog->setCandidateInputModels(candidateModelNames);
Chris@320 660 }
Chris@320 661
Chris@320 662 if (startFrame != 0 || duration != 0) {
Chris@320 663 dialog->setShowSelectionOnlyOption(true);
Chris@320 664 }
Chris@320 665
Chris@320 666 if (targetChannels > 0) {
Chris@320 667 dialog->setChannelArrangement(sourceChannels, targetChannels,
Chris@320 668 defaultChannel);
Chris@320 669 }
Chris@320 670
Chris@320 671 dialog->setOutputLabel(outputLabel, outputDescription);
Chris@320 672
Chris@320 673 dialog->setShowProcessingOptions(true, frequency);
Chris@320 674
Chris@320 675 if (dialog->exec() == QDialog::Accepted) {
Chris@320 676 ok = true;
Chris@320 677 }
Chris@320 678
Chris@320 679 QString selectedInput = dialog->getInputModel();
Chris@320 680 if (selectedInput != "") {
Chris@320 681 if (modelMap.find(selectedInput) != modelMap.end()) {
Chris@320 682 inputModel = modelMap[selectedInput];
Chris@320 683 std::cerr << "Found selected input \"" << selectedInput.toStdString() << "\" in model map, result is " << inputModel << std::endl;
Chris@320 684 } else {
Chris@320 685 std::cerr << "Failed to find selected input \"" << selectedInput.toStdString() << "\" in model map" << std::endl;
Chris@320 686 }
Chris@320 687 } else {
Chris@320 688 std::cerr << "Selected input empty: \"" << selectedInput.toStdString() << "\"" << std::endl;
Chris@320 689 }
Chris@320 690
Chris@320 691 configurationXml = PluginXml(plugin).toXmlString();
Chris@320 692 context.channel = dialog->getChannel();
Chris@320 693
Chris@320 694 if (startFrame != 0 || duration != 0) {
Chris@320 695 if (dialog->getSelectionOnly()) {
Chris@320 696 context.startFrame = startFrame;
Chris@320 697 context.duration = duration;
Chris@320 698 }
Chris@320 699 }
Chris@320 700
Chris@320 701 dialog->getProcessingParameters(context.stepSize,
Chris@320 702 context.blockSize,
Chris@320 703 context.windowType);
Chris@320 704
Chris@320 705 context.makeConsistentWithPlugin(plugin);
Chris@320 706
Chris@320 707 delete dialog;
Chris@320 708
Chris@320 709 if (effect && source) {
Chris@320 710 source->setAuditioningPlugin(0); // will delete our plugin
Chris@320 711 } else {
Chris@320 712 delete plugin;
Chris@320 713 }
Chris@320 714 }
Chris@320 715
Chris@320 716 if (ok) m_lastConfigurations[identifier] = configurationXml;
Chris@320 717
Chris@320 718 return ok ? inputModel : 0;
Chris@320 719 }
Chris@320 720
Chris@328 721 PluginTransformer::ExecutionContext
Chris@331 722 ModelTransformerFactory::getDefaultContextForTransformer(TransformId identifier,
Chris@320 723 Model *inputModel)
Chris@320 724 {
Chris@328 725 PluginTransformer::ExecutionContext context(-1);
Chris@320 726
Chris@320 727 QString id = identifier.section(':', 0, 2);
Chris@320 728
Chris@320 729 if (FeatureExtractionPluginFactory::instanceFor(id)) {
Chris@320 730
Chris@320 731 Vamp::Plugin *vp =
Chris@320 732 FeatureExtractionPluginFactory::instanceFor(id)->instantiatePlugin
Chris@320 733 (id, inputModel ? inputModel->getSampleRate() : 48000);
Chris@320 734
Chris@320 735 if (vp) {
Chris@328 736 context = PluginTransformer::ExecutionContext(-1, vp);
Chris@320 737 delete vp;
Chris@320 738 }
Chris@320 739 }
Chris@320 740
Chris@320 741 return context;
Chris@320 742 }
Chris@320 743
Chris@331 744 ModelTransformer *
Chris@331 745 ModelTransformerFactory::createTransformer(TransformId identifier, Model *inputModel,
Chris@328 746 const PluginTransformer::ExecutionContext &context,
Chris@320 747 QString configurationXml)
Chris@320 748 {
Chris@331 749 ModelTransformer *transformer = 0;
Chris@320 750
Chris@320 751 QString id = identifier.section(':', 0, 2);
Chris@320 752 QString output = identifier.section(':', 3);
Chris@320 753
Chris@320 754 if (FeatureExtractionPluginFactory::instanceFor(id)) {
Chris@331 755 transformer = new FeatureExtractionModelTransformer(inputModel,
Chris@331 756 id,
Chris@331 757 context,
Chris@331 758 configurationXml,
Chris@331 759 output);
Chris@331 760 } else if (RealTimePluginFactory::instanceFor(id)) {
Chris@331 761 transformer = new RealTimeEffectModelTransformer(inputModel,
Chris@320 762 id,
Chris@320 763 context,
Chris@320 764 configurationXml,
Chris@331 765 getTransformerUnits(identifier),
Chris@331 766 output == "A" ? -1 :
Chris@331 767 output.toInt());
Chris@320 768 } else {
Chris@331 769 std::cerr << "ModelTransformerFactory::createTransformer: Unknown transform \""
Chris@320 770 << identifier.toStdString() << "\"" << std::endl;
Chris@331 771 return transformer;
Chris@320 772 }
Chris@320 773
Chris@331 774 if (transformer) transformer->setObjectName(identifier);
Chris@331 775 return transformer;
Chris@320 776 }
Chris@320 777
Chris@320 778 Model *
Chris@331 779 ModelTransformerFactory::transform(TransformId identifier, Model *inputModel,
Chris@328 780 const PluginTransformer::ExecutionContext &context,
Chris@320 781 QString configurationXml)
Chris@320 782 {
Chris@331 783 ModelTransformer *t = createTransformer(identifier, inputModel, context,
Chris@331 784 configurationXml);
Chris@320 785
Chris@320 786 if (!t) return 0;
Chris@320 787
Chris@331 788 connect(t, SIGNAL(finished()), this, SLOT(transformerFinished()));
Chris@320 789
Chris@328 790 m_runningTransformers.insert(t);
Chris@320 791
Chris@320 792 t->start();
Chris@320 793 Model *model = t->detachOutputModel();
Chris@320 794
Chris@320 795 if (model) {
Chris@320 796 QString imn = inputModel->objectName();
Chris@328 797 QString trn = getTransformerFriendlyName(identifier);
Chris@320 798 if (imn != "") {
Chris@320 799 if (trn != "") {
Chris@320 800 model->setObjectName(tr("%1: %2").arg(imn).arg(trn));
Chris@320 801 } else {
Chris@320 802 model->setObjectName(imn);
Chris@320 803 }
Chris@320 804 } else if (trn != "") {
Chris@320 805 model->setObjectName(trn);
Chris@320 806 }
Chris@320 807 } else {
Chris@320 808 t->wait();
Chris@320 809 }
Chris@320 810
Chris@320 811 return model;
Chris@320 812 }
Chris@320 813
Chris@320 814 void
Chris@331 815 ModelTransformerFactory::transformerFinished()
Chris@320 816 {
Chris@320 817 QObject *s = sender();
Chris@331 818 ModelTransformer *transformer = dynamic_cast<ModelTransformer *>(s);
Chris@320 819
Chris@331 820 std::cerr << "ModelTransformerFactory::transformerFinished(" << transformer << ")" << std::endl;
Chris@320 821
Chris@331 822 if (!transformer) {
Chris@331 823 std::cerr << "WARNING: ModelTransformerFactory::transformerFinished: sender is not a transformer" << std::endl;
Chris@320 824 return;
Chris@320 825 }
Chris@320 826
Chris@331 827 if (m_runningTransformers.find(transformer) == m_runningTransformers.end()) {
Chris@331 828 std::cerr << "WARNING: ModelTransformerFactory::transformerFinished("
Chris@331 829 << transformer
Chris@331 830 << "): I have no record of this transformer running!"
Chris@320 831 << std::endl;
Chris@320 832 }
Chris@320 833
Chris@331 834 m_runningTransformers.erase(transformer);
Chris@320 835
Chris@331 836 transformer->wait(); // unnecessary but reassuring
Chris@331 837 delete transformer;
Chris@320 838 }
Chris@320 839
Chris@320 840 void
Chris@331 841 ModelTransformerFactory::modelAboutToBeDeleted(Model *m)
Chris@320 842 {
Chris@328 843 TransformerSet affected;
Chris@320 844
Chris@328 845 for (TransformerSet::iterator i = m_runningTransformers.begin();
Chris@328 846 i != m_runningTransformers.end(); ++i) {
Chris@320 847
Chris@331 848 ModelTransformer *t = *i;
Chris@320 849
Chris@320 850 if (t->getInputModel() == m || t->getOutputModel() == m) {
Chris@320 851 affected.insert(t);
Chris@320 852 }
Chris@320 853 }
Chris@320 854
Chris@328 855 for (TransformerSet::iterator i = affected.begin();
Chris@320 856 i != affected.end(); ++i) {
Chris@320 857
Chris@331 858 ModelTransformer *t = *i;
Chris@320 859
Chris@320 860 t->abandon();
Chris@320 861
Chris@320 862 t->wait(); // this should eventually call back on
Chris@331 863 // transformerFinished, which will remove from
Chris@328 864 // m_runningTransformers and delete.
Chris@320 865 }
Chris@320 866 }
Chris@320 867