svcore  1.9
RealTime.cpp
Go to the documentation of this file.
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