annotate base/RealTime.cpp @ 1061:c1e43c8d2527 tonioni

Thread-local debug was causing crash on exit with Qt 5.4.x. But we introduced that because QDebug itself was crashing when used from multiple threads. Replace with simpler fstream version
author Chris Cannam
date Tue, 31 Mar 2015 10:36:52 +0100
parents a1cd5abcb38b
children b8a788c9a6f1
rev   line source
Chris@49 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@0 2
Chris@0 3 /*
Chris@52 4 Sonic Visualiser
Chris@52 5 An audio file viewer and annotation editor.
Chris@52 6 Centre for Digital Music, Queen Mary, University of London.
Chris@0 7
Chris@52 8 This program is free software; you can redistribute it and/or
Chris@52 9 modify it under the terms of the GNU General Public License as
Chris@52 10 published by the Free Software Foundation; either version 2 of the
Chris@52 11 License, or (at your option) any later version. See the file
Chris@52 12 COPYING included with this distribution for more information.
Chris@0 13 */
Chris@0 14
Chris@0 15 /*
Chris@0 16 This is a modified version of a source file from the
Chris@0 17 Rosegarden MIDI and audio sequencer and notation editor.
Chris@17 18 This file copyright 2000-2006 Chris Cannam.
Chris@0 19 */
Chris@0 20
Chris@0 21 #include <iostream>
Chris@0 22
Chris@405 23 #include <cstdlib>
Chris@0 24 #include <sstream>
Chris@0 25
Chris@150 26 #include "RealTime.h"
Chris@26 27 #include "sys/time.h"
Chris@0 28
Chris@843 29 #include "Debug.h"
Chris@843 30
Chris@612 31 #include "Preferences.h"
Chris@612 32
Chris@0 33 // A RealTime consists of two ints that must be at least 32 bits each.
Chris@0 34 // A signed 32-bit int can store values exceeding +/- 2 billion. This
Chris@0 35 // means we can safely use our lower int for nanoseconds, as there are
Chris@0 36 // 1 billion nanoseconds in a second and we need to handle double that
Chris@0 37 // because of the implementations of addition etc that we use.
Chris@0 38 //
Chris@0 39 // The maximum valid RealTime on a 32-bit system is somewhere around
Chris@0 40 // 68 years: 999999999 nanoseconds longer than the classic Unix epoch.
Chris@0 41
Chris@0 42 #define ONE_BILLION 1000000000
Chris@0 43
Chris@0 44 RealTime::RealTime(int s, int n) :
Chris@0 45 sec(s), nsec(n)
Chris@0 46 {
Chris@0 47 if (sec == 0) {
Chris@0 48 while (nsec <= -ONE_BILLION) { nsec += ONE_BILLION; --sec; }
Chris@0 49 while (nsec >= ONE_BILLION) { nsec -= ONE_BILLION; ++sec; }
Chris@0 50 } else if (sec < 0) {
Chris@0 51 while (nsec <= -ONE_BILLION) { nsec += ONE_BILLION; --sec; }
Chris@0 52 while (nsec > 0) { nsec -= ONE_BILLION; ++sec; }
Chris@0 53 } else {
Chris@0 54 while (nsec >= ONE_BILLION) { nsec -= ONE_BILLION; ++sec; }
Chris@0 55 while (nsec < 0) { nsec += ONE_BILLION; --sec; }
Chris@0 56 }
Chris@0 57 }
Chris@0 58
Chris@26 59 RealTime
Chris@26 60 RealTime::fromSeconds(double sec)
Chris@26 61 {
Chris@1012 62 if (sec >= 0) {
Chris@1012 63 return RealTime(int(sec), int((sec - int(sec)) * ONE_BILLION + 0.5));
Chris@1012 64 } else {
Chris@1012 65 return -fromSeconds(-sec);
Chris@1012 66 }
Chris@26 67 }
Chris@26 68
Chris@26 69 RealTime
Chris@26 70 RealTime::fromMilliseconds(int msec)
Chris@26 71 {
Chris@26 72 return RealTime(msec / 1000, (msec % 1000) * 1000000);
Chris@26 73 }
Chris@26 74
Chris@26 75 RealTime
Chris@26 76 RealTime::fromTimeval(const struct timeval &tv)
Chris@26 77 {
Chris@1038 78 return RealTime(int(tv.tv_sec), int(tv.tv_usec * 1000));
Chris@26 79 }
Chris@0 80
Chris@439 81 RealTime
Chris@439 82 RealTime::fromXsdDuration(std::string xsdd)
Chris@439 83 {
Chris@439 84 RealTime t;
Chris@439 85
Chris@439 86 int year = 0, month = 0, day = 0, hour = 0, minute = 0;
Chris@439 87 double second = 0.0;
Chris@439 88
Chris@439 89 int i = 0;
Chris@439 90
Chris@439 91 const char *s = xsdd.c_str();
Chris@1038 92 int len = int(xsdd.length());
Chris@439 93
Chris@439 94 bool negative = false, afterT = false;
Chris@439 95
Chris@439 96 while (i < len) {
Chris@439 97
Chris@439 98 if (s[i] == '-') {
Chris@439 99 if (i == 0) negative = true;
Chris@439 100 ++i;
Chris@439 101 continue;
Chris@439 102 }
Chris@439 103
Chris@439 104 double value = 0.0;
Chris@439 105 char *eptr = 0;
Chris@439 106
Chris@439 107 if (isdigit(s[i]) || s[i] == '.') {
Chris@439 108 value = strtod(&s[i], &eptr);
Chris@1038 109 i = int(eptr - s);
Chris@439 110 }
Chris@439 111
Chris@439 112 if (i == len) break;
Chris@439 113
Chris@439 114 switch (s[i]) {
Chris@439 115 case 'Y': year = int(value + 0.1); break;
Chris@439 116 case 'D': day = int(value + 0.1); break;
Chris@439 117 case 'H': hour = int(value + 0.1); break;
Chris@439 118 case 'M':
Chris@439 119 if (afterT) minute = int(value + 0.1);
Chris@439 120 else month = int(value + 0.1);
Chris@439 121 break;
Chris@439 122 case 'S':
Chris@439 123 second = value;
Chris@439 124 break;
Chris@439 125 case 'T': afterT = true; break;
Chris@439 126 };
Chris@439 127
Chris@439 128 ++i;
Chris@439 129 }
Chris@439 130
Chris@439 131 if (year > 0) {
Chris@843 132 cerr << "WARNING: This xsd:duration (\"" << xsdd << "\") contains a non-zero year.\nWith no origin and a limited data size, I will treat a year as exactly 31556952\nseconds and you should expect overflow and/or poor results." << endl;
Chris@439 133 t = t + RealTime(year * 31556952, 0);
Chris@439 134 }
Chris@439 135
Chris@439 136 if (month > 0) {
Chris@843 137 cerr << "WARNING: This xsd:duration (\"" << xsdd << "\") contains a non-zero month.\nWith no origin and a limited data size, I will treat a month as exactly 2629746\nseconds and you should expect overflow and/or poor results." << endl;
Chris@439 138 t = t + RealTime(month * 2629746, 0);
Chris@439 139 }
Chris@439 140
Chris@439 141 if (day > 0) {
Chris@439 142 t = t + RealTime(day * 86400, 0);
Chris@439 143 }
Chris@439 144
Chris@439 145 if (hour > 0) {
Chris@439 146 t = t + RealTime(hour * 3600, 0);
Chris@439 147 }
Chris@439 148
Chris@439 149 if (minute > 0) {
Chris@439 150 t = t + RealTime(minute * 60, 0);
Chris@439 151 }
Chris@439 152
Chris@439 153 t = t + fromSeconds(second);
Chris@439 154
Chris@928 155 if (negative) {
Chris@928 156 return -t;
Chris@928 157 } else {
Chris@928 158 return t;
Chris@928 159 }
Chris@439 160 }
Chris@439 161
Chris@439 162 double
Chris@439 163 RealTime::toDouble() const
Chris@439 164 {
Chris@439 165 double d = sec;
Chris@439 166 d += double(nsec) / double(ONE_BILLION);
Chris@439 167 return d;
Chris@439 168 }
Chris@439 169
Chris@0 170 std::ostream &operator<<(std::ostream &out, const RealTime &rt)
Chris@0 171 {
Chris@0 172 if (rt < RealTime::zeroTime) {
Chris@0 173 out << "-";
Chris@0 174 } else {
Chris@0 175 out << " ";
Chris@0 176 }
Chris@0 177
Chris@0 178 int s = (rt.sec < 0 ? -rt.sec : rt.sec);
Chris@0 179 int n = (rt.nsec < 0 ? -rt.nsec : rt.nsec);
Chris@0 180
Chris@0 181 out << s << ".";
Chris@0 182
Chris@0 183 int nn(n);
Chris@0 184 if (nn == 0) out << "00000000";
Chris@0 185 else while (nn < (ONE_BILLION / 10)) {
Chris@0 186 out << "0";
Chris@0 187 nn *= 10;
Chris@0 188 }
Chris@0 189
Chris@0 190 out << n << "R";
Chris@0 191 return out;
Chris@0 192 }
Chris@0 193
Chris@0 194 std::string
Chris@121 195 RealTime::toString(bool align) const
Chris@0 196 {
Chris@0 197 std::stringstream out;
Chris@0 198 out << *this;
Chris@0 199
Chris@0 200 std::string s = out.str();
Chris@0 201
Chris@121 202 if (!align && *this >= RealTime::zeroTime) {
Chris@121 203 // remove leading " "
Chris@121 204 s = s.substr(1, s.length() - 1);
Chris@121 205 }
Chris@121 206
Chris@0 207 // remove trailing R
Chris@0 208 return s.substr(0, s.length() - 1);
Chris@0 209 }
Chris@0 210
Chris@350 211 RealTime
Chris@350 212 RealTime::fromString(std::string s)
Chris@350 213 {
Chris@350 214 bool negative = false;
Chris@957 215 int section = 0;
Chris@350 216 std::string ssec, snsec;
Chris@350 217
Chris@350 218 for (size_t i = 0; i < s.length(); ++i) {
Chris@350 219
Chris@350 220 char c = s[i];
Chris@350 221 if (isspace(c)) continue;
Chris@350 222
Chris@350 223 if (section == 0) {
Chris@350 224
Chris@350 225 if (c == '-') negative = true;
Chris@350 226 else if (isdigit(c)) { section = 1; ssec += c; }
Chris@350 227 else if (c == '.') section = 2;
Chris@350 228 else break;
Chris@350 229
Chris@350 230 } else if (section == 1) {
Chris@350 231
Chris@350 232 if (c == '.') section = 2;
Chris@350 233 else if (isdigit(c)) ssec += c;
Chris@350 234 else break;
Chris@350 235
Chris@350 236 } else if (section == 2) {
Chris@350 237
Chris@350 238 if (isdigit(c)) snsec += c;
Chris@350 239 else break;
Chris@350 240 }
Chris@350 241 }
Chris@350 242
Chris@350 243 while (snsec.length() < 8) snsec += '0';
Chris@350 244
Chris@350 245 int sec = atoi(ssec.c_str());
Chris@350 246 int nsec = atoi(snsec.c_str());
Chris@350 247 if (negative) sec = -sec;
Chris@350 248
Chris@690 249 // SVDEBUG << "RealTime::fromString: string " << s << " -> "
Chris@687 250 // << sec << " sec, " << nsec << " nsec" << endl;
Chris@350 251
Chris@350 252 return RealTime(sec, nsec);
Chris@350 253 }
Chris@350 254
Chris@0 255 std::string
Chris@0 256 RealTime::toText(bool fixedDp) const
Chris@0 257 {
Chris@247 258 if (*this < RealTime::zeroTime) return "-" + (-*this).toText(fixedDp);
Chris@0 259
Chris@612 260 Preferences *p = Preferences::getInstance();
Chris@612 261 if (p) {
Chris@612 262 int fps = 0;
Chris@612 263 switch (p->getTimeToTextMode()) {
Chris@612 264 case Preferences::TimeToTextMs: break;
Chris@612 265 case Preferences::TimeToTextUs: fps = 1000000; break;
Chris@612 266 case Preferences::TimeToText24Frame: fps = 24; break;
Chris@612 267 case Preferences::TimeToText25Frame: fps = 25; break;
Chris@612 268 case Preferences::TimeToText30Frame: fps = 30; break;
Chris@612 269 case Preferences::TimeToText50Frame: fps = 50; break;
Chris@612 270 case Preferences::TimeToText60Frame: fps = 60; break;
Chris@612 271 }
Chris@612 272 if (fps != 0) return toFrameText(fps);
Chris@612 273 }
Chris@612 274
Chris@0 275 std::stringstream out;
Chris@0 276
Chris@1031 277 if (p->getShowHMS()) {
Chris@1031 278
Chris@1031 279 if (sec >= 3600) {
Chris@1031 280 out << (sec / 3600) << ":";
Chris@1031 281 }
Chris@1031 282
Chris@1031 283 if (sec >= 60) {
Chris@1031 284 out << (sec % 3600) / 60 << ":";
Chris@1031 285 }
Chris@1031 286
Chris@1031 287 if (sec >= 10) {
Chris@1031 288 out << ((sec % 60) / 10);
Chris@1031 289 }
Chris@1031 290
Chris@1031 291 out << (sec % 10);
Chris@1031 292
Chris@1031 293 } else {
Chris@1031 294 out << sec;
Chris@0 295 }
Chris@0 296
Chris@0 297 int ms = msec();
Chris@0 298
Chris@0 299 if (ms != 0) {
Chris@0 300 out << ".";
Chris@0 301 out << (ms / 100);
Chris@0 302 ms = ms % 100;
Chris@0 303 if (ms != 0) {
Chris@0 304 out << (ms / 10);
Chris@0 305 ms = ms % 10;
Chris@0 306 } else if (fixedDp) {
Chris@0 307 out << "0";
Chris@0 308 }
Chris@0 309 if (ms != 0) {
Chris@0 310 out << ms;
Chris@0 311 } else if (fixedDp) {
Chris@0 312 out << "0";
Chris@0 313 }
Chris@0 314 } else if (fixedDp) {
Chris@0 315 out << ".000";
Chris@0 316 }
Chris@0 317
Chris@612 318 std::string s = out.str();
Chris@0 319
Chris@612 320 return s;
Chris@612 321 }
Chris@612 322
Chris@612 323 std::string
Chris@612 324 RealTime::toFrameText(int fps) const
Chris@612 325 {
Chris@612 326 if (*this < RealTime::zeroTime) return "-" + (-*this).toFrameText(fps);
Chris@612 327
Chris@1031 328 Preferences *p = Preferences::getInstance();
Chris@1031 329
Chris@612 330 std::stringstream out;
Chris@612 331
Chris@1031 332 if (p->getShowHMS()) {
Chris@1031 333
Chris@1031 334 if (sec >= 3600) {
Chris@1031 335 out << (sec / 3600) << ":";
Chris@1031 336 }
Chris@1031 337
Chris@1031 338 if (sec >= 60) {
Chris@1031 339 out << (sec % 3600) / 60 << ":";
Chris@1031 340 }
Chris@1031 341
Chris@1031 342 if (sec >= 10) {
Chris@1031 343 out << ((sec % 60) / 10);
Chris@1031 344 }
Chris@1031 345
Chris@1031 346 out << (sec % 10);
Chris@1031 347
Chris@1031 348 } else {
Chris@1031 349 out << sec;
Chris@612 350 }
Chris@612 351
Chris@612 352 int f = nsec / (ONE_BILLION / fps);
Chris@612 353
Chris@612 354 int div = 1;
Chris@612 355 int n = fps - 1;
Chris@612 356 while ((n = n / 10)) {
Chris@612 357 div *= 10;
Chris@612 358 }
Chris@612 359
Chris@612 360 out << ":";
Chris@612 361
Chris@843 362 // cerr << "div = " << div << ", f = "<< f << endl;
Chris@612 363
Chris@612 364 while (div) {
Chris@612 365 int d = (f / div) % 10;
Chris@612 366 out << d;
Chris@612 367 div /= 10;
Chris@612 368 }
Chris@612 369
Chris@0 370 std::string s = out.str();
Chris@0 371
Chris@843 372 // cerr << "converted " << toString() << " to " << s << endl;
Chris@612 373
Chris@0 374 return s;
Chris@0 375 }
Chris@0 376
Chris@247 377 std::string
Chris@247 378 RealTime::toSecText() const
Chris@247 379 {
Chris@247 380 if (*this < RealTime::zeroTime) return "-" + (-*this).toSecText();
Chris@247 381
Chris@247 382 std::stringstream out;
Chris@247 383
Chris@247 384 if (sec >= 3600) {
Chris@247 385 out << (sec / 3600) << ":";
Chris@247 386 }
Chris@247 387
Chris@247 388 if (sec >= 60) {
Chris@247 389 out << (sec % 3600) / 60 << ":";
Chris@247 390 }
Chris@247 391
Chris@247 392 if (sec >= 10) {
Chris@247 393 out << ((sec % 60) / 10);
Chris@247 394 }
Chris@247 395
Chris@247 396 out << (sec % 10);
Chris@247 397
Chris@247 398 if (sec < 60) {
Chris@247 399 out << "s";
Chris@247 400 }
Chris@247 401
Chris@247 402 std::string s = out.str();
Chris@247 403
Chris@247 404 return s;
Chris@247 405 }
Chris@247 406
Chris@494 407 std::string
Chris@494 408 RealTime::toXsdDuration() const
Chris@494 409 {
Chris@494 410 std::string s = "PT" + toString(false) + "S";
Chris@494 411 return s;
Chris@494 412 }
Chris@494 413
Chris@183 414 RealTime
Chris@183 415 RealTime::operator*(int m) const
Chris@183 416 {
Chris@183 417 double t = (double(nsec) / ONE_BILLION) * m;
Chris@183 418 t += sec * m;
Chris@183 419 return fromSeconds(t);
Chris@183 420 }
Chris@0 421
Chris@0 422 RealTime
Chris@0 423 RealTime::operator/(int d) const
Chris@0 424 {
Chris@0 425 int secdiv = sec / d;
Chris@0 426 int secrem = sec % d;
Chris@0 427
Chris@0 428 double nsecdiv = (double(nsec) + ONE_BILLION * double(secrem)) / d;
Chris@0 429
Chris@0 430 return RealTime(secdiv, int(nsecdiv + 0.5));
Chris@0 431 }
Chris@0 432
Chris@378 433 RealTime
Chris@378 434 RealTime::operator*(double m) const
Chris@378 435 {
Chris@378 436 double t = (double(nsec) / ONE_BILLION) * m;
Chris@378 437 t += sec * m;
Chris@378 438 return fromSeconds(t);
Chris@378 439 }
Chris@378 440
Chris@378 441 RealTime
Chris@378 442 RealTime::operator/(double d) const
Chris@378 443 {
Chris@378 444 double t = (double(nsec) / ONE_BILLION) / d;
Chris@378 445 t += sec / d;
Chris@378 446 return fromSeconds(t);
Chris@378 447 }
Chris@378 448
Chris@0 449 double
Chris@0 450 RealTime::operator/(const RealTime &r) const
Chris@0 451 {
Chris@0 452 double lTotal = double(sec) * ONE_BILLION + double(nsec);
Chris@0 453 double rTotal = double(r.sec) * ONE_BILLION + double(r.nsec);
Chris@0 454
Chris@0 455 if (rTotal == 0) return 0.0;
Chris@0 456 else return lTotal/rTotal;
Chris@0 457 }
Chris@0 458
Chris@1040 459 static RealTime
Chris@1040 460 frame2RealTime_i(sv_frame_t frame, sv_frame_t iSampleRate)
Chris@1040 461 {
Chris@1040 462 if (frame < 0) return -frame2RealTime_i(-frame, iSampleRate);
Chris@1040 463
Chris@1040 464 RealTime rt;
Chris@1040 465 sv_frame_t sec = frame / iSampleRate;
Chris@1040 466 rt.sec = int(sec);
Chris@1040 467 frame -= sec * iSampleRate;
Chris@1040 468 rt.nsec = (int)(((double(frame) * 1000000.0) / double(iSampleRate)) * 1000.0);
Chris@1040 469 return rt;
Chris@1040 470 }
Chris@1040 471
Chris@1038 472 sv_frame_t
Chris@1040 473 RealTime::realTime2Frame(const RealTime &time, sv_samplerate_t sampleRate)
Chris@0 474 {
Chris@0 475 if (time < zeroTime) return -realTime2Frame(-time, sampleRate);
Chris@427 476 double s = time.sec + double(time.nsec + 1) / 1000000000.0;
Chris@1040 477 return sv_frame_t(s * sampleRate);
Chris@0 478 }
Chris@0 479
Chris@0 480 RealTime
Chris@1040 481 RealTime::frame2RealTime(sv_frame_t frame, sv_samplerate_t sampleRate)
Chris@0 482 {
Chris@1040 483 if (sampleRate == double(int(sampleRate))) {
Chris@1040 484 return frame2RealTime_i(frame, int(sampleRate));
Chris@1040 485 }
Chris@0 486
Chris@1040 487 double sec = double(frame) / sampleRate;
Chris@1040 488 return fromSeconds(sec);
Chris@0 489 }
Chris@0 490
Chris@0 491 const RealTime RealTime::zeroTime(0,0);
Chris@0 492