annotate transform/TransformFactory.cpp @ 97:22494cc28c9f

* Reduce number of allocations and deallocations by keeping a spare buffer around (we were generally deallocating and then immediately allocating again, so it's much better not to have to bother as very large allocations can tie up the system)
author Chris Cannam
date Thu, 04 May 2006 20:17:28 +0000
parents 9e027aa5b5c3
children 0a846f83a4b7
rev   line source
Chris@49 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@0 2
Chris@0 3 /*
Chris@52 4 Sonic Visualiser
Chris@52 5 An audio file viewer and annotation editor.
Chris@52 6 Centre for Digital Music, Queen Mary, University of London.
Chris@52 7 This file copyright 2006 Chris Cannam.
Chris@0 8
Chris@52 9 This program is free software; you can redistribute it and/or
Chris@52 10 modify it under the terms of the GNU General Public License as
Chris@52 11 published by the Free Software Foundation; either version 2 of the
Chris@52 12 License, or (at your option) any later version. See the file
Chris@52 13 COPYING included with this distribution for more information.
Chris@0 14 */
Chris@0 15
Chris@0 16 #include "TransformFactory.h"
Chris@0 17
Chris@0 18 #include "FeatureExtractionPluginTransform.h"
Chris@60 19 #include "RealTimePluginTransform.h"
Chris@0 20
Chris@0 21 #include "plugin/FeatureExtractionPluginFactory.h"
Chris@60 22 #include "plugin/RealTimePluginFactory.h"
Chris@66 23 #include "plugin/PluginXml.h"
Chris@0 24
Chris@56 25 #include "widgets/PluginParameterDialog.h"
Chris@56 26
Chris@64 27 #include "model/DenseTimeValueModel.h"
Chris@64 28
Chris@0 29 #include <iostream>
Chris@63 30 #include <set>
Chris@63 31
Chris@63 32 #include <QRegExp>
Chris@0 33
Chris@0 34 TransformFactory *
Chris@0 35 TransformFactory::m_instance = new TransformFactory;
Chris@0 36
Chris@0 37 TransformFactory *
Chris@0 38 TransformFactory::instance()
Chris@0 39 {
Chris@0 40 return m_instance;
Chris@0 41 }
Chris@0 42
Chris@0 43 TransformFactory::~TransformFactory()
Chris@0 44 {
Chris@0 45 }
Chris@0 46
Chris@0 47 TransformFactory::TransformList
Chris@0 48 TransformFactory::getAllTransforms()
Chris@0 49 {
Chris@16 50 if (m_transforms.empty()) populateTransforms();
Chris@16 51
Chris@0 52 TransformList list;
Chris@56 53 for (TransformDescriptionMap::const_iterator i = m_transforms.begin();
Chris@16 54 i != m_transforms.end(); ++i) {
Chris@56 55 list.push_back(i->second);
Chris@16 56 }
Chris@0 57
Chris@16 58 return list;
Chris@16 59 }
Chris@16 60
Chris@63 61 std::vector<QString>
Chris@63 62 TransformFactory::getAllTransformTypes()
Chris@63 63 {
Chris@63 64 if (m_transforms.empty()) populateTransforms();
Chris@63 65
Chris@63 66 std::set<QString> types;
Chris@63 67 for (TransformDescriptionMap::const_iterator i = m_transforms.begin();
Chris@63 68 i != m_transforms.end(); ++i) {
Chris@63 69 types.insert(i->second.type);
Chris@63 70 }
Chris@63 71
Chris@63 72 std::vector<QString> rv;
Chris@63 73 for (std::set<QString>::iterator i = types.begin(); i != types.end(); ++i) {
Chris@63 74 rv.push_back(*i);
Chris@63 75 }
Chris@63 76
Chris@63 77 return rv;
Chris@63 78 }
Chris@63 79
Chris@16 80 void
Chris@16 81 TransformFactory::populateTransforms()
Chris@16 82 {
Chris@60 83 TransformDescriptionMap transforms;
Chris@60 84
Chris@60 85 populateFeatureExtractionPlugins(transforms);
Chris@60 86 populateRealTimePlugins(transforms);
Chris@60 87
Chris@60 88 // disambiguate plugins with similar descriptions
Chris@60 89
Chris@60 90 std::map<QString, int> descriptions;
Chris@60 91
Chris@60 92 for (TransformDescriptionMap::iterator i = transforms.begin();
Chris@60 93 i != transforms.end(); ++i) {
Chris@60 94
Chris@60 95 TransformDesc desc = i->second;
Chris@60 96
Chris@60 97 ++descriptions[desc.description];
Chris@60 98 ++descriptions[QString("%1 [%2]").arg(desc.description).arg(desc.maker)];
Chris@60 99 }
Chris@60 100
Chris@60 101 std::map<QString, int> counts;
Chris@60 102 m_transforms.clear();
Chris@60 103
Chris@60 104 for (TransformDescriptionMap::iterator i = transforms.begin();
Chris@60 105 i != transforms.end(); ++i) {
Chris@60 106
Chris@60 107 TransformDesc desc = i->second;
Chris@60 108 QString name = desc.name;
Chris@60 109 QString description = desc.description;
Chris@60 110 QString maker = desc.maker;
Chris@60 111
Chris@60 112 if (descriptions[description] > 1) {
Chris@60 113 description = QString("%1 [%2]").arg(description).arg(maker);
Chris@60 114 if (descriptions[description] > 1) {
Chris@60 115 description = QString("%1 <%2>")
Chris@60 116 .arg(description).arg(++counts[description]);
Chris@60 117 }
Chris@60 118 }
Chris@60 119
Chris@60 120 desc.description = description;
Chris@60 121 m_transforms[name] = desc;
Chris@60 122 }
Chris@60 123 }
Chris@60 124
Chris@60 125 void
Chris@60 126 TransformFactory::populateFeatureExtractionPlugins(TransformDescriptionMap &transforms)
Chris@60 127 {
Chris@60 128 std::vector<QString> plugs =
Chris@0 129 FeatureExtractionPluginFactory::getAllPluginIdentifiers();
Chris@0 130
Chris@60 131 for (size_t i = 0; i < plugs.size(); ++i) {
Chris@47 132
Chris@60 133 QString pluginId = plugs[i];
Chris@0 134
Chris@0 135 FeatureExtractionPluginFactory *factory =
Chris@0 136 FeatureExtractionPluginFactory::instanceFor(pluginId);
Chris@0 137
Chris@20 138 if (!factory) {
Chris@20 139 std::cerr << "WARNING: TransformFactory::populateTransforms: No feature extraction plugin factory for instance " << pluginId.toLocal8Bit().data() << std::endl;
Chris@20 140 continue;
Chris@20 141 }
Chris@0 142
Chris@66 143 Vamp::Plugin *plugin =
Chris@20 144 factory->instantiatePlugin(pluginId, 48000);
Chris@0 145
Chris@20 146 if (!plugin) {
Chris@20 147 std::cerr << "WARNING: TransformFactory::populateTransforms: Failed to instantiate plugin " << pluginId.toLocal8Bit().data() << std::endl;
Chris@20 148 continue;
Chris@20 149 }
Chris@20 150
Chris@20 151 QString pluginDescription = plugin->getDescription().c_str();
Chris@66 152 Vamp::Plugin::OutputList outputs =
Chris@20 153 plugin->getOutputDescriptors();
Chris@0 154
Chris@20 155 for (size_t j = 0; j < outputs.size(); ++j) {
Chris@0 156
Chris@20 157 QString transformName = QString("%1:%2")
Chris@20 158 .arg(pluginId).arg(outputs[j].name.c_str());
Chris@20 159
Chris@20 160 QString userDescription;
Chris@60 161 QString friendlyName;
Chris@63 162 QString units = outputs[j].unit.c_str();
Chris@20 163
Chris@20 164 if (outputs.size() == 1) {
Chris@20 165 userDescription = pluginDescription;
Chris@60 166 friendlyName = pluginDescription;
Chris@20 167 } else {
Chris@20 168 userDescription = QString("%1: %2")
Chris@20 169 .arg(pluginDescription)
Chris@20 170 .arg(outputs[j].description.c_str());
Chris@60 171 friendlyName = outputs[j].description.c_str();
Chris@0 172 }
Chris@20 173
Chris@56 174 bool configurable = (!plugin->getPrograms().empty() ||
Chris@56 175 !plugin->getParameterDescriptors().empty());
Chris@56 176
Chris@60 177 transforms[transformName] =
Chris@63 178 TransformDesc(tr("Analysis Plugin"),
Chris@63 179 transformName,
Chris@56 180 userDescription,
Chris@60 181 friendlyName,
Chris@60 182 plugin->getMaker().c_str(),
Chris@63 183 units,
Chris@56 184 configurable);
Chris@0 185 }
Chris@0 186 }
Chris@60 187 }
Chris@47 188
Chris@60 189 void
Chris@60 190 TransformFactory::populateRealTimePlugins(TransformDescriptionMap &transforms)
Chris@60 191 {
Chris@60 192 std::vector<QString> plugs =
Chris@60 193 RealTimePluginFactory::getAllPluginIdentifiers();
Chris@47 194
Chris@63 195 QRegExp unitRE("[\\[\\(]([A-Za-z0-9/]+)[\\)\\]]$");
Chris@63 196
Chris@60 197 for (size_t i = 0; i < plugs.size(); ++i) {
Chris@60 198
Chris@60 199 QString pluginId = plugs[i];
Chris@47 200
Chris@60 201 RealTimePluginFactory *factory =
Chris@60 202 RealTimePluginFactory::instanceFor(pluginId);
Chris@47 203
Chris@60 204 if (!factory) {
Chris@60 205 std::cerr << "WARNING: TransformFactory::populateTransforms: No real time plugin factory for instance " << pluginId.toLocal8Bit().data() << std::endl;
Chris@60 206 continue;
Chris@47 207 }
Chris@47 208
Chris@60 209 const RealTimePluginDescriptor *descriptor =
Chris@60 210 factory->getPluginDescriptor(pluginId);
Chris@60 211
Chris@60 212 if (!descriptor) {
Chris@60 213 std::cerr << "WARNING: TransformFactory::populateTransforms: Failed to query plugin " << pluginId.toLocal8Bit().data() << std::endl;
Chris@60 214 continue;
Chris@60 215 }
Chris@60 216
Chris@60 217 if (descriptor->controlOutputPortCount == 0 ||
Chris@60 218 descriptor->audioInputPortCount == 0) continue;
Chris@60 219
Chris@60 220 std::cout << "TransformFactory::populateRealTimePlugins: plugin " << pluginId.toStdString() << " has " << descriptor->controlOutputPortCount << " output ports" << std::endl;
Chris@60 221
Chris@60 222 QString pluginDescription = descriptor->name.c_str();
Chris@60 223
Chris@60 224 for (size_t j = 0; j < descriptor->controlOutputPortCount; ++j) {
Chris@60 225
Chris@60 226 QString transformName = QString("%1:%2").arg(pluginId).arg(j);
Chris@60 227 QString userDescription;
Chris@63 228 QString units;
Chris@60 229
Chris@60 230 if (j < descriptor->controlOutputPortNames.size() &&
Chris@60 231 descriptor->controlOutputPortNames[j] != "") {
Chris@63 232
Chris@63 233 QString portName = descriptor->controlOutputPortNames[j].c_str();
Chris@63 234
Chris@60 235 userDescription = tr("%1: %2")
Chris@60 236 .arg(pluginDescription)
Chris@63 237 .arg(portName);
Chris@63 238
Chris@63 239 if (unitRE.indexIn(portName) >= 0) {
Chris@63 240 units = unitRE.cap(1);
Chris@63 241 }
Chris@63 242
Chris@60 243 } else if (descriptor->controlOutputPortCount > 1) {
Chris@63 244
Chris@60 245 userDescription = tr("%1: Output %2")
Chris@60 246 .arg(pluginDescription)
Chris@60 247 .arg(j + 1);
Chris@63 248
Chris@60 249 } else {
Chris@63 250
Chris@60 251 userDescription = pluginDescription;
Chris@60 252 }
Chris@60 253
Chris@63 254
Chris@60 255 bool configurable = (descriptor->parameterCount > 0);
Chris@60 256
Chris@60 257 transforms[transformName] =
Chris@63 258 TransformDesc(tr("Real-Time Plugin"),
Chris@63 259 transformName,
Chris@60 260 userDescription,
Chris@60 261 userDescription,
Chris@60 262 descriptor->maker.c_str(),
Chris@63 263 units,
Chris@60 264 configurable);
Chris@60 265 }
Chris@60 266 }
Chris@16 267 }
Chris@16 268
Chris@16 269 QString
Chris@16 270 TransformFactory::getTransformDescription(TransformName name)
Chris@16 271 {
Chris@16 272 if (m_transforms.find(name) != m_transforms.end()) {
Chris@56 273 return m_transforms[name].description;
Chris@16 274 } else return "";
Chris@0 275 }
Chris@0 276
Chris@18 277 QString
Chris@18 278 TransformFactory::getTransformFriendlyName(TransformName name)
Chris@18 279 {
Chris@60 280 if (m_transforms.find(name) != m_transforms.end()) {
Chris@60 281 return m_transforms[name].friendlyName;
Chris@60 282 } else return "";
Chris@18 283 }
Chris@18 284
Chris@63 285 QString
Chris@63 286 TransformFactory::getTransformUnits(TransformName name)
Chris@63 287 {
Chris@63 288 if (m_transforms.find(name) != m_transforms.end()) {
Chris@63 289 return m_transforms[name].units;
Chris@63 290 } else return "";
Chris@63 291 }
Chris@63 292
Chris@56 293 bool
Chris@57 294 TransformFactory::isTransformConfigurable(TransformName name)
Chris@57 295 {
Chris@57 296 if (m_transforms.find(name) != m_transforms.end()) {
Chris@57 297 return m_transforms[name].configurable;
Chris@57 298 } else return false;
Chris@57 299 }
Chris@57 300
Chris@57 301 bool
Chris@64 302 TransformFactory::getTransformChannelRange(TransformName name,
Chris@64 303 int &min, int &max)
Chris@64 304 {
Chris@64 305 QString id = name.section(':', 0, 2);
Chris@64 306
Chris@64 307 if (FeatureExtractionPluginFactory::instanceFor(id)) {
Chris@64 308
Chris@66 309 Vamp::Plugin *plugin =
Chris@64 310 FeatureExtractionPluginFactory::instanceFor(id)->
Chris@64 311 instantiatePlugin(id, 48000);
Chris@64 312 if (!plugin) return false;
Chris@64 313
Chris@64 314 min = plugin->getMinChannelCount();
Chris@64 315 max = plugin->getMaxChannelCount();
Chris@64 316 delete plugin;
Chris@64 317
Chris@64 318 return true;
Chris@64 319
Chris@64 320 } else if (RealTimePluginFactory::instanceFor(id)) {
Chris@64 321
Chris@64 322 const RealTimePluginDescriptor *descriptor =
Chris@64 323 RealTimePluginFactory::instanceFor(id)->
Chris@64 324 getPluginDescriptor(id);
Chris@64 325 if (!descriptor) return false;
Chris@64 326
Chris@64 327 min = descriptor->audioInputPortCount;
Chris@64 328 max = descriptor->audioInputPortCount;
Chris@64 329
Chris@64 330 return true;
Chris@64 331 }
Chris@64 332
Chris@64 333 return false;
Chris@64 334 }
Chris@64 335
Chris@64 336 bool
Chris@79 337 TransformFactory::getChannelRange(TransformName name, Vamp::PluginBase *plugin,
Chris@79 338 int &minChannels, int &maxChannels)
Chris@79 339 {
Chris@79 340 Vamp::Plugin *vp = 0;
Chris@79 341 if ((vp = dynamic_cast<Vamp::Plugin *>(plugin))) {
Chris@79 342 minChannels = vp->getMinChannelCount();
Chris@79 343 maxChannels = vp->getMaxChannelCount();
Chris@79 344 return true;
Chris@79 345 } else {
Chris@79 346 return getTransformChannelRange(name, minChannels, maxChannels);
Chris@79 347 }
Chris@79 348 }
Chris@79 349
Chris@79 350 bool
Chris@56 351 TransformFactory::getConfigurationForTransform(TransformName name,
Chris@56 352 Model *inputModel,
Chris@64 353 int &channel,
Chris@56 354 QString &configurationXml)
Chris@0 355 {
Chris@56 356 QString id = name.section(':', 0, 2);
Chris@56 357 QString output = name.section(':', 3);
Chris@56 358
Chris@56 359 bool ok = false;
Chris@56 360 configurationXml = m_lastConfigurations[name];
Chris@56 361
Chris@56 362 std::cerr << "last configuration: " << configurationXml.toStdString() << std::endl;
Chris@56 363
Chris@66 364 Vamp::PluginBase *plugin = 0;
Chris@60 365
Chris@56 366 if (FeatureExtractionPluginFactory::instanceFor(id)) {
Chris@60 367
Chris@60 368 plugin = FeatureExtractionPluginFactory::instanceFor(id)->instantiatePlugin
Chris@56 369 (id, inputModel->getSampleRate());
Chris@60 370
Chris@60 371 } else if (RealTimePluginFactory::instanceFor(id)) {
Chris@60 372
Chris@60 373 plugin = RealTimePluginFactory::instanceFor(id)->instantiatePlugin
Chris@60 374 (id, 0, 0, inputModel->getSampleRate(), 1024, 1);
Chris@60 375 }
Chris@60 376
Chris@60 377 if (plugin) {
Chris@60 378 if (configurationXml != "") {
Chris@66 379 PluginXml(plugin).setParametersFromXml(configurationXml);
Chris@56 380 }
Chris@64 381
Chris@64 382 int sourceChannels = 1;
Chris@64 383 if (dynamic_cast<DenseTimeValueModel *>(inputModel)) {
Chris@64 384 sourceChannels = dynamic_cast<DenseTimeValueModel *>(inputModel)
Chris@64 385 ->getChannelCount();
Chris@64 386 }
Chris@64 387
Chris@64 388 int minChannels = 1, maxChannels = sourceChannels;
Chris@79 389 getChannelRange(name, plugin, minChannels, maxChannels);
Chris@64 390
Chris@64 391 int targetChannels = sourceChannels;
Chris@64 392 if (sourceChannels < minChannels) targetChannels = minChannels;
Chris@64 393 if (sourceChannels > maxChannels) targetChannels = maxChannels;
Chris@64 394
Chris@64 395 int defaultChannel = channel;
Chris@64 396
Chris@64 397 PluginParameterDialog *dialog = new PluginParameterDialog(plugin,
Chris@64 398 sourceChannels,
Chris@64 399 targetChannels,
Chris@64 400 defaultChannel);
Chris@60 401 if (dialog->exec() == QDialog::Accepted) {
Chris@60 402 ok = true;
Chris@60 403 }
Chris@66 404 configurationXml = PluginXml(plugin).toXmlString();
Chris@64 405 channel = dialog->getChannel();
Chris@60 406 delete dialog;
Chris@60 407 delete plugin;
Chris@56 408 }
Chris@56 409
Chris@56 410 if (ok) m_lastConfigurations[name] = configurationXml;
Chris@56 411
Chris@56 412 return ok;
Chris@0 413 }
Chris@0 414
Chris@0 415 Transform *
Chris@0 416 TransformFactory::createTransform(TransformName name, Model *inputModel,
Chris@64 417 int channel, QString configurationXml, bool start)
Chris@0 418 {
Chris@0 419 Transform *transform = 0;
Chris@0 420
Chris@64 421 //!!! use channel
Chris@64 422
Chris@56 423 QString id = name.section(':', 0, 2);
Chris@56 424 QString output = name.section(':', 3);
Chris@56 425
Chris@56 426 if (FeatureExtractionPluginFactory::instanceFor(id)) {
Chris@56 427 transform = new FeatureExtractionPluginTransform(inputModel,
Chris@56 428 id,
Chris@64 429 channel,
Chris@56 430 configurationXml,
Chris@56 431 output);
Chris@60 432 } else if (RealTimePluginFactory::instanceFor(id)) {
Chris@60 433 transform = new RealTimePluginTransform(inputModel,
Chris@60 434 id,
Chris@64 435 channel,
Chris@60 436 configurationXml,
Chris@63 437 getTransformUnits(name),
Chris@60 438 output.toInt());
Chris@0 439 } else {
Chris@77 440 std::cerr << "TransformFactory::createTransform: Unknown transform \""
Chris@77 441 << name.toStdString() << "\"" << std::endl;
Chris@77 442 return transform;
Chris@0 443 }
Chris@0 444
Chris@0 445 if (start && transform) transform->start();
Chris@16 446 transform->setObjectName(name);
Chris@0 447 return transform;
Chris@0 448 }
Chris@0 449
Chris@0 450 Model *
Chris@56 451 TransformFactory::transform(TransformName name, Model *inputModel,
Chris@64 452 int channel, QString configurationXml)
Chris@0 453 {
Chris@64 454 Transform *t = createTransform(name, inputModel, channel,
Chris@64 455 configurationXml, false);
Chris@0 456
Chris@0 457 if (!t) return 0;
Chris@0 458
Chris@0 459 connect(t, SIGNAL(finished()), this, SLOT(transformFinished()));
Chris@0 460
Chris@0 461 t->start();
Chris@0 462 return t->detachOutputModel();
Chris@0 463 }
Chris@0 464
Chris@0 465 void
Chris@0 466 TransformFactory::transformFinished()
Chris@0 467 {
Chris@0 468 QObject *s = sender();
Chris@0 469 Transform *transform = dynamic_cast<Transform *>(s);
Chris@0 470
Chris@0 471 if (!transform) {
Chris@0 472 std::cerr << "WARNING: TransformFactory::transformFinished: sender is not a transform" << std::endl;
Chris@0 473 return;
Chris@0 474 }
Chris@0 475
Chris@0 476 transform->wait(); // unnecessary but reassuring
Chris@0 477 delete transform;
Chris@0 478 }
Chris@0 479