lbajardsilogic@0: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ lbajardsilogic@0: lbajardsilogic@0: /* lbajardsilogic@0: Sonic Visualiser lbajardsilogic@0: An audio file viewer and annotation editor. lbajardsilogic@0: Centre for Digital Music, Queen Mary, University of London. lbajardsilogic@0: This file copyright 2006 Chris Cannam and QMUL. lbajardsilogic@0: lbajardsilogic@0: This program is free software; you can redistribute it and/or lbajardsilogic@0: modify it under the terms of the GNU General Public License as lbajardsilogic@0: published by the Free Software Foundation; either version 2 of the lbajardsilogic@0: License, or (at your option) any later version. See the file lbajardsilogic@0: COPYING included with this distribution for more information. lbajardsilogic@0: */ lbajardsilogic@0: lbajardsilogic@0: #include "TransformFactory.h" lbajardsilogic@0: lbajardsilogic@0: #include "FeatureExtractionPluginTransform.h" lbajardsilogic@0: #include "RealTimePluginTransform.h" lbajardsilogic@0: lbajardsilogic@0: #include "plugin/FeatureExtractionPluginFactory.h" lbajardsilogic@0: #include "plugin/RealTimePluginFactory.h" lbajardsilogic@0: #include "plugin/PluginXml.h" lbajardsilogic@0: lbajardsilogic@0: #include "widgets/PluginParameterDialog.h" lbajardsilogic@0: lbajardsilogic@0: #include "data/model/DenseTimeValueModel.h" lbajardsilogic@0: lbajardsilogic@0: #include "vamp-sdk/PluginHostAdapter.h" lbajardsilogic@0: lbajardsilogic@0: #include "sv/audioio/AudioCallbackPlaySource.h" //!!! shouldn't include here lbajardsilogic@0: lbajardsilogic@0: #include lbajardsilogic@0: #include lbajardsilogic@0: lbajardsilogic@0: #include lbajardsilogic@0: lbajardsilogic@0: TransformFactory * lbajardsilogic@0: TransformFactory::m_instance = new TransformFactory; lbajardsilogic@0: lbajardsilogic@0: TransformFactory * lbajardsilogic@0: TransformFactory::getInstance() lbajardsilogic@0: { lbajardsilogic@0: return m_instance; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: TransformFactory::~TransformFactory() lbajardsilogic@0: { lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: TransformFactory::TransformList lbajardsilogic@0: TransformFactory::getAllTransforms() lbajardsilogic@0: { lbajardsilogic@0: if (m_transforms.empty()) populateTransforms(); lbajardsilogic@0: lbajardsilogic@0: std::set dset; lbajardsilogic@0: for (TransformDescriptionMap::const_iterator i = m_transforms.begin(); lbajardsilogic@0: i != m_transforms.end(); ++i) { lbajardsilogic@0: dset.insert(i->second); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: TransformList list; lbajardsilogic@0: for (std::set::const_iterator i = dset.begin(); lbajardsilogic@0: i != dset.end(); ++i) { lbajardsilogic@0: list.push_back(*i); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: return list; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: std::vector lbajardsilogic@0: TransformFactory::getAllTransformTypes() lbajardsilogic@0: { lbajardsilogic@0: if (m_transforms.empty()) populateTransforms(); lbajardsilogic@0: lbajardsilogic@0: std::set types; lbajardsilogic@0: for (TransformDescriptionMap::const_iterator i = m_transforms.begin(); lbajardsilogic@0: i != m_transforms.end(); ++i) { lbajardsilogic@0: types.insert(i->second.type); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: std::vector rv; lbajardsilogic@0: for (std::set::iterator i = types.begin(); i != types.end(); ++i) { lbajardsilogic@0: rv.push_back(*i); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: return rv; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: std::vector lbajardsilogic@0: TransformFactory::getTransformCategories(QString transformType) lbajardsilogic@0: { lbajardsilogic@0: if (m_transforms.empty()) populateTransforms(); lbajardsilogic@0: lbajardsilogic@0: std::set categories; lbajardsilogic@0: for (TransformDescriptionMap::const_iterator i = m_transforms.begin(); lbajardsilogic@0: i != m_transforms.end(); ++i) { lbajardsilogic@0: if (i->second.type == transformType) { lbajardsilogic@0: categories.insert(i->second.category); lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: bool haveEmpty = false; lbajardsilogic@0: lbajardsilogic@0: std::vector rv; lbajardsilogic@0: for (std::set::iterator i = categories.begin(); lbajardsilogic@0: i != categories.end(); ++i) { lbajardsilogic@0: if (*i != "") rv.push_back(*i); lbajardsilogic@0: else haveEmpty = true; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: if (haveEmpty) rv.push_back(""); // make sure empty category sorts last lbajardsilogic@0: lbajardsilogic@0: return rv; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: std::vector lbajardsilogic@0: TransformFactory::getTransformMakers(QString transformType) lbajardsilogic@0: { lbajardsilogic@0: if (m_transforms.empty()) populateTransforms(); lbajardsilogic@0: lbajardsilogic@0: std::set makers; lbajardsilogic@0: for (TransformDescriptionMap::const_iterator i = m_transforms.begin(); lbajardsilogic@0: i != m_transforms.end(); ++i) { lbajardsilogic@0: if (i->second.type == transformType) { lbajardsilogic@0: makers.insert(i->second.maker); lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: bool haveEmpty = false; lbajardsilogic@0: lbajardsilogic@0: std::vector rv; lbajardsilogic@0: for (std::set::iterator i = makers.begin(); lbajardsilogic@0: i != makers.end(); ++i) { lbajardsilogic@0: if (*i != "") rv.push_back(*i); lbajardsilogic@0: else haveEmpty = true; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: if (haveEmpty) rv.push_back(""); // make sure empty category sorts last lbajardsilogic@0: lbajardsilogic@0: return rv; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: TransformFactory::populateTransforms() lbajardsilogic@0: { lbajardsilogic@0: TransformDescriptionMap transforms; lbajardsilogic@0: lbajardsilogic@0: populateFeatureExtractionPlugins(transforms); lbajardsilogic@0: populateRealTimePlugins(transforms); lbajardsilogic@0: lbajardsilogic@0: // disambiguate plugins with similar names lbajardsilogic@0: lbajardsilogic@0: std::map names; lbajardsilogic@0: std::map pluginSources; lbajardsilogic@0: std::map pluginMakers; lbajardsilogic@0: lbajardsilogic@0: for (TransformDescriptionMap::iterator i = transforms.begin(); lbajardsilogic@0: i != transforms.end(); ++i) { lbajardsilogic@0: lbajardsilogic@0: TransformDesc desc = i->second; lbajardsilogic@0: lbajardsilogic@0: QString td = desc.name; lbajardsilogic@0: QString tn = td.section(": ", 0, 0); lbajardsilogic@0: QString pn = desc.identifier.section(":", 1, 1); lbajardsilogic@0: lbajardsilogic@0: if (pluginSources.find(tn) != pluginSources.end()) { lbajardsilogic@0: if (pluginSources[tn] != pn && pluginMakers[tn] != desc.maker) { lbajardsilogic@0: ++names[tn]; lbajardsilogic@0: } lbajardsilogic@0: } else { lbajardsilogic@0: ++names[tn]; lbajardsilogic@0: pluginSources[tn] = pn; lbajardsilogic@0: pluginMakers[tn] = desc.maker; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: std::map counts; lbajardsilogic@0: m_transforms.clear(); lbajardsilogic@0: lbajardsilogic@0: for (TransformDescriptionMap::iterator i = transforms.begin(); lbajardsilogic@0: i != transforms.end(); ++i) { lbajardsilogic@0: lbajardsilogic@0: TransformDesc desc = i->second; lbajardsilogic@0: QString identifier = desc.identifier; lbajardsilogic@0: QString maker = desc.maker; lbajardsilogic@0: lbajardsilogic@0: QString td = desc.name; lbajardsilogic@0: QString tn = td.section(": ", 0, 0); lbajardsilogic@0: QString to = td.section(": ", 1); lbajardsilogic@0: lbajardsilogic@0: if (names[tn] > 1) { lbajardsilogic@0: maker.replace(QRegExp(tr(" [\\(<].*$")), ""); lbajardsilogic@0: tn = QString("%1 [%2]").arg(tn).arg(maker); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: if (to != "") { lbajardsilogic@0: desc.name = QString("%1: %2").arg(tn).arg(to); lbajardsilogic@0: } else { lbajardsilogic@0: desc.name = tn; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: m_transforms[identifier] = desc; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: TransformFactory::populateFeatureExtractionPlugins(TransformDescriptionMap &transforms) lbajardsilogic@0: { lbajardsilogic@0: std::vector plugs = lbajardsilogic@0: FeatureExtractionPluginFactory::getAllPluginIdentifiers(); lbajardsilogic@0: lbajardsilogic@0: for (size_t i = 0; i < plugs.size(); ++i) { lbajardsilogic@0: lbajardsilogic@0: QString pluginId = plugs[i]; lbajardsilogic@0: lbajardsilogic@0: FeatureExtractionPluginFactory *factory = lbajardsilogic@0: FeatureExtractionPluginFactory::instanceFor(pluginId); lbajardsilogic@0: lbajardsilogic@0: if (!factory) { lbajardsilogic@0: std::cerr << "WARNING: TransformFactory::populateTransforms: No feature extraction plugin factory for instance " << pluginId.toLocal8Bit().data() << std::endl; lbajardsilogic@0: continue; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: Vamp::Plugin *plugin = lbajardsilogic@0: factory->instantiatePlugin(pluginId, 48000); lbajardsilogic@0: lbajardsilogic@0: if (!plugin) { lbajardsilogic@0: std::cerr << "WARNING: TransformFactory::populateTransforms: Failed to instantiate plugin " << pluginId.toLocal8Bit().data() << std::endl; lbajardsilogic@0: continue; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: QString pluginName = plugin->getName().c_str(); lbajardsilogic@0: QString category = factory->getPluginCategory(pluginId); lbajardsilogic@0: lbajardsilogic@0: Vamp::Plugin::OutputList outputs = lbajardsilogic@0: plugin->getOutputDescriptors(); lbajardsilogic@0: lbajardsilogic@0: for (size_t j = 0; j < outputs.size(); ++j) { lbajardsilogic@0: lbajardsilogic@0: QString transformId = QString("%1:%2") lbajardsilogic@0: .arg(pluginId).arg(outputs[j].identifier.c_str()); lbajardsilogic@0: lbajardsilogic@0: QString userName; lbajardsilogic@0: QString friendlyName; lbajardsilogic@0: QString units = outputs[j].unit.c_str(); lbajardsilogic@0: QString description = plugin->getDescription().c_str(); lbajardsilogic@0: QString maker = plugin->getMaker().c_str(); lbajardsilogic@0: if (maker == "") maker = tr(""); lbajardsilogic@0: lbajardsilogic@0: if (description == "") { lbajardsilogic@0: if (outputs.size() == 1) { lbajardsilogic@0: description = tr("Extract features using \"%1\" plugin (from %2)") lbajardsilogic@0: .arg(pluginName).arg(maker); lbajardsilogic@0: } else { lbajardsilogic@0: description = tr("Extract features using \"%1\" output of \"%2\" plugin (from %3)") lbajardsilogic@0: .arg(outputs[j].name.c_str()).arg(pluginName).arg(maker); lbajardsilogic@0: } lbajardsilogic@0: } else { lbajardsilogic@0: if (outputs.size() == 1) { lbajardsilogic@0: description = tr("%1 using \"%2\" plugin (from %3)") lbajardsilogic@0: .arg(description).arg(pluginName).arg(maker); lbajardsilogic@0: } else { lbajardsilogic@0: description = tr("%1 using \"%2\" output of \"%3\" plugin (from %4)") lbajardsilogic@0: .arg(description).arg(outputs[j].name.c_str()).arg(pluginName).arg(maker); lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: if (outputs.size() == 1) { lbajardsilogic@0: userName = pluginName; lbajardsilogic@0: friendlyName = pluginName; lbajardsilogic@0: } else { lbajardsilogic@0: userName = QString("%1: %2") lbajardsilogic@0: .arg(pluginName) lbajardsilogic@0: .arg(outputs[j].name.c_str()); lbajardsilogic@0: friendlyName = outputs[j].name.c_str(); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: bool configurable = (!plugin->getPrograms().empty() || lbajardsilogic@0: !plugin->getParameterDescriptors().empty()); lbajardsilogic@0: lbajardsilogic@0: // std::cerr << "Feature extraction plugin transform: " << transformId.toStdString() << std::endl; lbajardsilogic@0: lbajardsilogic@0: transforms[transformId] = lbajardsilogic@0: TransformDesc(tr("Analysis"), lbajardsilogic@0: category, lbajardsilogic@0: transformId, lbajardsilogic@0: userName, lbajardsilogic@0: friendlyName, lbajardsilogic@0: description, lbajardsilogic@0: maker, lbajardsilogic@0: units, lbajardsilogic@0: configurable); lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: TransformFactory::populateRealTimePlugins(TransformDescriptionMap &transforms) lbajardsilogic@0: { lbajardsilogic@0: std::vector plugs = lbajardsilogic@0: RealTimePluginFactory::getAllPluginIdentifiers(); lbajardsilogic@0: lbajardsilogic@0: static QRegExp unitRE("[\\[\\(]([A-Za-z0-9/]+)[\\)\\]]$"); lbajardsilogic@0: lbajardsilogic@0: for (size_t i = 0; i < plugs.size(); ++i) { lbajardsilogic@0: lbajardsilogic@0: QString pluginId = plugs[i]; lbajardsilogic@0: lbajardsilogic@0: RealTimePluginFactory *factory = lbajardsilogic@0: RealTimePluginFactory::instanceFor(pluginId); lbajardsilogic@0: lbajardsilogic@0: if (!factory) { lbajardsilogic@0: std::cerr << "WARNING: TransformFactory::populateTransforms: No real time plugin factory for instance " << pluginId.toLocal8Bit().data() << std::endl; lbajardsilogic@0: continue; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: const RealTimePluginDescriptor *descriptor = lbajardsilogic@0: factory->getPluginDescriptor(pluginId); lbajardsilogic@0: lbajardsilogic@0: if (!descriptor) { lbajardsilogic@0: std::cerr << "WARNING: TransformFactory::populateTransforms: Failed to query plugin " << pluginId.toLocal8Bit().data() << std::endl; lbajardsilogic@0: continue; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: //!!! if (descriptor->controlOutputPortCount == 0 || lbajardsilogic@0: // descriptor->audioInputPortCount == 0) continue; lbajardsilogic@0: lbajardsilogic@0: // 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: lbajardsilogic@0: QString pluginName = descriptor->name.c_str(); lbajardsilogic@0: QString category = factory->getPluginCategory(pluginId); lbajardsilogic@0: bool configurable = (descriptor->parameterCount > 0); lbajardsilogic@0: QString maker = descriptor->maker.c_str(); lbajardsilogic@0: if (maker == "") maker = tr(""); lbajardsilogic@0: lbajardsilogic@0: if (descriptor->audioInputPortCount > 0) { lbajardsilogic@0: lbajardsilogic@0: for (size_t j = 0; j < descriptor->controlOutputPortCount; ++j) { lbajardsilogic@0: lbajardsilogic@0: QString transformId = QString("%1:%2").arg(pluginId).arg(j); lbajardsilogic@0: QString userName; lbajardsilogic@0: QString units; lbajardsilogic@0: QString portName; lbajardsilogic@0: lbajardsilogic@0: if (j < descriptor->controlOutputPortNames.size() && lbajardsilogic@0: descriptor->controlOutputPortNames[j] != "") { lbajardsilogic@0: lbajardsilogic@0: portName = descriptor->controlOutputPortNames[j].c_str(); lbajardsilogic@0: lbajardsilogic@0: userName = tr("%1: %2") lbajardsilogic@0: .arg(pluginName) lbajardsilogic@0: .arg(portName); lbajardsilogic@0: lbajardsilogic@0: if (unitRE.indexIn(portName) >= 0) { lbajardsilogic@0: units = unitRE.cap(1); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: } else if (descriptor->controlOutputPortCount > 1) { lbajardsilogic@0: lbajardsilogic@0: userName = tr("%1: Output %2") lbajardsilogic@0: .arg(pluginName) lbajardsilogic@0: .arg(j + 1); lbajardsilogic@0: lbajardsilogic@0: } else { lbajardsilogic@0: lbajardsilogic@0: userName = pluginName; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: QString description; lbajardsilogic@0: lbajardsilogic@0: if (portName != "") { lbajardsilogic@0: description = tr("Extract \"%1\" data output from \"%2\" effect plugin (from %3)") lbajardsilogic@0: .arg(portName) lbajardsilogic@0: .arg(pluginName) lbajardsilogic@0: .arg(maker); lbajardsilogic@0: } else { lbajardsilogic@0: description = tr("Extract data output %1 from \"%2\" effect plugin (from %3)") lbajardsilogic@0: .arg(j + 1) lbajardsilogic@0: .arg(pluginName) lbajardsilogic@0: .arg(maker); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: transforms[transformId] = lbajardsilogic@0: TransformDesc(tr("Effects Data"), lbajardsilogic@0: category, lbajardsilogic@0: transformId, lbajardsilogic@0: userName, lbajardsilogic@0: userName, lbajardsilogic@0: description, lbajardsilogic@0: maker, lbajardsilogic@0: units, lbajardsilogic@0: configurable); lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: if (!descriptor->isSynth || descriptor->audioInputPortCount > 0) { lbajardsilogic@0: lbajardsilogic@0: if (descriptor->audioOutputPortCount > 0) { lbajardsilogic@0: lbajardsilogic@0: QString transformId = QString("%1:A").arg(pluginId); lbajardsilogic@0: QString type = tr("Effects"); lbajardsilogic@0: lbajardsilogic@0: QString description = tr("Transform audio signal with \"%1\" effect plugin (from %2)") lbajardsilogic@0: .arg(pluginName) lbajardsilogic@0: .arg(maker); lbajardsilogic@0: lbajardsilogic@0: if (descriptor->audioInputPortCount == 0) { lbajardsilogic@0: type = tr("Generators"); lbajardsilogic@0: QString description = tr("Generate audio signal using \"%1\" plugin (from %2)") lbajardsilogic@0: .arg(pluginName) lbajardsilogic@0: .arg(maker); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: transforms[transformId] = lbajardsilogic@0: TransformDesc(type, lbajardsilogic@0: category, lbajardsilogic@0: transformId, lbajardsilogic@0: pluginName, lbajardsilogic@0: pluginName, lbajardsilogic@0: description, lbajardsilogic@0: maker, lbajardsilogic@0: "", lbajardsilogic@0: configurable); lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: QString lbajardsilogic@0: TransformFactory::getTransformName(TransformId identifier) lbajardsilogic@0: { lbajardsilogic@0: if (m_transforms.find(identifier) != m_transforms.end()) { lbajardsilogic@0: return m_transforms[identifier].name; lbajardsilogic@0: } else return ""; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: QString lbajardsilogic@0: TransformFactory::getTransformFriendlyName(TransformId identifier) lbajardsilogic@0: { lbajardsilogic@0: if (m_transforms.find(identifier) != m_transforms.end()) { lbajardsilogic@0: return m_transforms[identifier].friendlyName; lbajardsilogic@0: } else return ""; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: QString lbajardsilogic@0: TransformFactory::getTransformUnits(TransformId identifier) lbajardsilogic@0: { lbajardsilogic@0: if (m_transforms.find(identifier) != m_transforms.end()) { lbajardsilogic@0: return m_transforms[identifier].units; lbajardsilogic@0: } else return ""; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: bool lbajardsilogic@0: TransformFactory::isTransformConfigurable(TransformId identifier) lbajardsilogic@0: { lbajardsilogic@0: if (m_transforms.find(identifier) != m_transforms.end()) { lbajardsilogic@0: return m_transforms[identifier].configurable; lbajardsilogic@0: } else return false; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: bool lbajardsilogic@0: TransformFactory::getTransformChannelRange(TransformId identifier, lbajardsilogic@0: int &min, int &max) lbajardsilogic@0: { lbajardsilogic@0: QString id = identifier.section(':', 0, 2); lbajardsilogic@0: lbajardsilogic@0: if (FeatureExtractionPluginFactory::instanceFor(id)) { lbajardsilogic@0: lbajardsilogic@0: Vamp::Plugin *plugin = lbajardsilogic@0: FeatureExtractionPluginFactory::instanceFor(id)-> lbajardsilogic@0: instantiatePlugin(id, 48000); lbajardsilogic@0: if (!plugin) return false; lbajardsilogic@0: lbajardsilogic@0: min = plugin->getMinChannelCount(); lbajardsilogic@0: max = plugin->getMaxChannelCount(); lbajardsilogic@0: delete plugin; lbajardsilogic@0: lbajardsilogic@0: return true; lbajardsilogic@0: lbajardsilogic@0: } else if (RealTimePluginFactory::instanceFor(id)) { lbajardsilogic@0: lbajardsilogic@0: const RealTimePluginDescriptor *descriptor = lbajardsilogic@0: RealTimePluginFactory::instanceFor(id)-> lbajardsilogic@0: getPluginDescriptor(id); lbajardsilogic@0: if (!descriptor) return false; lbajardsilogic@0: lbajardsilogic@0: min = descriptor->audioInputPortCount; lbajardsilogic@0: max = descriptor->audioInputPortCount; lbajardsilogic@0: lbajardsilogic@0: return true; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: return false; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: bool lbajardsilogic@0: TransformFactory::getChannelRange(TransformId identifier, Vamp::PluginBase *plugin, lbajardsilogic@0: int &minChannels, int &maxChannels) lbajardsilogic@0: { lbajardsilogic@0: Vamp::Plugin *vp = 0; lbajardsilogic@0: if ((vp = dynamic_cast(plugin)) || lbajardsilogic@0: (vp = dynamic_cast(plugin))) { lbajardsilogic@0: minChannels = vp->getMinChannelCount(); lbajardsilogic@0: maxChannels = vp->getMaxChannelCount(); lbajardsilogic@0: return true; lbajardsilogic@0: } else { lbajardsilogic@0: return getTransformChannelRange(identifier, minChannels, maxChannels); lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: Model * lbajardsilogic@0: TransformFactory::getConfigurationForTransform(TransformId identifier, lbajardsilogic@0: const std::vector &candidateInputModels, lbajardsilogic@0: PluginTransform::ExecutionContext &context, lbajardsilogic@0: QString &configurationXml, lbajardsilogic@0: AudioCallbackPlaySource *source) lbajardsilogic@0: { lbajardsilogic@0: if (candidateInputModels.empty()) return 0; lbajardsilogic@0: lbajardsilogic@0: //!!! This will need revision -- we'll have to have a callback lbajardsilogic@0: //from the dialog for when the candidate input model is changed, lbajardsilogic@0: //as we'll need to reinitialise the channel settings in the dialog lbajardsilogic@0: Model *inputModel = candidateInputModels[0]; //!!! for now lbajardsilogic@0: QStringList candidateModelNames; lbajardsilogic@0: std::map modelMap; lbajardsilogic@0: for (size_t i = 0; i < candidateInputModels.size(); ++i) { lbajardsilogic@0: QString modelName = candidateInputModels[i]->objectName(); lbajardsilogic@0: QString origModelName = modelName; lbajardsilogic@0: int dupcount = 1; lbajardsilogic@0: while (modelMap.find(modelName) != modelMap.end()) { lbajardsilogic@0: modelName = tr("%1 <%2>").arg(origModelName).arg(++dupcount); lbajardsilogic@0: } lbajardsilogic@0: modelMap[modelName] = candidateInputModels[i]; lbajardsilogic@0: candidateModelNames.push_back(modelName); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: QString id = identifier.section(':', 0, 2); lbajardsilogic@0: QString output = identifier.section(':', 3); lbajardsilogic@0: QString outputLabel = ""; lbajardsilogic@0: QString outputDescription = ""; lbajardsilogic@0: lbajardsilogic@0: bool ok = false; lbajardsilogic@0: configurationXml = m_lastConfigurations[identifier]; lbajardsilogic@0: lbajardsilogic@0: // std::cerr << "last configuration: " << configurationXml.toStdString() << std::endl; lbajardsilogic@0: lbajardsilogic@0: Vamp::PluginBase *plugin = 0; lbajardsilogic@0: lbajardsilogic@0: bool frequency = false; lbajardsilogic@0: bool effect = false; lbajardsilogic@0: bool generator = false; lbajardsilogic@0: lbajardsilogic@0: if (FeatureExtractionPluginFactory::instanceFor(id)) { lbajardsilogic@0: lbajardsilogic@0: Vamp::Plugin *vp = lbajardsilogic@0: FeatureExtractionPluginFactory::instanceFor(id)->instantiatePlugin lbajardsilogic@0: (id, inputModel->getSampleRate()); lbajardsilogic@0: lbajardsilogic@0: if (vp) { lbajardsilogic@0: lbajardsilogic@0: plugin = vp; lbajardsilogic@0: frequency = (vp->getInputDomain() == Vamp::Plugin::FrequencyDomain); lbajardsilogic@0: lbajardsilogic@0: std::vector od = lbajardsilogic@0: vp->getOutputDescriptors(); lbajardsilogic@0: if (od.size() > 1) { lbajardsilogic@0: for (size_t i = 0; i < od.size(); ++i) { lbajardsilogic@0: if (od[i].identifier == output.toStdString()) { lbajardsilogic@0: outputLabel = od[i].name.c_str(); lbajardsilogic@0: outputDescription = od[i].description.c_str(); lbajardsilogic@0: break; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: } else if (RealTimePluginFactory::instanceFor(id)) { lbajardsilogic@0: lbajardsilogic@0: RealTimePluginFactory *factory = RealTimePluginFactory::instanceFor(id); lbajardsilogic@0: const RealTimePluginDescriptor *desc = factory->getPluginDescriptor(id); lbajardsilogic@0: lbajardsilogic@0: if (desc->audioInputPortCount > 0 && lbajardsilogic@0: desc->audioOutputPortCount > 0 && lbajardsilogic@0: !desc->isSynth) { lbajardsilogic@0: effect = true; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: if (desc->audioInputPortCount == 0) { lbajardsilogic@0: generator = true; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: if (output != "A") { lbajardsilogic@0: int outputNo = output.toInt(); lbajardsilogic@0: if (outputNo >= 0 && outputNo < int(desc->controlOutputPortCount)) { lbajardsilogic@0: outputLabel = desc->controlOutputPortNames[outputNo].c_str(); lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: size_t sampleRate = inputModel->getSampleRate(); lbajardsilogic@0: size_t blockSize = 1024; lbajardsilogic@0: size_t channels = 1; lbajardsilogic@0: if (effect && source) { lbajardsilogic@0: sampleRate = source->getTargetSampleRate(); lbajardsilogic@0: blockSize = source->getTargetBlockSize(); lbajardsilogic@0: channels = source->getTargetChannelCount(); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: RealTimePluginInstance *rtp = factory->instantiatePlugin lbajardsilogic@0: (id, 0, 0, sampleRate, blockSize, channels); lbajardsilogic@0: lbajardsilogic@0: plugin = rtp; lbajardsilogic@0: lbajardsilogic@0: if (effect && source && rtp) { lbajardsilogic@0: source->setAuditioningPlugin(rtp); lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: if (plugin) { lbajardsilogic@0: lbajardsilogic@0: context = PluginTransform::ExecutionContext(context.channel, plugin); lbajardsilogic@0: lbajardsilogic@0: if (configurationXml != "") { lbajardsilogic@0: PluginXml(plugin).setParametersFromXml(configurationXml); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: int sourceChannels = 1; lbajardsilogic@0: if (dynamic_cast(inputModel)) { lbajardsilogic@0: sourceChannels = dynamic_cast(inputModel) lbajardsilogic@0: ->getChannelCount(); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: int minChannels = 1, maxChannels = sourceChannels; lbajardsilogic@0: getChannelRange(identifier, plugin, minChannels, maxChannels); lbajardsilogic@0: lbajardsilogic@0: int targetChannels = sourceChannels; lbajardsilogic@0: if (!effect) { lbajardsilogic@0: if (sourceChannels < minChannels) targetChannels = minChannels; lbajardsilogic@0: if (sourceChannels > maxChannels) targetChannels = maxChannels; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: int defaultChannel = context.channel; lbajardsilogic@0: lbajardsilogic@0: PluginParameterDialog *dialog = new PluginParameterDialog(plugin); lbajardsilogic@0: lbajardsilogic@0: if (candidateModelNames.size() > 1 && !generator) { lbajardsilogic@0: dialog->setCandidateInputModels(candidateModelNames); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: if (targetChannels > 0) { lbajardsilogic@0: dialog->setChannelArrangement(sourceChannels, targetChannels, lbajardsilogic@0: defaultChannel); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: dialog->setOutputLabel(outputLabel, outputDescription); lbajardsilogic@0: lbajardsilogic@0: dialog->setShowProcessingOptions(true, frequency); lbajardsilogic@0: lbajardsilogic@0: if (dialog->exec() == QDialog::Accepted) { lbajardsilogic@0: ok = true; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: QString selectedInput = dialog->getInputModel(); lbajardsilogic@0: if (selectedInput != "") { lbajardsilogic@0: if (modelMap.find(selectedInput) != modelMap.end()) { lbajardsilogic@0: inputModel = modelMap[selectedInput]; lbajardsilogic@0: std::cerr << "Found selected input \"" << selectedInput.toStdString() << "\" in model map, result is " << inputModel << std::endl; lbajardsilogic@0: } else { lbajardsilogic@0: std::cerr << "Failed to find selected input \"" << selectedInput.toStdString() << "\" in model map" << std::endl; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: configurationXml = PluginXml(plugin).toXmlString(); lbajardsilogic@0: context.channel = dialog->getChannel(); lbajardsilogic@0: lbajardsilogic@0: dialog->getProcessingParameters(context.stepSize, lbajardsilogic@0: context.blockSize, lbajardsilogic@0: context.windowType); lbajardsilogic@0: lbajardsilogic@0: context.makeConsistentWithPlugin(plugin); lbajardsilogic@0: lbajardsilogic@0: delete dialog; lbajardsilogic@0: lbajardsilogic@0: if (effect && source) { lbajardsilogic@0: source->setAuditioningPlugin(0); // will delete our plugin lbajardsilogic@0: } else { lbajardsilogic@0: delete plugin; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: if (ok) m_lastConfigurations[identifier] = configurationXml; lbajardsilogic@0: lbajardsilogic@0: return ok ? inputModel : 0; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: PluginTransform::ExecutionContext lbajardsilogic@0: TransformFactory::getDefaultContextForTransform(TransformId identifier, lbajardsilogic@0: Model *inputModel) lbajardsilogic@0: { lbajardsilogic@0: PluginTransform::ExecutionContext context(-1); lbajardsilogic@0: lbajardsilogic@0: QString id = identifier.section(':', 0, 2); lbajardsilogic@0: lbajardsilogic@0: if (FeatureExtractionPluginFactory::instanceFor(id)) { lbajardsilogic@0: lbajardsilogic@0: Vamp::Plugin *vp = lbajardsilogic@0: FeatureExtractionPluginFactory::instanceFor(id)->instantiatePlugin lbajardsilogic@0: (id, inputModel ? inputModel->getSampleRate() : 48000); lbajardsilogic@0: lbajardsilogic@0: if (vp) context = PluginTransform::ExecutionContext(-1, vp); lbajardsilogic@0: lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: return context; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: Transform * lbajardsilogic@0: TransformFactory::createTransform(TransformId identifier, Model *inputModel, lbajardsilogic@0: const PluginTransform::ExecutionContext &context, lbajardsilogic@0: QString configurationXml) lbajardsilogic@0: { lbajardsilogic@0: Transform *transform = 0; lbajardsilogic@0: lbajardsilogic@0: QString id = identifier.section(':', 0, 2); lbajardsilogic@0: QString output = identifier.section(':', 3); lbajardsilogic@0: lbajardsilogic@0: if (FeatureExtractionPluginFactory::instanceFor(id)) { lbajardsilogic@0: transform = new FeatureExtractionPluginTransform(inputModel, lbajardsilogic@0: id, lbajardsilogic@0: context, lbajardsilogic@0: configurationXml, lbajardsilogic@0: output); lbajardsilogic@0: } else if (RealTimePluginFactory::instanceFor(id)) { lbajardsilogic@0: transform = new RealTimePluginTransform(inputModel, lbajardsilogic@0: id, lbajardsilogic@0: context, lbajardsilogic@0: configurationXml, lbajardsilogic@0: getTransformUnits(identifier), lbajardsilogic@0: output == "A" ? -1 : lbajardsilogic@0: output.toInt()); lbajardsilogic@0: } else { lbajardsilogic@0: std::cerr << "TransformFactory::createTransform: Unknown transform \"" lbajardsilogic@0: << identifier.toStdString() << "\"" << std::endl; lbajardsilogic@0: return transform; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: if (transform) transform->setObjectName(identifier); lbajardsilogic@0: return transform; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: Model * lbajardsilogic@0: TransformFactory::transform(TransformId identifier, Model *inputModel, lbajardsilogic@0: const PluginTransform::ExecutionContext &context, lbajardsilogic@0: QString configurationXml) lbajardsilogic@0: { lbajardsilogic@0: Transform *t = createTransform(identifier, inputModel, context, lbajardsilogic@0: configurationXml); lbajardsilogic@0: lbajardsilogic@0: if (!t) return 0; lbajardsilogic@0: lbajardsilogic@0: connect(t, SIGNAL(finished()), this, SLOT(transformFinished())); lbajardsilogic@0: lbajardsilogic@0: m_runningTransforms.insert(t); lbajardsilogic@0: lbajardsilogic@0: t->start(); lbajardsilogic@0: Model *model = t->detachOutputModel(); lbajardsilogic@0: lbajardsilogic@0: if (model) { lbajardsilogic@0: QString imn = inputModel->objectName(); lbajardsilogic@0: QString trn = getTransformFriendlyName(identifier); lbajardsilogic@0: if (imn != "") { lbajardsilogic@0: if (trn != "") { lbajardsilogic@0: model->setObjectName(tr("%1: %2").arg(imn).arg(trn)); lbajardsilogic@0: } else { lbajardsilogic@0: model->setObjectName(imn); lbajardsilogic@0: } lbajardsilogic@0: } else if (trn != "") { lbajardsilogic@0: model->setObjectName(trn); lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: return model; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: TransformFactory::transformFinished() lbajardsilogic@0: { lbajardsilogic@0: QObject *s = sender(); lbajardsilogic@0: Transform *transform = dynamic_cast(s); lbajardsilogic@0: lbajardsilogic@0: std::cerr << "TransformFactory::transformFinished(" << transform << ")" << std::endl; lbajardsilogic@0: lbajardsilogic@0: if (!transform) { lbajardsilogic@0: std::cerr << "WARNING: TransformFactory::transformFinished: sender is not a transform" << std::endl; lbajardsilogic@0: return; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: if (m_runningTransforms.find(transform) == m_runningTransforms.end()) { lbajardsilogic@0: std::cerr << "WARNING: TransformFactory::transformFinished(" lbajardsilogic@0: << transform lbajardsilogic@0: << "): I have no record of this transform running!" lbajardsilogic@0: << std::endl; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: m_runningTransforms.erase(transform); lbajardsilogic@0: lbajardsilogic@0: transform->wait(); // unnecessary but reassuring lbajardsilogic@0: delete transform; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: TransformFactory::modelAboutToBeDeleted(Model *m) lbajardsilogic@0: { lbajardsilogic@0: TransformSet affected; lbajardsilogic@0: lbajardsilogic@0: for (TransformSet::iterator i = m_runningTransforms.begin(); lbajardsilogic@0: i != m_runningTransforms.end(); ++i) { lbajardsilogic@0: lbajardsilogic@0: Transform *t = *i; lbajardsilogic@0: lbajardsilogic@0: if (t->getInputModel() == m || t->getOutputModel() == m) { lbajardsilogic@0: affected.insert(t); lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: for (TransformSet::iterator i = affected.begin(); lbajardsilogic@0: i != affected.end(); ++i) { lbajardsilogic@0: lbajardsilogic@0: Transform *t = *i; lbajardsilogic@0: lbajardsilogic@0: t->abandon(); lbajardsilogic@0: lbajardsilogic@0: t->wait(); // this should eventually call back on lbajardsilogic@0: // transformFinished, which will remove from lbajardsilogic@0: // m_runningTransforms and delete. lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: