cannam@0
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
cannam@0
|
2
|
cannam@0
|
3 /*
|
cannam@0
|
4 Vamp feature extraction plugin using the MATCH audio alignment
|
cannam@0
|
5 algorithm.
|
cannam@0
|
6
|
cannam@0
|
7 Centre for Digital Music, Queen Mary, University of London.
|
Chris@236
|
8 Copyright (c) 2007-2020 Simon Dixon, Chris Cannam, and Queen Mary
|
Chris@230
|
9 University of London, Copyright (c) 2014-2015 Tido GmbH.
|
cannam@0
|
10
|
cannam@0
|
11 This program is free software; you can redistribute it and/or
|
cannam@0
|
12 modify it under the terms of the GNU General Public License as
|
cannam@0
|
13 published by the Free Software Foundation; either version 2 of the
|
cannam@0
|
14 License, or (at your option) any later version. See the file
|
cannam@0
|
15 COPYING included with this distribution for more information.
|
cannam@0
|
16 */
|
cannam@0
|
17
|
Chris@220
|
18 //#define DEBUG_FINDER 1
|
Chris@220
|
19 //#define PERFORM_ERROR_CHECKS 1
|
Chris@220
|
20
|
cannam@0
|
21 #include "Finder.h"
|
cannam@0
|
22
|
Chris@30
|
23 #include "Path.h"
|
Chris@30
|
24
|
Chris@30
|
25 #include <algorithm>
|
Chris@92
|
26 #include <iomanip>
|
Chris@30
|
27
|
Chris@72
|
28 using namespace std;
|
cannam@0
|
29
|
Chris@72
|
30 Finder::Finder(Matcher *pm)
|
cannam@0
|
31 {
|
Chris@72
|
32 m_m = pm;
|
Chris@72
|
33 m_duration1 = -1;
|
Chris@72
|
34 m_duration2 = -1;
|
cannam@0
|
35 } // constructor
|
cannam@0
|
36
|
cannam@0
|
37 Finder::~Finder()
|
cannam@0
|
38 {
|
cannam@0
|
39 }
|
cannam@0
|
40
|
Chris@60
|
41 void
|
Chris@154
|
42 Finder::setMatcher(Matcher *pm)
|
Chris@154
|
43 {
|
Chris@155
|
44 cerr << "Finder::setMatcher: finder " << this << ", matcher " << pm << endl;
|
Chris@154
|
45 m_m = pm;
|
Chris@154
|
46 }
|
Chris@154
|
47
|
Chris@154
|
48 void
|
Chris@60
|
49 Finder::setDurations(int d1, int d2)
|
Chris@60
|
50 {
|
Chris@140
|
51 #ifdef DEBUG_FINDER
|
Chris@140
|
52 cerr << "*** setDurations: " << d1 << ", " << d2 << endl;
|
Chris@140
|
53 #endif
|
Chris@72
|
54 m_duration1 = d1;
|
Chris@72
|
55 m_duration2 = d2;
|
Chris@60
|
56 }
|
Chris@60
|
57
|
Chris@154
|
58 bool
|
Chris@191
|
59 Finder::getBestRowCost(int row, int &bestCol, normpathcost_t &min)
|
Chris@154
|
60 {
|
Chris@172
|
61 if (!m_m->isRowAvailable(row)) return false;
|
Chris@205
|
62 pair<int, int> colRange = m_m->getColRangeForRow(row);
|
Chris@172
|
63 if (colRange.first >= colRange.second) return false;
|
Chris@154
|
64 for (int index = colRange.first; index < colRange.second; index++) {
|
Chris@191
|
65 normpathcost_t tmp = m_m->getNormalisedPathCost(row, index);
|
Chris@154
|
66 if (index == colRange.first || tmp < min) {
|
Chris@154
|
67 min = tmp;
|
Chris@154
|
68 bestCol = index;
|
Chris@154
|
69 }
|
Chris@154
|
70 }
|
Chris@154
|
71 return true;
|
Chris@154
|
72 }
|
Chris@154
|
73
|
Chris@154
|
74 bool
|
Chris@191
|
75 Finder::getBestColCost(int col, int &bestRow, normpathcost_t &min)
|
Chris@154
|
76 {
|
Chris@154
|
77 if (!m_m->isColAvailable(col)) return false;
|
Chris@205
|
78 pair<int, int> rowRange = m_m->getRowRangeForCol(col);
|
Chris@154
|
79 if (rowRange.first >= rowRange.second) return false;
|
Chris@191
|
80 bestRow = rowRange.first;
|
Chris@154
|
81 for (int index = rowRange.first; index < rowRange.second; index++) {
|
Chris@191
|
82 normpathcost_t tmp = m_m->getNormalisedPathCost(index, col);
|
Chris@191
|
83 if (index == rowRange.first) {
|
Chris@191
|
84 min = tmp;
|
Chris@191
|
85 } else if (tmp < min) {
|
Chris@154
|
86 min = tmp;
|
Chris@154
|
87 bestRow = index;
|
Chris@154
|
88 }
|
Chris@154
|
89 }
|
Chris@154
|
90 return true;
|
Chris@154
|
91 }
|
Chris@154
|
92
|
Chris@147
|
93 void
|
Chris@147
|
94 Finder::getBestEdgeCost(int row, int col,
|
Chris@147
|
95 int &bestRow, int &bestCol,
|
Chris@191
|
96 normpathcost_t &min)
|
cannam@0
|
97 {
|
Chris@191
|
98 min = m_m->getNormalisedPathCost(row, col);
|
Chris@72
|
99
|
Chris@147
|
100 bestRow = row;
|
Chris@147
|
101 bestCol = col;
|
Chris@72
|
102
|
Chris@205
|
103 pair<int, int> rowRange = m_m->getRowRangeForCol(col);
|
Chris@72
|
104 if (rowRange.second > row+1) {
|
Chris@72
|
105 rowRange.second = row+1; // don't cheat by looking at future :)
|
Chris@72
|
106 }
|
Chris@72
|
107 for (int index = rowRange.first; index < rowRange.second; index++) {
|
Chris@191
|
108 normpathcost_t tmp = m_m->getNormalisedPathCost(index, col);
|
cannam@0
|
109 if (tmp < min) {
|
cannam@0
|
110 min = tmp;
|
cannam@0
|
111 bestRow = index;
|
cannam@0
|
112 }
|
cannam@0
|
113 }
|
Chris@72
|
114
|
Chris@205
|
115 pair<int, int> colRange = m_m->getColRangeForRow(row);
|
Chris@72
|
116 if (colRange.second > col+1) {
|
Chris@72
|
117 colRange.second = col+1; // don't cheat by looking at future :)
|
Chris@72
|
118 }
|
Chris@72
|
119 for (int index = colRange.first; index < colRange.second; index++) {
|
Chris@191
|
120 normpathcost_t tmp = m_m->getNormalisedPathCost(row, index);
|
cannam@0
|
121 if (tmp < min) {
|
cannam@0
|
122 min = tmp;
|
cannam@0
|
123 bestCol = index;
|
cannam@0
|
124 bestRow = row;
|
cannam@0
|
125 }
|
cannam@0
|
126 }
|
Chris@147
|
127 }
|
Chris@72
|
128
|
Chris@181
|
129 advance_t
|
Chris@171
|
130 Finder::getExpandDirection()
|
Chris@171
|
131 {
|
Chris@171
|
132 return getExpandDirection(m_m->getFrameCount() - 1,
|
Chris@171
|
133 m_m->getOtherFrameCount() - 1);
|
Chris@171
|
134 }
|
Chris@171
|
135
|
Chris@181
|
136 advance_t
|
Chris@147
|
137 Finder::getExpandDirection(int row, int col)
|
Chris@147
|
138 {
|
Chris@147
|
139 // To determine which direction to expand the search area in, we
|
Chris@147
|
140 // look at the path costs along the leading edges of the search
|
Chris@147
|
141 // area (the final row and column within the area). We find the
|
Chris@147
|
142 // lowest path cost within the final row, and the lowest within
|
Chris@147
|
143 // the final column, and we compare them. If the row is cheaper
|
Chris@147
|
144 // then we expand by adding another row next to it; if the column
|
Chris@147
|
145 // is cheaper then we expand by adding another column next to
|
Chris@147
|
146 // it. (The overall lowest path cost across the row and column
|
Chris@147
|
147 // represents the best alignment we have within the entire search
|
Chris@147
|
148 // area given the data available and the assumption that the piece
|
Chris@147
|
149 // is not ending yet.)
|
Chris@147
|
150
|
Chris@147
|
151 int bestRow = row;
|
Chris@147
|
152 int bestCol = col;
|
Chris@215
|
153 normpathcost_t bestCost = INVALID_PATHCOST;
|
Chris@147
|
154
|
Chris@155
|
155 // cerr << "Finder " << this << "::getExpandDirection: ";
|
Chris@155
|
156
|
Chris@147
|
157 getBestEdgeCost(row, col, bestRow, bestCol, bestCost);
|
Chris@147
|
158
|
Chris@147
|
159 // cerr << "at [" << row << "," << col << "] (cost " << m_m->getPathCost(row, col) << ") blocksize = " << m_m->getBlockSize() << " best is [" << bestRow << "," << bestCol << "] (cost " << bestCost << ")" << endl;
|
Chris@135
|
160
|
Chris@45
|
161 if (bestRow == row) {
|
Chris@45
|
162 if (bestCol == col) {
|
Chris@181
|
163 return AdvanceBoth;
|
Chris@45
|
164 } else {
|
Chris@181
|
165 return AdvanceThis;
|
Chris@45
|
166 }
|
Chris@45
|
167 } else if (bestCol == col) {
|
Chris@181
|
168 return AdvanceOther;
|
Chris@45
|
169 } else {
|
Chris@181
|
170 return AdvanceNone;
|
Chris@45
|
171 }
|
Chris@73
|
172 }
|
cannam@0
|
173
|
cannam@0
|
174 void
|
cannam@0
|
175 Finder::recalculatePathCostMatrix(int r1, int c1, int r2, int c2)
|
cannam@0
|
176 {
|
Chris@72
|
177 int prevRowStart = 0, prevRowStop = 0;
|
Chris@72
|
178
|
Chris@72
|
179 for (int r = r1; r <= r2; r++) {
|
Chris@72
|
180
|
Chris@205
|
181 pair<int, int> colRange = m_m->getColRangeForRow(r);
|
Chris@72
|
182
|
Chris@72
|
183 int rowStart = max(c1, colRange.first);
|
Chris@72
|
184 int rowStop = min(c2 + 1, colRange.second);
|
Chris@72
|
185
|
Chris@72
|
186 for (int c = rowStart; c < rowStop; c++) {
|
Chris@72
|
187
|
Chris@181
|
188 advance_t dir = AdvanceNone;
|
Chris@188
|
189 pathcost_t straightIncrement = m_m->getDistance(r, c);
|
Chris@188
|
190 pathcost_t diagIncrement = pathcost_t(straightIncrement *
|
Chris@188
|
191 m_m->getDiagonalWeight());
|
Chris@72
|
192
|
Chris@72
|
193 if (r > r1) { // not first row
|
Chris@215
|
194 pathcost_t min = INVALID_PATHCOST;
|
Chris@72
|
195 if ((c > prevRowStart) && (c <= prevRowStop)) {
|
Chris@72
|
196 // diagonal from (r-1,c-1)
|
Chris@188
|
197 min = m_m->getPathCost(r-1, c-1) + diagIncrement;
|
Chris@181
|
198 dir = AdvanceBoth;
|
Chris@72
|
199 }
|
Chris@72
|
200 if ((c >= prevRowStart) && (c < prevRowStop)) {
|
Chris@72
|
201 // vertical from (r-1,c)
|
Chris@188
|
202 pathcost_t cost = m_m->getPathCost(r-1, c) + straightIncrement;
|
Chris@215
|
203 if ((min == INVALID_PATHCOST) || (cost < min)) {
|
Chris@72
|
204 min = cost;
|
Chris@181
|
205 dir = AdvanceThis;
|
Chris@72
|
206 }
|
Chris@72
|
207 }
|
Chris@72
|
208 if (c > rowStart) {
|
Chris@72
|
209 // horizontal from (r,c-1)
|
Chris@188
|
210 pathcost_t cost = m_m->getPathCost(r, c-1) + straightIncrement;
|
Chris@215
|
211 if ((min == INVALID_PATHCOST) || (cost < min)) {
|
Chris@72
|
212 min = cost;
|
Chris@181
|
213 dir = AdvanceOther;
|
Chris@72
|
214 }
|
Chris@72
|
215 }
|
Chris@72
|
216
|
Chris@72
|
217 m_m->setPathCost(r, c, dir, min);
|
Chris@72
|
218
|
Chris@72
|
219 } else if (c > rowStart) { // first row
|
Chris@72
|
220 // horizontal from (r,c-1)
|
Chris@181
|
221 m_m->setPathCost(r, c, AdvanceOther,
|
Chris@188
|
222 m_m->getPathCost(r, c-1) + straightIncrement);
|
Chris@72
|
223 }
|
Chris@72
|
224 }
|
Chris@72
|
225
|
Chris@72
|
226 prevRowStart = rowStart;
|
Chris@72
|
227 prevRowStop = rowStop;
|
cannam@0
|
228 }
|
Chris@72
|
229 }
|
Chris@30
|
230
|
Chris@82
|
231 #ifdef PERFORM_ERROR_CHECKS
|
Chris@81
|
232 Finder::ErrorPosition
|
Chris@81
|
233 Finder::checkPathCostMatrix()
|
Chris@81
|
234 {
|
Chris@81
|
235 ErrorPosition err;
|
Chris@81
|
236
|
Chris@81
|
237 int r1 = 0;
|
Chris@81
|
238 int c1 = 0;
|
Chris@81
|
239 int r2 = m_m->getFrameCount() - 1;
|
Chris@81
|
240 int c2 = m_m->getOtherFrameCount() - 1;
|
Chris@81
|
241
|
Chris@81
|
242 if (r2 < r1 || c2 < c1) {
|
Chris@81
|
243 return err;
|
Chris@81
|
244 }
|
Chris@81
|
245
|
Chris@81
|
246 int prevRowStart = 0, prevRowStop = 0;
|
Chris@81
|
247
|
Chris@81
|
248 for (int r = r1; r <= r2; r++) {
|
Chris@81
|
249
|
Chris@205
|
250 pair<int, int> colRange = m_m->getColRangeForRow(r);
|
Chris@81
|
251
|
Chris@81
|
252 int rowStart = max(c1, colRange.first);
|
Chris@81
|
253 int rowStop = min(c2 + 1, colRange.second);
|
Chris@81
|
254
|
Chris@81
|
255 for (int c = rowStart; c < rowStop; c++) {
|
Chris@81
|
256
|
Chris@188
|
257 advance_t dir = AdvanceNone;
|
Chris@212
|
258 pathcost_t updateTo = INVALID_PATHCOST;
|
Chris@188
|
259 distance_t distance = m_m->getDistance(r, c);
|
Chris@188
|
260 pathcost_t straightIncrement = distance;
|
Chris@188
|
261 pathcost_t diagIncrement = pathcost_t(distance * m_m->getDiagonalWeight());
|
Chris@188
|
262 err.distance = distance;
|
Chris@81
|
263
|
Chris@95
|
264 if (r > r1) { // not first row
|
Chris@215
|
265 pathcost_t min = INVALID_PATHCOST;
|
Chris@81
|
266 if ((c > prevRowStart) && (c <= prevRowStop)) {
|
Chris@81
|
267 // diagonal from (r-1,c-1)
|
Chris@188
|
268 min = m_m->getPathCost(r-1, c-1) + diagIncrement;
|
Chris@81
|
269 err.prevCost = m_m->getPathCost(r-1, c-1);
|
Chris@181
|
270 dir = AdvanceBoth;
|
Chris@81
|
271 }
|
Chris@81
|
272 if ((c >= prevRowStart) && (c < prevRowStop)) {
|
Chris@81
|
273 // vertical from (r-1,c)
|
Chris@188
|
274 pathcost_t cost = m_m->getPathCost(r-1, c) + straightIncrement;
|
Chris@215
|
275 if ((min == INVALID_PATHCOST) || (cost < min)) {
|
Chris@81
|
276 min = cost;
|
Chris@81
|
277 err.prevCost = m_m->getPathCost(r-1, c);
|
Chris@181
|
278 dir = AdvanceThis;
|
Chris@81
|
279 }
|
Chris@81
|
280 }
|
Chris@81
|
281 if (c > rowStart) {
|
Chris@81
|
282 // horizontal from (r,c-1)
|
Chris@188
|
283 pathcost_t cost = m_m->getPathCost(r, c-1) + straightIncrement;
|
Chris@215
|
284 if ((min == INVALID_PATHCOST) || (cost < min)) {
|
Chris@81
|
285 min = cost;
|
Chris@81
|
286 err.prevCost = m_m->getPathCost(r, c-1);
|
Chris@181
|
287 dir = AdvanceOther;
|
Chris@81
|
288 }
|
Chris@81
|
289 }
|
Chris@81
|
290
|
Chris@81
|
291 updateTo = min;
|
Chris@81
|
292
|
Chris@82
|
293 } else { // first row
|
Chris@82
|
294
|
Chris@82
|
295 if (c > rowStart) {
|
Chris@82
|
296 // horizontal from (r,c-1)
|
Chris@188
|
297 updateTo = m_m->getPathCost(r, c-1) + straightIncrement;
|
Chris@83
|
298 err.prevCost = m_m->getPathCost(r, c-1);
|
Chris@181
|
299 dir = AdvanceOther;
|
Chris@82
|
300 }
|
Chris@81
|
301 }
|
Chris@81
|
302
|
Chris@181
|
303 if (dir != AdvanceNone) {
|
Chris@86
|
304 if (m_m->getAdvance(r, c) != dir) {
|
Chris@86
|
305 err.type = ErrorPosition::WrongAdvance;
|
Chris@86
|
306 err.r = r;
|
Chris@86
|
307 err.c = c;
|
Chris@86
|
308 err.costWas = m_m->getPathCost(r, c);
|
Chris@86
|
309 err.costShouldBe = updateTo;
|
Chris@86
|
310 err.advanceWas = m_m->getAdvance(r, c);
|
Chris@86
|
311 err.advanceShouldBe = dir;
|
Chris@86
|
312 return err;
|
Chris@86
|
313 }
|
Chris@84
|
314 if (m_m->getPathCost(r, c) != updateTo) {
|
Chris@84
|
315 err.type = ErrorPosition::WrongCost;
|
Chris@84
|
316 err.r = r;
|
Chris@84
|
317 err.c = c;
|
Chris@84
|
318 err.costWas = m_m->getPathCost(r, c);
|
Chris@84
|
319 err.costShouldBe = updateTo;
|
Chris@84
|
320 err.advanceWas = m_m->getAdvance(r, c);
|
Chris@84
|
321 err.advanceShouldBe = dir;
|
Chris@82
|
322 return err;
|
Chris@82
|
323 }
|
Chris@82
|
324 } else {
|
Chris@82
|
325 // AdvanceNone should occur only at r = r1, c = c1
|
Chris@82
|
326 if (r != r1 || c != c1) {
|
Chris@82
|
327 err.type = ErrorPosition::NoAdvance;
|
Chris@82
|
328 err.r = r;
|
Chris@82
|
329 err.c = c;
|
Chris@82
|
330 err.costWas = m_m->getPathCost(r, c);
|
Chris@82
|
331 err.costShouldBe = updateTo;
|
Chris@84
|
332 err.advanceWas = m_m->getAdvance(r, c);
|
Chris@84
|
333 err.advanceShouldBe = dir;
|
Chris@82
|
334 return err;
|
Chris@82
|
335 }
|
Chris@81
|
336 }
|
Chris@81
|
337 }
|
Chris@81
|
338
|
Chris@81
|
339 prevRowStart = rowStart;
|
Chris@81
|
340 prevRowStop = rowStop;
|
Chris@81
|
341 }
|
Chris@81
|
342
|
Chris@81
|
343 return err;
|
Chris@82
|
344 }
|
Chris@81
|
345
|
Chris@92
|
346 void
|
Chris@92
|
347 Finder::checkAndReport()
|
Chris@30
|
348 {
|
Chris@92
|
349 cerr << "Finder: Checking path-cost matrix..." << endl;
|
Chris@82
|
350 ErrorPosition err = checkPathCostMatrix();
|
Chris@92
|
351 if (err.type == ErrorPosition::NoError) {
|
Chris@92
|
352 cerr << "No errors found" << endl;
|
Chris@92
|
353 } else {
|
Chris@82
|
354 cerr << "\nWARNING: Checking path-cost matrix returned mismatch:" << endl;
|
Chris@92
|
355 cerr << "Type: " << err.type << ": ";
|
Chris@92
|
356 switch (err.type) {
|
Chris@92
|
357 case ErrorPosition::NoError: break;
|
Chris@92
|
358 case ErrorPosition::WrongCost: cerr << "WrongCost"; break;
|
Chris@92
|
359 case ErrorPosition::WrongAdvance: cerr << "WrongAdvance"; break;
|
Chris@92
|
360 case ErrorPosition::NoAdvance: cerr << "NoAdvance"; break;
|
Chris@92
|
361 }
|
Chris@92
|
362 cerr << endl;
|
Chris@84
|
363 cerr << "At row " << err.r << ", column " << err.c
|
Chris@84
|
364 << "\nShould be advancing "
|
Chris@84
|
365 << Matcher::advanceToString(err.advanceShouldBe)
|
Chris@84
|
366 << ", advance in matrix is "
|
Chris@84
|
367 << Matcher::advanceToString(err.advanceWas)
|
Chris@83
|
368 << "\nPrev cost " << err.prevCost
|
Chris@191
|
369 << " plus distance " << distance_print_t(err.distance)
|
Chris@191
|
370 << " [perhaps diagonalised] gives "
|
Chris@84
|
371 << err.costShouldBe << ", matrix contains " << err.costWas
|
Chris@83
|
372 << endl;
|
Chris@83
|
373 cerr << "Note: diagonal weight = " << m_m->getDiagonalWeight() << endl;
|
Chris@83
|
374 cerr << endl;
|
Chris@92
|
375
|
Chris@95
|
376 int w(4);
|
Chris@95
|
377 int ww(15);
|
Chris@92
|
378
|
Chris@92
|
379 cerr << "Distance matrix leading up to this point:" << endl;
|
Chris@95
|
380 cerr << setprecision(12) << setw(w) << "";
|
Chris@92
|
381 for (int i = -4; i <= 0; ++i) {
|
Chris@95
|
382 cerr << setw(ww) << i;
|
Chris@92
|
383 }
|
Chris@92
|
384 cerr << endl;
|
Chris@92
|
385 for (int j = -4; j <= 0; ++j) {
|
Chris@92
|
386 cerr << setw(w) << j;
|
Chris@92
|
387 for (int i = -4; i <= 0; ++i) {
|
Chris@191
|
388 cerr << setw(ww)
|
Chris@191
|
389 << distance_print_t(m_m->getDistance(err.r + j, err.c + i));
|
Chris@92
|
390 }
|
Chris@92
|
391 cerr << endl;
|
Chris@92
|
392 }
|
Chris@92
|
393 cerr << endl;
|
Chris@92
|
394
|
Chris@92
|
395 cerr << "Cost matrix leading up to this point:" << endl;
|
Chris@92
|
396 cerr << setw(w) << "";
|
Chris@92
|
397 for (int i = -4; i <= 0; ++i) {
|
Chris@95
|
398 cerr << setw(ww) << i;
|
Chris@92
|
399 }
|
Chris@92
|
400 cerr << endl;
|
Chris@92
|
401 for (int j = -4; j <= 0; ++j) {
|
Chris@92
|
402 cerr << setw(w) << j;
|
Chris@92
|
403 for (int i = -4; i <= 0; ++i) {
|
Chris@95
|
404 cerr << setw(ww) << m_m->getPathCost(err.r + j, err.c + i);
|
Chris@92
|
405 }
|
Chris@92
|
406 cerr << endl;
|
Chris@92
|
407 }
|
Chris@92
|
408 cerr << endl;
|
Chris@82
|
409 }
|
Chris@92
|
410 }
|
Chris@92
|
411 #endif
|
Chris@92
|
412
|
Chris@182
|
413 pathcost_t
|
Chris@163
|
414 Finder::getOverallCost()
|
Chris@163
|
415 {
|
Chris@163
|
416 int ex = m_m->getOtherFrameCount() - 1;
|
Chris@163
|
417 int ey = m_m->getFrameCount() - 1;
|
Chris@163
|
418
|
Chris@163
|
419 if (ex < 0 || ey < 0) {
|
Chris@163
|
420 return 0;
|
Chris@163
|
421 }
|
Chris@163
|
422
|
Chris@165
|
423 return m_m->getPathCost(ey, ex);
|
Chris@163
|
424 }
|
Chris@163
|
425
|
Chris@92
|
426 int
|
Chris@92
|
427 Finder::retrievePath(bool smooth, vector<int> &pathx, vector<int> &pathy)
|
Chris@92
|
428 {
|
Chris@92
|
429 pathx.clear();
|
Chris@92
|
430 pathy.clear();
|
Chris@92
|
431
|
Chris@92
|
432 #ifdef PERFORM_ERROR_CHECKS
|
Chris@92
|
433 checkAndReport();
|
Chris@82
|
434 #endif
|
Chris@82
|
435
|
Chris@72
|
436 int ex = m_m->getOtherFrameCount() - 1;
|
Chris@72
|
437 int ey = m_m->getFrameCount() - 1;
|
Chris@69
|
438
|
Chris@69
|
439 if (ex < 0 || ey < 0) {
|
Chris@69
|
440 return 0;
|
Chris@69
|
441 }
|
Chris@66
|
442
|
Chris@66
|
443 int x = ex;
|
Chris@66
|
444 int y = ey;
|
Chris@30
|
445
|
Chris@140
|
446 #ifdef DEBUG_FINDER
|
Chris@140
|
447 cerr << "*** retrievePath: smooth = " << smooth << endl;
|
Chris@140
|
448 cerr << "*** retrievePath: before: x = " << x << ", y = " << y << endl;
|
Chris@140
|
449 #endif
|
Chris@140
|
450
|
Chris@72
|
451 if (m_duration2 > 0 && m_duration2 < m_m->getOtherFrameCount()) {
|
Chris@72
|
452 x = m_duration2 - 1;
|
Chris@60
|
453 }
|
Chris@72
|
454 if (m_duration1 > 0 && m_duration1 < m_m->getFrameCount()) {
|
Chris@72
|
455 y = m_duration1 - 1;
|
Chris@60
|
456 }
|
Chris@60
|
457
|
Chris@72
|
458 if (!m_m->isAvailable(y, x)) {
|
Chris@66
|
459 // Path did not pass through the expected end point --
|
Chris@66
|
460 // probably means the pieces are substantially different in
|
Chris@66
|
461 // the later bits. Reset the expected end point to the end of
|
Chris@66
|
462 // both files including any trailing silence.
|
Chris@66
|
463 cerr << "NOTE: Path did not pass through expected end point, inputs are probably significantly different" << endl;
|
Chris@66
|
464 x = ex;
|
Chris@66
|
465 y = ey;
|
Chris@66
|
466 }
|
Chris@66
|
467
|
Chris@55
|
468 recalculatePathCostMatrix(0, 0, y, x);
|
Chris@55
|
469
|
Chris@140
|
470 #ifdef DEBUG_FINDER
|
Chris@140
|
471 cerr << "*** retrievePath: start: x = " << x << ", y = " << y << endl;
|
Chris@140
|
472 #endif
|
Chris@66
|
473
|
Chris@72
|
474 while (m_m->isAvailable(y, x) && (x > 0 || y > 0)) {
|
Chris@30
|
475
|
Chris@33
|
476 // cerr << "x = " << x << ", y = " << y;
|
Chris@33
|
477
|
Chris@30
|
478 pathx.push_back(x);
|
Chris@30
|
479 pathy.push_back(y);
|
Chris@30
|
480
|
Chris@72
|
481 switch (m_m->getAdvance(y, x)) {
|
Chris@181
|
482 case AdvanceThis:
|
Chris@70
|
483 // cerr << ", going down (dist = " << getDistance() << ")" << endl;
|
Chris@33
|
484 y--;
|
Chris@33
|
485 break;
|
Chris@181
|
486 case AdvanceOther:
|
Chris@70
|
487 // cerr << ", going left (dist = " << getDistance() << ")" << endl;
|
Chris@33
|
488 x--;
|
Chris@33
|
489 break;
|
Chris@181
|
490 case AdvanceBoth:
|
Chris@70
|
491 // cerr << ", going diag (dist = " << getDistance() << ")" << endl;
|
Chris@33
|
492 x--;
|
Chris@33
|
493 y--;
|
Chris@33
|
494 break;
|
Chris@181
|
495 case AdvanceNone: // this would indicate a bug, but we wouldn't want to hang
|
Chris@69
|
496 cerr << "WARNING: Neither matcher advanced in path backtrack at (" << x << "," << y << ")" << endl;
|
Chris@33
|
497 if (x > y) {
|
Chris@33
|
498 x--;
|
Chris@33
|
499 } else {
|
Chris@33
|
500 y--;
|
Chris@33
|
501 }
|
Chris@33
|
502 break;
|
Chris@30
|
503 }
|
Chris@30
|
504 }
|
Chris@30
|
505
|
Chris@72
|
506 if (x > 0 || y > 0) {
|
Chris@72
|
507 cerr << "WARNING: Ran out of available path at (" << y << "," << x
|
Chris@72
|
508 << ")!" << endl;
|
Chris@72
|
509 }
|
Chris@72
|
510
|
Chris@72
|
511 reverse(pathx.begin(), pathx.end());
|
Chris@72
|
512 reverse(pathy.begin(), pathy.end());
|
Chris@30
|
513
|
Chris@31
|
514 if (smooth) {
|
Chris@180
|
515 int smoothedLen = Path().smooth
|
Chris@180
|
516 (pathx, pathy, static_cast<int>(pathx.size()));
|
Chris@31
|
517 return smoothedLen;
|
Chris@31
|
518 } else {
|
Chris@180
|
519 return static_cast<int>(pathx.size());
|
Chris@31
|
520 }
|
Chris@30
|
521 }
|
Chris@30
|
522
|