Mercurial > hg > svapp
diff framework/Align.cpp @ 691:c8ba09756eff by-id
Work on management of alignment-related models
author | Chris Cannam |
---|---|
date | Fri, 12 Jul 2019 13:58:02 +0100 |
parents | e0b0f3e163ca |
children | 3e34eeb92647 |
line wrap: on
line diff
--- a/framework/Align.cpp Fri Jul 12 09:40:56 2019 +0100 +++ b/framework/Align.cpp Fri Jul 12 13:58:02 2019 +0100 @@ -103,40 +103,47 @@ if (!reference || !other) return false; - // This involves creating either three or four new models: + // This involves creating a number of new models: // // 1. an AggregateWaveModel to provide the mixdowns of the main // model and the new model in its two channels, as input to the - // MATCH plugin + // MATCH plugin. We just call this one aggregateModel // // 2a. a SparseTimeValueModel which will be automatically created // by FeatureExtractionModelTransformer when running the // TuningDifference plugin to receive the relative tuning of the // second model (if pitch-aware alignment is enabled in the - // preferences) + // preferences). We call this tuningDiffOutputModel. // // 2b. a SparseTimeValueModel which will be automatically created // by FeatureExtractionPluginTransformer when running the MATCH - // plugin to perform alignment (so containing the alignment path) + // plugin to perform alignment (so containing the alignment path). + // We call this one pathOutputModel. // - // 3. an AlignmentModel, which stores the path model and carries - // out alignment lookups on it. + // 2c. a SparseTimeValueModel used solely to provide faked + // completion information to the AlignmentModel while a + // TuningDifference calculation is going on. We call this + // preparatoryModel. // - // The AggregateWaveModel [1] is registered with the document, - // which deletes it when it is invalidated (when one of its - // components is deleted). The SparseTimeValueModel [2a] is reused - // by us when starting the alignment process proper, and is then - // deleted by us. The SparseTimeValueModel [2b] is passed to the - // AlignmentModel, which takes ownership of it. The AlignmentModel - // is attached to the new model we are aligning, which also takes - // ownership of it. The only one of these models that we need to - // delete here is the SparseTimeValueModel [2a]. - //!!! todo: review the above, especially management of AlignmentModel + // 3. an AlignmentModel, which stores the path and carries out + // alignment lookups on it. We just call this one alignmentModel. // - // (We also create a sneaky additional SparseTimeValueModel - // temporarily so we can attach completion information to it - - // this is quite unnecessary from the perspective of simply - // producing the results.) + // Models 1 and 3 are registered with the document, which will + // eventually release them. We don't release them here except in + // the case where an activity fails before the point where we + // would otherwise have registered them with the document. + // + // Models 2a (tuningDiffOutputModel), 2b (pathOutputModel) and 2c + // (preparatoryModel) are not registered with the document. Model + // 2b (pathOutputModel) is not registered because we do not have a + // stable reference to the document at the point where it is + // created. Model 2c (preparatoryModel) is not registered because + // it is a bodge that we are embarrassed about, so we try to + // manage it ourselves without anyone else noticing. Model 2a is + // not registered for symmetry with the other two. These have to + // be released by us when finished with, but their lifespans do + // not extend beyond the end of the alignment procedure, so this + // should be ok. AggregateWaveModel::ChannelSpecList components; @@ -148,7 +155,7 @@ auto aggregateModel = std::make_shared<AggregateWaveModel>(components); auto aggregateModelId = ModelById::add(aggregateModel); - doc->addAggregateModel(aggregateModelId); + doc->addNonDerivedModel(aggregateModelId); auto alignmentModel = std::make_shared<AlignmentModel> (referenceId, otherId, ModelId()); @@ -161,6 +168,7 @@ if (beginTransformDrivenAlignment(aggregateModelId, alignmentModelId)) { other->setAlignment(alignmentModelId); + doc->addNonDerivedModel(alignmentModelId); } else { error = alignmentModel->getError(); ModelById::release(alignmentModel); @@ -186,20 +194,24 @@ ModelTransformerFactory *mtf = ModelTransformerFactory::getInstance(); QString message; - ModelId transformOutput = mtf->transform(transform, - aggregateModelId, - message); + ModelId tuningDiffOutputModelId = mtf->transform(transform, + aggregateModelId, + message); - auto tdout = ModelById::getAs<SparseTimeValueModel>(transformOutput); - if (!tdout) { + auto tuningDiffOutputModel = + ModelById::getAs<SparseTimeValueModel>(tuningDiffOutputModelId); + if (!tuningDiffOutputModel) { SVCERR << "Align::alignModel: ERROR: Failed to create tuning-difference output model (no Tuning Difference plugin?)" << endl; error = message; + ModelById::release(alignmentModel); return false; } other->setAlignment(alignmentModelId); + doc->addNonDerivedModel(alignmentModelId); - connect(tdout.get(), SIGNAL(completionChanged(ModelId)), + connect(tuningDiffOutputModel.get(), + SIGNAL(completionChanged(ModelId)), this, SLOT(tuningDifferenceCompletionChanged(ModelId))); TuningDiffRec rec; @@ -216,43 +228,45 @@ rec.preparatory = preparatoryModelId; alignmentModel->setPathFrom(rec.preparatory); - m_pendingTuningDiffs[transformOutput] = rec; + m_pendingTuningDiffs[tuningDiffOutputModelId] = rec; } return true; } void -Align::tuningDifferenceCompletionChanged(ModelId tdId) +Align::tuningDifferenceCompletionChanged(ModelId tuningDiffOutputModelId) { QMutexLocker locker(&m_mutex); - if (m_pendingTuningDiffs.find(tdId) == m_pendingTuningDiffs.end()) { + if (m_pendingTuningDiffs.find(tuningDiffOutputModelId) == + m_pendingTuningDiffs.end()) { SVCERR << "ERROR: Align::tuningDifferenceCompletionChanged: Model " - << tdId << " not found in pending tuning diff map!" << endl; + << tuningDiffOutputModelId + << " not found in pending tuning diff map!" << endl; return; } - auto td = ModelById::getAs<SparseTimeValueModel>(tdId); - if (!td) { + auto tuningDiffOutputModel = + ModelById::getAs<SparseTimeValueModel>(tuningDiffOutputModelId); + if (!tuningDiffOutputModel) { SVCERR << "WARNING: Align::tuningDifferenceCompletionChanged: Model " - << tdId << " not known as SparseTimeValueModel" << endl; + << tuningDiffOutputModelId + << " not known as SparseTimeValueModel" << endl; return; } - TuningDiffRec rec = m_pendingTuningDiffs[tdId]; + TuningDiffRec rec = m_pendingTuningDiffs[tuningDiffOutputModelId]; - auto alignment = ModelById::getAs<AlignmentModel>(rec.alignment); - if (!alignment) { + auto alignmentModel = ModelById::getAs<AlignmentModel>(rec.alignment); + if (!alignmentModel) { SVCERR << "WARNING: Align::tuningDifferenceCompletionChanged:" << "alignment model has disappeared" << endl; return; } int completion = 0; - bool done = td->isReady(&completion); - -// SVCERR << "Align::tuningDifferenceCompletionChanged: done = " << done << ", completion = " << completion << endl; + bool done = tuningDiffOutputModel->isReady(&completion); if (!done) { // This will be the completion the alignment model reports, @@ -260,28 +274,30 @@ // 99 (not 100!) and then back to 0 again when we start // calculating the actual path in the following phase int clamped = (completion == 100 ? 99 : completion); -// SVCERR << "Align::tuningDifferenceCompletionChanged: setting rec.preparatory completion to " << clamped << endl; - auto preparatory = ModelById::getAs<SparseTimeValueModel> - (rec.preparatory); - if (preparatory) { - preparatory->setCompletion(clamped); + auto preparatoryModel = + ModelById::getAs<SparseTimeValueModel>(rec.preparatory); + if (preparatoryModel) { + preparatoryModel->setCompletion(clamped); } return; } float tuningFrequency = 440.f; - if (!td->isEmpty()) { - tuningFrequency = td->getAllEvents()[0].getValue(); + if (!tuningDiffOutputModel->isEmpty()) { + tuningFrequency = tuningDiffOutputModel->getAllEvents()[0].getValue(); SVCERR << "Align::tuningDifferenceCompletionChanged: Reported tuning frequency = " << tuningFrequency << endl; } else { SVCERR << "Align::tuningDifferenceCompletionChanged: No tuning frequency reported" << endl; } - m_pendingTuningDiffs.erase(tdId); - ModelById::release(tdId); + ModelById::release(tuningDiffOutputModel); - alignment->setPathFrom({}); + alignmentModel->setPathFrom({}); // replace preparatoryModel + ModelById::release(rec.preparatory); + rec.preparatory = {}; + + m_pendingTuningDiffs.erase(tuningDiffOutputModelId); beginTransformDrivenAlignment (rec.input, rec.alignment, tuningFrequency); @@ -296,8 +312,10 @@ TransformFactory *tf = TransformFactory::getInstance(); - auto aggregateModel = ModelById::getAs<AggregateWaveModel>(aggregateModelId); - auto alignmentModel = ModelById::getAs<AlignmentModel>(alignmentModelId); + auto aggregateModel = + ModelById::getAs<AggregateWaveModel>(aggregateModelId); + auto alignmentModel = + ModelById::getAs<AlignmentModel>(alignmentModelId); if (!aggregateModel || !alignmentModel) { SVCERR << "Align::alignModel: ERROR: One or other of the aggregate & alignment models has disappeared" << endl; @@ -320,29 +338,31 @@ ModelTransformerFactory *mtf = ModelTransformerFactory::getInstance(); QString message; - ModelId transformOutput = mtf->transform + ModelId pathOutputModelId = mtf->transform (transform, aggregateModelId, message); - if (transformOutput.isNone()) { + if (pathOutputModelId.isNone()) { transform.setStepSize(0); - transformOutput = mtf->transform + pathOutputModelId = mtf->transform (transform, aggregateModelId, message); } - auto path = ModelById::getAs<SparseTimeValueModel>(transformOutput); + auto pathOutputModel = + ModelById::getAs<SparseTimeValueModel>(pathOutputModelId); //!!! callers will need to be updated to get error from //!!! alignment model after initial call - if (!path) { + if (!pathOutputModel) { SVCERR << "Align::alignModel: ERROR: Failed to create alignment path (no MATCH plugin?)" << endl; - ModelById::release(transformOutput); alignmentModel->setError(message); return false; } - path->setCompletion(0); - alignmentModel->setPathFrom(transformOutput); //!!! who releases transformOutput? + pathOutputModel->setCompletion(0); + alignmentModel->setPathFrom(pathOutputModelId); + + m_pendingAlignments[alignmentModelId] = pathOutputModelId; connect(alignmentModel.get(), SIGNAL(completionChanged(ModelId)), this, SLOT(alignmentCompletionChanged(ModelId))); @@ -351,20 +371,30 @@ } void -Align::alignmentCompletionChanged(ModelId modelId) +Align::alignmentCompletionChanged(ModelId alignmentModelId) { QMutexLocker locker (&m_mutex); - auto am = ModelById::getAs<AlignmentModel>(modelId); - if (am && am->isReady()) { - disconnect(am.get(), SIGNAL(completionChanged(ModelId)), + auto alignmentModel = ModelById::getAs<AlignmentModel>(alignmentModelId); + + if (alignmentModel && alignmentModel->isReady()) { + + if (m_pendingAlignments.find(alignmentModelId) != + m_pendingAlignments.end()) { + ModelId pathOutputModelId = m_pendingAlignments[alignmentModelId]; + ModelById::release(pathOutputModelId); + m_pendingAlignments.erase(alignmentModelId); + } + + disconnect(alignmentModel.get(), + SIGNAL(completionChanged(ModelId)), this, SLOT(alignmentCompletionChanged(ModelId))); - emit alignmentComplete(modelId); + emit alignmentComplete(alignmentModelId); } } bool -Align::alignModelViaProgram(Document *, +Align::alignModelViaProgram(Document *doc, ModelId referenceId, ModelId otherId, QString program, @@ -417,11 +447,12 @@ << endl; error = "Alignment program could not be started"; m_pendingProcesses.erase(process); - //!!! who releases alignmentModel? does this? review other->setAlignment({}); + ModelById::release(alignmentModelId); delete process; } + doc->addNonDerivedModel(alignmentModelId); return success; }