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