aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sound/timestamp.cpp44
-rw-r--r--sound/timestamp.h38
-rw-r--r--test/sound/timestamp.h26
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);
}
};