annotate Finder.cpp @ 31:1ff9ae1dcb50

Make smoothing optional (internally, not exposed as a parameter)
author Chris Cannam
date Fri, 31 Oct 2014 15:54:15 +0000
parents 7784b0a0dd4d
children 333832a6ee5e
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 {
cannam@0 26 if (!p1->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];
cannam@0 34 } // constructor
cannam@0 35
cannam@0 36 Finder::~Finder()
cannam@0 37 {
cannam@0 38 delete[] rowRange;
cannam@0 39 delete[] colRange;
cannam@0 40 }
cannam@0 41
cannam@0 42 bool
cannam@0 43 Finder::find(int i1, int i2)
cannam@0 44 {
cannam@0 45 if (i1 >= 0) {
cannam@0 46 index1 = i1;
cannam@0 47 index2 = i2 - pm1->first[i1];
cannam@0 48 }
cannam@0 49 return (i1 >= 0) && (i2 >= pm1->first[i1]) && (i2 < pm1->last[i1]);
cannam@0 50 } // find()
cannam@0 51
cannam@0 52 void
cannam@0 53 Finder::getColRange(int row, int *range)
cannam@0 54 {
cannam@0 55 range[0] = pm1->first[row];
cannam@0 56 range[1] = pm1->last[row];
cannam@0 57 } // getColRange()
cannam@0 58
cannam@0 59 void
cannam@0 60 Finder::getRowRange(int col, int *range)
cannam@0 61 {
cannam@0 62 range[0] = pm2->first[col];
cannam@0 63 range[1] = pm2->last[col];
cannam@0 64 } // getRowRange()
cannam@0 65
cannam@0 66 int
cannam@0 67 Finder::getExpandDirection(int row, int col)
cannam@0 68 {
cannam@0 69 return getExpandDirection(row, col, false);
cannam@0 70 } // getExpandDirection()
cannam@0 71
cannam@0 72 int
cannam@0 73 Finder::getExpandDirection(int row, int col, bool check)
cannam@0 74 {
cannam@0 75 int min = getPathCost(row, col);
cannam@0 76 bestRow = row;
cannam@0 77 bestCol = col;
cannam@0 78 getRowRange(col, rowRange);
cannam@0 79 if (rowRange[1] > row+1)
cannam@0 80 rowRange[1] = row+1; // don't cheat by looking at future :)
cannam@0 81 for (int index = rowRange[0]; index < rowRange[1]; index++) {
cannam@0 82 int tmp = getPathCost(index, col);
cannam@0 83 if (tmp < min) {
cannam@0 84 min = tmp;
cannam@0 85 bestRow = index;
cannam@0 86 }
cannam@0 87 }
cannam@0 88 getColRange(row, colRange);
cannam@0 89 if (colRange[1] > col+1)
cannam@0 90 colRange[1] = col+1; // don't cheat by looking at future :)
cannam@0 91 for (int index = colRange[0]; index < colRange[1]; index++) {
cannam@0 92 int tmp = getPathCost(row, index);
cannam@0 93 if (tmp < min) {
cannam@0 94 min = tmp;
cannam@0 95 bestCol = index;
cannam@0 96 bestRow = row;
cannam@0 97 }
cannam@0 98 }
cannam@0 99 // System.err.print(" BEST: " + bestRow + " " + bestCol + " " + check);
cannam@0 100 // System.err.println(" " + pm1->frameCount + " " + pm2->frameCount);
cannam@0 101 if (check) {
cannam@0 102 // System.err.println(find(row+1, col) + " " + find(row, col+1));
cannam@0 103 if (!find(row, col+1))
cannam@0 104 return ADVANCE_THIS;
cannam@0 105 if (!find(row+1, col))
cannam@0 106 return ADVANCE_OTHER;
cannam@0 107 }
cannam@0 108 return ((bestRow==row)? ADVANCE_THIS: 0) |
cannam@0 109 ((bestCol==col)? ADVANCE_OTHER: 0);
cannam@0 110
cannam@0 111 } // getExpandDirection()
cannam@0 112
cannam@0 113 unsigned char
cannam@0 114 Finder::getDistance(int row, int col)
cannam@0 115 {
cannam@0 116 if (find(row, col)) {
cannam@0 117 return pm1->distance[row][col - pm1->first[row]];
cannam@0 118 }
cannam@0 119 std::cerr << "getDistance(" << row << "," << col << "): out of bounds" << std::endl;
cannam@0 120 throw "getDistance index out of bounds";
cannam@0 121 } // getDistance()/2
cannam@0 122
cannam@0 123 void
cannam@0 124 Finder::setDistance(int row, int col, unsigned char b)
cannam@0 125 {
cannam@0 126 if (find(row, col)) {
cannam@0 127 pm1->distance[row][col - pm1->first[row]] = b;
cannam@0 128 return;
cannam@0 129 }
cannam@0 130 std::cerr << "setDistance(" << row << "," << col << "," << b << "): out of bounds" << std::endl;
cannam@0 131 throw "setDistance index out of bounds";
cannam@0 132 } // setDistance()
cannam@0 133
cannam@0 134 int
cannam@0 135 Finder::getPathCost(int row, int col)
cannam@0 136 {
cannam@0 137 if (find(row, col)) // "1" avoids div by 0 below
cannam@0 138 return pm1->bestPathCost[row][col - pm1->first[row]]*100/ (1+row+col);
cannam@0 139 std::cerr << "getPathCost(" << row << "," << col << "): out of bounds" << std::endl;
cannam@0 140 throw "getPathCost index out of bounds";
cannam@0 141 } // getPathCost()
cannam@0 142
cannam@0 143 int
cannam@0 144 Finder::getRawPathCost(int row, int col)
cannam@0 145 {
cannam@0 146 if (find(row, col))
cannam@0 147 return pm1->bestPathCost[row][col - pm1->first[row]];
cannam@0 148 std::cerr << "getRawPathCost(" << row << "," << col << "): out of bounds" << std::endl;
cannam@0 149 throw "getRawPathCost index out of bounds";
cannam@0 150 } // getRawPathCost()
cannam@0 151
cannam@0 152 void
cannam@0 153 Finder::setPathCost(int row, int col, int i)
cannam@0 154 {
cannam@0 155 if (find(row, col)) {
cannam@0 156 pm1->bestPathCost[row][col - pm1->first[row]] = i;
cannam@0 157 return;
cannam@0 158 }
cannam@0 159 std::cerr << "setPathCost(" << row << "," << col << "," << i << "): out of bounds" << std::endl;
cannam@0 160 throw "setPathCost index out of bounds";
cannam@0 161 } // setPathCost()
cannam@0 162
cannam@0 163 unsigned char
cannam@0 164 Finder::getDistance()
cannam@0 165 {
cannam@0 166 return pm1->distance[index1][index2];
cannam@0 167 } // getDistance()/0
cannam@0 168
cannam@0 169 void
cannam@0 170 Finder::setDistance(int b)
cannam@0 171 {
cannam@0 172 pm1->distance[index1][index2] = (unsigned char)b;
cannam@0 173 } // setDistance()
cannam@0 174
cannam@0 175 int
cannam@0 176 Finder::getPathCost()
cannam@0 177 {
cannam@0 178 return pm1->bestPathCost[index1][index2];
cannam@0 179 } // getPathCost()
cannam@0 180
cannam@0 181 void
cannam@0 182 Finder::setPathCost(int i)
cannam@0 183 {
cannam@0 184 pm1->bestPathCost[index1][index2] = i;
cannam@0 185 } // setPathCost()
cannam@0 186
cannam@0 187 void
cannam@0 188 Finder::recalculatePathCostMatrix(int r1, int c1, int r2, int c2)
cannam@0 189 {
cannam@0 190 if (!find(r1,c1)) {
cannam@0 191 std::cerr << "recalculatePathCostMatrix(" << r1 << "," << c1 << "): out of bounds" << std::endl;
cannam@0 192 throw "recalculatePathCostMatrix index out of bounds";
cannam@0 193 }
cannam@0 194 int thisRowStart, c;
cannam@0 195 int prevRowStart = 0, prevRowStop = 0;
cannam@0 196 for (int r = r1; r <= r2; r++) {
cannam@0 197 thisRowStart = pm1->first[r];
cannam@0 198 if (thisRowStart < c1)
cannam@0 199 thisRowStart = c1;
cannam@0 200 for (c = thisRowStart; c <= c2; c++) {
cannam@0 201 if (find(r,c)) {
cannam@0 202 int i2 = index2;
cannam@0 203 int newCost = pm1->distance[r][i2];
cannam@0 204 int dir = 0;
cannam@0 205 if (r > r1) { // not first row
cannam@0 206 int min = -1;
cannam@0 207 if ((c > prevRowStart) && (c <= prevRowStop)) {
cannam@0 208 // diagonal from (r-1,c-1)
cannam@0 209 min = pm1->bestPathCost[r-1][c-pm1->first[r-1]-1] +
cannam@0 210 newCost * 2;
cannam@0 211 dir = ADVANCE_BOTH;
cannam@0 212 }
cannam@0 213 if ((c >= prevRowStart) && (c < prevRowStop)) {
cannam@0 214 // vertical from (r-1,c)
cannam@0 215 int cost = pm1->bestPathCost[r-1][c-pm1->first[r-1]] +
cannam@0 216 newCost;
cannam@0 217 if ((min == -1) || (cost < min)) {
cannam@0 218 min = cost;
cannam@0 219 dir = ADVANCE_THIS;
cannam@0 220 }
cannam@0 221 }
cannam@0 222 if (c > thisRowStart) {
cannam@0 223 // horizontal from (r,c-1)
cannam@0 224 int cost =pm1->bestPathCost[r][i2-1]+newCost;
cannam@0 225 if ((min == -1) || (cost < min)) {
cannam@0 226 min = cost;
cannam@0 227 dir = ADVANCE_OTHER;
cannam@0 228 }
cannam@0 229 }
cannam@0 230 pm1->bestPathCost[r][i2] = min;
cannam@0 231 } else if (c > thisRowStart) { // first row
cannam@0 232 // horizontal from (r,c-1)
cannam@0 233 pm1->bestPathCost[r][i2] = pm1->bestPathCost[r][i2-1] +
cannam@0 234 newCost;
cannam@0 235 dir = ADVANCE_OTHER;
cannam@0 236 }
cannam@0 237 if ((r != r1) || (c != c1)) {
cannam@0 238 pm1->distance[r][i2] = (unsigned char)
cannam@0 239 ((pm1->distance[r][i2] & MASK) | dir);
cannam@0 240 }
cannam@0 241 } else
cannam@0 242 break; // end of row
cannam@0 243 }
cannam@0 244 prevRowStart = thisRowStart;
cannam@0 245 prevRowStop = c;
cannam@0 246 }
cannam@0 247 } // recalculatePathCostMatrix()
Chris@30 248
Chris@30 249 int
Chris@31 250 Finder::retrievePath(bool smooth, vector<int> &pathx, vector<int> &pathy)
Chris@30 251 {
Chris@30 252 int x = pm2->getFrameCount() - 1;
Chris@30 253 int y = pm1->getFrameCount() - 1;
Chris@30 254
Chris@30 255 pathx.clear();
Chris@30 256 pathy.clear();
Chris@30 257
Chris@30 258 while (find(y, x) && ((x > 0) || (y > 0))) {
Chris@30 259
Chris@30 260 pathx.push_back(x);
Chris@30 261 pathy.push_back(y);
Chris@30 262
Chris@30 263 switch (getDistance() & ADVANCE_BOTH) {
Chris@30 264 case ADVANCE_THIS: y--; break;
Chris@30 265 case ADVANCE_OTHER: x--; break;
Chris@30 266 case ADVANCE_BOTH: x--; y--; break;
Chris@30 267 default: // this would indicate a bug, but we wouldn't want to hang
Chris@30 268 cerr << "WARNING: Neither matcher advanced in path backtrack at (" << x << "," << y << ")" << endl;
Chris@30 269 if (x > y) x--; else y--; break;
Chris@30 270 }
Chris@30 271 }
Chris@30 272
Chris@30 273 std::reverse(pathx.begin(), pathx.end());
Chris@30 274 std::reverse(pathy.begin(), pathy.end());
Chris@30 275
Chris@31 276 if (smooth) {
Chris@31 277 int smoothedLen = Path().smooth(pathx, pathy, pathx.size());
Chris@31 278 return smoothedLen;
Chris@31 279 } else {
Chris@31 280 return pathx.size();
Chris@31 281 }
Chris@30 282 }
Chris@30 283
Chris@30 284