# HG changeset patch # User Chris Cannam # Date 1195729766 0 # Node ID f14e2f7b24f7b9e172f3642b6abc8cc3c708848f # Parent 5cd7f6d10d47eb63e3c9175ae14bbe688e1a681d * More space and time efficient AlignmentModel diff -r 5cd7f6d10d47 -r f14e2f7b24f7 data/model/AlignmentModel.cpp --- a/data/model/AlignmentModel.cpp Thu Nov 15 13:19:25 2007 +0000 +++ b/data/model/AlignmentModel.cpp Thu Nov 22 11:09:26 2007 +0000 @@ -24,26 +24,29 @@ m_reference(reference), m_aligned(aligned), m_inputModel(inputModel), - m_path(path), + m_rawPath(path), + m_path(0), m_reversePath(0), m_pathBegun(false), m_pathComplete(false) { - connect(m_path, SIGNAL(modelChanged()), + connect(m_rawPath, SIGNAL(modelChanged()), this, SLOT(pathChanged())); - connect(m_path, SIGNAL(modelChanged(size_t, size_t)), + connect(m_rawPath, SIGNAL(modelChanged(size_t, size_t)), this, SLOT(pathChanged(size_t, size_t))); - connect(m_path, SIGNAL(completionChanged()), + connect(m_rawPath, SIGNAL(completionChanged()), this, SLOT(pathCompletionChanged())); + constructPath(); constructReversePath(); } AlignmentModel::~AlignmentModel() { delete m_inputModel; + delete m_rawPath; delete m_path; delete m_reversePath; } @@ -51,13 +54,13 @@ bool AlignmentModel::isOK() const { - return m_path->isOK(); + if (m_rawPath) return m_rawPath->isOK(); + else return true; } size_t AlignmentModel::getStartFrame() const { - //!!! do we care about distinct rates? size_t a = m_reference->getStartFrame(); size_t b = m_aligned->getStartFrame(); return std::min(a, b); @@ -66,7 +69,6 @@ size_t AlignmentModel::getEndFrame() const { - //!!! do we care about distinct rates? size_t a = m_reference->getEndFrame(); size_t b = m_aligned->getEndFrame(); return std::max(a, b); @@ -84,23 +86,27 @@ return new AlignmentModel (m_reference, m_aligned, m_inputModel ? m_inputModel->clone() : 0, - m_path ? static_cast(m_path->clone()) : 0); + m_rawPath ? static_cast(m_rawPath->clone()) : 0); } bool AlignmentModel::isReady(int *completion) const { if (!m_pathBegun) { - completion = 0; + if (completion) *completion = 0; return false; } - return m_path->isReady(completion); + if (m_pathComplete || !m_rawPath) { + if (completion) *completion = 100; + return true; + } + return m_rawPath->isReady(completion); } const ZoomConstraint * AlignmentModel::getZoomConstraint() const { - return m_path->getZoomConstraint(); + return 0; } const Model * @@ -127,6 +133,7 @@ AlignmentModel::fromReference(size_t frame) const { // std::cerr << "AlignmentModel::fromReference(" << frame << ")" << std::endl; + if (!m_path) constructPath(); return align(m_path, frame); } @@ -139,6 +146,7 @@ AlignmentModel::pathChanged(size_t, size_t) { if (!m_pathComplete) return; + constructPath(); constructReversePath(); } @@ -148,13 +156,23 @@ m_pathBegun = true; if (!m_pathComplete) { + int completion = 0; - m_path->isReady(&completion); + m_rawPath->isReady(&completion); + // std::cerr << "AlignmentModel::pathCompletionChanged: completion = " // << completion << std::endl; + m_pathComplete = (completion == 100); + if (m_pathComplete) { + + constructPath(); constructReversePath(); + + delete m_rawPath; + m_rawPath = 0; + delete m_inputModel; m_inputModel = 0; } @@ -164,78 +182,108 @@ } void -AlignmentModel::constructReversePath() const +AlignmentModel::constructPath() const { - if (!m_reversePath) { - m_reversePath = new SparseTimeValueModel - (m_path->getSampleRate(), m_path->getResolution(), false); + if (!m_path) { + if (!m_rawPath) { + std::cerr << "ERROR: AlignmentModel::constructPath: " + << "No raw path available" << std::endl; + return; + } + m_path = new PathModel + (m_rawPath->getSampleRate(), m_rawPath->getResolution(), false); + } else { + if (!m_rawPath) return; } - m_reversePath->clear(); + m_path->clear(); - SparseTimeValueModel::PointList points = m_path->getPoints(); + SparseTimeValueModel::PointList points = m_rawPath->getPoints(); for (SparseTimeValueModel::PointList::const_iterator i = points.begin(); i != points.end(); ++i) { long frame = i->frame; float value = i->value; long rframe = lrintf(value * m_aligned->getSampleRate()); - float rvalue = (float)frame / (float)m_reference->getSampleRate(); - m_reversePath->addPoint - (SparseTimeValueModel::Point(rframe, rvalue, "")); + m_path->addPoint(PathPoint(frame, rframe)); } - std::cerr << "AlignmentModel::constructReversePath: " << m_reversePath->getPointCount() << " points, at least " << (2 * m_reversePath->getPointCount() * (3 * sizeof(void *) + sizeof(int) + sizeof(SparseTimeValueModel::Point))) << " bytes" << std::endl; + std::cerr << "AlignmentModel::constructPath: " << m_path->getPointCount() << " points, at least " << (2 * m_path->getPointCount() * (3 * sizeof(void *) + sizeof(int) + sizeof(PathPoint))) << " bytes" << std::endl; +} + +void +AlignmentModel::constructReversePath() const +{ + if (!m_reversePath) { + if (!m_rawPath) { + std::cerr << "ERROR: AlignmentModel::constructReversePath: " + << "No raw path available" << std::endl; + return; + } + m_reversePath = new PathModel + (m_rawPath->getSampleRate(), m_rawPath->getResolution(), false); + } else { + if (!m_rawPath) return; + } + + m_reversePath->clear(); + + SparseTimeValueModel::PointList points = m_rawPath->getPoints(); + + for (SparseTimeValueModel::PointList::const_iterator i = points.begin(); + i != points.end(); ++i) { + long frame = i->frame; + float value = i->value; + long rframe = lrintf(value * m_aligned->getSampleRate()); + m_reversePath->addPoint(PathPoint(rframe, frame)); + } + + std::cerr << "AlignmentModel::constructReversePath: " << m_reversePath->getPointCount() << " points, at least " << (2 * m_reversePath->getPointCount() * (3 * sizeof(void *) + sizeof(int) + sizeof(PathPoint))) << " bytes" << std::endl; } size_t -AlignmentModel::align(SparseTimeValueModel *path, size_t frame) const +AlignmentModel::align(PathModel *path, size_t frame) const { - // The path consists of a series of points, each with x (time) - // equal to the time on the source model and y (value) equal to - // the time on the target model. Times and values are both - // monotonically increasing. + // The path consists of a series of points, each with frame equal + // to the frame on the source model and mapframe equal to the + // frame on the target model. Both should be monotonically + // increasing. - const SparseTimeValueModel::PointList &points = path->getPoints(); + const PathModel::PointList &points = path->getPoints(); if (points.empty()) { // std::cerr << "AlignmentModel::align: No points" << std::endl; return frame; } - SparseTimeValueModel::Point point(frame); - SparseTimeValueModel::PointList::const_iterator i = points.lower_bound(point); + PathModel::Point point(frame); + PathModel::PointList::const_iterator i = points.lower_bound(point); if (i == points.end()) --i; - while (i != points.begin() && i->frame > frame) --i; + while (i != points.begin() && i->frame > long(frame)) --i; long foundFrame = i->frame; - float foundTime = i->value; + long foundMapFrame = i->mapframe; long followingFrame = foundFrame; - float followingTime = foundTime; + long followingMapFrame = foundMapFrame; if (++i != points.end()) { followingFrame = i->frame; - followingTime = i->value; + followingMapFrame = i->mapframe; } - float resultTime = foundTime; + if (foundMapFrame < 0) return 0; - if (followingFrame != foundFrame && frame > foundFrame) { + size_t resultFrame = foundMapFrame; -// std::cerr << "AlignmentModel::align: foundFrame = " << foundFrame << ", frame = " << frame << ", followingFrame = " << followingFrame << std::endl; - - float interp = float(frame - foundFrame) / float(followingFrame - foundFrame); -// std::cerr << "AlignmentModel::align: interp = " << interp << ", result " << resultTime << " -> "; - - resultTime += (followingTime - foundTime) * interp; - -// std::cerr << resultTime << std::endl; + if (followingFrame != foundFrame && long(frame) > foundFrame) { + float interp = + float(frame - foundFrame) / + float(followingFrame - foundFrame); + resultFrame += lrintf((followingMapFrame - foundMapFrame) * interp); } - size_t resultFrame = lrintf(resultTime * getSampleRate()); - -// std::cerr << "AlignmentModel::align: resultFrame = " << resultFrame << std::endl; + std::cerr << "AlignmentModel::align: resultFrame = " << resultFrame << std::endl; return resultFrame; } diff -r 5cd7f6d10d47 -r f14e2f7b24f7 data/model/AlignmentModel.h --- a/data/model/AlignmentModel.h Thu Nov 15 13:19:25 2007 +0000 +++ b/data/model/AlignmentModel.h Thu Nov 22 11:09:26 2007 +0000 @@ -17,6 +17,11 @@ #define _ALIGNMENT_MODEL_H_ #include "Model.h" +#include "SparseModel.h" +#include "base/RealTime.h" + +#include +#include class SparseTimeValueModel; @@ -60,14 +65,65 @@ Model *m_aligned; // I don't own this Model *m_inputModel; // I own this - SparseTimeValueModel *m_path; // I own this - mutable SparseTimeValueModel *m_reversePath; // I own this + + struct PathPoint + { + PathPoint(long _frame) : frame(_frame), mapframe(_frame) { } + PathPoint(long _frame, long _mapframe) : + frame(_frame), mapframe(_mapframe) { } + + int getDimensions() const { return 2; } + + long frame; + long mapframe; + + QString getLabel() const { return ""; } + + void toXml(QTextStream &stream, QString indent = "", + QString extraAttributes = "") const { + stream << QString("%1\n") + .arg(indent).arg(frame).arg(mapframe).arg(extraAttributes); + } + + QString toDelimitedDataString(QString delimiter, + size_t sampleRate) const { + QStringList list; + list << RealTime::frame2RealTime(frame, sampleRate).toString().c_str(); + list << QString("%1").arg(mapframe); + return list.join(delimiter); + } + + struct Comparator { + bool operator()(const PathPoint &p1, const PathPoint &p2) const { + if (p1.frame != p2.frame) return p1.frame < p2.frame; + return p1.mapframe < p2.mapframe; + } + }; + + struct OrderComparator { + bool operator()(const PathPoint &p1, const PathPoint &p2) const { + return p1.frame < p2.frame; + } + }; + }; + + class PathModel : public SparseModel + { + public: + PathModel(size_t sampleRate, size_t resolution, bool notify = true) : + SparseModel(sampleRate, resolution, notify) { } + }; + + SparseTimeValueModel *m_rawPath; // I own this + mutable PathModel *m_path; // I own this + mutable PathModel *m_reversePath; // I own this bool m_pathBegun; bool m_pathComplete; + void constructPath() const; void constructReversePath() const; - size_t align(SparseTimeValueModel *path, size_t frame) const; + size_t align(PathModel *path, size_t frame) const; }; #endif diff -r 5cd7f6d10d47 -r f14e2f7b24f7 data/model/ImageModel.h --- a/data/model/ImageModel.h Thu Nov 15 13:19:25 2007 +0000 +++ b/data/model/ImageModel.h Thu Nov 22 11:09:26 2007 +0000 @@ -38,6 +38,8 @@ long frame; QString image; QString label; + + QString getLabel() const { return label; } void toXml(QTextStream &stream, QString indent = "", diff -r 5cd7f6d10d47 -r f14e2f7b24f7 data/model/NoteModel.h --- a/data/model/NoteModel.h Thu Nov 15 13:19:25 2007 +0000 +++ b/data/model/NoteModel.h Thu Nov 22 11:09:26 2007 +0000 @@ -43,6 +43,8 @@ size_t duration; QString label; + QString getLabel() const { return label; } + void toXml(QTextStream &stream, QString indent = "", QString extraAttributes = "") const diff -r 5cd7f6d10d47 -r f14e2f7b24f7 data/model/SparseModel.h --- a/data/model/SparseModel.h Thu Nov 15 13:19:25 2007 +0000 +++ b/data/model/SparseModel.h Thu Nov 22 11:09:26 2007 +0000 @@ -462,7 +462,7 @@ QMutexLocker locker(&m_mutex); m_points.insert(point); m_pointCount++; - if (point.label != "") m_hasTextLabels = true; + if (point.getLabel() != "") m_hasTextLabels = true; } // Even though this model is nominally sparse, there may still be diff -r 5cd7f6d10d47 -r f14e2f7b24f7 data/model/SparseOneDimensionalModel.h --- a/data/model/SparseOneDimensionalModel.h Thu Nov 15 13:19:25 2007 +0000 +++ b/data/model/SparseOneDimensionalModel.h Thu Nov 22 11:09:26 2007 +0000 @@ -30,7 +30,9 @@ long frame; QString label; - + + QString getLabel() const { return label; } + void toXml(QTextStream &stream, QString indent = "", QString extraAttributes = "") const diff -r 5cd7f6d10d47 -r f14e2f7b24f7 data/model/SparseTimeValueModel.h --- a/data/model/SparseTimeValueModel.h Thu Nov 15 13:19:25 2007 +0000 +++ b/data/model/SparseTimeValueModel.h Thu Nov 22 11:09:26 2007 +0000 @@ -38,6 +38,8 @@ long frame; float value; QString label; + + QString getLabel() const { return label; } void toXml(QTextStream &stream, QString indent = "", QString extraAttributes = "") const diff -r 5cd7f6d10d47 -r f14e2f7b24f7 data/model/TextModel.h --- a/data/model/TextModel.h Thu Nov 15 13:19:25 2007 +0000 +++ b/data/model/TextModel.h Thu Nov 22 11:09:26 2007 +0000 @@ -38,6 +38,8 @@ long frame; float height; QString label; + + QString getLabel() const { return label; } void toXml(QTextStream &stream, QString indent = "", QString extraAttributes = "") const