Mercurial > hg > svgui
changeset 1058:9a13bc339fa9 spectrogram-minor-refactor
Mid-refactor to pull out the bulk of paintDrawBuffer into chunks
author | Chris Cannam |
---|---|
date | Mon, 13 Jun 2016 16:17:44 +0100 |
parents | 218be6cf2d4f |
children | e1c2dcc7790e |
files | layer/SpectrogramLayer.cpp layer/SpectrogramLayer.h |
diffstat | 2 files changed, 201 insertions(+), 44 deletions(-) [+] |
line wrap: on
line diff
--- a/layer/SpectrogramLayer.cpp Mon Jun 13 12:46:36 2016 +0100 +++ b/layer/SpectrogramLayer.cpp Mon Jun 13 16:17:44 2016 +0100 @@ -2352,6 +2352,187 @@ return columnCount; } +void +SpectrogramLayer::normalise(vector<float> &values, Normalization norm) const +{ + if (norm == NormalizeColumns || + norm == NormalizeHybrid) { + + float max = 0.f; + for (int i = 0; in_range_for(i, values); ++i) { + if (i == 0 || values[i] > max) { + max = values[i]; + } + } + if (max > 0.f) { + float scale = 1.f / max; + if (norm == NormalizeHybrid) { + scale = scale * log10f(max + 1.f); + } + for (int i = 0; in_range_for(i, values); ++i) { + values[i] *= scale; + } + } + } +} + +vector<float> +SpectrogramLayer::getColumnFromFFTModel(FFTModel *fft, + int sx, // column number in model + int minbin, + int bincount) const +{ + vector<float> values(bincount, 0.f); + + if (m_colourScale == PhaseColourScale) { + fft->getPhasesAt(sx, values.data(), minbin, bincount); + } else { + fft->getMagnitudesAt(sx, values.data(), minbin, bincount); + } + + return move(values); +} + +vector<float> +SpectrogramLayer::getColumnFromGenericModel(DenseThreeDimensionalModel *model, + int sx, // column number in model + int minbin, + int bincount) const +{ + if (m_colourScale == PhaseColourScale) { + throw std::logic_error("can't use phase scale with generic 3d model"); + } + + auto col = model->getColumn(sx); + + return move(vector<float>(col.data() + minbin, + col.data() + minbin + bincount)); +} + +void +SpectrogramLayer::scaleColumn(vector<float> &col) +{ + if (m_normalization != NormalizeColumns && + m_normalization != NormalizeHybrid) { + float scale = 2.f / float(m_fftSize); + int n = int(col.size()); + for (int i = 0; i < n; ++i) { + col[i] *= scale; + } + } +} + +static bool +is_peak(const vector<float> &values, int ix) +{ + if (!in_range_for(ix-1, values)) return false; + if (!in_range_for(ix+1, values)) return false; + if (values[ix] < values[ix+1]) return false; + if (values[ix] < values[ix-1]) return false; + return true; +} + +vector<float> +SpectrogramLayer::distributeColumn(const vector<float> &in, + int h, + const vector<double> &binfory, + int minbin, + bool interpolate) +{ + vector<float> out(h, 0.f); + int bins = int(in.size()); + + for (int y = 0; y < h; ++y) { + + double sy0 = binfory[y] - minbin; + double sy1 = sy0 + 1; + if (y+1 < h) { + sy1 = binfory[y+1] - minbin; + } + + if (interpolate && fabs(sy1 - sy0) < 1.0) { + + double centre = (sy0 + sy1) / 2; + double dist = (centre - 0.5) - rint(centre - 0.5); + int bin = int(centre); + + int other = (dist < 0 ? (bin-1) : (bin+1)); + + if (bin < 0) bin = 0; + if (bin >= bins) bin = bins-1; + + if (other < 0 || other >= bins) { + other = bin; + } + + if (m_binDisplay == PeakBins) { + + if (is_peak(in, bin)) { + out[y] = in[bin]; + } else if (other != bin && is_peak(in, other)) { + out[y] = in[other]; + } + + } else { + + double prop = 1.0 - fabs(dist); + + double v0 = in[bin]; + double v1 = in[other]; + + out[y] = float(prop * v0 + (1.0 - prop) * v1); + } + + } else { // not interpolating this one + + int by0 = int(sy0 + 0.0001); + int by1 = int(sy1 + 0.0001); + if (by1 < by0 + 1) by1 = by0 + 1; + + for (int bin = by0; bin < by1; ++bin) { + + if (m_binDisplay == PeakBins && !is_peak(in, bin)) { + continue; + } + + float value = in[bin]; + + if (value > out[y] || m_colourScale == PhaseColourScale) { + out[y] = value; + } + } + } + } + + return out; +} + +void +SpectrogramLayer::recordColumnExtents(const vector<float> &col, + int sx, // column index, for m_columnMags + MagnitudeRange &overallMag, + bool &overallMagChanged) +{ + //!!! this differs from previous logic when in peak mode - as the + //!!! zeros between peaks are now sampled, where they were not + //!!! before + + if (!in_range_for(sx, m_columnMags)) { + throw logic_error("sx out of range for m_columnMags"); + } + MagnitudeRange mr; + for (auto v: col) { + mr.sample(v); + } + m_columnMags[sx] = mr; + if (overallMag.sample(mr)) { + overallMagChanged = true; + } +} + +// order: +// get column -> scale -> distribute/interpolate -> record extents -> normalise -> apply display gain + int SpectrogramLayer::paintDrawBuffer(LayerGeometryProvider *v, int w,
--- a/layer/SpectrogramLayer.h Mon Jun 13 12:46:36 2016 +0100 +++ b/layer/SpectrogramLayer.h Mon Jun 13 16:17:44 2016 +0100 @@ -18,6 +18,7 @@ #include "SliceableLayer.h" #include "base/Window.h" +#include "base/MagnitudeRange.h" #include "base/RealTime.h" #include "base/Thread.h" #include "base/PropertyContainer.h" @@ -360,53 +361,12 @@ const int m_peakCacheDivisor; mutable Model *m_sliceableModel; - class MagnitudeRange { - public: - MagnitudeRange() : m_min(0), m_max(0) { } - bool operator==(const MagnitudeRange &r) { - return r.m_min == m_min && r.m_max == m_max; - } - bool isSet() const { return (m_min != 0.f || m_max != 0.f); } - void set(float min, float max) { - m_min = min; - m_max = max; - if (m_max < m_min) m_max = m_min; - } - bool sample(float f) { - bool changed = false; - if (isSet()) { - if (f < m_min) { m_min = f; changed = true; } - if (f > m_max) { m_max = f; changed = true; } - } else { - m_max = m_min = f; - changed = true; - } - return changed; - } - bool sample(const MagnitudeRange &r) { - bool changed = false; - if (isSet()) { - if (r.m_min < m_min) { m_min = r.m_min; changed = true; } - if (r.m_max > m_max) { m_max = r.m_max; changed = true; } - } else { - m_min = r.m_min; - m_max = r.m_max; - changed = true; - } - return changed; - } - float getMin() const { return m_min; } - float getMax() const { return m_max; } - private: - float m_min; - float m_max; - }; - typedef std::map<int, MagnitudeRange> ViewMagMap; // key is view id mutable ViewMagMap m_viewMags; mutable std::vector<MagnitudeRange> m_columnMags; void invalidateMagnitudes(); bool updateViewMagnitudes(LayerGeometryProvider *v) const; + int paintDrawBuffer(LayerGeometryProvider *v, int w, int h, const std::vector<int> &binforx, const std::vector<double> &binfory, @@ -427,8 +387,24 @@ bool rightToLeft, double softTimeLimit) const; - virtual void updateMeasureRectYCoords(LayerGeometryProvider *v, const MeasureRect &r) const; - virtual void setMeasureRectYCoord(LayerGeometryProvider *v, MeasureRect &r, bool start, int y) const; + void normalise(std::vector<float> &, Normalization norm) const; + + std::vector<float> getColumnFromFFTModel(FFTModel *model, + int sx, + int minbin, + int bincount) const; + + std::vector<float> getColumnFromGenericModel(DenseThreeDimensionalModel *model, + int sx, + int minbin, + int bincount) const; + + void scaleColumn(std::vector<float> &col) const; + + virtual void updateMeasureRectYCoords(LayerGeometryProvider *v, + const MeasureRect &r) const; + virtual void setMeasureRectYCoord(LayerGeometryProvider *v, + MeasureRect &r, bool start, int y) const; }; #endif