annotate framework/Document.cpp @ 786:1089d65c585d tip

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