annotate framework/Document.cpp @ 109:2dd30a7cd21a

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