cannam@0: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ cannam@0: cannam@0: /* cannam@0: Vamp cannam@0: cannam@0: An API for audio analysis and feature extraction plugins. cannam@0: cannam@0: Centre for Digital Music, Queen Mary, University of London. cannam@0: Copyright 2006 Chris Cannam. cannam@0: cannam@0: Permission is hereby granted, free of charge, to any person cannam@0: obtaining a copy of this software and associated documentation cannam@0: files (the "Software"), to deal in the Software without cannam@0: restriction, including without limitation the rights to use, copy, cannam@0: modify, merge, publish, distribute, sublicense, and/or sell copies cannam@0: of the Software, and to permit persons to whom the Software is cannam@0: furnished to do so, subject to the following conditions: cannam@0: cannam@0: The above copyright notice and this permission notice shall be cannam@0: included in all copies or substantial portions of the Software. cannam@0: cannam@0: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, cannam@0: EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF cannam@0: MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND cannam@0: NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR cannam@0: ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF cannam@0: CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION cannam@0: WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. cannam@0: cannam@0: Except as contained in this notice, the names of the Centre for cannam@0: Digital Music; Queen Mary, University of London; and Chris Cannam cannam@0: shall not be used in advertising or otherwise to promote the sale, cannam@0: use or other dealings in this Software without prior written cannam@0: authorization. cannam@0: */ cannam@0: cannam@0: /* cannam@0: This is a modified version of a source file from the cannam@0: Rosegarden MIDI and audio sequencer and notation editor. cannam@0: This file copyright 2000-2006 Chris Cannam; relicensed as detailed above cannam@0: */ cannam@0: cannam@0: #include cannam@0: cannam@0: #if (__GNUC__ < 3) cannam@0: #include cannam@0: #define stringstream strstream cannam@0: #else cannam@0: #include cannam@0: #endif cannam@0: cannam@0: using std::cerr; cannam@0: using std::endl; cannam@0: cannam@0: #include "RealTime.h" cannam@0: #include "sys/time.h" cannam@0: cannam@0: namespace Vamp { cannam@0: cannam@0: // A RealTime consists of two ints that must be at least 32 bits each. cannam@0: // A signed 32-bit int can store values exceeding +/- 2 billion. This cannam@0: // means we can safely use our lower int for nanoseconds, as there are cannam@0: // 1 billion nanoseconds in a second and we need to handle double that cannam@0: // because of the implementations of addition etc that we use. cannam@0: // cannam@0: // The maximum valid RealTime on a 32-bit system is somewhere around cannam@0: // 68 years: 999999999 nanoseconds longer than the classic Unix epoch. cannam@0: cannam@0: #define ONE_BILLION 1000000000 cannam@0: cannam@0: RealTime::RealTime(int s, int n) : cannam@0: sec(s), nsec(n) cannam@0: { cannam@0: if (sec == 0) { cannam@0: while (nsec <= -ONE_BILLION) { nsec += ONE_BILLION; --sec; } cannam@0: while (nsec >= ONE_BILLION) { nsec -= ONE_BILLION; ++sec; } cannam@0: } else if (sec < 0) { cannam@0: while (nsec <= -ONE_BILLION) { nsec += ONE_BILLION; --sec; } cannam@0: while (nsec > 0) { nsec -= ONE_BILLION; ++sec; } cannam@0: } else { cannam@0: while (nsec >= ONE_BILLION) { nsec -= ONE_BILLION; ++sec; } cannam@0: while (nsec < 0) { nsec += ONE_BILLION; --sec; } cannam@0: } cannam@0: } cannam@0: cannam@0: RealTime cannam@0: RealTime::fromSeconds(double sec) cannam@0: { cannam@0: return RealTime(int(sec), int((sec - int(sec)) * ONE_BILLION)); cannam@0: } cannam@0: cannam@0: RealTime cannam@0: RealTime::fromMilliseconds(int msec) cannam@0: { cannam@0: return RealTime(msec / 1000, (msec % 1000) * 1000000); cannam@0: } cannam@0: cannam@0: RealTime cannam@0: RealTime::fromTimeval(const struct timeval &tv) cannam@0: { cannam@0: return RealTime(tv.tv_sec, tv.tv_usec * 1000); cannam@0: } cannam@0: cannam@0: std::ostream &operator<<(std::ostream &out, const RealTime &rt) cannam@0: { cannam@0: if (rt < RealTime::zeroTime) { cannam@0: out << "-"; cannam@0: } else { cannam@0: out << " "; cannam@0: } cannam@0: cannam@0: int s = (rt.sec < 0 ? -rt.sec : rt.sec); cannam@0: int n = (rt.nsec < 0 ? -rt.nsec : rt.nsec); cannam@0: cannam@0: out << s << "."; cannam@0: cannam@0: int nn(n); cannam@0: if (nn == 0) out << "00000000"; cannam@0: else while (nn < (ONE_BILLION / 10)) { cannam@0: out << "0"; cannam@0: nn *= 10; cannam@0: } cannam@0: cannam@0: out << n << "R"; cannam@0: return out; cannam@0: } cannam@0: cannam@0: std::string cannam@0: RealTime::toString() const cannam@0: { cannam@0: std::stringstream out; cannam@0: out << *this; cannam@0: cannam@0: #if (__GNUC__ < 3) cannam@0: out << std::ends; cannam@0: #endif cannam@0: cannam@0: std::string s = out.str(); cannam@0: cannam@0: // remove trailing R cannam@0: return s.substr(0, s.length() - 1); cannam@0: } cannam@0: cannam@0: std::string cannam@0: RealTime::toText(bool fixedDp) const cannam@0: { cannam@0: if (*this < RealTime::zeroTime) return "-" + (-*this).toText(); cannam@0: cannam@0: std::stringstream out; cannam@0: cannam@0: if (sec >= 3600) { cannam@0: out << (sec / 3600) << ":"; cannam@0: } cannam@0: cannam@0: if (sec >= 60) { cannam@0: out << (sec % 3600) / 60 << ":"; cannam@0: } cannam@0: cannam@0: if (sec >= 10) { cannam@0: out << ((sec % 60) / 10); cannam@0: } cannam@0: cannam@0: out << (sec % 10); cannam@0: cannam@0: int ms = msec(); cannam@0: cannam@0: if (ms != 0) { cannam@0: out << "."; cannam@0: out << (ms / 100); cannam@0: ms = ms % 100; cannam@0: if (ms != 0) { cannam@0: out << (ms / 10); cannam@0: ms = ms % 10; cannam@0: } else if (fixedDp) { cannam@0: out << "0"; cannam@0: } cannam@0: if (ms != 0) { cannam@0: out << ms; cannam@0: } else if (fixedDp) { cannam@0: out << "0"; cannam@0: } cannam@0: } else if (fixedDp) { cannam@0: out << ".000"; cannam@0: } cannam@0: cannam@0: #if (__GNUC__ < 3) cannam@0: out << std::ends; cannam@0: #endif cannam@0: cannam@0: std::string s = out.str(); cannam@0: cannam@0: return s; cannam@0: } cannam@0: cannam@0: cannam@0: RealTime cannam@0: RealTime::operator/(int d) const cannam@0: { cannam@0: int secdiv = sec / d; cannam@0: int secrem = sec % d; cannam@0: cannam@0: double nsecdiv = (double(nsec) + ONE_BILLION * double(secrem)) / d; cannam@0: cannam@0: return RealTime(secdiv, int(nsecdiv + 0.5)); cannam@0: } cannam@0: cannam@0: double cannam@0: RealTime::operator/(const RealTime &r) const cannam@0: { cannam@0: double lTotal = double(sec) * ONE_BILLION + double(nsec); cannam@0: double rTotal = double(r.sec) * ONE_BILLION + double(r.nsec); cannam@0: cannam@0: if (rTotal == 0) return 0.0; cannam@0: else return lTotal/rTotal; cannam@0: } cannam@0: cannam@0: long cannam@0: RealTime::realTime2Frame(const RealTime &time, unsigned int sampleRate) cannam@0: { cannam@0: if (time < zeroTime) return -realTime2Frame(-time, sampleRate); cannam@0: cannam@0: // We like integers. The last term is always zero unless the cannam@0: // sample rate is greater than 1MHz, but hell, you never know... cannam@0: cannam@0: long frame = cannam@0: time.sec * sampleRate + cannam@0: (time.msec() * sampleRate) / 1000 + cannam@0: ((time.usec() - 1000 * time.msec()) * sampleRate) / 1000000 + cannam@0: ((time.nsec - 1000 * time.usec()) * sampleRate) / 1000000000; cannam@0: cannam@0: return frame; cannam@0: } cannam@0: cannam@0: RealTime cannam@0: RealTime::frame2RealTime(long frame, unsigned int sampleRate) cannam@0: { cannam@0: if (frame < 0) return -frame2RealTime(-frame, sampleRate); cannam@0: cannam@0: RealTime rt; cannam@0: rt.sec = frame / long(sampleRate); cannam@0: frame -= rt.sec * long(sampleRate); cannam@0: rt.nsec = (int)(((float(frame) * 1000000) / long(sampleRate)) * 1000); cannam@0: return rt; cannam@0: } cannam@0: cannam@0: const RealTime RealTime::zeroTime(0,0); cannam@0: cannam@0: }