annotate framework/TransformUserConfigurator.cpp @ 771:1d6cca5a5621 pitch-align

Allow use of proper sparse models (i.e. retaining event time info) in alignment; use this to switch to note alignment, which is what we have most recently been doing in the external program. Not currently producing correct results, though
author Chris Cannam
date Fri, 29 May 2020 17:39:02 +0100
parents bac019c94e38
children
rev   line source
Chris@205 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@205 2
Chris@205 3 /*
Chris@205 4 Sonic Visualiser
Chris@205 5 An audio file viewer and annotation editor.
Chris@205 6 Centre for Digital Music, Queen Mary, University of London.
Chris@205 7
Chris@205 8 This program is free software; you can redistribute it and/or
Chris@205 9 modify it under the terms of the GNU General Public License as
Chris@205 10 published by the Free Software Foundation; either version 2 of the
Chris@205 11 License, or (at your option) any later version. See the file
Chris@205 12 COPYING included with this distribution for more information.
Chris@205 13 */
Chris@205 14
Chris@205 15 #include "TransformUserConfigurator.h"
Chris@205 16
Chris@205 17 #include "transform/TransformFactory.h"
Chris@205 18
Chris@205 19 #include "widgets/PluginParameterDialog.h"
Chris@205 20
Chris@205 21 #include "plugin/FeatureExtractionPluginFactory.h"
Chris@205 22 #include "plugin/RealTimePluginFactory.h"
Chris@205 23 #include "plugin/RealTimePluginInstance.h"
Chris@205 24
Chris@205 25 #include "data/model/DenseTimeValueModel.h"
Chris@205 26
Chris@205 27 #include <vamp-hostsdk/Plugin.h>
Chris@205 28
Chris@205 29 #include <QStringList>
Chris@205 30
Chris@205 31 #include <typeinfo>
Chris@205 32
Chris@636 33 static QWidget *parentWidget = nullptr;
Chris@395 34
Chris@395 35 void
Chris@395 36 TransformUserConfigurator::setParentWidget(QWidget *w)
Chris@395 37 {
Chris@395 38 parentWidget = w;
Chris@395 39 }
Chris@395 40
Chris@205 41 bool
Chris@205 42 TransformUserConfigurator::getChannelRange(TransformId identifier,
Chris@740 43 std::shared_ptr<Vamp::PluginBase> plugin,
Chris@595 44 int &minChannels, int &maxChannels)
Chris@205 45 {
Chris@205 46 if (plugin && plugin->getType() == "Feature Extraction Plugin") {
Chris@740 47 auto vp = std::dynamic_pointer_cast<Vamp::Plugin>(plugin);
Chris@740 48 if (vp) {
Chris@740 49 SVDEBUG << "TransformUserConfigurator::getChannelRange: is a Vamp plugin" << endl;
Chris@740 50 minChannels = int(vp->getMinChannelCount());
Chris@740 51 maxChannels = int(vp->getMaxChannelCount());
Chris@740 52 return true;
Chris@740 53 } else {
Chris@740 54 SVCERR << "TransformUserConfigurator::getChannelRange: inconsistent plugin identity!" << endl;
Chris@740 55 return false;
Chris@740 56 }
Chris@205 57 } else {
Chris@595 58 SVDEBUG << "TransformUserConfigurator::getChannelRange: is not a Vamp plugin" << endl;
Chris@205 59 return TransformFactory::getInstance()->
Chris@205 60 getTransformChannelRange(identifier, minChannels, maxChannels);
Chris@205 61 }
Chris@205 62 }
Chris@205 63
Chris@205 64 bool
Chris@205 65 TransformUserConfigurator::configure(ModelTransformer::Input &input,
Chris@595 66 Transform &transform,
Chris@740 67 std::shared_ptr<Vamp::PluginBase> plugin,
Chris@685 68 ModelId &inputModel,
Chris@595 69 AudioPlaySource *source,
Chris@595 70 sv_frame_t startFrame,
Chris@595 71 sv_frame_t duration,
Chris@685 72 const QMap<QString, ModelId> &modelMap,
Chris@595 73 QStringList candidateModelNames,
Chris@595 74 QString defaultModelName)
Chris@205 75 {
Chris@205 76 bool ok = false;
Chris@205 77 QString id = transform.getPluginIdentifier();
Chris@205 78 QString output = transform.getOutput();
Chris@205 79 QString outputLabel = "";
Chris@205 80 QString outputDescription = "";
Chris@205 81
Chris@205 82 bool frequency = false;
Chris@205 83 bool effect = false;
Chris@205 84 bool generator = false;
Chris@205 85
Chris@205 86 if (!plugin) return false;
Chris@205 87
Chris@536 88 SVDEBUG << "TransformUserConfigurator::configure: identifier " << id << endl;
Chris@536 89
Chris@529 90 if (RealTimePluginFactory::instanceFor(id)) {
Chris@205 91
Chris@205 92 RealTimePluginFactory *factory = RealTimePluginFactory::instanceFor(id);
Chris@740 93 RealTimePluginDescriptor desc = factory->getPluginDescriptor(id);
Chris@205 94
Chris@740 95 if (desc.audioInputPortCount > 0 &&
Chris@740 96 desc.audioOutputPortCount > 0 &&
Chris@740 97 !desc.isSynth) {
Chris@205 98 effect = true;
Chris@205 99 }
Chris@205 100
Chris@740 101 if (desc.audioInputPortCount == 0) {
Chris@205 102 generator = true;
Chris@205 103 }
Chris@205 104
Chris@205 105 if (output != "A") {
Chris@205 106 int outputNo = output.toInt();
Chris@740 107 if (outputNo >= 0 && outputNo < int(desc.controlOutputPortCount)) {
Chris@740 108 outputLabel = desc.controlOutputPortNames[outputNo].c_str();
Chris@205 109 }
Chris@205 110 }
Chris@205 111
Chris@740 112 auto auditionable = std::dynamic_pointer_cast<Auditionable>(plugin);
Chris@740 113
Chris@740 114 if (effect && source && auditionable) {
Chris@595 115 SVDEBUG << "Setting auditioning effect" << endl;
Chris@739 116 source->setAuditioningEffect(auditionable);
Chris@205 117 }
Chris@529 118
Chris@529 119 } else {
Chris@529 120
Chris@740 121 auto vp = std::dynamic_pointer_cast<Vamp::Plugin>(plugin);
Chris@529 122
Chris@595 123 frequency = (vp->getInputDomain() == Vamp::Plugin::FrequencyDomain);
Chris@529 124
Chris@595 125 std::vector<Vamp::Plugin::OutputDescriptor> od =
Chris@595 126 vp->getOutputDescriptors();
Chris@529 127
Chris@595 128 if (od.size() > 1) {
Chris@595 129 for (size_t i = 0; i < od.size(); ++i) {
Chris@595 130 if (od[i].identifier == output.toStdString()) {
Chris@595 131 outputLabel = od[i].name.c_str();
Chris@595 132 outputDescription = od[i].description.c_str();
Chris@595 133 break;
Chris@595 134 }
Chris@595 135 }
Chris@529 136 }
Chris@205 137 }
Chris@529 138
Chris@205 139 int sourceChannels = 1;
Chris@685 140
Chris@685 141 if (auto dtvm = ModelById::getAs<DenseTimeValueModel>(inputModel)) {
Chris@685 142 sourceChannels = dtvm->getChannelCount();
Chris@205 143 }
Chris@205 144
Chris@205 145 int minChannels = 1, maxChannels = sourceChannels;
Chris@205 146 getChannelRange(transform.getIdentifier(), plugin,
Chris@595 147 minChannels, maxChannels);
Chris@205 148
Chris@205 149 int targetChannels = sourceChannels;
Chris@205 150 if (!effect) {
Chris@595 151 if (sourceChannels < minChannels) targetChannels = minChannels;
Chris@595 152 if (sourceChannels > maxChannels) targetChannels = maxChannels;
Chris@205 153 }
Chris@205 154
Chris@205 155 int defaultChannel = -1; //!!! no longer saved! [was context.channel]
Chris@205 156
Chris@395 157 PluginParameterDialog *dialog = new PluginParameterDialog
Chris@395 158 (plugin, parentWidget);
Chris@205 159
Chris@205 160 dialog->setMoreInfoUrl(TransformFactory::getInstance()->
Chris@747 161 getTransformProvider(transform.getIdentifier())
Chris@747 162 .infoUrl);
Chris@205 163
Chris@205 164 if (candidateModelNames.size() > 1 && !generator) {
Chris@595 165 dialog->setCandidateInputModels(candidateModelNames,
Chris@595 166 defaultModelName);
Chris@205 167 }
Chris@205 168
Chris@205 169 if (startFrame != 0 || duration != 0) {
Chris@595 170 dialog->setShowSelectionOnlyOption(true);
Chris@205 171 }
Chris@205 172
Chris@205 173 if (targetChannels > 0) {
Chris@595 174 dialog->setChannelArrangement(sourceChannels, targetChannels,
Chris@595 175 defaultChannel);
Chris@205 176 }
Chris@205 177
Chris@205 178 dialog->setOutputLabel(outputLabel, outputDescription);
Chris@205 179
Chris@205 180 dialog->setShowProcessingOptions(true, frequency);
Chris@205 181
Chris@205 182 if (dialog->exec() == QDialog::Accepted) {
Chris@595 183 ok = true;
Chris@205 184 }
Chris@205 185
Chris@205 186 QString selectedInput = dialog->getInputModel();
Chris@205 187 if (selectedInput != "") {
Chris@595 188 if (modelMap.contains(selectedInput)) {
Chris@595 189 inputModel = modelMap.value(selectedInput);
Chris@595 190 SVDEBUG << "Found selected input \"" << selectedInput << "\" in model map, result is " << inputModel << endl;
Chris@595 191 } else {
Chris@595 192 SVDEBUG << "Failed to find selected input \"" << selectedInput << "\" in model map" << endl;
Chris@595 193 }
Chris@205 194 } else {
Chris@595 195 SVDEBUG << "Selected input empty: \"" << selectedInput << "\"" << endl;
Chris@205 196 }
Chris@205 197
Chris@205 198 // Write parameters back to transform object
Chris@205 199 TransformFactory::getInstance()->
Chris@595 200 setParametersFromPlugin(transform, plugin);
Chris@205 201
Chris@205 202 input.setChannel(dialog->getChannel());
Chris@205 203
Chris@205 204 //!!! The dialog ought to be taking & returning transform
Chris@205 205 //objects and input objects and stuff rather than passing
Chris@205 206 //around all this misc stuff, but that's for tomorrow
Chris@205 207 //(whenever that may be)
Chris@205 208
Chris@685 209 sv_samplerate_t sampleRate = 0;
Chris@685 210 if (auto m = ModelById::get(inputModel)) {
Chris@685 211 sampleRate = m->getSampleRate();
Chris@685 212 }
Chris@685 213
Chris@205 214 if (startFrame != 0 || duration != 0) {
Chris@685 215 if (dialog->getSelectionOnly() && sampleRate != 0) {
Chris@685 216 transform.setStartTime
Chris@685 217 (RealTime::frame2RealTime(startFrame, sampleRate));
Chris@685 218 transform.setDuration
Chris@685 219 (RealTime::frame2RealTime(duration, sampleRate));
Chris@595 220 }
Chris@205 221 }
Chris@205 222
Chris@366 223 int stepSize = 0, blockSize = 0;
Chris@205 224 WindowType windowType = HanningWindow;
Chris@205 225
Chris@205 226 dialog->getProcessingParameters(stepSize,
Chris@595 227 blockSize,
Chris@595 228 windowType);
Chris@205 229
Chris@205 230 transform.setStepSize(stepSize);
Chris@205 231 transform.setBlockSize(blockSize);
Chris@205 232 transform.setWindowType(windowType);
Chris@205 233
Chris@205 234 delete dialog;
Chris@205 235
Chris@205 236 if (effect && source) {
Chris@739 237 source->setAuditioningEffect({});
Chris@205 238 }
Chris@205 239
Chris@205 240 return ok;
Chris@205 241 }
Chris@205 242