annotate src/Matcher.cpp @ 43:6a5d165e5ea4 refactors

refactor: m_ prefix
author Chris Cannam
date Thu, 13 Nov 2014 13:53:52 +0000
parents 9aec2304b9f6
children a1b7df871496
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 "Matcher.h"
cannam@0 18
cannam@0 19 #include <iostream>
cannam@0 20
cannam@4 21 #include <cstdlib>
Chris@16 22 #include <cassert>
cannam@4 23
Chris@10 24 //#define DEBUG_MATCHER 1
Chris@10 25
Chris@38 26 Matcher::Matcher(Parameters parameters,
Chris@38 27 FeatureExtractor::Parameters feParams,
Chris@38 28 Matcher *p) :
Chris@43 29 m_params(parameters),
Chris@43 30 m_featureExtractor(feParams),
Chris@43 31 m_metric(parameters.distanceNorm)
cannam@0 32 {
Chris@10 33 #ifdef DEBUG_MATCHER
Chris@43 34 cerr << "Matcher::Matcher(" << m_params.sampleRate << ", " << p << ")" << endl;
Chris@10 35 #endif
cannam@0 36
Chris@43 37 m_otherMatcher = p; // the first matcher will need this to be set later
Chris@43 38 m_firstPM = (!p);
Chris@43 39 m_frameCount = 0;
Chris@43 40 m_runCount = 0;
Chris@43 41 m_featureSize = m_featureExtractor.getFeatureSize();
Chris@43 42 m_blockSize = 0;
Chris@23 43
Chris@43 44 m_blockSize = lrint(m_params.blockTime / m_params.hopTime);
Chris@23 45 #ifdef DEBUG_MATCHER
Chris@43 46 cerr << "Matcher: m_blockSize = " << m_blockSize << endl;
Chris@23 47 #endif
Chris@23 48
Chris@43 49 m_initialised = false;
Chris@23 50 }
Chris@23 51
Chris@43 52 Matcher::Matcher(Parameters parameters, Matcher *p, int m_featureSize_) :
Chris@43 53 m_params(parameters),
Chris@43 54 m_featureSize(m_featureSize_),
Chris@43 55 m_featureExtractor(FeatureExtractor::Parameters(m_params.sampleRate, m_params.fftSize)), // unused default config
Chris@43 56 m_metric(parameters.distanceNorm)
Chris@23 57 {
Chris@23 58 #ifdef DEBUG_MATCHER
Chris@43 59 cerr << "Matcher::Matcher(" << m_params.sampleRate << ", " << p << ", " << m_featureSize << ")" << endl;
Chris@23 60 #endif
Chris@23 61
Chris@43 62 m_otherMatcher = p; // the first matcher will need this to be set later
Chris@43 63 m_firstPM = (!p);
Chris@43 64 m_frameCount = 0;
Chris@43 65 m_runCount = 0;
Chris@43 66 m_blockSize = 0;
cannam@0 67
Chris@43 68 m_blockSize = lrint(m_params.blockTime / m_params.hopTime);
Chris@15 69 #ifdef DEBUG_MATCHER
Chris@43 70 cerr << "Matcher: m_blockSize = " << m_blockSize << endl;
Chris@15 71 #endif
cannam@0 72
Chris@43 73 m_initialised = false;
Chris@23 74 }
cannam@0 75
cannam@0 76 Matcher::~Matcher()
cannam@0 77 {
Chris@10 78 #ifdef DEBUG_MATCHER
Chris@15 79 cerr << "Matcher(" << this << ")::~Matcher()" << endl;
Chris@10 80 #endif
cannam@0 81 }
cannam@0 82
cannam@0 83 void
cannam@0 84 Matcher::init()
cannam@0 85 {
Chris@43 86 if (m_initialised) return;
cannam@0 87
Chris@43 88 m_frames = vector<vector<double> >
Chris@43 89 (m_blockSize, vector<double>(m_featureSize, 0));
cannam@0 90
Chris@43 91 m_distXSize = m_blockSize * 2;
Chris@41 92 size();
cannam@0 93
Chris@43 94 m_frameCount = 0;
Chris@43 95 m_runCount = 0;
Chris@38 96
Chris@43 97 m_initialised = true;
Chris@16 98 }
Chris@16 99
cannam@0 100 void
Chris@41 101 Matcher::size()
cannam@0 102 {
Chris@43 103 int distSize = (m_params.maxRunCount + 1) * m_blockSize;
Chris@43 104 m_bestPathCost.resize(m_distXSize, vector<int>(distSize, 0));
Chris@43 105 m_distance.resize(m_distXSize, vector<unsigned char>(distSize, 0));
Chris@43 106 m_distYSizes.resize(m_distXSize, distSize);
Chris@43 107 m_first.resize(m_distXSize, 0);
Chris@43 108 m_last.resize(m_distXSize, 0);
Chris@38 109 }
cannam@0 110
Chris@14 111 vector<double>
Chris@21 112 Matcher::consumeFrame(double *reBuffer, double *imBuffer)
cannam@0 113 {
Chris@43 114 if (!m_initialised) init();
cannam@0 115
Chris@43 116 vector<double> real(reBuffer, reBuffer + m_params.fftSize/2 + 1);
Chris@43 117 vector<double> imag(imBuffer, imBuffer + m_params.fftSize/2 + 1);
Chris@43 118 vector<double> feature = m_featureExtractor.process(real, imag);
Chris@43 119 int frameIndex = m_frameCount % m_blockSize;
Chris@43 120 m_frames[frameIndex] = feature;
Chris@21 121 calcAdvance();
Chris@21 122
Chris@38 123 return feature;
Chris@23 124 }
Chris@21 125
Chris@23 126 void
Chris@23 127 Matcher::consumeFeatureVector(std::vector<double> feature)
Chris@23 128 {
Chris@43 129 if (!m_initialised) init();
Chris@43 130 int frameIndex = m_frameCount % m_blockSize;
Chris@43 131 m_frames[frameIndex] = feature;
Chris@23 132 calcAdvance();
Chris@21 133 }
Chris@21 134
Chris@21 135 void
Chris@21 136 Matcher::calcAdvance()
Chris@21 137 {
Chris@43 138 int frameIndex = m_frameCount % m_blockSize;
Chris@21 139
Chris@43 140 if (m_frameCount >= m_distXSize) {
Chris@43 141 m_distXSize *= 2;
Chris@41 142 size();
cannam@0 143 }
cannam@0 144
Chris@43 145 if (m_firstPM && (m_frameCount >= m_blockSize)) {
cannam@0 146
Chris@43 147 int len = m_last[m_frameCount - m_blockSize] -
Chris@43 148 m_first[m_frameCount - m_blockSize];
cannam@0 149
Chris@43 150 // We need to copy distance[m_frameCount-m_blockSize] to
Chris@43 151 // distance[m_frameCount], and then truncate
Chris@43 152 // distance[m_frameCount-m_blockSize] to its first len elements.
cannam@0 153 // Same for bestPathCost.
cannam@0 154 /*
Chris@43 155 std::cerr << "Matcher(" << this << "): moving " << distYSizes[m_frameCount - m_blockSize] << " from " << m_frameCount - m_blockSize << " to "
Chris@43 156 << m_frameCount << ", allocating " << len << " for "
Chris@43 157 << m_frameCount - m_blockSize << std::endl;
cannam@0 158 */
Chris@43 159 m_distance[m_frameCount] = m_distance[m_frameCount - m_blockSize];
Chris@43 160 m_distance[m_frameCount - m_blockSize].resize(len, 0);
cannam@0 161 for (int i = 0; i < len; ++i) {
Chris@43 162 m_distance[m_frameCount - m_blockSize][i] =
Chris@43 163 m_distance[m_frameCount][i];
cannam@0 164 }
cannam@0 165
Chris@43 166 m_bestPathCost[m_frameCount] = m_bestPathCost[m_frameCount - m_blockSize];
Chris@43 167 m_bestPathCost[m_frameCount - m_blockSize].resize(len, 0);
cannam@0 168 for (int i = 0; i < len; ++i) {
Chris@43 169 m_bestPathCost[m_frameCount - m_blockSize][i] =
Chris@43 170 m_bestPathCost[m_frameCount][i];
cannam@0 171 }
cannam@0 172
Chris@43 173 m_distYSizes[m_frameCount] = m_distYSizes[m_frameCount - m_blockSize];
Chris@43 174 m_distYSizes[m_frameCount - m_blockSize] = len;
cannam@0 175 }
cannam@0 176
Chris@43 177 int stop = m_otherMatcher->m_frameCount;
Chris@43 178 int index = stop - m_blockSize;
cannam@0 179 if (index < 0)
cannam@0 180 index = 0;
Chris@43 181 m_first[m_frameCount] = index;
Chris@43 182 m_last[m_frameCount] = stop;
cannam@0 183
cannam@0 184 bool overflow = false;
cannam@0 185 int mn= -1;
cannam@0 186 int mx= -1;
cannam@0 187 for ( ; index < stop; index++) {
Chris@26 188
Chris@43 189 int dMN = m_metric.calcDistanceScaled
Chris@43 190 (m_frames[frameIndex],
Chris@43 191 m_otherMatcher->m_frames[index % m_blockSize],
Chris@43 192 m_params.distanceScale);
Chris@26 193
cannam@0 194 if (mx<0)
cannam@0 195 mx = mn = dMN;
cannam@0 196 else if (dMN > mx)
cannam@0 197 mx = dMN;
cannam@0 198 else if (dMN < mn)
cannam@0 199 mn = dMN;
cannam@0 200 if (dMN >= 255) {
cannam@0 201 overflow = true;
cannam@0 202 dMN = 255;
cannam@0 203 }
Chris@26 204
Chris@43 205 if ((m_frameCount == 0) && (index == 0)) // first element
cannam@0 206 setValue(0, 0, 0, 0, dMN);
Chris@43 207 else if (m_frameCount == 0) // first row
cannam@0 208 setValue(0, index, ADVANCE_OTHER,
cannam@0 209 getValue(0, index-1, true), dMN);
cannam@0 210 else if (index == 0) // first column
Chris@43 211 setValue(m_frameCount, index, ADVANCE_THIS,
Chris@43 212 getValue(m_frameCount - 1, 0, true), dMN);
Chris@43 213 else if (index == m_otherMatcher->m_frameCount - m_blockSize) {
cannam@0 214 // missing value(s) due to cutoff
cannam@0 215 // - no previous value in current row (resp. column)
cannam@0 216 // - no diagonal value if prev. dir. == curr. dirn
Chris@43 217 int min2 = getValue(m_frameCount - 1, index, true);
Chris@43 218 // if ((m_firstPM && (first[m_frameCount - 1] == index)) ||
Chris@43 219 // (!m_firstPM && (m_last[index-1] < m_frameCount)))
Chris@43 220 if (m_first[m_frameCount - 1] == index)
Chris@43 221 setValue(m_frameCount, index, ADVANCE_THIS, min2, dMN);
cannam@0 222 else {
Chris@43 223 int min1 = getValue(m_frameCount - 1, index - 1, true);
cannam@0 224 if (min1 + dMN <= min2)
Chris@43 225 setValue(m_frameCount, index, ADVANCE_BOTH, min1,dMN);
cannam@0 226 else
Chris@43 227 setValue(m_frameCount, index, ADVANCE_THIS, min2,dMN);
cannam@0 228 }
cannam@0 229 } else {
Chris@43 230 int min1 = getValue(m_frameCount, index-1, true);
Chris@43 231 int min2 = getValue(m_frameCount - 1, index, true);
Chris@43 232 int min3 = getValue(m_frameCount - 1, index-1, true);
cannam@0 233 if (min1 <= min2) {
cannam@0 234 if (min3 + dMN <= min1)
Chris@43 235 setValue(m_frameCount, index, ADVANCE_BOTH, min3,dMN);
cannam@0 236 else
Chris@43 237 setValue(m_frameCount, index, ADVANCE_OTHER,min1,dMN);
cannam@0 238 } else {
cannam@0 239 if (min3 + dMN <= min2)
Chris@43 240 setValue(m_frameCount, index, ADVANCE_BOTH, min3,dMN);
cannam@0 241 else
Chris@43 242 setValue(m_frameCount, index, ADVANCE_THIS, min2,dMN);
cannam@0 243 }
cannam@0 244 }
Chris@43 245 m_otherMatcher->m_last[index]++;
cannam@0 246 } // loop for row (resp. column)
cannam@0 247
Chris@43 248 m_frameCount++;
Chris@43 249 m_runCount++;
cannam@0 250
Chris@43 251 m_otherMatcher->m_runCount = 0;
cannam@0 252
Chris@43 253 if (overflow) {
cannam@0 254 cerr << "WARNING: overflow in distance metric: "
Chris@43 255 << "frame " << m_frameCount << ", val = " << mx << endl;
Chris@43 256 }
Chris@21 257 }
cannam@0 258
cannam@0 259 int
cannam@0 260 Matcher::getValue(int i, int j, bool firstAttempt)
cannam@0 261 {
Chris@43 262 if (m_firstPM)
Chris@43 263 return m_bestPathCost[i][j - m_first[i]];
cannam@0 264 else
Chris@43 265 return m_otherMatcher->m_bestPathCost[j][i - m_otherMatcher->m_first[j]];
cannam@0 266 } // getValue()
cannam@0 267
cannam@0 268 void
cannam@0 269 Matcher::setValue(int i, int j, int dir, int value, int dMN)
cannam@0 270 {
Chris@43 271 if (m_firstPM) {
Chris@43 272 m_distance[i][j - m_first[i]] = (unsigned char)((dMN & MASK) | dir);
Chris@43 273 m_bestPathCost[i][j - m_first[i]] =
cannam@0 274 (value + (dir==ADVANCE_BOTH? dMN*2: dMN));
cannam@0 275 } else {
cannam@0 276 if (dir == ADVANCE_THIS)
cannam@0 277 dir = ADVANCE_OTHER;
cannam@0 278 else if (dir == ADVANCE_OTHER)
cannam@0 279 dir = ADVANCE_THIS;
Chris@43 280 int idx = i - m_otherMatcher->m_first[j];
Chris@43 281 if (idx == (int)m_otherMatcher->m_distYSizes[j]) {
cannam@0 282 // This should never happen, but if we allow arbitrary
cannam@0 283 // pauses in either direction, and arbitrary lengths at
cannam@0 284 // end, it is better than a segmentation fault.
cannam@0 285 std::cerr << "Emergency resize: " << idx << " -> " << idx * 2 << std::endl;
Chris@43 286 m_otherMatcher->m_distYSizes[j] = idx * 2;
Chris@43 287 m_otherMatcher->m_bestPathCost[j].resize(idx * 2, 0);
Chris@43 288 m_otherMatcher->m_distance[j].resize(idx * 2, 0);
cannam@0 289 }
Chris@43 290 m_otherMatcher->m_distance[j][idx] = (unsigned char)((dMN & MASK) | dir);
Chris@43 291 m_otherMatcher->m_bestPathCost[j][idx] =
cannam@0 292 (value + (dir==ADVANCE_BOTH? dMN*2: dMN));
cannam@0 293 }
cannam@0 294 } // setValue()
cannam@0 295