annotate framework/TransformUserConfigurator.cpp @ 736:4b58b8f44be7

If a file that looks like audio can't be opened as audio, fail immediately - don't go trying to open .wav files or whatever as sessions or annotations. That only means the error shown to the user is less helpful.
author Chris Cannam
date Wed, 05 Feb 2020 10:45:03 +0000
parents 7540733f5480
children ddfac001b543
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@595 43 Vamp::PluginBase *plugin,
Chris@595 44 int &minChannels, int &maxChannels)
Chris@205 45 {
Chris@205 46 if (plugin && plugin->getType() == "Feature Extraction Plugin") {
Chris@595 47 Vamp::Plugin *vp = static_cast<Vamp::Plugin *>(plugin);
Chris@595 48 SVDEBUG << "TransformUserConfigurator::getChannelRange: is a Vamp plugin" << endl;
Chris@436 49 minChannels = int(vp->getMinChannelCount());
Chris@436 50 maxChannels = int(vp->getMaxChannelCount());
Chris@205 51 return true;
Chris@205 52 } else {
Chris@595 53 SVDEBUG << "TransformUserConfigurator::getChannelRange: is not a Vamp plugin" << endl;
Chris@205 54 return TransformFactory::getInstance()->
Chris@205 55 getTransformChannelRange(identifier, minChannels, maxChannels);
Chris@205 56 }
Chris@205 57 }
Chris@205 58
Chris@205 59 bool
Chris@205 60 TransformUserConfigurator::configure(ModelTransformer::Input &input,
Chris@595 61 Transform &transform,
Chris@595 62 Vamp::PluginBase *plugin,
Chris@685 63 ModelId &inputModel,
Chris@595 64 AudioPlaySource *source,
Chris@595 65 sv_frame_t startFrame,
Chris@595 66 sv_frame_t duration,
Chris@685 67 const QMap<QString, ModelId> &modelMap,
Chris@595 68 QStringList candidateModelNames,
Chris@595 69 QString defaultModelName)
Chris@205 70 {
Chris@205 71 bool ok = false;
Chris@205 72 QString id = transform.getPluginIdentifier();
Chris@205 73 QString output = transform.getOutput();
Chris@205 74 QString outputLabel = "";
Chris@205 75 QString outputDescription = "";
Chris@205 76
Chris@205 77 bool frequency = false;
Chris@205 78 bool effect = false;
Chris@205 79 bool generator = false;
Chris@205 80
Chris@205 81 if (!plugin) return false;
Chris@205 82
Chris@536 83 SVDEBUG << "TransformUserConfigurator::configure: identifier " << id << endl;
Chris@536 84
Chris@529 85 if (RealTimePluginFactory::instanceFor(id)) {
Chris@205 86
Chris@205 87 RealTimePluginFactory *factory = RealTimePluginFactory::instanceFor(id);
Chris@205 88 const RealTimePluginDescriptor *desc = factory->getPluginDescriptor(id);
Chris@205 89
Chris@205 90 if (desc->audioInputPortCount > 0 &&
Chris@205 91 desc->audioOutputPortCount > 0 &&
Chris@205 92 !desc->isSynth) {
Chris@205 93 effect = true;
Chris@205 94 }
Chris@205 95
Chris@205 96 if (desc->audioInputPortCount == 0) {
Chris@205 97 generator = true;
Chris@205 98 }
Chris@205 99
Chris@205 100 if (output != "A") {
Chris@205 101 int outputNo = output.toInt();
Chris@205 102 if (outputNo >= 0 && outputNo < int(desc->controlOutputPortCount)) {
Chris@205 103 outputLabel = desc->controlOutputPortNames[outputNo].c_str();
Chris@205 104 }
Chris@205 105 }
Chris@205 106
Chris@205 107 RealTimePluginInstance *rtp =
Chris@205 108 static_cast<RealTimePluginInstance *>(plugin);
Chris@205 109
Chris@205 110 if (effect && source) {
Chris@595 111 SVDEBUG << "Setting auditioning effect" << endl;
Chris@205 112 source->setAuditioningEffect(rtp);
Chris@205 113 }
Chris@529 114
Chris@529 115 } else {
Chris@529 116
Chris@529 117 Vamp::Plugin *vp = static_cast<Vamp::Plugin *>(plugin);
Chris@529 118
Chris@595 119 frequency = (vp->getInputDomain() == Vamp::Plugin::FrequencyDomain);
Chris@529 120
Chris@595 121 std::vector<Vamp::Plugin::OutputDescriptor> od =
Chris@595 122 vp->getOutputDescriptors();
Chris@529 123
Chris@595 124 if (od.size() > 1) {
Chris@595 125 for (size_t i = 0; i < od.size(); ++i) {
Chris@595 126 if (od[i].identifier == output.toStdString()) {
Chris@595 127 outputLabel = od[i].name.c_str();
Chris@595 128 outputDescription = od[i].description.c_str();
Chris@595 129 break;
Chris@595 130 }
Chris@595 131 }
Chris@529 132 }
Chris@205 133 }
Chris@529 134
Chris@205 135 int sourceChannels = 1;
Chris@685 136
Chris@685 137 if (auto dtvm = ModelById::getAs<DenseTimeValueModel>(inputModel)) {
Chris@685 138 sourceChannels = dtvm->getChannelCount();
Chris@205 139 }
Chris@205 140
Chris@205 141 int minChannels = 1, maxChannels = sourceChannels;
Chris@205 142 getChannelRange(transform.getIdentifier(), plugin,
Chris@595 143 minChannels, maxChannels);
Chris@205 144
Chris@205 145 int targetChannels = sourceChannels;
Chris@205 146 if (!effect) {
Chris@595 147 if (sourceChannels < minChannels) targetChannels = minChannels;
Chris@595 148 if (sourceChannels > maxChannels) targetChannels = maxChannels;
Chris@205 149 }
Chris@205 150
Chris@205 151 int defaultChannel = -1; //!!! no longer saved! [was context.channel]
Chris@205 152
Chris@395 153 PluginParameterDialog *dialog = new PluginParameterDialog
Chris@395 154 (plugin, parentWidget);
Chris@205 155
Chris@205 156 dialog->setMoreInfoUrl(TransformFactory::getInstance()->
Chris@595 157 getTransformInfoUrl(transform.getIdentifier()));
Chris@205 158
Chris@205 159 if (candidateModelNames.size() > 1 && !generator) {
Chris@595 160 dialog->setCandidateInputModels(candidateModelNames,
Chris@595 161 defaultModelName);
Chris@205 162 }
Chris@205 163
Chris@205 164 if (startFrame != 0 || duration != 0) {
Chris@595 165 dialog->setShowSelectionOnlyOption(true);
Chris@205 166 }
Chris@205 167
Chris@205 168 if (targetChannels > 0) {
Chris@595 169 dialog->setChannelArrangement(sourceChannels, targetChannels,
Chris@595 170 defaultChannel);
Chris@205 171 }
Chris@205 172
Chris@205 173 dialog->setOutputLabel(outputLabel, outputDescription);
Chris@205 174
Chris@205 175 dialog->setShowProcessingOptions(true, frequency);
Chris@205 176
Chris@205 177 if (dialog->exec() == QDialog::Accepted) {
Chris@595 178 ok = true;
Chris@205 179 }
Chris@205 180
Chris@205 181 QString selectedInput = dialog->getInputModel();
Chris@205 182 if (selectedInput != "") {
Chris@595 183 if (modelMap.contains(selectedInput)) {
Chris@595 184 inputModel = modelMap.value(selectedInput);
Chris@595 185 SVDEBUG << "Found selected input \"" << selectedInput << "\" in model map, result is " << inputModel << endl;
Chris@595 186 } else {
Chris@595 187 SVDEBUG << "Failed to find selected input \"" << selectedInput << "\" in model map" << endl;
Chris@595 188 }
Chris@205 189 } else {
Chris@595 190 SVDEBUG << "Selected input empty: \"" << selectedInput << "\"" << endl;
Chris@205 191 }
Chris@205 192
Chris@205 193 // Write parameters back to transform object
Chris@205 194 TransformFactory::getInstance()->
Chris@595 195 setParametersFromPlugin(transform, plugin);
Chris@205 196
Chris@205 197 input.setChannel(dialog->getChannel());
Chris@205 198
Chris@205 199 //!!! The dialog ought to be taking & returning transform
Chris@205 200 //objects and input objects and stuff rather than passing
Chris@205 201 //around all this misc stuff, but that's for tomorrow
Chris@205 202 //(whenever that may be)
Chris@205 203
Chris@685 204 sv_samplerate_t sampleRate = 0;
Chris@685 205 if (auto m = ModelById::get(inputModel)) {
Chris@685 206 sampleRate = m->getSampleRate();
Chris@685 207 }
Chris@685 208
Chris@205 209 if (startFrame != 0 || duration != 0) {
Chris@685 210 if (dialog->getSelectionOnly() && sampleRate != 0) {
Chris@685 211 transform.setStartTime
Chris@685 212 (RealTime::frame2RealTime(startFrame, sampleRate));
Chris@685 213 transform.setDuration
Chris@685 214 (RealTime::frame2RealTime(duration, sampleRate));
Chris@595 215 }
Chris@205 216 }
Chris@205 217
Chris@366 218 int stepSize = 0, blockSize = 0;
Chris@205 219 WindowType windowType = HanningWindow;
Chris@205 220
Chris@205 221 dialog->getProcessingParameters(stepSize,
Chris@595 222 blockSize,
Chris@595 223 windowType);
Chris@205 224
Chris@205 225 transform.setStepSize(stepSize);
Chris@205 226 transform.setBlockSize(blockSize);
Chris@205 227 transform.setWindowType(windowType);
Chris@205 228
Chris@205 229 delete dialog;
Chris@205 230
Chris@205 231 if (effect && source) {
Chris@636 232 source->setAuditioningEffect(nullptr);
Chris@205 233 }
Chris@205 234
Chris@205 235 return ok;
Chris@205 236 }
Chris@205 237