annotate data/model/AlignmentModel.cpp @ 300:5877d68815c7

* Change WaveFileModel API from getValues(start,end) to getData(start,count). It's much less error-prone to pass in frame counts instead of start/end locations. Should have done this ages ago. This closes #1794563. * Add option to apply a transform to only the selection region, instead of the whole audio. * (to make the above work properly) Add start frame offset to wave models
author Chris Cannam
date Mon, 01 Oct 2007 13:48:38 +0000
parents c022976d18e8
children df707a61b23f
rev   line source
Chris@297 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@297 2
Chris@297 3 /*
Chris@297 4 Sonic Visualiser
Chris@297 5 An audio file viewer and annotation editor.
Chris@297 6 Centre for Digital Music, Queen Mary, University of London.
Chris@297 7 This file copyright 2007 QMUL.
Chris@297 8
Chris@297 9 This program is free software; you can redistribute it and/or
Chris@297 10 modify it under the terms of the GNU General Public License as
Chris@297 11 published by the Free Software Foundation; either version 2 of the
Chris@297 12 License, or (at your option) any later version. See the file
Chris@297 13 COPYING included with this distribution for more information.
Chris@297 14 */
Chris@297 15
Chris@297 16 #include "AlignmentModel.h"
Chris@297 17
Chris@297 18 #include "SparseTimeValueModel.h"
Chris@297 19
Chris@297 20 AlignmentModel::AlignmentModel(Model *reference,
Chris@297 21 Model *aligned,
Chris@297 22 Model *inputModel,
Chris@297 23 SparseTimeValueModel *path) :
Chris@297 24 m_reference(reference),
Chris@297 25 m_aligned(aligned),
Chris@297 26 m_inputModel(inputModel),
Chris@297 27 m_path(path),
Chris@297 28 m_reversePath(0),
Chris@297 29 m_pathComplete(false)
Chris@297 30 {
Chris@297 31 connect(m_path, SIGNAL(modelChanged()),
Chris@297 32 this, SLOT(pathChanged()));
Chris@297 33
Chris@297 34 connect(m_path, SIGNAL(modelChanged(size_t, size_t)),
Chris@297 35 this, SLOT(pathChanged(size_t, size_t)));
Chris@297 36
Chris@297 37 connect(m_path, SIGNAL(completionChanged()),
Chris@297 38 this, SLOT(pathCompletionChanged()));
Chris@297 39
Chris@297 40 constructReversePath();
Chris@297 41 }
Chris@297 42
Chris@297 43 AlignmentModel::~AlignmentModel()
Chris@297 44 {
Chris@297 45 delete m_inputModel;
Chris@297 46 delete m_path;
Chris@297 47 delete m_reversePath;
Chris@297 48 }
Chris@297 49
Chris@297 50 bool
Chris@297 51 AlignmentModel::isOK() const
Chris@297 52 {
Chris@297 53 return m_path->isOK();
Chris@297 54 }
Chris@297 55
Chris@297 56 size_t
Chris@297 57 AlignmentModel::getStartFrame() const
Chris@297 58 {
Chris@297 59 //!!! do we care about distinct rates?
Chris@297 60 size_t a = m_reference->getStartFrame();
Chris@297 61 size_t b = m_aligned->getStartFrame();
Chris@297 62 return std::min(a, b);
Chris@297 63 }
Chris@297 64
Chris@297 65 size_t
Chris@297 66 AlignmentModel::getEndFrame() const
Chris@297 67 {
Chris@297 68 //!!! do we care about distinct rates?
Chris@297 69 size_t a = m_reference->getEndFrame();
Chris@297 70 size_t b = m_aligned->getEndFrame();
Chris@297 71 return std::max(a, b);
Chris@297 72 }
Chris@297 73
Chris@297 74 size_t
Chris@297 75 AlignmentModel::getSampleRate() const
Chris@297 76 {
Chris@297 77 return m_reference->getSampleRate();
Chris@297 78 }
Chris@297 79
Chris@297 80 Model *
Chris@297 81 AlignmentModel::clone() const
Chris@297 82 {
Chris@297 83 return new AlignmentModel
Chris@297 84 (m_reference, m_aligned,
Chris@297 85 m_inputModel ? m_inputModel->clone() : 0,
Chris@297 86 m_path ? static_cast<SparseTimeValueModel *>(m_path->clone()) : 0);
Chris@297 87 }
Chris@297 88
Chris@297 89 bool
Chris@297 90 AlignmentModel::isReady(int *completion) const
Chris@297 91 {
Chris@297 92 return m_path->isReady(completion);
Chris@297 93 }
Chris@297 94
Chris@297 95 const ZoomConstraint *
Chris@297 96 AlignmentModel::getZoomConstraint() const
Chris@297 97 {
Chris@297 98 return m_path->getZoomConstraint();
Chris@297 99 }
Chris@297 100
Chris@297 101 const Model *
Chris@297 102 AlignmentModel::getReferenceModel() const
Chris@297 103 {
Chris@297 104 return m_reference;
Chris@297 105 }
Chris@297 106
Chris@297 107 const Model *
Chris@297 108 AlignmentModel::getAlignedModel() const
Chris@297 109 {
Chris@297 110 return m_aligned;
Chris@297 111 }
Chris@297 112
Chris@297 113 size_t
Chris@297 114 AlignmentModel::toReference(size_t frame) const
Chris@297 115 {
Chris@297 116 // std::cerr << "AlignmentModel::toReference(" << frame << ")" << std::endl;
Chris@297 117 if (!m_reversePath) constructReversePath();
Chris@297 118 return align(m_reversePath, frame);
Chris@297 119 }
Chris@297 120
Chris@297 121 size_t
Chris@297 122 AlignmentModel::fromReference(size_t frame) const
Chris@297 123 {
Chris@297 124 // std::cerr << "AlignmentModel::fromReference(" << frame << ")" << std::endl;
Chris@297 125 return align(m_path, frame);
Chris@297 126 }
Chris@297 127
Chris@297 128 void
Chris@297 129 AlignmentModel::pathChanged()
Chris@297 130 {
Chris@297 131 }
Chris@297 132
Chris@297 133 void
Chris@297 134 AlignmentModel::pathChanged(size_t, size_t)
Chris@297 135 {
Chris@297 136 if (!m_pathComplete) return;
Chris@297 137 constructReversePath();
Chris@297 138 }
Chris@297 139
Chris@297 140 void
Chris@297 141 AlignmentModel::pathCompletionChanged()
Chris@297 142 {
Chris@297 143 if (!m_pathComplete) {
Chris@297 144 int completion = 0;
Chris@297 145 m_path->isReady(&completion);
Chris@297 146 std::cerr << "AlignmentModel::pathCompletionChanged: completion = "
Chris@297 147 << completion << std::endl;
Chris@297 148 m_pathComplete = (completion == 100); //!!! a bit of a hack
Chris@297 149 if (m_pathComplete) {
Chris@297 150 constructReversePath();
Chris@297 151 delete m_inputModel;
Chris@297 152 m_inputModel = 0;
Chris@297 153 }
Chris@297 154 }
Chris@297 155 emit completionChanged();
Chris@297 156 }
Chris@297 157
Chris@297 158 void
Chris@297 159 AlignmentModel::constructReversePath() const
Chris@297 160 {
Chris@297 161 if (!m_reversePath) {
Chris@297 162 m_reversePath = new SparseTimeValueModel
Chris@297 163 (m_path->getSampleRate(), m_path->getResolution(), false);
Chris@297 164 }
Chris@297 165
Chris@297 166 m_reversePath->clear();
Chris@297 167
Chris@297 168 SparseTimeValueModel::PointList points = m_path->getPoints();
Chris@297 169
Chris@297 170 for (SparseTimeValueModel::PointList::const_iterator i = points.begin();
Chris@297 171 i != points.end(); ++i) {
Chris@297 172 long frame = i->frame;
Chris@297 173 float value = i->value;
Chris@297 174 long rframe = lrintf(value * m_aligned->getSampleRate());
Chris@297 175 float rvalue = (float)frame / (float)m_reference->getSampleRate();
Chris@297 176 m_reversePath->addPoint
Chris@297 177 (SparseTimeValueModel::Point(rframe, rvalue, ""));
Chris@297 178 }
Chris@297 179
Chris@297 180 std::cerr << "AlignmentModel::constructReversePath: " << m_reversePath->getPointCount() << " points" << std::endl;
Chris@297 181 }
Chris@297 182
Chris@297 183 size_t
Chris@297 184 AlignmentModel::align(SparseTimeValueModel *path, size_t frame) const
Chris@297 185 {
Chris@297 186 // The path consists of a series of points, each with x (time)
Chris@297 187 // equal to the time on the source model and y (value) equal to
Chris@297 188 // the time on the target model. Times and values are both
Chris@297 189 // monotonically increasing.
Chris@297 190
Chris@297 191 const SparseTimeValueModel::PointList &points = path->getPoints();
Chris@297 192
Chris@297 193 if (points.empty()) {
Chris@297 194 // std::cerr << "AlignmentModel::align: No points" << std::endl;
Chris@297 195 return frame;
Chris@297 196 }
Chris@297 197
Chris@297 198 SparseTimeValueModel::Point point(frame);
Chris@297 199 SparseTimeValueModel::PointList::const_iterator i = points.lower_bound(point);
Chris@297 200 if (i == points.end()) --i;
Chris@297 201 float time = i->value;
Chris@297 202 size_t rv = lrintf(time * getSampleRate());
Chris@297 203
Chris@297 204 //!!! interpolate!
Chris@297 205
Chris@297 206 // std::cerr << "AlignmentModel::align: rv = " << rv << std::endl;
Chris@297 207
Chris@297 208 return rv;
Chris@297 209 }
Chris@297 210