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