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@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@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@297: if (!m_pathComplete) { Chris@297: int completion = 0; Chris@297: m_path->isReady(&completion); Chris@297: std::cerr << "AlignmentModel::pathCompletionChanged: completion = " Chris@297: << completion << std::endl; Chris@297: m_pathComplete = (completion == 100); //!!! a bit of a hack Chris@297: if (m_pathComplete) { Chris@297: constructReversePath(); Chris@297: delete m_inputModel; Chris@297: m_inputModel = 0; Chris@297: } Chris@297: } 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@297: std::cerr << "AlignmentModel::constructReversePath: " << m_reversePath->getPointCount() << " points" << 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@297: float time = i->value; Chris@297: size_t rv = lrintf(time * getSampleRate()); Chris@297: Chris@297: //!!! interpolate! Chris@297: Chris@297: // std::cerr << "AlignmentModel::align: rv = " << rv << std::endl; Chris@297: Chris@297: return rv; Chris@297: } Chris@297: