annotate data/model/AlignmentModel.cpp @ 316:3a6725f285d6

* Make RemoteFile far more pervasive, and use it for local files as well so that we can handle both transparently. Make it shallow copy with reference counting, so it can be used by value without having to worry about the cache file lifetime. Use RemoteFile for MainWindow file-open functions, etc
author Chris Cannam
date Thu, 18 Oct 2007 15:31:20 +0000
parents 29485aa03da4
children a71dec01c4d3
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@312 180 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 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@312 201 while (i != points.begin() && i->frame > frame) --i;
Chris@297 202
Chris@312 203 long foundFrame = i->frame;
Chris@312 204 float foundTime = i->value;
Chris@297 205
Chris@312 206 long followingFrame = foundFrame;
Chris@312 207 float followingTime = foundTime;
Chris@297 208
Chris@312 209 if (++i != points.end()) {
Chris@312 210 followingFrame = i->frame;
Chris@312 211 followingTime = i->value;
Chris@312 212 }
Chris@312 213
Chris@312 214 float resultTime = foundTime;
Chris@312 215
Chris@312 216 if (followingFrame != foundFrame && frame > foundFrame) {
Chris@312 217
Chris@313 218 // std::cerr << "AlignmentModel::align: foundFrame = " << foundFrame << ", frame = " << frame << ", followingFrame = " << followingFrame << std::endl;
Chris@312 219
Chris@312 220 float interp = float(frame - foundFrame) / float(followingFrame - foundFrame);
Chris@313 221 // std::cerr << "AlignmentModel::align: interp = " << interp << ", result " << resultTime << " -> ";
Chris@312 222
Chris@312 223 resultTime += (followingTime - foundTime) * interp;
Chris@312 224
Chris@313 225 // std::cerr << resultTime << std::endl;
Chris@312 226 }
Chris@312 227
Chris@312 228 size_t resultFrame = lrintf(resultTime * getSampleRate());
Chris@312 229
Chris@313 230 // std::cerr << "AlignmentModel::align: resultFrame = " << resultFrame << std::endl;
Chris@312 231
Chris@312 232 return resultFrame;
Chris@297 233 }
Chris@297 234