Chris@49: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@0: Chris@0: /* Chris@52: Sonic Visualiser Chris@52: An audio file viewer and annotation editor. Chris@52: Centre for Digital Music, Queen Mary, University of London. Chris@0: Chris@52: This program is free software; you can redistribute it and/or Chris@52: modify it under the terms of the GNU General Public License as Chris@52: published by the Free Software Foundation; either version 2 of the Chris@52: License, or (at your option) any later version. See the file Chris@52: COPYING included with this distribution for more information. Chris@0: */ Chris@0: Chris@0: /* Chris@0: This is a modified version of a source file from the Chris@0: Rosegarden MIDI and audio sequencer and notation editor. Chris@17: This file copyright 2000-2006 Chris Cannam. Chris@0: */ Chris@0: Chris@0: #include Chris@0: Chris@0: #if (__GNUC__ < 3) Chris@0: #include Chris@0: #define stringstream strstream Chris@0: #else Chris@0: #include Chris@0: #endif Chris@0: Chris@0: using std::cerr; Chris@0: using std::endl; Chris@0: Chris@150: #include "RealTime.h" Chris@26: #include "sys/time.h" Chris@0: Chris@0: // A RealTime consists of two ints that must be at least 32 bits each. Chris@0: // A signed 32-bit int can store values exceeding +/- 2 billion. This Chris@0: // means we can safely use our lower int for nanoseconds, as there are Chris@0: // 1 billion nanoseconds in a second and we need to handle double that Chris@0: // because of the implementations of addition etc that we use. Chris@0: // Chris@0: // The maximum valid RealTime on a 32-bit system is somewhere around Chris@0: // 68 years: 999999999 nanoseconds longer than the classic Unix epoch. Chris@0: Chris@0: #define ONE_BILLION 1000000000 Chris@0: Chris@0: RealTime::RealTime(int s, int n) : Chris@0: sec(s), nsec(n) Chris@0: { Chris@0: if (sec == 0) { Chris@0: while (nsec <= -ONE_BILLION) { nsec += ONE_BILLION; --sec; } Chris@0: while (nsec >= ONE_BILLION) { nsec -= ONE_BILLION; ++sec; } Chris@0: } else if (sec < 0) { Chris@0: while (nsec <= -ONE_BILLION) { nsec += ONE_BILLION; --sec; } Chris@0: while (nsec > 0) { nsec -= ONE_BILLION; ++sec; } Chris@0: } else { Chris@0: while (nsec >= ONE_BILLION) { nsec -= ONE_BILLION; ++sec; } Chris@0: while (nsec < 0) { nsec += ONE_BILLION; --sec; } Chris@0: } Chris@0: } Chris@0: Chris@26: RealTime Chris@26: RealTime::fromSeconds(double sec) Chris@26: { Chris@119: return RealTime(int(sec), int((sec - int(sec)) * ONE_BILLION + 0.5)); Chris@26: } Chris@26: Chris@26: RealTime Chris@26: RealTime::fromMilliseconds(int msec) Chris@26: { Chris@26: return RealTime(msec / 1000, (msec % 1000) * 1000000); Chris@26: } Chris@26: Chris@26: RealTime Chris@26: RealTime::fromTimeval(const struct timeval &tv) Chris@26: { Chris@26: return RealTime(tv.tv_sec, tv.tv_usec * 1000); Chris@26: } Chris@0: Chris@0: std::ostream &operator<<(std::ostream &out, const RealTime &rt) Chris@0: { Chris@0: if (rt < RealTime::zeroTime) { Chris@0: out << "-"; Chris@0: } else { Chris@0: out << " "; Chris@0: } Chris@0: Chris@0: int s = (rt.sec < 0 ? -rt.sec : rt.sec); Chris@0: int n = (rt.nsec < 0 ? -rt.nsec : rt.nsec); Chris@0: Chris@0: out << s << "."; Chris@0: Chris@0: int nn(n); Chris@0: if (nn == 0) out << "00000000"; Chris@0: else while (nn < (ONE_BILLION / 10)) { Chris@0: out << "0"; Chris@0: nn *= 10; Chris@0: } Chris@0: Chris@0: out << n << "R"; Chris@0: return out; Chris@0: } Chris@0: Chris@0: std::string Chris@121: RealTime::toString(bool align) const Chris@0: { Chris@0: std::stringstream out; Chris@0: out << *this; Chris@0: Chris@0: #if (__GNUC__ < 3) Chris@0: out << std::ends; Chris@0: #endif Chris@0: Chris@0: std::string s = out.str(); Chris@0: Chris@121: if (!align && *this >= RealTime::zeroTime) { Chris@121: // remove leading " " Chris@121: s = s.substr(1, s.length() - 1); Chris@121: } Chris@121: Chris@0: // remove trailing R Chris@0: return s.substr(0, s.length() - 1); Chris@0: } Chris@0: Chris@384: RealTime Chris@384: RealTime::fromString(std::string s) Chris@384: { Chris@384: bool negative = false; Chris@384: bool faulty = false; Chris@384: bool section = 0; Chris@384: std::string ssec, snsec; Chris@384: Chris@384: for (size_t i = 0; i < s.length(); ++i) { Chris@384: Chris@384: char c = s[i]; Chris@384: if (isspace(c)) continue; Chris@384: Chris@384: if (section == 0) { Chris@384: Chris@384: if (c == '-') negative = true; Chris@384: else if (isdigit(c)) { section = 1; ssec += c; } Chris@384: else if (c == '.') section = 2; Chris@384: else break; Chris@384: Chris@384: } else if (section == 1) { Chris@384: Chris@384: if (c == '.') section = 2; Chris@384: else if (isdigit(c)) ssec += c; Chris@384: else break; Chris@384: Chris@384: } else if (section == 2) { Chris@384: Chris@384: if (isdigit(c)) snsec += c; Chris@384: else break; Chris@384: } Chris@384: } Chris@384: Chris@384: while (snsec.length() < 8) snsec += '0'; Chris@384: Chris@384: int sec = atoi(ssec.c_str()); Chris@384: int nsec = atoi(snsec.c_str()); Chris@384: if (negative) sec = -sec; Chris@384: Chris@384: std::cerr << "RealTime::fromString: string " << s << " -> " Chris@384: << sec << " sec, " << nsec << " nsec" << std::endl; Chris@384: Chris@384: return RealTime(sec, nsec); Chris@384: } Chris@384: Chris@0: std::string Chris@0: RealTime::toText(bool fixedDp) const Chris@0: { Chris@247: if (*this < RealTime::zeroTime) return "-" + (-*this).toText(fixedDp); Chris@0: Chris@0: std::stringstream out; Chris@0: Chris@0: if (sec >= 3600) { Chris@0: out << (sec / 3600) << ":"; Chris@0: } Chris@0: Chris@0: if (sec >= 60) { Chris@0: out << (sec % 3600) / 60 << ":"; Chris@0: } Chris@0: Chris@0: if (sec >= 10) { Chris@0: out << ((sec % 60) / 10); Chris@0: } Chris@0: Chris@0: out << (sec % 10); Chris@0: Chris@0: int ms = msec(); Chris@0: Chris@0: if (ms != 0) { Chris@0: out << "."; Chris@0: out << (ms / 100); Chris@0: ms = ms % 100; Chris@0: if (ms != 0) { Chris@0: out << (ms / 10); Chris@0: ms = ms % 10; Chris@0: } else if (fixedDp) { Chris@0: out << "0"; Chris@0: } Chris@0: if (ms != 0) { Chris@0: out << ms; Chris@0: } else if (fixedDp) { Chris@0: out << "0"; Chris@0: } Chris@0: } else if (fixedDp) { Chris@0: out << ".000"; Chris@0: } Chris@0: Chris@0: #if (__GNUC__ < 3) Chris@0: out << std::ends; Chris@0: #endif Chris@0: Chris@0: std::string s = out.str(); Chris@0: Chris@0: return s; Chris@0: } Chris@0: Chris@247: std::string Chris@247: RealTime::toSecText() const Chris@247: { Chris@247: if (*this < RealTime::zeroTime) return "-" + (-*this).toSecText(); Chris@247: Chris@247: std::stringstream out; Chris@247: Chris@247: if (sec >= 3600) { Chris@247: out << (sec / 3600) << ":"; Chris@247: } Chris@247: Chris@247: if (sec >= 60) { Chris@247: out << (sec % 3600) / 60 << ":"; Chris@247: } Chris@247: Chris@247: if (sec >= 10) { Chris@247: out << ((sec % 60) / 10); Chris@247: } Chris@247: Chris@247: out << (sec % 10); Chris@247: Chris@247: if (sec < 60) { Chris@247: out << "s"; Chris@247: } Chris@247: Chris@247: Chris@247: #if (__GNUC__ < 3) Chris@247: out << std::ends; Chris@247: #endif Chris@247: Chris@247: std::string s = out.str(); Chris@247: Chris@247: return s; Chris@247: } Chris@247: Chris@183: RealTime Chris@183: RealTime::operator*(int m) const Chris@183: { Chris@183: double t = (double(nsec) / ONE_BILLION) * m; Chris@183: t += sec * m; Chris@183: return fromSeconds(t); Chris@183: } Chris@0: Chris@0: RealTime Chris@0: RealTime::operator/(int d) const Chris@0: { Chris@0: int secdiv = sec / d; Chris@0: int secrem = sec % d; Chris@0: Chris@0: double nsecdiv = (double(nsec) + ONE_BILLION * double(secrem)) / d; Chris@0: Chris@0: return RealTime(secdiv, int(nsecdiv + 0.5)); Chris@0: } Chris@0: Chris@384: RealTime Chris@384: RealTime::operator*(double m) const Chris@384: { Chris@384: double t = (double(nsec) / ONE_BILLION) * m; Chris@384: t += sec * m; Chris@384: return fromSeconds(t); Chris@384: } Chris@384: Chris@384: RealTime Chris@384: RealTime::operator/(double d) const Chris@384: { Chris@384: double t = (double(nsec) / ONE_BILLION) / d; Chris@384: t += sec / d; Chris@384: return fromSeconds(t); Chris@384: } Chris@384: Chris@0: double Chris@0: RealTime::operator/(const RealTime &r) const Chris@0: { Chris@0: double lTotal = double(sec) * ONE_BILLION + double(nsec); Chris@0: double rTotal = double(r.sec) * ONE_BILLION + double(r.nsec); Chris@0: Chris@0: if (rTotal == 0) return 0.0; Chris@0: else return lTotal/rTotal; Chris@0: } Chris@0: Chris@0: long Chris@0: RealTime::realTime2Frame(const RealTime &time, unsigned int sampleRate) Chris@0: { Chris@0: if (time < zeroTime) return -realTime2Frame(-time, sampleRate); Chris@0: Chris@0: // We like integers. The last term is always zero unless the Chris@0: // sample rate is greater than 1MHz, but hell, you never know... Chris@0: Chris@0: long frame = Chris@0: time.sec * sampleRate + Chris@0: (time.msec() * sampleRate) / 1000 + Chris@0: ((time.usec() - 1000 * time.msec()) * sampleRate) / 1000000 + Chris@0: ((time.nsec - 1000 * time.usec()) * sampleRate) / 1000000000; Chris@0: Chris@0: return frame; Chris@0: } Chris@0: Chris@0: RealTime Chris@0: RealTime::frame2RealTime(long frame, unsigned int sampleRate) Chris@0: { Chris@0: if (frame < 0) return -frame2RealTime(-frame, sampleRate); Chris@0: Chris@0: RealTime rt; Chris@0: rt.sec = frame / long(sampleRate); Chris@0: frame -= rt.sec * long(sampleRate); Chris@0: rt.nsec = (int)(((float(frame) * 1000000) / long(sampleRate)) * 1000); Chris@0: return rt; Chris@0: } Chris@0: Chris@0: const RealTime RealTime::zeroTime(0,0); Chris@0: