X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Fdcpomatic_time.h;h=df9c46c7157651fff9759b8f6e342c18b563ce2f;hb=e60bb3e51bd1508b149e6b8f6608f09b5196ae26;hp=05b4e1a5d7d1d2061fe26327068632e03c79c78b;hpb=a79d78d8bb6d51f6662f1f63b9f8fd19e1a0c5f1;p=dcpomatic.git diff --git a/src/lib/dcpomatic_time.h b/src/lib/dcpomatic_time.h index 05b4e1a5d..df9c46c71 100644 --- a/src/lib/dcpomatic_time.h +++ b/src/lib/dcpomatic_time.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2014 Carl Hetherington + Copyright (C) 2014-2015 Carl Hetherington 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 @@ -17,18 +17,32 @@ */ +/** @file src/lib/dcpomatic_time.h + * @brief Types to describe time. + */ + #ifndef DCPOMATIC_TIME_H #define DCPOMATIC_TIME_H -#include -#include #include "frame_rate_change.h" +#include "safe_stringstream.h" +#include "dcpomatic_assert.h" +#include +#include +#include +#include +#include class dcpomatic_round_up_test; -class Time; - -/** A time in seconds, expressed as a number scaled up by Time::HZ. */ +/** A time in seconds, expressed as a number scaled up by Time::HZ. We want two different + * versions of this class, ContentTime and DCPTime, and we want it to be impossible to + * convert implicitly between the two. Hence there's this template hack. I'm not + * sure if it's the best way to do it. + * + * S is the name of `this' class and O is its opposite (see the typedefs below). + */ +template class Time { public: @@ -36,179 +50,198 @@ public: : _t (0) {} - explicit Time (int64_t t) + typedef int64_t Type; + + explicit Time (Type t) : _t (t) {} - virtual ~Time () {} - - int64_t get () const { - return _t; - } - - double seconds () const { - return double (_t) / HZ; - } + explicit Time (Type n, Type d) + : _t (n * HZ / d) + {} - template - int64_t frames (T r) const { - return rint (_t * r / HZ); - } + /* Explicit conversion from type O */ + Time (Time d, FrameRateChange f); - operator bool () const { - return _t != 0; + Type get () const { + return _t; } -protected: - friend class dcptime_round_up_test; - - int64_t _t; - static const int HZ = 96000; -}; - -class DCPTime; - -class ContentTime : public Time -{ -public: - ContentTime () : Time () {} - explicit ContentTime (int64_t t) : Time (t) {} - ContentTime (int64_t n, int64_t d) : Time (n * HZ / d) {} - ContentTime (DCPTime d, FrameRateChange f); - - bool operator< (ContentTime const & o) const { + bool operator< (Time const & o) const { return _t < o._t; } - bool operator<= (ContentTime const & o) const { + bool operator<= (Time const & o) const { return _t <= o._t; } - bool operator== (ContentTime const & o) const { + bool operator== (Time const & o) const { return _t == o._t; } - bool operator!= (ContentTime const & o) const { + bool operator!= (Time const & o) const { return _t != o._t; } - bool operator>= (ContentTime const & o) const { + bool operator>= (Time const & o) const { return _t >= o._t; } - bool operator> (ContentTime const & o) const { + bool operator> (Time const & o) const { return _t > o._t; } - ContentTime operator+ (ContentTime const & o) const { - return ContentTime (_t + o._t); + Time operator+ (Time const & o) const { + return Time (_t + o._t); } - ContentTime & operator+= (ContentTime const & o) { + Time & operator+= (Time const & o) { _t += o._t; return *this; } - ContentTime operator- (ContentTime const & o) const { - return ContentTime (_t - o._t); + Time operator- () const { + return Time (-_t); + } + + Time operator- (Time const & o) const { + return Time (_t - o._t); } - ContentTime & operator-= (ContentTime const & o) { + Time & operator-= (Time const & o) { _t -= o._t; return *this; } - static ContentTime from_seconds (double s) { - return ContentTime (s * HZ); + /** Round up to the nearest sampling interval + * at some sampling rate. + * @param r Sampling rate. + */ + Time round_up (float r) { + Type const n = rint (HZ / r); + Type const a = _t + n - 1; + return Time (a - (a % n)); } - template - static ContentTime from_frames (int64_t f, T r) { - return ContentTime (f * HZ / r); + double seconds () const { + return double (_t) / HZ; } -}; -class DCPTime : public Time -{ -public: - DCPTime () : Time () {} - explicit DCPTime (int64_t t) : Time (t) {} - DCPTime (ContentTime t, FrameRateChange c) : Time (rint (t.get() / c.speed_up)) {} - - bool operator< (DCPTime const & o) const { - return _t < o._t; + Time abs () const { + return Time (std::abs (_t)); } - bool operator<= (DCPTime const & o) const { - return _t <= o._t; + template + int64_t frames (T r) const { + return rint (double (_t) * r / HZ); } - bool operator== (DCPTime const & o) const { - return _t == o._t; - } + /** @param r Frames per second */ + template + void split (T r, int& h, int& m, int& s, int& f) const + { + /* Do this calculation with frames so that we can round + to a frame boundary at the start rather than the end. + */ + int64_t ff = frames (r); - bool operator!= (DCPTime const & o) const { - return _t != o._t; - } + h = ff / (3600 * r); + ff -= h * 3600 * r; + m = ff / (60 * r); + ff -= m * 60 * r; + s = ff / r; + ff -= s * r; - bool operator>= (DCPTime const & o) const { - return _t >= o._t; + f = static_cast (ff); } - bool operator> (DCPTime const & o) const { - return _t > o._t; - } + template + std::string timecode (T r) const { + int h; + int m; + int s; + int f; + split (r, h, m, s, f); - DCPTime operator+ (DCPTime const & o) const { - return DCPTime (_t + o._t); + SafeStringStream o; + o.width (2); + o.fill ('0'); + o << std::setw(2) << std::setfill('0') << h << ":" + << std::setw(2) << std::setfill('0') << m << ":" + << std::setw(2) << std::setfill('0') << s << ":" + << std::setw(2) << std::setfill('0') << f; + return o.str (); } - DCPTime & operator+= (DCPTime const & o) { - _t += o._t; - return *this; - } - DCPTime operator- (DCPTime const & o) const { - return DCPTime (_t - o._t); + static Time from_seconds (double s) { + return Time (s * HZ); } - DCPTime & operator-= (DCPTime const & o) { - _t -= o._t; - return *this; + template + static Time from_frames (int64_t f, T r) { + DCPOMATIC_ASSERT (r > 0); + return Time (f * HZ / r); } - /** Round up to the nearest sampling interval - * at some sampling rate. - * @param r Sampling rate. - */ - DCPTime round_up (int r) { - int64_t const n = HZ / r; - int64_t const a = _t + n - 1; - return DCPTime (a - (a % n)); + static Time delta () { + return Time (1); } - DCPTime abs () const { - return DCPTime (std::abs (_t)); + static Time min () { + return Time (-INT64_MAX); } - static DCPTime from_seconds (double s) { - return DCPTime (s * HZ); + static Time max () { + return Time (INT64_MAX); } - template - static DCPTime from_frames (int64_t f, T r) { - return DCPTime (f * HZ / r); - } +private: + friend struct dcptime_round_up_test; - static DCPTime delta () { - return DCPTime (1); - } + Type _t; + static const int HZ = 96000; +}; + +class ContentTimeDifferentiator {}; +class DCPTimeDifferentiator {}; + +/* Specializations for the two allowed explicit conversions */ + +template<> +Time::Time (Time d, FrameRateChange f); - static DCPTime max () { - return DCPTime (INT64_MAX); +template<> +Time::Time (Time d, FrameRateChange f); + +/** Time relative to the start or position of a piece of content in its native frame rate */ +typedef Time ContentTime; +/** Time relative to the start of the output DCP in its frame rate */ +typedef Time DCPTime; + +class ContentTimePeriod +{ +public: + ContentTimePeriod () {} + + ContentTimePeriod (ContentTime f, ContentTime t) + : from (f) + , to (t) + {} + + ContentTime from; + ContentTime to; + + ContentTimePeriod operator+ (ContentTime const & o) const { + return ContentTimePeriod (from + o, to + o); } + + bool overlaps (ContentTimePeriod const & o) const; + bool contains (ContentTime const & o) const; }; DCPTime min (DCPTime a, DCPTime b); +std::ostream& operator<< (std::ostream& s, ContentTime t); +std::ostream& operator<< (std::ostream& s, DCPTime t); #endif