2009-03-04 06:58:28 +00:00
|
|
|
/* ScummVM - Graphic Adventure Engine
|
|
|
|
*
|
|
|
|
* ScummVM is the legal property of its developers, whose names
|
|
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
|
|
* file distributed with this source distribution.
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*
|
|
|
|
* $URL$
|
|
|
|
* $Id$
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "sound/timestamp.h"
|
|
|
|
|
|
|
|
namespace Audio {
|
|
|
|
|
2010-01-04 22:48:28 +00:00
|
|
|
static uint gcd(uint a, uint b) {
|
|
|
|
while (a > 0) {
|
|
|
|
int tmp = a;
|
|
|
|
a = b % a;
|
|
|
|
b = tmp;
|
|
|
|
}
|
|
|
|
return b;
|
|
|
|
}
|
|
|
|
|
2010-01-06 12:09:14 +00:00
|
|
|
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;
|
2010-01-04 22:48:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Timestamp Timestamp::convertToFramerate(int newFramerate) const {
|
|
|
|
Timestamp ts(*this);
|
|
|
|
|
2010-01-06 12:09:14 +00:00
|
|
|
if (ts.getFramerate() != newFramerate) {
|
|
|
|
ts._framerateFactor = 1000 / gcd(1000, newFramerate);
|
|
|
|
ts._framerate = newFramerate * ts._framerateFactor;
|
2010-01-04 22:48:28 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2010-01-06 12:09:14 +00:00
|
|
|
ts._secs += (ts._numberOfFrames / ts._framerate);
|
2010-01-04 22:48:28 +00:00
|
|
|
ts._numberOfFrames %= ts._framerate;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ts;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Timestamp::operator==(const Timestamp &ts) const {
|
2010-01-06 12:15:05 +00:00
|
|
|
return cmp(ts) == 0;
|
2010-01-04 22:48:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Timestamp::operator!=(const Timestamp &ts) const {
|
2010-01-06 12:15:05 +00:00
|
|
|
return cmp(ts) != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Timestamp::operator<(const Timestamp &ts) const {
|
|
|
|
return cmp(ts) < 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Timestamp::operator<=(const Timestamp &ts) const {
|
|
|
|
return cmp(ts) <= 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Timestamp::operator>(const Timestamp &ts) const {
|
|
|
|
return cmp(ts) > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Timestamp::operator>=(const Timestamp &ts) const {
|
|
|
|
return cmp(ts) >= 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Timestamp::cmp(const Timestamp &ts) const {
|
|
|
|
int delta = _secs - ts._secs;
|
|
|
|
if (!delta) {
|
|
|
|
const uint g = gcd(_framerate, ts._framerate);
|
|
|
|
const uint p = _framerate / g;
|
|
|
|
const uint q = ts._framerate / g;
|
|
|
|
|
|
|
|
delta = (_numberOfFrames * q - ts._numberOfFrames * p);
|
|
|
|
}
|
|
|
|
|
|
|
|
return delta;
|
2009-03-04 06:58:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Timestamp Timestamp::addFrames(int frames) const {
|
2010-01-04 22:48:28 +00:00
|
|
|
Timestamp ts(*this);
|
2010-01-06 12:09:14 +00:00
|
|
|
|
|
|
|
// The frames are given in the original framerate, so we have to
|
|
|
|
// adjust by _framerateFactor accordingly.
|
|
|
|
ts._numberOfFrames += frames * _framerateFactor;
|
2009-03-04 06:58:28 +00:00
|
|
|
|
2010-01-04 22:48:28 +00:00
|
|
|
if (ts._numberOfFrames < 0) {
|
|
|
|
int secsub = 1 + (-ts._numberOfFrames / ts._framerate);
|
2009-03-04 06:58:28 +00:00
|
|
|
|
2010-01-04 22:48:28 +00:00
|
|
|
ts._numberOfFrames += ts._framerate * secsub;
|
2010-01-06 12:09:14 +00:00
|
|
|
ts._secs -= secsub;
|
2009-03-04 06:58:28 +00:00
|
|
|
}
|
|
|
|
|
2010-01-06 12:09:14 +00:00
|
|
|
ts._secs += (ts._numberOfFrames / ts._framerate);
|
2010-01-04 22:48:28 +00:00
|
|
|
ts._numberOfFrames %= ts._framerate;
|
2009-03-04 06:58:28 +00:00
|
|
|
|
2010-01-04 22:48:28 +00:00
|
|
|
return ts;
|
2009-03-04 06:58:28 +00:00
|
|
|
}
|
|
|
|
|
2009-05-28 10:29:25 +00:00
|
|
|
Timestamp Timestamp::addMsecs(int ms) const {
|
2010-01-04 22:48:28 +00:00
|
|
|
Timestamp ts(*this);
|
2010-01-06 12:09:14 +00:00
|
|
|
ts._secs += ms / 1000;
|
|
|
|
// Add the remaining frames. Note that _framerate is always divisible by 1000.
|
|
|
|
return ts.addFrames((ms % 1000) * (_framerate / 1000));
|
2009-05-28 10:29:25 +00:00
|
|
|
}
|
|
|
|
|
2010-01-04 22:48:28 +00:00
|
|
|
int Timestamp::frameDiff(const Timestamp &ts) const {
|
|
|
|
|
|
|
|
int delta = 0;
|
2010-01-06 12:09:14 +00:00
|
|
|
if (_secs != ts._secs)
|
|
|
|
delta = (long(_secs) - long(ts._secs)) * _framerate;
|
2010-01-04 22:48:28 +00:00
|
|
|
|
|
|
|
delta += _numberOfFrames;
|
2009-03-04 06:58:28 +00:00
|
|
|
|
2010-01-04 22:48:28 +00:00
|
|
|
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;
|
|
|
|
}
|
2009-03-04 06:58:28 +00:00
|
|
|
|
2010-01-06 12:09:14 +00:00
|
|
|
return delta / _framerateFactor;
|
2009-03-04 06:58:28 +00:00
|
|
|
}
|
|
|
|
|
2010-01-04 22:48:28 +00:00
|
|
|
int Timestamp::msecsDiff(const Timestamp &ts) const {
|
|
|
|
return long(msecs()) - long(ts.msecs());
|
2009-03-04 06:58:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
uint32 Timestamp::msecs() const {
|
2010-01-06 12:09:14 +00:00
|
|
|
return _secs * 1000 + _numberOfFrames / (_framerate / 1000);
|
2009-03-04 06:58:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} // End of namespace Audio
|