annotate src/Finder.cpp @ 81:c603d77b00ac refactors

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