Mercurial > hg > svgui
comparison layer/SpectrogramLayer.cpp @ 1058:9a13bc339fa9 spectrogram-minor-refactor
Mid-refactor to pull out the bulk of paintDrawBuffer into chunks
author | Chris Cannam |
---|---|
date | Mon, 13 Jun 2016 16:17:44 +0100 |
parents | b4fd6c67fce5 |
children | e1c2dcc7790e |
comparison
equal
deleted
inserted
replaced
1057:218be6cf2d4f | 1058:9a13bc339fa9 |
---|---|
2350 } | 2350 } |
2351 | 2351 |
2352 return columnCount; | 2352 return columnCount; |
2353 } | 2353 } |
2354 | 2354 |
2355 void | |
2356 SpectrogramLayer::normalise(vector<float> &values, Normalization norm) const | |
2357 { | |
2358 if (norm == NormalizeColumns || | |
2359 norm == NormalizeHybrid) { | |
2360 | |
2361 float max = 0.f; | |
2362 for (int i = 0; in_range_for(i, values); ++i) { | |
2363 if (i == 0 || values[i] > max) { | |
2364 max = values[i]; | |
2365 } | |
2366 } | |
2367 if (max > 0.f) { | |
2368 float scale = 1.f / max; | |
2369 if (norm == NormalizeHybrid) { | |
2370 scale = scale * log10f(max + 1.f); | |
2371 } | |
2372 for (int i = 0; in_range_for(i, values); ++i) { | |
2373 values[i] *= scale; | |
2374 } | |
2375 } | |
2376 } | |
2377 } | |
2378 | |
2379 vector<float> | |
2380 SpectrogramLayer::getColumnFromFFTModel(FFTModel *fft, | |
2381 int sx, // column number in model | |
2382 int minbin, | |
2383 int bincount) const | |
2384 { | |
2385 vector<float> values(bincount, 0.f); | |
2386 | |
2387 if (m_colourScale == PhaseColourScale) { | |
2388 fft->getPhasesAt(sx, values.data(), minbin, bincount); | |
2389 } else { | |
2390 fft->getMagnitudesAt(sx, values.data(), minbin, bincount); | |
2391 } | |
2392 | |
2393 return move(values); | |
2394 } | |
2395 | |
2396 vector<float> | |
2397 SpectrogramLayer::getColumnFromGenericModel(DenseThreeDimensionalModel *model, | |
2398 int sx, // column number in model | |
2399 int minbin, | |
2400 int bincount) const | |
2401 { | |
2402 if (m_colourScale == PhaseColourScale) { | |
2403 throw std::logic_error("can't use phase scale with generic 3d model"); | |
2404 } | |
2405 | |
2406 auto col = model->getColumn(sx); | |
2407 | |
2408 return move(vector<float>(col.data() + minbin, | |
2409 col.data() + minbin + bincount)); | |
2410 } | |
2411 | |
2412 void | |
2413 SpectrogramLayer::scaleColumn(vector<float> &col) | |
2414 { | |
2415 if (m_normalization != NormalizeColumns && | |
2416 m_normalization != NormalizeHybrid) { | |
2417 float scale = 2.f / float(m_fftSize); | |
2418 int n = int(col.size()); | |
2419 for (int i = 0; i < n; ++i) { | |
2420 col[i] *= scale; | |
2421 } | |
2422 } | |
2423 } | |
2424 | |
2425 static bool | |
2426 is_peak(const vector<float> &values, int ix) | |
2427 { | |
2428 if (!in_range_for(ix-1, values)) return false; | |
2429 if (!in_range_for(ix+1, values)) return false; | |
2430 if (values[ix] < values[ix+1]) return false; | |
2431 if (values[ix] < values[ix-1]) return false; | |
2432 return true; | |
2433 } | |
2434 | |
2435 vector<float> | |
2436 SpectrogramLayer::distributeColumn(const vector<float> &in, | |
2437 int h, | |
2438 const vector<double> &binfory, | |
2439 int minbin, | |
2440 bool interpolate) | |
2441 { | |
2442 vector<float> out(h, 0.f); | |
2443 int bins = int(in.size()); | |
2444 | |
2445 for (int y = 0; y < h; ++y) { | |
2446 | |
2447 double sy0 = binfory[y] - minbin; | |
2448 double sy1 = sy0 + 1; | |
2449 if (y+1 < h) { | |
2450 sy1 = binfory[y+1] - minbin; | |
2451 } | |
2452 | |
2453 if (interpolate && fabs(sy1 - sy0) < 1.0) { | |
2454 | |
2455 double centre = (sy0 + sy1) / 2; | |
2456 double dist = (centre - 0.5) - rint(centre - 0.5); | |
2457 int bin = int(centre); | |
2458 | |
2459 int other = (dist < 0 ? (bin-1) : (bin+1)); | |
2460 | |
2461 if (bin < 0) bin = 0; | |
2462 if (bin >= bins) bin = bins-1; | |
2463 | |
2464 if (other < 0 || other >= bins) { | |
2465 other = bin; | |
2466 } | |
2467 | |
2468 if (m_binDisplay == PeakBins) { | |
2469 | |
2470 if (is_peak(in, bin)) { | |
2471 out[y] = in[bin]; | |
2472 } else if (other != bin && is_peak(in, other)) { | |
2473 out[y] = in[other]; | |
2474 } | |
2475 | |
2476 } else { | |
2477 | |
2478 double prop = 1.0 - fabs(dist); | |
2479 | |
2480 double v0 = in[bin]; | |
2481 double v1 = in[other]; | |
2482 | |
2483 out[y] = float(prop * v0 + (1.0 - prop) * v1); | |
2484 } | |
2485 | |
2486 } else { // not interpolating this one | |
2487 | |
2488 int by0 = int(sy0 + 0.0001); | |
2489 int by1 = int(sy1 + 0.0001); | |
2490 if (by1 < by0 + 1) by1 = by0 + 1; | |
2491 | |
2492 for (int bin = by0; bin < by1; ++bin) { | |
2493 | |
2494 if (m_binDisplay == PeakBins && !is_peak(in, bin)) { | |
2495 continue; | |
2496 } | |
2497 | |
2498 float value = in[bin]; | |
2499 | |
2500 if (value > out[y] || m_colourScale == PhaseColourScale) { | |
2501 out[y] = value; | |
2502 } | |
2503 } | |
2504 } | |
2505 } | |
2506 | |
2507 return out; | |
2508 } | |
2509 | |
2510 void | |
2511 SpectrogramLayer::recordColumnExtents(const vector<float> &col, | |
2512 int sx, // column index, for m_columnMags | |
2513 MagnitudeRange &overallMag, | |
2514 bool &overallMagChanged) | |
2515 { | |
2516 //!!! this differs from previous logic when in peak mode - as the | |
2517 //!!! zeros between peaks are now sampled, where they were not | |
2518 //!!! before | |
2519 | |
2520 if (!in_range_for(sx, m_columnMags)) { | |
2521 throw logic_error("sx out of range for m_columnMags"); | |
2522 } | |
2523 MagnitudeRange mr; | |
2524 for (auto v: col) { | |
2525 mr.sample(v); | |
2526 } | |
2527 m_columnMags[sx] = mr; | |
2528 if (overallMag.sample(mr)) { | |
2529 overallMagChanged = true; | |
2530 } | |
2531 } | |
2532 | |
2533 // order: | |
2534 // get column -> scale -> distribute/interpolate -> record extents -> normalise -> apply display gain | |
2535 | |
2355 int | 2536 int |
2356 SpectrogramLayer::paintDrawBuffer(LayerGeometryProvider *v, | 2537 SpectrogramLayer::paintDrawBuffer(LayerGeometryProvider *v, |
2357 int w, | 2538 int w, |
2358 int h, | 2539 int h, |
2359 const vector<int> &binforx, | 2540 const vector<int> &binforx, |