annotate transform/TransformFactory.cpp @ 88:51be0daa1386

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