annotate framework/Document.cpp @ 154:386b02c926bf

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