annotate data/model/AlignmentModel.cpp @ 392:183ee2a55fc7

* More work to abstract out interactive components used in the data library, so that it does not need to depend on QtGui.
author Chris Cannam
date Fri, 14 Mar 2008 17:14:21 +0000
parents 62789d79b98f
children 88ad01799040
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@376 20 //#define DEBUG_ALIGNMENT_MODEL 1
Chris@376 21
Chris@297 22 AlignmentModel::AlignmentModel(Model *reference,
Chris@297 23 Model *aligned,
Chris@297 24 Model *inputModel,
Chris@297 25 SparseTimeValueModel *path) :
Chris@297 26 m_reference(reference),
Chris@297 27 m_aligned(aligned),
Chris@297 28 m_inputModel(inputModel),
Chris@338 29 m_rawPath(path),
Chris@338 30 m_path(0),
Chris@297 31 m_reversePath(0),
Chris@323 32 m_pathBegun(false),
Chris@297 33 m_pathComplete(false)
Chris@297 34 {
Chris@371 35 if (m_rawPath) {
Chris@297 36
Chris@371 37 connect(m_rawPath, SIGNAL(modelChanged()),
Chris@371 38 this, SLOT(pathChanged()));
Chris@297 39
Chris@371 40 connect(m_rawPath, SIGNAL(modelChanged(size_t, size_t)),
Chris@371 41 this, SLOT(pathChanged(size_t, size_t)));
Chris@371 42
Chris@371 43 connect(m_rawPath, SIGNAL(completionChanged()),
Chris@371 44 this, SLOT(pathCompletionChanged()));
Chris@371 45 }
Chris@297 46
Chris@338 47 constructPath();
Chris@297 48 constructReversePath();
Chris@297 49 }
Chris@297 50
Chris@297 51 AlignmentModel::~AlignmentModel()
Chris@297 52 {
Chris@297 53 delete m_inputModel;
Chris@338 54 delete m_rawPath;
Chris@297 55 delete m_path;
Chris@297 56 delete m_reversePath;
Chris@297 57 }
Chris@297 58
Chris@297 59 bool
Chris@297 60 AlignmentModel::isOK() const
Chris@297 61 {
Chris@338 62 if (m_rawPath) return m_rawPath->isOK();
Chris@338 63 else return true;
Chris@297 64 }
Chris@297 65
Chris@297 66 size_t
Chris@297 67 AlignmentModel::getStartFrame() const
Chris@297 68 {
Chris@297 69 size_t a = m_reference->getStartFrame();
Chris@297 70 size_t b = m_aligned->getStartFrame();
Chris@297 71 return std::min(a, b);
Chris@297 72 }
Chris@297 73
Chris@297 74 size_t
Chris@297 75 AlignmentModel::getEndFrame() const
Chris@297 76 {
Chris@297 77 size_t a = m_reference->getEndFrame();
Chris@297 78 size_t b = m_aligned->getEndFrame();
Chris@297 79 return std::max(a, b);
Chris@297 80 }
Chris@297 81
Chris@297 82 size_t
Chris@297 83 AlignmentModel::getSampleRate() const
Chris@297 84 {
Chris@297 85 return m_reference->getSampleRate();
Chris@297 86 }
Chris@297 87
Chris@297 88 Model *
Chris@297 89 AlignmentModel::clone() const
Chris@297 90 {
Chris@297 91 return new AlignmentModel
Chris@297 92 (m_reference, m_aligned,
Chris@297 93 m_inputModel ? m_inputModel->clone() : 0,
Chris@338 94 m_rawPath ? static_cast<SparseTimeValueModel *>(m_rawPath->clone()) : 0);
Chris@297 95 }
Chris@297 96
Chris@297 97 bool
Chris@297 98 AlignmentModel::isReady(int *completion) const
Chris@297 99 {
Chris@323 100 if (!m_pathBegun) {
Chris@338 101 if (completion) *completion = 0;
Chris@323 102 return false;
Chris@323 103 }
Chris@338 104 if (m_pathComplete || !m_rawPath) {
Chris@338 105 if (completion) *completion = 100;
Chris@338 106 return true;
Chris@338 107 }
Chris@338 108 return m_rawPath->isReady(completion);
Chris@297 109 }
Chris@297 110
Chris@297 111 const ZoomConstraint *
Chris@297 112 AlignmentModel::getZoomConstraint() const
Chris@297 113 {
Chris@338 114 return 0;
Chris@297 115 }
Chris@297 116
Chris@297 117 const Model *
Chris@297 118 AlignmentModel::getReferenceModel() const
Chris@297 119 {
Chris@297 120 return m_reference;
Chris@297 121 }
Chris@297 122
Chris@297 123 const Model *
Chris@297 124 AlignmentModel::getAlignedModel() const
Chris@297 125 {
Chris@297 126 return m_aligned;
Chris@297 127 }
Chris@297 128
Chris@297 129 size_t
Chris@297 130 AlignmentModel::toReference(size_t frame) const
Chris@297 131 {
Chris@376 132 #ifdef DEBUG_ALIGNMENT_MODEL
Chris@376 133 std::cerr << "AlignmentModel::toReference(" << frame << ")" << std::endl;
Chris@376 134 #endif
Chris@371 135 if (!m_path) {
Chris@371 136 if (!m_rawPath) return frame;
Chris@371 137 constructPath();
Chris@371 138 }
Chris@339 139 return align(m_path, frame);
Chris@297 140 }
Chris@297 141
Chris@297 142 size_t
Chris@297 143 AlignmentModel::fromReference(size_t frame) const
Chris@297 144 {
Chris@376 145 #ifdef DEBUG_ALIGNMENT_MODEL
Chris@376 146 std::cerr << "AlignmentModel::fromReference(" << frame << ")" << std::endl;
Chris@376 147 #endif
Chris@371 148 if (!m_reversePath) {
Chris@371 149 if (!m_rawPath) return frame;
Chris@371 150 constructReversePath();
Chris@371 151 }
Chris@339 152 return align(m_reversePath, frame);
Chris@297 153 }
Chris@297 154
Chris@297 155 void
Chris@297 156 AlignmentModel::pathChanged()
Chris@297 157 {
Chris@339 158 if (m_pathComplete) {
Chris@339 159 std::cerr << "AlignmentModel: deleting raw path model" << std::endl;
Chris@339 160 delete m_rawPath;
Chris@339 161 m_rawPath = 0;
Chris@339 162 }
Chris@297 163 }
Chris@297 164
Chris@297 165 void
Chris@297 166 AlignmentModel::pathChanged(size_t, size_t)
Chris@297 167 {
Chris@297 168 if (!m_pathComplete) return;
Chris@338 169 constructPath();
Chris@297 170 constructReversePath();
Chris@297 171 }
Chris@297 172
Chris@297 173 void
Chris@297 174 AlignmentModel::pathCompletionChanged()
Chris@297 175 {
Chris@339 176 if (!m_rawPath) return;
Chris@323 177 m_pathBegun = true;
Chris@323 178
Chris@297 179 if (!m_pathComplete) {
Chris@338 180
Chris@297 181 int completion = 0;
Chris@338 182 m_rawPath->isReady(&completion);
Chris@338 183
Chris@376 184 #ifdef DEBUG_ALIGNMENT_MODEL
Chris@376 185 std::cerr << "AlignmentModel::pathCompletionChanged: completion = "
Chris@376 186 << completion << std::endl;
Chris@376 187 #endif
Chris@338 188
Chris@323 189 m_pathComplete = (completion == 100);
Chris@338 190
Chris@297 191 if (m_pathComplete) {
Chris@338 192
Chris@338 193 constructPath();
Chris@297 194 constructReversePath();
Chris@338 195
Chris@297 196 delete m_inputModel;
Chris@297 197 m_inputModel = 0;
Chris@297 198 }
Chris@297 199 }
Chris@323 200
Chris@297 201 emit completionChanged();
Chris@297 202 }
Chris@297 203
Chris@297 204 void
Chris@338 205 AlignmentModel::constructPath() const
Chris@297 206 {
Chris@338 207 if (!m_path) {
Chris@338 208 if (!m_rawPath) {
Chris@338 209 std::cerr << "ERROR: AlignmentModel::constructPath: "
Chris@338 210 << "No raw path available" << std::endl;
Chris@338 211 return;
Chris@338 212 }
Chris@338 213 m_path = new PathModel
Chris@338 214 (m_rawPath->getSampleRate(), m_rawPath->getResolution(), false);
Chris@338 215 } else {
Chris@338 216 if (!m_rawPath) return;
Chris@297 217 }
Chris@297 218
Chris@338 219 m_path->clear();
Chris@297 220
Chris@338 221 SparseTimeValueModel::PointList points = m_rawPath->getPoints();
Chris@297 222
Chris@297 223 for (SparseTimeValueModel::PointList::const_iterator i = points.begin();
Chris@297 224 i != points.end(); ++i) {
Chris@297 225 long frame = i->frame;
Chris@297 226 float value = i->value;
Chris@297 227 long rframe = lrintf(value * m_aligned->getSampleRate());
Chris@338 228 m_path->addPoint(PathPoint(frame, rframe));
Chris@297 229 }
Chris@297 230
Chris@376 231 #ifdef DEBUG_ALIGNMENT_MODEL
Chris@376 232 std::cerr << "AlignmentModel::constructPath: " << m_path->getPointCount() << " points, at least " << (2 * m_path->getPointCount() * (3 * sizeof(void *) + sizeof(int) + sizeof(PathPoint))) << " bytes" << std::endl;
Chris@376 233 #endif
Chris@338 234 }
Chris@338 235
Chris@338 236 void
Chris@338 237 AlignmentModel::constructReversePath() const
Chris@338 238 {
Chris@338 239 if (!m_reversePath) {
Chris@338 240 if (!m_rawPath) {
Chris@338 241 std::cerr << "ERROR: AlignmentModel::constructReversePath: "
Chris@338 242 << "No raw path available" << std::endl;
Chris@338 243 return;
Chris@338 244 }
Chris@338 245 m_reversePath = new PathModel
Chris@338 246 (m_rawPath->getSampleRate(), m_rawPath->getResolution(), false);
Chris@338 247 } else {
Chris@338 248 if (!m_rawPath) return;
Chris@338 249 }
Chris@338 250
Chris@338 251 m_reversePath->clear();
Chris@338 252
Chris@338 253 SparseTimeValueModel::PointList points = m_rawPath->getPoints();
Chris@338 254
Chris@338 255 for (SparseTimeValueModel::PointList::const_iterator i = points.begin();
Chris@338 256 i != points.end(); ++i) {
Chris@338 257 long frame = i->frame;
Chris@338 258 float value = i->value;
Chris@338 259 long rframe = lrintf(value * m_aligned->getSampleRate());
Chris@338 260 m_reversePath->addPoint(PathPoint(rframe, frame));
Chris@338 261 }
Chris@338 262
Chris@376 263 #ifdef DEBUG_ALIGNMENT_MODEL
Chris@376 264 std::cerr << "AlignmentModel::constructReversePath: " << m_reversePath->getPointCount() << " points, at least " << (2 * m_reversePath->getPointCount() * (3 * sizeof(void *) + sizeof(int) + sizeof(PathPoint))) << " bytes" << std::endl;
Chris@376 265 #endif
Chris@297 266 }
Chris@297 267
Chris@297 268 size_t
Chris@338 269 AlignmentModel::align(PathModel *path, size_t frame) const
Chris@297 270 {
Chris@339 271 if (!path) return frame;
Chris@339 272
Chris@338 273 // The path consists of a series of points, each with frame equal
Chris@338 274 // to the frame on the source model and mapframe equal to the
Chris@338 275 // frame on the target model. Both should be monotonically
Chris@338 276 // increasing.
Chris@297 277
Chris@338 278 const PathModel::PointList &points = path->getPoints();
Chris@297 279
Chris@297 280 if (points.empty()) {
Chris@379 281 #ifdef DEBUG_ALIGNMENT_MODEL
Chris@376 282 std::cerr << "AlignmentModel::align: No points" << std::endl;
Chris@379 283 #endif
Chris@297 284 return frame;
Chris@297 285 }
Chris@297 286
Chris@376 287 #ifdef DEBUG_ALIGNMENT_MODEL
Chris@376 288 std::cerr << "AlignmentModel::align: frame " << frame << " requested" << std::endl;
Chris@376 289 #endif
Chris@376 290
Chris@338 291 PathModel::Point point(frame);
Chris@338 292 PathModel::PointList::const_iterator i = points.lower_bound(point);
Chris@376 293 if (i == points.end()) {
Chris@376 294 #ifdef DEBUG_ALIGNMENT_MODEL
Chris@376 295 std::cerr << "Note: i == points.end()" << std::endl;
Chris@376 296 #endif
Chris@376 297 --i;
Chris@376 298 }
Chris@338 299 while (i != points.begin() && i->frame > long(frame)) --i;
Chris@297 300
Chris@312 301 long foundFrame = i->frame;
Chris@338 302 long foundMapFrame = i->mapframe;
Chris@297 303
Chris@312 304 long followingFrame = foundFrame;
Chris@338 305 long followingMapFrame = foundMapFrame;
Chris@297 306
Chris@312 307 if (++i != points.end()) {
Chris@376 308 #ifdef DEBUG_ALIGNMENT_MODEL
Chris@376 309 std::cerr << "another point available" << std::endl;
Chris@376 310 #endif
Chris@312 311 followingFrame = i->frame;
Chris@338 312 followingMapFrame = i->mapframe;
Chris@376 313 } else {
Chris@376 314 #ifdef DEBUG_ALIGNMENT_MODEL
Chris@376 315 std::cerr << "no other point available" << std::endl;
Chris@376 316 #endif
Chris@376 317 }
Chris@312 318
Chris@338 319 if (foundMapFrame < 0) return 0;
Chris@312 320
Chris@338 321 size_t resultFrame = foundMapFrame;
Chris@312 322
Chris@338 323 if (followingFrame != foundFrame && long(frame) > foundFrame) {
Chris@338 324 float interp =
Chris@338 325 float(frame - foundFrame) /
Chris@338 326 float(followingFrame - foundFrame);
Chris@338 327 resultFrame += lrintf((followingMapFrame - foundMapFrame) * interp);
Chris@312 328 }
Chris@312 329
Chris@376 330 #ifdef DEBUG_ALIGNMENT_MODEL
Chris@376 331 std::cerr << "AlignmentModel::align: resultFrame = " << resultFrame << std::endl;
Chris@376 332 #endif
Chris@312 333
Chris@312 334 return resultFrame;
Chris@297 335 }
Chris@297 336