Merge master.
[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 <cmath>
24 #include <ostream>
25 #include <sstream>
26 #include <iomanip>
27 #include <stdint.h>
28 #include "frame_rate_change.h"
29 #include "safe_stringstream.h"
30
31 class dcpomatic_round_up_test;
32
33 class Time;
34
35 /** A time in seconds, expressed as a number scaled up by Time::HZ. */
36 class Time
37 {
38 public:
39         Time ()
40                 : _t (0)
41         {}
42
43         typedef int64_t Type;
44
45         explicit Time (Type t)
46                 : _t (t)
47         {}
48
49         virtual ~Time () {}
50
51         Type get () const {
52                 return _t;
53         }
54
55         double seconds () const {
56                 return double (_t) / HZ;
57         }
58
59         template <typename T>
60         int64_t frames (T r) const {
61                 return rint (_t * r / HZ);
62         }
63
64         template <typename T>
65         void split (T r, int& h, int& m, int& s, int& f) const
66         {
67                 /* Do this calculation with frames so that we can round
68                    to a frame boundary at the start rather than the end.
69                 */
70                 int64_t ff = frames (r);
71                 
72                 h = ff / (3600 * r);
73                 ff -= h * 3600 * r;
74                 m = ff / (60 * r);
75                 ff -= m * 60 * r;
76                 s = ff / r;
77                 ff -= s * r;
78
79                 f = static_cast<int> (ff);
80         }
81
82         template <typename T>
83         std::string timecode (T r) const {
84                 int h;
85                 int m;
86                 int s;
87                 int f;
88                 split (r, h, m, s, f);
89
90                 SafeStringStream o;
91                 o.width (2);
92                 o.fill ('0');
93                 o << std::setw(2) << std::setfill('0') << h << ":"
94                   << std::setw(2) << std::setfill('0') << m << ":"
95                   << std::setw(2) << std::setfill('0') << s << ":"
96                   << std::setw(2) << std::setfill('0') << f;
97                 return o.str ();
98         }
99
100 protected:
101         friend struct dcptime_round_up_test;
102         
103         Type _t;
104         static const int HZ = 96000;
105 };
106
107 class DCPTime;
108
109 class ContentTime : public Time
110 {
111 public:
112         ContentTime () : Time () {}
113         explicit ContentTime (Type t) : Time (t) {}
114         ContentTime (Type n, Type d) : Time (n * HZ / d) {}
115         ContentTime (DCPTime d, FrameRateChange f);
116
117         bool operator< (ContentTime const & o) const {
118                 return _t < o._t;
119         }
120
121         bool operator<= (ContentTime const & o) const {
122                 return _t <= o._t;
123         }
124
125         bool operator== (ContentTime const & o) const {
126                 return _t == o._t;
127         }
128
129         bool operator!= (ContentTime const & o) const {
130                 return _t != o._t;
131         }
132
133         bool operator>= (ContentTime const & o) const {
134                 return _t >= o._t;
135         }
136
137         bool operator> (ContentTime const & o) const {
138                 return _t > o._t;
139         }
140
141         ContentTime operator+ (ContentTime const & o) const {
142                 return ContentTime (_t + o._t);
143         }
144
145         ContentTime & operator+= (ContentTime const & o) {
146                 _t += o._t;
147                 return *this;
148         }
149
150         ContentTime operator- () const {
151                 return ContentTime (-_t);
152         }
153
154         ContentTime operator- (ContentTime const & o) const {
155                 return ContentTime (_t - o._t);
156         }
157
158         ContentTime & operator-= (ContentTime const & o) {
159                 _t -= o._t;
160                 return *this;
161         }
162
163         /** Round up to the nearest sampling interval
164          *  at some sampling rate.
165          *  @param r Sampling rate.
166          */
167         ContentTime round_up (float r) {
168                 Type const n = rint (HZ / r);
169                 Type const a = _t + n - 1;
170                 return ContentTime (a - (a % n));
171         }
172
173         static ContentTime from_seconds (double s) {
174                 return ContentTime (s * HZ);
175         }
176
177         template <class T>
178         static ContentTime from_frames (int64_t f, T r) {
179                 assert (r > 0);
180                 return ContentTime (f * HZ / r);
181         }
182
183         static ContentTime max () {
184                 return ContentTime (INT64_MAX);
185         }
186 };
187
188 std::ostream& operator<< (std::ostream& s, ContentTime t);
189
190 class ContentTimePeriod
191 {
192 public:
193         ContentTimePeriod () {}
194         ContentTimePeriod (ContentTime f, ContentTime t)
195                 : from (f)
196                 , to (t)
197         {}
198
199         ContentTime from;
200         ContentTime to;
201
202         ContentTimePeriod operator+ (ContentTime const & o) const {
203                 return ContentTimePeriod (from + o, to + o);
204         }
205
206         bool overlaps (ContentTimePeriod const & o) const;
207         bool contains (ContentTime const & o) const;
208 };
209
210 class DCPTime : public Time
211 {
212 public:
213         DCPTime () : Time () {}
214         explicit DCPTime (Type t) : Time (t) {}
215         DCPTime (ContentTime t, FrameRateChange c) : Time (rint (t.get() / c.speed_up)) {}
216
217         bool operator< (DCPTime const & o) const {
218                 return _t < o._t;
219         }
220
221         bool operator<= (DCPTime const & o) const {
222                 return _t <= o._t;
223         }
224
225         bool operator== (DCPTime const & o) const {
226                 return _t == o._t;
227         }
228
229         bool operator!= (DCPTime const & o) const {
230                 return _t != o._t;
231         }
232
233         bool operator>= (DCPTime const & o) const {
234                 return _t >= o._t;
235         }
236
237         bool operator> (DCPTime const & o) const {
238                 return _t > o._t;
239         }
240
241         DCPTime operator+ (DCPTime const & o) const {
242                 return DCPTime (_t + o._t);
243         }
244
245         DCPTime & operator+= (DCPTime const & o) {
246                 _t += o._t;
247                 return *this;
248         }
249
250         DCPTime operator- () const {
251                 return DCPTime (-_t);
252         }
253
254         DCPTime operator- (DCPTime const & o) const {
255                 return DCPTime (_t - o._t);
256         }
257
258         DCPTime & operator-= (DCPTime const & o) {
259                 _t -= o._t;
260                 return *this;
261         }
262
263         /** Round up to the nearest sampling interval
264          *  at some sampling rate.
265          *  @param r Sampling rate.
266          */
267         DCPTime round_up (float r) {
268                 Type const n = rint (HZ / r);
269                 Type const a = _t + n - 1;
270                 return DCPTime (a - (a % n));
271         }
272
273         DCPTime abs () const {
274                 return DCPTime (std::abs (_t));
275         }
276
277         static DCPTime from_seconds (double s) {
278                 return DCPTime (s * HZ);
279         }
280
281         template <class T>
282         static DCPTime from_frames (int64_t f, T r) {
283                 assert (r > 0);
284                 return DCPTime (f * HZ / r);
285         }
286
287         static DCPTime delta () {
288                 return DCPTime (1);
289         }
290
291         static DCPTime max () {
292                 return DCPTime (INT64_MAX);
293         }
294 };
295
296 DCPTime min (DCPTime a, DCPTime b);
297 std::ostream& operator<< (std::ostream& s, DCPTime t);
298
299 #endif