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