Mercurial > hg > svgui
comparison layer/SpectrogramLayer.cpp @ 1060:5eb4d79334b9 spectrogram-minor-refactor
Replace old logic with calls to new functions; basic refactor part A done, the code now compiles again
author | Chris Cannam |
---|---|
date | Wed, 15 Jun 2016 09:46:20 +0100 |
parents | e1c2dcc7790e |
children | 861f40fc9958 |
comparison
equal
deleted
inserted
replaced
1059:e1c2dcc7790e | 1060:5eb4d79334b9 |
---|---|
2260 if (sx != psx) { | 2260 if (sx != psx) { |
2261 peakfreqs = fft->getPeakFrequencies(FFTModel::AllPeaks, sx, | 2261 peakfreqs = fft->getPeakFrequencies(FFTModel::AllPeaks, sx, |
2262 minbin, maxbin - 1); | 2262 minbin, maxbin - 1); |
2263 if (m_colourScale == PhaseColourScale) { | 2263 if (m_colourScale == PhaseColourScale) { |
2264 fft->getPhasesAt(sx, values, minbin, maxbin - minbin + 1); | 2264 fft->getPhasesAt(sx, values, minbin, maxbin - minbin + 1); |
2265 /*!!! | |
2265 } else if (m_normalization == NormalizeColumns) { | 2266 } else if (m_normalization == NormalizeColumns) { |
2266 fft->getNormalizedMagnitudesAt(sx, values, minbin, maxbin - minbin + 1); | 2267 fft->getNormalizedMagnitudesAt(sx, values, minbin, maxbin - minbin + 1); |
2267 } else if (m_normalization == NormalizeHybrid) { | 2268 } else if (m_normalization == NormalizeHybrid) { |
2268 float max = fft->getNormalizedMagnitudesAt | 2269 float max = fft->getNormalizedMagnitudesAt |
2269 (sx, values, minbin, maxbin - minbin + 1); | 2270 (sx, values, minbin, maxbin - minbin + 1); |
2270 float scale = log10f(max + 1.f); | 2271 float scale = log10f(max + 1.f); |
2271 for (int i = minbin; i <= maxbin; ++i) { | 2272 for (int i = minbin; i <= maxbin; ++i) { |
2272 values[i - minbin] *= scale; | 2273 values[i - minbin] *= scale; |
2273 } | 2274 }*/ |
2274 } else { | 2275 } else { |
2275 fft->getMagnitudesAt(sx, values, minbin, maxbin - minbin + 1); | 2276 fft->getMagnitudesAt(sx, values, minbin, maxbin - minbin + 1); |
2276 } | 2277 } |
2277 psx = sx; | 2278 psx = sx; |
2278 } | 2279 } |
2350 } | 2351 } |
2351 | 2352 |
2352 return columnCount; | 2353 return columnCount; |
2353 } | 2354 } |
2354 | 2355 |
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> | 2356 vector<float> |
2380 SpectrogramLayer::getColumnFromFFTModel(FFTModel *fft, | 2357 SpectrogramLayer::getColumnFromFFTModel(FFTModel *fft, |
2381 int sx, // column number in model | 2358 int sx, // column number in model |
2382 int minbin, | 2359 int minbin, |
2383 int bincount) const | 2360 int bincount) const |
2407 | 2384 |
2408 return move(vector<float>(col.data() + minbin, | 2385 return move(vector<float>(col.data() + minbin, |
2409 col.data() + minbin + bincount)); | 2386 col.data() + minbin + bincount)); |
2410 } | 2387 } |
2411 | 2388 |
2412 void | 2389 vector<float> |
2413 SpectrogramLayer::scaleColumn(vector<float> &col) const | 2390 SpectrogramLayer::scaleColumn(const vector<float> &in) const |
2414 { | 2391 { |
2415 if (m_normalization != NormalizeColumns && | 2392 if (m_normalization == NormalizeColumns || |
2416 m_normalization != NormalizeHybrid) { | 2393 m_normalization == NormalizeHybrid) { |
2417 float scale = 2.f / float(m_fftSize); | 2394 return in; |
2418 int n = int(col.size()); | 2395 } |
2419 for (int i = 0; i < n; ++i) { | 2396 vector<float> out; |
2420 col[i] *= scale; | 2397 out.reserve(in.size()); |
2421 } | 2398 float scale = 2.f / float(m_fftSize); |
2422 } | 2399 for (auto v: in) { |
2400 out.push_back(v * scale); | |
2401 } | |
2402 return move(out); | |
2423 } | 2403 } |
2424 | 2404 |
2425 static bool | 2405 static bool |
2426 is_peak(const vector<float> &values, int ix) | 2406 is_peak(const vector<float> &values, int ix) |
2427 { | 2407 { |
2428 if (!in_range_for(ix-1, values)) return false; | 2408 if (!in_range_for(values, ix-1)) return false; |
2429 if (!in_range_for(ix+1, values)) return false; | 2409 if (!in_range_for(values, ix+1)) return false; |
2430 if (values[ix] < values[ix+1]) return false; | 2410 if (values[ix] < values[ix+1]) return false; |
2431 if (values[ix] < values[ix-1]) return false; | 2411 if (values[ix] < values[ix-1]) return false; |
2432 return true; | 2412 return true; |
2433 } | 2413 } |
2434 | 2414 |
2496 SpectrogramLayer::recordColumnExtents(const vector<float> &col, | 2476 SpectrogramLayer::recordColumnExtents(const vector<float> &col, |
2497 int sx, // column index, for m_columnMags | 2477 int sx, // column index, for m_columnMags |
2498 MagnitudeRange &overallMag, | 2478 MagnitudeRange &overallMag, |
2499 bool &overallMagChanged) const | 2479 bool &overallMagChanged) const |
2500 { | 2480 { |
2501 if (!in_range_for(sx, m_columnMags)) { | 2481 if (!in_range_for(m_columnMags, sx)) { |
2502 throw logic_error("sx out of range for m_columnMags"); | 2482 throw logic_error("sx out of range for m_columnMags"); |
2503 } | 2483 } |
2504 MagnitudeRange mr; | 2484 MagnitudeRange mr; |
2505 for (auto v: col) { | 2485 for (auto v: col) { |
2506 mr.sample(v); | 2486 mr.sample(v); |
2510 overallMagChanged = true; | 2490 overallMagChanged = true; |
2511 } | 2491 } |
2512 } | 2492 } |
2513 | 2493 |
2514 vector<float> | 2494 vector<float> |
2495 SpectrogramLayer::normalizeColumn(const vector<float> &in) const | |
2496 { | |
2497 if (m_normalization == NoNormalization || | |
2498 m_normalization == NormalizeVisibleArea) { | |
2499 // NormalizeVisibleArea is handled through adjustment to m_gain | |
2500 return in; | |
2501 } | |
2502 | |
2503 float max = *max_element(in.begin(), in.end()); | |
2504 | |
2505 if (m_normalization == NormalizeColumns && max == 0.f) { | |
2506 return in; | |
2507 } | |
2508 | |
2509 if (m_normalization == NormalizeHybrid && max <= 0.f) { | |
2510 return in; | |
2511 } | |
2512 | |
2513 vector<float> out; | |
2514 out.reserve(in.size()); | |
2515 | |
2516 float scale; | |
2517 if (m_normalization == NormalizeHybrid) { | |
2518 scale = log10f(max + 1.f) / max; | |
2519 } else { | |
2520 scale = 1.f / max; | |
2521 } | |
2522 | |
2523 for (auto v: in) { | |
2524 out.push_back(v * scale); | |
2525 } | |
2526 return move(out); | |
2527 } | |
2528 | |
2529 vector<float> | |
2515 SpectrogramLayer::peakPickColumn(const vector<float> &in) const | 2530 SpectrogramLayer::peakPickColumn(const vector<float> &in) const |
2516 { | 2531 { |
2517 if (m_binDisplay != PeakBins) return in; | 2532 if (m_binDisplay != PeakBins) return in; |
2518 | 2533 |
2519 vector<float> out(in.size(), 0.f); | 2534 vector<float> out(in.size(), 0.f); |
2520 | 2535 |
2521 for (int i = 0; in_range_for(i, in); ++i) { | 2536 for (int i = 0; in_range_for(in, i); ++i) { |
2522 if (is_peak(in, i)) { | 2537 if (is_peak(in, i)) { |
2523 out[i] = in[i]; | 2538 out[i] = in[i]; |
2524 } | 2539 } |
2525 } | 2540 } |
2526 | 2541 |
2564 cerr << "SpectrogramLayer::paintDrawBuffer: minbin " << minbin << ", maxbin " << maxbin << "; w " << w << ", h " << h << endl; | 2579 cerr << "SpectrogramLayer::paintDrawBuffer: minbin " << minbin << ", maxbin " << maxbin << "; w " << w << ", h " << h << endl; |
2565 #endif | 2580 #endif |
2566 if (minbin < 0) minbin = 0; | 2581 if (minbin < 0) minbin = 0; |
2567 if (maxbin < 0) maxbin = minbin+1; | 2582 if (maxbin < 0) maxbin = minbin+1; |
2568 | 2583 |
2584 DenseThreeDimensionalModel *peakCacheModel = 0; | |
2585 FFTModel *fftModel = 0; | |
2569 DenseThreeDimensionalModel *sourceModel = 0; | 2586 DenseThreeDimensionalModel *sourceModel = 0; |
2570 FFTModel *fft = 0; | 2587 |
2571 int divisor = 1; | |
2572 #ifdef DEBUG_SPECTROGRAM_REPAINT | 2588 #ifdef DEBUG_SPECTROGRAM_REPAINT |
2573 cerr << "SpectrogramLayer::paintDrawBuffer: Note: bin display = " << m_binDisplay << ", w = " << w << ", binforx[" << w-1 << "] = " << binforx[w-1] << ", binforx[0] = " << binforx[0] << endl; | 2589 cerr << "SpectrogramLayer::paintDrawBuffer: Note: bin display = " << m_binDisplay << ", w = " << w << ", binforx[" << w-1 << "] = " << binforx[w-1] << ", binforx[0] = " << binforx[0] << endl; |
2574 #endif | 2590 #endif |
2591 | |
2592 int divisor = 1; | |
2575 if (usePeaksCache) { | 2593 if (usePeaksCache) { |
2576 sourceModel = getPeakCache(v); | 2594 peakCacheModel = getPeakCache(v); |
2577 divisor = m_peakCacheDivisor; | 2595 divisor = m_peakCacheDivisor; |
2578 minbin = 0; | 2596 sourceModel = peakCacheModel; |
2579 maxbin = sourceModel->getHeight(); | |
2580 } else { | 2597 } else { |
2581 sourceModel = fft = getFFTModel(v); | 2598 fftModel = getFFTModel(v); |
2599 sourceModel = fftModel; | |
2582 } | 2600 } |
2583 | 2601 |
2584 if (!sourceModel) return 0; | 2602 if (!sourceModel) return 0; |
2585 | 2603 |
2586 bool interpolate = false; | 2604 bool interpolate = false; |
2594 } | 2612 } |
2595 } | 2613 } |
2596 | 2614 |
2597 int psx = -1; | 2615 int psx = -1; |
2598 | 2616 |
2599 #ifdef __GNUC__ | |
2600 float autoarray[maxbin - minbin + 1]; | |
2601 float peaks[h]; | |
2602 #else | |
2603 float *autoarray = (float *)alloca((maxbin - minbin + 1) * sizeof(float)); | |
2604 float *peaks = (float *)alloca(h * sizeof(float)); | |
2605 #endif | |
2606 | |
2607 const float *values = autoarray; | |
2608 DenseThreeDimensionalModel::Column c; | |
2609 | |
2610 int minColumns = 4; | 2617 int minColumns = 4; |
2611 bool haveTimeLimits = (softTimeLimit > 0.0); | 2618 bool haveTimeLimits = (softTimeLimit > 0.0); |
2612 double hardTimeLimit = softTimeLimit * 2.0; | 2619 double hardTimeLimit = softTimeLimit * 2.0; |
2613 bool overridingSoftLimit = false; | 2620 bool overridingSoftLimit = false; |
2614 auto startTime = chrono::steady_clock::now(); | 2621 auto startTime = chrono::steady_clock::now(); |
2623 step = -1; | 2630 step = -1; |
2624 } | 2631 } |
2625 | 2632 |
2626 int columnCount = 0; | 2633 int columnCount = 0; |
2627 | 2634 |
2635 vector<float> preparedColumn; | |
2636 | |
2628 for (int x = start; x != finish; x += step) { | 2637 for (int x = start; x != finish; x += step) { |
2629 | 2638 |
2630 // x is the on-canvas pixel coord; sx (later) will be the | 2639 // x is the on-canvas pixel coord; sx (later) will be the |
2631 // source column index | 2640 // source column index |
2632 | 2641 |
2641 if (x+1 < w) sx1 = binforx[x+1] / divisor; | 2650 if (x+1 < w) sx1 = binforx[x+1] / divisor; |
2642 if (sx0 < 0) sx0 = sx1 - 1; | 2651 if (sx0 < 0) sx0 = sx1 - 1; |
2643 if (sx0 < 0) continue; | 2652 if (sx0 < 0) continue; |
2644 if (sx1 <= sx0) sx1 = sx0 + 1; | 2653 if (sx1 <= sx0) sx1 = sx0 + 1; |
2645 | 2654 |
2646 for (int y = 0; y < h; ++y) peaks[y] = 0.f; | |
2647 | |
2648 for (int sx = sx0; sx < sx1; ++sx) { | 2655 for (int sx = sx0; sx < sx1; ++sx) { |
2649 | 2656 |
2650 #ifdef DEBUG_SPECTROGRAM_REPAINT | 2657 #ifdef DEBUG_SPECTROGRAM_REPAINT |
2651 // cerr << "sx = " << sx << endl; | 2658 // cerr << "sx = " << sx << endl; |
2652 #endif | 2659 #endif |
2653 | 2660 |
2654 if (sx < 0 || sx >= int(sourceModel->getWidth())) continue; | 2661 if (sx < 0 || sx >= sourceModel->getWidth()) continue; |
2655 | 2662 |
2656 MagnitudeRange mag; | 2663 MagnitudeRange mag; |
2657 | 2664 |
2658 if (sx != psx) { | 2665 if (sx != psx) { |
2659 if (fft) { | 2666 |
2660 #ifdef DEBUG_SPECTROGRAM_REPAINT | 2667 vector<float> column; |
2661 // cerr << "Retrieving column " << sx << " from fft directly" << endl; | 2668 if (peakCacheModel) { |
2662 #endif | 2669 column = getColumnFromGenericModel(peakCacheModel, |
2663 if (m_colourScale == PhaseColourScale) { | 2670 sx, |
2664 fft->getPhasesAt(sx, autoarray, minbin, maxbin - minbin + 1); | 2671 minbin, |
2665 } else if (m_normalization == NormalizeColumns) { | 2672 maxbin - minbin + 1); |
2666 fft->getNormalizedMagnitudesAt(sx, autoarray, minbin, maxbin - minbin + 1); | |
2667 } else if (m_normalization == NormalizeHybrid) { | |
2668 float max = fft->getNormalizedMagnitudesAt | |
2669 (sx, autoarray, minbin, maxbin - minbin + 1); | |
2670 float scale = log10f(max + 1.f); | |
2671 for (int i = minbin; i <= maxbin; ++i) { | |
2672 autoarray[i - minbin] *= scale; | |
2673 } | |
2674 } else { | |
2675 fft->getMagnitudesAt(sx, autoarray, minbin, maxbin - minbin + 1); | |
2676 } | |
2677 } else { | 2673 } else { |
2678 #ifdef DEBUG_SPECTROGRAM_REPAINT | 2674 column = getColumnFromFFTModel(fftModel, |
2679 // cerr << "Retrieving column " << sx << " from peaks cache" << endl; | 2675 sx, |
2680 #endif | 2676 minbin, |
2681 c = sourceModel->getColumn(sx); | 2677 maxbin - minbin + 1); |
2682 if (m_normalization == NormalizeColumns || | |
2683 m_normalization == NormalizeHybrid) { | |
2684 for (int y = 0; y < h; ++y) { | |
2685 if (c[y] > columnMax) columnMax = c[y]; | |
2686 } | |
2687 } | |
2688 values = c.data() + minbin; | |
2689 } | 2678 } |
2679 | |
2680 vector<float> distributed = | |
2681 distributeColumn(scaleColumn(column), | |
2682 h, | |
2683 binfory, | |
2684 minbin, | |
2685 interpolate); | |
2686 | |
2687 recordColumnExtents(distributed, | |
2688 sx, | |
2689 overallMag, | |
2690 overallMagChanged); | |
2691 | |
2692 preparedColumn = | |
2693 applyDisplayGain(peakPickColumn | |
2694 (normalizeColumn(distributed))); | |
2695 | |
2690 psx = sx; | 2696 psx = sx; |
2691 } | 2697 } |
2692 | 2698 |
2693 for (int y = 0; y < h; ++y) { | 2699 //!!! now peak of all preparedColumns for this pixel |
2694 | 2700 } |
2695 double sy0 = binfory[y]; | 2701 |
2696 double sy1 = sy0 + 1; | |
2697 if (y+1 < h) sy1 = binfory[y+1]; | |
2698 | |
2699 double value = 0.0; | |
2700 | |
2701 if (interpolate && fabs(sy1 - sy0) < 1.0) { | |
2702 | |
2703 double centre = (sy0 + sy1) / 2; | |
2704 double dist = (centre - 0.5) - rint(centre - 0.5); | |
2705 int bin = int(centre); | |
2706 int other = (dist < 0 ? (bin-1) : (bin+1)); | |
2707 if (bin < minbin) bin = minbin; | |
2708 if (bin > maxbin) bin = maxbin; | |
2709 if (other < minbin || other > maxbin) other = bin; | |
2710 double prop = 1.0 - fabs(dist); | |
2711 | |
2712 double v0 = values[bin - minbin]; | |
2713 double v1 = values[other - minbin]; | |
2714 if (m_binDisplay == PeakBins) { | |
2715 if (bin == minbin || bin == maxbin || | |
2716 v0 < values[bin-minbin-1] || | |
2717 v0 < values[bin-minbin+1]) v0 = 0.0; | |
2718 if (other == minbin || other == maxbin || | |
2719 v1 < values[other-minbin-1] || | |
2720 v1 < values[other-minbin+1]) v1 = 0.0; | |
2721 } | |
2722 if (v0 == 0.0 && v1 == 0.0) continue; | |
2723 value = prop * v0 + (1.0 - prop) * v1; | |
2724 | |
2725 if (m_colourScale != PhaseColourScale) { | |
2726 if (m_normalization != NormalizeColumns && | |
2727 m_normalization != NormalizeHybrid) { | |
2728 value /= (m_fftSize/2.0); | |
2729 } | |
2730 mag.sample(float(value)); | |
2731 value *= m_gain; | |
2732 } | |
2733 | |
2734 peaks[y] = float(value); | |
2735 | |
2736 } else { | |
2737 | |
2738 int by0 = int(sy0 + 0.0001); | |
2739 int by1 = int(sy1 + 0.0001); | |
2740 if (by1 < by0 + 1) by1 = by0 + 1; | |
2741 | |
2742 for (int bin = by0; bin < by1; ++bin) { | |
2743 | |
2744 value = values[bin - minbin]; | |
2745 if (m_binDisplay == PeakBins) { | |
2746 if (bin == minbin || bin == maxbin || | |
2747 value < values[bin-minbin-1] || | |
2748 value < values[bin-minbin+1]) continue; | |
2749 } | |
2750 | |
2751 if (m_colourScale != PhaseColourScale) { | |
2752 if (m_normalization != NormalizeColumns && | |
2753 m_normalization != NormalizeHybrid) { | |
2754 value /= (m_fftSize/2.0); | |
2755 } | |
2756 mag.sample(float(value)); | |
2757 value *= m_gain; | |
2758 } | |
2759 | |
2760 if (value > peaks[y]) { | |
2761 peaks[y] = float(value); //!!! not right for phase! | |
2762 } | |
2763 } | |
2764 } | |
2765 } | |
2766 | |
2767 if (mag.isSet()) { | |
2768 if (sx >= int(m_columnMags.size())) { | |
2769 #ifdef DEBUG_SPECTROGRAM | |
2770 cerr << "INTERNAL ERROR: " << sx << " >= " | |
2771 << m_columnMags.size() | |
2772 << " at SpectrogramLayer.cpp::paintDrawBuffer" | |
2773 << endl; | |
2774 #endif | |
2775 } else { | |
2776 m_columnMags[sx].sample(mag); | |
2777 if (overallMag.sample(mag)) overallMagChanged = true; | |
2778 } | |
2779 } | |
2780 } | |
2781 | |
2782 // at this point we have updated m_columnMags and overallMag | |
2783 // -- used elsewhere for calculating the overall view range | |
2784 // for NormalizeVisibleArea mode -- and calculated "peaks" | |
2785 // (the possibly scaled and interpolated value array from | |
2786 // which we actually draw the column) and "columnMax" (maximum | |
2787 // value used for normalisation) | |
2788 | |
2789 for (int y = 0; y < h; ++y) { | 2702 for (int y = 0; y < h; ++y) { |
2790 | 2703 unsigned char pixel = getDisplayValue(v, preparedColumn[y]); |
2791 double peak = peaks[y]; | 2704 m_drawBuffer.setPixel(x, h-y-1, pixel); |
2792 | |
2793 if (m_colourScale != PhaseColourScale && | |
2794 (m_normalization == NormalizeColumns || | |
2795 m_normalization == NormalizeHybrid) && | |
2796 columnMax > 0.f) { | |
2797 peak /= columnMax; | |
2798 if (m_normalization == NormalizeHybrid) { | |
2799 peak *= log10(columnMax + 1.f); | |
2800 } | |
2801 } | |
2802 | |
2803 unsigned char peakpix = getDisplayValue(v, peak); | |
2804 | |
2805 m_drawBuffer.setPixel(x, h-y-1, peakpix); | |
2806 } | 2705 } |
2807 | 2706 |
2808 if (haveTimeLimits) { | 2707 if (haveTimeLimits) { |
2809 if (columnCount >= minColumns) { | 2708 if (columnCount >= minColumns) { |
2810 auto t = chrono::steady_clock::now(); | 2709 auto t = chrono::steady_clock::now(); |