| Chris@45 | 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */ | 
| Chris@45 | 2 | 
| Chris@45 | 3 /* | 
| Chris@45 | 4     Sonic Visualiser | 
| Chris@45 | 5     An audio file viewer and annotation editor. | 
| Chris@45 | 6     Centre for Digital Music, Queen Mary, University of London. | 
| Chris@45 | 7     This file copyright 2006 Chris Cannam and QMUL. | 
| Chris@45 | 8 | 
| Chris@45 | 9     This program is free software; you can redistribute it and/or | 
| Chris@45 | 10     modify it under the terms of the GNU General Public License as | 
| Chris@45 | 11     published by the Free Software Foundation; either version 2 of the | 
| Chris@45 | 12     License, or (at your option) any later version.  See the file | 
| Chris@45 | 13     COPYING included with this distribution for more information. | 
| Chris@45 | 14 */ | 
| Chris@45 | 15 | 
| Chris@45 | 16 #include "Document.h" | 
| Chris@45 | 17 | 
| Chris@45 | 18 #include "data/model/WaveFileModel.h" | 
| Chris@45 | 19 #include "data/model/WritableWaveFileModel.h" | 
| Chris@45 | 20 #include "data/model/DenseThreeDimensionalModel.h" | 
| Chris@45 | 21 #include "data/model/DenseTimeValueModel.h" | 
| Chris@45 | 22 #include "layer/Layer.h" | 
| Chris@45 | 23 #include "base/CommandHistory.h" | 
| Chris@45 | 24 #include "base/Command.h" | 
| Chris@45 | 25 #include "view/View.h" | 
| Chris@45 | 26 #include "base/PlayParameterRepository.h" | 
| Chris@45 | 27 #include "base/PlayParameters.h" | 
| Chris@54 | 28 #include "plugin/transform/TransformFactory.h" | 
| Chris@54 | 29 #include "plugin/transform/ModelTransformerFactory.h" | 
| Chris@45 | 30 #include <QApplication> | 
| Chris@45 | 31 #include <QTextStream> | 
| Chris@90 | 32 #include <QSettings> | 
| Chris@45 | 33 #include <iostream> | 
| Chris@45 | 34 | 
| Chris@45 | 35 // For alignment: | 
| Chris@45 | 36 #include "data/model/AggregateWaveModel.h" | 
| Chris@45 | 37 #include "data/model/SparseTimeValueModel.h" | 
| Chris@45 | 38 #include "data/model/AlignmentModel.h" | 
| Chris@45 | 39 | 
| Chris@81 | 40 //#define DEBUG_DOCUMENT 1 | 
| Chris@77 | 41 | 
| Chris@45 | 42 //!!! still need to handle command history, documentRestored/documentModified | 
| Chris@45 | 43 | 
| Chris@45 | 44 Document::Document() : | 
| Chris@47 | 45     m_mainModel(0), | 
| Chris@47 | 46     m_autoAlignment(false) | 
| Chris@45 | 47 { | 
| Chris@45 | 48     connect(this, SIGNAL(modelAboutToBeDeleted(Model *)), | 
| Chris@54 | 49             ModelTransformerFactory::getInstance(), | 
| Chris@45 | 50             SLOT(modelAboutToBeDeleted(Model *))); | 
| Chris@45 | 51 } | 
| Chris@45 | 52 | 
| Chris@45 | 53 Document::~Document() | 
| Chris@45 | 54 { | 
| Chris@45 | 55     //!!! Document should really own the command history.  atm we | 
| Chris@45 | 56     //still refer to it in various places that don't have access to | 
| Chris@45 | 57     //the document, be nice to fix that | 
| Chris@45 | 58 | 
| Chris@77 | 59 #ifdef DEBUG_DOCUMENT | 
| Chris@77 | 60     std::cerr << "\n\nDocument::~Document: about to clear command history" << std::endl; | 
| Chris@77 | 61 #endif | 
| Chris@45 | 62     CommandHistory::getInstance()->clear(); | 
| Chris@45 | 63 | 
| Chris@77 | 64 #ifdef DEBUG_DOCUMENT | 
| Chris@52 | 65     std::cerr << "Document::~Document: about to delete layers" << std::endl; | 
| Chris@77 | 66 #endif | 
| Chris@45 | 67     while (!m_layers.empty()) { | 
| Chris@45 | 68 	deleteLayer(*m_layers.begin(), true); | 
| Chris@45 | 69     } | 
| Chris@45 | 70 | 
| Chris@45 | 71     if (!m_models.empty()) { | 
| Chris@45 | 72 	std::cerr << "Document::~Document: WARNING: " | 
| Chris@45 | 73 		  << m_models.size() << " model(s) still remain -- " | 
| Chris@45 | 74 		  << "should have been garbage collected when deleting layers" | 
| Chris@45 | 75 		  << std::endl; | 
| Chris@45 | 76 	while (!m_models.empty()) { | 
| Chris@45 | 77             Model *model = m_models.begin()->first; | 
| Chris@45 | 78 	    if (model == m_mainModel) { | 
| Chris@45 | 79 		// just in case! | 
| Chris@45 | 80 		std::cerr << "Document::~Document: WARNING: Main model is also" | 
| Chris@45 | 81 			  << " in models list!" << std::endl; | 
| Chris@45 | 82 	    } else if (model) { | 
| Chris@79 | 83                 model->aboutToDelete(); | 
| Chris@45 | 84 		emit modelAboutToBeDeleted(model); | 
| Chris@45 | 85 		delete model; | 
| Chris@45 | 86 	    } | 
| Chris@45 | 87 	    m_models.erase(m_models.begin()); | 
| Chris@45 | 88 	} | 
| Chris@45 | 89     } | 
| Chris@45 | 90 | 
| Chris@77 | 91 #ifdef DEBUG_DOCUMENT | 
| Chris@77 | 92     std::cerr << "Document::~Document: About to get rid of main model" | 
| Chris@77 | 93 	      << std::endl; | 
| Chris@77 | 94 #endif | 
| Chris@45 | 95     if (m_mainModel) { | 
| Chris@79 | 96         m_mainModel->aboutToDelete(); | 
| Chris@45 | 97         emit modelAboutToBeDeleted(m_mainModel); | 
| Chris@45 | 98     } | 
| Chris@45 | 99 | 
| Chris@45 | 100     emit mainModelChanged(0); | 
| Chris@45 | 101     delete m_mainModel; | 
| Chris@45 | 102 | 
| Chris@45 | 103 } | 
| Chris@45 | 104 | 
| Chris@45 | 105 Layer * | 
| Chris@45 | 106 Document::createLayer(LayerFactory::LayerType type) | 
| Chris@45 | 107 { | 
| Chris@45 | 108     Layer *newLayer = LayerFactory::getInstance()->createLayer(type); | 
| Chris@45 | 109     if (!newLayer) return 0; | 
| Chris@45 | 110 | 
| Chris@45 | 111     newLayer->setObjectName(getUniqueLayerName(newLayer->objectName())); | 
| Chris@45 | 112 | 
| Chris@45 | 113     m_layers.insert(newLayer); | 
| Chris@52 | 114 | 
| Chris@77 | 115 #ifdef DEBUG_DOCUMENT | 
| Chris@77 | 116     std::cerr << "Document::createLayer: Added layer of type " << type | 
| Chris@77 | 117               << ", now have " << m_layers.size() << " layers" << std::endl; | 
| Chris@77 | 118 #endif | 
| Chris@52 | 119 | 
| Chris@45 | 120     emit layerAdded(newLayer); | 
| Chris@45 | 121 | 
| Chris@45 | 122     return newLayer; | 
| Chris@45 | 123 } | 
| Chris@45 | 124 | 
| Chris@45 | 125 Layer * | 
| Chris@45 | 126 Document::createMainModelLayer(LayerFactory::LayerType type) | 
| Chris@45 | 127 { | 
| Chris@45 | 128     Layer *newLayer = createLayer(type); | 
| Chris@45 | 129     if (!newLayer) return 0; | 
| Chris@45 | 130     setModel(newLayer, m_mainModel); | 
| Chris@45 | 131     return newLayer; | 
| Chris@45 | 132 } | 
| Chris@45 | 133 | 
| Chris@45 | 134 Layer * | 
| Chris@45 | 135 Document::createImportedLayer(Model *model) | 
| Chris@45 | 136 { | 
| Chris@45 | 137     LayerFactory::LayerTypeSet types = | 
| Chris@45 | 138 	LayerFactory::getInstance()->getValidLayerTypes(model); | 
| Chris@45 | 139 | 
| Chris@45 | 140     if (types.empty()) { | 
| Chris@45 | 141 	std::cerr << "WARNING: Document::importLayer: no valid display layer for model" << std::endl; | 
| Chris@45 | 142 	return 0; | 
| Chris@45 | 143     } | 
| Chris@45 | 144 | 
| Chris@45 | 145     //!!! for now, just use the first suitable layer type | 
| Chris@45 | 146     LayerFactory::LayerType type = *types.begin(); | 
| Chris@45 | 147 | 
| Chris@45 | 148     Layer *newLayer = LayerFactory::getInstance()->createLayer(type); | 
| Chris@45 | 149     if (!newLayer) return 0; | 
| Chris@45 | 150 | 
| Chris@45 | 151     newLayer->setObjectName(getUniqueLayerName(newLayer->objectName())); | 
| Chris@45 | 152 | 
| Chris@45 | 153     addImportedModel(model); | 
| Chris@45 | 154     setModel(newLayer, model); | 
| Chris@45 | 155 | 
| Chris@45 | 156     //!!! and all channels | 
| Chris@45 | 157     setChannel(newLayer, -1); | 
| Chris@45 | 158 | 
| Chris@45 | 159     m_layers.insert(newLayer); | 
| Chris@52 | 160 | 
| Chris@77 | 161 #ifdef DEBUG_DOCUMENT | 
| Chris@52 | 162     std::cerr << "Document::createImportedLayer: Added layer of type " << type | 
| Chris@52 | 163               << ", now have " << m_layers.size() << " layers" << std::endl; | 
| Chris@77 | 164 #endif | 
| Chris@52 | 165 | 
| Chris@45 | 166     emit layerAdded(newLayer); | 
| Chris@45 | 167     return newLayer; | 
| Chris@45 | 168 } | 
| Chris@45 | 169 | 
| Chris@45 | 170 Layer * | 
| Chris@45 | 171 Document::createEmptyLayer(LayerFactory::LayerType type) | 
| Chris@45 | 172 { | 
| Chris@61 | 173     if (!m_mainModel) return 0; | 
| Chris@61 | 174 | 
| Chris@45 | 175     Model *newModel = | 
| Chris@45 | 176 	LayerFactory::getInstance()->createEmptyModel(type, m_mainModel); | 
| Chris@45 | 177     if (!newModel) return 0; | 
| Chris@45 | 178 | 
| Chris@45 | 179     Layer *newLayer = createLayer(type); | 
| Chris@45 | 180     if (!newLayer) { | 
| Chris@45 | 181 	delete newModel; | 
| Chris@45 | 182 	return 0; | 
| Chris@45 | 183     } | 
| Chris@45 | 184 | 
| Chris@45 | 185     addImportedModel(newModel); | 
| Chris@45 | 186     setModel(newLayer, newModel); | 
| Chris@45 | 187 | 
| Chris@45 | 188     return newLayer; | 
| Chris@45 | 189 } | 
| Chris@45 | 190 | 
| Chris@45 | 191 Layer * | 
| Chris@45 | 192 Document::createDerivedLayer(LayerFactory::LayerType type, | 
| Chris@54 | 193 			     TransformId transform) | 
| Chris@45 | 194 { | 
| Chris@45 | 195     Layer *newLayer = createLayer(type); | 
| Chris@45 | 196     if (!newLayer) return 0; | 
| Chris@45 | 197 | 
| Chris@45 | 198     newLayer->setObjectName(getUniqueLayerName | 
| Chris@54 | 199                             (TransformFactory::getInstance()-> | 
| Chris@54 | 200                              getTransformFriendlyName(transform))); | 
| Chris@45 | 201 | 
| Chris@45 | 202     return newLayer; | 
| Chris@45 | 203 } | 
| Chris@45 | 204 | 
| Chris@45 | 205 Layer * | 
| Chris@72 | 206 Document::createDerivedLayer(const Transform &transform, | 
| Chris@72 | 207                              const ModelTransformer::Input &input) | 
| Chris@45 | 208 { | 
| Chris@78 | 209     QString message; | 
| Chris@78 | 210     Model *newModel = addDerivedModel(transform, input, message); | 
| Chris@45 | 211     if (!newModel) { | 
| Chris@78 | 212         emit modelGenerationFailed(transform.getIdentifier(), message); | 
| Chris@45 | 213         return 0; | 
| Chris@78 | 214     } else if (message != "") { | 
| Chris@78 | 215         emit modelGenerationWarning(transform.getIdentifier(), message); | 
| Chris@45 | 216     } | 
| Chris@45 | 217 | 
| Chris@45 | 218     LayerFactory::LayerTypeSet types = | 
| Chris@45 | 219 	LayerFactory::getInstance()->getValidLayerTypes(newModel); | 
| Chris@45 | 220 | 
| Chris@45 | 221     if (types.empty()) { | 
| Chris@72 | 222 	std::cerr << "WARNING: Document::createLayerForTransformer: no valid display layer for output of transform " << transform.getIdentifier().toStdString() << std::endl; | 
| Chris@45 | 223 	delete newModel; | 
| Chris@45 | 224 	return 0; | 
| Chris@45 | 225     } | 
| Chris@45 | 226 | 
| Chris@45 | 227     //!!! for now, just use the first suitable layer type | 
| Chris@45 | 228 | 
| Chris@45 | 229     Layer *newLayer = createLayer(*types.begin()); | 
| Chris@45 | 230     setModel(newLayer, newModel); | 
| Chris@45 | 231 | 
| Chris@45 | 232     //!!! We need to clone the model when adding the layer, so that it | 
| Chris@45 | 233     //can be edited without affecting other layers that are based on | 
| Chris@45 | 234     //the same model.  Unfortunately we can't just clone it now, | 
| Chris@45 | 235     //because it probably hasn't been completed yet -- the transform | 
| Chris@45 | 236     //runs in the background.  Maybe the transform has to handle | 
| Chris@45 | 237     //cloning and cacheing models itself. | 
| Chris@45 | 238     // | 
| Chris@45 | 239     // Once we do clone models here, of course, we'll have to avoid | 
| Chris@45 | 240     // leaking them too. | 
| Chris@45 | 241     // | 
| Chris@45 | 242     // We want the user to be able to add a model to a second layer | 
| Chris@45 | 243     // _while it's still being calculated in the first_ and have it | 
| Chris@45 | 244     // work quickly.  That means we need to put the same physical | 
| Chris@45 | 245     // model pointer in both layers, so they can't actually be cloned. | 
| Chris@45 | 246 | 
| Chris@45 | 247     if (newLayer) { | 
| Chris@45 | 248 	newLayer->setObjectName(getUniqueLayerName | 
| Chris@54 | 249                                 (TransformFactory::getInstance()-> | 
| Chris@72 | 250                                  getTransformFriendlyName | 
| Chris@72 | 251                                  (transform.getIdentifier()))); | 
| Chris@45 | 252     } | 
| Chris@45 | 253 | 
| Chris@45 | 254     emit layerAdded(newLayer); | 
| Chris@45 | 255     return newLayer; | 
| Chris@45 | 256 } | 
| Chris@45 | 257 | 
| Chris@45 | 258 void | 
| Chris@45 | 259 Document::setMainModel(WaveFileModel *model) | 
| Chris@45 | 260 { | 
| Chris@45 | 261     Model *oldMainModel = m_mainModel; | 
| Chris@45 | 262     m_mainModel = model; | 
| Chris@45 | 263 | 
| Chris@45 | 264     emit modelAdded(m_mainModel); | 
| Chris@45 | 265 | 
| Chris@45 | 266     std::vector<Layer *> obsoleteLayers; | 
| Chris@53 | 267     std::set<QString> failedTransformers; | 
| Chris@45 | 268 | 
| Chris@45 | 269     // We need to ensure that no layer is left using oldMainModel or | 
| Chris@45 | 270     // any of the old derived models as its model.  Either replace the | 
| Chris@45 | 271     // model, or delete the layer for each layer that is currently | 
| Chris@45 | 272     // using one of these.  Carry out this replacement before we | 
| Chris@45 | 273     // delete any of the models. | 
| Chris@45 | 274 | 
| Chris@77 | 275 #ifdef DEBUG_DOCUMENT | 
| Chris@77 | 276     std::cerr << "Document::setMainModel: Have " | 
| Chris@77 | 277               << m_layers.size() << " layers" << std::endl; | 
| Chris@77 | 278 #endif | 
| Chris@52 | 279 | 
| Chris@45 | 280     for (LayerSet::iterator i = m_layers.begin(); i != m_layers.end(); ++i) { | 
| Chris@45 | 281 | 
| Chris@45 | 282 	Layer *layer = *i; | 
| Chris@45 | 283 	Model *model = layer->getModel(); | 
| Chris@45 | 284 | 
| Chris@77 | 285 #ifdef DEBUG_DOCUMENT | 
| Chris@77 | 286         std::cerr << "Document::setMainModel: inspecting model " | 
| Chris@77 | 287                   << (model ? model->objectName().toStdString() : "(null)") << " in layer " | 
| Chris@77 | 288                   << layer->objectName().toStdString() << std::endl; | 
| Chris@77 | 289 #endif | 
| Chris@45 | 290 | 
| Chris@70 | 291 	if (model == oldMainModel) { | 
| Chris@77 | 292 #ifdef DEBUG_DOCUMENT | 
| Chris@77 | 293             std::cerr << "... it uses the old main model, replacing" << std::endl; | 
| Chris@77 | 294 #endif | 
| Chris@45 | 295 	    LayerFactory::getInstance()->setModel(layer, m_mainModel); | 
| Chris@45 | 296 	    continue; | 
| Chris@45 | 297 	} | 
| Chris@45 | 298 | 
| Chris@70 | 299 	if (model && (m_models.find(model) == m_models.end())) { | 
| Chris@45 | 300 	    std::cerr << "WARNING: Document::setMainModel: Unknown model " | 
| Chris@45 | 301 		      << model << " in layer " << layer << std::endl; | 
| Chris@45 | 302 	    // get rid of this hideous degenerate | 
| Chris@45 | 303 	    obsoleteLayers.push_back(layer); | 
| Chris@45 | 304 	    continue; | 
| Chris@45 | 305 	} | 
| Chris@45 | 306 | 
| Chris@70 | 307 	if (m_models[model].source && | 
| Chris@70 | 308             (m_models[model].source == oldMainModel)) { | 
| Chris@45 | 309 | 
| Chris@77 | 310 #ifdef DEBUG_DOCUMENT | 
| Chris@77 | 311             std::cerr << "... it uses a model derived from the old main model, regenerating" << std::endl; | 
| Chris@77 | 312 #endif | 
| Chris@45 | 313 | 
| Chris@45 | 314 	    // This model was derived from the previous main | 
| Chris@45 | 315 	    // model: regenerate it. | 
| Chris@45 | 316 | 
| Chris@72 | 317 	    const Transform &transform = m_models[model].transform; | 
| Chris@72 | 318             QString transformId = transform.getIdentifier(); | 
| Chris@45 | 319 | 
| Chris@72 | 320             //!!! We have a problem here if the number of channels in | 
| Chris@72 | 321             //the main model has changed. | 
| Chris@72 | 322 | 
| Chris@78 | 323             QString message; | 
| Chris@45 | 324 	    Model *replacementModel = | 
| Chris@45 | 325                 addDerivedModel(transform, | 
| Chris@72 | 326                                 ModelTransformer::Input | 
| Chris@78 | 327                                 (m_mainModel, m_models[model].channel), | 
| Chris@78 | 328                                 message); | 
| Chris@45 | 329 | 
| Chris@45 | 330 	    if (!replacementModel) { | 
| Chris@45 | 331 		std::cerr << "WARNING: Document::setMainModel: Failed to regenerate model for transform \"" | 
| Chris@72 | 332 			  << transformId.toStdString() << "\"" << " in layer " << layer << std::endl; | 
| Chris@72 | 333                 if (failedTransformers.find(transformId) | 
| Chris@72 | 334                     == failedTransformers.end()) { | 
| Chris@45 | 335                     emit modelRegenerationFailed(layer->objectName(), | 
| Chris@78 | 336                                                  transformId, | 
| Chris@78 | 337                                                  message); | 
| Chris@72 | 338                     failedTransformers.insert(transformId); | 
| Chris@45 | 339                 } | 
| Chris@45 | 340 		obsoleteLayers.push_back(layer); | 
| Chris@45 | 341 	    } else { | 
| Chris@78 | 342                 if (message != "") { | 
| Chris@78 | 343                     emit modelRegenerationWarning(layer->objectName(), | 
| Chris@78 | 344                                                   transformId, | 
| Chris@78 | 345                                                   message); | 
| Chris@78 | 346                 } | 
| Chris@77 | 347 #ifdef DEBUG_DOCUMENT | 
| Chris@77 | 348                 std::cerr << "Replacing model " << model << " (type " | 
| Chris@77 | 349                           << typeid(*model).name() << ") with model " | 
| Chris@77 | 350                           << replacementModel << " (type " | 
| Chris@77 | 351                           << typeid(*replacementModel).name() << ") in layer " | 
| Chris@77 | 352                           << layer << " (name " << layer->objectName().toStdString() << ")" | 
| Chris@77 | 353                           << std::endl; | 
| Chris@77 | 354 #endif | 
| Chris@45 | 355                 RangeSummarisableTimeValueModel *rm = | 
| Chris@45 | 356                     dynamic_cast<RangeSummarisableTimeValueModel *>(replacementModel); | 
| Chris@77 | 357 #ifdef DEBUG_DOCUMENT | 
| Chris@45 | 358                 if (rm) { | 
| Chris@45 | 359                     std::cerr << "new model has " << rm->getChannelCount() << " channels " << std::endl; | 
| Chris@45 | 360                 } else { | 
| Chris@45 | 361                     std::cerr << "new model is not a RangeSummarisableTimeValueModel!" << std::endl; | 
| Chris@45 | 362                 } | 
| Chris@77 | 363 #endif | 
| Chris@45 | 364 		setModel(layer, replacementModel); | 
| Chris@45 | 365 	    } | 
| Chris@45 | 366 	} | 
| Chris@45 | 367     } | 
| Chris@45 | 368 | 
| Chris@45 | 369     for (size_t k = 0; k < obsoleteLayers.size(); ++k) { | 
| Chris@45 | 370 	deleteLayer(obsoleteLayers[k], true); | 
| Chris@45 | 371     } | 
| Chris@45 | 372 | 
| Chris@48 | 373     for (ModelMap::iterator i = m_models.begin(); i != m_models.end(); ++i) { | 
| Chris@86 | 374 | 
| Chris@86 | 375         if (m_autoAlignment) { | 
| Chris@86 | 376 | 
| Chris@86 | 377             alignModel(i->first); | 
| Chris@86 | 378 | 
| Chris@86 | 379         } else if (oldMainModel && | 
| Chris@86 | 380                    (i->first->getAlignmentReference() == oldMainModel)) { | 
| Chris@86 | 381 | 
| Chris@48 | 382             alignModel(i->first); | 
| Chris@48 | 383         } | 
| Chris@48 | 384     } | 
| Chris@48 | 385 | 
| Chris@77 | 386     if (oldMainModel) { | 
| Chris@79 | 387         oldMainModel->aboutToDelete(); | 
| Chris@77 | 388         emit modelAboutToBeDeleted(oldMainModel); | 
| Chris@77 | 389     } | 
| Chris@77 | 390 | 
| Chris@86 | 391     if (m_autoAlignment) { | 
| Chris@86 | 392         alignModel(m_mainModel); | 
| Chris@86 | 393     } | 
| Chris@86 | 394 | 
| Chris@45 | 395     emit mainModelChanged(m_mainModel); | 
| Chris@45 | 396 | 
| Chris@45 | 397     delete oldMainModel; | 
| Chris@45 | 398 } | 
| Chris@45 | 399 | 
| Chris@45 | 400 void | 
| Chris@72 | 401 Document::addDerivedModel(const Transform &transform, | 
| Chris@72 | 402                           const ModelTransformer::Input &input, | 
| Chris@72 | 403                           Model *outputModelToAdd) | 
| Chris@45 | 404 { | 
| Chris@45 | 405     if (m_models.find(outputModelToAdd) != m_models.end()) { | 
| Chris@45 | 406 	std::cerr << "WARNING: Document::addDerivedModel: Model already added" | 
| Chris@45 | 407 		  << std::endl; | 
| Chris@45 | 408 	return; | 
| Chris@45 | 409     } | 
| Chris@45 | 410 | 
| Chris@77 | 411 #ifdef DEBUG_DOCUMENT | 
| Chris@77 | 412     std::cerr << "Document::addDerivedModel: source is " << input.getModel() << " \"" << input.getModel()->objectName().toStdString() << "\"" << std::endl; | 
| Chris@77 | 413 #endif | 
| Chris@45 | 414 | 
| Chris@45 | 415     ModelRecord rec; | 
| Chris@72 | 416     rec.source = input.getModel(); | 
| Chris@72 | 417     rec.channel = input.getChannel(); | 
| Chris@45 | 418     rec.transform = transform; | 
| Chris@45 | 419     rec.refcount = 0; | 
| Chris@45 | 420 | 
| Chris@72 | 421     outputModelToAdd->setSourceModel(input.getModel()); | 
| Chris@45 | 422 | 
| Chris@45 | 423     m_models[outputModelToAdd] = rec; | 
| Chris@45 | 424 | 
| Chris@45 | 425     emit modelAdded(outputModelToAdd); | 
| Chris@45 | 426 } | 
| Chris@45 | 427 | 
| Chris@45 | 428 | 
| Chris@45 | 429 void | 
| Chris@45 | 430 Document::addImportedModel(Model *model) | 
| Chris@45 | 431 { | 
| Chris@45 | 432     if (m_models.find(model) != m_models.end()) { | 
| Chris@45 | 433 	std::cerr << "WARNING: Document::addImportedModel: Model already added" | 
| Chris@45 | 434 		  << std::endl; | 
| Chris@45 | 435 	return; | 
| Chris@45 | 436     } | 
| Chris@45 | 437 | 
| Chris@45 | 438     ModelRecord rec; | 
| Chris@45 | 439     rec.source = 0; | 
| Chris@45 | 440     rec.refcount = 0; | 
| Chris@45 | 441 | 
| Chris@45 | 442     m_models[model] = rec; | 
| Chris@45 | 443 | 
| Chris@47 | 444     if (m_autoAlignment) alignModel(model); | 
| Chris@47 | 445 | 
| Chris@45 | 446     emit modelAdded(model); | 
| Chris@45 | 447 } | 
| Chris@45 | 448 | 
| Chris@45 | 449 Model * | 
| Chris@72 | 450 Document::addDerivedModel(const Transform &transform, | 
| Chris@78 | 451                           const ModelTransformer::Input &input, | 
| Chris@78 | 452                           QString &message) | 
| Chris@45 | 453 { | 
| Chris@45 | 454     Model *model = 0; | 
| Chris@45 | 455 | 
| Chris@45 | 456     for (ModelMap::iterator i = m_models.begin(); i != m_models.end(); ++i) { | 
| Chris@45 | 457 	if (i->second.transform == transform && | 
| Chris@72 | 458 	    i->second.source == input.getModel() && | 
| Chris@72 | 459             i->second.channel == input.getChannel()) { | 
| Chris@45 | 460 	    return i->first; | 
| Chris@45 | 461 	} | 
| Chris@45 | 462     } | 
| Chris@45 | 463 | 
| Chris@78 | 464     model = ModelTransformerFactory::getInstance()->transform | 
| Chris@78 | 465         (transform, input, message); | 
| Chris@45 | 466 | 
| Chris@83 | 467     // The transform we actually used was presumably identical to the | 
| Chris@83 | 468     // one asked for, except that the version of the plugin may | 
| Chris@83 | 469     // differ.  It's possible that the returned message contains a | 
| Chris@83 | 470     // warning about this; that doesn't concern us here, but we do | 
| Chris@83 | 471     // need to ensure that the transform we remember is correct for | 
| Chris@83 | 472     // what was actually applied, with the current plugin version. | 
| Chris@83 | 473 | 
| Chris@83 | 474     Transform applied = transform; | 
| Chris@83 | 475     applied.setPluginVersion | 
| Chris@83 | 476         (TransformFactory::getInstance()-> | 
| Chris@83 | 477          getDefaultTransformFor(transform.getIdentifier(), | 
| Chris@83 | 478                                 lrintf(transform.getSampleRate())) | 
| Chris@83 | 479          .getPluginVersion()); | 
| Chris@83 | 480 | 
| Chris@45 | 481     if (!model) { | 
| Chris@72 | 482 	std::cerr << "WARNING: Document::addDerivedModel: no output model for transform " << transform.getIdentifier().toStdString() << std::endl; | 
| Chris@45 | 483     } else { | 
| Chris@83 | 484 	addDerivedModel(applied, input, model); | 
| Chris@45 | 485     } | 
| Chris@45 | 486 | 
| Chris@45 | 487     return model; | 
| Chris@45 | 488 } | 
| Chris@45 | 489 | 
| Chris@45 | 490 void | 
| Chris@45 | 491 Document::releaseModel(Model *model) // Will _not_ release main model! | 
| Chris@45 | 492 { | 
| Chris@45 | 493     if (model == 0) { | 
| Chris@45 | 494 	return; | 
| Chris@45 | 495     } | 
| Chris@45 | 496 | 
| Chris@45 | 497     if (model == m_mainModel) { | 
| Chris@45 | 498 	return; | 
| Chris@45 | 499     } | 
| Chris@45 | 500 | 
| Chris@45 | 501     bool toDelete = false; | 
| Chris@45 | 502 | 
| Chris@45 | 503     if (m_models.find(model) != m_models.end()) { | 
| Chris@45 | 504 | 
| Chris@45 | 505 	if (m_models[model].refcount == 0) { | 
| Chris@45 | 506 	    std::cerr << "WARNING: Document::releaseModel: model " << model | 
| Chris@45 | 507 		      << " reference count is zero already!" << std::endl; | 
| Chris@45 | 508 	} else { | 
| Chris@45 | 509 	    if (--m_models[model].refcount == 0) { | 
| Chris@45 | 510 		toDelete = true; | 
| Chris@45 | 511 	    } | 
| Chris@45 | 512 	} | 
| Chris@45 | 513     } else { | 
| Chris@45 | 514 	std::cerr << "WARNING: Document::releaseModel: Unfound model " | 
| Chris@45 | 515 		  << model << std::endl; | 
| Chris@45 | 516 	toDelete = true; | 
| Chris@45 | 517     } | 
| Chris@45 | 518 | 
| Chris@45 | 519     if (toDelete) { | 
| Chris@45 | 520 | 
| Chris@45 | 521 	int sourceCount = 0; | 
| Chris@45 | 522 | 
| Chris@45 | 523 	for (ModelMap::iterator i = m_models.begin(); i != m_models.end(); ++i) { | 
| Chris@45 | 524 	    if (i->second.source == model) { | 
| Chris@45 | 525 		++sourceCount; | 
| Chris@45 | 526 		i->second.source = 0; | 
| Chris@45 | 527 	    } | 
| Chris@45 | 528 	} | 
| Chris@45 | 529 | 
| Chris@45 | 530 	if (sourceCount > 0) { | 
| Chris@45 | 531 	    std::cerr << "Document::releaseModel: Deleting model " | 
| Chris@45 | 532 		      << model << " even though it is source for " | 
| Chris@45 | 533 		      << sourceCount << " other derived model(s) -- resetting " | 
| Chris@45 | 534 		      << "their source fields appropriately" << std::endl; | 
| Chris@45 | 535 	} | 
| Chris@45 | 536 | 
| Chris@79 | 537         model->aboutToDelete(); | 
| Chris@45 | 538 	emit modelAboutToBeDeleted(model); | 
| Chris@45 | 539 	m_models.erase(model); | 
| Chris@45 | 540 	delete model; | 
| Chris@45 | 541     } | 
| Chris@45 | 542 } | 
| Chris@45 | 543 | 
| Chris@45 | 544 void | 
| Chris@45 | 545 Document::deleteLayer(Layer *layer, bool force) | 
| Chris@45 | 546 { | 
| Chris@45 | 547     if (m_layerViewMap.find(layer) != m_layerViewMap.end() && | 
| Chris@45 | 548 	m_layerViewMap[layer].size() > 0) { | 
| Chris@45 | 549 | 
| Chris@45 | 550 	std::cerr << "WARNING: Document::deleteLayer: Layer " | 
| Chris@45 | 551 		  << layer << " [" << layer->objectName().toStdString() << "]" | 
| Chris@45 | 552 		  << " is still used in " << m_layerViewMap[layer].size() | 
| Chris@45 | 553 		  << " views!" << std::endl; | 
| Chris@45 | 554 | 
| Chris@45 | 555 	if (force) { | 
| Chris@45 | 556 | 
| Chris@77 | 557 #ifdef DEBUG_DOCUMENT | 
| Chris@45 | 558 	    std::cerr << "(force flag set -- deleting from all views)" << std::endl; | 
| Chris@77 | 559 #endif | 
| Chris@45 | 560 | 
| Chris@45 | 561 	    for (std::set<View *>::iterator j = m_layerViewMap[layer].begin(); | 
| Chris@45 | 562 		 j != m_layerViewMap[layer].end(); ++j) { | 
| Chris@45 | 563 		// don't use removeLayerFromView, as it issues a command | 
| Chris@45 | 564 		layer->setLayerDormant(*j, true); | 
| Chris@45 | 565 		(*j)->removeLayer(layer); | 
| Chris@45 | 566 	    } | 
| Chris@45 | 567 | 
| Chris@45 | 568 	    m_layerViewMap.erase(layer); | 
| Chris@45 | 569 | 
| Chris@45 | 570 	} else { | 
| Chris@45 | 571 	    return; | 
| Chris@45 | 572 	} | 
| Chris@45 | 573     } | 
| Chris@45 | 574 | 
| Chris@45 | 575     if (m_layers.find(layer) == m_layers.end()) { | 
| Chris@45 | 576 	std::cerr << "Document::deleteLayer: Layer " | 
| Chris@45 | 577 		  << layer << " does not exist, or has already been deleted " | 
| Chris@45 | 578 		  << "(this may not be as serious as it sounds)" << std::endl; | 
| Chris@45 | 579 	return; | 
| Chris@45 | 580     } | 
| Chris@45 | 581 | 
| Chris@45 | 582     m_layers.erase(layer); | 
| Chris@45 | 583 | 
| Chris@52 | 584     std::cerr << "Document::deleteLayer: Removing, now have " | 
| Chris@52 | 585               << m_layers.size() << " layers" << std::endl; | 
| Chris@52 | 586 | 
| Chris@45 | 587     releaseModel(layer->getModel()); | 
| Chris@45 | 588     emit layerRemoved(layer); | 
| Chris@45 | 589     emit layerAboutToBeDeleted(layer); | 
| Chris@45 | 590     delete layer; | 
| Chris@45 | 591 } | 
| Chris@45 | 592 | 
| Chris@45 | 593 void | 
| Chris@45 | 594 Document::setModel(Layer *layer, Model *model) | 
| Chris@45 | 595 { | 
| Chris@45 | 596     if (model && | 
| Chris@45 | 597 	model != m_mainModel && | 
| Chris@45 | 598 	m_models.find(model) == m_models.end()) { | 
| Chris@45 | 599 	std::cerr << "ERROR: Document::setModel: Layer " << layer | 
| Chris@45 | 600 		  << " (\"" << layer->objectName().toStdString() | 
| Chris@45 | 601                   << "\") wants to use unregistered model " << model | 
| Chris@45 | 602 		  << ": register the layer's model before setting it!" | 
| Chris@45 | 603 		  << std::endl; | 
| Chris@45 | 604 	return; | 
| Chris@45 | 605     } | 
| Chris@45 | 606 | 
| Chris@45 | 607     Model *previousModel = layer->getModel(); | 
| Chris@45 | 608 | 
| Chris@45 | 609     if (previousModel == model) { | 
| Chris@45 | 610         std::cerr << "WARNING: Document::setModel: Layer " << layer << " (\"" | 
| Chris@45 | 611                   << layer->objectName().toStdString() | 
| Chris@45 | 612                   << "\") is already set to model " | 
| Chris@45 | 613                   << model << " (\"" | 
| Chris@45 | 614                   << (model ? model->objectName().toStdString() : "(null)") | 
| Chris@45 | 615                   << "\")" << std::endl; | 
| Chris@45 | 616         return; | 
| Chris@45 | 617     } | 
| Chris@45 | 618 | 
| Chris@45 | 619     if (model && model != m_mainModel) { | 
| Chris@45 | 620 	m_models[model].refcount ++; | 
| Chris@45 | 621     } | 
| Chris@45 | 622 | 
| Chris@45 | 623     if (model && previousModel) { | 
| Chris@45 | 624         PlayParameterRepository::getInstance()->copyParameters | 
| Chris@45 | 625             (previousModel, model); | 
| Chris@45 | 626     } | 
| Chris@45 | 627 | 
| Chris@45 | 628     LayerFactory::getInstance()->setModel(layer, model); | 
| Chris@45 | 629 | 
| Chris@45 | 630     if (previousModel) { | 
| Chris@45 | 631         releaseModel(previousModel); | 
| Chris@45 | 632     } | 
| Chris@45 | 633 } | 
| Chris@45 | 634 | 
| Chris@45 | 635 void | 
| Chris@45 | 636 Document::setChannel(Layer *layer, int channel) | 
| Chris@45 | 637 { | 
| Chris@45 | 638     LayerFactory::getInstance()->setChannel(layer, channel); | 
| Chris@45 | 639 } | 
| Chris@45 | 640 | 
| Chris@45 | 641 void | 
| Chris@45 | 642 Document::addLayerToView(View *view, Layer *layer) | 
| Chris@45 | 643 { | 
| Chris@45 | 644     Model *model = layer->getModel(); | 
| Chris@45 | 645     if (!model) { | 
| Chris@77 | 646 #ifdef DEBUG_DOCUMENT | 
| Chris@77 | 647 	std::cerr << "Document::addLayerToView: Layer (\"" | 
| Chris@77 | 648                   << layer->objectName().toStdString() | 
| Chris@77 | 649                   << "\") with no model being added to view: " | 
| Chris@77 | 650                   << "normally you want to set the model first" << std::endl; | 
| Chris@77 | 651 #endif | 
| Chris@45 | 652     } else { | 
| Chris@45 | 653 	if (model != m_mainModel && | 
| Chris@45 | 654 	    m_models.find(model) == m_models.end()) { | 
| Chris@45 | 655 	    std::cerr << "ERROR: Document::addLayerToView: Layer " << layer | 
| Chris@45 | 656 		      << " has unregistered model " << model | 
| Chris@45 | 657 		      << " -- register the layer's model before adding the layer!" << std::endl; | 
| Chris@45 | 658 	    return; | 
| Chris@45 | 659 	} | 
| Chris@45 | 660     } | 
| Chris@45 | 661 | 
| Chris@45 | 662     CommandHistory::getInstance()->addCommand | 
| Chris@45 | 663 	(new Document::AddLayerCommand(this, view, layer)); | 
| Chris@45 | 664 } | 
| Chris@45 | 665 | 
| Chris@45 | 666 void | 
| Chris@45 | 667 Document::removeLayerFromView(View *view, Layer *layer) | 
| Chris@45 | 668 { | 
| Chris@45 | 669     CommandHistory::getInstance()->addCommand | 
| Chris@45 | 670 	(new Document::RemoveLayerCommand(this, view, layer)); | 
| Chris@45 | 671 } | 
| Chris@45 | 672 | 
| Chris@45 | 673 void | 
| Chris@45 | 674 Document::addToLayerViewMap(Layer *layer, View *view) | 
| Chris@45 | 675 { | 
| Chris@45 | 676     bool firstView = (m_layerViewMap.find(layer) == m_layerViewMap.end() || | 
| Chris@45 | 677                       m_layerViewMap[layer].empty()); | 
| Chris@45 | 678 | 
| Chris@45 | 679     if (m_layerViewMap[layer].find(view) != | 
| Chris@45 | 680 	m_layerViewMap[layer].end()) { | 
| Chris@45 | 681 	std::cerr << "WARNING: Document::addToLayerViewMap:" | 
| Chris@45 | 682 		  << " Layer " << layer << " -> view " << view << " already in" | 
| Chris@45 | 683 		  << " layer view map -- internal inconsistency" << std::endl; | 
| Chris@45 | 684     } | 
| Chris@45 | 685 | 
| Chris@45 | 686     m_layerViewMap[layer].insert(view); | 
| Chris@45 | 687 | 
| Chris@45 | 688     if (firstView) emit layerInAView(layer, true); | 
| Chris@45 | 689 } | 
| Chris@45 | 690 | 
| Chris@45 | 691 void | 
| Chris@45 | 692 Document::removeFromLayerViewMap(Layer *layer, View *view) | 
| Chris@45 | 693 { | 
| Chris@45 | 694     if (m_layerViewMap[layer].find(view) == | 
| Chris@45 | 695 	m_layerViewMap[layer].end()) { | 
| Chris@45 | 696 	std::cerr << "WARNING: Document::removeFromLayerViewMap:" | 
| Chris@45 | 697 		  << " Layer " << layer << " -> view " << view << " not in" | 
| Chris@45 | 698 		  << " layer view map -- internal inconsistency" << std::endl; | 
| Chris@45 | 699     } | 
| Chris@45 | 700 | 
| Chris@45 | 701     m_layerViewMap[layer].erase(view); | 
| Chris@45 | 702 | 
| Chris@45 | 703     if (m_layerViewMap[layer].empty()) { | 
| Chris@45 | 704         m_layerViewMap.erase(layer); | 
| Chris@45 | 705         emit layerInAView(layer, false); | 
| Chris@45 | 706     } | 
| Chris@45 | 707 } | 
| Chris@45 | 708 | 
| Chris@45 | 709 QString | 
| Chris@45 | 710 Document::getUniqueLayerName(QString candidate) | 
| Chris@45 | 711 { | 
| Chris@45 | 712     for (int count = 1; ; ++count) { | 
| Chris@45 | 713 | 
| Chris@45 | 714         QString adjusted = | 
| Chris@45 | 715             (count > 1 ? QString("%1 <%2>").arg(candidate).arg(count) : | 
| Chris@45 | 716              candidate); | 
| Chris@45 | 717 | 
| Chris@45 | 718         bool duplicate = false; | 
| Chris@45 | 719 | 
| Chris@45 | 720         for (LayerSet::iterator i = m_layers.begin(); i != m_layers.end(); ++i) { | 
| Chris@45 | 721             if ((*i)->objectName() == adjusted) { | 
| Chris@45 | 722                 duplicate = true; | 
| Chris@45 | 723                 break; | 
| Chris@45 | 724             } | 
| Chris@45 | 725         } | 
| Chris@45 | 726 | 
| Chris@45 | 727         if (!duplicate) return adjusted; | 
| Chris@45 | 728     } | 
| Chris@45 | 729 } | 
| Chris@45 | 730 | 
| Chris@45 | 731 std::vector<Model *> | 
| Chris@72 | 732 Document::getTransformInputModels() | 
| Chris@45 | 733 { | 
| Chris@45 | 734     std::vector<Model *> models; | 
| Chris@45 | 735 | 
| Chris@45 | 736     if (!m_mainModel) return models; | 
| Chris@45 | 737 | 
| Chris@45 | 738     models.push_back(m_mainModel); | 
| Chris@45 | 739 | 
| Chris@45 | 740     //!!! This will pick up all models, including those that aren't visible... | 
| Chris@45 | 741 | 
| Chris@45 | 742     for (ModelMap::iterator i = m_models.begin(); i != m_models.end(); ++i) { | 
| Chris@45 | 743 | 
| Chris@45 | 744         Model *model = i->first; | 
| Chris@45 | 745         if (!model || model == m_mainModel) continue; | 
| Chris@45 | 746         DenseTimeValueModel *dtvm = dynamic_cast<DenseTimeValueModel *>(model); | 
| Chris@45 | 747 | 
| Chris@45 | 748         if (dtvm) { | 
| Chris@45 | 749             models.push_back(dtvm); | 
| Chris@45 | 750         } | 
| Chris@45 | 751     } | 
| Chris@45 | 752 | 
| Chris@45 | 753     return models; | 
| Chris@45 | 754 } | 
| Chris@45 | 755 | 
| Chris@50 | 756 bool | 
| Chris@77 | 757 Document::isKnownModel(const Model *model) const | 
| Chris@77 | 758 { | 
| Chris@77 | 759     if (model == m_mainModel) return true; | 
| Chris@77 | 760     return (m_models.find(const_cast<Model *>(model)) != m_models.end()); | 
| Chris@77 | 761 } | 
| Chris@77 | 762 | 
| Chris@90 | 763 TransformId | 
| Chris@90 | 764 Document::getAlignmentTransformName() | 
| Chris@90 | 765 { | 
| Chris@90 | 766     QSettings settings; | 
| Chris@90 | 767     settings.beginGroup("Alignment"); | 
| Chris@90 | 768     TransformId id = | 
| Chris@90 | 769         settings.value("transform-id", | 
| Chris@90 | 770                        "vamp:match-vamp-plugin:match:path").toString(); | 
| Chris@90 | 771     settings.endGroup(); | 
| Chris@90 | 772     return id; | 
| Chris@90 | 773 } | 
| Chris@90 | 774 | 
| Chris@77 | 775 bool | 
| Chris@51 | 776 Document::canAlign() | 
| Chris@50 | 777 { | 
| Chris@90 | 778     TransformId id = getAlignmentTransformName(); | 
| Chris@54 | 779     TransformFactory *factory = TransformFactory::getInstance(); | 
| Chris@54 | 780     return factory->haveTransform(id); | 
| Chris@50 | 781 } | 
| Chris@50 | 782 | 
| Chris@45 | 783 void | 
| Chris@45 | 784 Document::alignModel(Model *model) | 
| Chris@45 | 785 { | 
| Chris@86 | 786     if (!m_mainModel) return; | 
| Chris@45 | 787 | 
| Chris@45 | 788     RangeSummarisableTimeValueModel *rm = | 
| Chris@45 | 789         dynamic_cast<RangeSummarisableTimeValueModel *>(model); | 
| Chris@45 | 790     if (!rm) return; | 
| Chris@48 | 791 | 
| Chris@86 | 792     if (rm->getAlignmentReference() == m_mainModel) { | 
| Chris@86 | 793         std::cerr << "Document::alignModel: model " << rm << " is already aligned to main model " << m_mainModel << std::endl; | 
| Chris@86 | 794         return; | 
| Chris@86 | 795     } | 
| Chris@45 | 796 | 
| Chris@86 | 797     if (model == m_mainModel) { | 
| Chris@86 | 798         // The reference has an empty alignment to itself.  This makes | 
| Chris@86 | 799         // it possible to distinguish between the reference and any | 
| Chris@86 | 800         // unaligned model just by looking at the model itself, | 
| Chris@86 | 801         // without also knowing what the main model is | 
| Chris@86 | 802         std::cerr << "Document::alignModel(" << model << "): is main model, setting appropriately" << std::endl; | 
| Chris@86 | 803         rm->setAlignment(new AlignmentModel(model, model, 0, 0)); | 
| Chris@86 | 804         return; | 
| Chris@86 | 805     } | 
| Chris@86 | 806 | 
| Chris@45 | 807     // This involves creating three new models: | 
| Chris@45 | 808 | 
| Chris@45 | 809     // 1. an AggregateWaveModel to provide the mixdowns of the main | 
| Chris@45 | 810     // model and the new model in its two channels, as input to the | 
| Chris@45 | 811     // MATCH plugin | 
| Chris@45 | 812 | 
| Chris@45 | 813     // 2. a SparseTimeValueModel, which is the model automatically | 
| Chris@53 | 814     // created by FeatureExtractionPluginTransformer when running the | 
| Chris@45 | 815     // MATCH plugin (thus containing the alignment path) | 
| Chris@45 | 816 | 
| Chris@45 | 817     // 3. an AlignmentModel, which stores the path model and carries | 
| Chris@45 | 818     // out alignment lookups on it. | 
| Chris@45 | 819 | 
| Chris@45 | 820     // The first two of these are provided as arguments to the | 
| Chris@45 | 821     // constructor for the third, which takes responsibility for | 
| Chris@45 | 822     // deleting them.  The AlignmentModel, meanwhile, is passed to the | 
| Chris@45 | 823     // new model we are aligning, which also takes responsibility for | 
| Chris@45 | 824     // it.  We should not have to delete any of these new models here. | 
| Chris@45 | 825 | 
| Chris@45 | 826     AggregateWaveModel::ChannelSpecList components; | 
| Chris@45 | 827 | 
| Chris@45 | 828     components.push_back(AggregateWaveModel::ModelChannelSpec | 
| Chris@45 | 829                          (m_mainModel, -1)); | 
| Chris@45 | 830 | 
| Chris@45 | 831     components.push_back(AggregateWaveModel::ModelChannelSpec | 
| Chris@45 | 832                          (rm, -1)); | 
| Chris@45 | 833 | 
| Chris@45 | 834     Model *aggregate = new AggregateWaveModel(components); | 
| Chris@45 | 835 | 
| Chris@72 | 836     TransformId id = "vamp:match-vamp-plugin:match:path"; //!!! configure | 
| Chris@45 | 837 | 
| Chris@72 | 838     TransformFactory *tf = TransformFactory::getInstance(); | 
| Chris@45 | 839 | 
| Chris@72 | 840     Transform transform = tf->getDefaultTransformFor | 
| Chris@72 | 841         (id, aggregate->getSampleRate()); | 
| Chris@57 | 842 | 
| Chris@72 | 843     transform.setStepSize(transform.getBlockSize()/2); | 
| Chris@72 | 844     transform.setParameter("serialise", 1); | 
| Chris@64 | 845 | 
| Chris@81 | 846     std::cerr << "Document::alignModel: Alignment transform step size " << transform.getStepSize() << ", block size " << transform.getBlockSize() << std::endl; | 
| Chris@81 | 847 | 
| Chris@72 | 848     ModelTransformerFactory *mtf = ModelTransformerFactory::getInstance(); | 
| Chris@72 | 849 | 
| Chris@78 | 850     QString message; | 
| Chris@78 | 851     Model *transformOutput = mtf->transform(transform, aggregate, message); | 
| Chris@64 | 852 | 
| Chris@64 | 853     if (!transformOutput) { | 
| Chris@72 | 854         transform.setStepSize(0); | 
| Chris@78 | 855         transformOutput = mtf->transform(transform, aggregate, message); | 
| Chris@64 | 856     } | 
| Chris@45 | 857 | 
| Chris@45 | 858     SparseTimeValueModel *path = dynamic_cast<SparseTimeValueModel *> | 
| Chris@45 | 859         (transformOutput); | 
| Chris@45 | 860 | 
| Chris@45 | 861     if (!path) { | 
| Chris@45 | 862         std::cerr << "Document::alignModel: ERROR: Failed to create alignment path (no MATCH plugin?)" << std::endl; | 
| Chris@78 | 863         emit alignmentFailed(id, message); | 
| Chris@45 | 864         delete transformOutput; | 
| Chris@45 | 865         delete aggregate; | 
| Chris@45 | 866         return; | 
| Chris@45 | 867     } | 
| Chris@45 | 868 | 
| Chris@45 | 869     AlignmentModel *alignmentModel = new AlignmentModel | 
| Chris@45 | 870         (m_mainModel, model, aggregate, path); | 
| Chris@45 | 871 | 
| Chris@45 | 872     rm->setAlignment(alignmentModel); | 
| Chris@45 | 873 } | 
| Chris@45 | 874 | 
| Chris@45 | 875 void | 
| Chris@45 | 876 Document::alignModels() | 
| Chris@45 | 877 { | 
| Chris@45 | 878     for (ModelMap::iterator i = m_models.begin(); i != m_models.end(); ++i) { | 
| Chris@45 | 879         alignModel(i->first); | 
| Chris@45 | 880     } | 
| Chris@86 | 881     alignModel(m_mainModel); | 
| Chris@45 | 882 } | 
| Chris@45 | 883 | 
| Chris@45 | 884 Document::AddLayerCommand::AddLayerCommand(Document *d, | 
| Chris@45 | 885 					   View *view, | 
| Chris@45 | 886 					   Layer *layer) : | 
| Chris@45 | 887     m_d(d), | 
| Chris@45 | 888     m_view(view), | 
| Chris@45 | 889     m_layer(layer), | 
| Chris@45 | 890     m_name(qApp->translate("AddLayerCommand", "Add %1 Layer").arg(layer->objectName())), | 
| Chris@45 | 891     m_added(false) | 
| Chris@45 | 892 { | 
| Chris@45 | 893 } | 
| Chris@45 | 894 | 
| Chris@45 | 895 Document::AddLayerCommand::~AddLayerCommand() | 
| Chris@45 | 896 { | 
| Chris@77 | 897 #ifdef DEBUG_DOCUMENT | 
| Chris@77 | 898     std::cerr << "Document::AddLayerCommand::~AddLayerCommand" << std::endl; | 
| Chris@77 | 899 #endif | 
| Chris@45 | 900     if (!m_added) { | 
| Chris@45 | 901 	m_d->deleteLayer(m_layer); | 
| Chris@45 | 902     } | 
| Chris@45 | 903 } | 
| Chris@45 | 904 | 
| Chris@45 | 905 void | 
| Chris@45 | 906 Document::AddLayerCommand::execute() | 
| Chris@45 | 907 { | 
| Chris@45 | 908     for (int i = 0; i < m_view->getLayerCount(); ++i) { | 
| Chris@45 | 909 	if (m_view->getLayer(i) == m_layer) { | 
| Chris@45 | 910 	    // already there | 
| Chris@45 | 911 	    m_layer->setLayerDormant(m_view, false); | 
| Chris@45 | 912 	    m_added = true; | 
| Chris@45 | 913 	    return; | 
| Chris@45 | 914 	} | 
| Chris@45 | 915     } | 
| Chris@45 | 916 | 
| Chris@45 | 917     m_view->addLayer(m_layer); | 
| Chris@45 | 918     m_layer->setLayerDormant(m_view, false); | 
| Chris@45 | 919 | 
| Chris@45 | 920     m_d->addToLayerViewMap(m_layer, m_view); | 
| Chris@45 | 921     m_added = true; | 
| Chris@45 | 922 } | 
| Chris@45 | 923 | 
| Chris@45 | 924 void | 
| Chris@45 | 925 Document::AddLayerCommand::unexecute() | 
| Chris@45 | 926 { | 
| Chris@45 | 927     m_view->removeLayer(m_layer); | 
| Chris@45 | 928     m_layer->setLayerDormant(m_view, true); | 
| Chris@45 | 929 | 
| Chris@45 | 930     m_d->removeFromLayerViewMap(m_layer, m_view); | 
| Chris@45 | 931     m_added = false; | 
| Chris@45 | 932 } | 
| Chris@45 | 933 | 
| Chris@45 | 934 Document::RemoveLayerCommand::RemoveLayerCommand(Document *d, | 
| Chris@45 | 935 						 View *view, | 
| Chris@45 | 936 						 Layer *layer) : | 
| Chris@45 | 937     m_d(d), | 
| Chris@45 | 938     m_view(view), | 
| Chris@45 | 939     m_layer(layer), | 
| Chris@45 | 940     m_name(qApp->translate("RemoveLayerCommand", "Delete %1 Layer").arg(layer->objectName())), | 
| Chris@45 | 941     m_added(true) | 
| Chris@45 | 942 { | 
| Chris@45 | 943 } | 
| Chris@45 | 944 | 
| Chris@45 | 945 Document::RemoveLayerCommand::~RemoveLayerCommand() | 
| Chris@45 | 946 { | 
| Chris@77 | 947 #ifdef DEBUG_DOCUMENT | 
| Chris@77 | 948     std::cerr << "Document::RemoveLayerCommand::~RemoveLayerCommand" << std::endl; | 
| Chris@77 | 949 #endif | 
| Chris@45 | 950     if (!m_added) { | 
| Chris@45 | 951 	m_d->deleteLayer(m_layer); | 
| Chris@45 | 952     } | 
| Chris@45 | 953 } | 
| Chris@45 | 954 | 
| Chris@45 | 955 void | 
| Chris@45 | 956 Document::RemoveLayerCommand::execute() | 
| Chris@45 | 957 { | 
| Chris@45 | 958     bool have = false; | 
| Chris@45 | 959     for (int i = 0; i < m_view->getLayerCount(); ++i) { | 
| Chris@45 | 960 	if (m_view->getLayer(i) == m_layer) { | 
| Chris@45 | 961 	    have = true; | 
| Chris@45 | 962 	    break; | 
| Chris@45 | 963 	} | 
| Chris@45 | 964     } | 
| Chris@45 | 965 | 
| Chris@45 | 966     if (!have) { // not there! | 
| Chris@45 | 967 	m_layer->setLayerDormant(m_view, true); | 
| Chris@45 | 968 	m_added = false; | 
| Chris@45 | 969 	return; | 
| Chris@45 | 970     } | 
| Chris@45 | 971 | 
| Chris@45 | 972     m_view->removeLayer(m_layer); | 
| Chris@45 | 973     m_layer->setLayerDormant(m_view, true); | 
| Chris@45 | 974 | 
| Chris@45 | 975     m_d->removeFromLayerViewMap(m_layer, m_view); | 
| Chris@45 | 976     m_added = false; | 
| Chris@45 | 977 } | 
| Chris@45 | 978 | 
| Chris@45 | 979 void | 
| Chris@45 | 980 Document::RemoveLayerCommand::unexecute() | 
| Chris@45 | 981 { | 
| Chris@45 | 982     m_view->addLayer(m_layer); | 
| Chris@45 | 983     m_layer->setLayerDormant(m_view, false); | 
| Chris@45 | 984 | 
| Chris@45 | 985     m_d->addToLayerViewMap(m_layer, m_view); | 
| Chris@45 | 986     m_added = true; | 
| Chris@45 | 987 } | 
| Chris@45 | 988 | 
| Chris@45 | 989 void | 
| Chris@45 | 990 Document::toXml(QTextStream &out, QString indent, QString extraAttributes) const | 
| Chris@45 | 991 { | 
| Chris@45 | 992     out << indent + QString("<data%1%2>\n") | 
| Chris@45 | 993         .arg(extraAttributes == "" ? "" : " ").arg(extraAttributes); | 
| Chris@45 | 994 | 
| Chris@45 | 995     if (m_mainModel) { | 
| Chris@45 | 996 	m_mainModel->toXml(out, indent + "  ", "mainModel=\"true\""); | 
| Chris@45 | 997     } | 
| Chris@45 | 998 | 
| Chris@45 | 999     // Models that are not used in a layer that is in a view should | 
| Chris@45 | 1000     // not be written.  Get our list of required models first. | 
| Chris@45 | 1001 | 
| Chris@45 | 1002     std::set<const Model *> used; | 
| Chris@45 | 1003 | 
| Chris@45 | 1004     for (LayerViewMap::const_iterator i = m_layerViewMap.begin(); | 
| Chris@45 | 1005          i != m_layerViewMap.end(); ++i) { | 
| Chris@45 | 1006 | 
| Chris@45 | 1007         if (i->first && !i->second.empty() && i->first->getModel()) { | 
| Chris@45 | 1008             used.insert(i->first->getModel()); | 
| Chris@45 | 1009         } | 
| Chris@45 | 1010     } | 
| Chris@45 | 1011 | 
| Chris@45 | 1012     for (ModelMap::const_iterator i = m_models.begin(); | 
| Chris@45 | 1013 	 i != m_models.end(); ++i) { | 
| Chris@45 | 1014 | 
| Chris@45 | 1015         const Model *model = i->first; | 
| Chris@45 | 1016 	const ModelRecord &rec = i->second; | 
| Chris@45 | 1017 | 
| Chris@45 | 1018         if (used.find(model) == used.end()) continue; | 
| Chris@45 | 1019 | 
| Chris@45 | 1020         // We need an intelligent way to determine which models need | 
| Chris@45 | 1021         // to be streamed (i.e. have been edited, or are small) and | 
| Chris@45 | 1022         // which should not be (i.e. remain as generated by a | 
| Chris@45 | 1023         // transform, and are large). | 
| Chris@45 | 1024         // | 
| Chris@45 | 1025         // At the moment we can get away with deciding not to stream | 
| Chris@45 | 1026         // dense 3d models or writable wave file models, provided they | 
| Chris@45 | 1027         // were generated from a transform, because at the moment there | 
| Chris@45 | 1028         // is no way to edit those model types so it should be safe to | 
| Chris@45 | 1029         // regenerate them.  That won't always work in future though. | 
| Chris@45 | 1030         // It would be particularly nice to be able to ask the user, | 
| Chris@45 | 1031         // as well as making an intelligent guess. | 
| Chris@45 | 1032 | 
| Chris@45 | 1033         bool writeModel = true; | 
| Chris@45 | 1034         bool haveDerivation = false; | 
| Chris@45 | 1035 | 
| Chris@72 | 1036         if (rec.source && rec.transform.getIdentifier() != "") { | 
| Chris@45 | 1037             haveDerivation = true; | 
| Chris@45 | 1038         } | 
| Chris@45 | 1039 | 
| Chris@45 | 1040         if (haveDerivation) { | 
| Chris@45 | 1041             if (dynamic_cast<const WritableWaveFileModel *>(model)) { | 
| Chris@45 | 1042                 writeModel = false; | 
| Chris@45 | 1043             } else if (dynamic_cast<const DenseThreeDimensionalModel *>(model)) { | 
| Chris@45 | 1044                 writeModel = false; | 
| Chris@45 | 1045             } | 
| Chris@45 | 1046         } | 
| Chris@45 | 1047 | 
| Chris@45 | 1048         if (writeModel) { | 
| Chris@45 | 1049             i->first->toXml(out, indent + "  "); | 
| Chris@45 | 1050         } | 
| Chris@45 | 1051 | 
| Chris@45 | 1052 	if (haveDerivation) { | 
| Chris@72 | 1053             writeBackwardCompatibleDerivation(out, indent + "  ", | 
| Chris@72 | 1054                                               i->first, rec); | 
| Chris@45 | 1055 	} | 
| Chris@45 | 1056 | 
| Chris@45 | 1057         //!!! We should probably own the PlayParameterRepository | 
| Chris@45 | 1058         PlayParameters *playParameters = | 
| Chris@45 | 1059             PlayParameterRepository::getInstance()->getPlayParameters(i->first); | 
| Chris@45 | 1060         if (playParameters) { | 
| Chris@45 | 1061             playParameters->toXml | 
| Chris@45 | 1062                 (out, indent + "  ", | 
| Chris@45 | 1063                  QString("model=\"%1\"") | 
| Chris@45 | 1064                  .arg(XmlExportable::getObjectExportId(i->first))); | 
| Chris@45 | 1065         } | 
| Chris@45 | 1066     } | 
| Chris@45 | 1067 | 
| Chris@45 | 1068     for (LayerSet::const_iterator i = m_layers.begin(); | 
| Chris@45 | 1069 	 i != m_layers.end(); ++i) { | 
| Chris@45 | 1070 | 
| Chris@45 | 1071 	(*i)->toXml(out, indent + "  "); | 
| Chris@45 | 1072     } | 
| Chris@45 | 1073 | 
| Chris@45 | 1074     out << indent + "</data>\n"; | 
| Chris@45 | 1075 } | 
| Chris@45 | 1076 | 
| Chris@72 | 1077 void | 
| Chris@72 | 1078 Document::writeBackwardCompatibleDerivation(QTextStream &out, QString indent, | 
| Chris@72 | 1079                                             Model *targetModel, | 
| Chris@72 | 1080                                             const ModelRecord &rec) const | 
| Chris@72 | 1081 { | 
| Chris@72 | 1082     // There is a lot of redundancy in the XML we output here, because | 
| Chris@72 | 1083     // we want it to work with older SV session file reading code as | 
| Chris@72 | 1084     // well. | 
| Chris@72 | 1085     // | 
| Chris@72 | 1086     // Formerly, a transform was described using a derivation element | 
| Chris@72 | 1087     // which set out the source and target models, execution context | 
| Chris@72 | 1088     // (step size, input channel etc) and transform id, containing a | 
| Chris@72 | 1089     // plugin element which set out the transform parameters and so | 
| Chris@72 | 1090     // on.  (The plugin element came from a "configurationXml" string | 
| Chris@72 | 1091     // obtained from PluginXml.) | 
| Chris@72 | 1092     // | 
| Chris@72 | 1093     // This has been replaced by a derivation element setting out the | 
| Chris@72 | 1094     // source and target models and input channel, containing a | 
| Chris@72 | 1095     // transform element which sets out everything in the Transform. | 
| Chris@72 | 1096     // | 
| Chris@72 | 1097     // In order to retain compatibility with older SV code, however, | 
| Chris@72 | 1098     // we have to write out the same stuff into the derivation as | 
| Chris@72 | 1099     // before, and manufacture an appropriate plugin element as well | 
| Chris@72 | 1100     // as the transform element.  In order that newer code knows it's | 
| Chris@72 | 1101     // dealing with a newer format, we will also write an attribute | 
| Chris@72 | 1102     // 'type="transform"' in the derivation element. | 
| Chris@45 | 1103 | 
| Chris@72 | 1104     const Transform &transform = rec.transform; | 
| Chris@72 | 1105 | 
| Chris@72 | 1106     // Just for reference, this is what we would write if we didn't | 
| Chris@72 | 1107     // have to be backward compatible: | 
| Chris@72 | 1108     // | 
| Chris@72 | 1109     //    out << indent | 
| Chris@72 | 1110     //        << QString("<derivation type=\"transform\" source=\"%1\" " | 
| Chris@72 | 1111     //                   "model=\"%2\" channel=\"%3\">\n") | 
| Chris@72 | 1112     //        .arg(XmlExportable::getObjectExportId(rec.source)) | 
| Chris@72 | 1113     //        .arg(XmlExportable::getObjectExportId(targetModel)) | 
| Chris@72 | 1114     //        .arg(rec.channel); | 
| Chris@72 | 1115     // | 
| Chris@72 | 1116     //    transform.toXml(out, indent + "  "); | 
| Chris@72 | 1117     // | 
| Chris@72 | 1118     //    out << indent << "</derivation>\n"; | 
| Chris@72 | 1119     // | 
| Chris@72 | 1120     // Unfortunately, we can't just do that.  So we do this... | 
| Chris@72 | 1121 | 
| Chris@72 | 1122     QString extentsAttributes; | 
| Chris@72 | 1123     if (transform.getStartTime() != RealTime::zeroTime || | 
| Chris@72 | 1124         transform.getDuration() != RealTime::zeroTime) { | 
| Chris@72 | 1125         extentsAttributes = QString("startFrame=\"%1\" duration=\"%2\" ") | 
| Chris@72 | 1126             .arg(RealTime::realTime2Frame(transform.getStartTime(), | 
| Chris@72 | 1127                                           targetModel->getSampleRate())) | 
| Chris@72 | 1128             .arg(RealTime::realTime2Frame(transform.getDuration(), | 
| Chris@72 | 1129                                           targetModel->getSampleRate())); | 
| Chris@72 | 1130     } | 
| Chris@72 | 1131 | 
| Chris@72 | 1132     out << indent; | 
| Chris@72 | 1133     out << QString("<derivation type=\"transform\" source=\"%1\" " | 
| Chris@72 | 1134                    "model=\"%2\" channel=\"%3\" domain=\"%4\" " | 
| Chris@72 | 1135                    "stepSize=\"%5\" blockSize=\"%6\" %7windowType=\"%8\" " | 
| Chris@72 | 1136                    "transform=\"%9\">\n") | 
| Chris@72 | 1137         .arg(XmlExportable::getObjectExportId(rec.source)) | 
| Chris@72 | 1138         .arg(XmlExportable::getObjectExportId(targetModel)) | 
| Chris@72 | 1139         .arg(rec.channel) | 
| Chris@72 | 1140         .arg(TransformFactory::getInstance()->getTransformInputDomain | 
| Chris@72 | 1141              (transform.getIdentifier())) | 
| Chris@72 | 1142         .arg(transform.getStepSize()) | 
| Chris@72 | 1143         .arg(transform.getBlockSize()) | 
| Chris@72 | 1144         .arg(extentsAttributes) | 
| Chris@72 | 1145         .arg(int(transform.getWindowType())) | 
| Chris@72 | 1146         .arg(XmlExportable::encodeEntities(transform.getIdentifier())); | 
| Chris@72 | 1147 | 
| Chris@72 | 1148     transform.toXml(out, indent + "  "); | 
| Chris@72 | 1149 | 
| Chris@72 | 1150     out << indent << "  " | 
| Chris@72 | 1151         << TransformFactory::getInstance()->getPluginConfigurationXml(transform); | 
| Chris@72 | 1152 | 
| Chris@72 | 1153     out << indent << "</derivation>\n"; | 
| Chris@72 | 1154 } | 
| Chris@72 | 1155 |