annotate src/Finder.cpp @ 60:faa523be20f9 refactors_no_float

Update both Feeders so as to recognise the end of one input before the other has ended. MatchFeeder does this by detecting trailing silence (as both its inputs are technically the same length since the shorter is zero-padded) and reporting that to Finder. MatchFeatureFeeder simply recognises missing features at the end and won't queue them.
author Chris Cannam
date Fri, 14 Nov 2014 13:53:58 +0000
parents 47f7649ab9d5
children 19a93b15fcc3 ad417dd05e0b 61c7d11ba86d
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@30 261 int x = pm2->getFrameCount() - 1;
Chris@30 262 int y = pm1->getFrameCount() - 1;
Chris@30 263
Chris@60 264 if (duration2 > 0 && duration2 < pm2->getFrameCount()) {
Chris@60 265 x = duration2 - 1;
Chris@60 266 }
Chris@60 267 if (duration1 > 0 && duration1 < pm1->getFrameCount()) {
Chris@60 268 y = duration1 - 1;
Chris@60 269 }
Chris@60 270
Chris@55 271 recalculatePathCostMatrix(0, 0, y, x);
Chris@55 272
Chris@30 273 pathx.clear();
Chris@30 274 pathy.clear();
Chris@30 275
Chris@30 276 while (find(y, x) && ((x > 0) || (y > 0))) {
Chris@30 277
Chris@33 278 // cerr << "x = " << x << ", y = " << y;
Chris@33 279
Chris@30 280 pathx.push_back(x);
Chris@30 281 pathy.push_back(y);
Chris@30 282
Chris@30 283 switch (getDistance() & ADVANCE_BOTH) {
Chris@33 284 case ADVANCE_THIS:
Chris@33 285 // cerr << ", going down (dist = " << (int)getDistance() << ")" << endl;
Chris@33 286 y--;
Chris@33 287 break;
Chris@33 288 case ADVANCE_OTHER:
Chris@33 289 // cerr << ", going left (dist = " << (int)getDistance() << ")" << endl;
Chris@33 290 x--;
Chris@33 291 break;
Chris@33 292 case ADVANCE_BOTH:
Chris@33 293 // cerr << ", going diag (dist = " << (int)getDistance() << ")" << endl;
Chris@33 294 x--;
Chris@33 295 y--;
Chris@33 296 break;
Chris@30 297 default: // this would indicate a bug, but we wouldn't want to hang
Chris@33 298 // cerr << "WARNING: Neither matcher advanced in path backtrack at (" << x << "," << y << ")" << endl;
Chris@33 299 if (x > y) {
Chris@33 300 x--;
Chris@33 301 } else {
Chris@33 302 y--;
Chris@33 303 }
Chris@33 304 break;
Chris@30 305 }
Chris@30 306 }
Chris@30 307
Chris@30 308 std::reverse(pathx.begin(), pathx.end());
Chris@30 309 std::reverse(pathy.begin(), pathy.end());
Chris@30 310
Chris@31 311 if (smooth) {
Chris@31 312 int smoothedLen = Path().smooth(pathx, pathy, pathx.size());
Chris@31 313 return smoothedLen;
Chris@31 314 } else {
Chris@31 315 return pathx.size();
Chris@31 316 }
Chris@30 317 }
Chris@30 318
Chris@30 319