Chris@205: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@205: Chris@205: /* Chris@205: Sonic Visualiser Chris@205: An audio file viewer and annotation editor. Chris@205: Centre for Digital Music, Queen Mary, University of London. Chris@205: Chris@205: This program is free software; you can redistribute it and/or Chris@205: modify it under the terms of the GNU General Public License as Chris@205: published by the Free Software Foundation; either version 2 of the Chris@205: License, or (at your option) any later version. See the file Chris@205: COPYING included with this distribution for more information. Chris@205: */ Chris@205: Chris@205: #include "TransformUserConfigurator.h" Chris@205: Chris@205: #include "transform/TransformFactory.h" Chris@205: Chris@205: #include "widgets/PluginParameterDialog.h" Chris@205: Chris@205: #include "plugin/FeatureExtractionPluginFactory.h" Chris@205: #include "plugin/RealTimePluginFactory.h" Chris@205: #include "plugin/RealTimePluginInstance.h" Chris@205: Chris@205: #include "data/model/DenseTimeValueModel.h" Chris@205: Chris@205: #include Chris@205: Chris@205: #include Chris@205: Chris@205: #include Chris@205: Chris@636: static QWidget *parentWidget = nullptr; Chris@395: Chris@395: void Chris@395: TransformUserConfigurator::setParentWidget(QWidget *w) Chris@395: { Chris@395: parentWidget = w; Chris@395: } Chris@395: Chris@205: bool Chris@205: TransformUserConfigurator::getChannelRange(TransformId identifier, Chris@740: std::shared_ptr plugin, Chris@595: int &minChannels, int &maxChannels) Chris@205: { Chris@205: if (plugin && plugin->getType() == "Feature Extraction Plugin") { Chris@740: auto vp = std::dynamic_pointer_cast(plugin); Chris@740: if (vp) { Chris@740: SVDEBUG << "TransformUserConfigurator::getChannelRange: is a Vamp plugin" << endl; Chris@740: minChannels = int(vp->getMinChannelCount()); Chris@740: maxChannels = int(vp->getMaxChannelCount()); Chris@740: return true; Chris@740: } else { Chris@740: SVCERR << "TransformUserConfigurator::getChannelRange: inconsistent plugin identity!" << endl; Chris@740: return false; Chris@740: } Chris@205: } else { Chris@595: SVDEBUG << "TransformUserConfigurator::getChannelRange: is not a Vamp plugin" << endl; Chris@205: return TransformFactory::getInstance()-> Chris@205: getTransformChannelRange(identifier, minChannels, maxChannels); Chris@205: } Chris@205: } Chris@205: Chris@205: bool Chris@205: TransformUserConfigurator::configure(ModelTransformer::Input &input, Chris@595: Transform &transform, Chris@740: std::shared_ptr plugin, Chris@685: ModelId &inputModel, Chris@595: AudioPlaySource *source, Chris@595: sv_frame_t startFrame, Chris@595: sv_frame_t duration, Chris@685: const QMap &modelMap, Chris@595: QStringList candidateModelNames, Chris@595: QString defaultModelName) Chris@205: { Chris@205: bool ok = false; Chris@205: QString id = transform.getPluginIdentifier(); Chris@205: QString output = transform.getOutput(); Chris@205: QString outputLabel = ""; Chris@205: QString outputDescription = ""; Chris@205: Chris@205: bool frequency = false; Chris@205: bool effect = false; Chris@205: bool generator = false; Chris@205: Chris@205: if (!plugin) return false; Chris@205: Chris@536: SVDEBUG << "TransformUserConfigurator::configure: identifier " << id << endl; Chris@536: Chris@529: if (RealTimePluginFactory::instanceFor(id)) { Chris@205: Chris@205: RealTimePluginFactory *factory = RealTimePluginFactory::instanceFor(id); Chris@740: RealTimePluginDescriptor desc = factory->getPluginDescriptor(id); Chris@205: Chris@740: if (desc.audioInputPortCount > 0 && Chris@740: desc.audioOutputPortCount > 0 && Chris@740: !desc.isSynth) { Chris@205: effect = true; Chris@205: } Chris@205: Chris@740: if (desc.audioInputPortCount == 0) { Chris@205: generator = true; Chris@205: } Chris@205: Chris@205: if (output != "A") { Chris@205: int outputNo = output.toInt(); Chris@740: if (outputNo >= 0 && outputNo < int(desc.controlOutputPortCount)) { Chris@740: outputLabel = desc.controlOutputPortNames[outputNo].c_str(); Chris@205: } Chris@205: } Chris@205: Chris@740: auto auditionable = std::dynamic_pointer_cast(plugin); Chris@740: Chris@740: if (effect && source && auditionable) { Chris@595: SVDEBUG << "Setting auditioning effect" << endl; Chris@739: source->setAuditioningEffect(auditionable); Chris@205: } Chris@529: Chris@529: } else { Chris@529: Chris@740: auto vp = std::dynamic_pointer_cast(plugin); Chris@529: Chris@595: frequency = (vp->getInputDomain() == Vamp::Plugin::FrequencyDomain); Chris@529: Chris@595: std::vector od = Chris@595: vp->getOutputDescriptors(); Chris@529: Chris@595: if (od.size() > 1) { Chris@595: for (size_t i = 0; i < od.size(); ++i) { Chris@595: if (od[i].identifier == output.toStdString()) { Chris@595: outputLabel = od[i].name.c_str(); Chris@595: outputDescription = od[i].description.c_str(); Chris@595: break; Chris@595: } Chris@595: } Chris@529: } Chris@205: } Chris@529: Chris@205: int sourceChannels = 1; Chris@685: Chris@685: if (auto dtvm = ModelById::getAs(inputModel)) { Chris@685: sourceChannels = dtvm->getChannelCount(); Chris@205: } Chris@205: Chris@205: int minChannels = 1, maxChannels = sourceChannels; Chris@205: getChannelRange(transform.getIdentifier(), plugin, Chris@595: minChannels, maxChannels); Chris@205: Chris@205: int targetChannels = sourceChannels; Chris@205: if (!effect) { Chris@595: if (sourceChannels < minChannels) targetChannels = minChannels; Chris@595: if (sourceChannels > maxChannels) targetChannels = maxChannels; Chris@205: } Chris@205: Chris@205: int defaultChannel = -1; //!!! no longer saved! [was context.channel] Chris@205: Chris@395: PluginParameterDialog *dialog = new PluginParameterDialog Chris@395: (plugin, parentWidget); Chris@205: Chris@205: dialog->setMoreInfoUrl(TransformFactory::getInstance()-> Chris@747: getTransformProvider(transform.getIdentifier()) Chris@747: .infoUrl); Chris@205: Chris@205: if (candidateModelNames.size() > 1 && !generator) { Chris@595: dialog->setCandidateInputModels(candidateModelNames, Chris@595: defaultModelName); Chris@205: } Chris@205: Chris@205: if (startFrame != 0 || duration != 0) { Chris@595: dialog->setShowSelectionOnlyOption(true); Chris@205: } Chris@205: Chris@205: if (targetChannels > 0) { Chris@595: dialog->setChannelArrangement(sourceChannels, targetChannels, Chris@595: defaultChannel); Chris@205: } Chris@205: Chris@205: dialog->setOutputLabel(outputLabel, outputDescription); Chris@205: Chris@205: dialog->setShowProcessingOptions(true, frequency); Chris@205: Chris@205: if (dialog->exec() == QDialog::Accepted) { Chris@595: ok = true; Chris@205: } Chris@205: Chris@205: QString selectedInput = dialog->getInputModel(); Chris@205: if (selectedInput != "") { Chris@595: if (modelMap.contains(selectedInput)) { Chris@595: inputModel = modelMap.value(selectedInput); Chris@595: SVDEBUG << "Found selected input \"" << selectedInput << "\" in model map, result is " << inputModel << endl; Chris@595: } else { Chris@595: SVDEBUG << "Failed to find selected input \"" << selectedInput << "\" in model map" << endl; Chris@595: } Chris@205: } else { Chris@595: SVDEBUG << "Selected input empty: \"" << selectedInput << "\"" << endl; Chris@205: } Chris@205: Chris@205: // Write parameters back to transform object Chris@205: TransformFactory::getInstance()-> Chris@595: setParametersFromPlugin(transform, plugin); Chris@205: Chris@205: input.setChannel(dialog->getChannel()); Chris@205: Chris@205: //!!! The dialog ought to be taking & returning transform Chris@205: //objects and input objects and stuff rather than passing Chris@205: //around all this misc stuff, but that's for tomorrow Chris@205: //(whenever that may be) Chris@205: Chris@685: sv_samplerate_t sampleRate = 0; Chris@685: if (auto m = ModelById::get(inputModel)) { Chris@685: sampleRate = m->getSampleRate(); Chris@685: } Chris@685: Chris@205: if (startFrame != 0 || duration != 0) { Chris@685: if (dialog->getSelectionOnly() && sampleRate != 0) { Chris@685: transform.setStartTime Chris@685: (RealTime::frame2RealTime(startFrame, sampleRate)); Chris@685: transform.setDuration Chris@685: (RealTime::frame2RealTime(duration, sampleRate)); Chris@595: } Chris@205: } Chris@205: Chris@366: int stepSize = 0, blockSize = 0; Chris@205: WindowType windowType = HanningWindow; Chris@205: Chris@205: dialog->getProcessingParameters(stepSize, Chris@595: blockSize, Chris@595: windowType); Chris@205: Chris@205: transform.setStepSize(stepSize); Chris@205: transform.setBlockSize(blockSize); Chris@205: transform.setWindowType(windowType); Chris@205: Chris@205: delete dialog; Chris@205: Chris@205: if (effect && source) { Chris@739: source->setAuditioningEffect({}); Chris@205: } Chris@205: Chris@205: return ok; Chris@205: } Chris@205: