Mercurial > hg > svapp
changeset 768:1b1960009be6 pitch-align
Provide callback for output preprocessing before DTW, use it for freq-pitch conversion; use direct setting of completion on alignment models instead of creating fake outputs for completion only
author | Chris Cannam |
---|---|
date | Fri, 22 May 2020 17:17:44 +0100 |
parents | dd742e566e60 |
children | a316cb6fed81 |
files | align/Align.cpp align/TransformAligner.cpp align/TransformAligner.h align/TransformDTWAligner.cpp align/TransformDTWAligner.h |
diffstat | 5 files changed, 76 insertions(+), 104 deletions(-) [+] |
line wrap: on
line diff
--- a/align/Align.cpp Thu May 21 16:21:57 2020 +0100 +++ b/align/Align.cpp Fri May 22 17:17:44 2020 +0100 @@ -24,6 +24,8 @@ #include "transform/Transform.h" #include "transform/TransformFactory.h" +#include "base/Pitch.h" + #include <QSettings> #include <QTimer> @@ -151,7 +153,14 @@ reference, toAlign, transform, - TransformDTWAligner::RiseFall); + TransformDTWAligner::RiseFall, + [](double freq) { + if (freq < 0.0) { + return 0.0; + } else { + return double(Pitch::getPitchForFrequency(freq)); + } + }); break; }
--- a/align/TransformAligner.cpp Thu May 21 16:21:57 2020 +0100 +++ b/align/TransformAligner.cpp Fri May 22 17:17:44 2020 +0100 @@ -50,7 +50,6 @@ } } - ModelById::release(m_tuningDiffProgressModel); ModelById::release(m_tuningDiffOutputModel); ModelById::release(m_pathOutputModel); } @@ -117,11 +116,6 @@ // plugin to perform alignment (so containing the alignment path). // This is m_pathOutputModel. // - // 2c. a SparseTimeValueModel used solely to provide faked - // completion information to the AlignmentModel while a - // TuningDifference calculation is going on. We call this - // m_tuningDiffProgressModel. - // // 3. an AlignmentModel, which stores the path and carries out // alignment lookups on it. This one is m_alignmentModel. // @@ -130,12 +124,9 @@ // the case where an activity fails before the point where we // would otherwise have registered them with the document. // - // Models 2a (m_tuningDiffOutputModel), 2b (m_pathOutputModel) and - // 2c (m_tuningDiffProgressModel) are not registered with the - // document, because they are not intended to persist, and also - // Model 2c (m_tuningDiffProgressModel) is a bodge that we are - // embarrassed about, so we try to manage it ourselves without - // anyone else noticing. These have to be released by us when + // Models 2a (m_tuningDiffOutputModel) and 2b (m_pathOutputModel) + // are not registered with the document, because they are not + // intended to persist. 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. @@ -209,15 +200,6 @@ connect(tuningDiffOutputModel.get(), SIGNAL(completionChanged(ModelId)), this, SLOT(tuningDifferenceCompletionChanged(ModelId))); - - // This model exists only so that the AlignmentModel can get a - // completion value from somewhere while the tuning difference - // calculation is going on - auto progressModel = std::make_shared<SparseTimeValueModel> - (aggregateModel->getSampleRate(), 1); - m_tuningDiffProgressModel = ModelById::add(progressModel); - progressModel->setCompletion(0); - alignmentModel->setPathFrom(m_tuningDiffProgressModel); } } @@ -266,11 +248,7 @@ // 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); - auto progressModel = - ModelById::getAs<SparseTimeValueModel>(m_tuningDiffProgressModel); - if (progressModel) { - progressModel->setCompletion(clamped); - } + alignmentModel->setCompletion(clamped); return; } @@ -286,10 +264,6 @@ ModelById::release(tuningDiffOutputModel); m_tuningDiffOutputModel = {}; - alignmentModel->setPathFrom({}); // replace m_tuningDiffProgressModel - ModelById::release(m_tuningDiffProgressModel); - m_tuningDiffProgressModel = {}; - beginAlignmentPhase(); }
--- a/align/TransformAligner.h Thu May 21 16:21:57 2020 +0100 +++ b/align/TransformAligner.h Fri May 22 17:17:44 2020 +0100 @@ -54,7 +54,6 @@ ModelId m_toAlign; ModelId m_aggregateModel; // an AggregateWaveModel ModelId m_alignmentModel; // an AlignmentModel - ModelId m_tuningDiffProgressModel; // SparseTimeValueModel, unreg'd with doc ModelId m_tuningDiffOutputModel; // SparseTimeValueModel, unreg'd with doc ModelId m_pathOutputModel; // SparseTimeValueModel, unreg'd with doc bool m_withTuningDifference;
--- a/align/TransformDTWAligner.cpp Thu May 21 16:21:57 2020 +0100 +++ b/align/TransformDTWAligner.cpp Fri May 22 17:17:44 2020 +0100 @@ -39,11 +39,27 @@ m_document(doc), m_reference(reference), m_toAlign(toAlign), - m_referenceTransformComplete(false), - m_toAlignTransformComplete(false), m_transform(transform), m_dtwType(dtwType), - m_incomplete(true) + m_incomplete(true), + m_outputPreprocessor([](double x) { return x; }) +{ +} + +TransformDTWAligner::TransformDTWAligner(Document *doc, + ModelId reference, + ModelId toAlign, + Transform transform, + DTWType dtwType, + std::function<double(double)> + outputPreprocessor) : + m_document(doc), + m_reference(reference), + m_toAlign(toAlign), + m_transform(transform), + m_dtwType(dtwType), + m_incomplete(true), + m_outputPreprocessor(outputPreprocessor) { } @@ -57,7 +73,6 @@ ModelById::release(m_referenceOutputModel); ModelById::release(m_toAlignOutputModel); - ModelById::release(m_alignmentProgressModel); } bool @@ -114,14 +129,9 @@ this, SLOT(completionChanged(ModelId))); connect(toAlignOutputModel.get(), SIGNAL(completionChanged(ModelId)), this, SLOT(completionChanged(ModelId))); - - auto alignmentProgressModel = std::make_shared<SparseTimeValueModel> - (reference->getSampleRate(), m_transform.getStepSize(), false); - alignmentProgressModel->setCompletion(0); - m_alignmentProgressModel = ModelById::add(alignmentProgressModel); auto alignmentModel = std::make_shared<AlignmentModel> - (m_reference, m_toAlign, m_alignmentProgressModel); + (m_reference, m_toAlign, ModelId()); m_alignmentModel = ModelById::add(alignmentModel); toAlign->setAlignment(m_alignmentModel); @@ -153,8 +163,9 @@ auto referenceOutputModel = ModelById::get(m_referenceOutputModel); auto toAlignOutputModel = ModelById::get(m_toAlignOutputModel); + auto alignmentModel = ModelById::getAs<AlignmentModel>(m_alignmentModel); - if (!referenceOutputModel || !toAlignOutputModel) { + if (!referenceOutputModel || !toAlignOutputModel || !alignmentModel) { return; } @@ -162,17 +173,12 @@ bool referenceReady = referenceOutputModel->isReady(&referenceCompletion); bool toAlignReady = toAlignOutputModel->isReady(&toAlignCompletion); - auto alignmentProgressModel = - ModelById::getAs<SparseTimeValueModel>(m_alignmentProgressModel); - if (referenceReady && toAlignReady) { SVCERR << "TransformDTWAligner[" << this << "]: completionChanged: " << "ready, calling performAlignment" << endl; - if (alignmentProgressModel) { - alignmentProgressModel->setCompletion(95); - } + alignmentModel->setCompletion(95); if (performAlignment()) { emit complete(m_alignmentModel); @@ -186,12 +192,10 @@ << "not ready yet: reference completion " << referenceCompletion << ", toAlign completion " << toAlignCompletion << endl; - if (alignmentProgressModel) { - int completion = std::min(referenceCompletion, - toAlignCompletion); - completion = (completion * 94) / 100; - alignmentProgressModel->setCompletion(completion); - } + int completion = std::min(referenceCompletion, + toAlignCompletion); + completion = (completion * 94) / 100; + alignmentModel->setCompletion(completion); } } @@ -229,11 +233,11 @@ { auto events = referenceOutputSTVM->getAllEvents(); for (auto e: events) { - s1.push_back(e.getValue()); + s1.push_back(m_outputPreprocessor(e.getValue())); } events = toAlignOutputSTVM->getAllEvents(); for (auto e: events) { - s2.push_back(e.getValue()); + s2.push_back(m_outputPreprocessor(e.getValue())); } } @@ -260,14 +264,7 @@ } SVCERR << endl; - auto alignmentProgressModel = - ModelById::getAs<SparseTimeValueModel>(m_alignmentProgressModel); - if (alignmentProgressModel) { - alignmentProgressModel->setCompletion(100); - } - - // clear the alignment progress model - alignmentModel->setPathFrom(ModelId()); + alignmentModel->setCompletion(100); sv_frame_t resolution = referenceOutputSTVM->getResolution(); sv_frame_t sourceFrame = 0; @@ -306,36 +303,29 @@ if (!alignmentModel) { return false; } + + auto convertEvents = + [this](const EventVector &ee) { + vector<RiseFallDTW::Value> s; + double prev = 0.0; + for (auto e: ee) { + double v = m_outputPreprocessor(e.getValue()); + if (v == prev || s.empty()) { + s.push_back({ RiseFallDTW::Direction::None, 0.0 }); + } else if (v > prev) { + s.push_back({ RiseFallDTW::Direction::Up, v - prev }); + } else { + s.push_back({ RiseFallDTW::Direction::Down, prev - v }); + } + } + return s; + }; - vector<RiseFallDTW::Value> s1, s2; - double prev1 = 0.0, prev2 = 0.0; + vector<RiseFallDTW::Value> s1 = + convertEvents(referenceOutputSTVM->getAllEvents()); - { - auto events = referenceOutputSTVM->getAllEvents(); - for (auto e: events) { - double v = e.getValue(); - //!!! the original does this using MIDI pitch for the - //!!! pYin transform... rework with a lambda passed in - //!!! for modification maybe? + factor out s1/s2 of course - if (v > prev1) { - s1.push_back({ RiseFallDTW::Direction::Up, v - prev1 }); - } else { - s1.push_back({ RiseFallDTW::Direction::Down, prev1 - v }); - } - prev1 = v; - } - events = toAlignOutputSTVM->getAllEvents(); - for (auto e: events) { - double v = e.getValue(); - //!!! as above - if (v > prev2) { - s2.push_back({ RiseFallDTW::Direction::Up, v - prev2 }); - } else { - s2.push_back({ RiseFallDTW::Direction::Down, prev2 - v }); - } - prev2 = v; - } - } + vector<RiseFallDTW::Value> s2 = + convertEvents(toAlignOutputSTVM->getAllEvents()); SVCERR << "TransformDTWAligner[" << this << "]: performAlignment: " << "Have " << s1.size() << " events from reference, " @@ -361,14 +351,7 @@ } SVCERR << endl; - auto alignmentProgressModel = - ModelById::getAs<SparseTimeValueModel>(m_alignmentProgressModel); - if (alignmentProgressModel) { - alignmentProgressModel->setCompletion(100); - } - - // clear the alignment progress model - alignmentModel->setPathFrom(ModelId()); + alignmentModel->setCompletion(100); sv_frame_t resolution = referenceOutputSTVM->getResolution(); sv_frame_t sourceFrame = 0;
--- a/align/TransformDTWAligner.h Thu May 21 16:21:57 2020 +0100 +++ b/align/TransformDTWAligner.h Fri May 22 17:17:44 2020 +0100 @@ -19,6 +19,8 @@ #include "transform/Transform.h" +#include <functional> + class AlignmentModel; class Document; @@ -37,6 +39,13 @@ ModelId toAlign, Transform transform, DTWType dtwType); + + TransformDTWAligner(Document *doc, + ModelId reference, + ModelId toAlign, + Transform transform, + DTWType dtwType, + std::function<double(double)> outputPreprocessor); // Destroy the aligner, cleanly cancelling any ongoing alignment ~TransformDTWAligner(); @@ -58,13 +67,11 @@ ModelId m_toAlign; ModelId m_referenceOutputModel; ModelId m_toAlignOutputModel; - ModelId m_alignmentProgressModel; ModelId m_alignmentModel; - bool m_referenceTransformComplete; - bool m_toAlignTransformComplete; Transform m_transform; DTWType m_dtwType; bool m_incomplete; + std::function<double(double)> m_outputPreprocessor; }; #endif