annotate transform/ModelTransformerFactory.cpp @ 1078:ce82bcdc95d0

Fail upfront if the file is going to be too large. We expect the caller to split up large data sets into several MatrixFiles
author Chris Cannam
date Wed, 10 Jun 2015 13:10:26 +0100
parents c7e9afcbf070
children 6ea7761a418b
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@843 92 cerr << "last configuration: " << configurationXml << endl;
Chris@320 93
Chris@320 94 Vamp::PluginBase *plugin = 0;
Chris@320 95
Chris@320 96 if (FeatureExtractionPluginFactory::instanceFor(id)) {
Chris@320 97
Chris@843 98 cerr << "getConfigurationForTransform: instantiating Vamp plugin" << endl;
Chris@320 99
Chris@320 100 Vamp::Plugin *vp =
Chris@320 101 FeatureExtractionPluginFactory::instanceFor(id)->instantiatePlugin
Chris@1039 102 (id, float(inputModel->getSampleRate()));
Chris@320 103
Chris@653 104 plugin = vp;
Chris@320 105
Chris@320 106 } else if (RealTimePluginFactory::instanceFor(id)) {
Chris@320 107
Chris@320 108 RealTimePluginFactory *factory = RealTimePluginFactory::instanceFor(id);
Chris@320 109
Chris@1040 110 sv_samplerate_t sampleRate = inputModel->getSampleRate();
Chris@930 111 int blockSize = 1024;
Chris@930 112 int channels = 1;
Chris@653 113 if (source) {
Chris@320 114 sampleRate = source->getTargetSampleRate();
Chris@320 115 blockSize = source->getTargetBlockSize();
Chris@320 116 channels = source->getTargetChannelCount();
Chris@320 117 }
Chris@320 118
Chris@320 119 RealTimePluginInstance *rtp = factory->instantiatePlugin
Chris@320 120 (id, 0, 0, sampleRate, blockSize, channels);
Chris@320 121
Chris@320 122 plugin = rtp;
Chris@320 123 }
Chris@320 124
Chris@320 125 if (plugin) {
Chris@320 126
Chris@350 127 // Ensure block size etc are valid
Chris@350 128 TransformFactory::getInstance()->
Chris@350 129 makeContextConsistentWithPlugin(transform, plugin);
Chris@320 130
Chris@350 131 // Prepare the plugin with any existing parameters already
Chris@350 132 // found in the transform
Chris@350 133 TransformFactory::getInstance()->
Chris@350 134 setPluginParameters(transform, plugin);
Chris@350 135
Chris@350 136 // For this interactive usage, we want to override those with
Chris@350 137 // whatever the user chose last time around
Chris@350 138 PluginXml(plugin).setParametersFromXml(configurationXml);
Chris@320 139
Chris@653 140 if (configurator) {
Chris@653 141 ok = configurator->configure(input, transform, plugin,
Chris@653 142 inputModel, source,
Chris@653 143 startFrame, duration,
Chris@653 144 modelMap,
Chris@653 145 candidateModelNames,
Chris@653 146 defaultModelName);
Chris@320 147 }
Chris@320 148
Chris@516 149
Chris@350 150 TransformFactory::getInstance()->
Chris@350 151 makeContextConsistentWithPlugin(transform, plugin);
Chris@350 152
Chris@350 153 configurationXml = PluginXml(plugin).toXmlString();
Chris@320 154
Chris@653 155 delete plugin;
Chris@320 156 }
Chris@320 157
Chris@350 158 if (ok) {
Chris@350 159 m_lastConfigurations[transform.getIdentifier()] = configurationXml;
Chris@350 160 input.setModel(inputModel);
Chris@350 161 }
Chris@320 162
Chris@350 163 return input;
Chris@320 164 }
Chris@320 165
Chris@331 166 ModelTransformer *
Chris@850 167 ModelTransformerFactory::createTransformer(const Transforms &transforms,
Chris@350 168 const ModelTransformer::Input &input)
Chris@320 169 {
Chris@331 170 ModelTransformer *transformer = 0;
Chris@320 171
Chris@850 172 QString id = transforms[0].getPluginIdentifier();
Chris@320 173
Chris@320 174 if (FeatureExtractionPluginFactory::instanceFor(id)) {
Chris@350 175
Chris@350 176 transformer =
Chris@859 177 new FeatureExtractionModelTransformer(input, transforms);
Chris@350 178
Chris@331 179 } else if (RealTimePluginFactory::instanceFor(id)) {
Chris@350 180
Chris@350 181 transformer =
Chris@850 182 new RealTimeEffectModelTransformer(input, transforms[0]);
Chris@350 183
Chris@320 184 } else {
Chris@690 185 SVDEBUG << "ModelTransformerFactory::createTransformer: Unknown transform \""
Chris@850 186 << transforms[0].getIdentifier() << "\"" << endl;
Chris@331 187 return transformer;
Chris@320 188 }
Chris@320 189
Chris@850 190 if (transformer) transformer->setObjectName(transforms[0].getIdentifier());
Chris@331 191 return transformer;
Chris@320 192 }
Chris@320 193
Chris@320 194 Model *
Chris@350 195 ModelTransformerFactory::transform(const Transform &transform,
Chris@361 196 const ModelTransformer::Input &input,
Chris@877 197 QString &message,
Chris@877 198 AdditionalModelHandler *handler)
Chris@320 199 {
Chris@690 200 SVDEBUG << "ModelTransformerFactory::transform: Constructing transformer with input model " << input.getModel() << endl;
Chris@408 201
Chris@850 202 Transforms transforms;
Chris@850 203 transforms.push_back(transform);
Chris@877 204 vector<Model *> mm = transformMultiple(transforms, input, message, handler);
Chris@850 205 if (mm.empty()) return 0;
Chris@850 206 else return mm[0];
Chris@320 207 }
Chris@320 208
Chris@849 209 vector<Model *>
Chris@849 210 ModelTransformerFactory::transformMultiple(const Transforms &transforms,
Chris@849 211 const ModelTransformer::Input &input,
Chris@877 212 QString &message,
Chris@877 213 AdditionalModelHandler *handler)
Chris@849 214 {
Chris@849 215 SVDEBUG << "ModelTransformerFactory::transformMultiple: Constructing transformer with input model " << input.getModel() << endl;
Chris@849 216
Chris@849 217 ModelTransformer *t = createTransformer(transforms, input);
Chris@850 218 if (!t) return vector<Model *>();
Chris@849 219
Chris@877 220 if (handler) {
Chris@877 221 m_handlers[t] = handler;
Chris@877 222 }
Chris@849 223
Chris@849 224 m_runningTransformers.insert(t);
Chris@849 225
Chris@877 226 connect(t, SIGNAL(finished()), this, SLOT(transformerFinished()));
Chris@877 227
Chris@849 228 t->start();
Chris@850 229 vector<Model *> models = t->detachOutputModels();
Chris@849 230
Chris@850 231 if (!models.empty()) {
Chris@849 232 QString imn = input.getModel()->objectName();
Chris@849 233 QString trn =
Chris@849 234 TransformFactory::getInstance()->getTransformFriendlyName
Chris@850 235 (transforms[0].getIdentifier());
Chris@924 236 for (int i = 0; i < (int)models.size(); ++i) {
Chris@850 237 if (imn != "") {
Chris@850 238 if (trn != "") {
Chris@850 239 models[i]->setObjectName(tr("%1: %2").arg(imn).arg(trn));
Chris@850 240 } else {
Chris@850 241 models[i]->setObjectName(imn);
Chris@850 242 }
Chris@850 243 } else if (trn != "") {
Chris@850 244 models[i]->setObjectName(trn);
Chris@849 245 }
Chris@849 246 }
Chris@849 247 } else {
Chris@849 248 t->wait();
Chris@849 249 }
Chris@849 250
Chris@849 251 message = t->getMessage();
Chris@849 252
Chris@850 253 return models;
Chris@849 254 }
Chris@849 255
Chris@320 256 void
Chris@331 257 ModelTransformerFactory::transformerFinished()
Chris@320 258 {
Chris@320 259 QObject *s = sender();
Chris@331 260 ModelTransformer *transformer = dynamic_cast<ModelTransformer *>(s);
Chris@320 261
Chris@690 262 // SVDEBUG << "ModelTransformerFactory::transformerFinished(" << transformer << ")" << endl;
Chris@320 263
Chris@331 264 if (!transformer) {
Chris@843 265 cerr << "WARNING: ModelTransformerFactory::transformerFinished: sender is not a transformer" << endl;
Chris@320 266 return;
Chris@320 267 }
Chris@320 268
Chris@331 269 if (m_runningTransformers.find(transformer) == m_runningTransformers.end()) {
Chris@843 270 cerr << "WARNING: ModelTransformerFactory::transformerFinished("
Chris@331 271 << transformer
Chris@331 272 << "): I have no record of this transformer running!"
Chris@843 273 << endl;
Chris@320 274 }
Chris@320 275
Chris@331 276 m_runningTransformers.erase(transformer);
Chris@320 277
Chris@877 278 if (m_handlers.find(transformer) != m_handlers.end()) {
Chris@877 279 if (transformer->willHaveAdditionalOutputModels()) {
Chris@877 280 vector<Model *> mm = transformer->detachAdditionalOutputModels();
Chris@877 281 m_handlers[transformer]->moreModelsAvailable(mm);
Chris@878 282 } else {
Chris@878 283 m_handlers[transformer]->noMoreModelsAvailable();
Chris@877 284 }
Chris@877 285 m_handlers.erase(transformer);
Chris@877 286 }
Chris@877 287
Chris@331 288 transformer->wait(); // unnecessary but reassuring
Chris@331 289 delete transformer;
Chris@320 290 }
Chris@320 291
Chris@320 292 void
Chris@331 293 ModelTransformerFactory::modelAboutToBeDeleted(Model *m)
Chris@320 294 {
Chris@328 295 TransformerSet affected;
Chris@320 296
Chris@328 297 for (TransformerSet::iterator i = m_runningTransformers.begin();
Chris@328 298 i != m_runningTransformers.end(); ++i) {
Chris@320 299
Chris@331 300 ModelTransformer *t = *i;
Chris@320 301
Chris@850 302 if (t->getInputModel() == m) {
Chris@320 303 affected.insert(t);
Chris@850 304 } else {
Chris@850 305 vector<Model *> mm = t->getOutputModels();
Chris@850 306 for (int i = 0; i < (int)mm.size(); ++i) {
Chris@850 307 if (mm[i] == m) affected.insert(t);
Chris@850 308 }
Chris@320 309 }
Chris@320 310 }
Chris@320 311
Chris@328 312 for (TransformerSet::iterator i = affected.begin();
Chris@320 313 i != affected.end(); ++i) {
Chris@320 314
Chris@331 315 ModelTransformer *t = *i;
Chris@320 316
Chris@320 317 t->abandon();
Chris@320 318
Chris@320 319 t->wait(); // this should eventually call back on
Chris@331 320 // transformerFinished, which will remove from
Chris@328 321 // m_runningTransformers and delete.
Chris@320 322 }
Chris@320 323 }
Chris@320 324