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