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();