Mercurial > hg > svapp
comparison framework/SVFileReader.cpp @ 685:7540733f5480 by-id
Overhaul SV file reader etc
| author | Chris Cannam | 
|---|---|
| date | Thu, 04 Jul 2019 14:31:22 +0100 | 
| parents | c7406ebcd51c | 
| children | 610fa108fbcc | 
   comparison
  equal
  deleted
  inserted
  replaced
| 684:5e9b1956b609 | 685:7540733f5480 | 
|---|---|
| 56 QString location) : | 56 QString location) : | 
| 57 m_document(document), | 57 m_document(document), | 
| 58 m_paneCallback(callback), | 58 m_paneCallback(callback), | 
| 59 m_location(location), | 59 m_location(location), | 
| 60 m_currentPane(nullptr), | 60 m_currentPane(nullptr), | 
| 61 m_currentDataset(XmlExportable::NO_ID), | |
| 61 m_currentLayer(nullptr), | 62 m_currentLayer(nullptr), | 
| 62 m_currentDataset(nullptr), | 63 m_pendingDerivedModel(XmlExportable::NO_ID), | 
| 63 m_currentDerivedModel(nullptr), | |
| 64 m_currentDerivedModelId(-1), | |
| 65 m_currentPlayParameters(nullptr), | 64 m_currentPlayParameters(nullptr), | 
| 66 m_currentTransformSource(nullptr), | |
| 67 m_currentTransformChannel(0), | 65 m_currentTransformChannel(0), | 
| 68 m_currentTransformIsNewStyle(true), | 66 m_currentTransformIsNewStyle(true), | 
| 69 m_datasetSeparator(" "), | 67 m_datasetSeparator(" "), | 
| 70 m_inRow(false), | 68 m_inRow(false), | 
| 71 m_inLayer(false), | 69 m_inLayer(false), | 
| 106 SVCERR << "WARNING: SV-XML: File ended with " | 104 SVCERR << "WARNING: SV-XML: File ended with " | 
| 107 << m_awaitingDatasets.size() << " unfilled model dataset(s)" | 105 << m_awaitingDatasets.size() << " unfilled model dataset(s)" | 
| 108 << endl; | 106 << endl; | 
| 109 } | 107 } | 
| 110 | 108 | 
| 111 std::set<Model *> unaddedModels; | 109 std::set<ModelId> unaddedModels; | 
| 112 | 110 | 
| 113 for (std::map<int, Model *>::iterator i = m_models.begin(); | 111 for (auto i: m_models) { | 
| 114 i != m_models.end(); ++i) { | 112 if (m_addedModels.find(i.second) == m_addedModels.end()) { | 
| 115 if (m_addedModels.find(i->second) == m_addedModels.end()) { | 113 unaddedModels.insert(i.second); | 
| 116 unaddedModels.insert(i->second); | |
| 117 } | 114 } | 
| 118 } | 115 } | 
| 119 | 116 | 
| 120 if (!unaddedModels.empty()) { | 117 if (!unaddedModels.empty()) { | 
| 121 SVCERR << "WARNING: SV-XML: File contained " | 118 SVCERR << "WARNING: SV-XML: File contained " | 
| 122 << unaddedModels.size() << " unused models" | 119 << unaddedModels.size() << " unused models" | 
| 123 << endl; | 120 << endl; | 
| 124 while (!unaddedModels.empty()) { | 121 for (auto m: unaddedModels) { | 
| 125 delete *unaddedModels.begin(); | 122 ModelById::release(m); | 
| 126 unaddedModels.erase(unaddedModels.begin()); | 123 } | 
| 127 } | 124 } | 
| 128 } | 125 | 
| 126 if (!m_paths.empty()) { | |
| 127 SVCERR << "WARNING: SV-XML: File contained " | |
| 128 << m_paths.size() << " unused paths" | |
| 129 << endl; | |
| 130 for (auto p: m_paths) { | |
| 131 delete p.second; | |
| 132 } | |
| 133 } | |
| 129 } | 134 } | 
| 130 | 135 | 
| 131 bool | 136 bool | 
| 132 SVFileReader::startElement(const QString &, const QString &, | 137 SVFileReader::startElement(const QString &, const QString &, | 
| 133 const QString &qName, | 138 const QString &qName, | 
| 275 { | 280 { | 
| 276 QString name = qName.toLower(); | 281 QString name = qName.toLower(); | 
| 277 | 282 | 
| 278 if (name == "dataset") { | 283 if (name == "dataset") { | 
| 279 | 284 | 
| 280 if (m_currentDataset) { | 285 if (m_currentDataset != XmlExportable::NO_ID) { | 
| 281 | 286 | 
| 282 bool foundInAwaiting = false; | 287 bool foundInAwaiting = false; | 
| 283 | 288 | 
| 284 for (std::map<int, int>::iterator i = m_awaitingDatasets.begin(); | 289 for (auto i: m_awaitingDatasets) { | 
| 285 i != m_awaitingDatasets.end(); ++i) { | 290 if (i.second == m_currentDataset) { | 
| 286 if (haveModel(i->second) && | 291 m_awaitingDatasets.erase(i.first); | 
| 287 m_models[i->second] == m_currentDataset) { | |
| 288 m_awaitingDatasets.erase(i); | |
| 289 foundInAwaiting = true; | 292 foundInAwaiting = true; | 
| 290 break; | 293 break; | 
| 291 } | 294 } | 
| 292 } | 295 } | 
| 293 | 296 | 
| 294 if (!foundInAwaiting) { | 297 if (!foundInAwaiting) { | 
| 295 SVCERR << "WARNING: SV-XML: Dataset precedes model, or no model uses dataset" << endl; | 298 SVCERR << "WARNING: SV-XML: Dataset precedes model, or no model uses dataset" << endl; | 
| 296 } | 299 } | 
| 297 } | 300 } | 
| 298 | 301 | 
| 299 m_currentDataset = nullptr; | 302 m_currentDataset = XmlExportable::NO_ID; | 
| 300 | 303 | 
| 301 } else if (name == "data") { | 304 } else if (name == "data") { | 
| 302 | 305 | 
| 303 addUnaddedModels(); | 306 addUnaddedModels(); | 
| 304 m_inData = false; | 307 m_inData = false; | 
| 305 | 308 | 
| 306 } else if (name == "derivation") { | 309 } else if (name == "derivation") { | 
| 307 | 310 | 
| 308 if (!m_currentDerivedModel) { | 311 if (m_currentDerivedModel.isNone()) { | 
| 309 if (m_currentDerivedModelId < 0) { | 312 if (m_pendingDerivedModel == XmlExportable::NO_ID) { | 
| 310 SVCERR << "WARNING: SV-XML: Bad derivation output model id " | 313 SVCERR << "WARNING: SV-XML: No valid output model id " | 
| 311 << m_currentDerivedModelId << endl; | 314 << "for derivation" << endl; | 
| 312 } else if (haveModel(m_currentDerivedModelId)) { | 315 } else if (haveModel(m_pendingDerivedModel)) { | 
| 313 SVCERR << "WARNING: SV-XML: Derivation has existing model " | 316 SVCERR << "WARNING: SV-XML: Derivation has existing model " | 
| 314 << m_currentDerivedModelId | 317 << m_pendingDerivedModel | 
| 315 << " as target, not regenerating" << endl; | 318 << " as target, not regenerating" << endl; | 
| 316 } else { | 319 } else { | 
| 317 QString message; | 320 QString message; | 
| 318 m_currentDerivedModel = m_models[m_currentDerivedModelId] = | 321 m_currentDerivedModel = m_models[m_pendingDerivedModel] = | 
| 319 m_document->addDerivedModel | 322 m_document->addDerivedModel | 
| 320 (m_currentTransform, | 323 (m_currentTransform, | 
| 321 ModelTransformer::Input(m_currentTransformSource, | 324 ModelTransformer::Input(m_currentTransformSource, | 
| 322 m_currentTransformChannel), | 325 m_currentTransformChannel), | 
| 323 message); | 326 message); | 
| 324 if (!m_currentDerivedModel) { | 327 if (m_currentDerivedModel.isNone()) { | 
| 325 emit modelRegenerationFailed(tr("(derived model in SV-XML)"), | 328 emit modelRegenerationFailed(tr("(derived model in SV-XML)"), | 
| 326 m_currentTransform.getIdentifier(), | 329 m_currentTransform.getIdentifier(), | 
| 327 message); | 330 message); | 
| 328 } else if (message != "") { | 331 } else if (message != "") { | 
| 329 emit modelRegenerationWarning(tr("(derived model in SV-XML)"), | 332 emit modelRegenerationWarning(tr("(derived model in SV-XML)"), | 
| 338 m_currentTransformChannel), | 341 m_currentTransformChannel), | 
| 339 m_currentDerivedModel); | 342 m_currentDerivedModel); | 
| 340 } | 343 } | 
| 341 | 344 | 
| 342 m_addedModels.insert(m_currentDerivedModel); | 345 m_addedModels.insert(m_currentDerivedModel); | 
| 343 m_currentDerivedModel = nullptr; | 346 m_currentDerivedModel = {}; | 
| 344 m_currentDerivedModelId = -1; | 347 m_pendingDerivedModel = XmlExportable::NO_ID; | 
| 345 m_currentTransformSource = nullptr; | 348 m_currentTransformSource = {}; | 
| 346 m_currentTransform = Transform(); | 349 m_currentTransform = Transform(); | 
| 347 m_currentTransformChannel = -1; | 350 m_currentTransformChannel = -1; | 
| 348 | 351 | 
| 349 } else if (name == "row") { | 352 } else if (name == "row") { | 
| 350 m_inRow = false; | 353 m_inRow = false; | 
| 404 } | 407 } | 
| 405 | 408 | 
| 406 void | 409 void | 
| 407 SVFileReader::makeAggregateModels() | 410 SVFileReader::makeAggregateModels() | 
| 408 { | 411 { | 
| 409 std::map<int, PendingAggregateRec> stillPending; | 412 std::map<ExportId, PendingAggregateRec> stillPending; | 
| 410 | 413 | 
| 411 for (auto p: m_pendingAggregates) { | 414 for (auto p: m_pendingAggregates) { | 
| 412 | 415 | 
| 413 int id = p.first; | 416 int id = p.first; | 
| 414 const PendingAggregateRec &rec = p.second; | 417 const PendingAggregateRec &rec = p.second; | 
| 415 bool skip = false; | 418 bool skip = false; | 
| 416 | 419 | 
| 417 AggregateWaveModel::ChannelSpecList specs; | 420 AggregateWaveModel::ChannelSpecList specs; | 
| 418 for (int componentId: rec.components) { | 421 for (ExportId componentId: rec.components) { | 
| 419 bool found = false; | 422 bool found = false; | 
| 420 if (m_models.find(componentId) != m_models.end()) { | 423 if (m_models.find(componentId) != m_models.end()) { | 
| 421 RangeSummarisableTimeValueModel *rs = | 424 ModelId modelId = m_models[componentId]; | 
| 422 dynamic_cast<RangeSummarisableTimeValueModel *> | 425 auto rs = ModelById::getAs<RangeSummarisableTimeValueModel> | 
| 423 (m_models[componentId]); | 426 (modelId); | 
| 424 if (rs) { | 427 if (rs) { | 
| 425 //!!! NB difference between model id and model | |
| 426 //!!! export id - we need to be clearer about this | |
| 427 specs.push_back(AggregateWaveModel::ModelChannelSpec | 428 specs.push_back(AggregateWaveModel::ModelChannelSpec | 
| 428 (rs->getId(), -1)); | 429 (modelId, -1)); | 
| 429 found = true; | 430 found = true; | 
| 431 } else { | |
| 432 SVDEBUG << "SVFileReader::makeAggregateModels: " | |
| 433 << "Component model id " << componentId | |
| 434 << "in aggregate model id " << id | |
| 435 << "does not appear to be convertible to " | |
| 436 << "RangeSummarisableTimeValueModel" | |
| 437 << endl; | |
| 430 } | 438 } | 
| 431 } | 439 } | 
| 432 if (!found) { | 440 if (!found) { | 
| 433 SVDEBUG << "SVFileReader::makeAggregateModels:" | 441 SVDEBUG << "SVFileReader::makeAggregateModels: " | 
| 434 << "Unknown component model id " | 442 << "Unknown component model id " | 
| 435 << componentId << " in aggregate model id " << id | 443 << componentId << " in aggregate model id " << id | 
| 436 << ", hoping we won't be needing it just yet" | 444 << ", hoping we won't be needing it just yet" | 
| 437 << endl; | 445 << endl; | 
| 438 skip = true; | 446 skip = true; | 
| 440 } | 448 } | 
| 441 | 449 | 
| 442 if (skip) { | 450 if (skip) { | 
| 443 stillPending[id] = rec; | 451 stillPending[id] = rec; | 
| 444 } else { | 452 } else { | 
| 445 AggregateWaveModel *model = new AggregateWaveModel(specs); | 453 auto model = std::make_shared<AggregateWaveModel>(specs); | 
| 446 model->setObjectName(rec.name); | 454 model->setObjectName(rec.name); | 
| 447 | 455 m_models[id] = ModelById::add(model); | 
| 448 SVDEBUG << "SVFileReader::makeAggregateModels: created aggregate model id " | 456 | 
| 449 << id << " with " << specs.size() << " components" << endl; | 457 SVDEBUG << "SVFileReader::makeAggregateModels: created aggregate " | 
| 450 | 458 << "model id " << id << " with " << specs.size() | 
| 451 m_models[id] = model; | 459 << " components" << endl; | 
| 452 } | 460 } | 
| 453 } | 461 } | 
| 454 | 462 | 
| 455 m_pendingAggregates = stillPending; | 463 m_pendingAggregates = stillPending; | 
| 456 } | 464 } | 
| 457 | 465 | 
| 458 void | 466 void | 
| 459 SVFileReader::addUnaddedModels() | 467 SVFileReader::addUnaddedModels() | 
| 460 { | 468 { | 
| 461 makeAggregateModels(); | 469 makeAggregateModels(); | 
| 462 | 470 | 
| 463 for (std::map<int, Model *>::iterator i = m_models.begin(); | 471 for (auto i: m_models) { | 
| 464 i != m_models.end(); ++i) { | 472 | 
| 465 | 473 ModelId modelId = i.second; | 
| 466 Model *model = i->second; | 474 | 
| 467 | 475 if (m_addedModels.find(modelId) != m_addedModels.end()) { | 
| 468 if (m_addedModels.find(model) != m_addedModels.end()) { | |
| 469 // already added this one | 476 // already added this one | 
| 470 continue; | 477 continue; | 
| 471 } | 478 } | 
| 472 | 479 | 
| 473 // don't want to add path and alignment models to the | 480 //!!! todo: review this (i.e. who causes the release of what) | 
| 474 // document, because their lifespans are entirely dictated by | 481 | 
| 475 // the models that "own" them even though they were read | 482 // don't want to add alignment models to the document, because | 
| 476 // independently from the .sv file. (pity we don't have a | 483 // their lifespans are entirely dictated by the models that | 
| 477 // nicer way to handle this) | 484 // "own" them even though they were read independently from | 
| 478 if (!dynamic_cast<PathModel *>(model) && | 485 // the .sv file. (pity we don't have a nicer way to handle | 
| 479 !dynamic_cast<AlignmentModel *>(model)) { | 486 // this) | 
| 480 | 487 if (!ModelById::isa<AlignmentModel>(modelId)) { | 
| 481 m_document->addImportedModel(model); | 488 m_document->addImportedModel(modelId); | 
| 482 } | 489 } | 
| 483 | 490 | 
| 484 // but we add all models including path and alignment ones to | 491 // but we add all models including alignment ones to the added | 
| 485 // the added set, so they don't get deleted from our own | 492 // set, so they don't get released by our own destructor | 
| 486 // destructor | 493 m_addedModels.insert(modelId); | 
| 487 m_addedModels.insert(model); | |
| 488 } | 494 } | 
| 489 } | 495 } | 
| 490 | 496 | 
| 491 bool | 497 bool | 
| 492 SVFileReader::readModel(const QXmlAttributes &attributes) | 498 SVFileReader::readModel(const QXmlAttributes &attributes) | 
| 538 if (Preferences::getInstance()->getFixedSampleRate() != 0) { | 544 if (Preferences::getInstance()->getFixedSampleRate() != 0) { | 
| 539 rate = Preferences::getInstance()->getFixedSampleRate(); | 545 rate = Preferences::getInstance()->getFixedSampleRate(); | 
| 540 } else if (rate == 0 && | 546 } else if (rate == 0 && | 
| 541 !isMainModel && | 547 !isMainModel && | 
| 542 Preferences::getInstance()->getResampleOnLoad()) { | 548 Preferences::getInstance()->getResampleOnLoad()) { | 
| 543 WaveFileModel *mm = m_document->getMainModel(); | 549 auto mm = ModelById::getAs<WaveFileModel> | 
| 550 (m_document->getMainModel()); | |
| 544 if (mm) rate = mm->getSampleRate(); | 551 if (mm) rate = mm->getSampleRate(); | 
| 545 } | 552 } | 
| 546 | 553 | 
| 547 model = new ReadOnlyWaveFileModel(file, rate); | 554 model = new ReadOnlyWaveFileModel(file, rate); | 
| 548 if (!model->isOK()) { | 555 if (!model->isOK()) { | 
| 555 m_document->setIncomplete(true); | 562 m_document->setIncomplete(true); | 
| 556 return false; | 563 return false; | 
| 557 } | 564 } | 
| 558 | 565 | 
| 559 model->setObjectName(name); | 566 model->setObjectName(name); | 
| 560 m_models[id] = model; | 567 | 
| 568 ModelId modelId = model->getId(); | |
| 569 ModelById::add(std::shared_ptr<Model>(model)); | |
| 570 m_models[id] = modelId; | |
| 571 | |
| 561 if (isMainModel) { | 572 if (isMainModel) { | 
| 562 m_document->setMainModel(model); | 573 m_document->setMainModel(modelId); | 
| 563 m_addedModels.insert(model); | 574 m_addedModels.insert(modelId); | 
| 564 } | 575 } | 
| 565 // Derived models will be added when their derivation | 576 // Derived models will be added when their derivation | 
| 566 // is found. | 577 // is found. | 
| 567 | 578 | 
| 568 return true; | 579 return true; | 
| 570 } else if (type == "aggregatewave") { | 581 } else if (type == "aggregatewave") { | 
| 571 | 582 | 
| 572 QString components = attributes.value("components"); | 583 QString components = attributes.value("components"); | 
| 573 QStringList componentIdStrings = components.split(","); | 584 QStringList componentIdStrings = components.split(","); | 
| 574 std::vector<int> componentIds; | 585 std::vector<int> componentIds; | 
| 575 for (auto cid: componentIdStrings) { | 586 for (auto cidStr: componentIdStrings) { | 
| 576 bool ok = false; | 587 bool ok = false; | 
| 577 int id = cid.toInt(&ok); | 588 int cid = cidStr.toInt(&ok); | 
| 578 if (!ok) { | 589 if (!ok) { | 
| 579 SVCERR << "SVFileReader::readModel: Failed to convert component model id from part \"" << cid << "\" in \"" << components << "\"" << endl; | 590 SVCERR << "SVFileReader::readModel: Failed to convert component model id from part \"" << cidStr << "\" in \"" << components << "\"" << endl; | 
| 580 } else { | 591 } else { | 
| 581 componentIds.push_back(id); | 592 componentIds.push_back(cid); | 
| 582 } | 593 } | 
| 583 } | 594 } | 
| 584 PendingAggregateRec rec { name, sampleRate, componentIds }; | 595 PendingAggregateRec rec { name, sampleRate, componentIds }; | 
| 585 m_pendingAggregates[id] = rec; | 596 m_pendingAggregates[id] = rec; | 
| 586 | 597 | 
| 603 if (dimensions == 3) { | 614 if (dimensions == 3) { | 
| 604 | 615 | 
| 605 READ_MANDATORY(int, windowSize, toInt); | 616 READ_MANDATORY(int, windowSize, toInt); | 
| 606 READ_MANDATORY(int, yBinCount, toInt); | 617 READ_MANDATORY(int, yBinCount, toInt); | 
| 607 | 618 | 
| 608 EditableDenseThreeDimensionalModel *model = | 619 auto model = std::make_shared<EditableDenseThreeDimensionalModel> | 
| 609 new EditableDenseThreeDimensionalModel | |
| 610 (sampleRate, windowSize, yBinCount, | 620 (sampleRate, windowSize, yBinCount, | 
| 611 EditableDenseThreeDimensionalModel::NoCompression); | 621 EditableDenseThreeDimensionalModel::NoCompression); | 
| 622 | |
| 623 model->setObjectName(name); | |
| 624 m_models[id] = ModelById::add(model); | |
| 612 | 625 | 
| 613 float minimum = attributes.value("minimum").trimmed().toFloat(&ok); | 626 float minimum = attributes.value("minimum").trimmed().toFloat(&ok); | 
| 614 if (ok) model->setMinimumLevel(minimum); | 627 if (ok) model->setMinimumLevel(minimum); | 
| 615 | 628 | 
| 616 float maximum = attributes.value("maximum").trimmed().toFloat(&ok); | 629 float maximum = attributes.value("maximum").trimmed().toFloat(&ok); | 
| 620 if (ok) m_awaitingDatasets[dataset] = id; | 633 if (ok) m_awaitingDatasets[dataset] = id; | 
| 621 | 634 | 
| 622 int startFrame = attributes.value("startFrame").trimmed().toInt(&ok); | 635 int startFrame = attributes.value("startFrame").trimmed().toInt(&ok); | 
| 623 if (ok) model->setStartFrame(startFrame); | 636 if (ok) model->setStartFrame(startFrame); | 
| 624 | 637 | 
| 625 model->setObjectName(name); | |
| 626 m_models[id] = model; | |
| 627 return true; | 638 return true; | 
| 628 | 639 | 
| 629 } else { | 640 } else { | 
| 630 | 641 | 
| 631 SVCERR << "WARNING: SV-XML: Unexpected dense model dimension (" | 642 SVCERR << "WARNING: SV-XML: Unexpected dense model dimension (" | 
| 636 READ_MANDATORY(int, dimensions, toInt); | 647 READ_MANDATORY(int, dimensions, toInt); | 
| 637 | 648 | 
| 638 if (dimensions == 1) { | 649 if (dimensions == 1) { | 
| 639 | 650 | 
| 640 READ_MANDATORY(int, resolution, toInt); | 651 READ_MANDATORY(int, resolution, toInt); | 
| 641 | 652 | 
| 642 if (attributes.value("subtype") == "image") { | 653 if (attributes.value("subtype") == "image") { | 
| 643 | 654 | 
| 644 bool notifyOnAdd = (attributes.value("notifyOnAdd") == "true"); | 655 bool notifyOnAdd = (attributes.value("notifyOnAdd") == "true"); | 
| 645 ImageModel *model = new ImageModel(sampleRate, resolution, | 656 auto model = std::make_shared<ImageModel> | 
| 646 notifyOnAdd); | 657 (sampleRate, resolution, notifyOnAdd); | 
| 647 model->setObjectName(name); | 658 model->setObjectName(name); | 
| 648 m_models[id] = model; | 659 m_models[id] = ModelById::add(model); | 
| 649 | 660 | 
| 650 } else { | 661 } else { | 
| 651 | 662 | 
| 652 SparseOneDimensionalModel *model = new SparseOneDimensionalModel | 663 auto model = std::make_shared<SparseOneDimensionalModel> | 
| 653 (sampleRate, resolution); | 664 (sampleRate, resolution); | 
| 654 model->setObjectName(name); | 665 model->setObjectName(name); | 
| 655 m_models[id] = model; | 666 m_models[id] = ModelById::add(model); | 
| 656 } | 667 } | 
| 657 | 668 | 
| 658 int dataset = attributes.value("dataset").trimmed().toInt(&ok); | 669 int dataset = attributes.value("dataset").trimmed().toInt(&ok); | 
| 659 if (ok) m_awaitingDatasets[dataset] = id; | 670 if (ok) m_awaitingDatasets[dataset] = id; | 
| 660 | 671 | 
| 677 | 688 | 
| 678 QString units = attributes.value("units"); | 689 QString units = attributes.value("units"); | 
| 679 | 690 | 
| 680 if (dimensions == 2) { | 691 if (dimensions == 2) { | 
| 681 if (attributes.value("subtype") == "text") { | 692 if (attributes.value("subtype") == "text") { | 
| 682 TextModel *model = new TextModel | 693 auto model = std::make_shared<TextModel> | 
| 683 (sampleRate, resolution, notifyOnAdd); | 694 (sampleRate, resolution, notifyOnAdd); | 
| 684 model->setObjectName(name); | 695 model->setObjectName(name); | 
| 685 m_models[id] = model; | 696 m_models[id] = ModelById::add(model); | 
| 686 } else if (attributes.value("subtype") == "path") { | 697 } else if (attributes.value("subtype") == "path") { | 
| 687 PathModel *model = new PathModel | 698 // Paths are no longer actually models | 
| 688 (sampleRate, resolution, notifyOnAdd); | 699 Path *path = new Path(sampleRate, resolution); | 
| 689 model->setObjectName(name); | 700 m_paths[id] = path; | 
| 690 m_models[id] = model; | |
| 691 } else { | 701 } else { | 
| 692 SparseTimeValueModel *model; | 702 std::shared_ptr<SparseTimeValueModel> model; | 
| 693 if (haveMinMax) { | 703 if (haveMinMax) { | 
| 694 model = new SparseTimeValueModel | 704 model = std::make_shared<SparseTimeValueModel> | 
| 695 (sampleRate, resolution, minimum, maximum, notifyOnAdd); | 705 (sampleRate, resolution, minimum, maximum, | 
| 706 notifyOnAdd); | |
| 696 } else { | 707 } else { | 
| 697 model = new SparseTimeValueModel | 708 model = std::make_shared<SparseTimeValueModel> | 
| 698 (sampleRate, resolution, notifyOnAdd); | 709 (sampleRate, resolution, notifyOnAdd); | 
| 699 } | 710 } | 
| 700 model->setScaleUnits(units); | 711 model->setScaleUnits(units); | 
| 701 model->setObjectName(name); | 712 model->setObjectName(name); | 
| 702 m_models[id] = model; | 713 m_models[id] = ModelById::add(model); | 
| 703 } | 714 } | 
| 704 } else { | 715 } else { | 
| 705 if (attributes.value("subtype") == "region") { | 716 if (attributes.value("subtype") == "region") { | 
| 706 RegionModel *model; | 717 std::shared_ptr<RegionModel> model; | 
| 707 if (haveMinMax) { | 718 if (haveMinMax) { | 
| 708 model = new RegionModel | 719 model = std::make_shared<RegionModel> | 
| 709 (sampleRate, resolution, minimum, maximum, notifyOnAdd); | 720 (sampleRate, resolution, minimum, maximum, | 
| 721 notifyOnAdd); | |
| 710 } else { | 722 } else { | 
| 711 model = new RegionModel | 723 model = std::make_shared<RegionModel> | 
| 712 (sampleRate, resolution, notifyOnAdd); | 724 (sampleRate, resolution, notifyOnAdd); | 
| 713 } | 725 } | 
| 714 model->setValueQuantization(valueQuantization); | 726 model->setValueQuantization(valueQuantization); | 
| 715 model->setScaleUnits(units); | 727 model->setScaleUnits(units); | 
| 716 model->setObjectName(name); | 728 model->setObjectName(name); | 
| 717 m_models[id] = model; | 729 m_models[id] = ModelById::add(model); | 
| 718 } else if (attributes.value("subtype") == "flexinote") { | 730 } else if (attributes.value("subtype") == "flexinote") { | 
| 719 NoteModel *model; | 731 std::shared_ptr<NoteModel> model; | 
| 720 if (haveMinMax) { | 732 if (haveMinMax) { | 
| 721 model = new NoteModel | 733 model = std::make_shared<NoteModel> | 
| 722 (sampleRate, resolution, minimum, maximum, | 734 (sampleRate, resolution, minimum, maximum, | 
| 723 notifyOnAdd, | 735 notifyOnAdd, | 
| 724 NoteModel::FLEXI_NOTE); | 736 NoteModel::FLEXI_NOTE); | 
| 725 } else { | 737 } else { | 
| 726 model = new NoteModel | 738 model = std::make_shared<NoteModel> | 
| 727 (sampleRate, resolution, notifyOnAdd, | 739 (sampleRate, resolution, notifyOnAdd, | 
| 728 NoteModel::FLEXI_NOTE); | 740 NoteModel::FLEXI_NOTE); | 
| 729 } | 741 } | 
| 730 model->setValueQuantization(valueQuantization); | 742 model->setValueQuantization(valueQuantization); | 
| 731 model->setScaleUnits(units); | 743 model->setScaleUnits(units); | 
| 732 model->setObjectName(name); | 744 model->setObjectName(name); | 
| 733 m_models[id] = model; | 745 m_models[id] = ModelById::add(model); | 
| 734 } else { | 746 } else { | 
| 735 // note models written out by SV 1.3 and earlier | 747 // note models written out by SV 1.3 and earlier | 
| 736 // have no subtype, so we can't test that | 748 // have no subtype, so we can't test that | 
| 737 NoteModel *model; | 749 std::shared_ptr<NoteModel> model; | 
| 738 if (haveMinMax) { | 750 if (haveMinMax) { | 
| 739 model = new NoteModel | 751 model = std::make_shared<NoteModel> | 
| 740 (sampleRate, resolution, minimum, maximum, notifyOnAdd); | 752 (sampleRate, resolution, minimum, maximum, notifyOnAdd); | 
| 741 } else { | 753 } else { | 
| 742 model = new NoteModel | 754 model = std::make_shared<NoteModel> | 
| 743 (sampleRate, resolution, notifyOnAdd); | 755 (sampleRate, resolution, notifyOnAdd); | 
| 744 } | 756 } | 
| 745 model->setValueQuantization(valueQuantization); | 757 model->setValueQuantization(valueQuantization); | 
| 746 model->setScaleUnits(units); | 758 model->setScaleUnits(units); | 
| 747 model->setObjectName(name); | 759 model->setObjectName(name); | 
| 748 m_models[id] = model; | 760 m_models[id] = ModelById::add(model); | 
| 749 } | 761 } | 
| 750 } | 762 } | 
| 751 | 763 | 
| 752 int dataset = attributes.value("dataset").trimmed().toInt(&ok); | 764 int dataset = attributes.value("dataset").trimmed().toInt(&ok); | 
| 753 if (ok) m_awaitingDatasets[dataset] = id; | 765 if (ok) m_awaitingDatasets[dataset] = id; | 
| 764 | 776 | 
| 765 READ_MANDATORY(int, reference, toInt); | 777 READ_MANDATORY(int, reference, toInt); | 
| 766 READ_MANDATORY(int, aligned, toInt); | 778 READ_MANDATORY(int, aligned, toInt); | 
| 767 READ_MANDATORY(int, path, toInt); | 779 READ_MANDATORY(int, path, toInt); | 
| 768 | 780 | 
| 769 Model *refModel = nullptr, *alignedModel = nullptr, *pathModel = nullptr; | 781 ModelId refModel, alignedModel; | 
| 782 Path *pathPtr = nullptr; | |
| 770 | 783 | 
| 771 if (m_models.find(reference) != m_models.end()) { | 784 if (m_models.find(reference) != m_models.end()) { | 
| 772 refModel = m_models[reference]; | 785 refModel = m_models[reference]; | 
| 773 } else { | 786 } else { | 
| 774 SVCERR << "WARNING: SV-XML: Unknown reference model id " | 787 SVCERR << "WARNING: SV-XML: Unknown reference model id " | 
| 782 SVCERR << "WARNING: SV-XML: Unknown aligned model id " | 795 SVCERR << "WARNING: SV-XML: Unknown aligned model id " | 
| 783 << aligned << " in alignment model id " << id | 796 << aligned << " in alignment model id " << id | 
| 784 << endl; | 797 << endl; | 
| 785 } | 798 } | 
| 786 | 799 | 
| 787 if (m_models.find(path) != m_models.end()) { | 800 if (m_paths.find(path) != m_paths.end()) { | 
| 788 pathModel = m_models[path]; | 801 pathPtr = m_paths[path]; | 
| 789 } else { | 802 } else { | 
| 790 SVCERR << "WARNING: SV-XML: Unknown path model id " | 803 SVCERR << "WARNING: SV-XML: Unknown path id " | 
| 791 << path << " in alignment model id " << id | 804 << path << " in alignment model id " << id | 
| 792 << endl; | 805 << endl; | 
| 793 } | 806 } | 
| 794 | 807 | 
| 795 if (refModel && alignedModel && pathModel) { | 808 if (!refModel.isNone() && !alignedModel.isNone() && pathPtr) { | 
| 796 AlignmentModel *model = new AlignmentModel | 809 auto model = std::make_shared<AlignmentModel> | 
| 797 (refModel, alignedModel, nullptr); | 810 (refModel, alignedModel, ModelId()); | 
| 798 PathModel *pm = dynamic_cast<PathModel *>(pathModel); | 811 model->setPath(*pathPtr); | 
| 799 if (!pm) { | |
| 800 SVCERR << "WARNING: SV-XML: Model id " << path | |
| 801 << " referenced as path for alignment " << id | |
| 802 << " is not a path model" << endl; | |
| 803 } else { | |
| 804 model->setPath(pm); | |
| 805 pm->setCompletion(100); | |
| 806 } | |
| 807 model->setObjectName(name); | 812 model->setObjectName(name); | 
| 808 m_models[id] = model; | 813 m_models[id] = ModelById::add(model); | 
| 809 alignedModel->setAlignment(model); | 814 if (auto am = ModelById::get(alignedModel)) { | 
| 815 am->setAlignment(m_models[id]); | |
| 816 } | |
| 810 return true; | 817 return true; | 
| 818 } | |
| 819 | |
| 820 if (pathPtr) { | |
| 821 delete pathPtr; | |
| 822 m_paths.erase(path); | |
| 811 } | 823 } | 
| 812 | 824 | 
| 813 } else { | 825 } else { | 
| 814 | 826 | 
| 815 SVCERR << "WARNING: SV-XML: Unexpected model type \"" | 827 SVCERR << "WARNING: SV-XML: Unexpected model type \"" | 
| 972 bool modelOk = false; | 984 bool modelOk = false; | 
| 973 modelId = attributes.value("model").trimmed().toInt(&modelOk); | 985 modelId = attributes.value("model").trimmed().toInt(&modelOk); | 
| 974 | 986 | 
| 975 if (modelOk) { | 987 if (modelOk) { | 
| 976 if (haveModel(modelId)) { | 988 if (haveModel(modelId)) { | 
| 977 Model *model = m_models[modelId]; | 989 m_document->setModel(layer, m_models[modelId]); | 
| 978 m_document->setModel(layer, model); | |
| 979 } else { | 990 } else { | 
| 980 SVCERR << "WARNING: SV-XML: Unknown model id " << modelId | 991 SVCERR << "WARNING: SV-XML: Unknown model id " << modelId | 
| 981 << " in layer definition" << endl; | 992 << " in layer definition" << endl; | 
| 982 if (!layer->canExistWithoutModel()) { | 993 if (!layer->canExistWithoutModel()) { | 
| 983 // Don't add a layer with an unknown model id | 994 // Don't add a layer with an unknown model id | 
| 984 // unless it explicitly supports this state | 995 // unless it explicitly supports this state | 
| 985 m_document->deleteLayer(layer); | 996 m_document->deleteLayer(layer); | 
| 986 m_layers[id] = layer = nullptr; | 997 m_layers[id] = layer = nullptr; | 
| 1028 if (m_awaitingDatasets.find(id) == m_awaitingDatasets.end()) { | 1039 if (m_awaitingDatasets.find(id) == m_awaitingDatasets.end()) { | 
| 1029 SVCERR << "WARNING: SV-XML: Unwanted dataset " << id << endl; | 1040 SVCERR << "WARNING: SV-XML: Unwanted dataset " << id << endl; | 
| 1030 return false; | 1041 return false; | 
| 1031 } | 1042 } | 
| 1032 | 1043 | 
| 1033 int modelId = m_awaitingDatasets[id]; | 1044 int awaitingId = m_awaitingDatasets[id]; | 
| 1045 | |
| 1046 ModelId modelId; | |
| 1047 Path *path = nullptr; | |
| 1034 | 1048 | 
| 1035 Model *model = nullptr; | 1049 if (haveModel(awaitingId)) { | 
| 1036 if (haveModel(modelId)) { | 1050 modelId = m_models[awaitingId]; | 
| 1037 model = m_models[modelId]; | 1051 } else if (m_paths.find(awaitingId) != m_paths.end()) { | 
| 1052 path = m_paths[awaitingId]; | |
| 1038 } else { | 1053 } else { | 
| 1039 SVCERR << "WARNING: SV-XML: Internal error: Unknown model " << modelId | 1054 SVCERR << "WARNING: SV-XML: Internal error: Unknown model or path " | 
| 1040 << " expecting dataset " << id << endl; | 1055 << modelId << " awaiting dataset " << id << endl; | 
| 1041 return false; | 1056 return false; | 
| 1042 } | 1057 } | 
| 1043 | 1058 | 
| 1044 bool good = false; | 1059 bool good = false; | 
| 1045 | 1060 | 
| 1046 switch (dimensions) { | 1061 switch (dimensions) { | 
| 1047 case 1: | 1062 case 1: | 
| 1048 if (dynamic_cast<SparseOneDimensionalModel *>(model)) good = true; | 1063 good = | 
| 1049 else if (dynamic_cast<ImageModel *>(model)) good = true; | 1064 (ModelById::isa<SparseOneDimensionalModel>(modelId) || | 
| 1065 ModelById::isa<ImageModel>(modelId)); | |
| 1050 break; | 1066 break; | 
| 1051 | 1067 | 
| 1052 case 2: | 1068 case 2: | 
| 1053 if (dynamic_cast<SparseTimeValueModel *>(model)) good = true; | 1069 good = | 
| 1054 else if (dynamic_cast<TextModel *>(model)) good = true; | 1070 (ModelById::isa<SparseTimeValueModel>(modelId) || | 
| 1055 else if (dynamic_cast<PathModel *>(model)) good = true; | 1071 ModelById::isa<TextModel>(modelId) || | 
| 1072 path); | |
| 1056 break; | 1073 break; | 
| 1057 | 1074 | 
| 1058 case 3: | 1075 case 3: | 
| 1059 if (dynamic_cast<NoteModel *>(model)) good = true; | 1076 if (ModelById::isa<EditableDenseThreeDimensionalModel>(modelId)) { | 
| 1060 else if (dynamic_cast<RegionModel *>(model)) good = true; | 1077 good = true; | 
| 1061 else if (dynamic_cast<EditableDenseThreeDimensionalModel *>(model)) { | |
| 1062 m_datasetSeparator = attributes.value("separator"); | 1078 m_datasetSeparator = attributes.value("separator"); | 
| 1063 good = true; | 1079 } else { | 
| 1080 good = | |
| 1081 (ModelById::isa<NoteModel>(modelId) || | |
| 1082 ModelById::isa<RegionModel>(modelId)); | |
| 1064 } | 1083 } | 
| 1065 break; | 1084 break; | 
| 1066 } | 1085 } | 
| 1067 | 1086 | 
| 1068 if (!good) { | 1087 if (!good) { | 
| 1069 SVCERR << "WARNING: SV-XML: Model id " << modelId << " has wrong number of dimensions or inappropriate type for " << dimensions << "-D dataset " << id << endl; | 1088 SVCERR << "WARNING: SV-XML: Model id " << modelId << " has wrong number of dimensions or inappropriate type for " << dimensions << "-D dataset " << id << endl; | 
| 1070 m_currentDataset = nullptr; | 1089 m_currentDataset = XmlExportable::NO_ID; | 
| 1071 return false; | 1090 return false; | 
| 1072 } | 1091 } | 
| 1073 | 1092 | 
| 1074 m_currentDataset = model; | 1093 m_currentDataset = awaitingId; | 
| 1075 return true; | 1094 return true; | 
| 1076 } | 1095 } | 
| 1077 | 1096 | 
| 1078 bool | 1097 bool | 
| 1079 SVFileReader::addPointToDataset(const QXmlAttributes &attributes) | 1098 SVFileReader::addPointToDataset(const QXmlAttributes &attributes) | 
| 1080 { | 1099 { | 
| 1081 bool ok = false; | 1100 bool ok = false; | 
| 1082 | 1101 | 
| 1083 READ_MANDATORY(int, frame, toInt); | 1102 READ_MANDATORY(int, frame, toInt); | 
| 1084 | 1103 | 
| 1085 // SVDEBUG << "SVFileReader::addPointToDataset: frame = " << frame << endl; | 1104 if (m_paths.find(m_currentDataset) != m_paths.end()) { | 
| 1086 | 1105 Path *path = m_paths[m_currentDataset]; | 
| 1087 SparseOneDimensionalModel *sodm = dynamic_cast<SparseOneDimensionalModel *> | 1106 int mapframe = attributes.value("mapframe").trimmed().toInt(&ok); | 
| 1088 (m_currentDataset); | 1107 path->add(PathPoint(frame, mapframe)); | 
| 1089 | 1108 return ok; | 
| 1090 if (sodm) { | 1109 } | 
| 1091 // SVCERR << "Current dataset is a sparse one dimensional model" << endl; | 1110 | 
| 1111 if (!haveModel(m_currentDataset)) { | |
| 1112 SVCERR << "WARNING: SV-XML: Point element found in non-point dataset" | |
| 1113 << endl; | |
| 1114 return false; | |
| 1115 } | |
| 1116 | |
| 1117 ModelId modelId = m_models[m_currentDataset]; | |
| 1118 | |
| 1119 if (auto sodm = ModelById::getAs<SparseOneDimensionalModel>(modelId)) { | |
| 1092 QString label = attributes.value("label"); | 1120 QString label = attributes.value("label"); | 
| 1093 sodm->add(Event(frame, label)); | 1121 sodm->add(Event(frame, label)); | 
| 1094 return true; | 1122 return true; | 
| 1095 } | 1123 } | 
| 1096 | 1124 | 
| 1097 SparseTimeValueModel *stvm = dynamic_cast<SparseTimeValueModel *> | 1125 if (auto stvm = ModelById::getAs<SparseTimeValueModel>(modelId)) { | 
| 1098 (m_currentDataset); | |
| 1099 | |
| 1100 if (stvm) { | |
| 1101 // SVCERR << "Current dataset is a sparse time-value model" << endl; | |
| 1102 float value = 0.0; | 1126 float value = 0.0; | 
| 1103 value = attributes.value("value").trimmed().toFloat(&ok); | 1127 value = attributes.value("value").trimmed().toFloat(&ok); | 
| 1104 QString label = attributes.value("label"); | 1128 QString label = attributes.value("label"); | 
| 1105 stvm->add(Event(frame, value, label)); | 1129 stvm->add(Event(frame, value, label)); | 
| 1106 return ok; | 1130 return ok; | 
| 1107 } | 1131 } | 
| 1108 | 1132 | 
| 1109 NoteModel *nm = dynamic_cast<NoteModel *>(m_currentDataset); | 1133 if (auto nm = ModelById::getAs<NoteModel>(modelId)) { | 
| 1110 | |
| 1111 if (nm) { | |
| 1112 // SVCERR << "Current dataset is a note model" << endl; | |
| 1113 float value = 0.0; | 1134 float value = 0.0; | 
| 1114 value = attributes.value("value").trimmed().toFloat(&ok); | 1135 value = attributes.value("value").trimmed().toFloat(&ok); | 
| 1115 int duration = 0; | 1136 int duration = 0; | 
| 1116 duration = attributes.value("duration").trimmed().toInt(&ok); | 1137 duration = attributes.value("duration").trimmed().toInt(&ok); | 
| 1117 QString label = attributes.value("label"); | 1138 QString label = attributes.value("label"); | 
| 1122 } | 1143 } | 
| 1123 nm->add(Event(frame, value, duration, level, label)); | 1144 nm->add(Event(frame, value, duration, level, label)); | 
| 1124 return ok; | 1145 return ok; | 
| 1125 } | 1146 } | 
| 1126 | 1147 | 
| 1127 RegionModel *rm = dynamic_cast<RegionModel *>(m_currentDataset); | 1148 if (auto rm = ModelById::getAs<RegionModel>(modelId)) { | 
| 1128 | |
| 1129 if (rm) { | |
| 1130 // SVCERR << "Current dataset is a region model" << endl; | |
| 1131 float value = 0.0; | 1149 float value = 0.0; | 
| 1132 value = attributes.value("value").trimmed().toFloat(&ok); | 1150 value = attributes.value("value").trimmed().toFloat(&ok); | 
| 1133 int duration = 0; | 1151 int duration = 0; | 
| 1134 duration = attributes.value("duration").trimmed().toInt(&ok); | 1152 duration = attributes.value("duration").trimmed().toInt(&ok); | 
| 1135 QString label = attributes.value("label"); | 1153 QString label = attributes.value("label"); | 
| 1136 rm->add(Event(frame, value, duration, label)); | 1154 rm->add(Event(frame, value, duration, label)); | 
| 1137 return ok; | 1155 return ok; | 
| 1138 } | 1156 } | 
| 1139 | 1157 | 
| 1140 TextModel *tm = dynamic_cast<TextModel *>(m_currentDataset); | 1158 if (auto tm = ModelById::getAs<TextModel>(modelId)) { | 
| 1141 | |
| 1142 if (tm) { | |
| 1143 // SVCERR << "Current dataset is a text model" << endl; | |
| 1144 float height = 0.0; | 1159 float height = 0.0; | 
| 1145 height = attributes.value("height").trimmed().toFloat(&ok); | 1160 height = attributes.value("height").trimmed().toFloat(&ok); | 
| 1146 QString label = attributes.value("label"); | 1161 QString label = attributes.value("label"); | 
| 1147 // SVDEBUG << "SVFileReader::addPointToDataset: TextModel: frame = " << frame << ", height = " << height << ", label = " << label << ", ok = " << ok << endl; | |
| 1148 tm->add(Event(frame, height, label)); | 1162 tm->add(Event(frame, height, label)); | 
| 1149 return ok; | 1163 return ok; | 
| 1150 } | 1164 } | 
| 1151 | 1165 | 
| 1152 PathModel *pm = dynamic_cast<PathModel *>(m_currentDataset); | 1166 if (auto im = ModelById::getAs<ImageModel>(modelId)) { | 
| 1153 | |
| 1154 if (pm) { | |
| 1155 // SVCERR << "Current dataset is a path model" << endl; | |
| 1156 int mapframe = attributes.value("mapframe").trimmed().toInt(&ok); | |
| 1157 // SVDEBUG << "SVFileReader::addPointToDataset: PathModel: frame = " << frame << ", mapframe = " << mapframe << ", ok = " << ok << endl; | |
| 1158 pm->add(PathPoint(frame, mapframe)); | |
| 1159 return ok; | |
| 1160 } | |
| 1161 | |
| 1162 ImageModel *im = dynamic_cast<ImageModel *>(m_currentDataset); | |
| 1163 | |
| 1164 if (im) { | |
| 1165 // SVCERR << "Current dataset is an image model" << endl; | |
| 1166 QString image = attributes.value("image"); | 1167 QString image = attributes.value("image"); | 
| 1167 QString label = attributes.value("label"); | 1168 QString label = attributes.value("label"); | 
| 1168 // SVDEBUG << "SVFileReader::addPointToDataset: ImageModel: frame = " << frame << ", image = " << image << ", label = " << label << ", ok = " << ok << endl; | |
| 1169 im->add(Event(frame).withURI(image).withLabel(label)); | 1169 im->add(Event(frame).withURI(image).withLabel(label)); | 
| 1170 return ok; | 1170 return ok; | 
| 1171 } | 1171 } | 
| 1172 | 1172 | 
| 1173 SVCERR << "WARNING: SV-XML: Point element found in non-point dataset" << endl; | 1173 SVCERR << "WARNING: SV-XML: Point element found in non-point dataset" | 
| 1174 << endl; | |
| 1174 | 1175 | 
| 1175 return false; | 1176 return false; | 
| 1176 } | 1177 } | 
| 1177 | 1178 | 
| 1178 bool | 1179 bool | 
| 1179 SVFileReader::addBinToDataset(const QXmlAttributes &attributes) | 1180 SVFileReader::addBinToDataset(const QXmlAttributes &attributes) | 
| 1180 { | 1181 { | 
| 1181 EditableDenseThreeDimensionalModel *dtdm = | 1182 if (!haveModel(m_currentDataset)) { | 
| 1182 dynamic_cast<EditableDenseThreeDimensionalModel *> | 1183 SVCERR << "WARNING: SV-XML: Bin definition found in incompatible dataset" | 
| 1183 (m_currentDataset); | 1184 << endl; | 
| 1184 | 1185 return false; | 
| 1185 if (dtdm) { | 1186 } | 
| 1187 | |
| 1188 ModelId modelId = m_models[m_currentDataset]; | |
| 1189 | |
| 1190 if (auto dtdm = ModelById::getAs<EditableDenseThreeDimensionalModel> | |
| 1191 (modelId)) { | |
| 1186 | 1192 | 
| 1187 bool ok = false; | 1193 bool ok = false; | 
| 1188 int n = attributes.value("number").trimmed().toInt(&ok); | 1194 int n = attributes.value("number").trimmed().toInt(&ok); | 
| 1189 if (!ok) { | 1195 if (!ok) { | 
| 1190 SVCERR << "WARNING: SV-XML: Missing or invalid bin number" | 1196 SVCERR << "WARNING: SV-XML: Missing or invalid bin number" | 
| 1191 << endl; | 1197 << endl; | 
| 1192 return false; | 1198 return false; | 
| 1193 } | 1199 } | 
| 1194 | 1200 | 
| 1195 QString name = attributes.value("name"); | 1201 QString name = attributes.value("name"); | 
| 1196 | |
| 1197 dtdm->setBinName(n, name); | 1202 dtdm->setBinName(n, name); | 
| 1198 return true; | 1203 return true; | 
| 1199 } | 1204 } | 
| 1200 | 1205 | 
| 1201 SVCERR << "WARNING: SV-XML: Bin definition found in incompatible dataset" << endl; | 1206 SVCERR << "WARNING: SV-XML: Bin definition found in incompatible dataset" | 
| 1207 << endl; | |
| 1202 | 1208 | 
| 1203 return false; | 1209 return false; | 
| 1204 } | 1210 } | 
| 1205 | 1211 | 
| 1206 | 1212 | 
| 1225 } | 1231 } | 
| 1226 | 1232 | 
| 1227 bool | 1233 bool | 
| 1228 SVFileReader::readRowData(const QString &text) | 1234 SVFileReader::readRowData(const QString &text) | 
| 1229 { | 1235 { | 
| 1230 EditableDenseThreeDimensionalModel *dtdm = | 1236 if (!haveModel(m_currentDataset)) { | 
| 1231 dynamic_cast<EditableDenseThreeDimensionalModel *> | 1237 SVCERR << "WARNING: SV-XML: Row data found in non-row dataset" << endl; | 
| 1232 (m_currentDataset); | 1238 return false; | 
| 1233 | 1239 } | 
| 1240 | |
| 1241 ModelId modelId = m_models[m_currentDataset]; | |
| 1234 bool warned = false; | 1242 bool warned = false; | 
| 1235 | 1243 | 
| 1236 if (dtdm) { | 1244 if (auto dtdm = ModelById::getAs<EditableDenseThreeDimensionalModel> | 
| 1245 (modelId)) { | |
| 1246 | |
| 1237 QStringList data = text.split(m_datasetSeparator); | 1247 QStringList data = text.split(m_datasetSeparator); | 
| 1238 | 1248 | 
| 1239 DenseThreeDimensionalModel::Column values; | 1249 DenseThreeDimensionalModel::Column values; | 
| 1240 | 1250 | 
| 1241 for (QStringList::iterator i = data.begin(); i != data.end(); ++i) { | 1251 for (QStringList::iterator i = data.begin(); i != data.end(); ++i) { | 
| 1262 dtdm->setColumn(m_rowNumber, values); | 1272 dtdm->setColumn(m_rowNumber, values); | 
| 1263 return true; | 1273 return true; | 
| 1264 } | 1274 } | 
| 1265 | 1275 | 
| 1266 SVCERR << "WARNING: SV-XML: Row data found in non-row dataset" << endl; | 1276 SVCERR << "WARNING: SV-XML: Row data found in non-row dataset" << endl; | 
| 1267 | |
| 1268 return false; | 1277 return false; | 
| 1269 } | 1278 } | 
| 1270 | 1279 | 
| 1271 bool | 1280 bool | 
| 1272 SVFileReader::readDerivation(const QXmlAttributes &attributes) | 1281 SVFileReader::readDerivation(const QXmlAttributes &attributes) | 
| 1273 { | 1282 { | 
| 1274 int modelId = 0; | 1283 int modelExportId = 0; | 
| 1275 bool modelOk = false; | 1284 bool modelOk = false; | 
| 1276 modelId = attributes.value("model").trimmed().toInt(&modelOk); | 1285 modelExportId = attributes.value("model").trimmed().toInt(&modelOk); | 
| 1277 | 1286 | 
| 1278 if (!modelOk) { | 1287 if (!modelOk) { | 
| 1279 SVCERR << "WARNING: SV-XML: No model id specified for derivation" << endl; | 1288 SVCERR << "WARNING: SV-XML: No model id specified for derivation" << endl; | 
| 1280 return false; | 1289 return false; | 
| 1281 } | 1290 } | 
| 1282 | 1291 | 
| 1283 if (haveModel(modelId)) { | 1292 if (haveModel(modelExportId)) { | 
| 1284 m_currentDerivedModel = m_models[modelId]; | 1293 m_currentDerivedModel = m_models[modelExportId]; | 
| 1285 } else { | 1294 } else { | 
| 1286 // we'll regenerate the model when the derivation element ends | 1295 // we'll regenerate the model when the derivation element ends | 
| 1287 m_currentDerivedModel = nullptr; | 1296 m_currentDerivedModel = {}; | 
| 1288 } | 1297 } | 
| 1289 | 1298 | 
| 1290 m_currentDerivedModelId = modelId; | 1299 m_pendingDerivedModel = modelExportId; | 
| 1291 | 1300 | 
| 1292 int sourceId = 0; | 1301 int sourceId = 0; | 
| 1293 bool sourceOk = false; | 1302 bool sourceOk = false; | 
| 1294 sourceId = attributes.value("source").trimmed().toInt(&sourceOk); | 1303 sourceId = attributes.value("source").trimmed().toInt(&sourceOk); | 
| 1295 | 1304 | 
| 1330 if (ok) m_currentTransform.setBlockSize(blockSize); | 1339 if (ok) m_currentTransform.setBlockSize(blockSize); | 
| 1331 | 1340 | 
| 1332 int windowType = attributes.value("windowType").trimmed().toInt(&ok); | 1341 int windowType = attributes.value("windowType").trimmed().toInt(&ok); | 
| 1333 if (ok) m_currentTransform.setWindowType(WindowType(windowType)); | 1342 if (ok) m_currentTransform.setWindowType(WindowType(windowType)); | 
| 1334 | 1343 | 
| 1335 if (!m_currentTransformSource) return true; | 1344 auto currentTransformSourceModel = ModelById::get(m_currentTransformSource); | 
| 1345 if (!currentTransformSourceModel) return true; | |
| 1346 | |
| 1347 sv_samplerate_t sampleRate = currentTransformSourceModel->getSampleRate(); | |
| 1336 | 1348 | 
| 1337 QString startFrameStr = attributes.value("startFrame"); | 1349 QString startFrameStr = attributes.value("startFrame"); | 
| 1338 QString durationStr = attributes.value("duration"); | 1350 QString durationStr = attributes.value("duration"); | 
| 1339 | 1351 | 
| 1340 int startFrame = 0; | 1352 int startFrame = 0; | 
| 1348 duration = durationStr.trimmed().toInt(&ok); | 1360 duration = durationStr.trimmed().toInt(&ok); | 
| 1349 if (!ok) duration = 0; | 1361 if (!ok) duration = 0; | 
| 1350 } | 1362 } | 
| 1351 | 1363 | 
| 1352 m_currentTransform.setStartTime | 1364 m_currentTransform.setStartTime | 
| 1353 (RealTime::frame2RealTime | 1365 (RealTime::frame2RealTime(startFrame, sampleRate)); | 
| 1354 (startFrame, m_currentTransformSource->getSampleRate())); | |
| 1355 | 1366 | 
| 1356 m_currentTransform.setDuration | 1367 m_currentTransform.setDuration | 
| 1357 (RealTime::frame2RealTime | 1368 (RealTime::frame2RealTime(duration, sampleRate)); | 
| 1358 (duration, m_currentTransformSource->getSampleRate())); | |
| 1359 | 1369 | 
| 1360 return true; | 1370 return true; | 
| 1361 } | 1371 } | 
| 1362 | 1372 | 
| 1363 bool | 1373 bool | 
| 1364 SVFileReader::readPlayParameters(const QXmlAttributes &attributes) | 1374 SVFileReader::readPlayParameters(const QXmlAttributes &attributes) | 
| 1365 { | 1375 { | 
| 1366 m_currentPlayParameters = nullptr; | 1376 m_currentPlayParameters = nullptr; | 
| 1367 | 1377 | 
| 1368 int modelId = 0; | 1378 int modelExportId = 0; | 
| 1369 bool modelOk = false; | 1379 bool modelOk = false; | 
| 1370 modelId = attributes.value("model").trimmed().toInt(&modelOk); | 1380 modelExportId = attributes.value("model").trimmed().toInt(&modelOk); | 
| 1371 | 1381 | 
| 1372 if (!modelOk) { | 1382 if (!modelOk) { | 
| 1373 SVCERR << "WARNING: SV-XML: No model id specified for play parameters" << endl; | 1383 SVCERR << "WARNING: SV-XML: No model id specified for play parameters" << endl; | 
| 1374 return false; | 1384 return false; | 
| 1375 } | 1385 } | 
| 1376 | 1386 | 
| 1377 if (haveModel(modelId)) { | 1387 if (haveModel(modelExportId)) { | 
| 1378 | 1388 | 
| 1379 bool ok = false; | 1389 bool ok = false; | 
| 1380 | 1390 | 
| 1381 PlayParameters *parameters = PlayParameterRepository::getInstance()-> | 1391 PlayParameters *parameters = PlayParameterRepository::getInstance()-> | 
| 1382 getPlayParameters(m_models[modelId]); | 1392 getPlayParameters(m_models[modelExportId].untyped); | 
| 1383 | 1393 | 
| 1384 if (!parameters) { | 1394 if (!parameters) { | 
| 1385 SVCERR << "WARNING: SV-XML: Play parameters for model " | 1395 SVCERR << "WARNING: SV-XML: Play parameters for model " | 
| 1386 << modelId | 1396 << modelExportId | 
| 1387 << " not found - has model been added to document?" | 1397 << " not found - has model been added to document?" | 
| 1388 << endl; | 1398 << endl; | 
| 1389 return false; | 1399 return false; | 
| 1390 } | 1400 } | 
| 1391 | 1401 | 
| 1401 QString clipId = attributes.value("clipId"); | 1411 QString clipId = attributes.value("clipId"); | 
| 1402 if (clipId != "") parameters->setPlayClipId(clipId); | 1412 if (clipId != "") parameters->setPlayClipId(clipId); | 
| 1403 | 1413 | 
| 1404 m_currentPlayParameters = parameters; | 1414 m_currentPlayParameters = parameters; | 
| 1405 | 1415 | 
| 1406 // SVCERR << "Current play parameters for model: " << m_models[modelId] << ": " << m_currentPlayParameters << endl; | 1416 // SVCERR << "Current play parameters for model: " << m_models[modelExportId] << ": " << m_currentPlayParameters << endl; | 
| 1407 | 1417 | 
| 1408 } else { | 1418 } else { | 
| 1409 | 1419 | 
| 1410 SVCERR << "WARNING: SV-XML: Unknown model " << modelId | 1420 SVCERR << "WARNING: SV-XML: Unknown model " << modelExportId | 
| 1411 << " for play parameters" << endl; | 1421 << " for play parameters" << endl; | 
| 1412 return false; | 1422 return false; | 
| 1413 } | 1423 } | 
| 1414 | 1424 | 
| 1415 return true; | 1425 return true; | 
| 1416 } | 1426 } | 
| 1417 | 1427 | 
| 1418 bool | 1428 bool | 
| 1419 SVFileReader::readPlugin(const QXmlAttributes &attributes) | 1429 SVFileReader::readPlugin(const QXmlAttributes &attributes) | 
| 1420 { | 1430 { | 
| 1421 if (m_currentDerivedModelId >= 0) { | 1431 if (m_pendingDerivedModel != XmlExportable::NO_ID) { | 
| 1422 return readPluginForTransform(attributes); | 1432 return readPluginForTransform(attributes); | 
| 1423 } else if (m_currentPlayParameters) { | 1433 } else if (m_currentPlayParameters) { | 
| 1424 return readPluginForPlayback(attributes); | 1434 return readPluginForPlayback(attributes); | 
| 1425 } else { | 1435 } else { | 
| 1426 SVCERR << "WARNING: SV-XML: Plugin found outside derivation or play parameters" << endl; | 1436 SVCERR << "WARNING: SV-XML: Plugin found outside derivation or play parameters" << endl; | 
| 1467 } | 1477 } | 
| 1468 | 1478 | 
| 1469 bool | 1479 bool | 
| 1470 SVFileReader::readTransform(const QXmlAttributes &attributes) | 1480 SVFileReader::readTransform(const QXmlAttributes &attributes) | 
| 1471 { | 1481 { | 
| 1472 if (m_currentDerivedModelId < 0) { | 1482 if (m_pendingDerivedModel == XmlExportable::NO_ID) { | 
| 1473 SVCERR << "WARNING: SV-XML: Transform found outside derivation" << endl; | 1483 SVCERR << "WARNING: SV-XML: Transform found outside derivation" << endl; | 
| 1474 return false; | 1484 return false; | 
| 1475 } | 1485 } | 
| 1476 | 1486 | 
| 1477 m_currentTransform = Transform(); | 1487 m_currentTransform = Transform(); | 
| 1480 } | 1490 } | 
| 1481 | 1491 | 
| 1482 bool | 1492 bool | 
| 1483 SVFileReader::readParameter(const QXmlAttributes &attributes) | 1493 SVFileReader::readParameter(const QXmlAttributes &attributes) | 
| 1484 { | 1494 { | 
| 1485 if (m_currentDerivedModelId < 0) { | 1495 if (m_pendingDerivedModel == XmlExportable::NO_ID) { | 
| 1486 SVCERR << "WARNING: SV-XML: Parameter found outside derivation" << endl; | 1496 SVCERR << "WARNING: SV-XML: Parameter found outside derivation" << endl; | 
| 1487 return false; | 1497 return false; | 
| 1488 } | 1498 } | 
| 1489 | 1499 | 
| 1490 QString name = attributes.value("name"); | 1500 QString name = attributes.value("name"); | 
