annotate maths/MathUtilities.cpp @ 73:dcb555b90924

* Key detector: when returning key strengths, use the peak value of the three underlying chromagram correlations (from 36-bin chromagram) corresponding to each key, instead of the mean. Rationale: This is the same method as used when returning the key value, and it's nice to have the same results in both returned value and plot. The peak performed better than the sum with a simple test set of triads, so it seems reasonable to change the plot to match the key output rather than the other way around. * FFT: kiss_fftr returns only the non-conjugate bins, synthesise the rest rather than leaving them (perhaps dangerously) undefined. Fixes an uninitialised data error in chromagram that could cause garbage results from key detector. * Constant Q: remove precalculated values again, I reckon they're not proving such a good tradeoff.
author cannam
date Fri, 05 Jun 2009 15:12:39 +0000
parents d72fcd34d9a7
children 054c384d860d
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 QM DSP Library
cannam@0 5
cannam@0 6 Centre for Digital Music, Queen Mary, University of London.
cannam@0 7 This file copyright 2005-2006 Christian Landone.
cannam@0 8 All rights reserved.
cannam@0 9 */
cannam@0 10
cannam@0 11 #include "MathUtilities.h"
cannam@0 12
cannam@0 13 #include <iostream>
cannam@0 14 #include <cmath>
cannam@0 15
cannam@0 16
cannam@0 17 double MathUtilities::mod(double x, double y)
cannam@0 18 {
cannam@0 19 double a = floor( x / y );
cannam@0 20
cannam@0 21 double b = x - ( y * a );
cannam@0 22 return b;
cannam@0 23 }
cannam@0 24
cannam@0 25 double MathUtilities::princarg(double ang)
cannam@0 26 {
cannam@0 27 double ValOut;
cannam@0 28
cannam@0 29 ValOut = mod( ang + M_PI, -2 * M_PI ) + M_PI;
cannam@0 30
cannam@0 31 return ValOut;
cannam@0 32 }
cannam@0 33
cannam@0 34 void MathUtilities::getAlphaNorm(const double *data, unsigned int len, unsigned int alpha, double* ANorm)
cannam@0 35 {
cannam@0 36 unsigned int i;
cannam@0 37 double temp = 0.0;
cannam@0 38 double a=0.0;
cannam@0 39
cannam@0 40 for( i = 0; i < len; i++)
cannam@0 41 {
cannam@0 42 temp = data[ i ];
cannam@0 43
cannam@0 44 a += ::pow( fabs(temp), alpha );
cannam@0 45 }
cannam@0 46 a /= ( double )len;
cannam@0 47 a = ::pow( a, ( 1.0 / (double) alpha ) );
cannam@0 48
cannam@0 49 *ANorm = a;
cannam@0 50 }
cannam@0 51
cannam@0 52 double MathUtilities::getAlphaNorm( const std::vector <double> &data, unsigned int alpha )
cannam@0 53 {
cannam@0 54 unsigned int i;
cannam@0 55 unsigned int len = data.size();
cannam@0 56 double temp = 0.0;
cannam@0 57 double a=0.0;
cannam@0 58
cannam@0 59 for( i = 0; i < len; i++)
cannam@0 60 {
cannam@0 61 temp = data[ i ];
cannam@0 62
cannam@0 63 a += ::pow( fabs(temp), alpha );
cannam@0 64 }
cannam@0 65 a /= ( double )len;
cannam@0 66 a = ::pow( a, ( 1.0 / (double) alpha ) );
cannam@0 67
cannam@0 68 return a;
cannam@0 69 }
cannam@0 70
cannam@0 71 double MathUtilities::round(double x)
cannam@0 72 {
cannam@0 73 double val = (double)floor(x + 0.5);
cannam@0 74
cannam@0 75 return val;
cannam@0 76 }
cannam@0 77
cannam@0 78 double MathUtilities::median(const double *src, unsigned int len)
cannam@0 79 {
cannam@0 80 unsigned int i, j;
cannam@0 81 double tmp = 0.0;
cannam@0 82 double tempMedian;
cannam@0 83 double medianVal;
cannam@0 84
cannam@0 85 double* scratch = new double[ len ];//Vector < double > sortedX = Vector < double > ( size );
cannam@0 86
cannam@0 87 for ( i = 0; i < len; i++ )
cannam@0 88 {
cannam@0 89 scratch[i] = src[i];
cannam@0 90 }
cannam@0 91
cannam@0 92 for ( i = 0; i < len - 1; i++ )
cannam@0 93 {
cannam@0 94 for ( j = 0; j < len - 1 - i; j++ )
cannam@0 95 {
cannam@0 96 if ( scratch[j + 1] < scratch[j] )
cannam@0 97 {
cannam@0 98 // compare the two neighbors
cannam@0 99 tmp = scratch[j]; // swap a[j] and a[j+1]
cannam@0 100 scratch[j] = scratch[j + 1];
cannam@0 101 scratch[j + 1] = tmp;
cannam@0 102 }
cannam@0 103 }
cannam@0 104 }
cannam@0 105 int middle;
cannam@0 106 if ( len % 2 == 0 )
cannam@0 107 {
cannam@0 108 middle = len / 2;
cannam@0 109 tempMedian = ( scratch[middle] + scratch[middle - 1] ) / 2;
cannam@0 110 }
cannam@0 111 else
cannam@0 112 {
cannam@0 113 middle = ( int )floor( len / 2.0 );
cannam@0 114 tempMedian = scratch[middle];
cannam@0 115 }
cannam@0 116
cannam@0 117 medianVal = tempMedian;
cannam@0 118
cannam@0 119 delete [] scratch;
cannam@0 120 return medianVal;
cannam@0 121 }
cannam@0 122
cannam@0 123 double MathUtilities::sum(const double *src, unsigned int len)
cannam@0 124 {
cannam@0 125 unsigned int i ;
cannam@0 126 double retVal =0.0;
cannam@0 127
cannam@0 128 for( i = 0; i < len; i++)
cannam@0 129 {
cannam@0 130 retVal += src[ i ];
cannam@0 131 }
cannam@0 132
cannam@0 133 return retVal;
cannam@0 134 }
cannam@0 135
cannam@0 136 double MathUtilities::mean(const double *src, unsigned int len)
cannam@0 137 {
cannam@0 138 double retVal =0.0;
cannam@0 139
cannam@0 140 double s = sum( src, len );
cannam@0 141
cannam@0 142 retVal = s / (double)len;
cannam@0 143
cannam@0 144 return retVal;
cannam@0 145 }
cannam@0 146
cannam@54 147 double MathUtilities::mean(const std::vector<double> &src,
cannam@54 148 unsigned int start,
cannam@54 149 unsigned int count)
cannam@54 150 {
cannam@54 151 double sum = 0.;
cannam@54 152
cannam@54 153 for (int i = 0; i < count; ++i)
cannam@54 154 {
cannam@54 155 sum += src[start + i];
cannam@54 156 }
cannam@54 157
cannam@54 158 return sum / count;
cannam@54 159 }
cannam@54 160
cannam@0 161 void MathUtilities::getFrameMinMax(const double *data, unsigned int len, double *min, double *max)
cannam@0 162 {
cannam@0 163 unsigned int i;
cannam@0 164 double temp = 0.0;
cannam@0 165 double a=0.0;
cannam@58 166
cannam@58 167 if (len == 0) {
cannam@58 168 *min = *max = 0;
cannam@58 169 return;
cannam@58 170 }
cannam@0 171
cannam@0 172 *min = data[0];
cannam@0 173 *max = data[0];
cannam@0 174
cannam@0 175 for( i = 0; i < len; i++)
cannam@0 176 {
cannam@0 177 temp = data[ i ];
cannam@0 178
cannam@0 179 if( temp < *min )
cannam@0 180 {
cannam@0 181 *min = temp ;
cannam@0 182 }
cannam@0 183 if( temp > *max )
cannam@0 184 {
cannam@0 185 *max = temp ;
cannam@0 186 }
cannam@0 187
cannam@0 188 }
cannam@0 189 }
cannam@7 190
cannam@7 191 int MathUtilities::getMax( double* pData, unsigned int Length, double* pMax )
cannam@7 192 {
cannam@7 193 unsigned int index = 0;
cannam@7 194 unsigned int i;
cannam@7 195 double temp = 0.0;
cannam@7 196
cannam@7 197 double max = pData[0];
cannam@7 198
cannam@7 199 for( i = 0; i < Length; i++)
cannam@7 200 {
cannam@7 201 temp = pData[ i ];
cannam@7 202
cannam@7 203 if( temp > max )
cannam@7 204 {
cannam@7 205 max = temp ;
cannam@7 206 index = i;
cannam@7 207 }
cannam@7 208
cannam@7 209 }
cannam@7 210
cannam@54 211 if (pMax) *pMax = max;
cannam@54 212
cannam@54 213
cannam@54 214 return index;
cannam@54 215 }
cannam@54 216
cannam@54 217 int MathUtilities::getMax( const std::vector<double> & data, double* pMax )
cannam@54 218 {
cannam@54 219 unsigned int index = 0;
cannam@54 220 unsigned int i;
cannam@54 221 double temp = 0.0;
cannam@54 222
cannam@54 223 double max = data[0];
cannam@54 224
cannam@54 225 for( i = 0; i < data.size(); i++)
cannam@54 226 {
cannam@54 227 temp = data[ i ];
cannam@54 228
cannam@54 229 if( temp > max )
cannam@54 230 {
cannam@54 231 max = temp ;
cannam@54 232 index = i;
cannam@54 233 }
cannam@54 234
cannam@54 235 }
cannam@54 236
cannam@54 237 if (pMax) *pMax = max;
cannam@7 238
cannam@7 239
cannam@7 240 return index;
cannam@7 241 }
cannam@7 242
cannam@7 243 void MathUtilities::circShift( double* pData, int length, int shift)
cannam@7 244 {
cannam@7 245 shift = shift % length;
cannam@7 246 double temp;
cannam@7 247 int i,n;
cannam@7 248
cannam@7 249 for( i = 0; i < shift; i++)
cannam@7 250 {
cannam@7 251 temp=*(pData + length - 1);
cannam@7 252
cannam@7 253 for( n = length-2; n >= 0; n--)
cannam@7 254 {
cannam@7 255 *(pData+n+1)=*(pData+n);
cannam@7 256 }
cannam@7 257
cannam@7 258 *pData = temp;
cannam@7 259 }
cannam@7 260 }
cannam@7 261
cannam@7 262 int MathUtilities::compareInt (const void * a, const void * b)
cannam@7 263 {
cannam@7 264 return ( *(int*)a - *(int*)b );
cannam@7 265 }
cannam@7 266
cannam@34 267 void MathUtilities::normalise(double *data, int length, NormaliseType type)
cannam@34 268 {
cannam@34 269 switch (type) {
cannam@34 270
cannam@34 271 case NormaliseNone: return;
cannam@34 272
cannam@34 273 case NormaliseUnitSum:
cannam@34 274 {
cannam@34 275 double sum = 0.0;
cannam@34 276 for (int i = 0; i < length; ++i) {
cannam@34 277 sum += data[i];
cannam@34 278 }
cannam@34 279 if (sum != 0.0) {
cannam@34 280 for (int i = 0; i < length; ++i) {
cannam@34 281 data[i] /= sum;
cannam@34 282 }
cannam@34 283 }
cannam@34 284 }
cannam@34 285 break;
cannam@34 286
cannam@34 287 case NormaliseUnitMax:
cannam@34 288 {
cannam@34 289 double max = 0.0;
cannam@34 290 for (int i = 0; i < length; ++i) {
cannam@34 291 if (fabs(data[i]) > max) {
cannam@34 292 max = fabs(data[i]);
cannam@34 293 }
cannam@34 294 }
cannam@34 295 if (max != 0.0) {
cannam@34 296 for (int i = 0; i < length; ++i) {
cannam@34 297 data[i] /= max;
cannam@34 298 }
cannam@34 299 }
cannam@34 300 }
cannam@34 301 break;
cannam@34 302
cannam@34 303 }
cannam@34 304 }
cannam@34 305
cannam@34 306 void MathUtilities::normalise(std::vector<double> &data, NormaliseType type)
cannam@34 307 {
cannam@34 308 switch (type) {
cannam@34 309
cannam@34 310 case NormaliseNone: return;
cannam@34 311
cannam@34 312 case NormaliseUnitSum:
cannam@34 313 {
cannam@34 314 double sum = 0.0;
cannam@34 315 for (int i = 0; i < data.size(); ++i) sum += data[i];
cannam@34 316 if (sum != 0.0) {
cannam@34 317 for (int i = 0; i < data.size(); ++i) data[i] /= sum;
cannam@34 318 }
cannam@34 319 }
cannam@34 320 break;
cannam@34 321
cannam@34 322 case NormaliseUnitMax:
cannam@34 323 {
cannam@34 324 double max = 0.0;
cannam@34 325 for (int i = 0; i < data.size(); ++i) {
cannam@34 326 if (fabs(data[i]) > max) max = fabs(data[i]);
cannam@34 327 }
cannam@34 328 if (max != 0.0) {
cannam@34 329 for (int i = 0; i < data.size(); ++i) data[i] /= max;
cannam@34 330 }
cannam@34 331 }
cannam@34 332 break;
cannam@34 333
cannam@34 334 }
cannam@34 335 }
cannam@34 336
cannam@54 337 void MathUtilities::adaptiveThreshold(std::vector<double> &data)
cannam@54 338 {
cannam@54 339 int sz = int(data.size());
cannam@54 340 if (sz == 0) return;
cannam@54 341
cannam@54 342 std::vector<double> smoothed(sz);
cannam@54 343
cannam@54 344 int p_pre = 8;
cannam@54 345 int p_post = 7;
cannam@54 346
cannam@54 347 for (int i = 0; i < sz; ++i) {
cannam@54 348
cannam@54 349 int first = std::max(0, i - p_pre);
cannam@54 350 int last = std::min(sz - 1, i + p_post);
cannam@54 351
cannam@54 352 smoothed[i] = mean(data, first, last - first + 1);
cannam@54 353 }
cannam@54 354
cannam@54 355 for (int i = 0; i < sz; i++) {
cannam@54 356 data[i] -= smoothed[i];
cannam@54 357 if (data[i] < 0.0) data[i] = 0.0;
cannam@54 358 }
cannam@54 359 }
cannam@34 360
cannam@55 361 bool
cannam@55 362 MathUtilities::isPowerOfTwo(int x)
cannam@55 363 {
cannam@55 364 if (x < 2) return false;
cannam@55 365 if (x & (x-1)) return false;
cannam@55 366 return true;
cannam@55 367 }
cannam@55 368
cannam@55 369 int
cannam@55 370 MathUtilities::nextPowerOfTwo(int x)
cannam@55 371 {
cannam@55 372 if (isPowerOfTwo(x)) return x;
cannam@55 373 int n = 1;
cannam@55 374 while (x) { x >>= 1; n <<= 1; }
cannam@55 375 return n;
cannam@55 376 }
cannam@55 377
cannam@55 378 int
cannam@55 379 MathUtilities::previousPowerOfTwo(int x)
cannam@55 380 {
cannam@55 381 if (isPowerOfTwo(x)) return x;
cannam@55 382 int n = 1;
cannam@55 383 x >>= 1;
cannam@55 384 while (x) { x >>= 1; n <<= 1; }
cannam@55 385 return n;
cannam@55 386 }
cannam@55 387
cannam@55 388 int
cannam@55 389 MathUtilities::nearestPowerOfTwo(int x)
cannam@55 390 {
cannam@55 391 if (isPowerOfTwo(x)) return x;
cannam@55 392 int n0 = previousPowerOfTwo(x), n1 = nearestPowerOfTwo(x);
cannam@55 393 if (x - n0 < n1 - x) return n0;
cannam@55 394 else return n1;
cannam@55 395 }
cannam@55 396