annotate framework/Document.cpp @ 180:84b2c1a4984a

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