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) {