# HG changeset patch # User Chris Cannam # Date 1542022474 0 # Node ID fc3d89f886909a90c39e3c9cef85c9252058cc8e # Parent 37e9d6a1e00cfe20d806b5ace9a3d69d01fcffe3 Use log-frequency rather than log-bin for calculating x coord in spectrum. This has the advantage that frequency positions don't move when we change the window size or oversampling ratio, but it does give us an unhelpfully large amount of space for very low frequencies - to be considered diff -r 37e9d6a1e00c -r fc3d89f88690 layer/SliceLayer.cpp --- a/layer/SliceLayer.cpp Thu Nov 08 12:55:36 2018 +0000 +++ b/layer/SliceLayer.cpp Mon Nov 12 11:34:34 2018 +0000 @@ -193,13 +193,20 @@ double SliceLayer::getXForBin(const LayerGeometryProvider *v, double bin) const { + return getXForScalePoint(v, bin, m_minbin, m_maxbin); +} + +double +SliceLayer::getXForScalePoint(const LayerGeometryProvider *v, + double p, double pmin, double pmax) const +{ double x = 0; - bin -= m_minbin; - if (bin < 0) bin = 0; + p -= pmin; + if (p < 0) p = 0; - double count = m_maxbin - m_minbin; - if (count < 0) count = 0; + double extent = pmax - pmin; + if (extent < 0) extent = 0; int pw = v->getPaintWidth(); int origin = m_xorigins[v->getId()]; @@ -209,7 +216,7 @@ switch (m_binScale) { case LinearBins: - x = (w * bin) / count; + x = (w * p) / extent; break; case LogBins: @@ -225,11 +232,11 @@ // as "a bit less than 1", so that most of it is visible but a // bit is tactfully cropped at the left edge so it doesn't // take up so much space. - x = (w * log10(bin + 0.8)) / log10(count + 0.8); + x = (w * log10(p + 0.8)) / log10(extent + 0.8); break; case InvertedLogBins: - x = w - (w * log10(count - bin - 1)) / log10(count); + x = w - (w * log10(extent - p - 1)) / log10(extent); break; } @@ -239,10 +246,17 @@ double SliceLayer::getBinForX(const LayerGeometryProvider *v, double x) const { - double bin = 0; + return getScalePointForX(v, x, m_minbin, m_maxbin); +} - double count = m_maxbin - m_minbin; - if (count < 0) count = 0; +double +SliceLayer::getScalePointForX(const LayerGeometryProvider *v, + double x, double pmin, double pmax) const +{ + double p = 0; + + double extent = pmax - pmin; + if (extent < 0) extent = 0; int pw = v->getPaintWidth(); int origin = m_xorigins[v->getId()]; @@ -258,20 +272,20 @@ switch (m_binScale) { case LinearBins: - bin = (x * count) / w + eps; + p = (x * extent) / w + eps; break; case LogBins: - // See comment in getXForBin - bin = pow(10.0, (x * log10(count + 0.8)) / w) - 0.8 + eps; + // See comment in getXForScalePoint + p = pow(10.0, (x * log10(extent + 0.8)) / w) - 0.8 + eps; break; case InvertedLogBins: - bin = count + 1 - pow(10.0, (log10(count) * (w - x)) / double(w)) + eps; + p = extent + 1 - pow(10.0, (log10(extent) * (w - x)) / double(w)) + eps; break; } - return bin + m_minbin; + return p + pmin; } double diff -r 37e9d6a1e00c -r fc3d89f88690 layer/SliceLayer.h --- a/layer/SliceLayer.h Thu Nov 08 12:55:36 2018 +0000 +++ b/layer/SliceLayer.h Mon Nov 12 11:34:34 2018 +0000 @@ -121,9 +121,22 @@ void modelAboutToBeDeleted(Model *); protected: + /// Convert a (possibly non-integral) bin into x-coord. May be overridden virtual double getXForBin(const LayerGeometryProvider *, double bin) const; + + /// Convert an x-coord into (possibly non-integral) bin. May be overridden virtual double getBinForX(const LayerGeometryProvider *, double x) const; + /// Convert a point such as a bin number into x-coord, given max & + /// min. For use by getXForBin etc + double getXForScalePoint(const LayerGeometryProvider *, + double p, double pmin, double pmax) const; + + /// Convert an x-coord into a point such as a bin number, given + /// max & min. For use by getBinForX etc + double getScalePointForX(const LayerGeometryProvider *, + double x, double pmin, double pmax) const; + virtual double getYForValue(const LayerGeometryProvider *v, double value, double &norm) const; virtual double getValueForY(const LayerGeometryProvider *v, double y) const; diff -r 37e9d6a1e00c -r fc3d89f88690 layer/SpectrumLayer.cpp --- a/layer/SpectrumLayer.cpp Thu Nov 08 12:55:36 2018 +0000 +++ b/layer/SpectrumLayer.cpp Mon Nov 12 11:34:34 2018 +0000 @@ -346,26 +346,61 @@ } double +SpectrumLayer::getBinForFrequency(double freq) const +{ + if (!m_sliceableModel) return 0; + double bin = (freq * getFFTSize()) / m_sliceableModel->getSampleRate(); + // we assume the frequency of a bin corresponds to the centre of + // its visual range + bin += 0.5; + return bin; +} + +double +SpectrumLayer::getBinForX(const LayerGeometryProvider *v, double x) const +{ + if (!m_sliceableModel) return 0; + double bin = getBinForFrequency(getFrequencyForX(v, x)); + return bin; +} + +double SpectrumLayer::getFrequencyForX(const LayerGeometryProvider *v, double x) const { if (!m_sliceableModel) return 0; - double bin = getBinForX(v, x); + double freq = getScalePointForX(v, x, + getFrequencyForBin(m_minbin), + getFrequencyForBin(m_maxbin)); + return freq; +} + +double +SpectrumLayer::getFrequencyForBin(double bin) const +{ + if (!m_sliceableModel) return 0; // we assume the frequency of a bin corresponds to the centre of // its visual range bin -= 0.5; - return (m_sliceableModel->getSampleRate() * bin) / - (m_sliceableModel->getHeight() * 2); + double freq = (bin * m_sliceableModel->getSampleRate()) / getFFTSize(); + return freq; +} + +double +SpectrumLayer::getXForBin(const LayerGeometryProvider *v, double bin) const +{ + if (!m_sliceableModel) return 0; + double x = getXForFrequency(v, getFrequencyForBin(bin)); + return x; } double SpectrumLayer::getXForFrequency(const LayerGeometryProvider *v, double freq) const { if (!m_sliceableModel) return 0; - double bin = (freq * m_sliceableModel->getHeight() * 2) / - m_sliceableModel->getSampleRate(); - // we want the centre of the bin range - bin += 0.5; - return getXForBin(v, bin); + double x = getXForScalePoint(v, freq, + getFrequencyForBin(m_minbin), + getFrequencyForBin(m_maxbin)); + return x; } bool diff -r 37e9d6a1e00c -r fc3d89f88690 layer/SpectrumLayer.h --- a/layer/SpectrumLayer.h Thu Nov 08 12:55:36 2018 +0000 +++ b/layer/SpectrumLayer.h Mon Nov 12 11:34:34 2018 +0000 @@ -125,6 +125,14 @@ void setupFFT(); + virtual double getBinForFrequency(double freq) const; + virtual double getFrequencyForBin(double bin) const; + + virtual double getXForBin(const LayerGeometryProvider *, double bin) + const override; + virtual double getBinForX(const LayerGeometryProvider *, double x) + const override; + virtual void getBiasCurve(BiasCurve &) const override; BiasCurve m_biasCurve;