annotate base/RealTime.cpp @ 537:3cc4b7cd2aa5

* Merge from one-fftdataserver-per-fftmodel branch. This bit of reworking (which is not described very accurately by the title of the branch) turns the MatrixFile object into something that either reads or writes, but not both, and separates the FFT file cache reader and writer implementations separately. This allows the FFT data server to have a single thread owning writers and one reader per "customer" thread, and for all locking to be vastly simplified and concentrated in the data server alone (because none of the classes it makes use of is used in more than one thread at a time). The result is faster and more trustworthy code.
author Chris Cannam
date Tue, 27 Jan 2009 13:25:10 +0000
parents 81963c51b488
children 75f154085a4d
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@494 345 std::string
Chris@494 346 RealTime::toXsdDuration() const
Chris@494 347 {
Chris@494 348 std::string s = "PT" + toString(false) + "S";
Chris@494 349 return s;
Chris@494 350 }
Chris@494 351
Chris@183 352 RealTime
Chris@183 353 RealTime::operator*(int m) const
Chris@183 354 {
Chris@183 355 double t = (double(nsec) / ONE_BILLION) * m;
Chris@183 356 t += sec * m;
Chris@183 357 return fromSeconds(t);
Chris@183 358 }
Chris@0 359
Chris@0 360 RealTime
Chris@0 361 RealTime::operator/(int d) const
Chris@0 362 {
Chris@0 363 int secdiv = sec / d;
Chris@0 364 int secrem = sec % d;
Chris@0 365
Chris@0 366 double nsecdiv = (double(nsec) + ONE_BILLION * double(secrem)) / d;
Chris@0 367
Chris@0 368 return RealTime(secdiv, int(nsecdiv + 0.5));
Chris@0 369 }
Chris@0 370
Chris@378 371 RealTime
Chris@378 372 RealTime::operator*(double m) const
Chris@378 373 {
Chris@378 374 double t = (double(nsec) / ONE_BILLION) * m;
Chris@378 375 t += sec * m;
Chris@378 376 return fromSeconds(t);
Chris@378 377 }
Chris@378 378
Chris@378 379 RealTime
Chris@378 380 RealTime::operator/(double d) const
Chris@378 381 {
Chris@378 382 double t = (double(nsec) / ONE_BILLION) / d;
Chris@378 383 t += sec / d;
Chris@378 384 return fromSeconds(t);
Chris@378 385 }
Chris@378 386
Chris@0 387 double
Chris@0 388 RealTime::operator/(const RealTime &r) const
Chris@0 389 {
Chris@0 390 double lTotal = double(sec) * ONE_BILLION + double(nsec);
Chris@0 391 double rTotal = double(r.sec) * ONE_BILLION + double(r.nsec);
Chris@0 392
Chris@0 393 if (rTotal == 0) return 0.0;
Chris@0 394 else return lTotal/rTotal;
Chris@0 395 }
Chris@0 396
Chris@0 397 long
Chris@0 398 RealTime::realTime2Frame(const RealTime &time, unsigned int sampleRate)
Chris@0 399 {
Chris@0 400 if (time < zeroTime) return -realTime2Frame(-time, sampleRate);
Chris@427 401 double s = time.sec + double(time.nsec + 1) / 1000000000.0;
Chris@427 402 return long(s * sampleRate);
Chris@0 403 }
Chris@0 404
Chris@0 405 RealTime
Chris@0 406 RealTime::frame2RealTime(long frame, unsigned int sampleRate)
Chris@0 407 {
Chris@0 408 if (frame < 0) return -frame2RealTime(-frame, sampleRate);
Chris@0 409
Chris@0 410 RealTime rt;
Chris@0 411 rt.sec = frame / long(sampleRate);
Chris@0 412 frame -= rt.sec * long(sampleRate);
Chris@427 413 rt.nsec = (int)(((double(frame) * 1000000.0) / long(sampleRate)) * 1000.0);
Chris@0 414 return rt;
Chris@0 415 }
Chris@0 416
Chris@0 417 const RealTime RealTime::zeroTime(0,0);
Chris@0 418