Mercurial > hg > svgui
comparison layer/TimeRulerLayer.cpp @ 1346:4c28e3302045 zoom
Avoid overflow problems when dealing with large numbers of microseconds
author | Chris Cannam |
---|---|
date | Fri, 28 Sep 2018 18:28:44 +0100 |
parents | 3fa8cdbf362c |
children | dddfd28e4f02 |
comparison
equal
deleted
inserted
replaced
1345:3fa8cdbf362c | 1346:4c28e3302045 |
---|---|
29 | 29 |
30 #include <iostream> | 30 #include <iostream> |
31 #include <cmath> | 31 #include <cmath> |
32 #include <stdexcept> | 32 #include <stdexcept> |
33 | 33 |
34 #define DEBUG_TIME_RULER_LAYER 1 | 34 //#define DEBUG_TIME_RULER_LAYER 1 |
35 | 35 |
36 | 36 |
37 TimeRulerLayer::TimeRulerLayer() : | 37 TimeRulerLayer::TimeRulerLayer() : |
38 SingleColourLayer(), | 38 SingleColourLayer(), |
39 m_model(0), | 39 m_model(0), |
58 resolution = 1; | 58 resolution = 1; |
59 return false; | 59 return false; |
60 } | 60 } |
61 | 61 |
62 bool q; | 62 bool q; |
63 int tickUSec = getMajorTickUSec(v, q); | 63 int64_t tickUSec = getMajorTickUSec(v, q); |
64 RealTime rtick = RealTime(0, tickUSec * 1000); | 64 RealTime rtick = RealTime::fromMicroseconds(tickUSec); |
65 sv_samplerate_t rate = m_model->getSampleRate(); | 65 sv_samplerate_t rate = m_model->getSampleRate(); |
66 | 66 |
67 RealTime rt = RealTime::frame2RealTime(frame, rate); | 67 RealTime rt = RealTime::frame2RealTime(frame, rate); |
68 double ratio = rt / rtick; | 68 double ratio = rt / rtick; |
69 | 69 |
140 // SVDEBUG << " -> " << frame << " (resolution = " << resolution << ")" << endl; | 140 // SVDEBUG << " -> " << frame << " (resolution = " << resolution << ")" << endl; |
141 | 141 |
142 return true; | 142 return true; |
143 } | 143 } |
144 | 144 |
145 int | 145 int64_t |
146 TimeRulerLayer::getMajorTickUSec(LayerGeometryProvider *v, | 146 TimeRulerLayer::getMajorTickUSec(LayerGeometryProvider *v, |
147 bool &quarterTicks) const | 147 bool &quarterTicks) const |
148 { | 148 { |
149 // return value is in microseconds | 149 // return value is in microseconds |
150 if (!m_model || !v) return 1000 * 1000; | 150 if (!m_model || !v) return 1000 * 1000; |
162 | 162 |
163 int count = v->getPaintWidth() / minPixelSpacing; | 163 int count = v->getPaintWidth() / minPixelSpacing; |
164 if (count < 1) count = 1; | 164 if (count < 1) count = 1; |
165 RealTime rtGap = (rtEnd - rtStart) / count; | 165 RealTime rtGap = (rtEnd - rtStart) / count; |
166 | 166 |
167 int incus; | 167 int64_t incus; |
168 quarterTicks = false; | 168 quarterTicks = false; |
169 | 169 |
170 if (rtGap.sec > 0) { | 170 if (rtGap.sec > 0) { |
171 incus = 1000 * 1000; | 171 incus = 1000 * 1000; |
172 int s = rtGap.sec; | 172 int s = rtGap.sec; |
236 | 236 |
237 void | 237 void |
238 TimeRulerLayer::paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const | 238 TimeRulerLayer::paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const |
239 { | 239 { |
240 #ifdef DEBUG_TIME_RULER_LAYER | 240 #ifdef DEBUG_TIME_RULER_LAYER |
241 SVDEBUG << "TimeRulerLayer::paint (" << rect.x() << "," << rect.y() | 241 SVCERR << "TimeRulerLayer::paint (" << rect.x() << "," << rect.y() |
242 << ") [" << rect.width() << "x" << rect.height() << "]" << endl; | 242 << ") [" << rect.width() << "x" << rect.height() << "]" << endl; |
243 #endif | 243 #endif |
244 | 244 |
245 if (!m_model || !m_model->isOK()) return; | 245 if (!m_model || !m_model->isOK()) return; |
246 | 246 |
247 sv_samplerate_t sampleRate = m_model->getSampleRate(); | 247 sv_samplerate_t sampleRate = m_model->getSampleRate(); |
248 if (!sampleRate) return; | 248 if (!sampleRate) return; |
249 | 249 |
250 sv_frame_t startFrame = v->getFrameForX(rect.x() - 50); | 250 sv_frame_t startFrame = v->getFrameForX(rect.x() - 50); |
251 | 251 |
252 #ifdef DEBUG_TIME_RULER_LAYER | 252 #ifdef DEBUG_TIME_RULER_LAYER |
253 cerr << "start frame = " << startFrame << endl; | 253 SVCERR << "start frame = " << startFrame << endl; |
254 #endif | 254 #endif |
255 | 255 |
256 bool quarter = false; | 256 bool quarter = false; |
257 int incus = getMajorTickUSec(v, quarter); | 257 int64_t incus = getMajorTickUSec(v, quarter); |
258 | 258 int64_t us = int64_t(floor(1000.0 * 1000.0 * (double(startFrame) / |
259 int us = int(lrint(1000.0 * 1000.0 * (double(startFrame) / | 259 double(sampleRate)))); |
260 double(sampleRate)))); | |
261 us = (us / incus) * incus - incus; | 260 us = (us / incus) * incus - incus; |
262 | 261 |
263 #ifdef DEBUG_TIME_RULER_LAYER | 262 #ifdef DEBUG_TIME_RULER_LAYER |
264 cerr << "start us = " << us << " at step " << incus << endl; | 263 SVCERR << "start us = " << us << " at step " << incus << endl; |
265 #endif | 264 #endif |
266 | 265 |
267 Preferences *prefs = Preferences::getInstance(); | 266 Preferences *prefs = Preferences::getInstance(); |
268 auto origTimeTextMode = prefs->getTimeToTextMode(); | 267 auto origTimeTextMode = prefs->getTimeToTextMode(); |
269 if (incus < 1000) { | 268 if (incus < 1000) { |
277 // values for x and frame counts here will do, no rounding issue. | 276 // values for x and frame counts here will do, no rounding issue. |
278 // We always use the exact incus in our calculations for where to | 277 // We always use the exact incus in our calculations for where to |
279 // draw the actual ticks or lines. | 278 // draw the actual ticks or lines. |
280 | 279 |
281 int minPixelSpacing = 50; | 280 int minPixelSpacing = 50; |
282 sv_frame_t incFrame = lrint((incus * sampleRate) / 1000000); | 281 sv_frame_t incFrame = lrint((double(incus) * sampleRate) / 1000000); |
283 int incX = int(round(v->getZoomLevel().framesToPixels(double(incFrame)))); | 282 int incX = int(round(v->getZoomLevel().framesToPixels(double(incFrame)))); |
284 int ticks = 10; | 283 int ticks = 10; |
285 if (incX < minPixelSpacing * 2) { | 284 if (incX < minPixelSpacing * 2) { |
286 ticks = quarter ? 4 : 5; | 285 ticks = quarter ? 4 : 5; |
287 } | 286 } |
299 // frame is used to determine where to draw the lines, so it | 298 // frame is used to determine where to draw the lines, so it |
300 // needs to correspond to an exact pixel (so that we don't get | 299 // needs to correspond to an exact pixel (so that we don't get |
301 // a different pixel when scrolling a small amount and | 300 // a different pixel when scrolling a small amount and |
302 // re-drawing with a different start frame). | 301 // re-drawing with a different start frame). |
303 | 302 |
304 double dus = us; | 303 double dus = double(us); |
305 | 304 |
306 int x = getXForUSec(v, dus); | 305 int x = getXForUSec(v, dus); |
307 | 306 |
308 if (x >= rect.x() + rect.width() + 50) { | 307 if (x >= rect.x() + rect.width() + 50) { |
309 #ifdef DEBUG_TIME_RULER_LAYER | 308 #ifdef DEBUG_TIME_RULER_LAYER |
310 cerr << "X well out of range, ending here" << endl; | 309 SVCERR << "X well out of range, ending here" << endl; |
311 #endif | 310 #endif |
312 break; | 311 break; |
313 } | 312 } |
314 | 313 |
315 if (x >= rect.x() - 50 && us >= minlabel) { | 314 if (x >= rect.x() - 50 && us >= minlabel) { |
316 | 315 |
317 RealTime rt = RealTime::fromMicroseconds(us); | 316 RealTime rt = RealTime::fromMicroseconds(us); |
318 | 317 |
319 #ifdef DEBUG_TIME_RULER_LAYER | 318 #ifdef DEBUG_TIME_RULER_LAYER |
320 cerr << "X in range, drawing line here for time " << rt.toText() << " (usec = " << us << ")" << endl; | 319 SVCERR << "X in range, drawing line here for time " << rt.toText() << " (usec = " << us << ")" << endl; |
321 #endif | 320 #endif |
322 | 321 |
323 QString text(QString::fromStdString(rt.toText())); | 322 QString text(QString::fromStdString(rt.toText())); |
324 | 323 |
325 QFontMetrics metrics = paint.fontMetrics(); | 324 QFontMetrics metrics = paint.fontMetrics(); |
327 | 326 |
328 if (tw < 50 && | 327 if (tw < 50 && |
329 (x < rect.x() - tw/2 || | 328 (x < rect.x() - tw/2 || |
330 x >= rect.x() + rect.width() + tw/2)) { | 329 x >= rect.x() + rect.width() + tw/2)) { |
331 #ifdef DEBUG_TIME_RULER_LAYER | 330 #ifdef DEBUG_TIME_RULER_LAYER |
332 cerr << "hm, maybe X isn't in range after all (x = " << x << ", tw = " << tw << ", rect.x() = " << rect.x() << ", rect.width() = " << rect.width() << ")" << endl; | 331 SVCERR << "hm, maybe X isn't in range after all (x = " << x << ", tw = " << tw << ", rect.x() = " << rect.x() << ", rect.width() = " << rect.width() << ")" << endl; |
333 #endif | 332 #endif |
334 } | 333 } |
335 | 334 |
336 paint.setPen(greyColour); | 335 paint.setPen(greyColour); |
337 paint.drawLine(x, 0, x, v->getPaintHeight()); | 336 paint.drawLine(x, 0, x, v->getPaintHeight()); |
367 | 366 |
368 paint.setPen(greyColour); | 367 paint.setPen(greyColour); |
369 | 368 |
370 for (int i = 1; i < ticks; ++i) { | 369 for (int i = 1; i < ticks; ++i) { |
371 | 370 |
372 dus = us + (i * double(incus)) / ticks; | 371 dus = double(us) + (i * double(incus)) / ticks; |
373 | 372 |
374 x = getXForUSec(v, dus); | 373 x = getXForUSec(v, dus); |
375 | 374 |
376 if (x < rect.x() || x >= rect.x() + rect.width()) { | 375 if (x < rect.x() || x >= rect.x() + rect.width()) { |
377 #ifdef DEBUG_TIME_RULER_LAYER | 376 #ifdef DEBUG_TIME_RULER_LAYER |
378 // cerr << "tick " << i << ": X out of range, going on to next tick" << endl; | 377 // SVCERR << "tick " << i << ": X out of range, going on to next tick" << endl; |
379 #endif | 378 #endif |
380 continue; | 379 continue; |
381 } | 380 } |
382 | 381 |
383 #ifdef DEBUG_TIME_RULER_LAYER | 382 #ifdef DEBUG_TIME_RULER_LAYER |
384 cerr << "tick " << i << " in range, drawing at " << x << endl; | 383 SVCERR << "tick " << i << " in range, drawing at " << x << endl; |
385 #endif | 384 #endif |
386 | 385 |
387 int sz = 5; | 386 int sz = 5; |
388 if (ticks == 10) { | 387 if (ticks == 10) { |
389 if ((i % 2) == 1) { | 388 if ((i % 2) == 1) { |