Mercurial > hg > svgui
changeset 1097:92ac1fce7102 spectrogram-minor-refactor
Introduce peak frequency rendering (basics of)
author | Chris Cannam |
---|---|
date | Mon, 11 Jul 2016 16:03:39 +0100 |
parents | 6288f1b5f49b |
children | d9f1d2756b59 |
files | layer/Colour3DPlotLayer.h layer/Colour3DPlotRenderer.cpp layer/Colour3DPlotRenderer.h |
diffstat | 3 files changed, 173 insertions(+), 2 deletions(-) [+] |
line wrap: on
line diff
--- a/layer/Colour3DPlotLayer.h Mon Jul 11 14:37:03 2016 +0100 +++ b/layer/Colour3DPlotLayer.h Mon Jul 11 16:03:39 2016 +0100 @@ -19,6 +19,9 @@ #include "SliceableLayer.h" #include "VerticalBinLayer.h" +#include "ColourScale.h" +#include "Colour3DPlotRenderer.h" + #include "data/model/DenseThreeDimensionalModel.h" class View; @@ -194,7 +197,7 @@ // always snap to whole bins at view edges. int m_miny; int m_maxy; - + /** * Return the y coordinate at which the given bin "starts" * (i.e. at the bottom of the bin, if the given bin is an integer
--- a/layer/Colour3DPlotRenderer.cpp Mon Jul 11 14:37:03 2016 +0100 +++ b/layer/Colour3DPlotRenderer.cpp Mon Jul 11 16:03:39 2016 +0100 @@ -279,13 +279,26 @@ binfory[y] = m_sources.verticalBinLayer->getBinForY(v, h - y - 1); } - int attainedWidth = renderDrawBuffer(repaintWidth, + int attainedWidth; + + if (m_params.binDisplay == PeakFrequencies) { + attainedWidth = renderDrawBufferPeakFrequencies(v, + repaintWidth, + h, + binforx, + binfory, + rightToLeft, + timeConstrained); + + } else { + attainedWidth = renderDrawBuffer(repaintWidth, h, binforx, binfory, usePeaksCache, rightToLeft, timeConstrained); + } if (attainedWidth == 0) return; @@ -576,6 +589,152 @@ return columnCount; } +int +Colour3DPlotRenderer::renderDrawBufferPeakFrequencies(LayerGeometryProvider *v, + int w, int h, + const vector<int> &binforx, + const vector<double> &binfory, + bool rightToLeft, + bool timeConstrained) +{ + // Callers must have checked that the appropriate subset of + // Sources data members are set for the supplied flags (e.g. that + // fft model exists) + + RenderTimer timer(timeConstrained ? + RenderTimer::FastRender : + RenderTimer::NoTimeout); + + int minbin = int(binfory[0] + 0.0001); + int maxbin = int(binfory[h-1]); + if (minbin < 0) minbin = 0; + if (maxbin < 0) maxbin = minbin+1; + + FFTModel *fft = m_sources.fft; + + FFTModel::PeakSet peakfreqs; + + int psx = -1; + + int start = 0; + int finish = w; + int step = 1; + + if (rightToLeft) { + start = w-1; + finish = -1; + step = -1; + } + + int columnCount = 0; + + vector<float> preparedColumn; + + int modelWidth = fft->getWidth(); + cerr << "modelWidth " << modelWidth << endl; + + double minFreq = (double(minbin) * fft->getSampleRate()) / fft->getFFTSize(); + double maxFreq = (double(maxbin) * fft->getSampleRate()) / fft->getFFTSize(); + + bool logarithmic = (m_params.binScale == LogBinScale); + + for (int x = start; x != finish; x += step) { + + // x is the on-canvas pixel coord; sx (later) will be the + // source column index + + ++columnCount; + + if (binforx[x] < 0) continue; + + int sx0 = binforx[x]; + int sx1 = sx0; + if (x+1 < w) sx1 = binforx[x+1]; + if (sx0 < 0) sx0 = sx1 - 1; + if (sx0 < 0) continue; + if (sx1 <= sx0) sx1 = sx0 + 1; + + vector<float> pixelPeakColumn; + + for (int sx = sx0; sx < sx1; ++sx) { + + if (sx < 0 || sx >= modelWidth) { + continue; + } + + if (sx != psx) { + + ColumnOp::Column fullColumn = fft->getColumn(sx); + + ColumnOp::Column column = + vector<float>(fullColumn.data() + minbin, + fullColumn.data() + maxbin + 1); + +//!!! fft scale if (m_colourScale != ColourScale::PhaseColourScale) { +// column = ColumnOp::fftScale(column, getFFTSize()); +// } + +//!!! extents recordColumnExtents(column, +// sx, +// overallMag, +// overallMagChanged); + +//!!! if (m_colourScale != ColourScale::PhaseColourScale) { + column = ColumnOp::normalize(column, m_params.normalization); +//!!! } + + preparedColumn = column; +//!!! gain? preparedColumn = ColumnOp::applyGain(column, m_params.gain); + + psx = sx; + } + + if (sx == sx0) { + pixelPeakColumn = preparedColumn; + peakfreqs = fft->getPeakFrequencies(FFTModel::AllPeaks, sx, + minbin, maxbin - 1); + } else { + for (int i = 0; in_range_for(pixelPeakColumn, i); ++i) { + pixelPeakColumn[i] = std::max(pixelPeakColumn[i], + preparedColumn[i]); + } + } + } + + if (!pixelPeakColumn.empty()) { + for (FFTModel::PeakSet::const_iterator pi = peakfreqs.begin(); + pi != peakfreqs.end(); ++pi) { + + int bin = pi->first; + double freq = pi->second; + + if (bin < minbin) continue; + if (bin > maxbin) break; + + double value = pixelPeakColumn[bin - minbin]; + + double y = v->getYForFrequency + (freq, minFreq, maxFreq, logarithmic); + + int iy = int(y + 0.5); + if (iy < 0 || iy >= h) continue; + + m_drawBuffer.setPixel + (x, + iy, + m_params.colourScale.getPixel(value)); + } + } + + double fractionComplete = double(columnCount) / double(w); + if (timer.outOfTime(fractionComplete)) { + return columnCount; + } + } + + return columnCount; +} + void Colour3DPlotRenderer::recreateDrawBuffer(int w, int h) {
--- a/layer/Colour3DPlotRenderer.h Mon Jul 11 14:37:03 2016 +0100 +++ b/layer/Colour3DPlotRenderer.h Mon Jul 11 16:03:39 2016 +0100 @@ -190,12 +190,21 @@ bool timeConstrained); void renderToCacheBinResolution(LayerGeometryProvider *v, int x0, int repaintWidth); + int renderDrawBuffer(int w, int h, const std::vector<int> &binforx, const std::vector<double> &binfory, bool usePeaksCache, bool rightToLeft, bool timeConstrained); + + int renderDrawBufferPeakFrequencies(LayerGeometryProvider *v, + int w, int h, + const std::vector<int> &binforx, + const std::vector<double> &binfory, + bool rightToLeft, + bool timeConstrained); + void recreateDrawBuffer(int w, int h); void clearDrawBuffer(int w, int h); };