annotate transform/ModelTransformerFactory.cpp @ 683:f84f147572b9

Avoid crash when generating/processing a very short file
author Chris Cannam
date Wed, 11 May 2011 11:04:02 +0100
parents 12578237b99c
children b4a8d8221eaf
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@331 38 ModelTransformerFactory *
Chris@331 39 ModelTransformerFactory::m_instance = new ModelTransformerFactory;
Chris@320 40
Chris@331 41 ModelTransformerFactory *
Chris@331 42 ModelTransformerFactory::getInstance()
Chris@320 43 {
Chris@320 44 return m_instance;
Chris@320 45 }
Chris@320 46
Chris@331 47 ModelTransformerFactory::~ModelTransformerFactory()
Chris@320 48 {
Chris@320 49 }
Chris@320 50
Chris@350 51 ModelTransformer::Input
Chris@350 52 ModelTransformerFactory::getConfigurationForTransform(Transform &transform,
Chris@350 53 const std::vector<Model *> &candidateInputModels,
Chris@350 54 Model *defaultInputModel,
Chris@389 55 AudioPlaySource *source,
Chris@350 56 size_t startFrame,
Chris@653 57 size_t duration,
Chris@653 58 UserConfigurator *configurator)
Chris@320 59 {
Chris@350 60 ModelTransformer::Input input(0);
Chris@350 61
Chris@350 62 if (candidateInputModels.empty()) return input;
Chris@320 63
Chris@320 64 //!!! This will need revision -- we'll have to have a callback
Chris@320 65 //from the dialog for when the candidate input model is changed,
Chris@320 66 //as we'll need to reinitialise the channel settings in the dialog
Chris@345 67 Model *inputModel = candidateInputModels[0];
Chris@320 68 QStringList candidateModelNames;
Chris@345 69 QString defaultModelName;
Chris@653 70 QMap<QString, Model *> modelMap;
Chris@320 71 for (size_t i = 0; i < candidateInputModels.size(); ++i) {
Chris@320 72 QString modelName = candidateInputModels[i]->objectName();
Chris@320 73 QString origModelName = modelName;
Chris@320 74 int dupcount = 1;
Chris@653 75 while (modelMap.contains(modelName)) {
Chris@320 76 modelName = tr("%1 <%2>").arg(origModelName).arg(++dupcount);
Chris@320 77 }
Chris@320 78 modelMap[modelName] = candidateInputModels[i];
Chris@320 79 candidateModelNames.push_back(modelName);
Chris@345 80 if (candidateInputModels[i] == defaultInputModel) {
Chris@345 81 defaultModelName = modelName;
Chris@345 82 }
Chris@320 83 }
Chris@320 84
Chris@350 85 QString id = transform.getPluginIdentifier();
Chris@320 86
Chris@653 87 bool ok = true;
Chris@350 88 QString configurationXml = m_lastConfigurations[transform.getIdentifier()];
Chris@320 89
Chris@350 90 std::cerr << "last configuration: " << configurationXml.toStdString() << std::endl;
Chris@320 91
Chris@320 92 Vamp::PluginBase *plugin = 0;
Chris@320 93
Chris@320 94 if (FeatureExtractionPluginFactory::instanceFor(id)) {
Chris@320 95
Chris@350 96 std::cerr << "getConfigurationForTransform: instantiating Vamp plugin" << std::endl;
Chris@320 97
Chris@320 98 Vamp::Plugin *vp =
Chris@320 99 FeatureExtractionPluginFactory::instanceFor(id)->instantiatePlugin
Chris@320 100 (id, inputModel->getSampleRate());
Chris@320 101
Chris@653 102 plugin = vp;
Chris@320 103
Chris@320 104 } else if (RealTimePluginFactory::instanceFor(id)) {
Chris@320 105
Chris@320 106 RealTimePluginFactory *factory = RealTimePluginFactory::instanceFor(id);
Chris@320 107 const RealTimePluginDescriptor *desc = factory->getPluginDescriptor(id);
Chris@320 108
Chris@320 109 size_t sampleRate = inputModel->getSampleRate();
Chris@320 110 size_t blockSize = 1024;
Chris@320 111 size_t channels = 1;
Chris@653 112 if (source) {
Chris@320 113 sampleRate = source->getTargetSampleRate();
Chris@320 114 blockSize = source->getTargetBlockSize();
Chris@320 115 channels = source->getTargetChannelCount();
Chris@320 116 }
Chris@320 117
Chris@320 118 RealTimePluginInstance *rtp = factory->instantiatePlugin
Chris@320 119 (id, 0, 0, sampleRate, blockSize, channels);
Chris@320 120
Chris@320 121 plugin = rtp;
Chris@320 122 }
Chris@320 123
Chris@320 124 if (plugin) {
Chris@320 125
Chris@350 126 // Ensure block size etc are valid
Chris@350 127 TransformFactory::getInstance()->
Chris@350 128 makeContextConsistentWithPlugin(transform, plugin);
Chris@320 129
Chris@350 130 // Prepare the plugin with any existing parameters already
Chris@350 131 // found in the transform
Chris@350 132 TransformFactory::getInstance()->
Chris@350 133 setPluginParameters(transform, plugin);
Chris@350 134
Chris@350 135 // For this interactive usage, we want to override those with
Chris@350 136 // whatever the user chose last time around
Chris@350 137 PluginXml(plugin).setParametersFromXml(configurationXml);
Chris@320 138
Chris@653 139 if (configurator) {
Chris@653 140 ok = configurator->configure(input, transform, plugin,
Chris@653 141 inputModel, source,
Chris@653 142 startFrame, duration,
Chris@653 143 modelMap,
Chris@653 144 candidateModelNames,
Chris@653 145 defaultModelName);
Chris@320 146 }
Chris@320 147
Chris@516 148
Chris@350 149 TransformFactory::getInstance()->
Chris@350 150 makeContextConsistentWithPlugin(transform, plugin);
Chris@350 151
Chris@350 152 configurationXml = PluginXml(plugin).toXmlString();
Chris@320 153
Chris@653 154 delete plugin;
Chris@320 155 }
Chris@320 156
Chris@350 157 if (ok) {
Chris@350 158 m_lastConfigurations[transform.getIdentifier()] = configurationXml;
Chris@350 159 input.setModel(inputModel);
Chris@350 160 }
Chris@320 161
Chris@350 162 return input;
Chris@320 163 }
Chris@320 164
Chris@331 165 ModelTransformer *
Chris@350 166 ModelTransformerFactory::createTransformer(const Transform &transform,
Chris@350 167 const ModelTransformer::Input &input)
Chris@320 168 {
Chris@331 169 ModelTransformer *transformer = 0;
Chris@320 170
Chris@350 171 QString id = transform.getPluginIdentifier();
Chris@320 172
Chris@320 173 if (FeatureExtractionPluginFactory::instanceFor(id)) {
Chris@350 174
Chris@350 175 transformer =
Chris@350 176 new FeatureExtractionModelTransformer(input, transform);
Chris@350 177
Chris@331 178 } else if (RealTimePluginFactory::instanceFor(id)) {
Chris@350 179
Chris@350 180 transformer =
Chris@350 181 new RealTimeEffectModelTransformer(input, transform);
Chris@350 182
Chris@320 183 } else {
Chris@331 184 std::cerr << "ModelTransformerFactory::createTransformer: Unknown transform \""
Chris@350 185 << transform.getIdentifier().toStdString() << "\"" << std::endl;
Chris@331 186 return transformer;
Chris@320 187 }
Chris@320 188
Chris@350 189 if (transformer) transformer->setObjectName(transform.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@361 196 QString &message)
Chris@320 197 {
Chris@408 198 std::cerr << "ModelTransformerFactory::transform: Constructing transformer with input model " << input.getModel() << std::endl;
Chris@408 199
Chris@350 200 ModelTransformer *t = createTransformer(transform, input);
Chris@320 201 if (!t) return 0;
Chris@320 202
Chris@331 203 connect(t, SIGNAL(finished()), this, SLOT(transformerFinished()));
Chris@320 204
Chris@328 205 m_runningTransformers.insert(t);
Chris@320 206
Chris@320 207 t->start();
Chris@320 208 Model *model = t->detachOutputModel();
Chris@320 209
Chris@320 210 if (model) {
Chris@350 211 QString imn = input.getModel()->objectName();
Chris@332 212 QString trn =
Chris@332 213 TransformFactory::getInstance()->getTransformFriendlyName
Chris@350 214 (transform.getIdentifier());
Chris@320 215 if (imn != "") {
Chris@320 216 if (trn != "") {
Chris@320 217 model->setObjectName(tr("%1: %2").arg(imn).arg(trn));
Chris@320 218 } else {
Chris@320 219 model->setObjectName(imn);
Chris@320 220 }
Chris@320 221 } else if (trn != "") {
Chris@320 222 model->setObjectName(trn);
Chris@320 223 }
Chris@320 224 } else {
Chris@320 225 t->wait();
Chris@320 226 }
Chris@320 227
Chris@361 228 message = t->getMessage();
Chris@361 229
Chris@320 230 return model;
Chris@320 231 }
Chris@320 232
Chris@320 233 void
Chris@331 234 ModelTransformerFactory::transformerFinished()
Chris@320 235 {
Chris@320 236 QObject *s = sender();
Chris@331 237 ModelTransformer *transformer = dynamic_cast<ModelTransformer *>(s);
Chris@320 238
Chris@436 239 // std::cerr << "ModelTransformerFactory::transformerFinished(" << transformer << ")" << std::endl;
Chris@320 240
Chris@331 241 if (!transformer) {
Chris@331 242 std::cerr << "WARNING: ModelTransformerFactory::transformerFinished: sender is not a transformer" << std::endl;
Chris@320 243 return;
Chris@320 244 }
Chris@320 245
Chris@331 246 if (m_runningTransformers.find(transformer) == m_runningTransformers.end()) {
Chris@331 247 std::cerr << "WARNING: ModelTransformerFactory::transformerFinished("
Chris@331 248 << transformer
Chris@331 249 << "): I have no record of this transformer running!"
Chris@320 250 << std::endl;
Chris@320 251 }
Chris@320 252
Chris@331 253 m_runningTransformers.erase(transformer);
Chris@320 254
Chris@331 255 transformer->wait(); // unnecessary but reassuring
Chris@331 256 delete transformer;
Chris@320 257 }
Chris@320 258
Chris@320 259 void
Chris@331 260 ModelTransformerFactory::modelAboutToBeDeleted(Model *m)
Chris@320 261 {
Chris@328 262 TransformerSet affected;
Chris@320 263
Chris@328 264 for (TransformerSet::iterator i = m_runningTransformers.begin();
Chris@328 265 i != m_runningTransformers.end(); ++i) {
Chris@320 266
Chris@331 267 ModelTransformer *t = *i;
Chris@320 268
Chris@320 269 if (t->getInputModel() == m || t->getOutputModel() == m) {
Chris@320 270 affected.insert(t);
Chris@320 271 }
Chris@320 272 }
Chris@320 273
Chris@328 274 for (TransformerSet::iterator i = affected.begin();
Chris@320 275 i != affected.end(); ++i) {
Chris@320 276
Chris@331 277 ModelTransformer *t = *i;
Chris@320 278
Chris@320 279 t->abandon();
Chris@320 280
Chris@320 281 t->wait(); // this should eventually call back on
Chris@331 282 // transformerFinished, which will remove from
Chris@328 283 // m_runningTransformers and delete.
Chris@320 284 }
Chris@320 285 }
Chris@320 286