annotate framework/Document.cpp @ 285:32d8084f8543

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