xoreos  0.0.5
timestamp.cpp
Go to the documentation of this file.
1 /* xoreos - A reimplementation of BioWare's Aurora engine
2  *
3  * xoreos is the legal property of its developers, whose names
4  * can be found in the AUTHORS file distributed with this source
5  * distribution.
6  *
7  * xoreos is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 3
10  * of the License, or (at your option) any later version.
11  *
12  * xoreos is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with xoreos. If not, see <http://www.gnu.org/licenses/>.
19  */
20 
25 /* Based on ScummVM (<http://scummvm.org>) code, which is released
26  * under the terms of version 2 or later of the GNU General Public
27  * License.
28  *
29  * The original copyright note in ScummVM reads as follows:
30  *
31  * ScummVM is the legal property of its developers, whose names
32  * are too numerous to list here. Please refer to the COPYRIGHT
33  * file distributed with this source distribution.
34  *
35  * This program is free software; you can redistribute it and/or
36  * modify it under the terms of the GNU General Public License
37  * as published by the Free Software Foundation; either version 2
38  * of the License, or (at your option) any later version.
39  *
40  * This program is distributed in the hope that it will be useful,
41  * but WITHOUT ANY WARRANTY; without even the implied warranty of
42  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
43  * GNU General Public License for more details.
44  *
45  * You should have received a copy of the GNU General Public License
46  * along with this program; if not, write to the Free Software
47  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
48  */
49 
50 #include "src/common/algorithm.h"
51 #include "src/common/error.h"
52 #include "src/common/rational.h"
53 #include "src/common/timestamp.h"
54 
55 namespace Common {
56 
58  if (fr == 0)
59  throw Exception("Invalid frame rate 0");
60 
61  _secs = ms / 1000;
62  _framerateFactor = 1000 / gcd<uint64>(1000, fr);
64 
65  // Note that _framerate is always divisible by 1000.
66  _numFrames = (ms % 1000) * (_framerate / 1000);
67 }
68 
70  if (fr == 0)
71  throw Exception("Invalid frame rate 0");
72 
73  _secs = s + (frames / fr);
74  _framerateFactor = 1000 / gcd<uint64>(1000, fr);
76  _numFrames = (frames % fr) * _framerateFactor;
77 }
78 
79 Timestamp::Timestamp(uint64 s, uint64 frames, const Rational &newFramerate) {
80  if (newFramerate <= 0)
81  throw Exception("Invalid frame rate %d/%d", newFramerate.getNumerator(), newFramerate.getDenominator());
82 
83  uint64 fr;
84  if (newFramerate.getDenominator() == 1) {
85  fr = newFramerate.getNumerator();
86  } else {
87  Rational time = newFramerate.getInverse() * frames;
88  frames = time.getNumerator();
89  fr = time.getDenominator();
90  }
91 
92  _secs = s + (frames / fr);
93  _framerateFactor = 1000 / gcd<uint64>(1000, fr);
95  _numFrames = (frames % fr) * _framerateFactor;
96 }
97 
99  assert(_framerate != 0);
100  assert(newFramerate != 0);
101 
102  Timestamp ts(*this);
103 
104  if (ts.framerate() != newFramerate) {
105  ts._framerateFactor = 1000 / gcd<uint64>(1000, newFramerate);
106  ts._framerate = newFramerate * ts._framerateFactor;
107 
108  const uint64 g = gcd(_framerate, ts._framerate);
109  const uint64 p = _framerate / g;
110  const uint64 q = ts._framerate / g;
111 
112  // Convert the frame offset to the new framerate.
113  // We round to the nearest (as opposed to always
114  // rounding down), to minimize rounding errors during
115  // round trip conversions.
116  ts._numFrames = (ts._numFrames * q + p/2) / p;
117 
118  ts.normalize();
119  }
120 
121  return ts;
122 }
123 
125  // Convert negative _numFrames values to positive ones by adjusting _secs
126  if (_numFrames < 0) {
127  int64 secsub = 1 + (-_numFrames / _framerate);
128 
129  _numFrames += _framerate * secsub;
130  _secs -= secsub;
131  }
132 
133  // Wrap around if necessary
134  _secs += (_numFrames / _framerate);
136 }
137 
138 bool Timestamp::operator==(const Timestamp &ts) const {
139  return cmp(ts) == 0;
140 }
141 
142 bool Timestamp::operator!=(const Timestamp &ts) const {
143  return cmp(ts) != 0;
144 }
145 
146 bool Timestamp::operator<(const Timestamp &ts) const {
147  return cmp(ts) < 0;
148 }
149 
150 bool Timestamp::operator<=(const Timestamp &ts) const {
151  return cmp(ts) <= 0;
152 }
153 
154 bool Timestamp::operator>(const Timestamp &ts) const {
155  return cmp(ts) > 0;
156 }
157 
158 bool Timestamp::operator>=(const Timestamp &ts) const {
159  return cmp(ts) >= 0;
160 }
161 
162 int64 Timestamp::cmp(const Timestamp &ts) const {
163  assert(_framerate != 0);
164  assert(ts._framerate != 0);
165 
166  int64 delta = _secs - ts._secs;
167  if (!delta) {
168  const uint64 g = gcd(_framerate, ts._framerate);
169  const uint64 p = _framerate / g;
170  const uint64 q = ts._framerate / g;
171 
172  delta = (_numFrames * q - ts._numFrames * p);
173  }
174 
175  return delta;
176 }
177 
178 
180  Timestamp ts(*this);
181 
182  // The frames are given in the original framerate, so we have to
183  // adjust by _framerateFactor accordingly.
184  ts._numFrames += frames * _framerateFactor;
185  ts.normalize();
186 
187  return ts;
188 }
189 
191  Timestamp ts(*this);
192  ts._secs += ms / 1000;
193  // Add the remaining frames. Note that _framerate is always divisible by 1000.
194  ts._numFrames += (ms % 1000) * (ts._framerate / 1000);
195 
196  ts.normalize();
197 
198  return ts;
199 }
200 
202  if (_framerate != ts._framerate)
203  throw Exception("Cannot add two timestamps of different frame rates");
204 
205  _secs += ts._secs;
206  _numFrames += ts._numFrames;
207 
208  normalize();
209 }
210 
212  Timestamp result(*this);
213  result._secs = -_secs;
214  result._numFrames = -_numFrames;
215  result.normalize();
216  return result;
217 }
218 
220  Timestamp result(*this);
221  result.addIntern(ts);
222  return result;
223 }
224 
226  Timestamp result(*this);
227  result.addIntern(-ts);
228  return result;
229 }
230 
232  assert(_framerate != 0);
233  assert(ts._framerate != 0);
234 
235  int64 delta = 0;
236  if (_secs != ts._secs)
237  delta = (_secs - ts._secs) * _framerate;
238 
239  delta += _numFrames;
240 
241  if (_framerate == ts._framerate) {
242  delta -= ts._numFrames;
243  } else {
244  // We need to multiply by the quotient of the two framerates.
245  // We cancel the GCD in this fraction to reduce the risk of
246  // overflows.
247  const uint64 g = gcd(_framerate, ts._framerate);
248  const uint64 p = _framerate / g;
249  const uint64 q = ts._framerate / g;
250 
251  delta -= ((long)ts._numFrames * p + q/2) / (long)q;
252  }
253 
254  return delta / (int64)_framerateFactor;
255 }
256 
258  return msecs() - ts.msecs();
259 }
260 
262  // Note that _framerate is always divisible by 1000.
263  return _secs * 1000 + _numFrames / (_framerate / 1000);
264 }
265 
266 
267 } // End of namespace Common
T gcd(T a, T b)
Euclid&#39;s algorithm to compute the greatest common divisor.
Definition: algorithm.h:59
int64 frameDiff(const Timestamp &ts) const
Computes the number of frames between this timestamp and ts.
Definition: timestamp.cpp:231
Definition: 2dafile.h:39
A simple rational class that holds fractions.
Definition: rational.h:56
Supplemental algorithms.
uint64 framerate() const
Return the framerate used by this timestamp.
Definition: timestamp.h:223
uint64_t uint64
Definition: types.h:206
uint64 _framerate
The internal framerate, i.e.
Definition: timestamp.h:273
bool operator==(const Timestamp &ts) const
Check whether to timestamps describe the exact same moment in time.
Definition: timestamp.cpp:138
int64 msecsDiff(const Timestamp &ts) const
Computes the number off milliseconds between this timestamp and ts.
Definition: timestamp.cpp:257
bool operator!=(const Timestamp &ts) const
Definition: timestamp.cpp:142
Lossless timestamping.
int64 _secs
The seconds part of this timestamp.
Definition: timestamp.h:250
bool operator>=(const Timestamp &ts) const
Definition: timestamp.cpp:158
bool operator<=(const Timestamp &ts) const
Definition: timestamp.cpp:150
Timestamp operator-() const
Definition: timestamp.cpp:211
Basic exceptions to throw.
Timestamp(uint64 msecs=0, uint64 framerate=1)
Set up a timestamp with a given time and framerate.
Definition: timestamp.cpp:57
Timestamp addMsecs(int64 msecs) const
Returns a new timestamp, which corresponds to the time encoded by this timestamp with the given numbe...
Definition: timestamp.cpp:190
Timestamp operator+(const Timestamp &ts) const
Compute the sum of two timestamps.
Definition: timestamp.cpp:219
uint64 _framerateFactor
Factor by which the original framerate specified by the client code was multipled to obtain the inter...
Definition: timestamp.h:279
int64 cmp(const Timestamp &ts) const
Compare this timestamp to another one and return a value similar to strcmp.
Definition: timestamp.cpp:162
void normalize()
Normalize this timestamp by making _numFrames non-negative and reducing it modulo _framerate...
Definition: timestamp.cpp:124
StackException Exception
Definition: error.h:59
int64_t int64
Definition: types.h:205
int getDenominator() const
Definition: rational.h:108
bool operator>(const Timestamp &ts) const
Definition: timestamp.cpp:154
bool operator<(const Timestamp &ts) const
Definition: timestamp.cpp:146
Timestamps allow specifying points in time and measuring time intervals with a sub-millisecond granul...
Definition: timestamp.h:108
int64 msecs() const
Return the time in milliseconds described by this timestamp, rounded down.
Definition: timestamp.cpp:261
Rational number implementation.
int64 _numFrames
The number of frames which together with _secs encodes the timestamp.
Definition: timestamp.h:264
Timestamp addFrames(int64 frames) const
Returns a new timestamp, which corresponds to the time encoded by this timestamp with the given numbe...
Definition: timestamp.cpp:179
Rational getInverse() const
Definition: rational.cpp:279
Timestamp convertToFramerate(uint64 newFramerate) const
Return a timestamp which represents as closely as possible the point in time describes by this timest...
Definition: timestamp.cpp:98
int getNumerator() const
Definition: rational.h:107
void addIntern(const Timestamp &ts)
Add another timestamp to this one and normalize the result.
Definition: timestamp.cpp:201