File: timestamp.h

package info (click to toggle)
scummvm 2.9.1%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 450,580 kB
  • sloc: cpp: 4,299,825; asm: 28,322; python: 12,901; sh: 11,302; java: 9,289; xml: 7,895; perl: 2,639; ansic: 2,465; yacc: 1,670; javascript: 1,020; makefile: 933; lex: 578; awk: 275; objc: 82; sed: 11; php: 1
file content (288 lines) | stat: -rw-r--r-- 9,387 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
/* 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 3 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, see <http://www.gnu.org/licenses/>.
 *
 */

#ifndef AUDIO_TIMESTAMP_H
#define AUDIO_TIMESTAMP_H

#include "common/scummsys.h"

namespace Audio {

/**
 * @defgroup audio_timestamp Timestamp
 * @ingroup audio
 *
 * @brief Timestamp class for specifying points in time and measuring time intervals.
 * @{
 */

/**
* When dealing with audio and video decoding, it is often necessary to
 * measure the time (intervals) in terms of frames, relative to a fixed
 * frame rate (that is, a fixed number of frames per seconds). For
 * example, in a typical video there are 24 frames per second, and in a
 * typical sound there are 44100 frames (i.e. samples for mono sound
 * and pairs of samples for stereo) per second.
 *
 * At the same time, the system clock provided by ScummVM measures time
 * in milliseconds. For syncing purposes and other reasons, it is often
 * necessary to convert between and compare time measures given on
 * one hand as a frame count, and on the other hand as a number of
 * milliseconds.
 *
 * If handled carelessly, this can introduce rounding errors that
 * quickly accumulate, resulting in user-noticeable disturbance, such as
 * audio and video running out of sync. For example, a typical approach is to
 * measure all time in milliseconds. But with a frame rate of 24 frames
 * per second, one frame is 41.66666... milliseconds long. On the other
 * hand, if measuring in frames, then a similar rounding issue occurs when
 * converting from milliseconds to frames.
 *
 * One solution is to use floating point arithmetic to compute with
 * fractional frames resp. (milli)seconds. This has other undesirable
 * side effects. Foremost, some platforms that ScummVM runs on still have
 * only limited (and slow) floating point support.
 *
 * This class provides an alternative solution. It stores time in terms of
 * frames, but with a twist: client code can specify arbitrary
 * (integral) frame rates but, internally, Timestamp modifies the
 * frame rate to be a multiple of 1000. This way, both the number of frames
 * (relative to the original frame rate), as well as milliseconds can be
 * represented as integers. This change is completely hidden from the
 * user, however.
 *
 * A timestamp can be converted to a frame count or milliseconds at
 * virtually no cost. Likewise, it is possible to compute the difference
 * between two timestamps in terms of milliseconds or number of frames.
 * Timestamps can be easily compared using regular comparison operators,
 * resulting in nicely readable code. This is even possible for
 * timestamps that are specified using different frame rates.
 * Client code can modify timestamps by adding a number of frames
 * to it, or adding a number of milliseconds. Adding negative amounts is
 * also allowed, and a timestamp can even represent a "negative time",
 * which is useful when using the timestamp to store a time interval.
 */
class Timestamp {
public:
	/**
	 * Set up a timestamp with a given time and frame rate.
	 *
	 * @param msecs      Starting time in milliseconds.
	 * @param framerate  Number of frames per second (must be > 0).
	 */
	Timestamp(uint msecs = 0, uint framerate = 1);

	/**
	 * Set up a timestamp with the given time, frames, and frame rate.
	 *
	 * @param secs       Starting time in seconds.
	 * @param frames     Starting frames.
	 * @param framerate  Number of frames per second (must be > 0).
	 */
	Timestamp(uint secs, uint frames, uint framerate);

	/**
	 * Return a timestamp that represents as closely as possible
	 * the point in time described by this timestamp, but with
	 * a different frame rate.
	 */
	Timestamp convertToFramerate(uint newFramerate) const;

	/**
	 * Check whether two timestamps describe the exact same moment
	 * in time.
	 *
	 * This means that two timestamps can compare as equal
	 * even if they use different frame rates.
	 */
	bool operator==(const Timestamp &ts) const;
	/**
	 * Check whether two timestamps describe a different moment in time.
	 */
	bool operator!=(const Timestamp &ts) const;
	/**
	 * Check whether this timestamp describes an earlier moment in time than another timestamp.
	 */
	bool operator<(const Timestamp &ts) const;
	/**
	 * Check whether this timestamp describes an earlier or the same moment in time as another timestamp.
	 */
	bool operator<=(const Timestamp &ts) const;
	/**
	 * Check whether this timestamp describes a later moment in time than another timestamp.
	 */
	bool operator>(const Timestamp &ts) const;
	/**
	 * Check whether this timestamp describes a later or the same moment in time as another timestamp.
	 */
	bool operator>=(const Timestamp &ts) const;

	/**
	 * Return a new timestamp that corresponds to the time encoded
	 * by this timestamp with the given number of frames added.
	 *
	 * @param frames  Number of frames to add.
	 */
	Timestamp addFrames(int frames) const;

	/**
	 * Return a new timestamp that corresponds to the time encoded
	 * by this timestamp with the given number of milliseconds added.
	 *
	 * @param msecs  Number of milliseconds to add.
	 */
	Timestamp addMsecs(int msecs) const;


	/**
	 * Return a new timestamp with the negative value of the time encoded
	 * by this timestamp.
	 *
	 * This is a unary minus operation.
	 */
	Timestamp operator-() const;

	/**
	 * Compute the sum of two timestamps.
	 *
	 * This is only allowed if they use the same frame rate.
	 */
	Timestamp operator+(const Timestamp &ts) const;

	/**
	 * Compute the difference between two timestamps.
	 *
	 * This is only allowed if they use the same frame rate.
	 */
	Timestamp operator-(const Timestamp &ts) const;

	/**
	 * Compute the number of frames between this timestamp and @p ts.
	 *
	 * The frames are counted with respect to the frame rate used by this
	 * timestamp (which may differ from the frame rate used by @p ts).
	 */
	int frameDiff(const Timestamp &ts) const;

	/** Compute the number of milliseconds between this timestamp and @p ts. */
	int msecsDiff(const Timestamp &ts) const;

	/**
	 * Return the time in milliseconds described by this timestamp,
	 * rounded down.
	 */
	int msecs() const;

	/**
	 * Return the time in seconds described by this timestamp,
	 * rounded down.
	 */
	inline int secs() const {
		return _secs;
	}

	/**
	 * Return the time in frames described by this timestamp.
	 */
	inline int totalNumberOfFrames() const {
		return _numFrames / (int)_framerateFactor + _secs * (int)(_framerate / _framerateFactor);
	}

	/**
	 * A timestamp consists of a number of seconds, plus a number
	 * of frames, the latter describing a fraction of a second.
	 * This method returns the latter number.
	 */
	inline int numberOfFrames() const {
		return _numFrames / (int)_framerateFactor;
	}

	/** Return the frame rate used by this timestamp. */
	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;

	/**
	 * Normalize this timestamp by making _numFrames non-negative
	 * and reducing its modulo _framerate.
	 */
	void normalize();

	/**
	 * Add another timestamp to this one and normalize the result.
	 */
	void addIntern(const Timestamp &ts);

protected:
	/**
	 * The seconds part of this timestamp.
	 * The total time in seconds represented by this timestamp can be
	 * computed as follows:
	 * @code
	 *   _secs + (double)_numFrames / _framerate
	 * @endcode
	 */
	int _secs;

	/**
	 * The number of frames that, together with @c _secs, encode the
	 * timestamp.
	 *
	 * The total number of *internal* frames represented
	 * by this timestamp can be computed as follows:
	 * @code
	 *   _numFrames + _secs * _framerate
	 *  @endcode
	 * To obtain the number of frames with respect to the original
	 * frame rate, this value must be divided by _framerateFactor.
	 *
	 * This is always a value greater than or equal to zero.
	 * The only reason this is an int and not a uint is to
	 * allow intermediate negative values.
	 */
	int _numFrames;

	/**
	 * The internal frame rate, i.e. the number of frames per second.
	 *
	 * This is computed as the least common multiple of the frame rate
	 * specified by the client code, and 1000.
	 * This ensures that both frames and milliseconds can be stored
	 * without any rounding losses.
	 */
	uint _framerate;

	/**
	 * Factor by which the original frame rate specified by the client
	 * code has been multiplied to obtain the internal _framerate value.
	 */
	uint _framerateFactor;
};

/** @} */
} // End of namespace Audio

#endif