annotate framework/Document.cpp @ 736:4b58b8f44be7

If a file that looks like audio can't be opened as audio, fail immediately - don't go trying to open .wav files or whatever as sessions or annotations. That only means the error shown to the user is less helpful.
author Chris Cannam
date Wed, 05 Feb 2020 10:45:03 +0000
parents b8bf2900a478
children 36772d79cf44
rev   line source
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@420 18 #include "Align.h"
Chris@420 19
Chris@45 20 #include "data/model/WaveFileModel.h"
Chris@45 21 #include "data/model/WritableWaveFileModel.h"
Chris@45 22 #include "data/model/DenseThreeDimensionalModel.h"
Chris@45 23 #include "data/model/DenseTimeValueModel.h"
Chris@588 24 #include "data/model/AggregateWaveModel.h"
gyorgyf@270 25
Chris@45 26 #include "layer/Layer.h"
Chris@105 27 #include "widgets/CommandHistory.h"
Chris@45 28 #include "base/Command.h"
Chris@45 29 #include "view/View.h"
Chris@45 30 #include "base/PlayParameterRepository.h"
Chris@45 31 #include "base/PlayParameters.h"
Chris@106 32 #include "transform/TransformFactory.h"
Chris@106 33 #include "transform/ModelTransformerFactory.h"
gyorgyf@270 34 #include "transform/FeatureExtractionModelTransformer.h"
Chris@45 35 #include <QApplication>
Chris@45 36 #include <QTextStream>
Chris@90 37 #include <QSettings>
Chris@45 38 #include <iostream>
Chris@212 39 #include <typeinfo>
Chris@45 40
Chris@45 41 #include "data/model/AlignmentModel.h"
Chris@423 42 #include "Align.h"
Chris@45 43
Chris@297 44 using std::vector;
Chris@297 45
Chris@679 46 #define DEBUG_DOCUMENT 1
Chris@77 47
Chris@45 48 //!!! still need to handle command history, documentRestored/documentModified
Chris@45 49
Chris@45 50 Document::Document() :
Chris@423 51 m_autoAlignment(false),
Chris@601 52 m_align(new Align()),
Chris@601 53 m_isIncomplete(false)
Chris@45 54 {
Chris@456 55 connect(ModelTransformerFactory::getInstance(),
Chris@456 56 SIGNAL(transformFailed(QString, QString)),
Chris@456 57 this,
Chris@456 58 SIGNAL(modelGenerationFailed(QString, QString)));
Chris@459 59
Chris@683 60 connect(m_align, SIGNAL(alignmentComplete(ModelId)),
Chris@683 61 this, SIGNAL(alignmentComplete(ModelId)));
Chris@45 62 }
Chris@45 63
Chris@45 64 Document::~Document()
Chris@45 65 {
Chris@45 66 //!!! Document should really own the command history. atm we
Chris@45 67 //still refer to it in various places that don't have access to
Chris@45 68 //the document, be nice to fix that
Chris@45 69
Chris@77 70 #ifdef DEBUG_DOCUMENT
Chris@660 71 SVDEBUG << "\n\nDocument::~Document: about to clear command history" << endl;
Chris@77 72 #endif
Chris@45 73 CommandHistory::getInstance()->clear();
Chris@45 74
Chris@77 75 #ifdef DEBUG_DOCUMENT
Chris@691 76 SVCERR << "Document::~Document: about to delete layers" << endl;
Chris@77 77 #endif
Chris@45 78 while (!m_layers.empty()) {
Chris@595 79 deleteLayer(*m_layers.begin(), true);
Chris@45 80 }
Chris@45 81
Chris@691 82 #ifdef DEBUG_DOCUMENT
Chris@691 83 SVCERR << "Document::~Document: about to release normal models" << endl;
Chris@691 84 #endif
Chris@683 85 for (auto mr: m_models) {
Chris@683 86 ModelById::release(mr.first);
Chris@683 87 }
Chris@691 88
Chris@691 89 #ifdef DEBUG_DOCUMENT
Chris@691 90 SVCERR << "Document::~Document: about to release aggregate models" << endl;
Chris@691 91 #endif
Chris@683 92 for (auto m: m_aggregateModels) {
Chris@683 93 ModelById::release(m);
Chris@45 94 }
Chris@45 95
Chris@691 96 #ifdef DEBUG_DOCUMENT
Chris@691 97 SVCERR << "Document::~Document: about to release alignment models" << endl;
Chris@691 98 #endif
Chris@691 99 for (auto m: m_alignmentModels) {
Chris@691 100 ModelById::release(m);
Chris@691 101 }
Chris@691 102
Chris@691 103 #ifdef DEBUG_DOCUMENT
Chris@691 104 SVCERR << "Document::~Document: about to release main model" << endl;
Chris@691 105 #endif
Chris@687 106 if (!m_mainModel.isNone()) {
Chris@687 107 ModelById::release(m_mainModel);
Chris@687 108 }
Chris@691 109
Chris@683 110 m_mainModel = {};
Chris@687 111 emit mainModelChanged({});
Chris@45 112 }
Chris@45 113
Chris@45 114 Layer *
Chris@45 115 Document::createLayer(LayerFactory::LayerType type)
Chris@45 116 {
Chris@45 117 Layer *newLayer = LayerFactory::getInstance()->createLayer(type);
Chris@636 118 if (!newLayer) return nullptr;
Chris@45 119
Chris@45 120 newLayer->setObjectName(getUniqueLayerName(newLayer->objectName()));
Chris@45 121
Chris@663 122 m_layers.push_back(newLayer);
Chris@52 123
Chris@77 124 #ifdef DEBUG_DOCUMENT
Chris@233 125 SVDEBUG << "Document::createLayer: Added layer of type " << type
Chris@229 126 << ", now have " << m_layers.size() << " layers" << endl;
Chris@77 127 #endif
Chris@52 128
Chris@45 129 emit layerAdded(newLayer);
Chris@45 130
Chris@45 131 return newLayer;
Chris@45 132 }
Chris@45 133
Chris@45 134 Layer *
Chris@45 135 Document::createMainModelLayer(LayerFactory::LayerType type)
Chris@45 136 {
Chris@45 137 Layer *newLayer = createLayer(type);
Chris@636 138 if (!newLayer) return nullptr;
Chris@45 139 setModel(newLayer, m_mainModel);
Chris@45 140 return newLayer;
Chris@45 141 }
Chris@45 142
Chris@45 143 Layer *
Chris@683 144 Document::createImportedLayer(ModelId modelId)
Chris@45 145 {
Chris@45 146 LayerFactory::LayerTypeSet types =
Chris@683 147 LayerFactory::getInstance()->getValidLayerTypes(modelId);
Chris@45 148
Chris@45 149 if (types.empty()) {
Chris@660 150 SVCERR << "WARNING: Document::importLayer: no valid display layer for model" << endl;
Chris@636 151 return nullptr;
Chris@45 152 }
Chris@45 153
Chris@45 154 //!!! for now, just use the first suitable layer type
Chris@45 155 LayerFactory::LayerType type = *types.begin();
Chris@45 156
Chris@45 157 Layer *newLayer = LayerFactory::getInstance()->createLayer(type);
Chris@636 158 if (!newLayer) return nullptr;
Chris@45 159
Chris@45 160 newLayer->setObjectName(getUniqueLayerName(newLayer->objectName()));
Chris@45 161
Chris@691 162 addNonDerivedModel(modelId);
Chris@683 163 setModel(newLayer, modelId);
Chris@45 164
Chris@45 165 //!!! and all channels
Chris@45 166 setChannel(newLayer, -1);
Chris@45 167
Chris@663 168 m_layers.push_back(newLayer);
Chris@52 169
Chris@77 170 #ifdef DEBUG_DOCUMENT
Chris@233 171 SVDEBUG << "Document::createImportedLayer: Added layer of type " << type
Chris@229 172 << ", now have " << m_layers.size() << " layers" << endl;
Chris@77 173 #endif
Chris@52 174
Chris@45 175 emit layerAdded(newLayer);
Chris@45 176 return newLayer;
Chris@45 177 }
Chris@45 178
Chris@45 179 Layer *
Chris@45 180 Document::createEmptyLayer(LayerFactory::LayerType type)
Chris@45 181 {
Chris@683 182 if (m_mainModel.isNone()) return nullptr;
Chris@61 183
Chris@683 184 auto newModel =
Chris@595 185 LayerFactory::getInstance()->createEmptyModel(type, m_mainModel);
Chris@636 186 if (!newModel) return nullptr;
Chris@683 187
Chris@45 188 Layer *newLayer = createLayer(type);
Chris@45 189 if (!newLayer) {
Chris@636 190 return nullptr;
Chris@45 191 }
Chris@45 192
Chris@687 193 auto newModelId = ModelById::add(newModel);
Chris@691 194 addNonDerivedModel(newModelId);
Chris@687 195 setModel(newLayer, newModelId);
Chris@45 196
Chris@45 197 return newLayer;
Chris@45 198 }
Chris@45 199
Chris@45 200 Layer *
Chris@45 201 Document::createDerivedLayer(LayerFactory::LayerType type,
Chris@595 202 TransformId transform)
Chris@45 203 {
Chris@45 204 Layer *newLayer = createLayer(type);
Chris@636 205 if (!newLayer) return nullptr;
Chris@45 206
Chris@45 207 newLayer->setObjectName(getUniqueLayerName
Chris@54 208 (TransformFactory::getInstance()->
Chris@54 209 getTransformFriendlyName(transform)));
Chris@45 210
Chris@45 211 return newLayer;
Chris@45 212 }
Chris@297 213
Chris@45 214 Layer *
Chris@72 215 Document::createDerivedLayer(const Transform &transform,
Chris@72 216 const ModelTransformer::Input &input)
Chris@45 217 {
Chris@297 218 Transforms transforms;
Chris@297 219 transforms.push_back(transform);
Chris@297 220 vector<Layer *> layers = createDerivedLayers(transforms, input);
Chris@636 221 if (layers.empty()) return nullptr;
Chris@297 222 else return layers[0];
Chris@297 223 }
Chris@297 224
Chris@297 225 vector<Layer *>
Chris@297 226 Document::createDerivedLayers(const Transforms &transforms,
Chris@297 227 const ModelTransformer::Input &input)
Chris@297 228 {
Chris@78 229 QString message;
Chris@683 230 vector<ModelId> newModels =
Chris@683 231 addDerivedModels(transforms, input, message, nullptr);
Chris@297 232
Chris@297 233 if (newModels.empty()) {
Chris@297 234 //!!! This identifier may be wrong!
Chris@297 235 emit modelGenerationFailed(transforms[0].getIdentifier(), message);
Chris@297 236 return vector<Layer *>();
Chris@78 237 } else if (message != "") {
Chris@297 238 //!!! This identifier may be wrong!
Chris@297 239 emit modelGenerationWarning(transforms[0].getIdentifier(), message);
Chris@45 240 }
Chris@45 241
Chris@329 242 QStringList names;
Chris@683 243 for (int i = 0; in_range_for(newModels, i); ++i) {
Chris@329 244 names.push_back(getUniqueLayerName
Chris@329 245 (TransformFactory::getInstance()->
Chris@329 246 getTransformFriendlyName
Chris@329 247 (transforms[i].getIdentifier())));
Chris@329 248 }
Chris@329 249
Chris@329 250 vector<Layer *> layers = createLayersForDerivedModels(newModels, names);
Chris@329 251 return layers;
Chris@329 252 }
Chris@329 253
Chris@329 254 class AdditionalModelConverter :
Chris@329 255 public ModelTransformerFactory::AdditionalModelHandler
Chris@329 256 {
Chris@329 257 public:
Chris@329 258 AdditionalModelConverter(Document *doc,
Chris@329 259 Document::LayerCreationHandler *handler) :
Chris@329 260 m_doc(doc),
Chris@329 261 m_handler(handler) {
Chris@329 262 }
Chris@329 263
Chris@633 264 ~AdditionalModelConverter() override { }
Chris@329 265
Chris@329 266 void
Chris@329 267 setPrimaryLayers(vector<Layer *> layers) {
Chris@329 268 m_primary = layers;
Chris@329 269 }
Chris@329 270
Chris@329 271 void
Chris@683 272 moreModelsAvailable(vector<ModelId> models) override {
Chris@660 273 SVDEBUG << "AdditionalModelConverter::moreModelsAvailable: " << models.size() << " model(s)" << endl;
Chris@329 274 // We can't automatically regenerate the additional models on
Chris@683 275 // reload - so they go in m_additionalModels instead of m_models
Chris@329 276 QStringList names;
Chris@683 277 foreach (ModelId modelId, models) {
Chris@683 278 m_doc->addAdditionalModel(modelId);
Chris@329 279 names.push_back(QString());
Chris@329 280 }
Chris@329 281 vector<Layer *> layers = m_doc->createLayersForDerivedModels
Chris@329 282 (models, names);
Chris@363 283 m_handler->layersCreated(this, m_primary, layers);
Chris@329 284 delete this;
Chris@329 285 }
Chris@329 286
Chris@329 287 void
Chris@633 288 noMoreModelsAvailable() override {
Chris@660 289 SVDEBUG << "AdditionalModelConverter::noMoreModelsAvailable" << endl;
Chris@363 290 m_handler->layersCreated(this, m_primary, vector<Layer *>());
Chris@329 291 delete this;
Chris@329 292 }
Chris@329 293
Chris@697 294 void cancel() {
Chris@697 295 foreach (Layer *layer, m_primary) {
Chris@697 296 m_doc->setModel(layer, {});
Chris@697 297 }
Chris@697 298 }
Chris@697 299
Chris@329 300 private:
Chris@329 301 Document *m_doc;
Chris@329 302 vector<Layer *> m_primary;
Chris@329 303 Document::LayerCreationHandler *m_handler; //!!! how to handle destruction of this?
Chris@329 304 };
Chris@329 305
Chris@363 306 Document::LayerCreationAsyncHandle
Chris@329 307 Document::createDerivedLayersAsync(const Transforms &transforms,
Chris@329 308 const ModelTransformer::Input &input,
Chris@329 309 LayerCreationHandler *handler)
Chris@329 310 {
Chris@329 311 QString message;
Chris@329 312
Chris@329 313 AdditionalModelConverter *amc = new AdditionalModelConverter(this, handler);
Chris@329 314
Chris@683 315 vector<ModelId> newModels = addDerivedModels
Chris@329 316 (transforms, input, message, amc);
Chris@329 317
Chris@329 318 QStringList names;
Chris@683 319 for (int i = 0; in_range_for(newModels, i); ++i) {
Chris@329 320 names.push_back(getUniqueLayerName
Chris@329 321 (TransformFactory::getInstance()->
Chris@329 322 getTransformFriendlyName
Chris@329 323 (transforms[i].getIdentifier())));
Chris@329 324 }
Chris@329 325
Chris@329 326 vector<Layer *> layers = createLayersForDerivedModels(newModels, names);
Chris@329 327 amc->setPrimaryLayers(layers);
Chris@329 328
Chris@329 329 if (newModels.empty()) {
Chris@329 330 //!!! This identifier may be wrong!
Chris@329 331 emit modelGenerationFailed(transforms[0].getIdentifier(), message);
Chris@363 332 //!!! what to do with amc?
Chris@329 333 } else if (message != "") {
Chris@329 334 //!!! This identifier may be wrong!
Chris@329 335 emit modelGenerationWarning(transforms[0].getIdentifier(), message);
Chris@363 336 //!!! what to do with amc?
Chris@329 337 }
Chris@363 338
Chris@363 339 return amc;
Chris@363 340 }
Chris@363 341
Chris@697 342 void
Chris@697 343 Document::cancelAsyncLayerCreation(Document::LayerCreationAsyncHandle h)
Chris@697 344 {
Chris@697 345 AdditionalModelConverter *conv = static_cast<AdditionalModelConverter *>(h);
Chris@697 346 conv->cancel();
Chris@697 347 }
Chris@697 348
Chris@329 349 vector<Layer *>
Chris@683 350 Document::createLayersForDerivedModels(vector<ModelId> newModels,
Chris@329 351 QStringList names)
Chris@329 352 {
Chris@297 353 vector<Layer *> layers;
Chris@329 354
Chris@683 355 for (int i = 0; in_range_for(newModels, i); ++i) {
Chris@297 356
Chris@683 357 ModelId newModelId = newModels[i];
Chris@297 358
Chris@297 359 LayerFactory::LayerTypeSet types =
Chris@683 360 LayerFactory::getInstance()->getValidLayerTypes(newModelId);
Chris@297 361
Chris@297 362 if (types.empty()) {
Chris@660 363 SVCERR << "WARNING: Document::createLayerForTransformer: no valid display layer for output of transform " << names[i] << endl;
Chris@695 364 releaseModel(newModelId);
Chris@297 365 return vector<Layer *>();
Chris@297 366 }
Chris@297 367
Chris@297 368 //!!! for now, just use the first suitable layer type
Chris@297 369
Chris@297 370 Layer *newLayer = createLayer(*types.begin());
Chris@683 371 setModel(newLayer, newModelId);
Chris@297 372
Chris@297 373 //!!! We need to clone the model when adding the layer, so that it
Chris@297 374 //can be edited without affecting other layers that are based on
Chris@297 375 //the same model. Unfortunately we can't just clone it now,
Chris@297 376 //because it probably hasn't been completed yet -- the transform
Chris@297 377 //runs in the background. Maybe the transform has to handle
Chris@297 378 //cloning and cacheing models itself.
Chris@297 379 //
Chris@297 380 // Once we do clone models here, of course, we'll have to avoid
Chris@297 381 // leaking them too.
Chris@297 382 //
Chris@297 383 // We want the user to be able to add a model to a second layer
Chris@297 384 // _while it's still being calculated in the first_ and have it
Chris@297 385 // work quickly. That means we need to put the same physical
Chris@297 386 // model pointer in both layers, so they can't actually be cloned.
Chris@297 387
Chris@297 388 if (newLayer) {
Chris@329 389 newLayer->setObjectName(names[i]);
Chris@297 390 }
Chris@297 391
Chris@297 392 emit layerAdded(newLayer);
Chris@297 393 layers.push_back(newLayer);
Chris@45 394 }
Chris@45 395
Chris@297 396 return layers;
Chris@45 397 }
Chris@45 398
Chris@45 399 void
Chris@683 400 Document::setMainModel(ModelId modelId)
Chris@45 401 {
Chris@683 402 ModelId oldMainModel = m_mainModel;
Chris@683 403 m_mainModel = modelId;
Chris@160 404
Chris@45 405 emit modelAdded(m_mainModel);
Chris@683 406
Chris@683 407 if (auto model = ModelById::get(modelId)) {
Chris@160 408 emit activity(tr("Set main model to %1").arg(model->objectName()));
Chris@160 409 } else {
Chris@160 410 emit activity(tr("Clear main model"));
Chris@160 411 }
Chris@45 412
Chris@45 413 std::vector<Layer *> obsoleteLayers;
Chris@53 414 std::set<QString> failedTransformers;
Chris@45 415
Chris@45 416 // We need to ensure that no layer is left using oldMainModel or
Chris@45 417 // any of the old derived models as its model. Either replace the
Chris@45 418 // model, or delete the layer for each layer that is currently
Chris@45 419 // using one of these. Carry out this replacement before we
Chris@45 420 // delete any of the models.
Chris@45 421
Chris@77 422 #ifdef DEBUG_DOCUMENT
Chris@660 423 SVDEBUG << "Document::setMainModel: Have "
Chris@293 424 << m_layers.size() << " layers" << endl;
Chris@661 425 SVDEBUG << "Models now: ";
Chris@661 426 for (const auto &r: m_models) {
Chris@683 427 SVDEBUG << r.first << " ";
Chris@664 428 }
Chris@660 429 SVDEBUG << endl;
Chris@660 430 SVDEBUG << "Old main model: " << oldMainModel << endl;
Chris@77 431 #endif
Chris@52 432
Chris@663 433 for (Layer *layer: m_layers) {
Chris@45 434
Chris@683 435 ModelId modelId = layer->getModel();
Chris@45 436
Chris@77 437 #ifdef DEBUG_DOCUMENT
Chris@660 438 SVDEBUG << "Document::setMainModel: inspecting model "
Chris@683 439 << modelId << " in layer " << layer->objectName() << endl;
Chris@77 440 #endif
Chris@45 441
Chris@683 442 if (modelId == oldMainModel) {
Chris@77 443 #ifdef DEBUG_DOCUMENT
Chris@660 444 SVDEBUG << "... it uses the old main model, replacing" << endl;
Chris@77 445 #endif
Chris@595 446 LayerFactory::getInstance()->setModel(layer, m_mainModel);
Chris@595 447 continue;
Chris@595 448 }
Chris@45 449
Chris@683 450 if (modelId.isNone()) {
Chris@660 451 SVCERR << "WARNING: Document::setMainModel: Null model in layer "
Chris@660 452 << layer << endl;
Chris@595 453 // get rid of this hideous degenerate
Chris@595 454 obsoleteLayers.push_back(layer);
Chris@595 455 continue;
Chris@595 456 }
Chris@137 457
Chris@683 458 if (m_models.find(modelId) == m_models.end()) {
Chris@661 459 SVCERR << "WARNING: Document::setMainModel: Unknown model "
Chris@683 460 << modelId << " in layer " << layer << endl;
Chris@595 461 // and this one
Chris@595 462 obsoleteLayers.push_back(layer);
Chris@595 463 continue;
Chris@595 464 }
Chris@661 465
Chris@683 466 ModelRecord record = m_models[modelId];
Chris@661 467
Chris@683 468 if (!record.source.isNone() && (record.source == oldMainModel)) {
Chris@45 469
Chris@77 470 #ifdef DEBUG_DOCUMENT
Chris@660 471 SVDEBUG << "... it uses a model derived from the old main model, regenerating" << endl;
Chris@77 472 #endif
Chris@45 473
Chris@595 474 // This model was derived from the previous main
Chris@595 475 // model: regenerate it.
Chris@595 476
Chris@661 477 const Transform &transform = record.transform;
Chris@72 478 QString transformId = transform.getIdentifier();
Chris@595 479
Chris@72 480 //!!! We have a problem here if the number of channels in
Chris@72 481 //the main model has changed.
Chris@72 482
Chris@78 483 QString message;
Chris@683 484 ModelId replacementModel =
Chris@45 485 addDerivedModel(transform,
Chris@72 486 ModelTransformer::Input
Chris@661 487 (m_mainModel, record.channel),
Chris@78 488 message);
Chris@595 489
Chris@683 490 if (replacementModel.isNone()) {
Chris@660 491 SVCERR << "WARNING: Document::setMainModel: Failed to regenerate model for transform \""
Chris@660 492 << transformId << "\"" << " in layer " << layer << endl;
Chris@72 493 if (failedTransformers.find(transformId)
Chris@72 494 == failedTransformers.end()) {
Chris@45 495 emit modelRegenerationFailed(layer->objectName(),
Chris@78 496 transformId,
Chris@78 497 message);
Chris@72 498 failedTransformers.insert(transformId);
Chris@45 499 }
Chris@595 500 obsoleteLayers.push_back(layer);
Chris@595 501 } else {
Chris@78 502 if (message != "") {
Chris@78 503 emit modelRegenerationWarning(layer->objectName(),
Chris@78 504 transformId,
Chris@78 505 message);
Chris@78 506 }
Chris@77 507 #ifdef DEBUG_DOCUMENT
Chris@683 508 SVDEBUG << "Replacing model " << modelId << ") with model "
Chris@683 509 << replacementModel << ") in layer "
Chris@660 510 << layer << " (name " << layer->objectName() << ")"
Chris@660 511 << endl;
Chris@366 512
Chris@683 513 auto rm = ModelById::getAs<RangeSummarisableTimeValueModel>(replacementModel);
Chris@45 514 if (rm) {
Chris@660 515 SVDEBUG << "new model has " << rm->getChannelCount() << " channels " << endl;
Chris@45 516 } else {
Chris@660 517 SVDEBUG << "new model " << replacementModel << " is not a RangeSummarisableTimeValueModel!" << endl;
Chris@45 518 }
Chris@77 519 #endif
Chris@595 520 setModel(layer, replacementModel);
Chris@595 521 }
Chris@595 522 }
Chris@45 523 }
Chris@45 524
Chris@45 525 for (size_t k = 0; k < obsoleteLayers.size(); ++k) {
Chris@595 526 deleteLayer(obsoleteLayers[k], true);
Chris@45 527 }
Chris@45 528
Chris@683 529 std::set<ModelId> additionalModels;
Chris@661 530 for (const auto &rec : m_models) {
Chris@683 531 if (rec.second.additional) {
Chris@683 532 additionalModels.insert(rec.first);
Chris@329 533 }
Chris@329 534 }
Chris@683 535 for (ModelId a: additionalModels) {
Chris@683 536 m_models.erase(a);
Chris@661 537 }
Chris@329 538
Chris@661 539 for (const auto &rec : m_models) {
Chris@86 540
Chris@683 541 auto m = ModelById::get(rec.first);
Chris@683 542 if (!m) continue;
Chris@137 543
Chris@137 544 #ifdef DEBUG_DOCUMENT
Chris@683 545 SVDEBUG << "considering alignment for model " << rec.first << endl;
Chris@137 546 #endif
Chris@137 547
Chris@86 548 if (m_autoAlignment) {
Chris@86 549
Chris@683 550 alignModel(rec.first);
Chris@86 551
Chris@683 552 } else if (!oldMainModel.isNone() &&
Chris@137 553 (m->getAlignmentReference() == oldMainModel)) {
Chris@86 554
Chris@683 555 alignModel(rec.first);
Chris@48 556 }
Chris@48 557 }
Chris@48 558
Chris@86 559 if (m_autoAlignment) {
Chris@387 560 SVDEBUG << "Document::setMainModel: auto-alignment is on, aligning model if possible" << endl;
Chris@86 561 alignModel(m_mainModel);
Chris@667 562 } else {
Chris@667 563 SVDEBUG << "Document::setMainModel: auto-alignment is off" << endl;
Chris@86 564 }
Chris@86 565
Chris@45 566 emit mainModelChanged(m_mainModel);
Chris@45 567
Chris@687 568 if (!oldMainModel.isNone()) {
Chris@687 569
Chris@687 570 // Remove the playable explicitly - the main model's dtor will
Chris@687 571 // do this, but just in case something is still hanging onto a
Chris@687 572 // shared_ptr to the old main model so it doesn't get deleted
Chris@687 573 PlayParameterRepository::getInstance()->removePlayable
Chris@687 574 (oldMainModel.untyped);
Chris@687 575
Chris@687 576 ModelById::release(oldMainModel);
Chris@687 577 }
Chris@45 578 }
Chris@45 579
Chris@45 580 void
Chris@329 581 Document::addAlreadyDerivedModel(const Transform &transform,
Chris@329 582 const ModelTransformer::Input &input,
Chris@683 583 ModelId outputModelToAdd)
Chris@45 584 {
Chris@683 585 if (m_models.find(outputModelToAdd) != m_models.end()) {
Chris@661 586 SVCERR << "WARNING: Document::addAlreadyDerivedModel: Model already added"
Chris@683 587 << endl;
Chris@595 588 return;
Chris@45 589 }
Chris@683 590
Chris@77 591 #ifdef DEBUG_DOCUMENT
Chris@683 592 SVDEBUG << "Document::addAlreadyDerivedModel: source is " << input.getModel() << endl;
Chris@77 593 #endif
Chris@45 594
Chris@45 595 ModelRecord rec;
Chris@72 596 rec.source = input.getModel();
Chris@72 597 rec.channel = input.getChannel();
Chris@45 598 rec.transform = transform;
Chris@329 599 rec.additional = false;
Chris@45 600
Chris@683 601 if (auto m = ModelById::get(outputModelToAdd)) {
Chris@683 602 m->setSourceModel(input.getModel());
Chris@683 603 }
Chris@45 604
Chris@683 605 m_models[outputModelToAdd] = rec;
Chris@45 606
Chris@137 607 #ifdef DEBUG_DOCUMENT
Chris@661 608 SVDEBUG << "Document::addAlreadyDerivedModel: Added model " << outputModelToAdd << endl;
Chris@661 609 SVDEBUG << "Models now: ";
Chris@661 610 for (const auto &rec : m_models) {
Chris@683 611 SVDEBUG << rec.first << " ";
Chris@137 612 }
Chris@660 613 SVDEBUG << endl;
Chris@137 614 #endif
Chris@137 615
Chris@45 616 emit modelAdded(outputModelToAdd);
Chris@45 617 }
Chris@45 618
Chris@45 619 void
Chris@691 620 Document::addNonDerivedModel(ModelId modelId)
Chris@45 621 {
Chris@691 622 if (ModelById::isa<AggregateWaveModel>(modelId)) {
Chris@691 623 #ifdef DEBUG_DOCUMENT
Chris@691 624 SVCERR << "Document::addNonDerivedModel: Model " << modelId << " is an aggregate model, adding it to aggregates" << endl;
Chris@691 625 #endif
Chris@691 626 m_aggregateModels.insert(modelId);
Chris@691 627 return;
Chris@691 628 }
Chris@691 629 if (ModelById::isa<AlignmentModel>(modelId)) {
Chris@691 630 #ifdef DEBUG_DOCUMENT
Chris@691 631 SVCERR << "Document::addNonDerivedModel: Model " << modelId << " is an alignment model, adding it to alignments" << endl;
Chris@691 632 #endif
Chris@691 633 m_alignmentModels.insert(modelId);
Chris@691 634 return;
Chris@691 635 }
Chris@691 636
Chris@683 637 if (m_models.find(modelId) != m_models.end()) {
Chris@691 638 SVCERR << "WARNING: Document::addNonDerivedModel: Model already added"
Chris@683 639 << endl;
Chris@595 640 return;
Chris@45 641 }
Chris@45 642
Chris@45 643 ModelRecord rec;
Chris@683 644 rec.source = {};
Chris@408 645 rec.channel = 0;
Chris@329 646 rec.additional = false;
Chris@45 647
Chris@683 648 m_models[modelId] = rec;
Chris@45 649
Chris@137 650 #ifdef DEBUG_DOCUMENT
Chris@691 651 SVCERR << "Document::addNonDerivedModel: Added model " << modelId << endl;
Chris@691 652 SVCERR << "Models now: ";
Chris@661 653 for (const auto &rec : m_models) {
Chris@691 654 SVCERR << rec.first << " ";
Chris@137 655 }
Chris@691 656 SVCERR << endl;
Chris@137 657 #endif
Chris@137 658
Chris@387 659 if (m_autoAlignment) {
Chris@691 660 SVDEBUG << "Document::addNonDerivedModel: auto-alignment is on, aligning model if possible" << endl;
Chris@683 661 alignModel(modelId);
Chris@387 662 } else {
Chris@691 663 SVDEBUG << "Document(" << this << "): addNonDerivedModel: auto-alignment is off" << endl;
Chris@387 664 }
Chris@47 665
Chris@683 666 emit modelAdded(modelId);
Chris@45 667 }
Chris@45 668
Chris@329 669 void
Chris@683 670 Document::addAdditionalModel(ModelId modelId)
Chris@329 671 {
Chris@683 672 if (m_models.find(modelId) != m_models.end()) {
Chris@661 673 SVCERR << "WARNING: Document::addAdditionalModel: Model already added"
Chris@683 674 << endl;
Chris@595 675 return;
Chris@329 676 }
Chris@329 677
Chris@329 678 ModelRecord rec;
Chris@683 679 rec.source = {};
Chris@408 680 rec.channel = 0;
Chris@329 681 rec.additional = true;
Chris@329 682
Chris@683 683 m_models[modelId] = rec;
Chris@329 684
Chris@329 685 #ifdef DEBUG_DOCUMENT
Chris@683 686 SVDEBUG << "Document::addAdditionalModel: Added model " << modelId << endl;
Chris@661 687 SVDEBUG << "Models now: ";
Chris@661 688 for (const auto &rec : m_models) {
Chris@683 689 SVDEBUG << rec.first << " ";
Chris@329 690 }
Chris@660 691 SVDEBUG << endl;
Chris@329 692 #endif
Chris@329 693
Chris@691 694 if (m_autoAlignment &&
Chris@691 695 ModelById::isa<RangeSummarisableTimeValueModel>(modelId)) {
Chris@691 696 SVDEBUG << "Document::addAdditionalModel: auto-alignment is on and model is an alignable type, aligning it if possible" << endl;
Chris@683 697 alignModel(modelId);
Chris@387 698 }
Chris@329 699
Chris@683 700 emit modelAdded(modelId);
Chris@329 701 }
Chris@329 702
Chris@683 703 ModelId
Chris@72 704 Document::addDerivedModel(const Transform &transform,
Chris@78 705 const ModelTransformer::Input &input,
Chris@296 706 QString &message)
Chris@45 707 {
Chris@661 708 for (auto &rec : m_models) {
Chris@683 709 if (rec.second.transform == transform &&
Chris@683 710 rec.second.source == input.getModel() &&
Chris@683 711 rec.second.channel == input.getChannel()) {
Chris@661 712 SVDEBUG << "derived model taken from map " << endl;
Chris@683 713 return rec.first;
Chris@297 714 }
Chris@45 715 }
Chris@45 716
Chris@297 717 Transforms tt;
Chris@297 718 tt.push_back(transform);
Chris@683 719 vector<ModelId> mm = addDerivedModels(tt, input, message, nullptr);
Chris@683 720 if (mm.empty()) return {};
Chris@297 721 else return mm[0];
Chris@297 722 }
Chris@45 723
Chris@683 724 vector<ModelId>
Chris@297 725 Document::addDerivedModels(const Transforms &transforms,
Chris@297 726 const ModelTransformer::Input &input,
Chris@329 727 QString &message,
Chris@329 728 AdditionalModelConverter *amc)
Chris@297 729 {
Chris@683 730 vector<ModelId> mm =
Chris@297 731 ModelTransformerFactory::getInstance()->transformMultiple
Chris@329 732 (transforms, input, message, amc);
Chris@83 733
Chris@683 734 for (int j = 0; in_range_for(mm, j); ++j) {
Chris@83 735
Chris@683 736 ModelId modelId = mm[j];
Chris@683 737 Transform applied = transforms[j];
Chris@683 738
Chris@683 739 if (modelId.isNone()) {
Chris@683 740 SVCERR << "WARNING: Document::addDerivedModel: no output model for transform " << applied.getIdentifier() << endl;
Chris@683 741 continue;
Chris@683 742 }
Chris@297 743
Chris@297 744 // The transform we actually used was presumably identical to
Chris@297 745 // the one asked for, except that the version of the plugin
Chris@297 746 // may differ. It's possible that the returned message
Chris@297 747 // contains a warning about this; that doesn't concern us
Chris@297 748 // here, but we do need to ensure that the transform we
Chris@297 749 // remember is correct for what was actually applied, with the
Chris@297 750 // current plugin version.
Chris@297 751
Chris@536 752 //!!! would be nice to short-circuit this -- the version is
Chris@536 753 //!!! static data, shouldn't have to construct a plugin for it
Chris@536 754 //!!! (which may be expensive in Piper-world)
Chris@297 755 applied.setPluginVersion
Chris@297 756 (TransformFactory::getInstance()->
Chris@297 757 getDefaultTransformFor(applied.getIdentifier(),
Chris@436 758 applied.getSampleRate())
Chris@297 759 .getPluginVersion());
Chris@297 760
Chris@683 761 addAlreadyDerivedModel(applied, input, modelId);
Chris@45 762 }
Chris@595 763
Chris@297 764 return mm;
Chris@45 765 }
Chris@45 766
Chris@45 767 void
Chris@690 768 Document::releaseModel(ModelId modelId)
Chris@45 769 {
Chris@690 770 // This is called when a layer has been deleted or has replaced
Chris@690 771 // its model, in order to reclaim storage for the old model. It
Chris@690 772 // could be a no-op without making any functional difference, as
Chris@690 773 // all the models stored in the ById pool are released when the
Chris@690 774 // document is deleted. But models can sometimes be large, so if
Chris@690 775 // we know no other layer is using one, we should release it. If
Chris@690 776 // we happen to release one that is being used, the ModelById
Chris@690 777 // borrowed-pointer mechanism will at least prevent memory errors,
Chris@690 778 // although the other code will have to stop whatever it's doing.
Chris@683 779
Chris@719 780 // "warning: expression with side effects will be evaluated despite
Chris@719 781 // being used as an operand to 'typeid'"
Chris@719 782 #ifdef __clang__
Chris@719 783 #pragma clang diagnostic ignored "-Wpotentially-evaluated-expression"
Chris@719 784 #endif
Chris@719 785
Chris@691 786 if (auto model = ModelById::get(modelId)) {
Chris@691 787 SVCERR << "Document::releaseModel(" << modelId << "), name "
Chris@691 788 << model->objectName() << ", type "
Chris@691 789 << typeid(*model.get()).name() << endl;
Chris@691 790 } else {
Chris@691 791 SVCERR << "Document::releaseModel(" << modelId << ")" << endl;
Chris@691 792 }
Chris@683 793
Chris@683 794 if (modelId.isNone()) {
Chris@595 795 return;
Chris@45 796 }
Chris@683 797
Chris@665 798 #ifdef DEBUG_DOCUMENT
Chris@690 799 SVCERR << "Document::releaseModel(" << modelId << ")" << endl;
Chris@665 800 #endif
Chris@690 801
Chris@683 802 if (modelId == m_mainModel) {
Chris@690 803 #ifdef DEBUG_DOCUMENT
Chris@690 804 SVCERR << "Document::releaseModel: It's the main model, ignoring"
Chris@690 805 << endl;
Chris@690 806 #endif
Chris@595 807 return;
Chris@45 808 }
Chris@45 809
Chris@690 810 if (m_models.find(modelId) == m_models.end()) {
Chris@691 811 // No point in releasing aggregate and alignment models,
Chris@690 812 // they're not large
Chris@664 813 #ifdef DEBUG_DOCUMENT
Chris@690 814 SVCERR << "Document::releaseModel: It's not a regular layer model, ignoring" << endl;
Chris@664 815 #endif
Chris@690 816 return;
Chris@45 817 }
Chris@45 818
Chris@690 819 for (auto layer: m_layers) {
Chris@690 820 if (layer->getModel() == modelId) {
Chris@137 821 #ifdef DEBUG_DOCUMENT
Chris@692 822 SVCERR << "Document::releaseModel: It's still in use in at least one layer (e.g. " << layer << ", \"" << layer->getLayerPresentationName() << "\"), ignoring" << endl;
Chris@137 823 #endif
Chris@690 824 return;
Chris@676 825 }
Chris@45 826 }
Chris@683 827
Chris@690 828 #ifdef DEBUG_DOCUMENT
Chris@690 829 SVCERR << "Document::releaseModel: Seems to be OK to release this one"
Chris@690 830 << endl;
Chris@683 831 #endif
Chris@690 832
Chris@690 833 int sourceCount = 0;
Chris@690 834
Chris@690 835 for (auto &m: m_models) {
Chris@690 836 if (m.second.source == modelId) {
Chris@690 837 ++sourceCount;
Chris@690 838 m.second.source = {};
Chris@690 839 }
Chris@690 840 }
Chris@690 841
Chris@690 842 if (sourceCount > 0) {
Chris@690 843 SVCERR << "Document::releaseModel: Request to release model "
Chris@690 844 << modelId << " even though it was source for "
Chris@690 845 << sourceCount << " other derived model(s) -- have cleared "
Chris@690 846 << "their source fields" << endl;
Chris@690 847 }
Chris@690 848
Chris@690 849 m_models.erase(modelId);
Chris@690 850 ModelById::release(modelId);
Chris@45 851 }
Chris@45 852
Chris@45 853 void
Chris@45 854 Document::deleteLayer(Layer *layer, bool force)
Chris@45 855 {
Chris@45 856 if (m_layerViewMap.find(layer) != m_layerViewMap.end() &&
Chris@595 857 m_layerViewMap[layer].size() > 0) {
Chris@45 858
Chris@595 859 if (force) {
Chris@45 860
Chris@672 861 SVDEBUG << "NOTE: Document::deleteLayer: Layer "
Chris@672 862 << layer << " [" << layer->objectName() << "]"
Chris@672 863 << " is still used in " << m_layerViewMap[layer].size()
Chris@672 864 << " views. Force flag set, so removing from them" << endl;
Chris@672 865
Chris@595 866 for (std::set<View *>::iterator j = m_layerViewMap[layer].begin();
Chris@595 867 j != m_layerViewMap[layer].end(); ++j) {
Chris@595 868 // don't use removeLayerFromView, as it issues a command
Chris@595 869 layer->setLayerDormant(*j, true);
Chris@595 870 (*j)->removeLayer(layer);
Chris@595 871 }
Chris@595 872
Chris@595 873 m_layerViewMap.erase(layer);
Chris@45 874
Chris@595 875 } else {
Chris@672 876
Chris@672 877 SVCERR << "WARNING: Document::deleteLayer: Layer "
Chris@672 878 << layer << " [" << layer->objectName() << "]"
Chris@672 879 << " is still used in " << m_layerViewMap[layer].size()
Chris@672 880 << " views! Force flag is not set, so not deleting" << endl;
Chris@672 881
Chris@595 882 return;
Chris@595 883 }
Chris@45 884 }
Chris@45 885
Chris@663 886 bool found = false;
Chris@663 887 for (auto itr = m_layers.begin(); itr != m_layers.end(); ++itr) {
Chris@663 888 if (*itr == layer) {
Chris@663 889 found = true;
Chris@663 890 m_layers.erase(itr);
Chris@663 891 break;
Chris@663 892 }
Chris@663 893 }
Chris@663 894 if (!found) {
Chris@595 895 SVDEBUG << "Document::deleteLayer: Layer "
Chris@665 896 << layer << " (typeid " << typeid(layer).name() <<
Chris@212 897 ") does not exist, or has already been deleted "
Chris@595 898 << "(this may not be as serious as it sounds)" << endl;
Chris@595 899 return;
Chris@45 900 }
Chris@45 901
Chris@132 902 #ifdef DEBUG_DOCUMENT
Chris@665 903 SVDEBUG << "Document::deleteLayer: Removing (and about to release model), now have "
Chris@229 904 << m_layers.size() << " layers" << endl;
Chris@132 905 #endif
Chris@52 906
Chris@45 907 releaseModel(layer->getModel());
Chris@45 908 emit layerRemoved(layer);
Chris@45 909 emit layerAboutToBeDeleted(layer);
Chris@45 910 delete layer;
Chris@45 911 }
Chris@45 912
Chris@45 913 void
Chris@683 914 Document::setModel(Layer *layer, ModelId modelId)
Chris@45 915 {
Chris@683 916 if (!modelId.isNone() &&
Chris@683 917 modelId != m_mainModel &&
Chris@683 918 m_models.find(modelId) == m_models.end()) {
Chris@661 919 SVCERR << "ERROR: Document::setModel: Layer " << layer
Chris@683 920 << " (\"" << layer->objectName()
Chris@683 921 << "\") wants to use unregistered model " << modelId
Chris@683 922 << ": register the layer's model before setting it!"
Chris@683 923 << endl;
Chris@595 924 return;
Chris@45 925 }
Chris@45 926
Chris@683 927 ModelId previousModel = layer->getModel();
Chris@45 928
Chris@683 929 if (previousModel == modelId) {
Chris@233 930 SVDEBUG << "NOTE: Document::setModel: Layer " << layer << " (\""
Chris@683 931 << layer->objectName()
Chris@683 932 << "\") is already set to model "
Chris@683 933 << modelId << endl;
Chris@45 934 return;
Chris@45 935 }
Chris@691 936
Chris@683 937 if (!modelId.isNone() && !previousModel.isNone()) {
Chris@45 938 PlayParameterRepository::getInstance()->copyParameters
Chris@683 939 (previousModel.untyped, modelId.untyped);
Chris@45 940 }
Chris@45 941
Chris@683 942 LayerFactory::getInstance()->setModel(layer, modelId);
Chris@45 943
Chris@683 944 releaseModel(previousModel);
Chris@45 945 }
Chris@45 946
Chris@45 947 void
Chris@45 948 Document::setChannel(Layer *layer, int channel)
Chris@45 949 {
Chris@45 950 LayerFactory::getInstance()->setChannel(layer, channel);
Chris@45 951 }
Chris@45 952
Chris@45 953 void
Chris@45 954 Document::addLayerToView(View *view, Layer *layer)
Chris@45 955 {
Chris@683 956 ModelId modelId = layer->getModel();
Chris@683 957 if (modelId.isNone()) {
Chris@77 958 #ifdef DEBUG_DOCUMENT
Chris@595 959 SVDEBUG << "Document::addLayerToView: Layer (\""
Chris@660 960 << layer->objectName()
Chris@660 961 << "\") with no model being added to view: "
Chris@229 962 << "normally you want to set the model first" << endl;
Chris@77 963 #endif
Chris@45 964 } else {
Chris@683 965 if (modelId != m_mainModel &&
Chris@683 966 m_models.find(modelId) == m_models.end()) {
Chris@661 967 SVCERR << "ERROR: Document::addLayerToView: Layer " << layer
Chris@683 968 << " has unregistered model " << modelId
Chris@595 969 << " -- register the layer's model before adding the layer!" << endl;
Chris@595 970 return;
Chris@595 971 }
Chris@45 972 }
Chris@45 973
Chris@45 974 CommandHistory::getInstance()->addCommand
Chris@595 975 (new Document::AddLayerCommand(this, view, layer));
Chris@45 976 }
Chris@45 977
Chris@45 978 void
Chris@45 979 Document::removeLayerFromView(View *view, Layer *layer)
Chris@45 980 {
Chris@45 981 CommandHistory::getInstance()->addCommand
Chris@595 982 (new Document::RemoveLayerCommand(this, view, layer));
Chris@45 983 }
Chris@45 984
Chris@45 985 void
Chris@45 986 Document::addToLayerViewMap(Layer *layer, View *view)
Chris@45 987 {
Chris@45 988 bool firstView = (m_layerViewMap.find(layer) == m_layerViewMap.end() ||
Chris@45 989 m_layerViewMap[layer].empty());
Chris@45 990
Chris@45 991 if (m_layerViewMap[layer].find(view) !=
Chris@595 992 m_layerViewMap[layer].end()) {
Chris@660 993 SVCERR << "WARNING: Document::addToLayerViewMap:"
Chris@595 994 << " Layer " << layer << " -> view " << view << " already in"
Chris@595 995 << " layer view map -- internal inconsistency" << endl;
Chris@45 996 }
Chris@45 997
Chris@45 998 m_layerViewMap[layer].insert(view);
Chris@45 999
Chris@45 1000 if (firstView) emit layerInAView(layer, true);
Chris@45 1001 }
Chris@45 1002
Chris@45 1003 void
Chris@45 1004 Document::removeFromLayerViewMap(Layer *layer, View *view)
Chris@45 1005 {
Chris@45 1006 if (m_layerViewMap[layer].find(view) ==
Chris@595 1007 m_layerViewMap[layer].end()) {
Chris@660 1008 SVCERR << "WARNING: Document::removeFromLayerViewMap:"
Chris@595 1009 << " Layer " << layer << " -> view " << view << " not in"
Chris@595 1010 << " layer view map -- internal inconsistency" << endl;
Chris@45 1011 }
Chris@45 1012
Chris@45 1013 m_layerViewMap[layer].erase(view);
Chris@45 1014
Chris@45 1015 if (m_layerViewMap[layer].empty()) {
Chris@45 1016 m_layerViewMap.erase(layer);
Chris@45 1017 emit layerInAView(layer, false);
Chris@45 1018 }
Chris@45 1019 }
Chris@45 1020
Chris@45 1021 QString
Chris@45 1022 Document::getUniqueLayerName(QString candidate)
Chris@45 1023 {
Chris@45 1024 for (int count = 1; ; ++count) {
Chris@45 1025
Chris@45 1026 QString adjusted =
Chris@45 1027 (count > 1 ? QString("%1 <%2>").arg(candidate).arg(count) :
Chris@45 1028 candidate);
Chris@45 1029
Chris@45 1030 bool duplicate = false;
Chris@45 1031
Chris@663 1032 for (auto i = m_layers.begin(); i != m_layers.end(); ++i) {
Chris@45 1033 if ((*i)->objectName() == adjusted) {
Chris@45 1034 duplicate = true;
Chris@45 1035 break;
Chris@45 1036 }
Chris@45 1037 }
Chris@45 1038
Chris@45 1039 if (!duplicate) return adjusted;
Chris@45 1040 }
Chris@45 1041 }
Chris@45 1042
Chris@683 1043 std::vector<ModelId>
Chris@72 1044 Document::getTransformInputModels()
Chris@45 1045 {
Chris@683 1046 std::vector<ModelId> models;
Chris@45 1047
Chris@683 1048 if (m_mainModel.isNone()) return models;
Chris@45 1049
Chris@45 1050 models.push_back(m_mainModel);
Chris@45 1051
Chris@45 1052 //!!! This will pick up all models, including those that aren't visible...
Chris@45 1053
Chris@683 1054 for (auto rec: m_models) {
Chris@45 1055
Chris@683 1056 ModelId modelId = rec.first;
Chris@683 1057 if (modelId == m_mainModel) continue;
Chris@683 1058
Chris@683 1059 auto dtvm = ModelById::getAs<DenseTimeValueModel>(modelId);
Chris@45 1060 if (dtvm) {
Chris@683 1061 models.push_back(modelId);
Chris@45 1062 }
Chris@45 1063 }
Chris@45 1064
Chris@45 1065 return models;
Chris@45 1066 }
Chris@45 1067
Chris@50 1068 bool
Chris@683 1069 Document::isKnownModel(const ModelId modelId) const
Chris@77 1070 {
Chris@683 1071 if (modelId == m_mainModel) return true;
Chris@683 1072 for (auto rec: m_models) {
Chris@683 1073 if (rec.first == modelId) return true;
Chris@661 1074 }
Chris@661 1075 return false;
Chris@77 1076 }
Chris@77 1077
Chris@428 1078 bool
Chris@428 1079 Document::canAlign()
Chris@90 1080 {
Chris@428 1081 return Align::canAlign();
Chris@50 1082 }
Chris@50 1083
Chris@45 1084 void
Chris@683 1085 Document::alignModel(ModelId modelId, bool forceRecalculate)
Chris@45 1086 {
Chris@683 1087 SVDEBUG << "Document::alignModel(" << modelId << ", " << forceRecalculate
Chris@672 1088 << ") (main model is " << m_mainModel << ")" << endl;
Chris@683 1089
Chris@683 1090 auto rm = ModelById::getAs<RangeSummarisableTimeValueModel>(modelId);
Chris@387 1091 if (!rm) {
Chris@683 1092 SVDEBUG << "(model " << modelId << " is not an alignable sort)" << endl;
Chris@387 1093 return;
Chris@387 1094 }
Chris@48 1095
Chris@683 1096 if (m_mainModel.isNone()) {
Chris@672 1097 SVDEBUG << "(no main model to align to)" << endl;
Chris@683 1098 if (forceRecalculate && !rm->getAlignment().isNone()) {
Chris@672 1099 SVDEBUG << "(but model is aligned, and forceRecalculate is true, "
Chris@672 1100 << "so resetting alignment to nil)" << endl;
Chris@683 1101 rm->setAlignment({});
Chris@672 1102 }
Chris@672 1103 return;
Chris@672 1104 }
Chris@672 1105
Chris@86 1106 if (rm->getAlignmentReference() == m_mainModel) {
Chris@683 1107 SVDEBUG << "(model " << modelId << " is already aligned to main model "
Chris@672 1108 << m_mainModel << ")" << endl;
Chris@672 1109 if (!forceRecalculate) {
Chris@672 1110 return;
Chris@672 1111 } else {
Chris@672 1112 SVDEBUG << "(but forceRecalculate is true, so realigning anyway)"
Chris@672 1113 << endl;
Chris@672 1114 }
Chris@86 1115 }
Chris@45 1116
Chris@683 1117 if (modelId == m_mainModel) {
Chris@86 1118 // The reference has an empty alignment to itself. This makes
Chris@86 1119 // it possible to distinguish between the reference and any
Chris@86 1120 // unaligned model just by looking at the model itself,
Chris@86 1121 // without also knowing what the main model is
Chris@683 1122 SVDEBUG << "Document::alignModel(" << modelId
Chris@672 1123 << "): is main model, setting alignment to itself" << endl;
Chris@683 1124 auto alignment = std::make_shared<AlignmentModel>(modelId, modelId,
Chris@683 1125 ModelId());
Chris@691 1126
Chris@691 1127 ModelId alignmentModelId = ModelById::add(alignment);
Chris@691 1128 rm->setAlignment(alignmentModelId);
Chris@691 1129 m_alignmentModels.insert(alignmentModelId);
Chris@86 1130 return;
Chris@86 1131 }
Chris@86 1132
Chris@683 1133 auto w = ModelById::getAs<WritableWaveFileModel>(modelId);
Chris@679 1134 if (w && w->getWriteProportion() < 100) {
Chris@683 1135 SVDEBUG << "Document::alignModel(" << modelId
Chris@679 1136 << "): model write is not complete, deferring"
Chris@679 1137 << endl;
Chris@687 1138 connect(w.get(), SIGNAL(writeCompleted(ModelId)),
Chris@687 1139 this, SLOT(performDeferredAlignment(ModelId)));
Chris@679 1140 return;
Chris@679 1141 }
Chris@679 1142
Chris@667 1143 SVDEBUG << "Document::alignModel: aligning..." << endl;
Chris@683 1144 if (!rm->getAlignmentReference().isNone()) {
Chris@667 1145 SVDEBUG << "(Note: model " << rm << " is currently aligned to model "
Chris@667 1146 << rm->getAlignmentReference() << "; this will replace that)"
Chris@667 1147 << endl;
Chris@667 1148 }
Chris@670 1149
Chris@670 1150 QString err;
Chris@683 1151 if (!m_align->alignModel(this, m_mainModel, modelId, err)) {
Chris@670 1152 SVCERR << "Alignment failed: " << err << endl;
Chris@670 1153 emit alignmentFailed(err);
Chris@64 1154 }
Chris@45 1155 }
Chris@45 1156
Chris@45 1157 void
Chris@687 1158 Document::performDeferredAlignment(ModelId modelId)
Chris@679 1159 {
Chris@683 1160 SVDEBUG << "Document::performDeferredAlignment: aligning..." << endl;
Chris@683 1161 alignModel(modelId);
Chris@679 1162 }
Chris@679 1163
Chris@679 1164 void
Chris@45 1165 Document::alignModels()
Chris@45 1166 {
Chris@683 1167 for (auto rec: m_models) {
Chris@683 1168 alignModel(rec.first);
Chris@45 1169 }
Chris@86 1170 alignModel(m_mainModel);
Chris@45 1171 }
Chris@45 1172
Chris@672 1173 void
Chris@672 1174 Document::realignModels()
Chris@672 1175 {
Chris@683 1176 for (auto rec: m_models) {
Chris@683 1177 alignModel(rec.first, true);
Chris@672 1178 }
Chris@672 1179 alignModel(m_mainModel);
Chris@672 1180 }
Chris@672 1181
Chris@45 1182 Document::AddLayerCommand::AddLayerCommand(Document *d,
Chris@595 1183 View *view,
Chris@595 1184 Layer *layer) :
Chris@45 1185 m_d(d),
Chris@45 1186 m_view(view),
Chris@45 1187 m_layer(layer),
Chris@45 1188 m_name(qApp->translate("AddLayerCommand", "Add %1 Layer").arg(layer->objectName())),
Chris@45 1189 m_added(false)
Chris@45 1190 {
Chris@45 1191 }
Chris@45 1192
Chris@45 1193 Document::AddLayerCommand::~AddLayerCommand()
Chris@45 1194 {
Chris@77 1195 #ifdef DEBUG_DOCUMENT
Chris@233 1196 SVDEBUG << "Document::AddLayerCommand::~AddLayerCommand" << endl;
Chris@77 1197 #endif
Chris@45 1198 if (!m_added) {
Chris@595 1199 m_d->deleteLayer(m_layer);
Chris@45 1200 }
Chris@45 1201 }
Chris@45 1202
Chris@159 1203 QString
Chris@159 1204 Document::AddLayerCommand::getName() const
Chris@159 1205 {
Chris@165 1206 #ifdef DEBUG_DOCUMENT
Chris@233 1207 SVDEBUG << "Document::AddLayerCommand::getName(): Name is "
Chris@229 1208 << m_name << endl;
Chris@165 1209 #endif
Chris@159 1210 return m_name;
Chris@159 1211 }
Chris@159 1212
Chris@45 1213 void
Chris@45 1214 Document::AddLayerCommand::execute()
Chris@45 1215 {
Chris@45 1216 for (int i = 0; i < m_view->getLayerCount(); ++i) {
Chris@595 1217 if (m_view->getLayer(i) == m_layer) {
Chris@595 1218 // already there
Chris@595 1219 m_layer->setLayerDormant(m_view, false);
Chris@595 1220 m_added = true;
Chris@595 1221 return;
Chris@595 1222 }
Chris@45 1223 }
Chris@45 1224
Chris@45 1225 m_view->addLayer(m_layer);
Chris@45 1226 m_layer->setLayerDormant(m_view, false);
Chris@45 1227
Chris@45 1228 m_d->addToLayerViewMap(m_layer, m_view);
Chris@45 1229 m_added = true;
Chris@45 1230 }
Chris@45 1231
Chris@45 1232 void
Chris@45 1233 Document::AddLayerCommand::unexecute()
Chris@45 1234 {
Chris@45 1235 m_view->removeLayer(m_layer);
Chris@45 1236 m_layer->setLayerDormant(m_view, true);
Chris@45 1237
Chris@45 1238 m_d->removeFromLayerViewMap(m_layer, m_view);
Chris@45 1239 m_added = false;
Chris@45 1240 }
Chris@45 1241
Chris@45 1242 Document::RemoveLayerCommand::RemoveLayerCommand(Document *d,
Chris@595 1243 View *view,
Chris@595 1244 Layer *layer) :
Chris@45 1245 m_d(d),
Chris@45 1246 m_view(view),
Chris@45 1247 m_layer(layer),
Chris@339 1248 m_wasDormant(layer->isLayerDormant(view)),
Chris@45 1249 m_name(qApp->translate("RemoveLayerCommand", "Delete %1 Layer").arg(layer->objectName())),
Chris@45 1250 m_added(true)
Chris@45 1251 {
Chris@45 1252 }
Chris@45 1253
Chris@45 1254 Document::RemoveLayerCommand::~RemoveLayerCommand()
Chris@45 1255 {
Chris@77 1256 #ifdef DEBUG_DOCUMENT
Chris@233 1257 SVDEBUG << "Document::RemoveLayerCommand::~RemoveLayerCommand" << endl;
Chris@77 1258 #endif
Chris@45 1259 if (!m_added) {
Chris@595 1260 m_d->deleteLayer(m_layer);
Chris@45 1261 }
Chris@45 1262 }
Chris@45 1263
Chris@159 1264 QString
Chris@159 1265 Document::RemoveLayerCommand::getName() const
Chris@159 1266 {
Chris@171 1267 #ifdef DEBUG_DOCUMENT
Chris@233 1268 SVDEBUG << "Document::RemoveLayerCommand::getName(): Name is "
Chris@229 1269 << m_name << endl;
Chris@171 1270 #endif
Chris@159 1271 return m_name;
Chris@159 1272 }
Chris@159 1273
Chris@45 1274 void
Chris@45 1275 Document::RemoveLayerCommand::execute()
Chris@45 1276 {
Chris@45 1277 bool have = false;
Chris@45 1278 for (int i = 0; i < m_view->getLayerCount(); ++i) {
Chris@595 1279 if (m_view->getLayer(i) == m_layer) {
Chris@595 1280 have = true;
Chris@595 1281 break;
Chris@595 1282 }
Chris@45 1283 }
Chris@45 1284
Chris@45 1285 if (!have) { // not there!
Chris@595 1286 m_layer->setLayerDormant(m_view, true);
Chris@595 1287 m_added = false;
Chris@595 1288 return;
Chris@45 1289 }
Chris@45 1290
Chris@45 1291 m_view->removeLayer(m_layer);
Chris@45 1292 m_layer->setLayerDormant(m_view, true);
Chris@45 1293
Chris@45 1294 m_d->removeFromLayerViewMap(m_layer, m_view);
Chris@45 1295 m_added = false;
Chris@45 1296 }
Chris@45 1297
Chris@45 1298 void
Chris@45 1299 Document::RemoveLayerCommand::unexecute()
Chris@45 1300 {
Chris@45 1301 m_view->addLayer(m_layer);
Chris@339 1302 m_layer->setLayerDormant(m_view, m_wasDormant);
Chris@45 1303
Chris@45 1304 m_d->addToLayerViewMap(m_layer, m_view);
Chris@45 1305 m_added = true;
Chris@45 1306 }
Chris@45 1307
Chris@45 1308 void
Chris@45 1309 Document::toXml(QTextStream &out, QString indent, QString extraAttributes) const
Chris@45 1310 {
Chris@226 1311 toXml(out, indent, extraAttributes, false);
Chris@226 1312 }
Chris@226 1313
Chris@226 1314 void
Chris@226 1315 Document::toXmlAsTemplate(QTextStream &out, QString indent, QString extraAttributes) const
Chris@226 1316 {
Chris@226 1317 toXml(out, indent, extraAttributes, true);
Chris@226 1318 }
Chris@226 1319
Chris@226 1320 void
Chris@226 1321 Document::toXml(QTextStream &out, QString indent, QString extraAttributes,
Chris@226 1322 bool asTemplate) const
Chris@226 1323 {
Chris@45 1324 out << indent + QString("<data%1%2>\n")
Chris@45 1325 .arg(extraAttributes == "" ? "" : " ").arg(extraAttributes);
Chris@45 1326
Chris@683 1327 auto mainModel = ModelById::getAs<WaveFileModel>(m_mainModel);
Chris@683 1328 if (mainModel) {
Chris@108 1329
Chris@660 1330 #ifdef DEBUG_DOCUMENT
Chris@660 1331 SVDEBUG << "Document::toXml: writing main model" << endl;
Chris@660 1332 #endif
Chris@660 1333
Chris@226 1334 if (asTemplate) {
Chris@226 1335 writePlaceholderMainModel(out, indent + " ");
Chris@226 1336 } else {
Chris@683 1337 mainModel->toXml(out, indent + " ", "mainModel=\"true\"");
Chris@226 1338 }
Chris@108 1339
Chris@686 1340 auto playParameters =
Chris@683 1341 PlayParameterRepository::getInstance()->getPlayParameters
Chris@683 1342 (m_mainModel.untyped);
Chris@108 1343 if (playParameters) {
Chris@108 1344 playParameters->toXml
Chris@108 1345 (out, indent + " ",
Chris@108 1346 QString("model=\"%1\"")
Chris@683 1347 .arg(mainModel->getExportId()));
Chris@108 1348 }
Chris@660 1349 } else {
Chris@660 1350 #ifdef DEBUG_DOCUMENT
Chris@660 1351 SVDEBUG << "Document::toXml: have no main model to write" << endl;
Chris@660 1352 #endif
Chris@45 1353 }
Chris@45 1354
Chris@45 1355 // Models that are not used in a layer that is in a view should
Chris@45 1356 // not be written. Get our list of required models first.
Chris@45 1357
Chris@683 1358 std::set<ModelId> used;
Chris@45 1359
Chris@45 1360 for (LayerViewMap::const_iterator i = m_layerViewMap.begin();
Chris@45 1361 i != m_layerViewMap.end(); ++i) {
Chris@45 1362
Chris@589 1363 if (i->first && !i->second.empty()) { // Layer exists, is in views
Chris@683 1364 ModelId modelId = i->first->getModel();
Chris@700 1365 ModelId sourceId = i->first->getSourceModel();
Chris@700 1366 if (!modelId.isNone()) used.insert(modelId);
Chris@700 1367 if (!sourceId.isNone()) used.insert(sourceId);
Chris@45 1368 }
Chris@45 1369 }
Chris@45 1370
Chris@589 1371 // Write aggregate models first, so that when re-reading
Chris@589 1372 // derivations we already know about their existence. But only
Chris@589 1373 // those that are actually used
Chris@629 1374 //
Chris@629 1375 // Later note: This turns out not to be a great idea - we can't
Chris@629 1376 // use an aggregate model to drive a derivation unless its
Chris@629 1377 // component models have all also already been loaded. So we
Chris@629 1378 // really should have written non-aggregate read-only
Chris@629 1379 // (i.e. non-derived) wave-type models first, then aggregate
Chris@629 1380 // models, then models that have derivations. But we didn't do
Chris@629 1381 // that, so existing sessions will always have the aggregate
Chris@629 1382 // models first and we might as well stick with that.
Chris@589 1383
Chris@683 1384 for (auto modelId: m_aggregateModels) {
Chris@589 1385
Chris@660 1386 #ifdef DEBUG_DOCUMENT
Chris@683 1387 SVDEBUG << "Document::toXml: checking aggregate model "
Chris@683 1388 << modelId << endl;
Chris@660 1389 #endif
Chris@683 1390
Chris@683 1391 auto aggregate = ModelById::getAs<AggregateWaveModel>(modelId);
Chris@589 1392 if (!aggregate) continue;
Chris@683 1393 if (used.find(modelId) == used.end()) {
Chris@660 1394 #ifdef DEBUG_DOCUMENT
Chris@589 1395 SVDEBUG << "(unused, skipping)" << endl;
Chris@660 1396 #endif
Chris@589 1397 continue;
Chris@589 1398 }
Chris@589 1399
Chris@660 1400 #ifdef DEBUG_DOCUMENT
Chris@589 1401 SVDEBUG << "(used, writing)" << endl;
Chris@660 1402 #endif
Chris@589 1403
Chris@589 1404 aggregate->toXml(out, indent + " ");
Chris@589 1405 }
Chris@589 1406
Chris@683 1407 std::set<ModelId> written;
Chris@111 1408
Chris@629 1409 // Now write the other models in two passes: first the models that
Chris@629 1410 // aren't derived from anything (in case they are source
Chris@629 1411 // components for an aggregate model, in which case we need to
Chris@629 1412 // have seen them before we see any models derived from aggregates
Chris@629 1413 // that use them - see the lament above) and then the models that
Chris@629 1414 // have derivations.
Chris@45 1415
Chris@629 1416 const int nonDerivedPass = 0, derivedPass = 1;
Chris@629 1417 for (int pass = nonDerivedPass; pass <= derivedPass; ++pass) {
Chris@629 1418
Chris@683 1419 for (auto rec: m_models) {
Chris@45 1420
Chris@683 1421 ModelId modelId = rec.first;
Chris@629 1422
Chris@683 1423 if (used.find(modelId) == used.end()) continue;
Chris@45 1424
Chris@683 1425 auto model = ModelById::get(modelId);
Chris@683 1426 if (!model) continue;
Chris@683 1427
Chris@660 1428 #ifdef DEBUG_DOCUMENT
Chris@683 1429 SVDEBUG << "Document::toXml: looking at model " << modelId
Chris@683 1430 << " [pass = " << pass << "]" << endl;
Chris@660 1431 #endif
Chris@660 1432
Chris@629 1433 // We need an intelligent way to determine which models
Chris@629 1434 // need to be streamed (i.e. have been edited, or are
Chris@629 1435 // small) and which should not be (i.e. remain as
Chris@629 1436 // generated by a transform, and are large).
Chris@629 1437 //
Chris@629 1438 // At the moment we can get away with deciding not to
Chris@629 1439 // stream dense 3d models or writable wave file models,
Chris@629 1440 // provided they were generated from a transform, because
Chris@629 1441 // at the moment there is no way to edit those model types
Chris@629 1442 // so it should be safe to regenerate them. That won't
Chris@629 1443 // always work in future though. It would be particularly
Chris@629 1444 // nice to be able to ask the user, as well as making an
Chris@629 1445 // intelligent guess.
Chris@45 1446
Chris@629 1447 bool writeModel = true;
Chris@629 1448 bool haveDerivation = false;
Chris@629 1449
Chris@683 1450 if (!rec.second.source.isNone() &&
Chris@683 1451 rec.second.transform.getIdentifier() != "") {
Chris@629 1452 haveDerivation = true;
Chris@629 1453 }
Chris@45 1454
Chris@629 1455 if (pass == nonDerivedPass) {
Chris@629 1456 if (haveDerivation) {
Chris@629 1457 SVDEBUG << "skipping derived model " << model->objectName() << " during nonDerivedPass" << endl;
Chris@629 1458 continue;
Chris@629 1459 }
Chris@629 1460 } else {
Chris@629 1461 if (!haveDerivation) {
Chris@629 1462 SVDEBUG << "skipping non-derived model " << model->objectName() << " during derivedPass" << endl;
Chris@629 1463 continue;
Chris@629 1464 }
Chris@629 1465 }
Chris@45 1466
Chris@629 1467 if (haveDerivation) {
Chris@683 1468 if (ModelById::isa<WritableWaveFileModel>(modelId) ||
Chris@683 1469 ModelById::isa<DenseThreeDimensionalModel>(modelId)) {
Chris@629 1470 writeModel = false;
Chris@629 1471 }
Chris@629 1472 }
Chris@629 1473
Chris@629 1474 if (writeModel) {
Chris@629 1475 model->toXml(out, indent + " ");
Chris@683 1476 written.insert(modelId);
Chris@629 1477 }
Chris@629 1478
Chris@629 1479 if (haveDerivation) {
Chris@629 1480 writeBackwardCompatibleDerivation(out, indent + " ",
Chris@683 1481 modelId, rec.second);
Chris@629 1482 }
Chris@629 1483
Chris@686 1484 auto playParameters =
Chris@683 1485 PlayParameterRepository::getInstance()->getPlayParameters
Chris@683 1486 (modelId.untyped);
Chris@629 1487 if (playParameters) {
Chris@629 1488 playParameters->toXml
Chris@629 1489 (out, indent + " ",
Chris@629 1490 QString("model=\"%1\"")
Chris@657 1491 .arg(model->getExportId()));
Chris@45 1492 }
Chris@45 1493 }
Chris@45 1494 }
Chris@111 1495
Chris@111 1496 // We should write out the alignment models here. AlignmentModel
Chris@111 1497 // needs a toXml that writes out the export IDs of its reference
Chris@111 1498 // and aligned models, and then streams its path model. Note that
Chris@111 1499 // this will only work when the alignment is complete, so we
Chris@111 1500 // should probably wait for it if it isn't already by this point.
Chris@111 1501
Chris@683 1502 for (auto modelId: written) {
Chris@111 1503
Chris@683 1504 auto model = ModelById::get(modelId);
Chris@683 1505 if (!model) continue;
Chris@683 1506
Chris@683 1507 auto alignment = ModelById::get(model->getAlignment());
Chris@111 1508 if (!alignment) continue;
Chris@111 1509
Chris@111 1510 alignment->toXml(out, indent + " ");
Chris@111 1511 }
Chris@111 1512
Chris@663 1513 for (auto i = m_layers.begin(); i != m_layers.end(); ++i) {
Chris@595 1514 (*i)->toXml(out, indent + " ");
Chris@45 1515 }
Chris@45 1516
Chris@45 1517 out << indent + "</data>\n";
Chris@45 1518 }
Chris@45 1519
Chris@72 1520 void
Chris@226 1521 Document::writePlaceholderMainModel(QTextStream &out, QString indent) const
Chris@226 1522 {
Chris@683 1523 auto mainModel = ModelById::get(m_mainModel);
Chris@683 1524 if (!mainModel) return;
Chris@226 1525 out << indent;
Chris@226 1526 out << QString("<model id=\"%1\" name=\"placeholder\" sampleRate=\"%2\" type=\"wavefile\" file=\":samples/silent.wav\" mainModel=\"true\"/>\n")
Chris@683 1527 .arg(mainModel->getExportId())
Chris@683 1528 .arg(mainModel->getSampleRate());
Chris@226 1529 }
Chris@226 1530
Chris@226 1531 void
Chris@72 1532 Document::writeBackwardCompatibleDerivation(QTextStream &out, QString indent,
Chris@683 1533 ModelId targetModelId,
Chris@72 1534 const ModelRecord &rec) const
Chris@72 1535 {
Chris@72 1536 // There is a lot of redundancy in the XML we output here, because
Chris@72 1537 // we want it to work with older SV session file reading code as
Chris@72 1538 // well.
Chris@72 1539 //
Chris@72 1540 // Formerly, a transform was described using a derivation element
Chris@72 1541 // which set out the source and target models, execution context
Chris@72 1542 // (step size, input channel etc) and transform id, containing a
Chris@72 1543 // plugin element which set out the transform parameters and so
Chris@72 1544 // on. (The plugin element came from a "configurationXml" string
Chris@72 1545 // obtained from PluginXml.)
Chris@72 1546 //
Chris@72 1547 // This has been replaced by a derivation element setting out the
Chris@72 1548 // source and target models and input channel, containing a
Chris@72 1549 // transform element which sets out everything in the Transform.
Chris@72 1550 //
Chris@72 1551 // In order to retain compatibility with older SV code, however,
Chris@72 1552 // we have to write out the same stuff into the derivation as
Chris@72 1553 // before, and manufacture an appropriate plugin element as well
Chris@72 1554 // as the transform element. In order that newer code knows it's
Chris@72 1555 // dealing with a newer format, we will also write an attribute
Chris@72 1556 // 'type="transform"' in the derivation element.
Chris@45 1557
Chris@72 1558 const Transform &transform = rec.transform;
Chris@683 1559
Chris@683 1560 auto targetModel = ModelById::get(targetModelId);
Chris@683 1561 if (!targetModel) return;
Chris@683 1562
Chris@72 1563 // Just for reference, this is what we would write if we didn't
Chris@72 1564 // have to be backward compatible:
Chris@72 1565 //
Chris@72 1566 // out << indent
Chris@72 1567 // << QString("<derivation type=\"transform\" source=\"%1\" "
Chris@72 1568 // "model=\"%2\" channel=\"%3\">\n")
Chris@657 1569 // .arg(rec.source->getExportId())
Chris@657 1570 // .arg(targetModel->getExportId())
Chris@72 1571 // .arg(rec.channel);
Chris@72 1572 //
Chris@72 1573 // transform.toXml(out, indent + " ");
Chris@72 1574 //
Chris@72 1575 // out << indent << "</derivation>\n";
Chris@72 1576 //
Chris@72 1577 // Unfortunately, we can't just do that. So we do this...
Chris@72 1578
Chris@72 1579 QString extentsAttributes;
Chris@72 1580 if (transform.getStartTime() != RealTime::zeroTime ||
Chris@72 1581 transform.getDuration() != RealTime::zeroTime) {
Chris@72 1582 extentsAttributes = QString("startFrame=\"%1\" duration=\"%2\" ")
Chris@72 1583 .arg(RealTime::realTime2Frame(transform.getStartTime(),
Chris@72 1584 targetModel->getSampleRate()))
Chris@72 1585 .arg(RealTime::realTime2Frame(transform.getDuration(),
Chris@72 1586 targetModel->getSampleRate()));
Chris@72 1587 }
Chris@595 1588
Chris@72 1589 out << indent;
Chris@72 1590 out << QString("<derivation type=\"transform\" source=\"%1\" "
Chris@72 1591 "model=\"%2\" channel=\"%3\" domain=\"%4\" "
Chris@72 1592 "stepSize=\"%5\" blockSize=\"%6\" %7windowType=\"%8\" "
Chris@72 1593 "transform=\"%9\">\n")
Chris@683 1594 .arg(ModelById::getExportId(rec.source))
Chris@657 1595 .arg(targetModel->getExportId())
Chris@72 1596 .arg(rec.channel)
Chris@72 1597 .arg(TransformFactory::getInstance()->getTransformInputDomain
Chris@72 1598 (transform.getIdentifier()))
Chris@72 1599 .arg(transform.getStepSize())
Chris@72 1600 .arg(transform.getBlockSize())
Chris@72 1601 .arg(extentsAttributes)
Chris@72 1602 .arg(int(transform.getWindowType()))
Chris@72 1603 .arg(XmlExportable::encodeEntities(transform.getIdentifier()));
Chris@72 1604
Chris@72 1605 transform.toXml(out, indent + " ");
Chris@72 1606
Chris@72 1607 out << indent << " "
Chris@72 1608 << TransformFactory::getInstance()->getPluginConfigurationXml(transform);
Chris@72 1609
Chris@72 1610 out << indent << "</derivation>\n";
Chris@72 1611 }
Chris@72 1612