Mercurial > hg > svapp
changeset 685:7540733f5480 by-id
Overhaul SV file reader etc
author | Chris Cannam |
---|---|
date | Thu, 04 Jul 2019 14:31:22 +0100 |
parents | 5e9b1956b609 |
children | 610fa108fbcc |
files | framework/MainWindowBase.cpp framework/MainWindowBase.h framework/SVFileReader.cpp framework/SVFileReader.h framework/TransformUserConfigurator.cpp framework/TransformUserConfigurator.h |
diffstat | 6 files changed, 302 insertions(+), 263 deletions(-) [+] |
line wrap: on
line diff
--- a/framework/MainWindowBase.cpp Wed Jul 03 14:21:05 2019 +0100 +++ b/framework/MainWindowBase.cpp Thu Jul 04 14:31:22 2019 +0100 @@ -2665,14 +2665,14 @@ } ModelId -MainWindowBase::getMainModelId() +MainWindowBase::getMainModelId() const { if (!m_document) return {}; return m_document->getMainModel(); } std::shared_ptr<WaveFileModel> -MainWindowBase::getMainModel() +MainWindowBase::getMainModel() const { return ModelById::getAs<WaveFileModel>(getMainModelId()); }
--- a/framework/MainWindowBase.h Wed Jul 03 14:21:05 2019 +0100 +++ b/framework/MainWindowBase.h Thu Jul 04 14:31:22 2019 +0100 @@ -420,8 +420,8 @@ mutable QLabel *m_statusLabel; QLabel *getStatusLabel() const; - ModelId getMainModelId(); - std::shared_ptr<WaveFileModel> getMainModel(); + ModelId getMainModelId() const; + std::shared_ptr<WaveFileModel> getMainModel() const; void createDocument(); FileOpenStatus addOpenedAudioModel(FileSource source,
--- a/framework/SVFileReader.cpp Wed Jul 03 14:21:05 2019 +0100 +++ b/framework/SVFileReader.cpp Thu Jul 04 14:31:22 2019 +0100 @@ -58,12 +58,10 @@ m_paneCallback(callback), m_location(location), m_currentPane(nullptr), + m_currentDataset(XmlExportable::NO_ID), m_currentLayer(nullptr), - m_currentDataset(nullptr), - m_currentDerivedModel(nullptr), - m_currentDerivedModelId(-1), + m_pendingDerivedModel(XmlExportable::NO_ID), m_currentPlayParameters(nullptr), - m_currentTransformSource(nullptr), m_currentTransformChannel(0), m_currentTransformIsNewStyle(true), m_datasetSeparator(" "), @@ -108,24 +106,31 @@ << endl; } - std::set<Model *> unaddedModels; + std::set<ModelId> unaddedModels; - for (std::map<int, Model *>::iterator i = m_models.begin(); - i != m_models.end(); ++i) { - if (m_addedModels.find(i->second) == m_addedModels.end()) { - unaddedModels.insert(i->second); + for (auto i: m_models) { + if (m_addedModels.find(i.second) == m_addedModels.end()) { + unaddedModels.insert(i.second); } } if (!unaddedModels.empty()) { SVCERR << "WARNING: SV-XML: File contained " - << unaddedModels.size() << " unused models" - << endl; - while (!unaddedModels.empty()) { - delete *unaddedModels.begin(); - unaddedModels.erase(unaddedModels.begin()); + << unaddedModels.size() << " unused models" + << endl; + for (auto m: unaddedModels) { + ModelById::release(m); } - } + } + + if (!m_paths.empty()) { + SVCERR << "WARNING: SV-XML: File contained " + << m_paths.size() << " unused paths" + << endl; + for (auto p: m_paths) { + delete p.second; + } + } } bool @@ -277,15 +282,13 @@ if (name == "dataset") { - if (m_currentDataset) { + if (m_currentDataset != XmlExportable::NO_ID) { bool foundInAwaiting = false; - for (std::map<int, int>::iterator i = m_awaitingDatasets.begin(); - i != m_awaitingDatasets.end(); ++i) { - if (haveModel(i->second) && - m_models[i->second] == m_currentDataset) { - m_awaitingDatasets.erase(i); + for (auto i: m_awaitingDatasets) { + if (i.second == m_currentDataset) { + m_awaitingDatasets.erase(i.first); foundInAwaiting = true; break; } @@ -296,7 +299,7 @@ } } - m_currentDataset = nullptr; + m_currentDataset = XmlExportable::NO_ID; } else if (name == "data") { @@ -305,23 +308,23 @@ } else if (name == "derivation") { - if (!m_currentDerivedModel) { - if (m_currentDerivedModelId < 0) { - SVCERR << "WARNING: SV-XML: Bad derivation output model id " - << m_currentDerivedModelId << endl; - } else if (haveModel(m_currentDerivedModelId)) { + if (m_currentDerivedModel.isNone()) { + if (m_pendingDerivedModel == XmlExportable::NO_ID) { + SVCERR << "WARNING: SV-XML: No valid output model id " + << "for derivation" << endl; + } else if (haveModel(m_pendingDerivedModel)) { SVCERR << "WARNING: SV-XML: Derivation has existing model " - << m_currentDerivedModelId - << " as target, not regenerating" << endl; + << m_pendingDerivedModel + << " as target, not regenerating" << endl; } else { QString message; - m_currentDerivedModel = m_models[m_currentDerivedModelId] = + m_currentDerivedModel = m_models[m_pendingDerivedModel] = m_document->addDerivedModel (m_currentTransform, ModelTransformer::Input(m_currentTransformSource, m_currentTransformChannel), message); - if (!m_currentDerivedModel) { + if (m_currentDerivedModel.isNone()) { emit modelRegenerationFailed(tr("(derived model in SV-XML)"), m_currentTransform.getIdentifier(), message); @@ -340,9 +343,9 @@ } m_addedModels.insert(m_currentDerivedModel); - m_currentDerivedModel = nullptr; - m_currentDerivedModelId = -1; - m_currentTransformSource = nullptr; + m_currentDerivedModel = {}; + m_pendingDerivedModel = XmlExportable::NO_ID; + m_currentTransformSource = {}; m_currentTransform = Transform(); m_currentTransformChannel = -1; @@ -406,7 +409,7 @@ void SVFileReader::makeAggregateModels() { - std::map<int, PendingAggregateRec> stillPending; + std::map<ExportId, PendingAggregateRec> stillPending; for (auto p: m_pendingAggregates) { @@ -415,22 +418,27 @@ bool skip = false; AggregateWaveModel::ChannelSpecList specs; - for (int componentId: rec.components) { + for (ExportId componentId: rec.components) { bool found = false; if (m_models.find(componentId) != m_models.end()) { - RangeSummarisableTimeValueModel *rs = - dynamic_cast<RangeSummarisableTimeValueModel *> - (m_models[componentId]); + ModelId modelId = m_models[componentId]; + auto rs = ModelById::getAs<RangeSummarisableTimeValueModel> + (modelId); if (rs) { - //!!! NB difference between model id and model - //!!! export id - we need to be clearer about this specs.push_back(AggregateWaveModel::ModelChannelSpec - (rs->getId(), -1)); + (modelId, -1)); found = true; + } else { + SVDEBUG << "SVFileReader::makeAggregateModels: " + << "Component model id " << componentId + << "in aggregate model id " << id + << "does not appear to be convertible to " + << "RangeSummarisableTimeValueModel" + << endl; } } if (!found) { - SVDEBUG << "SVFileReader::makeAggregateModels:" + SVDEBUG << "SVFileReader::makeAggregateModels: " << "Unknown component model id " << componentId << " in aggregate model id " << id << ", hoping we won't be needing it just yet" @@ -442,13 +450,13 @@ if (skip) { stillPending[id] = rec; } else { - AggregateWaveModel *model = new AggregateWaveModel(specs); + auto model = std::make_shared<AggregateWaveModel>(specs); model->setObjectName(rec.name); + m_models[id] = ModelById::add(model); - SVDEBUG << "SVFileReader::makeAggregateModels: created aggregate model id " - << id << " with " << specs.size() << " components" << endl; - - m_models[id] = model; + SVDEBUG << "SVFileReader::makeAggregateModels: created aggregate " + << "model id " << id << " with " << specs.size() + << " components" << endl; } } @@ -459,32 +467,30 @@ SVFileReader::addUnaddedModels() { makeAggregateModels(); - - for (std::map<int, Model *>::iterator i = m_models.begin(); - i != m_models.end(); ++i) { - Model *model = i->second; + for (auto i: m_models) { - if (m_addedModels.find(model) != m_addedModels.end()) { + ModelId modelId = i.second; + + if (m_addedModels.find(modelId) != m_addedModels.end()) { // already added this one continue; } + + //!!! todo: review this (i.e. who causes the release of what) - // don't want to add path and alignment models to the - // document, because their lifespans are entirely dictated by - // the models that "own" them even though they were read - // independently from the .sv file. (pity we don't have a - // nicer way to handle this) - if (!dynamic_cast<PathModel *>(model) && - !dynamic_cast<AlignmentModel *>(model)) { - - m_document->addImportedModel(model); + // don't want to add alignment models to the document, because + // their lifespans are entirely dictated by the models that + // "own" them even though they were read independently from + // the .sv file. (pity we don't have a nicer way to handle + // this) + if (!ModelById::isa<AlignmentModel>(modelId)) { + m_document->addImportedModel(modelId); } - // but we add all models including path and alignment ones to - // the added set, so they don't get deleted from our own - // destructor - m_addedModels.insert(model); + // but we add all models including alignment ones to the added + // set, so they don't get released by our own destructor + m_addedModels.insert(modelId); } } @@ -540,7 +546,8 @@ } else if (rate == 0 && !isMainModel && Preferences::getInstance()->getResampleOnLoad()) { - WaveFileModel *mm = m_document->getMainModel(); + auto mm = ModelById::getAs<WaveFileModel> + (m_document->getMainModel()); if (mm) rate = mm->getSampleRate(); } @@ -557,10 +564,14 @@ } model->setObjectName(name); - m_models[id] = model; + + ModelId modelId = model->getId(); + ModelById::add(std::shared_ptr<Model>(model)); + m_models[id] = modelId; + if (isMainModel) { - m_document->setMainModel(model); - m_addedModels.insert(model); + m_document->setMainModel(modelId); + m_addedModels.insert(modelId); } // Derived models will be added when their derivation // is found. @@ -572,13 +583,13 @@ QString components = attributes.value("components"); QStringList componentIdStrings = components.split(","); std::vector<int> componentIds; - for (auto cid: componentIdStrings) { + for (auto cidStr: componentIdStrings) { bool ok = false; - int id = cid.toInt(&ok); + int cid = cidStr.toInt(&ok); if (!ok) { - SVCERR << "SVFileReader::readModel: Failed to convert component model id from part \"" << cid << "\" in \"" << components << "\"" << endl; + SVCERR << "SVFileReader::readModel: Failed to convert component model id from part \"" << cidStr << "\" in \"" << components << "\"" << endl; } else { - componentIds.push_back(id); + componentIds.push_back(cid); } } PendingAggregateRec rec { name, sampleRate, componentIds }; @@ -605,10 +616,12 @@ READ_MANDATORY(int, windowSize, toInt); READ_MANDATORY(int, yBinCount, toInt); - EditableDenseThreeDimensionalModel *model = - new EditableDenseThreeDimensionalModel + auto model = std::make_shared<EditableDenseThreeDimensionalModel> (sampleRate, windowSize, yBinCount, EditableDenseThreeDimensionalModel::NoCompression); + + model->setObjectName(name); + m_models[id] = ModelById::add(model); float minimum = attributes.value("minimum").trimmed().toFloat(&ok); if (ok) model->setMinimumLevel(minimum); @@ -622,8 +635,6 @@ int startFrame = attributes.value("startFrame").trimmed().toInt(&ok); if (ok) model->setStartFrame(startFrame); - model->setObjectName(name); - m_models[id] = model; return true; } else { @@ -638,21 +649,21 @@ if (dimensions == 1) { READ_MANDATORY(int, resolution, toInt); - + if (attributes.value("subtype") == "image") { bool notifyOnAdd = (attributes.value("notifyOnAdd") == "true"); - ImageModel *model = new ImageModel(sampleRate, resolution, - notifyOnAdd); + auto model = std::make_shared<ImageModel> + (sampleRate, resolution, notifyOnAdd); model->setObjectName(name); - m_models[id] = model; + m_models[id] = ModelById::add(model); } else { - SparseOneDimensionalModel *model = new SparseOneDimensionalModel + auto model = std::make_shared<SparseOneDimensionalModel> (sampleRate, resolution); model->setObjectName(name); - m_models[id] = model; + m_models[id] = ModelById::add(model); } int dataset = attributes.value("dataset").trimmed().toInt(&ok); @@ -679,73 +690,74 @@ if (dimensions == 2) { if (attributes.value("subtype") == "text") { - TextModel *model = new TextModel + auto model = std::make_shared<TextModel> (sampleRate, resolution, notifyOnAdd); model->setObjectName(name); - m_models[id] = model; + m_models[id] = ModelById::add(model); } else if (attributes.value("subtype") == "path") { - PathModel *model = new PathModel - (sampleRate, resolution, notifyOnAdd); - model->setObjectName(name); - m_models[id] = model; + // Paths are no longer actually models + Path *path = new Path(sampleRate, resolution); + m_paths[id] = path; } else { - SparseTimeValueModel *model; + std::shared_ptr<SparseTimeValueModel> model; if (haveMinMax) { - model = new SparseTimeValueModel - (sampleRate, resolution, minimum, maximum, notifyOnAdd); + model = std::make_shared<SparseTimeValueModel> + (sampleRate, resolution, minimum, maximum, + notifyOnAdd); } else { - model = new SparseTimeValueModel + model = std::make_shared<SparseTimeValueModel> (sampleRate, resolution, notifyOnAdd); } model->setScaleUnits(units); model->setObjectName(name); - m_models[id] = model; + m_models[id] = ModelById::add(model); } } else { if (attributes.value("subtype") == "region") { - RegionModel *model; + std::shared_ptr<RegionModel> model; if (haveMinMax) { - model = new RegionModel - (sampleRate, resolution, minimum, maximum, notifyOnAdd); + model = std::make_shared<RegionModel> + (sampleRate, resolution, minimum, maximum, + notifyOnAdd); } else { - model = new RegionModel + model = std::make_shared<RegionModel> (sampleRate, resolution, notifyOnAdd); } model->setValueQuantization(valueQuantization); model->setScaleUnits(units); model->setObjectName(name); - m_models[id] = model; + m_models[id] = ModelById::add(model); } else if (attributes.value("subtype") == "flexinote") { - NoteModel *model; + std::shared_ptr<NoteModel> model; if (haveMinMax) { - model = new NoteModel + model = std::make_shared<NoteModel> (sampleRate, resolution, minimum, maximum, notifyOnAdd, NoteModel::FLEXI_NOTE); } else { - model = new NoteModel + model = std::make_shared<NoteModel> (sampleRate, resolution, notifyOnAdd, NoteModel::FLEXI_NOTE); } model->setValueQuantization(valueQuantization); model->setScaleUnits(units); model->setObjectName(name); - m_models[id] = model; + m_models[id] = ModelById::add(model); } else { // note models written out by SV 1.3 and earlier // have no subtype, so we can't test that - NoteModel *model; + std::shared_ptr<NoteModel> model; if (haveMinMax) { - model = new NoteModel + model = std::make_shared<NoteModel> (sampleRate, resolution, minimum, maximum, notifyOnAdd); } else { - model = new NoteModel + model = std::make_shared<NoteModel> (sampleRate, resolution, notifyOnAdd); } model->setValueQuantization(valueQuantization); model->setScaleUnits(units); model->setObjectName(name); - m_models[id] = model; + m_models[id] = ModelById::add(model); } } @@ -766,7 +778,8 @@ READ_MANDATORY(int, aligned, toInt); READ_MANDATORY(int, path, toInt); - Model *refModel = nullptr, *alignedModel = nullptr, *pathModel = nullptr; + ModelId refModel, alignedModel; + Path *pathPtr = nullptr; if (m_models.find(reference) != m_models.end()) { refModel = m_models[reference]; @@ -784,31 +797,30 @@ << endl; } - if (m_models.find(path) != m_models.end()) { - pathModel = m_models[path]; + if (m_paths.find(path) != m_paths.end()) { + pathPtr = m_paths[path]; } else { - SVCERR << "WARNING: SV-XML: Unknown path model id " + SVCERR << "WARNING: SV-XML: Unknown path id " << path << " in alignment model id " << id << endl; } - if (refModel && alignedModel && pathModel) { - AlignmentModel *model = new AlignmentModel - (refModel, alignedModel, nullptr); - PathModel *pm = dynamic_cast<PathModel *>(pathModel); - if (!pm) { - SVCERR << "WARNING: SV-XML: Model id " << path - << " referenced as path for alignment " << id - << " is not a path model" << endl; - } else { - model->setPath(pm); - pm->setCompletion(100); + if (!refModel.isNone() && !alignedModel.isNone() && pathPtr) { + auto model = std::make_shared<AlignmentModel> + (refModel, alignedModel, ModelId()); + model->setPath(*pathPtr); + model->setObjectName(name); + m_models[id] = ModelById::add(model); + if (auto am = ModelById::get(alignedModel)) { + am->setAlignment(m_models[id]); } - model->setObjectName(name); - m_models[id] = model; - alignedModel->setAlignment(model); return true; } + + if (pathPtr) { + delete pathPtr; + m_paths.erase(path); + } } else { @@ -974,11 +986,10 @@ if (modelOk) { if (haveModel(modelId)) { - Model *model = m_models[modelId]; - m_document->setModel(layer, model); + m_document->setModel(layer, m_models[modelId]); } else { SVCERR << "WARNING: SV-XML: Unknown model id " << modelId - << " in layer definition" << endl; + << " in layer definition" << endl; if (!layer->canExistWithoutModel()) { // Don't add a layer with an unknown model id // unless it explicitly supports this state @@ -1030,14 +1041,18 @@ return false; } - int modelId = m_awaitingDatasets[id]; + int awaitingId = m_awaitingDatasets[id]; + + ModelId modelId; + Path *path = nullptr; - Model *model = nullptr; - if (haveModel(modelId)) { - model = m_models[modelId]; + if (haveModel(awaitingId)) { + modelId = m_models[awaitingId]; + } else if (m_paths.find(awaitingId) != m_paths.end()) { + path = m_paths[awaitingId]; } else { - SVCERR << "WARNING: SV-XML: Internal error: Unknown model " << modelId - << " expecting dataset " << id << endl; + SVCERR << "WARNING: SV-XML: Internal error: Unknown model or path " + << modelId << " awaiting dataset " << id << endl; return false; } @@ -1045,33 +1060,37 @@ switch (dimensions) { case 1: - if (dynamic_cast<SparseOneDimensionalModel *>(model)) good = true; - else if (dynamic_cast<ImageModel *>(model)) good = true; + good = + (ModelById::isa<SparseOneDimensionalModel>(modelId) || + ModelById::isa<ImageModel>(modelId)); break; case 2: - if (dynamic_cast<SparseTimeValueModel *>(model)) good = true; - else if (dynamic_cast<TextModel *>(model)) good = true; - else if (dynamic_cast<PathModel *>(model)) good = true; + good = + (ModelById::isa<SparseTimeValueModel>(modelId) || + ModelById::isa<TextModel>(modelId) || + path); break; case 3: - if (dynamic_cast<NoteModel *>(model)) good = true; - else if (dynamic_cast<RegionModel *>(model)) good = true; - else if (dynamic_cast<EditableDenseThreeDimensionalModel *>(model)) { + if (ModelById::isa<EditableDenseThreeDimensionalModel>(modelId)) { + good = true; m_datasetSeparator = attributes.value("separator"); - good = true; + } else { + good = + (ModelById::isa<NoteModel>(modelId) || + ModelById::isa<RegionModel>(modelId)); } break; } if (!good) { SVCERR << "WARNING: SV-XML: Model id " << modelId << " has wrong number of dimensions or inappropriate type for " << dimensions << "-D dataset " << id << endl; - m_currentDataset = nullptr; + m_currentDataset = XmlExportable::NO_ID; return false; } - m_currentDataset = model; + m_currentDataset = awaitingId; return true; } @@ -1082,23 +1101,28 @@ READ_MANDATORY(int, frame, toInt); -// SVDEBUG << "SVFileReader::addPointToDataset: frame = " << frame << endl; + if (m_paths.find(m_currentDataset) != m_paths.end()) { + Path *path = m_paths[m_currentDataset]; + int mapframe = attributes.value("mapframe").trimmed().toInt(&ok); + path->add(PathPoint(frame, mapframe)); + return ok; + } - SparseOneDimensionalModel *sodm = dynamic_cast<SparseOneDimensionalModel *> - (m_currentDataset); + if (!haveModel(m_currentDataset)) { + SVCERR << "WARNING: SV-XML: Point element found in non-point dataset" + << endl; + return false; + } + + ModelId modelId = m_models[m_currentDataset]; - if (sodm) { -// SVCERR << "Current dataset is a sparse one dimensional model" << endl; + if (auto sodm = ModelById::getAs<SparseOneDimensionalModel>(modelId)) { QString label = attributes.value("label"); sodm->add(Event(frame, label)); return true; } - SparseTimeValueModel *stvm = dynamic_cast<SparseTimeValueModel *> - (m_currentDataset); - - if (stvm) { -// SVCERR << "Current dataset is a sparse time-value model" << endl; + if (auto stvm = ModelById::getAs<SparseTimeValueModel>(modelId)) { float value = 0.0; value = attributes.value("value").trimmed().toFloat(&ok); QString label = attributes.value("label"); @@ -1106,10 +1130,7 @@ return ok; } - NoteModel *nm = dynamic_cast<NoteModel *>(m_currentDataset); - - if (nm) { -// SVCERR << "Current dataset is a note model" << endl; + if (auto nm = ModelById::getAs<NoteModel>(modelId)) { float value = 0.0; value = attributes.value("value").trimmed().toFloat(&ok); int duration = 0; @@ -1124,10 +1145,7 @@ return ok; } - RegionModel *rm = dynamic_cast<RegionModel *>(m_currentDataset); - - if (rm) { -// SVCERR << "Current dataset is a region model" << endl; + if (auto rm = ModelById::getAs<RegionModel>(modelId)) { float value = 0.0; value = attributes.value("value").trimmed().toFloat(&ok); int duration = 0; @@ -1137,40 +1155,23 @@ return ok; } - TextModel *tm = dynamic_cast<TextModel *>(m_currentDataset); - - if (tm) { -// SVCERR << "Current dataset is a text model" << endl; + if (auto tm = ModelById::getAs<TextModel>(modelId)) { float height = 0.0; height = attributes.value("height").trimmed().toFloat(&ok); QString label = attributes.value("label"); -// SVDEBUG << "SVFileReader::addPointToDataset: TextModel: frame = " << frame << ", height = " << height << ", label = " << label << ", ok = " << ok << endl; tm->add(Event(frame, height, label)); return ok; } - PathModel *pm = dynamic_cast<PathModel *>(m_currentDataset); - - if (pm) { -// SVCERR << "Current dataset is a path model" << endl; - int mapframe = attributes.value("mapframe").trimmed().toInt(&ok); -// SVDEBUG << "SVFileReader::addPointToDataset: PathModel: frame = " << frame << ", mapframe = " << mapframe << ", ok = " << ok << endl; - pm->add(PathPoint(frame, mapframe)); - return ok; - } - - ImageModel *im = dynamic_cast<ImageModel *>(m_currentDataset); - - if (im) { -// SVCERR << "Current dataset is an image model" << endl; + if (auto im = ModelById::getAs<ImageModel>(modelId)) { QString image = attributes.value("image"); QString label = attributes.value("label"); -// SVDEBUG << "SVFileReader::addPointToDataset: ImageModel: frame = " << frame << ", image = " << image << ", label = " << label << ", ok = " << ok << endl; im->add(Event(frame).withURI(image).withLabel(label)); return ok; } - SVCERR << "WARNING: SV-XML: Point element found in non-point dataset" << endl; + SVCERR << "WARNING: SV-XML: Point element found in non-point dataset" + << endl; return false; } @@ -1178,11 +1179,16 @@ bool SVFileReader::addBinToDataset(const QXmlAttributes &attributes) { - EditableDenseThreeDimensionalModel *dtdm = - dynamic_cast<EditableDenseThreeDimensionalModel *> - (m_currentDataset); + if (!haveModel(m_currentDataset)) { + SVCERR << "WARNING: SV-XML: Bin definition found in incompatible dataset" + << endl; + return false; + } + + ModelId modelId = m_models[m_currentDataset]; - if (dtdm) { + if (auto dtdm = ModelById::getAs<EditableDenseThreeDimensionalModel> + (modelId)) { bool ok = false; int n = attributes.value("number").trimmed().toInt(&ok); @@ -1193,12 +1199,12 @@ } QString name = attributes.value("name"); - dtdm->setBinName(n, name); return true; } - SVCERR << "WARNING: SV-XML: Bin definition found in incompatible dataset" << endl; + SVCERR << "WARNING: SV-XML: Bin definition found in incompatible dataset" + << endl; return false; } @@ -1227,13 +1233,17 @@ bool SVFileReader::readRowData(const QString &text) { - EditableDenseThreeDimensionalModel *dtdm = - dynamic_cast<EditableDenseThreeDimensionalModel *> - (m_currentDataset); - + if (!haveModel(m_currentDataset)) { + SVCERR << "WARNING: SV-XML: Row data found in non-row dataset" << endl; + return false; + } + + ModelId modelId = m_models[m_currentDataset]; bool warned = false; - if (dtdm) { + if (auto dtdm = ModelById::getAs<EditableDenseThreeDimensionalModel> + (modelId)) { + QStringList data = text.split(m_datasetSeparator); DenseThreeDimensionalModel::Column values; @@ -1264,30 +1274,29 @@ } SVCERR << "WARNING: SV-XML: Row data found in non-row dataset" << endl; - return false; } bool SVFileReader::readDerivation(const QXmlAttributes &attributes) { - int modelId = 0; + int modelExportId = 0; bool modelOk = false; - modelId = attributes.value("model").trimmed().toInt(&modelOk); + modelExportId = attributes.value("model").trimmed().toInt(&modelOk); if (!modelOk) { SVCERR << "WARNING: SV-XML: No model id specified for derivation" << endl; return false; } - if (haveModel(modelId)) { - m_currentDerivedModel = m_models[modelId]; + if (haveModel(modelExportId)) { + m_currentDerivedModel = m_models[modelExportId]; } else { // we'll regenerate the model when the derivation element ends - m_currentDerivedModel = nullptr; + m_currentDerivedModel = {}; } - m_currentDerivedModelId = modelId; + m_pendingDerivedModel = modelExportId; int sourceId = 0; bool sourceOk = false; @@ -1332,7 +1341,10 @@ int windowType = attributes.value("windowType").trimmed().toInt(&ok); if (ok) m_currentTransform.setWindowType(WindowType(windowType)); - if (!m_currentTransformSource) return true; + auto currentTransformSourceModel = ModelById::get(m_currentTransformSource); + if (!currentTransformSourceModel) return true; + + sv_samplerate_t sampleRate = currentTransformSourceModel->getSampleRate(); QString startFrameStr = attributes.value("startFrame"); QString durationStr = attributes.value("duration"); @@ -1350,12 +1362,10 @@ } m_currentTransform.setStartTime - (RealTime::frame2RealTime - (startFrame, m_currentTransformSource->getSampleRate())); + (RealTime::frame2RealTime(startFrame, sampleRate)); m_currentTransform.setDuration - (RealTime::frame2RealTime - (duration, m_currentTransformSource->getSampleRate())); + (RealTime::frame2RealTime(duration, sampleRate)); return true; } @@ -1365,25 +1375,25 @@ { m_currentPlayParameters = nullptr; - int modelId = 0; + int modelExportId = 0; bool modelOk = false; - modelId = attributes.value("model").trimmed().toInt(&modelOk); + modelExportId = attributes.value("model").trimmed().toInt(&modelOk); if (!modelOk) { SVCERR << "WARNING: SV-XML: No model id specified for play parameters" << endl; return false; } - if (haveModel(modelId)) { + if (haveModel(modelExportId)) { bool ok = false; PlayParameters *parameters = PlayParameterRepository::getInstance()-> - getPlayParameters(m_models[modelId]); + getPlayParameters(m_models[modelExportId].untyped); if (!parameters) { SVCERR << "WARNING: SV-XML: Play parameters for model " - << modelId + << modelExportId << " not found - has model been added to document?" << endl; return false; @@ -1403,12 +1413,12 @@ m_currentPlayParameters = parameters; -// SVCERR << "Current play parameters for model: " << m_models[modelId] << ": " << m_currentPlayParameters << endl; +// SVCERR << "Current play parameters for model: " << m_models[modelExportId] << ": " << m_currentPlayParameters << endl; } else { - SVCERR << "WARNING: SV-XML: Unknown model " << modelId - << " for play parameters" << endl; + SVCERR << "WARNING: SV-XML: Unknown model " << modelExportId + << " for play parameters" << endl; return false; } @@ -1418,7 +1428,7 @@ bool SVFileReader::readPlugin(const QXmlAttributes &attributes) { - if (m_currentDerivedModelId >= 0) { + if (m_pendingDerivedModel != XmlExportable::NO_ID) { return readPluginForTransform(attributes); } else if (m_currentPlayParameters) { return readPluginForPlayback(attributes); @@ -1469,7 +1479,7 @@ bool SVFileReader::readTransform(const QXmlAttributes &attributes) { - if (m_currentDerivedModelId < 0) { + if (m_pendingDerivedModel == XmlExportable::NO_ID) { SVCERR << "WARNING: SV-XML: Transform found outside derivation" << endl; return false; } @@ -1482,7 +1492,7 @@ bool SVFileReader::readParameter(const QXmlAttributes &attributes) { - if (m_currentDerivedModelId < 0) { + if (m_pendingDerivedModel == XmlExportable::NO_ID) { SVCERR << "WARNING: SV-XML: Parameter found outside derivation" << endl; return false; }
--- a/framework/SVFileReader.h Wed Jul 03 14:21:05 2019 +0100 +++ b/framework/SVFileReader.h Thu Jul 04 14:31:22 2019 +0100 @@ -25,6 +25,7 @@ class Pane; class Model; +class Path; class Document; class PlayParameters; @@ -182,15 +183,15 @@ void setCurrentPane(Pane *pane) { m_currentPane = pane; } bool startElement(const QString &namespaceURI, - const QString &localName, - const QString &qName, - const QXmlAttributes& atts) override; - + const QString &localName, + const QString &qName, + const QXmlAttributes& atts) override; + bool characters(const QString &) override; bool endElement(const QString &namespaceURI, - const QString &localName, - const QString &qName) override; + const QString &localName, + const QString &qName) override; bool error(const QXmlParseException &exception) override; bool fatalError(const QXmlParseException &exception) override; @@ -233,32 +234,57 @@ void makeAggregateModels(); void addUnaddedModels(); - bool haveModel(int id) { - return (m_models.find(id) != m_models.end()) && m_models[id]; + // We use the term "pending" of things that have been referred to + // but not yet constructed because their definitions are + // incomplete. They are just referred to with an ExportId. Models + // that have been constructed are always added straight away to + // ById and are referred to with a ModelId (everywhere where + // previously we would have used a Model *). m_models maps from + // ExportId (as read from the file) to complete Models, or to a + // ModelId of None for any model that could not be constructed for + // some reason. + + typedef XmlExportable::ExportId ExportId; + + bool haveModel(ExportId id) { + return (m_models.find(id) != m_models.end()) && !m_models[id].isNone(); } - + struct PendingAggregateRec { QString name; sv_samplerate_t sampleRate; - std::vector<int> components; + std::vector<ExportId> components; }; Document *m_document; SVFileReaderPaneCallback &m_paneCallback; QString m_location; Pane *m_currentPane; - std::map<int, Layer *> m_layers; - std::map<int, Model *> m_models; - std::set<Model *> m_addedModels; - std::map<int, PendingAggregateRec> m_pendingAggregates; - std::map<int, int> m_awaitingDatasets; // map dataset id -> model id + std::map<ExportId, Layer *> m_layers; + std::map<ExportId, ModelId> m_models; + std::map<ExportId, Path *> m_paths; + std::set<ModelId> m_addedModels; // i.e. added to Document, not just ById + std::map<ExportId, PendingAggregateRec> m_pendingAggregates; + + // A model element often contains a dataset id, and the dataset + // then follows it. When the model is read, an entry in this map + // is added, mapping from the dataset's export id (the actual + // dataset has not been read yet) back to the export id of the + // object that needs it. We map to export id rather than model id, + // because the object might be a path rather than a model. + std::map<ExportId, ExportId> m_awaitingDatasets; + + // And then this is the model or path that a dataset element is + // currently being read into, i.e. the value looked up from + // m_awaitingDatasets at the point where the dataset is found. + ExportId m_currentDataset; + Layer *m_currentLayer; - Model *m_currentDataset; - Model *m_currentDerivedModel; - int m_currentDerivedModelId; + ModelId m_currentDerivedModel; + ExportId m_pendingDerivedModel; PlayParameters *m_currentPlayParameters; Transform m_currentTransform; - Model *m_currentTransformSource; + ModelId m_currentTransformSource; int m_currentTransformChannel; bool m_currentTransformIsNewStyle; QString m_datasetSeparator;
--- a/framework/TransformUserConfigurator.cpp Wed Jul 03 14:21:05 2019 +0100 +++ b/framework/TransformUserConfigurator.cpp Thu Jul 04 14:31:22 2019 +0100 @@ -60,11 +60,11 @@ TransformUserConfigurator::configure(ModelTransformer::Input &input, Transform &transform, Vamp::PluginBase *plugin, - Model *&inputModel, + ModelId &inputModel, AudioPlaySource *source, sv_frame_t startFrame, sv_frame_t duration, - const QMap<QString, Model *> &modelMap, + const QMap<QString, ModelId> &modelMap, QStringList candidateModelNames, QString defaultModelName) { @@ -121,8 +121,6 @@ std::vector<Vamp::Plugin::OutputDescriptor> od = vp->getOutputDescriptors(); -// cerr << "configure: looking for output: " << output << endl; - if (od.size() > 1) { for (size_t i = 0; i < od.size(); ++i) { if (od[i].identifier == output.toStdString()) { @@ -135,9 +133,9 @@ } int sourceChannels = 1; - if (dynamic_cast<DenseTimeValueModel *>(inputModel)) { - sourceChannels = dynamic_cast<DenseTimeValueModel *>(inputModel) - ->getChannelCount(); + + if (auto dtvm = ModelById::getAs<DenseTimeValueModel>(inputModel)) { + sourceChannels = dtvm->getChannelCount(); } int minChannels = 1, maxChannels = sourceChannels; @@ -203,12 +201,17 @@ //around all this misc stuff, but that's for tomorrow //(whenever that may be) + sv_samplerate_t sampleRate = 0; + if (auto m = ModelById::get(inputModel)) { + sampleRate = m->getSampleRate(); + } + if (startFrame != 0 || duration != 0) { - if (dialog->getSelectionOnly()) { - transform.setStartTime(RealTime::frame2RealTime - (startFrame, inputModel->getSampleRate())); - transform.setDuration(RealTime::frame2RealTime - (duration, inputModel->getSampleRate())); + if (dialog->getSelectionOnly() && sampleRate != 0) { + transform.setStartTime + (RealTime::frame2RealTime(startFrame, sampleRate)); + transform.setDuration + (RealTime::frame2RealTime(duration, sampleRate)); } }
--- a/framework/TransformUserConfigurator.h Wed Jul 03 14:21:05 2019 +0100 +++ b/framework/TransformUserConfigurator.h Thu Jul 04 14:31:22 2019 +0100 @@ -23,15 +23,15 @@ // This is of course absolutely gross bool configure(ModelTransformer::Input &input, - Transform &transform, - Vamp::PluginBase *plugin, - Model *&inputModel, - AudioPlaySource *source, - sv_frame_t startFrame, - sv_frame_t duration, - const QMap<QString, Model *> &modelMap, - QStringList candidateModelNames, - QString defaultModelName) override; + Transform &transform, + Vamp::PluginBase *plugin, + ModelId &inputModel, + AudioPlaySource *source, + sv_frame_t startFrame, + sv_frame_t duration, + const QMap<QString, ModelId> &modelMap, + QStringList candidateModelNames, + QString defaultModelName) override; static void setParentWidget(QWidget *);