svapp
1.9
|
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ 00002 00003 /* 00004 Sonic Visualiser 00005 An audio file viewer and annotation editor. 00006 Centre for Digital Music, Queen Mary, University of London. 00007 This file copyright 2006 Chris Cannam and QMUL. 00008 00009 This program is free software; you can redistribute it and/or 00010 modify it under the terms of the GNU General Public License as 00011 published by the Free Software Foundation; either version 2 of the 00012 License, or (at your option) any later version. See the file 00013 COPYING included with this distribution for more information. 00014 */ 00015 00016 #include "Document.h" 00017 00018 #include "data/model/WaveFileModel.h" 00019 #include "data/model/WritableWaveFileModel.h" 00020 #include "data/model/DenseThreeDimensionalModel.h" 00021 #include "data/model/DenseTimeValueModel.h" 00022 #include "data/model/FlexiNoteModel.h" 00023 00024 #include "layer/Layer.h" 00025 #include "widgets/CommandHistory.h" 00026 #include "base/Command.h" 00027 #include "view/View.h" 00028 #include "base/PlayParameterRepository.h" 00029 #include "base/PlayParameters.h" 00030 #include "transform/TransformFactory.h" 00031 #include "transform/ModelTransformerFactory.h" 00032 #include "transform/FeatureExtractionModelTransformer.h" 00033 #include <QApplication> 00034 #include <QTextStream> 00035 #include <QSettings> 00036 #include <iostream> 00037 #include <typeinfo> 00038 00039 // For alignment: 00040 #include "data/model/AggregateWaveModel.h" 00041 #include "data/model/SparseTimeValueModel.h" 00042 #include "data/model/AlignmentModel.h" 00043 00044 using std::vector; 00045 00046 //#define DEBUG_DOCUMENT 1 00047 00049 00050 Document::Document() : 00051 m_mainModel(0), 00052 m_autoAlignment(false) 00053 { 00054 connect(this, SIGNAL(modelAboutToBeDeleted(Model *)), 00055 ModelTransformerFactory::getInstance(), 00056 SLOT(modelAboutToBeDeleted(Model *))); 00057 } 00058 00059 Document::~Document() 00060 { 00062 //still refer to it in various places that don't have access to 00063 //the document, be nice to fix that 00064 00065 #ifdef DEBUG_DOCUMENT 00066 cerr << "\n\nDocument::~Document: about to clear command history" << endl; 00067 #endif 00068 CommandHistory::getInstance()->clear(); 00069 00070 #ifdef DEBUG_DOCUMENT 00071 SVDEBUG << "Document::~Document: about to delete layers" << endl; 00072 #endif 00073 while (!m_layers.empty()) { 00074 deleteLayer(*m_layers.begin(), true); 00075 } 00076 00077 if (!m_models.empty()) { 00078 SVDEBUG << "Document::~Document: WARNING: " 00079 << m_models.size() << " model(s) still remain -- " 00080 << "should have been garbage collected when deleting layers" 00081 << endl; 00082 while (!m_models.empty()) { 00083 Model *model = m_models.begin()->first; 00084 if (model == m_mainModel) { 00085 // just in case! 00086 SVDEBUG << "Document::~Document: WARNING: Main model is also" 00087 << " in models list!" << endl; 00088 } else if (model) { 00089 model->aboutToDelete(); 00090 emit modelAboutToBeDeleted(model); 00091 delete model; 00092 } 00093 m_models.erase(m_models.begin()); 00094 } 00095 } 00096 00097 #ifdef DEBUG_DOCUMENT 00098 SVDEBUG << "Document::~Document: About to get rid of main model" 00099 << endl; 00100 #endif 00101 if (m_mainModel) { 00102 m_mainModel->aboutToDelete(); 00103 emit modelAboutToBeDeleted(m_mainModel); 00104 } 00105 00106 emit mainModelChanged(0); 00107 delete m_mainModel; 00108 } 00109 00110 Layer * 00111 Document::createLayer(LayerFactory::LayerType type) 00112 { 00113 Layer *newLayer = LayerFactory::getInstance()->createLayer(type); 00114 if (!newLayer) return 0; 00115 00116 newLayer->setObjectName(getUniqueLayerName(newLayer->objectName())); 00117 00118 m_layers.insert(newLayer); 00119 00120 #ifdef DEBUG_DOCUMENT 00121 SVDEBUG << "Document::createLayer: Added layer of type " << type 00122 << ", now have " << m_layers.size() << " layers" << endl; 00123 #endif 00124 00125 emit layerAdded(newLayer); 00126 00127 return newLayer; 00128 } 00129 00130 Layer * 00131 Document::createMainModelLayer(LayerFactory::LayerType type) 00132 { 00133 Layer *newLayer = createLayer(type); 00134 if (!newLayer) return 0; 00135 setModel(newLayer, m_mainModel); 00136 return newLayer; 00137 } 00138 00139 Layer * 00140 Document::createImportedLayer(Model *model) 00141 { 00142 LayerFactory::LayerTypeSet types = 00143 LayerFactory::getInstance()->getValidLayerTypes(model); 00144 00145 if (types.empty()) { 00146 cerr << "WARNING: Document::importLayer: no valid display layer for model" << endl; 00147 return 0; 00148 } 00149 00151 LayerFactory::LayerType type = *types.begin(); 00152 00153 Layer *newLayer = LayerFactory::getInstance()->createLayer(type); 00154 if (!newLayer) return 0; 00155 00156 newLayer->setObjectName(getUniqueLayerName(newLayer->objectName())); 00157 00158 addImportedModel(model); 00159 setModel(newLayer, model); 00160 00162 setChannel(newLayer, -1); 00163 00164 m_layers.insert(newLayer); 00165 00166 #ifdef DEBUG_DOCUMENT 00167 SVDEBUG << "Document::createImportedLayer: Added layer of type " << type 00168 << ", now have " << m_layers.size() << " layers" << endl; 00169 #endif 00170 00171 emit layerAdded(newLayer); 00172 return newLayer; 00173 } 00174 00175 Layer * 00176 Document::createEmptyLayer(LayerFactory::LayerType type) 00177 { 00178 if (!m_mainModel) return 0; 00179 00180 Model *newModel = 00181 LayerFactory::getInstance()->createEmptyModel(type, m_mainModel); 00182 if (!newModel) return 0; 00183 00184 Layer *newLayer = createLayer(type); 00185 if (!newLayer) { 00186 delete newModel; 00187 return 0; 00188 } 00189 00190 addImportedModel(newModel); 00191 setModel(newLayer, newModel); 00192 00193 return newLayer; 00194 } 00195 00196 Layer * 00197 Document::createDerivedLayer(LayerFactory::LayerType type, 00198 TransformId transform) 00199 { 00200 Layer *newLayer = createLayer(type); 00201 if (!newLayer) return 0; 00202 00203 newLayer->setObjectName(getUniqueLayerName 00204 (TransformFactory::getInstance()-> 00205 getTransformFriendlyName(transform))); 00206 00207 return newLayer; 00208 } 00209 00210 Layer * 00211 Document::createDerivedLayer(const Transform &transform, 00212 const ModelTransformer::Input &input) 00213 { 00214 Transforms transforms; 00215 transforms.push_back(transform); 00216 vector<Layer *> layers = createDerivedLayers(transforms, input); 00217 if (layers.empty()) return 0; 00218 else return layers[0]; 00219 } 00220 00221 vector<Layer *> 00222 Document::createDerivedLayers(const Transforms &transforms, 00223 const ModelTransformer::Input &input) 00224 { 00225 QString message; 00226 vector<Model *> newModels = addDerivedModels(transforms, input, message, 0); 00227 00228 if (newModels.empty()) { 00230 emit modelGenerationFailed(transforms[0].getIdentifier(), message); 00231 return vector<Layer *>(); 00232 } else if (message != "") { 00234 emit modelGenerationWarning(transforms[0].getIdentifier(), message); 00235 } 00236 00237 QStringList names; 00238 for (int i = 0; i < (int)newModels.size(); ++i) { 00239 names.push_back(getUniqueLayerName 00240 (TransformFactory::getInstance()-> 00241 getTransformFriendlyName 00242 (transforms[i].getIdentifier()))); 00243 } 00244 00245 vector<Layer *> layers = createLayersForDerivedModels(newModels, names); 00246 return layers; 00247 } 00248 00249 class AdditionalModelConverter : 00250 public ModelTransformerFactory::AdditionalModelHandler 00251 { 00252 public: 00253 AdditionalModelConverter(Document *doc, 00254 Document::LayerCreationHandler *handler) : 00255 m_doc(doc), 00256 m_handler(handler) { 00257 } 00258 00259 virtual ~AdditionalModelConverter() { } 00260 00261 void 00262 setPrimaryLayers(vector<Layer *> layers) { 00263 m_primary = layers; 00264 } 00265 00266 void 00267 moreModelsAvailable(vector<Model *> models) { 00268 std::cerr << "AdditionalModelConverter::moreModelsAvailable: " << models.size() << " model(s)" << std::endl; 00269 // We can't automatically regenerate the additional models on 00270 // reload -- we should delete them instead 00271 QStringList names; 00272 foreach (Model *model, models) { 00273 m_doc->addAdditionalModel(model); 00274 names.push_back(QString()); 00275 } 00276 vector<Layer *> layers = m_doc->createLayersForDerivedModels 00277 (models, names); 00278 m_handler->layersCreated(this, m_primary, layers); 00279 delete this; 00280 } 00281 00282 void 00283 noMoreModelsAvailable() { 00284 std::cerr << "AdditionalModelConverter::noMoreModelsAvailable" << std::endl; 00285 m_handler->layersCreated(this, m_primary, vector<Layer *>()); 00286 delete this; 00287 } 00288 00289 void cancel() { 00290 foreach (Layer *layer, m_primary) { 00291 Model *model = layer->getModel(); 00292 if (model) { 00293 model->abandon(); 00294 } 00295 } 00296 } 00297 00298 private: 00299 Document *m_doc; 00300 vector<Layer *> m_primary; 00301 Document::LayerCreationHandler *m_handler; 00302 }; 00303 00304 Document::LayerCreationAsyncHandle 00305 Document::createDerivedLayersAsync(const Transforms &transforms, 00306 const ModelTransformer::Input &input, 00307 LayerCreationHandler *handler) 00308 { 00309 QString message; 00310 00311 AdditionalModelConverter *amc = new AdditionalModelConverter(this, handler); 00312 00313 vector<Model *> newModels = addDerivedModels 00314 (transforms, input, message, amc); 00315 00316 QStringList names; 00317 for (int i = 0; i < (int)newModels.size(); ++i) { 00318 names.push_back(getUniqueLayerName 00319 (TransformFactory::getInstance()-> 00320 getTransformFriendlyName 00321 (transforms[i].getIdentifier()))); 00322 } 00323 00324 vector<Layer *> layers = createLayersForDerivedModels(newModels, names); 00325 amc->setPrimaryLayers(layers); 00326 00327 if (newModels.empty()) { 00329 emit modelGenerationFailed(transforms[0].getIdentifier(), message); 00331 } else if (message != "") { 00333 emit modelGenerationWarning(transforms[0].getIdentifier(), message); 00335 } 00336 00337 return amc; 00338 } 00339 00340 void 00341 Document::cancelAsyncLayerCreation(Document::LayerCreationAsyncHandle h) 00342 { 00343 AdditionalModelConverter *conv = static_cast<AdditionalModelConverter *>(h); 00344 conv->cancel(); 00345 } 00346 00347 vector<Layer *> 00348 Document::createLayersForDerivedModels(vector<Model *> newModels, 00349 QStringList names) 00350 { 00351 vector<Layer *> layers; 00352 00353 for (int i = 0; i < (int)newModels.size(); ++i) { 00354 00355 Model *newModel = newModels[i]; 00356 00357 LayerFactory::LayerTypeSet types = 00358 LayerFactory::getInstance()->getValidLayerTypes(newModel); 00359 00360 if (types.empty()) { 00361 cerr << "WARNING: Document::createLayerForTransformer: no valid display layer for output of transform " << names[i] << endl; 00363 newModel->aboutToDelete(); 00364 emit modelAboutToBeDeleted(newModel); 00365 m_models.erase(newModel); 00366 delete newModel; 00367 return vector<Layer *>(); 00368 } 00369 00371 00372 Layer *newLayer = createLayer(*types.begin()); 00373 setModel(newLayer, newModel); 00374 00376 //can be edited without affecting other layers that are based on 00377 //the same model. Unfortunately we can't just clone it now, 00378 //because it probably hasn't been completed yet -- the transform 00379 //runs in the background. Maybe the transform has to handle 00380 //cloning and cacheing models itself. 00381 // 00382 // Once we do clone models here, of course, we'll have to avoid 00383 // leaking them too. 00384 // 00385 // We want the user to be able to add a model to a second layer 00386 // _while it's still being calculated in the first_ and have it 00387 // work quickly. That means we need to put the same physical 00388 // model pointer in both layers, so they can't actually be cloned. 00389 00390 if (newLayer) { 00391 newLayer->setObjectName(names[i]); 00392 } 00393 00394 emit layerAdded(newLayer); 00395 layers.push_back(newLayer); 00396 } 00397 00398 return layers; 00399 } 00400 00401 void 00402 Document::setMainModel(WaveFileModel *model) 00403 { 00404 Model *oldMainModel = m_mainModel; 00405 m_mainModel = model; 00406 00407 emit modelAdded(m_mainModel); 00408 if (model) { 00409 emit activity(tr("Set main model to %1").arg(model->objectName())); 00410 } else { 00411 emit activity(tr("Clear main model")); 00412 } 00413 00414 std::vector<Layer *> obsoleteLayers; 00415 std::set<QString> failedTransformers; 00416 00417 // We need to ensure that no layer is left using oldMainModel or 00418 // any of the old derived models as its model. Either replace the 00419 // model, or delete the layer for each layer that is currently 00420 // using one of these. Carry out this replacement before we 00421 // delete any of the models. 00422 00423 #ifdef DEBUG_DOCUMENT 00424 cerr << "Document::setMainModel: Have " 00425 << m_layers.size() << " layers" << endl; 00426 cerr << "Models now: "; 00427 for (ModelMap::const_iterator i = m_models.begin(); i != m_models.end(); ++i) { 00428 cerr << i->first << " "; 00429 } 00430 cerr << endl; 00431 cerr << "Old main model: " << oldMainModel << endl; 00432 #endif 00433 00434 for (LayerSet::iterator i = m_layers.begin(); i != m_layers.end(); ++i) { 00435 00436 Layer *layer = *i; 00437 Model *model = layer->getModel(); 00438 00439 #ifdef DEBUG_DOCUMENT 00440 cerr << "Document::setMainModel: inspecting model " 00441 << (model ? model->objectName(): "(null)") << " in layer " 00442 << layer->objectName() << endl; 00443 #endif 00444 00445 if (model == oldMainModel) { 00446 #ifdef DEBUG_DOCUMENT 00447 cerr << "... it uses the old main model, replacing" << endl; 00448 #endif 00449 LayerFactory::getInstance()->setModel(layer, m_mainModel); 00450 continue; 00451 } 00452 00453 if (!model) { 00454 cerr << "WARNING: Document::setMainModel: Null model in layer " 00455 << layer << endl; 00456 // get rid of this hideous degenerate 00457 obsoleteLayers.push_back(layer); 00458 continue; 00459 } 00460 00461 if (m_models.find(model) == m_models.end()) { 00462 cerr << "WARNING: Document::setMainModel: Unknown model " 00463 << model << " in layer " << layer << endl; 00464 // and this one 00465 obsoleteLayers.push_back(layer); 00466 continue; 00467 } 00468 00469 if (m_models[model].source && 00470 (m_models[model].source == oldMainModel)) { 00471 00472 #ifdef DEBUG_DOCUMENT 00473 cerr << "... it uses a model derived from the old main model, regenerating" << endl; 00474 #endif 00475 00476 // This model was derived from the previous main 00477 // model: regenerate it. 00478 00479 const Transform &transform = m_models[model].transform; 00480 QString transformId = transform.getIdentifier(); 00481 00483 //the main model has changed. 00484 00485 QString message; 00486 Model *replacementModel = 00487 addDerivedModel(transform, 00488 ModelTransformer::Input 00489 (m_mainModel, m_models[model].channel), 00490 message); 00491 00492 if (!replacementModel) { 00493 cerr << "WARNING: Document::setMainModel: Failed to regenerate model for transform \"" 00494 << transformId << "\"" << " in layer " << layer << endl; 00495 if (failedTransformers.find(transformId) 00496 == failedTransformers.end()) { 00497 emit modelRegenerationFailed(layer->objectName(), 00498 transformId, 00499 message); 00500 failedTransformers.insert(transformId); 00501 } 00502 obsoleteLayers.push_back(layer); 00503 } else { 00504 if (message != "") { 00505 emit modelRegenerationWarning(layer->objectName(), 00506 transformId, 00507 message); 00508 } 00509 #ifdef DEBUG_DOCUMENT 00510 cerr << "Replacing model " << model << " (type " 00511 << typeid(*model).name() << ") with model " 00512 << replacementModel << " (type " 00513 << typeid(*replacementModel).name() << ") in layer " 00514 << layer << " (name " << layer->objectName() << ")" 00515 << endl; 00516 00517 RangeSummarisableTimeValueModel *rm = 00518 dynamic_cast<RangeSummarisableTimeValueModel *>(replacementModel); 00519 if (rm) { 00520 cerr << "new model has " << rm->getChannelCount() << " channels " << endl; 00521 } else { 00522 cerr << "new model " << replacementModel << " is not a RangeSummarisableTimeValueModel!" << endl; 00523 } 00524 #endif 00525 setModel(layer, replacementModel); 00526 } 00527 } 00528 } 00529 00530 for (size_t k = 0; k < obsoleteLayers.size(); ++k) { 00531 deleteLayer(obsoleteLayers[k], true); 00532 } 00533 00534 for (ModelMap::iterator i = m_models.begin(); i != m_models.end(); ++i) { 00535 if (i->second.additional) { 00536 Model *m = i->first; 00537 emit modelAboutToBeDeleted(m); 00538 delete m; 00539 } 00540 } 00541 00542 for (ModelMap::iterator i = m_models.begin(); i != m_models.end(); ++i) { 00543 00544 Model *m = i->first; 00545 00546 #ifdef DEBUG_DOCUMENT 00547 SVDEBUG << "considering alignment for model " << m << " (name \"" 00548 << m->objectName() << "\")" << endl; 00549 #endif 00550 00551 if (m_autoAlignment) { 00552 00553 alignModel(m); 00554 00555 } else if (oldMainModel && 00556 (m->getAlignmentReference() == oldMainModel)) { 00557 00558 alignModel(m); 00559 } 00560 } 00561 00562 if (oldMainModel) { 00563 oldMainModel->aboutToDelete(); 00564 emit modelAboutToBeDeleted(oldMainModel); 00565 } 00566 00567 if (m_autoAlignment) { 00568 SVDEBUG << "Document::setMainModel: auto-alignment is on, aligning model if possible" << endl; 00569 alignModel(m_mainModel); 00570 } 00571 00572 emit mainModelChanged(m_mainModel); 00573 00574 delete oldMainModel; 00575 } 00576 00577 void 00578 Document::addAlreadyDerivedModel(const Transform &transform, 00579 const ModelTransformer::Input &input, 00580 Model *outputModelToAdd) 00581 { 00582 if (m_models.find(outputModelToAdd) != m_models.end()) { 00583 cerr << "WARNING: Document::addAlreadyDerivedModel: Model already added" 00584 << endl; 00585 return; 00586 } 00587 00588 #ifdef DEBUG_DOCUMENT 00589 if (input.getModel()) { 00590 cerr << "Document::addAlreadyDerivedModel: source is " << input.getModel() << " \"" << input.getModel()->objectName() << "\"" << endl; 00591 } else { 00592 cerr << "Document::addAlreadyDerivedModel: source is " << input.getModel() << endl; 00593 } 00594 #endif 00595 00596 ModelRecord rec; 00597 rec.source = input.getModel(); 00598 rec.channel = input.getChannel(); 00599 rec.transform = transform; 00600 rec.additional = false; 00601 rec.refcount = 0; 00602 00603 outputModelToAdd->setSourceModel(input.getModel()); 00604 00605 m_models[outputModelToAdd] = rec; 00606 00607 #ifdef DEBUG_DOCUMENT 00608 cerr << "Document::addAlreadyDerivedModel: Added model " << outputModelToAdd << endl; 00609 cerr << "Models now: "; 00610 for (ModelMap::const_iterator i = m_models.begin(); i != m_models.end(); ++i) { 00611 cerr << i->first << " "; 00612 } 00613 cerr << endl; 00614 #endif 00615 00616 emit modelAdded(outputModelToAdd); 00617 } 00618 00619 00620 void 00621 Document::addImportedModel(Model *model) 00622 { 00623 if (m_models.find(model) != m_models.end()) { 00624 cerr << "WARNING: Document::addImportedModel: Model already added" 00625 << endl; 00626 return; 00627 } 00628 00629 ModelRecord rec; 00630 rec.source = 0; 00631 rec.channel = 0; 00632 rec.refcount = 0; 00633 rec.additional = false; 00634 00635 m_models[model] = rec; 00636 00637 #ifdef DEBUG_DOCUMENT 00638 SVDEBUG << "Document::addImportedModel: Added model " << model << endl; 00639 cerr << "Models now: "; 00640 for (ModelMap::const_iterator i = m_models.begin(); i != m_models.end(); ++i) { 00641 cerr << i->first << " "; 00642 } 00643 cerr << endl; 00644 #endif 00645 00646 if (m_autoAlignment) { 00647 SVDEBUG << "Document::addImportedModel: auto-alignment is on, aligning model if possible" << endl; 00648 alignModel(model); 00649 } else { 00650 SVDEBUG << "Document(" << this << "): addImportedModel: auto-alignment is off" << endl; 00651 } 00652 00653 emit modelAdded(model); 00654 } 00655 00656 void 00657 Document::addAdditionalModel(Model *model) 00658 { 00659 if (m_models.find(model) != m_models.end()) { 00660 cerr << "WARNING: Document::addAdditionalModel: Model already added" 00661 << endl; 00662 return; 00663 } 00664 00665 ModelRecord rec; 00666 rec.source = 0; 00667 rec.channel = 0; 00668 rec.refcount = 0; 00669 rec.additional = true; 00670 00671 m_models[model] = rec; 00672 00673 #ifdef DEBUG_DOCUMENT 00674 SVDEBUG << "Document::addAdditionalModel: Added model " << model << endl; 00675 cerr << "Models now: "; 00676 for (ModelMap::const_iterator i = m_models.begin(); i != m_models.end(); ++i) { 00677 cerr << i->first << " "; 00678 } 00679 cerr << endl; 00680 #endif 00681 00682 if (m_autoAlignment) { 00683 SVDEBUG << "Document::addAdditionalModel: auto-alignment is on, aligning model if possible" << endl; 00684 alignModel(model); 00685 } 00686 00687 emit modelAdded(model); 00688 } 00689 00690 Model * 00691 Document::addDerivedModel(const Transform &transform, 00692 const ModelTransformer::Input &input, 00693 QString &message) 00694 { 00695 for (ModelMap::iterator i = m_models.begin(); i != m_models.end(); ++i) { 00696 if (i->second.transform == transform && 00697 i->second.source == input.getModel() && 00698 i->second.channel == input.getChannel()) { 00699 std::cerr << "derived model taken from map " << std::endl; 00700 return i->first; 00701 } 00702 } 00703 00704 Transforms tt; 00705 tt.push_back(transform); 00706 vector<Model *> mm = addDerivedModels(tt, input, message, 0); 00707 if (mm.empty()) return 0; 00708 else return mm[0]; 00709 } 00710 00711 vector<Model *> 00712 Document::addDerivedModels(const Transforms &transforms, 00713 const ModelTransformer::Input &input, 00714 QString &message, 00715 AdditionalModelConverter *amc) 00716 { 00717 vector<Model *> mm = 00718 ModelTransformerFactory::getInstance()->transformMultiple 00719 (transforms, input, message, amc); 00720 00721 for (int j = 0; j < (int)mm.size(); ++j) { 00722 00723 Model *model = mm[j]; 00724 00725 // The transform we actually used was presumably identical to 00726 // the one asked for, except that the version of the plugin 00727 // may differ. It's possible that the returned message 00728 // contains a warning about this; that doesn't concern us 00729 // here, but we do need to ensure that the transform we 00730 // remember is correct for what was actually applied, with the 00731 // current plugin version. 00732 00733 Transform applied = transforms[j]; 00734 applied.setPluginVersion 00735 (TransformFactory::getInstance()-> 00736 getDefaultTransformFor(applied.getIdentifier(), 00737 lrintf(applied.getSampleRate())) 00738 .getPluginVersion()); 00739 00740 if (!model) { 00741 cerr << "WARNING: Document::addDerivedModel: no output model for transform " << applied.getIdentifier() << endl; 00742 } else { 00743 addAlreadyDerivedModel(applied, input, model); 00744 } 00745 } 00746 00747 return mm; 00748 } 00749 00750 void 00751 Document::releaseModel(Model *model) // Will _not_ release main model! 00752 { 00753 if (model == 0) { 00754 return; 00755 } 00756 00757 if (model == m_mainModel) { 00758 return; 00759 } 00760 00761 bool toDelete = false; 00762 00763 if (m_models.find(model) != m_models.end()) { 00764 00765 if (m_models[model].refcount == 0) { 00766 cerr << "WARNING: Document::releaseModel: model " << model 00767 << " reference count is zero already!" << endl; 00768 } else { 00769 if (--m_models[model].refcount == 0) { 00770 toDelete = true; 00771 } 00772 } 00773 } else { 00774 cerr << "WARNING: Document::releaseModel: Unfound model " 00775 << model << endl; 00776 toDelete = true; 00777 } 00778 00779 if (toDelete) { 00780 00781 int sourceCount = 0; 00782 00783 for (ModelMap::iterator i = m_models.begin(); i != m_models.end(); ++i) { 00784 if (i->second.source == model) { 00785 ++sourceCount; 00786 i->second.source = 0; 00787 } 00788 } 00789 00790 if (sourceCount > 0) { 00791 SVDEBUG << "Document::releaseModel: Deleting model " 00792 << model << " even though it is source for " 00793 << sourceCount << " other derived model(s) -- resetting " 00794 << "their source fields appropriately" << endl; 00795 } 00796 00797 model->aboutToDelete(); 00798 emit modelAboutToBeDeleted(model); 00799 m_models.erase(model); 00800 00801 #ifdef DEBUG_DOCUMENT 00802 SVDEBUG << "Document::releaseModel: Deleted model " << model << endl; 00803 cerr << "Models now: "; 00804 for (ModelMap::const_iterator i = m_models.begin(); i != m_models.end(); ++i) { 00805 cerr << i->first << " "; 00806 } 00807 cerr << endl; 00808 #endif 00809 00810 delete model; 00811 } 00812 } 00813 00814 void 00815 Document::deleteLayer(Layer *layer, bool force) 00816 { 00817 if (m_layerViewMap.find(layer) != m_layerViewMap.end() && 00818 m_layerViewMap[layer].size() > 0) { 00819 00820 cerr << "WARNING: Document::deleteLayer: Layer " 00821 << layer << " [" << layer->objectName() << "]" 00822 << " is still used in " << m_layerViewMap[layer].size() 00823 << " views!" << endl; 00824 00825 if (force) { 00826 00827 #ifdef DEBUG_DOCUMENT 00828 cerr << "(force flag set -- deleting from all views)" << endl; 00829 #endif 00830 00831 for (std::set<View *>::iterator j = m_layerViewMap[layer].begin(); 00832 j != m_layerViewMap[layer].end(); ++j) { 00833 // don't use removeLayerFromView, as it issues a command 00834 layer->setLayerDormant(*j, true); 00835 (*j)->removeLayer(layer); 00836 } 00837 00838 m_layerViewMap.erase(layer); 00839 00840 } else { 00841 return; 00842 } 00843 } 00844 00845 if (m_layers.find(layer) == m_layers.end()) { 00846 SVDEBUG << "Document::deleteLayer: Layer " 00847 << layer << " (" << typeid(layer).name() << 00848 ") does not exist, or has already been deleted " 00849 << "(this may not be as serious as it sounds)" << endl; 00850 return; 00851 } 00852 00853 m_layers.erase(layer); 00854 00855 #ifdef DEBUG_DOCUMENT 00856 SVDEBUG << "Document::deleteLayer: Removing, now have " 00857 << m_layers.size() << " layers" << endl; 00858 #endif 00859 00860 releaseModel(layer->getModel()); 00861 emit layerRemoved(layer); 00862 emit layerAboutToBeDeleted(layer); 00863 delete layer; 00864 } 00865 00866 void 00867 Document::setModel(Layer *layer, Model *model) 00868 { 00869 if (model && 00870 model != m_mainModel && 00871 m_models.find(model) == m_models.end()) { 00872 cerr << "ERROR: Document::setModel: Layer " << layer 00873 << " (\"" << layer->objectName() 00874 << "\") wants to use unregistered model " << model 00875 << ": register the layer's model before setting it!" 00876 << endl; 00877 return; 00878 } 00879 00880 Model *previousModel = layer->getModel(); 00881 00882 if (previousModel == model) { 00883 SVDEBUG << "NOTE: Document::setModel: Layer " << layer << " (\"" 00884 << layer->objectName() << "\") is already set to model " 00885 << model << " (\"" 00886 << (model ? model->objectName(): "(null)") 00887 << "\")" << endl; 00888 return; 00889 } 00890 00891 if (model && model != m_mainModel) { 00892 m_models[model].refcount ++; 00893 } 00894 00895 if (model && previousModel) { 00896 PlayParameterRepository::getInstance()->copyParameters 00897 (previousModel, model); 00898 } 00899 00900 LayerFactory::getInstance()->setModel(layer, model); 00901 // std::cerr << "layer type: " << LayerFactory::getInstance()->getLayerTypeName(LayerFactory::getInstance()->getLayerType(layer)) << std::endl; 00902 00903 if (previousModel) { 00904 releaseModel(previousModel); 00905 } 00906 } 00907 00908 void 00909 Document::setChannel(Layer *layer, int channel) 00910 { 00911 LayerFactory::getInstance()->setChannel(layer, channel); 00912 } 00913 00914 void 00915 Document::addLayerToView(View *view, Layer *layer) 00916 { 00917 Model *model = layer->getModel(); 00918 if (!model) { 00919 #ifdef DEBUG_DOCUMENT 00920 SVDEBUG << "Document::addLayerToView: Layer (\"" 00921 << layer->objectName() << "\") with no model being added to view: " 00922 << "normally you want to set the model first" << endl; 00923 #endif 00924 } else { 00925 if (model != m_mainModel && 00926 m_models.find(model) == m_models.end()) { 00927 cerr << "ERROR: Document::addLayerToView: Layer " << layer 00928 << " has unregistered model " << model 00929 << " -- register the layer's model before adding the layer!" << endl; 00930 return; 00931 } 00932 } 00933 00934 CommandHistory::getInstance()->addCommand 00935 (new Document::AddLayerCommand(this, view, layer)); 00936 } 00937 00938 void 00939 Document::removeLayerFromView(View *view, Layer *layer) 00940 { 00941 CommandHistory::getInstance()->addCommand 00942 (new Document::RemoveLayerCommand(this, view, layer)); 00943 } 00944 00945 void 00946 Document::addToLayerViewMap(Layer *layer, View *view) 00947 { 00948 bool firstView = (m_layerViewMap.find(layer) == m_layerViewMap.end() || 00949 m_layerViewMap[layer].empty()); 00950 00951 if (m_layerViewMap[layer].find(view) != 00952 m_layerViewMap[layer].end()) { 00953 cerr << "WARNING: Document::addToLayerViewMap:" 00954 << " Layer " << layer << " -> view " << view << " already in" 00955 << " layer view map -- internal inconsistency" << endl; 00956 } 00957 00958 m_layerViewMap[layer].insert(view); 00959 00960 if (firstView) emit layerInAView(layer, true); 00961 } 00962 00963 void 00964 Document::removeFromLayerViewMap(Layer *layer, View *view) 00965 { 00966 if (m_layerViewMap[layer].find(view) == 00967 m_layerViewMap[layer].end()) { 00968 cerr << "WARNING: Document::removeFromLayerViewMap:" 00969 << " Layer " << layer << " -> view " << view << " not in" 00970 << " layer view map -- internal inconsistency" << endl; 00971 } 00972 00973 m_layerViewMap[layer].erase(view); 00974 00975 if (m_layerViewMap[layer].empty()) { 00976 m_layerViewMap.erase(layer); 00977 emit layerInAView(layer, false); 00978 } 00979 } 00980 00981 QString 00982 Document::getUniqueLayerName(QString candidate) 00983 { 00984 for (int count = 1; ; ++count) { 00985 00986 QString adjusted = 00987 (count > 1 ? QString("%1 <%2>").arg(candidate).arg(count) : 00988 candidate); 00989 00990 bool duplicate = false; 00991 00992 for (LayerSet::iterator i = m_layers.begin(); i != m_layers.end(); ++i) { 00993 if ((*i)->objectName() == adjusted) { 00994 duplicate = true; 00995 break; 00996 } 00997 } 00998 00999 if (!duplicate) return adjusted; 01000 } 01001 } 01002 01003 std::vector<Model *> 01004 Document::getTransformInputModels() 01005 { 01006 std::vector<Model *> models; 01007 01008 if (!m_mainModel) return models; 01009 01010 models.push_back(m_mainModel); 01011 01013 01014 for (ModelMap::iterator i = m_models.begin(); i != m_models.end(); ++i) { 01015 01016 Model *model = i->first; 01017 if (!model || model == m_mainModel) continue; 01018 DenseTimeValueModel *dtvm = dynamic_cast<DenseTimeValueModel *>(model); 01019 01020 if (dtvm) { 01021 models.push_back(dtvm); 01022 } 01023 } 01024 01025 return models; 01026 } 01027 01028 bool 01029 Document::isKnownModel(const Model *model) const 01030 { 01031 if (model == m_mainModel) return true; 01032 return (m_models.find(const_cast<Model *>(model)) != m_models.end()); 01033 } 01034 01035 TransformId 01036 Document::getAlignmentTransformName() 01037 { 01038 QSettings settings; 01039 settings.beginGroup("Alignment"); 01040 TransformId id = 01041 settings.value("transform-id", 01042 "vamp:match-vamp-plugin:match:path").toString(); 01043 settings.endGroup(); 01044 return id; 01045 } 01046 01047 bool 01048 Document::canAlign() 01049 { 01050 TransformId id = getAlignmentTransformName(); 01051 TransformFactory *factory = TransformFactory::getInstance(); 01052 return factory->haveTransform(id); 01053 } 01054 01055 void 01056 Document::alignModel(Model *model) 01057 { 01058 SVDEBUG << "Document::alignModel(" << model << ")" << endl; 01059 01060 if (!m_mainModel) { 01061 SVDEBUG << "(no main model to align to)" << endl; 01062 return; 01063 } 01064 01065 RangeSummarisableTimeValueModel *rm = 01066 dynamic_cast<RangeSummarisableTimeValueModel *>(model); 01067 if (!rm) { 01068 SVDEBUG << "(main model is not alignable-to)" << endl; 01069 return; 01070 } 01071 01072 if (rm->getAlignmentReference() == m_mainModel) { 01073 SVDEBUG << "(model " << rm << " is already aligned to main model " << m_mainModel << ")" << endl; 01074 return; 01075 } 01076 01077 if (model == m_mainModel) { 01078 // The reference has an empty alignment to itself. This makes 01079 // it possible to distinguish between the reference and any 01080 // unaligned model just by looking at the model itself, 01081 // without also knowing what the main model is 01082 SVDEBUG << "Document::alignModel(" << model << "): is main model, setting appropriately" << endl; 01083 rm->setAlignment(new AlignmentModel(model, model, 0, 0)); 01084 return; 01085 } 01086 01087 // This involves creating three new models: 01088 01089 // 1. an AggregateWaveModel to provide the mixdowns of the main 01090 // model and the new model in its two channels, as input to the 01091 // MATCH plugin 01092 01093 // 2. a SparseTimeValueModel, which is the model automatically 01094 // created by FeatureExtractionPluginTransformer when running the 01095 // MATCH plugin (thus containing the alignment path) 01096 01097 // 3. an AlignmentModel, which stores the path model and carries 01098 // out alignment lookups on it. 01099 01100 // The first two of these are provided as arguments to the 01101 // constructor for the third, which takes responsibility for 01102 // deleting them. The AlignmentModel, meanwhile, is passed to the 01103 // new model we are aligning, which also takes responsibility for 01104 // it. We should not have to delete any of these new models here. 01105 01106 AggregateWaveModel::ChannelSpecList components; 01107 01108 components.push_back(AggregateWaveModel::ModelChannelSpec 01109 (m_mainModel, -1)); 01110 01111 components.push_back(AggregateWaveModel::ModelChannelSpec 01112 (rm, -1)); 01113 01114 Model *aggregateModel = new AggregateWaveModel(components); 01115 ModelTransformer::Input aggregate(aggregateModel); 01116 01117 TransformId id = "vamp:match-vamp-plugin:match:path"; 01118 01119 TransformFactory *tf = TransformFactory::getInstance(); 01120 01121 Transform transform = tf->getDefaultTransformFor 01122 (id, aggregateModel->getSampleRate()); 01123 01124 transform.setStepSize(transform.getBlockSize()/2); 01125 transform.setParameter("serialise", 1); 01126 01127 SVDEBUG << "Document::alignModel: Alignment transform step size " << transform.getStepSize() << ", block size " << transform.getBlockSize() << endl; 01128 01129 ModelTransformerFactory *mtf = ModelTransformerFactory::getInstance(); 01130 01131 QString message; 01132 Model *transformOutput = mtf->transform(transform, aggregate, message); 01133 01134 if (!transformOutput) { 01135 transform.setStepSize(0); 01136 transformOutput = mtf->transform(transform, aggregate, message); 01137 } 01138 01139 SparseTimeValueModel *path = dynamic_cast<SparseTimeValueModel *> 01140 (transformOutput); 01141 01142 if (!path) { 01143 cerr << "Document::alignModel: ERROR: Failed to create alignment path (no MATCH plugin?)" << endl; 01144 emit alignmentFailed(id, message); 01145 delete transformOutput; 01146 delete aggregateModel; 01147 return; 01148 } 01149 01150 path->setCompletion(0); 01151 01152 AlignmentModel *alignmentModel = new AlignmentModel 01153 (m_mainModel, model, aggregateModel, path); 01154 01155 rm->setAlignment(alignmentModel); 01156 } 01157 01158 void 01159 Document::alignModels() 01160 { 01161 for (ModelMap::iterator i = m_models.begin(); i != m_models.end(); ++i) { 01162 alignModel(i->first); 01163 } 01164 alignModel(m_mainModel); 01165 } 01166 01167 Document::AddLayerCommand::AddLayerCommand(Document *d, 01168 View *view, 01169 Layer *layer) : 01170 m_d(d), 01171 m_view(view), 01172 m_layer(layer), 01173 m_name(qApp->translate("AddLayerCommand", "Add %1 Layer").arg(layer->objectName())), 01174 m_added(false) 01175 { 01176 } 01177 01178 Document::AddLayerCommand::~AddLayerCommand() 01179 { 01180 #ifdef DEBUG_DOCUMENT 01181 SVDEBUG << "Document::AddLayerCommand::~AddLayerCommand" << endl; 01182 #endif 01183 if (!m_added) { 01184 m_d->deleteLayer(m_layer); 01185 } 01186 } 01187 01188 QString 01189 Document::AddLayerCommand::getName() const 01190 { 01191 #ifdef DEBUG_DOCUMENT 01192 SVDEBUG << "Document::AddLayerCommand::getName(): Name is " 01193 << m_name << endl; 01194 #endif 01195 return m_name; 01196 } 01197 01198 void 01199 Document::AddLayerCommand::execute() 01200 { 01201 for (int i = 0; i < m_view->getLayerCount(); ++i) { 01202 if (m_view->getLayer(i) == m_layer) { 01203 // already there 01204 m_layer->setLayerDormant(m_view, false); 01205 m_added = true; 01206 return; 01207 } 01208 } 01209 01210 m_view->addLayer(m_layer); 01211 m_layer->setLayerDormant(m_view, false); 01212 01213 m_d->addToLayerViewMap(m_layer, m_view); 01214 m_added = true; 01215 } 01216 01217 void 01218 Document::AddLayerCommand::unexecute() 01219 { 01220 m_view->removeLayer(m_layer); 01221 m_layer->setLayerDormant(m_view, true); 01222 01223 m_d->removeFromLayerViewMap(m_layer, m_view); 01224 m_added = false; 01225 } 01226 01227 Document::RemoveLayerCommand::RemoveLayerCommand(Document *d, 01228 View *view, 01229 Layer *layer) : 01230 m_d(d), 01231 m_view(view), 01232 m_layer(layer), 01233 m_wasDormant(layer->isLayerDormant(view)), 01234 m_name(qApp->translate("RemoveLayerCommand", "Delete %1 Layer").arg(layer->objectName())), 01235 m_added(true) 01236 { 01237 } 01238 01239 Document::RemoveLayerCommand::~RemoveLayerCommand() 01240 { 01241 #ifdef DEBUG_DOCUMENT 01242 SVDEBUG << "Document::RemoveLayerCommand::~RemoveLayerCommand" << endl; 01243 #endif 01244 if (!m_added) { 01245 m_d->deleteLayer(m_layer); 01246 } 01247 } 01248 01249 QString 01250 Document::RemoveLayerCommand::getName() const 01251 { 01252 #ifdef DEBUG_DOCUMENT 01253 SVDEBUG << "Document::RemoveLayerCommand::getName(): Name is " 01254 << m_name << endl; 01255 #endif 01256 return m_name; 01257 } 01258 01259 void 01260 Document::RemoveLayerCommand::execute() 01261 { 01262 bool have = false; 01263 for (int i = 0; i < m_view->getLayerCount(); ++i) { 01264 if (m_view->getLayer(i) == m_layer) { 01265 have = true; 01266 break; 01267 } 01268 } 01269 01270 if (!have) { // not there! 01271 m_layer->setLayerDormant(m_view, true); 01272 m_added = false; 01273 return; 01274 } 01275 01276 m_view->removeLayer(m_layer); 01277 m_layer->setLayerDormant(m_view, true); 01278 01279 m_d->removeFromLayerViewMap(m_layer, m_view); 01280 m_added = false; 01281 } 01282 01283 void 01284 Document::RemoveLayerCommand::unexecute() 01285 { 01286 m_view->addLayer(m_layer); 01287 m_layer->setLayerDormant(m_view, m_wasDormant); 01288 01289 m_d->addToLayerViewMap(m_layer, m_view); 01290 m_added = true; 01291 } 01292 01293 void 01294 Document::toXml(QTextStream &out, QString indent, QString extraAttributes) const 01295 { 01296 toXml(out, indent, extraAttributes, false); 01297 } 01298 01299 void 01300 Document::toXmlAsTemplate(QTextStream &out, QString indent, QString extraAttributes) const 01301 { 01302 toXml(out, indent, extraAttributes, true); 01303 } 01304 01305 void 01306 Document::toXml(QTextStream &out, QString indent, QString extraAttributes, 01307 bool asTemplate) const 01308 { 01309 out << indent + QString("<data%1%2>\n") 01310 .arg(extraAttributes == "" ? "" : " ").arg(extraAttributes); 01311 01312 if (m_mainModel) { 01313 01314 if (asTemplate) { 01315 writePlaceholderMainModel(out, indent + " "); 01316 } else { 01317 m_mainModel->toXml(out, indent + " ", "mainModel=\"true\""); 01318 } 01319 01320 PlayParameters *playParameters = 01321 PlayParameterRepository::getInstance()->getPlayParameters(m_mainModel); 01322 if (playParameters) { 01323 playParameters->toXml 01324 (out, indent + " ", 01325 QString("model=\"%1\"") 01326 .arg(XmlExportable::getObjectExportId(m_mainModel))); 01327 } 01328 } 01329 01330 // Models that are not used in a layer that is in a view should 01331 // not be written. Get our list of required models first. 01332 01333 std::set<const Model *> used; 01334 01335 for (LayerViewMap::const_iterator i = m_layerViewMap.begin(); 01336 i != m_layerViewMap.end(); ++i) { 01337 01338 if (i->first && !i->second.empty() && i->first->getModel()) { 01339 used.insert(i->first->getModel()); 01340 } 01341 } 01342 01343 std::set<Model *> written; 01344 01345 for (ModelMap::const_iterator i = m_models.begin(); 01346 i != m_models.end(); ++i) { 01347 01348 Model *model = i->first; 01349 const ModelRecord &rec = i->second; 01350 01351 if (used.find(model) == used.end()) continue; 01352 01353 // We need an intelligent way to determine which models need 01354 // to be streamed (i.e. have been edited, or are small) and 01355 // which should not be (i.e. remain as generated by a 01356 // transform, and are large). 01357 // 01358 // At the moment we can get away with deciding not to stream 01359 // dense 3d models or writable wave file models, provided they 01360 // were generated from a transform, because at the moment there 01361 // is no way to edit those model types so it should be safe to 01362 // regenerate them. That won't always work in future though. 01363 // It would be particularly nice to be able to ask the user, 01364 // as well as making an intelligent guess. 01365 01366 bool writeModel = true; 01367 bool haveDerivation = false; 01368 01369 if (rec.source && rec.transform.getIdentifier() != "") { 01370 haveDerivation = true; 01371 } 01372 01373 if (haveDerivation) { 01374 if (dynamic_cast<const WritableWaveFileModel *>(model)) { 01375 writeModel = false; 01376 } else if (dynamic_cast<const DenseThreeDimensionalModel *>(model)) { 01377 writeModel = false; 01378 } 01379 } 01380 01381 if (writeModel) { 01382 model->toXml(out, indent + " "); 01383 written.insert(model); 01384 } 01385 01386 if (haveDerivation) { 01387 writeBackwardCompatibleDerivation(out, indent + " ", 01388 model, rec); 01389 } 01390 01392 PlayParameters *playParameters = 01393 PlayParameterRepository::getInstance()->getPlayParameters(model); 01394 if (playParameters) { 01395 playParameters->toXml 01396 (out, indent + " ", 01397 QString("model=\"%1\"") 01398 .arg(XmlExportable::getObjectExportId(model))); 01399 } 01400 } 01401 01403 01404 // We should write out the alignment models here. AlignmentModel 01405 // needs a toXml that writes out the export IDs of its reference 01406 // and aligned models, and then streams its path model. Note that 01407 // this will only work when the alignment is complete, so we 01408 // should probably wait for it if it isn't already by this point. 01409 01410 for (std::set<Model *>::const_iterator i = written.begin(); 01411 i != written.end(); ++i) { 01412 01413 const Model *model = *i; 01414 const AlignmentModel *alignment = model->getAlignment(); 01415 if (!alignment) continue; 01416 01417 alignment->toXml(out, indent + " "); 01418 } 01419 01420 for (LayerSet::const_iterator i = m_layers.begin(); 01421 i != m_layers.end(); ++i) { 01422 01423 (*i)->toXml(out, indent + " "); 01424 } 01425 01426 out << indent + "</data>\n"; 01427 } 01428 01429 void 01430 Document::writePlaceholderMainModel(QTextStream &out, QString indent) const 01431 { 01432 out << indent; 01433 out << QString("<model id=\"%1\" name=\"placeholder\" sampleRate=\"%2\" type=\"wavefile\" file=\":samples/silent.wav\" mainModel=\"true\"/>\n") 01434 .arg(getObjectExportId(m_mainModel)) 01435 .arg(m_mainModel->getSampleRate()); 01436 } 01437 01438 void 01439 Document::writeBackwardCompatibleDerivation(QTextStream &out, QString indent, 01440 Model *targetModel, 01441 const ModelRecord &rec) const 01442 { 01443 // There is a lot of redundancy in the XML we output here, because 01444 // we want it to work with older SV session file reading code as 01445 // well. 01446 // 01447 // Formerly, a transform was described using a derivation element 01448 // which set out the source and target models, execution context 01449 // (step size, input channel etc) and transform id, containing a 01450 // plugin element which set out the transform parameters and so 01451 // on. (The plugin element came from a "configurationXml" string 01452 // obtained from PluginXml.) 01453 // 01454 // This has been replaced by a derivation element setting out the 01455 // source and target models and input channel, containing a 01456 // transform element which sets out everything in the Transform. 01457 // 01458 // In order to retain compatibility with older SV code, however, 01459 // we have to write out the same stuff into the derivation as 01460 // before, and manufacture an appropriate plugin element as well 01461 // as the transform element. In order that newer code knows it's 01462 // dealing with a newer format, we will also write an attribute 01463 // 'type="transform"' in the derivation element. 01464 01465 const Transform &transform = rec.transform; 01466 01467 // Just for reference, this is what we would write if we didn't 01468 // have to be backward compatible: 01469 // 01470 // out << indent 01471 // << QString("<derivation type=\"transform\" source=\"%1\" " 01472 // "model=\"%2\" channel=\"%3\">\n") 01473 // .arg(XmlExportable::getObjectExportId(rec.source)) 01474 // .arg(XmlExportable::getObjectExportId(targetModel)) 01475 // .arg(rec.channel); 01476 // 01477 // transform.toXml(out, indent + " "); 01478 // 01479 // out << indent << "</derivation>\n"; 01480 // 01481 // Unfortunately, we can't just do that. So we do this... 01482 01483 QString extentsAttributes; 01484 if (transform.getStartTime() != RealTime::zeroTime || 01485 transform.getDuration() != RealTime::zeroTime) { 01486 extentsAttributes = QString("startFrame=\"%1\" duration=\"%2\" ") 01487 .arg(RealTime::realTime2Frame(transform.getStartTime(), 01488 targetModel->getSampleRate())) 01489 .arg(RealTime::realTime2Frame(transform.getDuration(), 01490 targetModel->getSampleRate())); 01491 } 01492 01493 out << indent; 01494 out << QString("<derivation type=\"transform\" source=\"%1\" " 01495 "model=\"%2\" channel=\"%3\" domain=\"%4\" " 01496 "stepSize=\"%5\" blockSize=\"%6\" %7windowType=\"%8\" " 01497 "transform=\"%9\">\n") 01498 .arg(XmlExportable::getObjectExportId(rec.source)) 01499 .arg(XmlExportable::getObjectExportId(targetModel)) 01500 .arg(rec.channel) 01501 .arg(TransformFactory::getInstance()->getTransformInputDomain 01502 (transform.getIdentifier())) 01503 .arg(transform.getStepSize()) 01504 .arg(transform.getBlockSize()) 01505 .arg(extentsAttributes) 01506 .arg(int(transform.getWindowType())) 01507 .arg(XmlExportable::encodeEntities(transform.getIdentifier())); 01508 01509 transform.toXml(out, indent + " "); 01510 01511 out << indent << " " 01512 << TransformFactory::getInstance()->getPluginConfigurationXml(transform); 01513 01514 out << indent << "</derivation>\n"; 01515 } 01516