annotate framework/Document.cpp @ 771:1d6cca5a5621 pitch-align

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