diff options
-rw-r--r-- | sound/timestamp.cpp | 44 | ||||
-rw-r--r-- | sound/timestamp.h | 38 | ||||
-rw-r--r-- | test/sound/timestamp.h | 26 |
3 files changed, 81 insertions, 27 deletions
diff --git a/sound/timestamp.cpp b/sound/timestamp.cpp index ad13d75c9f..3d9178da2b 100644 --- a/sound/timestamp.cpp +++ b/sound/timestamp.cpp @@ -36,17 +36,23 @@ static uint gcd(uint a, uint b) { return b; } -Timestamp::Timestamp(uint32 m, int framerate) : - _msecs(m), _framerate(framerate), _numberOfFrames(0) { - assert(_framerate > 0); +Timestamp::Timestamp(uint32 ms, int framerate) { + assert(framerate > 0); + + _secs = ms / 1000; + _framerateFactor = 1000 / gcd(1000, framerate); + _framerate = framerate * _framerateFactor; + + _numberOfFrames = (ms % 1000) * _framerate / 1000; } Timestamp Timestamp::convertToFramerate(int newFramerate) const { Timestamp ts(*this); - if (ts._framerate != newFramerate) { - ts._framerate = newFramerate; + if (ts.getFramerate() != newFramerate) { + ts._framerateFactor = 1000 / gcd(1000, newFramerate); + ts._framerate = newFramerate * ts._framerateFactor; const uint g = gcd(_framerate, ts._framerate); const uint p = _framerate / g; @@ -58,7 +64,7 @@ Timestamp Timestamp::convertToFramerate(int newFramerate) const { // round trip conversions. ts._numberOfFrames = (ts._numberOfFrames * q + p/2) / p; - ts._msecs += (ts._numberOfFrames / ts._framerate) * 1000; + ts._secs += (ts._numberOfFrames / ts._framerate); ts._numberOfFrames %= ts._framerate; } @@ -66,8 +72,8 @@ Timestamp Timestamp::convertToFramerate(int newFramerate) const { } bool Timestamp::operator==(const Timestamp &ts) const { - // TODO: Improve this - return (ts.msecs() == msecs()) && !frameDiff(ts); + return (ts._secs == _secs) && + (ts._numberOfFrames * _framerate == _numberOfFrames * ts._framerate); } bool Timestamp::operator!=(const Timestamp &ts) const { @@ -77,16 +83,19 @@ bool Timestamp::operator!=(const Timestamp &ts) const { Timestamp Timestamp::addFrames(int frames) const { Timestamp ts(*this); - ts._numberOfFrames += frames; + + // The frames are given in the original framerate, so we have to + // adjust by _framerateFactor accordingly. + ts._numberOfFrames += frames * _framerateFactor; if (ts._numberOfFrames < 0) { int secsub = 1 + (-ts._numberOfFrames / ts._framerate); ts._numberOfFrames += ts._framerate * secsub; - ts._msecs -= secsub * 1000; + ts._secs -= secsub; } - ts._msecs += (ts._numberOfFrames / ts._framerate) * 1000; + ts._secs += (ts._numberOfFrames / ts._framerate); ts._numberOfFrames %= ts._framerate; return ts; @@ -94,15 +103,16 @@ Timestamp Timestamp::addFrames(int frames) const { Timestamp Timestamp::addMsecs(int ms) const { Timestamp ts(*this); - ts._msecs += ms; - return ts; + ts._secs += ms / 1000; + // Add the remaining frames. Note that _framerate is always divisible by 1000. + return ts.addFrames((ms % 1000) * (_framerate / 1000)); } int Timestamp::frameDiff(const Timestamp &ts) const { int delta = 0; - if (_msecs != ts._msecs) - delta = (long(_msecs) - long(ts._msecs)) * _framerate / 1000; + if (_secs != ts._secs) + delta = (long(_secs) - long(ts._secs)) * _framerate; delta += _numberOfFrames; @@ -119,7 +129,7 @@ int Timestamp::frameDiff(const Timestamp &ts) const { delta -= (ts._numberOfFrames * p + q/2) / q; } - return delta; + return delta / _framerateFactor; } int Timestamp::msecsDiff(const Timestamp &ts) const { @@ -127,7 +137,7 @@ int Timestamp::msecsDiff(const Timestamp &ts) const { } uint32 Timestamp::msecs() const { - return _msecs + _numberOfFrames * 1000L / _framerate; + return _secs * 1000 + _numberOfFrames / (_framerate / 1000); } diff --git a/sound/timestamp.h b/sound/timestamp.h index 218198dcf7..2e8689a81d 100644 --- a/sound/timestamp.h +++ b/sound/timestamp.h @@ -39,24 +39,36 @@ namespace Audio { class Timestamp { protected: /** - * The millisecond part of this timestamp. - * The total time represented by this timestamp is + * The seconds part of this timestamp. + * The total time in seconds represented by this timestamp can be * computed as follows: - * _msecs + 1000 * _numberOfFrames / _framerate + * _secs + (double)_numberOfFrames / _framerate */ - uint _msecs; + uint _secs; /** - * The number of frames which together with _msecs encodes + * The number of frames which together with _secs encodes * the timestamp. The total number of frames represented * by this timestamp is computed as follows: - * _numberOfFrames + _msecs * _framerate / 1000 + * _numberOfFrames + _secs * _framerate */ int _numberOfFrames; - /** The framerate, i.e. the number of frames per second. */ + /** + * The internal framerate, i.e. the number of frames per second. + * This is computed as the least common multiple of the framerate + * specified by the client code, and 1000. + * This way, we ensure that we can store both frames and + * milliseconds without any rounding losses. + */ int _framerate; + /** + * Factor by which the original framerate specified by the client + * code was multipled to obtain the internal _framerate value. + */ + int _framerateFactor; + public: /** * Set up a timestamp with a given time and framerate. @@ -72,7 +84,13 @@ public: */ Timestamp convertToFramerate(int newFramerate) const; + /** + * Check whether to timestamps describe the exact same moment + * in time. This means that two timestamps can compare + * as equal even if they use different framerates. + */ bool operator==(const Timestamp &ts) const; + bool operator!=(const Timestamp &ts) const; // bool operator<(const Timestamp &ts) const; // bool operator<=(const Timestamp &ts) const; @@ -82,14 +100,16 @@ public: /** * Returns a new timestamp, which corresponds to the time encoded * by this timestamp with the given number of frames added. + * @param frames number of frames to add */ Timestamp addFrames(int frames) const; /** * Returns a new timestamp, which corresponds to the time encoded * by this timestamp with the given number of milliseconds added. + * @param msecs number of milliseconds to add */ - Timestamp addMsecs(int ms) const; + Timestamp addMsecs(int msecs) const; /** * Computes the number of frames between this timestamp and ts. @@ -108,7 +128,7 @@ public: uint32 msecs() const; /** Return the framerate used by this timestamp. */ - int getFramerate() const { return _framerate; } + int getFramerate() const { return _framerate / _framerateFactor; } }; diff --git a/test/sound/timestamp.h b/test/sound/timestamp.h index 4945a18f88..d4cd0edc44 100644 --- a/test/sound/timestamp.h +++ b/test/sound/timestamp.h @@ -87,8 +87,32 @@ class TimestampTestSuite : public CxxTest::TestSuite void test_equals() { const Audio::Timestamp a = Audio::Timestamp(500, 1000); - const Audio::Timestamp b = Audio::Timestamp(0, 1000).addFrames(500); + Audio::Timestamp b = Audio::Timestamp(0, 1000); + Audio::Timestamp c = Audio::Timestamp(0, 100); + + TS_ASSERT(a != b); + TS_ASSERT(a != c); + TS_ASSERT(b == c); + + b = b.addFrames(500); + c = c.addFrames(50); TS_ASSERT(a == b); + TS_ASSERT(a == c); + TS_ASSERT(b == c); + } + + + void test_framerate() { + const Audio::Timestamp a = Audio::Timestamp(500, 1000); + const Audio::Timestamp b = Audio::Timestamp(500, 67); + const Audio::Timestamp c = Audio::Timestamp(500, 100); + const Audio::Timestamp d = Audio::Timestamp(500, 44100); + + + TS_ASSERT_EQUALS(a.getFramerate(), 1000); + TS_ASSERT_EQUALS(b.getFramerate(), 67); + TS_ASSERT_EQUALS(c.getFramerate(), 100); + TS_ASSERT_EQUALS(d.getFramerate(), 44100); } }; |