2010-12-21 02:05:13 +01:00
|
|
|
/*
|
|
|
|
|
TIMEVALUE.hpp - basic definitions for time values and time intervals
|
|
|
|
|
|
|
|
|
|
Copyright (C) Lumiera.org
|
|
|
|
|
2010, Hermann Vosseler <Ichthyostega@web.de>
|
|
|
|
|
|
|
|
|
|
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 the Free Software Foundation; either version 2 of
|
|
|
|
|
the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
2013-08-13 01:27:37 +02:00
|
|
|
/** @file timevalue.hpp
|
|
|
|
|
** a family of time value like entities and their relationships.
|
|
|
|
|
** This is the foundation for the Lumiera time handling framework. On the implementation
|
2022-10-30 01:31:25 +02:00
|
|
|
** level, time values are represented as 64bit integer values `gavl_time_t`. But for the
|
2013-08-13 01:27:37 +02:00
|
|
|
** actual use, we create several kinds of time "values", based on their logical properties.
|
|
|
|
|
** These time values are considered to be fixed (immutable) values, which may only be
|
2022-10-30 01:31:25 +02:00
|
|
|
** created through some limited construction paths, and any time based calculation
|
2013-08-13 01:27:37 +02:00
|
|
|
** is forced to go through our time calculation library. This is prerequisite for
|
2022-10-30 01:31:25 +02:00
|
|
|
** the definition of _frame aligned_ time values and time code representation
|
2013-08-13 01:27:37 +02:00
|
|
|
** implemented as display format based on these frame quantised time values.
|
|
|
|
|
**
|
2022-10-30 01:31:25 +02:00
|
|
|
** # Time entities
|
|
|
|
|
**
|
|
|
|
|
** The value types defined in this header represent time points and time intervals
|
|
|
|
|
** based on an internal time scale (µs ticks) and not related to any known fixed time
|
2022-10-30 23:12:34 +01:00
|
|
|
** zone or time base; rather they are interpreted in usage context, and the intended
|
|
|
|
|
** way to retrieve such a value is by formatting it into a time code format.
|
2022-10-30 01:31:25 +02:00
|
|
|
**
|
|
|
|
|
** The lib::time::TimeValue serves as foundation for all further time calculations;
|
|
|
|
|
** in fact it is implemented as a single 64bit µ-tick value (`gavl_time_t`). The
|
|
|
|
|
** further time entities are implemented as value objects (without virtual functions):
|
|
|
|
|
** - lib::time::Time represents a time instant and is the reference for any usage
|
|
|
|
|
** - lib::time::TimeVar is a mutable time variable and can be used for calculations
|
|
|
|
|
** - lib::time::Offset can be used to express a positive or negative shift on time scale
|
|
|
|
|
** - lib::time::Duration represents the extension or an amount of time
|
|
|
|
|
** - lib::time::TimeSpan represents a distinct interval, with start time and duration
|
|
|
|
|
** - lib::time::FrameRate can be used to mark a number to denote a frames-per-second spec
|
|
|
|
|
** - lib::time::FSecs is a rational number to represent seconds or fractions thereof
|
|
|
|
|
**
|
|
|
|
|
** # Manipulating time values
|
|
|
|
|
**
|
|
|
|
|
** Time values are conceived as fixed, immutable entities, similar to numbers; you can't
|
|
|
|
|
** just change the number two, and likewise, two seconds are two seconds. However, for
|
|
|
|
|
** many use cases we have to combine time values to perform calculations
|
|
|
|
|
** - Time entities can be combined with operators, to form new time entities
|
|
|
|
|
** - the TimeVar can be used as accumulator or variable for ongoing calculations
|
|
|
|
|
** - since TimeSpan, Duration (and the grid-aligned, "quantised" flavours) will often
|
|
|
|
|
** represent some time-like property or entity, e.g. the temporal specification of
|
|
|
|
|
** a media Clip with start and duration, there is the concept of an explicit *mutation*,
|
|
|
|
|
** which is _accepted_ by these entities. Notably the lib::time::Control can be attached
|
|
|
|
|
** to these entities, and can then receive manipulations (nudging, offset); moreover it
|
|
|
|
|
** is possible to attach as listener to such a "controller" and be notified by any
|
|
|
|
|
** manipulation; this setup is the base for running time display, playback cursors etc.
|
|
|
|
|
**
|
2022-10-30 23:12:34 +01:00
|
|
|
** # Quantised time
|
|
|
|
|
**
|
|
|
|
|
** While these _internal time values_ can be considered _sufficiently precise,_ in practice
|
|
|
|
|
** any time specifications in the context of media handling will be aligned to some grid,
|
|
|
|
|
** and expressed in a _time code format._ Typically, we want to know the number of frames
|
|
|
|
|
** since playback started at the beginning of the timeline, and such a specification also
|
|
|
|
|
** relies on some implicitly known _frame rate_ (24fps for film in US, 25fps for film and
|
|
|
|
|
** TV in Europe, ...). By _deliberate choice,_ in Lumiera we *do not incorporate* such
|
|
|
|
|
** implicit assumptions into the actual time values. Rather, they need to be made explicitly
|
|
|
|
|
** in the relevant usage context. This is also the reason why the time entities defined in
|
|
|
|
|
** this header _do not offer an API_ to get the "real" time (whatever this means). Rather,
|
|
|
|
|
** the user of these time entities should get used to the concept that these abstract
|
|
|
|
|
** opaque values are the real thing, and a concrete, human readable time code is only
|
|
|
|
|
** a derivation, and any such derivation also incurs information loss. To reiterate that,
|
|
|
|
|
** _any time quantisation is a lossy information;_ grid aligned values are not "cleaner",
|
|
|
|
|
** they are just easier to handle for humans.
|
|
|
|
|
**
|
|
|
|
|
** \par how can I extract a time value?
|
|
|
|
|
** Taking the aforementioned into account, it depends on the context what to expect and to get
|
|
|
|
|
** - the standard path is to create a lib::time::QuTime by associating the internal time value
|
|
|
|
|
** with a pre-defined _time grid._ From there you can call QuTime::formatAs() to build an
|
|
|
|
|
** actual timecode instance, which can then be investigated or just printed.
|
|
|
|
|
** - for debugging purpose, lib::time::Time defines an `operator string()`, which breaks down
|
|
|
|
|
** the internal values into the format `-hh:mm:ss.mss`
|
|
|
|
|
** - advanced calculations with the need to access the implementation data in full precision
|
|
|
|
|
** should go through lib::time::TimeVar, which offers conversions to raw `int64_t` and the
|
|
|
|
|
** even more fine grained `FSec`, which is a rational (fraction) `boost::rational<int64_t>`
|
|
|
|
|
**
|
2013-08-13 01:27:37 +02:00
|
|
|
** @see time.h basic time calculation library functions
|
|
|
|
|
** @see timequant.hpp
|
|
|
|
|
** @see TimeValue_test
|
|
|
|
|
**
|
|
|
|
|
*/
|
|
|
|
|
|
2010-12-21 02:05:13 +01:00
|
|
|
|
|
|
|
|
#ifndef LIB_TIME_TIMEVALUE_H
|
|
|
|
|
#define LIB_TIME_TIMEVALUE_H
|
|
|
|
|
|
2011-01-09 04:56:46 +01:00
|
|
|
#include "lib/error.hpp"
|
|
|
|
|
|
2010-12-22 04:49:57 +01:00
|
|
|
#include <boost/operators.hpp>
|
2010-12-31 05:59:53 +01:00
|
|
|
#include <boost/rational.hpp>
|
2010-12-28 05:22:20 +01:00
|
|
|
#include <cstdlib>
|
2010-12-21 02:05:13 +01:00
|
|
|
#include <string>
|
|
|
|
|
|
2010-12-22 04:49:57 +01:00
|
|
|
extern "C" {
|
|
|
|
|
#include <stdint.h>
|
|
|
|
|
#include <gavl/gavltime.h>
|
|
|
|
|
}
|
|
|
|
|
|
2010-12-21 02:05:13 +01:00
|
|
|
|
|
|
|
|
namespace lib {
|
|
|
|
|
namespace time {
|
|
|
|
|
|
2011-01-09 04:56:46 +01:00
|
|
|
namespace error = lumiera::error;
|
|
|
|
|
|
2011-06-11 20:20:20 +02:00
|
|
|
// forwards...
|
|
|
|
|
class FrameRate;
|
|
|
|
|
class TimeSpan;
|
|
|
|
|
class Mutation;
|
|
|
|
|
|
2010-12-21 02:05:13 +01:00
|
|
|
|
|
|
|
|
/**
|
2010-12-27 06:58:27 +01:00
|
|
|
* basic constant internal time value.
|
|
|
|
|
* These time values provide the implementation base
|
|
|
|
|
* for all further time types. They can be created by
|
|
|
|
|
* wrapping up a raw micro tick value (gavl_time_t),
|
|
|
|
|
* are totally ordered, but besides that,
|
|
|
|
|
* they are opaque and non-mutable.
|
|
|
|
|
* @note clients should prefer to use Time instances,
|
|
|
|
|
* which explicitly denote an Lumiera internal
|
|
|
|
|
* time value and are easier to use.
|
2022-10-30 01:31:25 +02:00
|
|
|
* @see TimeVar when full arithmetics are required
|
2010-12-21 02:05:13 +01:00
|
|
|
*/
|
|
|
|
|
class TimeValue
|
2010-12-27 02:04:34 +01:00
|
|
|
: boost::totally_ordered<TimeValue,
|
2016-12-23 04:23:03 +01:00
|
|
|
boost::totally_ordered<TimeValue, gavl_time_t>>
|
2010-12-22 04:49:57 +01:00
|
|
|
{
|
2010-12-26 23:00:34 +01:00
|
|
|
protected:
|
2010-12-27 05:55:15 +01:00
|
|
|
/** the raw (internal) time value
|
|
|
|
|
* used to implement the time types */
|
2010-12-22 04:49:57 +01:00
|
|
|
gavl_time_t t_;
|
|
|
|
|
|
|
|
|
|
|
2010-12-27 05:55:15 +01:00
|
|
|
/** Assigning of time values is not allowed,
|
|
|
|
|
* but derived classed might allow that */
|
|
|
|
|
TimeValue&
|
|
|
|
|
operator= (TimeValue const& o)
|
|
|
|
|
{
|
|
|
|
|
t_ = o.t_;
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-04 02:43:01 +02:00
|
|
|
/** some subclasses may receive modification messages */
|
|
|
|
|
friend class Mutation;
|
|
|
|
|
|
2010-12-27 05:55:15 +01:00
|
|
|
public:
|
2022-10-17 04:19:26 +02:00
|
|
|
/** Number of micro ticks (µs) per second as basic time scale */
|
2018-11-17 18:00:39 +01:00
|
|
|
static const gavl_time_t SCALE;
|
|
|
|
|
|
2011-01-08 20:01:26 +01:00
|
|
|
/** explicit limit of allowed time range */
|
|
|
|
|
static gavl_time_t limited (gavl_time_t raw);
|
|
|
|
|
|
|
|
|
|
|
2022-10-30 01:31:25 +02:00
|
|
|
explicit
|
2018-11-17 18:00:39 +01:00
|
|
|
TimeValue (gavl_time_t val=0) ///< time given in µ ticks here
|
2011-01-08 20:01:26 +01:00
|
|
|
: t_(limited (val))
|
2010-12-22 04:49:57 +01:00
|
|
|
{ }
|
|
|
|
|
|
2010-12-27 05:55:15 +01:00
|
|
|
/** copy initialisation allowed */
|
|
|
|
|
TimeValue (TimeValue const& o)
|
|
|
|
|
: t_(o.t_)
|
|
|
|
|
{ }
|
2010-12-22 04:49:57 +01:00
|
|
|
|
2011-01-06 13:31:13 +01:00
|
|
|
/** @internal to pass Time values to C functions */
|
|
|
|
|
friend gavl_time_t _raw (TimeValue const& time) { return time.t_; }
|
2011-01-08 20:01:26 +01:00
|
|
|
static TimeValue buildRaw_(gavl_time_t);
|
2011-01-06 13:31:13 +01:00
|
|
|
|
2015-09-25 02:03:12 +02:00
|
|
|
/** @internal diagnostics */
|
|
|
|
|
operator std::string () const;
|
|
|
|
|
|
2010-12-22 04:49:57 +01:00
|
|
|
// Supporting totally_ordered
|
2010-12-26 23:00:34 +01:00
|
|
|
friend bool operator< (TimeValue const& t1, TimeValue const& t2) { return t1.t_ < t2.t_; }
|
|
|
|
|
friend bool operator< (TimeValue const& t1, gavl_time_t t2) { return t1.t_ < t2 ; }
|
|
|
|
|
friend bool operator> (TimeValue const& t1, gavl_time_t t2) { return t1.t_ > t2 ; }
|
|
|
|
|
friend bool operator== (TimeValue const& t1, TimeValue const& t2) { return t1.t_ == t2.t_; }
|
|
|
|
|
friend bool operator== (TimeValue const& t1, gavl_time_t t2) { return t1.t_ == t2 ; }
|
2010-12-22 04:49:57 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2010-12-27 05:55:15 +01:00
|
|
|
|
2022-10-30 01:31:25 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* ======= specific Time entities ==================== */
|
|
|
|
|
|
|
|
|
|
/** relative framecount or frame number.
|
|
|
|
|
* Used within the engine at places where the underlying
|
|
|
|
|
* grid and origin is obvious from the call context.
|
|
|
|
|
* @warning do not mix up gavl_time_t and FrameCnt.
|
|
|
|
|
* @warning use 64bit consistently.
|
2022-10-30 23:12:34 +01:00
|
|
|
* beware: `long` is 32bit on i386
|
2022-10-30 01:31:25 +02:00
|
|
|
* @note any conversion to frame numbers should go through
|
|
|
|
|
* time quantisation followed by conversion to FrameNr
|
|
|
|
|
*/
|
2022-10-30 23:12:34 +01:00
|
|
|
using FrameCnt = int64_t;
|
2022-10-30 01:31:25 +02:00
|
|
|
|
|
|
|
|
/** rational representation of fractional seconds
|
|
|
|
|
* @warning do not mix up gavl_time_t and FSecs */
|
2022-10-30 23:12:34 +01:00
|
|
|
using FSecs = boost::rational<int64_t>;
|
2022-10-30 01:31:25 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2010-12-27 05:55:15 +01:00
|
|
|
/** a mutable time value,
|
2010-12-27 06:58:27 +01:00
|
|
|
* behaving like a plain number,
|
|
|
|
|
* allowing copy and re-accessing
|
2010-12-28 07:24:54 +01:00
|
|
|
* @note supports scaling by a factor,
|
2022-10-30 01:31:25 +02:00
|
|
|
* which _deliberately_ is chosen
|
2010-12-28 07:24:54 +01:00
|
|
|
* as int, not gavl_time_t, because the
|
2011-01-27 14:35:46 +01:00
|
|
|
* multiplying of times is meaningless.
|
2010-12-27 05:55:15 +01:00
|
|
|
*/
|
2010-12-22 04:49:57 +01:00
|
|
|
class TimeVar
|
|
|
|
|
: public TimeValue
|
2010-12-27 06:58:27 +01:00
|
|
|
, boost::additive<TimeVar,
|
|
|
|
|
boost::additive<TimeVar, TimeValue,
|
|
|
|
|
boost::multipliable<TimeVar, int>
|
|
|
|
|
> >
|
2010-12-22 04:49:57 +01:00
|
|
|
{
|
|
|
|
|
public:
|
2011-01-05 18:15:44 +01:00
|
|
|
TimeVar (TimeValue const& time = TimeValue())
|
2010-12-22 04:49:57 +01:00
|
|
|
: TimeValue(time)
|
|
|
|
|
{ }
|
|
|
|
|
|
2022-10-30 01:31:25 +02:00
|
|
|
/** Allow to pick up precise fractional seconds
|
|
|
|
|
* @warning truncating fractional µ-ticks */
|
|
|
|
|
TimeVar (FSecs const&);
|
|
|
|
|
|
|
|
|
|
/// Allowing copy and assignment
|
2010-12-27 05:55:15 +01:00
|
|
|
TimeVar (TimeVar const& o)
|
|
|
|
|
: TimeValue(o)
|
|
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
TimeVar&
|
|
|
|
|
operator= (TimeValue const& o)
|
|
|
|
|
{
|
|
|
|
|
t_ = TimeVar(o);
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-30 01:31:25 +02:00
|
|
|
/// Support mixing with plain long int arithmetics
|
|
|
|
|
operator gavl_time_t() const { return t_; }
|
|
|
|
|
/// Support for micro-tick precise time arithmetics
|
|
|
|
|
operator FSecs() const { return FSecs{t_, TimeValue::SCALE}; }
|
2010-12-22 04:49:57 +01:00
|
|
|
|
2022-10-30 01:31:25 +02:00
|
|
|
/// Supporting additive
|
2010-12-22 04:49:57 +01:00
|
|
|
TimeVar& operator+= (TimeVar const& tx) { t_ += tx.t_; return *this; }
|
|
|
|
|
TimeVar& operator-= (TimeVar const& tx) { t_ -= tx.t_; return *this; }
|
|
|
|
|
|
2022-10-30 01:31:25 +02:00
|
|
|
/// Supporting multiplication with integral factor
|
2012-04-24 05:06:05 +02:00
|
|
|
TimeVar& operator*= (int64_t fact) { t_ *= fact; return *this; }
|
2011-01-08 19:11:42 +01:00
|
|
|
|
2022-10-30 01:31:25 +02:00
|
|
|
/// Supporting sign flip
|
2011-01-08 19:11:42 +01:00
|
|
|
TimeVar operator- () const { return TimeVar(*this)*=-1; }
|
2010-12-22 04:49:57 +01:00
|
|
|
|
2022-10-30 01:31:25 +02:00
|
|
|
// baseclass TimeValue is already totally_ordered
|
2010-12-22 04:49:57 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2010-12-28 05:22:20 +01:00
|
|
|
|
2013-11-18 00:01:43 +01:00
|
|
|
|
2022-10-30 01:31:25 +02:00
|
|
|
/**********************************************************//**
|
2013-11-18 00:01:43 +01:00
|
|
|
* Lumiera's internal time value datatype.
|
|
|
|
|
* This is a TimeValue, but now more specifically denoting
|
|
|
|
|
* a point in time, measured in reference to an internal
|
|
|
|
|
* (opaque) time scale.
|
|
|
|
|
*
|
|
|
|
|
* Lumiera Time provides some limited capabilities for
|
|
|
|
|
* direct manipulation; Time values can be created directly
|
2022-10-30 01:31:25 +02:00
|
|
|
* from `(ms,sec,min,hour)` specification and there is an
|
2013-11-18 00:01:43 +01:00
|
|
|
* string representation intended for internal use (reporting
|
|
|
|
|
* and debugging). Any real output, formatting and persistent
|
|
|
|
|
* storage should be based on the (quantised) timecode
|
|
|
|
|
* formats though, which can be generated from time values.
|
|
|
|
|
*
|
|
|
|
|
* Similar to TimeValue, also Time objects are considered
|
|
|
|
|
* immutable values. As convenience shortcut, some operators
|
|
|
|
|
* are provided, creating a TimVar for further calculations.
|
|
|
|
|
*/
|
|
|
|
|
class Time
|
|
|
|
|
: public TimeValue
|
|
|
|
|
{
|
|
|
|
|
/// direct assignment prohibited
|
|
|
|
|
Time& operator= (Time const);
|
|
|
|
|
|
|
|
|
|
/// suppress possible direct conversions
|
|
|
|
|
Time(int);
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
static const Time MAX ;
|
|
|
|
|
static const Time MIN ;
|
|
|
|
|
static const Time ZERO;
|
|
|
|
|
|
|
|
|
|
static const Time ANYTIME; ///< border condition marker value. #ANYTIME <= any time value
|
|
|
|
|
static const Time NEVER; ///< border condition marker value. #NEVER >= any time value
|
|
|
|
|
|
|
|
|
|
explicit
|
|
|
|
|
Time (TimeValue const& val =TimeValue(0))
|
|
|
|
|
: TimeValue(val)
|
|
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
Time (TimeVar const& calcResult)
|
|
|
|
|
: TimeValue(calcResult)
|
|
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
explicit
|
|
|
|
|
Time (FSecs const& fractionalSeconds);
|
|
|
|
|
|
|
|
|
|
Time ( long millis
|
|
|
|
|
, uint secs
|
|
|
|
|
, uint mins =0
|
|
|
|
|
, uint hours=0
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
/** @internal diagnostics */
|
|
|
|
|
operator std::string () const;
|
|
|
|
|
|
|
|
|
|
/** convenience start for time calculations */
|
|
|
|
|
TimeVar operator+ (TimeValue const& tval) const { return TimeVar(*this) + tval; }
|
|
|
|
|
TimeVar operator- (TimeValue const& tval) const { return TimeVar(*this) - tval; }
|
|
|
|
|
TimeVar operator- () const { return -TimeVar(*this); }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2010-12-28 05:22:20 +01:00
|
|
|
/**
|
|
|
|
|
* Offset measures a distance in time.
|
|
|
|
|
* It may be used to relate two points in time,
|
|
|
|
|
* or to create a modification for time-like entities.
|
|
|
|
|
* Similar to (basic) time values, offsets can be compared,
|
2010-12-28 07:24:54 +01:00
|
|
|
* but are otherwise opaque and immutable. Yet they allow
|
|
|
|
|
* to build derived values, including
|
2022-10-30 23:12:34 +01:00
|
|
|
* - the _absolute (positive) distance_ for this offset: #abs
|
2010-12-28 07:24:54 +01:00
|
|
|
* - a combined offset by chaining another offset
|
2010-12-28 05:22:20 +01:00
|
|
|
*/
|
|
|
|
|
class Offset
|
|
|
|
|
: public TimeValue
|
|
|
|
|
{
|
2011-01-22 23:20:12 +01:00
|
|
|
protected:
|
2011-01-27 14:35:46 +01:00
|
|
|
/** generally immutable,
|
|
|
|
|
* but derived classes allow some limited mutation
|
|
|
|
|
* through special API calls */
|
2011-01-22 23:20:12 +01:00
|
|
|
Offset&
|
2022-10-30 01:31:25 +02:00
|
|
|
operator= (Offset const& o)
|
2011-01-22 23:20:12 +01:00
|
|
|
{
|
|
|
|
|
TimeValue::operator= (o);
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
2018-04-28 03:02:02 +02:00
|
|
|
|
2010-12-28 05:22:20 +01:00
|
|
|
public:
|
2022-10-30 01:31:25 +02:00
|
|
|
explicit
|
2017-01-11 04:09:32 +01:00
|
|
|
Offset (TimeValue const& distance =Time::ZERO)
|
2010-12-28 05:22:20 +01:00
|
|
|
: TimeValue(distance)
|
|
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
Offset (TimeValue const& origin, TimeValue const& target)
|
|
|
|
|
: TimeValue(TimeVar(target) -= origin)
|
|
|
|
|
{ }
|
|
|
|
|
|
2013-11-18 00:01:43 +01:00
|
|
|
Offset (FrameCnt count, FrameRate const& fps);
|
2011-06-11 20:20:20 +02:00
|
|
|
|
2011-06-04 17:16:29 +02:00
|
|
|
static const Offset ZERO;
|
|
|
|
|
|
2011-06-11 20:20:20 +02:00
|
|
|
|
2010-12-28 05:22:20 +01:00
|
|
|
TimeValue
|
|
|
|
|
abs() const
|
|
|
|
|
{
|
|
|
|
|
return TimeValue(std::llabs (t_));
|
|
|
|
|
}
|
2011-04-25 18:51:50 +02:00
|
|
|
|
2018-04-28 03:02:02 +02:00
|
|
|
/** @internal stretch offset by a possibly fractional factor,
|
|
|
|
|
* and quantise into raw (micro tick) grid */
|
|
|
|
|
Offset stretchedByRationalFactor (boost::rational<int64_t>) const;
|
|
|
|
|
|
2016-01-08 00:13:59 +01:00
|
|
|
/** @internal diagnostics, indicating ∆ */
|
|
|
|
|
operator std::string () const;
|
|
|
|
|
|
2011-04-25 18:51:50 +02:00
|
|
|
// Supporting sign flip
|
|
|
|
|
Offset operator- () const;
|
2010-12-28 05:22:20 +01:00
|
|
|
};
|
|
|
|
|
|
2011-01-15 01:45:55 +01:00
|
|
|
//-- support linear offset chaining ---------------
|
|
|
|
|
|
|
|
|
|
inline Offset
|
|
|
|
|
operator+ (Offset const& start, Offset const& toChain)
|
|
|
|
|
{
|
|
|
|
|
TimeVar distance(start);
|
|
|
|
|
distance += toChain;
|
|
|
|
|
return Offset(distance);
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-17 00:49:58 +01:00
|
|
|
template<typename INT>
|
|
|
|
|
inline Offset
|
|
|
|
|
operator* (Offset const& distance, INT factor)
|
|
|
|
|
{
|
|
|
|
|
return factor*distance;
|
|
|
|
|
}
|
|
|
|
|
|
2012-04-24 05:06:05 +02:00
|
|
|
template<typename INT>
|
2011-01-15 01:45:55 +01:00
|
|
|
inline Offset
|
2012-04-24 05:06:05 +02:00
|
|
|
operator* (INT factor, Offset const& o)
|
2011-01-15 01:45:55 +01:00
|
|
|
{
|
|
|
|
|
TimeVar distance(o);
|
|
|
|
|
distance *= factor;
|
|
|
|
|
return Offset(distance);
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-25 01:56:16 +01:00
|
|
|
template<typename INTX>
|
|
|
|
|
inline Offset
|
2018-04-28 03:02:02 +02:00
|
|
|
operator* (boost::rational<INTX> factor, Offset const& offset)
|
2012-03-25 01:56:16 +01:00
|
|
|
{
|
2018-04-28 03:02:02 +02:00
|
|
|
return offset.stretchedByRationalFactor (boost::rational<int64_t>(factor.numerator(), factor.denominator()));
|
2012-03-25 01:56:16 +01:00
|
|
|
}
|
|
|
|
|
|
2011-01-15 01:45:55 +01:00
|
|
|
|
2012-03-17 00:49:58 +01:00
|
|
|
/** flip offset direction */
|
2011-04-25 18:51:50 +02:00
|
|
|
inline Offset
|
|
|
|
|
Offset::operator- () const
|
|
|
|
|
{
|
2022-10-30 01:31:25 +02:00
|
|
|
return -1 * (*this);
|
2011-04-25 18:51:50 +02:00
|
|
|
}
|
2010-12-28 05:22:20 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2011-01-09 09:49:48 +01:00
|
|
|
|
2010-12-28 05:22:20 +01:00
|
|
|
/**
|
|
|
|
|
* Duration is the internal Lumiera time metric.
|
|
|
|
|
* It is an absolute (positive) value, but can be
|
2011-04-04 02:07:09 +02:00
|
|
|
* promoted from an offset. While Duration generally
|
2022-10-30 01:31:25 +02:00
|
|
|
* is treated as immutable value, there is the
|
|
|
|
|
* possibility to send a _Mutation message_.
|
2010-12-28 05:22:20 +01:00
|
|
|
*/
|
|
|
|
|
class Duration
|
2011-06-08 02:12:38 +02:00
|
|
|
: public TimeValue
|
2010-12-22 04:49:57 +01:00
|
|
|
{
|
2011-01-22 23:20:12 +01:00
|
|
|
/// direct assignment prohibited
|
|
|
|
|
Duration& operator= (Duration const&);
|
|
|
|
|
|
2010-12-21 02:05:13 +01:00
|
|
|
public:
|
2016-02-07 02:59:03 +01:00
|
|
|
Duration()
|
|
|
|
|
: Duration(Time::ZERO)
|
|
|
|
|
{ }
|
|
|
|
|
|
2010-12-28 05:22:20 +01:00
|
|
|
Duration (Offset const& distance)
|
2011-06-08 02:12:38 +02:00
|
|
|
: TimeValue(distance.abs())
|
2010-12-22 04:49:57 +01:00
|
|
|
{ }
|
2011-01-09 04:56:46 +01:00
|
|
|
|
2011-01-09 09:49:48 +01:00
|
|
|
explicit
|
2011-04-04 00:41:38 +02:00
|
|
|
Duration (TimeValue const& timeSpec)
|
2011-06-08 02:12:38 +02:00
|
|
|
: TimeValue(Offset(timeSpec).abs())
|
2011-01-09 09:49:48 +01:00
|
|
|
{ }
|
|
|
|
|
|
2011-03-31 18:43:50 +02:00
|
|
|
explicit
|
|
|
|
|
Duration (FSecs const& timeSpan_in_secs)
|
2011-06-08 02:12:38 +02:00
|
|
|
: TimeValue(Offset(Time(timeSpan_in_secs)).abs())
|
2011-03-31 18:43:50 +02:00
|
|
|
{ }
|
|
|
|
|
|
2011-01-09 09:49:48 +01:00
|
|
|
Duration (TimeSpan const& interval);
|
2013-11-18 00:01:43 +01:00
|
|
|
Duration (FrameCnt count, FrameRate const& fps);
|
2011-01-09 04:56:46 +01:00
|
|
|
|
2022-11-18 02:55:28 +01:00
|
|
|
Duration (Duration const& o)
|
|
|
|
|
: Duration{Offset(o)}
|
|
|
|
|
{ }
|
|
|
|
|
|
2011-01-09 04:56:46 +01:00
|
|
|
static const Duration NIL;
|
2011-04-04 02:07:09 +02:00
|
|
|
|
|
|
|
|
void accept (Mutation const&);
|
2011-06-08 02:12:38 +02:00
|
|
|
|
2016-01-08 00:13:59 +01:00
|
|
|
|
|
|
|
|
/** @internal diagnostics */
|
|
|
|
|
operator std::string () const;
|
|
|
|
|
|
2011-06-08 02:12:38 +02:00
|
|
|
/// Supporting backwards use as offset
|
|
|
|
|
Offset operator- () const;
|
|
|
|
|
|
2010-12-22 04:49:57 +01:00
|
|
|
};
|
2011-06-08 02:12:38 +02:00
|
|
|
|
|
|
|
|
//-- support using a Duration to build offsets ---------------
|
|
|
|
|
|
|
|
|
|
inline Duration
|
|
|
|
|
operator+ (Duration const& base, Duration const& toAdd)
|
|
|
|
|
{
|
|
|
|
|
return Offset(base) + Offset(toAdd);
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-17 00:49:58 +01:00
|
|
|
template<typename INT>
|
2011-06-08 02:12:38 +02:00
|
|
|
inline Offset
|
2012-03-17 00:49:58 +01:00
|
|
|
operator* (INT factor, Duration const& dur)
|
2011-06-08 02:12:38 +02:00
|
|
|
{
|
|
|
|
|
return factor * Offset(dur);
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-17 00:49:58 +01:00
|
|
|
template<typename INT>
|
2011-06-08 02:12:38 +02:00
|
|
|
inline Offset
|
2012-03-17 00:49:58 +01:00
|
|
|
operator* (Duration const& dur, INT factor)
|
2011-06-08 02:12:38 +02:00
|
|
|
{
|
|
|
|
|
return factor*dur;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline Offset
|
|
|
|
|
Duration::operator- () const
|
|
|
|
|
{
|
2022-10-30 01:31:25 +02:00
|
|
|
return -1 * (*this);
|
2011-06-08 02:12:38 +02:00
|
|
|
}
|
2010-12-27 06:58:27 +01:00
|
|
|
|
2010-12-21 02:05:13 +01:00
|
|
|
|
|
|
|
|
|
2010-12-28 05:22:20 +01:00
|
|
|
/**
|
|
|
|
|
* A time interval anchored at a specific point in time.
|
|
|
|
|
* The start point of this timespan is also its nominal
|
|
|
|
|
* position, and the end point is normalised to happen
|
|
|
|
|
* never before the start point. A TimeSpan is enough
|
|
|
|
|
* to fully specify the temporal properties of an
|
|
|
|
|
* object within the model.
|
|
|
|
|
*
|
2011-04-02 04:01:06 +02:00
|
|
|
* As an exception to the generally immutable Time
|
|
|
|
|
* entities, a non constant TimeSpan may receive
|
2022-10-30 23:12:34 +01:00
|
|
|
* _mutation messages_, both for the start point
|
2011-04-02 04:01:06 +02:00
|
|
|
* and the duration. This allows for changing
|
|
|
|
|
* position and length of objects in the timeline.
|
|
|
|
|
*
|
|
|
|
|
* @todo define these mutations
|
2010-12-28 05:22:20 +01:00
|
|
|
*/
|
2010-12-22 04:49:57 +01:00
|
|
|
class TimeSpan
|
|
|
|
|
: public Time
|
2011-04-04 00:41:38 +02:00
|
|
|
, boost::totally_ordered<TimeSpan>
|
2010-12-22 04:49:57 +01:00
|
|
|
{
|
|
|
|
|
Duration dur_;
|
|
|
|
|
|
|
|
|
|
public:
|
2011-04-04 00:41:38 +02:00
|
|
|
TimeSpan(TimeValue const& start, Duration const& length)
|
2010-12-22 04:49:57 +01:00
|
|
|
: Time(start)
|
|
|
|
|
, dur_(length)
|
|
|
|
|
{ }
|
2011-04-02 04:01:06 +02:00
|
|
|
|
2011-04-04 00:41:38 +02:00
|
|
|
TimeSpan(TimeValue const& start, Offset const& reference_distance)
|
|
|
|
|
: Time(start)
|
|
|
|
|
, dur_(reference_distance)
|
|
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
TimeSpan(TimeValue const& start, TimeValue const& end)
|
|
|
|
|
: Time(start)
|
|
|
|
|
, dur_(Offset(start,end))
|
|
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
TimeSpan(TimeValue const& start, FSecs(duration_in_secs))
|
2011-04-02 04:01:06 +02:00
|
|
|
: Time(start)
|
|
|
|
|
, dur_(duration_in_secs)
|
|
|
|
|
{ }
|
|
|
|
|
|
2016-02-06 19:23:16 +01:00
|
|
|
TimeSpan()
|
|
|
|
|
: TimeSpan(Time::ZERO, Time::ZERO)
|
|
|
|
|
{ }
|
|
|
|
|
|
2010-12-28 05:22:20 +01:00
|
|
|
|
2011-04-25 05:42:05 +02:00
|
|
|
Duration&
|
2022-10-30 01:31:25 +02:00
|
|
|
duration()
|
2011-04-25 05:42:05 +02:00
|
|
|
{
|
|
|
|
|
return dur_;
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-09 09:49:48 +01:00
|
|
|
Duration
|
2022-10-30 01:31:25 +02:00
|
|
|
duration() const
|
2010-12-28 05:22:20 +01:00
|
|
|
{
|
|
|
|
|
return dur_;
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-02 04:01:06 +02:00
|
|
|
Time
|
|
|
|
|
start() const
|
|
|
|
|
{
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
2010-12-28 05:22:20 +01:00
|
|
|
Time
|
2011-01-09 09:49:48 +01:00
|
|
|
end() const
|
2010-12-28 05:22:20 +01:00
|
|
|
{
|
2011-05-16 04:02:26 +02:00
|
|
|
return TimeVar(*this) += dur_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
contains (TimeValue const& tp) const
|
|
|
|
|
{
|
|
|
|
|
return *this <= tp
|
|
|
|
|
&& tp < end();
|
2010-12-28 05:22:20 +01:00
|
|
|
}
|
2011-04-04 00:41:38 +02:00
|
|
|
|
2011-04-04 02:07:09 +02:00
|
|
|
/** may change start / duration */
|
|
|
|
|
void accept (Mutation const&);
|
|
|
|
|
|
2015-09-25 02:03:12 +02:00
|
|
|
/** @internal diagnostics */
|
|
|
|
|
operator std::string () const;
|
2011-04-04 02:07:09 +02:00
|
|
|
|
2011-04-04 00:41:38 +02:00
|
|
|
/// Supporting extended total order, based on start and interval length
|
|
|
|
|
friend bool operator== (TimeSpan const& t1, TimeSpan const& t2) { return t1.t_==t2.t_ && t1.dur_==t2.dur_; }
|
|
|
|
|
friend bool operator< (TimeSpan const& t1, TimeSpan const& t2) { return t1.t_< t2.t_ ||
|
|
|
|
|
(t1.t_==t2.t_ && t1.dur_< t2.dur_);}
|
2010-12-22 04:49:57 +01:00
|
|
|
};
|
|
|
|
|
|
2010-12-21 02:05:13 +01:00
|
|
|
|
2011-01-09 04:56:46 +01:00
|
|
|
/**
|
|
|
|
|
* Framerate specified as frames per second.
|
|
|
|
|
* Implemented as rational number.
|
|
|
|
|
*/
|
|
|
|
|
class FrameRate
|
|
|
|
|
: public boost::rational<uint>
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
FrameRate (uint fps) ;
|
|
|
|
|
FrameRate (uint num, uint denom);
|
Timehandling: choose safer representation for fractional seconds (closes #939)
When drafting the time handling framework some years ago,
I foresaw the possible danger of mixing up numbers relating
to fractional seconds, with other plain numbers intended as
frame counts or as micro ticks. Thus I deliberately picked
an incompatible integer type for FSecs = boost::rational<long>
However, using long is problematic in itself, since its actual
bit length is not fixed, and especially on 32bit platforms long
is quite surprisingly defined to be the same as int.
However, meanwhile, using the new C++ features, I have blocked
pretty much any possible implicit conversion path, requiring
explicit conversions in the relevant ctor invocations. So,
after weighting in the alternatives, FSecs is now defined
as boost::rational<int64_t>.
2020-02-17 02:36:54 +01:00
|
|
|
FrameRate (boost::rational<uint> const& fractionalRate);
|
2011-01-09 04:56:46 +01:00
|
|
|
|
|
|
|
|
// standard copy acceptable;
|
|
|
|
|
|
2011-01-09 05:51:26 +01:00
|
|
|
double asDouble() const;
|
|
|
|
|
|
2011-01-09 04:56:46 +01:00
|
|
|
static const FrameRate PAL;
|
|
|
|
|
static const FrameRate NTSC;
|
|
|
|
|
|
2013-06-15 04:02:48 +02:00
|
|
|
static const FrameRate HALTED;
|
|
|
|
|
|
2011-01-09 04:56:46 +01:00
|
|
|
/** duration of one frame */
|
|
|
|
|
Duration duration() const;
|
2013-09-01 17:36:05 +02:00
|
|
|
|
|
|
|
|
operator std::string() const;
|
2011-01-09 04:56:46 +01:00
|
|
|
};
|
|
|
|
|
|
2019-06-22 21:26:18 +02:00
|
|
|
/** convenient conversion to duration in fractional seconds */
|
|
|
|
|
inline FSecs
|
|
|
|
|
operator/ (int n, FrameRate rate)
|
|
|
|
|
{
|
Timehandling: choose safer representation for fractional seconds (closes #939)
When drafting the time handling framework some years ago,
I foresaw the possible danger of mixing up numbers relating
to fractional seconds, with other plain numbers intended as
frame counts or as micro ticks. Thus I deliberately picked
an incompatible integer type for FSecs = boost::rational<long>
However, using long is problematic in itself, since its actual
bit length is not fixed, and especially on 32bit platforms long
is quite surprisingly defined to be the same as int.
However, meanwhile, using the new C++ features, I have blocked
pretty much any possible implicit conversion path, requiring
explicit conversions in the relevant ctor invocations. So,
after weighting in the alternatives, FSecs is now defined
as boost::rational<int64_t>.
2020-02-17 02:36:54 +01:00
|
|
|
return FSecs{ n*rate.denominator(), rate.numerator()};
|
2019-06-22 21:26:18 +02:00
|
|
|
}
|
|
|
|
|
|
2011-01-09 04:56:46 +01:00
|
|
|
|
2011-01-08 20:01:26 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
/* == implementations == */
|
2011-01-09 04:56:46 +01:00
|
|
|
|
|
|
|
|
namespace { // implementation helpers...
|
|
|
|
|
|
|
|
|
|
template<typename NUM>
|
|
|
|
|
inline NUM
|
|
|
|
|
__ensure_nonzero (NUM n)
|
|
|
|
|
{
|
2019-06-22 15:15:56 +02:00
|
|
|
if (n == NUM{0})
|
2013-06-15 04:02:48 +02:00
|
|
|
throw error::Logic ("Degenerated frame grid not allowed"
|
2018-04-02 01:48:51 +02:00
|
|
|
, error::LERR_(BOTTOM_VALUE));
|
2011-01-09 04:56:46 +01:00
|
|
|
return n;
|
|
|
|
|
}
|
|
|
|
|
}//(End) implementation helpers
|
|
|
|
|
|
|
|
|
|
|
2011-01-08 20:01:26 +01:00
|
|
|
|
|
|
|
|
/** @internal applies a limiter on the provided
|
|
|
|
|
* raw time value to keep it within the arbitrary
|
|
|
|
|
* boundaries defined by (Time::MAX, Time::MIN).
|
|
|
|
|
* While Time entities are \c not a "safeInt"
|
|
|
|
|
* implementation, we limit new values and
|
|
|
|
|
* establish this safety margin to prevent
|
|
|
|
|
* wrap-around during time quantisation */
|
|
|
|
|
inline gavl_time_t
|
|
|
|
|
TimeValue::limited (gavl_time_t raw)
|
|
|
|
|
{
|
2022-10-30 01:31:25 +02:00
|
|
|
return raw > Time::MAX? Time::MAX.t_
|
|
|
|
|
: raw < Time::MIN? Time::MIN.t_
|
2011-01-08 20:01:26 +01:00
|
|
|
: raw;
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-30 01:31:25 +02:00
|
|
|
inline
|
|
|
|
|
TimeVar::TimeVar (FSecs const& fractionalSeconds)
|
|
|
|
|
: TimeVar{Time(fractionalSeconds)}
|
|
|
|
|
{ }
|
|
|
|
|
|
2011-01-09 09:49:48 +01:00
|
|
|
inline
|
|
|
|
|
Duration::Duration (TimeSpan const& interval)
|
2011-06-08 02:12:38 +02:00
|
|
|
: TimeValue(interval.duration())
|
2011-01-09 09:49:48 +01:00
|
|
|
{ }
|
|
|
|
|
|
2011-01-09 04:56:46 +01:00
|
|
|
inline
|
|
|
|
|
FrameRate::FrameRate (uint fps)
|
Timehandling: choose safer representation for fractional seconds (closes #939)
When drafting the time handling framework some years ago,
I foresaw the possible danger of mixing up numbers relating
to fractional seconds, with other plain numbers intended as
frame counts or as micro ticks. Thus I deliberately picked
an incompatible integer type for FSecs = boost::rational<long>
However, using long is problematic in itself, since its actual
bit length is not fixed, and especially on 32bit platforms long
is quite surprisingly defined to be the same as int.
However, meanwhile, using the new C++ features, I have blocked
pretty much any possible implicit conversion path, requiring
explicit conversions in the relevant ctor invocations. So,
after weighting in the alternatives, FSecs is now defined
as boost::rational<int64_t>.
2020-02-17 02:36:54 +01:00
|
|
|
: boost::rational<uint> (__ensure_nonzero(fps))
|
2011-01-09 04:56:46 +01:00
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
inline
|
|
|
|
|
FrameRate::FrameRate (uint num, uint denom)
|
Timehandling: choose safer representation for fractional seconds (closes #939)
When drafting the time handling framework some years ago,
I foresaw the possible danger of mixing up numbers relating
to fractional seconds, with other plain numbers intended as
frame counts or as micro ticks. Thus I deliberately picked
an incompatible integer type for FSecs = boost::rational<long>
However, using long is problematic in itself, since its actual
bit length is not fixed, and especially on 32bit platforms long
is quite surprisingly defined to be the same as int.
However, meanwhile, using the new C++ features, I have blocked
pretty much any possible implicit conversion path, requiring
explicit conversions in the relevant ctor invocations. So,
after weighting in the alternatives, FSecs is now defined
as boost::rational<int64_t>.
2020-02-17 02:36:54 +01:00
|
|
|
: boost::rational<uint> (__ensure_nonzero(num), denom)
|
2011-01-09 04:56:46 +01:00
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
inline
|
Timehandling: choose safer representation for fractional seconds (closes #939)
When drafting the time handling framework some years ago,
I foresaw the possible danger of mixing up numbers relating
to fractional seconds, with other plain numbers intended as
frame counts or as micro ticks. Thus I deliberately picked
an incompatible integer type for FSecs = boost::rational<long>
However, using long is problematic in itself, since its actual
bit length is not fixed, and especially on 32bit platforms long
is quite surprisingly defined to be the same as int.
However, meanwhile, using the new C++ features, I have blocked
pretty much any possible implicit conversion path, requiring
explicit conversions in the relevant ctor invocations. So,
after weighting in the alternatives, FSecs is now defined
as boost::rational<int64_t>.
2020-02-17 02:36:54 +01:00
|
|
|
FrameRate::FrameRate (boost::rational<uint> const& fractionalRate)
|
|
|
|
|
: boost::rational<uint> (__ensure_nonzero(fractionalRate))
|
2011-01-09 04:56:46 +01:00
|
|
|
{ }
|
|
|
|
|
|
2011-01-09 05:51:26 +01:00
|
|
|
inline double
|
|
|
|
|
FrameRate::asDouble() const
|
|
|
|
|
{
|
|
|
|
|
return boost::rational_cast<double> (*this);
|
|
|
|
|
}
|
2011-01-09 11:41:08 +01:00
|
|
|
|
2011-01-09 05:51:26 +01:00
|
|
|
|
2011-01-09 04:56:46 +01:00
|
|
|
|
2011-01-08 20:01:26 +01:00
|
|
|
|
2010-12-21 02:05:13 +01:00
|
|
|
}} // lib::time
|
2011-01-09 04:56:46 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace util {
|
2022-10-30 01:31:25 +02:00
|
|
|
|
2011-01-09 04:56:46 +01:00
|
|
|
inline bool
|
|
|
|
|
isnil (lib::time::Duration const& dur)
|
|
|
|
|
{
|
|
|
|
|
return 0 == dur;
|
|
|
|
|
}
|
|
|
|
|
|
Timehandling: choose safer representation for fractional seconds (closes #939)
When drafting the time handling framework some years ago,
I foresaw the possible danger of mixing up numbers relating
to fractional seconds, with other plain numbers intended as
frame counts or as micro ticks. Thus I deliberately picked
an incompatible integer type for FSecs = boost::rational<long>
However, using long is problematic in itself, since its actual
bit length is not fixed, and especially on 32bit platforms long
is quite surprisingly defined to be the same as int.
However, meanwhile, using the new C++ features, I have blocked
pretty much any possible implicit conversion path, requiring
explicit conversions in the relevant ctor invocations. So,
after weighting in the alternatives, FSecs is now defined
as boost::rational<int64_t>.
2020-02-17 02:36:54 +01:00
|
|
|
// repeated or forward declaration, see meta/util.hpp
|
|
|
|
|
template<typename X, typename COND>
|
|
|
|
|
struct StringConv;
|
|
|
|
|
|
|
|
|
|
/** specialisation: render fractional seconds (for diagnostics) */
|
|
|
|
|
template<>
|
|
|
|
|
struct StringConv<lib::time::FSecs, void>
|
|
|
|
|
{
|
|
|
|
|
static std::string
|
|
|
|
|
invoke (lib::time::FSecs) noexcept;
|
|
|
|
|
};
|
2011-01-09 04:56:46 +01:00
|
|
|
}
|
Timehandling: choose safer representation for fractional seconds (closes #939)
When drafting the time handling framework some years ago,
I foresaw the possible danger of mixing up numbers relating
to fractional seconds, with other plain numbers intended as
frame counts or as micro ticks. Thus I deliberately picked
an incompatible integer type for FSecs = boost::rational<long>
However, using long is problematic in itself, since its actual
bit length is not fixed, and especially on 32bit platforms long
is quite surprisingly defined to be the same as int.
However, meanwhile, using the new C++ features, I have blocked
pretty much any possible implicit conversion path, requiring
explicit conversions in the relevant ctor invocations. So,
after weighting in the alternatives, FSecs is now defined
as boost::rational<int64_t>.
2020-02-17 02:36:54 +01:00
|
|
|
#endif /*LIB_TIME_TIMEVALUE_H*/
|