Mercurial > hg > svgui
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 { |