annotate sv/transform/TransformFactory.cpp @ 282:d9319859a4cf tip

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