comparison layer/SpectrogramLayer.cpp @ 253:1b1e6947c124

* FFT: fix invalid write of normalisation factor in compact mode of disc cache * FFT: fix range problem for normalisation factor in compact mode (it was stored as an unsigned scaled from an assumed float range of 0->1, which is not very plausible and not accurate enough even if true -- use a float instead) * Spectrogram: fix vertical zoom behaviour for log frequency spectrograms: make the thing in the middle of the display remain in the middle after zoom * Overview widget: don't update the detailed waveform if still decoding the audio file (too expensive to do all those redraws)
author Chris Cannam
date Fri, 08 Jun 2007 15:19:50 +0000
parents 8d89f8869cfb
children 11021509c4eb
comparison
equal deleted inserted replaced
252:8d89f8869cfb 253:1b1e6947c124
20 #include "base/AudioLevel.h" 20 #include "base/AudioLevel.h"
21 #include "base/Window.h" 21 #include "base/Window.h"
22 #include "base/Pitch.h" 22 #include "base/Pitch.h"
23 #include "base/Preferences.h" 23 #include "base/Preferences.h"
24 #include "base/RangeMapper.h" 24 #include "base/RangeMapper.h"
25 #include "base/LogRange.h"
25 #include "ColourMapper.h" 26 #include "ColourMapper.h"
26 27
27 #include <QPainter> 28 #include <QPainter>
28 #include <QImage> 29 #include <QImage>
29 #include <QPixmap> 30 #include <QPixmap>
1397 if (q == q0i) freqMin = binfreq; 1398 if (q == q0i) freqMin = binfreq;
1398 if (q == q1i) freqMax = binfreq; 1399 if (q == q1i) freqMax = binfreq;
1399 1400
1400 if (peaksOnly && !fft->isLocalPeak(s, q)) continue; 1401 if (peaksOnly && !fft->isLocalPeak(s, q)) continue;
1401 1402
1402 if (!fft->isOverThreshold(s, q, m_threshold)) continue; 1403 if (!fft->isOverThreshold(s, q, m_threshold * (m_fftSize/2))) continue;
1403 1404
1404 float freq = binfreq; 1405 float freq = binfreq;
1405 bool steady = false; 1406 bool steady = false;
1406 1407
1407 if (s < int(fft->getWidth()) - 1) { 1408 if (s < int(fft->getWidth()) - 1) {
1693 } 1694 }
1694 1695
1695 void 1696 void
1696 SpectrogramLayer::paint(View *v, QPainter &paint, QRect rect) const 1697 SpectrogramLayer::paint(View *v, QPainter &paint, QRect rect) const
1697 { 1698 {
1699 // What a lovely, old-fashioned function this is.
1700 // It's practically FORTRAN 77 in its clarity and linearity.
1701
1698 Profiler profiler("SpectrogramLayer::paint", true); 1702 Profiler profiler("SpectrogramLayer::paint", true);
1699 #ifdef DEBUG_SPECTROGRAM_REPAINT 1703 #ifdef DEBUG_SPECTROGRAM_REPAINT
1700 std::cerr << "SpectrogramLayer::paint(): m_model is " << m_model << ", zoom level is " << v->getZoomLevel() << ", m_updateTimer " << m_updateTimer << std::endl; 1704 std::cerr << "SpectrogramLayer::paint(): m_model is " << m_model << ", zoom level is " << v->getZoomLevel() << ", m_updateTimer " << m_updateTimer << std::endl;
1701 1705
1702 std::cerr << "rect is " << rect.x() << "," << rect.y() << " " << rect.width() << "x" << rect.height() << std::endl; 1706 std::cerr << "rect is " << rect.x() << "," << rect.y() << " " << rect.width() << "x" << rect.height() << std::endl;
1984 int sr = m_model->getSampleRate(); 1988 int sr = m_model->getSampleRate();
1985 1989
1986 // Set minFreq and maxFreq to the frequency extents of the possibly 1990 // Set minFreq and maxFreq to the frequency extents of the possibly
1987 // zero-padded visible bin range, and displayMinFreq and displayMaxFreq 1991 // zero-padded visible bin range, and displayMinFreq and displayMaxFreq
1988 // to the actual scale frequency extents (presumably not zero padded). 1992 // to the actual scale frequency extents (presumably not zero padded).
1989 1993
1990 size_t maxbin = fftSize / 2; 1994 // If we are zero padding, we want to use the zero-padded
1995 // equivalents of the bins that we would be using if not zero
1996 // padded, to avoid spaces at the top and bottom of the display.
1997
1998 // Note fftSize is the actual zero-padded fft size, m_fftSize the
1999 // nominal fft size.
2000
2001 size_t maxbin = m_fftSize / 2;
1991 if (m_maxFrequency > 0) { 2002 if (m_maxFrequency > 0) {
1992 maxbin = int((double(m_maxFrequency) * fftSize) / sr + 0.1); 2003 maxbin = int((double(m_maxFrequency) * m_fftSize) / sr + 0.001);
1993 if (maxbin > fftSize / 2) maxbin = fftSize / 2; 2004 if (maxbin > m_fftSize / 2) maxbin = m_fftSize / 2;
1994 } 2005 }
1995 2006
1996 size_t minbin = 1; 2007 size_t minbin = 1;
1997 if (m_minFrequency > 0) { 2008 if (m_minFrequency > 0) {
1998 minbin = int((double(m_minFrequency) * fftSize) / sr + 0.1); 2009 minbin = int((double(m_minFrequency) * m_fftSize) / sr + 0.001);
2010 // std::cerr << "m_minFrequency = " << m_minFrequency << " -> minbin = " << minbin << std::endl;
1999 if (minbin < 1) minbin = 1; 2011 if (minbin < 1) minbin = 1;
2000 if (minbin >= maxbin) minbin = maxbin - 1; 2012 if (minbin >= maxbin) minbin = maxbin - 1;
2001 } 2013 }
2014
2015 int zpl = getZeroPadLevel(v) + 1;
2016 minbin = minbin * zpl;
2017 maxbin = (maxbin + 1) * zpl - 1;
2002 2018
2003 float minFreq = (float(minbin) * sr) / fftSize; 2019 float minFreq = (float(minbin) * sr) / fftSize;
2004 float maxFreq = (float(maxbin) * sr) / fftSize; 2020 float maxFreq = (float(maxbin) * sr) / fftSize;
2005 2021
2006 float displayMinFreq = minFreq; 2022 float displayMinFreq = minFreq;
2008 2024
2009 if (fftSize != m_fftSize) { 2025 if (fftSize != m_fftSize) {
2010 displayMinFreq = getEffectiveMinFrequency(); 2026 displayMinFreq = getEffectiveMinFrequency();
2011 displayMaxFreq = getEffectiveMaxFrequency(); 2027 displayMaxFreq = getEffectiveMaxFrequency();
2012 } 2028 }
2029
2030 // std::cerr << "(giving actual minFreq " << minFreq << " and display minFreq " << displayMinFreq << ")" << std::endl;
2013 2031
2014 float ymag[h]; 2032 float ymag[h];
2015 float ydiv[h]; 2033 float ydiv[h];
2016 float yval[maxbin + 1]; //!!! cache this? 2034 float yval[maxbin + 1]; //!!! cache this?
2017 2035
2102 m_binDisplay == PeakFrequencies) { 2120 m_binDisplay == PeakFrequencies) {
2103 if (!fft->isLocalPeak(s, q)) continue; 2121 if (!fft->isLocalPeak(s, q)) continue;
2104 } 2122 }
2105 2123
2106 if (m_threshold != 0.f && 2124 if (m_threshold != 0.f &&
2107 !fft->isOverThreshold(s, q, m_threshold)) { 2125 !fft->isOverThreshold(s, q, m_threshold * (m_fftSize/2))) {
2108 continue; 2126 continue;
2109 } 2127 }
2110 2128
2111 float sprop = 1.0; 2129 float sprop = 1.0;
2112 if (s == s0i) sprop *= (s + 1) - s0; 2130 if (s == s0i) sprop *= (s + 1) - s0;
2411 bool 2429 bool
2412 SpectrogramLayer::getDisplayExtents(float &min, float &max) const 2430 SpectrogramLayer::getDisplayExtents(float &min, float &max) const
2413 { 2431 {
2414 min = getEffectiveMinFrequency(); 2432 min = getEffectiveMinFrequency();
2415 max = getEffectiveMaxFrequency(); 2433 max = getEffectiveMaxFrequency();
2434
2416 // std::cerr << "SpectrogramLayer::getDisplayExtents: " << min << "->" << max << std::endl; 2435 // std::cerr << "SpectrogramLayer::getDisplayExtents: " << min << "->" << max << std::endl;
2417 return true; 2436 return true;
2418 } 2437 }
2419 2438
2420 bool 2439 bool
2421 SpectrogramLayer::setDisplayExtents(float min, float max) 2440 SpectrogramLayer::setDisplayExtents(float min, float max)
2422 { 2441 {
2423 if (!m_model) return false; 2442 if (!m_model) return false;
2424 2443
2425 std::cerr << "SpectrogramLayer::setDisplayExtents: " << min << "->" << max << std::endl; 2444 // std::cerr << "SpectrogramLayer::setDisplayExtents: " << min << "->" << max << std::endl;
2426 2445
2427 if (min < 0) min = 0; 2446 if (min < 0) min = 0;
2428 if (max > m_model->getSampleRate()/2) max = m_model->getSampleRate()/2; 2447 if (max > m_model->getSampleRate()/2) max = m_model->getSampleRate()/2;
2429 2448
2430 size_t minf = lrintf(min); 2449 size_t minf = lrintf(min);
2954 } 2973 }
2955 2974
2956 void 2975 void
2957 SpectrogramLayer::setVerticalZoomStep(int step) 2976 SpectrogramLayer::setVerticalZoomStep(int step)
2958 { 2977 {
2959 //!!! does not do the right thing for log scale
2960
2961 if (!m_model) return; 2978 if (!m_model) return;
2962 2979
2963 float dmin, dmax; 2980 float dmin = m_minFrequency, dmax = m_maxFrequency;
2964 getDisplayExtents(dmin, dmax); 2981 // getDisplayExtents(dmin, dmax);
2982
2983 // std::cerr << "current range " << dmin << " -> " << dmax << ", range " << dmax-dmin << ", mid " << (dmax + dmin)/2 << std::endl;
2965 2984
2966 int sr = m_model->getSampleRate(); 2985 int sr = m_model->getSampleRate();
2967 SpectrogramRangeMapper mapper(sr, m_fftSize); 2986 SpectrogramRangeMapper mapper(sr, m_fftSize);
2968 float ddist = mapper.getValueForPosition(step); 2987 float newdist = mapper.getValueForPosition(step);
2969 2988
2970 float dmid = (dmax + dmin) / 2; 2989 float newmin, newmax;
2971 float newmin = dmid - ddist / 2; 2990
2972 float newmax = dmid + ddist / 2; 2991 if (m_frequencyScale == LogFrequencyScale) {
2992
2993 // need to pick newmin and newmax such that
2994 //
2995 // (log(newmin) + log(newmax)) / 2 == logmid
2996 // and
2997 // newmax - newmin = newdist
2998 //
2999 // so log(newmax - newdist) + log(newmax) == 2logmid
3000 // log(newmax(newmax - newdist)) == 2logmid
3001 // newmax.newmax - newmax.newdist == exp(2logmid)
3002 // newmax^2 + (-newdist)newmax + -exp(2logmid) == 0
3003 // quadratic with a = 1, b = -newdist, c = -exp(2logmid), all known
3004 //
3005 // positive root
3006 // newmax = (newdist + sqrt(newdist^2 + 4exp(2logmid))) / 2
3007 //
3008 // but logmid = (log(dmin) + log(dmax)) / 2
3009 // so exp(2logmid) = exp(log(dmin) + log(dmax))
3010 // = exp(log(dmin.dmax))
3011 // = dmin.dmax
3012 // so newmax = (newdist + sqrtf(newdist^2 + 4dmin.dmax)) / 2
3013
3014 newmax = (newdist + sqrtf(newdist*newdist + 4*dmin*dmax)) / 2;
3015 newmin = newmax - newdist;
3016
3017 // std::cerr << "newmin = " << newmin << ", newmax = " << newmax << std::endl;
3018
3019 } else {
3020 float dmid = (dmax + dmin) / 2;
3021 newmin = dmid - newdist / 2;
3022 newmax = dmid + newdist / 2;
3023 }
2973 3024
2974 float mmin, mmax; 3025 float mmin, mmax;
2975 mmin = 0; 3026 mmin = 0;
2976 mmax = float(sr) / 2; 3027 mmax = float(sr) / 2;
2977 3028
2981 } 3032 }
2982 if (newmax > mmax) { 3033 if (newmax > mmax) {
2983 newmax = mmax; 3034 newmax = mmax;
2984 } 3035 }
2985 3036
2986 // std::cerr << "SpectrogramLayer::setVerticalZoomStep: " << step << ": " << newmin << " -> " << newmax << " (range " << ddist << ")" << std::endl; 3037 // std::cerr << "SpectrogramLayer::setVerticalZoomStep: " << step << ": " << newmin << " -> " << newmax << " (range " << newdist << ")" << std::endl;
2987 3038
2988 setMinFrequency(int(newmin)); 3039 setMinFrequency(lrintf(newmin));
2989 setMaxFrequency(int(newmax)); 3040 setMaxFrequency(lrintf(newmax));
2990 } 3041 }
2991 3042
2992 RangeMapper * 3043 RangeMapper *
2993 SpectrogramLayer::getNewVerticalZoomRangeMapper() const 3044 SpectrogramLayer::getNewVerticalZoomRangeMapper() const
2994 { 3045 {