annotate plugins/AdaptiveSpectrogram.cpp @ 266:d04675d44928 tip master

Refer to SDK from Github
author Chris Cannam <cannam@all-day-breakfast.com>
date Wed, 02 Jun 2021 14:41:26 +0100
parents f96ea0e4b475
children
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@135 7
c@135 8 This program is free software; you can redistribute it and/or
c@135 9 modify it under the terms of the GNU General Public License as
c@135 10 published by the Free Software Foundation; either version 2 of the
c@135 11 License, or (at your option) any later version. See the file
c@135 12 COPYING included with this distribution for more information.
c@92 13 */
c@92 14
c@92 15 #include "AdaptiveSpectrogram.h"
c@92 16
c@92 17 #include <cstdlib>
c@133 18 #include <cstdio>
c@92 19 #include <cstring>
c@114 20 #include <cfloat>
c@92 21
c@92 22 #include <iostream>
c@92 23
c@92 24 #include <dsp/transforms/FFT.h>
c@156 25 #include <dsp/rateconversion/Decimator.h>
c@92 26
c@92 27 using std::string;
c@92 28 using std::vector;
c@92 29 using std::cerr;
c@92 30 using std::endl;
c@92 31
c@92 32 using Vamp::RealTime;
c@92 33
c@99 34 //#define DEBUG_VERBOSE 1
c@99 35
c@92 36 AdaptiveSpectrogram::AdaptiveSpectrogram(float inputSampleRate) :
c@92 37 Plugin(inputSampleRate),
c@104 38 m_w(8),
c@114 39 m_n(2),
c@114 40 m_coarse(false),
c@109 41 m_threaded(true),
c@156 42 m_decFactor(1),
c@178 43 m_buffer(0),
c@156 44 m_buflen(0),
c@178 45 m_decimator(0),
c@178 46 m_threadsInUse(false)
c@92 47 {
c@92 48 }
c@92 49
c@92 50 AdaptiveSpectrogram::~AdaptiveSpectrogram()
c@92 51 {
c@178 52 for (int i = 0; i < int(m_cutThreads.size()); ++i) {
c@104 53 delete m_cutThreads[i];
c@104 54 }
c@104 55 m_cutThreads.clear();
c@105 56
c@110 57 for (FFTMap::iterator i = m_fftThreads.begin();
c@110 58 i != m_fftThreads.end(); ++i) {
c@106 59 delete i->second;
c@105 60 }
c@105 61 m_fftThreads.clear();
c@156 62
c@156 63 delete[] m_buffer;
c@156 64 delete m_decimator;
c@92 65 }
c@92 66
c@92 67 string
c@92 68 AdaptiveSpectrogram::getIdentifier() const
c@92 69 {
c@93 70 return "qm-adaptivespectrogram";
c@92 71 }
c@92 72
c@92 73 string
c@92 74 AdaptiveSpectrogram::getName() const
c@92 75 {
c@92 76 return "Adaptive Spectrogram";
c@92 77 }
c@92 78
c@92 79 string
c@92 80 AdaptiveSpectrogram::getDescription() const
c@92 81 {
c@92 82 return "Produce an adaptive spectrogram by adaptive selection from spectrograms at multiple resolutions";
c@92 83 }
c@92 84
c@92 85 string
c@92 86 AdaptiveSpectrogram::getMaker() const
c@92 87 {
c@92 88 return "Queen Mary, University of London";
c@92 89 }
c@92 90
c@92 91 int
c@92 92 AdaptiveSpectrogram::getPluginVersion() const
c@92 93 {
c@156 94 return 2;
c@92 95 }
c@92 96
c@92 97 string
c@92 98 AdaptiveSpectrogram::getCopyright() const
c@92 99 {
c@92 100 return "Plugin by Wen Xue and Chris Cannam. Copyright (c) 2009 Wen Xue and QMUL - All Rights Reserved";
c@92 101 }
c@92 102
c@92 103 size_t
c@92 104 AdaptiveSpectrogram::getPreferredStepSize() const
c@92 105 {
c@156 106 return getPreferredBlockSize();
c@92 107 }
c@92 108
c@92 109 size_t
c@92 110 AdaptiveSpectrogram::getPreferredBlockSize() const
c@92 111 {
c@156 112 // the /2 at the end is for 50% overlap (we handle framing ourselves)
c@156 113 return ((2 << m_w) << m_n) * m_decFactor / 2;
c@92 114 }
c@92 115
c@92 116 bool
c@92 117 AdaptiveSpectrogram::initialise(size_t channels, size_t stepSize, size_t blockSize)
c@92 118 {
c@92 119 if (channels < getMinChannelCount() ||
c@92 120 channels > getMaxChannelCount()) return false;
c@92 121
c@156 122 if (blockSize != getPreferredBlockSize()) {
c@156 123 std::cerr << "AdaptiveSpectrogram::initialise: Block size " << blockSize << " does not match required block size of " << getPreferredBlockSize() << std::endl;
c@156 124 return false;
c@156 125 }
c@156 126 if (stepSize != getPreferredStepSize()) {
c@156 127 std::cerr << "AdaptiveSpectrogram::initialise: Step size " << stepSize << " does not match required step size of " << getPreferredStepSize() << std::endl;
c@156 128 return false;
c@156 129 }
c@156 130
c@156 131 if (m_decFactor > 1) {
c@156 132 m_decimator = new Decimator(blockSize, m_decFactor);
c@156 133 }
c@156 134
c@156 135 m_buflen = (blockSize * 2) / m_decFactor; // *2 for 50% overlap
c@156 136 m_buffer = new float[m_buflen];
c@156 137
c@156 138 reset();
c@156 139
c@92 140 return true;
c@92 141 }
c@92 142
c@92 143 void
c@92 144 AdaptiveSpectrogram::reset()
c@92 145 {
c@156 146 if (m_decimator) m_decimator->resetFilter();
c@156 147 for (int i = 0; i < m_buflen; ++i) m_buffer[i] = 0.f;
c@92 148 }
c@92 149
c@92 150 AdaptiveSpectrogram::ParameterList
c@92 151 AdaptiveSpectrogram::getParameterDescriptors() const
c@92 152 {
c@92 153 ParameterList list;
c@92 154
c@92 155 ParameterDescriptor desc;
c@92 156 desc.identifier = "n";
c@92 157 desc.name = "Number of resolutions";
c@114 158 desc.description = "Number of consecutive powers of two in the range to be used as spectrogram resolutions, starting with the minimum resolution specified";
c@92 159 desc.unit = "";
c@114 160 desc.minValue = 2;
c@92 161 desc.maxValue = 10;
c@114 162 desc.defaultValue = 3;
c@92 163 desc.isQuantized = true;
c@92 164 desc.quantizeStep = 1;
c@92 165 list.push_back(desc);
c@92 166
c@92 167 ParameterDescriptor desc2;
c@92 168 desc2.identifier = "w";
c@92 169 desc2.name = "Smallest resolution";
c@92 170 desc2.description = "Smallest of the consecutive powers of two to use as spectrogram resolutions";
c@92 171 desc2.unit = "";
c@92 172 desc2.minValue = 1;
c@92 173 desc2.maxValue = 14;
c@104 174 desc2.defaultValue = 9;
c@92 175 desc2.isQuantized = true;
c@92 176 desc2.quantizeStep = 1;
c@92 177 // I am so lazy
c@92 178 desc2.valueNames.push_back("2");
c@92 179 desc2.valueNames.push_back("4");
c@92 180 desc2.valueNames.push_back("8");
c@92 181 desc2.valueNames.push_back("16");
c@92 182 desc2.valueNames.push_back("32");
c@92 183 desc2.valueNames.push_back("64");
c@92 184 desc2.valueNames.push_back("128");
c@92 185 desc2.valueNames.push_back("256");
c@92 186 desc2.valueNames.push_back("512");
c@92 187 desc2.valueNames.push_back("1024");
c@92 188 desc2.valueNames.push_back("2048");
c@92 189 desc2.valueNames.push_back("4096");
c@92 190 desc2.valueNames.push_back("8192");
c@92 191 desc2.valueNames.push_back("16384");
c@92 192 list.push_back(desc2);
c@92 193
c@156 194 desc2.identifier = "dec";
c@156 195 desc2.name = "Decimation factor";
c@156 196 desc2.description = "Factor to down-sample by, increasing speed but lowering maximum frequency";
c@156 197 desc2.unit = "";
c@156 198 desc2.minValue = 0;
c@156 199 desc2.maxValue = 3;
c@156 200 desc2.defaultValue = 0;
c@156 201 desc2.isQuantized = true;
c@156 202 desc2.quantizeStep = 1;
c@156 203 desc2.valueNames.clear();
c@156 204 desc2.valueNames.push_back("No decimation");
c@156 205 desc2.valueNames.push_back("2");
c@156 206 desc2.valueNames.push_back("4");
c@156 207 desc2.valueNames.push_back("8");
c@156 208 list.push_back(desc2);
c@156 209
c@109 210 ParameterDescriptor desc3;
c@114 211 desc3.identifier = "coarse";
c@114 212 desc3.name = "Omit alternate resolutions";
c@114 213 desc3.description = "Generate a coarser spectrogram faster by excluding every alternate resolution (first and last resolution are always retained)";
c@114 214 desc3.unit = "";
c@114 215 desc3.minValue = 0;
c@114 216 desc3.maxValue = 1;
c@114 217 desc3.defaultValue = 0;
c@114 218 desc3.isQuantized = true;
c@114 219 desc3.quantizeStep = 1;
c@114 220 list.push_back(desc3);
c@114 221
c@109 222 desc3.identifier = "threaded";
c@109 223 desc3.name = "Multi-threaded processing";
c@110 224 desc3.description = "Perform calculations using several threads in parallel";
c@109 225 desc3.unit = "";
c@109 226 desc3.minValue = 0;
c@109 227 desc3.maxValue = 1;
c@109 228 desc3.defaultValue = 1;
c@109 229 desc3.isQuantized = true;
c@109 230 desc3.quantizeStep = 1;
c@109 231 list.push_back(desc3);
c@109 232
c@92 233 return list;
c@92 234 }
c@92 235
c@92 236 float
c@92 237 AdaptiveSpectrogram::getParameter(std::string id) const
c@92 238 {
c@92 239 if (id == "n") return m_n+1;
c@92 240 else if (id == "w") return m_w+1;
c@109 241 else if (id == "threaded") return (m_threaded ? 1 : 0);
c@114 242 else if (id == "coarse") return (m_coarse ? 1 : 0);
c@156 243 else if (id == "dec") {
c@156 244 int f = m_decFactor;
c@156 245 int p = 0;
c@156 246 while (f > 1) {
c@156 247 f >>= 1;
c@156 248 p += 1;
c@156 249 }
c@156 250 return p;
c@156 251 }
c@92 252 return 0.f;
c@92 253 }
c@92 254
c@92 255 void
c@92 256 AdaptiveSpectrogram::setParameter(std::string id, float value)
c@92 257 {
c@92 258 if (id == "n") {
c@92 259 int n = lrintf(value);
c@92 260 if (n >= 1 && n <= 10) m_n = n-1;
c@92 261 } else if (id == "w") {
c@92 262 int w = lrintf(value);
c@92 263 if (w >= 1 && w <= 14) m_w = w-1;
c@109 264 } else if (id == "threaded") {
c@109 265 m_threaded = (value > 0.5);
c@114 266 } else if (id == "coarse") {
c@114 267 m_coarse = (value > 0.5);
c@156 268 } else if (id == "dec") {
c@156 269 int p = lrintf(value);
c@156 270 if (p >= 0 && p <= 3) m_decFactor = 1 << p;
c@109 271 }
c@92 272 }
c@92 273
c@92 274 AdaptiveSpectrogram::OutputList
c@92 275 AdaptiveSpectrogram::getOutputDescriptors() const
c@92 276 {
c@92 277 OutputList list;
c@92 278
c@92 279 OutputDescriptor d;
c@92 280 d.identifier = "output";
c@92 281 d.name = "Output";
c@92 282 d.description = "The output of the plugin";
c@92 283 d.unit = "";
c@92 284 d.hasFixedBinCount = true;
c@156 285 d.binCount = getPreferredBlockSize() / (m_decFactor * 2);
c@92 286 d.hasKnownExtents = false;
c@92 287 d.isQuantized = false;
c@92 288 d.sampleType = OutputDescriptor::FixedSampleRate;
c@156 289 d.sampleRate = m_inputSampleRate / (m_decFactor * ((2 << m_w) / 2));
c@92 290 d.hasDuration = false;
c@112 291 char name[20];
c@178 292 for (int i = 0; i < int(d.binCount); ++i) {
c@156 293 float freq = (m_inputSampleRate / (m_decFactor * (d.binCount * 2)) * (i + 1)); // no DC bin
c@157 294 sprintf(name, "%.1f Hz", freq);
c@112 295 d.binNames.push_back(name);
c@112 296 }
c@92 297 list.push_back(d);
c@92 298
c@92 299 return list;
c@92 300 }
c@92 301
c@92 302 AdaptiveSpectrogram::FeatureSet
c@92 303 AdaptiveSpectrogram::getRemainingFeatures()
c@92 304 {
c@92 305 FeatureSet fs;
c@92 306 return fs;
c@92 307 }
c@92 308
c@100 309 AdaptiveSpectrogram::FeatureSet
c@178 310 AdaptiveSpectrogram::process(const float *const *inputBuffers, RealTime)
c@100 311 {
c@156 312 // framing: shift and write the new data to right half
c@156 313 for (int i = 0; i < m_buflen/2; ++i) {
c@156 314 m_buffer[i] = m_buffer[m_buflen/2 + i];
c@156 315 }
c@156 316
c@156 317 if (m_decFactor == 1) {
c@156 318 for (int i = 0; i < m_buflen/2; ++i) {
c@156 319 m_buffer[m_buflen/2 + i] = inputBuffers[0][i];
c@156 320 }
c@156 321 } else {
c@156 322 m_decimator->process(inputBuffers[0], m_buffer + m_buflen/2);
c@156 323 }
c@156 324
c@100 325 FeatureSet fs;
c@100 326
c@100 327 int minwid = (2 << m_w), maxwid = ((2 << m_w) << m_n);
c@100 328
c@101 329 #ifdef DEBUG_VERBOSE
c@100 330 cerr << "widths from " << minwid << " to " << maxwid << " ("
c@100 331 << minwid/2 << " to " << maxwid/2 << " in real parts)" << endl;
c@101 332 #endif
c@100 333
c@100 334 Spectrograms s(minwid/2, maxwid/2, 1);
c@100 335
c@100 336 int w = minwid;
c@100 337 int index = 0;
c@100 338
c@100 339 while (w <= maxwid) {
c@114 340
c@114 341 if (!isResolutionWanted(s, w/2)) {
c@114 342 w *= 2;
c@114 343 ++index;
c@114 344 continue;
c@114 345 }
c@114 346
c@106 347 if (m_fftThreads.find(w) == m_fftThreads.end()) {
c@106 348 m_fftThreads[w] = new FFTThread(w);
c@106 349 }
c@109 350 if (m_threaded) {
c@156 351 m_fftThreads[w]->startCalculation(m_buffer, s, index, maxwid);
c@109 352 } else {
c@156 353 m_fftThreads[w]->setParameters(m_buffer, s, index, maxwid);
c@109 354 m_fftThreads[w]->performTask();
c@109 355 }
c@100 356 w *= 2;
c@100 357 ++index;
c@100 358 }
c@100 359
c@109 360 if (m_threaded) {
c@109 361 w = minwid;
c@114 362 index = 0;
c@109 363 while (w <= maxwid) {
c@114 364 if (!isResolutionWanted(s, w/2)) {
c@114 365 w *= 2;
c@114 366 ++index;
c@114 367 continue;
c@114 368 }
c@109 369 m_fftThreads[w]->await();
c@109 370 w *= 2;
c@114 371 ++index;
c@109 372 }
c@105 373 }
c@102 374
c@109 375 m_threadsInUse = false;
c@104 376
c@114 377 // std::cerr << "maxwid/2 = " << maxwid/2 << ", minwid/2 = " << minwid/2 << ", n+1 = " << m_n+1 << ", 2^(n+1) = " << (2<<m_n) << std::endl;
c@110 378
c@114 379 int cutwid = maxwid/2;
c@114 380 Cutting *cutting = cut(s, cutwid, 0, 0, cutwid, 0);
c@100 381
c@101 382 #ifdef DEBUG_VERBOSE
c@100 383 printCutting(cutting, " ");
c@101 384 #endif
c@100 385
c@100 386 vector<vector<float> > rmat(maxwid/minwid);
c@100 387 for (int i = 0; i < maxwid/minwid; ++i) {
c@100 388 rmat[i] = vector<float>(maxwid/2);
c@100 389 }
c@100 390
c@114 391 assemble(s, cutting, rmat, 0, 0, maxwid/minwid, cutwid);
c@100 392
c@110 393 cutting->erase();
c@100 394
c@178 395 for (int i = 0; i < int(rmat.size()); ++i) {
c@100 396 Feature f;
c@100 397 f.hasTimestamp = false;
c@100 398 f.values = rmat[i];
c@100 399 fs[0].push_back(f);
c@100 400 }
c@100 401
c@104 402 // std::cerr << "process returning!\n" << std::endl;
c@104 403
c@100 404 return fs;
c@100 405 }
c@100 406
c@100 407 void
c@104 408 AdaptiveSpectrogram::printCutting(Cutting *c, string pfx) const
c@100 409 {
c@100 410 if (c->first) {
c@100 411 if (c->cut == Cutting::Horizontal) {
c@100 412 cerr << pfx << "H" << endl;
c@100 413 } else if (c->cut == Cutting::Vertical) {
c@100 414 cerr << pfx << "V" << endl;
c@100 415 }
c@100 416 printCutting(c->first, pfx + " ");
c@100 417 printCutting(c->second, pfx + " ");
c@100 418 } else {
c@100 419 cerr << pfx << "* " << c->value << endl;
c@100 420 }
c@100 421 }
c@100 422
c@104 423 void
c@104 424 AdaptiveSpectrogram::getSubCuts(const Spectrograms &s,
c@104 425 int res,
c@104 426 int x, int y, int h,
c@114 427 Cutting **top, Cutting **bottom,
c@114 428 Cutting **left, Cutting **right,
c@113 429 BlockAllocator *allocator) const
c@104 430 {
c@109 431 if (m_threaded && !m_threadsInUse) {
c@104 432
c@109 433 m_threadsInUse = true;
c@104 434
c@104 435 if (m_cutThreads.empty()) {
c@104 436 for (int i = 0; i < 4; ++i) {
c@104 437 CutThread *t = new CutThread(this);
c@104 438 m_cutThreads.push_back(t);
c@104 439 }
c@104 440 }
c@104 441
c@109 442 // Cut threads 0 and 1 calculate the top and bottom halves;
c@110 443 // threads 2 and 3 calculate left and right. See notes in
c@110 444 // unthreaded code below for more information.
c@104 445
c@114 446 if (top) m_cutThreads[0]->cut(s, res, x, y + h/2, h/2);
c@114 447 if (bottom) m_cutThreads[1]->cut(s, res, x, y, h/2);
c@104 448
c@114 449 if (left) m_cutThreads[2]->cut(s, res/2, 2 * x, y/2, h/2);
c@114 450 if (right) m_cutThreads[3]->cut(s, res/2, 2 * x + 1, y/2, h/2);
c@114 451
c@114 452 if (top) *top = m_cutThreads[0]->get();
c@114 453 if (bottom) *bottom = m_cutThreads[1]->get();
c@114 454 if (left) *left = m_cutThreads[2]->get();
c@114 455 if (right) *right = m_cutThreads[3]->get();
c@104 456
c@104 457 } else {
c@104 458
c@110 459 // Unthreaded version
c@104 460
c@104 461 // The "vertical" division is a top/bottom split.
c@104 462 // Splitting this way keeps us in the same resolution,
c@104 463 // but with two vertical subregions of height h/2.
c@104 464
c@114 465 if (top) *top = cut(s, res, x, y + h/2, h/2, allocator);
c@114 466 if (bottom) *bottom = cut(s, res, x, y, h/2, allocator);
c@104 467
c@104 468 // The "horizontal" division is a left/right split. Splitting
c@104 469 // this way places us in resolution res/2, which has lower
c@104 470 // vertical resolution but higher horizontal resolution. We
c@104 471 // need to double x accordingly.
c@104 472
c@114 473 if (left) *left = cut(s, res/2, 2 * x, y/2, h/2, allocator);
c@114 474 if (right) *right = cut(s, res/2, 2 * x + 1, y/2, h/2, allocator);
c@104 475 }
c@104 476 }
c@104 477
c@100 478 AdaptiveSpectrogram::Cutting *
c@100 479 AdaptiveSpectrogram::cut(const Spectrograms &s,
c@100 480 int res,
c@110 481 int x, int y, int h,
c@110 482 BlockAllocator *allocator) const
c@100 483 {
c@100 484 // cerr << "res = " << res << ", x = " << x << ", y = " << y << ", h = " << h << endl;
c@100 485
c@110 486 Cutting *cutting;
c@110 487 if (allocator) {
c@110 488 cutting = (Cutting *)(allocator->allocate());
c@110 489 cutting->allocator = allocator;
c@110 490 } else {
c@110 491 cutting = new Cutting;
c@110 492 cutting->allocator = 0;
c@110 493 }
c@110 494
c@100 495 if (h > 1 && res > s.minres) {
c@100 496
c@114 497 if (!isResolutionWanted(s, res)) {
c@100 498
c@114 499 Cutting *left = 0, *right = 0;
c@114 500 getSubCuts(s, res, x, y, h, 0, 0, &left, &right, allocator);
c@114 501
c@114 502 double hcost = left->cost + right->cost;
c@101 503 double henergy = left->value + right->value;
c@114 504 hcost = normalize(hcost, henergy);
c@114 505
c@100 506 cutting->cut = Cutting::Horizontal;
c@100 507 cutting->first = left;
c@100 508 cutting->second = right;
c@100 509 cutting->cost = hcost;
c@111 510 cutting->value = left->value + right->value;
c@100 511
c@114 512 } else if (h == 2 && !isResolutionWanted(s, res/2)) {
c@100 513
c@114 514 Cutting *top = 0, *bottom = 0;
c@114 515 getSubCuts(s, res, x, y, h, &top, &bottom, 0, 0, allocator);
c@114 516
c@114 517 double vcost = top->cost + bottom->cost;
c@114 518 double venergy = top->value + bottom->value;
c@114 519 vcost = normalize(vcost, venergy);
c@114 520
c@100 521 cutting->cut = Cutting::Vertical;
c@100 522 cutting->first = top;
c@100 523 cutting->second = bottom;
c@100 524 cutting->cost = vcost;
c@111 525 cutting->value = top->value + bottom->value;
c@114 526
c@114 527 } else {
c@114 528
c@114 529 Cutting *top = 0, *bottom = 0, *left = 0, *right = 0;
c@114 530 getSubCuts(s, res, x, y, h, &top, &bottom, &left, &right, allocator);
c@114 531
c@114 532 double vcost = top->cost + bottom->cost;
c@114 533 double venergy = top->value + bottom->value;
c@114 534 vcost = normalize(vcost, venergy);
c@114 535
c@114 536 double hcost = left->cost + right->cost;
c@114 537 double henergy = left->value + right->value;
c@114 538 hcost = normalize(hcost, henergy);
c@114 539
c@114 540 if (vcost > hcost) {
c@114 541 cutting->cut = Cutting::Horizontal;
c@114 542 cutting->first = left;
c@114 543 cutting->second = right;
c@114 544 cutting->cost = hcost;
c@114 545 cutting->value = left->value + right->value;
c@114 546 top->erase();
c@114 547 bottom->erase();
c@114 548 return cutting;
c@114 549 } else {
c@114 550 cutting->cut = Cutting::Vertical;
c@114 551 cutting->first = top;
c@114 552 cutting->second = bottom;
c@114 553 cutting->cost = vcost;
c@114 554 cutting->value = top->value + bottom->value;
c@114 555 left->erase();
c@114 556 right->erase();
c@114 557 return cutting;
c@114 558 }
c@100 559 }
c@100 560
c@100 561 } else {
c@100 562
c@100 563 // no cuts possible from this level
c@100 564
c@100 565 cutting->cut = Cutting::Finished;
c@100 566 cutting->first = 0;
c@100 567 cutting->second = 0;
c@100 568
c@100 569 int n = 0;
c@114 570 for (int r = res; r > s.minres; r >>= 1) ++n;
c@100 571 const Spectrogram *spectrogram = s.spectrograms[n];
c@100 572 cutting->cost = cost(*spectrogram, x, y);
c@100 573 cutting->value = value(*spectrogram, x, y);
c@114 574 }
c@100 575
c@114 576 return cutting;
c@100 577 }
c@100 578
c@100 579 void
c@100 580 AdaptiveSpectrogram::assemble(const Spectrograms &s,
c@100 581 const Cutting *cutting,
c@100 582 vector<vector<float> > &rmat,
c@104 583 int x, int y, int w, int h) const
c@100 584 {
c@100 585 switch (cutting->cut) {
c@100 586
c@100 587 case Cutting::Finished:
c@100 588 for (int i = 0; i < w; ++i) {
c@100 589 for (int j = 0; j < h; ++j) {
c@114 590 rmat[x+i][y+j] = cutting->value;
c@100 591 }
c@100 592 }
c@100 593 return;
c@100 594
c@100 595 case Cutting::Horizontal:
c@100 596 assemble(s, cutting->first, rmat, x, y, w/2, h);
c@100 597 assemble(s, cutting->second, rmat, x+w/2, y, w/2, h);
c@100 598 break;
c@100 599
c@100 600 case Cutting::Vertical:
c@100 601 assemble(s, cutting->first, rmat, x, y+h/2, w, h/2);
c@100 602 assemble(s, cutting->second, rmat, x, y, w, h/2);
c@100 603 break;
c@100 604 }
c@100 605 }
c@100 606