Chris@297: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@297: Chris@297: /* Chris@297: Sonic Visualiser Chris@297: An audio file viewer and annotation editor. Chris@297: Centre for Digital Music, Queen Mary, University of London. Chris@297: This file copyright 2007 QMUL. Chris@297: Chris@297: This program is free software; you can redistribute it and/or Chris@297: modify it under the terms of the GNU General Public License as Chris@297: published by the Free Software Foundation; either version 2 of the Chris@297: License, or (at your option) any later version. See the file Chris@297: COPYING included with this distribution for more information. Chris@297: */ Chris@297: Chris@297: #include "AlignmentModel.h" Chris@297: Chris@297: #include "SparseTimeValueModel.h" Chris@297: Chris@297: AlignmentModel::AlignmentModel(Model *reference, Chris@297: Model *aligned, Chris@297: Model *inputModel, Chris@297: SparseTimeValueModel *path) : Chris@297: m_reference(reference), Chris@297: m_aligned(aligned), Chris@297: m_inputModel(inputModel), Chris@297: m_path(path), Chris@297: m_reversePath(0), Chris@323: m_pathBegun(false), Chris@297: m_pathComplete(false) Chris@297: { Chris@297: connect(m_path, SIGNAL(modelChanged()), Chris@297: this, SLOT(pathChanged())); Chris@297: Chris@297: connect(m_path, SIGNAL(modelChanged(size_t, size_t)), Chris@297: this, SLOT(pathChanged(size_t, size_t))); Chris@297: Chris@297: connect(m_path, SIGNAL(completionChanged()), Chris@297: this, SLOT(pathCompletionChanged())); Chris@297: Chris@297: constructReversePath(); Chris@297: } Chris@297: Chris@297: AlignmentModel::~AlignmentModel() Chris@297: { Chris@297: delete m_inputModel; Chris@297: delete m_path; Chris@297: delete m_reversePath; Chris@297: } Chris@297: Chris@297: bool Chris@297: AlignmentModel::isOK() const Chris@297: { Chris@297: return m_path->isOK(); Chris@297: } Chris@297: Chris@297: size_t Chris@297: AlignmentModel::getStartFrame() const Chris@297: { Chris@297: //!!! do we care about distinct rates? Chris@297: size_t a = m_reference->getStartFrame(); Chris@297: size_t b = m_aligned->getStartFrame(); Chris@297: return std::min(a, b); Chris@297: } Chris@297: Chris@297: size_t Chris@297: AlignmentModel::getEndFrame() const Chris@297: { Chris@297: //!!! do we care about distinct rates? Chris@297: size_t a = m_reference->getEndFrame(); Chris@297: size_t b = m_aligned->getEndFrame(); Chris@297: return std::max(a, b); Chris@297: } Chris@297: Chris@297: size_t Chris@297: AlignmentModel::getSampleRate() const Chris@297: { Chris@297: return m_reference->getSampleRate(); Chris@297: } Chris@297: Chris@297: Model * Chris@297: AlignmentModel::clone() const Chris@297: { Chris@297: return new AlignmentModel Chris@297: (m_reference, m_aligned, Chris@297: m_inputModel ? m_inputModel->clone() : 0, Chris@297: m_path ? static_cast(m_path->clone()) : 0); Chris@297: } Chris@297: Chris@297: bool Chris@297: AlignmentModel::isReady(int *completion) const Chris@297: { Chris@323: if (!m_pathBegun) { Chris@323: completion = 0; Chris@323: return false; Chris@323: } Chris@297: return m_path->isReady(completion); Chris@297: } Chris@297: Chris@297: const ZoomConstraint * Chris@297: AlignmentModel::getZoomConstraint() const Chris@297: { Chris@297: return m_path->getZoomConstraint(); Chris@297: } Chris@297: Chris@297: const Model * Chris@297: AlignmentModel::getReferenceModel() const Chris@297: { Chris@297: return m_reference; Chris@297: } Chris@297: Chris@297: const Model * Chris@297: AlignmentModel::getAlignedModel() const Chris@297: { Chris@297: return m_aligned; Chris@297: } Chris@297: Chris@297: size_t Chris@297: AlignmentModel::toReference(size_t frame) const Chris@297: { Chris@297: // std::cerr << "AlignmentModel::toReference(" << frame << ")" << std::endl; Chris@297: if (!m_reversePath) constructReversePath(); Chris@297: return align(m_reversePath, frame); Chris@297: } Chris@297: Chris@297: size_t Chris@297: AlignmentModel::fromReference(size_t frame) const Chris@297: { Chris@297: // std::cerr << "AlignmentModel::fromReference(" << frame << ")" << std::endl; Chris@297: return align(m_path, frame); Chris@297: } Chris@297: Chris@297: void Chris@297: AlignmentModel::pathChanged() Chris@297: { Chris@297: } Chris@297: Chris@297: void Chris@297: AlignmentModel::pathChanged(size_t, size_t) Chris@297: { Chris@297: if (!m_pathComplete) return; Chris@297: constructReversePath(); Chris@297: } Chris@297: Chris@297: void Chris@297: AlignmentModel::pathCompletionChanged() Chris@297: { Chris@323: m_pathBegun = true; Chris@323: Chris@297: if (!m_pathComplete) { Chris@297: int completion = 0; Chris@297: m_path->isReady(&completion); Chris@333: // std::cerr << "AlignmentModel::pathCompletionChanged: completion = " Chris@333: // << completion << std::endl; Chris@323: m_pathComplete = (completion == 100); Chris@297: if (m_pathComplete) { Chris@297: constructReversePath(); Chris@297: delete m_inputModel; Chris@297: m_inputModel = 0; Chris@297: } Chris@297: } Chris@323: Chris@297: emit completionChanged(); Chris@297: } Chris@297: Chris@297: void Chris@297: AlignmentModel::constructReversePath() const Chris@297: { Chris@297: if (!m_reversePath) { Chris@297: m_reversePath = new SparseTimeValueModel Chris@297: (m_path->getSampleRate(), m_path->getResolution(), false); Chris@297: } Chris@297: Chris@297: m_reversePath->clear(); Chris@297: Chris@297: SparseTimeValueModel::PointList points = m_path->getPoints(); Chris@297: Chris@297: for (SparseTimeValueModel::PointList::const_iterator i = points.begin(); Chris@297: i != points.end(); ++i) { Chris@297: long frame = i->frame; Chris@297: float value = i->value; Chris@297: long rframe = lrintf(value * m_aligned->getSampleRate()); Chris@297: float rvalue = (float)frame / (float)m_reference->getSampleRate(); Chris@297: m_reversePath->addPoint Chris@297: (SparseTimeValueModel::Point(rframe, rvalue, "")); Chris@297: } Chris@297: Chris@312: 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; Chris@297: } Chris@297: Chris@297: size_t Chris@297: AlignmentModel::align(SparseTimeValueModel *path, size_t frame) const Chris@297: { Chris@297: // The path consists of a series of points, each with x (time) Chris@297: // equal to the time on the source model and y (value) equal to Chris@297: // the time on the target model. Times and values are both Chris@297: // monotonically increasing. Chris@297: Chris@297: const SparseTimeValueModel::PointList &points = path->getPoints(); Chris@297: Chris@297: if (points.empty()) { Chris@297: // std::cerr << "AlignmentModel::align: No points" << std::endl; Chris@297: return frame; Chris@297: } Chris@297: Chris@297: SparseTimeValueModel::Point point(frame); Chris@297: SparseTimeValueModel::PointList::const_iterator i = points.lower_bound(point); Chris@297: if (i == points.end()) --i; Chris@312: while (i != points.begin() && i->frame > frame) --i; Chris@297: Chris@312: long foundFrame = i->frame; Chris@312: float foundTime = i->value; Chris@297: Chris@312: long followingFrame = foundFrame; Chris@312: float followingTime = foundTime; Chris@297: Chris@312: if (++i != points.end()) { Chris@312: followingFrame = i->frame; Chris@312: followingTime = i->value; Chris@312: } Chris@312: Chris@312: float resultTime = foundTime; Chris@312: Chris@312: if (followingFrame != foundFrame && frame > foundFrame) { Chris@312: Chris@313: // std::cerr << "AlignmentModel::align: foundFrame = " << foundFrame << ", frame = " << frame << ", followingFrame = " << followingFrame << std::endl; Chris@312: Chris@312: float interp = float(frame - foundFrame) / float(followingFrame - foundFrame); Chris@313: // std::cerr << "AlignmentModel::align: interp = " << interp << ", result " << resultTime << " -> "; Chris@312: Chris@312: resultTime += (followingTime - foundTime) * interp; Chris@312: Chris@313: // std::cerr << resultTime << std::endl; Chris@312: } Chris@312: Chris@312: size_t resultFrame = lrintf(resultTime * getSampleRate()); Chris@312: Chris@313: // std::cerr << "AlignmentModel::align: resultFrame = " << resultFrame << std::endl; Chris@312: Chris@312: return resultFrame; Chris@297: } Chris@297: