annotate data/model/AlignmentModel.cpp @ 588:d04b8674b710

* Try to identify the properly conformant audio file structure written out by Sonic Annotator (but we still don't actually import it yet)
author Chris Cannam
date Wed, 13 May 2009 13:30:08 +0000
parents 52303ec15cd2
children 6502c33b1cb1
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@409 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@407 45
Chris@407 46 constructPath();
Chris@407 47 constructReversePath();
Chris@371 48 }
Chris@297 49
Chris@407 50 if (m_rawPath && m_rawPath->isReady()) {
Chris@407 51 pathCompletionChanged();
Chris@407 52 }
Chris@297 53 }
Chris@297 54
Chris@297 55 AlignmentModel::~AlignmentModel()
Chris@297 56 {
Chris@407 57 if (m_inputModel) m_inputModel->aboutToDelete();
Chris@297 58 delete m_inputModel;
Chris@407 59
Chris@407 60 if (m_rawPath) m_rawPath->aboutToDelete();
Chris@338 61 delete m_rawPath;
Chris@407 62
Chris@407 63 if (m_path) m_path->aboutToDelete();
Chris@297 64 delete m_path;
Chris@407 65
Chris@407 66 if (m_reversePath) m_reversePath->aboutToDelete();
Chris@297 67 delete m_reversePath;
Chris@297 68 }
Chris@297 69
Chris@297 70 bool
Chris@297 71 AlignmentModel::isOK() const
Chris@297 72 {
Chris@338 73 if (m_rawPath) return m_rawPath->isOK();
Chris@338 74 else return true;
Chris@297 75 }
Chris@297 76
Chris@297 77 size_t
Chris@297 78 AlignmentModel::getStartFrame() const
Chris@297 79 {
Chris@297 80 size_t a = m_reference->getStartFrame();
Chris@297 81 size_t b = m_aligned->getStartFrame();
Chris@297 82 return std::min(a, b);
Chris@297 83 }
Chris@297 84
Chris@297 85 size_t
Chris@297 86 AlignmentModel::getEndFrame() const
Chris@297 87 {
Chris@297 88 size_t a = m_reference->getEndFrame();
Chris@297 89 size_t b = m_aligned->getEndFrame();
Chris@297 90 return std::max(a, b);
Chris@297 91 }
Chris@297 92
Chris@297 93 size_t
Chris@297 94 AlignmentModel::getSampleRate() const
Chris@297 95 {
Chris@297 96 return m_reference->getSampleRate();
Chris@297 97 }
Chris@297 98
Chris@297 99 Model *
Chris@297 100 AlignmentModel::clone() const
Chris@297 101 {
Chris@297 102 return new AlignmentModel
Chris@297 103 (m_reference, m_aligned,
Chris@297 104 m_inputModel ? m_inputModel->clone() : 0,
Chris@338 105 m_rawPath ? static_cast<SparseTimeValueModel *>(m_rawPath->clone()) : 0);
Chris@297 106 }
Chris@297 107
Chris@297 108 bool
Chris@297 109 AlignmentModel::isReady(int *completion) const
Chris@297 110 {
Chris@411 111 if (!m_pathBegun && m_rawPath) {
Chris@338 112 if (completion) *completion = 0;
Chris@323 113 return false;
Chris@323 114 }
Chris@338 115 if (m_pathComplete || !m_rawPath) {
Chris@338 116 if (completion) *completion = 100;
Chris@338 117 return true;
Chris@338 118 }
Chris@338 119 return m_rawPath->isReady(completion);
Chris@297 120 }
Chris@297 121
Chris@297 122 const ZoomConstraint *
Chris@297 123 AlignmentModel::getZoomConstraint() const
Chris@297 124 {
Chris@338 125 return 0;
Chris@297 126 }
Chris@297 127
Chris@297 128 const Model *
Chris@297 129 AlignmentModel::getReferenceModel() const
Chris@297 130 {
Chris@297 131 return m_reference;
Chris@297 132 }
Chris@297 133
Chris@297 134 const Model *
Chris@297 135 AlignmentModel::getAlignedModel() const
Chris@297 136 {
Chris@297 137 return m_aligned;
Chris@297 138 }
Chris@297 139
Chris@297 140 size_t
Chris@297 141 AlignmentModel::toReference(size_t frame) const
Chris@297 142 {
Chris@376 143 #ifdef DEBUG_ALIGNMENT_MODEL
Chris@376 144 std::cerr << "AlignmentModel::toReference(" << frame << ")" << std::endl;
Chris@376 145 #endif
Chris@371 146 if (!m_path) {
Chris@371 147 if (!m_rawPath) return frame;
Chris@371 148 constructPath();
Chris@371 149 }
Chris@339 150 return align(m_path, frame);
Chris@297 151 }
Chris@297 152
Chris@297 153 size_t
Chris@297 154 AlignmentModel::fromReference(size_t frame) const
Chris@297 155 {
Chris@376 156 #ifdef DEBUG_ALIGNMENT_MODEL
Chris@376 157 std::cerr << "AlignmentModel::fromReference(" << frame << ")" << std::endl;
Chris@376 158 #endif
Chris@371 159 if (!m_reversePath) {
Chris@371 160 if (!m_rawPath) return frame;
Chris@371 161 constructReversePath();
Chris@371 162 }
Chris@339 163 return align(m_reversePath, frame);
Chris@297 164 }
Chris@297 165
Chris@297 166 void
Chris@297 167 AlignmentModel::pathChanged()
Chris@297 168 {
Chris@339 169 if (m_pathComplete) {
Chris@339 170 std::cerr << "AlignmentModel: deleting raw path model" << std::endl;
Chris@407 171 if (m_rawPath) m_rawPath->aboutToDelete();
Chris@339 172 delete m_rawPath;
Chris@339 173 m_rawPath = 0;
Chris@339 174 }
Chris@297 175 }
Chris@297 176
Chris@297 177 void
Chris@297 178 AlignmentModel::pathChanged(size_t, size_t)
Chris@297 179 {
Chris@297 180 if (!m_pathComplete) return;
Chris@338 181 constructPath();
Chris@297 182 constructReversePath();
Chris@297 183 }
Chris@297 184
Chris@297 185 void
Chris@297 186 AlignmentModel::pathCompletionChanged()
Chris@297 187 {
Chris@339 188 if (!m_rawPath) return;
Chris@323 189 m_pathBegun = true;
Chris@323 190
Chris@297 191 if (!m_pathComplete) {
Chris@338 192
Chris@297 193 int completion = 0;
Chris@338 194 m_rawPath->isReady(&completion);
Chris@338 195
Chris@376 196 #ifdef DEBUG_ALIGNMENT_MODEL
Chris@376 197 std::cerr << "AlignmentModel::pathCompletionChanged: completion = "
Chris@376 198 << completion << std::endl;
Chris@376 199 #endif
Chris@338 200
Chris@323 201 m_pathComplete = (completion == 100);
Chris@338 202
Chris@297 203 if (m_pathComplete) {
Chris@338 204
Chris@338 205 constructPath();
Chris@297 206 constructReversePath();
Chris@407 207
Chris@407 208 if (m_inputModel) m_inputModel->aboutToDelete();
Chris@297 209 delete m_inputModel;
Chris@297 210 m_inputModel = 0;
Chris@297 211 }
Chris@297 212 }
Chris@323 213
Chris@297 214 emit completionChanged();
Chris@297 215 }
Chris@297 216
Chris@297 217 void
Chris@338 218 AlignmentModel::constructPath() const
Chris@297 219 {
Chris@338 220 if (!m_path) {
Chris@338 221 if (!m_rawPath) {
Chris@338 222 std::cerr << "ERROR: AlignmentModel::constructPath: "
Chris@338 223 << "No raw path available" << std::endl;
Chris@338 224 return;
Chris@338 225 }
Chris@338 226 m_path = new PathModel
Chris@338 227 (m_rawPath->getSampleRate(), m_rawPath->getResolution(), false);
Chris@338 228 } else {
Chris@338 229 if (!m_rawPath) return;
Chris@297 230 }
Chris@297 231
Chris@338 232 m_path->clear();
Chris@297 233
Chris@338 234 SparseTimeValueModel::PointList points = m_rawPath->getPoints();
Chris@297 235
Chris@297 236 for (SparseTimeValueModel::PointList::const_iterator i = points.begin();
Chris@297 237 i != points.end(); ++i) {
Chris@297 238 long frame = i->frame;
Chris@297 239 float value = i->value;
Chris@297 240 long rframe = lrintf(value * m_aligned->getSampleRate());
Chris@338 241 m_path->addPoint(PathPoint(frame, rframe));
Chris@297 242 }
Chris@297 243
Chris@376 244 #ifdef DEBUG_ALIGNMENT_MODEL
Chris@376 245 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 246 #endif
Chris@338 247 }
Chris@338 248
Chris@338 249 void
Chris@338 250 AlignmentModel::constructReversePath() const
Chris@338 251 {
Chris@338 252 if (!m_reversePath) {
Chris@407 253 /*!!!
Chris@338 254 if (!m_rawPath) {
Chris@338 255 std::cerr << "ERROR: AlignmentModel::constructReversePath: "
Chris@338 256 << "No raw path available" << std::endl;
Chris@338 257 return;
Chris@338 258 }
Chris@338 259 m_reversePath = new PathModel
Chris@338 260 (m_rawPath->getSampleRate(), m_rawPath->getResolution(), false);
Chris@407 261 */
Chris@407 262 if (!m_path) {
Chris@407 263 std::cerr << "ERROR: AlignmentModel::constructReversePath: "
Chris@407 264 << "No forward path available" << std::endl;
Chris@407 265 return;
Chris@407 266 }
Chris@407 267 m_reversePath = new PathModel
Chris@407 268 (m_path->getSampleRate(), m_path->getResolution(), false);
Chris@338 269 } else {
Chris@407 270 /*!!!
Chris@338 271 if (!m_rawPath) return;
Chris@407 272 */
Chris@407 273 if (!m_path) return;
Chris@338 274 }
Chris@338 275
Chris@338 276 m_reversePath->clear();
Chris@407 277 /*!!!
Chris@338 278 SparseTimeValueModel::PointList points = m_rawPath->getPoints();
Chris@338 279
Chris@338 280 for (SparseTimeValueModel::PointList::const_iterator i = points.begin();
Chris@338 281 i != points.end(); ++i) {
Chris@338 282 long frame = i->frame;
Chris@338 283 float value = i->value;
Chris@338 284 long rframe = lrintf(value * m_aligned->getSampleRate());
Chris@338 285 m_reversePath->addPoint(PathPoint(rframe, frame));
Chris@338 286 }
Chris@407 287 */
Chris@407 288
Chris@407 289 PathModel::PointList points = m_path->getPoints();
Chris@407 290
Chris@407 291 for (PathModel::PointList::const_iterator i = points.begin();
Chris@407 292 i != points.end(); ++i) {
Chris@407 293 long frame = i->frame;
Chris@407 294 long rframe = i->mapframe;
Chris@407 295 m_reversePath->addPoint(PathPoint(rframe, frame));
Chris@407 296 }
Chris@338 297
Chris@376 298 #ifdef DEBUG_ALIGNMENT_MODEL
Chris@376 299 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 300 #endif
Chris@297 301 }
Chris@297 302
Chris@297 303 size_t
Chris@338 304 AlignmentModel::align(PathModel *path, size_t frame) const
Chris@297 305 {
Chris@339 306 if (!path) return frame;
Chris@339 307
Chris@338 308 // The path consists of a series of points, each with frame equal
Chris@338 309 // to the frame on the source model and mapframe equal to the
Chris@338 310 // frame on the target model. Both should be monotonically
Chris@338 311 // increasing.
Chris@297 312
Chris@338 313 const PathModel::PointList &points = path->getPoints();
Chris@297 314
Chris@297 315 if (points.empty()) {
Chris@379 316 #ifdef DEBUG_ALIGNMENT_MODEL
Chris@376 317 std::cerr << "AlignmentModel::align: No points" << std::endl;
Chris@379 318 #endif
Chris@297 319 return frame;
Chris@297 320 }
Chris@297 321
Chris@376 322 #ifdef DEBUG_ALIGNMENT_MODEL
Chris@376 323 std::cerr << "AlignmentModel::align: frame " << frame << " requested" << std::endl;
Chris@376 324 #endif
Chris@376 325
Chris@338 326 PathModel::Point point(frame);
Chris@338 327 PathModel::PointList::const_iterator i = points.lower_bound(point);
Chris@376 328 if (i == points.end()) {
Chris@376 329 #ifdef DEBUG_ALIGNMENT_MODEL
Chris@376 330 std::cerr << "Note: i == points.end()" << std::endl;
Chris@376 331 #endif
Chris@376 332 --i;
Chris@376 333 }
Chris@338 334 while (i != points.begin() && i->frame > long(frame)) --i;
Chris@297 335
Chris@312 336 long foundFrame = i->frame;
Chris@338 337 long foundMapFrame = i->mapframe;
Chris@297 338
Chris@312 339 long followingFrame = foundFrame;
Chris@338 340 long followingMapFrame = foundMapFrame;
Chris@297 341
Chris@312 342 if (++i != points.end()) {
Chris@376 343 #ifdef DEBUG_ALIGNMENT_MODEL
Chris@376 344 std::cerr << "another point available" << std::endl;
Chris@376 345 #endif
Chris@312 346 followingFrame = i->frame;
Chris@338 347 followingMapFrame = i->mapframe;
Chris@376 348 } else {
Chris@376 349 #ifdef DEBUG_ALIGNMENT_MODEL
Chris@376 350 std::cerr << "no other point available" << std::endl;
Chris@376 351 #endif
Chris@376 352 }
Chris@312 353
Chris@338 354 if (foundMapFrame < 0) return 0;
Chris@312 355
Chris@338 356 size_t resultFrame = foundMapFrame;
Chris@312 357
Chris@338 358 if (followingFrame != foundFrame && long(frame) > foundFrame) {
Chris@338 359 float interp =
Chris@338 360 float(frame - foundFrame) /
Chris@338 361 float(followingFrame - foundFrame);
Chris@338 362 resultFrame += lrintf((followingMapFrame - foundMapFrame) * interp);
Chris@312 363 }
Chris@312 364
Chris@376 365 #ifdef DEBUG_ALIGNMENT_MODEL
Chris@376 366 std::cerr << "AlignmentModel::align: resultFrame = " << resultFrame << std::endl;
Chris@376 367 #endif
Chris@312 368
Chris@312 369 return resultFrame;
Chris@297 370 }
Chris@407 371
Chris@407 372 void
Chris@407 373 AlignmentModel::setPath(PathModel *path)
Chris@407 374 {
Chris@407 375 if (m_path) m_path->aboutToDelete();
Chris@407 376 delete m_path;
Chris@407 377 m_path = path;
Chris@407 378 constructReversePath();
Chris@407 379 }
Chris@297 380
Chris@407 381 void
Chris@407 382 AlignmentModel::toXml(QTextStream &stream,
Chris@407 383 QString indent,
Chris@407 384 QString extraAttributes) const
Chris@407 385 {
Chris@407 386 if (!m_path) {
Chris@407 387 std::cerr << "AlignmentModel::toXml: no path" << std::endl;
Chris@407 388 return;
Chris@407 389 }
Chris@407 390
Chris@407 391 m_path->toXml(stream, indent, "");
Chris@407 392
Chris@407 393 Model::toXml(stream, indent,
Chris@407 394 QString("type=\"alignment\" reference=\"%1\" aligned=\"%2\" path=\"%3\" %4")
Chris@407 395 .arg(getObjectExportId(m_reference))
Chris@407 396 .arg(getObjectExportId(m_aligned))
Chris@407 397 .arg(getObjectExportId(m_path))
Chris@407 398 .arg(extraAttributes));
Chris@407 399 }
Chris@407 400
Chris@407 401