aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/made/scriptfuncs.cpp2
-rw-r--r--sound/audiostream.cpp8
-rw-r--r--sound/audiostream.h3
-rw-r--r--sound/timestamp.cpp130
-rw-r--r--sound/timestamp.h57
-rw-r--r--test/sound/timestamp.h63
6 files changed, 192 insertions, 71 deletions
diff --git a/engines/made/scriptfuncs.cpp b/engines/made/scriptfuncs.cpp
index 88bd440c51..e17b285b68 100644
--- a/engines/made/scriptfuncs.cpp
+++ b/engines/made/scriptfuncs.cpp
@@ -653,7 +653,7 @@ int16 ScriptFunctions::sfGetSoundEnergy(int16 argc, int16 *argv) {
while (_vm->_soundEnergyIndex < _vm->_soundEnergyArray->size()) {
SoundEnergyItem *soundEnergyItem = &(*_vm->_soundEnergyArray)[_vm->_soundEnergyIndex];
const Audio::Timestamp ts = _vm->_mixer->getElapsedTime(_audioStreamHandle);
- if (ts.convertToFramerate(_vm->_soundRate).totalNumberOfFrames() < soundEnergyItem->position) {
+ if (ts.convertToFramerate(_vm->_soundRate).totalNumberOfFrames() < (int)soundEnergyItem->position) {
result = soundEnergyItem->energy;
break;
}
diff --git a/sound/audiostream.cpp b/sound/audiostream.cpp
index 6d72b83dd1..3fcfbe14c0 100644
--- a/sound/audiostream.cpp
+++ b/sound/audiostream.cpp
@@ -222,9 +222,8 @@ SubSeekableAudioStream::SubSeekableAudioStream(SeekableAudioStream *parent, cons
: _parent(parent), _disposeAfterUse(disposeAfterUse),
_start(start.convertToFramerate(getRate())),
_pos(0, getRate() * (isStereo() ? 2 : 1)),
- _length(end.convertToFramerate(getRate())) {
- // TODO: This really looks like Timestamp::operator-
- _length = Timestamp(_length.secs() - _start.secs(), _length.numberOfFrames() - _start.numberOfFrames(), getRate());
+ _length((start - end).convertToFramerate(getRate())) {
+
_parent->seek(_start);
}
@@ -247,8 +246,7 @@ bool SubSeekableAudioStream::seek(const Timestamp &where) {
return false;
}
- // TODO: This really looks like Timestamp::operator+
- if (_parent->seek(Timestamp(_pos.secs() + _start.secs(), _pos.numberOfFrames() + _start.numberOfFrames(), getRate()))) {
+ if (_parent->seek(_pos + _start)) {
return true;
} else {
_pos = _length;
diff --git a/sound/audiostream.h b/sound/audiostream.h
index 1788561510..83bada8740 100644
--- a/sound/audiostream.h
+++ b/sound/audiostream.h
@@ -292,7 +292,8 @@ private:
bool _disposeAfterUse;
const Timestamp _start;
- Timestamp _pos, _length;
+ const Timestamp _length;
+ Timestamp _pos;
};
/**
diff --git a/sound/timestamp.cpp b/sound/timestamp.cpp
index 6157d87d32..f705ff4521 100644
--- a/sound/timestamp.cpp
+++ b/sound/timestamp.cpp
@@ -36,7 +36,7 @@ static uint gcd(uint a, uint b) {
return b;
}
-Timestamp::Timestamp(uint32 ms, int fr) {
+Timestamp::Timestamp(uint ms, uint fr) {
assert(fr > 0);
_secs = ms / 1000;
@@ -44,20 +44,21 @@ Timestamp::Timestamp(uint32 ms, int fr) {
_framerate = fr * _framerateFactor;
// Note that _framerate is always divisible by 1000.
- _numberOfFrames = (ms % 1000) * (_framerate / 1000);
+ _numFrames = (ms % 1000) * (_framerate / 1000);
}
-Timestamp::Timestamp(uint s, int frames, int fr) {
+Timestamp::Timestamp(uint s, uint frames, uint fr) {
assert(fr > 0);
_secs = s;
_framerateFactor = 1000 / gcd(1000, fr);
_framerate = fr * _framerateFactor;
- _numberOfFrames = 0;
- addFramesIntern(frames * _framerateFactor);
+ _numFrames = frames * _framerateFactor;
+
+ normalize();
}
-Timestamp Timestamp::convertToFramerate(int newFramerate) const {
+Timestamp Timestamp::convertToFramerate(uint newFramerate) const {
Timestamp ts(*this);
if (ts.framerate() != newFramerate) {
@@ -72,15 +73,28 @@ Timestamp Timestamp::convertToFramerate(int newFramerate) const {
// 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._numFrames = (ts._numFrames * q + p/2) / p;
- ts._secs += (ts._numberOfFrames / ts._framerate);
- ts._numberOfFrames %= ts._framerate;
+ ts.normalize();
}
return ts;
}
+void Timestamp::normalize() {
+ // Convert negative _numFrames values to positive ones by adjusting _secs
+ if (_numFrames < 0) {
+ int secsub = 1 + (-_numFrames / _framerate);
+
+ _numFrames += _framerate * secsub;
+ _secs -= secsub;
+ }
+
+ // Wrap around if necessary
+ _secs += (_numFrames / _framerate);
+ _numFrames %= _framerate;
+}
+
bool Timestamp::operator==(const Timestamp &ts) const {
return cmp(ts) == 0;
}
@@ -112,7 +126,7 @@ int Timestamp::cmp(const Timestamp &ts) const {
const uint p = _framerate / g;
const uint q = ts._framerate / g;
- delta = (_numberOfFrames * q - ts._numberOfFrames * p);
+ delta = (_numFrames * q - ts._numFrames * p);
}
return delta;
@@ -124,45 +138,91 @@ Timestamp Timestamp::addFrames(int frames) const {
// The frames are given in the original framerate, so we have to
// adjust by _framerateFactor accordingly.
- ts.addFramesIntern(frames * _framerateFactor);
+ ts._numFrames += frames * _framerateFactor;
+ ts.normalize();
return ts;
}
-void Timestamp::addFramesIntern(int frames) {
- _numberOfFrames += frames;
+Timestamp Timestamp::addMsecs(int ms) const {
+ Timestamp ts(*this);
+ ts._secs += ms / 1000;
+ // Add the remaining frames. Note that _framerate is always divisible by 1000.
+ ts._numFrames += (ms % 1000) * (ts._framerate / 1000);
+
+ ts.normalize();
+
+ return ts;
+}
- if (_numberOfFrames < 0) {
- int secsub = 1 + (-_numberOfFrames / _framerate);
+void Timestamp::addIntern(const Timestamp &ts) {
+ _secs += ts._secs;
- _numberOfFrames += _framerate * secsub;
- _secs -= secsub;
+ if (_framerate == ts._framerate) {
+ _numFrames += ts._numFrames;
+ } 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;
+
+ _framerate *= q;
+ _numFrames = _numFrames * q + ts._numFrames * p;
}
- // Wrap around if necessary
- _secs += (_numberOfFrames / _framerate);
- _numberOfFrames %= _framerate;
+ normalize();
}
-Timestamp Timestamp::addMsecs(int ms) const {
- assert(ms >= 0);
- Timestamp ts(*this);
- ts._secs += ms / 1000;
- // Add the remaining frames. Note that _framerate is always divisible by 1000.
- ts.addFramesIntern((ms % 1000) * (ts._framerate / 1000));
- return ts;
+Timestamp Timestamp::operator-() const {
+ Timestamp result(*this);
+ result._secs = -_secs;
+ result._numFrames = -_numFrames;
+ result.normalize();
+ return result;
+}
+
+Timestamp Timestamp::operator+(const Timestamp &ts) const {
+ Timestamp result(*this);
+ result.addIntern(ts);
+ return result;
+}
+
+Timestamp Timestamp::operator-(const Timestamp &ts) const {
+ Timestamp result(*this);
+ result.addIntern(-ts);
+ return result;
+}
+
+/*
+Timestamp &Timestamp::operator+=(const Timestamp &ts) {
+ addIntern(ts);
+ return *this;
+}
+
+Timestamp &Timestamp::operator-=(const Timestamp &ts) {
+ addIntern(-ts);
+ return *this;
+}
+*/
+
+/*
+int Timestamp::frameDiff(const Timestamp &ts) const {
+ return (*this - ts).totalNumberOfFrames();
}
+*/
int Timestamp::frameDiff(const Timestamp &ts) const {
int delta = 0;
if (_secs != ts._secs)
- delta = (long(_secs) - long(ts._secs)) * _framerate;
+ delta = (_secs - ts._secs) * _framerate;
- delta += _numberOfFrames;
+ delta += _numFrames;
if (_framerate == ts._framerate) {
- delta -= ts._numberOfFrames;
+ delta -= ts._numFrames;
} else {
// We need to multiply by the quotient of the two framerates.
// We cancel the GCD in this fraction to reduce the risk of
@@ -171,19 +231,19 @@ int Timestamp::frameDiff(const Timestamp &ts) const {
const uint p = _framerate / g;
const uint q = ts._framerate / g;
- delta -= (ts._numberOfFrames * p + q/2) / q;
+ delta -= ((long)ts._numFrames * p + q/2) / (long)q;
}
- return delta / _framerateFactor;
+ return delta / (int)_framerateFactor;
}
int Timestamp::msecsDiff(const Timestamp &ts) const {
- return long(msecs()) - long(ts.msecs());
+ return msecs() - ts.msecs();
}
-uint32 Timestamp::msecs() const {
+int Timestamp::msecs() const {
// Note that _framerate is always divisible by 1000.
- return _secs * 1000 + _numberOfFrames / (_framerate / 1000);
+ return _secs * 1000 + _numFrames / (_framerate / 1000);
}
diff --git a/sound/timestamp.h b/sound/timestamp.h
index 7c3b81ca32..0b55135355 100644
--- a/sound/timestamp.h
+++ b/sound/timestamp.h
@@ -42,17 +42,21 @@ protected:
* The seconds part of this timestamp.
* The total time in seconds represented by this timestamp can be
* computed as follows:
- * _secs + (double)_numberOfFrames / _framerate
+ * _secs + (double)_numFrames / _framerate
*/
- uint _secs;
+ int _secs;
/**
* 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 + _secs * _framerate
+ * _numFrames + _secs * _framerate
+ *
+ * This is always a value greater or equal to zero.
+ * The only reason this is an int and not an uint is to
+ * allow intermediate negative values.
*/
- int _numberOfFrames;
+ int _numFrames;
/**
* The internal framerate, i.e. the number of frames per second.
@@ -61,13 +65,13 @@ protected:
* This way, we ensure that we can store both frames and
* milliseconds without any rounding losses.
*/
- int _framerate;
+ uint _framerate;
/**
* Factor by which the original framerate specified by the client
* code was multipled to obtain the internal _framerate value.
*/
- int _framerateFactor;
+ uint _framerateFactor;
public:
/**
@@ -75,7 +79,7 @@ public:
* @param msecs starting time in milliseconds
* @param framerate number of frames per second (must be > 0)
*/
- Timestamp(uint32 msecs, int framerate);
+ Timestamp(uint msecs, uint framerate);
/**
* Set up a timestamp with a given time, frames and framerate.
@@ -83,14 +87,14 @@ public:
* @param frames starting frames
* @param framerate number of frames per second (must be > 0)
*/
- Timestamp(uint secs, int frames, int framerate);
+ Timestamp(uint secs, uint frames, uint framerate);
/**
* 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;
+ Timestamp convertToFramerate(uint newFramerate) const;
/**
* Check whether to timestamps describe the exact same moment
@@ -118,6 +122,16 @@ public:
*/
Timestamp addMsecs(int msecs) const;
+
+ // unary minus
+ Timestamp operator-() const;
+
+ Timestamp operator+(const Timestamp &ts) const;
+ Timestamp operator-(const Timestamp &ts) const;
+
+// Timestamp &operator+=(const Timestamp &ts);
+// Timestamp &operator-=(const Timestamp &ts);
+
/**
* Computes the number of frames between this timestamp and ts.
* The frames are with respect to the framerate used by this
@@ -132,13 +146,13 @@ public:
* Return the time in milliseconds described by this timestamp,
* rounded down.
*/
- uint32 msecs() const;
+ int msecs() const;
/**
* Return the time in seconds described by this timestamp,
* rounded down.
*/
- inline uint32 secs() const {
+ inline int secs() const {
return _secs;
}
@@ -146,7 +160,7 @@ public:
* Return the time in frames described by this timestamp.
*/
inline int totalNumberOfFrames() const {
- return _numberOfFrames / _framerateFactor + _secs * (_framerate / _framerateFactor);
+ return _numFrames / (int)_framerateFactor + _secs * (int)(_framerate / _framerateFactor);
}
/**
@@ -155,17 +169,30 @@ public:
* This method returns the latter number.
*/
inline int numberOfFrames() const {
- return _numberOfFrames / _framerateFactor;
+ return _numFrames / (int)_framerateFactor;
}
/** Return the framerate used by this timestamp. */
- inline int framerate() const { return _framerate / _framerateFactor; }
+ inline uint framerate() const { return _framerate / _framerateFactor; }
protected:
+ /**
+ * Compare this timestamp to another one and return
+ * a value similar to strcmp.
+ */
int cmp(const Timestamp &ts) const;
- void addFramesIntern(int frames);
+ /**
+ * Normalize this timestamp by making _numFrames non-negative
+ * and reducing it modulo _framerate.
+ */
+ void normalize();
+
+ /**
+ * Add another timestamp to this one and normalize the result.
+ */
+ void addIntern(const Timestamp &ts);
};
diff --git a/test/sound/timestamp.h b/test/sound/timestamp.h
index c5bd24c951..d78e58a0cc 100644
--- a/test/sound/timestamp.h
+++ b/test/sound/timestamp.h
@@ -59,8 +59,11 @@ class TimestampTestSuite : public CxxTest::TestSuite
const Audio::Timestamp a(1234, 60);
const Audio::Timestamp b(5678, 60);
- TS_ASSERT_EQUALS(a.msecs(), (uint32)1234);
- TS_ASSERT_EQUALS(b.msecs(), (uint32)5678);
+ TS_ASSERT_EQUALS(a.msecs(), 1234);
+ TS_ASSERT_EQUALS(b.msecs(), 5678);
+
+ TS_ASSERT_EQUALS(a.secs(), 1);
+ TS_ASSERT_EQUALS(b.secs(), 5);
TS_ASSERT_EQUALS(a.msecsDiff(b), 1234 - 5678);
TS_ASSERT_EQUALS(b.msecsDiff(a), 5678 - 1234);
@@ -68,15 +71,15 @@ class TimestampTestSuite : public CxxTest::TestSuite
TS_ASSERT_EQUALS(a.frameDiff(b), (1234 - 5678) * 60 / 1000);
TS_ASSERT_EQUALS(b.frameDiff(a), (5678 - 1234) * 60 / 1000);
- TS_ASSERT_EQUALS(a.addFrames(1).msecs(), (uint32)(1234 + 1000 * 1/60));
- TS_ASSERT_EQUALS(a.addFrames(59).msecs(), (uint32)(1234 + 1000 * 59/60));
- TS_ASSERT_EQUALS(a.addFrames(60).msecs(), (uint32)(1234 + 1000 * 60/60));
+ TS_ASSERT_EQUALS(a.addFrames(1).msecs(), (1234 + 1000 * 1/60));
+ TS_ASSERT_EQUALS(a.addFrames(59).msecs(), (1234 + 1000 * 59/60));
+ TS_ASSERT_EQUALS(a.addFrames(60).msecs(), (1234 + 1000 * 60/60));
// As soon as we go back even by only one frame, the msec value
// has to drop by at least one.
- TS_ASSERT_EQUALS(a.addFrames(-1).msecs(), (uint32)(1234 - 1000 * 1/60 - 1));
- TS_ASSERT_EQUALS(a.addFrames(-59).msecs(), (uint32)(1234 - 1000 * 59/60 - 1));
- TS_ASSERT_EQUALS(a.addFrames(-60).msecs(), (uint32)(1234 - 1000 * 60/60));
+ TS_ASSERT_EQUALS(a.addFrames(-1).msecs(), (1234 - 1000 * 1/60 - 1));
+ TS_ASSERT_EQUALS(a.addFrames(-59).msecs(), (1234 - 1000 * 59/60 - 1));
+ TS_ASSERT_EQUALS(a.addFrames(-60).msecs(), (1234 - 1000 * 60/60));
}
void test_more_add_diff() {
@@ -88,6 +91,38 @@ class TimestampTestSuite : public CxxTest::TestSuite
}
}
+ void test_negate() {
+ const Audio::Timestamp a = Audio::Timestamp(0, 60).addFrames(13);
+ const Audio::Timestamp b = -a;
+
+ TS_ASSERT_EQUALS(a.msecs() + 1, -b.msecs());
+ TS_ASSERT_EQUALS(a.totalNumberOfFrames(), -b.totalNumberOfFrames());
+ TS_ASSERT_EQUALS(a.numberOfFrames(), 60 - b.numberOfFrames());
+ }
+
+ void test_add_sub() {
+ const Audio::Timestamp a = Audio::Timestamp(0, 60).addFrames(13);
+ const Audio::Timestamp b = -a;
+ const Audio::Timestamp c = Audio::Timestamp(0, 60).addFrames(20);
+
+ TS_ASSERT_EQUALS((a+a).secs(), 0);
+ TS_ASSERT_EQUALS((a+a).numberOfFrames(), 2*13);
+
+ TS_ASSERT_EQUALS((a+b).secs(), 0);
+ TS_ASSERT_EQUALS((a+b).numberOfFrames(), 0);
+
+ TS_ASSERT_EQUALS((a+c).secs(), 0);
+ TS_ASSERT_EQUALS((a+c).numberOfFrames(), 13+20);
+
+ TS_ASSERT_EQUALS((a-a).secs(), 0);
+ TS_ASSERT_EQUALS((a-a).numberOfFrames(), 0);
+
+ TS_ASSERT_EQUALS((a-b).secs(), 0);
+ TS_ASSERT_EQUALS((a-b).numberOfFrames(), 2*13);
+
+ TS_ASSERT_EQUALS((a-c).secs(), -1);
+ TS_ASSERT_EQUALS((a-c).numberOfFrames(), 60 + (13 - 20));
+ }
void test_diff_with_conversion() {
const Audio::Timestamp a = Audio::Timestamp(10, 1000).addFrames(20);
@@ -188,18 +223,18 @@ class TimestampTestSuite : public CxxTest::TestSuite
const Audio::Timestamp b = a.addFrames(11025);
const Audio::Timestamp c = Audio::Timestamp(1500, 22050);
- TS_ASSERT_EQUALS(a.secs(), (uint32)0);
- TS_ASSERT_EQUALS(a.msecs(), (uint32)0);
+ TS_ASSERT_EQUALS(a.secs(), 0);
+ TS_ASSERT_EQUALS(a.msecs(), 0);
TS_ASSERT_EQUALS(a.numberOfFrames(), 0);
TS_ASSERT_EQUALS(a.totalNumberOfFrames(), 0);
- TS_ASSERT_EQUALS(b.secs(), (uint32)0);
- TS_ASSERT_EQUALS(b.msecs(), (uint32)500);
+ TS_ASSERT_EQUALS(b.secs(), 0);
+ TS_ASSERT_EQUALS(b.msecs(), 500);
TS_ASSERT_EQUALS(b.numberOfFrames(), 11025);
TS_ASSERT_EQUALS(b.totalNumberOfFrames(), 11025);
- TS_ASSERT_EQUALS(c.secs(), (uint32)1);
- TS_ASSERT_EQUALS(c.msecs(), (uint32)1500);
+ TS_ASSERT_EQUALS(c.secs(), 1);
+ TS_ASSERT_EQUALS(c.msecs(), 1500);
TS_ASSERT_EQUALS(c.numberOfFrames(), 11025);
TS_ASSERT_EQUALS(c.totalNumberOfFrames(), 33075);
}