Merge branch '2.0' of git.carlh.net:git/dcpomatic into 2.0
[dcpomatic.git] / src / lib / dcpomatic_time.h
1 /*
2     Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #ifndef DCPOMATIC_TIME_H
21 #define DCPOMATIC_TIME_H
22
23 #include "frame_rate_change.h"
24 #include "safe_stringstream.h"
25 #include "dcpomatic_assert.h"
26 #include <stdint.h>
27 #include <cmath>
28 #include <ostream>
29 #include <sstream>
30 #include <iomanip>
31
32 class dcpomatic_round_up_test;
33
34 class Time;
35
36 /** A time in seconds, expressed as a number scaled up by Time::HZ. */
37 class Time
38 {
39 public:
40         Time ()
41                 : _t (0)
42         {}
43
44         typedef int64_t Type;
45
46         explicit Time (Type t)
47                 : _t (t)
48         {}
49
50         virtual ~Time () {}
51
52         Type get () const {
53                 return _t;
54         }
55
56         double seconds () const {
57                 return double (_t) / HZ;
58         }
59
60         template <typename T>
61         int64_t frames (T r) const {
62                 return rint (double (_t) * r / HZ);
63         }
64
65         /** @param r Frames per second */
66         template <typename T>
67         void split (T r, int& h, int& m, int& s, int& f) const
68         {
69                 /* Do this calculation with frames so that we can round
70                    to a frame boundary at the start rather than the end.
71                 */
72                 int64_t ff = frames (r);
73                 
74                 h = ff / (3600 * r);
75                 ff -= h * 3600 * r;
76                 m = ff / (60 * r);
77                 ff -= m * 60 * r;
78                 s = ff / r;
79                 ff -= s * r;
80
81                 f = static_cast<int> (ff);
82         }
83
84         template <typename T>
85         std::string timecode (T r) const {
86                 int h;
87                 int m;
88                 int s;
89                 int f;
90                 split (r, h, m, s, f);
91
92                 SafeStringStream o;
93                 o.width (2);
94                 o.fill ('0');
95                 o << std::setw(2) << std::setfill('0') << h << ":"
96                   << std::setw(2) << std::setfill('0') << m << ":"
97                   << std::setw(2) << std::setfill('0') << s << ":"
98                   << std::setw(2) << std::setfill('0') << f;
99                 return o.str ();
100         }
101
102 protected:
103         friend struct dcptime_round_up_test;
104         
105         Type _t;
106         static const int HZ = 96000;
107 };
108
109 class DCPTime;
110
111 class ContentTime : public Time
112 {
113 public:
114         ContentTime () : Time () {}
115         explicit ContentTime (Type t) : Time (t) {}
116         ContentTime (Type n, Type d) : Time (n * HZ / d) {}
117         ContentTime (DCPTime d, FrameRateChange f);
118
119         bool operator< (ContentTime const & o) const {
120                 return _t < o._t;
121         }
122
123         bool operator<= (ContentTime const & o) const {
124                 return _t <= o._t;
125         }
126
127         bool operator== (ContentTime const & o) const {
128                 return _t == o._t;
129         }
130
131         bool operator!= (ContentTime const & o) const {
132                 return _t != o._t;
133         }
134
135         bool operator>= (ContentTime const & o) const {
136                 return _t >= o._t;
137         }
138
139         bool operator> (ContentTime const & o) const {
140                 return _t > o._t;
141         }
142
143         ContentTime operator+ (ContentTime const & o) const {
144                 return ContentTime (_t + o._t);
145         }
146
147         ContentTime & operator+= (ContentTime const & o) {
148                 _t += o._t;
149                 return *this;
150         }
151
152         ContentTime operator- () const {
153                 return ContentTime (-_t);
154         }
155
156         ContentTime operator- (ContentTime const & o) const {
157                 return ContentTime (_t - o._t);
158         }
159
160         ContentTime & operator-= (ContentTime const & o) {
161                 _t -= o._t;
162                 return *this;
163         }
164
165         /** Round up to the nearest sampling interval
166          *  at some sampling rate.
167          *  @param r Sampling rate.
168          */
169         ContentTime round_up (float r) {
170                 Type const n = rint (HZ / r);
171                 Type const a = _t + n - 1;
172                 return ContentTime (a - (a % n));
173         }
174
175         static ContentTime from_seconds (double s) {
176                 return ContentTime (s * HZ);
177         }
178
179         template <class T>
180         static ContentTime from_frames (int64_t f, T r) {
181                 DCPOMATIC_ASSERT (r > 0);
182                 return ContentTime (f * HZ / r);
183         }
184
185         static ContentTime max () {
186                 return ContentTime (INT64_MAX);
187         }
188 };
189
190 std::ostream& operator<< (std::ostream& s, ContentTime t);
191
192 class ContentTimePeriod
193 {
194 public:
195         ContentTimePeriod () {}
196         
197         ContentTimePeriod (ContentTime f, ContentTime t)
198                 : from (f)
199                 , to (t)
200         {}
201
202         ContentTime from;
203         ContentTime to;
204
205         ContentTimePeriod operator+ (ContentTime const & o) const {
206                 return ContentTimePeriod (from + o, to + o);
207         }
208
209         bool overlaps (ContentTimePeriod const & o) const;
210         bool contains (ContentTime const & o) const;
211 };
212
213 class DCPTime : public Time
214 {
215 public:
216         DCPTime () : Time () {}
217         explicit DCPTime (Type t) : Time (t) {}
218         DCPTime (ContentTime t, FrameRateChange c) : Time (rint (t.get() / c.speed_up)) {}
219
220         bool operator< (DCPTime const & o) const {
221                 return _t < o._t;
222         }
223
224         bool operator<= (DCPTime const & o) const {
225                 return _t <= o._t;
226         }
227
228         bool operator== (DCPTime const & o) const {
229                 return _t == o._t;
230         }
231
232         bool operator!= (DCPTime const & o) const {
233                 return _t != o._t;
234         }
235
236         bool operator>= (DCPTime const & o) const {
237                 return _t >= o._t;
238         }
239
240         bool operator> (DCPTime const & o) const {
241                 return _t > o._t;
242         }
243
244         DCPTime operator+ (DCPTime const & o) const {
245                 return DCPTime (_t + o._t);
246         }
247
248         DCPTime & operator+= (DCPTime const & o) {
249                 _t += o._t;
250                 return *this;
251         }
252
253         DCPTime operator- () const {
254                 return DCPTime (-_t);
255         }
256
257         DCPTime operator- (DCPTime const & o) const {
258                 return DCPTime (_t - o._t);
259         }
260
261         DCPTime & operator-= (DCPTime const & o) {
262                 _t -= o._t;
263                 return *this;
264         }
265
266         /** Round up to the nearest sampling interval
267          *  at some sampling rate.
268          *  @param r Sampling rate.
269          */
270         DCPTime round_up (float r) {
271                 Type const n = rint (HZ / r);
272                 Type const a = _t + n - 1;
273                 return DCPTime (a - (a % n));
274         }
275
276         DCPTime abs () const {
277                 return DCPTime (std::abs (_t));
278         }
279
280         static DCPTime from_seconds (double s) {
281                 return DCPTime (s * HZ);
282         }
283
284         template <class T>
285         static DCPTime from_frames (int64_t f, T r) {
286                 DCPOMATIC_ASSERT (r > 0);
287                 return DCPTime (f * HZ / r);
288         }
289
290         static DCPTime delta () {
291                 return DCPTime (1);
292         }
293
294         static DCPTime max () {
295                 return DCPTime (INT64_MAX);
296         }
297 };
298
299 DCPTime min (DCPTime a, DCPTime b);
300 std::ostream& operator<< (std::ostream& s, DCPTime t);
301
302 #endif