annotate data/model/AlignmentModel.cpp @ 333:1afaf98dbf11

* Factor out uses of "Sonic Visualiser" in "common" code to applicationName() * Add ability to show work title + artist in top-left of pane (thinking of Vect but may be useful in SV in future) * A few other generalisations useful for Vect
author Chris Cannam
date Fri, 09 Nov 2007 17:46:58 +0000
parents a71dec01c4d3
children f14e2f7b24f7 6f6ab834449d
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@323 29 m_pathBegun(false),
Chris@297 30 m_pathComplete(false)
Chris@297 31 {
Chris@297 32 connect(m_path, SIGNAL(modelChanged()),
Chris@297 33 this, SLOT(pathChanged()));
Chris@297 34
Chris@297 35 connect(m_path, SIGNAL(modelChanged(size_t, size_t)),
Chris@297 36 this, SLOT(pathChanged(size_t, size_t)));
Chris@297 37
Chris@297 38 connect(m_path, SIGNAL(completionChanged()),
Chris@297 39 this, SLOT(pathCompletionChanged()));
Chris@297 40
Chris@297 41 constructReversePath();
Chris@297 42 }
Chris@297 43
Chris@297 44 AlignmentModel::~AlignmentModel()
Chris@297 45 {
Chris@297 46 delete m_inputModel;
Chris@297 47 delete m_path;
Chris@297 48 delete m_reversePath;
Chris@297 49 }
Chris@297 50
Chris@297 51 bool
Chris@297 52 AlignmentModel::isOK() const
Chris@297 53 {
Chris@297 54 return m_path->isOK();
Chris@297 55 }
Chris@297 56
Chris@297 57 size_t
Chris@297 58 AlignmentModel::getStartFrame() const
Chris@297 59 {
Chris@297 60 //!!! do we care about distinct rates?
Chris@297 61 size_t a = m_reference->getStartFrame();
Chris@297 62 size_t b = m_aligned->getStartFrame();
Chris@297 63 return std::min(a, b);
Chris@297 64 }
Chris@297 65
Chris@297 66 size_t
Chris@297 67 AlignmentModel::getEndFrame() const
Chris@297 68 {
Chris@297 69 //!!! do we care about distinct rates?
Chris@297 70 size_t a = m_reference->getEndFrame();
Chris@297 71 size_t b = m_aligned->getEndFrame();
Chris@297 72 return std::max(a, b);
Chris@297 73 }
Chris@297 74
Chris@297 75 size_t
Chris@297 76 AlignmentModel::getSampleRate() const
Chris@297 77 {
Chris@297 78 return m_reference->getSampleRate();
Chris@297 79 }
Chris@297 80
Chris@297 81 Model *
Chris@297 82 AlignmentModel::clone() const
Chris@297 83 {
Chris@297 84 return new AlignmentModel
Chris@297 85 (m_reference, m_aligned,
Chris@297 86 m_inputModel ? m_inputModel->clone() : 0,
Chris@297 87 m_path ? static_cast<SparseTimeValueModel *>(m_path->clone()) : 0);
Chris@297 88 }
Chris@297 89
Chris@297 90 bool
Chris@297 91 AlignmentModel::isReady(int *completion) const
Chris@297 92 {
Chris@323 93 if (!m_pathBegun) {
Chris@323 94 completion = 0;
Chris@323 95 return false;
Chris@323 96 }
Chris@297 97 return m_path->isReady(completion);
Chris@297 98 }
Chris@297 99
Chris@297 100 const ZoomConstraint *
Chris@297 101 AlignmentModel::getZoomConstraint() const
Chris@297 102 {
Chris@297 103 return m_path->getZoomConstraint();
Chris@297 104 }
Chris@297 105
Chris@297 106 const Model *
Chris@297 107 AlignmentModel::getReferenceModel() const
Chris@297 108 {
Chris@297 109 return m_reference;
Chris@297 110 }
Chris@297 111
Chris@297 112 const Model *
Chris@297 113 AlignmentModel::getAlignedModel() const
Chris@297 114 {
Chris@297 115 return m_aligned;
Chris@297 116 }
Chris@297 117
Chris@297 118 size_t
Chris@297 119 AlignmentModel::toReference(size_t frame) const
Chris@297 120 {
Chris@297 121 // std::cerr << "AlignmentModel::toReference(" << frame << ")" << std::endl;
Chris@297 122 if (!m_reversePath) constructReversePath();
Chris@297 123 return align(m_reversePath, frame);
Chris@297 124 }
Chris@297 125
Chris@297 126 size_t
Chris@297 127 AlignmentModel::fromReference(size_t frame) const
Chris@297 128 {
Chris@297 129 // std::cerr << "AlignmentModel::fromReference(" << frame << ")" << std::endl;
Chris@297 130 return align(m_path, frame);
Chris@297 131 }
Chris@297 132
Chris@297 133 void
Chris@297 134 AlignmentModel::pathChanged()
Chris@297 135 {
Chris@297 136 }
Chris@297 137
Chris@297 138 void
Chris@297 139 AlignmentModel::pathChanged(size_t, size_t)
Chris@297 140 {
Chris@297 141 if (!m_pathComplete) return;
Chris@297 142 constructReversePath();
Chris@297 143 }
Chris@297 144
Chris@297 145 void
Chris@297 146 AlignmentModel::pathCompletionChanged()
Chris@297 147 {
Chris@323 148 m_pathBegun = true;
Chris@323 149
Chris@297 150 if (!m_pathComplete) {
Chris@297 151 int completion = 0;
Chris@297 152 m_path->isReady(&completion);
Chris@333 153 // std::cerr << "AlignmentModel::pathCompletionChanged: completion = "
Chris@333 154 // << completion << std::endl;
Chris@323 155 m_pathComplete = (completion == 100);
Chris@297 156 if (m_pathComplete) {
Chris@297 157 constructReversePath();
Chris@297 158 delete m_inputModel;
Chris@297 159 m_inputModel = 0;
Chris@297 160 }
Chris@297 161 }
Chris@323 162
Chris@297 163 emit completionChanged();
Chris@297 164 }
Chris@297 165
Chris@297 166 void
Chris@297 167 AlignmentModel::constructReversePath() const
Chris@297 168 {
Chris@297 169 if (!m_reversePath) {
Chris@297 170 m_reversePath = new SparseTimeValueModel
Chris@297 171 (m_path->getSampleRate(), m_path->getResolution(), false);
Chris@297 172 }
Chris@297 173
Chris@297 174 m_reversePath->clear();
Chris@297 175
Chris@297 176 SparseTimeValueModel::PointList points = m_path->getPoints();
Chris@297 177
Chris@297 178 for (SparseTimeValueModel::PointList::const_iterator i = points.begin();
Chris@297 179 i != points.end(); ++i) {
Chris@297 180 long frame = i->frame;
Chris@297 181 float value = i->value;
Chris@297 182 long rframe = lrintf(value * m_aligned->getSampleRate());
Chris@297 183 float rvalue = (float)frame / (float)m_reference->getSampleRate();
Chris@297 184 m_reversePath->addPoint
Chris@297 185 (SparseTimeValueModel::Point(rframe, rvalue, ""));
Chris@297 186 }
Chris@297 187
Chris@312 188 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 189 }
Chris@297 190
Chris@297 191 size_t
Chris@297 192 AlignmentModel::align(SparseTimeValueModel *path, size_t frame) const
Chris@297 193 {
Chris@297 194 // The path consists of a series of points, each with x (time)
Chris@297 195 // equal to the time on the source model and y (value) equal to
Chris@297 196 // the time on the target model. Times and values are both
Chris@297 197 // monotonically increasing.
Chris@297 198
Chris@297 199 const SparseTimeValueModel::PointList &points = path->getPoints();
Chris@297 200
Chris@297 201 if (points.empty()) {
Chris@297 202 // std::cerr << "AlignmentModel::align: No points" << std::endl;
Chris@297 203 return frame;
Chris@297 204 }
Chris@297 205
Chris@297 206 SparseTimeValueModel::Point point(frame);
Chris@297 207 SparseTimeValueModel::PointList::const_iterator i = points.lower_bound(point);
Chris@297 208 if (i == points.end()) --i;
Chris@312 209 while (i != points.begin() && i->frame > frame) --i;
Chris@297 210
Chris@312 211 long foundFrame = i->frame;
Chris@312 212 float foundTime = i->value;
Chris@297 213
Chris@312 214 long followingFrame = foundFrame;
Chris@312 215 float followingTime = foundTime;
Chris@297 216
Chris@312 217 if (++i != points.end()) {
Chris@312 218 followingFrame = i->frame;
Chris@312 219 followingTime = i->value;
Chris@312 220 }
Chris@312 221
Chris@312 222 float resultTime = foundTime;
Chris@312 223
Chris@312 224 if (followingFrame != foundFrame && frame > foundFrame) {
Chris@312 225
Chris@313 226 // std::cerr << "AlignmentModel::align: foundFrame = " << foundFrame << ", frame = " << frame << ", followingFrame = " << followingFrame << std::endl;
Chris@312 227
Chris@312 228 float interp = float(frame - foundFrame) / float(followingFrame - foundFrame);
Chris@313 229 // std::cerr << "AlignmentModel::align: interp = " << interp << ", result " << resultTime << " -> ";
Chris@312 230
Chris@312 231 resultTime += (followingTime - foundTime) * interp;
Chris@312 232
Chris@313 233 // std::cerr << resultTime << std::endl;
Chris@312 234 }
Chris@312 235
Chris@312 236 size_t resultFrame = lrintf(resultTime * getSampleRate());
Chris@312 237
Chris@313 238 // std::cerr << "AlignmentModel::align: resultFrame = " << resultFrame << std::endl;
Chris@312 239
Chris@312 240 return resultFrame;
Chris@297 241 }
Chris@297 242