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