annotate plugins/AdaptiveSpectrogram.cpp @ 92:3602e755b696

* Add the Adaptive Spectrogram plugin -- but it isn't working correctly yet. Also, when it does work, it will need to be refactored out into the qm-dsp library
author Chris Cannam <c.cannam@qmul.ac.uk>
date Fri, 27 Feb 2009 10:45:10 +0000
parents
children 385bec9df059
rev   line source
c@92 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
c@92 2
c@92 3 /*
c@92 4 QM Vamp Plugin Set
c@92 5
c@92 6 Centre for Digital Music, Queen Mary, University of London.
c@92 7 All rights reserved.
c@92 8 */
c@92 9
c@92 10 #include "AdaptiveSpectrogram.h"
c@92 11
c@92 12 #include <cstdlib>
c@92 13 #include <cstring>
c@92 14
c@92 15 #include <iostream>
c@92 16
c@92 17 #include <dsp/transforms/FFT.h>
c@92 18
c@92 19 using std::string;
c@92 20 using std::vector;
c@92 21 using std::cerr;
c@92 22 using std::endl;
c@92 23
c@92 24 using Vamp::RealTime;
c@92 25
c@92 26 AdaptiveSpectrogram::AdaptiveSpectrogram(float inputSampleRate) :
c@92 27 Plugin(inputSampleRate),
c@92 28 m_w(9),
c@92 29 m_n(2)
c@92 30 {
c@92 31 }
c@92 32
c@92 33 AdaptiveSpectrogram::~AdaptiveSpectrogram()
c@92 34 {
c@92 35 }
c@92 36
c@92 37 string
c@92 38 AdaptiveSpectrogram::getIdentifier() const
c@92 39 {
c@92 40 return "adaptivespectrogram";
c@92 41 }
c@92 42
c@92 43 string
c@92 44 AdaptiveSpectrogram::getName() const
c@92 45 {
c@92 46 return "Adaptive Spectrogram";
c@92 47 }
c@92 48
c@92 49 string
c@92 50 AdaptiveSpectrogram::getDescription() const
c@92 51 {
c@92 52 return "Produce an adaptive spectrogram by adaptive selection from spectrograms at multiple resolutions";
c@92 53 }
c@92 54
c@92 55 string
c@92 56 AdaptiveSpectrogram::getMaker() const
c@92 57 {
c@92 58 return "Queen Mary, University of London";
c@92 59 }
c@92 60
c@92 61 int
c@92 62 AdaptiveSpectrogram::getPluginVersion() const
c@92 63 {
c@92 64 return 1;
c@92 65 }
c@92 66
c@92 67 string
c@92 68 AdaptiveSpectrogram::getCopyright() const
c@92 69 {
c@92 70 return "Plugin by Wen Xue and Chris Cannam. Copyright (c) 2009 Wen Xue and QMUL - All Rights Reserved";
c@92 71 }
c@92 72
c@92 73 size_t
c@92 74 AdaptiveSpectrogram::getPreferredStepSize() const
c@92 75 {
c@92 76 return ((2 << m_w) << m_n) / 2;
c@92 77 }
c@92 78
c@92 79 size_t
c@92 80 AdaptiveSpectrogram::getPreferredBlockSize() const
c@92 81 {
c@92 82 return (2 << m_w) << m_n;
c@92 83 }
c@92 84
c@92 85 bool
c@92 86 AdaptiveSpectrogram::initialise(size_t channels, size_t stepSize, size_t blockSize)
c@92 87 {
c@92 88 if (channels < getMinChannelCount() ||
c@92 89 channels > getMaxChannelCount()) return false;
c@92 90
c@92 91 return true;
c@92 92 }
c@92 93
c@92 94 void
c@92 95 AdaptiveSpectrogram::reset()
c@92 96 {
c@92 97
c@92 98 }
c@92 99
c@92 100 AdaptiveSpectrogram::ParameterList
c@92 101 AdaptiveSpectrogram::getParameterDescriptors() const
c@92 102 {
c@92 103 ParameterList list;
c@92 104
c@92 105 ParameterDescriptor desc;
c@92 106 desc.identifier = "n";
c@92 107 desc.name = "Number of resolutions";
c@92 108 desc.description = "Number of consecutive powers of two to use as spectrogram resolutions, starting with the minimum resolution specified";
c@92 109 desc.unit = "";
c@92 110 desc.minValue = 1;
c@92 111 desc.maxValue = 10;
c@92 112 desc.defaultValue = 3;
c@92 113 desc.isQuantized = true;
c@92 114 desc.quantizeStep = 1;
c@92 115 list.push_back(desc);
c@92 116
c@92 117 ParameterDescriptor desc2;
c@92 118 desc2.identifier = "w";
c@92 119 desc2.name = "Smallest resolution";
c@92 120 desc2.description = "Smallest of the consecutive powers of two to use as spectrogram resolutions";
c@92 121 desc2.unit = "";
c@92 122 desc2.minValue = 1;
c@92 123 desc2.maxValue = 14;
c@92 124 desc2.defaultValue = 10;
c@92 125 desc2.isQuantized = true;
c@92 126 desc2.quantizeStep = 1;
c@92 127 // I am so lazy
c@92 128 desc2.valueNames.push_back("2");
c@92 129 desc2.valueNames.push_back("4");
c@92 130 desc2.valueNames.push_back("8");
c@92 131 desc2.valueNames.push_back("16");
c@92 132 desc2.valueNames.push_back("32");
c@92 133 desc2.valueNames.push_back("64");
c@92 134 desc2.valueNames.push_back("128");
c@92 135 desc2.valueNames.push_back("256");
c@92 136 desc2.valueNames.push_back("512");
c@92 137 desc2.valueNames.push_back("1024");
c@92 138 desc2.valueNames.push_back("2048");
c@92 139 desc2.valueNames.push_back("4096");
c@92 140 desc2.valueNames.push_back("8192");
c@92 141 desc2.valueNames.push_back("16384");
c@92 142 list.push_back(desc2);
c@92 143
c@92 144 return list;
c@92 145 }
c@92 146
c@92 147 float
c@92 148 AdaptiveSpectrogram::getParameter(std::string id) const
c@92 149 {
c@92 150 if (id == "n") return m_n+1;
c@92 151 else if (id == "w") return m_w+1;
c@92 152 return 0.f;
c@92 153 }
c@92 154
c@92 155 void
c@92 156 AdaptiveSpectrogram::setParameter(std::string id, float value)
c@92 157 {
c@92 158 if (id == "n") {
c@92 159 int n = lrintf(value);
c@92 160 if (n >= 1 && n <= 10) m_n = n-1;
c@92 161 } else if (id == "w") {
c@92 162 int w = lrintf(value);
c@92 163 if (w >= 1 && w <= 14) m_w = w-1;
c@92 164 }
c@92 165 }
c@92 166
c@92 167 AdaptiveSpectrogram::OutputList
c@92 168 AdaptiveSpectrogram::getOutputDescriptors() const
c@92 169 {
c@92 170 OutputList list;
c@92 171
c@92 172 OutputDescriptor d;
c@92 173 d.identifier = "output";
c@92 174 d.name = "Output";
c@92 175 d.description = "The output of the plugin";
c@92 176 d.unit = "";
c@92 177 d.hasFixedBinCount = true;
c@92 178 d.binCount = ((2 << m_w) << m_n) / 2;
c@92 179 d.hasKnownExtents = false;
c@92 180 d.isQuantized = false;
c@92 181 d.sampleType = OutputDescriptor::FixedSampleRate;
c@92 182 d.sampleRate = m_inputSampleRate / ((2 << m_w) / 2);
c@92 183 d.hasDuration = false;
c@92 184 list.push_back(d);
c@92 185
c@92 186 return list;
c@92 187 }
c@92 188
c@92 189 AdaptiveSpectrogram::FeatureSet
c@92 190 AdaptiveSpectrogram::getRemainingFeatures()
c@92 191 {
c@92 192 FeatureSet fs;
c@92 193 return fs;
c@92 194 }
c@92 195
c@92 196 AdaptiveSpectrogram::FeatureSet
c@92 197 AdaptiveSpectrogram::process(const float *const *inputBuffers, RealTime ts)
c@92 198 {
c@92 199 FeatureSet fs;
c@92 200
c@92 201 int wid = (2 << m_w), WID = ((2 << m_w) << m_n);
c@92 202 int Res = log2(WID/wid)+1;
c@92 203 double ***specs = new double **[Res];
c@92 204 int Wid = WID;
c@92 205 int wi = 0;
c@92 206
c@92 207 cerr << "wid = " << wid << ", WID = " << WID << endl;
c@92 208
c@92 209 double *tmpin = new double[WID];
c@92 210 double *tmprout = new double[WID];
c@92 211 double *tmpiout = new double[WID];
c@92 212
c@92 213 while (Wid >= wid) {
c@92 214 specs[wi] = new double *[WID/Wid];
c@92 215 for (int i = 0; i < WID/Wid; ++i) {
c@92 216 specs[wi][i] = new double[Wid/2];
c@92 217 int origin = WID/4 - Wid/4; // for 50% overlap
c@92 218 for (int j = 0; j < Wid; ++j) {
c@92 219 double mul = 0.50 - 0.50 * cos((2 * M_PI * j) / Wid);
c@92 220 tmpin[j] = inputBuffers[0][origin + i * Wid/2 + j] * mul;
c@92 221 }
c@92 222 FFT::process(Wid, false, tmpin, 0, tmprout, tmpiout);
c@92 223 for (int j = 0; j < Wid/2; ++j) {
c@92 224 double mag =
c@92 225 tmprout[j] * tmprout[j] +
c@92 226 tmpiout[j] * tmpiout[j];
c@92 227 specs[wi][i][j] = sqrt(mag) / Wid;
c@92 228 }
c@92 229 }
c@92 230 Wid /= 2;
c@92 231 ++wi;
c@92 232 }
c@92 233
c@92 234 int *spl = new int[WID/2];
c@92 235 double *spec = new double[WID/2];
c@92 236
c@92 237 // This prefill makes it easy to see which elements are actually
c@92 238 // set by the MixSpectrogramBlock2 call. Turns out that, with
c@92 239 // 1024, 2048 and 4096 as our widths, the spl array has elements
c@92 240 // 0-4094 (incl) filled in and the spec array has elements 0-4095
c@92 241
c@92 242 for (int i = 0; i < WID/2; ++i) {
c@92 243 spl[i] = i;
c@92 244 spec[i] = i;
c@92 245 }
c@92 246
c@92 247 MixSpectrogramBlock2(spl, spec, specs, WID/2, wid/2, false);
c@92 248
c@92 249 Wid = WID;
c@92 250 wi = 0;
c@92 251 while (Wid >= wid) {
c@92 252 for (int i = 0; i < WID/Wid; ++i) {
c@92 253 delete[] specs[wi][i];
c@92 254 }
c@92 255 delete[] specs[wi];
c@92 256 Wid /= 2;
c@92 257 ++wi;
c@92 258 }
c@92 259 delete[] specs;
c@92 260
c@92 261 std::cerr << "Results at " << ts << ":" << std::endl;
c@92 262 /* for (int i = 0; i < WID/2; ++i) {
c@92 263 if (spl[i] == i || spec[i] == i) {
c@92 264 std::cerr << "\n***\n";
c@92 265 }
c@92 266 std::cerr << "[" << i << "] " << spl[i] << "," << spec[i] << " ";
c@92 267 }
c@92 268 std::cerr << std::endl;
c@92 269 */
c@92 270 vector<vector<float> > rmat(WID/wid);
c@92 271 for (int i = 0; i < WID/wid; ++i) {
c@92 272 rmat[i] = vector<float>(WID/2);
c@92 273 }
c@92 274
c@92 275 int y = 0, h = WID/2;
c@92 276 int x = 0, w = WID/wid;
c@92 277 unpackResultMatrix(rmat, x, y, w, h, spl, spec, WID/2, WID);
c@92 278
c@92 279 delete[] spec;
c@92 280 delete[] spl;
c@92 281
c@92 282 for (int i = 0; i < rmat.size(); ++i) {
c@92 283 Feature f;
c@92 284 f.hasTimestamp = false;
c@92 285 f.values = rmat[i];
c@92 286 fs[0].push_back(f);
c@92 287 }
c@92 288
c@92 289 /*
c@92 290 if (m_stepSize == 0) {
c@92 291 cerr << "ERROR: AdaptiveSpectrogram::process: "
c@92 292 << "AdaptiveSpectrogram has not been initialised"
c@92 293 << endl;
c@92 294 return fs;
c@92 295 }
c@92 296 */
c@92 297 return fs;
c@92 298 }
c@92 299
c@92 300 void
c@92 301 AdaptiveSpectrogram::unpackResultMatrix(vector<vector<float> > &rmat,
c@92 302 int x, int y, int w, int h,
c@92 303 int *spl,
c@92 304 double *spec, int sz,
c@92 305 int res
c@92 306 )
c@92 307 {
c@92 308
c@92 309 cerr << "x = " << x << ", y = " << y << ", w = " << w << ", h = " << h
c@92 310 << ", sz = " << sz << ", *spl = " << *spl << ", *spec = " << *spec << ", res = " << res << endl;
c@92 311
c@92 312 if (sz <= 1) {
c@92 313
c@92 314 for (int i = 0; i < w; ++i) {
c@92 315 for (int j = 0; j < h; ++j) {
c@92 316 // rmat[x+i][y+j] = (off ? 0 : *spec);
c@92 317 if (rmat[x+i][y+j] != 0) {
c@92 318 cerr << "WARNING: Overwriting value " << rmat[x+i][y+j]
c@92 319 << " with " << res + i + j << " at " << x+i << "," << y+j << endl;
c@92 320 }
c@92 321 // cerr << "[" << x+i << "][" << y+j << "] <= " << res+i+j << endl;
c@92 322 rmat[x+i][y+j] = *spec;
c@92 323 }
c@92 324 }
c@92 325
c@92 326 // cerr << " (done)" << endl;
c@92 327 return;
c@92 328 }
c@92 329 // cerr << endl;
c@92 330
c@92 331 if (*spl == 0) {
c@92 332
c@92 333 unpackResultMatrix(rmat,
c@92 334 x, y,
c@92 335 w, h/2,
c@92 336 spl + 1,
c@92 337 spec,
c@92 338 sz/2,
c@92 339 res);
c@92 340
c@92 341 unpackResultMatrix(rmat,
c@92 342 x, y + h/2,
c@92 343 w, h/2,
c@92 344 spl + sz/2,
c@92 345 spec + sz/2,
c@92 346 sz/2,
c@92 347 res);
c@92 348
c@92 349 } else if (*spl == 1) {
c@92 350
c@92 351 unpackResultMatrix(rmat,
c@92 352 x, y,
c@92 353 w/2, h,
c@92 354 spl + 1,
c@92 355 spec,
c@92 356 sz/2,
c@92 357 res/2);
c@92 358
c@92 359 unpackResultMatrix(rmat,
c@92 360 x + w/2, y,
c@92 361 w/2, h,
c@92 362 spl + sz/2,
c@92 363 spec + sz/2,
c@92 364 sz/2,
c@92 365 res/2);
c@92 366
c@92 367 } else {
c@92 368 cerr << "ERROR: *spl = " << *spl << endl;
c@92 369 }
c@92 370 }
c@92 371
c@92 372 //spl[Y-1]
c@92 373 //Specs[R0][x0:x0+x-1][Y0:Y0+Y-1]
c@92 374 //Specs[R0+1][2x0:2x0+2x-1][Y0/2:Y0/2+Y/2-1]
c@92 375 //...
c@92 376 //Specs[R0+?][Nx0:Nx0+Nx-1][Y0/N:Y0/N+Y/N-1]
c@92 377 //N=WID/wid
c@92 378
c@92 379 /**
c@92 380 * DoCutSpectrogramBlock2 finds the optimal "cutting" and returns it in spl.
c@92 381 */
c@92 382 double
c@92 383 AdaptiveSpectrogram::DoCutSpectrogramBlock2(int* spl, double*** Specs, int Y, int R0,
c@92 384 int x0, int Y0, int N, double& ene)
c@92 385 {
c@92 386 double ent = 0;
c@92 387
c@92 388 if (Y > N) {
c@92 389
c@92 390 spl[0] = 0;
c@92 391 double ene1, ene2;
c@92 392
c@92 393 ent += DoCutSpectrogramBlock2
c@92 394 (&spl[1], Specs, Y/2, R0, x0, Y0, N, ene1);
c@92 395
c@92 396 ent += DoCutSpectrogramBlock2
c@92 397 (&spl[Y/2], Specs, Y/2, R0, x0, Y0+Y/2, N, ene2);
c@92 398
c@92 399 ene = ene1+ene2;
c@92 400
c@92 401 } else if (N == 1) {
c@92 402
c@92 403 double tmp = Specs[R0][x0][Y0];
c@92 404 ene = tmp;
c@92 405 ent = xlogx(tmp);
c@92 406
c@92 407 } else {
c@92 408 // Y == N, the square case
c@92 409
c@92 410 double enel, ener, enet, eneb, entl, entr, entt, entb;
c@92 411 int* tmpspl = new int[Y];
c@92 412
c@92 413 entl = DoCutSpectrogramBlock2
c@92 414 (&spl[1], Specs, Y/2, R0+1, 2*x0, Y0/2, N/2, enel);
c@92 415
c@92 416 entr = DoCutSpectrogramBlock2
c@92 417 (&spl[Y/2], Specs, Y/2, R0+1, 2*x0+1, Y0/2, N/2, ener);
c@92 418
c@92 419 entb = DoCutSpectrogramBlock2
c@92 420 (&tmpspl[1], Specs, Y/2, R0, x0, Y0, N/2, eneb);
c@92 421
c@92 422 entt = DoCutSpectrogramBlock2
c@92 423 (&tmpspl[Y/2], Specs, Y/2, R0, x0, Y0+Y/2, N/2, enet);
c@92 424
c@92 425 double
c@92 426 ene0 = enet + eneb,
c@92 427 ene1 = enel + ener,
c@92 428 ent0 = entt + entb,
c@92 429 ent1 = entl + entr;
c@92 430
c@92 431 // normalize
c@92 432
c@92 433 double eneres = 1 - (ene0+ene1)/2, norment0, norment1;
c@92 434 double a0 = 1 / (ene0+eneres), a1 = 1 / (ene1+eneres);
c@92 435
c@92 436 // quasi-global normalization
c@92 437
c@92 438 norment0 = (ent0 - ene0 * log(ene0+eneres)) / (ene0+eneres);
c@92 439 norment1 = (ent1 - ene1 * log(ene1+eneres)) / (ene1+eneres);
c@92 440
c@92 441 // local normalization
c@92 442
c@92 443 if (norment1 < norment0) {
c@92 444 spl[0] = 0;
c@92 445 ent = ent0, ene = ene0;
c@92 446 memcpy(&spl[1], &tmpspl[1], sizeof(int)*(Y-2));
c@92 447 } else {
c@92 448 spl[0] = 1;
c@92 449 ent = ent1, ene = ene1;
c@92 450 }
c@92 451 }
c@92 452 return ent;
c@92 453 }
c@92 454
c@92 455 /**
c@92 456 * DoMixSpectrogramBlock2 collects values from the multiple
c@92 457 * spectrograms Specs into a linear array Spec.
c@92 458 */
c@92 459 double
c@92 460 AdaptiveSpectrogram::DoMixSpectrogramBlock2(int* spl, double* Spec, double*** Specs, int Y,
c@92 461 int R0, int x0, int Y0, bool normmix, int res,
c@92 462 double* e)
c@92 463 {
c@92 464 if (Y == 1) {
c@92 465
c@92 466 Spec[0] = Specs[R0][x0][Y0]*e[0];
c@92 467
c@92 468 } else {
c@92 469
c@92 470 double le[32];
c@92 471
c@92 472 if (normmix && Y < (1<<res)) {
c@92 473
c@92 474 for (int i = 0, j = 1, k = Y;
c@92 475 i < res;
c@92 476 i++, j *= 2, k /= 2) {
c@92 477
c@92 478 double lle = 0;
c@92 479
c@92 480 for (int fr = 0; fr < j; fr++) {
c@92 481 for (int n = 0; n < k; n++) {
c@92 482 lle +=
c@92 483 Specs[i+R0][x0+fr][Y0+n] *
c@92 484 Specs[i+R0][x0+fr][Y0+n];
c@92 485 }
c@92 486 }
c@92 487
c@92 488 lle = sqrt(lle)*e[i];
c@92 489
c@92 490 if (i == 0) {
c@92 491 le[0] = lle;
c@92 492 } else if (lle > le[0]*2) {
c@92 493 le[i] = e[i]*le[0]*2/lle;
c@92 494 } else {
c@92 495 le[i] = e[i];
c@92 496 }
c@92 497 }
c@92 498
c@92 499 le[0] = e[0];
c@92 500
c@92 501 } else {
c@92 502
c@92 503 memcpy(le, e, sizeof(double)*res);
c@92 504 }
c@92 505
c@92 506 if (spl[0] == 0) {
c@92 507
c@92 508 int newres;
c@92 509 if (Y >= (1<<res)) newres = res;
c@92 510 else newres = res-1;
c@92 511
c@92 512 DoMixSpectrogramBlock2
c@92 513 (&spl[1], Spec, Specs, Y/2, R0, x0, Y0,
c@92 514 normmix, newres, le);
c@92 515
c@92 516 DoMixSpectrogramBlock2
c@92 517 (&spl[Y/2], &Spec[Y/2], Specs, Y/2, R0, x0, Y0+Y/2,
c@92 518 normmix, newres, le);
c@92 519
c@92 520 } else {
c@92 521
c@92 522 DoMixSpectrogramBlock2
c@92 523 (&spl[1], Spec, Specs, Y/2, R0+1, x0*2, Y0/2,
c@92 524 normmix, res-1, &le[1]);
c@92 525
c@92 526 DoMixSpectrogramBlock2
c@92 527 (&spl[Y/2], &Spec[Y/2], Specs, Y/2, R0+1, x0*2+1, Y0/2,
c@92 528 normmix, res-1, &le[1]);
c@92 529 }
c@92 530 }
c@92 531
c@92 532 return 0;
c@92 533 }
c@92 534
c@92 535 /**
c@92 536 * MixSpectrogramBlock2 calls the two Do...() to do the real work.
c@92 537 *
c@92 538 * At this point:
c@92 539 * spl is... what? the returned "cutting", organised how?
c@92 540 * Spec is... what? the returned spectrogram, organised how?
c@92 541 * Specs is an array of input spectrograms
c@92 542 * WID is the maximum window size
c@92 543 * wid is the minimum window size
c@92 544 * normmix is... what?
c@92 545 */
c@92 546 double
c@92 547 AdaptiveSpectrogram::MixSpectrogramBlock2(int* spl, double* Spec, double*** Specs, int
c@92 548 WID, int wid, bool normmix)
c@92 549 {
c@92 550 double ene[32];
c@92 551
c@92 552 // find the total energy and normalize
c@92 553
c@92 554 for (int i = 0, Fr = 1, Wid = WID; Wid >= wid; i++, Fr *= 2, Wid /= 2) {
c@92 555
c@92 556 double lene = 0;
c@92 557
c@92 558 for (int fr = 0; fr < Fr; fr++) {
c@92 559 for (int k = 0; k < Wid; k++) {
c@92 560 lene += Specs[i][fr][k]*Specs[i][fr][k];
c@92 561 }
c@92 562 }
c@92 563
c@92 564 ene[i] = lene;
c@92 565
c@92 566 if (lene != 0) {
c@92 567 double ilene = 1.0/lene;
c@92 568 for (int fr = 0; fr < Fr; fr++) {
c@92 569 for (int k = 0; k < Wid; k++) {
c@92 570 Specs[i][fr][k] = Specs[i][fr][k]*Specs[i][fr][k]*ilene;
c@92 571 }
c@92 572 }
c@92 573 }
c@92 574 }
c@92 575
c@92 576
c@92 577 double result = DoCutSpectrogramBlock2
c@92 578 (spl, Specs, WID, 0, 0, 0, WID/wid, ene[31]);
c@92 579
c@92 580 // de-normalize
c@92 581
c@92 582 for (int i = 0, Fr = 1, Wid = WID; Wid >= wid; i++, Fr *= 2, Wid /= 2) {
c@92 583 double lene = ene[i];
c@92 584 if (lene != 0) {
c@92 585 for (int fr = 0; fr < Fr; fr++) {
c@92 586 for (int k = 0; k < Wid; k++) {
c@92 587 Specs[i][fr][k] = sqrt(Specs[i][fr][k]*lene);
c@92 588 }
c@92 589 }
c@92 590 }
c@92 591 }
c@92 592
c@92 593 double e[32];
c@92 594 for (int i = 0; i < 32; i++) e[i] = 1;
c@92 595
c@92 596 DoMixSpectrogramBlock2
c@92 597 (spl, Spec, Specs, WID, 0, 0, 0, normmix, log2(WID/wid)+1, e);
c@92 598
c@92 599 return result;
c@92 600 }
c@92 601
c@92 602 /**
c@92 603 * MixSpectrogram2 does the work for Fr frames (the largest frame),
c@92 604 * which basically calls MixSpectrogramBlock2 Fr times.
c@92 605 *
c@92 606 * the 3-D array Specs is the multiple spectrograms calculated with
c@92 607 * window sizes between wid and WID, Specs[0] is the 0th spectrogram,
c@92 608 * etc.
c@92 609 *
c@92 610 * spl and Spec for all frames are returned by MixSpectrogram2, each
c@92 611 * as a 2-D array.
c@92 612 */
c@92 613 double
c@92 614 AdaptiveSpectrogram::MixSpectrogram2(int** spl, double** Spec, double*** Specs, int Fr,
c@92 615 int WID, int wid, bool norm, bool normmix)
c@92 616 {
c@92 617 // totally Fr frames of WID samples
c@92 618 // each frame is divided into wid VERTICAL parts
c@92 619
c@92 620 int Res = log2(WID/wid)+1;
c@92 621 double*** lSpecs = new double**[Res];
c@92 622
c@92 623 for (int i = 0; i < Fr; i++) {
c@92 624
c@92 625 for (int j = 0, nfr = 1; j < Res; j++, nfr *= 2) {
c@92 626 lSpecs[j] = &Specs[j][i*nfr];
c@92 627 }
c@92 628
c@92 629 MixSpectrogramBlock2(spl[i], Spec[i], lSpecs, WID, wid, norm);
c@92 630 }
c@92 631
c@92 632 delete[] lSpecs;
c@92 633 return 0;
c@92 634 }
c@92 635