Mercurial > hg > svgui
changeset 1341:ab2cafd3a7cb zoom
Fixes for TimeRuler spacing and for the boundaries of the WaveformLayer paint area
author | Chris Cannam |
---|---|
date | Thu, 27 Sep 2018 15:20:25 +0100 |
parents | fc3c9971a43a |
children | ed6400d5b571 |
files | layer/TimeRulerLayer.cpp layer/TimeRulerLayer.h layer/WaveformLayer.cpp view/View.cpp |
diffstat | 4 files changed, 112 insertions(+), 77 deletions(-) [+] |
line wrap: on
line diff
--- a/layer/TimeRulerLayer.cpp Wed Sep 26 13:03:16 2018 +0100 +++ b/layer/TimeRulerLayer.cpp Thu Sep 27 15:20:25 2018 +0100 @@ -59,8 +59,8 @@ } bool q; - int tick = getMajorTickSpacing(v, q); - RealTime rtick = RealTime::fromMilliseconds(tick); + int tickUSec = getMajorTickUSec(v, q); + RealTime rtick = RealTime(0, tickUSec * 1000); sv_samplerate_t rate = m_model->getSampleRate(); RealTime rt = RealTime::frame2RealTime(frame, rate); @@ -142,19 +142,19 @@ } int -TimeRulerLayer::getMajorTickSpacing(LayerGeometryProvider *v, bool &quarterTicks) const +TimeRulerLayer::getMajorTickUSec(LayerGeometryProvider *v, + bool &quarterTicks) const { - // return value is in milliseconds - - if (!m_model || !v) return 1000; + // return value is in microseconds + if (!m_model || !v) return 1000 * 1000; sv_samplerate_t sampleRate = m_model->getSampleRate(); - if (!sampleRate) return 1000; + if (!sampleRate) return 1000 * 1000; sv_frame_t startFrame = v->getStartFrame(); sv_frame_t endFrame = v->getEndFrame(); - int minPixelSpacing = 50; + int minPixelSpacing = ViewManager::scalePixelSize(50); RealTime rtStart = RealTime::frame2RealTime(startFrame, sampleRate); RealTime rtEnd = RealTime::frame2RealTime(endFrame, sampleRate); @@ -163,35 +163,74 @@ if (count < 1) count = 1; RealTime rtGap = (rtEnd - rtStart) / count; - int incms; + int incus; quarterTicks = false; if (rtGap.sec > 0) { - incms = 1000; + incus = 1000 * 1000; int s = rtGap.sec; - if (s > 0) { incms *= 5; s /= 5; } - if (s > 0) { incms *= 2; s /= 2; } - if (s > 0) { incms *= 6; s /= 6; quarterTicks = true; } - if (s > 0) { incms *= 5; s /= 5; quarterTicks = false; } - if (s > 0) { incms *= 2; s /= 2; } - if (s > 0) { incms *= 6; s /= 6; quarterTicks = true; } + if (s > 0) { incus *= 5; s /= 5; } + if (s > 0) { incus *= 2; s /= 2; } + if (s > 0) { incus *= 6; s /= 6; quarterTicks = true; } + if (s > 0) { incus *= 5; s /= 5; quarterTicks = false; } + if (s > 0) { incus *= 2; s /= 2; } + if (s > 0) { incus *= 6; s /= 6; quarterTicks = true; } while (s > 0) { - incms *= 10; + incus *= 10; s /= 10; quarterTicks = false; } + } else if (rtGap.msec() > 0) { + incus = 1000; + int ms = rtGap.msec(); + if (ms > 0) { incus *= 10; ms /= 10; } + if (ms > 0) { incus *= 10; ms /= 10; } + if (ms > 0) { incus *= 5; ms /= 5; } + if (ms > 0) { incus *= 2; ms /= 2; } } else { - incms = 1; - int ms = rtGap.msec(); -// cerr << "rtGap.msec = " << ms << ", rtGap = " << rtGap << ", count = " << count << endl; -// cerr << "startFrame = " << startFrame << ", endFrame = " << endFrame << " rtStart = " << rtStart << ", rtEnd = " << rtEnd << endl; - if (ms > 0) { incms *= 10; ms /= 10; } - if (ms > 0) { incms *= 10; ms /= 10; } - if (ms > 0) { incms *= 5; ms /= 5; } - if (ms > 0) { incms *= 2; ms /= 2; } + incus = 1; + int us = rtGap.usec(); + if (us > 0) { incus *= 10; us /= 10; } + if (us > 0) { incus *= 10; us /= 10; } + if (us > 0) { incus *= 5; us /= 5; } + if (us > 0) { incus *= 2; us /= 2; } } - return incms; + return incus; +} + +int +TimeRulerLayer::getXForUSec(LayerGeometryProvider *v, double us) const +{ + sv_samplerate_t sampleRate = m_model->getSampleRate(); + double dframe = (us * sampleRate) / 1000000.0; + double eps = 1e-7; + sv_frame_t frame = sv_frame_t(floor(dframe + eps)); + int x; + + ZoomLevel zoom = v->getZoomLevel(); + + if (zoom.zone == ZoomLevel::FramesPerPixel) { + + frame /= zoom.level; + frame *= zoom.level; // so frame corresponds to an exact pixel + + x = v->getXForFrame(frame); + + } else { + + double off = dframe - double(frame); + int x0 = v->getXForFrame(frame); + int x1 = v->getXForFrame(frame + 1); + + x = int(x0 + off * (x1 - x0)); + } + +#ifdef DEBUG_TIME_RULER_LAYER + cerr << "Considering frame = " << frame << ", x = " << x << endl; +#endif + + return x; } void @@ -214,22 +253,23 @@ #endif bool quarter = false; - int incms = getMajorTickSpacing(v, quarter); + int incus = getMajorTickUSec(v, quarter); - int ms = int(lrint(1000.0 * (double(startFrame) / double(sampleRate)))); - ms = (ms / incms) * incms - incms; + int us = int(lrint(1000.0 * 1000.0 * (double(startFrame) / + double(sampleRate)))); + us = (us / incus) * incus - incus; #ifdef DEBUG_TIME_RULER_LAYER - cerr << "start ms = " << ms << " at step " << incms << endl; + cerr << "start us = " << us << " at step " << incus << endl; #endif // Calculate the number of ticks per increment -- approximate // values for x and frame counts here will do, no rounding issue. - // We always use the exact incms in our calculations for where to + // We always use the exact incus in our calculations for where to // draw the actual ticks or lines. int minPixelSpacing = 50; - sv_frame_t incFrame = lrint((incms * sampleRate) / 1000); + sv_frame_t incFrame = lrint((incus * sampleRate) / 1000000); int incX = int(round(v->getZoomLevel().framesToPixels(double(incFrame)))); int ticks = 10; if (incX < minPixelSpacing * 2) { @@ -242,10 +282,7 @@ // Do not label time zero - we now overlay an opaque area over // time < 0 which would cut it in half - int minlabel = 1; // ms - - // used for a sanity check - sv_frame_t prevframe = 0; + int minlabel = 1; // us while (1) { @@ -254,26 +291,9 @@ // a different pixel when scrolling a small amount and // re-drawing with a different start frame). - double dms = ms; - sv_frame_t frame = lrint((dms * sampleRate) / 1000.0); - ZoomLevel zoom = v->getZoomLevel(); - if (zoom.zone == ZoomLevel::FramesPerPixel) { - frame /= zoom.level; - frame *= zoom.level; // so frame corresponds to an exact pixel - } + double dus = us; - if (frame == prevframe && prevframe != 0) { - cerr << "ERROR: frame == prevframe (== " << frame - << ") in TimeRulerLayer::paint" << endl; - throw std::logic_error("frame == prevframe in TimeRulerLayer::paint"); - } - prevframe = frame; - - int x = v->getXForFrame(frame); - -#ifdef DEBUG_TIME_RULER_LAYER - cerr << "Considering frame = " << frame << ", x = " << x << endl; -#endif + int x = getXForUSec(v, dus); if (x >= rect.x() + rect.width() + 50) { #ifdef DEBUG_TIME_RULER_LAYER @@ -282,9 +302,9 @@ break; } - if (x >= rect.x() - 50 && ms >= minlabel) { + if (x >= rect.x() - 50 && us >= minlabel) { - RealTime rt = RealTime::fromMilliseconds(ms); + RealTime rt = RealTime(0, us * 1000); #ifdef DEBUG_TIME_RULER_LAYER cerr << "X in range, drawing line here for time " << rt.toText() << endl; @@ -338,14 +358,9 @@ for (int i = 1; i < ticks; ++i) { - dms = ms + (i * double(incms)) / ticks; - frame = lrint((dms * sampleRate) / 1000.0); - if (zoom.zone == ZoomLevel::FramesPerPixel) { - frame /= zoom.level; - frame *= zoom.level; // exact pixel as above - } + dus = us + (i * double(incus)) / ticks; - x = v->getXForFrame(frame); + x = getXForUSec(v, dus); if (x < rect.x() || x >= rect.x() + rect.width()) { #ifdef DEBUG_TIME_RULER_LAYER @@ -372,7 +387,7 @@ paint.drawLine(x, v->getPaintHeight() - sz - 1, x, v->getPaintHeight() - 1); } - ms += incms; + us += incus; } paint.restore();
--- a/layer/TimeRulerLayer.h Wed Sep 26 13:03:16 2018 +0100 +++ b/layer/TimeRulerLayer.h Thu Sep 27 15:20:25 2018 +0100 @@ -68,7 +68,8 @@ virtual int getDefaultColourHint(bool dark, bool &impose); - int getMajorTickSpacing(LayerGeometryProvider *, bool &quarterTicks) const; + int getMajorTickUSec(LayerGeometryProvider *, bool &quarterTicks) const; + int getXForUSec(LayerGeometryProvider *, double usec) const; }; #endif
--- a/layer/WaveformLayer.cpp Wed Sep 26 13:03:16 2018 +0100 +++ b/layer/WaveformLayer.cpp Thu Sep 27 15:20:25 2018 +0100 @@ -427,11 +427,14 @@ f0 = f0 / modelZoomLevel; f0 = f0 * modelZoomLevel; - viewFrame = v->getFrameForX(x + 1); - - f1 = viewFrame; - f1 = f1 / modelZoomLevel; - f1 = f1 * modelZoomLevel; + if (v->getZoomLevel().zone == ZoomLevel::PixelsPerFrame) { + f1 = f0 + 1; + } else { + viewFrame = v->getFrameForX(x + 1); + f1 = viewFrame; + f1 = f1 / modelZoomLevel; + f1 = f1 * modelZoomLevel; + } return (f0 < m_model->getEndFrame()); }
--- a/view/View.cpp Wed Sep 26 13:03:16 2018 +0100 +++ b/view/View.cpp Thu Sep 27 15:20:25 2018 +0100 @@ -381,15 +381,25 @@ int View::getXForFrame(sv_frame_t frame) const { + // In FramesPerPixel mode, the pixel should be the one "covering" + // the given frame, i.e. to the "left" of it - not necessarily the + // nearest boundary. + + sv_frame_t level = m_zoomLevel.level; sv_frame_t fdiff = frame - getCentreFrame(); + int diff, result; if (m_zoomLevel.zone == ZoomLevel::FramesPerPixel) { - fdiff /= m_zoomLevel.level; + diff = fdiff / level; + if ((fdiff < 0) && ((fdiff % level) != 0)) { + --diff; // round to the left + } } else { - fdiff *= m_zoomLevel.level; + diff = fdiff * level; } - return int(fdiff + (width()/2)); + result = int(diff + (width()/2)); + return result; } sv_frame_t @@ -397,7 +407,10 @@ { // Note, this must always return a value that is on a zoom-level // boundary - regardless of whether the nominal centre frame is on - // such a boundary or not + // such a boundary or not. + + // In PixelsPerFrame mode, the frame should be the one immediately + // left of the given pixel, not necessarily the nearest. int diff = x - (width()/2); sv_frame_t level = m_zoomLevel.level; @@ -408,9 +421,12 @@ result = ((fdiff + m_centreFrame) / level) * level; } else { fdiff = diff / level; + if ((diff < 0) && ((diff % level) != 0)) { + --fdiff; // round to the left + } result = fdiff + m_centreFrame; } -/* + if (x == 0) { SVCERR << "getFrameForX(" << x << "): diff = " << diff << ", fdiff = " << fdiff << ", m_centreFrame = " << m_centreFrame @@ -420,7 +436,7 @@ << ", will return " << result << endl; } -*/ + return result; }