[Scummvm-cvs-logs] SF.net SVN: scummvm:[46994] scummvm/trunk

fingolfin at users.sourceforge.net fingolfin at users.sourceforge.net
Mon Jan 4 23:48:28 CET 2010


Revision: 46994
          http://scummvm.svn.sourceforge.net/scummvm/?rev=46994&view=rev
Author:   fingolfin
Date:     2010-01-04 22:48:28 +0000 (Mon, 04 Jan 2010)

Log Message:
-----------
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

Modified Paths:
--------------
    scummvm/trunk/sound/timestamp.cpp
    scummvm/trunk/sound/timestamp.h
    scummvm/trunk/test/sound/timestamp.h

Modified: scummvm/trunk/sound/timestamp.cpp
===================================================================
--- scummvm/trunk/sound/timestamp.cpp	2010-01-04 22:23:45 UTC (rev 46993)
+++ scummvm/trunk/sound/timestamp.cpp	2010-01-04 22:48:28 UTC (rev 46994)
@@ -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 msecdelta = 0;
-	if (_msecs != b._msecs)
-		msecdelta = (long(_msecs) - long(b._msecs)) * _frameRate / 1000;
+	int delta = 0;
+	if (_msecs != ts._msecs)
+		delta = (long(_msecs) - long(ts._msecs)) * _framerate / 1000;
 
-	return msecdelta + _frameOffset - b._frameOffset;
+	delta += _numberOfFrames;
+
+	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 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;
 }
 
 

Modified: scummvm/trunk/sound/timestamp.h
===================================================================
--- scummvm/trunk/sound/timestamp.h	2010-01-04 22:23:45 UTC (rev 46993)
+++ scummvm/trunk/sound/timestamp.h	2010-01-04 22:48:28 UTC (rev 46994)
@@ -38,33 +38,77 @@
  */
 class Timestamp {
 protected:
-	uint32 _msecs;
-	int _frameRate;
-	int _frameOffset;
-	/* Total time: msecs + frame_offset/frame_rate */
+	/**
+	 * The millisecond part of this timestamp.
+	 * The total time represented by this timestamp is
+	 * computed as follows:
+	 *   _msecs + 1000 * _numberOfFrames / _framerate
+	 */
+	uint _msecs;
 
+	/**
+	 * The number of frames which together with _msecs encodes
+	 * the timestamp. The total number of frames represented
+	 * by this timestamp is computed as follows:
+	 *   _numberOfFrames + _msecs * _framerate / 1000
+	 */
+	int _numberOfFrames;
+
+	/** The framerate, i.e. the number of frames per second. */
+	int _framerate;
+
 public:
 	/**
 	 * Set up a timestamp with a given time and framerate.
-	 * @param msecs     staring time in milliseconds
-	 * @param frameRate number of frames per second (must be > 0)
+	 * @param msecs     starting time in milliseconds
+	 * @param framerate number of frames per second (must be > 0)
 	 */
-	Timestamp(uint32 msecs, int frameRate);
+	Timestamp(uint32 msecs, int framerate);
 
-	/** Adds a number of frames to a timestamp. */
+	/**
+	 * Return a timestamp which represents as closely as possible
+	 * the point in time describes by this timestamp, but with
+	 * a different framerate.
+	 */
+	Timestamp convertToFramerate(int newFramerate) const;
+
+	bool operator==(const Timestamp &ts) const;
+	bool operator!=(const Timestamp &ts) const;
+// 	bool operator<(const Timestamp &ts) const;
+// 	bool operator<=(const Timestamp &ts) const;
+// 	bool operator>(const Timestamp &ts) const;
+// 	bool operator>=(const Timestamp &ts) const;
+
+	/**
+	 * Returns a new timestamp, which corresponds to the time encoded
+	 * by this timestamp with the given number of frames added.
+	 */
 	Timestamp addFrames(int frames) const;
 
-	/** Adds a number of milliseconds to a timestamp. */
+	/**
+	 * Returns a new timestamp, which corresponds to the time encoded
+	 * by this timestamp with the given number of milliseconds added.
+	 */
 	Timestamp addMsecs(int ms) const;
 
-	/** Computes the difference (# of frames) between this timestamp and b. */
-	int frameDiff(const Timestamp &b) const;
+	/**
+	 * Computes the number of frames between this timestamp and ts.
+	 * The frames are with respect to the framerate used by this
+	 * Timestamp (which may differ from the framerate used by ts).
+	 */
+	int frameDiff(const Timestamp &ts) const;
 
-	/** Computes the difference (# of milliseconds) between this timestamp and b. */
-	int msecsDiff(const Timestamp &b) const;
+	/** Computes the number off milliseconds between this timestamp and ts. */
+	int msecsDiff(const Timestamp &ts) const;
 
-	/** Determines the time in milliseconds described by this timestamp. */
+	/**
+	 * Determines the time in milliseconds described by this timestamp,
+	 * rounded down.
+	 */
 	uint32 msecs() const;
+
+	/** Return the framerate used by this timestamp. */
+	int getFramerate() const { return _framerate; }
 };
 
 

Modified: scummvm/trunk/test/sound/timestamp.h
===================================================================
--- scummvm/trunk/test/sound/timestamp.h	2010-01-04 22:23:45 UTC (rev 46993)
+++ scummvm/trunk/test/sound/timestamp.h	2010-01-04 22:48:28 UTC (rev 46994)
@@ -47,7 +47,6 @@
 		TS_ASSERT_EQUALS(a.addFrames(-60).msecs(), (uint32)(1234 - 1000 * 60/60));
 	}
 
-
 	void test_more_add_diff() {
 		const Audio::Timestamp c(10002, 1000);
 
@@ -56,4 +55,33 @@
 			TS_ASSERT_EQUALS(v, i);
 		}
 	}
+
+
+	void test_diff_with_conversion() {
+		const Audio::Timestamp a = Audio::Timestamp(10, 1000).addFrames(20);
+		const Audio::Timestamp b = Audio::Timestamp(10, 1000/5).addFrames(20/5);
+		const Audio::Timestamp c = Audio::Timestamp(10, 1000*2).addFrames(20*2);
+
+		TS_ASSERT_EQUALS(a.frameDiff(a), 0);
+		TS_ASSERT_EQUALS(a.frameDiff(b), 0);
+		TS_ASSERT_EQUALS(a.frameDiff(c), 0);
+
+		TS_ASSERT_EQUALS(b.frameDiff(a), 0);
+		TS_ASSERT_EQUALS(b.frameDiff(b), 0);
+		TS_ASSERT_EQUALS(b.frameDiff(c), 0);
+
+		TS_ASSERT_EQUALS(c.frameDiff(a), 0);
+		TS_ASSERT_EQUALS(c.frameDiff(b), 0);
+		TS_ASSERT_EQUALS(c.frameDiff(c), 0);
+	}
+
+
+	void test_convert() {
+		const Audio::Timestamp a = Audio::Timestamp(10, 1000).addFrames(20);
+		const Audio::Timestamp b = Audio::Timestamp(10, 1000/5).addFrames(20/5);
+		const Audio::Timestamp c = Audio::Timestamp(10, 1000*2).addFrames(20*2);
+
+		TS_ASSERT_EQUALS(a.convertToFramerate(1000/5), b);
+		TS_ASSERT_EQUALS(a.convertToFramerate(1000*2), c);
+	}
 };


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the Scummvm-git-logs mailing list