aboutsummaryrefslogtreecommitdiff
path: root/sound/timestamp.cpp
diff options
context:
space:
mode:
authorMax Horn2010-01-04 22:48:28 +0000
committerMax Horn2010-01-04 22:48:28 +0000
commit4ae9412a3aea75990008c3a32080c54533fdb389 (patch)
tree5f7910434efd0e25c9278fa75cc86628dab7a4ce /sound/timestamp.cpp
parenta6aaeb70e6dfb3a9727e8861041601cf658aa5cd (diff)
downloadscummvm-rg350-4ae9412a3aea75990008c3a32080c54533fdb389.tar.gz
scummvm-rg350-4ae9412a3aea75990008c3a32080c54533fdb389.tar.bz2
scummvm-rg350-4ae9412a3aea75990008c3a32080c54533fdb389.zip
Make some improvements for Audio::Timestamp.
* Add convertToFramerate() method * Add framerate() method * Add operator == and != * Improve frameDiff() to work for two timestamps with distinct framerates * Improve Doxygen comments svn-id: r46994
Diffstat (limited to 'sound/timestamp.cpp')
-rw-r--r--sound/timestamp.cpp107
1 files changed, 83 insertions, 24 deletions
diff --git a/sound/timestamp.cpp b/sound/timestamp.cpp
index c85ec47ae8..a517462bb4 100644
--- a/sound/timestamp.cpp
+++ b/sound/timestamp.cpp
@@ -27,51 +27,110 @@
namespace Audio {
-Timestamp::Timestamp(uint32 m, int frameRate) :
- _msecs(m), _frameRate(frameRate), _frameOffset(0) {
- assert(_frameRate > 0);
+static uint gcd(uint a, uint b) {
+ while (a > 0) {
+ int tmp = a;
+ a = b % a;
+ b = tmp;
+ }
+ return b;
+}
+
+Timestamp::Timestamp(uint32 m, int framerate) :
+ _msecs(m), _framerate(framerate), _numberOfFrames(0) {
+ assert(_framerate > 0);
+}
+
+
+Timestamp Timestamp::convertToFramerate(int newFramerate) const {
+ Timestamp ts(*this);
+
+ if (ts._framerate != newFramerate) {
+ ts._framerate = newFramerate;
+
+ const uint g = gcd(_framerate, ts._framerate);
+ const uint p = _framerate / g;
+ const uint q = ts._framerate / g;
+
+ // Convert the frame offset to the new framerate.
+ // We round to the nearest (as opposed to always
+ // rounding down), to minimize rounding errors during
+ // round trip conversions.
+ ts._numberOfFrames = (ts._numberOfFrames * q + p/2) / p;
+
+ ts._msecs += (ts._numberOfFrames / ts._framerate) * 1000;
+ ts._numberOfFrames %= ts._framerate;
+ }
+
+ return ts;
+}
+
+bool Timestamp::operator==(const Timestamp &ts) const {
+ // TODO: Alternatively, we could define equality to mean that
+ // two timestamps describe the exacts same moment in time.
+ return (_msecs == ts._msecs) &&
+ (_numberOfFrames == ts._numberOfFrames) &&
+ (_framerate == ts._framerate);
+}
+
+bool Timestamp::operator!=(const Timestamp &ts) const {
+ return !(*this == ts);
}
Timestamp Timestamp::addFrames(int frames) const {
- Timestamp timestamp(*this);
- timestamp._frameOffset += frames;
+ Timestamp ts(*this);
+ ts._numberOfFrames += frames;
- if (timestamp._frameOffset < 0) {
- int secsub = 1 + (-timestamp._frameOffset / timestamp._frameRate);
+ if (ts._numberOfFrames < 0) {
+ int secsub = 1 + (-ts._numberOfFrames / ts._framerate);
- timestamp._frameOffset += timestamp._frameRate * secsub;
- timestamp._msecs -= secsub * 1000;
+ ts._numberOfFrames += ts._framerate * secsub;
+ ts._msecs -= secsub * 1000;
}
- timestamp._msecs += (timestamp._frameOffset / timestamp._frameRate) * 1000;
- timestamp._frameOffset %= timestamp._frameRate;
+ ts._msecs += (ts._numberOfFrames / ts._framerate) * 1000;
+ ts._numberOfFrames %= ts._framerate;
- return timestamp;
+ return ts;
}
Timestamp Timestamp::addMsecs(int ms) const {
- Timestamp timestamp(*this);
- timestamp._msecs += ms;
- return timestamp;
+ Timestamp ts(*this);
+ ts._msecs += ms;
+ return ts;
}
-int Timestamp::frameDiff(const Timestamp &b) const {
- assert(_frameRate == b._frameRate);
+int Timestamp::frameDiff(const Timestamp &ts) const {
+
+ int delta = 0;
+ if (_msecs != ts._msecs)
+ delta = (long(_msecs) - long(ts._msecs)) * _framerate / 1000;
+
+ delta += _numberOfFrames;
- int msecdelta = 0;
- if (_msecs != b._msecs)
- msecdelta = (long(_msecs) - long(b._msecs)) * _frameRate / 1000;
+ if (_framerate == ts._framerate) {
+ delta -= ts._numberOfFrames;
+ } else {
+ // We need to multiply by the quotient of the two framerates.
+ // We cancel the GCD in this fraction to reduce the risk of
+ // overflows.
+ const uint g = gcd(_framerate, ts._framerate);
+ const uint p = _framerate / g;
+ const uint q = ts._framerate / g;
+
+ delta -= (ts._numberOfFrames * p + q/2) / q;
+ }
- return msecdelta + _frameOffset - b._frameOffset;
+ return delta;
}
-int Timestamp::msecsDiff(const Timestamp &b) const {
- return long(msecs()) - long(b.msecs());
+int Timestamp::msecsDiff(const Timestamp &ts) const {
+ return long(msecs()) - long(ts.msecs());
}
uint32 Timestamp::msecs() const {
- return _msecs + _frameOffset * 1000L / _frameRate;
+ return _msecs + _numberOfFrames * 1000L / _framerate;
}