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
|
cannam@0
|
19
|
cannam@0
|
20 Finder::Finder(Matcher *p1, Matcher *p2)
|
cannam@0
|
21 {
|
cannam@0
|
22 if (!p1->firstPM)
|
cannam@0
|
23 std::cerr << "Warning: wrong args in Finder()" << std::endl;
|
cannam@0
|
24 pm1 = p1;
|
cannam@0
|
25 pm2 = p2;
|
cannam@0
|
26 index1 = 0;
|
cannam@0
|
27 index2 = 0;
|
cannam@0
|
28 rowRange = new int[2];
|
cannam@0
|
29 colRange = new int[2];
|
cannam@0
|
30 } // constructor
|
cannam@0
|
31
|
cannam@0
|
32 Finder::~Finder()
|
cannam@0
|
33 {
|
cannam@0
|
34 delete[] rowRange;
|
cannam@0
|
35 delete[] colRange;
|
cannam@0
|
36 }
|
cannam@0
|
37
|
cannam@0
|
38 bool
|
cannam@0
|
39 Finder::find(int i1, int i2)
|
cannam@0
|
40 {
|
cannam@0
|
41 if (i1 >= 0) {
|
cannam@0
|
42 index1 = i1;
|
cannam@0
|
43 index2 = i2 - pm1->first[i1];
|
cannam@0
|
44 }
|
cannam@0
|
45 return (i1 >= 0) && (i2 >= pm1->first[i1]) && (i2 < pm1->last[i1]);
|
cannam@0
|
46 } // find()
|
cannam@0
|
47
|
cannam@0
|
48 void
|
cannam@0
|
49 Finder::getColRange(int row, int *range)
|
cannam@0
|
50 {
|
cannam@0
|
51 range[0] = pm1->first[row];
|
cannam@0
|
52 range[1] = pm1->last[row];
|
cannam@0
|
53 } // getColRange()
|
cannam@0
|
54
|
cannam@0
|
55 void
|
cannam@0
|
56 Finder::getRowRange(int col, int *range)
|
cannam@0
|
57 {
|
cannam@0
|
58 range[0] = pm2->first[col];
|
cannam@0
|
59 range[1] = pm2->last[col];
|
cannam@0
|
60 } // getRowRange()
|
cannam@0
|
61
|
cannam@0
|
62 int
|
cannam@0
|
63 Finder::getExpandDirection(int row, int col)
|
cannam@0
|
64 {
|
cannam@0
|
65 return getExpandDirection(row, col, false);
|
cannam@0
|
66 } // getExpandDirection()
|
cannam@0
|
67
|
cannam@0
|
68 int
|
cannam@0
|
69 Finder::getExpandDirection(int row, int col, bool check)
|
cannam@0
|
70 {
|
cannam@0
|
71 int min = getPathCost(row, col);
|
cannam@0
|
72 bestRow = row;
|
cannam@0
|
73 bestCol = col;
|
cannam@0
|
74 getRowRange(col, rowRange);
|
cannam@0
|
75 if (rowRange[1] > row+1)
|
cannam@0
|
76 rowRange[1] = row+1; // don't cheat by looking at future :)
|
cannam@0
|
77 for (int index = rowRange[0]; index < rowRange[1]; index++) {
|
cannam@0
|
78 int tmp = getPathCost(index, col);
|
cannam@0
|
79 if (tmp < min) {
|
cannam@0
|
80 min = tmp;
|
cannam@0
|
81 bestRow = index;
|
cannam@0
|
82 }
|
cannam@0
|
83 }
|
cannam@0
|
84 getColRange(row, colRange);
|
cannam@0
|
85 if (colRange[1] > col+1)
|
cannam@0
|
86 colRange[1] = col+1; // don't cheat by looking at future :)
|
cannam@0
|
87 for (int index = colRange[0]; index < colRange[1]; index++) {
|
cannam@0
|
88 int tmp = getPathCost(row, index);
|
cannam@0
|
89 if (tmp < min) {
|
cannam@0
|
90 min = tmp;
|
cannam@0
|
91 bestCol = index;
|
cannam@0
|
92 bestRow = row;
|
cannam@0
|
93 }
|
cannam@0
|
94 }
|
cannam@0
|
95 // System.err.print(" BEST: " + bestRow + " " + bestCol + " " + check);
|
cannam@0
|
96 // System.err.println(" " + pm1->frameCount + " " + pm2->frameCount);
|
cannam@0
|
97 if (check) {
|
cannam@0
|
98 // System.err.println(find(row+1, col) + " " + find(row, col+1));
|
cannam@0
|
99 if (!find(row, col+1))
|
cannam@0
|
100 return ADVANCE_THIS;
|
cannam@0
|
101 if (!find(row+1, col))
|
cannam@0
|
102 return ADVANCE_OTHER;
|
cannam@0
|
103 }
|
cannam@0
|
104 return ((bestRow==row)? ADVANCE_THIS: 0) |
|
cannam@0
|
105 ((bestCol==col)? ADVANCE_OTHER: 0);
|
cannam@0
|
106
|
cannam@0
|
107 } // getExpandDirection()
|
cannam@0
|
108
|
cannam@0
|
109 unsigned char
|
cannam@0
|
110 Finder::getDistance(int row, int col)
|
cannam@0
|
111 {
|
cannam@0
|
112 if (find(row, col)) {
|
cannam@0
|
113 return pm1->distance[row][col - pm1->first[row]];
|
cannam@0
|
114 }
|
cannam@0
|
115 std::cerr << "getDistance(" << row << "," << col << "): out of bounds" << std::endl;
|
cannam@0
|
116 throw "getDistance index out of bounds";
|
cannam@0
|
117 } // getDistance()/2
|
cannam@0
|
118
|
cannam@0
|
119 void
|
cannam@0
|
120 Finder::setDistance(int row, int col, unsigned char b)
|
cannam@0
|
121 {
|
cannam@0
|
122 if (find(row, col)) {
|
cannam@0
|
123 pm1->distance[row][col - pm1->first[row]] = b;
|
cannam@0
|
124 return;
|
cannam@0
|
125 }
|
cannam@0
|
126 std::cerr << "setDistance(" << row << "," << col << "," << b << "): out of bounds" << std::endl;
|
cannam@0
|
127 throw "setDistance index out of bounds";
|
cannam@0
|
128 } // setDistance()
|
cannam@0
|
129
|
cannam@0
|
130 int
|
cannam@0
|
131 Finder::getPathCost(int row, int col)
|
cannam@0
|
132 {
|
cannam@0
|
133 if (find(row, col)) // "1" avoids div by 0 below
|
cannam@0
|
134 return pm1->bestPathCost[row][col - pm1->first[row]]*100/ (1+row+col);
|
cannam@0
|
135 std::cerr << "getPathCost(" << row << "," << col << "): out of bounds" << std::endl;
|
cannam@0
|
136 throw "getPathCost index out of bounds";
|
cannam@0
|
137 } // getPathCost()
|
cannam@0
|
138
|
cannam@0
|
139 int
|
cannam@0
|
140 Finder::getRawPathCost(int row, int col)
|
cannam@0
|
141 {
|
cannam@0
|
142 if (find(row, col))
|
cannam@0
|
143 return pm1->bestPathCost[row][col - pm1->first[row]];
|
cannam@0
|
144 std::cerr << "getRawPathCost(" << row << "," << col << "): out of bounds" << std::endl;
|
cannam@0
|
145 throw "getRawPathCost index out of bounds";
|
cannam@0
|
146 } // getRawPathCost()
|
cannam@0
|
147
|
cannam@0
|
148 void
|
cannam@0
|
149 Finder::setPathCost(int row, int col, int i)
|
cannam@0
|
150 {
|
cannam@0
|
151 if (find(row, col)) {
|
cannam@0
|
152 pm1->bestPathCost[row][col - pm1->first[row]] = i;
|
cannam@0
|
153 return;
|
cannam@0
|
154 }
|
cannam@0
|
155 std::cerr << "setPathCost(" << row << "," << col << "," << i << "): out of bounds" << std::endl;
|
cannam@0
|
156 throw "setPathCost index out of bounds";
|
cannam@0
|
157 } // setPathCost()
|
cannam@0
|
158
|
cannam@0
|
159 unsigned char
|
cannam@0
|
160 Finder::getDistance()
|
cannam@0
|
161 {
|
cannam@0
|
162 return pm1->distance[index1][index2];
|
cannam@0
|
163 } // getDistance()/0
|
cannam@0
|
164
|
cannam@0
|
165 void
|
cannam@0
|
166 Finder::setDistance(int b)
|
cannam@0
|
167 {
|
cannam@0
|
168 pm1->distance[index1][index2] = (unsigned char)b;
|
cannam@0
|
169 } // setDistance()
|
cannam@0
|
170
|
cannam@0
|
171 int
|
cannam@0
|
172 Finder::getPathCost()
|
cannam@0
|
173 {
|
cannam@0
|
174 return pm1->bestPathCost[index1][index2];
|
cannam@0
|
175 } // getPathCost()
|
cannam@0
|
176
|
cannam@0
|
177 void
|
cannam@0
|
178 Finder::setPathCost(int i)
|
cannam@0
|
179 {
|
cannam@0
|
180 pm1->bestPathCost[index1][index2] = i;
|
cannam@0
|
181 } // setPathCost()
|
cannam@0
|
182
|
cannam@0
|
183 void
|
cannam@0
|
184 Finder::recalculatePathCostMatrix(int r1, int c1, int r2, int c2)
|
cannam@0
|
185 {
|
cannam@0
|
186 if (!find(r1,c1)) {
|
cannam@0
|
187 std::cerr << "recalculatePathCostMatrix(" << r1 << "," << c1 << "): out of bounds" << std::endl;
|
cannam@0
|
188 throw "recalculatePathCostMatrix index out of bounds";
|
cannam@0
|
189 }
|
cannam@0
|
190 int thisRowStart, c;
|
cannam@0
|
191 int prevRowStart = 0, prevRowStop = 0;
|
cannam@0
|
192 for (int r = r1; r <= r2; r++) {
|
cannam@0
|
193 thisRowStart = pm1->first[r];
|
cannam@0
|
194 if (thisRowStart < c1)
|
cannam@0
|
195 thisRowStart = c1;
|
cannam@0
|
196 for (c = thisRowStart; c <= c2; c++) {
|
cannam@0
|
197 if (find(r,c)) {
|
cannam@0
|
198 int i2 = index2;
|
cannam@0
|
199 int newCost = pm1->distance[r][i2];
|
cannam@0
|
200 int dir = 0;
|
cannam@0
|
201 if (r > r1) { // not first row
|
cannam@0
|
202 int min = -1;
|
cannam@0
|
203 if ((c > prevRowStart) && (c <= prevRowStop)) {
|
cannam@0
|
204 // diagonal from (r-1,c-1)
|
cannam@0
|
205 min = pm1->bestPathCost[r-1][c-pm1->first[r-1]-1] +
|
cannam@0
|
206 newCost * 2;
|
cannam@0
|
207 dir = ADVANCE_BOTH;
|
cannam@0
|
208 }
|
cannam@0
|
209 if ((c >= prevRowStart) && (c < prevRowStop)) {
|
cannam@0
|
210 // vertical from (r-1,c)
|
cannam@0
|
211 int cost = pm1->bestPathCost[r-1][c-pm1->first[r-1]] +
|
cannam@0
|
212 newCost;
|
cannam@0
|
213 if ((min == -1) || (cost < min)) {
|
cannam@0
|
214 min = cost;
|
cannam@0
|
215 dir = ADVANCE_THIS;
|
cannam@0
|
216 }
|
cannam@0
|
217 }
|
cannam@0
|
218 if (c > thisRowStart) {
|
cannam@0
|
219 // horizontal from (r,c-1)
|
cannam@0
|
220 int cost =pm1->bestPathCost[r][i2-1]+newCost;
|
cannam@0
|
221 if ((min == -1) || (cost < min)) {
|
cannam@0
|
222 min = cost;
|
cannam@0
|
223 dir = ADVANCE_OTHER;
|
cannam@0
|
224 }
|
cannam@0
|
225 }
|
cannam@0
|
226 pm1->bestPathCost[r][i2] = min;
|
cannam@0
|
227 } else if (c > thisRowStart) { // first row
|
cannam@0
|
228 // horizontal from (r,c-1)
|
cannam@0
|
229 pm1->bestPathCost[r][i2] = pm1->bestPathCost[r][i2-1] +
|
cannam@0
|
230 newCost;
|
cannam@0
|
231 dir = ADVANCE_OTHER;
|
cannam@0
|
232 }
|
cannam@0
|
233 if ((r != r1) || (c != c1)) {
|
cannam@0
|
234 pm1->distance[r][i2] = (unsigned char)
|
cannam@0
|
235 ((pm1->distance[r][i2] & MASK) | dir);
|
cannam@0
|
236 }
|
cannam@0
|
237 } else
|
cannam@0
|
238 break; // end of row
|
cannam@0
|
239 }
|
cannam@0
|
240 prevRowStart = thisRowStart;
|
cannam@0
|
241 prevRowStop = c;
|
cannam@0
|
242 }
|
cannam@0
|
243 } // recalculatePathCostMatrix()
|