Chris@49: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@0: Chris@0: /* Chris@52: Sonic Visualiser Chris@52: An audio file viewer and annotation editor. Chris@52: Centre for Digital Music, Queen Mary, University of London. Chris@52: This file copyright 2006 Chris Cannam. Chris@0: Chris@52: This program is free software; you can redistribute it and/or Chris@52: modify it under the terms of the GNU General Public License as Chris@52: published by the Free Software Foundation; either version 2 of the Chris@52: License, or (at your option) any later version. See the file Chris@52: COPYING included with this distribution for more information. Chris@0: */ Chris@0: Chris@0: #include "TransformFactory.h" Chris@0: Chris@0: #include "FeatureExtractionPluginTransform.h" Chris@0: Chris@0: #include "plugin/FeatureExtractionPluginFactory.h" Chris@0: Chris@56: #include "widgets/PluginParameterDialog.h" Chris@56: Chris@0: #include Chris@0: Chris@0: TransformFactory * Chris@0: TransformFactory::m_instance = new TransformFactory; Chris@0: Chris@0: TransformFactory * Chris@0: TransformFactory::instance() Chris@0: { Chris@0: return m_instance; Chris@0: } Chris@0: Chris@0: TransformFactory::~TransformFactory() Chris@0: { Chris@0: } Chris@0: Chris@0: TransformFactory::TransformList Chris@0: TransformFactory::getAllTransforms() Chris@0: { Chris@16: if (m_transforms.empty()) populateTransforms(); Chris@16: Chris@0: TransformList list; Chris@56: for (TransformDescriptionMap::const_iterator i = m_transforms.begin(); Chris@16: i != m_transforms.end(); ++i) { Chris@56: list.push_back(i->second); Chris@16: } Chris@0: Chris@16: return list; Chris@16: } Chris@16: Chris@16: void Chris@16: TransformFactory::populateTransforms() Chris@16: { Chris@0: std::vector fexplugs = Chris@0: FeatureExtractionPluginFactory::getAllPluginIdentifiers(); Chris@0: Chris@47: std::map makers; Chris@47: Chris@0: for (size_t i = 0; i < fexplugs.size(); ++i) { Chris@0: Chris@0: QString pluginId = fexplugs[i]; Chris@0: Chris@0: FeatureExtractionPluginFactory *factory = Chris@0: FeatureExtractionPluginFactory::instanceFor(pluginId); Chris@0: Chris@20: if (!factory) { Chris@20: std::cerr << "WARNING: TransformFactory::populateTransforms: No feature extraction plugin factory for instance " << pluginId.toLocal8Bit().data() << std::endl; Chris@20: continue; Chris@20: } Chris@0: Chris@20: FeatureExtractionPlugin *plugin = Chris@20: factory->instantiatePlugin(pluginId, 48000); Chris@0: Chris@20: if (!plugin) { Chris@20: std::cerr << "WARNING: TransformFactory::populateTransforms: Failed to instantiate plugin " << pluginId.toLocal8Bit().data() << std::endl; Chris@20: continue; Chris@20: } Chris@20: Chris@20: QString pluginDescription = plugin->getDescription().c_str(); Chris@20: FeatureExtractionPlugin::OutputList outputs = Chris@20: plugin->getOutputDescriptors(); Chris@0: Chris@20: for (size_t j = 0; j < outputs.size(); ++j) { Chris@0: Chris@20: QString transformName = QString("%1:%2") Chris@20: .arg(pluginId).arg(outputs[j].name.c_str()); Chris@20: Chris@20: QString userDescription; Chris@20: Chris@20: if (outputs.size() == 1) { Chris@20: userDescription = pluginDescription; Chris@20: } else { Chris@20: userDescription = QString("%1: %2") Chris@20: .arg(pluginDescription) Chris@20: .arg(outputs[j].description.c_str()); Chris@0: } Chris@20: Chris@56: bool configurable = (!plugin->getPrograms().empty() || Chris@56: !plugin->getParameterDescriptors().empty()); Chris@56: Chris@56: m_transforms[transformName] = Chris@56: TransformDesc(transformName, Chris@56: userDescription, Chris@56: configurable); Chris@47: Chris@47: makers[transformName] = plugin->getMaker().c_str(); Chris@0: } Chris@0: } Chris@47: Chris@47: // disambiguate plugins with similar descriptions Chris@47: Chris@47: std::map descriptions; Chris@47: Chris@56: for (TransformDescriptionMap::iterator i = m_transforms.begin(); Chris@56: i != m_transforms.end(); ++i) { Chris@47: Chris@56: TransformDesc desc = i->second; Chris@47: Chris@56: ++descriptions[desc.description]; Chris@56: ++descriptions[QString("%1 [%2]").arg(desc.description).arg(makers[desc.name])]; Chris@47: } Chris@47: Chris@47: std::map counts; Chris@56: TransformDescriptionMap newMap; Chris@47: Chris@56: for (TransformDescriptionMap::iterator i = m_transforms.begin(); Chris@56: i != m_transforms.end(); ++i) { Chris@47: Chris@56: TransformDesc desc = i->second; Chris@56: QString name = desc.name, description = desc.description; Chris@47: Chris@47: if (descriptions[description] > 1) { Chris@47: description = QString("%1 [%2]").arg(description).arg(makers[name]); Chris@47: if (descriptions[description] > 1) { Chris@47: description = QString("%1 <%2>") Chris@47: .arg(description).arg(++counts[description]); Chris@47: } Chris@47: } Chris@47: Chris@56: desc.description = description; Chris@56: newMap[name] = desc; Chris@47: } Chris@47: Chris@47: m_transforms = newMap; Chris@16: } Chris@16: Chris@16: QString Chris@16: TransformFactory::getTransformDescription(TransformName name) Chris@16: { Chris@16: if (m_transforms.find(name) != m_transforms.end()) { Chris@56: return m_transforms[name].description; Chris@16: } else return ""; Chris@0: } Chris@0: Chris@18: QString Chris@18: TransformFactory::getTransformFriendlyName(TransformName name) Chris@18: { Chris@18: QString description = getTransformDescription(name); Chris@18: Chris@18: int i = description.indexOf(':'); Chris@18: if (i >= 0) { Chris@18: return description.remove(0, i + 2); Chris@18: } else { Chris@18: return description; Chris@18: } Chris@18: } Chris@18: Chris@56: bool Chris@57: TransformFactory::isTransformConfigurable(TransformName name) Chris@57: { Chris@57: if (m_transforms.find(name) != m_transforms.end()) { Chris@57: return m_transforms[name].configurable; Chris@57: } else return false; Chris@57: } Chris@57: Chris@57: bool Chris@56: TransformFactory::getConfigurationForTransform(TransformName name, Chris@56: Model *inputModel, Chris@56: QString &configurationXml) Chris@0: { Chris@56: QString id = name.section(':', 0, 2); Chris@56: QString output = name.section(':', 3); Chris@56: Chris@56: bool ok = false; Chris@56: configurationXml = m_lastConfigurations[name]; Chris@56: Chris@56: std::cerr << "last configuration: " << configurationXml.toStdString() << std::endl; Chris@56: Chris@56: if (FeatureExtractionPluginFactory::instanceFor(id)) { Chris@56: FeatureExtractionPlugin *plugin = Chris@56: FeatureExtractionPluginFactory::instanceFor(id)->instantiatePlugin Chris@56: (id, inputModel->getSampleRate()); Chris@56: if (plugin) { Chris@56: if (configurationXml != "") { Chris@56: plugin->setParametersFromXml(configurationXml); Chris@56: } Chris@56: PluginParameterDialog *dialog = new PluginParameterDialog(plugin); Chris@56: if (dialog->exec() == QDialog::Accepted) { Chris@56: ok = true; Chris@56: } Chris@56: configurationXml = plugin->toXmlString(); Chris@57: delete dialog; Chris@56: delete plugin; Chris@56: } Chris@56: } Chris@56: Chris@56: if (ok) m_lastConfigurations[name] = configurationXml; Chris@56: Chris@56: return ok; Chris@0: } Chris@0: Chris@0: Transform * Chris@0: TransformFactory::createTransform(TransformName name, Model *inputModel, Chris@56: QString configurationXml, bool start) Chris@0: { Chris@0: Transform *transform = 0; Chris@0: Chris@56: // The only transform type we support at the moment is the Chris@56: // FeatureExtractionPluginTransform. In future we may wish to Chris@56: // support e.g. RealTimePluginTransform for audio->audio or Chris@56: // audio->midi transforms using standard effects plugins. Chris@56: Chris@56: QString id = name.section(':', 0, 2); Chris@56: QString output = name.section(':', 3); Chris@56: Chris@56: if (FeatureExtractionPluginFactory::instanceFor(id)) { Chris@56: transform = new FeatureExtractionPluginTransform(inputModel, Chris@56: id, Chris@56: configurationXml, Chris@56: output); Chris@0: } else { Chris@56: std::cerr << "TransformFactory::createTransform: Unknown transform " Chris@56: << name.toStdString() << std::endl; Chris@0: } Chris@0: Chris@0: if (start && transform) transform->start(); Chris@16: transform->setObjectName(name); Chris@0: return transform; Chris@0: } Chris@0: Chris@0: Model * Chris@56: TransformFactory::transform(TransformName name, Model *inputModel, Chris@56: QString configurationXml) Chris@0: { Chris@56: Transform *t = createTransform(name, inputModel, configurationXml, false); Chris@0: Chris@0: if (!t) return 0; Chris@0: Chris@0: connect(t, SIGNAL(finished()), this, SLOT(transformFinished())); Chris@0: Chris@0: t->start(); Chris@0: return t->detachOutputModel(); Chris@0: } Chris@0: Chris@0: void Chris@0: TransformFactory::transformFinished() Chris@0: { Chris@0: QObject *s = sender(); Chris@0: Transform *transform = dynamic_cast(s); Chris@0: Chris@0: if (!transform) { Chris@0: std::cerr << "WARNING: TransformFactory::transformFinished: sender is not a transform" << std::endl; Chris@0: return; Chris@0: } Chris@0: Chris@0: transform->wait(); // unnecessary but reassuring Chris@0: delete transform; Chris@0: } Chris@0: