Mercurial > hg > svgui
changeset 1338:6d091348e4e9 zoom
Get oversampled rendering almost working, but I think we need to take more care with the oversampling itself
author | Chris Cannam |
---|---|
date | Tue, 25 Sep 2018 16:38:50 +0100 |
parents | 4f9a3c84be60 |
children | b0555b434575 |
files | layer/WaveformLayer.cpp layer/WaveformLayer.h |
diffstat | 2 files changed, 178 insertions(+), 131 deletions(-) [+] |
line wrap: on
line diff
--- a/layer/WaveformLayer.cpp Tue Sep 25 12:52:08 2018 +0100 +++ b/layer/WaveformLayer.cpp Tue Sep 25 16:38:50 2018 +0100 @@ -33,7 +33,8 @@ #include <bqresample/Resampler.h> -//#define DEBUG_WAVEFORM_PAINT 1 +#define DEBUG_WAVEFORM_PAINT 1 +//#define DEBUG_WAVEFORM_PAINT_BY_PIXEL 1 using std::vector; @@ -50,8 +51,6 @@ m_scale(LinearScale), m_middleLineHeight(0.5), m_aggressive(false), - m_oversampleRate(8), - m_oversampleTail(200), m_oversampler(0), m_cache(0), m_cacheValid(false) @@ -88,8 +87,10 @@ delete m_oversampler; breakfastquay::Resampler::Parameters params; params.initialSampleRate = m_model->getSampleRate(); - m_oversampler = new breakfastquay::Resampler - (params, m_model->getChannelCount()); + // Oversampler is initialised with 1 channel: we resample the + // channels individually for practical reasons (because channel + // configuration may vary) + m_oversampler = new breakfastquay::Resampler(params, 1); connectSignals(m_model); @@ -433,7 +434,6 @@ } f0 = viewFrame; - f0 = f0 / modelZoomLevel; f0 = f0 * modelZoomLevel; @@ -497,7 +497,7 @@ #ifdef DEBUG_WAVEFORM_PAINT Profiler profiler("WaveformLayer::paint", true); - cerr << "WaveformLayer::paint (" << rect.x() << "," << rect.y() + SVCERR << "WaveformLayer::paint (" << rect.x() << "," << rect.y() << ") [" << rect.width() << "x" << rect.height() << "]: zoom " << zoomLevel << endl; #endif @@ -516,7 +516,7 @@ if (m_aggressive) { #ifdef DEBUG_WAVEFORM_PAINT - cerr << "WaveformLayer::paint: aggressive is true" << endl; + SVCERR << "WaveformLayer::paint: aggressive is true" << endl; #endif using namespace std::rel_ops; @@ -528,7 +528,7 @@ if (!m_cache || m_cache->width() != w || m_cache->height() != h) { #ifdef DEBUG_WAVEFORM_PAINT if (m_cache) { - cerr << "WaveformLayer::paint: cache size " << m_cache->width() << "x" << m_cache->height() << " differs from view size " << w << "x" << h << ": regenerating aggressive cache" << endl; + SVCERR << "WaveformLayer::paint: cache size " << m_cache->width() << "x" << m_cache->height() << " differs from view size " << w << "x" << h << ": regenerating aggressive cache" << endl; } #endif delete m_cache; @@ -603,9 +603,10 @@ getSourceFramesForX(v, x1, blockSize, spare, frame1); #ifdef DEBUG_WAVEFORM_PAINT - cerr << "Painting waveform from " << frame0 << " to " << frame1 << " (" << (x1-x0+1) << " pixels at zoom " << zoomLevel << " and model zoom " << blockSize << ")" << endl; + SVCERR << "Painting waveform from " << frame0 << " to " << frame1 << " (" << (x1-x0+1) << " pixels at zoom " << zoomLevel << " and model zoom " << blockSize << ")" << endl; #endif + m_effectiveGains.clear(); while ((int)m_effectiveGains.size() <= maxChannel) { m_effectiveGains.push_back(m_gain); } @@ -615,38 +616,22 @@ } } + RangeVec ranges; + if (v->getZoomLevel().zone == ZoomLevel::FramesPerPixel) { - - vector<RangeSummarisableTimeValueModel::RangeBlock> ranges; + getSummaryRanges(minChannel, maxChannel, + mixingChannels || mergingChannels, + frame0, frame1, + blockSize, ranges); + } else { + getOversampledRanges(minChannel, maxChannel, + mixingChannels || mergingChannels, + frame0, frame1, + v->getZoomLevel().level, ranges); + } - for (int ch = minChannel; ch <= maxChannel; ++ch) { - ranges.push_back({}); - m_model->getSummaries(ch, frame0, frame1 - frame0, - ranges[ch - minChannel], blockSize); -#ifdef DEBUG_WAVEFORM_PAINT - cerr << "channel " << ch << ": " << ranges[ch - minChannel].size() << " ranges from " << frame0 << " to " << frame1 << " at zoom level " << blockSize << endl; -#endif - } - - if (mergingChannels || mixingChannels) { - if (minChannel != 0 || maxChannel != 0) { - SVCERR << "Internal error: min & max channels should be 0 when merging or mixing all channels" << endl; - } else if (m_model->getChannelCount() > 1) { - ranges.push_back({}); - m_model->getSummaries - (1, frame0, frame1 - frame0, ranges[1], blockSize); - } - } - - for (int ch = minChannel; ch <= maxChannel; ++ch) { - paintChannelSummarised(v, paint, rect, ch, - ranges, blockSize, frame0, frame1); - } - } else { - - for (int ch = minChannel; ch <= maxChannel; ++ch) { - paintChannelOversampled(v, paint, rect, ch, frame0, frame1); - } + for (int ch = minChannel; ch <= maxChannel; ++ch) { + paintChannel(v, paint, rect, ch, ranges, blockSize, frame0, frame1); } if (m_middleLineHeight != 0.5) { @@ -665,12 +650,108 @@ } void -WaveformLayer::paintChannelSummarised(LayerGeometryProvider *v, - QPainter *paint, - QRect rect, int ch, - const vector<RangeSummarisableTimeValueModel::RangeBlock> &ranges, - int blockSize, - sv_frame_t frame0, sv_frame_t frame1) +WaveformLayer::getSummaryRanges(int minChannel, int maxChannel, + bool mixingOrMerging, + sv_frame_t frame0, sv_frame_t frame1, + int blockSize, RangeVec &ranges) + const +{ + for (int ch = minChannel; ch <= maxChannel; ++ch) { + ranges.push_back({}); + m_model->getSummaries(ch, frame0, frame1 - frame0, + ranges[ch - minChannel], blockSize); +#ifdef DEBUG_WAVEFORM_PAINT + SVCERR << "channel " << ch << ": " << ranges[ch - minChannel].size() << " ranges from " << frame0 << " to " << frame1 << " at zoom level " << blockSize << endl; +#endif + } + + if (mixingOrMerging) { + if (minChannel != 0 || maxChannel != 0) { + SVCERR << "Internal error: min & max channels should be 0 when merging or mixing all channels" << endl; + } else if (m_model->getChannelCount() > 1) { + ranges.push_back({}); + m_model->getSummaries + (1, frame0, frame1 - frame0, ranges[1], blockSize); + } + } +} + +void +WaveformLayer::getOversampledRanges(int minChannel, int maxChannel, + bool mixingOrMerging, + sv_frame_t frame0, sv_frame_t frame1, + int oversampleBy, RangeVec &ranges) + const +{ + // These frame values, tail length, etc variables are at the model + // sample rate, not the oversampled rate + + sv_frame_t tail = 16; + sv_frame_t leftTail = tail, rightTail = tail; + sv_frame_t startFrame = m_model->getStartFrame(); + sv_frame_t endFrame = m_model->getEndFrame(); + + sv_frame_t rf0 = frame0 - tail; + if (rf0 < startFrame) { + leftTail = frame0 - startFrame; + rf0 = 0; + } + + sv_frame_t rf1 = frame1 + tail; + if (rf1 >= endFrame) { + rightTail = endFrame - 1 - frame1; + rf1 = endFrame - 1; + } + if (rf1 <= rf0) { + SVCERR << "WARNING: getOversampledRanges: rf1 (" << rf1 << ") <= rf0 (" + << rf0 << ")" << endl; + return; + } + + for (int ch = minChannel; ch <= maxChannel; ++ch) { + floatvec_t raw = m_model->getData(ch, rf0, rf1 - rf0); + floatvec_t oversampled(oversampleBy * (frame1 - frame0 + 2 * tail), + 0.f); + //!!! return value, err etc + m_oversampler->reset(); + m_oversampler->resampleInterleaved(oversampled.data(), + oversampled.size(), + raw.data(), + raw.size(), + oversampleBy, + true); + RangeSummarisableTimeValueModel::RangeBlock rr; + for (sv_frame_t ix = leftTail * oversampleBy; + in_range_for(oversampled, ix + (rightTail * oversampleBy)); + ++ix) { + RangeSummarisableTimeValueModel::Range r; + r.sample(oversampled[ix]); + rr.push_back(r); + } + ranges.push_back(rr); + +#ifdef DEBUG_WAVEFORM_PAINT + SVCERR << "getOversampledRanges: " << frame0 << " -> " << frame1 + << " (" << frame1 - frame0 << "-frame range) at ratio " + << oversampleBy << " with tail " << tail + << " -> got " << oversampled.size() + << " oversampled values for channel " << ch + << ", from which returning " << rr.size() << " ranges" << endl; +#endif + } + + //!!! + channel modes + + return; +} + +void +WaveformLayer::paintChannel(LayerGeometryProvider *v, + QPainter *paint, + QRect rect, int ch, + const RangeVec &ranges, + int blockSize, + sv_frame_t frame0, sv_frame_t frame1) const { int x0 = rect.left(); @@ -709,7 +790,7 @@ int my = m + (((ch - minChannel) * h) / channels); #ifdef DEBUG_WAVEFORM_PAINT - cerr << "ch = " << ch << ", channels = " << channels << ", m = " << m << ", my = " << my << ", h = " << h << endl; + SVCERR << "ch = " << ch << ", channels = " << channels << ", m = " << m << ", my = " << my << ", h = " << h << endl; #endif if (my - m > y1 || my + m < y0) return; @@ -726,27 +807,44 @@ paintChannelScaleGuides(v, paint, rect, ch); int rangeix = ch - minChannel; - + +#ifdef DEBUG_WAVEFORM_PAINT + SVCERR << "paint channel " << ch << ": frame0 = " << frame0 << ", frame1 = " << frame1 << ", blockSize = " << blockSize << ", have " << ranges.size() << " range blocks of which ours is index " << rangeix << " with " << ranges[rangeix].size() << " ranges in it" << endl; +#endif + for (int x = x0; x <= x1; ++x) { sv_frame_t f0, f1; - if (!getSourceFramesForX(v, x, blockSize, f0, f1)) continue; - f1 = f1 - 1; + sv_frame_t i0, i1; + + bool showIndividualSample = false; + + if (v->getZoomLevel().zone == ZoomLevel::FramesPerPixel) { + if (!getSourceFramesForX(v, x, blockSize, f0, f1)) { + continue; + } + f1 = f1 - 1; + i0 = (f0 - frame0) / blockSize; + i1 = (f1 - frame0) / blockSize; + } else { + int oversampleBy = v->getZoomLevel().level; + f0 = f1 = v->getFrameForX(x); + int xf0 = v->getXForFrame(f0); + showIndividualSample = (x == xf0); + i0 = i1 = (f0 - frame0) * oversampleBy + (x - xf0); + } if (f0 < frame0) { - cerr << "ERROR: WaveformLayer::paint: pixel " << x << " has f0 = " << f0 << " which is less than range frame0 " << frame0 << " for x0 = " << x0 << endl; + SVCERR << "ERROR: WaveformLayer::paint: pixel " << x << " has f0 = " << f0 << " which is less than range frame0 " << frame0 << " for x0 = " << x0 << endl; continue; } - sv_frame_t i0 = (f0 - frame0) / blockSize; - sv_frame_t i1 = (f1 - frame0) / blockSize; - -#ifdef DEBUG_WAVEFORM_PAINT - cerr << "WaveformLayer::paint: pixel " << x << ": i0 " << i0 << " (f " << f0 << "), i1 " << i1 << " (f " << f1 << ")" << endl; +#ifdef DEBUG_WAVEFORM_PAINT_BY_PIXEL + SVCERR << "WaveformLayer::paint: pixel " << x << ": i0 " << i0 << " (f " << f0 << "), i1 " << i1 << " (f " << f1 << ")" << endl; #endif if (i1 > i0 + 1) { - cerr << "WaveformLayer::paint: ERROR: i1 " << i1 << " > i0 " << i0 << " plus one (zoom = " << v->getZoomLevel() << ", model zoom = " << blockSize << ")" << endl; + SVCERR << "WaveformLayer::paint: ERROR: i1 " << i1 << " > i0 " << i0 << " plus one (zoom = " << v->getZoomLevel() << ", model zoom = " << blockSize << ")" << endl; } const auto &r = ranges[rangeix]; @@ -764,7 +862,7 @@ } else { #ifdef DEBUG_WAVEFORM_PAINT - cerr << "No (or not enough) ranges for i0 = " << i0 << endl; + SVCERR << "No (or not enough) ranges for index i0 = " << i0 << " (there are " << r.size() << " range(s))" << endl; #endif continue; } @@ -884,6 +982,11 @@ else drawMean = false; } + if (showIndividualSample) { + paint->setPen(baseColour); + paint->drawRect(x-1, rangeTop-1, 3, 3); + } + if (x != x0 && prevRangeBottom != -1) { if (prevRangeBottom > rangeBottom + 1 && prevRangeTop > rangeBottom + 1) { @@ -914,8 +1017,8 @@ paint->setPen(midColour); } -#ifdef DEBUG_WAVEFORM_PAINT - cerr << "range " << rangeBottom << " -> " << rangeTop << ", means " << meanBottom << " -> " << meanTop << ", raw range " << range.min() << " -> " << range.max() << endl; +#ifdef DEBUG_WAVEFORM_PAINT_BY_PIXEL + SVCERR << "range " << rangeBottom << " -> " << rangeTop << ", means " << meanBottom << " -> " << meanTop << ", raw range " << range.min() << " -> " << range.max() << endl; #endif if (rangeTop == rangeBottom) { @@ -957,68 +1060,6 @@ } void -WaveformLayer::paintChannelOversampled(LayerGeometryProvider *v, - QPainter *paint, - QRect rect, - int ch, - sv_frame_t frame0, sv_frame_t frame1) - const -{ - int x0 = rect.left(); - int y0 = rect.top(); - - int x1 = rect.right(); - int y1 = rect.bottom(); - - int h = v->getPaintHeight(); - - int channels = 0, minChannel = 0, maxChannel = 0; - bool mergingChannels = false, mixingChannels = false; - - channels = getChannelArrangement(minChannel, maxChannel, - mergingChannels, mixingChannels); - if (channels == 0) return; - - QColor baseColour = getBaseQColor(); - vector<QColor> greys = getPartialShades(v); - - QColor midColour = baseColour; - if (midColour == Qt::black) { - midColour = Qt::gray; - } else if (v->hasLightBackground()) { - midColour = midColour.light(150); - } else { - midColour = midColour.light(50); - } - - double gain = m_effectiveGains[ch]; - - int m = (h / channels) / 2; - int my = m + (((ch - minChannel) * h) / channels); - -#ifdef DEBUG_WAVEFORM_PAINT - cerr << "ch = " << ch << ", channels = " << channels << ", m = " << m << ", my = " << my << ", h = " << h << endl; -#endif - - if (my - m > y1 || my + m < y0) return; - - if ((m_scale == dBScale || m_scale == MeterScale) && - m_channelMode != MergeChannels) { - m = (h / channels); - my = m + (((ch - minChannel) * h) / channels); - } - - paint->setPen(greys[1]); - paint->drawLine(x0, my, x1, my); - - paintChannelScaleGuides(v, paint, rect, ch); - - for (sv_frame_t f = frame0; f <= frame1; ++f) { - - } -} - -void WaveformLayer::paintChannelScaleGuides(LayerGeometryProvider *v, QPainter *paint, QRect rect, @@ -1206,7 +1247,7 @@ break; } -// cerr << "mergingChannels= " << mergingChannels << ", channel = " << channel << ", value = " << value << ", vy = " << vy << endl; +// SVCERR << "mergingChannels= " << mergingChannels << ", channel = " << channel << ", value = " << value << ", vy = " << vy << endl; return my - vy; }
--- a/layer/WaveformLayer.h Tue Sep 25 12:52:08 2018 +0100 +++ b/layer/WaveformLayer.h Tue Sep 25 16:38:50 2018 +0100 @@ -211,21 +211,29 @@ const RangeSummarisableTimeValueModel *m_model; // I do not own this + typedef std::vector<RangeSummarisableTimeValueModel::RangeBlock> RangeVec; + /// Return value is number of channels displayed int getChannelArrangement(int &min, int &max, bool &merging, bool &mixing) const; - void paintChannelSummarised + void paintChannel (LayerGeometryProvider *, QPainter *paint, QRect rect, int channel, - const std::vector<RangeSummarisableTimeValueModel::RangeBlock> &ranges, + const RangeVec &ranges, int blockSize, sv_frame_t frame0, sv_frame_t frame1) const; - - void paintChannelOversampled - (LayerGeometryProvider *, QPainter *paint, QRect rect, int channel, - sv_frame_t frame0, sv_frame_t frame1) const; void paintChannelScaleGuides(LayerGeometryProvider *, QPainter *paint, QRect rect, int channel) const; + + void getSummaryRanges(int minChannel, int maxChannel, + bool mixingOrMerging, + sv_frame_t f0, sv_frame_t f1, + int blockSize, RangeVec &ranges) const; + + void getOversampledRanges(int minChannel, int maxChannel, + bool mixingOrMerging, + sv_frame_t f0, sv_frame_t f1, + int oversampleBy, RangeVec &ranges) const; int getYForValue(const LayerGeometryProvider *v, double value, int channel) const; @@ -247,8 +255,6 @@ Scale m_scale; double m_middleLineHeight; bool m_aggressive; - int m_oversampleRate; - int m_oversampleTail; mutable std::vector<float> m_effectiveGains;