Mercurial > hg > svgui
diff layer/SpectrogramLayer.cpp @ 1063:a0f234acd6e7 spectrogram-minor-refactor
Pull out column ops into ColumnOp
author | Chris Cannam |
---|---|
date | Mon, 20 Jun 2016 11:30:15 +0100 |
parents | 38ecdd5924ac |
children | 77564d4fff43 |
line wrap: on
line diff
--- a/layer/SpectrogramLayer.cpp Fri Jun 17 10:19:55 2016 +0100 +++ b/layer/SpectrogramLayer.cpp Mon Jun 20 11:30:15 2016 +0100 @@ -23,6 +23,7 @@ #include "base/Preferences.h" #include "base/RangeMapper.h" #include "base/LogRange.h" +#include "base/ColumnOp.h" #include "widgets/CommandHistory.h" #include "ColourMapper.h" #include "ImageRegionFinder.h" @@ -73,7 +74,7 @@ m_colourMap(0), m_frequencyScale(LinearFrequencyScale), m_binDisplay(AllBins), - m_normalization(NoNormalization), + m_normalization(ColumnOp::NoNormalization), m_lastEmittedZoomStep(-1), m_synchronous(false), m_haveDetailedScale(false), @@ -108,7 +109,7 @@ setFrequencyScale(LogFrequencyScale); setColourScale(LinearColourScale); setBinDisplay(PeakFrequencies); - setNormalization(NormalizeColumns); + setNormalization(ColumnOp::NormalizeColumns); colourConfigName = "spectrogram-melodic-colour"; colourConfigDefault = int(ColourMapper::Sunset); } @@ -367,7 +368,7 @@ *min = 0; *max = 3; - *deflt = int(NoNormalization); + *deflt = int(ColumnOp::NoNormalization); val = (int)m_normalization; } else { @@ -572,10 +573,10 @@ } else if (name == "Normalization") { switch (value) { default: - case 0: setNormalization(NoNormalization); break; - case 1: setNormalization(NormalizeColumns); break; - case 2: setNormalization(NormalizeVisibleArea); break; - case 3: setNormalization(NormalizeHybrid); break; + case 0: setNormalization(ColumnOp::NoNormalization); break; + case 1: setNormalization(ColumnOp::NormalizeColumns); break; + case 2: setNormalization(ColumnOp::NormalizeVisibleArea); break; + case 3: setNormalization(ColumnOp::NormalizeHybrid); break; } } } @@ -888,7 +889,7 @@ } void -SpectrogramLayer::setNormalization(Normalization n) +SpectrogramLayer::setNormalization(ColumnOp::Normalization n) { if (m_normalization == n) return; @@ -899,7 +900,7 @@ emit layerParametersChanged(); } -SpectrogramLayer::Normalization +ColumnOp::Normalization SpectrogramLayer::getNormalization() const { return m_normalization; @@ -1050,10 +1051,10 @@ double min = 0.0; double max = 1.0; - if (m_normalization == NormalizeVisibleArea) { + if (m_normalization == ColumnOp::NormalizeVisibleArea) { min = m_viewMags[v->getId()].getMin(); max = m_viewMags[v->getId()].getMax(); - } else if (m_normalization != NormalizeColumns) { + } else if (m_normalization != ColumnOp::NormalizeColumns) { if (m_colourScale == LinearColourScale //|| // m_colourScale == MeterColourScale) { ) { @@ -1686,7 +1687,7 @@ #ifdef DEBUG_SPECTROGRAM_REPAINT cerr << "SpectrogramLayer: magnitude range changed to [" << m_viewMags[v->getId()].getMin() << "->" << m_viewMags[v->getId()].getMax() << "]" << endl; #endif - if (m_normalization == NormalizeVisibleArea) { + if (m_normalization == ColumnOp::NormalizeVisibleArea) { cache.invalidate(); } } @@ -2129,7 +2130,7 @@ if (!m_synchronous) { - if ((m_normalization != NormalizeVisibleArea) || !overallMagChanged) { + if ((m_normalization != ColumnOp::NormalizeVisibleArea) || !overallMagChanged) { QRect areaLeft(0, 0, cache.getValidLeft(), h); QRect areaRight(cache.getValidRight(), 0, @@ -2263,9 +2264,9 @@ if (m_colourScale == PhaseColourScale) { fft->getPhasesAt(sx, values, minbin, maxbin - minbin + 1); /*!!! - } else if (m_normalization == NormalizeColumns) { + } else if (m_normalization == ColumnOp::NormalizeColumns) { fft->getNormalizedMagnitudesAt(sx, values, minbin, maxbin - minbin + 1); - } else if (m_normalization == NormalizeHybrid) { + } else if (m_normalization == ColumnOp::NormalizeHybrid) { float max = fft->getNormalizedMagnitudesAt (sx, values, minbin, maxbin - minbin + 1); float scale = log10f(max + 1.f); @@ -2290,7 +2291,7 @@ double value = values[bin - minbin]; if (m_colourScale != PhaseColourScale) { - if (m_normalization != NormalizeColumns) { + if (m_normalization != ColumnOp::NormalizeColumns) { value /= (m_fftSize/2.0); } mag.sample(float(value)); @@ -2386,92 +2387,6 @@ col.data() + minbin + bincount); } -vector<float> -SpectrogramLayer::scaleColumn(const vector<float> &in) const -{ - if (m_normalization == NormalizeColumns || - m_normalization == NormalizeHybrid) { - return in; - } - vector<float> out; - out.reserve(in.size()); - float scale = 2.f / float(m_fftSize); - for (auto v: in) { - out.push_back(v * scale); - } - return out; -} - -static bool -is_peak(const vector<float> &values, int ix) -{ - if (!in_range_for(values, ix-1)) return false; - if (!in_range_for(values, ix+1)) 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) const -{ - 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; - } - - 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) { - - 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 @@ -2479,7 +2394,7 @@ bool &overallMagChanged) const { if (!in_range_for(m_columnMags, sx)) { - throw logic_error("sx out of range for m_columnMags"); + m_columnMags.resize(sx + 1); } MagnitudeRange mr; for (auto v: col) { @@ -2491,73 +2406,6 @@ } } -vector<float> -SpectrogramLayer::normalizeColumn(const vector<float> &in) const -{ - if (m_normalization == NoNormalization || - m_normalization == NormalizeVisibleArea) { - // NormalizeVisibleArea is handled through adjustment to m_gain - return in; - } - - float max = *max_element(in.begin(), in.end()); - - if (m_normalization == NormalizeColumns && max == 0.f) { - return in; - } - - if (m_normalization == NormalizeHybrid && max <= 0.f) { - return in; - } - - vector<float> out; - out.reserve(in.size()); - - float scale; - if (m_normalization == NormalizeHybrid) { - scale = log10f(max + 1.f) / max; - } else { - scale = 1.f / max; - } - - for (auto v: in) { - out.push_back(v * scale); - } - return out; -} - -vector<float> -SpectrogramLayer::peakPickColumn(const vector<float> &in) const -{ - if (m_binDisplay == AllBins) return in; - - vector<float> out(in.size(), 0.f); - - for (int i = 0; in_range_for(in, i); ++i) { - if (is_peak(in, i)) { - out[i] = in[i]; - } - } - - return out; -} - -vector<float> -SpectrogramLayer::applyDisplayGain(const vector<float> &in) const -{ - if (m_gain == 1.0) return in; - - vector<float> out; - out.reserve(in.size()); - for (auto v: in) { - out.push_back(v * m_gain); - } - return out; -} - -// order: -// get column -> scale -> record extents -> normalise -> peak pick -> apply display gain -> distribute/interpolate - int SpectrogramLayer::paintDrawBuffer(LayerGeometryProvider *v, int w, @@ -2664,7 +2512,12 @@ if (sx != psx) { - vector<float> column; + // order: get column -> scale -> record extents -> + // normalise -> peak pick -> apply display gain -> + // distribute/interpolate + + ColumnOp::Column column; + if (peakCacheModel) { column = getColumnFromGenericModel(peakCacheModel, sx, @@ -2677,22 +2530,26 @@ maxbin - minbin + 1); } - column = scaleColumn(column); - + column = ColumnOp::fftScale(column, m_fftSize); + recordColumnExtents(column, sx, overallMag, overallMagChanged); + column = ColumnOp::normalize(column, m_normalization); + + if (m_binDisplay == PeakBins) { + column = ColumnOp::peakPick(column); + } + preparedColumn = - distributeColumn(applyDisplayGain - (peakPickColumn - (normalizeColumn - (column))), - h, - binfory, - minbin, - interpolate); + ColumnOp::distribute + (ColumnOp::applyGain(column, m_gain), + h, + binfory, + minbin, + interpolate); psx = sx; } @@ -3588,8 +3445,8 @@ // area as well afterwards s += QString("columnNormalization=\"%1\" ") - .arg(m_normalization == NormalizeColumns ? "peak" : - m_normalization == NormalizeHybrid ? "hybrid" : "none"); + .arg(m_normalization == ColumnOp::NormalizeColumns ? "peak" : + m_normalization == ColumnOp::NormalizeHybrid ? "hybrid" : "none"); // Old-style normalization attribute. We *don't* write out // normalizeHybrid here because the only release that would accept @@ -3598,12 +3455,12 @@ // v2.0+ will look odd in Tony v1.0 s += QString("normalizeColumns=\"%1\" ") - .arg(m_normalization == NormalizeColumns ? "true" : "false"); + .arg(m_normalization == ColumnOp::NormalizeColumns ? "true" : "false"); // And this applies to both old- and new-style attributes s += QString("normalizeVisibleArea=\"%1\" ") - .arg(m_normalization == NormalizeVisibleArea ? "true" : "false"); + .arg(m_normalization == ColumnOp::NormalizeVisibleArea ? "true" : "false"); Layer::toXml(stream, indent, extraAttributes + " " + s); } @@ -3678,9 +3535,9 @@ haveNewStyleNormalization = true; if (columnNormalization == "peak") { - setNormalization(NormalizeColumns); + setNormalization(ColumnOp::NormalizeColumns); } else if (columnNormalization == "hybrid") { - setNormalization(NormalizeHybrid); + setNormalization(ColumnOp::NormalizeHybrid); } else if (columnNormalization == "none") { // do nothing } else { @@ -3694,23 +3551,23 @@ bool normalizeColumns = (attributes.value("normalizeColumns").trimmed() == "true"); if (normalizeColumns) { - setNormalization(NormalizeColumns); + setNormalization(ColumnOp::NormalizeColumns); } bool normalizeHybrid = (attributes.value("normalizeHybrid").trimmed() == "true"); if (normalizeHybrid) { - setNormalization(NormalizeHybrid); + setNormalization(ColumnOp::NormalizeHybrid); } } bool normalizeVisibleArea = (attributes.value("normalizeVisibleArea").trimmed() == "true"); if (normalizeVisibleArea) { - setNormalization(NormalizeVisibleArea); + setNormalization(ColumnOp::NormalizeVisibleArea); } - if (!haveNewStyleNormalization && m_normalization == NormalizeHybrid) { + if (!haveNewStyleNormalization && m_normalization == ColumnOp::NormalizeHybrid) { // Tony v1.0 is (and hopefully will remain!) the only released // SV-a-like to use old-style attributes when saving sessions // that ask for hybrid normalization. It saves them with the