annotate base/RealTime.cpp @ 490:c3fb8258e34d

* Make it possible to import an entire session from an RDF document. However, at the moment the timings of events appear to be constrained by how far the audio decoder has got through its audio file at the time the event is queried -- need to investigate.
author Chris Cannam
date Fri, 21 Nov 2008 18:03:14 +0000
parents beb2948baa77
children 81963c51b488
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@405 24
Chris@0 25 #if (__GNUC__ < 3)
Chris@0 26 #include <strstream>
Chris@0 27 #define stringstream strstream
Chris@0 28 #else
Chris@0 29 #include <sstream>
Chris@0 30 #endif
Chris@0 31
Chris@0 32 using std::cerr;
Chris@0 33 using std::endl;
Chris@0 34
Chris@150 35 #include "RealTime.h"
Chris@26 36 #include "sys/time.h"
Chris@0 37
Chris@0 38 // A RealTime consists of two ints that must be at least 32 bits each.
Chris@0 39 // A signed 32-bit int can store values exceeding +/- 2 billion. This
Chris@0 40 // means we can safely use our lower int for nanoseconds, as there are
Chris@0 41 // 1 billion nanoseconds in a second and we need to handle double that
Chris@0 42 // because of the implementations of addition etc that we use.
Chris@0 43 //
Chris@0 44 // The maximum valid RealTime on a 32-bit system is somewhere around
Chris@0 45 // 68 years: 999999999 nanoseconds longer than the classic Unix epoch.
Chris@0 46
Chris@0 47 #define ONE_BILLION 1000000000
Chris@0 48
Chris@0 49 RealTime::RealTime(int s, int n) :
Chris@0 50 sec(s), nsec(n)
Chris@0 51 {
Chris@0 52 if (sec == 0) {
Chris@0 53 while (nsec <= -ONE_BILLION) { nsec += ONE_BILLION; --sec; }
Chris@0 54 while (nsec >= ONE_BILLION) { nsec -= ONE_BILLION; ++sec; }
Chris@0 55 } else if (sec < 0) {
Chris@0 56 while (nsec <= -ONE_BILLION) { nsec += ONE_BILLION; --sec; }
Chris@0 57 while (nsec > 0) { nsec -= ONE_BILLION; ++sec; }
Chris@0 58 } else {
Chris@0 59 while (nsec >= ONE_BILLION) { nsec -= ONE_BILLION; ++sec; }
Chris@0 60 while (nsec < 0) { nsec += ONE_BILLION; --sec; }
Chris@0 61 }
Chris@0 62 }
Chris@0 63
Chris@26 64 RealTime
Chris@26 65 RealTime::fromSeconds(double sec)
Chris@26 66 {
Chris@119 67 return RealTime(int(sec), int((sec - int(sec)) * ONE_BILLION + 0.5));
Chris@26 68 }
Chris@26 69
Chris@26 70 RealTime
Chris@26 71 RealTime::fromMilliseconds(int msec)
Chris@26 72 {
Chris@26 73 return RealTime(msec / 1000, (msec % 1000) * 1000000);
Chris@26 74 }
Chris@26 75
Chris@26 76 RealTime
Chris@26 77 RealTime::fromTimeval(const struct timeval &tv)
Chris@26 78 {
Chris@26 79 return RealTime(tv.tv_sec, tv.tv_usec * 1000);
Chris@26 80 }
Chris@0 81
Chris@439 82 RealTime
Chris@439 83 RealTime::fromXsdDuration(std::string xsdd)
Chris@439 84 {
Chris@439 85 RealTime t;
Chris@439 86
Chris@439 87 int year = 0, month = 0, day = 0, hour = 0, minute = 0;
Chris@439 88 double second = 0.0;
Chris@439 89
Chris@439 90 int i = 0;
Chris@439 91
Chris@439 92 const char *s = xsdd.c_str();
Chris@439 93 int len = xsdd.length();
Chris@439 94
Chris@439 95 bool negative = false, afterT = false;
Chris@439 96
Chris@439 97 int valstart = 0;
Chris@439 98
Chris@439 99 while (i < len) {
Chris@439 100
Chris@439 101 if (s[i] == '-') {
Chris@439 102 if (i == 0) negative = true;
Chris@439 103 ++i;
Chris@439 104 continue;
Chris@439 105 }
Chris@439 106
Chris@439 107 double value = 0.0;
Chris@439 108 char *eptr = 0;
Chris@439 109
Chris@439 110 if (isdigit(s[i]) || s[i] == '.') {
Chris@439 111 valstart = i;
Chris@439 112 value = strtod(&s[i], &eptr);
Chris@439 113 i = eptr - s;
Chris@439 114 }
Chris@439 115
Chris@439 116 if (i == len) break;
Chris@439 117
Chris@439 118 switch (s[i]) {
Chris@439 119 case 'Y': year = int(value + 0.1); break;
Chris@439 120 case 'D': day = int(value + 0.1); break;
Chris@439 121 case 'H': hour = int(value + 0.1); break;
Chris@439 122 case 'M':
Chris@439 123 if (afterT) minute = int(value + 0.1);
Chris@439 124 else month = int(value + 0.1);
Chris@439 125 break;
Chris@439 126 case 'S':
Chris@439 127 second = value;
Chris@439 128 break;
Chris@439 129 case 'T': afterT = true; break;
Chris@439 130 };
Chris@439 131
Chris@439 132 ++i;
Chris@439 133 }
Chris@439 134
Chris@439 135 if (year > 0) {
Chris@439 136 std::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." << std::endl;
Chris@439 137 t = t + RealTime(year * 31556952, 0);
Chris@439 138 }
Chris@439 139
Chris@439 140 if (month > 0) {
Chris@439 141 std::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." << std::endl;
Chris@439 142 t = t + RealTime(month * 2629746, 0);
Chris@439 143 }
Chris@439 144
Chris@439 145 if (day > 0) {
Chris@439 146 t = t + RealTime(day * 86400, 0);
Chris@439 147 }
Chris@439 148
Chris@439 149 if (hour > 0) {
Chris@439 150 t = t + RealTime(hour * 3600, 0);
Chris@439 151 }
Chris@439 152
Chris@439 153 if (minute > 0) {
Chris@439 154 t = t + RealTime(minute * 60, 0);
Chris@439 155 }
Chris@439 156
Chris@439 157 t = t + fromSeconds(second);
Chris@439 158
Chris@439 159 return t;
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 #if (__GNUC__ < 3)
Chris@0 201 out << std::ends;
Chris@0 202 #endif
Chris@0 203
Chris@0 204 std::string s = out.str();
Chris@0 205
Chris@121 206 if (!align && *this >= RealTime::zeroTime) {
Chris@121 207 // remove leading " "
Chris@121 208 s = s.substr(1, s.length() - 1);
Chris@121 209 }
Chris@121 210
Chris@0 211 // remove trailing R
Chris@0 212 return s.substr(0, s.length() - 1);
Chris@0 213 }
Chris@0 214
Chris@350 215 RealTime
Chris@350 216 RealTime::fromString(std::string s)
Chris@350 217 {
Chris@350 218 bool negative = false;
Chris@350 219 bool section = 0;
Chris@350 220 std::string ssec, snsec;
Chris@350 221
Chris@350 222 for (size_t i = 0; i < s.length(); ++i) {
Chris@350 223
Chris@350 224 char c = s[i];
Chris@350 225 if (isspace(c)) continue;
Chris@350 226
Chris@350 227 if (section == 0) {
Chris@350 228
Chris@350 229 if (c == '-') negative = true;
Chris@350 230 else if (isdigit(c)) { section = 1; ssec += c; }
Chris@350 231 else if (c == '.') section = 2;
Chris@350 232 else break;
Chris@350 233
Chris@350 234 } else if (section == 1) {
Chris@350 235
Chris@350 236 if (c == '.') section = 2;
Chris@350 237 else if (isdigit(c)) ssec += c;
Chris@350 238 else break;
Chris@350 239
Chris@350 240 } else if (section == 2) {
Chris@350 241
Chris@350 242 if (isdigit(c)) snsec += c;
Chris@350 243 else break;
Chris@350 244 }
Chris@350 245 }
Chris@350 246
Chris@350 247 while (snsec.length() < 8) snsec += '0';
Chris@350 248
Chris@350 249 int sec = atoi(ssec.c_str());
Chris@350 250 int nsec = atoi(snsec.c_str());
Chris@350 251 if (negative) sec = -sec;
Chris@350 252
Chris@399 253 // std::cerr << "RealTime::fromString: string " << s << " -> "
Chris@399 254 // << sec << " sec, " << nsec << " nsec" << std::endl;
Chris@350 255
Chris@350 256 return RealTime(sec, nsec);
Chris@350 257 }
Chris@350 258
Chris@0 259 std::string
Chris@0 260 RealTime::toText(bool fixedDp) const
Chris@0 261 {
Chris@247 262 if (*this < RealTime::zeroTime) return "-" + (-*this).toText(fixedDp);
Chris@0 263
Chris@0 264 std::stringstream out;
Chris@0 265
Chris@0 266 if (sec >= 3600) {
Chris@0 267 out << (sec / 3600) << ":";
Chris@0 268 }
Chris@0 269
Chris@0 270 if (sec >= 60) {
Chris@0 271 out << (sec % 3600) / 60 << ":";
Chris@0 272 }
Chris@0 273
Chris@0 274 if (sec >= 10) {
Chris@0 275 out << ((sec % 60) / 10);
Chris@0 276 }
Chris@0 277
Chris@0 278 out << (sec % 10);
Chris@0 279
Chris@0 280 int ms = msec();
Chris@0 281
Chris@0 282 if (ms != 0) {
Chris@0 283 out << ".";
Chris@0 284 out << (ms / 100);
Chris@0 285 ms = ms % 100;
Chris@0 286 if (ms != 0) {
Chris@0 287 out << (ms / 10);
Chris@0 288 ms = ms % 10;
Chris@0 289 } else if (fixedDp) {
Chris@0 290 out << "0";
Chris@0 291 }
Chris@0 292 if (ms != 0) {
Chris@0 293 out << ms;
Chris@0 294 } else if (fixedDp) {
Chris@0 295 out << "0";
Chris@0 296 }
Chris@0 297 } else if (fixedDp) {
Chris@0 298 out << ".000";
Chris@0 299 }
Chris@0 300
Chris@0 301 #if (__GNUC__ < 3)
Chris@0 302 out << std::ends;
Chris@0 303 #endif
Chris@0 304
Chris@0 305 std::string s = out.str();
Chris@0 306
Chris@0 307 return s;
Chris@0 308 }
Chris@0 309
Chris@247 310 std::string
Chris@247 311 RealTime::toSecText() const
Chris@247 312 {
Chris@247 313 if (*this < RealTime::zeroTime) return "-" + (-*this).toSecText();
Chris@247 314
Chris@247 315 std::stringstream out;
Chris@247 316
Chris@247 317 if (sec >= 3600) {
Chris@247 318 out << (sec / 3600) << ":";
Chris@247 319 }
Chris@247 320
Chris@247 321 if (sec >= 60) {
Chris@247 322 out << (sec % 3600) / 60 << ":";
Chris@247 323 }
Chris@247 324
Chris@247 325 if (sec >= 10) {
Chris@247 326 out << ((sec % 60) / 10);
Chris@247 327 }
Chris@247 328
Chris@247 329 out << (sec % 10);
Chris@247 330
Chris@247 331 if (sec < 60) {
Chris@247 332 out << "s";
Chris@247 333 }
Chris@247 334
Chris@247 335
Chris@247 336 #if (__GNUC__ < 3)
Chris@247 337 out << std::ends;
Chris@247 338 #endif
Chris@247 339
Chris@247 340 std::string s = out.str();
Chris@247 341
Chris@247 342 return s;
Chris@247 343 }
Chris@247 344
Chris@183 345 RealTime
Chris@183 346 RealTime::operator*(int m) const
Chris@183 347 {
Chris@183 348 double t = (double(nsec) / ONE_BILLION) * m;
Chris@183 349 t += sec * m;
Chris@183 350 return fromSeconds(t);
Chris@183 351 }
Chris@0 352
Chris@0 353 RealTime
Chris@0 354 RealTime::operator/(int d) const
Chris@0 355 {
Chris@0 356 int secdiv = sec / d;
Chris@0 357 int secrem = sec % d;
Chris@0 358
Chris@0 359 double nsecdiv = (double(nsec) + ONE_BILLION * double(secrem)) / d;
Chris@0 360
Chris@0 361 return RealTime(secdiv, int(nsecdiv + 0.5));
Chris@0 362 }
Chris@0 363
Chris@378 364 RealTime
Chris@378 365 RealTime::operator*(double m) const
Chris@378 366 {
Chris@378 367 double t = (double(nsec) / ONE_BILLION) * m;
Chris@378 368 t += sec * m;
Chris@378 369 return fromSeconds(t);
Chris@378 370 }
Chris@378 371
Chris@378 372 RealTime
Chris@378 373 RealTime::operator/(double d) const
Chris@378 374 {
Chris@378 375 double t = (double(nsec) / ONE_BILLION) / d;
Chris@378 376 t += sec / d;
Chris@378 377 return fromSeconds(t);
Chris@378 378 }
Chris@378 379
Chris@0 380 double
Chris@0 381 RealTime::operator/(const RealTime &r) const
Chris@0 382 {
Chris@0 383 double lTotal = double(sec) * ONE_BILLION + double(nsec);
Chris@0 384 double rTotal = double(r.sec) * ONE_BILLION + double(r.nsec);
Chris@0 385
Chris@0 386 if (rTotal == 0) return 0.0;
Chris@0 387 else return lTotal/rTotal;
Chris@0 388 }
Chris@0 389
Chris@0 390 long
Chris@0 391 RealTime::realTime2Frame(const RealTime &time, unsigned int sampleRate)
Chris@0 392 {
Chris@0 393 if (time < zeroTime) return -realTime2Frame(-time, sampleRate);
Chris@427 394 double s = time.sec + double(time.nsec + 1) / 1000000000.0;
Chris@427 395 return long(s * sampleRate);
Chris@0 396 }
Chris@0 397
Chris@0 398 RealTime
Chris@0 399 RealTime::frame2RealTime(long frame, unsigned int sampleRate)
Chris@0 400 {
Chris@0 401 if (frame < 0) return -frame2RealTime(-frame, sampleRate);
Chris@0 402
Chris@0 403 RealTime rt;
Chris@0 404 rt.sec = frame / long(sampleRate);
Chris@0 405 frame -= rt.sec * long(sampleRate);
Chris@427 406 rt.nsec = (int)(((double(frame) * 1000000.0) / long(sampleRate)) * 1000.0);
Chris@0 407 return rt;
Chris@0 408 }
Chris@0 409
Chris@0 410 const RealTime RealTime::zeroTime(0,0);
Chris@0 411