Mercurial > hg > svcore
diff data/model/AlignmentModel.cpp @ 297:c022976d18e8
* Merge from sv-match-alignment branch (excluding alignment-specific document).
- add aggregate wave model (not yet complete enough to be added as a true
model in a layer, but there's potential)
- add play solo mode
- add alignment model -- unused in plain SV
- fix two plugin leaks
- add m3u playlist support (opens all files at once, potentially hazardous)
- fix retrieval of pre-encoded URLs
- add ability to resample audio files on import, so as to match rates with
other files previously loaded; add preference for same
- add preliminary support in transform code for range and rate of transform
input
- reorganise preferences dialog, move dark-background option to preferences,
add option for temporary directory location
author | Chris Cannam |
---|---|
date | Fri, 28 Sep 2007 13:56:38 +0000 |
parents | |
children | df707a61b23f |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/data/model/AlignmentModel.cpp Fri Sep 28 13:56:38 2007 +0000 @@ -0,0 +1,210 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Sonic Visualiser + An audio file viewer and annotation editor. + Centre for Digital Music, Queen Mary, University of London. + This file copyright 2007 QMUL. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#include "AlignmentModel.h" + +#include "SparseTimeValueModel.h" + +AlignmentModel::AlignmentModel(Model *reference, + Model *aligned, + Model *inputModel, + SparseTimeValueModel *path) : + m_reference(reference), + m_aligned(aligned), + m_inputModel(inputModel), + m_path(path), + m_reversePath(0), + m_pathComplete(false) +{ + connect(m_path, SIGNAL(modelChanged()), + this, SLOT(pathChanged())); + + connect(m_path, SIGNAL(modelChanged(size_t, size_t)), + this, SLOT(pathChanged(size_t, size_t))); + + connect(m_path, SIGNAL(completionChanged()), + this, SLOT(pathCompletionChanged())); + + constructReversePath(); +} + +AlignmentModel::~AlignmentModel() +{ + delete m_inputModel; + delete m_path; + delete m_reversePath; +} + +bool +AlignmentModel::isOK() const +{ + return m_path->isOK(); +} + +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); +} + +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); +} + +size_t +AlignmentModel::getSampleRate() const +{ + return m_reference->getSampleRate(); +} + +Model * +AlignmentModel::clone() const +{ + return new AlignmentModel + (m_reference, m_aligned, + m_inputModel ? m_inputModel->clone() : 0, + m_path ? static_cast<SparseTimeValueModel *>(m_path->clone()) : 0); +} + +bool +AlignmentModel::isReady(int *completion) const +{ + return m_path->isReady(completion); +} + +const ZoomConstraint * +AlignmentModel::getZoomConstraint() const +{ + return m_path->getZoomConstraint(); +} + +const Model * +AlignmentModel::getReferenceModel() const +{ + return m_reference; +} + +const Model * +AlignmentModel::getAlignedModel() const +{ + return m_aligned; +} + +size_t +AlignmentModel::toReference(size_t frame) const +{ +// std::cerr << "AlignmentModel::toReference(" << frame << ")" << std::endl; + if (!m_reversePath) constructReversePath(); + return align(m_reversePath, frame); +} + +size_t +AlignmentModel::fromReference(size_t frame) const +{ +// std::cerr << "AlignmentModel::fromReference(" << frame << ")" << std::endl; + return align(m_path, frame); +} + +void +AlignmentModel::pathChanged() +{ +} + +void +AlignmentModel::pathChanged(size_t, size_t) +{ + if (!m_pathComplete) return; + constructReversePath(); +} + +void +AlignmentModel::pathCompletionChanged() +{ + if (!m_pathComplete) { + int completion = 0; + m_path->isReady(&completion); + std::cerr << "AlignmentModel::pathCompletionChanged: completion = " + << completion << std::endl; + m_pathComplete = (completion == 100); //!!! a bit of a hack + if (m_pathComplete) { + constructReversePath(); + delete m_inputModel; + m_inputModel = 0; + } + } + emit completionChanged(); +} + +void +AlignmentModel::constructReversePath() const +{ + if (!m_reversePath) { + m_reversePath = new SparseTimeValueModel + (m_path->getSampleRate(), m_path->getResolution(), false); + } + + m_reversePath->clear(); + + SparseTimeValueModel::PointList points = m_path->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, "")); + } + + std::cerr << "AlignmentModel::constructReversePath: " << m_reversePath->getPointCount() << " points" << std::endl; +} + +size_t +AlignmentModel::align(SparseTimeValueModel *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. + + const SparseTimeValueModel::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); + if (i == points.end()) --i; + float time = i->value; + size_t rv = lrintf(time * getSampleRate()); + + //!!! interpolate! + +// std::cerr << "AlignmentModel::align: rv = " << rv << std::endl; + + return rv; +} +