annotate src/Finder.cpp @ 70:a130ec8e5eef refactors

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