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