# HG changeset patch # User Chris Cannam # Date 1431443985 -3600 # Node ID b8a788c9a6f1c02fe8b215b5eb057c94a31a0805 # Parent 32ab6c48efaa23d24a67315bccdc27f3ba1a18d5 Fixes to, and tests for, RealTime-to-text methods diff -r 32ab6c48efaa -r b8a788c9a6f1 base/RealTime.cpp --- a/base/RealTime.cpp Mon Apr 20 09:11:34 2015 +0100 +++ b/base/RealTime.cpp Tue May 12 16:19:45 2015 +0100 @@ -258,7 +258,10 @@ if (*this < RealTime::zeroTime) return "-" + (-*this).toText(fixedDp); Preferences *p = Preferences::getInstance(); + bool hms = true; + if (p) { + hms = p->getShowHMS(); int fps = 0; switch (p->getTimeToTextMode()) { case Preferences::TimeToTextMs: break; @@ -269,19 +272,24 @@ case Preferences::TimeToText50Frame: fps = 50; break; case Preferences::TimeToText60Frame: fps = 60; break; } - if (fps != 0) return toFrameText(fps); + if (fps != 0) return toFrameText(fps, hms); } - std::stringstream out; + return toMSText(fixedDp, hms); +} - if (p->getShowHMS()) { - +static void +writeSecPart(std::stringstream &out, bool hms, int sec) +{ + if (hms) { if (sec >= 3600) { out << (sec / 3600) << ":"; } if (sec >= 60) { - out << (sec % 3600) / 60 << ":"; + int minutes = (sec % 3600) / 60; + if (sec >= 3600 && minutes < 10) out << "0"; + out << minutes << ":"; } if (sec >= 10) { @@ -293,6 +301,16 @@ } else { out << sec; } +} + +std::string +RealTime::toMSText(bool fixedDp, bool hms) const +{ + if (*this < RealTime::zeroTime) return "-" + (-*this).toMSText(fixedDp, hms); + + std::stringstream out; + + writeSecPart(out, hms, sec); int ms = msec(); @@ -321,35 +339,18 @@ } std::string -RealTime::toFrameText(int fps) const +RealTime::toFrameText(int fps, bool hms) const { - if (*this < RealTime::zeroTime) return "-" + (-*this).toFrameText(fps); - - Preferences *p = Preferences::getInstance(); + if (*this < RealTime::zeroTime) return "-" + (-*this).toFrameText(fps, hms); std::stringstream out; - if (p->getShowHMS()) { - - if (sec >= 3600) { - out << (sec / 3600) << ":"; - } + writeSecPart(out, hms, sec); - if (sec >= 60) { - out << (sec % 3600) / 60 << ":"; - } - - if (sec >= 10) { - out << ((sec % 60) / 10); - } - - out << (sec % 10); - - } else { - out << sec; - } - - int f = nsec / (ONE_BILLION / fps); + // avoid rounding error if fps does not divide into ONE_BILLION + int64_t fbig = nsec; + fbig *= fps; + int f = int(fbig / ONE_BILLION); int div = 1; int n = fps - 1; @@ -381,19 +382,7 @@ std::stringstream out; - if (sec >= 3600) { - out << (sec / 3600) << ":"; - } - - if (sec >= 60) { - out << (sec % 3600) / 60 << ":"; - } - - if (sec >= 10) { - out << ((sec % 60) / 10); - } - - out << (sec % 10); + writeSecPart(out, true, sec); if (sec < 60) { out << "s"; diff -r 32ab6c48efaa -r b8a788c9a6f1 base/RealTime.h --- a/base/RealTime.h Mon Apr 20 09:11:34 2015 +0100 +++ b/base/RealTime.h Tue May 12 16:19:45 2015 +0100 @@ -18,8 +18,8 @@ This file copyright 2000-2006 Chris Cannam. */ -#ifndef _REAL_TIME_H_ -#define _REAL_TIME_H_ +#ifndef SV_REAL_TIME_H +#define SV_REAL_TIME_H #include "BaseTypes.h" @@ -128,23 +128,55 @@ static RealTime fromString(std::string); /** - * Return a user-readable string to the nearest millisecond, in a - * form like HH:MM:SS.mmm + * Return a user-readable string to the nearest millisecond, + * typically in a form like HH:MM:SS.mmm. The exact format will + * depend on the application preferences for time display + * precision and hours:minutes:seconds format -- this function + * simply dispatches to toMSText or toFrameText with appropriate + * arguments depending on the preferences. + * + * If fixedDp is true, the result will be padded to 3 dp, + * i.e. millisecond resolution, even if the number of milliseconds + * is a multiple of 10. */ std::string toText(bool fixedDp = false) const; + /** + * Return a user-readable string to the nearest millisecond. + * + * If fixedDp is true, the result will be padded to 3 dp, + * i.e. millisecond resolution, even if the number of milliseconds + * is a multiple of 10. + * + * If hms is true, results may be returned in the form + * HH:MM:SS.mmm (if the time is large enough). If hms is false, + * the result will always be a (fractional) number of seconds. + * + * Unlike toText, this function does not depend on the application + * preferences. + */ + std::string toMSText(bool fixedDp, bool hms) const; + /** * Return a user-readable string in which seconds are divided into * frames (presumably at a lower frame rate than audio rate, * e.g. 24 or 25 video frames), in a form like HH:MM:SS:FF. fps * gives the number of frames per second, and must be integral * (29.97 not supported). + * + * Unlike toText, this function does not depend on the application + * preferences. */ - std::string toFrameText(int fps) const; + std::string toFrameText(int fps, bool hms) const; /** - * Return a user-readable string to the nearest second, in a form - * like "6s" (for less than a minute) or "2:21" (for more). + * Return a user-readable string to the nearest second, in H:M:S + * form. Does not include milliseconds or frames. The result will + * be suffixed "s" if it contains only seconds (no hours or + * minutes). + * + * Unlike toText, this function does not depend on the application + * preferences. */ std::string toSecText() const; diff -r 32ab6c48efaa -r b8a788c9a6f1 base/test/TestRealTime.h --- a/base/test/TestRealTime.h Mon Apr 20 09:11:34 2015 +0100 +++ b/base/test/TestRealTime.h Tue May 12 16:19:45 2015 +0100 @@ -29,6 +29,10 @@ { Q_OBJECT + void compareTexts(string s, const char *e) { + QCOMPARE(QString(s.c_str()), QString(e)); + } + private slots: #define ONE_MILLION 1000000 @@ -296,6 +300,118 @@ } } } + + void toText() + { + // we want to use QStrings, because then the Qt test library + // will print out any conflicts. The compareTexts function + // does this for us + + int halfSec = ONE_BILLION/2; // nsec + + RealTime rt = RealTime(0, 0); + compareTexts(rt.toMSText(false, false), "0"); + compareTexts(rt.toMSText(true, false), "0.000"); + compareTexts(rt.toMSText(false, true), "0"); + compareTexts(rt.toMSText(true, true), "0.000"); + compareTexts(rt.toFrameText(24, false), "0:00"); + compareTexts(rt.toFrameText(24, true), "0:00"); + compareTexts(rt.toSecText(), "0s"); + + rt = RealTime(1, halfSec); + compareTexts(rt.toMSText(false, false), "1.5"); + compareTexts(rt.toMSText(true, false), "1.500"); + compareTexts(rt.toMSText(false, true), "1.5"); + compareTexts(rt.toMSText(true, true), "1.500"); + compareTexts(rt.toFrameText(24, false), "1:12"); + compareTexts(rt.toFrameText(24, true), "1:12"); + compareTexts(rt.toFrameText(25, false), "1:12"); + compareTexts(rt.toFrameText(25, true), "1:12"); + compareTexts(rt.toSecText(), "1s"); + + rt = RealTime::fromSeconds(-1.5); + compareTexts(rt.toMSText(false, false), "-1.5"); + compareTexts(rt.toMSText(true, false), "-1.500"); + compareTexts(rt.toMSText(false, true), "-1.5"); + compareTexts(rt.toMSText(true, true), "-1.500"); + compareTexts(rt.toFrameText(24, false), "-1:12"); + compareTexts(rt.toFrameText(24, true), "-1:12"); + compareTexts(rt.toSecText(), "-1s"); + + rt = RealTime(1, 1000); + compareTexts(rt.toMSText(false, false), "1"); + compareTexts(rt.toFrameText(24, false), "1:00"); + compareTexts(rt.toFrameText(ONE_MILLION, false), "1:000001"); + compareTexts(rt.toSecText(), "1s"); + + rt = RealTime(1, 100000); + compareTexts(rt.toFrameText(ONE_MILLION, false), "1:000100"); + compareTexts(rt.toSecText(), "1s"); + + rt = RealTime::fromSeconds(60); + compareTexts(rt.toMSText(false, false), "60"); + compareTexts(rt.toMSText(true, false), "60.000"); + compareTexts(rt.toMSText(false, true), "1:00"); + compareTexts(rt.toMSText(true, true), "1:00.000"); + compareTexts(rt.toFrameText(24, false), "60:00"); + compareTexts(rt.toFrameText(24, true), "1:00:00"); + compareTexts(rt.toSecText(), "1:00"); + + rt = RealTime::fromSeconds(61.05); + compareTexts(rt.toMSText(false, false), "61.05"); + compareTexts(rt.toMSText(true, false), "61.050"); + compareTexts(rt.toMSText(false, true), "1:01.05"); + compareTexts(rt.toMSText(true, true), "1:01.050"); + compareTexts(rt.toFrameText(24, false), "61:01"); + compareTexts(rt.toFrameText(24, true), "1:01:01"); + compareTexts(rt.toSecText(), "1:01"); + + rt = RealTime::fromSeconds(601.05); + compareTexts(rt.toMSText(false, false), "601.05"); + compareTexts(rt.toMSText(true, false), "601.050"); + compareTexts(rt.toMSText(false, true), "10:01.05"); + compareTexts(rt.toMSText(true, true), "10:01.050"); + compareTexts(rt.toFrameText(24, false), "601:01"); + compareTexts(rt.toFrameText(24, true), "10:01:01"); + compareTexts(rt.toSecText(), "10:01"); + + rt = RealTime::fromSeconds(3600); + compareTexts(rt.toMSText(false, false), "3600"); + compareTexts(rt.toMSText(true, false), "3600.000"); + compareTexts(rt.toMSText(false, true), "1:00:00"); + compareTexts(rt.toMSText(true, true), "1:00:00.000"); + compareTexts(rt.toFrameText(24, false), "3600:00"); + compareTexts(rt.toFrameText(24, true), "1:00:00:00"); + compareTexts(rt.toSecText(), "1:00:00"); + + // For practical reasons our time display always rounds down + rt = RealTime(3599, ONE_BILLION-1); + compareTexts(rt.toMSText(false, false), "3599.999"); + compareTexts(rt.toMSText(true, false), "3599.999"); + compareTexts(rt.toMSText(false, true), "59:59.999"); + compareTexts(rt.toMSText(true, true), "59:59.999"); + compareTexts(rt.toFrameText(24, false), "3599:23"); + compareTexts(rt.toFrameText(24, true), "59:59:23"); + compareTexts(rt.toSecText(), "59:59"); + + rt = RealTime::fromSeconds(3600 * 4 + 60 * 5 + 3 + 0.01); + compareTexts(rt.toMSText(false, false), "14703.01"); + compareTexts(rt.toMSText(true, false), "14703.010"); + compareTexts(rt.toMSText(false, true), "4:05:03.01"); + compareTexts(rt.toMSText(true, true), "4:05:03.010"); + compareTexts(rt.toFrameText(24, false), "14703:00"); + compareTexts(rt.toFrameText(24, true), "4:05:03:00"); + compareTexts(rt.toSecText(), "4:05:03"); + + rt = RealTime::fromSeconds(-(3600 * 4 + 60 * 5 + 3 + 0.01)); + compareTexts(rt.toMSText(false, false), "-14703.01"); + compareTexts(rt.toMSText(true, false), "-14703.010"); + compareTexts(rt.toMSText(false, true), "-4:05:03.01"); + compareTexts(rt.toMSText(true, true), "-4:05:03.010"); + compareTexts(rt.toFrameText(24, false), "-14703:00"); + compareTexts(rt.toFrameText(24, true), "-4:05:03:00"); + compareTexts(rt.toSecText(), "-4:05:03"); + } }; #endif