2 Copyright (C) 2012-2021 Carl Hetherington <cth@carlh.net>
4 This file is part of libdcp.
6 libdcp is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 libdcp is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with libdcp. If not, see <http://www.gnu.org/licenses/>.
19 In addition, as a special exception, the copyright holders give
20 permission to link the code of portions of this program with the
21 OpenSSL library under certain conditions as described in each
22 individual source file, and distribute linked combinations
25 You must obey the GNU General Public License in all respects
26 for all of the code used other than OpenSSL. If you modify
27 file(s) with this exception, you may extend this exception to your
28 version of the file(s), but you are not obligated to do so. If you
29 do not wish to do so, delete this exception statement from your
30 version. If you delete this exception statement from all source
31 files in the program, then also delete it here.
35 /** @file src/dcp_time.cc
40 #include "raw_convert.h"
42 #include "exceptions.h"
43 #include "compose.hpp"
44 #include "dcp_assert.h"
45 #include <boost/algorithm/string.hpp>
46 #include <boost/optional.hpp>
55 using boost::is_any_of;
56 using boost::optional;
60 Time::Time (int frame, double frames_per_second, int tcr_)
62 set (double (frame) / frames_per_second, tcr_);
66 Time::Time (double seconds, int tcr_)
72 /** Construct a Time with specified timecode rate and using the supplied
75 * @param seconds A number of seconds.
76 * @param tcr_ Timecode rate to use.
79 Time::set (double seconds, int tcr_)
84 e = int (round ((seconds - s) * tcr));
102 Time::Time (string time, optional<int> tcr_)
105 split (b, time, is_any_of (":"));
107 if (b.size() < 3 || b[0].empty() || b[1].empty() || b[0].length() > 2 || b[1].length() > 2) {
108 boost::throw_exception (ReadError (String::compose ("unrecognised time specification %1", time)));
114 /* HH:MM:SS.s[s[s]] */
116 split (bs, b[2], is_any_of ("."));
117 if (bs.size() != 2) {
118 boost::throw_exception (ReadError (String::compose ("unrecognised time specification %1", time)));
121 h = raw_convert<int> (b[0]);
122 m = raw_convert<int> (b[1]);
123 if (bs[0].empty() || bs[0].length() > 2) {
124 boost::throw_exception (ReadError (String::compose ("unrecognised time specification %1; %2 has bad length", time, bs[0])));
126 s = raw_convert<int> (bs[0]);
127 if (bs[1].empty() || bs[1].length() > 3) {
128 boost::throw_exception (ReadError (String::compose ("unrecognised time specification %1; %2 has bad length", time, bs[1])));
130 e = raw_convert<int> (bs[1]);
132 } else if (b.size() == 4) {
134 h = raw_convert<int> (b[0]);
135 m = raw_convert<int> (b[1]);
136 if (b[2].empty() || b[2].length() > 2) {
137 boost::throw_exception (ReadError (String::compose ("unrecognised time specification %1; %2 has bad length", time, b[2])));
139 s = raw_convert<int> (b[2]);
140 if (b[3].empty() || b[3].length() > 3) {
141 boost::throw_exception (ReadError (String::compose ("unrecognised time specification %1; %2 has bad length", time, b[3])));
143 e = raw_convert<int> (b[3]);
146 boost::throw_exception (ReadError (String::compose ("unrecognised time specification %1", time)));
150 /* SMPTE: HH:MM:SS:EE */
151 split (b, time, is_any_of (":"));
153 boost::throw_exception (ReadError (String::compose ("unrecognised time specification %1; does not have 4 parts", time)));
156 h = raw_convert<int> (b[0]);
157 m = raw_convert<int> (b[1]);
158 if (b[2].empty() || b[2].length() > 2) {
159 boost::throw_exception (ReadError (String::compose ("unrecognised time specification %1; %2 has bad length", time, b[2])));
161 s = raw_convert<int> (b[2]);
162 if (b[3].empty() || b[3].length() > 2) {
163 boost::throw_exception (ReadError (String::compose ("unrecognised time specification %1; %2 has bad length", time, b[3])));
165 e = raw_convert<int> (b[3]);
172 dcp::operator== (Time const & a, Time const & b)
174 return (a.h == b.h && a.m == b.m && a.s == b.s && (a.e * b.tcr) == (b.e * a.tcr));
179 dcp::operator!= (Time const & a, Time const & b)
186 dcp::operator<= (Time const & a, Time const & b)
188 return a < b || a == b;
193 dcp::operator>= (Time const & a, Time const & b)
195 return a > b || a == b;
200 dcp::operator< (Time const & a, Time const & b)
214 return (a.e * b.tcr) < (b.e * a.tcr);
219 dcp::operator> (Time const & a, Time const & b)
233 return (a.e * b.tcr) > (b.e * a.tcr);
238 dcp::operator<< (ostream& s, Time const & t)
240 s << t.h << ":" << t.m << ":" << t.s << "." << t.e;
246 dcp::operator+ (Time a, Time b)
250 /* Make sure we have a common tcr */
251 if (a.tcr != b.tcr) {
254 r.tcr = a.tcr * b.tcr;
284 dcp::operator- (Time a, Time b)
288 /* Make sure we have a common tcr */
289 if (a.tcr != b.tcr) {
292 r.tcr = a.tcr * b.tcr;
322 dcp::operator/ (Time a, Time const & b)
324 int64_t const at = a.h * 3600 + a.m * 60 + a.s * float (a.e) / a.tcr;
325 int64_t const bt = b.h * 3600 + b.m * 60 + b.s * float (b.e) / b.tcr;
326 return float (at) / bt;
331 Time::as_string (Standard standard) const
335 if (standard == Standard::SMPTE) {
336 snprintf (buffer, sizeof(buffer), "%02d:%02d:%02d:%02d", h, m, s, e);
338 snprintf (buffer, sizeof(buffer), "%02d:%02d:%02d:%03d", h, m, s, e);
346 Time::as_editable_units_floor (int tcr_) const
348 return floor(int64_t(e) * double(tcr_) / tcr) + int64_t(s) * tcr_ + int64_t(m) * 60 * tcr_ + int64_t(h) * 60 * 60 * tcr_;
353 Time::as_editable_units_ceil (int tcr_) const
355 return ceil(int64_t(e) * double(tcr_) / tcr) + int64_t(s) * tcr_ + int64_t(m) * 60 * tcr_ + int64_t(h) * 60 * 60 * tcr_;
360 Time::as_seconds () const
362 return h * 3600 + m * 60 + s + double(e) / tcr;
367 Time::rebase (int tcr_) const
369 long int e_ = lrintf (float (e) * tcr_ / tcr);
386 return Time (h_, m_, s_, e_, tcr_);