annotate transform/ModelTransformerFactory.cpp @ 1374:8db84bd61eaa

Some work to make spectrum layers (and slice layers generally) zoomable in the frequency axis. Also fixes a number of view id mixups in SliceLayer which broke offset calculations for the x axis scale.
author Chris Cannam
date Tue, 07 Feb 2017 14:55:19 +0000
parents ca43c4b7719c
children 48e9f538e6e9
rev   line source
Chris@320 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@320 2
Chris@320 3 /*
Chris@320 4 Sonic Visualiser
Chris@320 5 An audio file viewer and annotation editor.
Chris@320 6 Centre for Digital Music, Queen Mary, University of London.
Chris@320 7 This file copyright 2006 Chris Cannam and QMUL.
Chris@320 8
Chris@320 9 This program is free software; you can redistribute it and/or
Chris@320 10 modify it under the terms of the GNU General Public License as
Chris@320 11 published by the Free Software Foundation; either version 2 of the
Chris@320 12 License, or (at your option) any later version. See the file
Chris@320 13 COPYING included with this distribution for more information.
Chris@320 14 */
Chris@320 15
Chris@331 16 #include "ModelTransformerFactory.h"
Chris@320 17
Chris@331 18 #include "FeatureExtractionModelTransformer.h"
Chris@331 19 #include "RealTimeEffectModelTransformer.h"
Chris@320 20
Chris@332 21 #include "TransformFactory.h"
Chris@332 22
Chris@389 23 #include "base/AudioPlaySource.h"
Chris@389 24
Chris@320 25 #include "plugin/FeatureExtractionPluginFactory.h"
Chris@320 26 #include "plugin/RealTimePluginFactory.h"
Chris@320 27 #include "plugin/PluginXml.h"
Chris@320 28
Chris@320 29 #include "data/model/DenseTimeValueModel.h"
Chris@320 30
Chris@475 31 #include <vamp-hostsdk/PluginHostAdapter.h>
Chris@320 32
Chris@320 33 #include <iostream>
Chris@320 34 #include <set>
Chris@320 35
Chris@320 36 #include <QRegExp>
Chris@320 37
Chris@850 38 using std::vector;
Chris@850 39
Chris@331 40 ModelTransformerFactory *
Chris@331 41 ModelTransformerFactory::m_instance = new ModelTransformerFactory;
Chris@320 42
Chris@331 43 ModelTransformerFactory *
Chris@331 44 ModelTransformerFactory::getInstance()
Chris@320 45 {
Chris@320 46 return m_instance;
Chris@320 47 }
Chris@320 48
Chris@331 49 ModelTransformerFactory::~ModelTransformerFactory()
Chris@320 50 {
Chris@320 51 }
Chris@320 52
Chris@350 53 ModelTransformer::Input
Chris@350 54 ModelTransformerFactory::getConfigurationForTransform(Transform &transform,
Chris@350 55 const std::vector<Model *> &candidateInputModels,
Chris@350 56 Model *defaultInputModel,
Chris@389 57 AudioPlaySource *source,
Chris@1048 58 sv_frame_t startFrame,
Chris@1048 59 sv_frame_t duration,
Chris@653 60 UserConfigurator *configurator)
Chris@320 61 {
Chris@350 62 ModelTransformer::Input input(0);
Chris@350 63
Chris@350 64 if (candidateInputModels.empty()) return input;
Chris@320 65
Chris@320 66 //!!! This will need revision -- we'll have to have a callback
Chris@320 67 //from the dialog for when the candidate input model is changed,
Chris@320 68 //as we'll need to reinitialise the channel settings in the dialog
Chris@345 69 Model *inputModel = candidateInputModels[0];
Chris@320 70 QStringList candidateModelNames;
Chris@345 71 QString defaultModelName;
Chris@653 72 QMap<QString, Model *> modelMap;
Chris@930 73 for (int i = 0; i < (int)candidateInputModels.size(); ++i) {
Chris@320 74 QString modelName = candidateInputModels[i]->objectName();
Chris@320 75 QString origModelName = modelName;
Chris@320 76 int dupcount = 1;
Chris@653 77 while (modelMap.contains(modelName)) {
Chris@320 78 modelName = tr("%1 <%2>").arg(origModelName).arg(++dupcount);
Chris@320 79 }
Chris@320 80 modelMap[modelName] = candidateInputModels[i];
Chris@320 81 candidateModelNames.push_back(modelName);
Chris@345 82 if (candidateInputModels[i] == defaultInputModel) {
Chris@345 83 defaultModelName = modelName;
Chris@345 84 }
Chris@320 85 }
Chris@320 86
Chris@350 87 QString id = transform.getPluginIdentifier();
Chris@320 88
Chris@653 89 bool ok = true;
Chris@350 90 QString configurationXml = m_lastConfigurations[transform.getIdentifier()];
Chris@320 91
Chris@1264 92 SVDEBUG << "ModelTransformer: last configuration for identifier " << transform.getIdentifier() << ": " << configurationXml << endl;
Chris@320 93
Chris@320 94 Vamp::PluginBase *plugin = 0;
Chris@320 95
Chris@1225 96 if (RealTimePluginFactory::instanceFor(id)) {
Chris@320 97
Chris@1264 98 SVDEBUG << "ModelTransformerFactory::getConfigurationForTransform: instantiating real-time plugin" << endl;
Chris@1264 99
Chris@320 100 RealTimePluginFactory *factory = RealTimePluginFactory::instanceFor(id);
Chris@320 101
Chris@1040 102 sv_samplerate_t sampleRate = inputModel->getSampleRate();
Chris@930 103 int blockSize = 1024;
Chris@930 104 int channels = 1;
Chris@653 105 if (source) {
Chris@1321 106 sampleRate = source->getSourceSampleRate();
Chris@320 107 blockSize = source->getTargetBlockSize();
Chris@320 108 channels = source->getTargetChannelCount();
Chris@320 109 }
Chris@320 110
Chris@320 111 RealTimePluginInstance *rtp = factory->instantiatePlugin
Chris@320 112 (id, 0, 0, sampleRate, blockSize, channels);
Chris@320 113
Chris@320 114 plugin = rtp;
Chris@1225 115
Chris@1225 116 } else {
Chris@1225 117
Chris@1264 118 SVDEBUG << "ModelTransformerFactory::getConfigurationForTransform: instantiating Vamp plugin" << endl;
Chris@1225 119
Chris@1225 120 Vamp::Plugin *vp =
Chris@1225 121 FeatureExtractionPluginFactory::instance()->instantiatePlugin
Chris@1225 122 (id, float(inputModel->getSampleRate()));
Chris@1225 123
Chris@1225 124 plugin = vp;
Chris@320 125 }
Chris@320 126
Chris@320 127 if (plugin) {
Chris@320 128
Chris@350 129 // Ensure block size etc are valid
Chris@350 130 TransformFactory::getInstance()->
Chris@350 131 makeContextConsistentWithPlugin(transform, plugin);
Chris@320 132
Chris@350 133 // Prepare the plugin with any existing parameters already
Chris@350 134 // found in the transform
Chris@350 135 TransformFactory::getInstance()->
Chris@350 136 setPluginParameters(transform, plugin);
Chris@350 137
Chris@350 138 // For this interactive usage, we want to override those with
Chris@350 139 // whatever the user chose last time around
Chris@350 140 PluginXml(plugin).setParametersFromXml(configurationXml);
Chris@320 141
Chris@653 142 if (configurator) {
Chris@653 143 ok = configurator->configure(input, transform, plugin,
Chris@653 144 inputModel, source,
Chris@653 145 startFrame, duration,
Chris@653 146 modelMap,
Chris@653 147 candidateModelNames,
Chris@653 148 defaultModelName);
Chris@320 149 }
Chris@320 150
Chris@516 151
Chris@350 152 TransformFactory::getInstance()->
Chris@350 153 makeContextConsistentWithPlugin(transform, plugin);
Chris@350 154
Chris@350 155 configurationXml = PluginXml(plugin).toXmlString();
Chris@320 156
Chris@1264 157 SVDEBUG << "ModelTransformerFactory::getConfigurationForTransform: got configuration, deleting plugin" << endl;
Chris@1264 158
Chris@653 159 delete plugin;
Chris@320 160 }
Chris@320 161
Chris@350 162 if (ok) {
Chris@350 163 m_lastConfigurations[transform.getIdentifier()] = configurationXml;
Chris@350 164 input.setModel(inputModel);
Chris@350 165 }
Chris@320 166
Chris@350 167 return input;
Chris@320 168 }
Chris@320 169
Chris@331 170 ModelTransformer *
Chris@850 171 ModelTransformerFactory::createTransformer(const Transforms &transforms,
Chris@350 172 const ModelTransformer::Input &input)
Chris@320 173 {
Chris@331 174 ModelTransformer *transformer = 0;
Chris@320 175
Chris@850 176 QString id = transforms[0].getPluginIdentifier();
Chris@320 177
Chris@1225 178 if (RealTimePluginFactory::instanceFor(id)) {
Chris@350 179
Chris@350 180 transformer =
Chris@850 181 new RealTimeEffectModelTransformer(input, transforms[0]);
Chris@350 182
Chris@320 183 } else {
Chris@1225 184
Chris@1225 185 transformer =
Chris@1225 186 new FeatureExtractionModelTransformer(input, transforms);
Chris@320 187 }
Chris@320 188
Chris@850 189 if (transformer) transformer->setObjectName(transforms[0].getIdentifier());
Chris@331 190 return transformer;
Chris@320 191 }
Chris@320 192
Chris@320 193 Model *
Chris@350 194 ModelTransformerFactory::transform(const Transform &transform,
Chris@361 195 const ModelTransformer::Input &input,
Chris@877 196 QString &message,
Chris@877 197 AdditionalModelHandler *handler)
Chris@320 198 {
Chris@690 199 SVDEBUG << "ModelTransformerFactory::transform: Constructing transformer with input model " << input.getModel() << endl;
Chris@408 200
Chris@850 201 Transforms transforms;
Chris@850 202 transforms.push_back(transform);
Chris@877 203 vector<Model *> mm = transformMultiple(transforms, input, message, handler);
Chris@850 204 if (mm.empty()) return 0;
Chris@850 205 else return mm[0];
Chris@320 206 }
Chris@320 207
Chris@849 208 vector<Model *>
Chris@849 209 ModelTransformerFactory::transformMultiple(const Transforms &transforms,
Chris@849 210 const ModelTransformer::Input &input,
Chris@877 211 QString &message,
Chris@877 212 AdditionalModelHandler *handler)
Chris@849 213 {
Chris@849 214 SVDEBUG << "ModelTransformerFactory::transformMultiple: Constructing transformer with input model " << input.getModel() << endl;
Chris@849 215
Chris@849 216 ModelTransformer *t = createTransformer(transforms, input);
Chris@850 217 if (!t) return vector<Model *>();
Chris@849 218
Chris@877 219 if (handler) {
Chris@877 220 m_handlers[t] = handler;
Chris@877 221 }
Chris@849 222
Chris@849 223 m_runningTransformers.insert(t);
Chris@849 224
Chris@877 225 connect(t, SIGNAL(finished()), this, SLOT(transformerFinished()));
Chris@877 226
Chris@849 227 t->start();
Chris@850 228 vector<Model *> models = t->detachOutputModels();
Chris@849 229
Chris@850 230 if (!models.empty()) {
Chris@849 231 QString imn = input.getModel()->objectName();
Chris@849 232 QString trn =
Chris@849 233 TransformFactory::getInstance()->getTransformFriendlyName
Chris@850 234 (transforms[0].getIdentifier());
Chris@924 235 for (int i = 0; i < (int)models.size(); ++i) {
Chris@850 236 if (imn != "") {
Chris@850 237 if (trn != "") {
Chris@850 238 models[i]->setObjectName(tr("%1: %2").arg(imn).arg(trn));
Chris@850 239 } else {
Chris@850 240 models[i]->setObjectName(imn);
Chris@850 241 }
Chris@850 242 } else if (trn != "") {
Chris@850 243 models[i]->setObjectName(trn);
Chris@849 244 }
Chris@849 245 }
Chris@849 246 } else {
Chris@849 247 t->wait();
Chris@849 248 }
Chris@849 249
Chris@849 250 message = t->getMessage();
Chris@849 251
Chris@850 252 return models;
Chris@849 253 }
Chris@849 254
Chris@320 255 void
Chris@331 256 ModelTransformerFactory::transformerFinished()
Chris@320 257 {
Chris@320 258 QObject *s = sender();
Chris@331 259 ModelTransformer *transformer = dynamic_cast<ModelTransformer *>(s);
Chris@320 260
Chris@690 261 // SVDEBUG << "ModelTransformerFactory::transformerFinished(" << transformer << ")" << endl;
Chris@320 262
Chris@331 263 if (!transformer) {
Chris@843 264 cerr << "WARNING: ModelTransformerFactory::transformerFinished: sender is not a transformer" << endl;
Chris@320 265 return;
Chris@320 266 }
Chris@320 267
Chris@331 268 if (m_runningTransformers.find(transformer) == m_runningTransformers.end()) {
Chris@843 269 cerr << "WARNING: ModelTransformerFactory::transformerFinished("
Chris@331 270 << transformer
Chris@331 271 << "): I have no record of this transformer running!"
Chris@843 272 << endl;
Chris@320 273 }
Chris@320 274
Chris@331 275 m_runningTransformers.erase(transformer);
Chris@320 276
Chris@877 277 if (m_handlers.find(transformer) != m_handlers.end()) {
Chris@877 278 if (transformer->willHaveAdditionalOutputModels()) {
Chris@877 279 vector<Model *> mm = transformer->detachAdditionalOutputModels();
Chris@877 280 m_handlers[transformer]->moreModelsAvailable(mm);
Chris@878 281 } else {
Chris@878 282 m_handlers[transformer]->noMoreModelsAvailable();
Chris@877 283 }
Chris@877 284 m_handlers.erase(transformer);
Chris@877 285 }
Chris@877 286
Chris@1079 287 if (transformer->isAbandoned()) {
Chris@1079 288 if (transformer->getMessage() != "") {
Chris@1079 289 emit transformFailed("", transformer->getMessage());
Chris@1079 290 }
Chris@1079 291 }
Chris@1079 292
Chris@331 293 transformer->wait(); // unnecessary but reassuring
Chris@331 294 delete transformer;
Chris@320 295 }
Chris@320 296
Chris@320 297 void
Chris@331 298 ModelTransformerFactory::modelAboutToBeDeleted(Model *m)
Chris@320 299 {
Chris@328 300 TransformerSet affected;
Chris@320 301
Chris@328 302 for (TransformerSet::iterator i = m_runningTransformers.begin();
Chris@328 303 i != m_runningTransformers.end(); ++i) {
Chris@320 304
Chris@331 305 ModelTransformer *t = *i;
Chris@320 306
Chris@850 307 if (t->getInputModel() == m) {
Chris@320 308 affected.insert(t);
Chris@850 309 } else {
Chris@850 310 vector<Model *> mm = t->getOutputModels();
Chris@850 311 for (int i = 0; i < (int)mm.size(); ++i) {
Chris@850 312 if (mm[i] == m) affected.insert(t);
Chris@850 313 }
Chris@320 314 }
Chris@320 315 }
Chris@320 316
Chris@328 317 for (TransformerSet::iterator i = affected.begin();
Chris@320 318 i != affected.end(); ++i) {
Chris@320 319
Chris@331 320 ModelTransformer *t = *i;
Chris@320 321
Chris@320 322 t->abandon();
Chris@320 323
Chris@320 324 t->wait(); // this should eventually call back on
Chris@331 325 // transformerFinished, which will remove from
Chris@328 326 // m_runningTransformers and delete.
Chris@320 327 }
Chris@320 328 }
Chris@320 329