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