Mercurial > hg > svgui
comparison layer/SpectrogramLayer.cpp @ 490:aa477ddcadb5
* Restore (better quality) y-axis interpolation in spectrogram
* Make spectrogram x axis interpolation a preference
author | Chris Cannam |
---|---|
date | Fri, 06 Feb 2009 15:06:23 +0000 |
parents | 363157772fbd |
children | c74e511a3c96 |
comparison
equal
deleted
inserted
replaced
489:363157772fbd | 490:aa477ddcadb5 |
---|---|
43 using std::cerr; | 43 using std::cerr; |
44 using std::endl; | 44 using std::endl; |
45 #include <cassert> | 45 #include <cassert> |
46 #include <cmath> | 46 #include <cmath> |
47 | 47 |
48 #define DEBUG_SPECTROGRAM_REPAINT 1 | 48 //#define DEBUG_SPECTROGRAM_REPAINT 1 |
49 | 49 |
50 SpectrogramLayer::SpectrogramLayer(Configuration config) : | 50 SpectrogramLayer::SpectrogramLayer(Configuration config) : |
51 m_model(0), | 51 m_model(0), |
52 m_channel(0), | 52 m_channel(0), |
53 m_windowSize(1024), | 53 m_windowSize(1024), |
638 | 638 |
639 if (name == "Window Type") { | 639 if (name == "Window Type") { |
640 setWindowType(Preferences::getInstance()->getWindowType()); | 640 setWindowType(Preferences::getInstance()->getWindowType()); |
641 return; | 641 return; |
642 } | 642 } |
643 if (name == "Spectrogram Smoothing") { | 643 if (name == "Spectrogram Y Smoothing") { |
644 invalidateImageCaches(); | |
645 invalidateMagnitudes(); | |
646 emit layerParametersChanged(); | |
647 } | |
648 if (name == "Spectrogram X Smoothing") { | |
644 invalidateImageCaches(); | 649 invalidateImageCaches(); |
645 invalidateMagnitudes(); | 650 invalidateMagnitudes(); |
646 emit layerParametersChanged(); | 651 emit layerParametersChanged(); |
647 } | 652 } |
648 if (name == "Tuning Frequency") { | 653 if (name == "Tuning Frequency") { |
1322 bool logarithmic = (m_frequencyScale == LogFrequencyScale); | 1327 bool logarithmic = (m_frequencyScale == LogFrequencyScale); |
1323 | 1328 |
1324 q0 = v->getFrequencyForY(y, minf, maxf, logarithmic); | 1329 q0 = v->getFrequencyForY(y, minf, maxf, logarithmic); |
1325 q1 = v->getFrequencyForY(y - 1, minf, maxf, logarithmic); | 1330 q1 = v->getFrequencyForY(y - 1, minf, maxf, logarithmic); |
1326 | 1331 |
1327 // Now map these on to actual bins, using raw FFT size (unsmoothed) | 1332 // Now map these on to ("proportions of") actual bins, using raw |
1328 | 1333 // FFT size (unsmoothed) |
1329 int b0 = int((q0 * m_fftSize) / sr); | 1334 |
1330 int b1 = int((q1 * m_fftSize) / sr); | 1335 q0 = (q0 * m_fftSize) / sr; |
1331 | 1336 q1 = (q1 * m_fftSize) / sr; |
1332 //!!! this is supposed to return fractions-of-bins, as it were, hence the floats | |
1333 q0 = b0; | |
1334 q1 = b1; | |
1335 | |
1336 // q0 = (b0 * sr) / m_fftSize; | |
1337 // q1 = (b1 * sr) / m_fftSize; | |
1338 | 1337 |
1339 return true; | 1338 return true; |
1340 } | 1339 } |
1341 | 1340 |
1342 bool | 1341 bool |
1354 bool logarithmic = (m_frequencyScale == LogFrequencyScale); | 1353 bool logarithmic = (m_frequencyScale == LogFrequencyScale); |
1355 | 1354 |
1356 q0 = v->getFrequencyForY(y, minf, maxf, logarithmic); | 1355 q0 = v->getFrequencyForY(y, minf, maxf, logarithmic); |
1357 q1 = v->getFrequencyForY(y - 1, minf, maxf, logarithmic); | 1356 q1 = v->getFrequencyForY(y - 1, minf, maxf, logarithmic); |
1358 | 1357 |
1359 // Now map these on to actual bins, using zero-padded FFT size if | 1358 // Now map these on to ("proportions of") actual bins, using raw |
1360 // appropriate | 1359 // FFT size (unsmoothed) |
1361 | 1360 |
1362 int b0 = int((q0 * getFFTSize(v)) / sr); | 1361 q0 = (q0 * getFFTSize(v)) / sr; |
1363 int b1 = int((q1 * getFFTSize(v)) / sr); | 1362 q1 = (q1 * getFFTSize(v)) / sr; |
1364 | |
1365 //!!! this is supposed to return fractions-of-bins, as it were, hence the floats | |
1366 q0 = b0; | |
1367 q1 = b1; | |
1368 | |
1369 // q0 = (b0 * sr) / m_fftSize; | |
1370 // q1 = (b1 * sr) / m_fftSize; | |
1371 | 1363 |
1372 return true; | 1364 return true; |
1373 } | 1365 } |
1374 | 1366 |
1375 bool | 1367 bool |
2263 | 2255 |
2264 bufwid = w; | 2256 bufwid = w; |
2265 } | 2257 } |
2266 | 2258 |
2267 int binforx[bufwid]; | 2259 int binforx[bufwid]; |
2268 int binfory[h]; | 2260 float binfory[h]; |
2269 | 2261 |
2270 bool usePeaksCache = false; | 2262 bool usePeaksCache = false; |
2271 | 2263 |
2272 if (bufferBinResolution) { | 2264 if (bufferBinResolution) { |
2273 for (int x = 0; x < bufwid; ++x) { | 2265 for (int x = 0; x < bufwid; ++x) { |
2303 for (int y = 0; y < h; ++y) { | 2295 for (int y = 0; y < h; ++y) { |
2304 float q0 = 0, q1 = 0; | 2296 float q0 = 0, q1 = 0; |
2305 if (!getSmoothedYBinRange(v, h-y-1, q0, q1)) { | 2297 if (!getSmoothedYBinRange(v, h-y-1, q0, q1)) { |
2306 binfory[y] = -1; | 2298 binfory[y] = -1; |
2307 } else { | 2299 } else { |
2308 binfory[y] = int(q0 + 0.0001); | 2300 binfory[y] = q0; |
2309 // cerr << "binfory[" << y << "] = " << binfory[y] << endl; | 2301 // cerr << "binfory[" << y << "] = " << binfory[y] << endl; |
2310 } | 2302 } |
2311 } | 2303 } |
2312 | 2304 |
2313 paintDrawBuffer(v, bufwid, h, binforx, binfory, usePeaksCache); | 2305 paintDrawBuffer(v, bufwid, h, binforx, binfory, usePeaksCache); |
2382 #ifdef DEBUG_SPECTROGRAM_REPAINT | 2374 #ifdef DEBUG_SPECTROGRAM_REPAINT |
2383 cerr << "Rescaling image from " << bufwid | 2375 cerr << "Rescaling image from " << bufwid |
2384 << "x" << h << " to " | 2376 << "x" << h << " to " |
2385 << scaledRight-scaledLeft << "x" << h << endl; | 2377 << scaledRight-scaledLeft << "x" << h << endl; |
2386 #endif | 2378 #endif |
2379 Preferences::SpectrogramXSmoothing xsmoothing = | |
2380 Preferences::getInstance()->getSpectrogramXSmoothing(); | |
2381 cerr << "xsmoothing == " << xsmoothing << endl; | |
2387 QImage scaled = m_drawBuffer.scaled | 2382 QImage scaled = m_drawBuffer.scaled |
2388 (scaledRight - scaledLeft, h, | 2383 (scaledRight - scaledLeft, h, |
2389 Qt::IgnoreAspectRatio, Qt::SmoothTransformation); | 2384 Qt::IgnoreAspectRatio, |
2390 // cachePainter.setRenderHint(QPainter::SmoothPixmapTransform, true); | 2385 ((xsmoothing == Preferences::SpectrogramXInterpolated) ? |
2386 Qt::SmoothTransformation : Qt::FastTransformation)); | |
2391 int scaledLeftCrop = v->getXForFrame(leftCropFrame); | 2387 int scaledLeftCrop = v->getXForFrame(leftCropFrame); |
2392 int scaledRightCrop = v->getXForFrame(rightCropFrame); | 2388 int scaledRightCrop = v->getXForFrame(rightCropFrame); |
2393 #ifdef DEBUG_SPECTROGRAM_REPAINT | 2389 #ifdef DEBUG_SPECTROGRAM_REPAINT |
2394 cerr << "Drawing image region of width " << scaledRightCrop - scaledLeftCrop << " to " | 2390 cerr << "Drawing image region of width " << scaledRightCrop - scaledLeftCrop << " to " |
2395 << scaledLeftCrop << " from " << scaledLeftCrop - scaledLeft << endl; | 2391 << scaledLeftCrop << " from " << scaledLeftCrop - scaledLeft << endl; |
2577 if (sx >= int(m_columnMags.size())) { | 2573 if (sx >= int(m_columnMags.size())) { |
2578 std::cerr << "INTERNAL ERROR: " << sx << " >= " | 2574 std::cerr << "INTERNAL ERROR: " << sx << " >= " |
2579 << m_columnMags.size() | 2575 << m_columnMags.size() |
2580 << " at SpectrogramLayer.cpp::paintDrawBuffer" | 2576 << " at SpectrogramLayer.cpp::paintDrawBuffer" |
2581 << std::endl; | 2577 << std::endl; |
2578 } else { | |
2579 m_columnMags[sx].sample(mag); | |
2582 } | 2580 } |
2583 m_columnMags[sx].sample(mag); | |
2584 } | 2581 } |
2585 } | 2582 } |
2586 } | 2583 } |
2587 | 2584 |
2588 return true; | 2585 return true; |
2591 bool | 2588 bool |
2592 SpectrogramLayer::paintDrawBuffer(View *v, | 2589 SpectrogramLayer::paintDrawBuffer(View *v, |
2593 int w, | 2590 int w, |
2594 int h, | 2591 int h, |
2595 int *binforx, | 2592 int *binforx, |
2596 int *binfory, | 2593 float *binfory, |
2597 bool usePeaksCache) const | 2594 bool usePeaksCache) const |
2598 { | 2595 { |
2599 Profiler profiler("SpectrogramLayer::paintDrawBuffer"); | 2596 Profiler profiler("SpectrogramLayer::paintDrawBuffer"); |
2600 | 2597 |
2601 int minbin = binfory[0]; | 2598 int minbin = int(binfory[0] + 0.0001); |
2602 int maxbin = binfory[h-1]; | 2599 int maxbin = binfory[h-1]; |
2603 | 2600 |
2604 #ifdef DEBUG_SPECTROGRAM_REPAINT | 2601 #ifdef DEBUG_SPECTROGRAM_REPAINT |
2605 cerr << "minbin " << minbin << ", maxbin " << maxbin << "; w " << w << ", h " << h << endl; | 2602 cerr << "minbin " << minbin << ", maxbin " << maxbin << "; w " << w << ", h " << h << endl; |
2606 #endif | 2603 #endif |
2621 } else { | 2618 } else { |
2622 sourceModel = fft = getFFTModel(v); | 2619 sourceModel = fft = getFFTModel(v); |
2623 } | 2620 } |
2624 | 2621 |
2625 if (!sourceModel) return false; | 2622 if (!sourceModel) return false; |
2626 | |
2627 int psx = -1; | |
2628 float values[maxbin - minbin + 1]; | |
2629 DenseThreeDimensionalModel::Column c; | |
2630 float peaks[h]; | |
2631 | |
2632 for (int x = 0; x < w; ++x) { | |
2633 | |
2634 if (binforx[x] < 0) continue; | |
2635 | |
2636 // float columnGain = m_gain; | |
2637 float columnMax = 0.f; | |
2638 | |
2639 int sx0 = binforx[x] / divisor; | |
2640 int sx1 = sx0; | |
2641 if (x+1 < w) sx1 = binforx[x+1] / divisor; | |
2642 if (sx0 < 0) sx0 = sx1 - 1; | |
2643 if (sx0 < 0) continue; | |
2644 if (sx1 <= sx0) sx1 = sx0 + 1; | |
2645 | |
2646 for (int y = 0; y < h; ++y) peaks[y] = 0.f; | |
2647 | |
2648 for (int sx = sx0; sx < sx1; ++sx) { | |
2649 | |
2650 if (sx < 0 || sx >= int(sourceModel->getWidth())) continue; | |
2651 | |
2652 if (!m_synchronous) { | |
2653 if (!sourceModel->isColumnAvailable(sx)) { | |
2654 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
2655 std::cerr << "Met unavailable column at col " << sx << std::endl; | |
2656 #endif | |
2657 return false; | |
2658 } | |
2659 } | |
2660 | |
2661 MagnitudeRange mag; | |
2662 | |
2663 if (sx != psx) { | |
2664 if (fft) { | |
2665 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
2666 cerr << "Retrieving column " << sx << " from fft directly" << endl; | |
2667 #endif | |
2668 if (m_colourScale == PhaseColourScale) { | |
2669 fft->getPhasesAt(sx, values, minbin, maxbin - minbin + 1); | |
2670 } else if (m_normalizeColumns) { | |
2671 fft->getNormalizedMagnitudesAt(sx, values, minbin, maxbin - minbin + 1); | |
2672 } else { | |
2673 fft->getMagnitudesAt(sx, values, minbin, maxbin - minbin + 1); | |
2674 } | |
2675 } else { | |
2676 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
2677 cerr << "Retrieving column " << sx << " from peaks cache" << endl; | |
2678 #endif | |
2679 c = sourceModel->getColumn(sx); | |
2680 if (m_normalizeColumns) { | |
2681 for (int y = 0; y < h; ++y) { | |
2682 if (c[y] > columnMax) columnMax = c[y]; | |
2683 } | |
2684 } | |
2685 } | |
2686 psx = sx; | |
2687 } | |
2688 | |
2689 for (int y = 0; y < h; ++y) { | |
2690 | |
2691 int sy0 = binfory[y]; | |
2692 int sy1 = sy0; | |
2693 if (y+1 < h) sy1 = binfory[y+1]; | |
2694 if (sy0 < 0) sy0 = sy1 - 1; | |
2695 if (sy0 < 0) continue; | |
2696 if (sy1 <= sy0) sy1 = sy0 + 1; | |
2697 | |
2698 // cerr << "sy0 " << sy0 << " sy1 " << sy1 << endl; | |
2699 | |
2700 //!!! review -- if we know we're dealing with | |
2701 //!!! magnitudes here, we can just use peak of the | |
2702 //!!! float values | |
2703 | |
2704 for (int sy = sy0; sy < sy1; ++sy) { | |
2705 | |
2706 float value = 0.f; | |
2707 if (fft) { | |
2708 if (m_binDisplay == PeakBins) { | |
2709 if (!fft->isLocalPeak(sx, sy)) continue; | |
2710 } | |
2711 value = values[sy - minbin]; | |
2712 } else { | |
2713 if (m_binDisplay == PeakBins) { | |
2714 if (sy == 0 || sy+1 >= c.size() || | |
2715 c.at(sy) < c.at(sy-1) || | |
2716 c.at(sy) < c.at(sy+1)) continue; | |
2717 } | |
2718 value = c.at(sy); | |
2719 } | |
2720 | |
2721 if (m_colourScale != PhaseColourScale) { | |
2722 if (!m_normalizeColumns) { | |
2723 value /= (m_fftSize/2.f); | |
2724 } | |
2725 mag.sample(value); | |
2726 value *= m_gain; | |
2727 } | |
2728 | |
2729 /* | |
2730 if (m_colourScale != PhaseColourScale) { | |
2731 if (!m_normalizeColumns) { | |
2732 value /= (m_fftSize/2.f); | |
2733 } | |
2734 //!!! mag.sample(value); | |
2735 value *= m_gain; | |
2736 } | |
2737 | |
2738 unsigned char pix = getDisplayValue(v, value); | |
2739 if (pix > peakpix) peakpix = pix; | |
2740 // cerr <<x<<","<<y<<" -> "<<sx<<","<<sy<<" -> "<<values[sy]<<" -> "<<(int)pix<< endl; | |
2741 */ | |
2742 if (value > peaks[y]) peaks[y] = value; //!!! not right for phase! | |
2743 } | |
2744 } | |
2745 | |
2746 if (mag.isSet()) { | |
2747 if (sx >= int(m_columnMags.size())) { | |
2748 std::cerr << "INTERNAL ERROR: " << sx << " >= " | |
2749 << m_columnMags.size() | |
2750 << " at SpectrogramLayer.cpp::paintDrawBuffer" | |
2751 << std::endl; | |
2752 } | |
2753 m_columnMags[sx].sample(mag); | |
2754 } | |
2755 } | |
2756 | |
2757 // if (m_normalizeColumns && columnMax > 0.f) { | |
2758 // columnGain /= columnMax; | |
2759 // } | |
2760 | |
2761 for (int y = 0; y < h; ++y) { | |
2762 | |
2763 float peak = peaks[y]; | |
2764 | |
2765 if (m_colourScale != PhaseColourScale && | |
2766 m_normalizeColumns && | |
2767 columnMax > 0.f) { | |
2768 // if (!m_normalizeColumns) { | |
2769 // peak /= (m_fftSize/2.f); | |
2770 // } | |
2771 //!!! mag.sample(value); | |
2772 peak /= columnMax; | |
2773 } | |
2774 | |
2775 unsigned char peakpix = getDisplayValue(v, peak); | |
2776 | |
2777 m_drawBuffer.setPixel(x, h-y-1, peakpix); | |
2778 } | |
2779 } | |
2780 | |
2781 return true; | |
2782 } | |
2783 | |
2784 #ifdef NOT_DEFINED | |
2785 bool | |
2786 SpectrogramLayer::paintColumnValues(View *v, | |
2787 FFTModel *fft, | |
2788 int x0, | |
2789 int x, | |
2790 int minbin, | |
2791 int maxbin, | |
2792 float displayMinFreq, | |
2793 float displayMaxFreq, | |
2794 float xPixelRatio, | |
2795 const int h, | |
2796 const float *yforbin) const | |
2797 { | |
2798 float ymag[h]; | |
2799 float ydiv[h]; | |
2800 float values[maxbin - minbin + 1]; | |
2801 | |
2802 bool logarithmic = (m_frequencyScale == LogFrequencyScale); | |
2803 | 2623 |
2804 bool interpolate = false; | 2624 bool interpolate = false; |
2805 Preferences::SpectrogramSmoothing smoothing = | 2625 Preferences::SpectrogramSmoothing smoothing = |
2806 Preferences::getInstance()->getSpectrogramSmoothing(); | 2626 Preferences::getInstance()->getSpectrogramSmoothing(); |
2807 if (smoothing == Preferences::SpectrogramInterpolated || | 2627 if (smoothing == Preferences::SpectrogramInterpolated || |
2810 m_binDisplay != PeakFrequencies) { | 2630 m_binDisplay != PeakFrequencies) { |
2811 interpolate = true; | 2631 interpolate = true; |
2812 } | 2632 } |
2813 } | 2633 } |
2814 | 2634 |
2815 for (int y = 0; y < h; ++y) { | 2635 int psx = -1; |
2816 ymag[y] = 0.f; | 2636 float autoarray[maxbin - minbin + 1]; |
2817 ydiv[y] = 0.f; | 2637 const float *values = autoarray; |
2818 } | 2638 DenseThreeDimensionalModel::Column c; |
2819 | 2639 float peaks[h]; |
2820 float s0 = 0, s1 = 0; | 2640 |
2821 | 2641 for (int x = 0; x < w; ++x) { |
2822 if (!getXBinRange(v, x0 + x * xPixelRatio, s0, s1)) { | 2642 |
2823 #ifdef DEBUG_SPECTROGRAM_REPAINT | 2643 if (binforx[x] < 0) continue; |
2824 // std::cerr << "Out of range at " << x0 + x << std::endl; | 2644 |
2825 #endif | 2645 // float columnGain = m_gain; |
2826 assert(x <= m_drawBuffer.width()); | 2646 float columnMax = 0.f; |
2827 return true; | 2647 |
2828 } | 2648 int sx0 = binforx[x] / divisor; |
2829 | 2649 int sx1 = sx0; |
2830 int s0i = int(s0 + 0.001); | 2650 if (x+1 < w) sx1 = binforx[x+1] / divisor; |
2831 int s1i = int(s1); | 2651 if (sx0 < 0) sx0 = sx1 - 1; |
2832 | 2652 if (sx0 < 0) continue; |
2833 if (s1i >= int(fft->getWidth())) { | 2653 if (sx1 <= sx0) sx1 = sx0 + 1; |
2834 if (s0i >= int(fft->getWidth())) { | 2654 |
2835 #ifdef DEBUG_SPECTROGRAM_REPAINT | 2655 for (int y = 0; y < h; ++y) peaks[y] = 0.f; |
2836 std::cerr << "Column " << s0i << " out of range" << std::endl; | 2656 |
2837 #endif | 2657 for (int sx = sx0; sx < sx1; ++sx) { |
2838 return true; | 2658 |
2839 } else { | 2659 if (sx < 0 || sx >= int(sourceModel->getWidth())) continue; |
2840 s1i = s0i; | 2660 |
2841 } | 2661 if (!m_synchronous) { |
2842 } | 2662 if (!sourceModel->isColumnAvailable(sx)) { |
2843 | 2663 #ifdef DEBUG_SPECTROGRAM_REPAINT |
2844 FFTModel::PeakSet peaks; | 2664 std::cerr << "Met unavailable column at col " << sx << std::endl; |
2845 | 2665 #endif |
2846 for (int s = s0i; s <= s1i; ++s) { | 2666 return false; |
2847 | 2667 } |
2848 if (!m_synchronous) { | |
2849 if (!fft->isColumnAvailable(s)) { | |
2850 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
2851 std::cerr << "Met unavailable column at col " << s << std::endl; | |
2852 #endif | |
2853 return false; | |
2854 } | 2668 } |
2855 } | 2669 |
2856 /*!!! | 2670 MagnitudeRange mag; |
2857 if (!fftSuspended) { | 2671 |
2858 fft->suspendWrites(); | 2672 if (sx != psx) { |
2859 fftSuspended = true; | 2673 if (fft) { |
2674 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
2675 cerr << "Retrieving column " << sx << " from fft directly" << endl; | |
2676 #endif | |
2677 if (m_colourScale == PhaseColourScale) { | |
2678 fft->getPhasesAt(sx, autoarray, minbin, maxbin - minbin + 1); | |
2679 } else if (m_normalizeColumns) { | |
2680 fft->getNormalizedMagnitudesAt(sx, autoarray, minbin, maxbin - minbin + 1); | |
2681 } else { | |
2682 fft->getMagnitudesAt(sx, autoarray, minbin, maxbin - minbin + 1); | |
2683 } | |
2684 } else { | |
2685 #ifdef DEBUG_SPECTROGRAM_REPAINT | |
2686 cerr << "Retrieving column " << sx << " from peaks cache" << endl; | |
2687 #endif | |
2688 c = sourceModel->getColumn(sx); | |
2689 if (m_normalizeColumns) { | |
2690 for (int y = 0; y < h; ++y) { | |
2691 if (c[y] > columnMax) columnMax = c[y]; | |
2692 } | |
2693 } | |
2694 values = c.constData() + minbin; | |
2695 } | |
2696 psx = sx; | |
2860 } | 2697 } |
2861 */ | 2698 |
2862 Profiler innerprof2("SpectrogramLayer::paint: 1 data column"); | 2699 for (int y = 0; y < h; ++y) { |
2863 | 2700 |
2864 MagnitudeRange mag; | 2701 float sy0 = binfory[y]; |
2865 | 2702 float sy1 = sy0 + 1; |
2866 if (m_binDisplay == PeakFrequencies) { | 2703 if (y+1 < h) sy1 = binfory[y+1]; |
2867 if (s < int(fft->getWidth()) - 1) { | 2704 |
2868 peaks = fft->getPeakFrequencies(FFTModel::AllPeaks, | 2705 float value = 0.f; |
2869 s, | 2706 |
2870 minbin, maxbin - 1); | 2707 if (interpolate && fabsf(sy1 - sy0) < 1.f) { |
2871 } else { | 2708 |
2872 peaks.clear(); | 2709 float centre = (sy0 + sy1) / 2; |
2873 } | 2710 float dist = (centre - 0.5) - lrintf(centre - 0.5); |
2874 } | 2711 int bin = int(centre); |
2875 | 2712 int other = (dist < 0 ? (bin-1) : (bin+1)); |
2876 if (m_colourScale == PhaseColourScale) { | 2713 if (bin < minbin) bin = minbin; |
2877 fft->getPhasesAt(s, values, minbin, maxbin - minbin + 1); | 2714 if (bin > maxbin) bin = maxbin; |
2878 } else if (m_normalizeColumns) { | 2715 if (other < minbin || other > maxbin) other = bin; |
2879 fft->getNormalizedMagnitudesAt(s, values, minbin, maxbin - minbin + 1); | 2716 float prop = 1.f - fabsf(dist); |
2880 } else { | 2717 |
2881 fft->getMagnitudesAt(s, values, minbin, maxbin - minbin + 1); | 2718 float v0 = values[bin - minbin]; |
2882 } | 2719 float v1 = values[other - minbin]; |
2883 | 2720 if (m_binDisplay == PeakBins) { |
2884 for (size_t q = minbin; q < maxbin; ++q) { | 2721 if (bin == minbin || bin == maxbin || |
2885 | 2722 v0 < values[bin-minbin-1] || |
2886 Profiler innerprof3("SpectrogramLayer::paint: 1 bin"); | 2723 v0 < values[bin-minbin+1]) v0 = 0.f; |
2887 | 2724 if (other == minbin || other == maxbin || |
2888 float y0 = yforbin[q + 1 - minbin]; | 2725 v1 < values[other-minbin-1] || |
2889 float y1 = yforbin[q - minbin]; | 2726 v1 < values[other-minbin+1]) v1 = 0.f; |
2890 | 2727 } |
2891 if (m_binDisplay == PeakBins) { | 2728 if (v0 == 0.f && v1 == 0.f) continue; |
2892 if (!fft->isLocalPeak(s, q)) continue; | 2729 value = prop * v0 + (1.f - prop) * v1; |
2893 } | 2730 |
2894 if (m_binDisplay == PeakFrequencies) { | 2731 if (m_colourScale != PhaseColourScale) { |
2895 if (peaks.find(q) == peaks.end()) continue; | 2732 if (!m_normalizeColumns) { |
2896 } | 2733 value /= (m_fftSize/2.f); |
2897 | |
2898 if (m_threshold != 0.f && | |
2899 !fft->isOverThreshold(s, q, m_threshold * (m_fftSize/2))) { | |
2900 continue; | |
2901 } | |
2902 | |
2903 float sprop = 1.f; | |
2904 if (s == s0i) sprop *= (s + 1) - s0; | |
2905 if (s == s1i) sprop *= s1 - s; | |
2906 | |
2907 if (m_binDisplay == PeakFrequencies) { | |
2908 y0 = y1 = v->getYForFrequency | |
2909 (peaks[q], displayMinFreq, displayMaxFreq, logarithmic); | |
2910 } | |
2911 | |
2912 int y0i = int(y0 + 0.001f); | |
2913 int y1i = int(y1); | |
2914 | |
2915 float value = values[q - minbin]; | |
2916 | |
2917 if (m_colourScale != PhaseColourScale) { | |
2918 if (!m_normalizeColumns) { | |
2919 value /= (m_fftSize/2.f); | |
2920 } | |
2921 mag.sample(value); | |
2922 value *= m_gain; | |
2923 } | |
2924 | |
2925 if (interpolate) { | |
2926 | |
2927 int ypi = y0i; | |
2928 if (q < maxbin - 1) ypi = int(yforbin[q + 2 - minbin]); | |
2929 | |
2930 for (int y = ypi; y <= y1i; ++y) { | |
2931 | |
2932 if (y < 0 || y >= h) continue; | |
2933 | |
2934 float yprop = sprop; | |
2935 float iprop = yprop; | |
2936 | |
2937 if (ypi < y0i && y <= y0i) { | |
2938 | |
2939 float half = float(y0i - ypi) / 2.f; | |
2940 float dist = y - (ypi + half); | |
2941 | |
2942 if (dist >= 0) { | |
2943 iprop = (iprop * dist) / half; | |
2944 ymag[y] += iprop * value; | |
2945 } | 2734 } |
2946 } else { | 2735 mag.sample(value); |
2947 if (y1i > y0i) { | 2736 value *= m_gain; |
2948 | 2737 } |
2949 float half = float(y1i - y0i) / 2.f; | 2738 |
2950 float dist = y - (y0i + half); | 2739 peaks[y] = value; |
2951 | 2740 |
2952 if (dist >= 0) { | 2741 } else { |
2953 iprop = (iprop * (half - dist)) / half; | 2742 |
2743 int by0 = int(sy0 + 0.0001); | |
2744 int by1 = int(sy1 + 0.0001); | |
2745 if (by1 < by0 + 1) by1 = by0 + 1; | |
2746 | |
2747 for (int bin = by0; bin < by1; ++bin) { | |
2748 | |
2749 value = values[bin - minbin]; | |
2750 if (m_binDisplay == PeakBins) { | |
2751 if (bin == minbin || bin == maxbin || | |
2752 value < values[bin-minbin-1] || | |
2753 value < values[bin-minbin+1]) continue; | |
2754 } | |
2755 | |
2756 if (m_colourScale != PhaseColourScale) { | |
2757 if (!m_normalizeColumns) { | |
2758 value /= (m_fftSize/2.f); | |
2954 } | 2759 } |
2760 mag.sample(value); | |
2761 value *= m_gain; | |
2955 } | 2762 } |
2956 | 2763 |
2957 ymag[y] += iprop * value; | 2764 if (value > peaks[y]) peaks[y] = value; //!!! not right for phase! |
2958 ydiv[y] += yprop; | |
2959 } | |
2960 } | |
2961 | |
2962 } else { | |
2963 | |
2964 for (int y = y0i; y <= y1i; ++y) { | |
2965 | |
2966 if (y < 0 || y >= h) continue; | |
2967 | |
2968 float yprop = sprop; | |
2969 if (y == y0i) yprop *= (y + 1) - y0; | |
2970 if (y == y1i) yprop *= y1 - y; | |
2971 | |
2972 for (int y = y0i; y <= y1i; ++y) { | |
2973 | |
2974 if (y < 0 || y >= h) continue; | |
2975 | |
2976 float yprop = sprop; | |
2977 if (y == y0i) yprop *= (y + 1.f) - y0; | |
2978 if (y == y1i) yprop *= y1 - y; | |
2979 ymag[y] += yprop * value; | |
2980 ydiv[y] += yprop; | |
2981 } | 2765 } |
2982 } | 2766 } |
2983 } | 2767 } |
2984 } | 2768 |
2985 | 2769 if (mag.isSet()) { |
2986 if (mag.isSet()) { | 2770 if (sx >= int(m_columnMags.size())) { |
2987 | 2771 std::cerr << "INTERNAL ERROR: " << sx << " >= " |
2988 if (s >= int(m_columnMags.size())) { | 2772 << m_columnMags.size() |
2989 std::cerr << "INTERNAL ERROR: " << s << " >= " | 2773 << " at SpectrogramLayer.cpp::paintDrawBuffer" |
2990 << m_columnMags.size() << " at SpectrogramLayer.cpp:2087" << std::endl; | 2774 << std::endl; |
2775 } else { | |
2776 m_columnMags[sx].sample(mag); | |
2777 } | |
2991 } | 2778 } |
2992 | 2779 } |
2993 m_columnMags[s].sample(mag); | 2780 |
2994 /*!!! | 2781 for (int y = 0; y < h; ++y) { |
2995 if (overallMag.sample(mag)) { | 2782 |
2996 //!!! scaling would change here | 2783 float peak = peaks[y]; |
2997 overallMagChanged = true; | 2784 |
2998 #ifdef DEBUG_SPECTROGRAM_REPAINT | 2785 if (m_colourScale != PhaseColourScale && |
2999 std::cerr << "Overall mag changed (again?) at column " << s << ", to [" << overallMag.getMin() << "->" << overallMag.getMax() << "]" << std::endl; | 2786 m_normalizeColumns && |
3000 #endif | 2787 columnMax > 0.f) { |
2788 peak /= columnMax; | |
3001 } | 2789 } |
3002 */ | 2790 |
3003 } | 2791 unsigned char peakpix = getDisplayValue(v, peak); |
3004 } | 2792 |
3005 | 2793 m_drawBuffer.setPixel(x, h-y-1, peakpix); |
3006 for (int y = 0; y < h; ++y) { | 2794 } |
3007 | |
3008 float value = 0.f; | |
3009 | |
3010 if (ydiv[y] > 0.0) { | |
3011 value = ymag[y] / ydiv[y]; | |
3012 } | |
3013 | |
3014 unsigned char pixel = getDisplayValue(v, value); | |
3015 m_drawBuffer.setPixel(x, y, pixel); | |
3016 } | 2795 } |
3017 | 2796 |
3018 return true; | 2797 return true; |
3019 } | 2798 } |
3020 #endif | |
3021 | 2799 |
3022 void | 2800 void |
3023 SpectrogramLayer::illuminateLocalFeatures(View *v, QPainter &paint) const | 2801 SpectrogramLayer::illuminateLocalFeatures(View *v, QPainter &paint) const |
3024 { | 2802 { |
3025 Profiler profiler("SpectrogramLayer::illuminateLocalFeatures"); | 2803 Profiler profiler("SpectrogramLayer::illuminateLocalFeatures"); |