annotate src/Finder.cpp @ 66:61c7d11ba86d refactors_no_float

Fix handling of path lookup in case where the expected end point (end of silence in both files) is not available
author Chris Cannam
date Tue, 18 Nov 2014 10:31:37 +0000
parents faa523be20f9
children a3efb15e7faf 7aa1ab3db7c9
rev   line source
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@30 22
cannam@0 23
cannam@0 24 Finder::Finder(Matcher *p1, Matcher *p2)
cannam@0 25 {
Chris@43 26 if (!p1->m_firstPM)
cannam@0 27 std::cerr << "Warning: wrong args in Finder()" << std::endl;
cannam@0 28 pm1 = p1;
cannam@0 29 pm2 = p2;
cannam@0 30 index1 = 0;
cannam@0 31 index2 = 0;
cannam@0 32 rowRange = new int[2];
cannam@0 33 colRange = new int[2];
Chris@60 34 duration1 = -1;
Chris@60 35 duration2 = -1;
cannam@0 36 } // constructor
cannam@0 37
cannam@0 38 Finder::~Finder()
cannam@0 39 {
cannam@0 40 delete[] rowRange;
cannam@0 41 delete[] colRange;
cannam@0 42 }
cannam@0 43
Chris@60 44 void
Chris@60 45 Finder::setDurations(int d1, int d2)
Chris@60 46 {
Chris@60 47 duration1 = d1;
Chris@60 48 duration2 = d2;
Chris@60 49 }
Chris@60 50
cannam@0 51 bool
cannam@0 52 Finder::find(int i1, int i2)
cannam@0 53 {
cannam@0 54 if (i1 >= 0) {
cannam@0 55 index1 = i1;
Chris@43 56 index2 = i2 - pm1->m_first[i1];
cannam@0 57 }
Chris@43 58 return (i1 >= 0) && (i2 >= pm1->m_first[i1]) && (i2 < pm1->m_last[i1]);
cannam@0 59 } // find()
cannam@0 60
cannam@0 61 void
cannam@0 62 Finder::getColRange(int row, int *range)
cannam@0 63 {
Chris@43 64 range[0] = pm1->m_first[row];
Chris@43 65 range[1] = pm1->m_last[row];
cannam@0 66 } // getColRange()
cannam@0 67
cannam@0 68 void
cannam@0 69 Finder::getRowRange(int col, int *range)
cannam@0 70 {
Chris@43 71 range[0] = pm2->m_first[col];
Chris@43 72 range[1] = pm2->m_last[col];
cannam@0 73 } // getRowRange()
cannam@0 74
cannam@0 75 int
cannam@0 76 Finder::getExpandDirection(int row, int col)
cannam@0 77 {
cannam@0 78 return getExpandDirection(row, col, false);
cannam@0 79 } // getExpandDirection()
cannam@0 80
cannam@0 81 int
cannam@0 82 Finder::getExpandDirection(int row, int col, bool check)
cannam@0 83 {
cannam@0 84 int min = getPathCost(row, col);
cannam@0 85 bestRow = row;
cannam@0 86 bestCol = col;
cannam@0 87 getRowRange(col, rowRange);
cannam@0 88 if (rowRange[1] > row+1)
cannam@0 89 rowRange[1] = row+1; // don't cheat by looking at future :)
cannam@0 90 for (int index = rowRange[0]; index < rowRange[1]; index++) {
cannam@0 91 int tmp = getPathCost(index, col);
cannam@0 92 if (tmp < min) {
cannam@0 93 min = tmp;
cannam@0 94 bestRow = index;
cannam@0 95 }
cannam@0 96 }
cannam@0 97 getColRange(row, colRange);
cannam@0 98 if (colRange[1] > col+1)
cannam@0 99 colRange[1] = col+1; // don't cheat by looking at future :)
cannam@0 100 for (int index = colRange[0]; index < colRange[1]; index++) {
cannam@0 101 int tmp = getPathCost(row, index);
cannam@0 102 if (tmp < min) {
cannam@0 103 min = tmp;
cannam@0 104 bestCol = index;
cannam@0 105 bestRow = row;
cannam@0 106 }
cannam@0 107 }
cannam@0 108 // System.err.print(" BEST: " + bestRow + " " + bestCol + " " + check);
cannam@0 109 // System.err.println(" " + pm1->frameCount + " " + pm2->frameCount);
cannam@0 110 if (check) {
cannam@0 111 // System.err.println(find(row+1, col) + " " + find(row, col+1));
cannam@0 112 if (!find(row, col+1))
cannam@0 113 return ADVANCE_THIS;
cannam@0 114 if (!find(row+1, col))
cannam@0 115 return ADVANCE_OTHER;
cannam@0 116 }
cannam@0 117 return ((bestRow==row)? ADVANCE_THIS: 0) |
cannam@0 118 ((bestCol==col)? ADVANCE_OTHER: 0);
cannam@0 119
cannam@0 120 } // getExpandDirection()
cannam@0 121
cannam@0 122 unsigned char
cannam@0 123 Finder::getDistance(int row, int col)
cannam@0 124 {
cannam@0 125 if (find(row, col)) {
Chris@43 126 return pm1->m_distance[row][col - pm1->m_first[row]];
cannam@0 127 }
cannam@0 128 std::cerr << "getDistance(" << row << "," << col << "): out of bounds" << std::endl;
cannam@0 129 throw "getDistance index out of bounds";
cannam@0 130 } // getDistance()/2
cannam@0 131
cannam@0 132 void
cannam@0 133 Finder::setDistance(int row, int col, unsigned char b)
cannam@0 134 {
cannam@0 135 if (find(row, col)) {
Chris@43 136 pm1->m_distance[row][col - pm1->m_first[row]] = b;
cannam@0 137 return;
cannam@0 138 }
cannam@0 139 std::cerr << "setDistance(" << row << "," << col << "," << b << "): out of bounds" << std::endl;
cannam@0 140 throw "setDistance index out of bounds";
cannam@0 141 } // setDistance()
cannam@0 142
cannam@0 143 int
cannam@0 144 Finder::getPathCost(int row, int col)
cannam@0 145 {
cannam@0 146 if (find(row, col)) // "1" avoids div by 0 below
Chris@43 147 return pm1->m_bestPathCost[row][col - pm1->m_first[row]]*100/ (1+row+col);
cannam@0 148 std::cerr << "getPathCost(" << row << "," << col << "): out of bounds" << std::endl;
cannam@0 149 throw "getPathCost index out of bounds";
cannam@0 150 } // getPathCost()
cannam@0 151
cannam@0 152 int
cannam@0 153 Finder::getRawPathCost(int row, int col)
cannam@0 154 {
cannam@0 155 if (find(row, col))
Chris@43 156 return pm1->m_bestPathCost[row][col - pm1->m_first[row]];
cannam@0 157 std::cerr << "getRawPathCost(" << row << "," << col << "): out of bounds" << std::endl;
cannam@0 158 throw "getRawPathCost index out of bounds";
cannam@0 159 } // getRawPathCost()
cannam@0 160
cannam@0 161 void
cannam@0 162 Finder::setPathCost(int row, int col, int i)
cannam@0 163 {
cannam@0 164 if (find(row, col)) {
Chris@43 165 pm1->m_bestPathCost[row][col - pm1->m_first[row]] = i;
cannam@0 166 return;
cannam@0 167 }
cannam@0 168 std::cerr << "setPathCost(" << row << "," << col << "," << i << "): out of bounds" << std::endl;
cannam@0 169 throw "setPathCost index out of bounds";
cannam@0 170 } // setPathCost()
cannam@0 171
cannam@0 172 unsigned char
cannam@0 173 Finder::getDistance()
cannam@0 174 {
Chris@43 175 return pm1->m_distance[index1][index2];
cannam@0 176 } // getDistance()/0
cannam@0 177
cannam@0 178 void
cannam@0 179 Finder::setDistance(int b)
cannam@0 180 {
Chris@43 181 pm1->m_distance[index1][index2] = (unsigned char)b;
cannam@0 182 } // setDistance()
cannam@0 183
cannam@0 184 int
cannam@0 185 Finder::getPathCost()
cannam@0 186 {
Chris@43 187 return pm1->m_bestPathCost[index1][index2];
cannam@0 188 } // getPathCost()
cannam@0 189
cannam@0 190 void
cannam@0 191 Finder::setPathCost(int i)
cannam@0 192 {
Chris@43 193 pm1->m_bestPathCost[index1][index2] = i;
cannam@0 194 } // setPathCost()
cannam@0 195
cannam@0 196 void
cannam@0 197 Finder::recalculatePathCostMatrix(int r1, int c1, int r2, int c2)
cannam@0 198 {
cannam@0 199 if (!find(r1,c1)) {
cannam@0 200 std::cerr << "recalculatePathCostMatrix(" << r1 << "," << c1 << "): out of bounds" << std::endl;
cannam@0 201 throw "recalculatePathCostMatrix index out of bounds";
cannam@0 202 }
cannam@0 203 int thisRowStart, c;
cannam@0 204 int prevRowStart = 0, prevRowStop = 0;
cannam@0 205 for (int r = r1; r <= r2; r++) {
Chris@43 206 thisRowStart = pm1->m_first[r];
cannam@0 207 if (thisRowStart < c1)
cannam@0 208 thisRowStart = c1;
cannam@0 209 for (c = thisRowStart; c <= c2; c++) {
cannam@0 210 if (find(r,c)) {
cannam@0 211 int i2 = index2;
Chris@43 212 int newCost = pm1->m_distance[r][i2];
cannam@0 213 int dir = 0;
cannam@0 214 if (r > r1) { // not first row
cannam@0 215 int min = -1;
cannam@0 216 if ((c > prevRowStart) && (c <= prevRowStop)) {
cannam@0 217 // diagonal from (r-1,c-1)
Chris@43 218 min = pm1->m_bestPathCost[r-1][c-pm1->m_first[r-1]-1] +
cannam@0 219 newCost * 2;
cannam@0 220 dir = ADVANCE_BOTH;
cannam@0 221 }
cannam@0 222 if ((c >= prevRowStart) && (c < prevRowStop)) {
cannam@0 223 // vertical from (r-1,c)
Chris@43 224 int cost = pm1->m_bestPathCost[r-1][c-pm1->m_first[r-1]] +
cannam@0 225 newCost;
cannam@0 226 if ((min == -1) || (cost < min)) {
cannam@0 227 min = cost;
cannam@0 228 dir = ADVANCE_THIS;
cannam@0 229 }
cannam@0 230 }
cannam@0 231 if (c > thisRowStart) {
cannam@0 232 // horizontal from (r,c-1)
Chris@43 233 int cost =pm1->m_bestPathCost[r][i2-1]+newCost;
cannam@0 234 if ((min == -1) || (cost < min)) {
cannam@0 235 min = cost;
cannam@0 236 dir = ADVANCE_OTHER;
cannam@0 237 }
cannam@0 238 }
Chris@43 239 pm1->m_bestPathCost[r][i2] = min;
cannam@0 240 } else if (c > thisRowStart) { // first row
cannam@0 241 // horizontal from (r,c-1)
Chris@43 242 pm1->m_bestPathCost[r][i2] = pm1->m_bestPathCost[r][i2-1] +
cannam@0 243 newCost;
cannam@0 244 dir = ADVANCE_OTHER;
cannam@0 245 }
cannam@0 246 if ((r != r1) || (c != c1)) {
Chris@43 247 pm1->m_distance[r][i2] = (unsigned char)
Chris@43 248 ((pm1->m_distance[r][i2] & MASK) | dir);
cannam@0 249 }
cannam@0 250 } else
cannam@0 251 break; // end of row
cannam@0 252 }
cannam@0 253 prevRowStart = thisRowStart;
cannam@0 254 prevRowStop = c;
cannam@0 255 }
cannam@0 256 } // recalculatePathCostMatrix()
Chris@30 257
Chris@30 258 int
Chris@31 259 Finder::retrievePath(bool smooth, vector<int> &pathx, vector<int> &pathy)
Chris@30 260 {
Chris@66 261 int ex = pm2->getFrameCount() - 1;
Chris@66 262 int ey = pm1->getFrameCount() - 1;
Chris@66 263
Chris@66 264 int x = ex;
Chris@66 265 int y = ey;
Chris@66 266
Chris@66 267 // cerr << "before: x = " << x << ", y = " << y << endl;
Chris@30 268
Chris@60 269 if (duration2 > 0 && duration2 < pm2->getFrameCount()) {
Chris@60 270 x = duration2 - 1;
Chris@60 271 }
Chris@60 272 if (duration1 > 0 && duration1 < pm1->getFrameCount()) {
Chris@60 273 y = duration1 - 1;
Chris@60 274 }
Chris@60 275
Chris@66 276 if (!find(y, x)) {
Chris@66 277 // Path did not pass through the expected end point --
Chris@66 278 // probably means the pieces are substantially different in
Chris@66 279 // the later bits. Reset the expected end point to the end of
Chris@66 280 // both files including any trailing silence.
Chris@66 281 cerr << "NOTE: Path did not pass through expected end point, inputs are probably significantly different" << endl;
Chris@66 282 x = ex;
Chris@66 283 y = ey;
Chris@66 284 }
Chris@66 285
Chris@55 286 recalculatePathCostMatrix(0, 0, y, x);
Chris@55 287
Chris@30 288 pathx.clear();
Chris@30 289 pathy.clear();
Chris@30 290
Chris@66 291 // cerr << "start: x = " << x << ", y = " << y << endl;
Chris@66 292
Chris@30 293 while (find(y, x) && ((x > 0) || (y > 0))) {
Chris@30 294
Chris@33 295 // cerr << "x = " << x << ", y = " << y;
Chris@33 296
Chris@30 297 pathx.push_back(x);
Chris@30 298 pathy.push_back(y);
Chris@30 299
Chris@30 300 switch (getDistance() & ADVANCE_BOTH) {
Chris@33 301 case ADVANCE_THIS:
Chris@33 302 // cerr << ", going down (dist = " << (int)getDistance() << ")" << endl;
Chris@33 303 y--;
Chris@33 304 break;
Chris@33 305 case ADVANCE_OTHER:
Chris@33 306 // cerr << ", going left (dist = " << (int)getDistance() << ")" << endl;
Chris@33 307 x--;
Chris@33 308 break;
Chris@33 309 case ADVANCE_BOTH:
Chris@33 310 // cerr << ", going diag (dist = " << (int)getDistance() << ")" << endl;
Chris@33 311 x--;
Chris@33 312 y--;
Chris@33 313 break;
Chris@30 314 default: // this would indicate a bug, but we wouldn't want to hang
Chris@33 315 // cerr << "WARNING: Neither matcher advanced in path backtrack at (" << x << "," << y << ")" << endl;
Chris@33 316 if (x > y) {
Chris@33 317 x--;
Chris@33 318 } else {
Chris@33 319 y--;
Chris@33 320 }
Chris@33 321 break;
Chris@30 322 }
Chris@30 323 }
Chris@30 324
Chris@30 325 std::reverse(pathx.begin(), pathx.end());
Chris@30 326 std::reverse(pathy.begin(), pathy.end());
Chris@30 327
Chris@31 328 if (smooth) {
Chris@31 329 int smoothedLen = Path().smooth(pathx, pathy, pathx.size());
Chris@31 330 return smoothedLen;
Chris@31 331 } else {
Chris@31 332 return pathx.size();
Chris@31 333 }
Chris@30 334 }
Chris@30 335
Chris@30 336