From 590481b12daf2287b37fdae757f8cca349912754 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 11 Jan 2010 10:17:55 +0000 Subject: Improve support for negative Timestamps, and add + and - operators svn-id: r47244 --- sound/audiostream.cpp | 8 ++-- sound/audiostream.h | 3 +- sound/timestamp.cpp | 130 ++++++++++++++++++++++++++++++++++++-------------- sound/timestamp.h | 57 ++++++++++++++++------ 4 files changed, 142 insertions(+), 56 deletions(-) (limited to 'sound') 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); }; -- cgit v1.2.3