svcore
1.9
|
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ 00002 00003 /* 00004 Sonic Visualiser 00005 An audio file viewer and annotation editor. 00006 Centre for Digital Music, Queen Mary, University of London. 00007 00008 This program is free software; you can redistribute it and/or 00009 modify it under the terms of the GNU General Public License as 00010 published by the Free Software Foundation; either version 2 of the 00011 License, or (at your option) any later version. See the file 00012 COPYING included with this distribution for more information. 00013 */ 00014 00015 /* 00016 This is a modified version of a source file from the 00017 Rosegarden MIDI and audio sequencer and notation editor. 00018 This file copyright 2000-2006 Chris Cannam. 00019 */ 00020 00021 #include <iostream> 00022 00023 #include <cstdlib> 00024 #include <sstream> 00025 00026 #include "RealTime.h" 00027 #include "sys/time.h" 00028 00029 #include "Debug.h" 00030 00031 #include "Preferences.h" 00032 00033 // A RealTime consists of two ints that must be at least 32 bits each. 00034 // A signed 32-bit int can store values exceeding +/- 2 billion. This 00035 // means we can safely use our lower int for nanoseconds, as there are 00036 // 1 billion nanoseconds in a second and we need to handle double that 00037 // because of the implementations of addition etc that we use. 00038 // 00039 // The maximum valid RealTime on a 32-bit system is somewhere around 00040 // 68 years: 999999999 nanoseconds longer than the classic Unix epoch. 00041 00042 #define ONE_BILLION 1000000000 00043 00044 RealTime::RealTime(int s, int n) : 00045 sec(s), nsec(n) 00046 { 00047 if (sec == 0) { 00048 while (nsec <= -ONE_BILLION) { nsec += ONE_BILLION; --sec; } 00049 while (nsec >= ONE_BILLION) { nsec -= ONE_BILLION; ++sec; } 00050 } else if (sec < 0) { 00051 while (nsec <= -ONE_BILLION) { nsec += ONE_BILLION; --sec; } 00052 while (nsec > 0) { nsec -= ONE_BILLION; ++sec; } 00053 } else { 00054 while (nsec >= ONE_BILLION) { nsec -= ONE_BILLION; ++sec; } 00055 while (nsec < 0) { nsec += ONE_BILLION; --sec; } 00056 } 00057 } 00058 00059 RealTime 00060 RealTime::fromSeconds(double sec) 00061 { 00062 return RealTime(int(sec), int((sec - int(sec)) * ONE_BILLION + 0.5)); 00063 } 00064 00065 RealTime 00066 RealTime::fromMilliseconds(int msec) 00067 { 00068 return RealTime(msec / 1000, (msec % 1000) * 1000000); 00069 } 00070 00071 RealTime 00072 RealTime::fromTimeval(const struct timeval &tv) 00073 { 00074 return RealTime(tv.tv_sec, tv.tv_usec * 1000); 00075 } 00076 00077 RealTime 00078 RealTime::fromXsdDuration(std::string xsdd) 00079 { 00080 RealTime t; 00081 00082 int year = 0, month = 0, day = 0, hour = 0, minute = 0; 00083 double second = 0.0; 00084 00085 int i = 0; 00086 00087 const char *s = xsdd.c_str(); 00088 int len = xsdd.length(); 00089 00090 bool negative = false, afterT = false; 00091 00092 while (i < len) { 00093 00094 if (s[i] == '-') { 00095 if (i == 0) negative = true; 00096 ++i; 00097 continue; 00098 } 00099 00100 double value = 0.0; 00101 char *eptr = 0; 00102 00103 if (isdigit(s[i]) || s[i] == '.') { 00104 value = strtod(&s[i], &eptr); 00105 i = eptr - s; 00106 } 00107 00108 if (i == len) break; 00109 00110 switch (s[i]) { 00111 case 'Y': year = int(value + 0.1); break; 00112 case 'D': day = int(value + 0.1); break; 00113 case 'H': hour = int(value + 0.1); break; 00114 case 'M': 00115 if (afterT) minute = int(value + 0.1); 00116 else month = int(value + 0.1); 00117 break; 00118 case 'S': 00119 second = value; 00120 break; 00121 case 'T': afterT = true; break; 00122 }; 00123 00124 ++i; 00125 } 00126 00127 if (year > 0) { 00128 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; 00129 t = t + RealTime(year * 31556952, 0); 00130 } 00131 00132 if (month > 0) { 00133 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; 00134 t = t + RealTime(month * 2629746, 0); 00135 } 00136 00137 if (day > 0) { 00138 t = t + RealTime(day * 86400, 0); 00139 } 00140 00141 if (hour > 0) { 00142 t = t + RealTime(hour * 3600, 0); 00143 } 00144 00145 if (minute > 0) { 00146 t = t + RealTime(minute * 60, 0); 00147 } 00148 00149 t = t + fromSeconds(second); 00150 00151 if (negative) { 00152 return -t; 00153 } else { 00154 return t; 00155 } 00156 } 00157 00158 double 00159 RealTime::toDouble() const 00160 { 00161 double d = sec; 00162 d += double(nsec) / double(ONE_BILLION); 00163 return d; 00164 } 00165 00166 std::ostream &operator<<(std::ostream &out, const RealTime &rt) 00167 { 00168 if (rt < RealTime::zeroTime) { 00169 out << "-"; 00170 } else { 00171 out << " "; 00172 } 00173 00174 int s = (rt.sec < 0 ? -rt.sec : rt.sec); 00175 int n = (rt.nsec < 0 ? -rt.nsec : rt.nsec); 00176 00177 out << s << "."; 00178 00179 int nn(n); 00180 if (nn == 0) out << "00000000"; 00181 else while (nn < (ONE_BILLION / 10)) { 00182 out << "0"; 00183 nn *= 10; 00184 } 00185 00186 out << n << "R"; 00187 return out; 00188 } 00189 00190 std::string 00191 RealTime::toString(bool align) const 00192 { 00193 std::stringstream out; 00194 out << *this; 00195 00196 std::string s = out.str(); 00197 00198 if (!align && *this >= RealTime::zeroTime) { 00199 // remove leading " " 00200 s = s.substr(1, s.length() - 1); 00201 } 00202 00203 // remove trailing R 00204 return s.substr(0, s.length() - 1); 00205 } 00206 00207 RealTime 00208 RealTime::fromString(std::string s) 00209 { 00210 bool negative = false; 00211 int section = 0; 00212 std::string ssec, snsec; 00213 00214 for (size_t i = 0; i < s.length(); ++i) { 00215 00216 char c = s[i]; 00217 if (isspace(c)) continue; 00218 00219 if (section == 0) { 00220 00221 if (c == '-') negative = true; 00222 else if (isdigit(c)) { section = 1; ssec += c; } 00223 else if (c == '.') section = 2; 00224 else break; 00225 00226 } else if (section == 1) { 00227 00228 if (c == '.') section = 2; 00229 else if (isdigit(c)) ssec += c; 00230 else break; 00231 00232 } else if (section == 2) { 00233 00234 if (isdigit(c)) snsec += c; 00235 else break; 00236 } 00237 } 00238 00239 while (snsec.length() < 8) snsec += '0'; 00240 00241 int sec = atoi(ssec.c_str()); 00242 int nsec = atoi(snsec.c_str()); 00243 if (negative) sec = -sec; 00244 00245 // SVDEBUG << "RealTime::fromString: string " << s << " -> " 00246 // << sec << " sec, " << nsec << " nsec" << endl; 00247 00248 return RealTime(sec, nsec); 00249 } 00250 00251 std::string 00252 RealTime::toText(bool fixedDp) const 00253 { 00254 if (*this < RealTime::zeroTime) return "-" + (-*this).toText(fixedDp); 00255 00256 Preferences *p = Preferences::getInstance(); 00257 if (p) { 00258 int fps = 0; 00259 switch (p->getTimeToTextMode()) { 00260 case Preferences::TimeToTextMs: break; 00261 case Preferences::TimeToTextUs: fps = 1000000; break; 00262 case Preferences::TimeToText24Frame: fps = 24; break; 00263 case Preferences::TimeToText25Frame: fps = 25; break; 00264 case Preferences::TimeToText30Frame: fps = 30; break; 00265 case Preferences::TimeToText50Frame: fps = 50; break; 00266 case Preferences::TimeToText60Frame: fps = 60; break; 00267 } 00268 if (fps != 0) return toFrameText(fps); 00269 } 00270 00271 std::stringstream out; 00272 00273 if (sec >= 3600) { 00274 out << (sec / 3600) << ":"; 00275 } 00276 00277 if (sec >= 60) { 00278 out << (sec % 3600) / 60 << ":"; 00279 } 00280 00281 if (sec >= 10) { 00282 out << ((sec % 60) / 10); 00283 } 00284 00285 out << (sec % 10); 00286 00287 int ms = msec(); 00288 00289 if (ms != 0) { 00290 out << "."; 00291 out << (ms / 100); 00292 ms = ms % 100; 00293 if (ms != 0) { 00294 out << (ms / 10); 00295 ms = ms % 10; 00296 } else if (fixedDp) { 00297 out << "0"; 00298 } 00299 if (ms != 0) { 00300 out << ms; 00301 } else if (fixedDp) { 00302 out << "0"; 00303 } 00304 } else if (fixedDp) { 00305 out << ".000"; 00306 } 00307 00308 std::string s = out.str(); 00309 00310 return s; 00311 } 00312 00313 std::string 00314 RealTime::toFrameText(int fps) const 00315 { 00316 if (*this < RealTime::zeroTime) return "-" + (-*this).toFrameText(fps); 00317 00318 std::stringstream out; 00319 00320 if (sec >= 3600) { 00321 out << (sec / 3600) << ":"; 00322 } 00323 00324 if (sec >= 60) { 00325 out << (sec % 3600) / 60 << ":"; 00326 } 00327 00328 if (sec >= 10) { 00329 out << ((sec % 60) / 10); 00330 } 00331 00332 out << (sec % 10); 00333 00334 int f = nsec / (ONE_BILLION / fps); 00335 00336 int div = 1; 00337 int n = fps - 1; 00338 while ((n = n / 10)) { 00339 div *= 10; 00340 } 00341 00342 out << ":"; 00343 00344 // cerr << "div = " << div << ", f = "<< f << endl; 00345 00346 while (div) { 00347 int d = (f / div) % 10; 00348 out << d; 00349 div /= 10; 00350 } 00351 00352 std::string s = out.str(); 00353 00354 // cerr << "converted " << toString() << " to " << s << endl; 00355 00356 return s; 00357 } 00358 00359 std::string 00360 RealTime::toSecText() const 00361 { 00362 if (*this < RealTime::zeroTime) return "-" + (-*this).toSecText(); 00363 00364 std::stringstream out; 00365 00366 if (sec >= 3600) { 00367 out << (sec / 3600) << ":"; 00368 } 00369 00370 if (sec >= 60) { 00371 out << (sec % 3600) / 60 << ":"; 00372 } 00373 00374 if (sec >= 10) { 00375 out << ((sec % 60) / 10); 00376 } 00377 00378 out << (sec % 10); 00379 00380 if (sec < 60) { 00381 out << "s"; 00382 } 00383 00384 std::string s = out.str(); 00385 00386 return s; 00387 } 00388 00389 std::string 00390 RealTime::toXsdDuration() const 00391 { 00392 std::string s = "PT" + toString(false) + "S"; 00393 return s; 00394 } 00395 00396 RealTime 00397 RealTime::operator*(int m) const 00398 { 00399 double t = (double(nsec) / ONE_BILLION) * m; 00400 t += sec * m; 00401 return fromSeconds(t); 00402 } 00403 00404 RealTime 00405 RealTime::operator/(int d) const 00406 { 00407 int secdiv = sec / d; 00408 int secrem = sec % d; 00409 00410 double nsecdiv = (double(nsec) + ONE_BILLION * double(secrem)) / d; 00411 00412 return RealTime(secdiv, int(nsecdiv + 0.5)); 00413 } 00414 00415 RealTime 00416 RealTime::operator*(double m) const 00417 { 00418 double t = (double(nsec) / ONE_BILLION) * m; 00419 t += sec * m; 00420 return fromSeconds(t); 00421 } 00422 00423 RealTime 00424 RealTime::operator/(double d) const 00425 { 00426 double t = (double(nsec) / ONE_BILLION) / d; 00427 t += sec / d; 00428 return fromSeconds(t); 00429 } 00430 00431 double 00432 RealTime::operator/(const RealTime &r) const 00433 { 00434 double lTotal = double(sec) * ONE_BILLION + double(nsec); 00435 double rTotal = double(r.sec) * ONE_BILLION + double(r.nsec); 00436 00437 if (rTotal == 0) return 0.0; 00438 else return lTotal/rTotal; 00439 } 00440 00441 long 00442 RealTime::realTime2Frame(const RealTime &time, unsigned int sampleRate) 00443 { 00444 if (time < zeroTime) return -realTime2Frame(-time, sampleRate); 00445 double s = time.sec + double(time.nsec + 1) / 1000000000.0; 00446 return long(s * double(sampleRate)); 00447 } 00448 00449 RealTime 00450 RealTime::frame2RealTime(long frame, unsigned int sampleRate) 00451 { 00452 if (frame < 0) return -frame2RealTime(-frame, sampleRate); 00453 00454 RealTime rt; 00455 rt.sec = frame / long(sampleRate); 00456 frame -= rt.sec * long(sampleRate); 00457 rt.nsec = (int)(((double(frame) * 1000000.0) / long(sampleRate)) * 1000.0); 00458 return rt; 00459 } 00460 00461 const RealTime RealTime::zeroTime(0,0); 00462