annotate data/model/AlignmentModel.cpp @ 1061:c1e43c8d2527 tonioni

Thread-local debug was causing crash on exit with Qt 5.4.x. But we introduced that because QDebug itself was crashing when used from multiple threads. Replace with simpler fstream version
author Chris Cannam
date Tue, 31 Mar 2015 10:36:52 +0100
parents 2f49be7d4264
children 0fd3661bcfff
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@1038 40 connect(m_rawPath, SIGNAL(modelChangedWithin(sv_frame_t, sv_frame_t)),
Chris@1038 41 this, SLOT(pathChangedWithin(sv_frame_t, sv_frame_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@1038 77 sv_frame_t
Chris@297 78 AlignmentModel::getStartFrame() const
Chris@297 79 {
Chris@1038 80 sv_frame_t a = m_reference->getStartFrame();
Chris@1038 81 sv_frame_t b = m_aligned->getStartFrame();
Chris@297 82 return std::min(a, b);
Chris@297 83 }
Chris@297 84
Chris@1038 85 sv_frame_t
Chris@297 86 AlignmentModel::getEndFrame() const
Chris@297 87 {
Chris@1038 88 sv_frame_t a = m_reference->getEndFrame();
Chris@1038 89 sv_frame_t b = m_aligned->getEndFrame();
Chris@297 90 return std::max(a, b);
Chris@297 91 }
Chris@297 92
Chris@1040 93 sv_samplerate_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@1016 115 if (m_pathComplete) {
Chris@338 116 if (completion) *completion = 100;
Chris@338 117 return true;
Chris@338 118 }
Chris@1016 119 if (!m_rawPath) {
Chris@1016 120 // lack of raw path could mean path is complete (in which case
Chris@1016 121 // m_pathComplete true above) or else no alignment has been
Chris@1016 122 // set at all yet (this case)
Chris@1016 123 if (completion) *completion = 0;
Chris@1016 124 return false;
Chris@1016 125 }
Chris@338 126 return m_rawPath->isReady(completion);
Chris@297 127 }
Chris@297 128
Chris@297 129 const ZoomConstraint *
Chris@297 130 AlignmentModel::getZoomConstraint() const
Chris@297 131 {
Chris@338 132 return 0;
Chris@297 133 }
Chris@297 134
Chris@297 135 const Model *
Chris@297 136 AlignmentModel::getReferenceModel() const
Chris@297 137 {
Chris@297 138 return m_reference;
Chris@297 139 }
Chris@297 140
Chris@297 141 const Model *
Chris@297 142 AlignmentModel::getAlignedModel() const
Chris@297 143 {
Chris@297 144 return m_aligned;
Chris@297 145 }
Chris@297 146
Chris@1038 147 sv_frame_t
Chris@1038 148 AlignmentModel::toReference(sv_frame_t frame) const
Chris@297 149 {
Chris@376 150 #ifdef DEBUG_ALIGNMENT_MODEL
Chris@690 151 SVDEBUG << "AlignmentModel::toReference(" << frame << ")" << endl;
Chris@376 152 #endif
Chris@371 153 if (!m_path) {
Chris@371 154 if (!m_rawPath) return frame;
Chris@371 155 constructPath();
Chris@371 156 }
Chris@339 157 return align(m_path, frame);
Chris@297 158 }
Chris@297 159
Chris@1038 160 sv_frame_t
Chris@1038 161 AlignmentModel::fromReference(sv_frame_t frame) const
Chris@297 162 {
Chris@376 163 #ifdef DEBUG_ALIGNMENT_MODEL
Chris@690 164 SVDEBUG << "AlignmentModel::fromReference(" << frame << ")" << endl;
Chris@376 165 #endif
Chris@371 166 if (!m_reversePath) {
Chris@371 167 if (!m_rawPath) return frame;
Chris@371 168 constructReversePath();
Chris@371 169 }
Chris@339 170 return align(m_reversePath, frame);
Chris@297 171 }
Chris@297 172
Chris@297 173 void
Chris@297 174 AlignmentModel::pathChanged()
Chris@297 175 {
Chris@339 176 if (m_pathComplete) {
Chris@843 177 cerr << "AlignmentModel: deleting raw path model" << endl;
Chris@407 178 if (m_rawPath) m_rawPath->aboutToDelete();
Chris@339 179 delete m_rawPath;
Chris@339 180 m_rawPath = 0;
Chris@339 181 }
Chris@297 182 }
Chris@297 183
Chris@297 184 void
Chris@1038 185 AlignmentModel::pathChangedWithin(sv_frame_t, sv_frame_t)
Chris@297 186 {
Chris@297 187 if (!m_pathComplete) return;
Chris@338 188 constructPath();
Chris@297 189 constructReversePath();
Chris@297 190 }
Chris@297 191
Chris@297 192 void
Chris@297 193 AlignmentModel::pathCompletionChanged()
Chris@297 194 {
Chris@339 195 if (!m_rawPath) return;
Chris@323 196 m_pathBegun = true;
Chris@323 197
Chris@297 198 if (!m_pathComplete) {
Chris@338 199
Chris@297 200 int completion = 0;
Chris@338 201 m_rawPath->isReady(&completion);
Chris@338 202
Chris@376 203 #ifdef DEBUG_ALIGNMENT_MODEL
Chris@690 204 SVDEBUG << "AlignmentModel::pathCompletionChanged: completion = "
Chris@687 205 << completion << endl;
Chris@376 206 #endif
Chris@338 207
Chris@323 208 m_pathComplete = (completion == 100);
Chris@338 209
Chris@297 210 if (m_pathComplete) {
Chris@338 211
Chris@338 212 constructPath();
Chris@297 213 constructReversePath();
Chris@407 214
Chris@407 215 if (m_inputModel) m_inputModel->aboutToDelete();
Chris@297 216 delete m_inputModel;
Chris@297 217 m_inputModel = 0;
Chris@297 218 }
Chris@297 219 }
Chris@323 220
Chris@297 221 emit completionChanged();
Chris@297 222 }
Chris@297 223
Chris@297 224 void
Chris@338 225 AlignmentModel::constructPath() const
Chris@297 226 {
Chris@338 227 if (!m_path) {
Chris@338 228 if (!m_rawPath) {
Chris@843 229 cerr << "ERROR: AlignmentModel::constructPath: "
Chris@843 230 << "No raw path available" << endl;
Chris@338 231 return;
Chris@338 232 }
Chris@338 233 m_path = new PathModel
Chris@338 234 (m_rawPath->getSampleRate(), m_rawPath->getResolution(), false);
Chris@338 235 } else {
Chris@338 236 if (!m_rawPath) return;
Chris@297 237 }
Chris@297 238
Chris@338 239 m_path->clear();
Chris@297 240
Chris@338 241 SparseTimeValueModel::PointList points = m_rawPath->getPoints();
Chris@297 242
Chris@297 243 for (SparseTimeValueModel::PointList::const_iterator i = points.begin();
Chris@297 244 i != points.end(); ++i) {
Chris@1038 245 sv_frame_t frame = i->frame;
Chris@1038 246 double value = i->value;
Chris@1038 247 sv_frame_t rframe = lrint(value * m_aligned->getSampleRate());
Chris@338 248 m_path->addPoint(PathPoint(frame, rframe));
Chris@297 249 }
Chris@297 250
Chris@376 251 #ifdef DEBUG_ALIGNMENT_MODEL
Chris@690 252 SVDEBUG << "AlignmentModel::constructPath: " << m_path->getPointCount() << " points, at least " << (2 * m_path->getPointCount() * (3 * sizeof(void *) + sizeof(int) + sizeof(PathPoint))) << " bytes" << endl;
Chris@376 253 #endif
Chris@338 254 }
Chris@338 255
Chris@338 256 void
Chris@338 257 AlignmentModel::constructReversePath() const
Chris@338 258 {
Chris@338 259 if (!m_reversePath) {
Chris@407 260 if (!m_path) {
Chris@843 261 cerr << "ERROR: AlignmentModel::constructReversePath: "
Chris@843 262 << "No forward path available" << endl;
Chris@407 263 return;
Chris@407 264 }
Chris@407 265 m_reversePath = new PathModel
Chris@407 266 (m_path->getSampleRate(), m_path->getResolution(), false);
Chris@338 267 } else {
Chris@407 268 if (!m_path) return;
Chris@338 269 }
Chris@338 270
Chris@338 271 m_reversePath->clear();
Chris@407 272
Chris@407 273 PathModel::PointList points = m_path->getPoints();
Chris@407 274
Chris@407 275 for (PathModel::PointList::const_iterator i = points.begin();
Chris@407 276 i != points.end(); ++i) {
Chris@1038 277 sv_frame_t frame = i->frame;
Chris@1038 278 sv_frame_t rframe = i->mapframe;
Chris@407 279 m_reversePath->addPoint(PathPoint(rframe, frame));
Chris@407 280 }
Chris@338 281
Chris@376 282 #ifdef DEBUG_ALIGNMENT_MODEL
Chris@690 283 SVDEBUG << "AlignmentModel::constructReversePath: " << m_reversePath->getPointCount() << " points, at least " << (2 * m_reversePath->getPointCount() * (3 * sizeof(void *) + sizeof(int) + sizeof(PathPoint))) << " bytes" << endl;
Chris@376 284 #endif
Chris@297 285 }
Chris@297 286
Chris@1038 287 sv_frame_t
Chris@1038 288 AlignmentModel::align(PathModel *path, sv_frame_t frame) const
Chris@297 289 {
Chris@339 290 if (!path) return frame;
Chris@339 291
Chris@338 292 // The path consists of a series of points, each with frame equal
Chris@338 293 // to the frame on the source model and mapframe equal to the
Chris@338 294 // frame on the target model. Both should be monotonically
Chris@338 295 // increasing.
Chris@297 296
Chris@338 297 const PathModel::PointList &points = path->getPoints();
Chris@297 298
Chris@297 299 if (points.empty()) {
Chris@379 300 #ifdef DEBUG_ALIGNMENT_MODEL
Chris@690 301 SVDEBUG << "AlignmentModel::align: No points" << endl;
Chris@379 302 #endif
Chris@297 303 return frame;
Chris@297 304 }
Chris@297 305
Chris@376 306 #ifdef DEBUG_ALIGNMENT_MODEL
Chris@690 307 SVDEBUG << "AlignmentModel::align: frame " << frame << " requested" << endl;
Chris@376 308 #endif
Chris@376 309
Chris@338 310 PathModel::Point point(frame);
Chris@338 311 PathModel::PointList::const_iterator i = points.lower_bound(point);
Chris@376 312 if (i == points.end()) {
Chris@376 313 #ifdef DEBUG_ALIGNMENT_MODEL
Chris@843 314 cerr << "Note: i == points.end()" << endl;
Chris@376 315 #endif
Chris@376 316 --i;
Chris@376 317 }
Chris@1038 318 while (i != points.begin() && i->frame > frame) --i;
Chris@297 319
Chris@1038 320 sv_frame_t foundFrame = i->frame;
Chris@1038 321 sv_frame_t foundMapFrame = i->mapframe;
Chris@297 322
Chris@1038 323 sv_frame_t followingFrame = foundFrame;
Chris@1038 324 sv_frame_t followingMapFrame = foundMapFrame;
Chris@297 325
Chris@312 326 if (++i != points.end()) {
Chris@376 327 #ifdef DEBUG_ALIGNMENT_MODEL
Chris@843 328 cerr << "another point available" << endl;
Chris@376 329 #endif
Chris@312 330 followingFrame = i->frame;
Chris@338 331 followingMapFrame = i->mapframe;
Chris@376 332 } else {
Chris@376 333 #ifdef DEBUG_ALIGNMENT_MODEL
Chris@843 334 cerr << "no other point available" << endl;
Chris@376 335 #endif
Chris@376 336 }
Chris@312 337
Chris@338 338 if (foundMapFrame < 0) return 0;
Chris@312 339
Chris@1038 340 sv_frame_t resultFrame = foundMapFrame;
Chris@312 341
Chris@1038 342 if (followingFrame != foundFrame && frame > foundFrame) {
Chris@1038 343 double interp =
Chris@1038 344 double(frame - foundFrame) /
Chris@1038 345 double(followingFrame - foundFrame);
Chris@1038 346 resultFrame += lrint(double(followingMapFrame - foundMapFrame) * interp);
Chris@312 347 }
Chris@312 348
Chris@376 349 #ifdef DEBUG_ALIGNMENT_MODEL
Chris@690 350 SVDEBUG << "AlignmentModel::align: resultFrame = " << resultFrame << endl;
Chris@376 351 #endif
Chris@312 352
Chris@312 353 return resultFrame;
Chris@297 354 }
Chris@407 355
Chris@407 356 void
Chris@1016 357 AlignmentModel::setPathFrom(SparseTimeValueModel *rawpath)
Chris@1016 358 {
Chris@1016 359 if (m_rawPath) m_rawPath->aboutToDelete();
Chris@1016 360 delete m_rawPath;
Chris@1016 361
Chris@1016 362 m_rawPath = rawpath;
Chris@1016 363
Chris@1016 364 connect(m_rawPath, SIGNAL(modelChanged()),
Chris@1016 365 this, SLOT(pathChanged()));
Chris@1016 366
Chris@1046 367 connect(m_rawPath, SIGNAL(modelChangedWithin(sv_frame_t, sv_frame_t)),
Chris@1046 368 this, SLOT(pathChangedWithin(sv_frame_t, sv_frame_t)));
Chris@1016 369
Chris@1016 370 connect(m_rawPath, SIGNAL(completionChanged()),
Chris@1016 371 this, SLOT(pathCompletionChanged()));
Chris@1016 372
Chris@1016 373 constructPath();
Chris@1016 374 constructReversePath();
Chris@1016 375
Chris@1016 376 if (m_rawPath->isReady()) {
Chris@1016 377 pathCompletionChanged();
Chris@1016 378 }
Chris@1016 379 }
Chris@1016 380
Chris@1016 381 void
Chris@407 382 AlignmentModel::setPath(PathModel *path)
Chris@407 383 {
Chris@407 384 if (m_path) m_path->aboutToDelete();
Chris@407 385 delete m_path;
Chris@407 386 m_path = path;
Chris@662 387 #ifdef DEBUG_ALIGNMENT_MODEL
Chris@690 388 SVDEBUG << "AlignmentModel::setPath: path = " << m_path << endl;
Chris@662 389 #endif
Chris@407 390 constructReversePath();
Chris@662 391 #ifdef DEBUG_ALIGNMENT_MODEL
Chris@690 392 SVDEBUG << "AlignmentModel::setPath: after construction path = "
Chris@687 393 << m_path << ", rpath = " << m_reversePath << endl;
Chris@662 394 #endif
Chris@407 395 }
Chris@297 396
Chris@407 397 void
Chris@407 398 AlignmentModel::toXml(QTextStream &stream,
Chris@407 399 QString indent,
Chris@407 400 QString extraAttributes) const
Chris@407 401 {
Chris@407 402 if (!m_path) {
Chris@690 403 SVDEBUG << "AlignmentModel::toXml: no path" << endl;
Chris@407 404 return;
Chris@407 405 }
Chris@407 406
Chris@407 407 m_path->toXml(stream, indent, "");
Chris@407 408
Chris@407 409 Model::toXml(stream, indent,
Chris@407 410 QString("type=\"alignment\" reference=\"%1\" aligned=\"%2\" path=\"%3\" %4")
Chris@407 411 .arg(getObjectExportId(m_reference))
Chris@407 412 .arg(getObjectExportId(m_aligned))
Chris@407 413 .arg(getObjectExportId(m_path))
Chris@407 414 .arg(extraAttributes));
Chris@407 415 }
Chris@407 416
Chris@407 417