Mercurial > hg > svgui
changeset 1086:163cb9b98104 spectrogram-minor-refactor
Simplify the oversampling/zero-padding logic. FFT model selection no longer depends on the view.
author | Chris Cannam |
---|---|
date | Fri, 01 Jul 2016 18:30:42 +0100 |
parents | 179ea8a2f650 |
children | 6d990a24ac1b |
files | layer/SpectrogramLayer.cpp layer/SpectrogramLayer.h |
diffstat | 2 files changed, 43 insertions(+), 146 deletions(-) [+] |
line wrap: on
line diff
--- a/layer/SpectrogramLayer.cpp Fri Jul 01 17:54:31 2016 +0100 +++ b/layer/SpectrogramLayer.cpp Fri Jul 01 18:30:42 2016 +0100 @@ -61,7 +61,6 @@ m_windowSize(1024), m_windowType(HanningWindow), m_windowHopLevel(2), - m_zeroPadLevel(0), m_fftSize(1024), m_gain(1.0), m_initialGain(1.0), @@ -171,7 +170,6 @@ // list.push_back("Min Frequency"); // list.push_back("Max Frequency"); list.push_back("Frequency Scale"); -//// list.push_back("Zero Padding"); return list; } @@ -190,7 +188,6 @@ if (name == "Min Frequency") return tr("Min Frequency"); if (name == "Max Frequency") return tr("Max Frequency"); if (name == "Frequency Scale") return tr("Frequency Scale"); - if (name == "Zero Padding") return tr("Smoothing"); return ""; } @@ -206,7 +203,6 @@ if (name == "Gain") return RangeProperty; if (name == "Colour Rotation") return RangeProperty; if (name == "Threshold") return RangeProperty; - if (name == "Zero Padding") return ToggleProperty; return ValueProperty; } @@ -216,8 +212,7 @@ if (name == "Bin Display" || name == "Frequency Scale") return tr("Bins"); if (name == "Window Size" || - name == "Window Increment" || - name == "Zero Padding") return tr("Window"); + name == "Window Increment") return tr("Window"); if (name == "Colour" || name == "Threshold" || name == "Colour Rotation") return tr("Colour"); @@ -306,14 +301,6 @@ val = m_windowHopLevel; - } else if (name == "Zero Padding") { - - *min = 0; - *max = 1; - *deflt = 0; - - val = m_zeroPadLevel > 0 ? 1 : 0; - } else if (name == "Min Frequency") { *min = 0; @@ -414,10 +401,6 @@ case 5: return tr("93.75 %"); } } - if (name == "Zero Padding") { - if (value == 0) return tr("None"); - return QString("%1x").arg(value + 1); - } if (name == "Min Frequency") { switch (value) { default: @@ -510,8 +493,6 @@ setWindowSize(32 << value); } else if (name == "Window Increment") { setWindowHopLevel(value); - } else if (name == "Zero Padding") { - setZeroPadLevel(value > 0.1 ? 3 : 0); } else if (name == "Min Frequency") { switch (value) { default: @@ -605,6 +586,7 @@ return; } if (name == "Spectrogram Y Smoothing") { + setWindowSize(m_windowSize); invalidateImageCaches(); invalidateMagnitudes(); emit layerParametersChanged(); @@ -637,15 +619,35 @@ return m_channel; } +int +SpectrogramLayer::getFFTOversampling() const +{ + if (m_binDisplay != AllBins) { + return 1; + } + + Preferences::SpectrogramSmoothing smoothing = + Preferences::getInstance()->getSpectrogramSmoothing(); + + if (smoothing == Preferences::NoSpectrogramSmoothing || + smoothing == Preferences::SpectrogramInterpolated) { + return 1; + } + + return 4; +} + void SpectrogramLayer::setWindowSize(int ws) { - if (m_windowSize == ws) return; + int fftSize = ws * getFFTOversampling(); + + if (m_windowSize == ws && m_fftSize == fftSize) return; invalidateImageCaches(); m_windowSize = ws; - m_fftSize = ws * (m_zeroPadLevel + 1); + m_fftSize = fftSize; invalidateFFTModels(); @@ -681,27 +683,6 @@ } void -SpectrogramLayer::setZeroPadLevel(int v) -{ - if (m_zeroPadLevel == v) return; - - invalidateImageCaches(); - - m_zeroPadLevel = v; - m_fftSize = m_windowSize * (v + 1); - - invalidateFFTModels(); - - emit layerParametersChanged(); -} - -int -SpectrogramLayer::getZeroPadLevel() const -{ - return m_zeroPadLevel; -} - -void SpectrogramLayer::setWindowType(WindowType w) { if (m_windowType == w) return; @@ -1175,8 +1156,7 @@ q0 = v->getFrequencyForY(y, minf, maxf, logarithmic); q1 = v->getFrequencyForY(y - 1, minf, maxf, logarithmic); - // Now map these on to ("proportions of") actual bins, using raw - // FFT size (unsmoothed) + // Now map these on to ("proportions of") actual bins q0 = (q0 * m_fftSize) / sr; q1 = (q1 * m_fftSize) / sr; @@ -1184,32 +1164,6 @@ return true; } -bool -SpectrogramLayer::getSmoothedYBinRange(LayerGeometryProvider *v, int y, double &q0, double &q1) const -{ - Profiler profiler("SpectrogramLayer::getSmoothedYBinRange"); - - int h = v->getPaintHeight(); - if (y < 0 || y >= h) return false; - - sv_samplerate_t sr = m_model->getSampleRate(); - double minf = getEffectiveMinFrequency(); - double maxf = getEffectiveMaxFrequency(); - - bool logarithmic = (m_frequencyScale == LogFrequencyScale); - - q0 = v->getFrequencyForY(y, minf, maxf, logarithmic); - q1 = v->getFrequencyForY(y - 1, minf, maxf, logarithmic); - - // Now map these on to ("proportions of") actual bins, using raw - // FFT size (unsmoothed) - - q0 = (q0 * getFFTSize(v)) / sr; - q1 = (q1 * getFFTSize(v)) / sr; - - return true; -} - double SpectrogramLayer::getYForBin(LayerGeometryProvider *, double bin) const { //!!! not implemented @@ -1233,8 +1187,7 @@ double q = v->getFrequencyForY(y, minf, maxf, logarithmic); - // Now map on to ("proportions of") actual bins, using raw FFT - // size (unsmoothed) + // Now map on to ("proportions of") actual bins q = (q * getFFTSize(v)) / sr; @@ -1345,7 +1298,10 @@ if (peaksOnly && !fft->isLocalPeak(s, q)) continue; - if (!fft->isOverThreshold(s, q, float(m_threshold * double(m_fftSize)/2.0))) continue; + if (!fft->isOverThreshold + (s, q, float(m_threshold * double(m_fftSize)/2.0))) { + continue; + } double freq = binfreq; @@ -1391,10 +1347,6 @@ bool rv = false; - int zp = getZeroPadLevel(v); - q0i *= zp + 1; - q1i *= zp + 1; - FFTModel *fft = getFFTModel(v); if (fft) { @@ -1436,52 +1388,10 @@ } int -SpectrogramLayer::getZeroPadLevel(const LayerGeometryProvider *v) const +SpectrogramLayer::getFFTSize(const LayerGeometryProvider *) const { - //!!! tidy all this stuff - - if (m_binDisplay != AllBins) return 0; - - Preferences::SpectrogramSmoothing smoothing = - Preferences::getInstance()->getSpectrogramSmoothing(); - - if (smoothing == Preferences::NoSpectrogramSmoothing || - smoothing == Preferences::SpectrogramInterpolated) return 0; - - if (m_frequencyScale == LogFrequencyScale) return 3; - - sv_samplerate_t sr = m_model->getSampleRate(); - - int maxbin = m_fftSize / 2; - if (m_maxFrequency > 0) { - maxbin = int((double(m_maxFrequency) * m_fftSize) / sr + 0.1); - if (maxbin > m_fftSize / 2) maxbin = m_fftSize / 2; - } - - int minbin = 1; - if (m_minFrequency > 0) { - minbin = int((double(m_minFrequency) * m_fftSize) / sr + 0.1); - if (minbin < 1) minbin = 1; - if (minbin >= maxbin) minbin = maxbin - 1; - } - - double perPixel = - double(v->getPaintHeight()) / - double((maxbin - minbin) / (m_zeroPadLevel + 1)); - - if (perPixel > 2.8) { - return 3; // 4x oversampling - } else if (perPixel > 1.5) { - return 1; // 2x - } else { - return 0; // 1x - } -} - -int -SpectrogramLayer::getFFTSize(const LayerGeometryProvider *v) const -{ - return m_fftSize * (getZeroPadLevel(v) + 1); + //!!! + return m_fftSize; } FFTModel * @@ -1834,12 +1744,10 @@ // zero-padded visible bin range, and displayMinFreq and displayMaxFreq // to the actual scale frequency extents (presumably not zero padded). - // If we are zero padding, we want to use the zero-padded - // equivalents of the bins that we would be using if not zero - // padded, to avoid spaces at the top and bottom of the display. - - // Note fftSize is the actual zero-padded fft size, m_fftSize the - // nominal fft size. + // If we are zero padding (i.e. oversampling) we want to use the + // zero-padded equivalents of the bins that we would be using if + // not zero padded, to avoid spaces at the top and bottom of the + // display. int maxbin = m_fftSize / 2; if (m_maxFrequency > 0) { @@ -1855,9 +1763,9 @@ if (minbin >= maxbin) minbin = maxbin - 1; } - int zpl = getZeroPadLevel(v) + 1; - minbin = minbin * zpl; - maxbin = (maxbin + 1) * zpl - 1; + int over = getFFTOversampling(); + minbin = minbin * over; + maxbin = (maxbin + 1) * over - 1; double minFreq = (double(minbin) * sr) / fftSize; double maxFreq = (double(maxbin) * sr) / fftSize; @@ -2008,7 +1916,7 @@ for (int y = 0; y < h; ++y) { double q0 = 0, q1 = 0; - if (!getSmoothedYBinRange(v, h-y-1, q0, q1)) { + if (!getYBinRange(v, h-y-1, q0, q1)) { binfory[y] = -1; } else { binfory[y] = q0;
--- a/layer/SpectrogramLayer.h Fri Jul 01 17:54:31 2016 +0100 +++ b/layer/SpectrogramLayer.h Fri Jul 01 18:30:42 2016 +0100 @@ -115,9 +115,6 @@ void setWindowType(WindowType type); WindowType getWindowType() const; - void setZeroPadLevel(int level); - int getZeroPadLevel() const; - /** * Set the gain multiplier for sample values in this view. * The default is 1.0. @@ -255,8 +252,7 @@ int m_windowSize; WindowType m_windowType; int m_windowHopLevel; - int m_zeroPadLevel; - int m_fftSize; + int m_fftSize; // m_windowSize * oversampling level float m_gain; float m_initialGain; float m_threshold; @@ -325,15 +321,8 @@ double getEffectiveMinFrequency() const; double getEffectiveMaxFrequency() const; - // Note that the getYBin... methods return the nominal bin in the - // un-smoothed spectrogram. This is not necessarily the same bin - // as is pulled from the spectrogram and drawn at the given - // position, if the spectrogram has oversampling smoothing. Use - // getSmoothedYBinRange to obtain that. - bool getXBinRange(LayerGeometryProvider *v, int x, double &windowMin, double &windowMax) const; bool getYBinRange(LayerGeometryProvider *v, int y, double &freqBinMin, double &freqBinMax) const; - bool getSmoothedYBinRange(LayerGeometryProvider *v, int y, double &freqBinMin, double &freqBinMax) const; bool getYBinSourceRange(LayerGeometryProvider *v, int y, double &freqMin, double &freqMax) const; bool getAdjustedYBinSourceRange(LayerGeometryProvider *v, int x, int y, @@ -349,7 +338,7 @@ else return m_windowSize / (1 << (m_windowHopLevel - 1)); } - int getZeroPadLevel(const LayerGeometryProvider *v) const; + int getFFTOversampling() const; int getFFTSize(const LayerGeometryProvider *v) const; FFTModel *getFFTModel(const LayerGeometryProvider *v) const; Dense3DModelPeakCache *getPeakCache(const LayerGeometryProvider *v) const;