comparison data/model/AlignmentModel.cpp @ 1766:85b9b466a59f

Merge from branch by-id
author Chris Cannam
date Wed, 17 Jul 2019 14:24:51 +0100
parents 9945ad04c174
children f19711ab7074
comparison
equal deleted inserted replaced
1730:649ac57c5a2d 1766:85b9b466a59f
17 17
18 #include "SparseTimeValueModel.h" 18 #include "SparseTimeValueModel.h"
19 19
20 //#define DEBUG_ALIGNMENT_MODEL 1 20 //#define DEBUG_ALIGNMENT_MODEL 1
21 21
22 AlignmentModel::AlignmentModel(Model *reference, 22 AlignmentModel::AlignmentModel(ModelId reference,
23 Model *aligned, 23 ModelId aligned,
24 SparseTimeValueModel *path) : 24 ModelId pathSource) :
25 m_reference(reference), 25 m_reference(reference),
26 m_aligned(aligned), 26 m_aligned(aligned),
27 m_rawPath(path), 27 m_pathSource(pathSource),
28 m_path(nullptr), 28 m_path(nullptr),
29 m_reversePath(nullptr), 29 m_reversePath(nullptr),
30 m_pathBegun(false), 30 m_pathBegun(false),
31 m_pathComplete(false) 31 m_pathComplete(false)
32 { 32 {
33 if (m_rawPath) { 33 setPathFrom(pathSource);
34
35 connect(m_rawPath, SIGNAL(modelChanged()),
36 this, SLOT(pathChanged()));
37
38 connect(m_rawPath, SIGNAL(modelChangedWithin(sv_frame_t, sv_frame_t)),
39 this, SLOT(pathChangedWithin(sv_frame_t, sv_frame_t)));
40
41 connect(m_rawPath, SIGNAL(completionChanged()),
42 this, SLOT(pathCompletionChanged()));
43
44 constructPath();
45 constructReversePath();
46 }
47
48 if (m_rawPath && m_rawPath->isReady()) {
49 pathCompletionChanged();
50 }
51 34
52 if (m_reference == m_aligned) { 35 if (m_reference == m_aligned) {
53 // Trivial alignment, e.g. of main model to itself, which we 36 // Trivial alignment, e.g. of main model to itself, which we
54 // record so that we can distinguish the reference model for 37 // record so that we can distinguish the reference model for
55 // alignments from an unaligned model. No path required 38 // alignments from an unaligned model. No path required
60 AlignmentModel::~AlignmentModel() 43 AlignmentModel::~AlignmentModel()
61 { 44 {
62 #ifdef DEBUG_ALIGNMENT_MODEL 45 #ifdef DEBUG_ALIGNMENT_MODEL
63 SVCERR << "AlignmentModel(" << this << ")::~AlignmentModel()" << endl; 46 SVCERR << "AlignmentModel(" << this << ")::~AlignmentModel()" << endl;
64 #endif 47 #endif
65
66 if (m_rawPath) m_rawPath->aboutToDelete();
67 delete m_rawPath;
68
69 if (m_path) m_path->aboutToDelete();
70 delete m_path;
71
72 if (m_reversePath) m_reversePath->aboutToDelete();
73 delete m_reversePath;
74 } 48 }
75 49
76 bool 50 bool
77 AlignmentModel::isOK() const 51 AlignmentModel::isOK() const
78 { 52 {
79 if (m_error != "") return false; 53 if (m_error != "") return false;
80 if (m_rawPath) return m_rawPath->isOK(); 54 if (m_pathSource.isNone()) return true;
55 auto pathSourceModel =
56 ModelById::getAs<SparseTimeValueModel>(m_pathSource);
57 if (pathSourceModel) {
58 return pathSourceModel->isOK();
59 }
81 return true; 60 return true;
82 } 61 }
83 62
84 sv_frame_t 63 sv_frame_t
85 AlignmentModel::getStartFrame() const 64 AlignmentModel::getStartFrame() const
86 { 65 {
87 sv_frame_t a = m_reference->getStartFrame(); 66 auto reference = ModelById::get(m_reference);
88 sv_frame_t b = m_aligned->getStartFrame(); 67 auto aligned = ModelById::get(m_aligned);
89 return std::min(a, b); 68
69 if (reference && aligned) {
70 sv_frame_t a = reference->getStartFrame();
71 sv_frame_t b = aligned->getStartFrame();
72 return std::min(a, b);
73 } else {
74 return 0;
75 }
90 } 76 }
91 77
92 sv_frame_t 78 sv_frame_t
93 AlignmentModel::getTrueEndFrame() const 79 AlignmentModel::getTrueEndFrame() const
94 { 80 {
95 sv_frame_t a = m_reference->getEndFrame(); 81 auto reference = ModelById::get(m_reference);
96 sv_frame_t b = m_aligned->getEndFrame(); 82 auto aligned = ModelById::get(m_aligned);
97 return std::max(a, b); 83
84 if (reference && aligned) {
85 sv_frame_t a = reference->getEndFrame();
86 sv_frame_t b = aligned->getEndFrame();
87 return std::max(a, b);
88 } else {
89 return 0;
90 }
98 } 91 }
99 92
100 sv_samplerate_t 93 sv_samplerate_t
101 AlignmentModel::getSampleRate() const 94 AlignmentModel::getSampleRate() const
102 { 95 {
103 return m_reference->getSampleRate(); 96 auto reference = ModelById::get(m_reference);
97 if (reference) {
98 return reference->getSampleRate();
99 } else {
100 return 0;
101 }
104 } 102 }
105 103
106 bool 104 bool
107 AlignmentModel::isReady(int *completion) const 105 AlignmentModel::isReady(int *completion) const
108 { 106 {
109 if (!m_pathBegun && m_rawPath) { 107 if (!m_pathBegun && !m_pathSource.isNone()) {
110 if (completion) *completion = 0; 108 if (completion) *completion = 0;
111 #ifdef DEBUG_ALIGNMENT_MODEL 109 #ifdef DEBUG_ALIGNMENT_MODEL
112 SVCERR << "AlignmentModel::isReady: path not begun" << endl; 110 SVCERR << "AlignmentModel::isReady: path not begun" << endl;
113 #endif 111 #endif
114 return false; 112 return false;
118 #ifdef DEBUG_ALIGNMENT_MODEL 116 #ifdef DEBUG_ALIGNMENT_MODEL
119 SVCERR << "AlignmentModel::isReady: path complete" << endl; 117 SVCERR << "AlignmentModel::isReady: path complete" << endl;
120 #endif 118 #endif
121 return true; 119 return true;
122 } 120 }
123 if (!m_rawPath) { 121 if (m_pathSource.isNone()) {
124 // lack of raw path could mean path is complete (in which case 122 // lack of raw path could mean path is complete (in which case
125 // m_pathComplete true above) or else no alignment has been 123 // m_pathComplete true above) or else no path source has been
126 // set at all yet (this case) 124 // set at all yet (this case)
127 if (completion) *completion = 0; 125 if (completion) *completion = 0;
128 #ifdef DEBUG_ALIGNMENT_MODEL 126 #ifdef DEBUG_ALIGNMENT_MODEL
129 SVCERR << "AlignmentModel::isReady: no raw path" << endl; 127 SVCERR << "AlignmentModel::isReady: no raw path" << endl;
130 #endif 128 #endif
131 return false; 129 return false;
132 } 130 }
133 return m_rawPath->isReady(completion); 131 auto pathSourceModel =
132 ModelById::getAs<SparseTimeValueModel>(m_pathSource);
133 if (pathSourceModel) {
134 return pathSourceModel->isReady(completion);
135 } else {
136 return true; // there is no meaningful answer here
137 }
134 } 138 }
135 139
136 const ZoomConstraint * 140 const ZoomConstraint *
137 AlignmentModel::getZoomConstraint() const 141 AlignmentModel::getZoomConstraint() const
138 { 142 {
139 return nullptr; 143 return nullptr;
140 } 144 }
141 145
142 const Model * 146 ModelId
143 AlignmentModel::getReferenceModel() const 147 AlignmentModel::getReferenceModel() const
144 { 148 {
145 return m_reference; 149 return m_reference;
146 } 150 }
147 151
148 const Model * 152 ModelId
149 AlignmentModel::getAlignedModel() const 153 AlignmentModel::getAlignedModel() const
150 { 154 {
151 return m_aligned; 155 return m_aligned;
152 } 156 }
153 157
156 { 160 {
157 #ifdef DEBUG_ALIGNMENT_MODEL 161 #ifdef DEBUG_ALIGNMENT_MODEL
158 cerr << "AlignmentModel::toReference(" << frame << ")" << endl; 162 cerr << "AlignmentModel::toReference(" << frame << ")" << endl;
159 #endif 163 #endif
160 if (!m_path) { 164 if (!m_path) {
161 if (!m_rawPath) return frame; 165 if (m_pathSource.isNone()) {
166 return frame;
167 }
162 constructPath(); 168 constructPath();
163 } 169 }
164 return align(m_path, frame); 170 if (!m_path) {
171 return frame;
172 }
173
174 return performAlignment(*m_path, frame);
165 } 175 }
166 176
167 sv_frame_t 177 sv_frame_t
168 AlignmentModel::fromReference(sv_frame_t frame) const 178 AlignmentModel::fromReference(sv_frame_t frame) const
169 { 179 {
170 #ifdef DEBUG_ALIGNMENT_MODEL 180 #ifdef DEBUG_ALIGNMENT_MODEL
171 cerr << "AlignmentModel::fromReference(" << frame << ")" << endl; 181 cerr << "AlignmentModel::fromReference(" << frame << ")" << endl;
172 #endif 182 #endif
173 if (!m_reversePath) { 183 if (!m_reversePath) {
174 if (!m_rawPath) return frame; 184 if (m_pathSource.isNone()) {
185 return frame;
186 }
175 constructReversePath(); 187 constructReversePath();
176 } 188 }
177 return align(m_reversePath, frame); 189 if (!m_reversePath) {
178 } 190 return frame;
179 191 }
180 void 192
181 AlignmentModel::pathChanged() 193 return performAlignment(*m_reversePath, frame);
182 { 194 }
183 if (m_pathComplete) { 195
184 cerr << "AlignmentModel: deleting raw path model" << endl; 196 void
185 if (m_rawPath) m_rawPath->aboutToDelete(); 197 AlignmentModel::pathSourceChangedWithin(ModelId, sv_frame_t, sv_frame_t)
186 delete m_rawPath;
187 m_rawPath = nullptr;
188 }
189 }
190
191 void
192 AlignmentModel::pathChangedWithin(sv_frame_t, sv_frame_t)
193 { 198 {
194 if (!m_pathComplete) return; 199 if (!m_pathComplete) return;
195 constructPath(); 200 constructPath();
196 constructReversePath(); 201 constructReversePath();
197 } 202 }
198 203
199 void 204 void
200 AlignmentModel::pathCompletionChanged() 205 AlignmentModel::pathSourceCompletionChanged(ModelId)
201 { 206 {
202 if (!m_rawPath) return; 207 auto pathSourceModel =
208 ModelById::getAs<SparseTimeValueModel>(m_pathSource);
209 if (!pathSourceModel) return;
210
203 m_pathBegun = true; 211 m_pathBegun = true;
204 212
205 if (!m_pathComplete) { 213 if (!m_pathComplete) {
206 214
207 int completion = 0; 215 int completion = 0;
208 m_rawPath->isReady(&completion); 216 pathSourceModel->isReady(&completion);
209 217
210 #ifdef DEBUG_ALIGNMENT_MODEL 218 #ifdef DEBUG_ALIGNMENT_MODEL
211 SVCERR << "AlignmentModel::pathCompletionChanged: completion = " 219 SVCERR << "AlignmentModel::pathCompletionChanged: completion = "
212 << completion << endl; 220 << completion << endl;
213 #endif 221 #endif
223 SVCERR << "AlignmentModel: path complete" << endl; 231 SVCERR << "AlignmentModel: path complete" << endl;
224 #endif 232 #endif
225 } 233 }
226 } 234 }
227 235
228 emit completionChanged(); 236 emit completionChanged(getId());
229 } 237 }
230 238
231 void 239 void
232 AlignmentModel::constructPath() const 240 AlignmentModel::constructPath() const
233 { 241 {
242 auto alignedModel = ModelById::get(m_aligned);
243 if (!alignedModel) return;
244
245 auto pathSourceModel =
246 ModelById::getAs<SparseTimeValueModel>(m_pathSource);
234 if (!m_path) { 247 if (!m_path) {
235 if (!m_rawPath) { 248 if (!pathSourceModel) {
236 cerr << "ERROR: AlignmentModel::constructPath: " 249 cerr << "ERROR: AlignmentModel::constructPath: "
237 << "No raw path available" << endl; 250 << "No raw path available (id is " << m_pathSource
251 << ")" << endl;
238 return; 252 return;
239 } 253 }
240 m_path = new PathModel 254 m_path.reset(new Path
241 (m_rawPath->getSampleRate(), m_rawPath->getResolution(), false); 255 (pathSourceModel->getSampleRate(),
242 } else { 256 pathSourceModel->getResolution()));
243 if (!m_rawPath) return; 257 } else {
258 if (!pathSourceModel) return;
244 } 259 }
245 260
246 m_path->clear(); 261 m_path->clear();
247 262
248 EventVector points = m_rawPath->getAllEvents(); 263 EventVector points = pathSourceModel->getAllEvents();
249 264
250 for (const auto &p: points) { 265 for (const auto &p: points) {
251 sv_frame_t frame = p.getFrame(); 266 sv_frame_t frame = p.getFrame();
252 double value = p.getValue(); 267 double value = p.getValue();
253 sv_frame_t rframe = lrint(value * m_aligned->getSampleRate()); 268 sv_frame_t rframe = lrint(value * alignedModel->getSampleRate());
254 m_path->add(PathPoint(frame, rframe)); 269 m_path->add(PathPoint(frame, rframe));
255 } 270 }
256 271
257 #ifdef DEBUG_ALIGNMENT_MODEL 272 #ifdef DEBUG_ALIGNMENT_MODEL
258 cerr << "AlignmentModel::constructPath: " << m_path->getPointCount() << " points, at least " << (2 * m_path->getPointCount() * (3 * sizeof(void *) + sizeof(int) + sizeof(PathPoint))) << " bytes" << endl; 273 cerr << "AlignmentModel::constructPath: " << m_path->getPointCount() << " points, at least " << (2 * m_path->getPointCount() * (3 * sizeof(void *) + sizeof(int) + sizeof(PathPoint))) << " bytes" << endl;
266 if (!m_path) { 281 if (!m_path) {
267 cerr << "ERROR: AlignmentModel::constructReversePath: " 282 cerr << "ERROR: AlignmentModel::constructReversePath: "
268 << "No forward path available" << endl; 283 << "No forward path available" << endl;
269 return; 284 return;
270 } 285 }
271 m_reversePath = new PathModel 286 m_reversePath.reset(new Path
272 (m_path->getSampleRate(), m_path->getResolution(), false); 287 (m_path->getSampleRate(),
288 m_path->getResolution()));
273 } else { 289 } else {
274 if (!m_path) return; 290 if (!m_path) return;
275 } 291 }
276 292
277 m_reversePath->clear(); 293 m_reversePath->clear();
278 294
279 PathModel::PointList points = m_path->getPoints(); 295 Path::Points points = m_path->getPoints();
280 296
281 for (PathModel::PointList::const_iterator i = points.begin(); 297 for (auto p: points) {
282 i != points.end(); ++i) { 298 sv_frame_t frame = p.frame;
283 sv_frame_t frame = i->frame; 299 sv_frame_t rframe = p.mapframe;
284 sv_frame_t rframe = i->mapframe;
285 m_reversePath->add(PathPoint(rframe, frame)); 300 m_reversePath->add(PathPoint(rframe, frame));
286 } 301 }
287 302
288 #ifdef DEBUG_ALIGNMENT_MODEL 303 #ifdef DEBUG_ALIGNMENT_MODEL
289 cerr << "AlignmentModel::constructReversePath: " << m_reversePath->getPointCount() << " points, at least " << (2 * m_reversePath->getPointCount() * (3 * sizeof(void *) + sizeof(int) + sizeof(PathPoint))) << " bytes" << endl; 304 cerr << "AlignmentModel::constructReversePath: " << m_reversePath->getPointCount() << " points, at least " << (2 * m_reversePath->getPointCount() * (3 * sizeof(void *) + sizeof(int) + sizeof(PathPoint))) << " bytes" << endl;
290 #endif 305 #endif
291 } 306 }
292 307
293 sv_frame_t 308 sv_frame_t
294 AlignmentModel::align(PathModel *path, sv_frame_t frame) const 309 AlignmentModel::performAlignment(const Path &path, sv_frame_t frame) const
295 { 310 {
296 if (!path) return frame;
297
298 // The path consists of a series of points, each with frame equal 311 // The path consists of a series of points, each with frame equal
299 // to the frame on the source model and mapframe equal to the 312 // to the frame on the source model and mapframe equal to the
300 // frame on the target model. Both should be monotonically 313 // frame on the target model. Both should be monotonically
301 // increasing. 314 // increasing.
302 315
303 const PathModel::PointList &points = path->getPoints(); 316 const Path::Points &points = path.getPoints();
304 317
305 if (points.empty()) { 318 if (points.empty()) {
306 #ifdef DEBUG_ALIGNMENT_MODEL 319 #ifdef DEBUG_ALIGNMENT_MODEL
307 cerr << "AlignmentModel::align: No points" << endl; 320 cerr << "AlignmentModel::align: No points" << endl;
308 #endif 321 #endif
312 #ifdef DEBUG_ALIGNMENT_MODEL 325 #ifdef DEBUG_ALIGNMENT_MODEL
313 cerr << "AlignmentModel::align: frame " << frame << " requested" << endl; 326 cerr << "AlignmentModel::align: frame " << frame << " requested" << endl;
314 #endif 327 #endif
315 328
316 PathPoint point(frame); 329 PathPoint point(frame);
317 PathModel::PointList::const_iterator i = points.lower_bound(point); 330 Path::Points::const_iterator i = points.lower_bound(point);
318 if (i == points.end()) { 331 if (i == points.end()) {
319 #ifdef DEBUG_ALIGNMENT_MODEL 332 #ifdef DEBUG_ALIGNMENT_MODEL
320 cerr << "Note: i == points.end()" << endl; 333 cerr << "Note: i == points.end()" << endl;
321 #endif 334 #endif
322 --i; 335 --i;
323 } 336 }
324 while (i != points.begin() && i->frame > frame) --i; 337 while (i != points.begin() && i->frame > frame) {
338 --i;
339 }
325 340
326 sv_frame_t foundFrame = i->frame; 341 sv_frame_t foundFrame = i->frame;
327 sv_frame_t foundMapFrame = i->mapframe; 342 sv_frame_t foundMapFrame = i->mapframe;
328 343
329 sv_frame_t followingFrame = foundFrame; 344 sv_frame_t followingFrame = foundFrame;
345 cerr << "foundFrame = " << foundFrame << ", foundMapFrame = " << foundMapFrame 360 cerr << "foundFrame = " << foundFrame << ", foundMapFrame = " << foundMapFrame
346 << ", followingFrame = " << followingFrame << ", followingMapFrame = " 361 << ", followingFrame = " << followingFrame << ", followingMapFrame = "
347 << followingMapFrame << endl; 362 << followingMapFrame << endl;
348 #endif 363 #endif
349 364
350 if (foundMapFrame < 0) return 0; 365 if (foundMapFrame < 0) {
366 return 0;
367 }
351 368
352 sv_frame_t resultFrame = foundMapFrame; 369 sv_frame_t resultFrame = foundMapFrame;
353 370
354 if (followingFrame != foundFrame && frame > foundFrame) { 371 if (followingFrame != foundFrame && frame > foundFrame) {
355 double interp = 372 double interp =
364 381
365 return resultFrame; 382 return resultFrame;
366 } 383 }
367 384
368 void 385 void
369 AlignmentModel::setPathFrom(SparseTimeValueModel *rawpath) 386 AlignmentModel::setPathFrom(ModelId pathSource)
370 { 387 {
371 if (m_rawPath) m_rawPath->aboutToDelete(); 388 m_pathSource = pathSource;
372 delete m_rawPath; 389
373 390 auto pathSourceModel =
374 m_rawPath = rawpath; 391 ModelById::getAs<SparseTimeValueModel>(m_pathSource);
375 392
376 if (!m_rawPath) { 393 if (pathSourceModel) {
377 return; 394
378 } 395 connect(pathSourceModel.get(),
379 396 SIGNAL(modelChangedWithin(ModelId, sv_frame_t, sv_frame_t)),
380 connect(m_rawPath, SIGNAL(modelChanged()), 397 this, SLOT(pathSourceChangedWithin(ModelId, sv_frame_t, sv_frame_t)));
381 this, SLOT(pathChanged()));
382
383 connect(m_rawPath, SIGNAL(modelChangedWithin(sv_frame_t, sv_frame_t)),
384 this, SLOT(pathChangedWithin(sv_frame_t, sv_frame_t)));
385 398
386 connect(m_rawPath, SIGNAL(completionChanged()), 399 connect(pathSourceModel.get(), SIGNAL(completionChanged(ModelId)),
387 this, SLOT(pathCompletionChanged())); 400 this, SLOT(pathSourceCompletionChanged(ModelId)));
388 401
389 constructPath(); 402 constructPath();
403 constructReversePath();
404
405 if (pathSourceModel->isReady()) {
406 pathSourceCompletionChanged(m_pathSource);
407 }
408 }
409 }
410
411 void
412 AlignmentModel::setPath(const Path &path)
413 {
414 m_path.reset(new Path(path));
415 m_pathComplete = true;
390 constructReversePath(); 416 constructReversePath();
391
392 if (m_rawPath->isReady()) {
393 pathCompletionChanged();
394 }
395 }
396
397 void
398 AlignmentModel::setPath(PathModel *path)
399 {
400 if (m_path) m_path->aboutToDelete();
401 delete m_path;
402 m_path = path;
403 m_pathComplete = true;
404 #ifdef DEBUG_ALIGNMENT_MODEL
405 cerr << "AlignmentModel::setPath: path = " << m_path << endl;
406 #endif
407 constructReversePath();
408 #ifdef DEBUG_ALIGNMENT_MODEL
409 cerr << "AlignmentModel::setPath: after construction path = "
410 << m_path << ", rpath = " << m_reversePath << endl;
411 #endif
412 } 417 }
413 418
414 void 419 void
415 AlignmentModel::toXml(QTextStream &stream, 420 AlignmentModel::toXml(QTextStream &stream,
416 QString indent, 421 QString indent,
423 428
424 m_path->toXml(stream, indent, ""); 429 m_path->toXml(stream, indent, "");
425 430
426 Model::toXml(stream, indent, 431 Model::toXml(stream, indent,
427 QString("type=\"alignment\" reference=\"%1\" aligned=\"%2\" path=\"%3\" %4") 432 QString("type=\"alignment\" reference=\"%1\" aligned=\"%2\" path=\"%3\" %4")
428 .arg(m_reference->getExportId()) 433 .arg(ModelById::getExportId(m_reference))
429 .arg(m_aligned->getExportId()) 434 .arg(ModelById::getExportId(m_aligned))
430 .arg(m_path->getExportId()) 435 .arg(m_path->getExportId())
431 .arg(extraAttributes)); 436 .arg(extraAttributes));
432 } 437 }
433
434